Skip to main content
IBM Quantum Platform

ストレッチを使用したタイミングの遅延解決

OpenQASM 3言語仕様には、操作の絶対的なタイミングではなく相対的なタイミングを指定できるtype stretch が含まれています。 Qiskit v2.0.0 で、duration Delay として duration stretch を指定するサポートが追加されました。 ストレッチ持続時間の具体的な値は、キャリブレーション済みゲートの正確な持続時間が判明した後のコンパイル時に解決される。 コンパイラは、1つ以上の量子ビットに対するタイミング制約を条件として、ストレッチの持続時間を最小化しようとする。 その後、ゲート設計を表現できます。例えば、ゲートを均等に間隔を空けて配置する(高次エコーデカップリングシーケンスの実装など)、ゲート列を左揃えにする、あるいはサブ回路の動作期間中にゲートを適用するなど、正確なタイミングを知らなくても可能です。


動的分離

stretch の一般的な使用例は、別の量子ビットが条件演算を行っている間に、アイドリング中の量子ビットに動的デカップリングを適用することである。

例えば、 stretch 、0量子ビットに条件ブロックを適用している間、1量子ビットにXX動的デカップリングシーケンスを適用することができます:

以下の回路を示す図

対応する回路は以下のようになる。 この相対的なタイミングの境界を定めるには、一対のバリアが必要であることに注意。

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 を使って、2つのバリア間のゲート・シーケンスが、実際の持続時間がどうであれ、左揃えになるようにしている:

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

IBM Quantum Compute Service stretch で を使用する場合、ストレッチの解決によって生じた余剰分は、そのストレッチを使用する最初の遅延に加算されます。

例:

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という値に解決される。 最初のディレイ[a] 、残りが加算される。

ストレッチ解像度の方程式: a+8+a+8+a+8=100=3a+24a + 8 + a + 8 + a + 8 = 100 = 3*a + 24


IBM Quantum Compute Service でストレッチ値を確認する

ストレッチ期間の実際の値は、回路のスケジューリングが完了した後のコンパイル時に決定されます。 IBM Quantum Compute Service でサンプラージョブを実行すると、ジョブ結果のメタデータで解決されたストレッチ値を確認できます。 Quantum Compute における 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'])
Note

「コンパイル」メタデータには総実行時間が返されますが、これは課金対象となる時間(QPU時間)ではありません。

メタデータの出力を理解する

メタデータ stretch_values は以下の情報を返します:

  • 名前: 適用されたストレッチの名前。
  • 値: 要求された目標値。
  • 余剰分: ストレッチを解決した際の余剰分であり、ストレッチを使用する最初の遅延に追加される。
  • 拡張値: ストレッチの開始位置とその持続時間を指定する値の集合。

# 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 × 3 = 24)
  • foo value *2(8×2=16)

可視化を活用することで、タイミングの理解と検証を支援できます。

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

以下の図では、出力例に基づいて、 foo が量子ビット2上の伸張に対応します。 最初のストレッチ遅延は、の終わりに開始 foo``init_play する(1365)。 ストレッチの持続時間は10であるため、その遅延はゲート x が開始する時点(1365+10=1375)で終了する。 第二と第三のストレッチも同様に解釈できます。

draw_circuit_schedule_timing コマンドの出力を示します。

下部のスライダー、上部のコントロール(出力画像にカーソルを合わせると表示されます)、および出力画面の横にある凡例を使用して、表示をカスタマイズしてください。 画像にカーソルを合わせると正確なデータが表示されます。

詳細については、 「回路タイミングの可視化」 のトピックを参照してください。


量子コンピューティングの限界

Quantum Compute における stretch のサポートは現在実験段階であり、以下の制約があります:

  • バリア(暗黙的および明示的)間の量子ビットセットごとに最大1つのストレッチ変数。 量子ビットセットとは、1つまたは複数の量子ビットのことで、これらのセットは互いに排他的でなければならない。

    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
  • バリアで囲まれた領域をバリア領域と呼ぶ。 ストレッチ変数は複数のバリア領域で使用することはできない。

    # 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の不正
    な使用
  • ストレッチ式は、 X*stretch + YXY は浮動小数点数または整数定数)の形式に限定される。

    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)
  • ストレッチ式は単一のストレッチ変数のみを含むことができます。

    a = circuit.add_stretch("a")
    b = circuit.add_stretch("b")
    circuit.delay(expr.add(a, b), 0)
  • ストレッチ式は負の遅延値には解決できない。 現在のソルバーは非負制約を推論しない。

    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))
このページは役に立ちましたか?
バグや誤字の報告、またはコンテンツの要求はGitHubで行ってください。