mimiqcircuits.backends.backend

Abstract base classes for simulator backends.

This module defines the contract every simulator must satisfy:

See Implementing a Custom Backend for a step-by-step guide.

Classes

Backend()

Abstract base class for any simulator backend.

LocalBackend()

Base class for simulators that run in the local process.

RNGs(shot, noise, trajectory, pass_)

Four independent RNG streams, one per simulation stage.

RemoteBackend()

Base class for simulators that run on a remote service.

State()

Composite simulation state held by a backend.

class mimiqcircuits.backends.backend.RNGs(shot, noise, trajectory, pass_)[source]

Bases: object

Four independent RNG streams, one per simulation stage.

Keeping the streams separate means seeding one stage (for example sampling) does not affect the determinism of another (for example noise selection), even when the same execution touches both.

shot

Sampling shots from the final state.

Type:

random.Random

noise

Kraus and mixed-unitary noise sampling.

Type:

random.Random

trajectory

Monte Carlo trajectory selection.

Type:

random.Random

pass_

Randomised compilation passes (e.g. simulated-annealing reorderers).

Type:

random.Random

Construct from a single int seed via :py:meth:`from_seed`.
shot: Random
noise: Random
trajectory: Random
pass_: Random
static from_seed(master)[source]

Derive four streams from a single master seed.

XOR-tags the seed bits per stream — cheap, deterministic, and stable across Python versions, which matters because the downstream backends must reproduce results bit-for-bit from the same input.

static from_generator(gen)[source]

Draw a master seed from gen and forward to from_seed().

__init__(shot, noise, trajectory, pass_)
class mimiqcircuits.backends.backend.State[source]

Bases: ABC

Composite simulation state held by a backend.

A state bundles three registers:

  • the quantum register (whatever representation the backend uses; state vector, MPS, tensor network, …);

  • the classical-bit register written by measurements and IfStatement outcomes;

  • the complex-valued register written by non-destructive observations (Amplitude, ExpectationValue, BondDim, …).

Required surface for every subclass:

Optional surface:

  • expectation() — backend overrides when it can compute ⟨ψ|O|ψ⟩ non-destructively (gated by the "expectation_state" capability).

  • reset() — backend overrides when it can rebuild itself in place to the zero state.

abstract property num_qubits: int

Number of qubits in the quantum register.

abstract property num_bits: int

Number of classical bits in the classical register.

abstract property num_zvars: int

Number of complex slots in the z-register.

abstract amplitude(bs)[source]
abstract sample(nsamples, rng=None, *, seed=None)[source]

Sample nsamples measurement outcomes from the state.

Exactly one source of randomness is consumed:

  • rng (positional or keyword): a random.Random whose getrandbits(63) produces the seed forwarded to the simulator’s PRNG.

  • seed (keyword): an int that seeds the simulator’s default PRNG directly.

  • neither: the simulator draws fresh cryptographic entropy.

Passing both rng and seed must raise TypeError. The two arguments are mutually exclusive.

expectation(op, *qubits)[source]

Compute ⟨ψ|op|ψ⟩ on this state.

Most backends implement expectation on the Backend rather than the State (so they can route through the simulator’s compile / evolve machinery). State-level expectation is provided as a convenience hook for backends whose quantum register supports it directly.

abstract property classical_bits
abstract property complex_values
reset()[source]
class mimiqcircuits.backends.backend.Backend[source]

Bases: ABC

Abstract base class for any simulator backend.

A concrete backend must:

Pick the right base for your simulator:

  • LocalBackend — the simulator runs in-process and you can hand it a State it mutates with each instruction.

  • RemoteBackend — the simulator runs elsewhere (cloud service, queued executor) and your wrapper submits jobs and polls for results.

See Implementing a Custom Backend.

abstract property name: str
abstract property version: str
abstract capabilities()[source]
limits()[source]
topology()[source]
can_handle(circuit)[source]

Default admission check against limits() and the backend’s advertised capabilities().

Backends with richer admission criteria (bond-dimension estimates, hardware connectivity, gate-set whitelists) should override.

Rejects (returns Inadmissible) when:

  • the circuit exceeds one of max_qubits / max_classical_bits / max_zvars declared by limits();

  • the circuit contains a loss-bearing operation (LossErr, QubitLoss) but the backend does not advertise the "loss" capability.

Returns Admissible otherwise.

stochastic_kind(op_or_instruction)[source]

Classify how this backend resolves op_or_instructionStochasticKind.Deterministic, StochasticKind.TrajectorySampleable, or StochasticKind.RuntimeOnly.

The default delegates to default_stochastic_kind() (mix-unitary Kraus is TS; non-mix-unitary Kraus, mid-circuit Measure, and LossErr are RT; everything else Deterministic). Backends that handle a specific op type differently override this method.

