quchip.inverse_design¶
Inverse-design utilities.
Fit bare chip parameters (device freq/anharmonicity, a
coupling’s scalar strength) so that dressed observables (frequencies,
anharmonicities, chi, zz, exchange) match user-supplied
targets. The fit is
classical (scipy.optimize.least_squares) but every downstream use
of the returned Chip remains fully
JAX-traceable and differentiable — see
quchip.inverse_design.fit.fit_a_dress() for details.
- quchip.inverse_design.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.
- class quchip.inverse_design.FitADressResult(chip, loss, history, initial_targets, final_targets, initial_params, final_params, solver_info)[source]¶
Bases:
objectResult of a
fit_a_dress()optimization run.- Parameters:
- chip¶
Fitted chip — a clone of the seed with updated
freq/anharmonicityand coupling-strength values. The seed chip is never mutated. Exposing.chipmakes this satisfyChipTransformstructurally, with no inheritance required.- Type:
- history¶
1-D
numpyarray holding[loss_initial, loss_final]. A compact record of how far the solver moved; it is not a per-iteration trace becausescipy.optimize.least_squaresdoes not expose one.- Type:
Any
- initial_targets¶
One
ObservableReportper target, evaluated on the seed chip.- Type:
- final_targets¶
One
ObservableReportper target, evaluated on the fitted chip.- Type:
- 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"forCapacitive,"<coupling>.g_0"forTunableCapacitive,"<coupling>.chi"forCrossKerr.
- solver_info¶
scipysolver metadata (method,status,message,nfev,jacobian), plus the identifiability receipt recorded for everyfit_a_dress()call:n_free_parameters(length offinal_params),n_target_residuals(length offinal_targets), andunderdetermined_by_count(Truewhen the former exceeds the latter — a necessary, not sufficient, identifiability condition; no Jacobian-rank analysis is performed).jacobianis"jax"when a JAX-native backend supplies the exact residual Jacobian and"finite-difference"otherwise.
- history: Any¶
- initial_targets: tuple[ObservableReport, ...]¶
- final_targets: tuple[ObservableReport, ...]¶
- rebind(seed: BaseDevice | str, /) BaseDevice[source]¶
- rebind(seed: BaseDevice | str, /, *more: BaseDevice | str) tuple[BaseDevice, ...]
Look up the fitted clones matching one or more seed devices.
fit.rebind(qb, tc, cr)replaces theqb_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
fit_a_dress(). At least one is required.- Returns:
The matching device(s) on
chip(the fitted clone), in input order. A single positionalseedreturns that device directly; two or more return a tuple.- Return type:
BaseDevice or tuple[BaseDevice, …]
- Raises:
ValueError – No seeds were given.
- class quchip.inverse_design.ObservableReport(kind, label, target, initial, final, evaluator)[source]¶
Bases:
objectPer-target record from a
fit_a_dressrun.- 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.- Type:
Any
- evaluator¶
"full"if this target was evaluated on the whole chip or"local"if it was evaluated on a one-hop subsystem (seemax_hilbert_diminfit_a_dress()).- Type:
Modules
Dressed-observable fitting of bare chip parameters. |
|
Target-spec construction for |
|
Neighborhood extraction for large-chip observables. |
|