Quantum circuit simulation for TypeScript · four exact backends · 14 interchange formats · zero dependencies · 1,850 tests · v0.6.1
A general-purpose quantum circuit simulator for TypeScript and JavaScript. Four backends, 14 import/export formats, and no dependencies — install it and a Bell state is three lines away.
npm install @kirkelliott/ketNode ≥ 22, or straight from a CDN in the browser. No Python, no build step, no toolchain.
Circuit. Compose and branch without defensive copying..d.ts bolted on.RangeError at construction, not 200 gates later.
You don't have to know which representation fits your circuit. simulate() inspects it and
routes to the cheapest exact backend. Same call, three very different circuits:
| Circuit | Qubits | Routed to | Time |
|---|---|---|---|
| GHZ-8, Clifford-only gates | 8 | clifford | 3ms |
| QFT-10, non-Clifford phases | 10 | statevector | 2ms |
| 40 qubits, non-Clifford phases | 40 | mps | 4ms |
Exact in every case — routing changes the cost, never the answer.
ket matches its representation to the circuit instead of committing to one, so the same API stays efficient across shapes that usually need different tools. Pick a backend explicitly when you want to.
| Backend | Call | Memory | Best for | Measured |
|---|---|---|---|---|
| Statevector | run() | sparse → dense, automatic | Exact amplitudes to ~20 qubits | GHZ-20 — 1ms |
| MPS / tensor | runMps() | O(n·χ²), χ grows on demand | Low-entanglement circuits, 50+ qubits | GHZ-127 — 9ms |
| Density matrix | dm() | sparse → dense, automatic | Mixed states and exact noise channels | GHZ-8 + noise — 1ms |
| Clifford | runClifford() | O(n²) tableau | Clifford circuits, QEC thresholds | GHZ-1024 — 3587ms |
The statevector starts as a sparse map and promotes itself to a flat Float64Array past ⅛ fill.
MPS bond dimension χ is exact by default and grows on demand — maxBond is an initial
allocation, not a cap.
Four backends built on four unrelated representations — amplitudes, density matrices, tensor trains, stabilizer tableaux — have to agree. Where a circuit can be expressed in all four, ket checks that they do, and the suite is built on analytic expectations rather than snapshots. These numbers are computed while this page builds:
| Outcome | Statevector (exact) | Density matrix | MPS | Clifford |
|---|---|---|---|---|
|000000⟩ | 0.500000 | 0.500000 | 0.499870 | 0.499870 |
|111111⟩ | 0.500000 | 0.500000 | 0.500130 | 0.500130 |
The density matrix backend is exact, so it matches to floating-point precision. MPS and Clifford sample, so they land within shot noise of the analytic answer — which is the correct result, not a tolerance that was widened until it passed.
Every circuit can hand you its full 2ⁿ×2ⁿ unitary via circuitMatrix(). For a five-gate circuit mixing Clifford and non-Clifford rotations, U†U − I is:
Machine epsilon. The suite asserts this for every gate in the library, not just this one circuit.
A serious simulator tells you when its answer is approximate. MPS runs set
truncated the moment a physically significant singular value is discarded, and
report the peak bond dimension actually reached:
Exact by default. Approximation is something you opt into with truncErr or
maxChi, and it is always flagged.
A simulator you can't get circuits into or out of is a dead end. ket reads and writes the formats the field actually uses, with round-trips covered by the test suite for every one of them.
Not an oracle mock-up. The full Beauregard circuit, modular exponentiation compiled down to primitive gates, simulated exactly — then the period recovered from phase estimation by continued fractions.
| r.factors | [5n, 3n] |
| r.period | 4n |
| r.method | 'quantum' |
| r.qubits | 19 |
At these sizes classical shortcuts hit often — an even N, or a base sharing a factor with N,
falls to gcd with no circuit at all. method reports which path ran, so a
demo can prove the quantum one did.
This does not reach cryptographic sizes — no classical simulator does. What you get is the real circuit, exactly simulated, at sizes you can inspect.
IonQ's native gate set is built in, not bolted on. gpi, gpi2, ms,
and vz are first-class gates you can write directly, compile(device) transpiles
an abstract circuit into them, and toIonQ() emits submit-ready JSON.
A textbook Bell pair, rewritten into what the trap actually executes — GPI2 and MS, with virtual-Z frame rotations that cost nothing on hardware.
toIonQ() produces the API payload directly — no adapter, no Python bridge.
Every IonQ system ships with its native gate set and published error rates, so a noisy run is one option away — run({ noise: 'forte-1' }).
| Device | Qubits | Native gates | 1Q error | 2Q error | Readout |
|---|---|---|---|---|---|
| aria-1 | 25 | gpi, gpi2, ms, vz | 0.030% | 0.50% | 0.40% |
| forte-1 | 36 | gpi, gpi2, ms, vz, zz | 0.010% | 0.20% | 0.20% |
| harmony | 11 | gpi, gpi2, ms, vz | 0.100% | 1.50% | 1.00% |
No screenshots and no mock data — every chart, circuit diagram, and number on the rest of this page is produced by executing ket when the page is generated.
A 4-cycle graph has two optimal bipartitions: {0,2} vs {1,3} and {1,3} vs {0,2}, each cutting all 4 edges. QAOA p=1 finds them — the two dominant peaks are the correct answers.
toSVG() · blochSphere(q)Self-contained SVG string — no external fonts or stylesheets. Same column layout as draw(). Embed directly in HTML, save to a file, or use in notebooks.
300×300 SVG for a single qubit's state using cavalier projection. Partial-traces over all other qubits — works on any circuit, including entangled states.
The same 3-qubit Grover circuit (target: |101⟩) run across six backends with 4,096 shots each. Lower gate error rates preserve the quadratic amplitude advantage. All results use published device noise models — not real hardware runs.
A 1,024-qubit GHZ state built with one H gate + 1,023 CNOTs.
Classically infeasible with statevector simulation (21024 amplitudes),
but the Gottesman-Knill theorem lets us track it exactly in O(n²) space.
Each row is a stabilizer generator; each column is a qubit.
Row 0 (bright stripe): X⊗¹⁰²⁴ — all 1,024 qubits correlated via X. ·
Rows 1–1023 (diagonal): ZZ at adjacent qubit positions.
O(n²) per gate — statevector needs 2n complex numbers, impossible beyond ~50 qubits.
| Qubits | Time | Statevector RAM |
|---|---|---|
| 64 | <1ms | >16 PB |
| 128 | <1ms | > universe |
| 256 | <1ms | > universe |
| 512 | 2ms | > universe |
| 1,024 | 4ms | > universe |
| 2,048 | 22ms | > universe |
| 4,096 | 100ms | > universe |
Every qubit collapses to the same value — perfect quantum correlation across all 1,024 qubits.
The trajectory-MPS backend simulates noisy circuits at 127+ qubits by representing the quantum state
as a product of rank-3 tensors. Bond dimension χ tracks entanglement, not qubit count —
a 127-qubit GHZ state maintains χ = 2 throughout, making it as cheap as a 3-qubit simulation.
Noisy trajectories are embarrassingly parallel: pass workers: N for N× speedup.
P(|00…0⟩ + |11…1⟩) for an n-qubit GHZ state under depolarizing noise. Bond dimension stays at χ = 2 for all n — fidelity decays from gate errors only, not simulation approximation.
Statevector simulation of a 127-qubit circuit would require 2127 complex amplitudes — roughly 1020× more RAM than all data ever created. MPS stores O(n · χ²) numbers — linear in qubit count.
256 shots, IBM Sherbrooke noise model, single-threaded. Time scales linearly with n because χ = 2 throughout the GHZ circuit.
| Qubits | Time | χ | Statevector RAM |
|---|---|---|---|
| 10 | 5ms | 2 | 16 KB |
| 20 | 8ms | 2 | 16 MB |
| 50 | 16ms | 2 | >16 PB |
| 100 | 34ms | 2 | > universe |
| 127 | 41ms | 2 | > universe |
Each noisy trajectory is an independent simulation — distribute across OS threads with workers: N. Requires built bundle and Node.js ≥ 22.
Variational quantum eigensolver on the 12-qubit antiferromagnetic Heisenberg chain (H = Σ XiXi+1 + YiYi+1 + ZiZi+1) using MPS-based parameter-shift gradients. A 12-qubit statevector needs 128 KB — manageable — but 50+ qubits needs petabytes. MPS VQE scales to hundreds of qubits at low entanglement.
Parameter-shift gradients computed via MPS — same accuracy as statevector but O(n·χ²) memory. Each step: 2 × 36 MPS evaluations.
Bond entropies of the optimized ground state — the area-law profile confirms the Heisenberg chain has limited entanglement, making MPS the ideal representation.