11. Qubits Múltiples y Entangled States#
Los qubits individuales son interesantes, pero individualmente no ofrecen ninguna ventaja computacional. En este apartado veremos cómo representar varios qubits y cómo pueden interactuar entre sí. Hemos visto cómo podemos representar el estado de un qubit utilizando un vector 2D, ahora veremos cómo podemos representar el estado de múltiples qubits.
11.1. Representando el estado de Multi-Qubit #
Como ya hemos visto en el anterior apartado, el estado de un qubit tiene dos amplitudes representadas por numeros complejos. Si extendemos esta idea a dos qubits, podemos decir que tiene cuatros posibles estados.
00
01
10
11
Y además para describir el estado de dos qubits se requieren cuatro amplitudes indicadas por cuatro números complejos. De acuerdo con esta idea la representación que utilizaremos será la siguiente:
Siendo \(a_{i,j}\) números complejos.
Las probabilidades se calculan de la misma manera que para un qubit
Y también se debe cumplir la condición de normalización:
Cuando tenemos dos qubits separados, podemos describir su estado conjunto mediante el producto de kronecker:
Y siguiendo las mismas reglas, podemos utilizar el producto de kronecker para describir el estado colectivo de cualquier número de qubits. A continuación se muestra un ejemplo con tres qubits:
Si tenemos \(n\) qubits, necesitaremos tener en cuenta un total de \(2^n\) amplitudes complejas. Como vemos, estos vectores crecen exponencialmente con el número de qubits. Esta es la razón por la que los ordenadores cuánticos con un gran número de qubits son tan difíciles de simular. Un portátil moderno puede simular fácilmente un estado cuántico general de unos 20 qubits, pero simular 100 qubits es demasiado difícil incluso para los mayores superordenadores.
A continuación mostramos un circuito con tres qubits, y una serie de pertas lógicas
from qiskit import QuantumCircuit, Aer, assemble
import numpy as np
from qiskit.visualization import plot_histogram, plot_bloch_multivector
qc = QuantumCircuit(3)
# Aplicamos un apuerta H a cada uno de qubits:
for qubit in range(3):
qc.h(qubit)
# Mostramos el circuito
qc.draw(output='mpl', style='iqp')

Cada qubit tiene como salida el estado \(|+\rangle\), ya que \(H|0\rangle\) da como resultado el estado \(|+\rangle\). Por lo tanto el vector de salida será:
Veamos que esto es cierto utilizando código de qiskit.
# Let's see the result
svsim = Aer.get_backend('aer_simulator')
qc.save_statevector()
#qobj = assemble(qc)
#final_state = svsim.run(qobj).result().get_statevector()
final_state = svsim.run(qc).result().get_statevector()
# In Jupyter Notebooks we can display this nicely using Latex.
# If not using Jupyter Notebooks you may need to remove the
# array_to_latex function and use print(final_state) instead.
from qiskit.visualization import array_to_latex
array_to_latex(final_state, prefix="\\text{Statevector} = ")
C:\Users\Francisco\AppData\Local\Temp\ipykernel_2276\1334342041.py:2: DeprecationWarning: The 'qiskit.Aer' entry point is deprecated and will be removed in Qiskit 1.0. You should use 'qiskit_aer.Aer' directly instead.
svsim = Aer.get_backend('aer_simulator')
Obteniendo el resultado esperado.
Podemos también obtener la representación matricial de las tres puertas de Hadamar que se han utilizado, es decir el resultado de la siguiente expresión:
Siendo el producto anterior el denominado producto tensorial o producto de kronecker, cuyo significado ya se ha comentado anteriormente.
qc = QuantumCircuit(3)
# Apply H-gate to each qubit:
for qubit in range(3):
qc.h(qubit)
qc.save_unitary()
#qobj = assemble(qc)
#unitary = svsim.run(qobj).result().get_unitary()
unitary = svsim.run(qc).result().get_unitary()
from qiskit.visualization import array_to_latex
array_to_latex(unitary, prefix="\\text{Circuit = }\n")
11.1.1. Quick Ejercicios: #
Escribir el producto de kronecker de los siguintes qubits:
a) \(|0\rangle|1\rangle\)
b) \(|0\rangle|+\rangle\)
c) \(|+\rangle|1\rangle\)
d) \(|-\rangle|+\rangle\)Escribir el estado de: \(|\psi\rangle = \tfrac{1}{\sqrt{2}}|00\rangle + \tfrac{i}{\sqrt{2}}|01\rangle \) como dos qubits separados.
11.2. Single Qubit Gates on Multi-Qubit Statevectors #
Ya hemos visto que una puerta X,que actúa sobre un sólo qubit ,queda representada por una matriz 2x2 de la siguiente manera:
Y que por consiguiente actúa sobre un estado \(|0\rangle\) de la siguiente manera:
Pero puede que no esté claro cómo actuaría una puerta X sobre un qubit en un vector multiqubit. Afortunadamente, la regla es bastante sencilla; igual que utilizamos el producto kronecker para calcular vectores de estado multiqubit, utilizamos el producto tensor para calcular matrices que actúan sobre estos vectores de estado. Por ejemplo, en el circuito de abajo:
qc = QuantumCircuit(2)
qc.h(0)
qc.x(1)
qc.draw(output='mpl')
D:\programas\Anaconda\Lib\site-packages\qiskit\visualization\circuit\matplotlib.py:266: FutureWarning: The default matplotlib drawer scheme will be changed to "iqp" in a following release. To silence this warning, specify the current default explicitly as style="clifford", or the new default as style="iqp".
self._style, def_font_ratio = load_style(self._style)

