Saltar al contenido principal

Entradas y salidas de Estimator

Versiones de paquetes

El código de esta página fue desarrollado con los siguientes requisitos. Recomendamos usar estas versiones o más recientes.

qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1

Esta página ofrece una descripción general de las entradas y salidas del primitivo Estimator de Qiskit Runtime, que ejecuta cargas de trabajo en recursos de cómputo de IBM Quantum®. Estimator te permite definir eficientemente cargas de trabajo vectorizadas usando una estructura de datos llamada Bloque Unificado Primitivo (PUB). Se usan como entradas al método run() del primitivo Estimator, que ejecuta la carga de trabajo definida como un trabajo. Luego, después de que el trabajo haya completado, los resultados se devuelven en un formato que depende tanto de los PUBs utilizados como de las opciones de runtime especificadas desde el primitivo.

Entradas

Cada PUB está en este formato:

(<circuit único>, <uno o más observables>, <valores de parámetros opcionales>, <precisión opcional>),

Los valores de parámetros opcionales pueden ser una lista o un solo parámetro. Los elementos de los observables y los valores de parámetros se combinan siguiendo las reglas de difusión de NumPy como se describe en el tema Entradas y salidas de primitivos, y se devuelve una estimación del valor de expectación para cada elemento de la forma difundida.

información

Si la entrada contiene mediciones, se ignoran.

Para el primitivo Estimator, un PUB puede contener como máximo cuatro valores:

  • Un único QuantumCircuit, que puede contener uno o más objetos Parameter
  • Una lista de uno o más observables, que especifican los valores de expectación a estimar, organizados en un array (por ejemplo, un solo observable representado como un array 0-d, una lista de observables como un array 1-d, etc.). Los datos pueden estar en cualquiera de los formatos ObservablesArrayLike como Pauli, SparsePauliOp, PauliList o str.
    Observables que conmutan
    • Los observables que conmutan en el mismo PUB se agrupan usando este método.
    • Los observables que conmutan en diferentes PUBs, aunque tengan el mismo circuit, no se estiman usando la misma medición. Cada PUB representa una base diferente para la medición y, por lo tanto, se requieren mediciones separadas para cada PUB.
    • Para asegurarte de que los observables que conmutan se estimen usando la misma medición, agrúpalos dentro del mismo PUB.
  • Una colección de valores de parámetros para vincular al circuit. Esto se puede especificar como un único objeto similar a un array donde el último índice es sobre los objetos Parameter del circuit, u omitido (o equivalentemente, establecido en None) si el circuit no tiene objetos Parameter.
  • (Opcionalmente) Una precisión objetivo para los valores de expectación a estimar

El siguiente código demuestra un conjunto de ejemplo de entradas vectorizadas al primitivo Estimator y las ejecuta en un backend de IBM® como un único objeto RuntimeJobV2.

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit.circuit import (
Parameter,
QuantumCircuit,
)
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.quantum_info import SparsePauliOp

from qiskit_ibm_runtime import (
QiskitRuntimeService,
EstimatorV2 as Estimator,
)

import numpy as np

# Instantiate runtime service and get
# the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Define a circuit with two parameters.
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.ry(Parameter("a"), 0)
circuit.rz(Parameter("b"), 0)
circuit.cx(0, 1)
circuit.h(0)

# Transpile the circuit
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
transpiled_circuit = pm.run(circuit)
layout = transpiled_circuit.layout

# Now define a sweep over parameter values, the last axis of dimension 2 is
# for the two parameters "a" and "b"
params = np.vstack(
[
np.linspace(-np.pi, np.pi, 100),
np.linspace(-4 * np.pi, 4 * np.pi, 100),
]
).T

# Define three observables. The inner length-1 lists cause this array of
# observables to have shape (3, 1), rather than shape (3,) if they were
# omitted.
observables = [
[SparsePauliOp(["XX", "IY"], [0.5, 0.5])],
[SparsePauliOp("XX")],
[SparsePauliOp("IY")],
]
# Apply the same layout as the transpiled circuit.
observables = [
[observable.apply_layout(layout) for observable in observable_set]
for observable_set in observables
]

