quchip.engine.ir

IR types flowing between engine stages.

This module is the contract between the engine and its backends. It defines four families of immutable, JAX-pytree-friendly types:

  1. Signal Program AST — subclasses of SignalNode (Constant, EnvelopeRef, Window, Shift, Scale, PolarScale, Add, Multiply, Conjugate, RealPart, Carrier). A pure functional description of a time-dependent scalar coefficient f(t) : . Every leaf that a user may sweep (envelope parameters, amplitudes, phases, carrier frequencies) is a pytree leaf so the whole program is differentiable through JAX.

  2. CanonicalOperator — backend-free operator storage in dense / CSR / DIA layouts plus subsystem metadata. Backends convert to and from this format.

  3. Hamiltonian terms — StaticTerm, DynamicTerm, and the per-stage container HamiltonianDescription plus the batched BatchedHamiltonianDescription.

  4. Solve requests — SolveProblem and SolveBatch, the frozen hand-offs to backends. backend selection is chip-owned and is explicitly forbidden from options.

A note on 2π: every operator here has already been scaled by 2π at the stage-2 boundary. Carrier frequencies are stored in angular units (rad/ns). IR consumers (backends, analyses) must not re-apply 2π.

Functions

as_scalar_modulation(modulation, *, owner)

Normalize a user-supplied modulation input to a ScalarModulation.

decompose_carrier_bands(signal)

Rewrite signal into Σ_k envelope_k(t) · exp(i · freq_k · t) with carrier-free envelopes.

evaluate_signal_program(signal, t, *[, xp])

Evaluate a signal program at time(s) t (ns); xp defaults to NumPy.

signal_children(node)

Return the SignalProgram child nodes of node.

simplify_signal(signal)

Recursively simplify a signal program by canceling exact opposing carrier pairs.

Classes

Add(children)

BatchedHamiltonianDescription(batch_size, ...)

Batched Hamiltonian IR that splits shared vs per-element structure.

CanonicalOperator(layout, values, shape, ...)

Backend-free operator with explicit dense/CSR/DIA payload and subsystem metadata.

Carrier(freq[, sign])

Oscillating carrier exp(sign · i · freq · t).

CarrierBand(envelope, freq)

One band of a carrier-normalized signal: envelope(t) · exp(i · freq · t).

Conjugate(child)

Constant(value)

DriveOp(target_label, envelope[, freq, ...])

Drive operation scheduled on a device or a modulable coupling.

DroppedTerm(source, operator, reason[, ...])

Advisory record for a Hamiltonian term elided by an approximation.

DynamicTerm(operator, time_dependence[, ...])

Time-dependent Hamiltonian contribution operator · f(t).

EnvelopeRef(envelope)

Reference to a pulse envelope; its waveform(t) is called at evaluation time.

HamiltonianDescription(static_terms, ...[, ...])

Backend-agnostic time-dependent Hamiltonian — the stage-2 / backend contract.

HamiltonianTemplate(resolved_frame, dims[, ...])

Chip-topology-invariant Hamiltonian skeleton.

Multiply(children)

PolarScale(child, amplitude, theta)

Scale child by amplitude * exp(i * theta) (both are pytree leaves).

RealPart(child)

ResolvedFrame(frequencies, demod_freqs, mode)

Per-device frame information produced by stage 1.

ScalarModulation(signal)

Typed wrapper marking a SignalProgram as a scalar modulation on a DynamicTerm.

Scale(child, factor)

Multiply child by a complex scalar factor.

Shift(child, delta_t)

Time-shift child by delta_t: child(t - delta_t).

SignalNode()

Base class for signal-program AST nodes.

SignalProgram

SolveBatch(chip, hamiltonian, ...[, c_ops, ...])

Batched counterpart to SolveProblem.

SolveProblem(chip, hamiltonian, ...[, ...])

Immutable simulation request handed from the chip pipeline to a backend.

StaticTerm(operator[, coefficient, origin, ...])

