from typing import Any, ClassVar, overload

import numpy as np
from numpy.typing import NDArray
from qiskit import QuantumCircuit

__all__ = [
    "CircuitSimulator",
    "ConstructionMode",
    "DeterministicNoiseSimulator",
    "HybridCircuitSimulator",
    "HybridMode",
    "PathCircuitSimulator",
    "PathSimulatorConfiguration",
    "PathSimulatorMode",
    "StochasticNoiseSimulator",
    "UnitarySimulator",
    "dump_tensor_network",
    "get_matrix",
]

class CircuitSimulator:
    def __init__(
        self,
        circ: QuantumCircuit | str,
        approximation_step_fidelity: float = 1.0,
        approximation_steps: int = 1,
        approximation_strategy: str = "fidelity",
        seed: int = -1,
    ) -> None: ...
    def expectation_value(self, observable: QuantumCircuit | str) -> float: ...
    def export_dd_to_graphviz_file(
        self,
        filename: str,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> None: ...
    def export_dd_to_graphviz_str(
        self,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> str: ...
    def get_active_matrix_node_count(self) -> int: ...
    def get_active_vector_node_count(self) -> int: ...
    def get_max_matrix_node_count(self) -> int: ...
    def get_max_vector_node_count(self) -> int: ...
    def get_name(self) -> str: ...
    def get_number_of_qubits(self) -> int: ...
    def get_tolerance(self) -> float: ...
    def get_vector(self) -> list[complex]: ...
    def set_tolerance(self, tol: float) -> None: ...
    def simulate(self, shots: int) -> dict[str, int]: ...
    def statistics(self) -> dict[str, str]: ...

class DeterministicNoiseSimulator:
    def __init__(
        self,
        circ: QuantumCircuit | str,
        approximation_step_fidelity: float = 1.0,
        approximation_steps: int = 1,
        approximation_strategy: str = "fidelity",
        seed: int = -1,
        noise_effects: str = "APD",
        noise_probability: float = 0.01,
        amp_damping_probability: float | None = 0.02,
        multi_qubit_gate_factor: float = 2,
    ) -> None: ...
    def export_dd_to_graphviz_file(
        self,
        filename: str,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> None: ...
    def export_dd_to_graphviz_str(
        self,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> str: ...
    def get_active_matrix_node_count(self) -> int: ...
    def get_active_vector_node_count(self) -> int: ...
    def get_max_matrix_node_count(self) -> int: ...
    def get_max_vector_node_count(self) -> int: ...
    def get_name(self) -> str: ...
    def get_number_of_qubits(self) -> int: ...
    def get_tolerance(self) -> float: ...
    def get_vector(self) -> list[complex]: ...
    def set_tolerance(self, tol: float) -> None: ...
    def simulate(self, shots: int) -> dict[str, int]: ...
    def statistics(self) -> dict[str, str]: ...

class HybridMode:
    DD: ClassVar[HybridMode]  # value = <HybridMode.DD: 0>
    __members__: ClassVar[
        dict[str, HybridMode]
    ]  # value = {'DD': <HybridMode.DD: 0>, 'amplitude': <HybridMode.amplitude: 1>}
    amplitude: ClassVar[HybridMode]  # value = <HybridMode.amplitude: 1>

    def __eq__(self, other: object) -> bool: ...
    def __getstate__(self) -> int: ...
    def __hash__(self) -> int: ...
    def __index__(self) -> int: ...
    def __init__(self, value: int) -> None: ...
    def __int__(self) -> int: ...
    def __ne__(self, other: object) -> bool: ...
    def __setstate__(self, state: int) -> None: ...
    @property
    def name(self) -> str: ...
    @property
    def value(self) -> int: ...

class HybridCircuitSimulator:
    def __init__(
        self,
        circ: QuantumCircuit | str,
        approximation_step_fidelity: float = 1.0,
        approximation_steps: int = 1,
        approximation_strategy: str = "fidelity",
        seed: int = -1,
        mode: HybridMode = ...,
        nthreads: int = 2,
    ) -> None: ...
    def export_dd_to_graphviz_file(
        self,
        filename: str,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> None: ...
    def export_dd_to_graphviz_str(
        self,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> str: ...
    def get_active_matrix_node_count(self) -> int: ...
    def get_active_vector_node_count(self) -> int: ...
    def get_final_amplitudes(self) -> list[complex]: ...
    def get_max_matrix_node_count(self) -> int: ...
    def get_max_vector_node_count(self) -> int: ...
    def get_mode(self) -> HybridMode: ...
    def get_name(self) -> str: ...
    def get_number_of_qubits(self) -> int: ...
    def get_tolerance(self) -> float: ...
    def get_vector(self) -> list[complex]: ...
    def set_tolerance(self, tol: float) -> None: ...
    def simulate(self, shots: int) -> dict[str, int]: ...
    def statistics(self) -> dict[str, str]: ...

class PathSimulatorMode:
    __members__: ClassVar[
        dict[str, PathSimulatorMode]
    ]  # value = {'sequential': <PathSimulatorMode.sequential: 0>, 'pairwise_recursive': <PathSimulatorMode.pairwise_recursive: 1>, 'cotengra': <PathSimulatorMode.cotengra: 4>, 'bracket': <PathSimulatorMode.bracket: 2>, 'alternating': <PathSimulatorMode.alternating: 3>, 'gate_cost': <PathSimulatorMode.gate_cost: 5>}
    alternating: ClassVar[PathSimulatorMode]  # value = <PathSimulatorMode.alternating: 3>
    bracket: ClassVar[PathSimulatorMode]  # value = <PathSimulatorMode.bracket: 2>
    cotengra: ClassVar[PathSimulatorMode]  # value = <PathSimulatorMode.cotengra: 4>
    gate_cost: ClassVar[PathSimulatorMode]  # value = <PathSimulatorMode.gate_cost: 5>
    pairwise_recursive: ClassVar[PathSimulatorMode]  # value = <PathSimulatorMode.pairwise_recursive: 1>
    sequential: ClassVar[PathSimulatorMode]  # value = <PathSimulatorMode.sequential: 0>

    def __eq__(self, other: object) -> bool: ...
    def __getstate__(self) -> int: ...
    def __hash__(self) -> int: ...
    def __index__(self) -> int: ...
    @overload
    def __init__(self, value: int) -> None: ...
    @overload
    def __init__(self, arg0: str) -> None: ...
    def __int__(self) -> int: ...
    def __ne__(self, other: object) -> bool: ...
    def __setstate__(self, state: int) -> None: ...
    @property
    def name(self) -> str: ...
    @property
    def value(self) -> int: ...

class PathSimulatorConfiguration:
    def __init__(self) -> None: ...
    def json(self) -> dict[str, Any]: ...
    @property
    def bracket_size(self) -> int: ...
    @bracket_size.setter
    def bracket_size(self, arg0: int) -> None: ...
    @property
    def gate_cost(self) -> list[int]: ...
    @gate_cost.setter
    def gate_cost(self, arg0: list[int]) -> None: ...
    @property
    def mode(self) -> PathSimulatorMode: ...
    @mode.setter
    def mode(self, arg0: PathSimulatorMode) -> None: ...
    @property
    def seed(self) -> int: ...
    @seed.setter
    def seed(self, arg0: int) -> None: ...
    @property
    def starting_point(self) -> int: ...
    @starting_point.setter
    def starting_point(self, arg0: int) -> None: ...

class PathCircuitSimulator:
    @overload
    def __init__(self, circ: QuantumCircuit | str, config: PathSimulatorConfiguration = ...) -> None: ...
    @overload
    def __init__(
        self,
        circ: QuantumCircuit | str,
        mode: PathSimulatorMode = ...,
        bracket_size: int = 2,
        starting_point: int = 0,
        gate_cost: list[int] = ...,
        seed: int = ...,
    ) -> None: ...
    def export_dd_to_graphviz_file(
        self,
        filename: str,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> None: ...
    def export_dd_to_graphviz_str(
        self,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> str: ...
    def get_active_matrix_node_count(self) -> int: ...
    def get_active_vector_node_count(self) -> int: ...
    def get_max_matrix_node_count(self) -> int: ...
    def get_max_vector_node_count(self) -> int: ...
    def get_name(self) -> str: ...
    def get_number_of_qubits(self) -> int: ...
    def get_tolerance(self) -> float: ...
    def get_vector(self) -> list[complex]: ...
    def set_simulation_path(self, path: list[tuple[int, int]], assume_correct_order: bool = False) -> None: ...
    def set_tolerance(self, tol: float) -> None: ...
    def simulate(self, shots: int) -> dict[str, int]: ...
    def statistics(self) -> dict[str, str]: ...

class StochasticNoiseSimulator:
    def __init__(
        self,
        circ: QuantumCircuit | str,
        approximation_step_fidelity: float = 1.0,
        approximation_steps: int = 1,
        approximation_strategy: str = "fidelity",
        seed: int = -1,
        noise_effects: str = "APD",
        noise_probability: float = 0.01,
        amp_damping_probability: float | None = 0.02,
        multi_qubit_gate_factor: float = 2,
    ) -> None: ...
    def export_dd_to_graphviz_file(
        self,
        filename: str,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> None: ...
    def export_dd_to_graphviz_str(
        self,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> str: ...
    def get_active_matrix_node_count(self) -> int: ...
    def get_active_vector_node_count(self) -> int: ...
    def get_max_matrix_node_count(self) -> int: ...
    def get_max_vector_node_count(self) -> int: ...
    def get_name(self) -> str: ...
    def get_number_of_qubits(self) -> int: ...
    def get_tolerance(self) -> float: ...
    def get_vector(self) -> list[complex]: ...
    def set_tolerance(self, tol: float) -> None: ...
    def simulate(self, shots: int) -> dict[str, int]: ...
    def statistics(self) -> dict[str, str]: ...

class ConstructionMode:
    __members__: ClassVar[
        dict[str, ConstructionMode]
    ]  # value = {'recursive': <ConstructionMode.recursive: 1>, 'sequential': <ConstructionMode.sequential: 0>}
    recursive: ClassVar[ConstructionMode]  # value = <ConstructionMode.recursive: 1>
    sequential: ClassVar[ConstructionMode]  # value = <ConstructionMode.sequential: 0>

    def __eq__(self, other: object) -> bool: ...
    def __getstate__(self) -> int: ...
    def __hash__(self) -> int: ...
    def __index__(self) -> int: ...
    def __init__(self, value: int) -> None: ...
    def __int__(self) -> int: ...
    def __ne__(self, other: object) -> bool: ...
    def __setstate__(self, state: int) -> None: ...
    @property
    def name(self) -> str: ...
    @property
    def value(self) -> int: ...

class UnitarySimulator:
    def __init__(
        self,
        circ: QuantumCircuit | str,
        approximation_step_fidelity: float = 1.0,
        approximation_steps: int = 1,
        approximation_strategy: str = "fidelity",
        seed: int = -1,
        mode: ConstructionMode = ...,
    ) -> None: ...
    def construct(self) -> None: ...
    def export_dd_to_graphviz_file(
        self,
        filename: str,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> None: ...
    def export_dd_to_graphviz_str(
        self,
        colored: bool = True,
        edge_labels: bool = False,
        classic: bool = False,
        memory: bool = False,
        format_as_polar: bool = True,
    ) -> str: ...
    def get_active_matrix_node_count(self) -> int: ...
    def get_active_vector_node_count(self) -> int: ...
    def get_construction_time(self) -> float: ...
    def get_final_node_count(self) -> int: ...
    def get_max_matrix_node_count(self) -> int: ...
    def get_max_node_count(self) -> int: ...
    def get_max_vector_node_count(self) -> int: ...
    def get_mode(self) -> ConstructionMode: ...
    def get_name(self) -> str: ...
    def get_number_of_qubits(self) -> int: ...
    def get_tolerance(self) -> float: ...
    def set_tolerance(self, tol: float) -> None: ...
    def statistics(self) -> dict[str, str]: ...

def dump_tensor_network(circ: QuantumCircuit | str, filename: str) -> None: ...
def get_matrix(sim: UnitarySimulator, mat: NDArray[np.complex128]) -> None: ...
