French
Languages
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil

Note

Cette page a été générée et traduite à partir de tutorials/algorithms/09_IQPE.ipynb.

Algorithme itératif d’estimation 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 :

Portes conditionnées : la méthode c_if

Avant de s’attaquer à l’algorithme IPE, nous allons effectuer un bref rappel sur la méthode Qiskit conditionnelle, c_if, étant donné qu’elle intervient dans la construction du circuit de l’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\).

[1]:
from qiskit import QuantumCircuit

qc = QuantumCircuit(1, 1)
qc.h(0)
qc.measure(0,0)
qc.x(0).c_if(0, 0)
qc.draw(output='mpl')
[1]:
../../_images/tutorials_algorithms_09_IQPE_3_0.png

On remarquera que la méthode c_if attend comme premier argument un registre classique entier, et non pas un unique bit classique (ou une liste de bits classiques), tandis qu’elle s’attend à recevoir comme second argument une valeur en représentation décimale (un entier non négatif), et non pas la valeur d’un bit simple, 0, ou 1 (ni une liste/chaîne de bits).

Prenons un autre exemple. Considérons que nous voulons réaliser un bit flip sur le troisième qubit après les mesures dans le circuit suivant, lorsque les résultats de la mesure de :math:` q_0 ` et :math:` q_1 ` sont tous les deux :math:` 1 `.

[2]:
from qiskit import QuantumRegister, ClassicalRegister

q = QuantumRegister(3, 'q')
c = ClassicalRegister(3, 'c')
qc = QuantumCircuit(q, c)

qc.h([0, 1, 2])
qc.barrier()
qc.measure(q, c)

qc.draw('mpl')
[2]:
../../_images/tutorials_algorithms_09_IQPE_5_0.png

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 allons devoir encoder la valeur à passer à la méthode c_if pour qu’elle soit conditionnée par les valeurs 011 et 111 (en représentation binaire), puisque la valeur du bit le plus à gauche, à savoir celle de \(q_2\), n’importe pas.

On peut calculer les valeurs décimales de ces deux nombres binaires comme suit :

9bb5ae4a18b1450296322edb69311630

Nous pouvons vérifier les solutions en utilisant la méthode bin() en python (le préfixe 0b indique le format binaire).

[3]:
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.

[4]:
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')
[4]:
../../_images/tutorials_algorithms_09_IQPE_11_0.png

IPE

La motivation de l’utilisation de l’algorithme IPE est que l’algorithme QPE fonctionne bien pour les circuits de courte profondeur mais lorsque le circuit commence à croître, il ne fonctionne pas correctement en raison du bruit de la porte et des temps de décohérence.

L’explication détaillée du fonctionnement de l’algorithme peut être trouvée sur la page Iterative Phase Estimation (IPE) Algorithm. Pour comprendre l’algorithme QPE en profondeur, vous pouvez également voir Ch.3.6 Quantum Phase Estimation.

Exemple d’IPE avec une porte \(U\) s’appliquant sur un unique qubit

Nous voulons appliquer l’algorithme IPE pour estimer la phase d’une valeur propre d’un opérateur \(U\) s’appliquant sur un unique qubit. Par exemple, nous utilisons ici la porte \(S\).

Appliquons l’algorithme IPE pour estimer la phase pour \(S\)-gate. Sa matrice est

\[\begin{split} S = \begin{bmatrix} 1 & 0\\ 0 & e^\frac{i\pi}{2}\\ \end{bmatrix}\end{split}\]

Ainsi, la porte \(S\) ajoute une phase \(\frac{\pi}{2}\) à l’état \(|1\rangle\) et laisse inchangée la phase de l’état \(|0\rangle\)

\[S|1\rangle = e^\frac{i\pi}{2}|1\rangle\]

Dans ce qui suit, nous utiliserons la notation et les termes utilisés dans la section 2 du Lab 4.