Backend-dependent: a MixedUnitary is TrajectorySampleable for an MPS-style sampler but could be RuntimeOnly for a backend that resolves it state-dependently. The classification lives on the backend, not on the op.

default_passes()[source]
accepts_pass(p)[source]
delegates_pass(p)[source]
abstract execute(circuit, *, nsamples=1000, seed=None, rng=None, passes=None, callback=None, param_grid=None, strict_pass_order=True)[source]

Run circuit on this backend and return QCSResults.

Pass circuit as a single Circuit or a list of circuits — a list returns a list of results in the same shape.

seed and rng are mutually exclusive sources of randomness; pass at most one. With neither, the backend draws fresh entropy. To request specific amplitudes, push Amplitude instructions into circuit and read the resulting results.zstates.

expectation(state, op, *qubits)[source]

Compute ⟨ψ|op|ψ⟩ on state non-destructively.

qubits is the list of qubit indices op acts on (0-based). Backends override when they advertise the "expectation_state" capability; the default raises NotImplementedError so undeclared backends fail loudly rather than silently degrading.

class mimiqcircuits.backends.backend.LocalBackend[source]

Bases: Backend

Base class for simulators that run in the local process.

Subclasses implement a handful of primitives and inherit a full execute() driver — the Python analog of the Julia AbstractQCSs.execute driver. Once the hooks are wired up, routing (sampling-vs-trajectory), the final-block projection circuit, loss-sampling pre-pass, and amplitude lookups all work without any per-backend duplication.

Required hooks:

  • build_state() — allocate a fresh zero state.

  • compile() — turn a Circuit into a CompiledCircuit (a backend-specific lowered form).

  • evolve() — apply the compiled circuit to a state and return the mutated state plus a typed Fidelity.

Optional hooks (sensible defaults provided):

  • prepare_trajectory() — refresh the compiled artifact once per Monte Carlo trajectory (default: identity).

  • recompile_per_trajectory() — predicate; default returns True iff the circuit contains a mixed-unitary Kraus channel.

  • bind() — substitute parameters into a parametric compile artifact (default: re-compile after substitution).

abstract build_state(nq, nb=0, nz=0, **kwargs)[source]
abstract compile(circuit)[source]
prepare_trajectory(compiled, rng)[source]

Refresh compiled for one Monte Carlo trajectory.

Override when the compiled artifact contains stochastic elements (sampled mixed-unitary channels, sampled Kraus branches, …) that must be redrawn per trajectory. The default leaves compiled unchanged, which is correct for fully deterministic compilation.

abstract evolve(state, compiled, *, rng=None, callback=None, stopped=None)[source]
recompile_per_trajectory(circuit)[source]

Return True iff compile() should be re-run for every trajectory. The default fires on any mixed-unitary krauschannel: those backends sample a branch at compile time, so the compiled artifact has to be regenerated per trajectory to expose a fresh sample. Backends that own their per-trajectory sampling internally (inside prepare_trajectory() or evolve()) should override to return False.

Mirrors the Julia AbstractQCSs.recompile_per_trajectory.

bind(compiled, params)[source]

Substitute params into a parametric compiled circuit.

The default implementation substitutes the symbols in the source circuit and re-runs compile(). This is correct but pays the full compile cost at every parameter point. Override when your backend can re-bind a pre-compiled artifact in-place (slot maps, pre-baked gate templates, …).

execute(circuit, *, nsamples=1000, seed=None, rng=None, passes=None, callback=None, param_grid=None, strict_pass_order=True, stopped=None, num_qubits=None)[source]

Run circuit on this backend and return QCSResults.

Pass circuit as a single Circuit or a list of circuits — a list returns a list of results in the same shape.

seed and rng are mutually exclusive sources of randomness; pass at most one. With neither, the backend draws fresh entropy. To request specific amplitudes, push Amplitude instructions into circuit and read the resulting results.zstates.

class mimiqcircuits.backends.backend.RemoteBackend[source]

Bases: Backend

Base class for simulators that run on a remote service.

Subclasses implement submit(), which dispatches the request and returns a job handle. The inherited execute() calls submit(), then blocks on the returned job.wait().

abstract submit(circuits, nsamples, **kwargs)[source]

Send the request and return a job handle.

The job handle must expose a wait() method that blocks until results are available and returns mimiqcircuits.QCSResults (or a list when circuits was a list).

execute(circuit, *, nsamples=1000, seed=None, rng=None, passes=None, callback=None, param_grid=None, strict_pass_order=True)[source]

Run circuit on this backend and return QCSResults.

Pass circuit as a single Circuit or a list of circuits — a list returns a list of results in the same shape.

seed and rng are mutually exclusive sources of randomness; pass at most one. With neither, the backend draws fresh entropy. To request specific amplitudes, push Amplitude instructions into circuit and read the resulting results.zstates.