Spanish
Idiomas
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil

Nota

Esta página fue generada a partir de tutorials/textbook/01_IQPE.ipynb.

Algoritmo de Estimación de Fase Cuántica Iterativa

El objetivo de este tutorial es comprender cómo funciona el algoritmo de Estimación de Fase Iterativa (Iterative Phase Estimation, IPE), por qué usaríamos el algoritmo IPE en lugar del algoritmo QPE (Quantum Phase Estimation, Estimación de Fase Cuántica) y cómo construirlo con Qiskit utilizando el mismo circuito aprovechando la compuerta de reinicio y el método c_if que permite aplicar compuertas condicionadas por los valores almacenados en un registro clásico, resultantes de mediciones previas.

Referencias

[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

Compuertas condicionadas: el método c_if

Antes de iniciar el algoritmo IPE, vamos a dar un breve tutorial sobre el método condicional de Qiskit, c_if, a medida que se avanza en la construcción del circuito IPE.

c_if es una función (en realidad, un método de la clase compuerta) para realizar operaciones condicionadas basadas en el valor almacenado previamente en un registro clásico. Con esta función puedes aplicar compuertas después de una medición en el mismo circuito condicionado por el resultado de la medición.

Por ejemplo, el siguiente código ejecutará la compuerta \(X\) si el valor del registro clásico es \(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]:
../../_images/tutorials_textbook_01_IQPE_4_0.png

Resaltamos que el método c_if espera como primer argumento un registro clásico completo, no un solo bit clásico (o una lista de bits clásicos), y como segundo argumento un valor en representación decimal (un entero no negativo), no el valor de un solo bit, 0, o 1 (o una lista/cadena de dígitos binarios).

Hagamos otro ejemplo. Considera que queremos realizar un cambio de bit en el tercer qubit después de las mediciones en el siguiente circuito, cuando los resultados de la medición de \(q_0\) y \(q_1\) son ambos \(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]:
../../_images/tutorials_textbook_01_IQPE_6_0.png

Queremos aplicar la compuerta \(X\), solo si ambos resultados de la medición de \(q_0\) y \(q_1\) son \(1\). Podemos hacer esto usando el método c_if, condicionando la aplicación de \(X\) dependiendo del valor pasado como argumento a c_if.

Tendremos que codificar el valor para pasar al método c_if de manera que verifique los valores 011 y 111 (en representación binaria), ya que no importa cómo sea medido \(q_2\).

Los 2 valores enteros en representación decimal:

1165dfe4ff474c479d90caf8dca5424e

Podemos verificar las soluciones usando el método bin() en python (el prefijo 0b indica el formato binario).

[4]:
print(bin(3))
print(bin(7))
0b11
0b111

Entonces tenemos que aplicar \(X\) a \(q_2\) usando c_if dos veces, una para cada valor correspondiente a 011 y 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]:
../../_images/tutorials_textbook_01_IQPE_12_0.png

IPE

La motivación para usar el algoritmo IPE es que el algoritmo QPE funciona bien para circuitos de poca profundidad, pero cuando el circuito comienza a crecer, no funciona correctamente debido al ruido de la compuerta y los tiempos de decoherencia.

La explicación detallada de cómo funciona el algoritmo se puede encontrar en Algoritmo de Estimación de Fase Iterativa (IPE). Para comprender la QPE en profundidad, puedes consultar también Ch.3.6 Estimación de Fase Cuántica.

Ejemplo de IPE con una compuerta de 1 qubit para \(U\)

Queremos aplicar el algoritmo IPE para estimar la fase de un operador \(U\) de 1 qubit. Por ejemplo, aquí usamos la compuerta \(S\).

Apliquemos el algoritmo IPE para estimar la fase de la compuerta \(S\). Su matriz es

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

Es decir, la compuerta \(S\) agrega una fase de \(\pi/2\) al estado \(|1\rangle\), dejando sin cambios a la fase del estado \(|0\rangle\)

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

En lo siguiente, utilizaremos la notación y los términos utilizados en la Sección 2 del laboratorio 4.

Consideremos estimar la fase \(\phi=\frac{\pi}{2}\) para el estado propio \(|1\rangle\), deberíamos encontrar \(\varphi=\frac{1}{4}\) (donde \(\phi = 2 \pi \varphi\)). Por lo tanto, para estimar la fase necesitamos exactamente 2 bits de fase, es decir, \(m=2\), ya que \(1/2^2=1/4\). Entonces \(\varphi=0.\varphi_1\varphi_2\).

Recuerda de la teoría que para el algoritmo IPE, \(m\) es también el número de iteraciones, por lo que solo necesitamos \(2\) iteraciones o pasos.

Primero, inicializamos el circuito. IPE trabaja con solo 1 qubit auxiliar, en lugar de \(m\) qubits contados del algoritmo QPE. Por lo tanto, necesitamos 2 qubits, 1 qubit auxiliar y 1 para el estado propio de la compuerta \(U\), y un registro clásico de 2 bits, para los bits de fase \(\varphi_1\), \(\varphi_2\).

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

qc_S = QuantumCircuit(q,c)

Primer paso

