Documentation

Qumulator API & SDK Reference

Organised by domain: Quantum Simulation, Molecular Chemistry, Condensed Matter, and Photonics. Full API and SDK reference with code examples.

Get Started Install SDK REST API

Quickstart

New in v0.4 — open-source local engine. The Qumulator statevector engine now ships inside the SDK — run it locally, with full source code. No qubit limits — simulate as many qubits as your hardware supports. GPU acceleration (CuPy / JAX / PyTorch) is auto-detected. No API key, no account, no network required.
pip install qumulator-sdk           # CPU — unlimited qubits
pip install "qumulator-sdk[gpu]"    # GPU — CuPy / JAX / PyTorch, auto-detected
from qumulator.local import LocalStatevectorEngine
eng = LocalStatevectorEngine(n_qubits=28)  # no hard cap — use what your hardware has
eng.apply('h', 0)
for i in range(27): eng.apply('cx', [i, i+1])
result = eng.run(shots=4096, return_entropy_map=True)

Run your first quantum circuit in under two minutes. No account, no credit card, no hardware required.

Step 1 — Get an API key

One POST request returns a key immediately. The key is displayed once — save it somewhere safe.

# cURL
curl -s -X POST https://api.qumulator.com/keys \
  -H "Content-Type: application/json" \
  -d '{"name": "my-first-key"}'
# Response
{
  "key":        "qum_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "name":       "my-first-key",
  "created_at": "2026-04-20T12:00:00Z"
}

Step 2 — Install the SDK

pip install qumulator-sdk

Step 3 — Run a Bell-state circuit

from qumulator import QumulatorClient

client = QumulatorClient(
    api_url="https://api.qumulator.com",
    api_key="qum_xxxxxxxx...",
)

# Build and run a 2-qubit Bell state
eng = client.circuit.engine(n_qubits=2)
eng.apply('h', 0).apply('cx', [0, 1])

counts = eng.sample(shots=1024)
print(counts)   # {'00': ~512, '11': ~512}
Store your key in the environment variable QUMULATOR_API_KEY and read it with os.environ["QUMULATOR_API_KEY"] to keep it out of source code.

Authentication

Every request to the API (except POST /keys) must include your API key in the X-API-Key header.

curl https://api.qumulator.com/circuits \
  -H "X-API-Key: qum_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

The Python SDK handles this automatically once you pass api_key to QumulatorClient.

Keys are not recoverable after creation. If you lose a key, generate a new one via POST /keys. There is no limit on how many keys you can create.

Base URL & Versioning

Property Value
Base URL https://api.qumulator.com
Protocol HTTPS only
Request format JSON — Content-Type: application/json
Interactive docs api.qumulator.com/docs (Swagger UI)

The API is currently unversioned (no /v1/ prefix). Breaking changes will be announced in advance.

SDK — Installation

pip install qumulator-sdk

Requires Python 3.10 or later. The core package has a single dependency: httpx. Framework adapters (Qiskit, Cirq) require those packages installed separately.

# With Qiskit adapter
pip install qumulator-sdk qiskit

# With Cirq adapter
pip install qumulator-sdk cirq

SDK — QumulatorClient

QumulatorClient is the entry point for all computation types.

from qumulator import QumulatorClient

client = QumulatorClient(
    api_url="https://api.qumulator.com",
    api_key="qum_...",
)
Attribute Type Purpose
client.circuit CircuitClient Quantum circuit simulation (gate builder, QASM, Hamiltonian evolution)
client.hamiltonian HamiltonianClient Spin ground states and Pauli Hamiltonian energy
client.hafnian HafnianClient Photonic amplitudes (hafnian, permanent, GBS)
client.homo HomoClient Molecular HOMO/LUMO frontier orbital energies
client.molecular MolecularClient Molecular ground-state energy via MPS/MPO (≤ 50 orbitals)
client.dmrg DMRGClient Exact DMRG ground-state energy via two-site sweeps (≤ 30 orbitals)
client.notebook NotebookClient Remote Jupyter notebook execution

Quantum Simulation

Submit quantum circuits via the gate builder, OpenQASM 2/3, Qiskit, or Cirq. The cluster circuit engine automatically routes each job to the most efficient backend — statevector (≤20 qubits), MPS (≤1,000 qubits), cluster-exact, Green’s function, or Gaussian — based on qubit count and entanglement structure. Results include measurement counts, the full statevector, per-qubit von Neumann entropy, QFI-based multipartite entanglement depth, and a Gaussian simulability certificate.

Entanglement depth, not qubit count, is the simulation cost driver. A 1,000-qubit MPS circuit at depth 7 completes in under 1 second. The equivalent exact statevector would require 21000 complex amplitudes — more than the number of atoms in the observable universe.

⎯⎯Explore Quantum Simulation notebooks ›

SDK — Circuit Simulation

There are two ways to construct a circuit: the fluent gate builder and the direct gate-list API. Both are equivalent and produce identical results. No simulation runs locally — all execution is server-side.

Fluent gate builder

Obtain a CircuitEngine from client.circuit.engine(), accumulate gates with .apply(), then submit with .run() or .sample().

eng = client.circuit.engine(n_qubits=3)

eng.apply('h',   0           )  # Hadamard on qubit 0
   .apply('cx',  [0, 1]       )  # CNOT: control 0, target 1
   .apply('cx',  [0, 2]       )  # CNOT: control 0, target 2
   .apply('rz',  2, params=[1.5708])  # Rz(pi/2) on qubit 2

result = eng.run(
    shots=4096,
    return_statevector=True,
    return_entropy_map=True,
)