# Estimate the expectation value for all 300 combinations of observables
# and parameter values, where the pub result will have shape (3, 100).
#
# This shape is due to our array of parameter bindings having shape
# (100, 2), combined with our array of observables having shape (3, 1).
estimator_pub = (transpiled_circuit, observables, params)

# Instantiate the new Estimator object, then run the transpiled circuit
# using the set of parameters and observables.
estimator = Estimator(mode=backend)
job = estimator.run([estimator_pub])
result = job.result()

Salidas

Después de que uno o más PUBs son enviados a una QPU para su ejecución y un trabajo completa exitosamente, los datos se devuelven como un objeto contenedor PrimitiveResult al que se accede llamando al método RuntimeJobV2.result().

El PrimitiveResult contiene una lista iterable de objetos PubResult que contienen los resultados de ejecución para cada PUB.

Cada elemento de esta lista corresponde a cada PUB enviado al método run() del primitivo (por ejemplo, un trabajo enviado con 20 PUBs devolverá un objeto PrimitiveResult que contiene una lista de 20 objetos PubResult, uno correspondiente a cada PUB).

Cada PubResult para el primitivo Estimator contiene al menos un array de valores de expectación (PubResult.data.evs) y desviaciones estándar asociadas (ya sea PubResult.data.stds o PubResult.data.ensemble_standard_error dependiendo del resilience_level utilizado), pero puede contener más datos dependiendo de las opciones de mitigación de errores especificadas.

Cada objeto PubResult posee tanto un atributo data como un atributo metadata.

  • El atributo data es un DataBin personalizado que contiene los valores de medición reales, las desviaciones estándar, etc.
  • El DataBin tiene varios atributos dependiendo de la forma o estructura del PUB asociado, así como de las opciones de mitigación de errores especificadas por el primitivo utilizado para enviar el trabajo (por ejemplo, ZNE o PEC).
  • El atributo metadata contiene información sobre las opciones de runtime y mitigación de errores utilizadas (explicado más adelante en la sección Metadatos del resultado de esta página).

El siguiente es un esquema visual de la estructura de datos de PrimitiveResult para la salida de Estimator:

└── PrimitiveResult
├── PubResult[0]
│ ├── metadata
│ └── data ## In the form of a DataBin object
│ ├── evs
│ │ └── List of estimated expectation values in the shape
| | specified by the first pub
│ └── stds
│ └── List of calculated standard deviations in the
| same shape as above
├── PubResult[1]
| ├── metadata
| └── data ## In the form of a DataBin object
| ├── evs
| │ └── List of estimated expectation values in the shape
| | specified by the second pub
| └── stds
| └── List of calculated standard deviations in the
| same shape as above
├── ...
├── ...
└── ...

En pocas palabras, un solo trabajo devuelve un objeto PrimitiveResult y contiene una lista de uno o más objetos PubResult. Estos objetos PubResult luego almacenan los datos de medición para cada PUB que fue enviado al trabajo.

El siguiente fragmento de código describe el formato PrimitiveResult (y el PubResult asociado) para el trabajo creado anteriormente.

print(
f"The result of the submitted job had {len(result)} "
f"PUBs and has a value:\n {result}\n"
)
print(
"The associated PubResult of this job has the following data bins:\n "
"{result[0].data}\n"
)
print(f"And this DataBin has attributes: {result[0].data.keys()}")
print(
"Recall that this shape is due to our array of parameter binding sets"
"having shape (100, 2), where 2 is the number of parameters in the "
"circuit, combined with our array of observables having shape (3, 1). \n"
)
with np.printoptions(threshold=200):
print(
"The expectation values measured from this PUB are: \n"
"{result[0].data.evs}\n"
)
The result of the submitted job had 1 PUB and has a value:
PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(3, 100), dtype=float64>), stds=np.ndarray(<shape=(3, 100), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(3, 100), dtype=float64>), shape=(3, 100)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})

The associated PubResult of this job has the following data bins:
DataBin(evs=np.ndarray(<shape=(3, 100), dtype=float64>), stds=np.ndarray(<shape=(3, 100), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(3, 100), dtype=float64>), shape=(3, 100))

