Bits cuánticos, puertas y circuitos
Kifumi Numata (19 abr 2024)
Haz clic aquí para descargar el PDF de la clase original. Ten en cuenta que algunos fragmentos de código pueden estar desactualizados, ya que son imágenes estáticas.
Tiempo aproximado de QPU para este experimento: 5 segundos.
1. Introducción
Bits, puertas y circuitos son los componentes fundamentales de la computación cuántica. Aprenderás computación cuántica con el modelo de circuitos utilizando bits cuánticos y puertas, y además repasarás superposición, medición y entrelazamiento.
En esta lección aprenderás:
- Puertas de un solo qubit
- Esfera de Bloch
- Superposición
- Medición
- Puertas de dos qubits y estados entrelazados
Al final de esta clase, aprenderás sobre la profundidad de circuito, que es crucial para la computación cuántica a escala de utilidad.
2. La computación como diagrama
Cuando utilizamos qubits o bits, necesitamos manipularlos para convertir las entradas existentes en las salidas necesarias. Para los programas más sencillos con muy pocos bits, es útil representar este proceso en un diagrama conocido como diagrama de circuito.
La figura de abajo a la izquierda muestra un ejemplo de un circuito clásico, y la figura de abajo a la derecha muestra un ejemplo de un circuito cuántico. En ambos casos, las entradas están a la izquierda y las salidas a la derecha, mientras que las operaciones se representan mediante símbolos. Los símbolos utilizados para las operaciones se denominan "puertas" principalmente por razones históricas.
3. Puerta cuántica de un solo qubit
3.1 Estado cuántico y esfera de Bloch
El estado de un qubit se representa como una superposición de y . Un estado cuántico arbitrario se escribe como
donde y son números complejos tales que .
y son vectores en el espacio vectorial complejo bidimensional:
Por lo tanto, un estado cuántico arbitrario también se representa como
De esto podemos ver que el estado de un bit cuántico es un vector unitario en un espacio de producto interno complejo bidimensional con una base ortonormal de y . Está normalizado a 1.
también se denomina vector de estado (statevector).
Un estado cuántico de un solo qubit también se representa como
donde y son los ángulos de la esfera de Bloch en la siguiente figura.
En las siguientes celdas de código, construiremos cálculos básicos a partir de los componentes en Qiskit. Construiremos un circuito vacío y luego añadiremos operaciones cuánticas, discutiendo las puertas y visualizando sus efectos.
Puedes ejecutar la celda con "Shift" + "Enter". Primero importa las bibliotecas.
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit qiskit-aer qiskit-ibm-runtime
# Import the qiskit library
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.quantum_info import Statevector
from qiskit.visualization import plot_bloch_multivector
from qiskit_ibm_runtime import Sampler
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
from qiskit.visualization import plot_histogram
Preparación del circuito cuántico
Creamos y dibujamos un circuito de un solo qubit.
# Create the single-qubit quantum circuit
qc = QuantumCircuit(1)
# Draw the circuit
qc.draw("mpl")
Puerta X
La puerta X es una rotación de alrededor del eje de la esfera de Bloch. Aplicar la puerta X a produce , y aplicar la puerta X a produce , por lo que es una operación similar a la puerta clásica NOT y también se conoce como inversión de bit. La representación matricial de la puerta X se muestra a continuación.
qc = QuantumCircuit(1) # Prepare the single-qubit quantum circuit
# Apply a X gate to qubit 0
qc.x(0)
# Draw the circuit
qc.draw("mpl")
En IBM Quantum®, el estado inicial está establecido en , por lo que el circuito cuántico anterior en representación matricial es
A continuación, ejecutamos este circuito con un simulador de vector de estado.
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([0.+0.j, 1.+0.j],
dims=(2,))
El vector vertical se muestra como un vector fila, con números complejos (la parte imaginaria se indica con ).
Puerta H
La puerta Hadamard es una rotación de alrededor de un eje a medio camino entre los ejes y en la esfera de Bloch. Aplicar la puerta H a produce un estado de superposición como . La representación matricial de la puerta H se muestra a continuación.
qc = QuantumCircuit(1) # Create the single-qubit quantum circuit
# Apply an Hadamard gate to qubit 0
qc.h(0)
# Draw the circuit
qc.draw(output="mpl")
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([0.70710678+0.j, 0.70710678+0.j],
dims=(2,))
Esto es
Este estado de superposición es tan frecuente e importante que tiene su propio símbolo:
Al aplicar la puerta a , hemos creado una superposición de y , donde una medición en la base computacional (a lo largo de z en la imagen de la esfera de Bloch) produce cada estado con igual probabilidad.
Estado
Quizás hayas adivinado que existe un estado correspondiente:
Para crear este estado, aplica primero una puerta X para obtener , y luego una puerta H.
qc = QuantumCircuit(1) # Create the single-qubit quantum circuit
# Apply a X gate to qubit 0
qc.x(0)
# Apply an Hadamard gate to qubit 0
qc.h(0)
# draw the circuit
qc.draw(output="mpl")
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([ 0.70710678+0.j, -0.70710678+0.j],
dims=(2,))
Esto es
Aplicar la puerta a produce una superposición uniforme de y , pero el signo de es negativo.
3.2 Estado cuántico de un solo qubit y evolución unitaria
Los efectos de todas las puertas que hemos visto hasta ahora han sido unitarios, lo que significa que pueden representarse mediante un operador unitario. En otras palabras, el estado de salida puede obtenerse aplicando una matriz unitaria al estado inicial:
Una matriz unitaria es una matriz que satisface la siguiente condición
En términos del funcionamiento de los computadores cuánticos, diríamos que aplicar una puerta cuántica al qubit hace evolucionar el estado cuántico. Las puertas comunes de un solo qubit incluyen las siguientes.
Puertas de Pauli:
donde el producto externo se calculó de la siguiente manera:
Otras puertas típicas de un solo qubit:
El significado y uso de estas puertas se describe con más detalle en el curso Fundamentos de la información cuántica.
Ejercicio 1
Usa Qiskit para crear circuitos cuánticos que preparen los estados descritos a continuación. Luego ejecuta cada circuito con el simulador de vector de estado y muestra el estado resultante en la esfera de Bloch. Como bonus: intenta predecir cuál debería ser el estado final basándote en la intuición sobre las puertas y rotaciones en la esfera de Bloch.
(1)
(2)
(3)
Consejos: La puerta Z se puede usar de la siguiente manera
qc.z(0)
Solución:
### (1) XX|0> ###
# Create the single-qubit quantum circuit
qc = QuantumCircuit(1) ##your code goes here##
# Add a X gate to qubit 0
qc.x(0) ##your code goes here##
# Add a X gate to qubit 0
qc.x(0) ##your code goes here##
# Draw a circuit
qc.draw(output="mpl")
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([1.+0.j, 0.+0.j],
dims=(2,))
### (2) HH|0> ###
##your code goes here##
qc = QuantumCircuit(1)
qc.h(0)
qc.h(0)
qc.draw("mpl")
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([1.+0.j, 0.+0.j],
dims=(2,))
### (3) HZH|0> ###
##your code goes here##
qc = QuantumCircuit(1)
qc.h(0)
qc.z(0)
qc.h(0)
qc.draw("mpl")
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
# Draw a Bloch sphere
plot_bloch_multivector(out_vector)
Statevector([0.+0.j, 1.+0.j],
dims=(2,))
3.3 Medición
La medición es teóricamente un tema muy complicado. Pero en términos prácticos, una medición a lo largo de (como hacen todos los computadores cuánticos de IBM®) simplemente fuerza el estado del qubit a o y observamos el resultado.
- es la probabilidad de obtener al medir.
- es la probabilidad de obtener al medir.
Por lo tanto, y se denominan amplitudes de probabilidad. (ver "regla de Born")
Por ejemplo, tiene igual probabilidad de convertirse en o al medir. tiene un 75% de probabilidad de convertirse en .
Simulador Qiskit Aer
A continuación, medimos un circuito que prepara la superposición anterior con igual probabilidad. Debemos añadir las puertas de medición, ya que el simulador Qiskit Aer simula por defecto hardware cuántico ideal (sin ruido). Nota: El simulador Aer también puede aplicar un modelo de ruido basado en un computador cuántico real. Volveremos a los modelos de ruido más adelante.
# Create a new circuit with one qubits (first argument) and one classical bits (second argument)
qc = QuantumCircuit(1, 1)
qc.h(0)
qc.measure(0, 0) # Add the measurement gate
qc.draw(output="mpl")
Ahora estamos listos para ejecutar nuestro circuito en el simulador Aer. En este ejemplo usamos la configuración predeterminada shots=1024, lo que significa que medimos 1024 veces. Luego representamos estos conteos en un histograma.
# Run the circuit on a simulator to get the results
# Define backend
backend = AerSimulator()
# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc])
result = job.result()
# Print the results
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'0': 521, '1': 503}
Vemos que los 0s y 1s se midieron cada uno con una probabilidad de casi el 50%. Aunque no se simuló ruido aquí, los estados siguen siendo probabilísticos. Aunque esperamos aproximadamente una distribución 50-50, rara vez la encontraremos exactamente. Al igual que 100 lanzamientos de moneda rara vez darán exactamente 50 instancias de cada lado.
4. Puerta cuántica multi-qubit y entrelazamiento
4.1 Circuito cuántico multi-qubit
Podemos crear un circuito cuántico de dos qubits con el siguiente código. Aplicaremos una puerta H a cada qubit.
# Create the two qubits quantum circuit
qc = QuantumCircuit(2)
# Apply an H gate to qubit 0
qc.h(0)
# Apply an H gate to qubit 1
qc.h(1)
# Draw the circuit
qc.draw(output="mpl")
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
Statevector([0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j],
dims=(2, 2))
Nota: Ordenamiento de bits en Qiskit
Qiskit utiliza la notación Little-Endian al ordenar qubits y bits, lo que significa que el qubit 0 es el bit más a la derecha en las cadenas de bits. Ejemplo: significa que q0 es y q1 es . Ten cuidado, porque parte de la literatura de computación cuántica utiliza la notación Big-Endian (el qubit 0 es el bit más a la izquierda), y gran parte de la literatura de mecánica cuántica también.
Además, cabe señalar que al representar un circuito cuántico, siempre se coloca en la parte superior del circuito. Con este conocimiento, el estado cuántico del circuito anterior puede escribirse como un producto tensorial de estados cuánticos individuales de cada qubit.
( )
El estado inicial de Qiskit es , por lo que cambia a un estado de superposición uniforme al aplicar a cada qubit.
La regla de medición es la misma que en el caso de un solo qubit: la probabilidad de medir es .
# Draw a Bloch sphere
plot_bloch_multivector(out_vector)