Time-independent Hamiltonian contribution.

Window(child, start, stop)

Gate child to [start, stop]; zero outside.

class quchip.engine.ir.SignalNode[source]

Bases: object

Base class for signal-program AST nodes.

A node describes a time-dependent scalar f(t) : . Subclasses:

  • are @dataclass(frozen=True); every dataclass field is a JAX pytree child (registration happens automatically on subclass definition), so any field a user may sweep is differentiable;

  • name the fields that hold child nodes (or tuples of child nodes) in _signal_child_fields, which powers generic traversal (signal_children()) and rewriting (rebuild_children());

  • implement evaluate() — the node’s pointwise semantics;

  • override bands() when (and only when) the node interacts with Carrier leaves: the default treats any carrier-free subtree as a single zero-frequency band, which is exact for every envelope-like node.

signal_children()[source]

Return this node’s child nodes (flattening tuple-valued fields).

Return type:

tuple[SignalNode, …]

rebuild_children(transform)[source]

Reconstruct this node with transform applied to each child.

Non-child fields are preserved; nodes without children pass through untouched.

Parameters:

transform (Any)

Return type:

SignalNode

evaluate(t, *, xp)[source]

Evaluate the node at time(s) t (ns) in array namespace xp.

Parameters:
Return type:

Any

bands()[source]

Rewrite this subtree into carrier-normalized bands.

Default: a carrier-free subtree is exactly one zero-frequency band whose envelope is the subtree itself. Nodes whose subtrees may contain Carrier leaves must override this with their carrier algebra (see decompose_carrier_bands()).

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.Constant(value: 'complex')[source]

Bases: SignalNode

Parameters:

value (complex)

value: complex
evaluate(t, *, xp)[source]

Return the constant value, broadcast to the shape of t.

Parameters:
Return type:

Any

bands()[source]

Return the single zero-frequency band carrying this constant.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.EnvelopeRef(envelope)[source]

Bases: SignalNode

Reference to a pulse envelope; its waveform(t) is called at evaluation time.

Parameters:

envelope (BaseEnvelope)

envelope: BaseEnvelope
evaluate(t, *, xp)[source]

Return the referenced envelope’s waveform(t) (ns) as complex.

Parameters:
Return type:

Any

bands()[source]

Return the single zero-frequency band carrying this envelope.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.Window(child, start, stop)[source]

Bases: SignalNode

Gate child to [start, stop]; zero outside.

Parameters:
child: SignalNode
start: float
stop: float
evaluate(t, *, xp)[source]

Return the child value inside [start, stop] (ns), zero elsewhere.

Parameters:
Return type:

Any

bands()[source]

Return the child bands with the same time gate applied to each envelope.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.Shift(child, delta_t)[source]

Bases: SignalNode

Time-shift child by delta_t: child(t - delta_t).

Parameters:
child: SignalNode
delta_t: float
evaluate(t, *, xp)[source]

Return the child evaluated at t - delta_t (ns).

Parameters:
Return type:

Any

bands()[source]

Return the child bands, each carrying the shift’s carrier phase.

A time shift distributes over bands and contributes the constant carrier phase exp(-i·freq·Δt) per band.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.Scale(child, factor)[source]

Bases: SignalNode

Multiply child by a complex scalar factor.

Parameters:
child: SignalNode
factor: complex
evaluate(t, *, xp)[source]

Return the child value scaled by factor.

Parameters:
Return type:

Any

bands()[source]

Return the child bands with factor folded into each envelope.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.PolarScale(child, amplitude, theta)[source]

Bases: SignalNode

Scale child by amplitude * exp(i * theta) (both are pytree leaves).

Parameters:
child: SignalNode
amplitude: float
theta: float
evaluate(t, *, xp)[source]

Return the child value scaled by amplitude * exp(i * theta).

Parameters:
Return type:

Any

bands()[source]

Return the child bands with the polar scale folded into each envelope.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.Add(children: 'tuple[SignalNode, ...]')[source]

