Source code for quchip.control.drive

"""Drive classes and Hamiltonian channel definitions.

Drives model the classical control lines that couple a quantum device to
external fields — microwave charge/phase drives on transmons, real-valued
flux drives on tunable devices, and so on. Each drive owns its local
Hamiltonian contribution: it exposes an operator and a
:class:`~quchip.control.signal_spec.DriveModulation` tag that together
describe how its line signal enters the system Hamiltonian. Signal
transforms (delays, gains, crosstalk) live separately on
:class:`~quchip.control.equipment.ControlEquipment`.

Drives are frame-agnostic: they emit a
:class:`~quchip.control.signal_spec.DriveSignalSpec` in ordinary GHz
and never construct engine IR nodes. Stage 2 of the engine is the sole
place where the spec is composed with the resolved rotating frame into a
:class:`~quchip.engine.ir.SignalProgram`.

Conventions:

- Frequencies are GHz; times are ns.
- Operators are returned in the device's computational basis — embedding
  into the full chip Hilbert space is the engine's job.

References
----------
- Krantz et al., *A quantum engineer's guide to superconducting qubits*,
  APR 6, 021318 (2019) — microwave control of transmons (Sec. IV).
- Koch et al., PRA 76, 042319 (2007) — charge vs flux noise and drives
  in the transmon regime.
"""

from __future__ import annotations

import copy
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any, ClassVar

from quchip.backend.protocol import Operator
from quchip.control.signal_spec import DriveSignalSpec, DriveModulation
from quchip.devices.base import BaseDevice
from quchip.devices.protocols import ChargeCoupled, FluxCoupled, PhaseCoupled
from quchip.utils.labeling import auto_label
from quchip.utils.registry import Registrable

# Note: ``DriveOp`` appears only as a string annotation on
# :meth:`BaseDrive.signal_spec` — the class lives in
# :mod:`quchip.engine.ir` but must not be imported here, even under
# ``TYPE_CHECKING``, because drives are strictly frame-agnostic and
# cannot depend on engine IR.


