Resolução de tempo diferida usando alongamento
A especificação da linguagem 3 do OpenQASM contém um stretch tipo com o qual você pode especificar o tempo relativo das operações em vez do tempo absoluto. O suporte para durações stretch como instruções Delay foi adicionado no Qiskit v2.0.0. O valor concreto de uma duração de trecho é resolvido em tempo de compilação, após a duração exata dos portões calibrados ser conhecida. O compilador tenta minimizar a duração do alongamento, sujeito a restrições de tempo em um ou mais qubits. Você pode então expressar projetos de portas, como portas com espaçamento uniforme (por exemplo, para implementar uma sequência de desacoplamento de eco de ordem superior), alinhar à esquerda uma sequência de portas ou aplicar uma porta durante a duração de algum subcircuito, sem saber o tempo exato.
Exemplos
Desacoplamento dinâmico
Um caso de uso comum do stretch é aplicar o desacoplamento dinâmico a um qubit ocioso enquanto outro qubit está sendo submetido a operações condicionais.
Por exemplo, podemos usar o site stretch para aplicar uma sequência de desacoplamento dinâmico XX ao qubit 1, durante a duração do bloco condicional aplicado ao qubit 0, conforme ilustrado no diagrama a seguir:
O circuito correspondente seria parecido com o seguinte. Observe que é necessário um par de barreiras para definir os limites desse tempo relativo.
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()Alinhamento de programação
Este exemplo usa o site stretch para garantir que uma sequência de portas entre duas barreiras seja alinhada à esquerda, independentemente de suas durações reais:
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()Ao usar stretch com Qiskit Runtime, qualquer resto resultante de uma resolução de alongamento é adicionado ao primeiro atraso que usa o alongamento.
Exemplo:
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)O código acima resulta em um valor de 25 com um resto de 1. O primeiro atraso[a] terá o restante adicionado.
Equação de resolução de estiramento:
Visualizar valores de extensão em Qiskit Runtime
O valor real de uma duração de estiramento é resolvido no momento da compilação, após o circuito ser programado. Ao executar uma tarefa do Sampler em Qiskit Runtime, você pode visualizar os valores de extensão resolvidos nos metadados do resultado da tarefa. O suporte para stretch em Qiskit Runtime é atualmente experimental, portanto, você precisa primeiro definir uma opção experimental para habilitar sua recuperação e, em seguida, acessar os dados diretamente dos metadados da seguinte maneira:
# 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'])Embora o tempo total de execução do circuito seja informado nos metadados de "compilação", esse NÃO é o tempo utilizado para fins de cobrança (tempo de QPU).
Entenda a saída de metadados
Os stretch_values metadados retornam as seguintes informações:
- Nome: O nome do alongamento aplicado.
- Valor: O valor da meta solicitada.
- Remanesecente: O remanescente da resolução do alongamento, que é adicionado ao primeiro atraso que utiliza o alongamento.
- Valores expandidos: conjuntos de valores que especificam o início do alongamento e sua duração.
Exemplo
# 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()Saída de metadados
[{'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]]}
]Os valores retornados para a duração dependem do valor da meta e do restante calculado. Por exemplo, estas são as durações retornadas para foo:
foo value+remainder(8+2 = 10)foo value* 3 (8 x 3 = 24)foo value* 2 (8 x 2 = 16)
Você pode usar uma visualização para ajudar a entender e verificar o tempo.
draw_circuit_schedule_timing(job.result()[0].metadata
['compilation']['scheduler_timing']['timing'])Na imagem a seguir, com base no exemplo de saída, foo corresponde aos trechos no Qubit 2. O primeiro atraso de alongamento que usa foo começa no final do init_play (1365). A duração do intervalo é 10, de modo que o atraso termina quando o x portão é acionado (1365+10=1375). Você pode interpretar o segundo e o terceiro trechos de forma semelhante.

Use os controles deslizantes na parte inferior, os controles na parte superior (passe o mouse sobre a imagem de saída para revelá-los) e a legenda ao lado da saída para personalizar a visualização. Passe o cursor sobre a imagem para visualizar os dados exatos.
Para obter mais detalhes, consulte o tópico “Visualização do tempo de resposta do circuito ”.
Qiskit Runtime limitações
O suporte para stretch em Qiskit Runtime é atualmente experimental e tem as seguintes restrições:
-
No máximo uma variável de extensão por qubit definido entre barreiras (implícitas e explícitas). Um conjunto de qubits é um ou mais qubits; esses conjuntos devem ser mutuamente exclusivos.
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 q0a = circuit.add_stretch("a") b = circuit.add_stretch("b") circuit.delay(a, (q0, q1)) circuit.delay(b, q2) -
A área cercada por um conjunto de barreiras é chamada de região de barreira. Uma variável de extensão não pode ser usada em várias regiões de barreira.
# 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))do código anterior: uso inválido da função stretch em regiões de barreira # Stretch a is used inside a barrier region that is on q0 and q1 a = circuit.add_stretch("a") circuit.barrier((q0, q1)) circuit.delay(a, q0) circuit.barrier(q2) circuit.delay(a, q0) circuit.barrier((q0, q1))do código anterior: uso válido do stretch em uma região de barreira -
As expressões de alongamento são limitadas àquelas do formato
X*stretch + Yem queXeYsão constantes de ponto flutuante ou inteiras.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)from qiskit.circuit import Duration a = circuit.add_stretch("a") circuit.delay(expr.add(expr.mul(a, 2), Duration.dt(3)), 0) -
As expressões de alongamento só podem incluir uma única variável de alongamento.
a = circuit.add_stretch("a") b = circuit.add_stretch("b") circuit.delay(expr.add(a, b), 0)a = circuit.add_stretch("a") circuit.delay(expr.add(a, a), 0) -
As expressões de alongamento não podem ser resolvidas para valores de atraso negativos. O solucionador atual não infere restrições de não negatividade.
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))circuit.barrier((q0, q1)) circuit.delay(20, q1) circuit.delay(a, q0) circuit.barrier((q0, q1))