project · active · Rust
qsim-rs
State-vector quantum circuit simulator written from scratch, without a quantum SDK.
result Tests check physics, not code paths — unitarity of every gate, H² = I, HZH = X, Bell and GHZ correlations, and an 80k-shot histogram flat within 4σ.
I use Qiskit for quantum computing coursework, but I wanted to know what a simulator actually
does when you call run(). So I wrote one.
How it works
An -qubit pure state is a vector of complex amplitudes. Index in binary labels the basis state ; qubit 0 is the least significant bit, matching Qiskit.
The stride trick. A single-qubit gate on qubit only couples amplitude pairs whose indices differ in bit . With , those pairs are for every with bit clear, and each pair is updated by the unitary:
One pass over the vector, , and no matrix is ever built.
Controlled gates are index masking. Apply the same block only where the control bit is set. CNOT is a controlled-X; no separate matrix needed.
Measurement samples from (the Born rule) for full-register shots, or does a projective single-qubit measurement with collapse and renormalisation.
Gate set
H, X, Y, Z, S, T, Rx, Ry, Rz, CNOT, CZ — with a builder API:
// Bell state: H on q0, then CNOT(q0 → q1)
let state = Circuit::new(2).h(0).cnot(0, 1).run();
What I learned
Qubit ordering is a convention you must pick on day one. Half the confusion in comparing against textbooks comes from little- vs big-endian labelling.
Interference is the test that matters. restores exactly, which no classical probability model reproduces — it’s the cleanest check that the amplitudes, not just the probabilities, are right.
Limitations
- Exponential memory: every extra qubit doubles the state vector.
- Pure states only — no noise or mixed states yet.
Next
- Grover’s algorithm example (oracle + diffuser)
- BB84 key distribution
- Noise channels (depolarising, amplitude damping)
- Benchmark against Qiskit Aer’s statevector output