Pular para o conteúdo principal

Entradas e saídas do Estimator

Versões dos pacotes

O código desta página foi desenvolvido usando os seguintes requisitos. Recomendamos usar essas versões ou versões mais recentes.

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

Esta página fornece uma visão geral das entradas e saídas da primitiva Estimator do Qiskit Runtime, que executa cargas de trabalho nos recursos de computação IBM Quantum®. O Estimator permite que você defina eficientemente cargas de trabalho vetorizadas usando uma estrutura de dados chamada Bloco Unificado Primitivo (PUB). Eles são usados como entradas para o método run() da primitiva Estimator, que executa a carga de trabalho definida como um job. Então, após o job ser concluído, os resultados são retornados em um formato que depende tanto dos PUBs usados quanto das opções de runtime especificadas pela primitiva.

Entradas

Cada PUB está neste formato:

(<Circuit único>, <um ou mais observáveis>, <valores de parâmetros opcionais>, <precisão opcional>),

Os valores de parâmetros opcionais podem ser uma lista ou um único parâmetro. Os elementos de observáveis e valores de parâmetros são combinados seguindo as regras de broadcasting NumPy conforme descrito no tópico Entradas e saídas de primitivas, e uma estimativa de valor esperado é retornada para cada elemento do formato broadcast.

informação

Se a entrada contiver medições, elas serão ignoradas.

Para a primitiva Estimator, um PUB pode conter no máximo quatro valores:

  • Um único QuantumCircuit, que pode conter um ou mais objetos Parameter
  • Uma lista de um ou mais observáveis, que especificam os valores esperados a serem estimados, organizados em um array (por exemplo, um único observável representado como um array 0-d, uma lista de observáveis como um array 1-d e assim por diante). Os dados podem estar em qualquer um dos formatos ObservablesArrayLike como Pauli, SparsePauliOp, PauliList ou str.
    Observáveis que comutam
    • Os observáveis que comutam no mesmo PUB são agrupados usando este método.
    • Os observáveis que comutam em PUBs diferentes, mesmo que tenham o mesmo Circuit, não são estimados usando a mesma medição. Cada PUB representa uma base diferente para medição e, portanto, são necessárias medições separadas para cada PUB.
    • Para garantir que os observáveis que comutam sejam estimados usando a mesma medição, agrupe-os dentro do mesmo PUB.
  • Uma coleção de valores de parâmetros para vincular o circuito. Isso pode ser especificado como um único objeto semelhante a array onde o último índice é sobre os objetos Parameter do circuito ou omitido (ou equivalentemente, definido como None) se o circuito não tiver objetos Parameter.
  • (Opcionalmente) Uma precisão alvo para estimativas de valores esperados

O código a seguir demonstra um conjunto de exemplo de entradas vetorizadas para a primitiva Estimator e as executa em um Backend IBM® como um ú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()

Saídas

Depois que um ou mais PUBs são enviados a uma QPU para execução e um job é concluído com sucesso, os dados são retornados como um objeto contêiner PrimitiveResult acessado chamando o método RuntimeJobV2.result().

O PrimitiveResult contém uma lista iterável de objetos PubResult que contêm os resultados de execução para cada PUB.

Cada elemento desta lista corresponde a cada PUB enviado ao método run() da primitiva (por exemplo, um job enviado com 20 PUBs retornará um objeto PrimitiveResult que contém uma lista de 20 objetos PubResult, um correspondendo a cada PUB).

Cada PubResult para a primitiva Estimator contém pelo menos um array de valores esperados (PubResult.data.evs) e desvios padrão associados (seja PubResult.data.stds ou PubResult.data.ensemble_standard_error dependendo do resilience_level usado), mas pode conter mais dados dependendo das opções de mitigação de erros que foram especificadas.

Cada objeto PubResult possui tanto um atributo data quanto um atributo metadata.

  • O atributo data é um DataBin personalizado que contém os valores de medição reais, desvios padrão e assim por diante.
  • O DataBin tem vários atributos dependendo do formato ou estrutura do PUB associado, bem como das opções de mitigação de erros especificadas pela primitiva usada para enviar o job (por exemplo, ZNE ou PEC).
  • O atributo metadata contém informações sobre as opções de runtime e mitigação de erros usadas (explicado mais adiante na seção Metadados do resultado desta página).

A seguir está um esquema visual da estrutura de dados PrimitiveResult para a saída do 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
├── ...
├── ...
└── ...

Em termos simples, um único job retorna um objeto PrimitiveResult e contém uma lista de um ou mais objetos PubResult. Esses objetos PubResult então armazenam os dados de medição para cada PUB que foi enviado ao job.

O trecho de código abaixo descreve o formato PrimitiveResult (e PubResult associado) para o job criado acima.

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. ]]

Como a primitiva Estimator calcula o erro

Além da estimativa da média dos observáveis passados nos PUBs de entrada (o campo evs do DataBin), o Estimator também tenta entregar uma estimativa do erro associado a esses valores esperados. Todas as consultas do Estimator preencherão o campo stds com uma quantidade como o erro padrão da média para cada valor esperado, mas algumas opções de mitigação de erros produzem informações adicionais, como ensemble_standard_error.

Considere um único observável O\mathcal{O}. Na ausência de ZNE, você pode pensar em cada shot da execução do Estimator como fornecendo uma estimativa pontual do valor esperado O\langle \mathcal{O} \rangle. Se as estimativas pontuais estiverem em um vetor Os, então o valor retornado em ensemble_standard_error é equivalente ao seguinte (em que σO\sigma_{\mathcal{O}} é o desvio padrão da estimativa do valor esperado e NshotsN_{shots} é o número de shots):

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

que trata todos os shots como parte de um único ensemble. Se você solicitou twirling de gate (twirling.enable_gates = True), você pode ordenar as estimativas pontuais de O\langle \mathcal{O} \rangle em conjuntos que compartilham um twirl comum. Chame esses conjuntos de estimativas de O_twirls, e há num_randomizations (número de twirls) deles. Então stds é o erro padrão da média de O_twirls, como em

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

onde σO\sigma_{\mathcal{O}} é o desvio padrão de O_twirls e NtwirlsN_{twirls} é o número de twirls. Quando você não habilita o twirling, stds e ensemble_standard_error são iguais.

Se você habilitar o ZNE, então os stds descritos acima se tornam pesos em uma regressão não linear para um modelo extrapolador. O que finalmente é retornado em stds neste caso é a incerteza do modelo de ajuste avaliado em um fator de ruído zero. Quando há um ajuste ruim ou grande incerteza no ajuste, os stds relatados podem se tornar muito grandes. Quando o ZNE é habilitado, pub_result.data.evs_noise_factors e pub_result.data.stds_noise_factors também são preenchidos, para que você possa fazer sua própria extrapolação.

Metadados do resultado

Além dos resultados de execução, tanto os objetos PrimitiveResult quanto PubResult contêm um atributo de metadados sobre o job que foi enviado. Os metadados contendo informações para todos os PUBs enviados (como as várias opções de runtime disponíveis) podem ser encontrados em PrimitiveResult.metatada, enquanto os metadados específicos para cada PUB são encontrados em PubResult.metadata.

nota

No campo de metadados, as implementações de primitivas podem retornar qualquer informação sobre a execução que seja relevante para elas, e não há pares chave-valor garantidos pela primitiva base. Assim, os metadados retornados podem ser diferentes em diferentes implementações de primitivas.

# 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,