Source code for cutqc2.core.dag

from itertools import product
from qiskit.circuit import Qubit
from qiskit.dagcircuit import DAGCircuit


[docs] class DagNode: """ Represents a node in a quantum circuit DAG (Directed Acyclic Graph), corresponding to a specific gate on a specific wire (qubit/register). Since only inter-wire gates are important for the cut algorithm, any mention of `gate_index` refers to the index wrt inter-wire gates only. Attributes: wire_index (int): The index of the wire (qubit/register). gate_index (int): The index of the gate on the wire. Note: `gate_index` assumes that only inter-wire gates are considered. name (str): The name of the node (default 'q'). """
[docs] @classmethod def from_string(cls, s: str): """ Create a DagNode from a string representation. Args: s (str): The string representation of the node in the format 'name[wire_index]gate_index'. Returns: DagNode: The created DagNode instance. """ name, rest = s.split("[") wire_index, gate_index = map(int, rest.split("]")) return cls(wire_index, gate_index, name)
def __init__(self, wire_index: int, gate_index: int, name: str = "q"): """ Initialize a DagNode. Args: wire_index (int): The index of the wire (qubit/register). gate_index (int): The index of the gate on the wire. name (str, optional): The name of the node. Defaults to 'q'. """ self.wire_index = wire_index self.gate_index = gate_index self.name = name def __str__(self): """ Return a string representation of the DagNode. Returns: str: The string in the format 'name[wire_index]gate_index'. """ return "%s[%d]%d" % (self.name, self.wire_index, self.gate_index) def __eq__(self, other: "DagNode"): return ( self.wire_index == other.wire_index and self.gate_index == other.gate_index and self.name == other.name ) def __lt__(self, other: "DagNode"): """ Compare two DagNodes for ordering, first by wire_index, then by gate_index. Args: other (DagNode): The other DagNode to compare to. Returns: bool: True if this node is less than the other node. """ if self.wire_index < other.wire_index: return True elif self.wire_index == other.wire_index: return self.gate_index < other.gate_index return False def __sub__(self, other): """ Subtract two DagNodes on the same wire to get the difference in gate indices. Args: other (DagNode): The other DagNode to subtract. Returns: int: The difference in gate indices. Raises: ValueError: If the nodes are on different wires. """ if self.wire_index != other.wire_index: raise ValueError("Cannot subtract nodes on different wires") return self.gate_index - other.gate_index
[docs] def locate(self, dag_circuit: DAGCircuit) -> tuple[Qubit, int]: """ Locate the position of the DagNode in the DAGCircuit. Args: dag_circuit (DAGCircuit): The DAGCircuit containing the node. Returns: tuple[Qubit, int]: A tuple containing the Qubit and the index of the gate on that wire. Raises: ValueError: If the node cannot be found in the DAGCircuit. """ wire = dag_circuit.wires[self.wire_index] multi_wire_gate_i = 0 for i, gate in enumerate(dag_circuit.nodes_on_wire(wire, only_ops=True)): if len(gate.qargs) > 1: if multi_wire_gate_i == self.gate_index: return wire, i multi_wire_gate_i += 1 raise ValueError("not found")
[docs] class DAGEdge: """ Represents an edge in a quantum circuit DAG, connecting two DagNodes. Attributes: source (DagNode): The source node of the edge. dest (DagNode): The destination node of the edge. """
[docs] @classmethod def from_string(cls, edge_str: str) -> "DAGEdge": """ Create a DAGEdge from a string representation. Args: edge_str (str): The string representation of the edge in the format 'source dest'. Returns: DAGEdge: The created DAGEdge instance. """ source_str, dest_str = edge_str.split() return cls(DagNode.from_string(source_str), DagNode.from_string(dest_str))
def __init__(self, first: DagNode, second: DagNode): """ Initialize a DAGEdge between two DagNodes. Args: first (DagNode): The first node. second (DagNode): The second node. """ self.source, self.dest = sorted((first, second)) def __str__(self): """ Return a string representation of the DAGEdge. Returns: str: The string in the format 'source dest'. """ return f"{self.source} {self.dest}" def __eq__(self, other: "DAGEdge"): return self.source == other.source and self.dest == other.dest def __or__(self, other: "DAGEdge") -> tuple[DagNode, DagNode]: """ Find the pair of DagNodes (one from each edge) that share the same wire index. Args: other (DAGEdge): The other DAGEdge to compare with. Returns: tuple[DagNode, DagNode]: The pair of nodes with the same wire index, sorted. Raises: ValueError: If there is no common wire between the two edges. """ for a, b in product((self.source, self.dest), (other.source, other.dest)): if a.wire_index == b.wire_index: return tuple(sorted((a, b))) raise ValueError("No common wire")
[docs] def weight(self) -> int: return int(self.source.gate_index == 0) + int(self.dest.gate_index == 0)