A continuación, medimos este circuito.
# Create a new circuit with two qubits (first argument) and two classical bits (second argument)
qc = QuantumCircuit(2, 2)
# Apply the gates
qc.h(0)
qc.h(1)
# Add the measurement gates
qc.measure(0, 0) # Measure qubit 0 and save the result in bit 0
qc.measure(1, 1) # Measure qubit 1 and save the result in bit 1
# Draw the circuit
qc.draw(output="mpl")
Ahora utilizaremos nuevamente el simulador Aer para verificar experimentalmente que las probabilidades relativas de todos los posibles estados de salida son aproximadamente iguales.
# Run the circuit on a simulator to get the results
# Define backend
backend = AerSimulator()
# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
# Run the job
sampler = Sampler(mode=backend)
job = sampler.run([isa_qc])
result = job.result()
# Print the results
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'10': 262, '01': 246, '00': 265, '11': 251}
Como se esperaba, los estados , , , se midieron cada uno con casi el 25%.
4.2 Puertas cuánticas multi-qubit
Puerta CNOT
Una puerta CNOT ("controlled NOT" o CX) es una puerta de dos qubits cuya acción involucra dos qubits simultáneamente: el qubit de control y el qubit objetivo. Una CNOT invierte el qubit objetivo solo cuando el qubit de control es .
| Entrada (Objetivo,Control) | Salida (Objetivo,Control) |
|---|---|
| 00 | 00 |
| 01 | 11 |
| 10 | 10 |
| 11 | 01 |
Primero simulemos el efecto de esta puerta de dos qubits cuando q0 y q1 son ambos , y obtengamos el vector de estado de salida. La sintaxis de Qiskit utilizada es qc.cx(control qubit, target qubit).
# Create a circuit with two quantum registers and two classical registers
qc = QuantumCircuit(2, 2)
# Apply the CNOT (cx) gate to a |00> state.
qc.cx(0, 1) # Here the control is set to q0 and the target is set to q1.
# Draw the circuit
qc.draw(output="mpl")
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
Statevector([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
dims=(2, 2))
Como se esperaba, aplicar una puerta CNOT a no cambió el estado, ya que el qubit de control estaba en el estado . Volvamos a nuestra operación CNOT. Esta vez aplicamos una puerta CNOT a y veamos qué sucede.
qc = QuantumCircuit(2, 2)
# q0=1, q1=0
qc.x(0) # Apply a X gate to initialize q0 to 1
qc.cx(0, 1) # Set the control bit to q0 and the target bit to q1.
# Draw the circuit
qc.draw(output="mpl")
# See the statevector
out_vector = Statevector(qc)
print(out_vector)
Statevector([0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
dims=(2, 2))
Al aplicar una puerta CNOT, el estado se ha convertido en .
Verifiquemos estos resultados ejecutando el circuito en un simulador.
# Add measurements
qc.measure(0, 0)
qc.measure(1, 1)
# Draw the circuit
qc.draw(output="mpl")
# Run the circuit on a simulator to get the results
# Define backend
backend = AerSimulator()
# Transpile to backend
pm = generate_preset_pass_manager(backend=backend, optimization_level=1)
isa_qc = pm.run(qc)
# Run the job
sampler = Sampler(backend)
job = sampler.run([isa_qc])
result = job.result()
# Print the results
counts = result[0].data.c.get_counts()
print(counts)
# Plot the counts in a histogram
plot_histogram(counts)
{'11': 1024}
Los resultados deberían mostrar que se midió con un 100% de probabilidad.
4.3 Entrelazamiento cuántico y ejecución en un dispositivo cuántico real
Comencemos introduciendo un estado entrelazado específico que es particularmente importante en la computación cuántica, y luego definamos el término "entrelazado":
y este estado se denomina estado de Bell.
Un estado entrelazado es un estado , que consiste en los estados cuánticos y , que no puede representarse como un producto tensorial de estados cuánticos individuales.
Si a continuación tiene dos estados y ;
el producto tensorial de estos dos estados es el siguiente