はじめに
Qiskitには、パルスを扱うモジュールが存在しています。そのモジュールに最近ビルダープログラミングモデル(Builder構文)が導入されました。この記事ではその新しいプログラムの書き方を紹介していきたいと思います。
まず、Qiskit Pulseを動かすために必要な記述をまとめておきます。
import numpy as np
from qiskit import QuantumCircuit, transpile, Aer, IBMQ
from qiskit.visualization import *
IBMQ.load_account()
provider = IBMQ.get_provider(hub='ibm-q', group='open', project='main')
backend = provider.get_backend('ibmq_armonk')
backend_defaults = backend.defaults()
backend_config = backend.configuration()
従来の書き方
最初に従来の書き方をみていきたいと思います。対象は1量子ビットです。パルスを定義するためにはScheduleクラスを生成する必要があります。
from qiskit import pulse
from qiskit.pulse import DriveChannel
from qiskit.pulse import Play
from qiskit.pulse import Schedule
qubit=0
# 1 パルスの定義
drive_pulse = pulse.Gaussian(duration=300,
sigma=80,
amp=1.0,
name='sample gaussian')
# 2 チャネルの指定
drive_chan = pulse.DriveChannel(qubit)
# 3 測定パルスの定義
inst_sched_map = backend_defaults.instruction_schedule_map
measure = inst_sched_map.get('measure', qubits=backend_config.meas_map[0])
# 4 スケジュールを作成
schedule = pulse.Schedule(name='Sample')
schedule += Play(drive_pulse, drive_chan)
schedule += measure << schedule.duration
- パルスの定義
実験に使用するパルスを定義します。ここではGaussianパルスの駆動パルスを定義しています。 - チャネルの指定
パルスを適用するチャネルを指定します。この例では駆動チャネルを定義しており、これは量子ビットのIDによってインデックス化されます。 - 測定パルスの定義
自分で定義することはできますが、ここではバックエンドのデフォルトの命令スケジュールマップからキャリブレーション済みの測定パルスを取得します。 - スケジュールの作成
Scheduleクラスを生成し、Playを利用して、駆動パルスを駆動チャネルで動かすことを定義します。その後measureの実行を、スケジュールの開始時刻をある期間だけシフトする<<
を利用して、Playで定義したパルス分だけシフトして定義しています。
新しい書き方(Builder構文)
従来の書き方だと、上記の通り<<
を利用してパルスの順番を定義するなどプログラム構文を直接処理してパルスのフローを記述しています。これだとプログラム表現(データ)をプログラミング構文(コード)から分離することができていませんでした。
新しい書き方ではPythonのwith構文を利用し、その課題を解決できるようになっています。
from qiskit import pulse
GHz = 1.0e9 # Gigahertz
mem_slot=0
freq_GHz=4.95
freq=freq_GHz*GHz
# 1 Builder構文の定義
with pulse.build(backend) as sample_sched:
# 2 フローの定義
with pulse.align_sequential():
# 3 周波数の定義
pulse.set_frequency(freq, pulse.drive_channel(qubit))
pulse.play(pulse.Gaussian(duration=320,
amp=1.0,
sigma=80,
name='sample gaussian'),
pulse.drive_channel(qubit))
# 4 測定パルスの定義
pulse.measure(qubits=[qubit], registers=[pulse.MemorySlot(mem_slot)])
-
Builder構文の定義
Pythonのwith構文を使ってBuilderを定義します。パルスプログラミングを開始するには、最初にビルダー構文をbuild()
で初期化する必要があります。https://qiskit.org/documentation/stubs/qiskit.pulse.builder.build.html#qiskit.pulse.builder.build
-
フローの定義
ここではalign_sequential()
を利用してパルスのスケジュールをシーケンシャルに実行するように宣言しています。この場合align_sequential()
がないと、後続のGaussianパルスとmeasureパルスが同時に実行されることになります。他にもalign_left()
、align_right()
が提供されており自由に組み合わせることで多彩なパルスのフローを設定することができます。また下記のようにdefault_alignment
の値をsequential
とすることでも同じような設定となります。with pulse.build(backend=backend, default_alignment='sequential', name='sample') as sample_sched:
-
周波数の定義
set_frequency()
を利用して周波数を定義します。 -
測定パルスの定義
従来の書き方ではバックエンドのデフォルトの命令スケジュールマップからキャリブレーション済みの測定パルスを取得しましたが、この例のように書くことも可能です。アクティブなビルダー構文内の量子ビットを測定します。パルスレベルでは、測定はパルスと、システム測定ユニットにデータを取得して処理するように指示する取得命令の両方で構成されます。measure()
は、プロセスを自動化するために提供されていますが、必要に応じて、acquire()
およびplay()
を使用して完全に制御することもできます。
便利な機能の紹介
横軸は時間、縦軸はパルスを表していてD0は駆動パルス、M0は測定パルスを表現しています。(0は一つ目)まずは周波数が設定されその後、フロー通りGaussianパルスとmeasureパルスが実行されるスケジュールになっていることが分かります。ここでdraw()
にbackendを渡していますがこれはどのbackendを利用するか分からないので必要です。なにも指定しない場合dt
という内部データを利用した値でパルスが表示されます。
-
パルス設定表示
instructions
を使えば自分が定義したフローを上記とは違った見方で確認できます。自分が指定した内容が一覧で閲覧できるので便利です。sample_sched.instructions
まとめ
この記事ではBuilder構文について紹介しました。他にもいろいろ新しい機能が提供されているので紹介していきたいと思います。