quchip.declarative.models

Declarative base classes for device and coupling physics models.

DeviceModel and CouplingModel let a subclass declare its physics parameters as annotated class attributes via parameter() and implement only the Hamiltonian expression; both synthesize their own __init__, JAX pytree registration (for DeviceModel), and post-construction sign validation from the declared fields.

Classes

CouplingModel(device_a, device_b, *[, label])

Declarative two-body coupling base.

DeviceModel(*[, levels, label])

Declarative base for physics device models.

class quchip.declarative.models.DeviceModel(*, levels=2, label=None, **params)[source]

Bases: BaseDevice

Declarative base for physics device models.

Subclasses declare their parameters as annotated class attributes using parameter() (e.g. freq: Scalar = parameter(positive=True)) and implement local_hamiltonian(). The declared parameters become positional-or-keyword __init__ arguments and JAX pytree leaves so the full instance is traceable / differentiable / sweepable end-to-end.

The hamiltonian() adapter compiles the declarative expression returned by local_hamiltonian() into an operator for the active default backend.

Examples

>>> from quchip.declarative import DeviceModel, parameter, Scalar
>>> class DuffingOscillator(DeviceModel):
...     freq: Scalar = parameter(positive=True, unit="GHz")
...     anharmonicity: Scalar = parameter(unit="GHz")
...     def local_hamiltonian(self, op, p):
...         return p.freq * op.n + 0.5 * p.anharmonicity * op.n @ (op.n - op.I)
>>> device = DuffingOscillator(freq=5.0, anharmonicity=-0.3, levels=4)
>>> device.freq
5.0
Parameters:
  • levels (int)

  • label (str | None)

  • params (Any)

levels: int
label: Any
T1: Any = Parameter(default=None, positive=True, nonnegative=False, serialize=True, unit='ns', symbol=None, noise=True, kw_only=True, required=False)
T2: Any = Parameter(default=None, positive=True, nonnegative=False, serialize=True, unit='ns', symbol=None, noise=True, kw_only=True, required=False)
thermal_population: Any = Parameter(default=None, positive=False, nonnegative=True, serialize=True, unit=None, symbol=None, noise=True, kw_only=True, required=False)
approximation: ClassVar[str | None] = None

Declared approximation-regime statement surfaced by physics_notes() — the mechanism that keeps a model’s stated validity range attached to the class rather than buried in a docstring a caller may not read.

computational: ClassVar[bool] = False

Whether this device represents a computational qubit, as opposed to e.g. a bus resonator or a coupler element.

structural_setting_names: ClassVar[tuple[str, ...]] = ()
validate()[source]

Cross-field validation hook, run at the end of construction.

Default is a no-op. Subclasses override to enforce constraints that span multiple declared parameters (e.g. 2 * edge <= duration). Checks must be gated on concrete scalars via quchip.utils.jax_utils.maybe_concrete_scalar() so traced parameters never force concretization.

Return type:

None

local_hamiltonian(op, p)[source]

Return this device’s local Hamiltonian as a declarative expression.

Parameters:
  • op (LocalOps) – Operator namespace for this device’s endpoint, exposing a, adag, n, I and the Pauli handles as composable PhysicsExpr nodes.

  • p (ParameterNamespace) – Symbolic leaves for the parameters declared on this model.

Returns:

The local Hamiltonian expression, in ordinary-frequency units (GHz).

Return type:

PhysicsExpr

time_terms(op, p)[source]

Return local time-dependent Hamiltonian terms beyond the static model.

Parameters:
Return type:

tuple[TimeDependentTerm, …]

dissipation(op, p)[source]

Return device-local Lindblad channels.

The base channels implement T1, T2, and thermal occupation. Subclasses may append channels with super().dissipation(op, p).

Parameters:
Return type:

tuple[CollapseChannel, …]

unresolved_hamiltonian()[source]

Return the authored symbolic local Hamiltonian.

Return type:

Any

