quchip.inverse_design.fit¶
Dressed-observable fitting of bare chip parameters.
Calibration data arrives in the dressed frame: a spectroscopy peak is
a dressed eigenvalue, a Ramsey shift is a dispersive chi, a
parked-qubit detuning is a static zz. The chip model, on the
other hand, is parameterized by bare quantities — device freq
and anharmonicity, a coupling’s scalar strength (g, g_0,
chi, depending on the coupling type — see
coupling_strength).
fit_a_dress() closes that gap: given targets on dressed
observables, it finds bare parameters whose dressed spectrum
reproduces them.
References
Dispersive regime (chi, zz, and dressed frequencies):
Koch et al., Phys. Rev. A 76, 042319 (2007), “Charge-insensitive qubit design derived from the Cooper pair box” — the DuffingTransmon approximation and its dispersive shifts.
Gambetta et al., Phys. Rev. A 74, 042318 (2006), “Qubit-photon interactions in a cavity” — the
chi = g^2 / Deltaqubit-resonator dispersive shift at leading order, the dispersive-regime intuition behind thechiseed search (_estimate_bare_g()). Thezzseed makes no leading-order claim of its own: the seed search only requires the target to be bracketed by the observable at the endpoints ofseed_strength_bounds(checked, not assumed) — it does not require the observable to be monotone in between;scipy.optimize.brentq()finds a consistent root regardless of the observable’s direction (increasing or decreasing) within the bracket.
JAX traceability¶
Every bare parameter here (device.freq, device.anharmonicity, a
coupling’s coupling_strength) is a sweepable, differentiable
quantity. A chip using a JAX-native backend supplies a traced
dressed-observable residual and exact Jacobian; SciPy consumes their concrete
values only at the bounded trust-region boundary. The optimizer itself is not
JAX-traceable, while the output Chip remains fully
traceable for every downstream operation.
Functions
|
Fit bare chip parameters so dressed observables match targets. |
- quchip.inverse_design.fit.fit_a_dress(chip, *, coupling_targets=None, observable_targets=None, fit_parameters=None, max_hilbert_dim=10000, seed_strength_bounds=(1e-06, 0.25), max_nfev=1000)[source]¶
Fit bare chip parameters so dressed observables match targets.
With
fit_parameters=None(the default), every devicefreq/anharmonicityand every coupling’s scalar strength (coupling_strength) is a free variable in a bounded non-linear least-squares problem (scipy Trust-Region Reflective). Afit_parametersmapping instead is the complete free-parameter allowlist — seefit_parametersbelow — so any device or coupling it does not list is frozen instead of free. The fitted chip is returned as a clone — the input chip is never mutated.- Parameters:
chip (Chip) – Seed chip. Seeds only set the optimizer’s starting point.
coupling_targets (Mapping | None) – Mapping from coupling (or its label) to a target mode:
"chi","zz", or"g". For listed couplings, the coupling’s current strength is interpreted as the target value for that mode. Withfit_parameters=None, couplings not listed here are still free — they are optimized, just without a dedicated anchor; afit_parametersmapping can freeze them regardless (a coupling target does not itself make a coupling free). A"chi"target requires the coupling to have exactly one computational endpoint; both-computational or neither-computational raisesValueErrorat construction.observable_targets (Mapping | None) – Mapping of target observables. Keys are devices/labels or
(device_a, device_b)tuples; values are{kind: value}dicts. Supported kinds:"freq","anharmonicity"(device),"exchange","zz"(pair). Device-level targets override the auto-targeted defaults for the same(kind, label).fit_parameters (Mapping | None) –
None(default): every declared device tunable (tunable_params()) and every coupling’s scalar strength is free — the pre-existing behavior. A mapping is instead the complete free-parameter allowlist:{component_or_label: name_collection}, where a device’sname_collectionis a subset of its declared tunable names and a coupling’s is a subset of(coupling.coupling_strength_name,). A component (device or coupling, given as the object or its label) absent from the mapping is fully frozen — it does not default to free. An emptyname_collectionexplicitly freezes a listed component. A bare string value (e.g."E_J"instead of("E_J",)) is rejected, since a string is itself a collection of characters. Selected parameters are packed in chip order and each component’s own declared parameter order, not mapping or tuple order.initial_params/final_paramscontain only the selected (free) parameters.max_hilbert_dim (int) – Above this total Hilbert-space size the fit switches from dressing the whole chip to dressing one-hop subsystems per target (see
quchip.inverse_design.subsystems).seed_strength_bounds (tuple[float, float]) –
(lo, hi)magnitude bounds for the bare-coupling-strength seed root solve (_estimate_bare_g()) used forchi/zzcoupling targets. The target observable must be bracketed by the values at these two endpoints, or seeding raisesValueErrorrather than silently returning a saturated endpoint.max_nfev (int) – Maximum number of residual evaluations for the SciPy Trust-Region Reflective solver.
- Returns:
Fitted chip clone, loss, residual history, per-target
ObservableReporttuples, packed parameters, and solver metadata.- Return type:
- Raises:
ValueError – A
"chi"coupling target does not have exactly one computational endpoint, or achi/zzseed’s target observable is not bracketed withinseed_strength_bounds; afit_parameterskey does not resolve to a device or coupling label onchip, names a parameter the resolved component does not declare, resolves the same label twice, or is a bare string rather than a name collection; orfit_parametersselects zero free parameters overall.- Warns:
UserWarning – The number of free parameters exceeds the number of target residuals (underdetermined by count). This is a necessary, not sufficient, identifiability condition: it does not analyze the Jacobian’s rank, so a count-sufficient fit can still be practically underdetermined.
Notes
Residuals are normalized by
max(|target|, 1e-9)so every anchor contributes on equal relative-error footing. A coupling’s scalar strength bounds are symmetric around zero — the sign of a capacitive-type coupling is physical and must not be constrained. The solver’s convergence tolerances (ftol/xtol/gtol=1e-11) and itsx_scalefloor (1e-3, applied per parameter asmax(abs(x0), 1e-3)) are fixed fitter policy, not exposed as options.Two identifiability hazards the count check above does not catch. The free-parameter-vs-residual count is necessary but not sufficient: it cannot detect a flat Jacobian direction — a free parameter no target observable actually responds to — which stays underdetermined regardless of the count. And a custom
DeviceModelwhosetunable_param_namesis discovered (the derived default, not an explicit declaration) is not automatically fit-ready: an unbounded parameter still needs atunable_param_bounds()rule before the optimizer can search it.JAX traceability. When the chip uses a JAX-native backend, the complete parameter-to-residual map and its exact Jacobian are JAX-traceable; SciPy receives their concrete values for bounded trust-region control. The optimizer itself is not differentiated. Other backends retain SciPy’s numerical Jacobian. The returned chip remains fully traceable and differentiable in either case.