メインコンテンツまでスキップ

量子状態

量子状態は量子コンピューティングにおいて重要な要素です。QURI Partsでの標準的な使い方についてここで説明します。

前提条件

このチュートリアルで使用するQURI Partsモジュール: quri-parts-circuit,quri-parts-core

以下のようにインストールすることができます:

!pip install quri-parts

量子状態クラスとquantum_state関数の一覧

QURI Partsの量子状態クラスの一覧です:

  • ComputationalBasisState (source)
  • GeneralCircuitQuantumState (source)
  • QuantumStateVector (source)
  • ParametricCircuitQuantumState (source)
  • ParametricQuantumStateVector (source)

名前の通り、各々のクラスは量子状態を記述する独自の方法を持っています。それらがどのように働くのかをみてみましょう。最後の二つの状態はパラメータ付き回路を内部で使っているため説明しません。パラメータ付き回路状態に関するチュートリアルを参照してください。

量子状態を自動で構築してくれるquantum_state関数があるため、量子状態クラスの全ての名前を覚える必要はありません。quantum_state関数は量子ビットの数と、キーワード引数として(bits,circuit,vector)のサブセットをとります。ここでは、異なる入力の組み合わせの出力タイプを並べます。

  • パラメータなし状態:

    • quantum_state(n_qubits) \rightarrow ComputationalBasisState
    • quantum_state(n_qubits, bits) \rightarrow ComputationalBasisState
    • quantum_state(n_qubits, circuit) \rightarrow GeneralCircuitQuantumState
    • quantum_state(n_qubits, vector) \rightarrow QuantumStateVector
    • quantum_state(n_qubits, bits, circuit) \rightarrow GeneralCircuitQuantumState
    • quantum_state(n_qubits, vector, circuit) \rightarrow QuantumStateVector
  • パラメータ付き状態

    • quantum_state(n_qubits, parametric_circuit) \rightarrow ParametricCircuitQuantumState
    • quantum_state(n_qubits, bits, parametric_circuit) \rightarrow ParametricCircuitQuantumState
    • quantum_state(n_qubits, vector, parametric_circuit) \rightarrow ParametricQuantumStateVector

次に、これら全ての量子状態オブジェクトを紹介します。

CircuitQuantumState

CircuitQuantumStateは、000|00\cdots 0\rangle状態を回路に適用させることによって生成される量子状態を表現するクラスのためのインターフェースです。 ComputationalBasisStateGeneralCircuitQuantumStateCircuitQuantumStateの具体的なインスタンスです。

ComputationalBasisState (計算基底状態)

ComputationalBasisStateは計算基底状態を表します。n_qubitsbitsを含み、intphaseで表現されます。計算状態を設定するbitsキーワードはリトルエンディアンの慣例に従っていることに注意してください。例えば、状態bits = 0b10は、00番目の量子ビット計算基底の状態が0011番目の量子ビットが11の計算基底状態を表しており、例えば、状態10|10\rangle(QURI Partsでは00番目の量子ビットが右にきます)の計算基底状態は、状態000|00\cdots 0\rangleにパウリゲートを適用させた結果として与えられた状態としても考えられます。

from quri_parts.core.state import quantum_state, ComputationalBasisState

cb_state = quantum_state(5, bits=0b10101)
print(cb_state)

# Or equivalently:
# cb_state = ComputationalBasisState(5, bits=0b10101)
# output
ComputationalBasisState(qubit_count=5, bits=0b10101, phase=0π/2)

ComputationalBasisStateはいくつかのプロパティとメソッドを持っています:

from quri_parts.circuit import X

print("(ComputationalBasisState)")

# Bits
print("bits:", bin(cb_state.bits))
# Phase
print("phase:", cb_state.phase)
# Create a new state with a Pauli gate applied
pauli_added_state = cb_state.with_pauli_gate_applied(X(0))
print("new state:\n", pauli_added_state)
# output
(ComputationalBasisState)
bits: 0b10101
phase: 0.0
new state:
ComputationalBasisState(qubit_count=5, bits=0b10100, phase=0π/2)

GeneralCircuitQuantumState

量子回路オブジェクトを指定することで、GeneralCircuitQuantumStateを作成することができます。

from quri_parts.circuit import QuantumCircuit

circuit = QuantumCircuit(2)
circuit.add_Z_gate(0)
circuit.add_H_gate(1)

# A quantum state of 2 qubits with a given circuit (i.e. C|00> where C is the ciruict)
circuit_state = quantum_state(2, circuit=circuit)

# Or equivalently,
# from quri_parts.core.state import GeneralCircuitQuantumState
# circuit_state = GeneralCircuitQuantumState(2, circuit)

# A quantum state of 2 qubits with an empty circuit (i.e. |00>)
# circuit_state = GeneralCircuitQuantumState(2)

以前のセクションで紹介したComputationalBasisStateCircuitQuantumStateであることに注意してください。計算基底状態は、常にXゲートを00状態に適用することで構築することができるからです。

CircuitQuantumStateはいくつかのプロパティとメソッドを持っています:

from quri_parts.circuit import CNOT

print("(circuit_state)")

# Get how many qubits this state is for.
print("qubit_count:", circuit_state.qubit_count)
# Get the circuit of the state. This returns an immutable circuit.
print("circuit:", circuit_state.circuit)
# Create a new state with some new gates added.
gate_added_state = circuit_state.with_gates_applied([X(1), CNOT(1, 0)])
print("original circuit len:", len(circuit_state.circuit.gates))
print("new circuit len:", len(gate_added_state.circuit.gates))
# output
(circuit_state)
qubit_count: 2
circuit: <quri_parts.circuit.circuit.ImmutableQuantumCircuit object at 0x10d789370>
original circuit len: 2
new circuit len: 4

量子回路をComputationalBasisStateに適用させることで作成される状態はもはやComputationalBasisStateではなく一般的なGeneralCircuitQuantumStateであることに注意してください。

comp_basis_superpositionを使用すると、二つのComputationalBasisStateの重ね合わせを作成できます。出力はGeneralCircuitQuantumStateになります。QURI Partsでは、二つの計算基底状態s0|s_0\rangles1|s_1\rangleの重ねあわせはψ=cosθs0+sinθeiϕs1|\psi\rangle = \cos \theta | s_0\rangle + \sin \theta e^{i\phi}| s_1\rangle で定義されます。

from math import pi

from quri_parts.core.state import comp_basis_superposition

new_state = cb_state.with_gates_applied([CNOT(0, 1)])
print("new state:\n", new_state)

cb_state1 = quantum_state(2, bits=0b00)
cb_state2 = quantum_state(2, bits=0b11)

superposition_state = comp_basis_superposition(cb_state1, cb_state2, theta=-pi/4, phi=0.0)
print("superposition state circuit:\n", superposition_state.circuit.gates)
# output
new state:
GeneralCircuitQuantumState(n_qubits=5, circuit=<quri_parts.circuit.circuit.ImmutableQuantumCircuit object at 0x1079e3c70>)
superposition state circuit:
(QuantumGate(name='PauliRotation', target_indices=(0, 1), control_indices=(), classical_indices=(), params=(1.5707963267948966,), pauli_ids=(1, 1), unitary_matrix=()), QuantumGate(name='RZ', target_indices=(0,), control_indices=(), classical_indices=(), params=(-1.5707963267948966,), pauli_ids=(), unitary_matrix=()))

QuantumStateVector

QuantumStateVectorは状態ベクトルで定義された状態を表し、適用する回路は任意です。

from quri_parts.core.state import QuantumStateVector
import numpy as np

circuit = QuantumCircuit(2, gates=[X(0)])

sv = quantum_state(2, vector=np.array([1.0, 0.0, 0.0, 0.0]), circuit=circuit)
# Or equivalently,
# sv = QuantumStateVector(2, [1.0, 0.0, 0.0, 0.0], circuit)

QuantumStateVectorもいくつかのプロパティを持っています:

print("(quantum state vector)")
# Get how many qubits this state is for.
print("qubit_count:", sv.qubit_count)
# Get the circuit of the state. This returns an immutable circuit.
print("circuit:", sv.circuit)
# Get the vector of the state.
print("vector:", sv.vector)
# Create a new state with some new gates added.
gate_added_state = sv.with_gates_applied([X(1), CNOT(1, 0)])
print("original circuit len:", len(sv.circuit.gates))
print("new circuit len:", len(gate_added_state.circuit.gates))
# output
(quantum state vector)
qubit_count: 2
circuit: <quri_parts.circuit.circuit.ImmutableQuantumCircuit object at 0x10d77e130>
vector: [1.+0.j 0.+0.j 0.+0.j 0.+0.j]
original circuit len: 1
new circuit len: 3
備考

QuantumStateVectorは回路を保持していますが、.vector属性は回路によって更新された状態ベクトルを返しません。更新されたものが欲しい場合は、quri-parts-qulacsモジュールのevaluate_state_to_vectorを使用することを考慮してください。さらに詳しいことはシミュレータ チュートリアルを参照してください。

備考

QURI Parsの量子状態のクラスは常にイミュータブルです。作成された量子状態オブジェクトは修正することができません。

回路を状態に適用

QURI Partsには、量子回路を既存の状態に適用するための便利なヘルパー関数apply_circuitが用意されています。自動的に正確な量子状態のタイプを変換します。

from quri_parts.core.state import apply_circuit
# Apply a circuit to a ComputationalBasisState.
new_state1 = apply_circuit(
QuantumCircuit(2, gates=[X(1)]), cb_state
) # GeneralCircuitQuantumState

# Apply a circuit to a GeneralCircuitQuantumState.
new_state2 = apply_circuit(
QuantumCircuit(2, gates=[X(1)]), circuit_state
) # GeneralCircuitQuantumState

# Apply a circuit to a QuantumStateVector.
new_state3 = apply_circuit(QuantumCircuit(2, gates=[X(1)]), sv) # QuantumStateVector