And this DataBin has attributes: dict_keys(['evs', 'stds', 'ensemble_standard_error'])
Recall that this shape is due to our array of parameter binding sets having shape (100, 2) -- where 2 is the
number of parameters in the circuit -- combined with our array of observables having shape (3, 1).

The expectation values measured from this PUB are:
[[-0.00369065 0.15107692 0.30110431 ... -0.30159536 -0.15431523
0.00576586]
[ 0.00601655 0.04412133 0.1253447 ... -0.12434194 -0.04662823
0.01153171]
[-0.01339784 0.2580325 0.47686391 ... -0.47884878 -0.26200223
0. ]]

Cómo calcula el error el primitivo Estimator

Además de la estimación de la media de los observables pasados en los PUBs de entrada (el campo evs del DataBin), Estimator también intenta proporcionar una estimación del error asociado con esos valores de expectación. Todas las consultas de Estimator poblarán el campo stds con una cantidad parecida al error estándar de la media para cada valor de expectación, pero algunas opciones de mitigación de errores producen información adicional, como ensemble_standard_error.

Considera un solo observable O\mathcal{O}. En ausencia de ZNE, puedes pensar en cada shot de la ejecución de Estimator como proporcionando una estimación puntual del valor de expectación O\langle \mathcal{O} \rangle. Si las estimaciones puntuales están en un vector Os, entonces el valor devuelto en ensemble_standard_error es equivalente al siguiente (en el que σO\sigma_{\mathcal{O}} es la desviación estándar de la estimación del valor de expectación y NshotsN_{shots} es el número de shots):

σONshots,\frac{ \sigma_{\mathcal{O}} }{ \sqrt{N_{shots}} },

que trata todos los shots como parte de un solo conjunto. Si solicitaste twirling de gates (twirling.enable_gates = True), puedes ordenar las estimaciones puntuales de O\langle \mathcal{O} \rangle en conjuntos que comparten un twirl común. Llama a estos conjuntos de estimaciones O_twirls, y hay num_randomizations (número de twirls) de ellos. Entonces stds es el error estándar de la media de O_twirls, como en

σONtwirls,\frac{ \sigma_{\mathcal{O}} }{ \sqrt{N_{twirls}} },

donde σO\sigma_{\mathcal{O}} es la desviación estándar de O_twirls y NtwirlsN_{twirls} es el número de twirls. Cuando no habilitas el twirling, stds y ensemble_standard_error son iguales.

Si habilitas ZNE, entonces los stds descritos anteriormente se convierten en pesos en una regresión no lineal a un modelo extrapolador. Lo que finalmente se devuelve en stds en este caso es la incertidumbre del modelo de ajuste evaluado en un factor de ruido de cero. Cuando hay un mal ajuste, o gran incertidumbre en el ajuste, los stds reportados pueden volverse muy grandes. Cuando se habilita ZNE, pub_result.data.evs_noise_factors y pub_result.data.stds_noise_factors también se populan, para que puedas hacer tu propia extrapolación.

Metadatos del resultado

Además de los resultados de la ejecución, tanto los objetos PrimitiveResult como PubResult contienen un atributo de metadatos sobre el trabajo que se envió. Los metadatos que contienen información para todos los PUBs enviados (como las diversas opciones de runtime disponibles) se pueden encontrar en PrimitiveResult.metadata, mientras que los metadatos específicos de cada PUB se encuentran en PubResult.metadata.

nota

En el campo de metadatos, las implementaciones de primitivos pueden devolver cualquier información sobre la ejecución que sea relevante para ellos, y no hay pares clave-valor garantizados por el primitivo base. Por lo tanto, los metadatos devueltos podrían ser diferentes en diferentes implementaciones de primitivos.

# Print out the results metadata
print("The metadata of the PrimitiveResult is:")
for key, val in result.metadata.items():
print(f"'{key}' : {val},")

print("\nThe metadata of the PubResult result is:")
for key, val in result[0].metadata.items():
print(f"'{key}' : {val},")
The metadata of the PrimitiveResult is:
'dynamical_decoupling' : {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'},
'twirling' : {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'},
'resilience' : {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False},
'version' : 2,

The metadata of the PubResult result is:
'shots' : 4096,
'target_precision' : 0.015625,
'circuit_metadata' : {},
'resilience' : {},
'num_randomizations' : 32,