to_dict()[source]

Serialize common device state plus declared parameter values.

Return type:

dict[str, Any]

classmethod from_dict(d)[source]

Reconstruct the device from to_dict() output.

Parameters:

d (dict[str, Any])

Return type:

DeviceModel

physics_notes()[source]

Return base device notes plus the declared approximation, if any.

Return type:

list[str]

class quchip.declarative.models.CouplingModel(device_a, device_b, *, label=None, **params)[source]

Bases: BaseCoupling

Declarative two-body coupling base.

Subclasses declare physics parameters via parameter() and implement interaction() (returning a PhysicsExpr over the two endpoint operators). The chip’s approximation strategy is applied structurally by the engine after the authored interaction is assembled. Optional overrides:

  • time_terms() — time-dependent Hamiltonian terms, each pairing a local operator with a public time coefficient.

coupling_strength defaults to the first declared parameter field (suited for the common case of one g-like scalar). Override the property in subclasses with a different convention.

Note

Coupling instances are not registered as JAX pytrees and cannot be passed as dynamic jax.jit / jax.vmap / jax.grad arguments. Coupling parameters remain differentiable when the coupling (and the devices or chip it couples) is constructed from traced arguments inside the transformed function.

Examples

>>> from quchip.declarative import CouplingModel, parameter, Scalar
>>> class ExchangeCoupling(CouplingModel):
...     g: Scalar = parameter(unit="GHz")
...     def interaction(self, a, b, p):
...         return p.g * (a.a * b.adag + a.adag * b.a)
>>> c = ExchangeCoupling("q0", "q1", g=0.01)
>>> c.coupling_strength
0.01
Parameters:
device_a: BaseDevice | str
device_b: BaseDevice | str
label: Any
property coupling_strength: Any

Primary scalar coupling strength, defaulting to the first parameter.

property coupling_strength_name: str

Display name of coupling_strength, defaulting to the first parameter field.

interaction(a, b, p)[source]

Return the full two-body interaction expression.

Parameters:
  • a (EndpointOps) – Operator namespaces for the two coupled endpoints. Same-endpoint operators compose with @; cross-endpoint operators combine with * (tensor product).

  • b (EndpointOps) – Operator namespaces for the two coupled endpoints. Same-endpoint operators compose with @; cross-endpoint operators combine with * (tensor product).

  • p (Any)

Returns:

The interaction Hamiltonian expression, in ordinary-frequency units (GHz).

Return type:

PhysicsExpr

time_terms(a, b, p)[source]

Return time-dependent interaction terms.

Parameters:
  • a (EndpointOps) – Operator namespaces for the two coupled endpoints.

  • b (EndpointOps) – Operator namespaces for the two coupled endpoints.

  • p (Any)

Returns:

Local operators and their scalar time coefficients. The empty tuple denotes a purely static coupling.

Return type:

tuple of TimeDependentTerm

parametric_interaction(a, b, p)[source]

Return the parametric interaction structure, or None when this coupling is not modulable.

The coupling-side mirror of the device drive-dispatch protocols: a ParametricDrive accepts any coupling whose hook returns a PhysicsExpr.

Parameters:
Return type:

Any

dissipation(a, b, p)[source]

Return authored two-endpoint Lindblad channels.

Parameters:
Return type:

tuple[CollapseChannel, …]

interaction_hamiltonian()[source]

Return the authored symbolic interaction Hamiltonian.

Return type:

Any

collapse_channels()[source]

Return normalized coupling collapse channels.

Return type:

tuple[CollapseChannel, …]

classmethod from_dict(d, device_a, device_b)[source]

Reconstruct a coupling from to_dict() output.

Default implementation: forward declared parameters straight into __init__. Subclasses with bespoke serialization (e.g. envelope modulations) override this.

Parameters:
Return type:

CouplingModel

to_dict()[source]

Serialize common coupling state plus declared parameter values.

Return type:

dict[str, Any]