Despliega tu primer managed workflow
Versiones de los paquetes
El código de esta página se desarrolló con los siguientes requisitos. Recomendamos usar estas versiones o posteriores.
qiskit[all]~=2.6.1
qiskit-serverless~=0.38.0
Usa esta página para subir un workflow, ejecutarlo y obtener su resultado. El workflow de ejemplo optimiza y simula un circuito de Qiskit. Simula el circuito en hardware clásico, por lo que no consume tiempo de QPU.
Antes de empezar, instala el paquete cliente y autentícate.
Para desplegar tu propio código con ayuda de un asistente de IA, usa las habilidades de IA del repositorio de plantillas de Qiskit Function.
# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util
_needed = {"qiskit": "qiskit", "qiskit_ibm_catalog": "qiskit-ibm-catalog", "qiskit_serverless": "qiskit-serverless"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
Escribir un workflow
Crear la estructura de carpetas
Un managed workflow es una carpeta de archivos Python con un archivo de punto de entrada. Un managed workflow sube todo lo que hay en la carpeta, hasta 50 MB, y ejecuta el punto de entrada como un script. Como un workflow sube la carpeta completa, mantén tus archivos locales, como deploy.ipynb, fuera de la carpeta. Crea la siguiente estructura:
hello_world_project/
├── deploy.ipynb # Your local notebook: upload and run the workflow
└── source_files/ # The working directory that you upload
└── hello_world.py # The entrypoint
Escribir el punto de entrada hello world
El punto de entrada lee un circuito, lo optimiza y lo simula, y guarda los conteos y la profundidad de dos qubits. Guarda el siguiente código como source_files/hello_world.py:
Si lees esta página como un cuaderno, la celda de código de hello_world.py comienza con el comando mágico %%writefile. Cuando ejecutas esta celda, guarda el código en el archivo en lugar de ejecutarlo.
# This cell is hidden from users. It creates the working directory.
from pathlib import Path
Path("./source_files").mkdir(exist_ok=True)
%%writefile ./source_files/hello_world.py
from qiskit.primitives import StatevectorSampler
from qiskit.transpiler import generate_preset_pass_manager
from qiskit_serverless import Job, get_arguments, save_result, update_status
# Read the arguments that you pass to run()
arguments = get_arguments()
circuit = arguments["circuit"]
shots = arguments.get("shots", 1024)
# Optimize the circuit. Printed text goes to the job's logs.
update_status(Job.OPTIMIZING_HARDWARE)
pass_manager = generate_preset_pass_manager(
optimization_level=1, basis_gates=["cz", "rz", "sx", "x"]
)
isa_circuit = pass_manager.run(circuit)
two_qubit_depth = isa_circuit.depth(lambda instruction: instruction.operation.num_qubits == 2)
print(f"Two-qubit depth after optimization: {two_qubit_depth}", flush=True)
# Simulate the circuit and return the counts
sampler = StatevectorSampler(seed=1234)
pub_result = sampler.run([isa_circuit], shots=shots).result()[0]
save_result({"counts": pub_result.data.meas.get_counts(), "two_qubit_depth": two_qubit_depth})
Writing ./source_files/hello_world.py
El punto de entrada usa tres funciones de qiskit_serverless:
-
get_arguments()devuelve como diccionario los argumentos con nombre que pasas arun(). Cada valor debe ser serializable en JSON, o un objeto que el cliente pueda codificar, como unQuantumCircuit. Los objetos codificados llegan como los mismos objetos que pasaste. -
update_status(Job.OPTIMIZING_HARDWARE)establece el estado detalladoRUNNING: OPTIMIZING_FOR_HARDWARE, que puedes ver mientras el trabajo se ejecuta. Consulta Informar del progreso con update_status(). -
save_result()almacena un valor serializable en JSON que lees más tarde conjob.result(). El workflow devuelve los conteos como un diccionario y la profundidad de dos qubits del circuito optimizado como un entero.
Todo lo que el workflow escribe en la salida estándar, como la profundidad de dos qubits, va a los registros del trabajo. Para añadir marcas de tiempo y niveles de registro, usa el módulo logging. Consulta Escribir registros y gestionar errores.
Subir el workflow
En tu cuaderno local, ejecuta el siguiente código desde la carpeta hello_world_project. El código se conecta con tu cuenta guardada, define el workflow y lo sube. entrypoint es el archivo que ejecuta el workflow, y working_dir es la carpeta que subes:
from qiskit_ibm_catalog import ManagedWorkflow, ManagedWorkflowClient
client = ManagedWorkflowClient()
hello_world = ManagedWorkflow(
title="hello-world",
entrypoint="hello_world.py",
working_dir="./source_files/",
)
hello_world = client.upload(hello_world)
Ejecutar el workflow con entradas
Construye un circuito GHZ de tres qubits para pasarlo a hello_world como entrada:
from qiskit import QuantumCircuit
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.measure_all()
Ejecuta hello_world con el circuito y el número de shots como argumentos con nombre. Los nombres de los argumentos coinciden con las claves que el punto de entrada lee con get_arguments():
job = hello_world.run(circuit=circuit, shots=1024)
print(job.job_id)
54705348-5117-44b7-935b-e6986ef182fa
run() devuelve un Job después de que el workflow pone el trabajo en cola. No espera a que el trabajo se ejecute. El trabajo continúa en la nube después de que cierres tu sesión de Python. Para encontrarlo más tarde, lista tus trabajos recientes con client.jobs().
Obtener el estado, el resultado y los registros
Inmediatamente después de llamar a run(), el estado suele ser QUEUED:
job.status()
'QUEUED'
El estado cambia de QUEUED a INITIALIZING, RUNNING y luego DONE.
job.result() espera hasta que el trabajo termina y luego devuelve el valor que el workflow pasó a save_result():
job.result()
{'counts': {'111': 514, '000': 510}, 'two_qubit_depth': 2}
# This cell is hidden from users. It checks the result.
assert set(_["counts"]) <= {"000", "111"} # noqa: F821
assert sum(_["counts"].values()) == 1024 # noqa: F821
from qiskit.visualization import plot_histogram
plot_histogram(job.result()["counts"])
Puedes leer los registros mientras el trabajo se ejecuta. El workflow sube líneas nuevas aproximadamente cada 15 segundos. Los registros incluyen la línea que imprimió el workflow:
print(job.logs())
Two-qubit depth after optimization: 2
# This cell is hidden from users. It checks the logs.
assert "Two-qubit depth after optimization" in job.logs()
Actualizar el workflow
Para cambiar un workflow, edita sus archivos y llama de nuevo a upload() con el mismo title. La nueva subida reemplaza a la anterior, y los trabajos que ya comenzaron no se ven afectados.
Campos como arguments_schema y sizes_map conservan sus valores almacenados cuando los omites en la nueva subida.
Próximos pasos
- Define entradas y salidas para saber qué tipos de argumentos y resultados admite un workflow.
- Declara dependencias para usar más paquetes de Python en tu workflow.
- Ejecuta trabajos cuánticos desde un workflow para ejecutar tus circuitos en una QPU, informar de cada etapa y hacer seguimiento de los trabajos de QPU.
- Ejecuta un managed workflow para conocer todos los estados de los trabajos, depurar un trabajo fallido y encontrar un trabajo más tarde.
- Para partir de código que funciona, despliega una de las plantillas de Qiskit Function, o adapta una plantilla para tu propio workflow.