# 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) $\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
• Parametric state

• 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

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 $|00\cdots 0\rangle$ 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., $|10\rangle$ 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 $|00\cdots 0\rangle$ state.

from quri_parts.core.state import quantum_state, ComputationalBasisStatecb_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 Xprint("(ComputationalBasisState)")# Bitsprint("bits:", bin(cb_state.bits))# Phaseprint("phase:", cb_state.phase)# Create a new state with a Pauli gate appliedpauli_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 QuantumCircuitcircuit = 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 CNOTprint("(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 ComputationalBasisStates using comp_basis_superposition. The output will be a GeneralCircuitQuantumState. In QURI Parts, the superposition of 2 computational basis states $|s_0\rangle$ and $|s_1\rangle$ is defined as $|\psi\rangle = \cos \theta | s_0\rangle + \sin \theta e^{i\phi}| s_1\rangle$

from math import pifrom quri_parts.core.state import comp_basis_superpositionnew_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 QuantumStateVectorimport numpy as npcircuit = 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
info

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.

info

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