In [1]:
! python -m pip install qiskit qiskit-aer
Requirement already satisfied: qiskit in /home/benoit/qiskit-env/lib/python3.13/site-packages (2.2.1) Requirement already satisfied: qiskit-aer in /home/benoit/qiskit-env/lib/python3.13/site-packages (0.17.2) Requirement already satisfied: rustworkx>=0.15.0 in /home/benoit/qiskit-env/lib/python3.13/site-packages (from qiskit) (0.17.1) Requirement already satisfied: numpy<3,>=1.17 in /home/benoit/qiskit-env/lib/python3.13/site-packages (from qiskit) (1.26.4) Requirement already satisfied: scipy>=1.5 in /home/benoit/qiskit-env/lib/python3.13/site-packages (from qiskit) (1.16.2) Requirement already satisfied: dill>=0.3 in /home/benoit/qiskit-env/lib/python3.13/site-packages (from qiskit) (0.4.0) Requirement already satisfied: stevedore>=3.0.0 in /home/benoit/qiskit-env/lib/python3.13/site-packages (from qiskit) (5.5.0) Requirement already satisfied: typing-extensions in /home/benoit/qiskit-env/lib/python3.13/site-packages (from qiskit) (4.15.0) Requirement already satisfied: psutil>=5 in /home/benoit/qiskit-env/lib/python3.13/site-packages (from qiskit-aer) (7.1.0) Requirement already satisfied: python-dateutil>=2.8.0 in /home/benoit/qiskit-env/lib/python3.13/site-packages (from qiskit-aer) (2.9.0.post0) Requirement already satisfied: six>=1.5 in /home/benoit/qiskit-env/lib/python3.13/site-packages (from python-dateutil>=2.8.0->qiskit-aer) (1.17.0)
In [2]:
import numpy as np
from math import pi, gcd
from qiskit import *
from qiskit_aer import AerSimulator, StatevectorSimulator
def processOneState(st): # Longueur = puissance de 2
s = list(st)
if len(s) == 2:
return {'0' : s[0], '1' : s[1]}
else:
a0 = processOneState(s[:len(s)//2])
a1 = processOneState(s[len(s)//2:])
r = {}
for k in a0:
r['0' + k] = a0[k]
for k in a1:
r['1' + k] = a1[k]
return r
def printOneState(d): # get a dict as per processStates output
for k in d:
im = d[k].imag
re = d[k].real
if abs(im) >= 0.001 or abs(re) >= 0.001:
print("% .3f + % .3fj |%s>" % (re,im,k))
def printFinalRes(result):
printOneState(processOneState(list(np.asarray(result))))
def runStateVector(qc):
simulator = StatevectorSimulator()
job = simulator.run(qc.decompose(reps=6), memory=True)
job_result = job.result()
result = job_result.results[0].to_dict()['data']['statevector']
printFinalRes(result)
def runStateVectorSeveralTimes(qc, howmany):
qc.save_statevector(label = 'collect', pershot = True)
simulator = StatevectorSimulator()
job = simulator.run(qc.decompose(reps=6), memory=True, shots=howmany)
result = job.result()
memory = result.data(0)['memory']
collect = result.data(0)['collect']
r = {}
for i in range(len(collect)):
r[str(collect[i])] = (0, collect[i])
for i in range(len(collect)):
n, v = r[str(collect[i])]
r[str(collect[i])] = (n+1, v)
for k in r:
i, v = r[k]
print(f"With {i} occurences:")
printFinalRes(v)
def runSample(qc,howmany):
simulator = AerSimulator()
job = simulator.run(qc.decompose(reps=6), shots=howmany)
res = dict(job.result().get_counts(qc))
return res
0 - Introduction¶
In this exercice, we are going to experimentally verify the amplitude amplification coming from Grover algorithm.
We shall test the algorithm on a function over N variables:
$$f(x_1,\ldots,x_n) = (x_1\wedge \ldots \wedge x_n)$$
The set $f^{-1}\{1\}$ is of size $1$.
1 - Build the circuit TODO¶
Complete the missing bits in the following code. You might find useful the gate qc.mcx(controls, target). For instance
qc.mcx(q[1:], q[0])
place a multi-controlled NOT gate on q[0] with all the other wires of q as controls.
In [3]:
N = 5 # Number of variables of f
def oracle(qc,q,aux):
pass # TODO !!!!
def u0bot(qc,q):
pass # TODO !!!!!
def grover(n_iter):
q = QuantumRegister(N) # The variables in superposition
c = ClassicalRegister(N) # Registers to store their measure
aux = QuantumRegister(1) # to store the additional wire used for O. Note that there is no need to measure it !
qc = QuantumCircuit(q,aux,c)
# TODO initialize the circuit
for _ in range(n_iter):
qc.barrier() # To physically separate each iteration (does nothing but renders the circuit more legible)
# TODO
qc.measure(q,c) # Measure
return qc
print(grover(2)) # Show the circuit for 2 iterations
░ ░ ┌─┐
q0_0: ─░──░─┤M├────────────
░ ░ └╥┘┌─┐
q0_1: ─░──░──╫─┤M├─────────
░ ░ ║ └╥┘┌─┐
q0_2: ─░──░──╫──╫─┤M├──────
░ ░ ║ ║ └╥┘┌─┐
q0_3: ─░──░──╫──╫──╫─┤M├───
░ ░ ║ ║ ║ └╥┘┌─┐
q0_4: ─░──░──╫──╫──╫──╫─┤M├
░ ░ ║ ║ ║ ║ └╥┘
q1: ─░──░──╫──╫──╫──╫──╫─
░ ░ ║ ║ ║ ║ ║
c0: 5/═══════╩══╩══╩══╩══╩═
0 1 2 3 4
2 - Run the circuit TODO¶
What does the following code do ?
In [4]:
for i in range(15):
s = runSample(grover(i),1000)
k=""
for _ in range(N):
k += "1"
if k in s:
print(i, s[k])
else:
print(i, 0)
0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0
3 - Discussion TODO¶
- Can you explain the result ? Is there any regularity ? Why ? When is the maximum value obtained ? Why ?
- Change the value of
Nto8: Can you explain the changes?