Explorando la incertidumbre
Para este módulo de Qiskit en el aula, los estudiantes deben tener un entorno de Python funcional con los siguientes paquetes instalados:
qiskitv2.1.0 o más recienteqiskit-ibm-runtimev0.40.1 o más recienteqiskit-aerv0.17.0 o más recienteqiskit.visualizationnumpypylatexenc
Para configurar e instalar los paquetes anteriores, consulta la guía Instalar Qiskit. Para ejecutar trabajos en ordenadores cuánticos reales, los estudiantes deberán crear una cuenta en IBM Quantum® siguiendo los pasos de la guía Configura tu cuenta de IBM Cloud.
Este módulo fue probado y utilizó 8 minutos de tiempo de QPU. Esta es solo una estimación; tu uso real puede variar. Dos cálculos que consumen más tiempo están marcados como tales en los comentarios de cabecera y pueden ejecutarse en simuladores si los estudiantes tienen poco tiempo de QPU. Sin ellos, el módulo requiere solo ~30 segundos de tiempo de QPU.
# Added by doQumentation — required packages for this notebook
!pip install -q matplotlib numpy qiskit qiskit-aer qiskit-ibm-runtime
# Uncomment and modify this line as needed to install dependencies
#!pip install 'qiskit>=2.1.0' 'qiskit-ibm-runtime>=0.40.1' 'qiskit-aer>=0.17.0' 'numpy' 'pylatexenc'
Mira el recorrido del módulo por la Dra. Katie McCormick a continuación, o haz clic aquí para verlo en YouTube.
Introducción
Probablemente hayas oído hablar del principio de incertidumbre, incluso fuera de tus clases de física. Una reformulación coloquial habitual de la incertidumbre es "Al observar algo, lo influyes." Eso es cierto, sin duda. Pero una forma más física de describir la incertidumbre es que existen ciertas observables físicas con una incompatibilidad que les impide ser conocidas simultáneamente con precisión arbitraria. Muchos estudiantes encuentran por primera vez el par de variables incompatibles y , es decir, la posición a lo largo de un eje llamado eje y el momento lineal a lo largo de esa dirección, respectivamente. Para esas variables, la restricción sobre la incertidumbre se escribe Aquí, se llama "incertidumbre en ", que tiene la misma definición que la desviación estándar en estadística, y puede definirse como se define de la misma manera. No derivaremos aquí esta relación de incertidumbre; señalaremos que es consistente con nuestra comprensión de las ondas clásicas. Es decir, una onda con verdaderamente una sola frecuencia perfecta y longitud de onda se extendería indefinidamente como un seno perfecto. Cuánticamente, esto correspondería a conocer el momento de manera perfecta según la hipótesis de De Broglie: . Pero para saber está localizada una partícula ondulatoria, la onda que la describe debe volverse más pronunciada en el espacio, como una gaussiana muy estrecha, por ejemplo. Sabemos que podemos expresar cualquier función continua, incluidas tales funciones de onda muy pronunciadas, como una serie de Fourier de funciones sinusoidales con distintas longitudes de onda. Pero a medida que la función de onda se vuelve más pronunciada (y la posición se conoce mejor), necesitaremos más términos en la serie de Fourier, lo que significa una mezcla de más longitudes de onda (y por lo tanto, cuánticamente, más valores de momento).
Dicho de manera más simple: un estado con momento bien definido (un seno perfecto en el espacio) tiene una posición muy incierta. Un estado con posición bien definida (como una distribución delta de Dirac) tiene un momento muy incierto.
Hay otras variables que presentan dicha incompatibilidad. Por ejemplo, la proyección del espín de una partícula puede estar bien definida a lo largo de un eje, pero entonces no sabemos nada sobre la proyección en un eje ortogonal. Por ejemplo, el estado (para un qubit o una partícula de espín-1/2) tiene una proyección definida a lo largo del eje (de 1 en el contexto de un qubit, y de en el contexto de una partícula de espín-1/2). Pero este estado puede escribirse como una superposición de dos estados, cada uno con una proyección bien definida sobre el eje : o de manera equivalente tiene una proyección bien definida sobre , igual que . Así que si especificamos la proyección de un estado sobre el eje , no conocemos la proyección sobre el eje . Y si especificamos la proyección sobre el eje , no conocemos la proyección sobre . Existen diferencias menores al tratar esto en el contexto del espín y en el de los qubits. Pero en general, los autoestados de las matrices de Pauli tienen una relación interesante que podemos explorar. A lo largo de esta lección, verificaremos experimentalmente nuestra intuición sobre la incertidumbre en estas variables incompatibles, y comprobaremos que las relaciones de incertidumbre se cumplen en los ordenadores cuánticos de IBM®.
Comprobación sencilla de la intuición
En este primer experimento y a lo largo del módulo, usaremos un marco de trabajo para la computación cuántica conocido como "patrones de Qiskit", que divide los flujos de trabajo en los siguientes pasos:
- Paso 1: Mapear las entradas clásicas a un problema cuántico
- Paso 2: Optimizar el problema para su ejecución cuántica
- Paso 3: Ejecutar usando las primitivas de Qiskit Runtime
- Paso 4: Posprocesamiento y análisis clásico
En general seguiremos estos pasos, aunque no siempre los etiquetaremos explícitamente.
Empecemos cargando algunos paquetes necesarios, incluidas las primitivas de Runtime. También seleccionaremos el ordenador cuántico menos ocupado disponible.
El código de abajo incluye instrucciones para guardar tus credenciales la primera vez que lo uses. Asegúrate de eliminar esa información del notebook después de guardarla en tu entorno, para que tus credenciales no se compartan accidentalmente al compartir el notebook. Consulta Configura tu cuenta de IBM Cloud e Inicializa el servicio en un entorno no confiable para más orientación.
from numpy import pi
# Load the Qiskit Runtime service
from qiskit_ibm_runtime import QiskitRuntimeService
# Syntax for first saving your token. Delete these lines after saving your credentials.
# QiskitRuntimeService.save_account(channel='ibm_quantum_platform', instance = '<YOUR_IBM_INSTANCE_CRN>', token='<YOUR-API_KEY>', overwrite=True, set_as_default=True)
# service = QiskitRuntimeService(channel='ibm_quantum_platform')
# Load saved credentials
service = QiskitRuntimeService()
# Load the Runtime primitive and session
from qiskit_ibm_runtime import (
Batch,
SamplerV2 as Sampler,
EstimatorV2 as Estimator,
)
# Use the least busy backend
backend = service.least_busy(min_num_qubits=127)
print(backend.name)
ibm_sherbrooke
Si un estudiante agota su tiempo disponible de computación cuántica durante la lección, las líneas siguientes pueden descomentarse y usarse para configurar un simulador que imita parcialmente el comportamiento de ruido del ordenador cuántico seleccionado anteriormente.
# Import an estimator, this time from qiskit (we will import from Runtime for real hardware)
from qiskit_aer.primitives import SamplerV2, EstimatorV2
from qiskit_aer.noise import NoiseModel
# Generate the noise model from the backend properties
noise_model = NoiseModel.from_backend(backend)
noisy_sampler = SamplerV2(options={"backend_options": {"noise_model": noise_model}})
noisy_estimator = EstimatorV2(options={"backend_options": {"noise_model": noise_model}})
Puede que recuerdes que un autoestado de un operador, Z, no es un autoestado de otro operador X. Lo observaremos ahora, experimentalmente, realizando medidas a lo largo de los ejes y . Para la medida a lo largo de , simplemente usamos qc.measure(), porque los ordenadores cuánticos de IBM están diseñados para medir a lo largo de . Pero para medir a lo largo de , debemos rotar el sistema para llevar efectivamente el eje a la orientación sobre la que se mide. Esto se logra con una puerta Hadamard. Se requiere un paso similar para las medidas a lo largo de . Los pasos necesarios se recogen aquí para mayor comodidad:
- Para medir a lo largo de :
qc.measure() - Para medir a lo largo de :
qc.h()y luegoqc.measure() - Para medir a lo largo de :
qc.sdg(),qc.h(),qc.sy luegoqc.measure()
Paso 1: Mapear las entradas clásicas a un problema cuántico
En este caso, el paso de mapeo consiste simplemente en expresar las medidas y rotaciones descritas anteriormente en un circuito cuántico:
# Step 1: Map
# Import some general packages
from qiskit import ClassicalRegister, QuantumCircuit, QuantumRegister
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
# Add a first measurement
qc.measure(qr, cr[0])
qc.barrier()
# Change basis so that measurements made on quantum computer which normally tell us about z, now tell us about x.
qc.h(qr)
# Add a second measurement
qc.measure(qr, cr[1])
qc.draw("mpl")
Paso 2: Optimizar el problema para su ejecución cuántica
Este paso toma las operaciones que queremos realizar y las expresa en términos de la funcionalidad de un ordenador cuántico específico. También mapea nuestro problema al diseño del ordenador cuántico.
# Step 2: Transpile
from qiskit.transpiler.preset_passmanagers import generate_preset_pass_manager
target = backend.target
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
Paso 3: Ejecutar usando las primitivas de Qiskit Runtime
Podemos usar el Sampler para recopilar estadísticas de las medidas. Construiremos la primitiva Sampler para ejecutarse en un ordenador cuántico real usando mode = backend. Existen otros modos para otros flujos de trabajo, y usaremos uno más adelante. El Sampler se invoca llamando a su método run() con una lista de "pubs" (Primitive Unified Blocs). Cada pub contiene hasta tres valores que, juntos, definen una unidad de trabajo que el estimador debe completar: circuitos, observables, parámetros. También puedes proporcionar una lista de circuitos, una lista de observables y una lista de parámetros. Para más información, consulta la Descripción general de los PUBs.
Queremos ejecutarlo en un ordenador cuántico real para llevar a cabo un experimento de física cuántica real. Si agotás tu tiempo asignado en ordenadores cuánticos reales, puedes comentar el código de abajo para el ordenador cuántico y descomentar el código para ejecutar en un simulador.
# Step 3: Run the job on a real quantum computer
sampler = Sampler(mode=backend)
pubs = [qc_isa]
job = sampler.run(pubs)
res = job.result()
counts = res[0].data.c.get_counts()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_sampler.run([qc_isa])
# res=job.result()
# counts=res[0].data.c.get_counts()
Paso 4: Posprocesamiento
Este es un caso especialmente simple de posprocesamiento, en el que simplemente visualizamos los conteos.
Ten en cuenta que Qiskit ordena los qubits, las medidas y otros elementos listando el de número más bajo al final / a la derecha, una convención conocida como "little-endian". Esto significa que la columna etiquetada como "10" a continuación se refiere a los conteos donde la primera medida dio "0" y la segunda medida dio "1".
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Si esta convención no te convence, puedes usar marginal_counts para visualizar los resultados de cada medida por separado:
from qiskit.result import marginal_counts
plot_histogram(
marginal_counts(counts, indices=[0]), title="Counts after first measurement"
)
plot_histogram(
marginal_counts(counts, indices=[1]), title="Counts after second measurement"
)
Por defecto, los estados en Qiskit se inicializan al estado . Así que no sorprende que casi todas las primeras medidas hayan dado . Sin embargo, observa que hubo una división casi equitativa en la segunda medida (la que proporciona información sobre las proyecciones del estado sobre ). Parece que este estado, que nos da un resultado muy predecible de las medidas a lo largo de , nos da un conjunto muy impredecible de resultados para las medidas a lo largo de . Exploremos esto.
¿Qué ocurre si realizamos las medidas en el orden opuesto? Podríamos empezar usando la puerta Hadamard para obtener estadísticas sobre la probabilidad de que se mida en . Luego, para la segunda medida, volveríamos a la base usando una segunda puerta Hadamard.
# Step 1:
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(2, "c")
qc = QuantumCircuit(qr, cr)
# Change basis to measure along x.
qc.h(qr)
qc.measure(qr, cr[0])
qc.barrier()
# Change our basis back to z and make a second measurement
qc.h(qr)
qc.measure(qr, cr[1])
qc.draw("mpl")
# Step 2: Transpile the circuit for running on a quantum computer
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
# Step 3: Run the job on a real quantum computer
sampler = Sampler(mode=backend)
pubs = [qc_isa]
job = sampler.run(pubs)
res = job.result()
counts = res[0].data.c.get_counts()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_sampler.run([qc_isa])
# res=job.result()
# counts=res[0].data.c.get_counts()
# Step 4: Post-process
from qiskit.visualization import plot_histogram
plot_histogram(counts)
Aquí, ¡parece que tenemos aún menos predecibilidad! Antes, al menos sabíamos cuál sería el resultado de la primera medida; ahora tenemos una distribución bastante uniforme entre todos los estados posibles. No es difícil entender por qué ocurrió esto. Empezamos en , que es una mezcla 50-50 de y , según Así que claramente debe haber igual probabilidad de obtener el estado + o - (mapeados a 0 y 1 en el gráfico) en la primera medida. La medida a lo largo de colapsa el estado hacia un autoestado o el autoestado . Cada uno de esos estados es una mezcla 50-50 de y , según Así que una vez que el sistema está en un autoestado de , claramente las medidas a lo largo de darán tanto como , y lo harán con probabilidad aproximadamente igual. Nuestro primer ejemplo nos mostró que algunos estados tendrán resultados muy predecibles para ciertas medidas, pero impredecibles para otras. El ejemplo actual nos muestra que podemos ir más allá. Hay estados que pueden darnos resultados impredecibles para ambas medidas, aunque lo único que hagamos sea invertir el orden de las medidas. Investiguemos qué tan cierta o incierta es una magnitud para un estado dado.
Calculando la incertidumbre
Podemos cuantificar esto usando la incertidumbre, o varianza. La "incertidumbre" se define generalmente como la raíz cuadrada de la "varianza" de una distribución. Es decir, la incertidumbre de un observable se denota y viene dada por
Para el caso de las matrices de Pauli, en las que , esto se convierte en
Apliquemos esto a un ejemplo concreto. Comencemos con el estado y determinemos la incertidumbre del observable en ese estado.
Comprueba tu comprensión
Lee la pregunta a continuación, piensa en tu respuesta y luego haz clic en el triángulo para ver la solución.
Calcula la incertidumbre de en el estado , a mano.
Respuesta:
En el estado dado, esto produce:
Podemos crear un estado inicial arbitrario usando qc.initialize(). Ten en cuenta que la sintaxis para la unidad imaginaria aquí es .
# Step 1: Map the problem into a quantum circuit
from qiskit.quantum_info import SparsePauliOp
import numpy as np
obs = SparsePauliOp("X")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state
qc.initialize([1, 1j] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
estimator = Estimator(mode=backend)
pubs = [(qc_isa, obs_isa)]
job = estimator.run([[qc_isa, obs_isa]])
res = job.result()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc_isa,obs_isa]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print(res[0].data.evs)
-0.02408454165642664
Según nuestra ecuación anterior, Mantengamos ese mismo estado, pero calculemos ahora el valor esperado de :
# Step 1: Map the problem into a quantum circuit
obs = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state to |+>_y
qc.initialize([1, 1j] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs_isa = obs.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
estimator = Estimator(mode=backend)
pubs = [(qc_isa, obs_isa)]
job = estimator.run(pubs)
res = job.result()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc_isa,obs_isa]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print(res[0].data.evs)
0.04958271968581247
Podríamos hacer la misma operación matemática que antes, pero veríamos que la varianza es de nuevo muy cercana a 1.0. Podríamos concluir que . Esto es aproximadamente correcto para el estado que elegimos. ¿Pero podemos hacerlo mejor? ¿O peor?
Recuerda que existe una relación de incertidumbre entre la posición a lo largo de una dirección, y el momento a lo largo de esa misma dirección, Para esas variables, la forma más familiar es probablemente Si esto es todo lo que recordamos, podríamos caer en la tentación de pensar que y también podrían tener un límite fundamental similar en la incertidumbre. ¿Quizás es imposible que el producto llegue a cero? Probemos con otro estado y veamos si esto se cumple. Esta vez usaremos Veamos qué ocurre. Ten en cuenta que en el código siguiente, el estimator puede aceptar dos conjuntos de circuitos y observables en la misma entrega de trabajo.
# Step 1: Map the problem into a quantum circuit
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Initialize the state
qc.initialize([1, 1] / np.sqrt(2))
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, obs1_isa), (qc_isa, obs2_isa)]
job = estimator.run(pubs)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([[qc,obs1],[qc,obs2]])
# res=job.result()
# Step 4: Return the result in classical form, and analyze.
print("The expectation value of the first observable is: ", res[0].data.evs)
print("The expectation value of the second observable is: ", res[1].data.evs)
The expectation value of the first observable is: 1.0011036174126302
The expectation value of the second observable is: 0.0029429797670141016
El valor esperado de debería ser cercano a 1.0, pero no debería superar 1.0. No te preocupes si lo supera por una cantidad muy pequeña. Esto puede atribuirse a factores como el ruido y/o errores de lectura. Aunque este es un tema muy importante, podemos ignorarlo por ahora.
Obtuvimos un valor esperado de muy cercano a 1.0 (correspondiente a una varianza muy baja para ). Esto hace que el producto de las dos varianzas sea bastante bajo:
Aunque esto no es exactamente cero, este valor se está volviendo pequeño en comparación con los valores propios de los operadores de Pauli (). Bien, puede que recuerdes que la relación de incertidumbre entre la posición lineal y el momento puede escribirse de otra forma, usando explícitamente la relación de conmutación entre los operadores y :
donde
es el conmutador de y .
Esta es la forma que más fácilmente puede extenderse a los operadores de Pauli. En general, para dos operadores y ,
Y en el caso de las matrices de Pauli y , necesitamos para calcular
Mostramos esto a continuación y dejamos cálculos similares al lector como ejercicio:
Esta es una respuesta perfectamente válida, pero con un paso más vemos que
Nuestra relación de incertidumbre se convierte entonces en
Comprueba tu comprensión
Lee la pregunta a continuación, piensa en tu respuesta y luego haz clic en el triángulo para ver la solución.
Determina y . Usa esto para escribir las relaciones de incertidumbre entre & , y entre & .
Respuesta:
Combinando con la relación de incertidumbre general, tenemos
Verificar consistencia
Antes de continuar, comprobemos que esto fue consistente con nuestro hallazgo anterior. Usamos el estado Y encontramos que Ahora sabemos que este producto debería ser mayor o igual que
Efectivamente, Usa las preguntas a continuación para desarrollar intuición sobre estos resultados:
Comprueba tu comprensión
Lee las preguntas a continuación, piensa en tus respuestas y luego haz clic en los triángulos para ver las soluciones.
Responde los siguientes puntos en conjunto:
(a) ¿Para qué estados esperarías tener incertidumbre cero en ?
(b) ¿Para qué estados esperarías tener incertidumbre cero en ?
(c) ¿En qué estados obtendrías un valor esperado igual a cero?
(d) ¿Son consistentes las respuestas anteriores con el caso ?
(e) Escribe código para verificar esto explícitamente usando estimator.
Respuestas:
(a) Podríamos esperar que los estados propios del operador produzcan incertidumbre cero en . En efecto, usando tenemos
(b) Podríamos esperar que los estados propios del operador produzcan incertidumbre cero en . En efecto, usando tenemos
(c) Esperamos encontrar para cualquier estado que, al medirse, produzca una proyección positiva sobre el eje con la misma frecuencia que una negativa. Esto incluye los estados propios de y .
(d) Sí. Cabría esperar un valor muy pequeño para el producto de incertidumbres en los estados propios de o : Esto puede cumplirse porque también esperaríamos para esos mismos estados. Así que la relación de incertidumbre podría satisfacerse.
(e) Un código como el siguiente permitiría verificarlo:
obs1 = SparsePauliOp.from_list(
[("X", 1.000)]
)
obs2 = SparsePauliOp.from_list(
[("Y", 1.000)]
)
obs3 = SparsePauliOp.from_list(
[("Z", 1.000)]
)
qc = QuantumCircuit(1,1)
qc.ry(pi/2,0)
job = estimator.run([(qc, [[obs1], [obs2], [obs3]])], precision=0.001)
res=job.result()
Donde el resultado devuelve todos los valores esperados. Para recuperar todos los valores esperados y calcular las incertidumbres, podríamos usar:
xs=res[0].data.evs[0]
ys=abs(res[0].data.evs[1])
zs=res[0].data.evs[2]
import math
prodxz=((1-xs[i]*xs[i])**0.5)*(1-zs[i]*zs[i])**0.5
Responde los siguientes puntos en conjunto:
(a) ¿Puedes pensar en un estado en el que tendrías un valor esperado grande?
(b) ¿Esperarías que ese mismo estado tenga una incertidumbre grande o pequeña en ?
(c) ¿Esperarías que ese mismo estado tenga una incertidumbre grande o pequeña en ?
(d) ¿Son consistentes las respuestas anteriores con el caso ?
(e) Escribe código para verificar esto explícitamente usando estimator.
Respuestas:
(a) Esperamos encontrar para el estado propio de : .
(b) Podríamos esperar que tenga una incertidumbre grande en el estado ya que medir en ese estado produciría un resultado positivo y uno negativo con igual frecuencia/probabilidad.
(c) Podríamos esperar que tenga una incertidumbre grande en el estado ya que medir en ese estado produciría un resultado positivo y uno negativo con igual frecuencia/probabilidad.
(d) Sí. Cabría esperar un valor grande para el producto de incertidumbres en los estados propios de y en particular para . También esperaríamos para ese mismo estado. Por tanto, tanto como son bastante grandes en ese estado, y es plausible que la relación de incertidumbre vuelva a satisfacerse.
(e) Un código como el siguiente permitiría verificarlo:
obs1 = SparsePauliOp.from_list(
[("X", 1.000)]
)
obs2 = SparsePauliOp.from_list(
[("Y", 1.000)]
)
obs3 = SparsePauliOp.from_list(
[("Z", 1.000)]
)
qc = QuantumCircuit(1,1)
qc.rx(-pi/2,0)
job = estimator.run([(qc, [[obs1], [obs2], [obs3]])], precision=0.001)
res=job.result()
Donde el resultado devuelve todos los valores esperados. Para recuperar todos los valores esperados y calcular las incertidumbres, podríamos usar:
xs=res[0].data.evs[0]
ys=abs(res[0].data.evs[1])
zs=res[0].data.evs[2]
import math
prodxz=((1-xs[i]*xs[i])**0.5)*(1-zs[i]*zs[i])**0.5
Probando las relaciones de incertidumbre
La prueba anterior solo demostró la validez de la relación de incertidumbre para una única elección del vector de estado . Para convencernos de que esto es generalmente consistente con el experimento, deberíamos realizar cálculos similares usando el estimador para muchas elecciones del vector de estado. Empecemos rotando nuestro vector de estado alejándolo del eje , usando una compuerta RY para producir distintos estados iniciales mediante un parámetro .
# The calculation below uses approximately 3-4 minutes of QPU time.
# Step 1: Map the problem into a quantum circuit
from qiskit.circuit import Parameter
import numpy as np
# Specify observables
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Y")
obs3 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Rotate away from |0>
theta = Parameter("θ")
qc.ry(theta, 0)
params = np.linspace(0, 2, num=21)
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
obs3_isa = obs3.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, [[obs1_isa], [obs2_isa], [obs3_isa]], [params])]
job = estimator.run(pubs, precision=0.01)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([(qc, [[obs1], [obs2], [obs3]], [params])])
# res=job.result()
# Step 4: Post-processing and classical analysis.
xs = res[0].data.evs[0]
ys = abs(res[0].data.evs[1])
zs = res[0].data.evs[2]
# Calculate uncertainties
delx = []
delz = []
prodxz = []
for i in range(len(xs)):
delx.append(abs((1 - xs[i] * xs[i])) ** 0.5)
delz.append(abs((1 - zs[i] * zs[i])) ** 0.5)
prodxz.append(delx[i] * delz[i])
# Here we can plot the results from this simulation.
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r"$\Delta$ X")
plt.plot(params, ys, label=r"$\langle$ Y $\rangle$")
plt.plot(params, delz, label=r"$\Delta$ Z")
plt.plot(params, prodxz, label=r"$\Delta$X $\Delta$Z")
plt.xlabel(r"$\theta$")
plt.ylabel("Expectation/Uncertainty Values")
plt.legend()
plt.show()
Observa que la curva roja es siempre mayor que la curva naranja A veces el producto de incertidumbre desciende y se acerca bastante al límite, y otras veces sube y se aleja más del límite, pero siempre obedece la relación de incertidumbre.
Por supuesto, esta puede no ser la mejor prueba de la relación de incertidumbre, ya que nuestro límite está siempre muy cercano a cero. Usemos un estado cuántico que tenga una proyección mayor sobre los autoestados de . En concreto, seguiremos rotando hacia abajo desde el eje con ángulos variables, pero ahora también rotaremos ese estado resultante alrededor de un cierto ángulo, quizás , y veremos qué ocurre.
# The calculation below uses approximately 3-4 minutes of QPU time.
from qiskit.circuit import Parameter
import numpy as np
# Step 1: Map the problem to a quantum circuit
# Specify observables
obs1 = SparsePauliOp("X")
obs2 = SparsePauliOp("Y")
obs3 = SparsePauliOp("Z")
# Define registers
qr = QuantumRegister(1, "q")
cr = ClassicalRegister(1, "c")
qc = QuantumCircuit(qr, cr)
# Rotate away from |0> along one plane, and then along a transverse direction.
theta = Parameter("θ")
qc.ry(theta, 0)
qc.rz(pi / 4, 0)
params = np.linspace(0, 2, num=21)
# Step 2: Transpile the circuit
pm = generate_preset_pass_manager(target=target, optimization_level=3)
qc_isa = pm.run(qc)
obs1_isa = obs1.apply_layout(layout=qc_isa.layout)
obs2_isa = obs2.apply_layout(layout=qc_isa.layout)
obs3_isa = obs3.apply_layout(layout=qc_isa.layout)
# Step 3: Run the circuit on a real quantum computer
with Batch(backend=backend) as batch:
estimator = Estimator(mode=batch)
pubs = [(qc_isa, [[obs1_isa], [obs2_isa], [obs3_isa]], [params])]
job = estimator.run(pubs, precision=0.01)
res = job.result()
batch.close()
# Run the job on the Aer simulator with noise model from real backend
# job = noisy_estimator.run([(qc, [[obs1], [obs2], [obs3]], [params])])
# res=job.result()
# Step 4: Post-processing and classical analysis.
xs = res[0].data.evs[0]
ys = abs(res[0].data.evs[1])
zs = res[0].data.evs[2]
# Calculate uncertainties
delx = []
delz = []
prodxz = []
for i in range(len(xs)):
delx.append(abs((1 - xs[i] * xs[i])) ** 0.5)
delz.append(abs((1 - zs[i] * zs[i])) ** 0.5)
prodxz.append(delx[i] * delz[i])
# Here we can plot the results from this simulation.
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r"$\Delta$ X")
plt.plot(params, ys, label=r"$\langle$ Y $\rangle$")
plt.plot(params, delz, label=r"$\Delta$ Z")
plt.plot(params, prodxz, label=r"$\Delta$X $\Delta$Z")
plt.xlabel(r"$\theta$")
plt.ylabel("Expectation/Uncertainty Values")
plt.legend()
plt.show()
¡Ahora vemos que el límite sobre la incertidumbre está siendo puesto a prueba! La curva roja se acerca mucho más a la curva naranja que antes. De hecho, en ausencia de ruido, la relación de incertidumbre quedaría exactamente saturada () en un punto. En presencia de ruido y error de lectura, no debería sorprendernos que una ejecución ocasionalmente arroje un valor de ligeramente mayor que Esto no es una violación real de la incertidumbre; es simplemente un artefacto de un error no nulo.
Comprueba tu comprensión
Lee las preguntas a continuación, piensa en tus respuestas y luego haz clic en los triángulos para ver las soluciones.
¿Cómo llevarías esto al límite absoluto, haciendo lo más grande posible?
Respuesta:
El código actualmente tiene líneas que rotan el estado inicial por defecto hacia abajo desde el eje un ángulo parametrizado y luego también alrededor del eje un ángulo lo que rota el vector de estado parte del camino hacia el eje .
qc.ry(theta,0)
qc.rz(pi/4,0)
Podríamos cambiar la rotación alrededor de de a , rotando completamente hasta un autoestado de :
qc.ry(theta,0)
qc.rz(pi/2,0)
No se requeriría ningún otro cambio.
Modifica el código o cópialo e implementa esa verificación de la relación de incertidumbre con el valor esperado de Y maximizado. ¿Se cumple la relación de incertidumbre?
Respuesta:
Usaríamos exactamente el código del ejemplo anterior, con
qc.rz(pi/2,0)
reemplazando a
qc.rz(pi/4,0).
La figura resultante debería verse como la que aparece a continuación, y sí, el principio de incertidumbre debería seguir siendo válido.

