API reference

Backend

class mimiq_qiskit.MimiqBackend(runner, *, name='mimiq', num_qubits=64, description=None, provider=None)[source]

Qiskit BackendV2 powered by MIMIQ.

Parameters:
  • runner (Any) – A MIMIQ connection, a MIMIQ Backend instance, or a (circuit, *, nsamples, seed) -> QCSResults callable.

  • name (str) – Backend name reported to Qiskit. Defaults to "mimiq".

  • num_qubits (int) – Qubit count advertised on the Target. The MIMIQ cloud handles many more; raise this when transpiling wide circuits against the backend.

  • description (str | None) – Human-readable backend description.

Beyond shots and seed, run accepts MIMIQ-specific options which are forwarded to MIMIQ when set: the circuit-preparation knobs fuse, fuse_threshold, canonicaldecompose, reorderqubits, remove_swaps, and the simulator/job settings bonddim, entdim, mpscutoff, mpsmethod, mpotraversal, timelimit, noisemodel, label.

property max_circuits: int | None

The maximum number of circuits that can be run in a single job.

If there is no limit this will return None

property num_qubits: int

Return the number of qubits the backend has.

run(run_input, **options)[source]

Convert and submit one circuit or a list of circuits to MIMIQ.

Parameters:
  • run_input – A QuantumCircuit or an iterable of them.

  • **optionsshots and seed, plus any of the MIMIQ-specific run options listed on the class. Options set here override the backend defaults for this call.

Return type:

MimiqJob

Returns:

A MimiqJob running the whole batch as one MIMIQ job; call job.result() to block for the qiskit.result.Result.

property target: Target

A qiskit.transpiler.Target object for the backend.

Return type:

Target

class mimiq_qiskit.MimiqJob(backend, *, qiskit_circuits, work, shots, job_id=None)[source]

Background-thread job. One thread per run() call.

work is a zero-argument callable returning the list of QCSResults (one per submitted circuit); the whole batch is one MIMIQ job.

Parameters:
cancel()[source]

Attempt to cancel the job.

Return type:

None

result(timeout=None)[source]

Return the results of the job.

Parameters:

timeout (float | None)

Return type:

Result

status()[source]

Return the status of the job, among the values of JobStatus.

Return type:

JobStatus

submit()[source]

Submit the job to the backend for execution.

Return type:

None

class mimiq_qiskit.MimiqProvider(runner, *, num_qubits=64)[source]

Expose the MIMIQ backend for a single connection or runner.

Example:

from mimiqlink import MimiqConnection
from mimiq_qiskit import MimiqProvider

conn = MimiqConnection(); conn.connect()
provider = MimiqProvider(conn)
backend = provider.get_backend("mimiq")
Parameters:
  • runner (Any)

  • num_qubits (int)

Primitives

Native Qiskit V2 primitives backed by MIMIQ. Prefer these over Qiskit’s generic BackendSamplerV2 / BackendEstimatorV2: the estimator reads observables off the state instead of sampling them, and both batch a pub’s circuits into a single MIMIQ submission. See Circuits that end in an ensemble for how the estimator handles a circuit that ends in an ensemble.

class mimiq_qiskit.MimiqSamplerV2(backend, *, default_shots=1024, seed=None, run_options=None)[source]

BaseSamplerV2 that samples bitstrings on MIMIQ.

Parameters:
  • backend – A MimiqBackend, or a connection / MIMIQ backend / runner that MimiqBackend can wrap.

  • default_shots (int) – Shots used for pubs that don’t specify their own.

  • seed – Seed forwarded to MIMIQ. Defaults to the backend’s.

  • run_options – Extra MIMIQ run options (noisemodel, bonddim, …) merged over the backend’s.

run(pubs, *, shots=None)[source]

Run and collect samples from each pub.

Parameters:
  • pubs (Iterable) – An iterable of pub-like objects. For example, a list of circuits or tuples (circuit, parameter_values).

  • shots (int | None) – The total number of shots to sample for each sampler pub that does not specify its own shots. If None, the primitive’s default shots value will be used, which can vary by implementation.

