Getting started#
BGLS
is a Python package that implements the Bravyi, Gosset, and Liu Sampling algorithm presented in How to simulate quantum measurement without computing marginals (Phys. Rev. Lett.) (arXiv).
Quick start#
Install BGLS
via pip install bgls
. The following example shows how to use the package.
"""Setup."""
import cirq
import bgls
"""Define a circuit."""
nqubits = 2
qubits = cirq.LineQubit.range(nqubits)
circuit = cirq.Circuit(
cirq.H.on(qubits[0]),
cirq.CNOT.on(qubits[0], qubits[1]),
cirq.measure(*qubits, key="z")
)
circuit
0: ───H───@───M('z')─── │ │ 1: ───────X───M────────
"""Use BGLS to simulate the circuit."""
simulator = bgls.Simulator(
initial_state=cirq.StateVectorSimulationState(qubits=qubits, initial_state=0),
apply_op=cirq.protocols.act_on,
compute_probability=bgls.born.compute_probability_state_vector,
)
results = simulator.run(circuit, repetitions=10)
cirq.plot_state_histogram(results);
More detail: How to create a bgls.Simulator
#
Notice from the above example that there are three ingredients needed to create a bgls.Simulator
:
initial_state
: The initial quantum state (wavefunction) of the circuit, including what type the wavefunction is (state vector, density matrix, tensor network, etc.).apply_op
: A function for applying operations to the initial (and intermediate) states.compute_probability
: A function for calculating the probability of sampling a bitstring from the input state type.
Note: A function to compute marginal distributions, which is used in the typical “qubit-by-qubit” sampling algorithm, is not needed. This is the primary purpose of the BGLS “gate-by-gate” sampling algorithm: when it is easier to compute probabilities than it is to compute marginal distributions, the BGLS algorithm is advantageous to use. See more in How
BGLS
works and When to useBGLS
.
Any wavefunction type can be used with BGLS
. In the example above, we used a cirq.StateVectorSimulationState
which represents the wavefunction as a state vector.
"""Provide a representation of the (initial) wavefunction, here a cirq.StateVectorSimulationState."""
wavefunction = cirq.StateVectorSimulationState(qubits=qubits, initial_state=0)
# Visualize the wavefunction.
wavefunction.target_tensor.reshape(2 ** nqubits)
array([1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j], dtype=complex64)
Once the state is provided, BGLS
needs to know how to apply operations to the state. Here, we can do this with cirq.protocols.act_on
.
"""Define a function for applying operations to the state."""
from typing import Any
def apply_op(operation: cirq.GateOperation, state: cirq.StateVectorSimulationState) -> None:
cirq.protocols.act_on(operation, state)
# Example: Apply operation and visualize the updated wavefunction.
apply_op(cirq.H.on(qubits[0]), wavefunction)
wavefunction.target_tensor.reshape(2 ** nqubits).round(3)
array([ 0.707+0.j, 0. +0.j, 0.707+0.j, -0. +0.j], dtype=complex64)
Note: The
apply_op
function must modify thestate
in-place as above.
Last, BGLS
needs to know how to compute the probability of sampling a bitstring z
from the wavefunction
\(|\psi\rangle\). Here this is given by \(| \langle z | \psi \rangle | ^ 2\) and can be computed via the following function.
"""Define a function for computing the probability of sampling a bitstring."""
import numpy as np
def probability_of_bitstring(
wavefunction: cirq.StateVectorSimulationState,
bitstring: str,
) -> float:
return np.abs(wavefunction.target_tensor.reshape(2 ** nqubits)[int(bitstring, 2)]) ** 2
# Example: Calculating some p(z) for some bitstrings z.
for bitstring in {"00", "10"}:
print(f"Probability of sampling {bitstring} is {probability_of_bitstring(wavefunction, bitstring):.2f}")
Probability of sampling 10 is 0.50
Probability of sampling 00 is 0.50
Note: This function is identical to
bgls.born.compute_probability_state_vector
used in the Quick start example.
With these three ingredients you can create a bgls.Simulator
and execute circuits with bgls.Simulator.run
.
simulator = bgls.Simulator(wavefunction, apply_op, probability_of_bitstring)
simulator.run(circuit)
z=0, 0
When to use the bgls.Simulator
#
Other than introducing the bgls.Simulator
, there’s (probably) no good reason to use BGLS
with a statevector simulator as above: the samples can be drawn from the final state just as easily. The power of the bgls.Simulator
comes in situations where it is easier to compute probabilities than compute marginal distributions - see When to use BGLS
for more discussion and examples.