Modifica el código anterior para hacer una imagen similar, demostrando que a partir de mediciones en el computador cuántico el producto se comporta como debería. Elige cualquier conjunto de estados que quieras.
Respuesta:
Usaríamos exactamente el código del ejemplo anterior, y de hecho podríamos usar los mismos resultados de arriba, calculando simplemente distintas incertidumbres a partir de los valores esperados. Por ejemplo, podríamos usar
xs=res[0].data.evs[0]
ys=res[0].data.evs[1]
zs=abs(res[0].data.evs[2])
import math
delx = []
dely = []
prodxy=[]
for i in range(len(xs)):
delx.append((1-xs[i]*xs[i])**0.5)
dely.append((1-ys[i]*ys[i])**0.5)
prodxy.append(((1-xs[i]*xs[i])**0.5)*(1-ys[i]*ys[i])**0.5)
y podríamos graficar
import matplotlib.pyplot as plt
plt.plot(params, delx, label=r'$\Delta$ X')
plt.plot(params, dely, label=r'$\langle$ Y $\rangle$')
plt.plot(params, zs, label=r'$\Delta$ Z')
plt.plot(params, prodxy, label=r'$\Delta$X $\Delta$Z')
plt.xlabel(r'$\theta$')
plt.ylabel('Expectation/Uncertainty Values')
plt.legend()
plt.show()
Desafío: Escribe código para recorrer muchos valores de , tal como recorrimos muchos valores de , y crea un gráfico en 3D que muestre que la relación de incertidumbre nunca se viola. Elige cualquier observable que quieras.
Preguntas
Los instructores pueden solicitar versiones de estos cuadernos con claves de respuestas y orientación sobre su ubicación en currículos comunes completando esta encuesta rápida sobre cómo se están usando los cuadernos.
Conceptos clave:
- Existen relaciones de incertidumbre entre muchos conjuntos de observables físicos, incluyendo la posición y el momento lineal, y las componentes del espín.
- Las matrices de Pauli no conmutan. Esto es un reflejo matemático del hecho de que no todas las componentes del espín pueden conocerse/determinarse simultáneamente.
- La computación cuántica hace un uso intensivo de los operadores/matrices de Pauli, por lo que resulta útil conocer la relación de incertidumbre para los operadores de Pauli, así como los operadores de espín estrechamente relacionados.
- Una fórmula general para la incertidumbre de dos operadores y es
- Un autoestado de algún operador produce incertidumbre cero en el observable físico asociado a ese operador. Incluso experimentalmente,
- Un autoestado de algún operador producirá una mayor incertidumbre para un operador que no conmute con .
- Los resultados experimentales obtenidos con un computador cuántico real confirman la intuición que obtenemos de las representaciones matriciales de los operadores físicos.
Preguntas V/F:
- V/F Se pueden medir e simultáneamente, pero no .
- V/F Se pueden medir y simultáneamente, pero no .
- V/F Los operadores de posición lineal y momento lineal no conmutan.
- V/F Los computadores cuánticos de IBM miden a lo largo de por defecto, por lo que debe realizarse una rotación para medir a lo largo de cualquier otra dirección.
- V/F El circuito de abajo mide efectivamente y luego .
Preguntas de opción múltiple:
-
El diagrama a continuación demuestra cuál de las siguientes relaciones de incertidumbre:
- a.
- b.
- c.
- d. Ninguna de las anteriores

