Skip to main content
IBM Quantum Platform

Entradas y salidas del ejecutor

  • El código de esta página se ha desarrollado teniendo en cuenta los siguientes requisitos. Recomendamos utilizar estas versiones o posteriores.

    qiskit[all]~=2.4.0
    qiskit-ibm-runtime~=0.46.1
    samplomatic~=0.18.0
    

La primitiva «Executor» forma parte del modelo de ejecución dirigida, que ofrece mayor flexibilidad a la hora de personalizar un flujo de trabajo de mitigación de errores.

Las entradas y salidas de la primitiva «Executor» son muy diferentes de las de las primitivas «Sampler» y «Estimator ». Por ejemplo, en lugar de tomar como entrada una lista de PUB, Executor toma un QuantumProgram, que contiene una lista de QuantumProgramItem objetos. Estas clases de contenedores te ofrecen más flexibilidad que un « PUB », que es una estructura de datos de tipo tupla simple.

El resultado de «executor» es un QuantumProgramResult, que es un objeto iterable y contiene un elemento por cada entrada QuantumProgramItem.


Entradas: Programas de Quantum

Como se ha indicado anteriormente, la entrada de una primitiva «Executor» es un QuantumProgram, que es una secuencia iterable de QuantumProgramItem objetos. Estos objetos pueden ser de dos tipos:

  • CircuitItem, que suele contener un circuito y los valores de sus parámetros (si los hay).
  • SamplexItem, que suele contener lo siguiente:
    • Un circuito modelo
    • Un objeto «samplex», que se utiliza para generar conjuntos aleatorios de parámetros en tiempo de ejecución (por ejemplo, para realizar twirling o introducir ruido)
    • Argumentos para el samplex, que pueden incluir valores de parámetros del circuito original

Cada uno de estos elementos representa una tarea diferente que debe realizar Executor.

Antes de empezar

Algunos de los ejemplos de código de esta página utilizan samplex, que forma parte del paquete Samplomatic. Por lo tanto, antes de ejecutar esos bloques de código, debes instalar Samplomatic, tal y como se muestra en el siguiente bloque de código. Para obtener más información, consulta la documentación de Samplomatic.

pip install samplomatic

# For visualization support, include the visualization dependencies.
# pip install samplomatic[vis]

Ejemplo: Crea una lista QuantumProgram con dos tareas diferentes

En primer lugar, inicializa tu programa cuántico y, a continuación, añádele elementos utilizando o append_samplex_item``append_circuit_item (si hay un samplex), tal y como se muestra en los siguientes ejemplos.

La siguiente celda inicializa un QuantumProgram y especifica que debe ejecutar 1024 simulaciones para cada configuración de cada elemento del programa.

Note

A diferencia de Sampler, un QuantumProgram solo admite un valor de disparo. QuantumProgramSi quieres un valor de exposición diferente, necesitarás una toma aparte, lo que supondría un trabajo adicional.

from qiskit.transpiler import generate_preset_pass_manager
from qiskit_ibm_runtime.quantum_program import QuantumProgram
from qiskit_ibm_runtime import Executor, QiskitRuntimeService
from qiskit.circuit import Parameter, QuantumCircuit
import numpy as np
from samplomatic import build
from samplomatic.transpiler import generate_boxing_pass_manager

# Initialize an empty program
program = QuantumProgram(shots=1024)

# Initialize and transpile a 3-qubit quantum circuit with 2 parameters.
circuit = QuantumCircuit(3)
circuit.h(0)
circuit.cx(0, 1)
circuit.cx(1, 2)
circuit.rz(Parameter("theta"), 0)
circuit.rz(Parameter("phi"), 1)

# `measure_all` adds a 3-bit classical register named "meas"
circuit.measure_all()

# Choose the least busy backend
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

# Generate a preset pass manager
# This will be used to convert the abstract circuit to an
# equivalent Instruction Set Architecture (ISA) circuit.
preset_pass_manager = generate_preset_pass_manager(
    backend=backend, optimization_level=0
)

# Transpile the circuit
isa_circuit = preset_pass_manager.run(circuit)

Añadir un CircuitItem

A continuación, añade el circuito de destino, que se ha transpuesto de acuerdo con la arquitectura del conjunto de instrucciones (ISA) del backend, al archivo QuantumProgram. Dado que este circuito tiene dos parámetros, también debemos indicar los valores de los parámetros (10 conjuntos en este ejemplo). La ejecución de esto CircuitItem es la primera tarea que llevará a cabo el programa.

# Append the transpiled circuit and an array
# containing 10 sets of parameter values to the program
program.append_circuit_item(
    isa_circuit,
    circuit_arguments=np.random.rand(
        10, 2
    ),  # 10 sets of parameter values and 2 parameters
)

Añadir un SamplexItem

