2

I've implemented a quantum counting algorithm for a sudoku example by following the amplitude estimation algorithm introduced in Mosca's textbook (An Introduction to Quantum Computing, page#172): enter image description here

However, when I ran my code I got an incorrect counting 13, while the right count is 2 (this sudoku has 2 answers).

I've verified the grover's operator(oracle+diffuser) gives a right answer for the sudoku, thus I believe something should be wrong with other parts of the circuit other than Grover's operator itself but don't now where.

I would appreciate any hints from you on my implementation. I've attached a diagram of my circuit.

enter image description here

taketoshi kinoshita
  • 1,249
  • 1
  • 2
  • 11

1 Answers1

0

The answer was explained here. I needed to output N - M as the number of solutions instead of just M. This fix's given a right answer.

#!/usr/bin/env python
# coding: utf-8

In[1]:

from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, transpile from qiskit_aer import AerSimulator, Aer from qiskit.visualization import plot_histogram, plot_bloch_multivector, plot_distribution from qiskit_ibm_runtime import QiskitRuntimeService from numpy import pi import numpy as np import math import matplotlib.pyplot as plt from qiskit.circuit.library import ZGate, XGate, RZGate, SGate from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager from qiskit_ibm_runtime import Session, SamplerV2 as Sampler

service = QiskitRuntimeService()

In[2]:

def diffuser(nqubits): #import pdb; pdb.set_trace() circ = QuantumCircuit(nqubits) # Apply transformation |s> -> |00..0> (H-gates) for qubit in range(nqubits): circ.h(qubit) # Apply transformation |00..0> -> |11..1> (X-gates) for qubit in range(nqubits): circ.x(qubit) # Do multi-controlled-Z gate circ.h(nqubits-1)

circ.append(XGate().control(nqubits-1), list(range(nqubits))) 

circ.h(nqubits-1)
# Apply transformation |11..1> -> |00..0>
for qubit in range(nqubits):
    circ.x(qubit)
# Apply transformation |00..0> -> |s>
for qubit in range(nqubits):
    circ.h(qubit)
# We will return the diffuser as a gate
U_s = circ.to_gate()
U_s.name = "U_0"
return U_s


In[3]:

apply inverse phase shift rotation gates in recursive

def inv_qft_rotation(circuit, n, m): if n==0: return circuit # get theta index for rotation l = range(2, m-n+2) revl = list(l)[::-1]

control_idx = 0
n-=1

for k in revl:
    circuit.cp(-pi/2**(k-1), control_idx, m-n-1)
    control_idx+=1
circuit.h(m-n-1)
return inv_qft_rotation(circuit, n, m)


In[4]:

apply swap gates

def qft_swap(circuit, n): # num of times of swap swap_num = (int)(n/2) m = n-1 for i in range(swap_num): circuit.swap(i, m) m -= 1

In[5]:

apply inverse qft transform

def inv_qft(circuit, n, m): qft_swap(circuit, n) inv_qft_rotation(circuit, n, m)

In[6]:

apply phase shift rotation gates in recursive

def qft_rotation(circuit, n): if n==0: return circuit n-=1 circuit.h(n) control_idx = n-1 for k in range(2, n+2): circuit.cp(pi/2**(k-1), control_idx, n) control_idx-=1 return qft_rotation(circuit, n)

In[7]:

apply swap gates

def qft_swap(circuit, n): # num of times of swap swap_num = (int)(n/2) m = n-1 for i in range(swap_num): circuit.swap(i, m) m -= 1

In[8]:

apply qft transform

def qft(circuit, n): qft_rotation(circuit, n) qft_swap(circuit, n)

In[9]:

problem1

sudoku

---------

|V0 | V1|

|-------|

|V2 | V3|

---------

In[10]:

clause_list = [[0,1], [2,3], [0,2], [1,3]]

In[11]:

def XOR(qc, a, b, output): qc.cx(a, output) qc.cx(b, output)

In[12]:

nqubits = len(clause_list) tqubits = nqubits + 1

In[13]:

prepare registers

count_qubits = QuantumRegister(tqubits, name='count') var_qubits = QuantumRegister(nqubits, name='v') clause_qubits = QuantumRegister(nqubits, name='c') output_qubit = QuantumRegister(1, name='out') meas = ClassicalRegister(tqubits, name="meas") qc = QuantumCircuit(count_qubits, var_qubits, clause_qubits, output_qubit, meas) #qc.draw()

In[14]:

apply QFT/hadamard gate

#qc.h(count_qubits) qft(qc, tqubits) qc.h(var_qubits)

#qc.barrier() #qc.draw()

In[15]:

def sudoku_oracle(nqubits): var_qubits = QuantumRegister(nqubits) clause_qubits = QuantumRegister(nqubits) output_qubit = QuantumRegister(1) circ = QuantumCircuit(var_qubits, clause_qubits, output_qubit)
# Compute clauses i = 0 #compute clauses for clause in clause_list: XOR(circ, var_qubits[clause[0]], var_qubits[clause[1]], clause_qubits[i]) i += 1 # inverse the output qubit if all the control bits are 1. circ.append(XGate().control(nqubits), list(clause_qubits)+[output_qubit]) circ.z(output_qubit) circ.append(XGate().control(nqubits), list(clause_qubits)+[output_qubit])

#uncompute clauses
i = 0
for clause in clause_list[::-1]:
    XOR(circ, var_qubits[clause[1]], var_qubits[clause[0]], clause_qubits[nqubits-1-i])
    i += 1
U_f = circ.to_gate()
U_f.label = "U_f"
return U_f


In[16]:

def get_grover_op(niter, nqubits): #import pdb; pdb.set_trace() var_qubits = QuantumRegister(nqubits) clause_qubits = QuantumRegister(nqubits) output_qubit = QuantumRegister(1) q = QuantumCircuit(var_qubits, clause_qubits, output_qubit) for i in range(niter): q.append(sudoku_oracle(nqubits), list(var_qubits)+list(clause_qubits)+[output_qubit]) q.append(diffuser(nqubits), list(var_qubits)) U_g = q.to_gate() U_g.label = f"Grover$^{niter}$" return U_g

In[17]:

repetitions = 1 for counting_qubit in range(tqubits): #import pdb; pdb.set_trace() gop = get_grover_op(repetitions, nqubits) circ_grover_iter = gop.control() qc.append(circ_grover_iter, [count_qubits[counting_qubit]]+list(var_qubits)+list(clause_qubits)+[output_qubit]) repetitions *= 2

In[18]:

Apply inverse QFT

inv_qft(qc, tqubits, tqubits) for i in range(tqubits): qc.measure(count_qubits[i], meas[i]) qc.draw("mpl",plot_barriers = False,fold=-1)

In[19]:

backend = AerSimulator() pm = generate_preset_pass_manager(backend=backend, optimization_level=0) shots = 1024

isa_qc = pm.run(qc) sampler = Sampler(backend) result = sampler.run([isa_qc], shots=shots).result()

pub_result = result[0] counts = pub_result.data.meas.get_counts()

plot_distribution(counts, title="phase estimation")

In[20]:

measured_str = max(counts, key=counts.get) measured_int = int(measured_str, 2) print("Register Output = %i" % measured_int)

In[21]:

theta = pi * measured_int/(2**tqubits) print("theta = %f" % theta)

In[22]:

N = 2nqubits print("N = %i" % N) M = N * (math.sin(theta)2) print("num of solutions : %f " % (N-M))

In[ ]:

num of solutions : 2.343146

taketoshi kinoshita
  • 1,249
  • 1
  • 2
  • 11