podemos representar las operaciones simultáneas (H & X) utilizando su producto de kronecker, de la siguiente manera:
Estas operaciones se harían de la siguiente manera:
Matriz que luego podemos aplicar a nuestro vector de estado (statevector) 4D \(|q_1 q_0\rangle\). Utilizando tanto numéro quizá no veamos con claridad qué resultado se obtiene,por ese motivo a menudo se ve la notación más clara de la siguiente manera:
En lugar de calcular esto a mano,como se ha hecho anteriormente, podemos utilizar el aer_simulator
de Qiskit para que lo calcule por nosotros. El simulador Aer multiplica todas las puertas de nuestro circuito para compilar una única matriz unitaria que ejecuta todo el circuito cuántico:
usim = Aer.get_backend('aer_simulator')
qc.save_unitary()
#qobj = assemble(qc)
#unitary = usim.run(qobj).result().get_unitary()
unitary = usim.run(qc).result().get_unitary()
y obteniendo como resultado el siguiente:
# In Jupyter Notebooks we can display this nicely using Latex.
# If not using Jupyter Notebooks you may need to remove the
# array_to_latex function and use print(unitary) instead.
from qiskit.visualization import array_to_latex
array_to_latex(unitary, prefix="\\text{Circuit = }\n")
Si queremos aplicar una puerta sólo a un qubit a la vez (como en el circuito que mostramos a continuación de este párrafo), lo describimos usando el producto de kronecker con la matriz identidad, y así por ejemplo:
Esta expresión, utilizando qiskit sería de la siguiente manera:
qc = QuantumCircuit(2)
qc.x(1)
qc.draw(output='mpl')

Y la matriz unitaria que obtenemos sería la siguiente:
# Simulate the unitary
usim = Aer.get_backend('aer_simulator')
qc.save_unitary()
#qobj = assemble(qc)
unitary = usim.run(qc).result().get_unitary()
# Display the results:
array_to_latex(unitary, prefix="\\text{Circuit = } ")
Podemos ver que Qiskit ha realizado el producto kronecker:
11.2.1. Quick Ejercicios: #
Calcular la matriz unitaria (\(U\)) obtenida mediante la siguiente secuencia de operaciones de puertas de qubits: \(U = XZH\). Utilizar el aer_simulator de qiskit para comprobar el resultado obtenido de forma manual.
Prueba a cambiar las puertas del circuito anterior. Calcula su producto de Kronecker y comprueba tu respuesta con el simulador Aer.
Nota: Diferentes libros, softwares y sitios web ordenan los qubits de forma diferente a como se ha expuesto aquí y en el sentido con el que trabaja qiskit. Esto significaría que el producto kronecker de un mismo circuito puede parecer muy diferente. Tenlo en cuenta cuando consultes otras fuentes.
11.3. Multi-Qubit Gates #
Ahora que sabemos cómo representar el estado de múltiples qubits, estamos preparados para aprender cómo interactúan los qubits entre sí. Una puerta importante de dos qubits es la puerta CNOT, que a continuación se pasa a explicar.
11.3.1. CNOT-Gate #
Esta puerta es una puerta condicional que ejecuta una puerta-X en el segundo qubit (objetivo o target), si el estado del primer qubit (control) es \(|1\rangle\). La puerta se dibuja en un circuito como el que se muestra a continuación, con q0
como control y q1
como objetivo:
qc = QuantumCircuit(2)
# Apply CNOT
qc.cx(0,1)
# See the circuit:
qc.draw(output='mpl')