print(result.counts)        # {'000': ~2048, '111': ~2048}
print(result.entropy_map)   # [1.0, 0.0, 0.0]  — qubit 0 maximally entangled
print(result.statevector)   # complex ndarray, length 8

Gate-list API

result = client.circuit.run(
    gates=[
        ('h',  0),
        ('cx', [0, 1]),
    ],
    n_qubits=2,
    shots=2048,
)

Supported gates

Gate(s) Qubits Params Description
h, x, y, z 1 Pauli and Hadamard
s, t, sdg, tdg 1 Phase / T gates and their adjoints
rx, ry, rz 1 [θ] Rotation gates; angle in radians
u 1 [θ, φ, λ] General single-qubit unitary (IBM U gate)
cx, cnot 2 CNOT (control, target)
cz 2 Controlled-Z
swap 2 SWAP
iswap 2 iSWAP
fsim 2 [θ, φ] fSim gate (Google Sycamore / Willow family)
syc 2 Sycamore gate
ecr 2 Echoed cross-resonance (IBM native gate)
ccx, toffoli 3 Toffoli (CCNOT)
cswap, fredkin 3 Fredkin
unitary 1–N matrix Arbitrary unitary; pass a 2N×2N complex matrix via params
Qubits are 0-indexed. For two-qubit gates, pass a list: eng.apply('cx', [0, 1]). Bitstrings in results are MSB-first: qubit 0 is the leftmost character.

engine() parameters

Parameter Type Description
n_qubits int required Number of qubits in the register
mode str Simulation mode. Default: "mps". See Simulation Modes.
bond_dim int Bond dimension cap for "cluster_mps" and "mps" modes

run() parameters

Parameter Type Default Description
shots int 1024 Measurement samples (1 to 1 000 000)
seed int None RNG seed for reproducible sampling
return_statevector bool False Include complex amplitude vector (requires N ≤ 20, "statevector" mode only)
return_probabilities bool False Include probability vector (requires N ≤ 20, "statevector" mode only)
return_entropy_map bool False Include per-qubit entanglement entropy values

SDK — OpenQASM Input

Both OpenQASM 2 and OpenQASM 3 source strings are accepted. Pass the source to client.circuit.run_qasm().

qasm_source = """
OPENQASM 3.0;
include "stdgates.inc";
qubit[3] q;
bit[3]   c;

h  q[0];
cx q[0], q[1];
cx q[0], q[2];
measure q -> c;
"""

result = client.circuit.run_qasm(
    qasm=qasm_source,
    shots=2048,
    mode="statevector",
    return_entropy_map=True,
)
print(result.counts)    # {'000': ~1024, '111': ~1024}
QASM 2 circuits exported from Qiskit are fully supported. The server handles both formats transparently. Standard gate libraries including stdgates.inc, qelib1.inc, and custom gate definitions are all supported.

Custom unitary gates via the instructions API

For gates with no standard QASM name (e.g. the SYC gate in Google Willow circuits), use the instructions input with an explicit matrix:

import numpy as np

# Arbitrary 2-qubit unitary (e.g. Google SYC gate)
my_gate = np.array([
    [1, 0,     0,   0   ],
    [0, 0,    -1j,  0   ],
    [0, -1j,   0,   0   ],
    [0, 0,     0,   np.exp(1j * np.pi / 6)],
])

eng = client.circuit.engine(n_qubits=4)
eng.apply('unitary', [0, 1], params=my_gate.tolist())
   .apply('unitary', [2, 3], params=my_gate.tolist())

result = eng.run(shots=1024)

SDK — Simulation Modes

Pass mode= to engine() or run(). The default "mps" uses the MPS backend and scales to 1,000 qubits.

Mode Best for N limit
"auto" Let the engine choose. Analyses the circuit’s entanglement graph and selects the optimal backend automatically using the Kaplan–Yorke dimension (DKY). The resolved mode and routing diagnostics are returned in result.resolved_mode and result.preflight_report. ≤ 1000
"statevector" Small circuits requiring full amplitude precision. Statevector and probability arrays available. ≤ 20
"mps" General use. Matrix Product State backend — scales to 1,000 qubits. Optimal for circuits with 1D or near-1D connectivity, VQE, QAOA, chemistry ansätze. ≤ 1000
"cluster_mps" Cluster-factorised MPS. Best for circuits with moderate entanglement and block structure — shallow random circuits, variational ansätze. ≤ 1000
"hamiltonian" Direct time evolution under a Pauli-string Hamiltonian. Use with evolve_hamiltonian(). ≤ 1000
"gaussian" Clifford-heavy circuits. Returns a GaussianCertificate classifying non-Clifford content. Memory scales as O(N²). ≤ 1000
"cluster_statevector" Exact cluster-factorisation engine. No 2N state vector is ever allocated. Memory O(∑ 2kc) where kc is the size of each entangled cluster. Exact for all circuits (TVD = 0). Returns per-qubit marginal probabilities. ≤ 1000
"greens" Green’s function / Bloch encoding. Exact within the free-fermion (Gaussian) subspace. O(N2) memory. Returns per-qubit marginals and von Neumann entropy map. Note: CNOT in the exchange subspace is not faithfully represented — use "cluster_statevector" for exact results on entangling circuits. ≤ 1000
"fibonacci_anyon" Topological quantum computing. SU(2)3 Chern–Simons Fibonacci anyons. Hilbert space dimension FN+2. Native braid gates: fibonacci_f, fibonacci_r, fibonacci_b, fibonacci_bdg. Topological XEB score available. Matches Microsoft topological qubit target. ≤ 1000
"kuramoto" Bose-Hubbard BEC / Kuramoto synchronisation. Phase-oscillator engine; superfluid order parameter r = |⟨e⟩|. O(N2) memory. Call kuramoto_diagnostics() for full phase-space output. Scales to N = 10,000+ oscillators. ≤ 10000
"cluster_gaussian" Cluster-factorised exact probability engine. Never builds 2N statevector; O(∑ 2kc) memory. Exact joint probabilities P(x) via cluster Born rule. ≤ 1000
"sparse" Adaptive sparse exact simulation. O(K log K) per gate where K = active basis states. Up to 78× faster than dense statevector for GHZ / particle-conserving circuits. Automatically hands off to MPS when K exceeds the MPS crossover threshold. Unlimited (K ≪ 2N)
Depth limits apply depending on qubit count. Exceeding a tier limit returns HTTP 422 with a self-documenting error. See Simulation Limits.

