"""Elimination target registry and the public ``eliminate`` dispatcher.
A transformation consumes a chip and produces a new one, so transformations
compose through ``Chip`` (for example
``eliminate(fit_a_dress(chip).chip, "r").chip``). :class:`ChipTransform` is a
thin *structural* protocol that captures only the ``.chip`` output that every
transformation result exposes.
:class:`~quchip.inverse_design.types.FitADressResult` already satisfies it.
``eliminate`` removes a mode or edge, or diagonalizes effective terms, and
keeps its calculated correction in ``EffectiveTerms``. Surviving authored
parameters stay unchanged. The result reports the approximation, diagnostics
and captured coordinate map.
Each target *kind* is an :class:`EliminationTarget`: a pair of
``(claims, reduce)`` closures. The dispatcher scans the registry and gives the
target to the first kind that claims it, or raises a clear error if none does.
A new reducible target kind registers here and does not change the handler
modules or :mod:`quchip.chip.sw`.
"""
# The unifying abstraction is the `Chip` type itself, not a base class.
#
# Elimination target kinds are registered in `_ELIMINATION_TARGETS`.
#
# The reductions are in the sibling handler modules
# (`quchip.chip.transformations.eliminate_device`,
# `quchip.chip.transformations.eliminate_coupling`,
# `quchip.chip.transformations.eliminate_effective`), which register at import
# time. The generic P/Q partitioning physics is in `quchip.chip.sw`. This module
# owns only the registry and the dispatch.
from __future__ import annotations
from dataclasses import dataclass
from typing import TYPE_CHECKING, Any, Callable
from quchip.chip.transformations.methods import reduction_method_names
from quchip.chip.transformations.result import EliminationResult
from quchip.utils.labeling import resolve_label
if TYPE_CHECKING:
from quchip.chip.chip import Chip
[docs]
@dataclass(frozen=True)
class EliminationTarget:
"""One registered elimination target kind: how it recognizes a target and reduces it.
A new kind registers an instance with :func:`register_elimination_target`
at the bottom of its handler module. That module must be imported for the
side effect, which the package ``__init__`` does for the shipped handlers.
This is the same registration ritual as
:func:`~quchip.chip.retarget.register_retarget_rule`.
Attributes
----------
kind
A short label for the target kind (``"device"``, ``"coupling"``,
``"effective terms"``), for diagnostics.
claims
``claims(chip, target) -> bool``: whether this kind owns ``target`` on
``chip`` (for example, the label names a device, a coupling or
effective terms). Chip rejects colliding device, coupling and
effective-term labels, so at most one shipped kind claims a target.
reduce
``reduce(chip, target, method) -> EliminationResult``: does the
reduction. ``method`` is the already validated route string. A handler
that has no concept of a route ignores it.
reduce_local
The same reduction read from a patch around the target, for
``eliminate(..., local=True)``. ``None`` means the kind has no local
reduction.
"""
kind: str
claims: Callable[[Any, Any], bool]
reduce: Callable[[Any, Any, str], EliminationResult]
reduce_local: Callable[[Any, Any, str], EliminationResult] | None = None
_ELIMINATION_TARGETS: list[EliminationTarget] = []
[docs]
def register_elimination_target(target: EliminationTarget) -> None:
"""Register an elimination target kind.
Parameters
----------
target : EliminationTarget
Target handler added to the dispatch registry.
"""
_ELIMINATION_TARGETS.append(target)
[docs]
def eliminate(chip: "Chip", target: Any, *, method: str = "sw", local: bool = False) -> EliminationResult:
"""Reduce a far-detuned device, an edge coupling or effective terms, and return a reduced chip.
``target`` is resolved against the chip's device, coupling and
effective-term labels. These labels are disjoint by construction, because
:class:`~quchip.chip.chip.Chip` rejects colliding labels. ``target``
dispatches to one of three model reductions:
- **Device target**: remove a far-detuned mode and keep its calculated
Hamiltonian correction, transformed channels and interpretation map.
Surviving devices and direct couplings keep their authored values. A mode
that connects several survivors contributes a separate mediated exchange edge
per pair. Each edge reports ``∂J/∂ω_c`` for control retargeting. Capacitive
legs emit :class:`~quchip.chip.couplings.Capacitive` or
:class:`~quchip.chip.couplings.TunableCapacitive` when controls require it.
Other legs emit a first-transition exchange edge. Direct and mediated
contributions can cancel in the complete Hamiltonian. Successive reductions
compose through ``eliminate(eliminate(chip, "TC1").chip, "TC2")``.
- **Coupling target**: keep both endpoints and remove the selected edge. A
coordinate change from that isolated pair acts on the entire Hamiltonian,
including parallel and spectator interactions. The exact route keeps a
full unitary transformation. SW keeps terms through second order. The
correction keeps per-level shifts and does not fold them into endpoint
frequencies or a uniform cross-Kerr coefficient.
- **Effective-terms target**: keep every device and edge. Diagonalize the
selected :class:`~quchip.chip.effective.EffectiveTerms` exactly with the
local Hamiltonians of the devices they act on, for example the junction
cosine of an energy-participation chip. The rotation acts on the entire
Hamiltonian, and the correction keeps each level's shift, so dressed
queries on the reduced chip return the source spectrum. Only
``method="exact"`` is implemented.
Parameters
----------
chip
Source chip (never mutated).
target
The device, coupling or effective terms to eliminate, as a label string
or object.
method
``"sw"`` (default) keeps second-order Schrieffer-Wolff terms with the
chip's approximation. ``"exact"`` uses the unapproximated static
Hamiltonian. For device targets, it diagonalizes the full chip and
selects a kept subspace, and it rejects ambiguous computational labels.
For edge targets, it diagonalizes the selected isolated pair and
transforms the full chip through that unitary. Surviving noise operators
follow the captured map, and components keep rate ownership. Control
operators are not transformed yet.
local
For a device target with ``method="sw"``, compute its generator on a
patch. The patch holds the device and every device that shares a
coupling, an effective Hamiltonian or a port with it. It also holds the
far device of each coupling whose diagonal part depends on such a
neighbour's level, as for a ``CrossKerr`` edge. It holds each such effective
Hamiltonian. It also holds every device that the device's
port operators act on. The reduction never assembles the full product space, and
devices and couplings outside the patch stay unchanged. Each part of
the correction and each transformed channel keeps its own support, so
later patches stay local. The result matches full-chip reduction up to
recorded numerical omissions. Devices linked only through a feedline
do not enlarge the patch: the full network regenerates its terms from
transformed ports. The removed mode's reference section reads its
intermediate states from all local Hamiltonian terms, including
spectator dressing.
``chi`` describes only the patch. Chips with baths
raise ``NotImplementedError``. In a chain of local steps, an
operator on a kept device spreads over each patch that it meets, so
the order of the steps sets its size. If every coupler of a ring
goes first, a drive on one transmon spreads over all of them.
:func:`~quchip.chip.transformations.eliminate_spectators` chooses an
order (PHYSICS.md §10.8). Each local step reports its widest operator
support in ``notes`` and warns when one dense copy of that operator
needs 256 MiB or more.
Returns
-------
EliminationResult
Examples
--------
>>> from quchip import DuffingTransmon, Resonator, Capacitive, Chip
>>> from quchip.chip.transformations import eliminate
>>> q = DuffingTransmon(freq=5.0, anharmonicity=-0.25, levels=3, label="q")
>>> r = Resonator(freq=7.0, levels=5, label="r")
>>> chip = Chip([q, r], couplings=[Capacitive(q, r, g=0.05)])
>>> result = eliminate(chip, r) # r removed; its correction is retained
>>> reduced = result.chip
>>> [d.label for d in reduced.devices]
['q']
"""
from quchip.engine.routes import require_workflow
require_workflow(chip, "eliminate()")
if method not in reduction_method_names():
expected = " or ".join(repr(n) for n in sorted(reduction_method_names()))
raise ValueError(f"Unknown method {method!r} for eliminate(); expected {expected}.")
for spec in _ELIMINATION_TARGETS:
if spec.claims(chip, target):
if not local:
return spec.reduce(chip, target, method)
if spec.reduce_local is None:
raise NotImplementedError(f"local=True does not support {spec.kind} targets.")
return spec.reduce_local(chip, target, method)
raise KeyError(
f"'{resolve_label(target)}' names no device, coupling or effective terms on chip '{chip.label}'."
)