A fast quantum stabilizer circuit simulator.
Project description
Stim
Stim is a fast simulator for quantum stabilizer circuits.
API references are available on the stim github wiki: https://github.com/quantumlib/stim/wiki
Stim can be installed into a python 3 environment using pip:
pip install stim
Once stim is installed, you can import stim
and use it.
There are three supported use cases:
- Interactive simulation with
stim.TableauSimulator
. - High speed sampling with samplers compiled from
stim.Circuit
. - Independent exploration using
stim.Tableau
andstim.PauliString
.
Interactive Simulation
Use stim.TableauSimulator
to simulate operations one by one while inspecting the results:
import stim
s = stim.TableauSimulator()
# Create a GHZ state.
s.h(0)
s.cnot(0, 1)
s.cnot(0, 2)
# Look at the simulator state re-inverted to be forwards:
t = s.current_inverse_tableau()
print(t**-1)
# prints:
# +-xz-xz-xz-
# | ++ ++ ++
# | ZX _Z _Z
# | _X XZ __
# | _X __ XZ
# Measure the GHZ state.
print(s.measure_many(0, 1, 2))
# prints one of:
# [True, True, True]
# or:
# [False, False, False]
High Speed Sampling
By creating a stim.Circuit
and compiling it into a sampler, samples can be generated very quickly:
import stim
# Create a circuit that measures a large GHZ state.
c = stim.Circuit()
c.append_operation("H", [0])
for k in range(1, 30):
c.append_operation("CNOT", [0, k])
c.append_operation("M", range(30))
# Compile the circuit into a high performance sampler.
sampler = c.compile_sampler()
# Collect a batch of samples.
# Note: the ideal batch size, in terms of speed per sample, is roughly 1024.
# Smaller batches are slower because they are not sufficiently vectorized.
# Bigger batches are slower because they use more memory.
batch = sampler.sample(1024)
print(type(batch)) # numpy.ndarray
print(batch.dtype) # numpy.uint8
print(batch.shape) # (1024, 30)
print(batch)
# Prints something like:
# [[1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
# [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
# [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
# ...
# [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
# [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]
# [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
# [1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1]]
This also works on circuits that include noise:
import stim
import numpy as np
c = stim.Circuit("""
X_ERROR(0.1) 0
Y_ERROR(0.2) 1
Z_ERROR(0.3) 2
DEPOLARIZE1(0.4) 3
DEPOLARIZE2(0.5) 4 5
M 0 1 2 3 4 5
""")
batch = c.compile_sampler().sample(2**20)
print(np.mean(batch, axis=0).round(3))
# Prints something like:
# [0.1 0.2 0. 0.267 0.267 0.266]
You can also sample annotated detection events using stim.Circuit.compile_detector_sampler
.
Independent Exploration
Stim provides data types stim.PauliString
and stim.Tableau
, which support a variety of fast operations.
import stim
xx = stim.PauliString("XX")
yy = stim.PauliString("YY")
assert xx * yy == -stim.PauliString("ZZ")
s = stim.Tableau.from_named_gate("S")
print(repr(s))
# prints:
# stim.Tableau.from_conjugated_generators(
# xs=[
# stim.PauliString("+Y"),
# ],
# zs=[
# stim.PauliString("+Z"),
# ],
# )
s_dag = stim.Tableau.from_named_gate("S_DAG")
assert s**-1 == s_dag
assert s**1000000003 == s_dag
cnot = stim.Tableau.from_named_gate("CNOT")
cz = stim.Tableau.from_named_gate("CZ")
h = stim.Tableau.from_named_gate("H")
t = stim.Tableau(5)
t.append(cnot, [1, 4])
t.append(h, [4])
t.append(cz, [1, 4])
t.prepend(h, [4])
assert t == stim.Tableau(5)
Supported Gates
General facts about all gates.
-
Qubit Targets: Qubits are referred to by non-negative integers. There is a qubit
0
, a qubit1
, and so forth (up to an implemented-defined maximum of16777215
). For example, the lineX 2
says to apply anX
gate to qubit2
. Beware that touching qubit999999
implicitly tells simulators to resize their internal state to accommodate a million qubits. -
Measurement Record Targets: Measurement results are referred to by
rec[-#]
arguments, where the index within the square brackets uses python-style negative indices to refer to the end of the growing measurement record. For example,CNOT rec[-1] 3
says "toggle qubit3
if the most recent measurement returnedTrue
andCZ 1 rec[-2]
means "phase flip qubit1
if the second most recent measurement returnedTrue
. There is implementation-defined maximum lookback of-16777215
when accessing the measurement record. Non-negative indices are not permitted. -
Broadcasting: Most gates support broadcasting over multiple targets. For example,
H 0 1 2
will broadcast a Hadamard gate over qubits0
,1
, and2
. Two qubit gates can also broadcast, and do so over aligned pair of targets. For example,CNOT 0 1 2 3
will applyCNOT 0 1
and thenCNOT 2 3
. Broadcasting is always evaluated in left-to-right order.
Single qubit gates
Z
: Pauli Z gate. Phase flip.Y
: Pauli Y gate.X
: Pauli X gate. Bit flip.H
(alternate nameH_XZ
): Hadamard gate. Swaps the X and Z axes. Unitary equals (X + Z) / sqrt(2).H_XY
: Variant of the Hadamard gate that swaps the X and Y axes (instead of X and Z). Unitary equals (X + Y) / sqrt(2).H_YZ
: Variant of the Hadamard gate that swaps the Y and Z axes (instead of X and Z). Unitary equals (Y + Z) / sqrt(2).S
(alternate nameSQRT_Z
): Principle square root of Z gate. Equal todiag(1, i)
.S_DAG
(alternate nameSQRT_Z_DAG
): Adjoint square root of Z gate. Equal todiag(1, -i)
.SQRT_Y
: Principle square root of Y gate. Equal toH_YZ*S*H_YZ
.SQRT_Y_DAG
: Adjoint square root of Y gate. Equal toH_YZ*S_DAG*H_YZ
.SQRT_X
: Principle square root of X gate. Equal toH*S*H
.SQRT_X_DAG
: Adjoint square root of X gate. Equal toH*S_DAG*H
.I
: Identity gate. Does nothing. Why is this even here? Probably out of a misguided desire for closure.
Two qubit gates
SWAP
: Swaps two qubits.ISWAP
: Swaps two qubits while phasing the ZZ observable by i. Equal toSWAP * CZ * (S tensor S)
.ISWAP_DAG
: Swaps two qubits while phasing the ZZ observable by -i. Equal toSWAP * CZ * (S_DAG tensor S_DAG)
.CNOT
(alternate namesCX
,ZCX
): Controlled NOT operation. Qubit pairs are in name order (first qubit is the control, second is the target). This gate can be controlled by on the measurement record. Examples: unitaryCNOT 1 2
, feedbackCNOT rec[-1] 4
.CY
(alternate nameZCY
): Controlled Y operation. Qubit pairs are in name order (first qubit is the control, second is the target). This gate can be controlled by on the measurement record. Examples: unitaryCY 1 2
, feedbackCY rec[-1] 4
.CZ
(alternate nameZCZ
): Controlled Z operation. This gate can be controlled by on the measurement record. Examples: unitaryCZ 1 2
, feedbackCZ rec[-1] 4
orCZ 4 rec[-1]
.YCZ
: Y-basis-controlled Z operation (i.e. the reversed-argument-order controlled-Y). Qubit pairs are in name order. This gate can be controlled by on the measurement record. Examples: unitaryYCZ 1 2
, feedbackYCZ 4 rec[-1]
.YCY
: Y-basis-controlled Y operation.YCX
: Y-basis-controlled X operation. Qubit pairs are in name order.XCZ
: X-basis-controlled Z operation (i.e. the reversed-argument-order controlled-not). Qubit pairs are in name order. This gate can be controlled by on the measurement record. Examples: unitaryXCZ 1 2
, feedbackXCZ 4 rec[-1]
.XCY
: X-basis-controlled Y operation. Qubit pairs are in name order.XCX
: X-basis-controlled X operation.
Collapsing gates
M
: Z-basis measurement. Examples:M 0
,M 2 1
,M 0 !3 1 2
. Collapses the target qubits and reports their values (optionally flipped). Prefixing a target with a!
indicates that the measurement result should be inverted when reported. In the tableau simulator, this operation may require a transpose and so is more efficient when grouped (e.g. preferM 0 1 \n H 0
overM 0 \n H 0 \n M 1
).R
: Reset to |0>. Examples:R 0
,R 2 1
,R 0 3 1 2
. Silently measures the target qubits and bit flips them if they're in the |1> state. Equivalently, discards the target qubits for zero'd qubits. In the tableau simulator, this operation may require a transpose and so is more efficient when grouped (e.g. preferR 0 1 \n X 0
overR 0 \n X 0 \ nR 1
).MR
: Z-basis measurement and reset. Examples:MR 0
,MR 2 1
,MR 0 !3 1 2
. Collapses the target qubits, reports their values (optionally flipped), then resets them to the |0> state. Prefixing a target with a!
indicates that the measurement result should be inverted when reported. (The ! does not change that the qubit is reset to |0>.) In the tableau simulator, this operation may require a transpose and so is more efficient when grouped (e.g. preferMR 0 1 \n H 0
overMR 0 \n H 0 \n MR 1
).
Noise Gates
-
DEPOLARIZE1(p)
: Single qubit depolarizing error. Examples:DEPOLARIZE1(0.001) 1
,DEPOLARIZE1(0.0003) 0 2 4 6
. With probabilityp
, applies independent single-qubit depolarizing kicks to the given qubits. A single-qubit depolarizing kick isX
,Y
, orZ
chosen uniformly at random. -
DEPOLARIZE2(p)
: Two qubit depolarizing error. Examples:DEPOLARIZE2(0.001) 0 1
,DEPOLARIZE2(0.0003) 0 2 4 6
. With probabilityp
, applies independent two-qubit depolarizing kicks to the given qubit pairs. A two-qubit depolarizing kick isIX
,IY
,IZ
,XI
,XX
,XY
,XZ
,YI
,YX
,YY
,YZ
,ZI
,ZX
,ZY
,ZZ
chosen uniformly at random. -
X_ERROR(p)
: Single-qubit probabilistic X error. Examples:X_ERROR(0.001) 0 1
. For each target qubit, independently applies an X gate With probabilityp
. -
Y_ERROR(p)
: Single-qubit probabilistic Y error. Examples:Y_ERROR(0.001) 0 1
. For each target qubit, independently applies a Y gate With probabilityp
. -
Z_ERROR(p)
: Single-qubit probabilistic Z error. Examples:Z_ERROR(0.001) 0 1
. For each target qubit, independently applies a Z gate With probabilityp
. -
CORRELATED_ERROR(p)
(alternate nameE
) andELSE_CORRELATED_ERROR(p)
: Pauli product error cases. Probabilistically applies a Pauli product error with probabilityp
, unless the "correlated error occurred" flag is already set.CORRELATED_ERROR
is equivalent toELSE_CORRELATED_ERROR
except thatCORRELATED_ERROR
starts by clearing the "correlated error occurred" flag. Both operations set the "correlated error occurred" flag if they apply their error. Example:# With 40% probability, uniformly pick X1*Y2 or Z2*Z3 or X1*Y2*Z3. CORRELATED_ERROR(0.2) X1 Y2 ELSE_CORRELATED_ERROR(0.25) Z2 Z3 ELSE_CORRELATED_ERROR(0.33333333333) X1 Y2 Z3
Annotations
DETECTOR
: Asserts that a set of measurements have a deterministic result, and that this result changing can be used to detect errors. Ignored in measurement sampling mode. In detection sampling mode, a detector produces a sample indicating if it was inverted by noise or not. Example:DETECTOR rec[-1] rec[-2]
.OBSERVABLE_INCLUDE(k)
: Adds physical measurement locations to a specified logical observable. The logical measurement result is the parity of all physical measurements added to it. Behaves similarly to a Detector, except observables can be built up globally over the entire circuit instead of being defined locally. Ignored in measurement sampling mode. In detection sampling mode, a logical observable can produce a sample indicating if it was inverted by noise or not. These samples are dropped or put before or after detector samples, depending on command line flags. Examples:OBSERVABLE_INCLUDE(0) rec[-1] rec[-2]
,OBSERVABLE_INCLUDE(3) rec[-7]
.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.