Note
Cette page a été générée à partir de tutorials/algorithms/06_qaoa.ipynb.
Algorithme d’estimation iterative de phase quantique¶
L’objectif de ce tutoriel est de comprendre comment fonctionne l’algorithme itératif d’estimation de phase quantique (IPE en anglais), pourquoi utiliser cet algorithme au lieu de l’algorithme QPE (Quantum Phase Estimation) et comment le construire avec Qiskit en utilisant le même circuit exploitant la porte de réinitialisation et la méthode c_if
qui permet d’appliquer des portes conditionnées par les valeurs stockées dans un registre classique, résultant de mesures antérieures.
Références :
Section 2 du Lab 4: Algorithme d’estimation itérative de phase (IPE) <https://qiskit.org/textbook/ch-labs/Lab04_IterativePhaseEstimation.html#2-iterative-phase-estimation-ipe-algorithm>` __
` Ch. 3.6 Estimation de la phase quantique <https://qiskit.org/textbook/ch-algorithms/quantum-phase-estimation.html>` __
[1]:
from qiskit import QuantumCircuit, ClassicalRegister, QuantumRegister, execute, assemble, Aer
from qiskit.tools.visualization import plot_histogram
from math import pi
import matplotlib.pyplot as plt
Portes conditionnées : la méthode c_if¶
Avant de commencer l’algorithme IPE, nous allons donner un bref tutoriel sur la méthode Qiskit conditionnelle, c_if, dans la construction du circuit IPE.
c_if
est une fonction (ou plus exactement une méthode de la classe Gate
) pour effectuer des opérations conditionnées par la valeur stockée précédemment dans un registre classique. Avec cette fonctionnalité, il est possible d’appliquer des portes après une mesure dans le même circuit conditionnées par le résultat de ladite mesure.
Par exemple, le code suivant exécutera la porte \(X\) si la valeur du registre classique est \(0\).
[2]:
q = QuantumRegister(1,'q')
c = ClassicalRegister(1,'c')
qc = QuantumCircuit(q, c)
qc.h(0)
qc.measure(0,0)
qc.x(0).c_if(c, 0)
qc.draw(output='mpl')
[2]:

Soulignons que la méthode c_if prévoit comme premier argument un registre classique entier, pas un bit classique simple (ni une liste de bits classiques), et comme second argument une valeur en représentation décimale (un entier non négatif), pas la valeur d’un bit simple, 0, ou 1 (ni une liste / chaîne de chiffres binaires).
Let’s make another example. Consider that we want to perform a bit flip on the third qubit after the measurements in the following circuit, when the results of the measurement of \(q_0\) and \(q_1\) are both \(1\).
[3]:
q = QuantumRegister(3,'q')
c = ClassicalRegister(3,'c')
qc = QuantumCircuit(q, c)
qc.h(q[0])
qc.h(q[1])
qc.h(q[2])
qc.barrier()
qc.measure(q,c)
qc.draw('mpl')
[3]:

Nous voulons appliquer la porte \(X\) seulement si les deux résultats de la mesure de \(q_0\) et \(q_1\) sont \(1\). Nous pouvons le faire en utilisant la méthode c_if
, avec la condition d’application de \(X\) basée sur la valeur transmise comme argument à c_if
.
Nous devrons encoder la valeur à passer à la méthode c_if pour qu’elle vérifie les valeurs 011 et 111 (en représentation binaire), car ce n’est pas important ce que \(q_2\) est mesuré.
Les deux valeurs entières dans la représentation décimale:
Nous pouvons vérifier les solutions en utilisant la méthode bin() en python (le préfixe 0b
indique le format binaire).
[4]:
print(bin(3))
print(bin(7))
0b11
0b111
Nous devons donc appliquer \(X\) à \(q_2\) en utilisant c_if deux fois, une pour chaque valeur correspondant à 011 et 111.
[5]:
q = QuantumRegister(3,'q')
c = ClassicalRegister(3,'c')
qc = QuantumCircuit(q, c)
qc.h(0)
qc.h(1)
qc.h(2)
qc.barrier()
qc.measure(q,c)
qc.x(2).c_if(c, 3) # for the 011 case
qc.x(2).c_if(c, 7) # for the 111 case
qc.draw(output='mpl')
[5]:

IPE¶
The motivation for using the IPE algorithm is that QPE algorithm works fine for short depth circuits but when the circuit starts to grow, it doesn’t work properly due to gate noise and decoherence times.
L’explication détaillée du fonctionnement de l’algorithme peut être trouvée dans l’algorithme Iterative Phase Estimation (IPE) Algorithm. Pour comprendre QPE en profondeur, vous pouvez également voir Ch.3.6 Quantum Phase Estimation.
Exemple d’IPE avec un portail 1-qubit pour :math:` U `¶
Nous voulons appliquer l’algorithme IPE pour estimer la phase pour un opérateur 1-qubit :math:` U . Par exemple, nous utilisons ici la porte :math: S”.
Let’s apply the IPE algorithm to estimate the phase for \(S\)-gate. Its matrix is
C’est-à-dire que la porte :math:` S ajoute une phase :math:` pi/2 ` à l’état :math:` | 1rangle , laissant inchangée la phase de l’état :math: | 0rangle `
Dans ce qui suit, nous utiliserons la notation et les termes utilisés dans la section 2 du lab 4 <https://qiskit.org/textbook/ch-labs/Lab04_IterativePhaseEstimation.html#2-iterative-phase-estimation-ipe-algorithm>` __.
Let’s consider to estimate the phase \(\phi=\frac{\pi}{2}\) for the eigenstate \(|1\rangle\), we should find \(\varphi=\frac{1}{4}\) (where \(\phi = 2 \pi \varphi\)). Therefore to estimate the phase we need exactly 2 phase bits, i.e. \(m=2\), since \(1/2^2=1/4\). So \(\varphi=0.\varphi_1\varphi_2\).
Rappelez-vous de la théorie selon laquelle pour l’algorithme IPE, \(m\) est aussi le nombre d’itérations, donc nous n’avons besoin que de \(2\) itérations ou étapes.
Tout d’abord, nous initialisons le circuit. IPE fonctionne avec seulement 1 qubit auxiliaire, au lieu de \(m\) comptant des qubits de l’algorithme QPE. Nous avons donc besoin de 2 qubits, 1 qubit auxiliaire et 1 pour l’état propre de \(U\)-gate, et un registre classique de 2 bits, pour les bits de phase \(\varphi_1\), \(\varphi_2\).
[6]:
nq = 2
m = 2
q = QuantumRegister(nq,'q')
c = ClassicalRegister(m,'c')
qc_S = QuantumCircuit(q,c)
Première étape¶
Now we build the quantum circuit for the first step, that is, the first iteration of the algorithm, to estimate the least significant phase bit \(\varphi_m\), in this case \(\varphi_2\). For the first step we have 3 sub-steps: - initialization - application of the Controlled-\(U\) gates - measure of the auxiliary qubit in x-basis
Application of the Controlled-\(U\) gates¶
Then we have to apply \(2^t\) times the Controlled-\(U\) operators (see also in the docs Two qubit gates), that, in this example, is the Controlled-\(S\) gate (\(CS\) for short).
Pour implémenter :math:` CS ` dans le circuit, puisque :math:` S ` est une porte de phase, nous pouvons utiliser la porte de phase contrôlée \(\text{CP}(\theta) \)theta = pi/2 `.
[8]:
cu_circ = QuantumCircuit(2)
cu_circ.cp(pi/2,0,1)
cu_circ.draw('mpl')
[8]:

Let’s apply \(2^t\) times \(\text{CP}(\pi/2)\). Since for the first step \(t=m-1\), and \(m=2\), we have \(2^t=2\).
[9]:
for _ in range(2**(m-1)):
qc_S.cp(pi/2,0,1)
qc_S.draw('mpl')
[9]:

Mesure dans la base : math:x¶
Finalement, nous effectuons la mesure du qubit auxiliaire dans la base : math:X. Nous allons donc définir une fonction pour effectuer la mesure-: math:X, puis l’appliquer.
[10]:
def x_measurement(qc, qubit, cbit):
"""Measure 'qubit' in the X-basis, and store the result in 'cbit'"""
qc.h(qubit)
qc.measure(qubit, cbit)
De cette façon, nous obtenons le bit de phase \(\varphi_2\) et le stockons dans le bit classique \(c_0\).
[11]:
x_measurement(qc_S, q[0], c[0])
qc_S.draw('mpl')
[11]:

Étapes suivantes (2ème étape)¶
Now we build the quantum circuit for the other remaining steps, in this example, only the second one. In these steps we have 4 sub-steps: the 3 sub-steps as in the first step and, in the middle, the additional step of the phase correction - initialization with reset - phase correction - application of the Controlled-\(U\) gates - measure of the auxiliary qubit in x-basis
Initialisation avec réinitialisation¶
Comme nous voulons réaliser un algorithme itératif dans le même circuit, nous devons réinitialiser le qubit auxiliaire \(q0\) après la porte de mesure et l’initialiser à nouveau comme précédemment pour recycler le qubit.
[12]:
qc_S.reset(0)
qc_S.h(0)
qc_S.draw('mpl')
[12]:

Correction de phase (pour l’étape 2)¶
As seen in the theory, in order to extract the phase bit \(\varphi_{1}\), we perform a phase correction of \(-\pi\varphi_2/2\). Of course, we need to apply the phase correction in the circuit only if the phase bit \(\varphi_2=1\), i.e. we have to apply the phase correction of \(-\pi/2\) only if the classical bit \(c_0\) is 1.
Ainsi, après la réinitialisation, nous appliquons la porte de phase \(P(\theta)\) avec la phase \(\theta=-\pi/2\) conditionnée par le bit classique \(c_0\) (\(=\varphi_2\)) en utilisant la méthode c_if
. Ainsi, comme nous l’avons vu dans la première partie de ce tutoriel, nous devons utiliser la méthode c_if
avec une valeur de 1, comme :math:` 1_{10} = 001 _{2}` (les indices \(1_{10}\) et \(_{2}\) indiquent respectivement les représentations décimales et binaires).
[13]:
qc_S.p(-pi/2,0).c_if(c,1)
qc_S.draw('mpl')
[13]:

Application of the Controlled-\(U\) gates and x-measurement (for step 2)¶
Nous appliquons alors les portes :math: »CU » comme nous l’avons fait lors de la première étape. Pour la deuxième étape, nous avons \(t=m-2\), donc \(2^t=1\). Nous appliquons donc \(\text{CP}(\pi/2\)\) une seule fois. Ensuite, nous réalisons la mesure dans la base \(X\) du qubit \(q_0\), et enregistrons le résultat, à savoir le bit de phase \(\varphi_1\), dans le bit \(c_1\) du registre classique.
[14]:
## 2^t c-U operations (with t=m-2)
for _ in range(2**(m-2)):
qc_S.cp(pi/2,0,1)
x_measurement(qc_S, q[0], c[1])
Et voilà ! nous avons notre circuit final
[15]:
qc_S.draw('mpl')
[15]:

Let’s execute the circuit with the qasm_simulator
, the simulator without noise that run locally.
[16]:
sim = Aer.get_backend('qasm_simulator')
count0 = execute(qc_S, sim).result().get_counts()
key_new = [str(int(key,2)/2**m) for key in list(count0.keys())]
count1 = dict(zip(key_new, count0.values()))
fig, ax = plt.subplots(1,2)
plot_histogram(count0, ax=ax[0])
plot_histogram(count1, ax=ax[1])
plt.tight_layout()
Sur cette image, nous avons les mêmes histogrammes, à l’exception du fait que sur l’axe X de celui de gauche se trouve la représentation binaire de \(\varphi\), c’est-à-dire les valeurs de \(\varphi_1\) et de \(\varphi_2\) tandis sa représentation décimale se trouve sur celui de droite.
Comme nous nous y attendions, nous trouvons \(\varphi=\frac{1}{4}=0,25\) avec une probabilité de \(100\%\).
Exemple d’IPE avec une porte à deux qubits¶
Now, we want to apply the IPE algorithm to estimate the phase for a 2-qubit gate \(U\). For this example, let’s consider the controlled version of the \(T\) gate, i.e. the gate \(U=\textrm{Controlled-}T\) (that from now we will express more compactly with \(CT\)). Its matrix is
Ainsi, la porte \(CT\) ajoute une phase de \(\frac{\pi}{4}\) à l’état \(|11\rangle\), et laisse inchangées les phases des autres états de base, à savoir \(|00\rangle\), \(|01\rangle\) et \(|10\rangle\).
Let’s consider to estimate the phase \(\phi=\pi/4\) for the eigenstate \(|11\rangle\), we should find \(\varphi=1/8\), since \(\phi = 2 \pi \varphi\). Therefore to estimate the phase we need exactly 3 classical bits, i.e. \(m=3\), since \(1/2^3=1/8\). So \(\varphi=0.\varphi_1\varphi_2\varphi_3\).
Comme cela a été fait dans l’exemple pour un opérateur à un qubit \(U\), nous allons passer par les mêmes étapes, bien que nous aurons cette fois \(3\) étapes, étant donné que \(m=3\) et nous ne répéterons pas toutes les explications. Donc pour plus de détails, nous conseillons de se référer à l’exemple ci-dessus portant sur un opérateur à un qubit \(U\) gate.
Tout d’abord, nous initialisons le circuit avec 3 qubits, 1 pour le qubit auxiliaire et 2 sur lesquels on appliquera notre opérateur, ainsi qu’avec 3 bits classiques pour stocker les bits de phase \(\varphi_1\), \(\varphi_2\) et \(\varphi_3\).
[17]:
nq = 3 # number of qubits
m = 3 # number of classical bits
q = QuantumRegister(nq,'q')
c = ClassicalRegister(m,'c')
qc = QuantumCircuit(q,c)
Première étape¶
Nous construisons alors le circuit quantique pour la première étape, afin d’estimer le bit de phase le moins significatif \(\varphi_m = \varphi_3\).
Initialisation¶
Nous initialisons le qubit auxiliaire en appliquant une porte d’Hadamard et les deux autres qubits en les mettant dans l’état propre \(|11\rangle\).
[18]:
qc.h(0)
qc.x([1,2])
qc.draw('mpl')
[18]:

Application of the Controlled-\(U\) gates¶
Then we have to apply multiple times the \(CU\) operator, that, in this example, is the Controlled-\(CT\) gate (\(CCT\) for short).
Afin d’implémenter \(CCT\), nous pouvons utiliser le fait que \(CT\) est une porte de phase. Nous pouvons donc utiliser la porte de phase contrôlée de façon multiple \(\text{MCP}(\theta)\), avec \(\theta=\pi/4\).
[19]:
cu_circ = QuantumCircuit(nq)
cu_circ.mcp(pi/4,[0,1],2)
cu_circ.draw('mpl')
[19]:

Let’s apply \(2^t\) times \(\text{MCP}(\pi/4)\). Since for the first step \(t=m-1\) and \(m=3\), we have \(2^t=4\).
[20]:
for _ in range(2**(m-1)):
qc.mcp(pi/4,[0,1],2)
qc.draw('mpl')
[20]:

Mesure dans la base : math:x¶
Enfin, nous réalisons la mesure du qubit auxiliaire dans la base x. Nous pouvons utiliser la fonction x_measurement
définie précédemment dans l’exemple d’un opérateur à 1 qubit. Ainsi, nous obtenons le bit de phase \(\varphi_3\) et l’enregistrons dans le bit classique \(c_0\).
[21]:
x_measurement(qc, q[0], c[0])
qc.draw('mpl')
[21]:

Étapes suivantes (deuxième et troisième étapes)¶
Nous construisons alors le circuit quantique pour les étapes restantes, la seconde et la troisième. Comme expliqué dans le premier exemple, dans ces étapes, nous avons la sous-étape supplémentaire de la correction de la phase.
Correction de phase (pour l’étape 2)¶
Afin d’extraire le bit de phase \(\varphi_{2}\), nous effectuons une correction de phase de \(-\pi \varphi_3 /2\).
Ainsi, après la réinitialisation, nous appliquons la porte de phase \(P(\theta)\) avec la phase \(\theta=-\pi/2\) conditionnée par le bit classique \(c_0\) (\(=\varphi_3\)).
[23]:
qc.p(-pi/2,0).c_if(c,1)
qc.draw('mpl')
[23]:

Application of the Controlled-\(U\) gates and x-measurement (for step 2)¶
Nous appliquons alors les portes :math: »CU » comme nous l’avons fait lors de la première étape. Pour la deuxième étape, nous avons \(t=m-2\), donc \(2^t=2\). Nous appliquons donc \(\text{MCP}\left(\frac{\pi}{4}\right)\) deux fois. Ensuite, nous réalisons la mesure dans la base \(X\) du qubit \(q_0\), stockant le résultat, à savoir le bit de phase \(\varphi_2\), dans le bit \(c_1\) du registre classique.
[24]:
for _ in range(2**(m-2)):
qc.mcp(pi/4,[0,1],2)
x_measurement(qc, q[0], c[1])
qc.draw('mpl')
[24]:

Toutes les sous-étapes de la 3ème étape¶
Pour la troisième et dernière étape, nous effectuons la réinitialisation et l’initialisation du qubit auxiliaire, comme nous l’avons fait lors de la deuxième étape.
Puis à la 3ème étape, nous devons effectuer la correction de phase de \(-2\pi 0.0\varphi_{2}\varphi_{3}= -2\pi \left(\frac{\varphi_2}{4}+\frac{\varphi_3}{8}\right)=-\frac{\varphi_2\pi}{2}-\frac{ \varphi_3\pi}{4}\), ainsi nous devons appliquer 2 corrections de phases conditionnelles, l’une étant conditionnée par \(\varphi_3\) (\(=c_0\)) et l’autre par \(\varphi_2\)(\(=c_1\)). Pour cela noous appliquons les portes suivantes : - porte \(P(-\pi/4)\) conditionné par \(c_0=1\), c’est à dire \(c=001\) (c_if avec la valeur \(1\)) - porte \(P(-\pi/2)\) conditionnée par \(c_1=1\), c’est à dire, la porte est appliquée lorsque \(c=010\) (c_if avec la valeur \(2\)) - porte \(P(-3\pi/4)\) coonditiononée par \(c_1=1\) et \(c_0=1\) c’est à dire que la porte est appliquée si \(c=011\) (c_if avec la valeur \(3\))
Ensuite, pour ce qui est des portes \(CU\), nous appliquons \(2^t\) fois la porte \(\text{MCP}\left(\frac{\pi}{4}\right)\) t=m-3 = 0`, nous n’appliquons cette porte qu’une seule fois.
[25]:
# initialization of qubit q0
qc.reset(0)
qc.h(0)
# phase correction
qc.p(-pi/4,0).c_if(c,1)
qc.p(-pi/2,0).c_if(c,2)
qc.p(-3*pi/4,0).c_if(c,3)
# c-U operations
for _ in range(2**(m-3)):
qc.mcp(pi/4,[0,1],2)
# X measurement
qc.h(0)
qc.measure(0,2)
qc.draw('mpl')
[25]:

Nous exécutons ensuite ce circuit avec le simulateur sans erreur.
[26]:
count0 = execute(qc, sim).result().get_counts()
key_new = [str(int(key,2)/2**m) for key in list(count0.keys())]
count1 = dict(zip(key_new, count0.values()))
fig, ax = plt.subplots(1,2)
plot_histogram(count0, ax=ax[0])
plot_histogram(count1, ax=ax[1])
fig.tight_layout()
Nous avons obtenu \(100\%\) de probabilité de trouver \(\varphi=0.125\), c’est-à-dire \(1/8\), comme nous nous y attendions.
[27]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
/opt/miniconda3/envs/qiskit/lib/python3.9/site-packages/qiskit/aqua/operators/operator_globals.py:48: DeprecationWarning: `from_label` is deprecated and will be removed no earlier than 3 months after the release date. Use Pauli(label) instead.
X = make_immutable(PrimitiveOp(Pauli.from_label('X')))
Version Information
Qiskit Software | Version |
---|---|
Qiskit | 0.24.1 |
Terra | 0.17.3 |
Aer | 0.7.6 |
Ignis | 0.5.2 |
Aqua | 0.8.2 |
IBM Q Provider | 0.13.1 |
System information | |
Python | 3.9.5 (default, May 18 2021, 12:31:01) [Clang 10.0.0 ] |
OS | Darwin |
CPUs | 4 |
Memory (Gb) | 16.0 |
Fri Jul 02 06:38:27 2021 EDT |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.