min_qsim
A minimalistic n-qubit statevector quantum circuit simulator, built from scratch in NumPy for educational purposes. No external quantum computing libraries — every gate, measurement, and state operation is implemented directly on top of the raw statevector using explicit bit-manipulation, not black-box matrix libraries.
This project exists to make the bridge between pen-and-paper quantum mechanics (bra-ket notation, unitary matrices, tensor products, Born's rule) and working code as transparent as possible.
Installation
pip install min-qsim
Requires Python >= 3.9 and NumPy >= 1.24.
Quick example
import min_qsim as q
# Bell state: |00> -> H(q0) -> CNOT(q0, q1)
qc = q.Circuit(2)
qc.h(0).cnot(0, 1)
print(qc)
# 0.707|00> + 0.707|11>
outcome = qc.fmeasure()
print(outcome)
# '00' or '11' -- collapses the entangled pair together
The Circuit class
Circuit wraps every operation in the library so you don't have to manually thread a statevector and qubit count through function calls. Every gate method mutates the circuit's internal state and returns self, so calls can be chained.
qc = q.Circuit(n, tol=1e-6) # n qubits, initialized to |00...0>
tolcontrols how small an amplitude has to be before it's hidden from the printed representation (print(qc)), not the internal precision of any calculation.
Single-qubit gates
qc.x(qubit) # Pauli-X
qc.y(qubit) # Pauli-Y
qc.z(qubit) # Pauli-Z
qc.h(qubit) # Hadamard
qc.s(qubit) # S (phase) gate
qc.t(qubit) # T gate
qc.rx(qubit, theta) # rotation about x-axis
qc.ry(qubit, theta) # rotation about y-axis
qc.rz(qubit, theta) # rotation about z-axis
Multi-qubit gates
qc.cnot(control, target)
qc.cz(qubit_a, qubit_b) # symmetric: order doesn't matter
qc.swap(qubit_a, qubit_b) # symmetric: order doesn't matter
qc.ccx(qubit_a, qubit_b, target) # Toffoli/CCX; qubit_a/qubit_b symmetric
All multi-qubit gates work on arbitrary, non-adjacent qubits — there's no requirement that control and target be next to each other.
Measurement
qc.fmeasure() # full measurement: collapses the entire state, returns a basis string like '011'
qc.pmeasure([0, 2]) # partial measurement on specific qubits, returns a combo string
qc.probabilities() # dict of {basis_state: probability} without collapsing anything
qc.probabilities('01') # probability of one specific basis state
Other operations
qc.reset(qubit) # forces a qubit back to |0>, collapsing any entanglement first
qc.set_state(vector) # load a custom statevector (must match 2**n in length and be normalized)
qc.compose(other_circuit) # tensor-product this circuit with another; self's qubits come first
Inspecting a circuit
print(qc) # human-readable ket notation, e.g. "0.707|00> + 0.707|11>"
Function-level API
Every Circuit method is a thin wrapper around standalone functions, all of which are also importable directly if you'd rather work with raw statevectors:
from min_qsim import (
init_state, custom_state,
X, Y, Z, H, S, T, CNOT, CZ, SWAP, CCX, # gate constants
rx, ry, rz, # parameterized gate constructors
apply_gate, apply_cnot, apply_cz, apply_swap, apply_ccx,
get_probabilities, sampling, full_measurement, partial_measurement,
reset_qubit, is_normalized,
state_to_string, format_amplitude,
)
init_state(n)/custom_state(vector, n)— build a statevector from scratch or from a user-provided array.apply_gate(state, gate, qubit_index, n)— apply any single-qubit gate to any qubit in an n-qubit system.apply_cnot/apply_cz/apply_swap/apply_ccx— multi-qubit gates, all generalized to arbitrary qubit positions via bit-manipulation on basis-state indices.get_probabilities(state, n, basis_state=None)— raw probabilities without collapsing the state.sampling(state, n, shots)— repeated measurement, returns frequency counts.full_measurement/partial_measurement— collapse and observe (single draw, not multi-shot).reset_qubit(state, n, qubit_index)— measure-and-correct a single qubit back to |0>.is_normalized(state, n)— sanity-check a statevector sums to probability 1.state_to_string(state, n, tol=1e-6)— human-readable ket notation for any statevector.
Design notes
- Leftmost-first convention: qubit 0 is the most-significant bit of every basis-state index.
- Multi-qubit gates use direct bit-manipulation (
(i >> (n-1-q)) & 1to extract a bit, XOR/OR of masks to flip) rather than constructing full kron-chain matrices — this keeps memory and computation manageable and mirrors how you'd reason about the gate by hand. partial_measurement/reset_qubitpreserve relative phase and magnitude between surviving amplitudes; only a fully-collapsed single-basis-state result can have its amplitude hardcoded to 1.0 (global phase is unobservable).
License
MIT
Metadata
Release files for min-qsim 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| min_qsim-0.1.1.tar.gz | 12.9 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| min_qsim-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.3 kB
Release files / min_qsim-0.1.1.tar.gz
| Download URL | min_qsim-0.1.1.tar.gz |
|---|---|
| Size | 12.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
db9defd2a11c98c4cff34f8992316fd0c929a5797158a51ebec7b904d8ac013f
|
|
BLAKE2b-256 checksum How to use checksums |
af9b69b1c87defe4db7f809249403e0e079acb7afbd9baa9f7388b738498e78c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / min_qsim-0.1.1-py3-none-any.whl
| Download URL | min_qsim-0.1.1-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
fea172d762cdd11b592ef459978b3ba8c2bc8bc44ef346df4a54341cabd0cd92
|
|
BLAKE2b-256 checksum How to use checksums |
4070ffaea3f944462753440d14521376db8d0c6dd66a0c083cbe4f813d128ddb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Security for min-qsim 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.