"""Notebook widgets: ``Circuit``, ``Result``, ``Receipt`` and ``Bloch``. Each shows what the engine said, never its own reckoning: a circuit is the engine's drawing; a result's histogram is the engine's counts, with the method and the accuracy class it names; a receipt's badge is the engine's check, made here; a Bloch vector is the engine's expectation values. With the ``widgets`` extra installed (``anywidget``), each is an interactive widget whose front end is a small plain ES module (``static/*.js``): a gate clicked in a ``Circuit`` sets ``selected``, a ``Result`` switches between counts and frequencies, a ``Bloch`` sphere turns when dragged and keeps its ``view``. Without it, or in a front end without the widget extension, each still renders, as static HTML (``_repr_html_``), and a ``Circuit`` also as SVG (``_repr_svg_``). Each widget's data is one dict, ``data``, built by ``circuit_data``, ``result_data``, ``receipt_data`` and ``bloch_data``: plain values, so a page or a test can read exactly what is drawn. """ from __future__ import annotations from pathlib import Path from typing import Any, Dict, List, Mapping, Optional, Sequence, Union from . import _api, _render from ._data import bloch_data, circuit_data, receipt_data, result_data __all__ = ["Circuit", "Result", "Receipt", "Bloch", "circuit_data", "result_data", "receipt_data", "bloch_data", "HAVE_WIDGETS"] _STATIC = Path(__file__).parent / "static" try: # The interactive front end is optional. import anywidget as _anywidget import traitlets as _traitlets HAVE_WIDGETS = True except ImportError: # pragma: no cover - exercised in a process without it _anywidget = None _traitlets = None HAVE_WIDGETS = False # -- the widgets ------------------------------------------------------------ if HAVE_WIDGETS: class _Base(_anywidget.AnyWidget): _css = _STATIC / "widgets.css" data = _traitlets.Dict().tag(sync=True) def __init__(self, data: Dict[str, Any], **traits: Any) -> None: super().__init__(data=data, **traits) else: class _Base: # type: ignore[no-redef] def __init__(self, data: Dict[str, Any], **traits: Any) -> None: self.data = data for k, v in traits.items(): setattr(self, k, v) class Circuit(_Base): """A program's circuit, the engine's drawing. Clicking a gate sets ``selected`` to its operation's index (``None`` when nothing is). Pass ``hands=`` (one per operation) or ``history=`` (and ``version=``) to mark each gate with whose hand it is in.""" if HAVE_WIDGETS: _esm = _STATIC / "circuit.js" selected = _traitlets.Int(None, allow_none=True).tag(sync=True) def __init__(self, program: _api.Program, *, hands: Optional[Sequence[str]] = None, history: Optional[Mapping[str, Any]] = None, version: Optional[str] = None) -> None: traits = {} if HAVE_WIDGETS else {"selected": None} super().__init__(circuit_data(program, hands=hands, history=history, version=version), **traits) def _repr_html_(self) -> str: return _render.circuit_html(self.data) def _repr_svg_(self) -> str: return self.data["svg"] def __repr__(self) -> str: lay = self.data["layout"] items = sum(len(c) for c in lay["columns"]) return f"Circuit({lay['qubits']} qubits, {items} operations in {len(lay['columns'])} columns)" class Result(_Base): """A job's result: its counts as a histogram (or their sampled frequencies), its expectation values and amplitudes, with the method, the accuracy class and the receipt's check.""" if HAVE_WIDGETS: _esm = _STATIC / "result.js" frequencies = _traitlets.Bool(False).tag(sync=True) top = _traitlets.Int(_render.TOP).tag(sync=True) def __init__(self, job: Mapping[str, Any], *, frequencies: bool = False, top: int = _render.TOP) -> None: super().__init__(result_data(job), frequencies=frequencies, top=top) def _repr_html_(self) -> str: return _render.result_html(self.data) def __repr__(self) -> str: d = self.data return f"Result({d['method']}, accuracy {d['accuracy']}, {d['shots']} shots, {len(d['expectations'])} expectation values)" class Receipt(_Base): """A job's receipt: who signed it, its digest, and whether it seals the request and the result, as the engine checks it here.""" if HAVE_WIDGETS: _esm = _STATIC / "receipt.js" def __init__(self, job: Mapping[str, Any]) -> None: super().__init__(receipt_data(job)) @property def valid(self) -> bool: return self.data["valid"] is True def _repr_html_(self) -> str: return _render.receipt_html(self.data) def __repr__(self) -> str: return f"Receipt({'valid' if self.valid else 'INVALID'}, signed by {self.data['signer']})" class Bloch(_Base): """Each qubit's reduced state as a Bloch vector on its sphere, from the engine. Dragging a sphere turns the view (``view``: azimuth and elevation, degrees). Takes a program (and ``bloch``'s keywords) or what ``wai_quantum.bloch`` returned.""" if HAVE_WIDGETS: _esm = _STATIC / "bloch.js" view = _traitlets.List(list(_render.VIEW)).tag(sync=True) def __init__(self, program: Union[_api.Program, Mapping[str, Any]], **kw: Any) -> None: super().__init__(bloch_data(program, **kw), view=list(_render.VIEW)) def _repr_html_(self) -> str: return _render.bloch_html(self.data) def __repr__(self) -> str: return f"Bloch({len(self.data['qubits'])} qubits, {self.data['method']}, accuracy {self.data['accuracy']})"