Entrées et sorties Estimator
Versions des packages
Le code sur cette page a été développé en utilisant les exigences suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.
qiskit[all]~=2.4.0
qiskit-ibm-runtime~=0.46.1
Cette page donne un aperçu des entrées et des sorties de la primitive Qiskit Runtime Estimator, qui exécute des charges de travail sur les ressources de calcul IBM Quantum®. Estimator te permet de définir efficacement des charges de travail vectorisées en utilisant une structure de données appelée un Bloc Unifié de Primitive (PUB). Ils sont utilisés comme entrées pour la méthode run() pour la primitive Estimator, qui exécute la charge de travail définie comme un job. Ensuite, une fois le job terminé, les résultats sont renvoyés dans un format qui dépend à la fois des PUBs utilisés et des options d'exécution spécifiées par la primitive.
Entrées
Chaque PUB est dans ce format :
(<circuit unique>, <un ou plusieurs observables>, <valeurs de paramètres optionnelles>, <précision optionnelle>),
Les valeurs de paramètres optionnelles peuvent être une liste ou un seul paramètre. Les éléments des observables et des valeurs de paramètres sont combinés en suivant les règles de diffusion NumPy telles que décrites dans le sujet Entrées et sorties des primitives, et une estimation de la valeur d'espérance est renvoyée pour chaque élément de la forme diffusée.
Si l'entrée contient des mesures, elles sont ignorées.
Pour la primitive Estimator, un PUB peut contenir au maximum quatre valeurs :
- Un seul
QuantumCircuit, qui peut contenir un ou plusieurs objetsParameter - Une liste d'un ou plusieurs observables, qui spécifient les valeurs d'espérance à estimer, arrangées dans un tableau (par exemple, un seul observable représenté sous forme de tableau 0-d, une liste d'observables sous forme de tableau 1-d, etc.). Les données peuvent être dans l'un des formats
ObservablesArrayLikecommePauli,SparsePauliOp,PauliListoustr.Observables commutatifs- Les observables commutatifs dans le même PUB sont regroupés ensemble en utilisant cette méthode.
- Les observables commutatifs dans différents PUBs, même s'ils ont le même circuit, ne sont pas estimés en utilisant la même mesure. Chaque PUB représente une base différente pour la mesure, et par conséquent, des mesures séparées sont requises pour chaque PUB.
- Pour s'assurer que les observables commutatifs sont estimés en utilisant la même mesure, regroupe-les dans le même PUB.
- Une collection de valeurs de paramètres à lier au circuit. Cela peut être spécifié comme un seul objet de type tableau où le dernier index est sur les objets
Parameterdu circuit ou omis (ou de manière équivalente, défini àNone) si le circuit n'a pas d'objetsParameter. - (Optionnellement) Une précision cible pour les valeurs d'espérance à estimer
Le code suivant démontre un exemple d'ensemble d'entrées vectorisées pour la primitive Estimator et les exécute sur un Backend IBM® comme un seul objet 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()
Sorties
Après qu'un ou plusieurs PUBs sont envoyés à une QPU pour exécution et qu'un job se termine avec succès, les données sont renvoyées sous forme d'objet conteneur PrimitiveResult accessible en appelant la méthode RuntimeJobV2.result().
Le PrimitiveResult contient une liste itérable d'objets PubResult qui contiennent les résultats d'exécution pour chaque PUB.
Chaque élément de cette liste correspond à chaque PUB soumis à la méthode run() de la primitive (par exemple, un job soumis avec 20 PUBs renverra un objet PrimitiveResult qui contient une liste de 20 objets PubResult, un correspondant à chaque PUB).
Chaque PubResult pour la primitive Estimator contient au moins un tableau de valeurs d'espérance (PubResult.data.evs) et les écarts-types associés (soit PubResult.data.stds soit PubResult.data.ensemble_standard_error selon le resilience_level utilisé), mais peut contenir plus de données selon les options d'atténuation d'erreurs qui ont été spécifiées.
Chaque objet PubResult possède à la fois un attribut data et un attribut metadata.
- L'attribut
dataest unDataBinpersonnalisé qui contient les valeurs de mesure réelles, les écarts-types, etc. - Le
DataBina divers attributs selon la forme ou la structure du PUB associé ainsi que les options d'atténuation d'erreurs spécifiées par la primitive utilisée pour soumettre le job (par exemple, ZNE ou PEC). - L'attribut
metadatacontient des informations sur les options d'exécution et d'atténuation d'erreurs utilisées (expliquées plus loin dans la section Métadonnées des résultats de cette page).
Ce qui suit est un aperçu visuel de la structure de données PrimitiveResult pour la sortie 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 termes simples, un seul job renvoie un objet PrimitiveResult et contient une liste d'un ou plusieurs objets PubResult. Ces objets PubResult stockent ensuite les données de mesure pour chaque PUB qui a été soumis au job.
L'extrait de code ci-dessous décrit le format PrimitiveResult (et le PubResult associé) pour le job créé ci-dessus.
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. ]]
Comment la primitive Estimator calcule les erreurs
En plus de l'estimation de la moyenne des observables passés dans les PUBs d'entrée (le champ evs du DataBin), Estimator essaie également de fournir une estimation de l'erreur associée à ces valeurs d'espérance. Toutes les requêtes Estimator peuplent le champ stds avec une quantité comme l'erreur standard de la moyenne pour chaque valeur d'espérance, mais certaines options d'atténuation d'erreurs produisent des informations supplémentaires, comme ensemble_standard_error.
Considère un seul observable . En l'absence de ZNE, tu peux penser à chaque shot de l'exécution de l'Estimator comme fournissant une estimation ponctuelle de la valeur d'espérance . Si les estimations ponctuelles sont dans un vecteur Os, alors la valeur renvoyée dans ensemble_standard_error est équivalente à ce qui suit (dans lequel est l'écart-type de l'estimation de la valeur d'espérance et est le nombre de shots) :
ce qui traite tous les shots comme faisant partie d'un seul ensemble. Si tu as demandé la torsion de gate (twirling.enable_gates = True), tu peux trier les estimations ponctuelles de en ensembles qui partagent une torsion commune. Appelle ces ensembles d'estimations O_twirls, et il y en a num_randomizations (nombre de torsions). Alors stds est l'erreur standard de la moyenne de O_twirls, comme dans
où est l'écart-type de O_twirls et est le nombre de torsions. Lorsque tu n'actives pas la torsion, stds et ensemble_standard_error sont égaux.
Si tu actives ZNE, alors les stds décrits ci-dessus deviennent des poids dans une régression non linéaire vers un modèle d'extrapolation. Ce qui est finalement renvoyé dans les stds dans ce cas est l'incertitude du modèle d'ajustement évalué à un facteur de bruit de zéro. Lorsqu'il y a un mauvais ajustement, ou une grande incertitude dans l'ajustement, les stds signalés peuvent devenir très grands. Lorsque ZNE est activé, pub_result.data.evs_noise_factors et pub_result.data.stds_noise_factors sont également peuplés, afin que tu puisses faire ta propre extrapolation.
Métadonnées des résultats
En plus des résultats d'exécution, les objets PrimitiveResult et PubResult contiennent un attribut de métadonnées sur le job qui a été soumis. Les métadonnées contenant des informations pour tous les PUBs soumis (comme les diverses options d'exécution disponibles) peuvent être trouvées dans PrimitiveResult.metatada, tandis que les métadonnées spécifiques à chaque PUB se trouvent dans PubResult.metadata.
Dans le champ de métadonnées, les implémentations de primitives peuvent renvoyer toute information sur l'exécution qui leur est pertinente, et il n'y a pas de paires clé-valeur garanties par la primitive de base. Ainsi, les métadonnées renvoyées pourraient être différentes dans différentes implémentations de primitives.
# 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,