Auto-routing

When mode="auto" is used, the engine builds the circuit’s entanglement graph, estimates the fractal dimension DKY of its entanglement structure, and routes to the optimal backend before simulation begins. Tree-topology circuits are routed to "mps"; Clifford-only circuits to "gaussian"; high-entanglement small circuits to "statevector". No simulation cost is incurred for the analysis. Use POST /circuits/preflight to inspect the routing decision without running a simulation at all (zero compute units).

Hamiltonian evolution

Use mode="hamiltonian" and call evolve_hamiltonian() to apply e−iHt directly from a Pauli-string Hamiltonian, without requiring a gate decomposition.

eng = client.circuit.engine(n_qubits=4, mode="hamiltonian")

eng.apply('h', 0).apply('h', 1)  # initial state preparation

eng.evolve_hamiltonian(
    pauli_terms=[
        ( 0.5,  'ZZII'),   # ZZ coupling on sites 0-1
        ( 0.5,  'IZZI'),   # ZZ coupling on sites 1-2
        (-1.0, 'XIIX'),   # transverse field
    ],
    t=1.0,  # evolution time
)

result = eng.run(shots=2048, return_entropy_map=True)

Pauli strings use I X Y Z per qubit; the leftmost character is qubit 0.

Gaussian mode and the simulation certificate

eng = client.circuit.engine(n_qubits=20, mode="gaussian")

for i in range(20):
    eng.apply('h', i)
for i in range(0, 19, 2):
    eng.apply('cz', [i, i+1])
eng.apply('t', 5)   # non-Clifford gate

result = eng.run(shots=1024)
cert   = result.gaussian_certificate

print(cert.rcs_certificate)            # "LIKELY_GAUSSIAN"
print(cert.entanglement_regime)        # "area_law"
print(cert.gaussian_fidelity)          # 0.991
print(cert.wigner_negativity_estimate) # small positive float
Certificate label Meaning
GAUSSIAN_SIMULABLE Purely Clifford circuit; Gaussian approximation is exact.
LIKELY_GAUSSIAN Non-Clifford content is small; high-fidelity approximation.
NON_GAUSSIAN_CORRECTION_NEEDED Substantial non-Clifford content; switch to "statevector" or "cluster_mps" for full accuracy.

SDK — Qiskit Integration

QumulatorBackend is a drop-in replacement for any Qiskit simulator backend. Build your circuit in Qiskit as normal; the adapter transpiles and runs it on Qumulator.

from qumulator import QumulatorClient
from qumulator.backends.qiskit_backend import QumulatorBackend
from qiskit import QuantumCircuit

client  = QumulatorClient(api_url="https://api.qumulator.com", api_key="qum_...")
backend = QumulatorBackend(client)

qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

job    = backend.run(qc, shots=2048)
result = job.result()
counts = result.get_counts()
print(counts)   # {'00': ~1024, '11': ~1024}
Bit ordering: Qiskit places qubit 0 as the least-significant bit. The adapter reverses bitstrings at output so get_counts() returns Qiskit-standard keys. No changes to your existing code are needed.

Specifying a simulation mode

# cluster_mps mode for a large variational circuit
backend = QumulatorBackend(client, mode="cluster_mps")
job     = backend.run(qc, shots=8192)

Using with Qiskit VQE / QAOA

Any Qiskit circuit can be sent to Qumulator. The adapter automatically transpiles to the supported gate set. Gates that expose gate.to_matrix() are submitted as arbitrary unitaries and simulated exactly.

# Run your parameterised ansatz on Qumulator instead of a local simulator
bound_circuit = ansatz.assign_parameters(theta_values)
bound_circuit.measure_all()

job = backend.run(bound_circuit, shots=4096)
counts = job.result().get_counts()
expectation_value = compute_energy(counts, hamiltonian)

SDK — Cirq Integration

QumulatorSimulator implements Cirq's Simulator interface and supports both sampling and statevector simulation.

import cirq
from qumulator import QumulatorClient
from qumulator.backends.cirq_simulator import QumulatorSimulator

client = QumulatorClient(api_url="https://api.qumulator.com", api_key="qum_...")
sim    = QumulatorSimulator(client)

q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
    cirq.H(q0),
    cirq.CNOT(q0, q1),
    cirq.measure(q0, q1, key='result'),
)

# Sampling
result = sim.run(circuit, repetitions=1024)
print(result.histogram(key='result'))  # Counter({0: ~512, 3: ~512})

# Statevector
sv = sim.simulate(circuit)
print(sv.final_state_vector)
# array([0.707+0j, 0+0j, 0+0j, 0.707+0j])
All Cirq gates are submitted via cirq.unitary(), so any gate with a unitary representation is supported — including custom operations and Sycamore-family gates.

