Japanese
言語
English
Bengali
French
German
Japanese
Korean
Portuguese
Spanish
Tamil

注釈

当ページは tutorials/circuits_advanced/06_building_pulse_schedules.ipynb から生成されました。

Pulseスケジュールの構築

パルスゲートは、回路ゲートの低レベルで正確な表現を定義します。 あるひとつの演算は、複数の低レベル命令で構成されるパルス・プログラムで実装することができます。 パルスゲートの詳細については、 こちら を参照してください。

注: IBM デバイスでは、ゲートを記述するサブルーチンとしてパルス・プログラムが使用されます。 以前は、このフォーマットで完全なプログラムを受け入れたデバイスもありましたが、これは2021年12月に終了しています。 他のプロバイダーでは、まだこの形式で完全なプログラムを受け入れることができます。 プログラムがどのように使われるかに関わらず、プログラムを構築するための構文は同じです。その方法をご紹介しましょう!

パルス・プログラムは、Schedule と呼ばれ、制御エレクトロニクスの命令シーケンスを記述します。 Pulse Builder を使用して Schedule を作成します。スケジュールを初期化するのは簡単です:

[20]:
from qiskit import pulse

with pulse.build(name='my_example') as my_program:
    # Add instructions here
    pass

my_program
[20]:
ScheduleBlock(, name="my_example", transform=AlignLeft())

命令がまだないことがわかります。 このページの次のセクションでは、スケジュールに追加する各命令について説明します。 そして最後のセクションでは、さまざまな 配置コンテキスト について説明します。これにより、命令が互いに相対的にどのように時間内に配置されるかが決まります。

Schedule 命令

各命令タイプは、独自のオペランドセットを持ちます。上記のように、それぞれに少なくとも1つの Channel が含まれており、命令の適用先を特定しています。

Channels は、制御ハードウェアから量子チップへの信号線のラベルです。

  • DriveChannel は通常、単一量子ビットの回転を ドライブ するのに使用されます。

  • ControlChannel は通常、複数量子ビットゲートや、調整可能な量子ビットの追加ドライブ線に使用されます。

  • MeasureChannel は、読み出しを促す送信パルスに特化しています。

  • AcquireChannel は、読み出し信号を収集するデジタイザーをトリガーするために使用されます。

DriveChannelControlChannelMeasureChannel は、すべて PulseChannel です。これは、これらが 送信 パルスをサポートしていることを意味します。一方、 AcquireChannel は受信チャンネルのみであり、波形を出すことはできません。

以下の例では、PulseChannel を受け取る Instruction ごとに、ひとつの DriveChannel インスタンスを生成しています。チャンネルは、ひとつの数値 index 引数を取ります。 ControlChannel を除き、インデックスが量子ビットラベルにマッピングされるのは自明です。

[21]:
from qiskit.pulse import DriveChannel

channel = DriveChannel(0)

パルス Schedule は実行するバックエンドに依存しません。 しかしながら、pulse.build にターゲットバックエンドを提供することで、それを認識するコンテキストでプログラムを構築することができます。 可能な場合はバックエンドを提供するべきです。チャンネル・アクセサの pulse.<type>_channel(<idx>) を使うことで、利用可能なデバイス・リソースのみを使用することができます。

[22]:
from qiskit.providers.fake_provider import FakeValencia

backend = FakeValencia()

with pulse.build(backend=backend, name='backend_aware') as backend_aware_program:
    channel = pulse.drive_channel(0)
    print(pulse.num_qubits())
    # Raises an error as backend only has 5 qubits
    #pulse.drive_channel(100)
5

delay

最も簡単な命令のひとつは delay です。これはブロッキング命令で、指定された継続時間中、指定されたチャンネルに信号を出力しないように、制御電子装置に対して指示を出します。他の命令のタイミングを制御するのに便利です。

ここやその他の場所における期間は、バックエンドのサイクル時間 (1 / サンプルレート) を単位とした dt です。整数値をとります。

