This software implements the methods described in BH21 for simulating Clifford circuits.
A reference implementation in Python is in the reference
directory. The
implementation is in simplex.py
. It requires numpy
and bidict
:
pip install numpy bidict
To run the unit tests:
cd reference
./test-simplex
There is an option to perform some additional internal state validation during testing:
cd reference
./test-simplex --validate
However, this requires that sagemath
be installed on your system and that sage
scripts be executable with /usr/bin/python
. (It uses sage for a matrix rank
computation.) It also slows down the tests considerably.
The main class is the Simplex
class, defined and documented in simplex.py
.
Example usage:
from simplex import Simplex
S = Simplex(2) # 2 qubits, initially in the all-zero state
S.H(0) # apply a Hadamard on qubit 0
S.CX(0,1) # apply a CNOT between qubits 0 and 1
b0 = S.MeasZ(0) # measure qubit 0 in the Z basis, return 0 or 1
b1 = S.MeasZ(1) # measure qubit 1 in the Z basis, return 0 or 1
assert b0 == b1 # it's a Bell state
assert not S.is_deterministic() # at least one non-deterministic measurement has been performed
By default, non-deterministic measurements use a PRNG to decide the result. However, for reproduciblility and testing you may specify "coins" by passing an extra argument to the measure operation. For example:
b0 = S.MeasZ(0, coin=0)
assert b0 == 0
Note that is_deterministic()
will still return False
regardless of whether a
coin was actually specified.
The C++ implementation is in the simplex
directory. It is built using cmake
. To build the library and the unit tests:
cd simplex
mkdir build
cd build
cmake ..
cmake --build .
Then to run the tests:
./test/simplex-test
There are two implementations, one (the default) optimized for sparse circuits
(and hence sparse matrices), the other not. If you are working with dense
circuits, then the dense-matrix-based implementation may be faster. To build
this, simply set the SIMPLEX_DENSE
option when running cmake
. From the
build
directory:
rm -f CMakeCache.txt
cmake .. -DSIMPLEX_DENSE=ON
cmake --build .
The C++ API is similar to the API of the Python reference implementation.
#include <simplex.hpp>
Simplex S(2);
S.H(0);
S.CX(0, 1);
Measurements return integer values 0 or 1. There is also the same optional argument to the measure operations for specifying coins:
int b0 = S.MeasY(0, 1); // b0 will be 1
int b1 = S.MeasZ(1);
The internal state can be viewed by means of the operator<<
method:
#include <iostream>
// ...
std::cout << S;
This will print out the matrices A and Q, the vector b, and the mapping p as described in BH21.
The C++ implementation is wrapped in a Python module, pysimplex
. The binding
code is in the simplex/pysimplex
directory. To build and install this module:
cd simplex
pip install .
The API is similar to that of the reference and C++ implementations. For example:
from pysimplex import Simplex
S = Simplex(3)
S.H(0).CX(0, 1).CX(1, 2)
print(S.MeasZ(0))
print(S.MeasZ(1))
To see the internal state, use print(S)
.
It is possible to initialize a Simplex
from a file in Stim format by
passing a file path and (optionally) an integer seed. For example:
S = Simplex("./test-circuits/random_circuit_64.stim", seed=1)
Most but not all Stim instructions are supported. There is little leniency in the parser.
To install the current stable version from pypi, simply:
pip install pysimplex
The package is available for Linux, MacOS and Windows, and for Python versions 3.10, 3.11 and 3.12.