Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quantum-kittens
GitHub Repository: quantum-kittens/platypus
Path: blob/main/translations/es/ch-labs/Lab09_QuantumSimulationSearchAlgorithm.ipynb
3855 views
Kernel: Python 3

Laboratorio 9 Simulación Cuántica como un Algoritmo de Búsqueda

Requisitos previos:

Otros materiales relevantes:

  • [Ch 6.2 en QCQI] Michael A. Nielsen and Isaac L. Chuang. Quantum Computation and Quantum Information, p255

from qiskit import * from qiskit.quantum_info import Statevector, partial_trace from qiskit.visualization import plot_state_qsphere, plot_histogram import numpy as np import matplotlib.pyplot as plt import scipy.linalg as la
sim = Aer.get_backend('qasm_simulator')

Parte 1: Simulación Hamiltoniana


Meta

En este laboratorio, consideramos cambios en un estado cuántico visto como un proceso de evolución generado por un Hamiltoniano dado. Para un Hamiltoniano específico, existe un operador unitario correspondiente que determina el estado final para cualquier estado inicial dado.

Para un estado inicial, ψ(0)|\psi(0)\rangle y un Hamiltoniano HH independiente del tiempo, el estado final ψ(t)|\psi(t)\rangle es ψ(t)=eiHtψ(0)|\psi(t)\rangle = e^{-iHt}|\psi(0)\rangle. Por lo tanto, al construir una compuerta apropiada para el operador unitario eiHte^{-iHt}, podemos construir un circuito cuántico que simule la evolución del estado cuántico ψ|\psi\rangle.

1. Construye un circuito cuántico para un Hamiltoniano dado.

Cuando el Hamiltoniano HH y el estado inicial del sistema, ψ(0)|\psi(0)\rangle, están dados por

H=00+++,    ψ(0)=+=12(0+1)H = |0\rangle\langle0| + |+\rangle\langle+|, ~~~~ |\psi(0)\rangle = |+\rangle = \frac{1}{\sqrt 2}(|0\rangle + |1\rangle).

Construye el circuito con dos qubits para evolucionar el estado, ψ(0)|\psi(0)\rangle, por HH durante un tiempo Δt=θ\Delta t = \theta, donde el estado del sistema se codifica en el qubit 0 y el primer qubit es un auxiliar. Luego, el estado final ψ(θ)|\psi(\theta)\rangle es ψ(θ)=eiθ (00 + ++) ψ(0)|\psi(\theta)\rangle = e^{-i\theta ~ ( |0\rangle\langle0| ~ + ~ |+\rangle\langle+| )}~|\psi(0)\rangle.

📓Paso A. Muestra que la compuerta H1 del siguiente circuito realiza la operación eiπ900e^{-i\frac{\pi}{9}|0\rangle\langle0|} en el qubit 0 cuando el estado del sistema es codificado en el qubit 0 y el 1er qubit, auxiliar, se establece en el estado 0|0\rangle.

h1 = QuantumCircuit(2, name = 'H1') h1.cnot(0, 1) h1.p(np.pi/9, 1) h1.cnot(0, 1) H1 = h1.to_gate() h1.draw()
Image in a Jupyter notebook

Tu Solución:

📓Paso B. Construye la compuerta H2 completando el siguiente código para que el circuito `h2` realice la operación eiπ9++e^{-i\frac{\pi}{9}|+\rangle\langle+|} en el qubit 0 cuando el estado del sistema está codificado en el qubit 0 y el 1er qubit, auxiliar, se establece en el estado 0|0\rangle.

h2 = QuantumCircuit(2, name='H2') #### Tu código va aquí ### ############################# H2 = h2.to_gate() h2.draw()

2. Ejecuta la celda a continuación para generar el estado del qubit 0 después de cada iteración.

El circuito realiza (H1H2)7+=( eiπ9 00eiπ9 ++ )7 +(H1H2)^7|+\rangle = (~ e^{-i\frac{\pi}{9} ~ |0\rangle\langle0|}e^{-i\frac{\pi}{9}~|+\rangle\langle+|} ~)^7~|+\rangle en el qubit 0. El estado del qubit 0 después de cada operación H1H2 se almacena en la variable de lista 'myst'.

from qiskit.quantum_info import Statevector, partial_trace def st_out(qc): out = Statevector.from_instruction(qc) out_red = partial_trace(out, [1]) prob, st_all = la.eig(out_red.data) cond = (prob>0.99) & (prob<1.01) st = st_all[:, cond].ravel() return(st) myst = [] circ = QuantumCircuit(2) circ.h(0) st = st_out(circ) myst.append(Statevector(st)) for _ in range(7): circ.append(H1, range(2)) circ.append(H2, range(2)) st = st_out(circ) myst.append(Statevector(st)) circ.draw()

