"""Human-readable text summaries — the ``describe()`` surface.
This *view* layer renders what the user built (devices, couplings, control
wiring, scheduled pulses) as a sectioned plain-text report, and what a
transform derived, e.g. an ``eliminate()`` fold report. It never calculates
physics beyond ordinary arithmetic on already-derived quantities, and never
concretizes a traced value except for display. Tracers render as ``<traced>``
even on this debugging surface.
Units come from the declarative :func:`~quchip.declarative.parameters.parameter`
metadata (``unit=``), so extension authors who declare units get correct
``describe()`` output for free.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from quchip.declarative.parameters import parameter_fields
from quchip.utils.jax_utils import contains_tracer, maybe_concrete_scalar
if TYPE_CHECKING:
from quchip.chip.chip import Chip
from quchip.chip.transformations import EliminationResult
from quchip.control.sequence import QuantumSequence
from quchip.engine.frames import FramePlan
def _param_text(name: str, value: Any, unit: str | None) -> str:
text = f"{name} = {format_value(value)}"
if unit is not None and value is not None:
text += f" {unit}"
return text
def _declared_param_line(obj: Any) -> str:
"""One indented line joining an object's declared parameters with units."""
fields = parameter_fields(type(obj))
parts = [
_param_text(name, getattr(obj, name), spec.unit)
for name, spec in fields.items()
]
return " ".join(parts)
def _section(title: str, rule: str = "─") -> list[str]:
return [title, rule * len(title)]
def _sector_line(chip: "Chip") -> str:
"""Summarize the excitation-number verdict and the largest dressed block for labels with N <= 2."""
import numpy as np
from quchip.engine.excitation import format_changes
if chip.backend.array_module is np and contains_tracer(dict(chip.parameters)):
return "not available while JAX traces a QuTiP chip"
structure = chip.excitation_structure()
block = structure.largest_block(2)
if structure.cutoff is not None:
classes = ", ".join(str(group) for group in structure.classes(structure.cutoff))
return f"cutoff classes {classes}; dressed queries with N <= 2 diagonalize at most {block} states"
if structure.conserves:
return f"N conserved; dressed queries with N <= 2 diagonalize at most {block} states"
breaking = ", ".join(f"{term.label} ({format_changes(term.changes)})" for term in structure.breaking)
verdict = "N not proven conserved" if any(term.changes is None for term in structure.breaking) else (
"N not conserved")
return f"{verdict} by {breaking}; dressed queries diagonalize all {block} states"
[docs]
def describe_chip(chip: "Chip") -> str:
"""Sectioned plain-text report of a chip's composition. See :meth:`Chip.describe`."""
lines: list[str] = []
title = "Chip" if chip.label is None else f"Chip {chip.label!r}"
lines += _section(title, "═")
frame = chip.frame if isinstance(chip.frame, str) else format_value(chip.frame)
lines.append(f"Frame : {frame}")
if frame == "auto":
from quchip.engine.frames import plan_frame
plan = plan_frame(chip, (), approximation=chip.approximation, strict=False)
lines += [f" {line}" for line in _format_frame_plan(plan)]
lines.append(f"Approx. : {type(chip.approximation).__name__}")
if chip.space is not None:
from quchip.engine.excitation import sector_size
retained = sum(sector_size(chip.dims, total) for total in range(chip.space.max_total + 1))
kept = "every product label" if not chip.space.binds(chip.dims) else f"{retained} product labels"
lines.append(f"Space : N <= {chip.space.max_total} (ExcitationCutoff), {kept}")
lines.append(f"Dressed : {'cached' if chip.is_dressed else 'not computed'}")
dims = chip.dims
if dims:
lines.append(
f"Hilbert : {' x '.join(str(n) for n in dims)} = {chip.total_dim} levels"
)
lines.append(f"Sectors : {_sector_line(chip)}")
lines.append("")
lines += _section(f"Devices ({len(chip.devices)})")
for dev, dim in zip(chip.devices, dims):
lines.append(f"{dev.label} — {type(dev).__name__}")
params = _declared_param_line(dev)
detail = f"{params} levels = {dim}" if params else f"levels = {dim}"
lines.append(f" {detail}")
noise = [
_param_text(name, getattr(dev, name), unit)
for name, unit in (("T1", "ns"), ("T2", "ns"), ("thermal_occupation", None))
if getattr(dev, name) is not None
]
if noise:
lines.append(f" {' '.join(noise)}")
if chip.couplings:
lines.append("")
lines += _section(f"Couplings ({len(chip.couplings)})")
for coupling in chip.couplings:
pair = f"{coupling.device_a_label} ↔ {coupling.device_b_label}"
lines.append(f"{coupling.label} : {pair}")
detail = _declared_param_line(coupling)
if detail:
lines.append(f" {detail}")
if chip.effective_terms:
lines.append("")
lines += _section(f"Effective terms ({len(chip.effective_terms)})")
for terms in chip.effective_terms:
support = ", ".join(f"{label} ({dim})" for label, dim in zip(terms.labels, terms.dims))
lines.append(f"{terms.label} : {support}")
if terms.channels:
lines.append(f" channels: {', '.join(channel.name for channel in terms.channels)}")
equipment = chip.control_equipment
if equipment is not None and equipment.lines:
lines.append("")
lines += _section(f"Control ({len(equipment.lines)} line{'s' if len(equipment.lines) != 1 else ''})")
for drive in equipment.lines:
target = drive.device_label if drive.device_label is not None else "(unwired)"
lines.append(f"{drive.label} — {type(drive).__name__} → {target}")
chain = equipment.signal_chain
if chain:
counts: dict[str, int] = {}
for transform in chain:
name = type(transform).__name__
counts[name] = counts.get(name, 0) + 1
summary = ", ".join(
f"{name} ×{n}" if n > 1 else name for name, n in sorted(counts.items())
)
lines.append(f" signal chain: {summary}")
if chip.baths:
lines.append("")
lines += _section(f"Baths ({len(chip.baths)})")
for bath in chip.baths:
targets = ", ".join(bath.resolve_targets(chip))
detail = f"{bath.label} — model={bath.recipe} on {targets}"
extras = [
_param_text(name, getattr(bath, name), unit)
for name, unit in (("temperature", "mK"), ("rate", "1/ns"))
if getattr(bath, name) is not None
]
if extras:
detail += f" ({' '.join(extras)})"
lines.append(detail)
if chip.ports:
lines.append("")
lines += _section(f"Ports ({len(chip.ports)})")
for port in chip.ports:
targets = ", ".join(port.resolve_targets(chip))
if port.rate is not None:
port_coupling = _param_text("rate", port.rate, "1/ns")
else:
port_coupling = _param_text("external_quality_factor", port.external_quality_factor, None)
lines.append(
f"{port.label} — {targets} {port_coupling} phase = {format_value(port.phase)} rad"
)
return "\n".join(lines)
def _envelope_text(envelope: Any) -> str:
"""Compact envelope rendering: type name plus its declared parameters."""
fields = parameter_fields(type(envelope))
parts = []
for name, spec in fields.items():
text = f"{name}={format_value(getattr(envelope, name))}"
if spec.unit is not None:
text += f" {spec.unit}"
parts.append(text)
return f"{type(envelope).__name__}({', '.join(parts)})" if parts else type(envelope).__name__
[docs]
def describe_sequence(seq: "QuantumSequence") -> str:
"""Timeline table of a sequence's pulses. See :meth:`QuantumSequence.describe`."""
ops = seq.scheduled_ops
header = (
f"QuantumSequence — {len(ops)} pulse{'s' if len(ops) != 1 else ''}, "
f"total duration {format_value(seq.total_duration)} ns"
)
lines = [header, "─" * len(header)]
if ops:
rows = [("window (ns)", "drive", "envelope", "freq")]
for op in ops:
start = maybe_concrete_scalar(op.start_time)
duration = maybe_concrete_scalar(op.envelope.duration)
if start is not None and duration is not None:
window = f"[{start:.6g}, {start + duration:.6g}]"
else:
window = f"[{format_value(op.start_time)}, +{format_value(op.envelope.duration)}]"
drive = f"{op.drive_label} → {op.target_label}"
if op.frame is not None and op.frame != op.target_label:
drive += f" (frame {op.frame})"
freq = "baseband" if op.freq is None else f"{format_value(op.freq)} GHz"
if op.detuning is not None:
freq += f", detuning {format_value(op.detuning)} GHz"
rows.append((window, drive, _envelope_text(op.envelope), freq))
widths = [max(len(row[i]) for row in rows) for i in range(len(rows[0]))]
for row in rows:
lines.append(" ".join(cell.ljust(width) for cell, width in zip(row, widths)).rstrip())
if isinstance(seq._chip.frame, str) and seq._chip.frame == "auto":
lines += ["", *_section("Frame"), *_format_frame_plan(seq.resolve().resolved_frame.plan)]
other = [entry for entry in seq._entries if not hasattr(entry, "envelope")]
if other:
counts: dict[str, int] = {}
for entry in other:
name = type(entry).__name__.strip("_").removesuffix("Entry")
counts[name] = counts.get(name, 0) + 1
summary = ", ".join(f"{n} {name}" for name, n in sorted(counts.items()))
lines.append(f"(plus {summary})")
return "\n".join(lines)
def _format_frame_plan(plan: "FramePlan | None") -> list[str]:
"""Render device frequencies, accepted tones, pins, and residual oscillations."""
if plan is None:
return []
lines = [f"{label:<8} : {format_value(freq)} GHz" for label, freq in plan.frequencies.items()]
for tone in plan.tones:
devices = ", ".join(label for label, _ in tone.coefficients)
lines.append(f"tone : {tone.source} on {devices} at {format_value(tone.freq)} GHz")
if plan.pins:
pinned = ", ".join(f"{label} @ {format_value(freq)} GHz" for label, freq in plan.pins)
lines.append(f"pins : {pinned}")
for residual in plan.residuals:
weight = "" if residual.weight is None else f", weight {format_value(residual.weight)}"
lines.append(
f"residual : {residual.source} on {', '.join(residual.devices)} "
f"oscillates at {format_value(residual.frequency)} GHz{weight}"
)
return lines
def _concrete(value: Any) -> float | None:
"""Best-effort float for report arithmetic and unit conversion; ``None`` when traced."""
return maybe_concrete_scalar(value)
def _survivor_lines(label: str, entry: Any, reduced_device: Any) -> list[str]:
"""Before -> after freq (and T1, when either side carries one) for one survivor."""
freq_after = _concrete(entry["freq_after"])
lamb_shift = _concrete(entry["lamb_shift"])
if freq_after is None or lamb_shift is None:
lines = [f"{label}: freq <traced> → <traced> GHz"]
else:
freq_before = freq_after - lamb_shift
sign = "+" if lamb_shift >= 0 else ""
lines = [
f"{label}: freq {freq_before:.6g} → {freq_after:.6g} GHz "
f"(Lamb shift {sign}{lamb_shift * 1e3:.3g} MHz)"
]
t1_after_raw = getattr(reduced_device, "T1", None)
if t1_after_raw is not None:
lines.append(f" intrinsic T1: {format_value(t1_after_raw / 1e3)} µs")
rate = entry.get("purcell_rate", 0.0)
concrete_rate = _concrete(rate)
if concrete_rate is None or concrete_rate > 0:
lines.append(f" Purcell contribution to 1→0 lowering: {format_value(rate)} 1/ns (separate channel)")
return lines
def _exchange_lines(chip: "Chip", entry: Any) -> list[str]:
"""Emitted-edge and Yan-formula details, including ZZ when available."""
lines: list[str] = []
edge_label = entry.get("coupling")
if edge_label is not None:
edge = chip.coupling_map.get(edge_label)
strength = _concrete(edge.coupling_strength) if edge is not None else None
strength_name = edge.coupling_strength_name if edge is not None else "g"
edge_type = type(edge).__name__ if edge is not None else "?"
strength_text = f"{strength * 1e3:.4g} MHz" if strength is not None else "<traced>"
lines.append(
f"edge '{edge_label}': {edge_type}({strength_name} = {strength_text}) "
"[J = g_a g_b / 2 · (1/Δ_a + 1/Δ_b)]"
)
label_a, label_b = entry.get("between", ("?", "?"))
zz = entry.get("zz")
if zz is None:
zz_text = '— (available under method="exact")'
else:
zz_value = _concrete(zz)
zz_text = f"{zz_value * 1e3:.4g} MHz" if zz_value is not None else "<traced>"
lines.append(f"ZZ({label_a}, {label_b}) = {zz_text}")
return lines
def _validity_line(validity: dict[str, Any]) -> str:
"""One verdict per eliminated coupling or line section, plus the shared min block gap."""
parts = []
min_gap = None
for label, v in validity.items():
if "residual_margin" in v:
margin, is_valid = _concrete(v["margin"]), _concrete(v["is_valid"])
if margin is None or is_valid is None:
parts.append(f"{label} weight margin=<traced>")
else:
parts.append(f"{label} weight margin={margin:.2g} {'✓' if is_valid else '✗'} (≥ 0)")
continue
if "self_energy_over_width" in v:
symbol, key = "|Σ|/h", "self_energy_over_width"
else:
symbol, key = ("κ/Δ", "kappa_over_delta") if "kappa_over_delta" in v else ("g/Δ", "g_over_delta")
ratio = _concrete(v.get(key))
is_valid = _concrete(v.get("is_valid"))
if min_gap is None and "min_block_gap" in v:
min_gap = _concrete(v["min_block_gap"])
if v.get(key) is None:
parts.append(f"{label} {symbol}=unavailable")
elif ratio is None or is_valid is None:
parts.append(f"{label} {symbol}=<traced>")
else:
mark = "✓" if is_valid else "✗"
parts.append(f"{label} {symbol}={ratio:.2g} {mark} (< 0.1)")
line = "validity: " + " · ".join(parts)
if min_gap is not None:
line += f" · min block gap {min_gap:.3g} GHz"
return line
def _classify_notes(notes: list[str]) -> tuple[str | None, str | None, list[str], list[str]]:
"""Split fold notes into (method, dropped text, retarget lines, leftover lines).
The method tag and the "Dropped: ..." summary are literal substrings
``eliminate()`` always emits for a device target; a retarget conversion
note always opens with ``"drive '<label>': "`` (:func:`quchip.chip.retarget._flux_bridge_rule`
and any rule following the same convention). Everything else — the
coupling-elimination summary, a folded-direct-coupling note, the
per-pair exchange-formula note — is not itemized further here and
renders verbatim.
"""
method: str | None = None
dropped: str | None = None
retarget: list[str] = []
leftover: list[str] = []
for note in notes:
if "(method='sw')" in note:
method = "sw"
elif "(method='exact')" in note:
method = "exact"
elif note.startswith("Dropped: "):
dropped = note[len("Dropped: ") :].rstrip(".")
elif note.startswith("drive '"):
retarget.append(note)
else:
leftover.append(note)
return method, dropped, retarget, leftover
[docs]
def describe_elimination(result: "EliminationResult") -> str:
"""Human-readable fold report for :func:`~quchip.chip.transformations.eliminate`.
The report states every fold explicitly, before -> after, with the
per-survivor freq (and T1 when either side has one). It shows the
emitted/upgraded exchange edge with its Yan-formula tag, and ZZ
availability under ``method="sw"`` or the exact residual under
``method="exact"``. It also shows any control-line retarget, the
per-coupling validity verdict, and the dropped-physics summary. See
:meth:`~quchip.chip.transformations.EliminationResult.describe`.
"""
method, dropped, retarget, leftover = _classify_notes(result.notes)
lines = _section("Elimination fold report" + (f" (method='{method}')" if method else ""))
for label, entry in result.effective_params.items():
if label == "exchange":
continue
lines.extend(_survivor_lines(label, entry, result.chip[label]))
exchange = result.effective_params.get("exchange")
if exchange is not None:
if "between" in exchange:
lines.extend(_exchange_lines(result.chip, exchange))
else:
for pair in sorted(exchange):
lines.extend(_exchange_lines(result.chip, exchange[pair]))
lines.extend(retarget)
if result.validity:
lines.append(_validity_line(result.validity))
if dropped:
items = [item.strip() for item in dropped.split(",")]
lines.append("dropped: " + " · ".join(items))
if leftover:
lines.append("notes:")
lines.extend(f" - {note}" for note in leftover)
return "\n".join(lines)