Skip to main content
IBM Quantum Platform

Resolución temporal diferida mediante estiramiento

La especificación de lenguaje 3 de OpenQASM contiene un stretch tipo con el que se puede especificar la sincronización relativa de las operaciones en lugar de la sincronización absoluta. En Qiskit v2.0.0 se ha añadido compatibilidad con stretch como duraciones para Delay instrucciones. El valor concreto de una duración de tramo se resuelve en tiempo de compilación, una vez que se conoce la duración exacta de las puertas calibradas. El compilador intenta minimizar la duración del estiramiento, sujeto a restricciones de tiempo en uno o más qubits. A continuación, puede expresar diseños de puertas, como puertas espaciadas uniformemente (por ejemplo, para implementar una secuencia de desacoplamiento de eco de orden superior), alinear a la izquierda una secuencia de puertas o aplicar una puerta durante la duración de algún subcircuito, sin conocer la sincronización exacta.


Ejemplos

Desacoplamiento dinámico

Un caso de uso común de stretch es aplicar el desacoplamiento dinámico a un qubit inactivo mientras otro qubit está siendo sometido a operaciones condicionales.

Por ejemplo, podemos utilizar stretch para aplicar una secuencia de desacoplamiento dinámico XX al qubit 1, durante la duración del bloque condicional aplicado al qubit 0, como se ilustra en el siguiente diagrama:

Imagen que ilustra el siguiente circuito

El circuito correspondiente tendría el siguiente aspecto. Obsérvese que se necesita un par de barreras para definir los límites de esta temporización relativa.

from qiskit.circuit import QuantumCircuit, QuantumRegister, ClassicalRegister
from qiskit.circuit.classical import expr

qubits = QuantumRegister(2)
clbits = ClassicalRegister(2)
circuit = QuantumCircuit(qubits, clbits)
(q0, q1) = qubits
(c0, c1) = clbits

# Add barriers to define the boundaries
circuit.barrier()
circuit.h(q0)
circuit.measure(q0, c0)
with circuit.if_test((c0, 1)) as else_:
    circuit.h(q0)
with else_:
    circuit.x(q0)

# Apply an XX DD sequence with stretch on qubit 1
s = circuit.add_stretch("s")
circuit.delay(s, q1)
circuit.x(q1)
circuit.delay(expr.mul(s, 2), q1)
circuit.x(q1)
circuit.delay(s, q1)
circuit.barrier()

Alineación de la programación

Este ejemplo utiliza stretch para garantizar que una secuencia de puertas entre dos barreras esté alineada a la izquierda, sea cual sea su duración real:

from qiskit import QuantumCircuit
from numpy import pi

qc = QuantumCircuit(5)
qc.barrier()
qc.cx(0, 1)
qc.u(pi/4, 0, pi/2, 2)
qc.cx(3, 4)

a = qc.add_stretch("a")
b = qc.add_stretch("b")
c = qc.add_stretch("c")

# Use the stretches as Delay duration.
qc.delay(a, [0, 1])
qc.delay(b, 2)
qc.delay(c, [3, 4])
qc.barrier()
Note

Cuando se utiliza stretch con Qiskit Runtime, cualquier resto resultante de una resolución de estiramiento se añade al primer retardo que utiliza el estiramiento.

Ejemplo:

a = circuit.add_stretch("a")
circuit.barrier(q0, q1)
circuit.delay(100, q0)
circuit.delay(a, q1)  # resolve to 26
circuit.x(q1)  # duration: 8
circuit.delay(a, q1)  # resolve to 25
circuit.x(q1)  # duration: 8
circuit.delay(a, q1)  # resolve to 25
circuit.x(q1)  # duration: 8
circuit.barrier(q0, q1)

El código anterior resuelve un valor de 25 con un resto de 1. Al primer retraso[a] se le añadirá el resto.

Ecuación de resolución del estiramiento: a+8+a+8+a+8=100=3a+24a + 8 + a + 8 + a + 8 = 100 = 3*a + 24


Ver valores de estiramiento en Qiskit Runtime

El valor real de una duración de tramo se resuelve en tiempo de compilación, después de programar el circuito. Al ejecutar un trabajo de Sampler en Qiskit Runtime, puede ver los valores de estiramiento resueltos en los metadatos del resultado del trabajo. La compatibilidad con stretch en Qiskit Runtime es actualmente experimental, por lo que primero debe configurar una opción experimental para habilitar su recuperación y, a continuación, acceder a los datos directamente desde los metadatos de la siguiente manera:

# Enable stretch value retrieval.
sampler.options.experimental = {
    "execution": {
        "stretch_values": True,
        "scheduler_timing": True,
    },
}

# Access the stretch values from the metadata.
job_result = job.result()
circuit_stretch_values = (
    job_result[0].metadata["compilation"]["stretch_values"]
    )

# Visualize the timing.
# Use the sliders at the bottom, the controls at the top, and the 
# legend on the side of the output to customize the view.
draw_circuit_schedule_timing(ob.result()[0].metadata['compilation']
    ['scheduler_timing']['timing'])
Note

Aunque el tiempo total de ejecución del circuito figura en los metadatos de «compilación», este NO es el tiempo que se utiliza para la facturación (tiempo de CPU).

Comprender la salida de metadatos

Los stretch_values metadatos devuelven la siguiente información:

  • Nombre: El nombre del estiramiento aplicado.
  • Valor: El valor objetivo solicitado.
  • Resto: El resto resultante de resolver el estiramiento, que se añade al primer retraso que utiliza el estiramiento.
  • Valores ampliados: Conjuntos de valores que especifican el inicio del estiramiento y su duración.

Ejemplo

# Define the circuit
circuit = QuantumCircuit(4)
foo = circuit.add_stretch("foo")
bar = circuit.add_stretch("bar")
circuit.barrier()
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.cz(0, 1)
circuit.cz(0, 1)

circuit.delay(foo, 2)
circuit.x(2)
# 3*foo
circuit.delay(expr.mul(3, foo), 2)
circuit.x(2)
# 2*foo
circuit.delay(expr.mul(2, foo), 2)

circuit.delay(bar, 3)
circuit.x(3)
circuit.delay(bar, 3)

circuit.measure_all()

Salida de metadatos

 [{'name': 'bar',
  'value': 29,
  'remainder': 1,
  'expanded_values': [[1365, 30], [1404, 29]]},
 {'name': 'foo',
  'value': 8,
  'remainder': 2,
  'expanded_values': [[1365, 10], [1384, 24], [1417, 16]]}
  ]

Los valores devueltos para la duración dependen del valor objetivo y del resto calculado. Por ejemplo, estas son las duraciones devueltas para foo:

  • foo value + remainder (8+2 = 10)
  • foo value * 3 (8 x 3 = 24)
  • foo value * 2 (8 x 2 = 16)

Puede utilizar una visualización para comprender y verificar la sincronización.

draw_circuit_schedule_timing(job.result()[0].metadata
    ['compilation']['scheduler_timing']['timing'])

En la siguiente imagen, basada en el ejemplo de salida, foo corresponde a los estiramientos en Qubit 2. El primer retraso de estiramiento que utiliza foo comienza al final del init_play (1365). La duración del tramo es 10, por lo que el retraso finaliza cuando se inicia la x puerta (1365+10=1375). Puedes interpretar el segundo y tercer tramo de manera similar.

Se muestra el resultado del comando draw_circuit_schedule_timing.

Utilice los controles deslizantes de la parte inferior, los controles de la parte superior (pase el cursor por encima de la imagen de salida para mostrarlos) y la leyenda situada al lado de la salida para personalizar la vista. Pase el cursor sobre la imagen para ver los datos exactos.

Para obtener más información, consulta el tema «Visualización de la sincronización de circuitos ».


Qiskit Runtime limitaciones

El soporte de stretch en Qiskit Runtime es actualmente experimental y tiene las siguientes limitaciones:

  • Como máximo una variable de estiramiento por qubit establecido entre barreras (implícitas y explícitas). Un conjunto de qubits es uno o más qubits; estos conjuntos deben ser mutuamente excluyentes.

    a = circuit.add_stretch("a")
    b = circuit.add_stretch("b")
    circuit.delay(a, (q0, q1))
    circuit.delay(b, q0)  # Invalid because 2 stretches are applied on q0
  • La zona rodeada por un conjunto de barreras se denomina región barrera. Una variable de estiramiento no puede utilizarse en varias regiones de barrera.

    # Stretch a is used in two barrier regions
    a = circuit.add_stretch("a")
    circuit.barrier((q0, q1))
    circuit.delay(a, q0)
    circuit.barrier((q0, q1))
    circuit.delay(a, q0)
    circuit.barrier((q0, q1))
    Ilustración del resultado
    del código anterior: uso incorrecto de «stretch» en regiones de barrera
  • Las expresiones de estiramiento se limitan a las de la forma X*stretch + Y donde X y Y son constantes de coma flotante o enteras.

    a = circuit.add_stretch("a")
    b = circuit.add_stretch("b")
    c = circuit.add_stretch("c")
    
    # (a /  b) * c is not supported
    circuit.delay(expr.mul(expr.div(a, b), c), q1)
  • Las expresiones de estiramiento sólo pueden incluir una única variable de estiramiento.

    a = circuit.add_stretch("a")
    b = circuit.add_stretch("b")
    circuit.delay(expr.add(a, b), 0)
  • Las expresiones de estiramiento no pueden resolverse en valores de retardo negativos. El solucionador actual no infiere restricciones de no negatividad.

    from qiskit.circuit import Duration
    
    circuit.barrier((q0, q1))
    circuit.delay(20, q1)
    # The length of this barrier region is 20dt, meaning the
    # equation for solving stretch 'a' is a + 40dt = 20dt, giving a = -20dt.
    circuit.delay(expr.add(a, Duration.dt(40)), q0)
    circuit.barrier((q0, q1))
¿Le ha resultado útil esta página?
Informe de un error, de una errata o solicite contenido en GitHub.