Browse documentation
aner.quantum

Experimental quantum computing

Build concise quantum circuits, simulate locally on CPU, and explore an explicit backend contract for future GPU clusters and compatible physical quantum hardware.

Experimental moduleImplemented in development

Experimental module, available only in the updated native development runtime built from this source. The initial implementation executes small ideal quantum circuits on a local CPU. GPU, GPU cluster and physical quantum hardware backends are planned; their descriptors report unavailable and execution fails explicitly. Earlier published Aner binaries do not acquire this module by updating the editor.

aner.quantum lets researchers describe a quantum circuit in ordinary concise Aner, sample its measurements and combine the results with classical numerical code. The CPU examples require no new language keywords, external framework, credentials or hardware purchase.

Why quantum belongs in Aner

Aner already brings scientific data, numerical computation, machine learning and heterogeneous execution into one language. Quantum research also needs those classical capabilities: preparing inputs, generating circuit families, evaluating measurement statistics, updating parameters and comparing experiments. A dedicated module gives these workflows a common circuit and result contract while the hardware ecosystem develops.

  • Scientific computing: learn interference and entanglement locally, check small model calculations and compare sampled measurements against ideal reference probabilities. Hamiltonian simulation and chemistry are future application areas, rather than capabilities established by this prototype.
  • Machine learning: compose parameterized rotations and a classical optimizer. The runnable example below estimates a gradient from two circuit evaluations; integration with aner.nn automatic differentiation and full quantum learning models remains planned.
  • Parallel execution: independent circuits, parameter shifts and shot batches offer useful future scheduling units. Distributing one entangled state across GPUs is a separate simulation problem that requires communication between devices.
  • Reproducibility: make backend selection, shots, seed and bit ordering explicit before experiments depend on remote devices. Ideal references, sampling error and hardware error need distinct interpretations.

The value today is a working programming and validation foundation. This module does not establish a quantum speedup, scientific advantage or hardware fidelity. Quantum algorithms only offer advantages for particular problems and execution conditions; small classical baselines remain essential.

One circuit, selected backend

Aner circuit and validation lead to a working local CPU backend and planned GPU, GPU-cluster and physical quantum adapters.

The same circuit description should execute on a local CPU, a GPU cluster or compatible physical quantum hardware by changing the backend. This is the module's portability goal. Today only the CPU path is implemented:

aner
import aner.quantum

let backend = quantum.cpu()
let program = quantum.circuit(qubits: 2).h(0).cx(0, 1)
let result = program.run(backend: backend, shots: 4096, seed: 2026)
print(result.counts())

The alternative selector lines already construct descriptors, allowing programs to inspect their availability. They are not executable backends yet:

aner
let gpu = quantum.gpu()
let cluster = quantum.cluster()
let hardware = quantum.hardware(target: "configured-device")
print(gpu.available())       // false
print(cluster.available())   // false
print(hardware.available())  // false

Once adapters exist, change the backend binding and retain the circuit and sampled result code. Selecting an unavailable backend fails rather than silently running on the CPU. Creating a hardware descriptor neither contacts a provider nor submits a job. The target is an opaque future configuration identifier, not evidence that a device exists.

BackendCurrent statusWork required for the portability goal
quantum.cpu()Implemented experimental ideal statevector simulatorCPU reference and bounded shot sampling
quantum.gpu()Unavailable descriptorDevice kernels, precision/resource admission and conformance against CPU
quantum.cluster()Unavailable descriptorMulti GPU placement, state partitioning, communication and failure handling
quantum.hardware(target: String)Unavailable descriptorProvider adapter, target capabilities, native gate translation, routing, credentials and asynchronous jobs

Backend portability preserves the requested circuit semantics and sampled result interpretation. It cannot promise identical noisy observations, timing or random outcomes across devices. A hardware adapter must validate supported gates, connectivity, qubit capacity, measurement modes and shot limits before submission. Unsupported programs must be rejected or transformed with a documented equivalent lowering; a backend switch cannot make every circuit run on every device.

Future hardware lowering can use an interoperable format such as OpenQASM, whose specification explicitly permits hardware implementations to support different feature subsets. IBM's transpilation guide describes basis gate translation, physical layout and routing constraints. Export, import and provider submission are future work in Aner.

Entangle two qubits

Bell circuit: apply a Hadamard to qubit zero, then a controlled X from qubit zero to qubit one, and measure both. Only 00 and 11 occur in the ideal model.

A qubit starts in state zero. h(0) creates a superposition on the first qubit; cx(0, 1) entangles the pair into ( |00> + |11> ) / sqrt(2). A shot is one complete circuit preparation followed by a computational basis measurement of every qubit. Repeating this ideal circuit produces approximately half 00 and half 11; individual shot totals fluctuate.

Run the complete Bell example:

sh
aner check examples/quantum_bell.aner
aner run examples/quantum_bell.aner