On veut alors estimer la phase \(\phi=\frac{\pi}{2}\) pour la valeur propre \(|1\rangle\), nous devrions trouver \(\varphi=\frac{1}{4}\) (où \(\phi = 2 \pi \varphi\)). Par conséquent, pour estimer la phase, nous avons besoin d’exactement 2 bits de phase, c’est-à-dire \(m=2\), comme \(1/2^2=1/4\). Donc \(\varphi=0.\varphi_1\varphi_2\).

On rappelle que 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, il nous faut initialiser le circuit. L’algorithme IPE fonctionne avec seulement un qubit auxiliaire, au lieu des \(m\) qubits à mesurer de l’algorithme QPE. Nous avons donc besoin de 2 qubits, 1 qubit auxiliaire et 1 pour l’état propre de la porte \(U\), ainsi que d’un registre classique de 2 bits, pour les bits de phase \(\varphi_1\) et \(\varphi_2\).

[5]:
nq = 2
m = 2
q = QuantumRegister(nq, 'q')
c = ClassicalRegister(m, 'c')

qc_S = QuantumCircuit(q,c)

Première étape

Nous construisons maintenant le circuit quantique pour la première étape, c’est-à-dire la première itération de l’algorithme, afin d’estimer le bit de phase le moins significatif \(\varphi_m\), dans ce cas \(\varphi_2\). Pour la première étape, nous avons 3 sous-étapes :- initialisation - application de la porte contrôle \(U\) - mesure du qubit auxiliaire dans la base X

Initialisation

L’initialisation consiste à appliquer une porte d’Hadamard au qubit auxiliaire et à préparer l’état propre \(|1\rangle\).

[6]:
qc_S.h(0)
qc_S.x(1)
qc_S.draw('mpl')
[6]:
../../_images/tutorials_algorithms_09_IQPE_15_0.png

Application des portes Control-\(U\)

Nous devons ensuite appliquer \(2^t\) fois les portes Control-\(U\) (voir la documentation relatives aux portes à deux qubits), qui, dans cet exemple, est la porte Control-\(S\) (\(CS\) en abrégé).

Pour implémenter \(CS\), nous pouvons utiliser le fait que \(S\) soit une porte de phase. Nous pouvons donc utiliser la porte de phase contrôlée \(\text{CP}(\theta)\), avec \(\theta=\frac{\pi}{2}\).

[7]:
from math import pi

cu_circ = QuantumCircuit(2)
cu_circ.cp(pi/2, 0, 1)
cu_circ.draw('mpl')
[7]:
../../_images/tutorials_algorithms_09_IQPE_17_0.png

Appliquons \(2^t\) fois \(\text{CP}(\pi/2)\). Comme pour la première étape \(t=m-1\), et \(m=2\), nous avons donc \(2^t=2\).

[8]:
for _ in range(2 ** (m - 1)):
    qc_S.cp(pi/2, 0, 1)
qc_S.draw('mpl')
[8]:
../../_images/tutorials_algorithms_09_IQPE_19_0.png

Mesure dans la base X

Enfin, nous effectuons la mesure du qubit auxiliaire dans la base X. Nous allons donc définir une fonction pour effectuer la x_measurement et puis l’appliquer.

[9]:
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)

Ainsi, nous obtenons le bit de phase \(\varphi_2\) et le stockons dans le bit classique \(c_0\).

[10]:
x_measurement(qc_S, q[0], c[0])
qc_S.draw('mpl')
[10]:
../../_images/tutorials_algorithms_09_IQPE_23_0.png

Étapes suivantes (deuxième étape)

Nous construisons maintenant le circuit quantique pour les étapes restantes, dans cet exemple, on ne montrera que la seconde. Dans ces étapes, nous avons 4 sous-étapes : les 3 sous-étapes identiques à la première étape et, au milieu, l’étape supplémentaire de la correction de phase - initialisation avec réinitialisation - correction de phase - application des portes Control-\(U\) - mesure du qubit auxiliaire en base X

Initialisation avec réinitialisation

