Your first chip

Build a coupled transmon–resonator model, read its dressed frequencies, and find bare parameters that meet a design target. Frequencies are in GHz.

Declare the model

from quchip import Capacitive, Chip, DuffingTransmon, Resonator, fit_a_dress

q = DuffingTransmon(freq=5.0, anharmonicity=-0.25, levels=4, label="q")
r = Resonator(freq=7.0, levels=5, label="r")
qr = Capacitive(q, r, g=0.05, label="qr")
chip = Chip([q, r], [qr])

Labels name the model’s parameters: q.freq, q.anharmonicity, and qr.g. Inspect the declaration with describe():

print(chip.describe())

Output:

Chip
════
Frame    : lab
Approx.  : RWA
Dressed  : not computed
Hilbert  : 4 x 5 = 20 levels
Sectors  : N conserved; dressed queries with N <= 2 diagonalize at most 3 states

Devices (2)
───────────
q — DuffingTransmon
    T1 = None   T2 = None   thermal_occupation = None   freq = 5 GHz   anharmonicity = -0.25 GHz   levels = 4
r — Resonator
    T1 = None   T2 = None   thermal_occupation = None   freq = 7 GHz   internal_quality_factor = None   levels = 5

Couplings (1)
─────────────
qr : q ↔ r
    g = 0.05 GHz

The Sectors line shows that this RWA model conserves the total excitation number \(N\), the sum of the device levels. Dressed queries therefore diagonalize one small block for each \(N\) instead of all 20 levels. chip.excitation_structure() lists the terms that decide this.

Read dressed observables

Device constructors specify bare parameters, and chip returns the coupled system’s frequencies and interactions.

print(f"Qubit f01: {chip.freq(q):.6f} GHz")
print(f"Resonator frequency: {chip.freq(r):.6f} GHz")
print(f"Conditional resonator pull: {1000 * chip.dispersive_shift(q, r):.3f} MHz")

Output:

Qubit f01: 4.998751 GHz
Resonator frequency: 7.001249 GHz
Conditional resonator pull: -0.277 MHz

The full conditional pull is \(E_{11}-E_{10}-E_{01}+E_{00}\). For quchip’s \(Z=|0\rangle\langle0|-|1\rangle\langle1|\), the coefficient of \(Z n_r\) is negative half this pull: \(\chi_Z=-\mathrm{dispersive\_shift}/2\). chip.kerr_matrix() collects full pulls off-diagonal and dressed anharmonicities on the diagonal.

Change a parameter

with_params() returns a new chip, and the source declaration stays available.

shifted = chip.with_params({"q.freq": 5.1})

print(f"Original bare / dressed: {q.freq:.3f} / {chip.freq(q):.6f} GHz")
print(f"Changed bare / dressed: {shifted.parameters['q.freq']:.3f} / {shifted.freq('q'):.6f} GHz")

Output:

Original bare / dressed: 5.000 / 4.998751 GHz
Changed bare / dressed: 5.100 / 5.098685 GHz

Inspect the Hamiltonian

unresolved_hamiltonian() shows the Hamiltonian you declared. hamiltonian() is the expression selected for simulation, after basis, frame, and RWA choices. Both show as equations in a notebook.

declared = chip.unresolved_hamiltonian()
resolved = chip.resolve(frame="rotating")

print(resolved.dropped_terms_summary())

Output:

2 term(s) dropped:
  [qr] coupling band (-1, -1) on q·r  (discarded by RWA band selection; amp 0.173205 GHz, detuning 11.5 GHz)
  [qr] coupling band (+1, +1) on q·r  (discarded by RWA band selection; amp 0.173205 GHz, detuning 11.5 GHz)

The dropped terms create or annihilate two excitations. Each record shows the matrix element with the largest |V|²/ΔE and its bare-energy detuning. Here the detunings are much larger than the matrix elements. Band weights use column - row, so lowering has positive weight. See the physics reference for frame and approximation conventions.

Fit a dressed target

For fit_a_dress(), device values specify desired dressed frequencies and anharmonicities. Coupling values specify desired full cross-Kerr pulls. The fit returns the bare parameters that produce those targets.

target_q = DuffingTransmon(freq=5.0, anharmonicity=-0.25, levels=4, label="q")
target_r = Resonator(freq=7.0, levels=5, label="r")
target_pull = Capacitive(target_q, target_r, g=-0.0003, label="qr")
target = Chip([target_q, target_r], [target_pull])

fit = fit_a_dress(target)

print(f"Converged: {fit.converged}; normalized loss: {fit.loss:.2e}")

Output:

Converged: True; normalized loss: 5.43e-24
Inspect fitted parameters and residuals
print(fit.summary())

Output:

fit_a_dress: converged | loss 5.43e-24 | targets: 4 | parameters: 4
identifiability: rank 4/4 | condition 35.8
`xtol` termination condition is satisfied.
targets (GHz):
  q.freq [component default]: 5 -> 5 (error +1.8e-15)
  q.anharmonicity [component default]: -0.25 -> -0.25 (error +3.6e-15)
  r.freq [component default]: 7 -> 7 (error +0)
  qr.cross_kerr [component default]: -0.0003 -> -0.0003 (error +7e-16)
bare parameters (GHz):
  q.freq: 5 -> 5.00135 [component declaration]
  q.anharmonicity: -0.25 -> -0.2503 [component declaration]
  r.freq: 7 -> 6.99865 [component declaration]
  qr.g: 0.0520244 -> 0.0519304 [isolated-pair root solve; positive convention]

Continue with spectra and parameter sweeps to sweep the coupled spectrum. For imported or custom models, see scqubits interoperability and extensions.