quchip quchip

An open-source Python toolkit for modeling superconducting quantum chips.

A chip is declared once — devices, couplings, control lines, dissipation, observables. That declaration is then used for dressed-state analysis, model reduction, control sequencing, open-system simulation, parameter sweeps, and JAX gradients.

$ pip install quchipcopy
source on GitHub
Python ≥ 3.11 · Apache 2.0
WHAT THE MODEL HOLDS

Explicit model parts

Device physics, control-line transformations, frames and approximations, dissipation, and measured observables each have their own representation in the model.

Control lines

Gain, delay, and crosstalk are properties of the control chain, so Hamiltonian terms don't have to be written by hand to account for them.

One declaration

Analysis, reduction, sequencing, simulation, and sweeps all read the same chip object; nothing is re-specified per task.

JAX gradients

With the dynamiqs backend, declared device and control parameters stay differentiable through the solve.

Backends

QuTiP by default; dynamiqs, graph visualization, and scqubits interop as optional extras.

Recorded approximations

The engine resolves each device's frame, applies the requested approximations, and records the bands it drops. Conventions are written down in PHYSICS.md.

A MINIMAL CHIP

A transmon, a readout resonator, one π pulse

import numpy as np
from quchip import (Capacitive, ChargeDrive, Chip, DuffingTransmon,
                    Gaussian, QuantumSequence, Resonator)

qubit   = DuffingTransmon(freq=5.24, anharmonicity=-0.26, levels=3)
readout = Resonator(freq=6.65, levels=4)
chip    = Chip([qubit, readout],
               couplings=[Capacitive(qubit, readout, g=0.060)],
               frame="rotating")

drive = ChargeDrive(qubit)
chip.wire(drive)

sequence = QuantumSequence(chip)
sequence.schedule(drive, envelope=Gaussian(duration=40.0, amplitude=0.030),
                  freq=chip.freq(qubit))
result = sequence.simulate(tlist=np.linspace(0.0, 40.0, 81),
                           initial_state=chip.state({qubit: 0, readout: 0}),
                           e_ops={qubit: qubit.projector(1, 1)})

result.plot_populations(trace_out=readout)
Qubit populations during the π pulse
The saved output of the snippet: qubit populations during the π pulse, readout resonator traced out. The pulse carrier comes from the dressed chip frequency.