"""Classical control lines and their quantum Hamiltonian couplings.
A drive builds the complete scheduled analytic signal, then maps its physical
I/Q quadratures to target-local quantum operators. Control equipment may alter
that signal before the Hamiltonian mapping. Projection, frames, approximation,
embedding, unit conversion, and backend lowering remain engine responsibilities.
Conventions:
- Frequencies are GHz; times are ns.
- Operators are returned in the device's authored local 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
import inspect
from typing import Any, ClassVar
from quchip.control.signal import AnalyticSignal
from quchip.declarative.dissipation import CollapseChannel, normalize_dissipation
from quchip.declarative.expr import ParameterNamespace, as_operator_expr
from quchip.declarative.ops import LocalOps
from quchip.declarative.parameters import (
DriveDeclarativeMeta,
Parameter,
constructor_field,
parameter_fields,
resolve_declared_params,
resolve_declared_settings,
serializable_value,
setting_fields,
validate_declared_fields,
validate_sign,
)
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
def _device_operator_expr(device: Any, value: Any, *, name: str) -> Any:
"""Normalize a device capability into its authored local expression."""
dimension = (
device.local_space().dimension
if hasattr(device, "local_space")
else int(device.levels)
)
return as_operator_expr(
value,
labels=(device.label,),
dims=(dimension,),
name=name,
)
def _synthesize_drive_init(cls: type["BaseDrive"]) -> Any:
"""Build a constructor from a target and declared drive fields."""
trailing = tuple(
inspect.Parameter(
name,
inspect.Parameter.KEYWORD_ONLY,
default=inspect.Parameter.empty if spec.required else spec.default,
)
for name, spec in parameter_fields(cls).items()
) + tuple(
inspect.Parameter(name, inspect.Parameter.KEYWORD_ONLY, default=spec.default)
for name, spec in setting_fields(cls).items()
) + (
inspect.Parameter("label", inspect.Parameter.KEYWORD_ONLY, default=None),
)
signature = inspect.Signature(
(
inspect.Parameter("self", inspect.Parameter.POSITIONAL_OR_KEYWORD),
inspect.Parameter("target", inspect.Parameter.POSITIONAL_OR_KEYWORD, default=None),
*trailing,
)
)
def __init__(self: BaseDrive, *args: Any, **kwargs: Any) -> None:
bound = signature.bind(self, *args, **kwargs)
bound.apply_defaults()
arguments = dict(bound.arguments)
arguments.pop("self")
target = arguments.pop("target")
label = arguments.pop("label")
BaseDrive.__init__(self, target=target, label=label, **arguments)
__init__.__signature__ = signature # type: ignore[attr-defined]
__init__.__qualname__ = f"{cls.__qualname__}.__init__"
__init__.__doc__ = f"Initialize {cls.__name__} from its target and declared fields."
return __init__
[docs]
class BaseDrive(Registrable, registry_root=True, metaclass=DriveDeclarativeMeta):
"""Base class for classical control lines attached to one quantum target.
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, BaseCoupling, str, or None
Target accepted by the concrete drive. A :class:`DeviceDrive` targets
a device; a :class:`CouplingDrive` targets a coupling. The target may
be connected later or resolved by label through :class:`Chip`.
label : str | None
Optional explicit label; otherwise auto-generated.
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: ClassVar[str] = "drive"
target: Any = constructor_field(default=None, kw_only=False)
label: Any = constructor_field(default=None, kw_only=True)
__quchip_param_fields__: ClassVar[dict[str, Parameter]] = {}
def __init_subclass__(cls, **kwargs: Any) -> None:
super().__init_subclass__(**kwargs)
validate_declared_fields(cls)
cls.__quchip_param_fields__ = parameter_fields(cls)
if "__init__" not in cls.__dict__:
cls.__init__ = _synthesize_drive_init(cls) # type: ignore[method-assign]
def __init__(
self,
target: Any | str | None = None,
*,
label: str | None = None,
**params: Any,
) -> None:
params = dict(params)
settings = resolve_declared_settings(type(self), params)
values = resolve_declared_params(
type(self), params, fields=type(self).__quchip_param_fields__
)
self.label = label if label is not None else auto_label(type(self)._type_prefix)
self._target: Any | str | None = None
for name, value in settings.items():
setattr(self, name, value)
for name, value in values.items():
setattr(self, name, value)
if target is not None:
if isinstance(target, str):
self._target = target
else:
self.connect(target)
[docs]
def connect(self, target: Any) -> None:
"""Attach this device-drive implementation to *target*.
If previously attached, the drive is removed from the old device's
``_connected_drives`` list. :class:`CouplingDrive` overrides this
handshake because couplings do not own connected-drive lists.
"""
old_target = self._target
if old_target is not None and not isinstance(old_target, str) and old_target is not target:
old_target._connected_drives = [d for d in old_target._connected_drives if d is not self]
self._target = target
target.connect(self)
[docs]
def parameter_values(self) -> dict[str, Any]:
"""Return drive-owned bindable values declared by the subclass."""
return {name: getattr(self, name) for name in type(self).__quchip_param_fields__}
[docs]
def set_parameter_value(self, name: str, value: Any) -> None:
"""Apply one drive-owned value on an isolated drive copy."""
spec = type(self).__quchip_param_fields__.get(name)
if spec is None:
raise KeyError(name)
validate_sign(name, spec, value)
setattr(self, name, value)
@property
def device_label(self) -> str | None:
"""Label of the connected device, or ``None`` if unconnected."""
target = self._target
if target is None:
return None
return target if isinstance(target, str) else target.label
@property
def target_label(self) -> str | None:
"""Label of this drive's target, or ``None`` if unconnected.
Device-target drives alias :attr:`device_label`;
:class:`ParametricDrive` resolves its coupling target instead.
"""
return self.device_label
[docs]
def dissipation(
self,
target: BaseDevice,
op: LocalOps,
p: ParameterNamespace,
) -> tuple[CollapseChannel, ...]:
"""Return target-local Lindblad channels contributed by this line."""
_ = (target, op, p)
return ()
def _collapse_channels_with_paths(
self,
target: BaseDevice,
) -> tuple[tuple[CollapseChannel, tuple[str, ...]], ...]:
"""Normalize authored line dissipation and infer dependencies."""
fields = type(self).__quchip_param_fields__
op = LocalOps(target.label, target.local_space(), device=target)
p = ParameterNamespace(f"drive.{self.label}", fields)
bindings = {
f"drive.{self.label}.{name}": getattr(self, name)
for name in fields
}
return normalize_dissipation(
self.dissipation(target, op, p),
labels=(target.label,),
dims=(target.local_space().dimension,),
owner=self,
scope=f"drive.{self.label}",
allowed=fields,
bindings=bindings,
)
[docs]
def signal(self, pulse: Any, target: Any) -> AnalyticSignal:
"""Build the complete scheduled analytic signal for one pulse."""
_ = target
return AnalyticSignal.from_pulse(pulse)
[docs]
def hamiltonian(self, target: Any, signal: AnalyticSignal) -> Any:
"""Map a delivered classical signal to target-local quantum physics."""
raise NotImplementedError(
f"{type(self).__name__} must implement hamiltonian(target, signal)"
)
[docs]
def physics_notes(self) -> list[str]:
"""Return human-readable declarations of this drive's approximations.
Subclasses append their physical coupling details to the shared target
line. Aggregated by :meth:`Chip.physics_notes`.
"""
target = self.target_label if self.target_label is not None else "<unconnected>"
return [f"Target: '{target}'"]
[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()
for name, spec in type(self).__quchip_param_fields__.items():
if spec.serialize:
data[name] = serializable_value(getattr(self, name))
for name, setting_spec in setting_fields(type(self)).items():
if setting_spec.serialize:
data[name] = getattr(self, name)
data["target_label"] = self.target_label
data["label"] = self.label
return data
@classmethod
def _from_dict_payload(
cls,
d: dict[str, Any],
target: Any | str | None = None,
) -> "BaseDrive":
"""Reconstruct a concrete drive, rebinding it to *target*.
Shared by every standard drive whose only persisted state is its
label and declared fields; 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`.
"""
allowed = {"type", "target_label", "label"}
allowed.update(
name
for name, spec in cls.__quchip_param_fields__.items()
if spec.serialize
)
allowed.update(
name
for name, spec in setting_fields(cls).items()
if spec.serialize
)
unexpected = set(d) - allowed
if unexpected:
raise TypeError(
f"Unsupported serialized fields for {cls.__name__}: "
+ ", ".join(sorted(unexpected))
)
params = {
name: d[name]
for name, spec in cls.__quchip_param_fields__.items()
if spec.serialize and name in d
}
settings = {
name: d[name]
for name, spec in setting_fields(cls).items()
if spec.serialize and name in d
}
return cls(target=target, label=d.get("label"), **params, **settings)
def __repr__(self) -> str:
attrs = []
if self.target_label is not None:
attrs.append(f"target={self.target_label!r}")
return f"{type(self).__name__}({', '.join(attrs)})"
[docs]
class DeviceDrive(BaseDrive):
"""Drive authoring base for a device-local Hamiltonian."""
[docs]
class CouplingDrive(BaseDrive):
"""Drive authoring base for a two-endpoint coupling Hamiltonian.
Subclasses implement :meth:`hamiltonian` for the coupling physics they
accept. The base class imposes no parametric-interaction requirement.
"""
@property
def device_label(self) -> None:
"""Return ``None`` because a coupling drive has no device target."""
return None
@property
def target_label(self) -> str | None:
"""Label of the connected coupling, if any."""
target = self._target
if target is None:
return None
return target if isinstance(target, str) else target.label
[docs]
def connect(self, target: Any) -> None:
"""Attach this line to a coupling without a device-side handshake."""
self._target = target
[docs]
class ChargeDrive(DeviceDrive):
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 in-phase quadrature of the complete
delivered classical signal. 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
>>> q = DuffingTransmon(freq=5.0, anharmonicity=-0.25, levels=3)
>>> drive = ChargeDrive(target=q)
>>> drive.target_label == q.label
True
"""
_type_prefix: ClassVar[str] = "charge"
[docs]
def hamiltonian(self, device: Any, signal: AnalyticSignal) -> Any:
if not isinstance(device, ChargeCoupled):
raise TypeError(
f"ChargeDrive requires {type(device).__name__} to define "
"charge_coupling_operator()."
)
return signal.i * _device_operator_expr(
device,
device.charge_coupling_operator(),
name=rf"\hat H_{{charge,{getattr(device, 'label')}}}",
)
[docs]
def physics_notes(self) -> list[str]:
return super().physics_notes() + [
"Drive coupling: delivered in-phase signal times the device charge operator"
]
[docs]
class PhaseDrive(DeviceDrive):
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 modelling
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: ClassVar[str] = "phase"
[docs]
def hamiltonian(self, device: Any, signal: AnalyticSignal) -> Any:
if not isinstance(device, PhaseCoupled):
raise TypeError(
f"PhaseDrive requires {type(device).__name__} to define "
"phase_coupling_operator()."
)
return signal.i * _device_operator_expr(
device,
device.phase_coupling_operator(),
name=rf"\hat H_{{phase,{getattr(device, 'label')}}}",
)
[docs]
def physics_notes(self) -> list[str]:
return super().physics_notes() + [
"Drive coupling: delivered in-phase signal times the device phase operator"
]
[docs]
class FluxDrive(DeviceDrive):
r"""Real-valued flux drive coupling to :math:`\hat n`.
The delivered signal's in-phase quadrature modulates the device frequency
through its flux-coupling operator
(Koch et al. 2007, Sec. II; Krantz et al. 2019, Sec. V.A on flux
tunability).
Examples
--------
>>> from quchip import DuffingTransmon, FluxDrive
>>> q = DuffingTransmon(freq=5.0, anharmonicity=-0.25, levels=3)
>>> flux = FluxDrive(target=q)
>>> flux.target_label == q.label
True
"""
_type_prefix: ClassVar[str] = "flux"
[docs]
def hamiltonian(self, device: Any, signal: AnalyticSignal) -> Any:
if not isinstance(device, FluxCoupled):
raise TypeError(
f"FluxDrive requires {type(device).__name__} to define "
"flux_coupling_operator()."
)
return signal.i * _device_operator_expr(
device,
device.flux_coupling_operator(),
name=rf"\hat H_{{flux,{getattr(device, 'label')}}}",
)
[docs]
def physics_notes(self) -> list[str]:
return super().physics_notes() + [
"Drive coupling: delivered in-phase signal times the device flux operator"
]
[docs]
class ParametricDrive(CouplingDrive):
"""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 carrier the pump is
``δ(t) = A(t)·cos(2π·freq·t - phase)``; with ``freq`` omitted the pump is
carrier-free, ``δ(t) = A(t)`` directly. Approximation belongs to the
chip's selected engine strategy, not to the drive.
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.
"""
_type_prefix: ClassVar[str] = "parametric"
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:
"""Attach this line after confirming that the coupling is modulable."""
_probe_modulable(coupling)
self._target = coupling
[docs]
def hamiltonian(self, coupling: Any, signal: AnalyticSignal) -> Any:
operator = coupling._bind_parametric_interaction()
if operator is None:
raise TypeError(
f"{type(coupling).__name__} is not modulable: its "
"parametric_interaction() hook returns None."
)
return signal.i * operator
[docs]
def physics_notes(self) -> list[str]:
return super().physics_notes() + [
"Edge pump: delivered in-phase signal multiplies the coupling's parametric structure"
]
def _probe_modulable(coupling: Any) -> None:
"""Raise the teaching TypeError when *coupling* declines the parametric hook."""
from quchip.declarative.models import _symbolic_parameters
from quchip.declarative.ops import EndpointOps
probe = getattr(coupling, "parametric_interaction", None)
expr = None
if probe is not None:
if getattr(coupling, "is_resolved", False):
expr = coupling._bind_parametric_interaction()
else:
from quchip.devices.spaces import FockSpace
expr = probe(
EndpointOps(label=coupling.device_a_label, space=FockSpace(2)),
EndpointOps(label=coupling.device_b_label, space=FockSpace(2)),
_symbolic_parameters(coupling),
)
if expr is None:
raise TypeError(
f"{type(coupling).__name__} is not modulable: its parametric_interaction() hook "
"returns None. Implement parametric_interaction() on "
"the coupling (see CouplingModel), or use a modulable coupling such as TunableCapacitive."
)