delay 命令を追加するには、期間とチャンネルを渡します。ここで、channelAcquireChannel を含む任意の種類のチャンネルになります。 Pulse Builder コンテキストを開始するには pulse.build を使用します。これにより、スケジュール delay_5dt に遅延が自動的にスケジュールされます。

[23]:
with pulse.build(backend) as delay_5dt:
    pulse.delay(5, channel)

これがすべてです。 同じチャンネルでこの遅延の後に追加された命令は、この遅延がない場合よりも 5 タイムステップ遅れて実行されます。

play

play 命令は*パルス*の実行を担当します。play 命令を追加するのは簡単です。

with pulse.build() as sched:
    pulse.play(pulse, channel)

pulse の引数が何であるかを明確にして、それを構築するいくつかの異なる方法を探りましょう。

パルス

Pulse は、任意のパルス エンベロープ を指定します。出力波形の変調周波数と位相は、次に説明する setFrequencyshiftPhase 命令によって制御されます。

以下の画像は、なぜそれらが個別に指定されているかを直感的に示しています。一般的な研究機器である任意波形発生器 (arbitrary waveform generator、AWG) への入力として、エンベロープを表すパルスを考えてください。これは左の画像に示されています。制限されたサンプルレートが信号を区別していることに注意してください。AWGによって生成された信号は、連続正弦波ジェネレータと混合されます。その出力の周波数は、正弦波発生器への指示によって制御されます。中央の画像を参照してください。最後に、量子ビットに送信された信号は、下の画像の右側に示されています。

注記 :ハードウェアは他の方法で実装することもできますが、命令を別々にしておけば、変調周波数の値などの明示的な情報が失われるのを回避できます。

altテキスト

パルスを構築するために利用できる方法は多くあります。Qiskit Pulse 内の library には、 Pulse を構築するための便利なメソッドが含まれています。たとえば、単純なガウスパルス、つまりサンプリングされたガウス関数によって記述されたエンベロープを持つパルスを考えてみましょう。振幅1、標準偏差10 \(\sigma\) 、および128サンプルポイントを任意に選択します。

注記:振幅ノルムは 1.0 に制限されています。個々のバックエンドシステムは、更なる制約、例えば最小パルスサイズは64など、も課しています。これらの追加の制約は、利用可能な場合、 ここ で説明する BackendConfiguration を通じて提供されます。

[24]:
from qiskit.pulse import library

amp = 1
sigma = 10
num_samples = 128

パラメトリック・パルス

Gaussian パラメトリック・パルスを使用してガウスパルスを作成してみましょう。パラメトリック・パルスは、個々のサンプルごとではなく、関数の名前とそのパラメーターをバックエンドに送信します。 パラメトリック・パルスを使用すると、バックエンドに送信するジョブがはるかに小さくなります。 IBM Quantum バックエンドは、それらが受け入れる最大ジョブサイズを制限するため、パラメトリック・パルスを使うことで、より大きなプログラムを実行できる場合があります。

library の他のパラメトリック・パルスには、GaussianSquareDrag 、および Constant が含まれます。

注記 :バックエンドには、パラメトリック・パルスをサンプリングする方法を正確に決定する責任があります。パラメトリック・パルスを描画することは可能ですが、表示されるサンプルがバックエンドで実行されたものと同じであるとは限りません。

[25]:
gaus = pulse.library.Gaussian(num_samples, amp, sigma,
                              name="Parametric Gaus")
gaus.draw()
[25]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_12_0.png

サンプルによって記述されたパルス波形

Waveform は、時間順に並べられた複素振幅または サンプル の配列として指定されたパルス信号です。各サンプルは、バックエンドによって決定される1サイクル、タイムステップ dt で再生されます。プログラムのリアルタイムダイナミクスを知りたい場合は、 dt の値を知る必要があります。\(i^{th}\) サンプル(インデックスは0開始)を、量子ビット周波数によって調節された、時間 i*dt から (i + 1)*dt まで再生します。

[26]:
import numpy as np

times = np.arange(num_samples)
gaussian_samples = np.exp(-1/2 *((times - num_samples / 2) ** 2 / sigma**2))