Las instrucciones del circuito se ejecutan sin ningún tipo de aleatoriedad. Por el contrario, los elementos de Samplex te permiten especificar cómo aleatorizar su contenido. La siguiente celda utiliza la generate_boxing_pass_manager() función para agrupar las puertas y las mediciones del circuito en recuadros y añadir una anotación giratoria a cada recuadro. A continuación, genera un circuito de plantilla y un par de samplex utilizando la build() función.

La ejecución de esto SamplexItem es la segunda tarea que llevará a cabo el programa.

Consulte la documentación de la API de Samplomatic para obtener información detallada sobre samplex y sus argumentos. Consulte la guía de Samplomatic Transpiler para obtener información sobre cómo utilizar la generate_boxing_pass_manager() función.

# Transpile the circuit, additionally grouping gates and measurements into annotated boxes
preset_pass_manager = generate_preset_pass_manager(
    backend=backend, optimization_level=0
)

# Use the boxing pass manager to group gates
# and measurements into boxes and add
# a`Twirl` annotation.
preset_pass_manager.post_scheduling = generate_boxing_pass_manager(
    # Add gate twirling
    enable_gates=True,
    # Add measurement twirling
    enable_measures=True,
)
boxed_circuit = preset_pass_manager.run(circuit)

# Build the template circuit and the samplex.  The template circuit has parametric gates
# without fixed values and the samplex randomly generates the parameter
# values on the server side at runtime to perform twirling.
template_circuit, samplex = build(boxed_circuit)

# Determine what arguments are required by the samplex.
# Input the arguments in samplex_arguments.
print(samplex.inputs())

Output:

TensorInterface(<
  - 'parameter_values' <float64[2]>: Input parameter values to use during sampling.
>)
# Append the template circuit and samplex as a samplex item
program.append_samplex_item(
    template_circuit,
    samplex=samplex,
    samplex_arguments={
        # the arguments required by the samplex.sample method
        "parameter_values": np.random.rand(10, 2),
    },
    shape=(28, 10),  # 28 randomizations and 10 sets of parameter values
)
# Initialize an Executor with the default options
executor = Executor(mode=backend)

# Submit the job
job = executor.run(program)

# Retrieve the result
result = job.result()

Resultados

El resultado de «executor» es un QuantumProgramResult, que es un iterable. Contiene una entrada por cada entrada QuantumProgramItem , en el mismo orden que los elementos de la entrada. Cada uno de estos elementos de salida es un diccionario cuyas claves son cadenas que se corresponden con los nombres de los registros clásicos de los circuitos de entrada (entre otros), por lo que ya no es necesario memorizar estos nombres como ocurría con la salida del Sampler. Los valores del diccionario son de tipo np.ndarray.

El resultado del ejemplo anterior contiene los siguientes elementos:

CircuitItem resultado

CircuitItemEl primer elemento contiene los resultados de la ejecución de la primera tarea (a) del programa. Contiene una sola clave, meas, que es el nombre del registro clásico en el circuito de entrada. El valor de esta clave se corresponde con un np.ndarray de forma (parameter sets, shots, register bits), que en el ejemplo anterior es (10, 1024, 3).

El siguiente código muestra cómo acceder a esta información:

# Access the results of the classical register of task #0, a CircuitItem
result_0 = result[0]["meas"]
print(f"Result shape: {result_0.shape}")

Output:

Result shape: (10, 1024, 3)

SamplexItem resultado

El segundo elemento contiene los resultados de la ejecución de la segunda tarea (a SamplexItem) del programa. Este artículo contiene varias llaves. La meas clave, que es el nombre del registro clásico del circuito de entrada, se asigna a la matriz de resultados de dicho registro. Esta matriz tiene la forma (randomizations, parameter sets, shots, classical bits), o (28, 10, 1024, 3) en este ejemplo. Además, la salida contiene una measurement_flips.meas clave, que corresponde a las correcciones de inversión de bits necesarias para contrarrestar la distorsión de la medición en el meas registro. En nuestro ejemplo, esta matriz de salida será (28, 10, 1, 3), ya que solo se necesita una operación para realizar la inversión de bits.

# Access the results of the classical register of task #1
result_1 = result[1]["meas"]
print(f"Result shape: {result_1.shape}")

# Access the bit-flip corrections
flips_1 = result[1]["measurement_flips.meas"]
print(f"Bit-flip corrections shape: {flips_1.shape}")

# Undo the bit flips via classical XOR
unflipped_result_1 = result_1 ^ flips_1

Output:

Result shape: (28, 10, 1024, 3)
Bit-flip corrections shape: (28, 10, 1, 3)

Próximos pasos

Recomendaciones
¿Le ha resultado útil esta página?
Informe de un error, de una errata o solicite contenido en GitHub.