Saltar al contenido principal

Sampler con la API REST

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

nota

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

1. Inicializar la cuenta

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

Encuentra detalles sobre cómo inicializar tu cuenta, ver los backends disponibles y trabajar con tokens en Configurar para usar IBM Quantum Platform con la API REST.

2. Crear un circuit QASM

Necesitas al menos un circuit como entrada para el primitivo Sampler.

Define un circuit cuántico QASM:

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 fragmentos de código que se presentan a continuación asumen que el qasm_string ha sido transpilado a una nueva cadena resulting_qasm.

3. Ejecutar el circuit cuántico usando la API Sampler V2

nota

Los trabajos a continuación usan primitivos V2 de Qiskit Runtime. SamplerV2 toma uno o más bloques unificados primitivos (PUBs) como entrada. Cada PUB es una tupla que contiene un circuit y los datos difundidos a ese circuit, que pueden ser múltiples parámetros, y devuelve un resultado por PUB.

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': 'sampler',
"backend": backend,
"params": {
# primitive unified blocs (PUBs) containing one circuit each:
"pubs": [[resulting_qasm],[resulting_qasm,None,500]]
}}

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 trabajo 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-942fb30edced
>>> Job Status: JobStatus.RUNNING

Obtén los resultados del trabajo:

response_result= requests.get(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

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

5. Trabajar con opciones de Qiskit Runtime

Las técnicas de mitigación de errores permiten a los usuarios mitigar errores del circuit modelando el ruido del dispositivo en el momento de la ejecución. Esto típicamente resulta en una sobrecarga de preprocesamiento cuántico relacionada con el entrenamiento del modelo, y una sobrecarga de postprocesamiento clásico para mitigar errores en los resultados sin procesar 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 trabajo. Sampler V2 no admite la especificación de niveles de resiliencia. Sin embargo, puedes activar o desactivar métodos individuales de mitigación/supresión de errores.

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

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': 'sampler',
"backend": backend,
"params": {
# primitive unified blocs (PUBs) containing one circuit each:
"pubs": [[resulting_qasm]],
"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': 'sampler',
"backend": backend,
"params": {
# primitive unified blocs (PUBs) containing one circuit each:
"pubs": [[resulting_qasm]],
"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}")

Circuits parametrizados

1. Inicializar la cuenta

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

Encuentra 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')
# In case we want to pass a dictionary:
parameter_values = {'theta': 1.57, 'phi': 3.14}

3. Crear un circuit cuántico y agregar gates parametrizados

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 circuit cuántico usando la API Sampler 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': 'sampler',
"backend": backend,
"params": {
# Choose one option: direct parameter transfer or through a dictionary
# # primitive unified blocs (PUBs) containing one circuit each:
#"pubs": [[qasm_str,[1,2],500]],

# primitive unified blocs (PUBs) containing one circuit each:
"pubs": [[qasm_str,parameter_values,500]],
}}

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 trabajo 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'}

Obtén los resultados del trabajo:

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 trabajo, modo sesión y modo lote. Aprende cómo trabajar con el modo sesión y el modo lote en el tema sobre modos de ejecución. Ten en cuenta que los usuarios del Plan Open no pueden enviar trabajos de sesión.
  • Aprende a inicializar tu cuenta con la API REST.
  • Practica con los primitivos trabajando en la lección de función de costo en IBM Quantum Learning.
  • Aprende a transpilar localmente en la sección Transpilar.