Primeros pasos con las primitivas
La versión beta de un nuevo modelo de ejecución ya está disponible. El modelo de ejecución dirigida ofrece mayor flexibilidad al personalizar tu flujo de trabajo de mitigación de errores. Consulta la guía del Modelo de ejecución dirigida para más información.
Si bien esta documentación utiliza las primitivas de Qiskit Runtime, que te permiten usar backends de IBM®, las primitivas también pueden ejecutarse con cualquier proveedor usando las primitivas de backend. Además, puedes usar las primitivas de referencia para ejecutar en un simulador de vector de estado local. Consulta Simulación exacta con las primitivas de Qiskit para más detalles.
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
Los pasos de este tema describen cómo configurar las primitivas, explorar las opciones disponibles para configurarlas e invocarlas en un programa.
Para usar los fractional gates recién incorporados, establece use_fractional_gates=True al solicitar un backend a una instancia de QiskitRuntimeService. Por ejemplo:
service = QiskitRuntimeService()
fractional_gate_backend = service.least_busy(use_fractional_gates=True)
Ten en cuenta que esta es una función experimental y podría cambiar en el futuro.
Versiones de paquetes
El código de esta página fue desarrollado con los siguientes requisitos. Recomendamos usar estas versiones o versiones más recientes.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
Primeros pasos con Estimator
1. Inicializa la cuenta
Dado que Qiskit Runtime Estimator es un servicio administrado, primero debes inicializar tu cuenta. Luego puedes seleccionar la QPU que quieres usar para calcular el valor esperado.
Sigue los pasos del tema de instalación y configuración si aún no tienes una cuenta.
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. Crea un Circuit y un observable
Necesitas al menos un Circuit y un observable como entradas para la 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...', ...]
El Circuit y el observable deben transformarse para usar únicamente instrucciones compatibles con la QPU (denominados circuitos de arquitectura de conjunto de instrucciones (ISA)). Usaremos el Transpiler para esto.
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. Inicializa Qiskit Runtime Estimator
Al inicializar el Estimator, usa el parámetro mode para especificar el modo en que quieres ejecutarlo. Los valores posibles son objetos batch, session o backend para los modos de ejecución por lote, sesión y trabajo, respectivamente. Para más información, consulta Introducción a los modos de ejecución de Qiskit Runtime.
from qiskit_ibm_runtime import EstimatorV2 as Estimator
estimator = Estimator(mode=backend)
4. Invoca el Estimator y obtén los resultados
A continuación, invoca el método run() para calcular los valores esperados de los circuitos y observables de entrada. El Circuit, el observable y los conjuntos opcionales de valores de parámetros se ingresan 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}
Primeros pasos con Sampler
1. Inicializa la cuenta
Dado que Qiskit Runtime Sampler es un servicio administrado, primero debes inicializar tu cuenta. Luego puedes seleccionar la QPU que quieres usar para calcular el valor esperado.
Sigue los pasos del tema de instalación y configuración si aún no tienes una cuenta configurada.
from qiskit_ibm_runtime import QiskitRuntimeService
service = QiskitRuntimeService()
backend = service.least_busy(
operational=True, simulator=False, min_num_qubits=127
)
2. Crea un Circuit
Necesitas al menos un Circuit como entrada para la 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)
Usa el Transpiler para obtener un Circuit 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. Inicializa el Qiskit Runtime Sampler
Al inicializar el Sampler, usa el parámetro mode para especificar el modo en que quieres ejecutarlo. Los valores posibles son objetos batch, session o backend para los modos de ejecución por lote, sesión y trabajo, respectivamente. Para más información, consulta Introducción a los modos de ejecución de Qiskit Runtime. Ten en cuenta que los usuarios del Plan Abierto no pueden enviar trabajos de sesión.
from qiskit_ibm_runtime import SamplerV2 as Sampler
sampler = Sampler(mode=backend)
4. Invoca el Sampler y obtén los resultados
A continuación, invoca el método run() para generar la salida. El Circuit y los conjuntos opcionales de valores de parámetros se ingresan 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']
Primeros pasos con las primitivas de backend
A diferencia de las primitivas específicas de cada proveedor, las primitivas de backend son implementaciones genéricas que pueden usarse con cualquier objeto backend, siempre que implemente la interfaz Backend.
- La primitiva Sampler puede ejecutarse con cualquier proveedor usando
qiskit.primitives.BackendSamplerV2. - La primitiva Estimator puede ejecutarse con cualquier proveedor usando
qiskit.primitives.BackendEstimatorV2.
Algunos proveedores implementan primitivas de forma nativa. Consulta la página del Ecosistema Qiskit para más detalles.
Ejemplo: BackendEstimator
from qiskit.primitives import BackendEstimatorV2
from <some_qiskit_provider> import QiskitProvider
provider = QiskitProvider()
backend = provider.get_backend('backend_name')
estimator = BackendEstimatorV2(backend)
Ejemplo: BackendSampler
from qiskit.primitives import BackendSamplerV2
from <some_qiskit_provider> import QiskitProvider
provider = QiskitProvider()
backend = provider.get_backend('backend_name')
sampler = BackendSamplerV2(backend)
Similitudes y diferencias entre las primitivas de backend y de Runtime
-
Las entradas y salidas de
qiskit.primitives.BackendSamplerV2yqiskit.primitives.BackendEstimatorV2siguen el mismo formato PUB que las primitivas en Qiskit Runtime. Consulta Entradas y salidas de las primitivas para más detalles. Sin embargo, puede haber diferencias en los campos de los metadatos devueltos. -
La clase
qiskit.primitives.BackendEstimatorV2no ofrece implementaciones de mitigación de errores de medición ni de Gate de forma predeterminada, ya que las primitivas de backend están diseñadas para ejecutarse localmente en la máquina del usuario. -
La clase
qiskit.primitives.BackendSamplerV2requiere un backend que admita la opciónmemory. -
Las interfaces de las primitivas de backend exponen opciones personalizadas de
SamplerV2yEstimatorV2que son distintas de las implementaciones de Runtime.
Próximos pasos
- Aprende a probar localmente antes de ejecutar en computadoras cuánticas.
- Revisa ejemplos detallados de primitivas.
- Practica con las primitivas siguiendo la lección sobre funciones de costo en IBM Quantum Learning.
- Aprende a transpilar localmente en la sección Transpile.
- Prueba la guía Comparar configuraciones del Transpiler.
- Aprende a usar las opciones de las primitivas.
- Consulta la API para las opciones de Sampler y Estimator.
- Lee Migrar a las primitivas V2.