Puisque nous voulons réaliser un algorithme itératif en utilisant le même circuit, nous devons réinitialiser le qubit auxiliaire \(q_0\) après la mesure et l’initialiser à nouveau comme précédemment afin de pouvoir réutiliser le qubit.

[11]:
qc_S.reset(0)
qc_S.h(0)
qc_S.draw('mpl')
[11]:
../../_images/tutorials_algorithms_09_IQPE_25_0.png

Correction de phase (pour l’étape 2)

Comme vu dans la théorie, afin d’extraire le bit de phase :math:` varphi_{1}`, nous effectuons une correction de phase de \(-\pi\varphi_2/2\). Bien sûr, nous devons appliquer la correction de phase dans le circuit seulement si la phase bit \(\varphi_2=1\), c’est-à-dire que nous devons appliquer la correction de phase du \(-\pi/2\) seulement si le bit classique \(c_0\) est 1.

Ainsi, après la réinitialisation, nous appliquons la porte de phase \(\text{P}(\theta)\) avec la phase \(\theta=-\frac{\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 \(_{10}\) et :math:`_2 ` indiquent respectivement les représentations décimales et binaires).

[12]:
qc_S.p(-pi/2, 0).c_if(c, 1)
qc_S.draw('mpl')
[12]:
../../_images/tutorials_algorithms_09_IQPE_27_0.png

Application des portes Control-\(U\) et mesure dans la base X (pour l’étape 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.

[13]:
## 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

[14]:
qc_S.draw('mpl')
[14]:
../../_images/tutorials_algorithms_09_IQPE_31_0.png

Échantillons le circuit avec la primitive de Qiskit Aer Sampler, un simulateur local sans bruit qui s’exécute localement.

[15]:
import matplotlib.pyplot as plt

from qiskit.tools.visualization import plot_histogram
from qiskit_aer.primitives import Sampler

sampler = Sampler()

job = sampler.run(qc_S)
result = job.result()

dist0 = result.quasi_dists[0]

key_new = [str(key/2**m) for key in list(dist0.keys())]
dist1 = dict(zip(key_new, dist0.values()))

fig, ax = plt.subplots(1,2)
plot_histogram(dist0, ax=ax[0])
plot_histogram(dist1, ax=ax[1])
plt.tight_layout()
../../_images/tutorials_algorithms_09_IQPE_33_0.png

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 que se trouve sur celui de droite sa représentation décimale.

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

Maintenant, nous voulons appliquer l’algorithme IPE pour estimer la phase d’une porte s’apliquant sur 2 qubits \(U\). Pour cet exemple, considérons la version contrôlée de la porte \(T\), c’est à dire la porte \(U=\textrm{Controlled-}T\) (ce que nous allons désormais exprimer plus compactement avec \(CT\)). Sa matrice est

\[\begin{split} CT = \begin{bmatrix} 1 & 0 & 0 & 0\\ 0 & 1 & 0 & 0\\ 0 & 0 & 1 & 0\\ 0 & 0 & 0 & e^\frac{i\pi}{4}\\ \end{bmatrix}\end{split}\]

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\).

On veut estimer la phase \(\phi=\pi/4\) pour l’état propre \(|11\rangle\), nous devrions trouver \(\varphi=1/8\), puisque \(\phi = 2 \pi \varphi\). Donc pour estimer la phase, nous avons besoin exactement 3 bits classiques, c’est-à-dire \(m=3\), depuis \(1/2^3=1/8\). Donc \(\varphi=0.\varphi_1\varphi_2\varphi_3\).

Comme cela a été fait dans l’exemple pour un opérateur à un qubit, 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.

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\).

[16]:
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 dessus et les deux autres qubits en les mettant dans l’état propre \(|11\rangle\).

[17]:
qc.h(0)
qc.x([1, 2])
qc.draw('mpl')
[17]:
../../_images/tutorials_algorithms_09_IQPE_38_0.png

Application des portes Control-\(U\)

Ensuite, nous devons appliquer plusieurs fois l’opérateur \(CU\), qui, dans cet exemple, est la porte Control-\(CT\) (\(CCT\) en abrégé).

