Saltar al contenido principal

Estimator con la API REST

Versiones de los paquetes

El código de esta página se desarrolló utilizando los siguientes requisitos. Recomendamos usar estas versiones o más recientes.

qiskit[all]~=2.3.0

Los pasos de este tema describen cómo ejecutar y configurar cargas de trabajo con la API REST, y muestran cómo invocarlas desde cualquier programa de tu elección.

nota

Esta documentación utiliza el módulo requests de Python para demostrar la API REST de Qiskit Runtime. Sin embargo, este flujo de trabajo puede ejecutarse con cualquier lenguaje o framework que soporte el trabajo con APIs REST. Consulta la documentación de referencia de la API para más detalles.

1. Inicializar la cuenta

Como Qiskit Runtime Estimator es un servicio gestionado, primero necesitas inicializar tu cuenta. Luego puedes seleccionar el dispositivo que quieres usar para calcular el valor esperado.

Encuentra los detalles sobre cómo inicializar tu cuenta, ver los backends disponibles e invalidar tokens en este tema.

2. Crear un circuito QASM

Necesitas al menos un circuito como entrada al primitivo Estimator.

Define un circuito cuántico QASM. Por ejemplo:

qasm_string='''
OPENQASM 3;
include "stdgates.inc";
qreg q[2];
creg c[2];
x q[0];
cx q[0], q[1];
c[0] = measure q[0];
c[1] = measure q[1];
'''

Los siguientes fragmentos de código asumen que qasm_string ha sido transpilado a una nueva cadena resulting_qasm.

3. Ejecutar el circuito cuántico con la API Estimator V2

nota

Los siguientes jobs usan primitivos Qiskit Runtime V2. Tanto SamplerV2 como EstimatorV2 toman uno o más bloques unificados de primitivos (PUBs) como entrada. Cada PUB es una tupla que contiene un circuito y los datos transmitidos a ese circuito, que pueden ser múltiples observables y parámetros. Cada PUB devuelve un resultado.

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}

job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each.
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
}}

response = requests.post(url, headers=headers, json=job_input)

if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")

4. Verificar el estado del job y obtener resultados

A continuación, pasa el job_id a la API:

response_status_singlejob= requests.get(url+'/'+job_id, headers=headers)
response_status_singlejob.json().get('state')

Salida

>>> Job ID: 58223448-5100-4dec-a47a-942fb30edcad
>>> Job Status: JobStatus.RUNNING

Obtener los resultados del job:

response_result= requests.get(url+'/'+job_id+'/results', headers=headers)

res_dict=response_result.json()

estimator_result=res_dict['results']
print(estimator_result)

Salida

[{'data': {'evs': 0.7428980350102542, 'stds': 0.029884014518789213, 'ensemble_standard_error': 0.03261147170624149}, 'metadata': {'shots': 10016, 'target_precision': 0.01, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32}}]

5. Trabajar con opciones de Runtime

Las técnicas de mitigación de errores permiten a los usuarios mitigar errores del circuito modelando el ruido del dispositivo en el momento de la ejecución. Esto generalmente conlleva una sobrecarga de preprocesamiento cuántico relacionada con el entrenamiento del modelo, y una sobrecarga de posprocesamiento clásico para mitigar los errores en los resultados brutos usando el modelo generado.

Las técnicas de mitigación de errores integradas en los primitivos son opciones avanzadas de resiliencia. Para especificar estas opciones, usa la opción resilience_level al enviar tu job.

Los siguientes ejemplos demuestran las opciones predeterminadas para desacoplamiento dinámico, twirling y TREX + ZNE. Encuentra más opciones y detalles adicionales en el tema Técnicas de mitigación y supresión de errores.

TREX + ZNE

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "BACKEND_NAME"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
"options": {
"resilience": {
"measure_mitigation": True,
"zne_mitigation": True,
"zne": {
"extrapolator":["exponential", "linear"],
"noise_factors":[1, 3, 5],
},
},
},
}
}

response = requests.post(url, headers=headers, json=job_input)

if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")

Desacoplamiento dinámico

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "BACKEND_NAME"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
"options": {
"dynamical_decoupling": {
"enable": True,
"sequence_type": 'XpXm',
"extra_slack_distribution": 'middle',
"scheduling_method": 'alap',
},
},
}
}

response = requests.post(url, headers=headers, json=job_input)

if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")