Cuando nuestros qubits no están en superposición de \(|0\rangle\) o \(|1\rangle\) (comportándose como bits clásicos), esta puerta es muy sencilla e intuitiva de entender. Podemos utilizar la tabla de verdad clásica siguiente:
Input (t,c) |
Output (t,c) |
---|---|
00 |
00 |
01 |
11 |
10 |
10 |
11 |
01 |
Y actuando sobre nuestro vector estado 4D, tiene una de las dos matrices siguientes:
dependiendo de qué qubit es el control y cuál es el objetivo. Diferentes libros, simuladores y documentos ordenan los qubits de forma diferente. En nuestro caso, la matriz de la izquierda corresponde a la CNOT del circuito anteriormente dibujado. Esta matriz intercambia las amplitudes de \(|01\rangle\) y \(|11\rangle\) en nuestro vector de estado:
Hemos visto cómo actúa sobre estados clásicos, pero veamos ahora cómo actúa sobre un qubit en superposición. Pondremos un qubit en el estado \(|+\rangle\):
qc = QuantumCircuit(2)
# Apply H-gate to the first:
qc.h(0)
qc.draw(output='mpl')

# Let's see the result:
svsim = Aer.get_backend('aer_simulator')
qc.save_statevector()
#qobj = assemble(qc)
final_state = svsim.run(qc).result().get_statevector()
# Print the statevector neatly:
array_to_latex(final_state, prefix="\\text{Statevector = }")
Como es de esperar, esto genera el estado \(|0\rangle \otimes |{+}\rangle = |0{+}\rangle\) (recordar que \(H|0\rangle\) genera el estado \(|+\rangle\)):
Y veamos qué ocurre cuando aplicamos la puerta CNOT, con qiskit:
qc = QuantumCircuit(2)
# Apply H-gate to the first:
qc.h(0)
# Apply a CNOT:
qc.cx(0,1)
qc.draw(output='mpl')

# Let's get the result:
qc.save_statevector()
#qobj = assemble(qc)
result = svsim.run(qc).result()
# Print the statevector neatly:
final_state = result.get_statevector()
array_to_latex(final_state, prefix="\\text{Statevector = }")
Es decir obtenemos el siguiente estado:
Este estado es muy interesante para nosotros, porque está entangled. Esto nos lleva claramente a la siguiente sección.
11.3.2. Entangled States #
Vimos en la sección anterior que podíamos crear el estado siguiente:
Este estado es conocido como Bell state. Podemos ver que este estado tiene un 50% de probabilidad de ser medido en el estado \(|00\rangle\), y un 50% de probabilidad de ser medido en el estado \(|11\rangle\). Lo más interesante es que tiene un 0% de probabilidad de ser medido en los estados \(|01\rangle\) o \(|10\rangle\). Podemos ver esto de forma gráfica en Qiskit:
from qiskit.visualization import plot_distribution
# con plot_histogram da un warning de que está deprecated
plot_distribution(result.get_counts())

Este estado combinado no puede escribirse como dos estados qubit separados, lo que tiene interesantes implicaciones. Aunque nuestros qubits están en superposición, medir uno nos dirá el estado del otro y colapsará su superposición. Por ejemplo, si medimos el qubit superior y obtenemos el estado \(|1\rangle\), el estado colectivo de nuestros qubits cambia así:
Aunque separemos estos qubits a años luz de distancia, la medición de uno de ellos colapsa la superposición y parece tener un efecto inmediato sobre el otro. Esta es la ‘espeluznante acción a distancia’ que perturbó a tantos físicos a principios del siglo XX.
Es importante señalar que el resultado de la medición es aleatorio, y que las estadísticas de medición de un qubit no se ven afectadas por ninguna operación en el otro qubit. Debido a esto, no hay ningún modo de utilizar estados cuánticos compartidos para comunicarse. Esto se conoce como el teorema de la no-comunicación.
11.3.3. Visualización de Entangled States#
Hemos visto que este estado no se puede escribir como dos estados qubit separados, esto también significa que perdemos información cuando intentamos graficar nuestro estado en esferas de Bloch separadas:
plot_bloch_multivector(final_state)