Ahora construimos el circuito cuántico para el primer paso, es decir, la primera iteración del algoritmo, para estimar el bit de fase menos significativo \(\varphi_m\), en este caso \(\varphi_2\). Para el primer paso tenemos 3 subpasos: - inicialización - aplicación de las compuertas \(U\) controladas - medición del qubit auxiliar en la base x

Inicialización

La inicialización consiste en la aplicación de la compuerta Hadamard al qubit auxiliar y la preparación del estado propio \(|1\rangle\).

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

Aplicación de las compuertas \(U\) controladas

Luego tenemos que aplicar \(2^t\) veces los operadores \(U\) controlados (ver también en la documentación Compuertas de dos qubits), que, en este ejemplo, es la compuerta \(S\) controlada (\(CS\) para abreviar).

Para implementar \(CS\) en el circuito, ya que \(S\) es una compuerta de fase, podemos usar la compuerta de fase controlada \(\text{CP}(\theta)\), con \(\theta=\pi/2\).

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

Apliquemos \(2^t\) veces \(\text{CP}(\pi/2)\). Dado que para el primer paso \(t=m-1\), y \(m=2\), tenemos \(2^t=2\).

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

Medición en la base x

Finalmente, realizamos la medición del qubit auxiliar en la base x. Así que definiremos una función para realizar la x_measure y luego la aplicaremos.