Bases: SignalNode

Parameters:

children (tuple[SignalNode, ...])

children: tuple[SignalNode, ...]
evaluate(t, *, xp)[source]

Return the sum of the children evaluated at t (ns).

Parameters:
Return type:

Any

bands()[source]

Return the concatenation of every child’s bands.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.Multiply(children: 'tuple[SignalNode, ...]')[source]

Bases: SignalNode

Parameters:

children (tuple[SignalNode, ...])

children: tuple[SignalNode, ...]
evaluate(t, *, xp)[source]

Return the product of the children evaluated at t (ns).

Parameters:
Return type:

Any

bands()[source]

Return the frequency convolution: the Cartesian product of child bands.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.Conjugate(child: 'SignalNode')[source]

Bases: SignalNode

Parameters:

child (SignalNode)

child: SignalNode
evaluate(t, *, xp)[source]

Return the complex conjugate of the child evaluated at t (ns).

Parameters:
Return type:

Any

bands()[source]

Return the child bands with each envelope conjugated and its frequency negated.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.RealPart(child: 'SignalNode')[source]

Bases: SignalNode

Parameters:

child (SignalNode)

child: SignalNode
evaluate(t, *, xp)[source]

Return the real part of the child evaluated at t (ns).

Parameters:
Return type:

Any

bands()[source]

Return each band split into ±freq halves via Re z = (z + z̄) / 2.

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.Carrier(freq, sign=-1)[source]

Bases: SignalNode

Oscillating carrier exp(sign · i · freq · t).

freq is in angular units (rad/ns). The default sign = -1 matches the convention used in rotating-frame decompositions (Scully & Zubairy, Quantum Optics, §5), where a raising-type band on a detuning rotates as exp(−iΔt). Both fields are registered as pytree children (freq may be traced; sign is semantically a static ±1 — do not map over it).

Parameters:
freq: float
sign: Literal[-1, 1] = -1
evaluate(t, *, xp)[source]

Return exp(sign · i · freq · t) at time(s) t (ns).

Parameters:
Return type:

Any

bands()[source]

Return the single sign·freq band with a unit-constant envelope.

Return type:

tuple[CarrierBand, …]

quchip.engine.ir.SignalProgram

alias of SignalNode

class quchip.engine.ir.ScalarModulation(signal)[source]

Bases: object

Typed wrapper marking a SignalProgram as a scalar modulation on a DynamicTerm.

Parameters:

signal (SignalNode)

signal: SignalNode
quchip.engine.ir.as_scalar_modulation(modulation, *, owner)[source]

Normalize a user-supplied modulation input to a ScalarModulation.

Accepts a BaseEnvelope (wrapped as ScalarModulation(EnvelopeRef(env))) or an existing ScalarModulation. Shared by tunable devices and couplings so the coercion rules live in one place.

Parameters:
  • modulation (Any)

  • owner (str)

Return type:

ScalarModulation

quchip.engine.ir.signal_children(node)[source]

Return the SignalProgram child nodes of node.

Dispatches to SignalNode.signal_children(); a ScalarModulation wrapper contributes its signal. EnvelopeRef.envelope is a BaseEnvelope, not a SignalProgram child, and so is not returned here.

Parameters:

node (Any)

Return type:

tuple

quchip.engine.ir.evaluate_signal_program(signal, t, *, xp=None)[source]

Evaluate a signal program at time(s) t (ns); xp defaults to NumPy.

Parameters:
Return type:

Any

quchip.engine.ir.simplify_signal(signal)[source]

Recursively simplify a signal program by canceling exact opposing carrier pairs.

Parameters:

signal (SignalNode)

Return type:

SignalNode

class quchip.engine.ir.CarrierBand(envelope, freq)[source]

Bases: object

One band of a carrier-normalized signal: envelope(t) · exp(i · freq · t).