Teniendo en cuenta cómo hemos definido la esfera de Bloch en los capítulos anteriores, puede que no esté claro cómo Qiskit incluso calcula los vectores de Bloch con qubits enredados como éste. En el caso de un solo qubit, la posición del vector de Bloch a lo largo de un eje se corresponde perfectamente con el valor de expectativa de la medición en esa base. Si tomamos esto como la regla de trazado de los vectores de Bloch, llegamos a la conclusión anterior. Esto nos muestra que no hay ninguna base de medida de un solo qubit para la que esté garantizada una medida específica. Esto contrasta con nuestros estados de qubit único, en los que siempre podríamos elegir una base de qubit único. Si observamos los qubits individuales de este modo, pasamos por alto el importante efecto de la correlación entre los qubits. No podemos distinguir entre diferentes estados entrelazados. Por ejemplo, los dos estados
tendrán ambas el mismo aspecto en estas esferas de Bloch separadas, a pesar de ser estados muy diferentes con resultados de medición distintos.
¿De qué otra forma podríamos visualizar este vector de estado? Este vector de estado es simplemente una colección de cuatro amplitudes (números complejos), y hay infinitas formas de representarlo en una imagen. Una de ellas es la “Q-sphere”, en la que cada amplitud está representada por una mancha en la superficie de una esfera. El tamaño de la mancha es proporcional a la magnitud de la amplitud, y el color es proporcional a la fase de la amplitud. En el ejemplo que estamos contemplando, las amplitudes para \(|00\rangle\) y \(|11\rangle\) son iguales, y todas las demás amplitudes son 0:
from qiskit.visualization import plot_state_qsphere
plot_state_qsphere(final_state)

Aquí podemos ver claramente la correlación entre los qubits. La forma de la esfera Q no tiene ningún significado, es simplemente una forma agradable de organizar nuestros blobs; el número de 0
s en el estado es proporcional a la posición de los estados en el eje Z, así que aquí podemos ver que la amplitud de \(|00\rangle\) está en el polo superior de la esfera, y la amplitud de \(|11\rangle\) está en el polo inferior de la esfera.
11.3.4. Ejercicios: #
Crear un circuito cuántico que produzca el estado de Bell: \(\tfrac{1}{\sqrt{2}}(|01\rangle + |10\rangle)\). Utiliza el simulador de vectores de estado para verificar tu resultado.
El circuito que has creado en la pregunta 1 transforma el estado \(|00\rangle\) a \(\tfrac{1}{\sqrt{2}}(|01\rangle + |10\rangle)\), calcula la matriz unitaria de este circuito utilizando el simulador de Qiskit. Comprueba que esta matriz unitariz realiza la transformación correcta.
Piensa en otras formas de representar visualmente un vector de estado. ¿Puedes diseñar una visualización interesante en la que puedas leer la magnitud y la fase de cada amplitud?
11.4. Referencias#
[1] Asher Peres, Daniel R. Terno, Quantum Information and Relativity Theory, 2004, https://arxiv.org/abs/quant-ph/0212023
import qiskit.tools.jupyter
%qiskit_version_table
C:\Users\Francisco\AppData\Local\Temp\ipykernel_2276\3369625891.py:1: DeprecationWarning: qiskit.tools.jupyter is deprecated and will be removed in Qiskit 1.0.0
import qiskit.tools.jupyter
Version Information
Software | Version |
---|---|
qiskit | 0.46.0 |
qiskit_aer | 0.13.2 |
System information | |
Python version | 3.11.4 |
Python compiler | MSC v.1916 64 bit (AMD64) |
Python build | main, Jul 5 2023 13:38:37 |
OS | Windows |
CPUs | 4 |
Memory (Gb) | 11.799663543701172 |
Sat Feb 03 21:20:15 2024 Hora estándar romance |