回路を構築する
パッケージバージョン
このページのコードは、以下の要件を使用して開発されました。 これらのバージョンまたはそれ以降のバージョンの使用を推奨します。
qiskit[all]~=2.3.0
このページでは、Qiskit SDKのQuantumCircuitクラスについて詳しく見ていきます。量子回路を作成するために使用できるより高度なメソッドも含まれています。
量子回路とは何か?
シンプルな量子回路は、量子ビットのコレクションと、それらの量子ビットに作用する命令のリストです。デモンストレーションのために、次のセルは2つの新しい量子ビットを持つ新しい回路を作成し、回路のqubits属性を表示します。これは、最下位ビットから最上位ビットまで順番に並んだQubitsのリストです。
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubits
[<Qubit register=(2, "q"), index=0>, <Qubit register=(2, "q"), index=1>]
複数のQuantumRegisterオブジェクトとClassicalRegisterオブジェクトを組み合わせて回路を作成できます。すべてのQuantumRegisterとClassicalRegisterには名前を付けることもできます。
from qiskit.circuit import QuantumRegister, ClassicalRegister
qr1 = QuantumRegister(2, "qreg1") # 2つの量子ビットを持つQuantumRegisterを作成
qr2 = QuantumRegister(1, "qreg2") # 1つの量子ビットを持つQuantumRegisterを作成
cr1 = ClassicalRegister(3, "creg1") # 3つの古典ビットを持つClassicalRegisterを作成
combined_circ = QuantumCircuit(
qr1, qr2, cr1
) # 2つのQuantumRegisterと1つのClassicalRegisterを持つ量子回路を作成
combined_circ.qubits
[<Qubit register=(2, "qreg1"), index=0>,
<Qubit register=(2, "qreg1"), index=1>,
<Qubit register=(1, "qreg2"), index=0>]
回路のfind_bitメソッドとその属性を使用して、量子ビットのインデックスとレジスターを見つけることができます。
desired_qubit = qr2[0] # レジスター 'qreg2' の量子ビット 0
print("Index:", combined_circ.find_bit(desired_qubit).index)
print("Register:", combined_circ.find_bit(desired_qubit).registers)
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]
回路に命令を追加すると、回路のdata属性に命令が追加されます。次のセル出力は、dataがCircuitInstructionオブジェクトのリストであり、それぞれがoperation属性とqubits属性を持つことを示しています。
qc.x(0) # 量子ビット0にXゲ ートを追加
qc.data
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(<Qubit register=(2, "q"), index=0>,), clbits=())]
この情報を表示する最も簡単な方法は、回路の可視化を返すdrawメソッドを使用することです。量子回路を表示するさまざまな方法については、回路の可視化を参照してください。
qc.draw("mpl")
回路命令オブジェクトには、より基本的な命令の観点から命令を記述する「定義」回路を含めることができます。たとえば、Xゲートは、より一般的な単一量子ビットゲートであるU3ゲートの特定のケースとして定義されています。
# `qc`の0番目の命令の定義回路を描画
qc.data[0].operation.definition.draw("mpl")
命令と回路は、どちらもビットと量子ビットの操作を記述するという点で似ていますが、異なる目的があります:
- 命令は固定として扱われ、そのメソッドは通常、新しい命令を返します(元のオブジェクトを変更しません)。
- 回路は、多くのコード行にわたって構築されるように設計されており、
QuantumCircuitメソッドは多くの場合、既存のオブジェクトを変更します。
回路の深さとは何か?
量子回路のdepth()は、並列実行される量子ゲートの「レイヤー」の数の尺度であり、回路によって定義される計算を完了するために必要です。量子ゲートの実装には時間がかかるため、回路の深さは、量子コンピューターが回路を実行するのにかかる時間にほぼ対応します。したがって、回路の深さは、量子回路がデバイスで実行できるかどうかを測定するために使用される重要な量の1つです。
このページの残りの部分では、量子回路を操作する方法を説明します。
回路を構築する
QuantumCircuit.hやQuantumCircuit.cxなどのメソッドは、特定の命令を回路に追加します。より一般的に回路に命令を追加するには、appendメソッドを使用します。これは、命令と、命令を適用する量子ビットのリストを取ります。サポートされている命令のリストについては、回路ライブラリAPIドキュメントを参照してください。
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # 新しいHGate命令
[0], # 量子ビット0に適用
)
qc.draw("mpl")
2つの回路を結合するには、composeメソッドを使用します。これは、別のQuantumCircuitとオプションの量子ビットマッピングのリストを受け入れます。
qc_a = QuantumCircuit(4)
qc_a.x(0)
qc_b = QuantumCircuit(2, name="qc_b")
qc_b.y(0)
qc_b.z(1)
# qc_aの量子ビット(0, 1)をqc_bの量子ビット(1, 3)にそれぞれ合成
combined = qc_a.compose(qc_b, qubits=[1, 3])
combined.draw("mpl")
また、回路を整理するために、回路を命令にコンパイルすることもできます。to_instructionメソッドを使用して回路を命令に変換し、他の命令と同様に別の回路に追加できます。次のセルで描画される回路は、前のセルで描画される回路と機能的に同等です。
inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")
回路がユニタリーである場合、to_gateメソッドを使用してGateに変換できます。Gateオブジェクトは、量子制御を追加するcontrolメソッドなど、いくつかの追加機能を持つ特定のタイプの命令です。
gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")
何が起こっているかを確認するには、decomposeメソッドを使用して、各命令をその定義に展開できます。
decomposeメソッドは新しい回路を返し、作用する回路を変更しません。
qc_a.decompose().draw("mpl")
量子ビットを測定する
測定は、個々の量子ビットの状態をサンプリングし、結果を古典レジスターに転送するために使用されます。Samplerプリミティブに回路を送信する場合、測定が必要であることに注意してください。ただし、Estimatorプリミティブに送信される回路には測定を含めてはいけません。
量子ビットは、3つのメソッドを使用して測定できます: measure、measure_all、measure_active。測定結果を可視化する方法については、結果の可視化ページを参照してください。
-
QuantumCircuit.measure: 最初の引数の各量子ビットを、2番目の引数として指定された古典ビットに測定します。このメソッドは、測定結果の保存場所を完全に制御できます。 -
QuantumCircuit.measure_all: 引数を取らず、事前定義された古典ビットのない量子回路に使用できます。古典ワイヤーを作成し、測定結果を順番に保存します。たとえば、量子ビットの測定は古典ビットに保存されます。また、測定の前にバリアを追加します。 -
QuantumCircuit.measure_active:measure_allと似ていますが、操作がある量子ビットのみを測定します。
qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)
qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)
qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)
パラメータ化された回路
多くの近期量子アルゴリズムは、量子回路の多くのバリエーションを実行することを含みます。大規模な回路の構築と最適化は計算コストが高くなる可能性があるため、Qiskitはパラメータ化された回路をサポートしています。これらの回路には未定義のパラメータがあり、その値は回路を実行する直前まで定義する必要がありません。これにより、回路の構築と最適化をメインプログラムループの外に移動できます。次のセルは、パラメータ化された回路を作成して表示します。
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.circuit import Parameter
angle = Parameter("angle") # 未定義の数値
# 回路を一度作成して最適化
qc = QuantumCircuit(1)
qc.rx(angle, 0)
qc = generate_preset_pass_manager(
optimization_level=3, basis_gates=["u", "cx"]
).run(qc)
qc.draw("mpl")
次のセルは、この回路の多くのバリエーションを作成し、バリエーションの1つを表示します。
circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))
circuits[0].draw("mpl")
回路の未定義パラメータのリストは、そのparameters属性で見つけることができます。
qc.parameters
ParameterView([Parameter(angle)])
パラメータ名を変更する
デフォルトでは、パラメータ化された回路のパラメータ名にはxがプレフィックスとして付けられます。たとえば、x[0]です。次の例に示すように、定義後に 名前を変更できます。
from qiskit.circuit.library import z_feature_map
from qiskit.circuit import ParameterVector
# デフォルト名を持つパラメータ化された回路を定義
# たとえば、x[0]
circuit = z_feature_map(2)
# 新しいパラメータ名を設定
# これらは代わりに`hi`というプレフィックスが付けられます
# たとえば、hi[0]
training_params = ParameterVector("hi", 2)
# 量子回路にパラメータ名を割り当てる
circuit = circuit.assign_parameters(parameters=training_params)
次のステップ
- 近期量子アルゴリズムについて学ぶには、変分アルゴリズム設計コースを受講してください。
- Groverのアルゴリズムチュートリアルで回路の使用例を参照してください。
- IBM Quantum Composerを使用してシンプルな回路を操作してください。