decompose_carrier_bands() rewrites any SignalProgram into a sum of these bands, where envelope is guaranteed carrier-free (no Carrier leaves) and therefore slow, and freq is the angular band frequency (rad/ns, sign folded in, JAX-traceable). Backends use this to keep the fast oscillation analytic while sampling only the slow envelope — exact regardless of how resonant the carrier is, unlike pre-sampling the whole product.

Parameters:
envelope: SignalNode
freq: Any
quchip.engine.ir.decompose_carrier_bands(signal)[source]

Rewrite signal into Σ_k envelope_k(t) · exp(i · freq_k · t) with carrier-free envelopes.

This is the scalar-coefficient analogue of the operator band decomposition in quchip.engine.bands: every Carrier leaf is pulled out into a band frequency, leaving a slow, carrier-free envelope per band. The rewrite is exact and follows the carrier algebra, implemented node-locally in each SignalNode.bands():

  • Carrier(freq, sign) → one band (1, sign·freq).

  • Conjugate → conjugate the envelope, flip the band frequency.

  • RealPart → split each band into ±freq (Re z = (z+z̄)/2).

  • Multiply → frequency convolution (Cartesian product of bands).

  • Add → concatenate bands.

  • Scale / PolarScale / Window / Shift → distribute over bands (Shift also contributes the constant phase exp(-i·freq·Δt)).

All frequency arithmetic stays in JAX-traceable terms (no float(), no branching on traced values).

Parameters:

signal (SignalNode)

Return type:

tuple[CarrierBand, …]

class quchip.engine.ir.CanonicalOperator(layout, values, shape, dims, basis, subsystem_labels, indices=None, indptr=None, offsets=None, tag=None)[source]

Bases: object

Backend-free operator with explicit dense/CSR/DIA payload and subsystem metadata.

For dense the payload is the full 2D matrix; for csr it is the 1D nonzero value array paired with indices/indptr; for dia it is a 2D (n_diags, n_cols) array paired with offsets. dims must multiply to shape[0] and subsystem_labels names each subsystem.

Parameters:
layout: Literal['dense', 'csr', 'dia']
values: Any
shape: tuple[int, int]
dims: tuple[int, ...]
basis: str
subsystem_labels: tuple[str, ...]
indices: Any | None = None
indptr: Any | None = None
offsets: Any | None = None
tag: str | None = None
property is_sparse: bool

True for the csr / dia layouts, False for dense.

classmethod from_dense(values, *, dims, basis, subsystem_labels, tag=None)[source]
Parameters:
Return type:

CanonicalOperator

classmethod from_csr(values, indices, indptr, *, shape, dims, basis, subsystem_labels, tag=None)[source]
Parameters:
Return type:

CanonicalOperator

classmethod from_dia(values, offsets, *, shape, dims, basis, subsystem_labels, tag=None)[source]
Parameters:
Return type:

CanonicalOperator

with_metadata(*, dims=None, basis=None, subsystem_labels=None, tag=None)[source]

Return a metadata-adjusted copy (payload unchanged).

Parameters:
Return type:

CanonicalOperator

to_dense()[source]

Materialize the payload as a dense shape-sized matrix.

Vectorized and array-namespace-preserving (JAX-safe): a traced JAX payload yields a JAX array via .at[].set / .add, a concrete NumPy payload yields a NumPy array. Callers that need a guaranteed concrete NumPy matrix must wrap the result in np.asarray(..., dtype=complex) themselves.

Return type:

Any

fingerprint()[source]

Batching key: value-sensitive, with an automatic tracer-safe fallback.

Two crosstalk-rebuilt operators carrying the same coefficients collapse to the same key so they batch into one slot (stage 4). Under jax.jit the payload is a tracer (possibly hidden inside a backend qarray wrapper, e.g. dynamiqs SparseDIAQArray); contains_tracer() detects that and the key falls back to layout + shape/dtype structure only, so tobytes() is never called on a tracer and two equivalent traced operators in different batch slots still produce identical keys.

Return type:

tuple

class quchip.engine.ir.StaticTerm(operator, coefficient=1.0, origin='device', metadata=<factory>)[source]

Bases: object

Time-independent Hamiltonian contribution.

The operator payload has already been scaled by 2π at the stage-2 boundary; backends must not re-apply it. coefficient multiplies operator and may be a concrete scalar or a JAX tracer (sweeps over static couplings, detunings, etc.). origin is purely advisory metadata.

Parameters:
operator: CanonicalOperator
coefficient: complex = 1.0
origin: Literal['device', 'coupling', 'drive', 'crosstalk', 'flux'] = 'device'
metadata: dict[str, Any]
class quchip.engine.ir.DynamicTerm(operator, time_dependence, origin='drive', tag=None)[source]

Bases: object

Time-dependent Hamiltonian contribution operator · f(t).

f(t) is wrapped in ScalarModulation, which each backend lowers into its native coefficient representation (QuTiP callback, dynamiqs sampled array, etc.). The operator is 2π-scaled already (see module docstring). tag is an optional human label; it does not participate in physics.

Parameters:
operator: CanonicalOperator
time_dependence: ScalarModulation
origin: Literal['device', 'coupling', 'drive', 'crosstalk', 'flux'] = 'drive'
tag: str | None = None
class quchip.engine.ir.DroppedTerm(source, operator, reason, band_weights=None, amplitude=None, frequency=None)[source]

Bases: object

Advisory record for a Hamiltonian term elided by an approximation.

Emitted by physics components (couplings, drives, …) whose local Hamiltonian routines discard terms under an approximation such as the rotating-wave approximation. Stage 2 aggregates these records into HamiltonianDescription.dropped_terms so callers can audit what was silently removed — in particular, compare each dropped band’s amplitude against its oscillation frequency, the smallness ratio that governs RWA validity (leading correction ∼ amplitude²/frequency, the Bloch–Siegert scale).

The string fields are static and value-free. amplitude and frequency hold raw numeric values in GHz ordinary frequency — possibly JAX-traced; they are never formatted or branched on during assembly. band_weights is static structure (excitation-change weights, one per mode the operator acts on) that stage 2 uses to resolve frequency from the frame without the owner knowing frame references.

Parameters:
  • source (str) – Label of the owning component (coupling / drive / …) that dropped the term.

  • operator (str) – Human-readable operator string (e.g. "a_q0 · a_q1").

  • reason (str) – Short reason (e.g. "counter-rotating under RWA").

  • band_weights (tuple[int, ...] | None) – Excitation-change weights of the dropped band, one per endpoint mode in the owner’s declared order (e.g. (-1, -1) for a·b). None when not applicable.

  • amplitude (Any | None) – Static prefactor of the dropped term in GHz (e.g. the coupling g); possibly traced. None when the prefactor is time-dependent (drive envelopes) or unknown.

  • frequency (Any | None) – Oscillation frequency of the dropped band in the assembly frame, GHz, positive; possibly traced. None until resolved (stage 2 fills it from the frame and band_weights).

source: str
operator: str
reason: str
band_weights: tuple[int, ...] | None = None
amplitude: Any = None
frequency: Any = None
class quchip.engine.ir.HamiltonianDescription(static_terms, dynamic_terms, dims=(), metadata=<factory>, dropped_terms=())[source]

Bases: object

Backend-agnostic time-dependent Hamiltonian — the stage-2 / backend contract.

Represents

\[H(t) \;=\; \sum_s c_s \, O_s \;+\; \sum_d O_d \, f_d(t)\]

where each static / dynamic operator already carries 2π and each f_d(t) is a ScalarModulation over a SignalProgram AST. metadata carries advisory solver hints (e.g. max_carrier_freq_ghz, max_step_ns); a backend may consult them or apply an equivalent numerical strategy of its own, but remains responsible for resolving finite-support dynamics — a finite-width pulse must not be silently skipped by an adaptive integrator that never samples it. dropped_terms records any terms that owning components elided under an approximation (RWA, etc.) — advisory metadata for auditing, never consumed by backends.

