from collections import namedtuple
from typing import Dict, Iterable, Optional, Tuple, List, Set, Sequence, Iterator

Variant = namedtuple("Variant", "position allele quality")

class NumericSampleIds:
    def __getitem__(self, sample: str) -> int: ...
    def __len__(self) -> int: ...
    def __str__(self) -> str: ...
    def freeze(self) -> None: ...
    def inverse_mapping(self) -> Dict[int, str]: ...

class Read:
    def __init__(
        self,
        name: Optional[str] = ...,
        mapq: int = ...,
        source_id: int = ...,
        sample_id: int = ...,
        reference_start: int = ...,
        BX_tag: Optional[str] = ...,
    ): ...
    @property
    def mapqs(self) -> Tuple[int]: ...
    @property
    def name(self) -> str: ...
    @property
    def source_id(self) -> int: ...
    @property
    def sample_id(self) -> int: ...
    @property
    def reference_start(self) -> int: ...
    @property
    def BX_tag(self) -> str: ...
    def __iter__(self) -> Iterator[Variant]: ...
    def __len__(self) -> int: ...
    def __getitem__(self, key: int) -> Variant: ...
    def __setitem__(self, index: int, variant: Variant): ...
    def __contains__(self, position: int) -> bool: ...
    def add_variant(self, position: int, allele: int, quality: int) -> None: ...
    def add_mapq(self, mapq: int) -> None: ...
    def sort(self) -> None: ...
    def is_sorted(self) -> bool: ...
    def has_BX_tag(self) -> bool: ...

class ReadSet:
    def add(self, read: Read) -> None: ...
    def __iter__(self) -> Iterator[Read]: ...
    def __len__(self) -> int: ...
    def __getitem__(self, key: int) -> Read: ...
    def sort(self) -> None: ...
    def subset(self, reads_to_select: Iterable[int]) -> ReadSet: ...
    def get_positions(self) -> List[int]: ...

class PedigreeDPTable:
    def __init__(
        self,
        readset: ReadSet,
        recombcost: int,
        pedigree: Pedigree,
        distrust_genotypes: bool = ...,
        positions: Optional[Iterable[int]] = ...,
    ): ...
    def get_super_reads(self) -> Tuple[List[ReadSet], List[int]]: ...
    def get_optimal_cost(self) -> int: ...
    def get_optimal_partitioning(self) -> List[int]: ...

class Pedigree:
    def __init__(self, numeric_sample_ids: NumericSampleIds): ...
    def add_individual(
        self,
        id: int,
        genotypes: Iterable[Genotype],
        genotype_likelihoods: Optional[Iterable[PhredGenotypeLikelihoods]] = ...,
    ) -> None: ...
    def add_relationship(self, father_id: int, mother_id: int, child_id: int) -> None: ...
    @property
    def variant_count(self) -> int: ...
    def genotype(self, sample_id: int, variant_index: int) -> Genotype: ...
    def genotype_likelihoods(
        self, sample_id: int, variant_index: int
    ) -> Optional[PhredGenotypeLikelihoods]: ...
    def __len__(self) -> int: ...

class PhredGenotypeLikelihoods:
    def __init__(self, gl: Iterable[float], ploidy: int = ..., nr_alleles: int = ...): ...
    def __getitem__(self, genotype: Genotype) -> float: ...
    def __len__(self) -> int: ...
    def __iter__(self) -> Iterator[float]: ...
    def __eq__(self, other) -> bool: ...
    def genotypes(self) -> List[Genotype]: ...

def binomial_coefficient(n: int, k: int) -> int: ...

class Genotype:
    def __init__(self, alleles: List[int]): ...
    def is_none(self) -> bool: ...
    def get_index(self) -> int: ...
    def as_vector(self) -> List[int]: ...
    def is_homozygous(self) -> bool: ...
    def is_diploid_and_biallelic(self) -> bool: ...
    def get_ploidy(self) -> int: ...
    def __eq__(self, other) -> bool: ...
    def __ne__(self, other) -> bool: ...
    def __lt__(self, other) -> bool: ...

def get_max_genotype_ploidy() -> int: ...
def get_max_genotype_alleles() -> int: ...

class GenotypeDPTable:
    def __init__(
        self,
        numeric_sample_ids: NumericSampleIds,
        readset: ReadSet,
        recombcost: int,
        pedigree: Pedigree,
        positions: Optional[Iterable[int]] = ...,
    ): ...
    def get_genotype_likelihoods(self, sample_id: int, pos: int) -> PhredGenotypeLikelihoods: ...

def compute_genotypes(
    readset: ReadSet, positions: Optional[Iterable[int]] = ...
) -> Tuple[List[Genotype], List[Tuple[float, float, float]]]: ...
def compute_polyploid_genotypes(
    readset: ReadSet, ploidy: int, positions: Optional[Iterable[int]] = ...
) -> List[List[int]]: ...

class HapChatCore:
    def __init__(self, readset: ReadSet): ...
    def get_length(self) -> int: ...
    def get_super_reads(self) -> Tuple[List[ReadSet], List[int]]: ...
    def get_optimal_cost(self) -> int: ...
    def get_optimal_partitioning(self) -> List[int]: ...

def readselection(
    readset: ReadSet,
    max_cov: int,
    preferred_source_ids: Optional[Set[int]] = ...,
    bridging: bool = ...,
) -> Set[int]: ...

class ClusterEditingSolver:
    def __init__(self, m: TriangleSparseMatrix, bundle_edges: bool): ...
    def run(self) -> List[List[int]]: ...

class TriangleSparseMatrix:
    def __init__(self): ...
    def get(self, i: int, j: int) -> float: ...
    def set(self, i: int, j: int, value: float) -> None: ...
    def size(self) -> int: ...
    def getEntries(self) -> List[Tuple[int, int]]: ...
    def __iter__(self) -> Iterator[Tuple[int, int]]: ...
    def __len__(self) -> int: ...

# class ReadScoring:
#     def __init__(self): ...
def scoreReadsetGlobal(readset: ReadSet, min_overlap: int, ploidy: int) -> TriangleSparseMatrix: ...
def scoreReadsetLocal(
    readset: ReadSet, ref_haplotypes: List[List[int]], min_overlap: int, ploidy: int
) -> TriangleSparseMatrix: ...
def scoreReadsetBayesian(
    readset: ReadSet, min_overlap: int, ploidy: int
) -> TriangleSparseMatrix: ...

class HaploThreader:
    def __init__(
        self,
        ploidy: int,
        switch_cost: float,
        affine_switch_cost: float,
        symmetry_optimization: bool,
        row_limit: int,
    ): ...
    def computePathsBlockwise(
        self,
        block_starts: List[int],
        coverage_map: List[List[int]],
        coverage: List[List[float]],
        consensus: List[List[int]],
        genotypes: List[Dict[int, int]],
    ) -> List[List[int]]: ...
    def computePaths(
        self,
        start: int,
        end: int,
        coverage_map: List[List[int]],
        coverage: List[List[float]],
        consensus: List[List[int]],
        genotypes: List[Dict[int, int]],
    ) -> List[List[int]]: ...

class SwitchFlipCalculator:
    def __init__(self, ploidy: int, switch_cost: int = ..., flip_cost: int = ...): ...
    def compute_switch_flips_poly(
        self, phasing0: Sequence[str], phasing1: Sequence[str]
    ) -> Tuple[float, float, List[int], List[List[int]], List[List[int]]]: ...
