Spanish
Idiomas
English
Japanese
Spanish

Calcular los valores esperados en un algoritmo

La primitiva Estimator se usa para diseñar un algoritmo que calcula los valores esperados.

Antecedentes

El rol de la primitiva Estimator es doble: actúa como un punto de entrada a los dispositivos cuánticos o simuladores, reemplazando la interfaz Backend (comúnmente conocida como backend.run()). Además, es una abstracción algorítmica para los cálculos del valor esperado, por lo que no tienes que construir manualmente el circuito final de valor esperado. Esto da como resultado una reducción considerable de la complejidad del código y un diseño de algoritmo más compacto.

Nota

Modelo del backend.run(): En este modelo, accediste a backends reales y simuladores remotos utilizando el módulo qiskit-ibmq-provider (ahora migrado a qiskit-ibm-provider). Para ejecutar simulaciones locales, puedes importar un backend específico de qiskit-aer. Todos ellos siguieron la interfaz backend.run().

Code example for qiskit-ibmq-provider & backend.run()
from qiskit import IBMQ

# Select provider
provider = IBMQ.get_provider(hub="ibm-q", group="open", project="main")

# Get backend
backend = provider.get_backend("ibmq_qasm_simulator") # cloud simulator

# Run
result = backend.run(expectation_circuits)

Code example for qiskit-aer & backend.run()
from qiskit_aer import AerSimulator # former import: from qiskit import Aer

# Get local simulator backend
backend = AerSimulator()

# Run
result = backend.run(expectation_circuits)

Modelo de primitivas: Accede a backends reales y simuladores remotos a través de las primitivas de qiskit-ibm-runtime (Sampler y Estimator). Para ejecutar simulaciones locales, puedes importar primitivas local específicas de qiskit_aer.primitives y qiskit.primitives. Todas siguen las interfaces BaseSampler y BaseEstimator, pero solo las primitivas Runtime ofrecen acceso al servicio Runtime, las sesiones y la mitigación de errores integrada.

Code example for Runtime Estimator
from qiskit_ibm_runtime import QiskitRuntimeService, Estimator

# Define service
service = QiskitRuntimeService()

# Get backend
backend = service.backend("ibmq_qasm_simulator") # cloud simulator

# Define Estimator
estimator = Estimator(backend=backend)

# Run Expectation value calculation
result = estimator.run(circuits, observables).result()

Code example for Aer Estimator
from qiskit_aer import Estimator

# Get local simulator Estimator
estimator = Estimator()

# Run expectation value calculation
result = estimator.run(circuits, observables).result()

Si tu código calculaba previamente los valores esperados usando backend.run(), lo más probable es que hayas usado el módulo qiskit.opflow para manejar operadores y funciones de estado. Para admitir este escenario, el siguiente ejemplo de migración muestra cómo reemplazar el flujo de trabajo (qiskit.opflow y backend.run()) con un flujo de trabajo basado en Estimator.

Ejemplo de principio a fin

1. Definición del problema

Queremos calcular el valor esperado de un estado cuántico (circuito) con respecto a un determinado operador. En este ejemplo, estamos usando la molécula de H2 y un circuito arbitrario como estado cuántico:

from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp

# Step 1: Define operator
op = SparsePauliOp.from_list(
    [
        ("II", -1.052373245772859),
        ("IZ", 0.39793742484318045),
        ("ZI", -0.39793742484318045),
        ("ZZ", -0.01128010425623538),
        ("XX", 0.18093119978423156),
    ]
)

# Step 2: Define quantum state
state = QuantumCircuit(2)
state.x(0)
state.x(1)

1.a. [Anterior] Convertir el problema a opflow

qiskit.opflow proporcionaba sus propias clases para representar tanto a los operadores como a los estados cuánticos, por lo que el problema definido anteriormente se encapsularía como:

from qiskit.opflow import CircuitStateFn, PauliSumOp

opflow_op = PauliSumOp(op)
opflow_state = CircuitStateFn(state)

Este paso ya no es necesario cuando se utilizan las primitivas.

Nota

Para obtener instrucciones sobre cómo migrar desde qiskit.opflow, consulta la guía de migración de opflow.

2. Calcular los valores esperados en un dispositivo real o simulador en la nube

2.a. [Anterior] Usar opflow y backend.run()

