Skip to main content

Simulators

Sometimes when we assemble algorithms, it is useful to check whether or not the resulting state is consistent with our expectation. As the state is not something we have access to with experiment, we need to use a simulator to obtain the exact final output state. In QURI Parts, a simulator is any function that work with the explicit state vector or density matrices.

Qulacs simulators

In the quri_parts.qulacs.simulator module, we provide 3 simulator features for state vectors.

  • evaluate_state_to_vector
  • run_circuit
  • get_marginal_probability

We introduce their functionalities in the following sections.

evaluate_state_to_vector

evaluate_state_to_vector is a function that converts any non-parametric states into a QuantumStateVector with an empty circuit.

from quri_parts.qulacs.simulator import evaluate_state_to_vector
from quri_parts.core.state import quantum_state

Converts a ComputationalBasisState

For example, bits = 2 = 0b10 represents 10|10\rangle. Note that vectors are arranged as follows: |00>, |01>, |10>, |11>, ... .

comp_state = quantum_state(n_qubits=2, bits=2)

out_state = evaluate_state_to_vector(comp_state)

print("State vector:")
print(out_state.vector)
print("")
print("Circuit:")
print(out_state.circuit.gates)
#output
State vector:
[0.+0.j 0.+0.j 1.+0.j 0.+0.j]

Circuit:
()

Converts a GeneralCircuitQuantumState

from quri_parts.circuit import QuantumCircuit

circuit = QuantumCircuit(2)
circuit.add_H_gate(0)
circuit.add_CNOT_gate(0, 1)

bell_state = quantum_state(n_qubits=2, circuit=circuit)
out_state = evaluate_state_to_vector(bell_state)

print("State vector:")
print(out_state.vector)
print("")
print("Circuit:")
print(out_state.circuit.gates)
#output
State vector:
[0.70710678+0.j 0. +0.j 0. +0.j 0.70710678+0.j]

Circuit:
()

Converts a QuantumStateVector

import numpy as np
from scipy.stats import unitary_group


circuit = QuantumCircuit(2)
circuit.add_H_gate(0)
circuit.add_CNOT_gate(0, 1)

init_state_vector = unitary_group.rvs(4)[:, 0]
state = quantum_state(n_qubits=2, vector=init_state_vector, circuit=circuit)
out_state = evaluate_state_to_vector(state)

print("State vector:")
print(out_state.vector)
print("")
print("Circuit:")
print(out_state.circuit.gates)
#output
State vector:
[ 0.18421042+0.45591396j -0.29168606+0.44172833j -0.28458075+0.61735372j
-0.10691909+0.06678914j]

Circuit:
()

run_circuit

run_circuit is a function that acts a quantum circuit on a state vector represented by a numpy.array and returns the resulting state vector.

from quri_parts.qulacs.simulator import run_circuit

n_qubits = 2

circuit = QuantumCircuit(n_qubits)
circuit.add_H_gate(0)
circuit.add_CNOT_gate(0, 1)

init_state_vector = unitary_group.rvs(2**n_qubits)[:, 0]
out_state = run_circuit(circuit, init_state_vector)
out_state
#output
array([0.43459926-0.04472012j, 0.18045739+0.10382554j,
0.5202943 -0.51833746j, 0.21666993+0.42361922j])

get_marginal_probability

Sometimes we need to perform partial measurement to a state. get_marginal_probability returns the probability of obtaining the specified computational basis eigenstate after measuring a subset of the qubits. For example, for a state with 3 qubits, setting measured_values={0: 1, 2: 0} outputs the probability of obtaining 1 from the 0th qubit and 0 from the 2nd qubit. That is, the probability is obtained from the coefficients of 001|001\rangle and 011|011\rangle.

from quri_parts.qulacs.simulator import get_marginal_probability

n_qubits = 3

init_state = unitary_group.rvs(2**n_qubits)[:, 0]

state = quantum_state(n_qubits=n_qubits, vector=init_state)
out_state = evaluate_state_to_vector(state)
print("State vector:")
print(out_state.vector)
print("")
print(
"Probability of measuring 1 from to 0th qubit and 0 from the 2nd qubit:",
get_marginal_probability(init_state, measured_values={0: 1, 2: 0})
)
#output
State vector:
[-0.01264178-0.02125235j 0.3049721 -0.36580166j -0.25013693-0.26850866j
0.03871132-0.15817578j -0.27692887+0.45944717j -0.32775336+0.40284975j
-0.19829442-0.0291523j 0.1171112 -0.00301804j]

Probability of measuring 1 from to 0th qubit and 0 from the 2nd qubit: 0.2533369796205178

Stim simulators

We also provide

  • evaluate_state_to_vector
  • run_circuit

in the quri_parts.stim.simulator module. The functionalities are the same as those in quri_parts.qulacs.simulator except that they only accept Clifford circuits and performs the circuit execution using Stim.