gaus = library.Waveform(gaussian_samples, name="WF Gaus")
gaus.draw()
[26]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_14_0.png

パルス・ライブラリー関数

独自のパルス・ライブラリーには、一般的な関数から Waveform を作成するためのサンプリング・メソッドがあります。

[27]:
gaus = library.gaussian(duration=num_samples, amp=amp, sigma=sigma, name="Lib Gaus")
gaus.draw()
[27]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_16_0.png

pulse を指定する方法に関係なく、play は同じ方法でスケジュールに追加されます:

[28]:
with pulse.build() as schedule:
    pulse.play(gaus, channel)
schedule.draw()
[28]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_18_0.png

複雑なリストや配列を直接 play に指定することもできます。

[29]:
with pulse.build() as schedule:
    pulse.play([0.001*i for i in range(160)], channel)
schedule.draw()
[29]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_20_0.png

play 命令は、Pulse から期間を取得します。パラメーター化されたパルスの期間は明示的な引数であり、Waveform の期間は入力サンプルの数です。

set_frequency

前述したように、出力パルス波形エンベロープも周波数と位相によって変調されます。各チャンネルには、 backend.defaults() にリストされているデフォルトの周波数があります(参照 )。

チャンネルの周波数は、 set_frequency 命令により Schedule 内でいつでも更新できます。浮動小数点の frequencyPulseChannel channel を入力として受け取ります。 set_frequency 命令に続くチャンネル上のすべてのパルスは、別の set_frequency 命令が検出されるまで、またはプログラムが終了するまで、指定された周波数で変調されます。

命令の暗黙の期間は 0 です。

注記 :要求できる周波数は、各ハードウェア・チャンネルの合計帯域幅と瞬時帯域幅によって制限されます。将来的には、これらは backend によって報告されます。

[30]:
with pulse.build(backend) as schedule:
    pulse.set_frequency(4.5e9, channel)

shift_phase

shift_phase 命令は、周波数変調の位相を phase ごとに増やします。 set_frequency と同様に、この位相シフトは、プログラムが終了するまで、同じチャンネル上のすべての後続の命令に影響します。 shift_phase の影響を元に戻すには、負の phase を新しい命令に渡すことができます。

set_frequency と同様に、命令の暗黙の期間は 0 です。

[31]:
with pulse.build(backend) as schedule:
    pulse.shift_phase(np.pi, channel)

acquire

acquire 命令は、読み出しのためのデータ取得をトリガーします。 それは、持続時間、測定されている量子ビットにマップする AcquireChannel および、 MemorySlot または RegisterSlot を必要とします。 MemorySlot は、読み出し結果が保存される古典的なメモリです。 RegisterSlot は、高速フィードバックのための読み出し結果を保存する制御電子回路のレジスタにマッピングします。

acquire 命令は、キーワード引数としてカスタム DiscriminatorKernel を取ることもできます。

[32]:
from qiskit.pulse import Acquire, AcquireChannel, MemorySlot

with pulse.build(backend) as schedule:
    pulse.acquire(1200, pulse.acquire_channel(0), MemorySlot(0))

Schedule 命令を追加する方法がわかったので、再生されるタイミングを正確に制御する方法を学びましょう。

Pulse Builder

ここでは、スケジュールの作成方法を学ぶための最も重要なPulse Builder機能について説明します。 ここの記述は完全なものではありません。Pulse Builder を使用してできることの詳細については、Pulse API reference を参照してください。

配置コンテキスト

ビルダーは、スケジュールの構築方法に影響する配置コンテキストを持ちます。 コンテキストを入れ子にすることもできます。それらを試し、.draw() を使用してパルスがどのように配置されるかを確認してください。

配置コンテキストに関係なく、結果のスケジュールの長さは、すべての命令を含め配置ルールに従うのと同等くらい短いです。これにより、「最も長いパス」から命令をスケジュールするある程度の自由度があります。以下の例ではこれを示しています。

align_left

ビルダーはスケジュールの構築方法に影響する配置コンテキストを持っています。デフォルトは align_left です。

[33]:
with pulse.build(backend, name='Left align example') as program:
    with pulse.align_left():
        gaussian_pulse = library.gaussian(100, 0.5, 20)
        pulse.play(gaussian_pulse, pulse.drive_channel(0))
        pulse.play(gaussian_pulse, pulse.drive_channel(1))
        pulse.play(gaussian_pulse, pulse.drive_channel(1))

program.draw()
[33]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_28_0.png

D1 上のパルスにはスケジューリングの自由度がないことに注意してください。2 番目の波形は最初の波形の直後に始まります。 D0 上のパルスは、スケジュール全体の期間を変更することなく、t=0t=100 の間でいつでも開始できます。 align_left コンテキストでは、パルスの開始時刻を t=0 に設定します。これはテキスト文書の左揃えのように考えることができます。

align_right

当然、align_rightalign_left の反対です。D0 上でガウスパルスを開始する上記の例では t=100 を選択します。 左と右は、それぞれ「できるだけ早く」と「できるだけ遅く」スケジューリングとも呼ばれることがあります。

[34]:
with pulse.build(backend, name='Right align example') as program:
    with pulse.align_right():
        gaussian_pulse = library.gaussian(100, 0.5, 20)
        pulse.play(gaussian_pulse, pulse.drive_channel(0))
        pulse.play(gaussian_pulse, pulse.drive_channel(1))
        pulse.play(gaussian_pulse, pulse.drive_channel(1))

program.draw()
[34]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_30_0.png

align_equispaced(duration)

特定のブロックの期間がわかっている場合は、 align_equispace を使って各命令の間に同じ長さの遅延を挿入することもできます。

[35]:
with pulse.build(backend, name='example') as program:
    gaussian_pulse = library.gaussian(100, 0.5, 20)
    with pulse.align_equispaced(2*gaussian_pulse.duration):
        pulse.play(gaussian_pulse, pulse.drive_channel(0))
    pulse.play(gaussian_pulse, pulse.drive_channel(1))
    pulse.play(gaussian_pulse, pulse.drive_channel(1))

program.draw()
[35]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_32_0.png

align_sequential

この配置コンテキストは、並列に命令をスケジュールしません。各命令は、以前に追加した命令の最後に開始されます。

[36]:
with pulse.build(backend, name='example') as program:
    with pulse.align_sequential():
        gaussian_pulse = library.gaussian(100, 0.5, 20)
        pulse.play(gaussian_pulse, pulse.drive_channel(0))
        pulse.play(gaussian_pulse, pulse.drive_channel(1))
        pulse.play(gaussian_pulse, pulse.drive_channel(1))

program.draw()
[36]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_34_0.png

位相および周波数オフセット

このビルダーを使用すると、チャンネル上のパルスの周波数や位相を一時的に補正することができます。

[37]:
with pulse.build(backend, name='Offset example') as program:
    with pulse.phase_offset(3.14, pulse.drive_channel(0)):
        pulse.play(gaussian_pulse, pulse.drive_channel(0))
        with pulse.frequency_offset(10e6, pulse.drive_channel(0)):
            pulse.play(gaussian_pulse, pulse.drive_channel(0))

program.draw()
[37]:
../../_images/tutorials_circuits_advanced_06_building_pulse_schedules_36_0.png

詳細については、Pulse API reference を参照することをお勧めします。

[38]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright

Version Information

Qiskit SoftwareVersion
qiskit-terra0.22.3
qiskit-aer0.11.2
qiskit-ignis0.7.0
qiskit-ibmq-provider0.19.2
qiskit0.39.4
System information
Python version3.10.6
Python compilerGCC 11.3.0
Python buildmain, Nov 14 2022 16:10:14
OSLinux
CPUs4
Memory (Gb)3.7695083618164062
Thu Dec 22 18:42:20 2022 JST

This code is a part of Qiskit

© Copyright IBM 2017, 2022.

This code is licensed under the Apache License, Version 2.0. You may
obtain a copy of this license in the LICENSE.txt file in the root directory
of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.

Any modifications or derivative works of this code must retain this
copyright notice, and modified files need to carry a notice indicating
that they have been altered from the originals.