It prints summaries and observed counts, verifies that the two correlated outcomes account for every shot, and compares an ideal probability with a sampled observable:

aner
print(result.count("00") + result.count("11") == result.shots())
print(result.probability("00")) // ideal CPU reference: approximately 0.5
print(result.sampled_z(0))      // sampled mean: approximately 0.0

The Bell correlation is not a communication channel: each individual qubit measurement is random. A classical mixture can reproduce these particular Z basis correlations; establishing entanglement experimentally also requires measurements in other bases and an appropriate witness. The simulator constructs the entangled state by its circuit model.

Qubit indices start at zero. Qubit zero is the least significant bit; printed bitstrings use q[n-1]...q[0]. Thus quantum.circuit(qubits: 2).x(0) produces "01". count and probability require a binary string with exactly the circuit's width. Count lookup returns zero for a valid unobserved outcome.

A circuit is an immutable description. Each gate call returns a new circuit; let base = quantum.circuit(qubits: 1) followed by let rotated = base.h(0) leaves base unchanged. Running does not consume or collapse the description. This first version measures all qubits at the end; it does not expose live qubit objects, arbitrary state copying, mid circuit measurement, reset or classical feed forward.

Combine quantum evaluation with classical optimization

Hybrid loop: classical parameters define a circuit; a chosen backend produces measurements; a classical objective and parameter-shift gradient update the parameters.

The complete variational example minimizes the sampled expectation of Pauli Z after one Ry rotation. It is deliberately small enough to check against the classical formula cos(theta), with minimum -1 at theta = pi modulo 2*pi.

aner
import aner.quantum

fn energy(theta: Float64, backend: QuantumBackend, seed: Int64) {
    return quantum.circuit(qubits: 1).ry(0, theta)
        .run(backend: backend, shots: 8192, seed: seed).sampled_z(0)
}

let backend = quantum.cpu()
let half_pi = 1.5707963267948966
var theta = 0.4
for step in Range(40) {
    let plus = energy(theta + half_pi, backend, 2026 + 2 * step)
    let minus = energy(theta - half_pi, backend, 2027 + 2 * step)
    theta -= 0.3 * (plus - minus) / 2.0
}
print(energy(theta, backend, 9000))

For this gate and observable, the exact derivative is (E(theta + pi/2) - E(theta - pi/2)) / 2. Finite shots produce a noisy gradient estimate. This formula must not be assumed for arbitrary parameterizations, noisy hardware or all gate generators. The classical Aner loop performs the update; aner.nn does not differentiate a QuantumCircuit or a QuantumResult.

This is a hybrid optimization teaching example, not a full variational eigensolver, chemistry model or useful quantum machine learning benchmark. More complex Hamiltonians require weighted observable terms, measurement basis changes and an explicit measurement budget. Those higher level facilities remain planned. The same sampled observable interface is intended to support compatible hardware later; exact simulator probabilities cannot be assumed available there.

Native API

Import aner.quantum to use the three opaque native types QuantumCircuit, QuantumBackend and QuantumResult. Binding and return types can be inferred. Integer inputs are Int64; angles are finite Float64 values in radians, with explicit conversions where needed.

Construction or methodResult and meaning
quantum.circuit(qubits: Int64)New QuantumCircuit initialized conceptually to all zero
quantum.cpu(), quantum.gpu(), quantum.cluster()QuantumBackend descriptor
quantum.hardware(target: String)Planned physical target descriptor; target requires 1 to 1,024 bytes
backend.available()Bool; CPU is currently the only available backend
backend.summary()Human readable backend status
circuit.h(qubit), .x(qubit), .y(qubit), .z(qubit), .s(qubit), .t(qubit)New circuit with a Hadamard, Pauli or phase gate appended
circuit.rx(qubit, angle), .ry(qubit, angle), .rz(qubit, angle)New circuit with a rotation exp(-i * angle * Pauli / 2)
circuit.cx(control, target), .cz(control, target)New circuit with controlled X or Z; distinct indices
circuit.swap(a, b)New circuit with two distinct qubits exchanged
circuit.qubits(), .gates()Int64 qubit count and gate count
circuit.summary()Human readable circuit description
circuit.run(backend: QuantumBackend, shots: Int64, seed: Int64)Execute and return an immutable QuantumResult; all three arguments are required
result.shots()Requested number of shots
result.count(bits: String)Observed count for one valid full width bitstring
result.counts()Detached Dictionary of observed bitstrings and Int64 counts, inserted in lexicographic bitstring order
result.sampled_z(qubit: Int64)Shot mean of Z: (count_zero - count_one) / shots on that qubit
result.probability(bits: String)CPU only ideal basis probability, independent of shots
result.expectation_z(qubit: Int64)CPU only ideal Z expectation, independent of shots
result.summary()Human readable execution summary

Use the backend example for a three qubit GHZ circuit and explicit availability checks. Gate and run calls use the same named argument and fluent chain rules as other Aner modules. There is no implicit global quantum backend: numerical Tensor device flags do not select a quantum backend.