Google Sycamore / Willow circuits

q = cirq.LineQubit.range(4)
circuit = cirq.Circuit(
    [cirq.H(qi) for qi in q],
    cirq.SYC(q[0], q[1]),
    cirq.SYC(q[2], q[3]),
    [cirq.measure(qi, key=str(i)) for i, qi in enumerate(q)],
)
result = sim.run(circuit, repetitions=2048)

Molecular Chemistry

Compute molecular properties directly from SMILES strings or PySCF active-space integrals (1e/2e arrays). Three complementary methods are available: HOMO/LUMO frontier orbital energies via DFT (B3LYP/6-31G* default; any basis and functional supported); MPS/MPO ground-state energies for multi-fragment active spaces up to 50 orbitals; and DMRG for exact FCI-quality energies up to 30 orbitals with systematic bond-dimension convergence.

Chemical accuracy target: < 1 mHa (≈ 0.6 kcal/mol). Verified on H2, LiH, and N2 against full-CI references with 100 % correlation energy recovery.

⎯⎯Explore Molecular Chemistry notebooks ›

SDK — Molecular Orbitals

Compute HOMO and LUMO frontier orbital energies from a SMILES string. Results include the HOMO–LUMO gap and per-atom orbital density weights.

# Resveratrol
result = client.homo.run("Oc1ccc(/C=C/c2cc(O)cc(O)c2)cc1")

print(result.homo_E_eV)    # -5.515 eV  (B3LYP/6-31G*)
print(result.lumo_E_eV)    # -0.821 eV
print(result.gap_eV)       # HOMO-LUMO gap in eV
print(result.heavy_symbols) # ['C', 'C', ..., 'O', 'O']
print(result.homo_density)  # per-heavy-atom HOMO weight

Basis set and functional

# Use a larger basis set and a different functional
result = client.homo.run(
    "c1ccccc1",   # benzene
    basis="6-31g",
    xc="pbe0",
)

HomoResult fields

Field Type Description
homo_E_eV float HOMO energy in eV
lumo_E_eV float LUMO energy in eV
gap_eV float HOMO–LUMO gap in eV
homo_density list[float] Per-heavy-atom HOMO orbital density
lumo_density list[float] Per-heavy-atom LUMO orbital density
heavy_symbols list[str] Element symbol for each heavy atom
n_occ int Number of occupied orbitals
basis str Basis set used (default: 6-31g*)
xc str Exchange-correlation functional (default: b3lyp)

SDK — Molecular Energy (MPS/MPO)

Compute the quantum ground-state energy of an active-space Hamiltonian using the Givens-MPS / Matrix Product Operator (MPS/MPO) engine. Accepts one-body and two-body integrals extracted from any PySCF active-space calculation.

from pyscf import gto, scf, mcscf, ao2mo

# Build molecule and extract active-space integrals
mol = gto.M(atom="H 0 0 0; H 0 0 0.74", basis="sto-3g")
mf  = scf.RHF(mol).run()
mc  = mcscf.CASSCF(mf, ncas=2, nelecas=2).run()

h1e, e_core = mc.get_h1eff()
h2e  = ao2mo.restore(1, mc.get_h2eff(), mc.ncas)
e_nuc = mc.energy_nuc() + e_core

# Call the MPS/MPO engine
result = client.molecular.energy(
    h1e=h1e.tolist(),
    h2e=h2e.tolist(),
    n_elec=[1, 1],
    e_nuc=float(e_nuc),
)

print(result.energy)        # ground-state energy in Ha
print(result.n_qubits)      # 2 × n_orb spin-orbitals
print(result.n_components)  # MPS bond dimension (entanglement measure)

With Givens rotation circuit

circuit = [
    {"type": "givens", "i": 0, "j": 1, "theta": 0.3},
]
result = client.molecular.energy(
    h1e=h1e.tolist(), h2e=h2e.tolist(),
    n_elec=[1, 1], e_nuc=float(e_nuc),
    circuit=circuit,
)

MolecularEnergyResult fields

Field Type Description
energy float Ground-state energy in Hartrees
n_qubits int Spin-orbitals = 2 × n_orb
n_orb int Active orbitals
n_components int MPS bond dimension
zz_correlators list[list[float]] | None ⟨ZiZj⟩ correlator matrix

Limits

Parameter Limit
n_orb ≤ 30
Default timeout 300 s

SDK — DMRG Ground-State Energy

Compute the quantum ground-state energy using the Density Matrix Renormalization Group (DMRG) engine. DMRG sweeps converge systematically to the exact FCI limit as the bond dimension d_max increases.

result = client.dmrg.energy(
    h1e=h1e.tolist(),
    h2e=h2e.tolist(),
    n_elec=[1, 1],
    e_nuc=float(e_nuc),
    d_max=64,      # bond dimension — higher = more accurate
    n_sweeps=8,    # number of DMRG sweeps
)

print(result.energy)        # ground-state energy in Ha
print(result.converged)     # True if |ΔE| < tol
print(result.wall_time_s)   # server-side runtime

Recommended d_max by active space size

Active orbitals d_max n_sweeps
≤ 6 16–32 8
6–12 64 8–12
12–20 128–256 10–20
20–30 256–512 15–50

DMRGEnergyResult fields

Field Type Description
energy float Ground-state energy in Hartrees
converged bool True if |ΔE| < tol
n_sweeps_run int Sweeps performed
d_max_used int Bond dimension used
n_orb int Active orbitals
n_so int Spin-orbitals = 2 × n_orb
wall_time_s float Server-side wall time (s)

