注釈
当ページは tutorials/circuits_advanced/06_building_pulse_schedules.ipynb から生成されました。
IBM Quantum lab でインタラクティブに実行します。
Pulseスケジュールの構築¶
パルス・プログラムは、Schedule
と呼ばれ、制御エレクトロニクスの命令シーケンスを記述します。 Pulse Builder を使用して Schedule
を作成します。スケジュールを初期化するのは簡単です:
[1]:
from qiskit import pulse
with pulse.build(name='my_example') as my_program:
# Add instructions here
pass
my_program
[1]:
Schedule(, name="my_example")
命令がまだないことがわかります。 このページの次のセクションでは、スケジュールに追加する各命令について説明します。 そして最後のセクションでは、さまざまな 配置コンテキスト について説明します。これにより、命令が互いに相対的にどのように時間内に配置されるかが決まります。
``Schedule``命令¶
各命令タイプは、独自のオペランドセットを持ちます。上記のように、それぞれに少なくとも1つの Channel
が含まれており、命令の適用先を特定しています。
Channels は、制御ハードウェアから量子チップへの信号線のラベルです。
DriveChannel
は通常、単一量子ビットの回転を ドライブ するのに使用されます。ControlChannel
は通常、複数量子ビットゲートや、調整可能な量子ビットの追加ドライブ線に使用されます。MeasureChannel
は、読み出しを促す送信パルスに特化しています。AcquireChannel
は、読み出し信号を収集するデジタイザーをトリガーするために使用されます。
DriveChannel
、 ControlChannel
、 MeasureChannel
は、すべて PulseChannel
です。これは、これらが 送信 パルスをサポートしていることを意味します。一方、 AcquireChannel
は受信チャンネルのみであり、波形を出すことはできません。
以下の例では、PulseChannel
を受け取る Instruction
ごとに、ひとつの DriveChannel
インスタンスを生成しています。チャンネルは、ひとつの数値 index
引数を取ります。 `` ControlChannel`` を除き、インデックスが量子ビットラベルにマッピングされるのは自明です。
[2]:
from qiskit.pulse import DriveChannel
channel = DriveChannel(0)
The pulse Schedule
is independent of the backend it runs on. However, we can build our program in a context that is aware of the target backend by supplying it to pulse.build
. When possible you should supply a backend. By using the channel accessors pulse.<type>_channel(<idx>)
we can make sure we are only using available device resources.
[3]:
from qiskit.test.mock 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
命令を追加するには、期間とチャンネルを渡します。ここで、channel
は AcquireChannel
を含む任意の種類のチャンネルになります。 Pulse Builder コンテキストを開始するには pulse.build
を使用します。これにより、スケジュール delay_5dt
に遅延が自動的にスケジュールされます。
[4]:
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
は、任意のパルス エンベロープ を指定します。出力波形の変調周波数と位相は、次に説明する setFrequency
と shiftPhase
命令によって制御されます。
以下の画像は、なぜそれらが個別に指定されているかを直感的に示しています。一般的な研究機器である任意波形発生器 (arbitrary waveform generator、AWG) への入力として、エンベロープを表すパルスを考えてください。これは左の画像に示されています。制限されたサンプルレートが信号を区別していることに注意してください。AWGによって生成された信号は、連続正弦波ジェネレータと混合されます。その出力の周波数は、正弦波発生器への指示によって制御されます。中央の画像を参照してください。最後に、量子ビットに送信された信号は、下の画像の右側に示されています。
注記 :ハードウェアは他の方法で実装することもできますが、命令を別々にしておけば、変調周波数の値などの明示的な情報が失われるのを回避できます。

パルスを構築するために利用できる方法は多くあります。Qiskit Pulse 内の library
には、 Pulse
を構築するための便利なメソッドが含まれています。たとえば、単純なガウスパルス、つまりサンプリングされたガウス関数によって記述されたエンベロープを持つパルスを考えてみましょう。振幅1、標準偏差10 \(\sigma\) 、および128サンプルポイントを任意に選択します。
注記:振幅ノルムは 1.0
に制限されています。個々のバックエンドシステムは、更なる制約、例えば最小パルスサイズは64など、も課しています。これらの追加の制約は、利用可能な場合、 ここ で説明する BackendConfiguration
を通じて提供されます。
[5]:
from qiskit.pulse import library
amp = 1
sigma = 10
num_samples = 128
パラメトリック・パルス¶
Gaussian
パラメトリック・パルスを使用してガウスパルスを作成してみましょう。パラメトリック・パルスは、個々のサンプルごとではなく、関数の名前とそのパラメーターをバックエンドに送信します。 パラメトリック・パルスを使用すると、バックエンドに送信するジョブがはるかに小さくなります。 IBM Quantum バックエンドは、それらが受け入れる最大ジョブサイズを制限するため、パラメトリック・パルスを使うことで、より大きなプログラムを実行できる場合があります。
library
の他のパラメトリック・パルスには、GaussianSquare
、 Drag
、および Constant
が含まれます。
注記 :バックエンドには、パラメトリック・パルスをサンプリングする方法を正確に決定する責任があります。パラメトリック・パルスを描画することは可能ですが、表示されるサンプルがバックエンドで実行されたものと同じであるとは限りません。
[6]:
gaus = pulse.library.Gaussian(num_samples, amp, sigma,
name="Parametric Gaus")
gaus.draw()
[6]:

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

