Quantum states
Quantum states are essential when working on quantum computing. Here we describe basic treatment of them in QURI Parts.
Prerequisite
QURI Parts modules used in this tutorial: quri-parts-circuit
and quri-parts-core
. You can install them as follows:
!pip install quri-parts
List of quantum state classes and the quantum_state
function
Here is the list of quantum states classes in QURI Parts:
- ComputationalBasisState (source)
- GeneralCircuitQuantumState (source)
- QuantumStateVector (source)
- ParametricCircuitQuantumState (source)
- ParametricQuantumStateVector (source)
As name suggests, each class has its own way to describe a quantum state. Let's see how we can work with them. The last two states will not be explaind in this tutorial since they use ParametricCircuit inside. Please refer to parametric circuits and states tutorial about them.
It is not necessary to remember all the names of the quantum state classes as we provide a quantum_state
function to construct them automatically. The quantum_state
function takes in the number of qubits as a positional argument and a subset of (bits
, circuit
, vector
) as keyword argument. Here, we list out the output type of quantum_state
with different input combinations.
-
Non-parametric state:
- quantum_state(n_qubits)
ComputationalBasisState
- quantum_state(n_qubits, bits)
ComputationalBasisState
- quantum_state(n_qubits, circuit)
GeneralCircuitQuantumState
- quantum_state(n_qubits, vector)
QuantumStateVector
- quantum_state(n_qubits, bits, circuit)
GeneralCircuitQuantumState
- quantum_state(n_qubits, vector, circuit)
QuantumStateVector
- quantum_state(n_qubits)
-
Parametric state
- quantum_state(n_qubits, parametric_circuit)
ParametricCircuitQuantumState
- quantum_state(n_qubits, bits, parametric_circuit)
ParametricCircuitQuantumState
- quantum_state(n_qubits, vector, parametric_circuit)
ParametricQuantumStateVector
- quantum_state(n_qubits, parametric_circuit)
Next, we start to introduce all of these quantum state objects.
CircuitQuantumState
CircuitQuantumState
is an interface for classes representing a quantum state generated by applying a circuit to state. ComputationalBasisState
and GeneralCircuitQuantumState
are the concrete instances of CircuitQuantumState
ComputationalBasisState
ComputationalBasisState
represents a computational basis state. It consists of n_qubits
, bits
represented as an int
, and phase
. Note that the bits
keyword that sets the computational state follows the little endian convention. For example, a state with bits = 0b10
represents a computational basis state with its zeroth qubit being 0 and first qubit being 1, i.e., state (in QURI Parts, zeroth qubit comes first to the right). A computational basis state can also be considered as a state given as a result of applying Pauli gates to state.
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
has some properties and methods:
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
You can create a CircuitQuantumState
with a quantum circuit object by 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)
Note that the ComputationalBasisState
we introduced in the previous section is also a CircuitQuantumState
, since such a state can always be constructed by applying a circuit to a zero state.
CircuitQuantumState
has some properties and methods:
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
Note that the state created by applying quantum circuit to a ComputationalBasisState
is no longer a ComputationalBasisState
but GeneralCircuitQuantumState
in general.
You can create the superposition of two ComputationalBasisState
s using comp_basis_superposition
. The output will be a GeneralCircuitQuantumState
. In QURI Parts, the superposition of 2 computational basis states and is defined as
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
represents a state defined by a state vector with an optional circuit to be applied.
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
also have some properties:
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
Although QuantumStateVector
holds a circuit, .vector
attribute does not return a state vector updated by the circuit. If you want to get an updated one, consider to use evaluate_state_to_vector
in quri-parts-qulacs
module. For more details, please refer to simulator tutorial.
Classes for quantum states in QURI Parts are always immutable; you cannot modify an already created quantum state object.
Apply circuit to state
QURI Parts provides a useful helper function: apply_circuit
for applying a quantum circuit to an existing state. It automatically returns the correct quantum state type.
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