qarp.engines¶
Execution engines. Public depth: flat. Submodules are private.
- class qarp.engines.CudaqEngine(*, backend: str = 'statevector', precision: str = 'fp64', max_bond_dim: int = 0, target: str | None = None, n_shots: int | Shots = 10000, seed: int | None = None)[source]¶
Bases:
EnginePure-Python engine wrapping the C++ Transpiler +
qx.CudaqSimulator.provides_amplitudes = True(base default) — noiseless simulator; the device→host statevector transfer is separately capped by_check_statevector_host.Gradients:
"default"resolves to the batched parameter shift, which stays on-device for StateVector expectation values over a QubitOperator (batch_expectation); other targets pull the host statevector per point."adjoint"is refused — the adjoint is a CPU kernel and this engine never constructs a CPU simulator behind the caller’s back (a GPU adjoint is post-release work); use QarpEngine for it.- Parameters:
backend – One of
statevector(single GPU, default),statevector-mgpu(multi-GPU + MPI),tensornet,tensornet-mps.precision –
fp64(default) orfp32.max_bond_dim – Bond-dimension cap for
tensornet-mps(ignored otherwise).target – Optional NVQIR backend name passed verbatim to the simulator (
CUDAQ_DEFAULT_SIMULATOR), overridingbackend/precision. Use"qpp"to run on CPU (e.g. for tests/CI without a GPU) or to reach a backend not covered by thebackendenum.n_shots – Default shot count used when a primitive has
n_shots=None;qarp.EXACTmakes exact readout the engine-wide default.seed – Optional RNG seed (passed to the simulator). EXACT readouts involve no RNG and are seed-independent.
- class qarp.engines.Engine[source]¶
Bases:
ABCCommon surface implemented by all concrete engines.
Concrete engines own a transpiler + simulator, compile each primitive’s
sub_blocksonce onbuild(), then dispatch one or many parameter sets throughrun()/batch_run()keeping the per-shot loop in C++ (no Python round-trip per shot).- batch_run(primitives: list[Runnable], param_sets: Sequence[Mapping], n_shots: int | Shots | None = None, rebuild: bool = True) list[list[float | complex | dict[tuple[int, ...], float]]][source]¶
Sweep one set of primitives over multiple parameter dicts.
The inner simulation loop stays entirely in C++ (no Python round-trip per parameter set). Template:
_batch_setupthen_sweep.- Parameters:
primitives – Primitive instances to evaluate.
param_sets – One dict per evaluation point.
n_shots – Override engine-default shot count for this sweep.
rebuild – If False, reuse transpilation from a prior
build()call when the primitive structure is unchanged.
- Returns:
results_by_set[set_idx][prim_idx] = scalar.
- build(primitives: list[Runnable], params: Mapping = {}, rebuild: bool = True) None[source]¶
Compile all primitives (template method).
Per primitive:
prim.build()→_validate_primitive→ per block: flatten → substitute →_validate_flat_commands→_warn_uninitialised_conditions→_compile_one→_post_compile_check. The reuse path (rebuild=Falsewith compiled circuits present) re-validates — capability-relevant state may have changed — and keeps prior routing maps, so results stay in logical qubit order.
- prepare_structured_qpe(kind: Literal['qpe', 'dosqpe'], unitary, state, n_ancilla: int, primitive: Runnable) StructuredQPEPlan | None[source]¶
Offer a fast-path plan for canonical / DOS phase estimation.
unitary/stateare built blocks. Returns aStructuredQPEPlanwhen this engine can evaluate the QPE via a structured sampler (matrix exponentiation — the controlled-U ladder is never compiled), or None → the caller builds the generic circuit. Base default: no fast path.Callers must not probe why a plan was refused — every eligibility rule lives in the engine override (see
QarpEngine).
- resolve_gradient_method(prim: Runnable, method: str) str[source]¶
The concrete method
run_gradient(method=...)would use forprim.
- resource_modeler() ResourceModeler | None[source]¶
Modeler for
qarp.resources.ResourceEstimator, or None.Engines pricing gates beyond raw counting (e.g. a digital-Rz T-cost) override this. No in-tree engine does: the base
Noneis the only return, and the hook is the seam a modeling engine re-attaches to.
- run(params: Mapping = {}) list[float | complex | dict[tuple[int, ...], float]][source]¶
Simulate all built primitives and return their scalar results.
Template method: re-validates every primitive per call (noise toggles and
initial_statemutations must not slip through), substitutes parameters, and defers the engine-specific simulation to_dispatch_one.
- run_gradient(params: Mapping, method: str = 'default', options: Mapping | None = None) list[ndarray][source]¶
Per-primitive gradients — one array per built primitive.
Contract (
docs/contracts/qarp_conventions.md§17):result[i]has shape(len(params),)with columns in the insertion order ofparams— for every method.dtype is
float64, orcomplex128when the primitive’s value is complex by target (TRANSITION_AMPLITUDE, an expectation value over aqx.Blockoperator, a complex HadamardTest).The differentiated objective per target: EXPECTATION_VALUE and TRANSITION_AMPLITUDE — the value
run()returns (Re and Im separately); aStateVectorOVERLAP —|⟨bra|ket⟩|²althoughrun()returns the amplitude (gradient_kind == "squared_overlap"); every other primitive — the valuerun()returns.
method:"default"(this engine’s policy — adjoint where eligible on QarpEngine, parameter shift otherwise; may change between releases),"adjoint","parameter-shift","finite-diff"(options:fd_eps,fd_order1|2),"spsa"(options:spsa_c0,num_spsa,spsa_seed). An unknown name is aValueError; a method this engine does not declare ingradient_methodsis aCapabilityError.
- class qarp.engines.QarpEngine(device: Device | None = None, *, n_qubits: int | None = None, architecture: Architecture | None = None, noise_model=None, gate_set: GateSet | None = None, directedness: bool = False, n_shots: int | Shots = 10000, seed: int | None = None)[source]¶
Bases:
EnginePure Python engine wrapping C++ Transpiler + QarpSimulator.
- Pipeline:
- build(primitives) — calls primitive.build(), flattens, then runs
the device-aware compilation pipeline (qx.compile_for_device): check_fits → rebase → route → re-rebase (whichever stages are configured on the device).
- run(params) — dispatches per primitive on
consumes: AMPLITUDES →
primitive.run_from_amplitudes; COUNTS → csim sampling (anExactResultundern_shots=qarp.EXACT), reindexed back to logical-qubit order when the device routed, thenprimitive.run(results).- batch_run(…) — sweeps one set of primitives over multiple
parameter dicts; simulation loop stays in C++.
- Parameters:
device – A pre-built
qx.Device. Mutually exclusive with field-style kwargs.n_qubits/architecture/noise_model/gate_set/directedness – Field shorthand — assembles an effective Device internally (provided in lieu of device=…).
n_shots – Default shot count used when a primitive has n_shots=None.
qarp.EXACTmakes exact readout the engine-wide default.seed – Optional RNG seed (passed to QarpSimulator). EXACT readouts involve no RNG and are seed-independent / bit-reproducible.
- gradient_methods: frozenset[str] = frozenset({'adjoint', 'default', 'finite-diff', 'parameter-shift', 'spsa'})¶
- property noise_model¶
The device’s noise model (C++
qx.NoiseModel), or None.qx.Devicecopies the model at construction, so toggling the object originally passed in has no effect afterwards — toggle this one instead:engine.noise_model.enabled = False(the disable-noise-for-gradients workflow).
- prepare_structured_qpe(kind, unitary, state, n_ancilla: int, primitive: Runnable) StructuredQPEPlan | None[source]¶
Structured QPE / DOS-QPE fast path (matrix exponentiation in C++).
Eligibility — any miss falls back to the generic circuit (None):
EXACT readout (primitive or engine-wide): the structured C++ sampler has no analytic branch.
Enabled noise model:
simulate_*_structuredapplies raw commands only — the fast path would silently drop the noise.Routed device: the fast path bypasses the routing/l2p pipeline.
Parametric U after transpile: the ladder needs a concrete matrix.
Seeded primitive:
sample()cannot threadinitial_state(the C++ signature has no such parameter) — the generic path can.
The fast path never runs
build()/_validate_primitive— the primitive is consulted only for shot resolution at sample() time.
- class qarp.engines.Runnable(*args, **kwargs)[source]¶
Bases:
ProtocolMembers engines actually touch on an executable item.
target/operatorare typedAny: their concrete types (Target,QubitOperator) live above this layer, so engines matchtarget.nameby string and duck-type the rest — importing them here would recreate the engines⇄algorithms cycle this protocol removes.Consumesis importable: it lives inqarp._types, below both layers.