Afin d’implémenter \(CCT\), nous pouvons utiliser le fait que \(CT\) soit une porte de phase. Nous pouvons donc utiliser la porte de phase contrôlée de façon multiple \(\text{MCP}(\theta)\), avec \(\theta=\frac{\pi}{4}\).

[18]:
cu_circ = QuantumCircuit(nq)
cu_circ.mcp(pi/4, [0, 1], 2)
cu_circ.draw('mpl')
[18]:
../../_images/tutorials_algorithms_09_IQPE_40_0.png

Appliquons alors \(2^t\) fois \(\text{MCP}(\pi/4\)\). Puisque pour la première étape on a \(t=m-1\) et que l’on a \(m=3\), on en déduit \(2^t=4\).

[19]:
for _ in range(2 ** (m - 1)):
    qc.mcp(pi/4, [0, 1], 2)
qc.draw('mpl')
[19]:
../../_images/tutorials_algorithms_09_IQPE_42_0.png

Mesure dans la base 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\).

[20]:
x_measurement(qc, q[0], c[0])
qc.draw('mpl')
[20]:
../../_images/tutorials_algorithms_09_IQPE_44_0.png

É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.

Initialisation avec réinitialisation

[21]:
qc.reset(0)
qc.h(0)
qc.draw('mpl')
[21]:
../../_images/tutorials_algorithms_09_IQPE_46_0.png

Correction de phase (pour l’étape 2)

Afin d’extraire le bit de phase \(\varphi_{2}\), nous effectuons une correction de phase de \(-\varphi_3\frac{\pi}{2}\).

Ainsi, après la réinitialisation, nous appliquons la porte de phase \(\text{P}(\theta)\) avec la phase \(\theta=-\frac{\pi}{2}\) conditionnée par le bit classique \(c_0\) (\(=\varphi_3\)).

[22]:
qc.p(-pi/2, 0).c_if(c, 1)
qc.draw('mpl')
[22]:
../../_images/tutorials_algorithms_09_IQPE_48_0.png

Application des portes Control-\(U\) et mesure dans la base X (pour l’étape 2)

Nous appliquons 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}(\pi/4)\) \(2\) fois. Et 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\).

[23]:
for _ in range(2 ** (m - 2)):
    qc.mcp(pi/4, [0, 1], 2)
x_measurement(qc, q[0], c[1])
qc.draw('mpl')
[23]:
../../_images/tutorials_algorithms_09_IQPE_50_0.png

Les sous-étapes de la troisiè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 nous appliquons les portes suivantes : - porte \(P(-\pi/4)\) conditionné par \(c_0=1\), c’est à dire, par \(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)\) conditionné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.

[24]:
# 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/2, 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')
[24]:
../../_images/tutorials_algorithms_09_IQPE_52_0.png

Nous exécutons ensuite ce circuit avec le simulateur sans bruit.

[25]:
result = sampler.run(qc).result()
dist0 = result.quasi_dists[0]

key_new = [str(key/2**m) for key in list(dist0.keys())]
dist1 = dict(zip(key_new, dist0.values()))

fig, ax = plt.subplots(1,2)
plot_histogram(dist0, ax=ax[0])
plot_histogram(dist1, ax=ax[1])
plt.tight_layout()
../../_images/tutorials_algorithms_09_IQPE_54_0.png

Nous avons obtenu \(100\%\) probabilité de trouver \(\varphi=0.125\), c’est-à-dire \(1/8\), comme nous nous y attendions.

[26]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.23.0.dev0+1b4fed3
qiskit-aer0.11.1
qiskit-nature0.5.0
System information
Python version3.9.13
Python compilerClang 12.0.0
Python buildmain, Oct 13 2022 16:12:30
OSDarwin
CPUs4
Memory (Gb)32.0
Fri Dec 09 16:18:07 2022 CET

This code is a part of Qiskit

© Copyright IBM 2017, 2022.

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.