# Type stubs for the Rust bindings

from typing import (
    final,
    Tuple,
    List,
    Iterable,
    Optional,
    Mapping,
    Sequence,
    Set,
    Dict,
    Any,
    Union,
)
from pyzx.graph.base import BaseGraph, VertexType, EdgeType, FractionLike, FloatInt
from pyzx.simplify import Simplifier
from pyzx.graph.scalar import Scalar
import numpy as np

VT = int
ET = Tuple[int, int]

@final
class VecGraph(BaseGraph[VT, ET]):
    scalar: Scalar
    def clone(self) -> VecGraph: ...
    def inputs(self) -> Tuple[VT, ...]: ...
    def set_inputs(self, inputs: Tuple[VT, ...]): ...
    def outputs(self) -> Tuple[VT, ...]: ...
    def set_outputs(self, outputs: Tuple[VT, ...]): ...
    def add_vertices(self, amount: int) -> List[VT]: ...
    def add_vertex_indexed(self, v: VT) -> None: ...
    def add_edge(
        self, edge_pair: Tuple[VT, VT], edgetype: EdgeType = EdgeType.SIMPLE
    ) -> ET: ...
    def remove_vertices(self, vertices: Iterable[VT]) -> None: ...
    def remove_edges(self, edges: List[ET]) -> None: ...
    def num_vertices(self) -> int: ...
    def num_edges(self, s: Optional[VT] = None, t: Optional[VT] = None) -> int: ...
    def vertices(self) -> Iterable[VT]: ...
    def edges(self, s: Optional[VT] = None, t: Optional[VT] = None) -> Iterable[ET]: ...
    def edge_st(self, edge: ET) -> Tuple[VT, VT]: ...
    def incident_edges(self, vertex: VT) -> Sequence[ET]: ...
    def edge_type(self, e: ET) -> EdgeType: ...
    def set_edge_type(self, e: ET, t: EdgeType) -> None: ...
    def type(self, vertex: VT) -> VertexType: ...
    def set_type(self, vertex: VT, t: VertexType) -> None: ...
    def phase(self, vertex: VT) -> FractionLike: ...
    def set_phase(self, vertex: VT, phase: FractionLike) -> None: ...
    def qubit(self, vertex: VT) -> FloatInt: ...
    def set_qubit(self, vertex: VT, q: FloatInt) -> None: ...
    def row(self, vertex: VT) -> FloatInt: ...
    def set_row(self, vertex: VT, r: FloatInt) -> None: ...
    def clear_vdata(self, vertex: VT) -> None: ...
    def vdata_keys(self, vertex: VT) -> Sequence[str]: ...
    def vdata(self, vertex: VT, key: str, default: Any = 0) -> Any: ...
    def set_vdata(self, vertex: VT, key: str, val: Any) -> None: ...
    def is_ground(self, vertex: VT) -> bool: ...
    def grounds(self) -> Set[VT]: ...
    def set_ground(self, vertex: VT, flag: bool = True) -> None: ...
    def is_hybrid(self) -> bool: ...
    def multigraph(self) -> bool: ...
    def phases(self) -> Mapping[VT, FractionLike]: ...
    def types(self) -> Mapping[VT, VertexType]: ...
    def qubits(self) -> Mapping[VT, FloatInt]: ...
    def rows(self) -> Mapping[VT, FloatInt]: ...
    def depth(self) -> FloatInt: ...
    def edge(self, s: VT, t: VT, et: EdgeType = EdgeType.SIMPLE) -> ET: ...
    def connected(self, v1: VT, v2: VT) -> bool: ...
    def add_vertex(
        self,
        ty: VertexType = VertexType.BOUNDARY,
        qubit: FloatInt = -1,
        row: FloatInt = -1,
        phase: Optional[FractionLike] = None,
        ground: bool = False,
    ) -> VT: ...
    def add_edges(
        self, edge_pairs: Iterable[Tuple[VT, VT]], edgetype: EdgeType = EdgeType.SIMPLE
    ) -> None: ...
    def remove_vertex(self, vertex: VT) -> None: ...
    def remove_edge(self, edge: ET) -> None: ...
    def add_to_phase(self, vertex: VT, phase: FractionLike) -> None: ...
    def num_inputs(self) -> int: ...
    def num_outputs(self) -> int: ...
    def set_position(self, vertex: VT, q: FloatInt, r: FloatInt): ...
    def neighbors(self, vertex: VT) -> Sequence[VT]: ...
    def vertex_degree(self, vertex: VT) -> int: ...
    def edge_s(self, edge: ET) -> VT: ...
    def edge_t(self, edge: ET) -> VT: ...
    def vertex_set(self) -> Set[VT]: ...
    def edge_set(self) -> Set[ET]: ...
    def stats(self) -> str: ...
    def copy(
        self, adjoint: bool = False, backend: Optional[str] = None
    ) -> VecGraph: ...
    def adjoint(self) -> VecGraph: ...
    def map_qubits(self, qubit_map: Mapping[int, Tuple[float, float]]) -> None: ...
    def compose(self, other: BaseGraph[VT, ET]) -> None: ...
    def tensor(self, other: BaseGraph[VT, ET]) -> VecGraph: ...
    def __iadd__(self, other: BaseGraph[VT, ET]) -> VecGraph: ...
    def __add__(self, other: BaseGraph[VT, ET]) -> VecGraph: ...
    def __mul__(self, other: BaseGraph[VT, ET]) -> VecGraph: ...
    def __matmul__(self, other: BaseGraph[VT, ET]) -> VecGraph: ...
    def merge(self, other: BaseGraph[VT, ET]) -> Tuple[List[VT], List[ET]]: ...
    def subgraph_from_vertices(self, verts: List[VT]) -> VecGraph: ...
    def apply_state(self, state: str) -> None: ...
    def apply_effect(self, effect: str) -> None: ...
    def to_tensor(self, preserve_scalar: bool = True) -> np.ndarray: ...
    def to_matrix(self, preserve_scalar: bool = True) -> np.ndarray: ...
    def to_dict(self, include_scalar: bool = True) -> Dict[str, Any]: ...
    def to_json(self, include_scalar: bool = True) -> str: ...
    def to_graphml(self) -> str: ...
    def to_tikz(self, draw_scalar: bool = False) -> str: ...
    @classmethod
    def from_json(cls, js: Union[str, Dict[str, Any]]) -> VecGraph: ...
    @classmethod
    def from_tikz(
        cls,
        tikz: str,
        warn_overlap: bool = True,
        fuse_overlap: bool = True,
        ignore_nonzx: bool = False,
    ) -> VecGraph: ...
    def is_id(self) -> bool: ...
    def pack_circuit_rows(self) -> None: ...
    def qubit_count(self) -> int: ...
    def auto_detect_io(self): ...
    def normalize(self) -> None: ...
    def translate(self, x: FloatInt, y: FloatInt) -> VecGraph: ...
    def add_edge_table(self, etab: Mapping[Tuple[VT, VT], List[int]]) -> None: ...
    def set_phase_master(self, m: Simplifier) -> None: ...
    def update_phase_index(self, old: VT, new: VT) -> None: ...
    def fuse_phases(self, p1: VT, p2: VT) -> None: ...
    def phase_negate(self, v: VT) -> None: ...
    def vertex_from_phase_index(self, i: int) -> VT: ...
    def remove_isolated_vertices(self) -> None: ...
    def vdata_dict(self, vertex: VT) -> Dict[str, Any]: ...
    def set_vdata_dict(self, vertex: VT, d: Dict[str, Any]) -> None: ...
    def is_well_formed(self) -> bool: ...
    def get_auto_simplify(self) -> bool: ...
    def set_auto_simplify(self, s: bool) -> None: ...
    def is_phase_gadget(self, v: VT) -> bool: ...