La siguiente imagen de la esfera de Bloch muestra la evolución del estado del qubit 0. Como se muestra, el estado comienza desde el estado +|+\rangle gira hacia y pasa al estado 0|0\rangle. Por lo tanto, con el ángulo apropiado de las operaciones H1 y H2, el estado +|+\rangle evoluciona al estado 0|0\rangle aplicando H1H2=eiθ 00eiθ ++H1H2 = e^{-i\theta ~ |0\rangle\langle0|}e^{-i\theta~|+\rangle\langle+|} el número adecuado de veces.

Dibujo

Si instalaste kaleidoscope o ejecutaste este lab en IQX, puedes ejecutar la celda a continuación para visualizar la evolución del estado a través de la esfera de Bloch interactiva.

from kaleidoscope import bloch_sphere from matplotlib.colors import LinearSegmentedColormap, rgb2hex cm = LinearSegmentedColormap.from_list('graypurple', ["#999999", "#AA00FF"]) vectors_color = [rgb2hex(cm(kk)) for kk in np.linspace(-1,1,len(myst))] bloch_sphere(myst, vectors_color = vectors_color)

Parte 2: Búsqueda Cuántica como una Simulación Cuántica


Meta

En esta parte del laboratorio, resolvemos un problema de búsqueda mediante simulación cuántica.

En la Parte 1, mostramos que el Hamiltoniano, HH, transforma el estado, ψi|\psi_i\rangle, en ψj|\psi_j\rangle cuando su estructura depende de ambos estados como H=ψjψj+ψiψi H =|\psi_j\rangle\langle\psi_j| + |\psi_i\rangle\langle\psi_i| con una duración de tiempo adecuada.

Considerando un problema de búsqueda con solución única, deberíamos poder encontrar la solución con la forma del Hamiltoniano, H=xx+ψψ, H = |x\rangle\langle x| + |\psi\rangle\langle\psi|, cuando todos los elementos posibles se codifican en un estado de superposición ψ|\psi\rangle y se dan como el estado inicial, igual que en el algoritmo de Grover, mientras que x|x\rangle representa la solución desconocida.

Aplicando el operador unitario, U=eiHΔtU = e^{-iH\Delta t} en el estado inicial, ψ|\psi\rangle, el número correcto de veces con Δt\Delta t correctamente elegido, debería evolucionar el estado ψ|\psi\rangle en la solución x|x\rangle o lo suficientemente cerca de ella. El siguiente código construye la compuerta del oráculo para el problema de búsqueda. Ejecuta la celda de abajo.

n = 5 qc = QuantumCircuit(n+1, name='Oracle') qc.mct(list(range(n)), n) Oracle = qc.to_gate()

El siguiente circuito codifica la fase π\pi en el estado de la solución y cero en los otros ítems a través del retroceso de fase con el quinto qubit como auxiliar. Por lo tanto, el estado de salida del circuito es (ψx)+eiπx(|\psi\rangle - |x\rangle) + e^{i\pi}|x\rangle, que se puede confirmar visualmente mediante una gráfica qsphere donde el color indica la fase de cada estado base. Ejecuta las siguientes dos celdas.

test = QuantumCircuit(n+1) test.x(n) test.h(range(n+1)) test.append(Oracle, range(n+1)) test.h(n) test.draw()
Image in a Jupyter notebook
st = Statevector.from_instruction(test) st_red = partial_trace(st, [5]) plot_state_qsphere(st_red)
Image in a Jupyter notebook

1. Construye un circuito para aproximar el Hamiltoniano, H=xx+ψψH = |x\rangle\langle x| + |\psi\rangle\langle\psi|, cuando todos los elementos posibles se codifican en un estado de superposición ψ|\psi\rangle y se dan como el estado inicial, mientras que x|x\rangle representa la única solución desconocida.

Como hicimos en la Parte 1, construimos el circuito para la simulación con el Hamiltoniano, pero con más qubits para examinar todos los elementos de la pregunta. Regradúa el problema de búsqueda con una solución de 32 ítems.

📓Paso A. Construye la compuerta H1 realizando la operación eiΔtψψe^{-i\Delta t|\psi\rangle\langle\psi|} completando el siguiente código.

def H1(delt, n=5): h1 = QuantumCircuit(n+1, name='H1') #### Tu código va aquí ###### ############################### return h1.to_gate()

📓Paso B. Construye la compuerta H2 realizando la operación eiΔtxxe^{-i\Delta t|x\rangle\langle x|} completando el siguiente código.