Twirling

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "BACKEND_NAME"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}
job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
"pubs": [ #primitive unified blocs (PUBs) containing one circuit each
[resulting_qasm, # QASM circuit
{"IIZII": 1, "XIZZZ": 2.3}, # Observable
None # parameter values
]]
"options": {
"twirling": {
"enable_gates": True,
"enable_measure": True,
"num_randomizations": "auto",
"shots_per_randomization": "auto",
"strategy": "active-accum",
},
},
}
}

response = requests.post(url, headers=headers, json=job_input)

if response.status_code == 200:
job_id = response.json().get('id')
print("Job created:",response.text)
else:
print(f"Error: {response.status_code}")

Circuitos parametrizados

1. Inicializar la cuenta

Como Qiskit Runtime es un servicio gestionado, primero necesitas inicializar tu cuenta. Luego puedes seleccionar el dispositivo que quieres usar para ejecutar tus cálculos.

Encuentra los detalles sobre cómo inicializar tu cuenta, ver los backends disponibles e invalidar tokens en este tema.

2. Definir parámetros

import requests
import qiskit_ibm_runtime
from qiskit_ibm_runtime import QiskitRuntimeService
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.qasm3 import dumps
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
from qiskit import transpile

service = QiskitRuntimeService(channel='ibm_quantum')
backend = service.backend("<SPECIFY BACKEND>")

pm = generate_preset_pass_manager(backend=backend, optimization_level=1)

theta = Parameter('theta')
phi = Parameter('phi')
parameter_values = {'theta': 1.57, 'phi': 3.14} # In case we want to pass a dictionary

3. Crear un circuito cuántico y agregar gates parametrizadas

qc = QuantumCircuit(2)

# Add parameterized gates
qc.rx(theta, 0)
qc.ry(phi, 1)
qc.cx(0, 1)
qc.measure_all()

# Draw the original circuit
qc.draw('mpl')

# Get an ISA circuit
isa_circuit = pm.run(qc)

4. Generar código QASM 3

qasm_str = dumps(isa_circuit)
print("Generated QASM 3 code:")
print(qasm_str)

5. Ejecutar el circuito cuántico con la API Estimator V2

import requests

url = 'https://quantum.cloud.ibm.com/api/v1/jobs'
auth_id = "Bearer <YOUR_BEARER_TOKEN>"
crn = "<SERVICE-CRN>"
backend = "<BACKEND_NAME>"

headers = {
'Content-Type': 'application/json',
'Authorization':auth_id,
'Service-CRN': crn
}

job_input = {
'program_id': 'estimator',
"backend": backend,
"params": {
# Choose one option: direct parameter transfer or through a dictionary
#"pubs": [[qasm_str,[1,2],500]], # primitive unified blocs (PUBs) containing one circuit each.
"pubs": [[qasm_str,parameter_values,500]], # primitive unified blocs (PUBs) containing one circuit each.
}}

response = requests.post(url, headers=headers, json=job_input)

if response.status_code == 200:
job_id = response.json().get('id')
print(f"Job created: {response.text}")
else:
print(f"Error: {response.status_code}")
print(response.text)

6. Verificar el estado del job y obtener resultados

A continuación, pasa el job_id a la API:

response_status_singlejob = requests.get(f"{url}/{job_id}", headers=headers)
response_status_singlejob.json().get('state')

Salida

{'status': 'Completed'}

Obtener los resultados del job:

response_result = requests.get(f"{url}/{job_id}/results", headers=headers)

res_dict=response_result.json()

# Get results for the first PUB
counts=res_dict['results'][0]['data']['c']['samples']

print(counts[:20])

Salida

['0x1', '0x2', '0x1', '0x2', '0x1', '0x2', '0x0', '0x2', '0x1', '0x1', '0x2', '0x2', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1', '0x1']

Próximos pasos

Recomendaciones
  • Hay varias formas de ejecutar cargas de trabajo según tus necesidades: modo de trabajo, modo de sesión y modo de lote. Aprende a trabajar con el modo de sesión y el modo de lote en el tema sobre modos de ejecución. Ten en cuenta que los usuarios del Plan Abierto no pueden enviar jobs de sesión.
  • Aprende a inicializar tu cuenta con la API REST.
  • Practica con primitivos trabajando en la lección de funciones de costo en IBM Quantum® Learning.
  • Aprende a transpilar localmente en la sección Transpile.