quchip.results

Backend-agnostic simulation output containers.

Whatever backend produced the solver output (QuTiP, dynamiqs/JAX, …), users interact only with SimulationResult and SimulationBatchResult. Named expectation-value traces are exposed as ObservableTrace, and raw backend output is wrapped into a SimulationResult via wrap_solver_result(). A partitioned solve (see quchip.engine.partitioned) combines its per-component results into a PartitionedSimulationResult.

class quchip.results.ObservableTrace(values, raw)[source]

Bases: object

One named expectation-value trace, with pre- and post-processing values.

Parameters:
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

values: Any
raw: Any
class quchip.results.SimulationBatchResult(results, *, shape=None, axes=None)[source]

Bases: object

Ordered, immutable batch of SimulationResult with 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-aware expect() / population() accept reduce='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 SimulationResult objects in input order.

property shape: tuple[int, ...]

Return the natural sweep-grid shape for this batch.

property axes: tuple[tuple[str, Any], ...]

Return sweep-axis metadata as (name, values) pairs.

property backend: Backend

Return the backend shared by every element (raises on an empty batch).

with_sweep_metadata(*, shape, axes)[source]

Return an equivalent batch annotated with sweep-axis metadata.

Parameters:
Return type:

SimulationBatchResult

expect(key, index=None, *, reduce=None)[source]

Return expectation traces reshaped to the natural sweep grid.

Parameters:
  • key (Any)

  • index (int | None)

  • reduce (str | None)

Return type:

Any

population(device, level=0, *, reduce=None)[source]

Return population traces reshaped to the natural sweep grid.

Parameters:
Return type:

Any

final_overlap_magnitudes(targets)[source]

Return stacked final overlap magnitudes, one per (result, target) pair.

Parameters:

targets (list[Any] | tuple[Any, ...])

Return type:

Any

final_amplitudes(targets)[source]

Return stacked final complex amplitudes (phase-sensitive), one per (result, target) pair.

Parameters:

targets (list[Any] | tuple[Any, ...])

Return type:

Any

class quchip.results.SimulationResult(solver_result, backend, dims, *, device_info=None, observable_traces=None)[source]

Bases: object

Backend-agnostic container for the output of one solve.

A SimulationResult bundles 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), or None if store_states was off.

  • solver — the name reported by the backend.

  • stats — a plain dict of 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_traces when e_ops was passed as a dict. Each entry is an ObservableTrace or a list of them (list-valued observables, one per band, etc.).

Parameters:
property observable_traces: dict[Any, ObservableTrace | list[ObservableTrace]] | None

Return the dict of named ObservableTrace entries, or None.

None when e_ops was not passed as a dict. Visualization and analysis code that wants the full dict should read this property rather than the private _expect_data attribute.

expect(key, index=None)[source]

Return the full expectation-value array for observable key over self.times.

Parameters:
  • key (Any)

  • index (int | None)

Return type:

Any

expect_final(key, index=None)[source]

Return the final expectation value for observable key (self.expect(key)[-1]).

Parameters:
  • key (Any)

  • index (int | None)

Return type:

Any

expect_values(key, index=None)

Return the full expectation-value array for observable key over self.times.

Parameters:
  • key (Any)

  • index (int | None)

Return type:

Any

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.

Parameters:

target (Any)

Return type:

Any

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; use overlap_array() instead. One batched op, no per-point loop.

Parameters:

target (Any)

Return type:

Any

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.

Parameters:

target (Any)

Return type:

Any

state(t=None, *, dm=False)[source]

Return the state at time t (or final state if t is None); optionally coerced to a DM.

Parameters:
Return type:

Any

state_at(t)[source]

Return the state at the stored time nearest to t (ns).

Parameters:

t (float)

Return type:

Any

dm_at(t)[source]

Return the density matrix at the stored time nearest to t (ns) — promotes kets on demand.

Parameters:

t (float)

Return type:

Any

property final_state: Any

Return the final state — explicit final_state if 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:
Return type:

Any

property populations: dict[tuple[int, ...], ndarray]

Return per-basis-state populations |<n1, n2, ...|psi(t)>|**2 over time.

Returns a dict keyed by Fock tuple (n1, n2, ..., nK) — one per computational basis vector of the full chip — mapping to a real numpy.ndarray of length len(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:
Return type:

Any

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:
Return type:

Any

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:
Return type:

Any

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()).

Parameters:
Return type:

Any

plot_expectation(*, keys=None, ax=None, **kwargs)[source]

Plot expectation-value traces over time (delegates to quchip.viz.plot_expectation()).

Parameters:
Return type:

Any

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:
Return type:

Any

check_truncation(*, threshold=0.001, top_levels=1)[source]

Emit a UserWarning per device whose top-top_levels population 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_states and store_final_state both 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.

Parameters:
Return type:

dict[str, float]

class quchip.results.PartitionedSimulationResult(component_results, partition, key_plan)[source]

Bases: object

Result of one partitioned solve: K component results + a key plan.

Parameters:
  • component_results (list)

  • partition (Any)

  • key_plan (dict)

property components: tuple
property partition: Any
property device_order: tuple[str, ...]

Return the parent chip’s original device-label order.

This is not the concatenation of each component’s labels (which follows connected-component discovery order and can interleave differently whenever the chip’s device order doesn’t already group each component’s members together) — it is the order states and final_state are permuted into so they match the joint solve exactly.

expect(key, index=None)[source]
Parameters:
  • key (Any)

  • index (int | None)

Return type:

Any

expect_final(key, index=None)[source]
Parameters:
  • key (Any)

  • index (int | None)

Return type:

Any

expect_values(key, index=None)
Parameters:
  • key (Any)

  • index (int | None)

Return type:

Any

population(device, level=0)[source]
Parameters:
Return type:

Any

population_array(device, level=0)[source]
Parameters:
Return type:

Any

check_truncation(threshold=0.001)[source]

Run each component’s truncation check and merge the per-device results.

Mirrors check_truncation()’s return shape (a dict keyed by device label) for duck-typing parity between a joint and a partitioned result.

Parameters:

threshold (float)

Return type:

dict[str, float]

property states: list

Reconstruct the joint-state trajectory (ket trajectories only), in device_order.

Component states tensor together in connected-component discovery order, which can interleave differently from the parent chip’s own device order; each reconstructed step is permuted (permute_state()) into device_order so the result matches a joint solve of the original chip exactly.

See also final_state, which — unlike this accessor — intentionally also accepts density-matrix components: a tensor product of component density matrices is itself a valid joint state, whereas a per-step list of joint kets is only well-defined when every component stayed pure.

property final_state: Any

Reconstruct the joint final state, in device_order — a ket if every component stayed pure, otherwise a density matrix.

When components disagree, every component is first promoted to a density matrix (_promote_to_common_state_kind()) before tensoring, giving a valid joint density matrix. Components tensor together in connected-component discovery order, which can interleave differently from the parent chip’s own device order; the result is permuted (permute_state()) into device_order so it matches a joint solve of the original chip exactly.

describe()[source]
Return type:

str

quchip.results.wrap_solver_result(solver_result, problem, backend)[source]

Wrap a raw backend SolverResult into a user-facing SimulationResult.

The engine-side SolveProblem carries the metadata needed to rebuild dict-form observables (build_observable_traces()) and to label devices for partial-trace helpers.

Parameters:
Return type:

SimulationResult

Modules

partitioned

Combined view over per-component solves of a partitioned chip.

results

Backend-agnostic wrapper around solver output.