stretch를 사용한 지연된 타이밍 해석
OpenQASM 3 언어 명세에는 절대 타이밍 대신 연산의 상대적 타이밍을 지정할 수 있는 stretch 타입이 포함되어 있습니다. Delay 명령어의 지속 시간으로 stretch를 지원하는 기능이 Qiskit v2.0.0에 추가되었습니다. stretch 지속 시간의 구체적인 값은 보정된 Gate의 정확한 지속 시간이 확인된 이후 컴파일 시점에 해석됩니다. 컴파일러는 하나 이상의 Qubit에 대한 타이밍 제약 조건에 따라 stretch 지속 시간을 최소화하려 시도합니다. 이를 통해 정확한 타이밍을 알지 못하더라도 Gate를 균등하게 배치하거나(예: 고차 에코 디커플링 시퀀스 구현), Gate 시퀀스를 왼쪽 정렬하거나, 특정 서브 Circuit의 지속 시간 동안 Gate를 적용하는 등의 Gate 설계를 표현할 수 있습니다.
예제
동적 디커플링
stretch의 일반적인 사용 사례는 다른 Qubit이 조건부 연산 을 수행하는 동안 유휴 상태의 Qubit에 동적 디커플링을 적용하는 것입니다.
예를 들어, 다음 다이어그램과 같이 stretch를 사용하여 Qubit 0에 적용된 조건부 블록의 지속 시간 동안 Qubit 1에 XX 동적 디커플링 시퀀스를 적용할 수 있습니다.

이에 해당하는 Circuit은 다음과 같습니다. 이 상대적 타이밍의 경계를 정의하기 위해 한 쌍의 barrier가 필요하다는 점에 주의하세요.
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()
스케줄링 정렬
이 예제에서는 stretch를 사용하여 두 barrier 사이의 Gate 시퀀스가 실제 지속 시간에 관계없이 왼쪽 정렬되도록 합니다.
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()
Qiskit Runtime에서 stretch를 사용할 때, stretch 해석에서 발생하는 나머지 값은 해당 stretch를 사용하는 첫 번째 delay에 추가됩니다.
예시:
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)
위 코드는 나머지 값 1을 가진 25로 해석됩니다. 첫 번째 delay[a]에 나머지 값이 추가됩니다.
Stretch 해석 방정식:
Qiskit Runtime에서 stretch 값 확인하기
stretch 지속 시간의 실제 값은 Circuit이 스케줄된 이후 컴파일 시점에 해석됩니다. Qiskit Runtime에서 Sampler 작업을 실행할 때, 작업 결과 메타데이터에서 해석된 stretch 값을 확인할 수 있습니다. Qiskit Runtime에서 stretch 지원은 현재 실험적이므로, 먼저 실험적 옵션을 설정하여 검색을 활성화한 다음 아래와 같이 메타데이터에서 직접 데이터에 접근해야 합니다.
# 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'])
"compilation" 메타데이터에 총 Circuit 시간이 반환되지만, 이는 과금(양자 시간)에 사용되는 시간이 아닙니다.
메타데이터 출력 이해하기
stretch_values 메타데이터는 다음 정보를 반환합니다.
- Name: 적용된 stretch의 이름.
- Value: 요청된 목표 값.
- Remainder: stretch 해석에서 발생한 나머지로, stretch를 사용하는 첫 번째 delay에 추가됩니다.
- Expanded values: stretch의 시작 위치와 지속 시간을 지정하는 값 집합.
예제
# 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()
메타데이터 출력
[{'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]]}
]
반환된 지속 시간 값은 목표 값과 계산된 나머지에 따라 달라집니다. 예를 들어, 다음은 foo에 대해 반환된 지속 시간입니다.
foo value+remainder(8+2 = 10)foo value* 3 (8 x 3 = 24)foo value* 2 (8 x 2 = 16)
시각화를 통해 타이밍을 이해하고 검증할 수 있습니다.
draw_circuit_schedule_timing(job.result()[0].metadata['compilation']['scheduler_timing']['timing'])
다음 이미지는 예제 출력을 기반으로 하며, foo는 Qubit 2의 stretch에 해당합니다. foo를 사용하는 첫 번째 stretch delay는 init_play가 끝나는 시점(1365)에 시작됩니다. stretch 지속 시간은 10이므로 해당 delay는 x Gate가 시작될 때(1365+10=1375) 끝납니다. 두 번째와 세 번째 stretch도 유사하게 해석할 수 있습니다.

출력 이미지 위에 마우스를 올려 나타나는 하단의 슬라이더, 상단의 컨트롤, 측면의 범례를 사용하여 보기를 사용자 지정할 수 있습니다. 이미지 위에 마우스를 올리면 정확한 데이터를 확인할 수 있습니다.
자세한 내용은 Circuit 타이밍 시각화 항목을 참조하세요.
Qiskit Runtime 제한 사항
Qiskit Runtime에서 stretch 지원은 현재 실험적이며 다음과 같은 제약 사항이 있습니다.
-
barrier 사이의 _Qubit 집합_당 최대 하나의 stretch 변수만 허용됩니다(암시적 및 명시적 barrier 모두 포함). Qubit 집합은 하나 이상의 Qubit으로 구성되며, 이 집합들은 서로 겹치지 않아야 합니다.
- 잘못된 예
- 올바른 예
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) -
barrier 집합으로 둘러싸인 영역을 _barrier 영역_이라고 합니다. stretch 변수는 여러 barrier 영역에서 사용될 수 없습니다.
- 잘못된 예
- 올바른 예
# 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))
# 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))
-
stretch 표 현식은
X*stretch + Y형태로 제한됩니다. 여기서X와Y는 부동소수점 또는 정수 상수입니다.- 잘못된 예
- 올바른 예
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) -
stretch 표현식에는 단일 stretch 변수만 포함될 수 있습니다.
- 잘못된 예
- 올바른 예
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) -
stretch 표현식은 음수 delay 값으로 해석될 수 없습니다. 현재 솔버는 비음수 제약 조건을 추론하지 않습니다.
- 잘못된 예
- 올바른 예
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))