OpenQASM 2 と Qiskit SDK
Package versions
このページのコードは、以下の要件を使用して開発されました。 これらのバージョン以降を使用することを推奨します。
qiskit[all]~=2.4.0
# Added by doQumentation — required packages for this notebook
!pip install -q qiskit
Qiskit SDK は、量子プログラムの OpenQASM 表現と QuantumCircuit クラスの間で変換するためのツールを提供しています。
OpenQASM 2 プログラムを Qiskit にインポートする
OpenQASM 2 プログラムを Qiskit にインポートする関数が 2 つあります。
ファイル名を受け取る qasm2.load() と、OpenQASM 2 プログラムを文字列として受け取る qasm2.loads() です。
import qiskit.qasm2
qiskit.qasm2.load(filename, include_path=('.',), include_input_directory='append', custom_instructions=(), custom_classical=(), strict=False)
qiskit.qasm2.loads(program, include_path=('.',), custom_instructions=(), custom_classical=(), strict=False)
詳細については、OpenQASM 2 Qiskit API を参照してください。
シンプルなプログラムのインポート
ほとんどの OpenQASM 2 プログラムでは、qasm2.load と qasm2.loads を引数一つで使用するだけで問題ありません。
例:OpenQASM 2 プログラムを文字列としてインポートする
qasm2.loads() を使用して、OpenQASM 2 プログラムを文字列として QuantumCircuit にインポートします:
import qiskit.qasm2
program = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0], q[1];
measure q -> c;
"""
circuit = qiskit.qasm2.loads(program)
circuit.draw()
┌───┐ ┌─┐
q_0: ┤ H ├──■──┤M├───
└───┘┌─┴─┐└╥┘┌─┐
q_1: ─────┤ X ├─╫─┤M├
└───┘ ║ └╥┘
c: 2/═══════════╩══╩═
0 1
例:OpenQASM 2 プログラムをファイルからインポートする
load() を使用して、OpenQASM 2 プログラムをファイルから QuantumCircuit にインポートします:
import qiskit.qasm2
circuit = qiskit.qasm2.load("myfile.qasm")
OpenQASM 2 ゲートを Qiskit ゲートにリンクする
デフォルトでは、Qiskit の OpenQASM 2 インポーターはインクルードファイル "qelib1.inc" を事実上の標準ライブラリとして扱います。
インポーターは、このファイルが OpenQASM 2 を定義したオリジナルの論文で説明されているゲートを正確に含むものとして扱います。
Qiskit は "qelib1.inc" 内のゲートを表現するために 回路ライブラリ の組み込みゲートを使用します。
プログラム内で手動の OpenQASM 2 gate 文によって定義されたゲートは、デフォルトでカスタムの Qiskit Gate サブクラス として構築されます。
インポーターが検出する特定の gate 文に対して使用する Gate クラスを指定することができます。
このメカニズムを使用して、追加のゲート名を「組み込み」として扱うこともできます。つまり、明示的な定義を必要としないということです。
"qelib1.inc" 以外の gate 文に対して使用するゲートクラスを指定すると、生成される回路は通常より効率的に扱えるようになります。
Qiskit SDK v1.0 以降、Qiskit の OpenQASM 2 エクスポーター(Qiskit 回路を OpenQASM 2 にエクスポートする を参照)は、"qelib1.inc" に実際よりも多くのゲートがあるかのように動作し続けています。
つまり、インポーターのデフォルト設定では、自身のエクスポーターによってエクスポートされたプログラムをインポートできない場合があります。
この問題を解決するには、レガシーエクスポーターとの連携に関する具体的な例 を参照してください。
この不整合は Qiskit のレガシーな動作であり、Qiskit の今後のリリースで解決される予定です。
カスタム命令に関する情報を OpenQASM 2 インポーターに渡すには、qasm2.CustomInstruction クラス を使用します。
このクラスには、順番に 4 つの必須情報があります:
- OpenQASM 2 プログラムで使用されるゲートの名前
- ゲートが受け取る角度パラメーター数
- ゲートが作用する量子ビット数
- ゲートの Python コンストラクタークラスまたは関数(量子ビットではなく、ゲートパラメーターを個別の引数として受け取る)
インポーターが特定のカスタム命令に一致する gate 定義を検出すると、そのカスタム情報を使用してゲートオブジェクトを再構築します。
カスタム命令の name に一致する gate 文が検出されたが、パラメーター数と量子ビット数の両方が一致しない場合、インポーターは QASM2ParseError を発生させ、提供された情報とプログラムの不一致を示します。
さらに、5 番目の引数 builtin をオプションで True に設定すると、OpenQASM 2 プログラム内で明示的に定義されていなくてもゲートが自動的に利用可能になります。
インポーターが組み込みのカスタム命令に対する明示的な gate 定義を検出した場合、それをエラーなく受け入れます。
上記と同様に、同じ名前の明示的な定義が提供されたカスタム命令と互換性がない場合、QASM2ParseError が発生します。
これは、古い OpenQASM 2 エクスポーターとの互換性や、ハードウェアの「基底ゲート」を組み込み命令として扱う特定の量子プラットフォームとの互換性に役立ちます。
Qiskit は、Qiskit の OpenQASM 2 エクスポート機能 のレガシーバージョンによって生成された OpenQASM 2 プログラムを扱うためのデータ属性を提供しています。
これは qasm2.LEGACY_CUSTOM_INSTRUCTIONS であり、qasm2.load() と qasm2.loads() の custom_instructions 引数として渡すことができます。
例:Qiskit のレガシーエクスポーターで作成されたプログラムをインポートする
この OpenQASM 2 プログラムは、"qelib1.inc" のオリジナルバージョンには含まれていないゲートを宣言なしで使用していますが、これらは Qiskit のライブラリの標準ゲートです。
qasm2.LEGACY_CUSTOM_INSTRUCTIONS を使用することで、Qiskit の OpenQASM 2 エクスポーターが以前使用していたゲートセットを使用するようインポーターに簡単に伝えることができます。
from qiskit import qasm2
program = """
OPENQASM 2.0;
include "qelib1.inc";
qreg q[4];
creg c[4];
h q[0];
cx q[0], q[1];
// 'rxx' is not actually in `qelib1.inc`,
// but Qiskit used to behave as if it were.
rxx(0.75) q[2], q[3];
measure q -> c;
"""
circuit = qasm2.loads(
program,
custom_instructions=qasm2.LEGACY_CUSTOM_INSTRUCTIONS,
)
例:OpenQASM 2 プログラムをインポートする際に特定のゲートクラスを使用する
Qiskit は一般に、OpenQASM 2 の gate 文の定義が Qiskit の標準ライブラリゲートと完全に対応するかどうかを検証することができません。
代わりに、Qiskit は提供された正確な定義を使用してカスタムゲートを選択します。
これは、組み込みの標準ゲートやユーザー定義のカスタムゲートを使用するよりも効率が低い場合があります。
特定のクラスで gate 文を手動で定義することができます。
from qiskit import qasm2
from qiskit.circuit import Gate
from qiskit.circuit.library import RZXGate
# Define a custom gate that takes one qubit and two angles.
class MyGate(Gate):
def __init__(self, theta, phi):
super().__init__("my", 1, [theta, phi])
custom_instructions = [
# Link the OpenQASM 2 name 'my' with our custom gate.
qasm2.CustomInstruction("my", 2, 1, MyGate),
# Link the OpenQASM 2 name 'rzx' with Qiskit's
# built-in RZXGate.
qasm2.CustomInstruction("rzx", 1, 2, RZXGate),
]
program = """
OPENQASM 2.0;
gate my(theta, phi) q {
U(theta / 2, phi, -theta / 2) q;
}
gate rzx(theta) a, b {
// It doesn't matter what definition is
// supplied, if the parameters match;
// Qiskit will still use `RZXGate`.
}
qreg q[2];
my(0.25, 0.125) q[0];
rzx(pi) q[0], q[1];
"""
circuit = qasm2.loads(
program,
custom_instructions=custom_instructions,
)
例:OpenQASM 2 プログラムに新しい組み込みゲートを定義する
引数 builtin=True を設定すると、カスタムゲートに関連する定義がなくても構いません。
from qiskit import qasm2
from qiskit.circuit import Gate
# Define a custom gate that takes one qubit and two angles.
class MyGate(Gate):
def __init__(self, theta, phi):
super().__init__("my", 1, [theta, phi])
custom_instructions = [
qasm2.CustomInstruction("my", 2, 1, MyGate, builtin=True),
]
program = """
OPENQASM 2.0;
qreg q[1];
my(0.25, 0.125) q[0];
"""
circuit = qasm2.loads(
program,
custom_instructions=custom_instructions,
)
カスタム古典関数を定義する
OpenQASM 2 には、ゲート引数に使用できる組み込みの古典関数がいくつか含まれています。
qasm2.load() と qasm2.loads() への custom_classical 引数と qasm2.CustomClassical クラスを使用することで、より多くの関数で言語を拡張することができます。
カスタム古典関数を定義するには、以下を提供する必要があります:
- OpenQASM 2 プログラムに表示される関数の名前
- 受け取る浮動小数点引数の数
- 関数を評価する呼び出し可能な Python オブジェクト
定義されたすべてのカスタム古典関数は、インポーターによって OpenQASM 2 言語の組み込み関数として扱われます。 OpenQASM 2 言語内で新しい関数を定義する公式な方法はありません。これは Qiskit の拡張機能です。
例:カスタム古典命令を使用する
ここでは 2 つのカスタム古典関数を提供します。
最初のものはシンプルで、入力に 1 を加えるだけです。
2 番目は math.atan2 関数で、四象限を考慮した方法で数学演算 を表します。
import math
from qiskit import qasm2
program = """
include "qelib1.inc";
qreg q[2];
rx(arctan(pi, 3 + add_one(0.2))) q[0];
cx q[0], q[1];
"""
def add_one(x):
return x + 1
customs = [
# Our `add_one` takes only one parameter.
qasm2.CustomClassical("add_one", 1, add_one),
# `arctan` takes two parameters, and `math.atan2` implements it.
qasm2.CustomClassical("arctan", 2, math.atan2),
]
circuit = qasm2.loads(program, custom_classical=customs)
ストリクトモード
デフォルトでは、このパーサーは公式仕様よりも緩やかです。
パラメーターリスト内のトレーリングカンマ、不要な(空文)セミコロン、OPENQASM 2.0; バージョン文の省略、その他いくつかの利便性の改善をエラーなしで許可しています。
ただし、strict=True を使用することで「仕様に厳密に従う」モードを使用することができます。
Qiskit 回路を OpenQASM 2 にエクスポートする
Qiskit は QuantumCircuit を OpenQASM 2 にエクスポートすることもできます。
ファイルに書き出すには qasm2.dump() 関数を、文字列に書き出すには qasm2.dumps() を使用します。
これらの関数は現在、非常にシンプルなインターフェースを持っており、回路を受け取り、qasm2.dump() の場合のみ出力先の場所も受け取ります。
Qiskit の OpenQASM 2 エクスポーターは、"qelib1.inc" インクルードファイルのレガシーな非標準バージョンを引き続き想定しています。
これは Qiskit の今後のリリースで解決される予定ですが、それまでの間、Qiskit で作成した OpenQASM 2 プログラムを再インポートする必要がある場合は、レガシーゲートについてインポーターに伝える方法の上記の例 を使用してください。
例:回路を OpenQASM 2 にエクスポートする
from qiskit import QuantumCircuit, qasm2
# Define any circuit.
circuit = QuantumCircuit(2, 2)
circuit.h(0)
circuit.cx(0, 1)
circuit.measure([0, 1], [0, 1])
# Export to a string.
program = qasm2.dumps(circuit)
# Export to a file.
qasm2.dump(circuit, "my_file.qasm")
次のステップ
- IBM Quantum Composer ガイドで OpenQASM コードを生成する方法を学びましょう。
- OpenQASM 2 Qiskit API リファレンスを参照してください。
- プログラムの検証 トピックを確認してください。
- OpenQASM Live Specification を訪問してください。