Numerical, measurement and resource contract

CPU execution uses complex amplitudes with Float64 real and imaginary components. It simulates ideal unitary evolution followed by terminal Z basis sampling; it does not model decoherence, gate noise, readout error, error correction or device calibration. Small Float64 rounding errors remain possible.

probability and expectation_z inspect the ideal simulator distribution. They are reference/debugging operations, not portable physical readouts. sampled_z and counts depend on the finite shot sample. For Z outcomes in {-1, +1}, a useful sampling standard error estimate is sqrt((1 - mean*mean) / shots); finite samples, especially all equal outcomes, require care when constructing confidence intervals. This does not estimate hardware bias or model error.

The CPU prototype admits 1 to 20 qubits, 0 to 1,000,000 shots per run and at most 100,000 gates per circuit. Before allocating simulation state, it rejects a run whose gate count times 2^qubits exceeds 100,000,000 amplitude visits. shots: 0 requests exact inspection only, with an empty count dictionary; a sampled mean then has no observations and must fail explicitly. Invalid indices, equal two qubit indices, malformed bitstrings, nonfinite angles, invalid shot counts and unavailable backends fail before producing a result. Native quantum failures use a source located R3901; unavailable execution includes E_QUANTUM_BACKEND. Seeds are explicit for every run. CPU sampling uses mt19937_64 and an explicit 53 bit conversion to [0, 1); signed seeds are interpreted modulo 2^64. The same circuit, seed, shot count and backend implementation repeat the sample. Hardware randomness and cross backend identical shot sequences cannot be promised.

A dense statevector stores 2^n complex amplitudes, so the amplitude payload alone takes about 16 * 2^n bytes. That is 16 MiB at 20 qubits, 16 GiB at 30 and 16 TiB at 40, before sampling buffers, results and runtime overhead. The current cap is 20. Adding GPUs extends feasible simulation size but does not remove this exponential growth. NVIDIA's statevector algorithms documentation explains state partitioning and the global/local qubit distinction for multi GPU simulation; Aner does not integrate that library in this increment.

During CPU sampling, the simulator also allocates probabilities and a cumulative distribution, each about 8 * 2^n bytes, plus an observed count map and runtime overhead; retained results keep their probability and count data. Circuit append copies its existing gate description in O(gates) time and space, so constructing a long circuit one gate at a time performs O(gates²) aggregate copying. This prototype targets small circuits; a persistent circuit representation is a later optimization. Gate simulation costs O(gates * 2^qubits). Sampling builds an O(2^qubits) cumulative distribution, then each shot uses O(qubits) binary search/bitstring work and an ordered map insertion costing O(qubits * log(observed + 1)) in the worst case. Probability lookup is O(qubits) for bitstring validation; count lookup also searches that map. Exact Z readout scans O(2^qubits) probabilities, while sampled Z scans the observed outcomes. Export through counts() also follows the ordinary Dictionary heap/slot limits. The bounds are per object or per execution, rather than a process wide RAM quota. Keep experiments small and release unneeded results. A quantum circuit is a native opaque value, not a Tensor or an array of independently copyable physical qubits. Quantum calls and values are currently rejected inside checked parallel.repeat tasks, including constructing a circuit inside the task; use ordinary classical loops for parameter sweeps. The reserved quantum cluster descriptor does not reuse the existing neural or repetition cluster runtime.

Staged implementation and acceptance criteria

  1. CPU foundation, implemented experimentally: concise circuit construction; ideal gate kernels; explicit backend descriptors; seeded terminal sampling; exact and sampled Z readouts; bounded validation; Bell, GHZ, interference, rotations and failure tests.
  2. Portable execution contract: capability objects, versioned circuit representation, execution provenance and conformance fixtures. Separate simulator only inspection from sampled hardware compatible results. Retain requested/effective backend and precision; reject unsupported instructions explicitly.
  3. GPU and cluster simulation: validate single GPU kernels first, then distinguish independent circuit scheduling from partitioning one statevector. Compare numerical tolerances and statistical agreement with CPU; report peak memory and communication costs on measured hardware.
  4. Physical hardware adapters: add one explicit configured target with supported gate negotiation, topology aware lowering, job lifecycle, result normalization and user controlled submission. Verify bit ordering and shot accounting against simulator fixtures. Hardware access and costs must be explicit.
  5. Scientific and ML workflows: observable sums, noise models, parameter binding, reusable optimization components and selected aner.nn integration. Evaluate any claimed benefit against suitable classical baselines with complete resource accounting.

The circuit description and backend boundary make these later increments possible without requiring new syntax for every device. Experimental status permits the API to evolve as implementation and hardware evidence expose necessary constraints.

Continue with scalar mathematics, Tensor devices, Aner Neural and parallel computation. None of those existing capabilities implies a quantum GPU, cluster or hardware adapter is available today.

Aner documentation · Reference and guides