#
# Copyright © 2023-2026 QPerfect. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Capability vocabulary, numeric limits, topology, and admission types.
A backend's :meth:`Backend.capabilities` returns a set of
:data:`Capability` tokens drawn from :data:`CAPABILITY_VOCABULARY`.
A backend's :meth:`Backend.limits` returns a :class:`Limits`
instance, and :meth:`Backend.topology` returns one of the
:class:`Topology` subclasses (:class:`AllToAll`,
:class:`CouplingMap`, :class:`LinearChain`).
:meth:`Backend.can_handle` returns an :class:`AdmissionResult`
(:class:`Admissible`, :class:`Marginal`, or :class:`Inadmissible`).
"""
from __future__ import annotations
from dataclasses import dataclass, field
from typing import Callable, Optional
# ──────────────────────────────────────────────────────────────────────────
# Capability vocabulary
# ──────────────────────────────────────────────────────────────────────────
Capability = str
#: Canonical capability tokens a backend may advertise. Informational:
#: backends may declare tokens outside this set; conformance tests warn
#: but never fail on extras.
CAPABILITY_VOCABULARY: frozenset[Capability] = frozenset(
[
# core ops
"amplitude",
"sampling",
"classical_bits",
"zvars",
# measurement
"midcircuit_measure",
"midcircuit_reset",
"final_measure_only",
"reset_after_measure",
# classical control
"feed_forward",
"while_statement",
# noise
"noise",
"calibrated_noise",
"loss",
# observables
"expectation_1q",
"expectation_2q",
"expectation_paulistring",
"expectation_state",
# tensor-network
"bond_dim",
"schmidt_rank",
"streaming",
# parameters
"parametric",
"parametric_batch",
# batching
"batch",
"shared_prefix_batch",
# pass plumbing
"pass_order_honored",
]
)
# ──────────────────────────────────────────────────────────────────────────
# Limits
# ──────────────────────────────────────────────────────────────────────────
[docs]
@dataclass(frozen=True)
class Limits:
"""Numeric limits a simulator advertises.
`None` for any field means "unbounded" (or "not applicable" for fields
like `max_bond_dim` on a state-vector simulator).
"""
max_qubits: Optional[int] = None
max_bond_dim: Optional[int] = None
max_classical_bits: Optional[int] = None
max_zvars: Optional[int] = None
max_samples: Optional[int] = None
max_circuit_depth: Optional[int] = None
# ──────────────────────────────────────────────────────────────────────────
# Topology
# ──────────────────────────────────────────────────────────────────────────
[docs]
class Topology:
"""Base class for device / connectivity topologies."""
[docs]
@dataclass(frozen=True)
class AllToAll(Topology):
"""All-to-all connectivity (no constraint). Default for simulators."""
[docs]
@dataclass(frozen=True)
class CouplingMap(Topology):
"""Coupling map: each edge ``(i, j)`` means qubits ``i`` and ``j`` can
interact directly. 1-based qubit indices to match the rest of MIMIQ.
"""
edges: tuple[tuple[int, int], ...]
[docs]
@dataclass(frozen=True)
class LinearChain(Topology):
"""Linear chain of ``n`` qubits with nearest-neighbor coupling."""
n: int
# ──────────────────────────────────────────────────────────────────────────
# AdmissionResult
# ──────────────────────────────────────────────────────────────────────────
[docs]
class AdmissionResult:
"""Base class for ``can_handle(backend, circuit)`` results."""
[docs]
@dataclass(frozen=True)
class Admissible(AdmissionResult):
"""The backend can execute the circuit."""
[docs]
@dataclass(frozen=True)
class Marginal(AdmissionResult):
"""The backend can execute the circuit but it is near a limit
(memory, bond dimension, runtime). ``warning`` is a user-facing
message; downstream code still treats this as admissible.
"""
warning: str
[docs]
@dataclass(frozen=True)
class Inadmissible(AdmissionResult):
"""The backend cannot execute the circuit."""
reason: str
[docs]
def is_admissible(result: AdmissionResult) -> bool:
"""``True`` for :class:`Admissible` and :class:`Marginal`."""
return isinstance(result, (Admissible, Marginal))
# ──────────────────────────────────────────────────────────────────────────
# UnsupportedCapabilityError
# ──────────────────────────────────────────────────────────────────────────
[docs]
class UnsupportedCapabilityError(Exception):
"""Raised when a backend is asked to run a feature it does not
advertise in :meth:`Backend.capabilities`.
Backends use this to fail loudly rather than silently degrade.
Tests rely on it to verify a backend's capability set is honest
(no "positive lies").
"""
[docs]
def __init__(self, backend_name: str, capability: Capability, detail: str = ""):
self.backend_name = backend_name
self.capability = capability
self.detail = detail
super().__init__(
f"UnsupportedCapabilityError: backend {backend_name} does not "
f"declare :{capability}"
+ (f" ({detail})" if detail else "")
)
# ──────────────────────────────────────────────────────────────────────────
# CAP_PROBES — anti-capability conformance harness registry
# ──────────────────────────────────────────────────────────────────────────
#: Registry of probe-circuit factories keyed by capability. Populated
#: lazily by callers (typically the conformance test module) so that
#: importing this module does not drag in the full circuit-construction
#: surface.
CAP_PROBES: dict[Capability, Callable] = {}
[docs]
def register_cap_probe(capability: Capability, factory: Callable):
"""Register a probe-circuit constructor for ``capability``.
``factory()`` must return a Circuit whose execution requires the
named capability. Conformance tests use this registry to assert
that backends reject what they do not advertise — silently
accepting an undeclared feature would let "positive lies" slip
through.
"""
CAP_PROBES[capability] = factory
return factory