Limits

Parameter Limit
n_orb ≤ 30
d_max ≤ 512
n_sweeps ≤ 50
Default timeout 900 s

Condensed Matter

Compute ground states and real-time dynamics of lattice spin models via exact diagonalisation (Pauli-string Hamiltonian input) or TEBD (Time-Evolving Block Decimation). Supported Hamiltonian presets include the transverse-field Ising model (TFIM), XX free-fermion chain, Heisenberg XXX, Kuramoto–Ising, and the AKLT spin-1 chain. Observable outputs include per-bond von Neumann entropy, QFI density, magnetisation trajectory, Kibble–Zurek defect density, and the AKLT hidden string order parameter Ostring.

⎯⎯Explore Condensed Matter notebooks ›

SDK — Spin Ground States

Compute ground-state energies for interacting spin systems or arbitrary Pauli-string Hamiltonians. Returns the minimum energy configuration plus a per-site entanglement entropy map.

Pauli Hamiltonian (recommended)

Pass a dictionary of Pauli-string → coefficient entries. Each key is an N-character string over {I, X, Y, Z}, one character per site.

# H2 molecule — STO-3G, Jordan-Wigner mapping (2 sites)
result = client.hamiltonian.run(
    pauli_hamiltonian={
        "II": -1.8572750,   # constant / nuclear repulsion
        "ZI": -0.3979374,
        "IZ": -0.3979374,
        "ZZ":  0.3980202,
        "XX":  0.1809270,
        "YY":  0.1809270,
    },
)
print(result.energy)       # ground-state energy in Hartree
print(result.entropy_list) # per-site entanglement entropy

Ising / Heisenberg J-matrix

import numpy as np

N = 16
J = np.random.randn(N, N)
J = (J + J.T) / 2  # symmetrize
np.fill_diagonal(J, 0)

result = client.hamiltonian.run(interaction_matrix=J.tolist())
print(result.energy)   # ground-state energy
print(result.states)   # per-site spin expectation values
print(result.max_S)    # max bipartite entanglement entropy

SpinGroundStateResult fields

Field Type Description
energy float Ground-state energy
states list[float] Per-site expectation values
entropy_list list[float] Per-site entanglement entropy
max_S float Maximum bipartite entanglement entropy
mean_S float Mean entanglement entropy across all bipartitions

SDK — Hamiltonian Time Evolution (TEBD)

The client.evolve sub-client provides Hamiltonian time evolution via TEBD (Time-Evolving Block Decimation) and exact state preparation. Six endpoints are available:

Method Description
client.evolve.run() Real-time TEBD evolution (Suzuki-Trotter 1st/2nd order). Returns a trajectory list of observables (entropy, magnetization, QFI) at each timestep.
client.evolve.quench() Sudden quench / collapse-and-revival protocol. Returns trajectory + optional C_tR ZZ-correlator heatmap.
client.evolve.ground() Imaginary-time evolution to the ground state. Returns energy, bond_entropy, and converged.
client.evolve.aklt() Exact AKLT Valence Bond Solid state preparation (depth-O(1), χ=2 MPS). Returns bond entropy, phase labels, and hidden string order parameter Ostring.
client.evolve.qkzm() Kibble-Zurek quench protocol. Returns kzm_defect_density, kzm_prediction, and tau_Q.
client.evolve.lattice() 2D lattice regime classifier. Returns bond_entropy_2d heatmap and phase_label.

Real-time evolution

# 10-site transverse-field Ising model, critical point J=h=1
result = client.evolve.run(
    n_qubits=10,
    hamiltonian={"preset": "ising_1d", "J": 1.0, "h": 1.0},
    t_max=2.0,
    dt=0.1,
    bond_dim=64,
    observables=["entropy", "magnetization", "qfi"],
    initial_state="ferromagnet",
    order=2,
)

for pt in result.trajectory:
    print(pt["t"], pt.get("max_entropy"), pt.get("f_Q_density"))

Ground state preparation (imaginary time)

gs = client.evolve.ground(
    n_qubits=10,
    hamiltonian={"preset": "ising_1d", "J": 1.0, "h": 1.0},
    bond_dim=64,
)
print(gs.energy)        # ground-state energy
print(gs.bond_entropy)  # per-bond von Neumann entropy

QKZM Kibble-Zurek quench

qkzm = client.evolve.qkzm(
    n_qubits=20, J=1.0, h0=5.0, h_f=0.2, t_ramp=5.0,
)
print(qkzm.kzm_defect_density)   # n_d ∝ τ_Q^{−1/2}
print(qkzm.kzm_prediction)

Hamiltonian presets

Preset Model Parameters
"ising_1d" Transverse-field Ising chain J, h
"xx_model" XX free-fermion chain t
"heisenberg" XXX Heisenberg chain J
"kuramoto_ising" Kuramoto-Ising H (DM coupling) J, K
"aklt" AKLT spin-1 chain (Haldane phase, 2 qubits per spin-1 site) J_AF, J_FM

Custom Pauli-sum Hamiltonians are also supported via terms: each term is {"sites": [i, j], "operator": "ZZ", "strength": -1.0}.

SDK — AKLT Valence Bond Solid

The AKLT model (Affleck-Kennedy-Lieb-Tasaki, 1987) is a spin-1 chain with an exactly-known ground state called the Valence Bond Solid (VBS). It is the prototypical example of a symmetry-protected topological (SPT) phase — the Haldane phase — and a universal resource for measurement-based quantum computation (MBQC).

Signature observables