El flujo de trabajo anterior requería muchos pasos para calcular un valor esperado:

Nota

Reemplaza ibmq_qasm_simulator con el nombre de tu dispositivo para ver el flujo de trabajo completo para un dispositivo real.

from qiskit.opflow import StateFn, PauliExpectation, CircuitSampler
from qiskit import IBMQ

# Define the state to sample
measurable_expression = StateFn(opflow_op, is_measurement=True).compose(opflow_state)

# Convert to expectation value calculation object
expectation = PauliExpectation().convert(measurable_expression)

# Define provider and backend
provider = IBMQ.get_provider(hub="ibm-q", group="open", project="main")
backend = provider.get_backend("ibmq_qasm_simulator")

# Inject backend into circuit sampler
sampler = CircuitSampler(backend).convert(expectation)

# Evaluate
expectation_value = sampler.eval().real
>>> print("expectation: ", expectation_value)
expectation:  -1.065734058826613

2.b. [Nuevo] Usar la primitiva Estimator de Runtime

El Estimator simplifica la sintaxis del lado del usuario, convirtiéndolo en una herramienta más conveniente para el diseño de algoritmos.

Nota

Reemplaza ibmq_qasm_simulator con el nombre de tu dispositivo para ver el flujo de trabajo completo para un dispositivo real.

from qiskit_ibm_runtime import QiskitRuntimeService, Estimator

service = QiskitRuntimeService(channel="ibm_quantum")
backend = service.backend("ibmq_qasm_simulator")

estimator = Estimator(backend=backend)

expectation_value = estimator.run(state, op).result().values

Ten en cuenta que el Estimator devuelve una lista de valores, ya que puede realizar evaluaciones por lotes.

>>> print("expectation: ", expectation_value)
expectation:  [-1.06329149]

La primitiva Estimator de Runtime ofrece una serie de características y opciones de ajuste que no tienen una alternativa en el modo anterior a ser migrada, pero pueden ayudar a mejorar tu rendimiento y resultados. Para obtener más información, consulta lo siguiente:

3. Otras alternativas de ejecución (no Runtime)

Esta sección describe cómo usar primitivas que no son de Runtime para probar un algoritmo usando simulación local. Supongamos que queremos resolver el problema definido anteriormente con una simulación de vector de estado local.

3.a. [Anterior] Usar el simulador Qiskit Aer

from qiskit.opflow import StateFn, PauliExpectation, CircuitSampler
from qiskit_aer import AerSimulator

# Define the state to sample
measurable_expression = StateFn(opflow_op, is_measurement=True).compose(opflow_state)

# Convert to expectation value calculation object
expectation = PauliExpectation().convert(measurable_expression)

# Define statevector simulator
simulator = AerSimulator(method="statevector", shots=100)

# Inject backend into circuit sampler
circuit_sampler = CircuitSampler(simulator).convert(expectation)

# Evaluate
expectation_value = circuit_sampler.eval().real
>>> print("expectation: ", expectation_value)
expectation:  -1.0636533500290943

3.b. [Nuevo] Usar la primitiva Estimator de referencia o el Estimator de Aer

El Estimator de referencia te permite realizar una simulación exacta o ruidosa basada en iteraciones de la clase Statevector en el módulo qiskit.quantum_info.

from qiskit.primitives import Estimator

estimator = Estimator()

expectation_value = estimator.run(state, op).result().values

# for shot-based simulation:
expectation_value = estimator.run(state, op, shots=100).result().values
>>> print("expectation: ", expectation_value)
expectation:  [-1.03134297]

Todavía puedes acceder al Simulador Aer a través de su Estimator dedicado. Esto puede ser útil para realizar simulaciones con modelos de ruido. En este ejemplo, el método de simulación se ha actualizado para que coincida con el resultado de 3.a.

from qiskit_aer.primitives import Estimator # import change!!!

estimator = Estimator(run_options= {"method": "statevector"})

expectation_value = estimator.run(state, op, shots=100).result().values
>>> print("expectation: ", expectation_value)
expectation:  [-1.06365335]

Para obtener más información sobre el uso de las primitivas Aer, consulta el tutorial de VQE .

Para obtener más información sobre cómo ejecutar simulaciones ruidosas con las primitivas de Runtime, consulta este tema.