[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 esta forma obtenemos el bit de fase \(\varphi_2\) y lo almacenamos en el bit clásico \(c_0\).

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

Pasos posteriores (segundo paso)

Ahora construimos el circuito cuántico para los otros pasos restantes, en este ejemplo, solo el segundo. En estos pasos tenemos 4 subpasos: los 3 subpasos como en el primer paso y, en medio, el paso adicional de la corrección de fase - inicialización con restablecimiento - corrección de fase - aplicación de la compuerta \(U\) controlada - medición del qubit auxiliar en la base x

Inicialización con restablecimiento

Como queremos realizar un algoritmo iterativo en el mismo circuito, necesitamos restablecer el qubit auxiliar \(q0\) después de la compuerta de medición e inicializarlo nuevamente como antes para reciclar el qubit.

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

Corrección de fase (para el paso 2)

Como se ve en la teoría, para extraer el bit de fase \(\varphi_{1}\), realizamos una corrección de fase de \(-\pi\varphi_2/2\). Por supuesto, necesitamos aplicar la corrección de fase en el circuito solo si el bit de fase \(\varphi_2=1\), es decir, tenemos que aplicar la corrección de fase de \(-\pi/2\) solo si el bit clásico \(c_0\) es 1.

Entonces, después del restablecimiento, aplicamos la compuerta de fase \(P(\theta)\) con fase \(\theta=-\pi/2\) condicionada por el bit clásico \(c_0\) (\(=\varphi_2\)) usando el método c_if. Entonces, como vimos en la primera parte de este tutorial, tenemos que usar el método c_if con un valor de 1, como \(1_{10} = 001_{2}\) (los subíndices \(_{10}\) y \(_2\) indican las representaciones decimal y binaria).

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

Aplicación de las compuertas \(U\) controladas y medición en x (para el paso 2)

Aplicamos las operaciones \(CU\) como hicimos en el primer paso. Para el segundo paso tenemos \(t=m-2\), por lo tanto \(2^t=1\). Entonces aplicamos \(\text{CP}(\pi/2)\) una vez. Y luego realizamos la medición en x del qubit \(q_0\), almacenando el resultado, el bit de fase \(\varphi_1\), en el bit \(c_1\) del registro clásico.

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

Y listo, tenemos nuestro circuito final

[15]:
qc_S.draw('mpl')
[15]:
../../_images/tutorials_textbook_01_IQPE_32_0.png

Ejecutemos el circuito con el qasm_simulator, el simulador sin ruido que se ejecuta localmente.

[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()

En la imagen tenemos los mismos histogramas, pero a la izquierda tenemos en el eje x la cadena con bits de fase \(\varphi_1\), \(\varphi_2\) y a la derecha la fase real \(\varphi\) en representación decimal.

Como esperábamos, hemos encontrado \(\varphi=\frac{1}{4}=0.25\) con una probabilidad de \(100\%\).

Ejemplo de IPE con una compuerta de 2 qubits

Ahora, queremos aplicar el algoritmo IPE para estimar la fase para una compuerta \(U\) de 2 qubits. Para este ejemplo, consideremos la versión controlada de la compuerta \(T\), es decir, la compuerta \(U=\textrm{Controlled-}T\) (que a partir de ahora expresaremos de manera más compacta con \(CT\)). Su matriz es

\[\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}\]

Es decir, la compuerta \(CT\) agrega una fase de \(\pi/4\) al estado \(|11\rangle\), dejando sin cambios la fase de los otros estados de la base computacional \(|00\rangle\), \(|01\rangle\), \(|10\rangle\).

Consideremos estimar la fase \(\phi=\pi/4\) para el estado propio \(|11\rangle\), deberíamos encontrar \(\varphi=1/8\), ya que \(\phi = 2 \pi \varphi\). Por lo tanto, para estimar la fase necesitamos exactamente 3 bits clásicos, es decir, \(m=3\), ya que \(1/2^3=1/8\). Entonces \(\varphi=0.\varphi_1\varphi_2\varphi_3\).

Como se hizo con el ejemplo para el operador \(U\) de 1 qubit, seguiremos los mismos pasos, pero esta vez tendremos \(3\) pasos ya que \(m=3\), y no repetiremos todas las explicaciones. Entonces, para obtener más detalles, consulta el ejemplo anterior para la compuerta \(U\) de 1 qubit.

Primero, inicializamos el circuito con 3 qubits, 1 para el qubit auxiliar y 2 para la compuerta de 2 qubits, y 3 bits clásicos para almacenar los bits de fase \(\varphi_1\), \(\varphi_2\), \(\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)

Primer paso

Ahora construimos el circuito cuántico para el primer paso, para estimar el bit de fase menos significativo \(\varphi_m=\varphi_3\).

Inicialización

Inicializamos el qubit auxiliar y los otros qubits con el estado propio \(|11\rangle\).

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

Aplicación de las compuertas \(U\) controladas

Luego tenemos que aplicar varias veces el operador \(CU\), que, en este ejemplo, es la compuerta \(CT\) controlada (\(CCT\) para abreviar).

Para implementar \(CCT\) en el circuito, ya que \(T\) es una compuerta de fase, podemos usar la compuerta de fase multicontrolada \(\text{MCP}(\theta)\), con \(\theta=\pi/4\).

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

Apliquemos \(2^t\) veces \(\text{MCP}(\pi/4)\). Dado que para el primer paso \(t=m-1\) y \(m=3\), tenemos \(2^t=4\).

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

Medición en la base x

Finalmente, realizamos la medición del qubit auxiliar en la base x. Podemos usar la función x_measurement definida anteriormente en el ejemplo para la compuerta de 1 qubit. De esta forma hemos obtenido el bit de fase \(\varphi_3\) y lo almacenamos en el bit clásico \(c_0\).

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

Pasos posteriores (segundo, tercero)

Ahora construimos el circuito cuántico para los otros pasos restantes, el segundo y el tercero. Como se dijo en el primer ejemplo, en estos pasos tenemos el subpaso adicional de la corrección de fase.

Inicialización con restablecimiento

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

Corrección de fase (para el paso 2)

Para extraer el bit de fase \(\varphi_{2}\), realizamos una corrección de fase de \(-\pi\varphi_3/2\).

Entonces, después del restablecimiento, aplicamos la compuerta de fase \(P(\theta)\) con la fase \(\theta=-\pi/2\) condicionada por el bit clásico \(c_0\) (\(=\varphi_3\)).

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

Aplicación de las compuertas \(U\) controladas y medición en x (para el paso 2)

Aplicamos las operaciones \(CU\) como hicimos en el primer paso. Para el segundo paso tenemos \(t=m-2\), por lo tanto \(2^t=2\). Entonces aplicamos \(\text{MCP}(\pi/4)\) \(2\) veces. Y luego realizamos la medición en x del qubit \(q_0\), almacenando el bit de fase \(\varphi_2\) en el bit \(c_1\).

[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]:
../../_images/tutorials_textbook_01_IQPE_51_0.png

Todos los subpasos del 3er paso

Para el tercer y último paso, realizamos el restablecimiento e inicialización del qubit auxiliar como se hizo en el segundo paso.

Luego, en el tercer paso, tenemos que realizar la corrección de fase 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}\), por lo que tenemos que aplicar 2 correcciones de fase condicionadas, una condicionada por \(\varphi_3\) (\(=c_0\)) y la otra por \(\varphi_2\)(\(=c_1\)). Para ello tenemos que aplicar lo siguiente: - compuerta \(P(-\pi/4)\) condicionada por \(c_0=1\), es decir, por \(c=001\) (c_if con valor \(1\)) - compuerta \(P(-\pi/2)\) condicionada por \(c_1=1\), es decir, la compuerta se aplica cuando \(c=010\) (c_if con valor \(2\)) - compuerta \(P(-3\pi/4)\) condicionada por \(c_1=1\) y \(c_0=1\) es decir, la compuerta se aplica cuando \(c=011\) (c_if con valor \(3\))

A continuación, las operaciones \(CU\): aplicamos \(2^t\) veces la compuerta \(\text{MCP}(\pi/4)\) y dado que en el 3er paso \(t=m-3=0\), aplicamos la compuerta solo una vez.

[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]:
../../_images/tutorials_textbook_01_IQPE_53_0.png

Ahora, ejecutamos el circuito con el simulador sin ruido.

[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()

Hemos obtenido \(100\%\) de probabilidad de encontrar \(\varphi=0.125\), es decir, \(1/8\), como se esperaba.

[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 SoftwareVersion
Qiskit0.24.1
Terra0.17.3
Aer0.7.6
Ignis0.5.2
Aqua0.8.2
IBM Q Provider0.13.1
System information
Python3.9.5 (default, May 18 2021, 12:31:01) [Clang 10.0.0 ]
OSDarwin
CPUs4
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.