Observable Expected value Meaning
Bond entropy S 1.000 bit (inter-site bonds exact) One singlet = one ebit per virtual bond; entanglement label "topological_class". Intra-site bonds S = 0 ("product_state").
Max bond dimension χ 2 (all chain lengths) Minimum non-trivial MPS; area-law entanglement
String order Ostring −1/4 = −0.250 (constant) Hidden Z₂×Z₂ order in the 2-qubit virtual-bond encoding; constant for all site separations; vanishes outside the Haldane phase
Haldane gap Δ ≈ 0.41 J Finite gap protecting the SPT phase

MPS bond entanglement regime labels

phase_labels is a list of per-bond entanglement regime identifiers, derived from the von Neumann entropy S of each MPS bond's Schmidt decomposition. These labels are standard quantum-information terminology and apply to all TEBD endpoints.

Label Entropy range Description
"product_state" S < 0.1 bits Unentangled — qubits on either side of the bond are independent
"area_law" 0.1–0.6 bits Bounded entanglement; MPS-tractable at any depth
"topological_class" 0.6–1.2 bits SPT / topological phase regime — the AKLT VBS inter-site bond has S = 1 bit and lands here exactly
"near_volume_law" 1.2–2.5 bits High entanglement, approaching volume-law
"volume_law" S ≥ 2.5 bits Near-maximal entanglement — Haar-random / deep circuit regime

Exact VBS state preparation

# Prepare exact AKLT VBS for 10 spin-1 sites (20 qubits), no TEBD needed
vbs = client.evolve.aklt(
    n_sites=10,
    observables=["entropy", "string_order", "qfi"],
    string_order_pairs=[[0, 9], [1, 8], [2, 7]],
)

print(vbs.max_bond_dim)         # 2 — exact χ=2 MPS
print(vbs.mean_bond_entropy)    # ≈ 0.50 bits (inter-site=1.0, intra-site=0.0)
print(vbs.phase_labels[1])        # "topological_class" (inter-site bonds, S=1 bit — SPT/Haldane regime)
print(vbs.string_order)         # {"O_string(0,9)": -0.250, ...}

Ground state via imaginary-time TEBD

# Use "aklt" preset: n_qubits = 2 × n_sites
# initial_state="neel" is required — the default |0…0⟩ is a fixed point
gs = client.evolve.ground(
    n_qubits=20,
    hamiltonian={"preset": "aklt", "J_AF": 1.0, "J_FM": 2.0},
    initial_state="neel",
    dtau=0.05,
    n_steps=400,
    bond_dim=4,
)
print(gs.energy)       # converges to AKLT ground energy
print(gs.converged)    # True

Real-time dynamics

dyn = client.evolve.run(
    n_qubits=20,
    hamiltonian={"preset": "aklt"},
    t_max=5.0,
    dt=0.05,
    observables=["entropy", "magnetization"],
)

AKLT Hamiltonian — technical details

Each spin-1 site is encoded in 2 qubits: qubit 2i is the left virtual spin-1/2 and qubit 2i+1 is the right virtual spin-1/2. The Hamiltonian contains only nearest-neighbour qubit interactions, fully compatible with the TEBD engine:

Bond type Qubits Operator Strength Physics
Inter-site (AF) (2i+1, 2i+2) XX + YY + ZZ JAF/4 Singlet formation on virtual bond
Intra-site (FM) (2i, 2i+1) XX + YY + ZZ JFM/4 Enforces symmetric (triplet) subspace

Photonics

Compute hafnian and permanent amplitudes for Gaussian boson sampling (GBS) circuits. Input is a symmetric coupling matrix A of dimension 2m×2m for an m-mode GBS device. Results are computed in arbitrary-precision arithmetic (configurable via mp_dps, default 34 decimal digits) and verified against double-precision references to below 5×10−15 relative error. An 8-mode hafnian completes in 39 ms; 12-mode in 43 ms.

⎯⎯Explore Photonics notebooks ›

SDK — Photonic Amplitudes

Compute the hafnian, permanent, or Gaussian boson sampling amplitudes from a symmetric coupling matrix. The result is a complex number computed to configurable precision.

import numpy as np

n = 8
A = np.random.randn(n, n)
A = (A + A.T) / 2
np.fill_diagonal(A, 0)

result = client.hafnian.run(matrix_real=A.tolist())

print(result.value)    # complex: haf_real + 1j*haf_imag
print(result.elapsed)  # server compute time in seconds

Complex matrices and precision

# Complex coupling matrix, 50 decimal digits of precision
result = client.hafnian.run(
    matrix_real=A_real.tolist(),
    matrix_imag=A_imag.tolist(),
    mp_dps=50,   # default: 34
)

HafnianResult fields

Field Type Description
haf_real float Real part of the hafnian
haf_imag float Imaginary part
value complex Property: haf_real + 1j*haf_imag
elapsed float Server-side compute time (seconds)
max_S float Maximum coupling entropy
n_edges int Number of non-trivial coupling pairs
est_matchings float Estimated number of perfect matchings

SDK — Notebook Execution

Submit a Jupyter notebook (.ipynb) for remote execution. The notebook runs in an isolated sandbox environment with qumulator-sdk and the full scientific Python stack pre-installed.

# Submit and wait for completion
with open("my_experiment.ipynb", "rb") as f:
    nb_bytes = f.read()

status = client.notebook.run(nb_bytes)
print(status.status)   # "completed"
# status.result contains the executed notebook with outputs

Async: submit then poll

import time

with open("my_experiment.ipynb", "rb") as f:
    job_id = client.notebook.submit(f.read())