Parameters:
static_terms: tuple[StaticTerm, ...]
dynamic_terms: tuple[DynamicTerm, ...]
dims: tuple[int, ...] = ()
metadata: dict[str, Any]
dropped_terms: tuple[DroppedTerm, ...] = ()
dropped_terms_summary()[source]

Format dropped_terms as a multi-line human-readable string.

Traced amplitude / frequency values print as traced rather than being concretized.

Return type:

str

class quchip.engine.ir.HamiltonianTemplate(resolved_frame, dims, static_terms=(), invariant_dynamic_terms=(), drive_terms=(), reference_drive_ops=(), dropped_terms=(), weight_zero_drops=(), static_spectral_bound_ghz=None)[source]

Bases: object

Chip-topology-invariant Hamiltonian skeleton.

Contains:

  • static_terms — already assembled H₀ and any static (same-frame) coupling folds.

  • invariant_dynamic_terms — dynamic terms whose signal programs do not depend on drive variants (e.g. band-decomposed couplings), already simplified at template-compile time.

  • drive_terms — pre-embedded, 2π-scaled drive bands (CompiledDriveTerm) ready for per-variant reinstantiation.

  • reference_drive_ops — the structural yardstick used by instantiate_hamiltonian_description() to reject drive-ops that change the template’s skeleton (device, drive, envelope type, or drive type).

Sweep leaves (envelope parameters, drive frequencies, phases, frame scalars) are not in the template; they rebuild on every instantiation.

Parameters:
resolved_frame: Any
dims: tuple[int, ...]
static_terms: tuple[Any, ...] = ()
invariant_dynamic_terms: tuple[Any, ...] = ()
drive_terms: tuple[Any, ...] = ()
reference_drive_ops: tuple[Any, ...] = ()
dropped_terms: tuple[Any, ...] = ()
weight_zero_drops: tuple[Any, ...] = ()

SINGLE_TONE weight-0 bands dropped structurally under RWA at compile time (_compile_drive_terms()). The drop decision needs no drive frequency; resolving each entry into a DroppedTerm does, so this stays a pointer (tuple[stage2._StructuralDrop, ...]) until instantiation.

static_spectral_bound_ghz: float | None = None

Advisory spectral-bound hint (ordinary GHz) for the static terms. Computed once at template compile — the static terms are invariant across a sweep, so re-materializing their dense diagonal on every instantiation is wasted work. None when empty, oversized, or not fully concrete (a traced coefficient stays dynamic). Only the variant-specific carrier-frequency hint is recomputed per instantiation.

quchip.engine.ir.FrameSpec: TypeAlias
class quchip.engine.ir.ResolvedFrame(frequencies, demod_freqs, mode)[source]

Bases: object

Per-device frame information produced by stage 1.

Describes the rotating-frame transformation applied uniformly to the chip:

  • frequencies[label] — the per-device integration-frame frequency ω_frame in GHz. The static Hamiltonian gets the counter-term −Σᵢ ω_frame,ᵢ nᵢ.

  • demod_freqs[label] = reference_freq ω_frame — the demodulation frequency used post-solve by stage 3 to rotate expectations back into the user’s control frame. reference_freq is the device attribute (see reference_freq); it merely defaults to the dressed drive frequency when not set explicitly.

  • mode — one of "lab" / "rotating" / "float" / "dict".

Parameters:
frequencies: dict[str, Any]
demod_freqs: dict[str, Any]
mode: str
class quchip.engine.ir.SolveProblem(chip, hamiltonian, initial_state, tlist, c_ops=(), e_ops=None, e_ops_meta=None, resolved_frame=None, solver=None, options=<factory>)[source]

Bases: object

Immutable simulation request handed from the chip pipeline to a backend.

