Source code for qarp.cutting._auto_cut_finder

"""Abstract AutoCutFinder and CutterResult, operating on lists of qx.Command."""

from abc import ABC, abstractmethod
from typing import Optional

import qarpx as qx


def remove_barriers(commands: list) -> list:
    """Remove all Barrier commands from a command list."""
    return [
        c for c in commands if not (isinstance(c, qx.Command) and c.gate == qx.GateType.Barrier)
    ]


[docs] class AutoCutFinder(ABC): def __init__( self, commands: list, n_qubits: int, max_size_subcircuits: list, penalization_term: float, verbose: bool = True, ) -> None: """Abstract base for automatic circuit cut finders. Args: commands: Flat list of qx.Command objects representing the circuit to cut (barriers already stripped, measurements removed). n_qubits: Number of qubits in the circuit. max_size_subcircuits: Maximum qubit count per subcircuit, e.g. [2, 2]. penalization_term: Penalty weight for invalid partitions in the optimisation objective. verbose: Print progress information. """ self.commands = remove_barriers(commands) self.n_qubits = n_qubits if max_size_subcircuits: self.n_subcircuits = len(max_size_subcircuits) assert sum(max_size_subcircuits) >= n_qubits, ( "max_size_subcircuits total capacity is less than n_qubits." ) assert self.n_subcircuits > 1, "At least 2 subcircuits required for circuit cutting." assert penalization_term > 1, "penalization_term must be > 1." self.max_size_subcircuits = max_size_subcircuits self.penalization_term = penalization_term self.verbose = verbose # Results populated by cut() self._subcircuits_cmds: list = [] # list of (commands, n_qubits) per subcircuit self._subcircuit_qubits: list = [] # global qubit indices per subcircuit self._cut_cmds_2q: list = [] # full circuit with 2q _CutMarker sentinels self._cut_cmds_1q: list = [] # same with 1q markers (for filtering) self._cut_performed: bool = False self.cut_names: dict = {} self.n_cuts: int = 0
[docs] @abstractmethod def cut(self, manual_setting: Optional[list] = None): """Find cut locations and partition the circuit into subcircuits. Args: manual_setting: Optional list of qubit-index lists, one per subcircuit. Returns: CutterResult """ raise NotImplementedError
@property def subcircuits(self): """List of (commands, n_qubits) tuples for each subcircuit.""" if self._cut_performed: return self._subcircuits_cmds raise RuntimeError("Circuit has not been cut yet.") @subcircuits.setter def subcircuits(self, value): assert len(value) >= self.n_subcircuits self._subcircuits_cmds = value @property def subcircuit_qubits(self): """Global qubit indices for each subcircuit.""" if self._cut_performed: return self._subcircuit_qubits raise RuntimeError("Circuit has not been cut yet.") @property def cut_qc(self): """2q _CutMarker command list (for decomposition iterator).""" if self._cut_performed: return self._cut_cmds_2q raise RuntimeError("Circuit has not been cut yet.") @cut_qc.setter def cut_qc(self, value): self._cut_cmds_2q = value
[docs] def check_cut_budget(n_cuts: int, *, force: bool = False) -> None: """Reject cut counts past ``config.max_number_of_cuts``. Every cut multiplies the experiment count by 6 (6^n_cuts total) — the guard lives here, in ``qarp.cutting``, so both the engine-integrated and the standalone execution paths consult it. """ from qarp import config if n_cuts >= config.max_number_of_cuts and not force: raise RuntimeError( f"Number of cuts ({n_cuts}) exceeds " f"config.max_number_of_cuts ({config.max_number_of_cuts}). " "Set force_max_number_cuts=True to override." )
[docs] class CutterResult: """Result of a circuit cutting operation.""" def __init__(self, cutter_obj: AutoCutFinder) -> None: self.custom_commands = cutter_obj.cut_qc # list with _CutMarker (2q form) self.subcircuits = cutter_obj.subcircuits # list of (cmds, n_qubits) self.subcircuit_qubits = cutter_obj.subcircuit_qubits # list of qubit-index lists self.cut_info = cutter_obj.cut_names self.n_subcircuits = cutter_obj.n_subcircuits self.n_cuts = len(cutter_obj.cut_names) self.n_qubits = cutter_obj.n_qubits def __str__(self) -> str: return ( f"Original circuit width: {self.n_qubits}\n" f"Number of subcircuits: {self.n_subcircuits}\n" f"Number of cuts: {self.n_cuts}" )