print("Job submitted:", job_id)

while True:
    status = client.notebook.status(job_id)
    if status.is_done:
        break
    time.sleep(3)

if status.ok:
    executed_notebook = status.result
else:
    print("Failed:", status.error)
Pre-installed packages: numpy, scipy, matplotlib, pandas, qiskit, cirq, and qumulator-sdk. Additional packages can be installed at the top of your notebook with !pip install ....

Quantum Simulation Notebooks

Gate-level circuit simulation, benchmarks against real quantum hardware, and algorithm demonstrations.

Notebook Description
Willow RCS Benchmark 105-qubit exact simulation on a Willow-layout SYC grid — XEB fidelity validation
CHSH Bell Inequality Bell state + CHSH correlator, S = 2√2 Tsirelson bound
Cluster Engine Demo Exact simulation without 2N state vector — mode="cluster_statevector"
Prime Factorization Shor’s algorithm — factors N=35 via quantum-inspired energy landscape
QUBO Optimisation 100-variable dense combinatorial optimisation — QAOA / variational
Green’s Function Engine Free-fermion circuits, O(N²) memory, entropy map — mode="greens"
Cluster Geometry Entanglement growth in random H/CX/Rz brickwork circuits

Molecular Chemistry Notebooks

Ab-initio ground state energies, orbital visualisation, and DMRG solvers for real molecules.

Notebook Description
N₂ Ground State 12-qubit exact simulation — CASCI(6,6), 79 kcal/mol correlation recovered (100%), 3.2 s
H₂ Ground State Exact 4-qubit simulation — CASCI(2,2)/STO-3G, 100% correlation recovery
LiH Ground State Pauli-Hamiltonian DMRG solver — 1.15 mHa error, chemical accuracy
H₁₂ Chain Ground State 12-site Ising chain via Hamiltonian solver — client.hamiltonian

Condensed Matter Notebooks

Many-body physics: topological phases, non-Abelian anyons, Floquet dynamics, and holographic protocols.

Notebook Description
Holographic Wormhole Traversable wormhole protocol (SYK model) — matches Google Sycamore 2022
Anyon Braiding Fibonacci anyons, SU(2)3 Chern–Simons non-Abelian braiding — matches Microsoft topological target — mode="fibonacci_anyon"
Discrete Time Crystal MBL Floquet dynamics, discrete time-translation symmetry breaking — matches Google Sycamore 2021
Collapse & Revival / QKZM TEBD Hamiltonian time evolution, Kibble-Zurek scaling — client.evolve
Kuramoto BEC N=500 Bose-Hubbard superfluid–Mott transition — Kuramoto order parameter r, condensate fraction — mode="kuramoto"
Sparse Circuit Engine GHZ at N=500, Givens particle-conserving circuits — up to 78× speedup over dense statevector — mode="sparse"

Photonics Notebooks

Gaussian boson sampling, hafnian amplitudes, and photonic quantum advantage.

Notebook Description
Boson Sampling Demo GBS correctness baseline, 8×8–12×12 hafnians, self-XEB at N=12, exact N=1,000 simulation — five independent capability demonstrations
Hafnian Benchmark 4×4 → 16×16 GBS matrices — compute time scaling, verified against thewalrus reference to <10&sup-10; relative error
GBS Output Distribution Full photon-number probability distribution for a 4-mode squeezed-vacuum GBS experiment — enumerates all patterns up to 6 photons, normalisation verified
Permanent vs Hafnian Distinguishable vs identical photons through a linear optical network — Hong-Ou-Mandel dip confirmed: P(1,1)=0 for bosons, P(1,1)=0.5 classically
Quantum Advantage Threshold Jiuzhang-style scaling analysis — classical spoofability crossover, log-scale extrapolation, Jiuzhang-2020 overlay at 50 photons, signed speedup certificate

Miscellaneous Notebooks

Quantum computing applied to everyday problems — no physics background required.

Notebook Description
European Call Option Pricer Quantum amplitude estimation vs Black-Scholes — <1% error on a 5-qubit circuit
Fantasy Football Lineup Optimizer DraftKings salary-cap QUBO solved with the Hamiltonian engine

REST API — API Keys

Create a key

POST /keys

No authentication required.

Field Type Description
name string Human-readable label
# Response 201
{
  "key":        "qum_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "name":       "my-key",
  "created_at": "2026-04-20T12:00:00Z"
}

REST API — Circuits

Submit a circuit

POST /circuits

Returns job_id immediately. Simulation runs asynchronously.

Field Type Description
qasm string OpenQASM 2 or 3 source. Provide either qasm or instructions.
instructions array JSON gate instruction list. Requires n_qubits.
n_qubits int Register width. Required when using instructions.
shots int Measurement samples. Default: 1024. Max: 1 000 000.
mode string Simulation mode. Default: statevector.
seed int RNG seed for reproducible sampling.
return_statevector bool Include complex amplitude vector in result.
return_entropy_map bool Include per-qubit entropy values in result.
bond_dim int Bond dimension cap for tensor-network modes.
# Submit via cURL
curl -X POST https://api.qumulator.com/circuits \
  -H "X-API-Key: qum_..." \
  -H "Content-Type: application/json" \
  -d '{
    "qasm": "OPENQASM 3.0; include \"stdgates.inc\"; qubit[2] q; h q[0]; cx q[0],q[1]; bit[2] c; measure q->c;",
    "shots": 1024,
    "mode": "statevector"
  }'

# Response 202
{ "job_id": "01HX8M7PVKTA..." }

List recent circuits

GET/circuits

