Pular para o conteúdo principal

Primeiros passos com primitivas

Novo modelo de execução, agora em versão beta

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.

nota

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.

Usando Fractional Gates

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.

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

Próximos passos

Recomendações