Bundles the stage-2 HamiltonianDescription, an initial_state, solver time grid, collapse operators, decomposed e_ops + their BandMeta, the ResolvedFrame, and solver options. chip owns backend selection, so options must not contain a "backend" key (enforced in __post_init__). e_ops_meta is the metadata stage 3 uses to recombine flattened band expectations back into dict-keyed observables.

Parameters:
chip: Any
hamiltonian: Any
initial_state: Any
tlist: Any
c_ops: tuple[Any, ...] = ()
e_ops: Any = None
e_ops_meta: Any = None
resolved_frame: Any = None
solver: str | None = None
options: dict[str, Any]
class quchip.engine.ir.BatchedHamiltonianDescription(batch_size, static_terms, dynamic_operators, dynamic_origins, dynamic_tags, dynamic_signals, dims=(), metadata=<factory>, dropped_terms_by_element=())[source]

Bases: object

Batched Hamiltonian IR that splits shared vs per-element structure.

Describes N Hamiltonians with identical operator skeletons (static_terms and per-slot dynamic operators) but independent per-slot ScalarModulation signal programs. Backends convert the shared operators once and stitch per-element coefficient data into one prepared batch.

dynamic_signals is indexed [slot][element]; on sweep axes that do not touch signals every entry on a slot is identity-equal. dropped_terms_by_element is indexed [element]: which bands are dropped is template-structural and shared across the batch, but each record’s frequency depends on that element’s drive frequency, so the records themselves are stored per element and restored on the matching element() call.

Parameters:
batch_size: int
static_terms: tuple[StaticTerm, ...]
dynamic_operators: tuple[CanonicalOperator, ...]
dynamic_origins: tuple[Literal['device', 'coupling', 'drive', 'crosstalk', 'flux'], ...]
dynamic_tags: tuple[str | None, ...]
dynamic_signals: tuple[tuple[ScalarModulation, ...], ...]
dims: tuple[int, ...] = ()
metadata: dict[str, Any]
dropped_terms_by_element: tuple[tuple[DroppedTerm, ...], ...] = ()
element(index)[source]

Reconstruct the single-element description at index.

Parameters:

index (int)

Return type:

HamiltonianDescription

class quchip.engine.ir.SolveBatch(chip, hamiltonian, initial_states, tlist, c_ops=(), e_ops=None, e_ops_meta=None, resolved_frame=None, solver=None, options=<factory>)[source]

Bases: object

Batched counterpart to SolveProblem.

Bundles one BatchedHamiltonianDescription plus shared solver metadata and per-element initial states. Backends solve the N elements in one native batched call (vmap on dynamiqs; shared-operator + stitched coefficient arrays on QuTiP).

Parameters:
chip: Any
hamiltonian: BatchedHamiltonianDescription
initial_states: tuple[Any, ...]
tlist: Any
c_ops: tuple[Any, ...] = ()
e_ops: Any = None
e_ops_meta: Any = None
resolved_frame: Any = None
solver: str | None = None
options: dict[str, Any]
property batch_size: int

Number of elements N in the batch.

element(index)[source]

Reconstruct the single-element SolveProblem at index.

Parameters:

index (int)

Return type:

SolveProblem

class quchip.engine.ir.DriveOp(target_label, envelope, freq=None, start_time=0.0, phase_offset=0.0, drive_label='')[source]

Bases: object

Drive operation scheduled on a device or a modulable coupling.

freq is in GHz; None selects flux drive (or baseband edge pump). start_time and phase_offset apply in the control frame. drive_label resolves the drive in the chip’s control equipment (e.g. "charge_0"). target_label resolves in the chip’s device or coupling label space.

The pulse window [start_time, start_time + envelope.duration] must overlap the solve tlist with positive measure — a window that only touches a tlist endpoint contributes no evolution and is rejected (prepare_solve_problem_context()).

Parameters:
target_label: str
envelope: BaseEnvelope
freq: float | None = None
start_time: float = 0.0
phase_offset: float = 0.0
drive_label: str = ''