パルス・ライブラリー関数¶
独自のパルス・ライブラリーには、一般的な関数から Waveform
を作成するためのサンプリング・メソッドがあります。
[8]:
gaus = library.gaussian(duration=num_samples, amp=amp, sigma=sigma, name="Lib Gaus")
gaus.draw()
[8]:

pulse
を指定する方法に関係なく、play
は同じ方法でスケジュールに追加されます:
[9]:
with pulse.build() as schedule:
pulse.play(gaus, channel)
schedule.draw()
[9]:

You may also supply a complex list or array directly to play
[10]:
with pulse.build() as schedule:
pulse.play([0.001*i for i in range(160)], channel)
schedule.draw()
[10]:

play
命令は、Pulse
から期間を取得します。パラメーター化されたパルスの期間は明示的な引数であり、``Waveform``の期間は入力サンプルの数です。
set_frequency
¶
As explained previously, the output pulse waveform envelope is also modulated by a frequency and phase. Each channel has a default frequency listed in the backend.defaults().
チャンネルの周波数は、 set_frequency
命令により Schedule
内でいつでも更新できます。浮動小数点の frequency
と PulseChannel
channel
を入力として受け取ります。 set_frequency
命令に続くチャンネル上のすべてのパルスは、別の set_frequency
命令が検出されるまで、またはプログラムが終了するまで、指定された周波数で変調されます。
命令の暗黙の期間は 0
です。
注記 :要求できる周波数は、各ハードウェア・チャンネルの合計帯域幅と瞬時帯域幅によって制限されます。将来的には、これらは backend
によって報告されます。
[11]:
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
です。
[12]:
with pulse.build(backend) as schedule:
pulse.shift_phase(np.pi, channel)
## acquire¶
acquire
命令は、読み出しのためのデータ取得をトリガーします。 それは、持続時間、測定されている量子ビットにマップする AcquireChannel
および、 MemorySlot
または RegisterSlot
を必要とします。 MemorySlot
は、読み出し結果が保存される古典的なメモリです。 RegisterSlot
は、高速フィードバックのための読み出し結果を保存する制御電子回路のレジスタにマッピングします。
acquire
命令は、キーワード引数としてカスタム``Discriminator``と``Kernel``を取ることもできます。
[13]:
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 を参照してください。
Alignment contexts¶
ビルダーは、スケジュールの構築方法に影響する配置コンテキストを持ちます。 コンテキストを入れ子にすることもできます。それらを試し、.draw()
を使用してパルスがどのように配置されるかを確認してください。
配置コンテキストに関係なく、結果のスケジュールの長さは、すべての命令を含め配置ルールに従うのと同等くらい短いです。これにより、「最も長いパス」から命令をスケジュールするある程度の自由度があります。以下の例ではこれを示しています。
align_left
¶
ビルダーはスケジュールの構築方法に影響する配置コンテキストを持っています。デフォルトは align_left
です。
[14]:
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()
[14]:

D1
上のパルスにはスケジューリングの自由度がないことに注意してください。2 番目の波形は最初の波形の直後に始まります。 D0
上のパルスは、スケジュール全体の期間を変更することなく、t=0
と t=100
の間でいつでも開始できます。 align_left
コンテキストでは、パルスの開始時刻を t=0
に設定します。これはテキスト文書の左揃えのように考えることができます。
align_right
¶
当然、align_right
は align_left
の反対です。D0
上でガウスパルスを開始する上記の例では t=100
を選択します。 左と右は、それぞれ「できるだけ早く」と「できるだけ遅く」スケジューリングとも呼ばれることがあります。
[15]:
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()
[15]:

align_equispaced(duration)
¶
特定のブロックの期間がわかっている場合は、 align_equispace
を使って各命令の間に同じ長さの遅延を挿入することもできます。
[16]:
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()
[16]:

align_sequential
¶
この配置コンテキストは、並列に命令をスケジュールしません。各命令は、以前に追加した命令の最後に開始されます。
[17]:
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()
[17]:

Phase and frequency offsets¶
このビルダーを使用すると、チャンネル上のパルスの周波数や位相を一時的に補正することができます。
[18]:
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()
[18]:

詳細については、Pulse API reference を参照することをお勧めします。
[19]:
import qiskit.tools.jupyter
%qiskit_version_table
%qiskit_copyright
/Users/thomas/opt/anaconda3/envs/qiskit-3.8/lib/python3.8/site-packages/qiskit/aqua/operators/operator_globals.py:48: DeprecationWarning: `from_label` is deprecated and will be removed no earlier than 3 months after the release date. Use Pauli(label) instead.
X = make_immutable(PrimitiveOp(Pauli.from_label('X')))
Version Information
Qiskit Software | Version |
---|---|
Qiskit | 0.23.6 |
Terra | 0.17.0 |
Aer | 0.7.5 |
Ignis | 0.5.2 |
Aqua | 0.8.2 |
IBM Q Provider | 0.11.1 |
System information | |
Python | 3.8.5 (default, Aug 5 2020, 03:39:04) [Clang 10.0.0 ] |
OS | Darwin |
CPUs | 8 |
Memory (Gb) | 32.0 |
Sat Feb 27 11:04:23 2021 AST |
This code is a part of Qiskit
© Copyright IBM 2017, 2021.
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.