quchip.results.results¶
Backend-agnostic wrapper around solver output.
This module is the contract between backends and users. The engine emits backend-agnostic physics descriptions, and each backend converts them into its own optimal solver-ready form; the result of solving is then re-wrapped here so that user code never has to know whether QuTiP or dynamiqs/JAX produced the numbers.
Key classes:
SimulationResult— one solve’s states, times, expectations, and partial-trace / population accessors.SimulationBatchResult— ordered, immutable batch of results with helpers that stack across the batch for e.g. sweeps.ObservableTrace— one named expectation-value trace, keeping the pre-processing and post-processing values side by side (band reconstruction, demodulation, etc.).
All helpers that return arrays stay inside the backend’s array module
(JAX / NumPy) to preserve differentiability. The convenience wrappers
SimulationResult.overlap() and SimulationResult.population()
additionally materialize to a concrete numpy.ndarray when the
underlying values are concrete (e.g. the QuTiP backend, or an eager
dynamiqs call) — but return the backend-native array unchanged when
concretization would break differentiability (a traced value under
jax.jit/grad on the dynamiqs backend).
Functions
|
Wrap a raw backend |
Wrap backend results from a batched solve that shares one |
Classes
|
One named expectation-value trace, with pre- and post-processing values. |
|
Ordered, immutable batch of |
|
Backend-agnostic container for the output of one solve. |
- class quchip.results.results.ObservableTrace(values, raw)[source]¶
Bases:
objectOne named expectation-value trace, with pre- and post-processing values.
- values¶
Post-processed expectation values over time (e.g. demodulated, phase-corrected, band-summed). This is what user code normally wants.
- Type:
Any
- raw¶
The same quantity before post-processing — useful for debugging frame conventions, band decomposition, and demodulation.
- Type:
Any
- class quchip.results.results.SimulationResult(solver_result, backend, dims, *, device_info=None, observable_traces=None)[source]¶
Bases:
objectBackend-agnostic container for the output of one solve.
A
SimulationResultbundles everything a user needs after a solve finishes:times— the time grid the solver stored (ns).states— the list of stored states (kets or density matrices), orNoneifstore_stateswas off.solver— the name reported by the backend.stats— a plaindictof solver statistics.dims— the per-device Hilbert-space dimensions, in chip order.device_info—[(label, computational), …]for partial-trace helpers to resolve device indices by label or by object.
Expectation values live in
observable_traceswhene_opswas passed as a dict. Each entry is anObservableTraceor a list of them (list-valued observables, one per band, etc.).- Parameters:
solver_result (SolverResult)
backend (Backend)
observable_traces (dict[Any, ObservableTrace | list[ObservableTrace]] | None)
- property observable_traces: dict[Any, ObservableTrace | list[ObservableTrace]] | None¶
Return the dict of named
ObservableTraceentries, orNone.Nonewhene_opswas not passed as a dict. Visualization and analysis code that wants the full dict should read this property rather than the private_expect_dataattribute.
- expect(key, index=None)[source]¶
Return the full expectation-value array for observable key over
self.times.
- expect_final(key, index=None)[source]¶
Return the final expectation value for observable key (
self.expect(key)[-1]).
- expect_values(key, index=None)¶
Return the full expectation-value array for observable key over
self.times.
- overlap_array(target)[source]¶
Return the overlap with target at every stored time.
For ket trajectories returns
|<target|psi(t)>|**2; for density matrices returns<target|rho(t)|target>. Stays in the backend’s array module so the result is differentiable. One batched op over the leading time axis — no per-point loop.
- amplitude_array(target)[source]¶
Return the phase-sensitive complex projection
<target|psi(t)>for kets.Density-matrix trajectories raise
TypeError— there is no single phase-sensitive amplitude for a mixed state; useoverlap_array()instead. One batched op, no per-point loop.
- overlap(target)[source]¶
Wrap
overlap_array()for convenience.Returns a NumPy array under the QuTiP backend; under JAX (dynamiqs) returns the backend-native array so the call stays JIT/grad-friendly.
- state(t=None, *, dm=False)[source]¶
Return the state at time t (or final state if t is
None); optionally coerced to a DM.
- dm_at(t)[source]¶
Return the density matrix at the stored time nearest to t (ns) — promotes kets on demand.
- property final_state: Any¶
Return the final state — explicit
final_stateif stored, else the last stored trajectory entry.
- reduced_state(t, device)[source]¶
Partial-trace the state at time t down to device’s subspace.
- Parameters:
t (float)
device (str | BaseDevice)
- Return type:
- property populations: dict[tuple[int, ...], ndarray]¶
Return per-basis-state populations
|<n1, n2, ...|psi(t)>|**2over time.Returns a dict keyed by Fock tuple
(n1, n2, ..., nK)— one per computational basis vector of the full chip — mapping to a realnumpy.ndarrayof lengthlen(self.times).Requires
store_states; density-matrix trajectories are handled transparently by reading the diagonal of each timestep’s DM.
- population_array(device, level=0)[source]¶
Return the population of Fock level on device over time, in the backend’s array module.
- Parameters:
device (str | BaseDevice)
level (int)
- Return type:
- population(device, level=0)[source]¶
Wrap
population_array()for convenience.Returns a NumPy array under the QuTiP backend; under JAX (dynamiqs) returns the backend-native array so the call stays JIT/grad-friendly. Use
population_array()directly when you want to keep gradient flow regardless of context.- Parameters:
device (str | BaseDevice)
level (int)
- Return type:
- plot_populations(*, trace_out=None, computational=False, ax=None, **kwargs)[source]¶
Plot per-basis-state populations over time (delegates to
quchip.viz.plot_populations()).- Parameters:
trace_out (str | BaseDevice | list[str | BaseDevice] | None)
computational (bool)
ax (Any)
kwargs (Any)
- Return type:
- plot_state(index, *, trace_out=None, computational=False, mode='population', ax=None, **kwargs)[source]¶
Plot one stored state as populations or a density matrix (delegates to
quchip.viz.plot_state()).
- plot_expectation(*, keys=None, ax=None, **kwargs)[source]¶
Plot expectation-value traces over time (delegates to
quchip.viz.plot_expectation()).
- plot_wigner(index=-1, *, trace_out=None, ax=None, **kwargs)[source]¶
Plot the Wigner function of one stored state (delegates to
quchip.viz.plot_wigner()).- Parameters:
index (int)
trace_out (str | BaseDevice | list[str | BaseDevice] | None)
ax (Any)
kwargs (Any)
- Return type:
- check_truncation(*, threshold=0.001, top_levels=1)[source]¶
Emit a
UserWarningper device whose top-top_levelspopulation exceeds threshold.Uses the final stored state only — cheap, one full-chip diagonal read, no per-timestep loop, no partial traces. Silently no-ops when no final state is available (e.g.
store_statesandstore_final_stateboth disabled).Returns the per-device top-level population actually observed, keyed by device label, so callers can surface the numbers without re-parsing the warning text.
- class quchip.results.results.SimulationBatchResult(results, *, shape=None, axes=None)[source]¶
Bases:
objectOrdered, immutable batch of
SimulationResultwith stacked helpers.Returned by
solve_many()and by any sweep that solves many problems in one call. The batch preserves iteration order so that per-element results map one-to-one onto the inputs that produced them.The
final_*helpers stack along a new leading batch axis in the backend’s array module, and the grid-awareexpect()/population()acceptreduce='last'for a final-value slice, so a loss function that sums over the batch stays JAX-traceable end-to-end.- Parameters:
- property results: tuple[SimulationResult, ...]¶
Return the per-element
SimulationResultobjects in input order.
- with_sweep_metadata(*, shape, axes)[source]¶
Return an equivalent batch annotated with sweep-axis metadata.
- expect(key, index=None, *, reduce=None)[source]¶
Return expectation traces reshaped to the natural sweep grid.
- population(device, level=0, *, reduce=None)[source]¶
Return population traces reshaped to the natural sweep grid.
- Parameters:
device (str | BaseDevice)
level (int)
reduce (str | None)
- Return type:
- quchip.results.results.wrap_solver_result(solver_result, problem, backend)[source]¶
Wrap a raw backend
SolverResultinto a user-facingSimulationResult.The engine-side
SolveProblemcarries the metadata needed to rebuild dict-form observables (build_observable_traces()) and to label devices for partial-trace helpers.- Parameters:
solver_result (SolverResult)
problem (SolveProblem)
backend (Backend)
- Return type:
- quchip.results.results.wrap_solver_results_from_batch(solver_results, batch, backend)[source]¶
Wrap backend results from a batched solve that shares one
SolveBatchcontext.Avoids rematerializing a per-element
SolveProblem(and its per-elementHamiltonianDescription) just to read the shared fields.- Parameters:
solver_results (list[SolverResult])
batch (SolveBatch)
backend (Backend)
- Return type: