Skip to content

qsimlab core — circuits, simulate, the planner, interop

Status: stable (phase 1; contract in ../API.md). This page is a runnable tutorial: every >>> block is executed by pytest in CI, so if it is here, it works.

1. Build a circuit

Gate methods return the circuit, so they chain. Qubit 0 is the leftmost character of a bitstring.

>>> import numpy as np
>>> import qsimlab as qs
>>> bell = qs.Circuit(2).h(0).cx(0, 1)
>>> bell.num_qubits
2

2. Ask for one thing with simulate

simulate(circuit, request) takes one request — statevector(), amplitudes([...]), samples(shots) or expectation([...]) — and the planner picks the engine.

>>> r = qs.simulate(bell, qs.statevector())
>>> r.state.round(4)
array([0.7071+0.j, 0.    +0.j, 0.    +0.j, 0.7071+0.j])
>>> r.probabilities().round(4)
array([0.5, 0. , 0. , 0.5])
>>> qs.simulate(bell, qs.amplitudes(["00", "11"])).amplitudes.round(4)
array([0.7071+0.j, 0.7071+0.j])
>>> qs.simulate(bell, qs.expectation(["Z0 Z1", "X0 X1", "Z0"])).values.round(6)
array([1., 1., 0.])

Sampling needs measurements; seed= makes it reproducible.

>>> s = qs.simulate(bell.copy().measure_all(), qs.samples(2000), seed=7)
>>> s.shots, sorted(s.counts())
(2000, ['00', '11'])

3. Ask why: explain=True and plan

explain=True attaches the planner's reasoning to the result. plan() gives the same prediction without running anything — use it before a big job.

>>> r = qs.simulate(bell, qs.statevector(), explain=True)
>>> r.engine
'statevector'
>>> wide = qs.Circuit(40).h(0).cx(0, 1).measure_all()   # 40 qubits, but all Clifford
>>> qs.plan(wide, qs.samples(10)).engine
'tableau'

A 40-qubit state vector would need 16 TiB; the planner sees the circuit is Clifford and routes it to the stabilizer tableau, which costs microseconds.

4. Move circuits in and out

OpenQASM 2 works with no extra dependencies; Qiskit, Cirq and Stim converters live in qsimlab.interop and raise MissingDependencyError if the package is absent.

>>> from qsimlab import interop
>>> print(interop.to_qasm(bell))
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
h q[0];
cx q[0],q[1];
<BLANKLINE>
>>> interop.from_qasm(interop.to_qasm(bell)).num_qubits
2

Next

  • qec.md — memory circuits, detector sampling, decoders, logical error rates.
  • shor.md — gate-level Shor, oracles, support prediction.
  • analysis.md — magic, simulability, monitored circuits.