Primeiros passos com primitivas
A versão beta de um novo modelo de execução já está disponível. O modelo de execução dirigida oferece mais flexibilidade para personalizar seu fluxo de trabalho de mitigação de erros. Consulte o guia Modelo de execução dirigida para mais informações.
Embora esta documentação use as primitivas do Qiskit Runtime, que permitem o uso de backends da IBM®, as primitivas podem ser executadas em qualquer provedor usando as primitivas de backend. Além disso, você pode usar as primitivas de referência para executar em um simulador de vetor de estado local. Consulte Simulação exata com as primitivas do Qiskit para mais detalhes.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
As etapas neste tópico descrevem como configurar as primitivas, explorar as opções disponíveis para configurá-las e invocá-las em um programa.
Para usar as fractional gates recentemente suportadas, defina use_fractional_gates=True ao solicitar um backend de uma instância QiskitRuntimeService. Por exemplo:
service = QiskitRuntimeService()
fractional_gate_backend = service.least_busy(use_fractional_gates=True)
Observe que este é um recurso experimental e pode ser alterado no futuro.
Versões dos pacotes
O código desta página foi desenvolvido usando os seguintes requisitos. Recomendamos o uso destas versões ou mais recentes.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Primeiros passos com o Estimator
1. Inicializar a conta
Como o Qiskit Runtime Estimator é um serviço gerenciado, você primeiro precisa inicializar sua conta. Em seguida, pode selecionar o QPU que deseja usar para calcular o valor esperado.
Siga as etapas no tópico Instalar e configurar se você ainda não tiver uma conta.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
print(backend.name)
ibm_torino
2. Criar um circuito e um observável
Você precisa de pelo menos um circuito e um observável como entradas para a primitiva Estimator.
from qiskit.circuit.library import qaoa_ansatz
from qiskit.quantum_info import SparsePauliOp
entanglement = [tuple(edge) for edge in backend.coupling_map.get_edges()]
observable = SparsePauliOp.from_sparse_list(
[("ZZ", [i, j], 0.5) for i, j in entanglement],
num_qubits=backend.num_qubits,
)
circuit = qaoa_ansatz(observable, reps=2)
# the circuit is parametrized, so we will define the parameter values for execution
param_values = [0.1, 0.2, 0.3, 0.4]
print(f">>> Observable: {observable.paulis}")
>>> Observable: ['IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...',
'IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII...', ...]
O circuito e o observável precisam ser transformados para usar apenas instruções suportadas pelo QPU (denominados circuitos de arquitetura de conjunto de instruções (ISA)). Usaremos o Transpiler para isso.
from qiskit.transpiler import generate_preset_pass_manager
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
isa_observable = observable.apply_layout(isa_circuit.layout)
print(f">>> Circuit ops (ISA): {isa_circuit.count_ops()}")
>>> Circuit ops (ISA): OrderedDict([('rz', 3826), ('sx', 1601), ('cz', 968)])
3. Inicializar o Qiskit Runtime Estimator
Ao inicializar o Estimator, use o parâmetro mode para especificar o modo em que ele deve ser executado. Os valores possíveis são objetos batch, session ou backend para os modos de execução em lote, sessão e trabalho, respectivamente. Para mais informações, consulte Introdução aos modos de execução do Qiskit Runtime.
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(mode=backend)
4. Invocar o Estimator e obter resultados
Em seguida, invoque o método run() para calcular os valores esperados para os circuitos e observáveis de entrada. O circuito, o observável e os conjuntos opcionais de valores de parâmetros são fornecidos como tuplas primitive unified bloc (PUB).
job = estimator.run([(isa_circuit, isa_observable, param_values)])
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: d5k96c4jt3vs73ds5smg
>>> Job Status: QUEUED
result = job.result()
print(f">>> {result}")
print(f" > Expectation value: {result[0].data.evs}")
print(f" > Metadata: {result[0].metadata}")
>>> PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(), dtype=float64>), stds=np.ndarray(<shape=(), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(), dtype=float64>)), 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})
> Expectation value: 25.8930784649363
> Metadata: {'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}
Primeiros passos com o Sampler
1. Inicializar a conta
Como o Qiskit Runtime Sampler é um serviço gerenciado, você primeiro precisa inicializar sua conta. Em seguida, pode selecionar o QPU que deseja usar para calcular o valor esperado.
Siga as etapas no tópico Instalar e configurar se você ainda não tiver uma conta configurada.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
2. Criar um circuito
Você precisa de pelo menos um circuito como entrada para a primitiva Sampler.
import numpy as np
from qiskit.circuit.library import efficient_su2
circuit = efficient_su2(127, entanglement="linear")
circuit.measure_all()
# The circuit is parametrized, so we will define the parameter values for execution
param_values = np.random.rand(circuit.num_parameters)
Use o Transpiler para obter um circuito ISA.
from qiskit.transpiler import generate_preset_pass_manager
pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
isa_circuit = pm.run(circuit)
print(f">>> Circuit ops (ISA): {isa_circuit.count_ops()}")
>>> Circuit ops (ISA): OrderedDict([('sx', 3089), ('rz', 3036), ('cz', 1092), ('measure', 127), ('barrier', 1)])
3. Inicializar o Qiskit Runtime Sampler
Ao inicializar o Sampler, use o parâmetro mode para especificar o modo em que ele deve ser executado. Os valores possíveis são objetos batch, session ou backend para os modos de execução em lote, sessão e trabalho, respectivamente. Para mais informações, consulte Introdução aos modos de execução do Qiskit Runtime. Observe que usuários do Plano Open não podem enviar trabalhos em sessão.
from qiskit_ibm_runtime import SamplerV2 as Sampler
sampler = Sampler(mode=backend)
4. Invocar o Sampler e obter resultados
Em seguida, invoque o método run() para gerar a saída. O circuito e os conjuntos opcionais de valores de parâmetros são fornecidos como tuplas primitive unified bloc (PUB).
job = sampler.run([(isa_circuit, param_values)])
print(f">>> Job ID: {job.job_id()}")
print(f">>> Job Status: {job.status()}")
>>> Job ID: d5k96rsjt3vs73ds5tig
>>> Job Status: QUEUED
result = job.result()
# Get results for the first (and only) PUB
pub_result = result[0]
print(
f"First ten results for the 'meas' output register: {pub_result.data.meas.get_bitstrings()[:10]}"
)
First ten results for the 'meas' output register: ['0101001101010000011001110001011000010010001100001000100110011111011110000010110001101000110011101010000100011011000110101111000', '0100111000000100110001100100000101111000111001101000110111101110110010010100001101001111001010011101010000010011000110000010001', '0101111101111111010011010101000000110100000010000010011101100011100011001100000100100001000101000000100001010101010011001101100', '1100110101111111001110010000010100101010101010001000001100100110011111010000000010001000110111010000010101100000100000110111001', '0010000001111001111010100100010111101000101000100000101100001000011100000100011010110110100011100110001001110110111101010011000', '0101110000001000100100010010100100111000010100000000010010000000010110010010000110000001110110010100000111001110100100111101100', '0100011111101001000111110011011101101101110101110001010111011101111110011101001000000001110000011110000101010000001010000100000', '0001010101011000110100000100111111100001011000111110000011000111001101010000010001001100000110000000100000110101010010101110010', '0100011010001110011110000110100101100100101001001111010100100101010100010000000010100000101010110010000000001000010101011111110', '0000011000000111000001000101111111110110101100110000001100010010011101011100001010000100011010001010001101000000000000010001001']
Primeiros passos com as primitivas de backend
Ao contrário das primitivas específicas de provedor, as primitivas de backend são implementações genéricas que podem ser usadas com qualquer objeto
backend, desde que implemente a interface Backend.
- A primitiva Sampler pode ser executada com qualquer provedor usando
qiskit.primitives.BackendSamplerV2. - A primitiva Estimator pode ser executada com qualquer provedor usando
qiskit.primitives.BackendEstimatorV2.
Alguns provedores implementam primitivas de forma nativa. Consulte a página do Ecossistema Qiskit para mais detalhes.
Exemplo: BackendEstimator
from qiskit.primitives import BackendEstimatorV2
from <some_qiskit_provider> import QiskitProvider
provider = QiskitProvider()
backend = provider.get_backend('backend_name')
estimator = BackendEstimatorV2(backend)
Exemplo: BackendSampler
from qiskit.primitives import BackendSamplerV2
from <some_qiskit_provider> import QiskitProvider
provider = QiskitProvider()
backend = provider.get_backend('backend_name')
sampler = BackendSamplerV2(backend)
Semelhanças e diferenças entre as primitivas de backend e as primitivas do Runtime
-
As entradas e saídas de
qiskit.primitives.BackendSamplerV2eqiskit.primitives.BackendEstimatorV2seguem o mesmo formato PUB que as primitivas do Qiskit Runtime. Consulte Entradas e saídas de primitivas para mais detalhes. No entanto, pode haver diferenças nos campos dos metadados retornados. -
A classe
qiskit.primitives.BackendEstimatorV2não oferece implementações de mitigação de erros de medição ou de Gate prontas para uso, pois as primitivas de backend são projetadas para ser executadas localmente na máquina do usuário. -
A classe
qiskit.primitives.BackendSamplerV2requer um backend que suporte a opçãomemory. -
As interfaces de primitivas de backend expõem opções personalizadas de
SamplerV2eEstimatorV2que são diferentes das implementações do Runtime.
Próximos passos
- Aprenda como testar localmente antes de executar em computadores quânticos.
- Revise exemplos detalhados de primitivas.
- Pratique com primitivas trabalhando na lição de função de custo no IBM Quantum Learning.
- Aprenda como transpilar localmente na seção Transpile.
- Experimente o guia Comparar configurações do Transpiler.
- Aprenda como usar as opções de primitivas.
- Veja a API para opções de Sampler e Estimator.
- Leia Migrar para primitivas V2.