[docs] @dataclass(frozen=True) class DriveChannel: """One Hamiltonian channel exposed by a drive on a target device. A channel pairs a local-basis operator with a :class:`~quchip.control.signal_spec.DriveModulation` tag that tells the engine how the channel's coefficient is built from the drive's line signal. A drive may expose multiple channels if, for example, it contributes both in-phase and quadrature couplings. """ operator: Operator modulation: DriveModulation
[docs] class BaseDrive(Registrable, registry_root=True): """Base class for classical control lines driving a single device. Drives own their local Hamiltonian contribution and are auto-labelled from their ``_type_prefix`` (e.g. ``charge_0``, ``flux_0``) unless *label* is given. Subclasses are auto-registered for serialization via the shared :class:`~quchip.utils.registry.Registrable` mixin. Parameters ---------- target : BaseDevice | None Device to attach this drive to. May be connected later via :meth:`connect`. label : str | None Optional explicit label; otherwise auto-generated. rwa : bool | None Per-drive RWA override. ``None`` means follow the chip-level setting. Examples -------- >>> from quchip import DuffingTransmon, ChargeDrive >>> q = DuffingTransmon(freq=5.0, anharmonicity=-0.25, levels=3) >>> drive = ChargeDrive(target=q) >>> drive.device_label == q.label True """ _type_prefix: str = "drive" #: Structural dispatch key for equipment/chip/sequence code: ``"device"`` #: for drives targeting a device (the default), ``"edge"`` for drives #: targeting a coupling (see :class:`ParametricDrive`). target_kind: ClassVar[str] = "device" #: True for microwave-style drives whose carrier frequency must be supplied #: explicitly when scheduling (cannot default to the device drive frequency). _carrier_required: bool = False #: True for microwave-style drives whose carrier frequency defaults to the #: target device's :attr:`~BaseDevice.drive_freq` when not given. _defaults_to_device_drive_freq: bool = False #: True for drives that participate in software-Z (virtual-Z) tracking — #: charge/phase microwave drives. Baseband flux drives leave virtual-Z #: phases unchanged. _accepts_virtual_z: bool = False # ------------------------------------------------------------------ # Declarative local-channel dispatch. # # A simple single-channel drive declares the five attributes below and # inherits :meth:`local_channels` / :meth:`physics_notes` from the base # — no copy-pasted protocol-dispatch body. Drives with a non-standard # decomposition (e.g. two-photon parametric drives) leave the protocol # unset and override :meth:`local_channels` directly. # ------------------------------------------------------------------ #: Device Protocol (ChargeCoupled / PhaseCoupled / FluxCoupled) whose #: physical coupling operator this drive prefers. ``None`` means the drive #: implements :meth:`local_channels` itself. _coupling_protocol: type | None = None #: Name of the device method returning the physical coupling operator when #: the target conforms to :attr:`_coupling_protocol`. _coupling_accessor: str | None = None #: Structural fallback building the coupling operator from the device's #: ``a`` / ``a†`` / ``n̂`` when it does not conform to the Protocol. _fallback: Callable[[BaseDevice], Operator] #: :class:`~quchip.control.signal_spec.DriveModulation` tag for the single #: channel exposed by :meth:`local_channels`. _modulation: DriveModulation | None = None #: ``physics_notes`` line declaring the coupling operator and modulation. _coupling_note: str | None = None def __init__( self, target: BaseDevice | None = None, *, label: str | None = None, rwa: bool | None = None, ) -> None: self.label = label if label is not None else auto_label(type(self)._type_prefix) self.rwa = rwa self._target: BaseDevice | None = None if target is not None: self.connect(target)
[docs] def connect(self, device: BaseDevice) -> None: """Attach (or re-attach) this drive to *device*. If the drive was previously attached to another device, it is detached from that device's ``_connected_drives`` list so that only the new attachment is visible on the chip. """ old_target = self._target if old_target is not None and old_target is not device: old_target._connected_drives = [d for d in old_target._connected_drives if d is not self] self._target = device device.connect(self)
@property def device_label(self) -> str | None: """Label of the connected device, or ``None`` if unconnected.""" return self._target.label if self._target is not None else None @property def target_label(self) -> str | None: """Label of this drive's target, or ``None`` if unconnected. Device-target drives (``target_kind == "device"``) alias :attr:`device_label`; :class:`ParametricDrive` overrides this to resolve its coupling target instead. """ return self.device_label
[docs] def collapse_operators(self, device: BaseDevice) -> list[Operator]: """Lindblad collapse operators contributed by this drive. Default: none. Override to model drive-induced dissipation (e.g. photon loss on a drive line). """ _ = device return []
[docs] def local_channels(self, device: BaseDevice) -> list[DriveChannel]: """Return the Hamiltonian channels this drive exposes on *device*. A simple single-channel drive declares :attr:`_coupling_protocol`, :attr:`_coupling_accessor`, :attr:`_fallback`, and :attr:`_modulation`; this method then dispatches generically — the device's physical coupling operator when it conforms to the Protocol, the structural fallback otherwise. Returned operators are in the device's local basis (no chip-wide embedding). Drives with a non-standard decomposition override this method instead. """ if self._coupling_accessor is None or self._modulation is None: raise NotImplementedError(f"{type(self).__name__} must implement local_channels()") if self._coupling_protocol is not None and isinstance(device, self._coupling_protocol): op = getattr(device, self._coupling_accessor)() else: op = self._fallback(device) return [DriveChannel(operator=op, modulation=self._modulation)]
[docs] def physics_notes(self) -> list[str]: """Return human-readable declarations of this drive's approximations. Returns the shared target/RWA lines plus this drive's :attr:`_coupling_note` when declared. Subclasses with extra notes ``super().physics_notes()`` and append their own. Aggregated by :meth:`Chip.physics_notes`. """ rwa_note = "inherits chip default" if self.rwa is None else str(self.rwa) target = self.device_label if self.device_label is not None else "<unconnected>" notes = [ f"Target device: '{target}'", f"RWA policy: {rwa_note}", ] if self._coupling_note is not None: notes.append(self._coupling_note) return notes
[docs] def signal_spec(self, drive_op: Any, device: BaseDevice) -> DriveSignalSpec: """Build the frame-agnostic signal spec for one scheduled pulse. Parameters ---------- drive_op : DriveOp Scheduled pulse with envelope, start time, phase offset, and (for microwave drives) carrier frequency. Typed as :class:`~typing.Any` because :class:`~quchip.engine.ir.DriveOp` lives in the engine IR, which drives must not import. device : BaseDevice Target device. Unused in the default implementation, kept as an extension hook so subclasses can emit device-aware specs (e.g. flux-tunable drives that query the device's tuning curve). Returns ------- DriveSignalSpec Frame-agnostic description of the pulse — envelope, start time, duration, phase offset, and carrier frequency (or ``None`` for baseband drives) — built directly from *drive_op*, with no frame or IR commitment. Notes ----- The default implementation produces a :class:`~quchip.control.signal_spec.DriveSignalSpec` describing a phase-rotated, time-shifted, finite-duration envelope. Stage 2 of the engine turns the spec into the raw :class:`~quchip.engine.ir.SignalProgram` ``Scale(Shift(Window(env, 0, duration), start), exp(i·phi))`` before applying the modulation dispatch. """ _ = device return DriveSignalSpec( envelope=drive_op.envelope, start_time=drive_op.start_time, duration=drive_op.envelope.duration, phase_offset=drive_op.phase_offset, drive_freq=drive_op.freq, )
[docs] def copy(self, *, target: BaseDevice | None = None) -> "BaseDrive": """Return a shallow copy, optionally rebound to a new target.""" cloned = copy.copy(self) cloned._target = None if target is not None: cloned.connect(target) return cloned
[docs] def to_dict(self) -> dict[str, Any]: """Serialize into a JSON-safe dictionary.""" data = super().to_dict() data["target_label"] = self.target_label data["label"] = self.label data["rwa"] = self.rwa return data
@classmethod def _from_dict_payload( cls, d: dict[str, Any], target: BaseDevice | None = None, ) -> "BaseDrive": """Reconstruct a concrete drive, rebinding it to *target*. Shared by every standard drive whose only persisted state is ``label`` / ``rwa``; the registry root's :meth:`from_dict` resolves the concrete class from the serialized ``type`` and forwards here. Subclasses with extra serialized state override :meth:`from_dict`. """ return cls( target=target, label=d.get("label"), rwa=d.get("rwa"), ) def __repr__(self) -> str: attrs = [] if self._target is not None: attrs.append(f"target={self._target.label!r}") if self.rwa is not None: attrs.append(f"rwa={self.rwa}") return f"{type(self).__name__}({', '.join(attrs)})"
def _charge_fallback(device: BaseDevice) -> Operator: """Structural charge coupling ``i(a − a†)`` when the device is not ChargeCoupled.""" a = device.lowering_operator() a_dag = device.raising_operator() return 1j * (a - a_dag) def _phase_fallback(device: BaseDevice) -> Operator: """Structural phase coupling ``a + a†`` when the device is not PhaseCoupled.""" a = device.lowering_operator() a_dag = device.raising_operator() return a + a_dag def _flux_fallback(device: BaseDevice) -> Operator: """Structural flux coupling ``n̂`` when the device is not FluxCoupled.""" return device.number_operator()
[docs] class ChargeDrive(BaseDrive): r"""Microwave charge drive on a transmon-like device. Contributes the standard charge-coupling Hamiltonian .. math:: H_d(t) = \epsilon(t)\, i(\hat a - \hat a^\dagger) with :math:`\epsilon(t)` the (real-projected) mixed signal built by the :attr:`~quchip.control.signal_spec.DriveModulation.SINGLE_TONE` dispatch in stage 2. This is the canonical transmon microwave drive (Koch et al., PRA 76, 042319 (2007); Krantz et al., APR 6, 021318 (2019), Eq. 90). Examples -------- >>> from quchip import DuffingTransmon, ChargeDrive, Gaussian >>> q = DuffingTransmon(freq=5.0, anharmonicity=-0.25, levels=3) >>> drive = ChargeDrive(target=q) >>> channels = drive.local_channels(q) >>> len(channels) == 1 True """ _type_prefix: str = "charge" _accepts_virtual_z: bool = True _defaults_to_device_drive_freq: bool = True _coupling_protocol = ChargeCoupled _coupling_accessor = "charge_coupling_operator" _fallback = staticmethod(_charge_fallback) _modulation = DriveModulation.SINGLE_TONE _coupling_note = "Drive coupling: charge operator n̂ (or i(a − a†) fallback); single-tone modulation"
[docs] class PhaseDrive(BaseDrive): r"""Microwave phase drive coupling to :math:`\hat a + \hat a^\dagger`. Same carrier machinery as :class:`ChargeDrive` but with an in-phase (rather than quadrature) coupling. Useful when modeling phase-noise channels or drives whose physical coupling is already referenced to the field quadrature. See Krantz et al. 2019, Sec. IV.A for the two conventions. """ _type_prefix: str = "phase" _accepts_virtual_z: bool = True _carrier_required: bool = True _coupling_protocol = PhaseCoupled _coupling_accessor = "phase_coupling_operator" _fallback = staticmethod(_phase_fallback) _modulation = DriveModulation.SINGLE_TONE _coupling_note = "Drive coupling: phase operator φ̂ (or a + a† fallback); single-tone modulation"
[docs] class FluxDrive(BaseDrive): r"""Real-valued flux drive coupling to :math:`\hat n`. Uses :attr:`~quchip.control.signal_spec.DriveModulation.DIRECT_REAL` — no carrier, no RWA — as appropriate for a baseband flux line that modulates the device frequency through its number operator (Koch et al. 2007, Sec. II; Krantz et al. 2019, Sec. V.A on flux tunability). The ``rwa`` kwarg is rejected: applying RWA to a baseband drive is ill-defined. Examples -------- >>> from quchip import DuffingTransmon, FluxDrive >>> q = DuffingTransmon(freq=5.0, anharmonicity=-0.25, levels=3) >>> flux = FluxDrive(target=q) >>> flux.rwa is None True """ _type_prefix: str = "flux" def __init__( self, target: BaseDevice | None = None, *, label: str | None = None, rwa: bool | None = None, ) -> None: if rwa is not None: raise ValueError("FluxDrive does not support an explicit rwa override.") super().__init__(target=target, label=label, rwa=None) _coupling_protocol = FluxCoupled _coupling_accessor = "flux_coupling_operator" _fallback = staticmethod(_flux_fallback) _modulation = DriveModulation.DIRECT_REAL _coupling_note = ( "Drive coupling: flux/φ̂ operator (or n̂ fallback); " "baseband direct-real modulation (no carrier, no RWA)" )
[docs] class ParametricDrive(BaseDrive): """Control line pumping a modulable coupling's strength δ(t) in GHz. Targets a coupling (object or label string; labels late-bind via :meth:`Chip.connect`). The scheduled envelope is the *real amplitude* ``A(t)``: with an explicit ``freq`` the pump is ``δ(t) = A(t)·cos(2π·freq·t - phase)``; with ``freq`` omitted the pump is baseband, ``δ(t) = A(t)`` directly. The pump tone is never RWA-split — the coupling's RWA policy selects the *operator structure* via its parametric hook; the tone keeps both sidebands (declared, the solver integrates the fast one). Accepted couplings implement :meth:`~quchip.declarative.models.CouplingModel.parametric_interaction`; a static coupling raises ``TypeError`` naming the hook. Parameters ---------- coupling : BaseCoupling | str Modulable coupling to pump, given as the coupling object or its label. A string label late-binds to the coupling instance via :meth:`Chip.connect`. label : str | None Optional explicit label; otherwise auto-generated from ``"parametric"``. Raises ------ TypeError *coupling* does not implement :meth:`~quchip.declarative.models.CouplingModel.parametric_interaction` (a static coupling), or an unexpected keyword argument is passed. ValueError An explicit ``rwa`` keyword argument is passed — the RWA policy is fixed by the coupling's parametric hook, not per-drive. """ target_kind = "edge" _type_prefix: str = "parametric" _accepts_virtual_z: bool = False _modulation = DriveModulation.EDGE_PUMP _coupling_note: str | None = ( "Edge pump: δ(t) in GHz multiplies the coupling's parametric structure; tone kept full (no RWA split)" ) def __init__(self, coupling: "Any | str", *, label: str | None = None, **kwargs: Any) -> None: if "rwa" in kwargs: raise ValueError( "ParametricDrive does not take an RWA flag: the coupling's RWA policy " "selects the pump's operator structure." ) if kwargs: raise TypeError(f"Unexpected arguments: {sorted(kwargs)}") self.label = label if label is not None else auto_label(type(self)._type_prefix) self.rwa = None self._target: Any = coupling if not isinstance(coupling, str): _probe_modulable(coupling) @property def device_label(self) -> None: """Always ``None``: an edge pump has no device target. Device-keyed paths (drive-noise collection, device-line bookkeeping) treat ``None`` as "skip this line"; edge code reads :attr:`target_label` instead. """ return None @property def target_label(self) -> str: """Label of the pumped coupling (resolves objects and label strings).""" target = self._target return target if isinstance(target, str) else target.label def __repr__(self) -> str: """Return a compact pump-line summary naming the coupling.""" return f"{type(self).__name__}(label='{self.label}', coupling='{self.target_label}')"
[docs] def connect(self, coupling: Any) -> None: """Rebind to *coupling* (no device-side handshake — couplings hold no drive list).""" _probe_modulable(coupling) self._target = coupling
[docs] def local_channels(self, device: Any) -> list[DriveChannel]: """Edge pumps have no device channel; stage 2 compiles them from the coupling's hook.""" raise NotImplementedError( "ParametricDrive exposes no device channel: the pumped operator comes from the " "coupling's parametric_interaction() at assembly time." )
@classmethod def _from_dict_payload(cls, d: dict[str, Any], target: Any = None) -> "ParametricDrive": """Reconstruct a pump line, rebinding it to *target* (a resolved coupling). Overrides :meth:`BaseDrive._from_dict_payload`: the base version calls ``cls(target=..., rwa=...)``, but :meth:`__init__` takes the coupling positionally and rejects an ``rwa`` kwarg outright. """ return cls(target, label=d.get("label"))
def _probe_modulable(coupling: Any) -> None: """Raise the teaching TypeError when *coupling* declines the parametric hook.""" from quchip.declarative.ops import EndpointOps probe = getattr(coupling, "parametric_interaction", None) expr = None if probe is not None: expr = probe( EndpointOps(label=coupling.device_a_label, levels=2), EndpointOps(label=coupling.device_b_label, levels=2), ) if expr is None: raise TypeError( f"{type(coupling).__name__} is not modulable: its parametric_interaction() hook " "returns None. Implement parametric_interaction()/rwa_parametric_interaction() on " "the coupling (see CouplingModel), or use a modulable coupling such as TunableCapacitive." )