Return type:

PrimitiveJob

Returns:

The job object of Sampler’s result.

class mimiq_qiskit.MimiqEstimatorV2(backend, *, method='auto', trajectories=None, shots=None, emulate_shot_noise=False, default_precision=0.0, seed=None, run_options=None)[source]

BaseEstimatorV2 that evaluates observables on MIMIQ.

Each Pauli term is evaluated on the simulator state rather than sampled, so a circuit that ends in a definite state gives an exact value at any term weight and reports a standard error of zero.

A circuit that ends in an ensemble has no single exact value: a mid-circuit measurement, a reset, a noise channel, or a server-side noisemodel makes MIMIQ re-evolve the circuit once per shot, and each trajectory has its own expectation value. The average over trajectories is the density-matrix value, so that is what this reports, with the sample standard error in stds. Reading one trajectory would be unbiased but as noisy as the observable’s range, so a stochastic circuit with no budget raises rather than returning it. A shots budget switches to hardware-style estimation from measurements in rotated bases.

mimiq_qiskit.estimation documents the three methods and how method="auto" chooses between them.

Parameters:
  • backend – A MimiqBackend, or anything it can wrap.

  • method (str) – "auto" (default), "exact", "trajectories", or "shots".

  • trajectories (int | None) – Trajectories to average for a stochastic circuit. None sizes it from precision. Ignored for a deterministic circuit, which has one answer.

  • shots (int | None) – Shots per measurement basis. Giving this selects sampled estimation; None sizes it from precision when method="shots".

  • emulate_shot_noise (bool) – Add Gaussian noise of width precision to an otherwise exact value, as Qiskit’s StatevectorEstimator does. One evolution instead of a shot budget, for code that wants to see plausible shot noise without paying for it.

  • default_precision (float) – Precision for run calls and pubs that do not carry their own. 0.0, meaning “as exact as the simulator gets”.

  • seed – Seed forwarded to MIMIQ, and to the emulate_shot_noise generator. Defaults to the backend’s.

  • run_options – Extra MIMIQ run options merged over the backend’s.

Result metadata reports method, whether the value is exact, whether the run was stochastic, the trajectories or shots spent, the target_precision, and min_fidelity: the lowest simulator fidelity behind the pub, which on an MPS backend is the truncation error that averaging cannot remove.

property default_precision: float

Precision used when run is called without one.

run(pubs, *, precision=None)[source]

Estimate every pub and return the job carrying the results.

precision overrides default_precision for this call. A positive value sizes the trajectory or shot budget as ceil(1/precision**2) where one is needed.

Parameters:
Return type:

PrimitiveJob

Converters

See What converts, and how for what each direction accepts.

mimiq_qiskit.qiskit_to_mimiq(qc)[source]

Convert a Qiskit QuantumCircuit to a MIMIQ mimiqcircuits.Circuit.

Parameters:

qc – A Qiskit QuantumCircuit.

Return type:

Circuit

Returns:

A MIMIQ Circuit with operations pushed in the same order.

Raises:

UnsupportedGateError – An operation in qc has neither a MIMIQ mapping nor a Qiskit definition to decompose.

mimiq_qiskit.mimiq_to_qiskit(circuit)[source]

Convert a MIMIQ Circuit back to a Qiskit QuantumCircuit.

Gates map onto concrete Qiskit gate classes, so the result is a fully defined circuit that Qiskit can transpile and simulate. Any unitary operation with no named counterpart – Control, Inverse, Power, Parallel, GateCustom, and gates Qiskit has no equivalent for such as GateSY or GateRNZ – becomes a UnitaryGate carrying its matrix. That is operator-faithful but not structure-faithful, so a round trip through both converters preserves the unitary, not the gate names.

The result uses single anonymous quantum and classical registers sized to the circuit; register identity from any original Qiskit circuit is not preserved.

Raises:

UnsupportedGateError – The circuit holds a non-unitary operation with no Qiskit equivalent (a noise channel, for instance), or a gate with unbound symbolic parameters.

Parameters:

circuit (Circuit)

exception mimiq_qiskit.converter.UnsupportedGateError[source]

Raised when a Qiskit or MIMIQ operation has no mapping.

mimiq_qiskit.gate_map.supported_qiskit_names()[source]

Names of Qiskit operations the converter recognises directly.

Not the limit of what it converts: an unlisted gate is decomposed through its own Qiskit definition, so anything the standard library builds from these primitives converts too.

Return type:

set[str]

Estimation internals

The engine behind MimiqEstimatorV2, and the Pauli-observable helpers it rests on. These are the shared surface a provider-specific estimator builds on, so that every MIMIQ estimator resolves methods, averages trajectories, and reports metadata identically.

The estimation engine behind the MIMIQ Qiskit estimators.

MimiqEstimatorV2 runs this against a MimiqBackend, and provider-specific estimators (such as TensorWeaver’s) run it against their own simulator, so that every one of them resolves methods, averages trajectories, and reports metadata the same way. Feed estimate_pub() an EstimatorPub, an EstimatorConfig, and a run callable that submits MIMIQ circuits.

Three ways to get an expectation value

exact

One evolution, and each Pauli term read straight off the state. No statistical error at all: the only error is the simulator’s own (for an MPS engine, the truncation). Only meaningful for a circuit that ends in a single definite state.

trajectories

A circuit carrying a mid-circuit measurement, a reset, a noise channel, or qubit loss does not end in one state; it ends in an ensemble. The engine re-evolves it once per shot, and each trajectory reports its own expectation value. Averaging them estimates the density-matrix value \(\mathrm{Tr}(\rho O)\) without bias, so that is what this does. Reading one trajectory instead, as a single-shot run must, returns a random draw whose spread can cover the observable’s whole range.

shots

What hardware and Qiskit’s own BackendEstimatorV2 do: rotate into each measurement basis, measure, and average the ±1 eigenvalues. Correct for every circuit, and the way to compare against a shot-based reference, but for the same budget it is strictly noisier than averaging trajectories, since it samples the observable on top of sampling the ensemble.

The default, "auto", evaluates exactly when the circuit is deterministic and averages trajectories when it is not. It refuses to guess a budget: a stochastic circuit with no trajectories, shots, or precision set raises rather than returning one trajectory dressed up as an exact number.

class mimiq_qiskit.estimation.EstimatorConfig(method='auto', trajectories=None, shots=None, emulate_shot_noise=False, default_precision=0.0, seed=None, assume_stochastic=False)[source]

How an estimator should turn circuits into expectation values.

Parameters:
  • method (str) – "auto" (the default) evaluates exactly when the circuit is deterministic and averages trajectories when it is not. "exact", "trajectories", and "shots" force one of the three methods described in this module.

  • trajectories (int | None) – Trajectories to average. None sizes it from the pub’s precision.

  • shots (int | None) – Shots per measurement basis for the sampled method. None sizes it from the pub’s precision. Giving this selects "shots" under method="auto".

  • emulate_shot_noise (bool) – Add Gaussian noise of width precision to a value that came out exact, the way Qiskit’s StatevectorEstimator does. A cheap stand-in for shot noise that costs one evolution instead of a shot budget. Ignored when the value carries real statistical error already.

  • default_precision (float) – Precision for pubs that do not carry their own.

  • seed (int | None) – Seeds the emulate_shot_noise generator. The simulator’s own seed belongs to the run callable.

  • assume_stochastic (bool) – Treat every circuit as stochastic even when its instructions look deterministic. Set this when the simulator adds noise the circuit does not show, such as a server-side noisemodel run option.

Raises:

ValueError – If method is unknown, a count is not positive, or both trajectories and shots are set, which would ask for two methods at once.

mimiq_qiskit.estimation.estimate_pub(pub, config, run)[source]

Estimate every observable in pub and package the result.

