quchip.inverse_design.fit

Fit bare chip parameters to a numerical dressed specification.

Devices and couplings declare how their input numbers map to dressed targets. The desired chip is read structurally, not diagonalized to discover those targets. Candidate chips are then evaluated in a bounded nonlinear least-squares solve. The deprecated explicit-target path remains available through 0.2.x for migration.

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 / Delta qubit-resonator dispersive shift at leading order, the dispersive-regime intuition behind the chi seed search (_estimate_bare_g()). The zz seed makes no leading-order claim of its own: the seed search only requires the target to be bracketed by the observable at the endpoints of seed_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_a_dress(chip, *[, constraints, vary, ...])

Find bare parameters for a numerically specified dressed chip.

quchip.inverse_design.fit.fit_a_dress(chip, *, constraints=None, vary=None, start=None, coupling_targets=None, observable_targets=None, fit_parameters=None, max_hilbert_dim=10000, seed_strength_bounds=(1e-06, 0.25), max_nfev=1000)[source]

Find bare parameters for a numerically specified dressed chip.

fit_a_dress(desired) reads component-owned target declarations without evaluating desired. Common spectral devices interpret their declared frequencies and anharmonicities as dressed targets. A Capacitive edge between two non-computational modes targets the dressed exchange_rate. Other Capacitive edges and CrossKerr couplings target the full cross_kerr = E11 - E10 - E01 + E00. The returned chip is a fitted clone; desired is never mutated.

constraints adds or replaces numerical observables, vary replaces the component-owned free-parameter selection, and start replaces selected starting values. The deprecated coupling_targets, observable_targets, and fit_parameters keywords keep their seed-chip semantics through 0.2.x. They cannot be mixed with the desired-chip keywords and will be removed in 0.3.0.

Parameters:
  • chip (Chip) – Desired dressed-chip specification. Component declarations supply numerical targets; no dressed analysis is run on this object.

  • constraints (Mapping | None) – Additional {component_or_pair: {observable: value_or_none}} constraints. Supported canonical observables are "freq", "anharmonicity", "cross_kerr", "exchange_rate", and "coupling_strength". "zz"/"static_zz", "exchange", and "g" are accepted aliases. An explicit value replaces the same component default; None removes it. Device pairs need not be direct coupling edges.

  • vary (Mapping | None) – Complete desired-chip allowlist of bare parameters that may move: {component_or_label: name_collection}. When omitted, each component’s conservative inverse-design policy is used. Components absent from an explicit mapping are frozen.

  • start (Mapping | None) – Optional {"<component>.<parameter>": value} replacements for the selected optimizer starting values. A key not selected by vary raises instead of being silently ignored.

  • coupling_targets (Mapping | None) – Deprecated since 0.2.1; use constraints. Maps a 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. With fit_parameters=None, couplings not listed here are still free — they are optimized, just without a dedicated anchor; a fit_parameters mapping 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 raises ValueError at construction.

  • observable_targets (Mapping | None) – Deprecated since 0.2.1; put numerical dressed values on chip and add extra observables with constraints. 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) – Deprecated since 0.2.1; use vary. None in the compatibility path selects every declared device tunable (tunable_params()) and every coupling’s scalar strength is free. A mapping is the complete free-parameter allowlist: {component_or_label: name_collection}, where a device’s name_collection is 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 empty name_collection explicitly 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_params contain 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 for cross_kerr/chi/zz coupling targets. The target observable must be bracketed by the values at these two endpoints, or seeding raises ValueError rather 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 ObservableReport tuples, packed parameters, and solver metadata.

Return type:

FitADressResult

Raises:

ValueError – Desired-chip and deprecated compatibility keyword families are mixed; a "chi" coupling target does not have exactly one computational endpoint, or a chi/zz seed’s target observable is not bracketed within seed_strength_bounds; an automatic desired-chip plan is underdetermined by count or rank; a fit_parameters key does not resolve to a device or coupling label on chip, names a parameter the resolved component does not declare, resolves the same label twice, or is a bare string rather than a name collection; or fit_parameters selects zero free parameters overall.

Warns:

UserWarning – A fit using explicit vary or deprecated compatibility keywords is underdetermined by target count or final scaled-Jacobian rank. Explicit plans are returned with diagnostics because the caller has taken ownership of the ambiguity; automatic desired-chip plans raise instead.

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 its x_scale floor (1e-3, applied per parameter as max(abs(x0), 1e-3)) are fixed fitter policy, not exposed as options.

Identifiability. The free-parameter-vs-residual count is necessary but not sufficient. The fitter therefore computes the final SVD rank and condition number from normalized residuals in the same scaled parameter coordinates used by the solver. A custom DeviceModel whose tunable_param_names is discovered (the derived default, not an explicit declaration) is not automatically fit-ready: an unbounded parameter still needs a tunable_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.