def H2(delt, n=5): h2 = QuantumCircuit(n+1, name='H2') #### Tu código va aquí ###### ############################### return h2.to_gate()

📓Paso C. Crea el circuito, 'sim_h', para calcular eiπHappψ=( eiπ xxeiπ ψψ )ψe^{-i \pi H_{app}}|\psi\rangle = (~e^{-i\pi~|x\rangle\langle x|}e^{-i\pi~|\psi\rangle\langle\psi|}~)|\psi\rangle que evoluciona el estado ψ|\psi\rangle bajo el Hamiltoniano H=xx+ψψH = |x\rangle\langle x| + |\psi\rangle\langle\psi| aproximadamente durante el tiempo de duración Δt=π\Delta t = \pi.

El estado ψ|\psi\rangle representa el estado de superposición de todos los elementos posibles.

Utiliza las compuertas H1 y H2.

#### Tu código va aquí #### ############ sim_h.draw()

2. Muestra que el problema de búsqueda se puede resolver a través de la simulación cuántica con HapprH_{appr} verificando que las dos operaciones, el algoritmo de Grover y U=eiΔt HapprU = e^{-i\Delta t~H_{appr}} con Δt=π\Delta t = \pi, son equivalentes.

Paso A. El siguiente circuito, `grover`, ejecuta el algoritmo de Grover para que el problema encuentre una solución para el oráculo que construimos arriba. Ejecuta la celda de abajo.

qc = QuantumCircuit(n+1, name='Amp') qc.h(range(n)) qc.x(range(n)) qc.mct(list(range(n)), n) qc.x(range(n)) qc.h(range(n)) Amp = qc.to_gate() grover = QuantumCircuit(n+1) grover.x(n) grover.h(range(n+1)) grover.append(Oracle, range(n+1)) grover.append(Amp, range(n+1)) grover.h(n) grover.x(n) grover.draw()
Image in a Jupyter notebook

Paso B. Al ejecutar las celdas a continuación, el resultado muestra que los circuitos, 'grover' y 'sim_h' son idénticos hasta en una fase global.

st_simh = Statevector.from_instruction(sim_h) st_grover = Statevector.from_instruction(grover) print('grover circuit and sim_h circuit genrate the same output state: ' ,st_simh == st_grover)
plot_state_qsphere(st_simh)
plot_state_qsphere(st_grover)

📓Paso C. Encuentra el número de interacciones de Grover, R, necesarias para encontrar las soluciones del oráculo que construimos.

#### tu código va aquí #### ###### print(R)

Paso D. Encuentra la solución al problema de búsqueda, para el oráculo que construimos, a través del algoritmo de Grover y la simulación calculando eiRπHappψ=( eiπ xxeiπ ψψ )Rψe^{-i R\pi H_{app}}|\psi\rangle = (~e^{-i\pi~|x\rangle\langle x|}e^{-i\pi~|\psi\rangle\langle\psi|}~)^R|\psi\rangle donde R es el número de iteraciones.

## El circuito para resolver el problema de búsqueda mediante el algoritmo de Grover. n = 5 qc_grover = QuantumCircuit(n+1, n) qc_grover.x(n) qc_grover.h(range(n+1)) for _ in range(int(R)): qc_grover.append(Oracle, range(n+1)) qc_grover.append(Amp, range(n+1)) qc_grover.h(n) qc_grover.x(n) qc_grover.barrier() qc_grover.measure(range(n), range(n)) qc_grover.draw()

📓 Completa el código para construir el circuito, qc_sim, para resolver el problema de búsqueda a través de la simulación.

qc_sim = QuantumCircuit(n+1, n) qc_sim.h(range(n)) #### Tu código va aquí ####

Ejecuta la siguiente celda para simular ambos circuitos, qc_grover y qc_sim y compara sus soluciones.

counts = execute([qc_grover, qc_sim], sim).result().get_counts() plot_histogram(counts, legend=['Grover', 'Hamiltonian'])

3. El siguiente resultado muestra un ejemplo donde la solución se puede encontrar con una probabilidad exactamente igual a uno a través de la simulación cuántica eligiendo la duración de tiempo adecuada Δt\Delta t.

n = 5 qc = QuantumCircuit(n+1, n) qc.h(range(n)) delt, R = np.pi/2.1, 6 for _ in range(int(R)): qc.append(H1(delt), range(n+1)) qc.append(H2(delt), range(n+1)) qc.measure(range(n) ,range(n)) qc.draw()
Image in a Jupyter notebook
count = execute(qc, sim).result().get_counts() plot_histogram(count)
Image in a Jupyter notebook