Parameters:
  • pub (EstimatorPub) – The pub to estimate. Its observables and parameter bindings broadcast against each other under Qiskit’s rules, and the result arrays take the broadcast shape.

  • config (EstimatorConfig) – Which method to use and what to spend on it.

  • run (Callable[[list, int], Sequence]) – run(circuits, nsamples) -> list[QCSResults], submitting a list of MIMIQ circuits and returning one result per circuit in the same order. Everything backend-specific (the connection, the simulator options, the seed) lives behind this callable.

Return type:

PubResult

Returns:

A PubResult whose evs and stds take the pub’s shape. Its metadata reports method, exact, stochastic, the budget actually spent, the target_precision, and min_fidelity where the backend reports one.

Raises:

ValueError – If the circuit is stochastic and no budget was given (see this module’s docstring), or if the backend returns a result the requested method cannot be read out of.

Pauli-observable helpers shared by the MIMIQ Qiskit estimators.

Qiskit hands an EstimatorV2 its observables as {pauli_label: coefficient} mappings, with qubit 0 on the right of each label. Everything here takes labels in that convention and reports qubit indices, so no caller has to reverse a label by hand.

Two estimation strategies need these helpers:

average_trajectories() serves the direct path when the circuit is stochastic and every trajectory returns its own value.

class mimiq_qiskit.observables.MeasurementGroup(labels, basis)[source]

A set of Pauli terms that one measurement can serve.

The members commute qubit-wise: on every qubit that two of them both act on, they act with the same Pauli. So rotating each qubit in basis into the Z basis and measuring it yields, in one pass, the eigenvalue of every member.

labels

The Qiskit Pauli labels in the group, in a deterministic order.

basis

{qubit: pauli} over every qubit any member acts on.

Parameters:
property qubits: list[int]

The measured qubits, ascending. Indexes the samples’ bit order.

mimiq_qiskit.observables.append_measurement(circuit, group)[source]

Copy circuit and measure group’s basis on the end of it.

Each qubit in the group’s basis is rotated into the Z basis (H for an X factor, Sdg then H for a Y one, nothing for a Z) and measured into a register added for the purpose. The rotations are the same ones Qiskit’s BackendEstimatorV2 uses.

Parameters:
Return type:

tuple[QuantumCircuit, list[int]]

Returns:

(measurement_circuit, clbits), where clbits holds the global classical-bit index of each measured qubit in group.qubits order. That is the order pauli_expectations() expects its samples in.

Raises:

ValueError – If circuit already has a register named _est, so adding ours would be ambiguous. Rename yours.

mimiq_qiskit.observables.average_trajectories(values)[source]

Mean and standard error of one expectation value per trajectory.