Returns the most recent circuit jobs for your API key.

Get a circuit job

GET/circuits/{job_id}

REST API — Jobs & Polling

All simulation endpoints return a job_id immediately. Poll until status is "completed" or "failed".

# Poll a job
curl https://api.qumulator.com/circuits/01HX8M7PVKTA \
  -H "X-API-Key: qum_..."

# While running
{ "job_id": "01HX...", "status": "running", "result": null }

# When complete
{
  "job_id":            "01HX...",
  "status":            "completed",
  "entanglement_dof":  3.8124,
  "dof_converged":     true,
  "result": {
    "counts":      { "00": 512, "11": 512 },
    "n_qubits":    2,
    "shots":       1024,
    "entropy_map": [1.0, 1.0]
  }
}
Status Meaning
queued Accepted and waiting for a worker
running Simulation in progress
completed Result available in result field
failed Error message in error field

Reference — Result Types

CircuitResult

Field Type Description
counts dict[str, int] Measurement outcome counts. Keys are MSB-first bitstrings (qubit 0 leftmost).
n_qubits int Register width
shots int Total measurement samples
statevector ndarray|None Complex amplitude vector of length 2N. Populated when return_statevector=True.
probabilities ndarray|None Probability vector. Populated when return_probabilities=True.
entropy_map list[float]|None Per-qubit entanglement entropy in bits. 1.0 = maximally entangled; 0.0 = product state.
f_Q_density float|None QFI density (Tóth–Gühne 2012). f_Q > k certifies genuine (k+1)-partite entanglement. 0.0 for product states.
entanglement_depth int|None Certified entanglement depth = ⌊f_Q⌋. 0 = separable; k = genuine (k+1)-partite entanglement.
predicted_tvd float|None TVD upper bound to the exact distribution. 0.0 for unconditionally exact modes ("statevector", "cluster_statevector").
phase_label str|None Entanglement-phase label (Z1–Z5) returned when using mode="phase".
gaussian_certificate GaussianCertificate|None Populated when mode="gaussian".
most_probable str (property) Bitstring with the highest count

GaussianCertificate

Field Type Description
rcs_certificate str GAUSSIAN_SIMULABLE | LIKELY_GAUSSIAN | NON_GAUSSIAN_CORRECTION_NEEDED
entanglement_regime str|None area_law | transitional | volume_law
wigner_negativity_estimate float|None Estimated non-Clifford correction from T-gate content
gaussian_fidelity float|None Estimated fidelity of the Gaussian approximation (0–1)
xeb_lower_bound float|None Cross-entropy benchmark lower bound

JobStatus

Field Type Description
job_id str Job identifier
status str queued | running | completed | failed
result dict|None Engine result when completed
error str|None Error message when failed
is_done bool Property: True when completed or failed
ok bool Property: True when completed
entanglement_dof float|None Effective entanglement degrees of freedom at job completion. Computed as (Σσi)² / Σσi² from the singular-value spectrum of the off-diagonal 1-RDM block. 0.0 = product state; N/2 = maximally entangled. null for non-circuit jobs.
dof_converged bool|None true when entanglement DOF has stopped growing between layers (relative change < 1 %). Indicates the circuit has reached entanglement saturation — additional depth will not increase correlation. null when entanglement_dof is not available.

Reference — Simulation Limits

Circuit depth, not qubit count, determines memory. Requests exceeding a tier limit return HTTP 422 with a self-documenting error message.

Tier Qubit range Max depth Peak memory Notes
1 1–20 20 layers ~335 MB Full-depth VQE, QAOA, variational ansätze at any structure.
2 21–54 9 layers ~216 MB Covers IBM Eagle (27 q) and Osprey (54 q) layouts.
3 55–105 8 layers ~105 MB Covers Willow-scale (105 q) near-term superconducting layouts.
4 106–1000 7 layers ~250 MB At depth 7, a 1,000-qubit circuit uses ~250 MB — within the platform's 350 MB cap.
N > 1000 Rejected (HTTP 422). Contact us for large-scale access.
"statevector" mode is limited to N ≤ 20 (Tier 1 only). All modes follow the tier depth limits above.

Reference — Rate Limits

Limit Value
Circuit simulations per key per minute 1
Circuit simulations per key per day 100
Window type Rolling 60-second window
HTTP status when exceeded 429 with Retry-After header

The Retry-After header tells you exactly how many seconds to wait. The SDK surfaces this as QumulatorHTTPError(status_code=429).

from qumulator import QumulatorHTTPError
import time

try:
    result = eng.run(shots=1024)
except QumulatorHTTPError as e:
    if e.status_code == 429:
        retry_after = int(e.response.headers.get("Retry-After", 10))
        time.sleep(retry_after)
        result = eng.run(shots=1024)   # retry once

Reference — Errors

All error responses use the shape {"detail": "...message..."}.

Status Meaning
400 Malformed JSON or missing required field.
401 Missing or invalid X-API-Key header.
422 Validation error — circuit exceeds a tier limit, unknown gate, or unsupported mode. The response body includes a self-documenting message with the full tier table.
429 Rate limit exceeded. Check the Retry-After header.
500 Internal server error. Retry after a moment; contact us if it persists.
# Example 422 response (circuit exceeds tier limit)
{
  "detail": "Limit Exceeded: 30 qubits at depth 15. Tier 2 (21-54 q) max depth is 9.
  Tiers: T1(1-20q,d≤20) T2(21-54q,d≤9) T3(55-105q,d≤8) T4(106-1000q,d≤7)"
}
Questions, bug reports, or large-scale access requests? Contact us via the main site.