@final
class Circuit:
    @staticmethod
    def from_qasm(qasm: str) -> Circuit: ...
    @staticmethod
    def load(file: str) -> Circuit: ...
    def to_qasm(self) -> str: ...
    def to_graph(self) -> VecGraph: ...
    def num_gates(self) -> int: ...
    def stats(self) -> str: ...

@final
class CircuitStats:
    def qubits(self) -> int: ...
    def total(self) -> int: ...
    def oneq(self) -> int: ...
    def twoq(self) -> int: ...
    def moreq(self) -> int: ...
    def cliff(self) -> int: ...
    def non_cliff(self) -> int: ...
    def to_string(self) -> str: ...

@final
class Decomposer:
    scalar: Scalar
    @staticmethod
    def empty() -> Decomposer: ...
    def __init__(self, g: VecGraph) -> None: ...
    def graphs(self) -> list[VecGraph]: ...
    def done(self) -> list[VecGraph]: ...
    def save(self, b: bool) -> None: ...
    def apply_optimizations(self, b: bool) -> None: ...
    def max_terms(self) -> int: ...
    def decomp_top(self) -> None: ...
    def decomp_all(self) -> None: ...
    def decomp_parallel(self, depth: int) -> None: ...
    def decomp_until_depth(self, depth: int) -> None: ...
    def use_cats(self, b: bool) -> None: ...
    def get_nterms(self) -> int: ...

def dummy(a: int) -> str: ...
def interior_clifford_simp(g: VecGraph): ...
def clifford_simp(g: VecGraph): ...
def full_simp(g: VecGraph): ...
def extract_circuit(g: VecGraph) -> Circuit: ...