The trajectory average is an unbiased estimator of the density-matrix expectation value: a branch sampled with probability \(\|K_k\psi\|^2\) and renormalised gives \(\mathbb{E}[\langle\psi_k|O|\psi_k\rangle] = \sum_k \langle\psi|K_k^\dagger O K_k|\psi\rangle = \mathrm{Tr}(\rho' O)\), and the same holds for measurement branches. So averaging is correct, and reading a single trajectory is one draw from a distribution whose spread can be as wide as the observable’s own range.

Parameters:

values (Sequence[float]) – One value per trajectory.

Return type:

tuple[float, float]

Returns:

(mean, standard_error). A single trajectory reports an error of zero, there being nothing to estimate a spread from; that zero means “unknown”, not “exact”, so check the run’s metadata before trusting it.

Raises:

ValueError – If values is empty.

mimiq_qiskit.observables.combine_sampled_terms(identity, terms, expectations, shots)[source]

Weight sampled term averages into one expectation value and its error.

Parameters:
Return type:

tuple[float, float]

Returns:

(expectation_value, standard_error). The error follows Qiskit’s BackendEstimatorV2 convention, Σ |cᵢ| √Var(Pᵢ) / √N, which adds the per-term errors as if the terms were perfectly correlated and so is an upper bound on the true standard error.

mimiq_qiskit.observables.measurement_groups(labels)[source]

Collect Pauli labels into qubit-wise commuting measurement groups.

Grouping is what keeps the circuit count down: an observable with 50 terms over a shared basis costs one measurement circuit, not 50. The partition comes from Qiskit’s own group_commuting(), so it matches what BackendEstimatorV2 would do with the same observable.

Parameters:

labels (Iterable[str]) – Non-identity Qiskit Pauli labels, all of the same width.

Return type:

list[MeasurementGroup]

Returns:

One MeasurementGroup per basis, ordered deterministically. Empty when labels is empty.

Raises:

ValueError – If a label is all-identity. Those carry no measurement; take them out with split_identity() first.

mimiq_qiskit.observables.pauli_expectations(group, samples)[source]

Average every term in group over one measurement’s shots.

A term’s eigenvalue on a shot is (-1) ** parity of the measured bits on its support, the rotations having already turned each factor into a Z.

Parameters:
Return type:

dict[str, tuple[float, float]]

Returns:

{label: (expectation, variance)}. The variance is the single-shot 1 - ⟨P⟩²; divide it by the shot count to get the squared standard error of the mean.

Raises:

ValueError – If samples is empty, since nothing can be averaged.

mimiq_qiskit.observables.pauli_support(label)[source]

Return (qubit, pauli) for each non-identity factor, qubit-ascending.

Qiskit Pauli labels are little-endian: the leftmost character acts on the highest-index qubit, so character k of an n-character label acts on qubit n - 1 - k.

Parameters:

label (str) – A Qiskit Pauli label such as "IXZ". Characters must be one of I, X, Y, Z.

Return type:

list[tuple[int, str]]

Returns:

The non-identity factors as (qubit index, pauli character) pairs, sorted by qubit index. Empty for an all-identity label.

Example:

>>> pauli_support("IXZ")
[(0, 'Z'), (1, 'X')]
mimiq_qiskit.observables.push_pauli_terms(circuit, labels, *, firstzvar=0)[source]

Push one ExpectationValue operation per Pauli label onto a circuit.

Each term is evaluated on the state itself rather than sampled, so it is exact at any weight, and only the term’s own qubits are named: a weight-2 term on a 500-qubit register stays a two-qubit operation.

Labels are pushed once each, so several observables sharing a term at the same parameter binding can share its z-variable and its evaluation.

Parameters:
  • circuit – A mimiqcircuits.Circuit, appended to in place.

  • labels (Iterable[str]) – Non-identity Qiskit Pauli labels, in the order they should take z-variables. Repeats are ignored.

  • firstzvar (int) – Index of the first z-variable to write into.

Return type:

dict[str, int]

Returns:

{label: zvar}, the z-variable each term’s value will land in. Pass it to read_pauli_terms() along with the z-register that comes back.

mimiq_qiskit.observables.read_pauli_terms(zstate, zvar_of, identity, terms)[source]

Combine one z-register into an observable’s expectation value.

Parameters:
Return type:

float

Returns:

identity + Σ cᵢ Re⟨Pᵢ⟩. Each ⟨Pᵢ⟩ is real for a Pauli string on a normalised state, so taking the real part discards only round-off.

mimiq_qiskit.observables.shots_for_precision(precision)[source]

Shots needed for a target precision, ceil(1 / precision²).

Qiskit’s convention, so a pub’s precision sizes a MIMIQ run the same way it would size a hardware one.

Parameters:

precision (float) – Target standard error. Must be positive.

Return type:

int

Returns:

The shot count, at least 1.

Raises:

ValueError – If precision is not positive.

mimiq_qiskit.observables.split_identity(observable)[source]

Separate an observable’s identity term from its measurable ones.

The identity term contributes its coefficient to the expectation value outright, with no evolution and no error, so it is kept apart from the terms that have to be evaluated.

Parameters:

observable (Mapping[str, complex]) – {pauli_label: coefficient}, as produced by coerce().

Return type:

tuple[float, dict[str, float]]

Returns:

(identity_coefficient, terms) where terms maps each non-identity label to its real coefficient. Repeated labels are summed.

Raises:

ValueError – If a coefficient has an imaginary part too large to be round-off. EstimatorV2 observables must be Hermitian, which in the Pauli basis means real coefficients, and silently discarding an imaginary part would hide the mistake.