Source code for quchip.inverse_design.types

from __future__ import annotations

from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, overload

if TYPE_CHECKING:
    from quchip.chip import Chip
    from quchip.devices.base import BaseDevice


[docs] @dataclass(frozen=True) class ObservableReport: """Per-target record from a ``fit_a_dress`` run. Attributes ---------- kind Observable kind: ``"freq"``, ``"anharmonicity"``, ``"chi"``, ``"zz"``, ``"exchange"``, or ``"g"``. label Target locator — a device label for single-device observables, a ``(label_a, label_b)`` tuple for pair observables, or a coupling label for coupling-keyed observables. target The value the optimizer tried to match (GHz). initial Observable value at the seed chip, before optimization (GHz). final Observable value at the fitted chip, after optimization (GHz). evaluator ``"full"`` if this target was evaluated on the whole chip or ``"local"`` if it was evaluated on a one-hop subsystem (see ``max_hilbert_dim`` in :func:`fit_a_dress`). """ kind: str label: Any target: float initial: float final: float evaluator: str
[docs] @dataclass(frozen=True) class FitADressResult: """Result of a :func:`fit_a_dress` optimization run. Attributes ---------- chip Fitted chip — a clone of the seed with updated ``freq``/``anharmonicity`` and coupling-strength values. The seed chip is never mutated. Exposing ``.chip`` makes this satisfy :class:`~quchip.chip.transformations.ChipTransform` structurally, with no inheritance required. loss Final objective (sum of squared, scale-normalized residuals). history 1-D ``numpy`` array holding ``[loss_initial, loss_final]``. A compact record of how far the solver moved; it is not a per-iteration trace because ``scipy.optimize.least_squares`` does not expose one. initial_targets One :class:`ObservableReport` per target, evaluated on the seed chip. final_targets One :class:`ObservableReport` per target, evaluated on the fitted chip. initial_params ``{parameter_name: seed_value}`` — the starting point passed to the optimizer. final_params ``{parameter_name: fitted_value}`` — the optimizer output. Parameter names follow ``"<device>.freq"``, ``"<device>.anharmonicity"``, and ``"<coupling>.<coupling_strength_name>"`` — ``"<coupling>.g"`` for :class:`~quchip.chip.couplings.Capacitive`, ``"<coupling>.g_0"`` for :class:`~quchip.chip.couplings.TunableCapacitive`, ``"<coupling>.chi"`` for :class:`~quchip.chip.couplings.CrossKerr`. solver_info ``scipy`` solver metadata (``method``, ``status``, ``message``, ``nfev``, ``jacobian``), plus the identifiability receipt recorded for every :func:`~quchip.inverse_design.fit.fit_a_dress` call: ``n_free_parameters`` (length of ``final_params``), ``n_target_residuals`` (length of ``final_targets``), and ``underdetermined_by_count`` (``True`` when the former exceeds the latter — a necessary, not sufficient, identifiability condition; no Jacobian-rank analysis is performed). ``jacobian`` is ``"jax"`` when a JAX-native backend supplies the exact residual Jacobian and ``"finite-difference"`` otherwise. """ chip: Chip loss: float history: Any initial_targets: tuple[ObservableReport, ...] final_targets: tuple[ObservableReport, ...] initial_params: dict[str, float] final_params: dict[str, float] solver_info: dict[str, Any] @overload def rebind(self, seed: BaseDevice | str, /) -> BaseDevice: ... @overload def rebind(self, seed: BaseDevice | str, /, *more: BaseDevice | str) -> tuple[BaseDevice, ...]: ...
[docs] def rebind(self, *seeds: BaseDevice | str) -> Any: """Look up the fitted clones matching one or more seed devices. ``fit.rebind(qb, tc, cr)`` replaces the ``qb_f = chip.device_map[qb.label]`` triple most tutorials opened with. Parameters ---------- *seeds : BaseDevice or str One or more devices (or their labels) from the *seed* chip passed to :func:`~quchip.inverse_design.fit.fit_a_dress`. At least one is required. Returns ------- BaseDevice or tuple[BaseDevice, ...] The matching device(s) on :attr:`chip` (the fitted clone), in input order. A single positional ``seed`` returns that device directly; two or more return a tuple. Raises ------ ValueError No seeds were given. """ if not seeds: raise ValueError("rebind requires at least one seed device or label") fitted = tuple(self.chip[s] for s in seeds) return fitted[0] if len(fitted) == 1 else fitted