Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Capability and Support Matrix

This page records which CPU and GPU architectures each PRISM-Q backend supports, and where distributed execution stands. CPU backends are written in portable Rust and run on every supported architecture; SIMD acceleration (AVX2/FMA/BMI2 on x86-64, NEON on ARM64) is selected at runtime where a kernel exists, otherwise a scalar path is used.

Legend

MarkMeaning
YesSupported
SIMDSupported with a dedicated SIMD-accelerated kernel on this architecture
ScalarRuns, but without a dedicated SIMD kernel (portable fallback)
NoNot available for this backend
PlannedNot implemented yet; on the roadmap

Backend support by architecture

The nine CPU backends implement the Backend trait; the distributed statevector backend is a tenth, feature-gated implementation covered by the Distributed column. Planned marks only work the roadmap carries: a ROCm port of the existing CUDA kernels. Backends without a CUDA kernel have nothing to port, so their ROCm cell is No, and the roadmap carries no distributed execution for any backend other than the statevector.

Backendx86-64AVX2/FMA/BMI2ARM64NEONCUDA (NVIDIA)ROCm (AMD)Distributed
StatevectorYesSIMDYesSIMDYesPlannedYes
StabilizerYesSIMDYesSIMDYesPlannedNo
Factored StabilizerYesSIMDYesSIMDNoNoNo
SparseYesScalarYesScalarNoNoNo
MPSYesSIMDYesSIMDNoNoNo
Product StateYesScalarYesScalarNoNoNo
Tensor NetworkYesScalarYesScalarNoNoNo
FactoredYesSIMDYesSIMDNoNoNo
Density MatrixYesSIMDYesSIMDNoNoNo

The Clifford+T engines below are not Backend implementations; they serve probability, shot, and observable queries through their own routes (see Clifford+T Simulation).

Enginex86-64AVX2/FMA/BMI2ARM64NEONCUDA (NVIDIA)ROCm (AMD)Distributed
Stabilizer RankYesSIMDYesSIMDNoNoNo
Stochastic PauliYesScalarYesScalarNoNoNo
Deterministic PauliYesScalarYesScalarNoNoNo

Notes:

  • AVX2/FMA/BMI2 is the x86-64 SIMD tier. The active tier is chosen at runtime (AVX2+FMA, then FMA, then SSE2 baseline). See Threading, SIMD, and Memory Layout.
  • NEON is the ARM64 SIMD tier. Backends marked SIMD carry a NEON kernel that mirrors the x86-64 path; the rest fall back to scalar code on ARM64.
  • CUDA covers the optional gpu feature. Only the statevector and stabilizer paths have device kernels; every other backend runs on CPU. See the GPU Backend guide.
  • Distributed covers the optional distributed and distributed-mpi features. The statevector backend splits the state across MPI ranks with exact results, including gates, measurement, reset, and multi-shot sampling without gathering the dense state. Use simulate(&circuit).distributed(context). A run can start from an injected amplitude vector through .initial_state(...): every rank receives the full 2^n vector and keeps only its own slice.

Shot and observable queries above the dense cap

simulate(...).shots(n), .sample_counts(n), and .expectation_values(...) answer from a dense 2^n vector unless the backend carries its own path. The dense route is capped by system memory (roughly 29 qubits on a 16 GiB host; see PRISM_MAX_SV_QUBITS). Backends marked Native below answer without it and are bounded only by their own representation.

BackendShots and countsExpectation values
SparseNative, CDF over the stored amplitudesNative, O(k) over the amplitude map
MPSNative, sequential conditional samplingNative, one chain contraction per observable
FactoredNative, one draw per sub-stateNative, product over the blocks
Product StateNative, one Bernoulli draw per qubitNative, one closed-form factor per qubit
Distributed StatevectorNative, rank-local CDF plus one scalar per rankNative, rank-local sandwich plus one Allreduce
StatevectorDense (streams from amplitudes, no probability vector)Dense
Stabilizer, Factored StabilizerCompiled Clifford samplerSparse Pauli Dynamics, exact
Stochastic / Deterministic PauliNot applicableNative Pauli propagation
Tensor NetworkDenseNative, one doubled-network contraction per observable
Density MatrixDenseRejected, naming the backend

Native sampling is deterministic from the seed alone: the same seed and shot count reproduce the same bitstrings. It is not shot-for-shot identical to the dense route, which consumes its randomness on a different schedule; the distributions agree.

Backends without an observable path return BackendUnsupported naming themselves, so a rejected request says which engine could not serve it rather than blaming the route that selected it.

simulate(...).marginals() reads per-qubit Z expectations rather than a distribution when the resolved backend has an observable path and the circuit routes straight to it. Sparse, MPS, product state, factored, tensor network, distributed, the density matrix, and both stabilizer backends have one, and the dense output cap does not apply on that route; a Clifford circuit with measurements reads its marginals off the tableau at any width. It falls back to the dense distribution on backends without an observable path, on a circuit that splits into independent blocks unless those blocks run as product states, and under a noise model, where the mixture is read densely and the density-matrix memory limit applies instead.

Under a noise model run() and marginals() answer from the exact mixture, so both reject a model carrying readout error instead of serving one: readout acts on the measurement record rather than the state, and it is indexed by classical bit where a marginal is indexed by qubit. shots and sample_counts are the terminals that apply it.

simulate(...).run() is the one terminal that needs the whole distribution, so on the distributed backend it rejects a register past the dense cap up front rather than running first and answering with no distribution.

What kind of answer a result is

Every result type carries a metadata field describing how it was produced: the engine automatic dispatch resolved to, whether that engine can discard state weight, where the state lived, and the shot count for a sampled result.

FieldReads
backendThe engine that answered, after Auto routing
exactnessExact, or Approximate with a fidelity lower bound when the engine reports one
placementHost or Device
shotsShots drawn, None for an analytic result

Approximate marks the route rather than the run. An MPS at bond 256 on a circuit that never fills a bond truncates nothing and still reports Approximate, with a bound of 1.0: the variant answers whether the answer could have been approximated, the bound answers whether it was.

The bound describes the normalized state, which is what every read returns: a truncating MPS does not renormalize its chain, but expectation values, shot sampling, the probability vector and the exported statevector all rescale on read, so the probabilities sum to 1 at any bond cap. The discarded weight the bound reports is error in that state, not weight missing from it.

Auto sends a circuit past the statevector cap to an MPS at a bounded bond dimension, which is the only route those circuits have. It is taken by default and the result says so. simulate(...).require_exact() rejects that route instead, with an error naming the engine it would have used.

Simulate::expectation_values_reported returns the values with a standard error per value on a route that estimates rather than evaluates. An evaluated route reports Exact and no interval, so a caller distinguishes "converged" from "not estimated" without comparing a float against zero.

Not yet supported

TargetStatusNotes
ROCm (AMD GPU)PlannedNo AMD device kernels; the GPU path is CUDA-only
Distributed GPUPlannedNo multi-node GPU execution
Multi-GPUPlannedA GPU context binds a single device; sharding one statevector across devices also needs peer access between them to stay ahead of the host path
Distributed noisy shotsPlannedNoise models are rejected on the distributed backend; trajectory execution is not lockstep across ranks

These targets are listed so the matrix reflects the roadmap rather than hiding the gaps.