-
¿Cuál de las siguientes es la secuencia estándar para realizar una medición a lo largo de ?
- a. Solo
qc.measure() - b.
qc.h()y luegoqc.measure() - c.
qc.h(),qc.h()y luegoqc.measure() - d.
qc.h(),qc.s,qc.h()y luegoqc.measure() - e.
qc.sdg(),qc.h(),qc.sy luegoqc.measure() - f.
qc.sdg(),qc.h(),qc.s,qc.h()y luegoqc.measure()
- a. Solo
-
¿Cuál de los siguientes estados produce el mayor valor esperado ?
- a.
- b.
- c. también llamado
- d. también llamado
- e. también llamado
- f. también llamado
-
¿Cuál de los siguientes estados produce la mayor incertidumbre ?
- a.
- b. también llamado
- c. también llamado
- d. a y b están empatados
- e. b y c están empatados
- f. a, b y c están empatados
Preguntas de discusión:
-
¿Este concepto de incertidumbre entra en conflicto de alguna manera con la noción del espín como una flecha vectorial en el espacio cartesiano? ¿Y en la esfera de Bloch?
-
Supón que orientas un dispositivo de medición a lo largo de una dirección a medio camino entre los ejes e . ¿Qué ocurre? ¿Puedes hacer una medición a lo largo de esa dirección? ¿Cómo se relaciona esto con la incertidumbre en e ?