回路を構成する
このページのコードは、以下の要件に基づいて開発された。 これらのバージョンまたは新しいバージョンの使用をお勧めします。
qiskit[all]~=2.5.1
このページではQiskit SDKの QuantumCircuit クラスについて詳しく見ていきます。
量子回路とは何か?
単純な量子回路は、量子ビットの集まりと、それらの量子ビットに作用する命令のリストである。 次のセルは、2つの新しい量子ビットを持つ新しい回路を作成し、その回路の qubits 属性を表示する。 Qubits を最下位ビット から最上位ビット の順に表示します。
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.qubitsOutput:
[<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") # Create a QuantumRegister with 2 qubits
qr2 = QuantumRegister(1, "qreg2") # Create a QuantumRegister with 1 qubit
cr1 = ClassicalRegister(3, "creg1") # Create a ClassicalRegister with 3 cbits
combined_circ = QuantumCircuit(
qr1, qr2, cr1
) # Create a quantum circuit with 2 QuantumRegisters and 1 ClassicalRegister
combined_circ.qubitsOutput:
[<Qubit register=(2, "qreg1"), index=0>,
<Qubit register=(2, "qreg1"), index=1>,
<Qubit register=(1, "qreg2"), index=0>]
量子ビットのインデックスとレジスタは、回路の find_bit メソッドとその属性を使用します。
desired_qubit = qr2[0] # Qubit 0 of register 'qreg2'
print("Index:", combined_circ.find_bit(desired_qubit).index)
print("Register:", combined_circ.find_bit(desired_qubit).registers)Output:
Index: 2
Register: [(QuantumRegister(1, 'qreg2'), 0)]
回路に命令を追加すると、その命令が回路の data 属性に追加されます。 次のセル出力は、 data がオブジェクトのリストであることを示している。 CircuitInstruction オブジェクトのリストであり、各オブジェクトは operation 属性と qubits 属性を持つ。
qc.x(0) # Add X-gate to qubit 0
qc.dataOutput:
[CircuitInstruction(operation=Instruction(name='x', num_qubits=1, num_clbits=0, params=[]), qubits=(<Qubit register=(2, "q"), index=0>,), clbits=())]
この情報を確認する最も簡単な方法は、回路の可視化結果を返す draw メソッドを使用することです。 量子回路の表示方法については、 「回路の可視化」 をご覧ください。
qc.draw("mpl")Output:
回路命令オブジェクトは、より基本的な命令の観点から命令を記述する "定義 "回路を含むことができる。 例えば、 Xゲートは、より一般的な単一量子ビット・ゲートである U3-gate より一般的な単一量子ビット・ゲートである。
# Draw definition circuit of 0th instruction in `qc`
qc.data[0].operation.definition.draw("mpl")Output:
命令と回路は、どちらもビットや量子ビットに対する操作を記述するという点では似ているが、その目的は異なる:
- 命令は固定されたものとして扱われ、そのメソッドは通常、(元のオブジェクトを変異させることなく)新しい命令を返す。
- 回路は何行にもわたって構築されるように設計されている。
QuantumCircuitメソッドはしばしば既存のオブジェクトを変更する。
回路深さとは何か?
量子回路の深さ(depth())とは、その回路で定義された計算を完了するために必要な量子ゲートの「層」の数を示す尺度である。 量子ゲートの実装には時間がかかるため、回路の深さは量子コンピューターが回路を実行するのにかかる時間にほぼ対応する。 したがって、回路の深さは、量子回路がデバイス上で実行可能かどうかを測定するために使用される重要な量の1つである。
このページの残りの部分では、量子回路の操作方法を説明する。
回路を構築する
などの方法がある。 QuantumCircuit.h や QuantumCircuit.cx などのメソッドは、回路に特定の命令を追加する。 より一般的に回路に命令を追加するには append メソッドを使います。 これは命令と、命令を適用する量子ビットのリストを受け取る。 サポートされている命令のリストについては、 Circuit Library API documentationを参照のこと。
from qiskit.circuit.library import HGate
qc = QuantumCircuit(1)
qc.append(
HGate(), # New HGate instruction
[0], # Apply to qubit 0
)
qc.draw("mpl")Output:
つの回路を組み合わせるには 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)
# compose qubits (0, 1) of qc_a to qubits (1, 3) of qc_b respectively
combined = qc_a.compose(qc_b, qubits=[1, 3])
combined.draw("mpl")Output:
また、回路を整理しておくために、回路をインストラクションにまとめるのもよいだろう。 メソッドを使って回路を命令に変換することができる。 to_instruction メソッドを使用して回路を命令に変換し、他の命令と同じようにこれを別の回路に追加します。 次のセルに描かれた回路は、前のセルに描かれた回路と機能的に等価である。
inst = qc_b.to_instruction()
qc_a.append(inst, [1, 3])
qc_a.draw("mpl")Output:
回路がユニタリーの場合、それを Gate に変換できます。 to_gate メソッドを使用します。 Gate オブジェクトは、量子制御を追加するメソッドなど、いくつかの追加機能を持つ特定のタイプの命令である。 control メソッドのような、量子制御を追加する特別な機能を持つ特定のタイプの命令である。
gate = qc_b.to_gate().control()
qc_a.append(gate, [0, 1, 3])
qc_a.draw("mpl")Output:
何が起こっているかを見るには decompose メソッドを使って各命令をその定義に展開することができる。
この decompose メソッドは新しい回路を返し、それが作用する回路を変更しない。
qc_a.decompose().draw("mpl")Output:
量子ビットを測定する
測定は、個々の量子ビットの状態をサンプリングし、その結果を古典的なレジスタに転送するために用いられる。 なお、 Sampler プリミティブに回路を送信する場合は、測定値の指定が必須となります。 ただし、 Estimator プリミティブに渡される回路には、測定値を含めてはなりません。
量子ビットの測定には、次の3つの方法がある: measure、 measure_all および measure_active。 測定結果の表示方法については、 「結果の表示」 ページをご覧ください。
-
QuantumCircuit.measureこれは、第一引数の各クォビットを、第二引数として与えられた古典ビットの上で測定する。 この方法では、測定結果の保存場所を完全にコントロールすることができる。 -
QuantumCircuit.measure_allこれは引数を取らず、あらかじめ定義された古典ビットを持たない量子回路に使用できる。 古典的なワイヤーを作成し、測定結果を順番に保存する。 例えば、qubit の測定値は cbit に格納される。)また、測定の前にバリアが追加される。 -
QuantumCircuit.measure_activemeasure_allと似ているが、演算を持つ量子ビットだけを測定する。
qc1 = QuantumCircuit(2, 2)
qc1.measure(0, 1)
qc1.draw("mpl", cregbundle=False)Output:
qc2 = QuantumCircuit(2)
qc2.measure_all()
qc2.draw("mpl", cregbundle=False)Output:
qc3 = QuantumCircuit(2)
qc3.x(1)
qc3.measure_active()
qc3.draw("mpl", cregbundle=False)Output:
パラメータ化回路
近い将来の量子アルゴリズムの多くは、量子回路の多くのバリエーションを実行することになる。 大規模な回路の構築と最適化には計算コストがかかるため、Qiskitはパラメータ化された回路をサポートしています。 これらの回路には未定義のパラメータがあり、その値は回路を実行する直前まで定義する必要はない。 これにより、回路の構築と最適化をメイン・プログラムのループから外すことができる。 次のセルはパラメータ化された回路を作成し、表示する。
from qiskit.transpiler import generate_preset_pass_manager
from qiskit.circuit import Parameter
angle = Parameter("angle") # undefined number
# Create and optimize circuit once
qc = QuantumCircuit(1)
qc.rx(angle, 0)
qc = generate_preset_pass_manager(
optimization_level=3, basis_gates=["u", "cx"]
).run(qc)
qc.draw("mpl")Output:
次のセルは、この回路の多くのバリエーションを作り、そのうちの1つを表示する。
circuits = []
for value in range(100):
circuits.append(qc.assign_parameters({angle: value}))
circuits[0].draw("mpl")Output:
回路の未定義パラメータのリストは、 parameters アトリビュートにあります。
qc.parametersOutput:
ParameterView([Parameter(angle)])
パラメータの名前を変更する
デフォルトでは、パラメータ化された回路のパラメータ名には接頭辞 x「-」が付与されます。例えば、 x[0]. 定義後に名前を変更できます。次の例に示すように。
from qiskit.circuit.library import z_feature_map
from qiskit.circuit import ParameterVector
# Define a parameterized circuit with default names
# For example, x[0]
circuit = z_feature_map(2)
# Set new parameter names
# They will now be prefixed by `hi` instead
# For example, hi[0]
training_params = ParameterVector("hi", 2)
# Assign parameter names to the quantum circuit
circuit = circuit.assign_parameters(parameters=training_params)次のステップ
- 近い将来の量子アルゴリズムについて学ぶには、 変分アルゴリズム設計コースを受講してください。
- Grover's Algorithmのチュートリアルで使用されている回路の例をご覧ください。
- IBM Quantum Composer を使って簡単な回路を作る。