# Copyright 2016-2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# See www.openfst.org for extensive documentation on this weighted
# finite-state transducer library.

import enum
import os
from typing import Optional, Union, overload, TypeVar, Tuple, Any, Type, Iterable, Iterator, List

## Custom exceptions.
class FstError(Exception): ...
class FstArgError(FstError, ValueError): ...
class FstBadWeightError(FstError, ValueError): ...
class FstIndexError(FstError, IndexError): ...
class FstIOError(FstError, IOError): ...
class FstOpError(FstError, RuntimeError): ...

# Custom Types
_Filename = Union[os.PathLike, str]
_Symbol = str
_Label = int
_StateId = int
_ArcIteratorPropertiesType = int
_EncodeMapperPropertiesType = int


# TODO(wolfsonkin): Drop version check once Python 3.8 is our minimum version.
import sys
if sys.version_info >= (3, 8):
    from typing import Literal
else:
    from typing_extensions import Literal

ArcMapType = Literal["identity", "input_epsilon", "invert",
                     "output_epsilon", "plus", "power", "quantize",
                     "rmweight", "superfinal", "times", "to_log",
                     # NOTE: Both spellings of "to_std"
                     "to_log64", "to_std", "to_standard"]
# NOTE: At runtime, any number of arc types could be linked in, even though a
# few are the most common, so no strong type checking.
_ArcTypeFlag = str
# NOTE: At runtime, any number of FST types could be linked in, even though a
# few are the most common, so no strong type checking.
_FstTypeFlag = str
ClosureType = Literal["star", "plus"]
ComposeFilter = Literal["alt_sequence", "auto", "match", "no_match",
                        "null", "sequence", "trivial"]
DeterminizeType = Literal["functional", "nonfunctional", "disambiguate"]
DrawFloatFormat = Literal["e", "f", "g"]
EpsNormalizeType = Literal["input", "output"]
FarType = Literal[
  "fst",
  "stlist",
  "sttable",
  "default"
]
ProjectType = Literal["input", "output"]
QueueType = Literal["auto", "fifo", "lifo", "shortest", "state", "top"]
RandArcSelection = Literal["uniform", "log_prob", "fast_log_prob"]
ReplaceLabelType = Literal["neither", "input", "output", "both"]
ReweightType = Literal["to_inital", "to_final"]
SortType = Literal["ilabel", "olabel"]
StateMapType = Literal["arc_sum", "arc_unique", "identity"]

## Weight and helpers.

_WeightType = str
_WeightStr = Union[str, int, float]
WeightLike = Union[Weight, _WeightStr]

class Weight:
  def __repr__(self) -> str: ...
  def __str__(self) -> str: ...
  def __float__(self) -> float: ...
  def __init__(self, weight_type: _WeightType, weight: _WeightStr) -> None: ...
  def copy(self) -> Weight: ...
  @classmethod
  def zero(cls, weight_type: _WeightType) -> Weight: ...
  @classmethod
  def one(cls, weight_type: _WeightType) -> Weight: ...
  @classmethod
  def no_weight(cls, weight_type: _WeightType) -> Weight: ...
  def __eq__(w1: Weight, w2: Weight) -> bool: ...
  def __ne__(w1: Weight, w2: Weight) -> bool: ...
  def to_string(self) -> str: ...
  def type(self) -> _WeightType: ...
  def member(self) -> bool: ...

# TODO(wolfsonkin): Look into converting these to operator overloading instead.
def plus(lhs: Weight, rhs: Weight) -> Weight: ...
def times(lhs: Weight, rhs: Weight) -> Weight: ...
def divide(lhs: Weight, rhs: Weight) -> Weight: ...
def power(w: Weight, n: int) -> Weight: ...
class SymbolTableView:
  def __init__(self) -> None: ...
  def __iter__(self) -> _SymbolTableIterator: ...
  def __reduce__(self) -> Union[str, Tuple[Any, ...]]: ...
  def available_key(self) -> _Label: ...
  def checksum(self) -> bytes: ...
  # NOTE: This is intentional. `copy()` produces a underscore-less (owned) SymbolTable object.
  def copy(self) -> SymbolTable: ...
  @overload
  def find(self, key: _Symbol) -> _Label: ...
  @overload
  def find(self, key: _Label) -> _Symbol: ...
  def get_nth_key(self, pos: int) -> _Label: ...
  def labeled_checksum(self) -> bytes: ...
  def member(self, key: Union[_Symbol, _Label]) -> bool: ...
  def name(self) -> str: ...
  def num_symbols(self) -> int: ...
  def write(self, source: _Filename) -> None: ...
  def write_text(self, source: _Filename) -> None: ...
  def write_to_string(self) -> bytes: ...

class _EncodeMapperSymbolTableView(SymbolTableView):
  def __repr__(self) -> str: ...

class _FstSymbolTableView(SymbolTableView):
  def __repr__(self) -> str: ...

class _MutableSymbolTable(SymbolTableView):
  def add_symbol(self, symbol: _Symbol, key: _Label = ...) -> _Label: ...
  def add_table(self, syms: SymbolTableView) -> None: ...
  def set_name(self, new_name: str) -> None: ...

class _MutableFstSymbolTableView(_MutableSymbolTable):
  def __repr__(self) -> str: ...

class SymbolTable(_MutableSymbolTable):
  def __repr__(self) -> str: ...
  def __init__(self, name: str = ...) -> None: ...
  @classmethod
  def read(cls, source: _Filename) -> SymbolTable: ...
  @classmethod
  def read_text(cls,
                source: _Filename,
                allow_negative_labels: bool = ...) -> SymbolTable: ...
  @classmethod
  def read_fst(cls, source: _Filename, input_table: bool) -> SymbolTable: ...

# Constructive SymbolTable operations.

def compact_symbol_table(syms: SymbolTableView) -> SymbolTable: ...
def merge_symbol_table(lhs: SymbolTableView,
                       rhs: SymbolTableView) -> SymbolTable: ...

## _SymbolTableIterator.

class _SymbolTableIterator:
  def __repr__(self) -> str: ...
  def __init__(self, syms: SymbolTableView) -> None: ...
  def __iter__(self) -> _SymbolTableIterator: ...
  def __next__(self) -> Tuple[_Label, _Symbol]: ...

## EncodeMapper.

class EncodeMapper:
  def __repr__(self) -> None: ...
  def __init__(self,
               arc_type: _ArcTypeFlag = ...,
               encode_labels: bool = ...,
               encode_weights: bool = ...) -> None: ...
  def __call__(self, arc: Arc) -> Arc: ...
  def __reduce__(self) -> Union[str, Tuple[Any, ...]]: ...
  def arc_type(self) -> _ArcTypeFlag: ...
  def weight_type(self) -> _WeightType: ...
  def flags(self) -> _EncodeMapperPropertiesType: ...
  def properties(self, mask: FstProperties) -> FstProperties: ...
  @classmethod
  def read(cls, source: _Filename) -> EncodeMapper: ...
  @staticmethod
  def read_from_string(state: bytes) -> EncodeMapper: ...
  def write(self, source: _Filename) -> None: ...
  def write_to_string(self) -> bytes: ...
  def input_symbols(self) -> _EncodeMapperSymbolTableView: ...
  def output_symbols(self) -> _EncodeMapperSymbolTableView: ...
  def set_input_symbols(self,
                        syms: Optional[SymbolTableView]) -> EncodeMapper: ...
  def set_output_symbols(self,
                         syms: Optional[SymbolTableView]) -> EncodeMapper: ...

U = TypeVar("U", bound="Fst")
class Fst:
  # TODO(wolfsonkin): Verify that `bytes` is really the output type here.
  def _repr_svg_(self) -> bytes: ...
  def __init__(self) -> None: ...
  def __reduce__(self) -> Union[str, Tuple[Any, ...]]: ...
  def __repr__(self) -> str: ...
  def __str__(self) -> str: ...
  def arc_type(self) -> _ArcTypeFlag: ...
  def arcs(self, state: _StateId) -> _ArcIterator: ...
  def copy(self: U) -> U: ...
  def draw(
      self,
      source: _Filename,
      isymbols: Optional[SymbolTableView] = ...,
      osymbols: Optional[SymbolTableView] = ...,
      ssymbols: Optional[SymbolTableView] = ...,
      acceptor: bool = ...,
      title: str = ...,
      width: float = ...,
      height: float = ...,
      portrait: bool = ...,
      vertical: bool = ...,
      ranksep: float = ...,
      nodesep: float = ...,
      fontsize: int = ...,
      precision: int = ...,
      float_format: DrawFloatFormat = ...,
      show_weight_one: bool = ...) -> None: ...
  def final(self, state: _StateId) -> Weight: ...
  def fst_type(self) -> _FstTypeFlag: ...
  def input_symbols(self) -> _FstSymbolTableView: ...
  def num_arcs(self, state: _StateId) -> int: ...
  def num_input_epsilons(self, state: _StateId) -> int: ...
  def num_output_epsilons(self, state: _StateId) -> int: ...
  def output_symbols(self) -> _FstSymbolTableView: ...
  def print(self,
            isymbols: Optional[SymbolTableView] = ...,
            osymbols: Optional[SymbolTableView] = ...,
            ssymbols: Optional[SymbolTableView] = ...,
            acceptor: bool = ...,
            show_weight_one: bool = ...,
            missing_sym: _Symbol = ...) -> str: ...
  def properties(self, mask: FstProperties, test: bool) -> FstProperties: ...
  @classmethod
  def read(cls: Type[U], source: _Filename) -> U: ...
  @classmethod
  def read_from_string(cls: Type[U], state: bytes) -> U: ...
  def start(self) -> _StateId: ...
  def states(self) -> _StateIterator: ...
  def verify(self) -> bool: ...
  def weight_type(self) -> _WeightType: ...
  def write(self, source: _Filename) -> None: ...
  def write_to_string(self) -> bytes: ...

T = TypeVar("T", bound="MutableFst")
class MutableFst(Fst):
  def add_arc(self: T, state: _StateId, arc: Arc) -> T: ...
  def add_state(self) -> _StateId: ...
  def add_states(self, n: int) -> None: ...
  def arcsort(self: T, sort_type: SortType = ...) -> T: ...
  def closure(self: T, closure_type: ClosureType = ...) -> T: ...
  def concat(self: T, fst2: Fst) -> T: ...
  def connect(self: T) -> T: ...
  def decode(self: T, mapper: EncodeMapper) -> T: ...
  def delete_arcs(self: T, state: _StateId, n: int = ...) -> T: ...
  def delete_states(self: T, states: Optional[Iterable[_StateId]] = ...) -> T: ...
  def encode(self: T, mapper: EncodeMapper) -> T: ...
  def invert(self: T) -> T: ...
  def minimize(self: T, delta: float = ..., allow_nondet: bool = ...) -> T: ...
  def mutable_arcs(self, state: _StateId) -> _MutableArcIterator: ...
  def mutable_input_symbols(self) -> _MutableFstSymbolTableView: ...
  def mutable_output_symbols(self) -> _MutableFstSymbolTableView: ...
  def num_states(self) -> _StateId: ...
  def project(self: T, project_type: ProjectType) -> T: ...
  def prune(self: T,
            delta: float = ...,
            nstate: _StateId = ...,
            weight: Optional[WeightLike] = ...) -> T: ...
  def push(self: T,
           delta: float = ...,
           remove_total_weight: bool = ...,
           reweight_type: ReweightType = ...) -> T: ...
  def relabel_pairs(
      self: T,
      ipairs: Optional[Iterable[Tuple[_Label, _Label]]] = ...,
      opairs: Optional[Iterable[Tuple[_Label, _Label]]] = ...) -> T: ...
  def relabel_tables(self: T,
                     old_isymbols: Optional[SymbolTableView] = ...,
                     new_isymbols: Optional[SymbolTableView] = ...,
                     unknown_isymbol: _Symbol = ...,
                     attach_new_isymbols: bool = ...,
                     old_osymbols: Optional[SymbolTableView] = ...,
                     new_osymbols: Optional[SymbolTableView] = ...,
                     unknown_osymbol: _Symbol = ...,
                     attach_new_osymbols: bool = ...) -> T: ...
  def reserve_arcs(self: T, state: _StateId, n: int) -> T: ...
  def reserve_states(self: T, n: _StateId) -> T: ...
  def reweight(self: T,
               potentials: Iterable[WeightLike],
               reweight_type: ReweightType = ...) -> T: ...
  def rmepsilon(self: T,
                queue_type: QueueType = ...,
                connect: bool = ...,
                weight: Optional[WeightLike] = ...,
                nstate: _StateId = ...,
                delta: float = ...) -> T: ...
  def set_final(self: T,
                state: _StateId,
                weight: Optional[WeightLike] = ...) -> T: ...
  def set_input_symbols(self: T, syms: Optional[SymbolTableView]) -> T: ...
  def set_output_symbols(self: T, syms: Optional[SymbolTableView]) -> T: ...
  def set_properties(self: T,
                     props: FstProperties,
                     mask: FstProperties) -> T: ...
  def set_start(self: T, state: _StateId) -> T: ...
  def topsort(self: T) -> T: ...
  def union(self: T, *fsts2: Fst) -> T: ...

class VectorFst(MutableFst):
  def __init__(self, arc_type: _ArcTypeFlag = ...) -> None: ...

def _read_Fst(source: _Filename) -> Fst: ...
def _read_Fst_from_string(state: str) -> Fst: ...
NO_LABEL: _Label
NO_STATE_ID: _StateId
# TODO(wolfosnkin): Extremely confusingly, `NO_SYMBOL` is a `_Label` rather than
# a `_Symbol`. Consider changing that down in the C++ layer.
NO_SYMBOL: _Label

## FST properties.

class FstProperties(enum.Flag):
  EXPANDED: int
  MUTABLE: int
  ERROR: int
  ACCEPTOR: int
  NOT_ACCEPTOR: int
  I_DETERMINISTIC: int
  NON_I_DETERMINISTIC: int
  O_DETERMINISTIC: int
  NON_O_DETERMINISTIC: int
  EPSILONS: int
  NO_EPSILONS: int
  I_EPSILONS: int
  NO_I_EPSILONS: int
  O_EPSILONS: int
  NO_O_EPSILONS: int
  I_LABEL_SORTED: int
  NOT_I_LABEL_SORTED: int
  O_LABEL_SORTED: int
  NOT_O_LABEL_SORTED: int
  WEIGHTED: int
  UNWEIGHTED: int
  CYCLIC: int
  ACYCLIC: int
  INITIAL_CYCLIC: int
  INITIAL_ACYCLIC: int
  TOP_SORTED: int
  NOT_TOP_SORTED: int
  ACCESSIBLE: int
  NOT_ACCESSIBLE: int
  COACCESSIBLE: int
  NOT_COACCESSIBLE: int
  STRING: int
  NOT_STRING: int
  WEIGHTED_CYCLES: int
  UNWEIGHTED_CYCLES: int
  NULL_PROPERTIES: int
  COPY_PROPERTIES: int
  INTRINSIC_PROPERTIES: int
  EXTRINSIC_PROPERTIES: int
  SET_START_PROPERTIES: int
  SET_FINAL_PROPERTIES: int
  ADD_STATE_PROPERTIES: int
  ADD_ARC_PROPERTIES: int
  SET_ARC_PROPERTIES: int
  DELETE_STATE_PROPERTIES: int
  DELETE_ARC_PROPERTIES: int
  STATE_SORT_PROPERTIES: int
  ARC_SORT_PROPERTIES: int
  I_LABEL_INVARIANT_PROPERTIES: int
  O_LABEL_INVARIANT_PROPERTIES: int
  WEIGHT_INVARIANT_PROPERTIES: int
  ADD_SUPERFINAL_PROPERTIES: int
  RM_SUPERFINAL_PROPERTIES: int
  BINARY_PROPERTIES: int
  TRINARY_PROPERTIES: int
  POS_TRINARY_PROPERTIES: int
  NEG_TRINARY_PROPERTIES: int
  FST_PROPERTIES: int

EXPANDED: FstProperties
MUTABLE: FstProperties
ERROR: FstProperties
ACCEPTOR: FstProperties
NOT_ACCEPTOR: FstProperties
I_DETERMINISTIC: FstProperties
NON_I_DETERMINISTIC: FstProperties
O_DETERMINISTIC: FstProperties
NON_O_DETERMINISTIC: FstProperties
EPSILONS: FstProperties
NO_EPSILONS: FstProperties
I_EPSILONS: FstProperties
NO_I_EPSILONS: FstProperties
O_EPSILONS: FstProperties
NO_O_EPSILONS: FstProperties
I_LABEL_SORTED: FstProperties
NOT_I_LABEL_SORTED: FstProperties
O_LABEL_SORTED: FstProperties
NOT_O_LABEL_SORTED: FstProperties
WEIGHTED: FstProperties
UNWEIGHTED: FstProperties
CYCLIC: FstProperties
ACYCLIC: FstProperties
INITIAL_CYCLIC: FstProperties
INITIAL_ACYCLIC: FstProperties
TOP_SORTED: FstProperties
NOT_TOP_SORTED: FstProperties
ACCESSIBLE: FstProperties
NOT_ACCESSIBLE: FstProperties
COACCESSIBLE: FstProperties
NOT_COACCESSIBLE: FstProperties
STRING: FstProperties
NOT_STRING: FstProperties
WEIGHTED_CYCLES: FstProperties
UNWEIGHTED_CYCLES: FstProperties
NULL_PROPERTIES: FstProperties
COPY_PROPERTIES: FstProperties
INTRINSIC_PROPERTIES: FstProperties
EXTRINSIC_PROPERTIES: FstProperties
SET_START_PROPERTIES: FstProperties
SET_FINAL_PROPERTIES: FstProperties
ADD_STATE_PROPERTIES: FstProperties
ADD_ARC_PROPERTIES: FstProperties
SET_ARC_PROPERTIES: FstProperties
DELETE_STATE_PROPERTIES: FstProperties
DELETE_ARC_PROPERTIES: FstProperties
STATE_SORT_PROPERTIES: FstProperties
ARC_SORT_PROPERTIES: FstProperties
I_LABEL_INVARIANT_PROPERTIES: FstProperties
O_LABEL_INVARIANT_PROPERTIES: FstProperties
WEIGHT_INVARIANT_PROPERTIES: FstProperties
ADD_SUPERFINAL_PROPERTIES: FstProperties
RM_SUPERFINAL_PROPERTIES: FstProperties
BINARY_PROPERTIES: FstProperties
TRINARY_PROPERTIES: FstProperties
POS_TRINARY_PROPERTIES: FstProperties
NEG_TRINARY_PROPERTIES: FstProperties
FST_PROPERTIES: FstProperties

## Arc iterator properties.

ARC_I_LABEL_VALUE: _ArcIteratorPropertiesType
ARC_O_LABEL_VALUE: _ArcIteratorPropertiesType
ARC_WEIGHT_VALUE: _ArcIteratorPropertiesType
ARC_NEXT_STATE_VALUE: _ArcIteratorPropertiesType
ARC_NO_CACHE: _ArcIteratorPropertiesType
ARC_VALUE_FLAGS: _ArcIteratorPropertiesType
ARC_FLAGS: _ArcIteratorPropertiesType

## EncodeMapper properties.

ENCODE_LABELS: _EncodeMapperPropertiesType
ENCODE_WEIGHTS: _EncodeMapperPropertiesType
ENCODE_FLAGS: _EncodeMapperPropertiesType

## Arc.

class Arc:
  def __repr__(self) -> str: ...
  def __init__(self, ilabel: _Label, olabel: _Label,
               weight: WeightLike, nextstate: _StateId) -> None: ...
  def copy(self) -> Arc: ...
  @property
  def ilabel(self) -> _Label: ...
  @ilabel.setter
  def ilabel(self, value: _Label) -> None: ...
  @property
  def olabel(self) -> _Label: ...
  @olabel.setter
  def olabel(self, value: _Label) -> None: ...
  @property
  def weight(self) -> Weight: ...
  @weight.setter
  def weight(self, value: WeightLike) -> None: ...
  @property
  def nextstate(self) -> _Label: ...
  @nextstate.setter
  def nextstate(self, value: _Label) -> None: ...

## ArcIterator and MutableArcIterator.

class _ArcIterator:
  def __repr__(self) -> str: ...
  # TODO(wolfsonkin): Consider making this `FstLike` instead.
  def __init__(self, ifst: Fst, state: _StateId) -> None: ...
  def __iter__(self) -> _ArcIterator: ...
  def __next__(self) -> Arc: ...
  def done(self) -> bool: ...
  def flags(self) -> _ArcIteratorPropertiesType: ...
  def next(self) -> None: ...
  def position(self) -> int: ...
  def reset(self) -> None: ...
  def seek(self, a: int) -> None: ...
  def set_flags(self,
                flags: _ArcIteratorPropertiesType,
                mask: _ArcIteratorPropertiesType) -> None: ...
  def value(self) -> Arc: ...

class _MutableArcIterator:
  def __repr__(self) -> str: ...
  # TODO(wolfsonkin): Consider making this `FstLike` instead.
  def __init__(self, ifst: MutableFst, state: _StateId) -> None: ...
  def __iter__(self) -> _MutableArcIterator: ...
  def __next__(self) -> Arc: ...
  def done(self) -> bool: ...
  def flags(self) -> _ArcIteratorPropertiesType: ...
  def next(self) -> None: ...
  def position(self) -> int: ...
  def reset(self) -> None: ...
  def seek(self, a: int) -> None: ...
  def set_flags(self,
                flags: _ArcIteratorPropertiesType,
                mask: _ArcIteratorPropertiesType) -> None: ...
  def set_value(self, arc: Arc) -> None: ...
  def value(self) -> Arc: ...

## _StateIterator.

class _StateIterator:
  def __repr__(self) -> str: ...
  # TODO(wolfsonkin): Consider making this `FstLike` instead.
  def __init__(self, ifst: Fst) -> None: ...
  def __iter__(self) -> _StateIterator: ...
  def __next__(self) -> _StateId: ...
  def done(self) -> bool: ...
  def next(self) -> None: ...
  def reset(self) -> None: ...
  def value(self) -> _StateId: ...

## FST operations.


def arcmap(
    ifst: Fst,
    delta: float = ...,
    map_type: ArcMapType = ...,
    power: float = ...,
    weight: Optional[WeightLike] = ...) -> Fst: ...
def compose(
    ifst1: Fst,
    ifst2: Fst,
    compose_filter: ComposeFilter = ...,
    connect: bool = ...) -> MutableFst: ...
def convert(ifst: Fst, fst_type: _FstTypeFlag = ...) -> Fst: ...
def determinize(
    ifst: Fst,
    delta: float = ...,
    det_type: DeterminizeType = ...,
    nstate: _StateId = ...,
    subsequential_label: _Label = ...,
    weight: Optional[WeightLike] = ...,
    increment_subsequential_label: bool = ...) -> MutableFst: ...
def difference(
    ifst1: Fst,
    ifst2: Fst,
    compose_filter: ComposeFilter = ...,
    connect: bool = ...) -> MutableFst: ...
def disambiguate(ifst: Fst,
                 delta: float = ...,
                 nstate: _StateId = ...,
                 subsequential_label: _Label = ...,
                 weight: Optional[WeightLike] = ...) -> MutableFst: ...
def epsnormalize(ifst: Fst, eps_norm_type: EpsNormalizeType = ...) -> MutableFst: ...
def equal(ifst1: Fst, ifst2: Fst, delta: float = ...) -> bool: ...
def equivalent(ifst1: Fst, ifst2: Fst, delta: float = ...) -> bool: ...
def intersect(ifst1: Fst,
              ifst2: Fst,
              compose_filter: ComposeFilter = ...,
              connect: bool = ...) -> MutableFst: ...
def isomorphic(ifst1: Fst, ifst2: Fst, delta: float = ...) -> bool: ...
def prune(ifst: Fst,
          delta: float = ...,
          nstate: _StateId = ...,
          weight: Optional[WeightLike] = ...) -> MutableFst: ...
def push(ifst: Fst,
         delta: float = ...,
         push_weights: bool = ...,
         push_labels: bool = ...,
         remove_common_affix: bool = ...,
         remove_total_weight: bool = ...,
         reweight_type: ReweightType = ...) -> MutableFst: ...
def randequivalent(
    ifst1: Fst,
    ifst2: Fst,
    npath: int = ...,
    delta: float = ...,
    select: RandArcSelection = ...,
    max_length: int = ...,
    seed: int = ...) -> bool: ...
def randgen(
    ifst: Fst,
    npath: int = ...,
    select: RandArcSelection = ...,
    max_length: int = ...,
    weighted: bool = ...,
    remove_total_weight: bool = ...,
    seed: int = ...) -> MutableFst: ...
def replace(
    pairs: Iterable[Tuple[int, Fst]],
    call_arc_labeling: ReplaceLabelType = ...,
    return_arc_labeling: ReplaceLabelType = ...,
    epsilon_on_replace: bool = ...,
    return_label: _Label = ...) -> MutableFst: ...
def reverse(ifst: Fst, require_superinitial: bool = ...) -> MutableFst: ...
def shortestdistance(
    ifst: Fst,
    delta: float = ...,
    nstate: _StateId = ...,
    queue_type: QueueType = ...,
    reverse: bool = ...) -> List[Weight]: ...
def shortestpath(
    ifst: Fst,
    delta: float = ...,
    nshortest: int = ...,
    nstate: _StateId = ...,
    queue_type: QueueType = ...,
    unique: bool = ...,
    weight: Optional[WeightLike] = ...) -> MutableFst: ...
def statemap(ifst: Fst, map_type: StateMapType) -> Fst: ...
def synchronize(ifst: Fst) -> MutableFst: ...
## Compiler.

class Compiler:
  # NOTE: Though the actual function in cython is __cinit__, it's exposed to
  # python as __init__.
  def __init__(
      self,
      fst_type: _FstTypeFlag = ...,
      arc_type: _ArcTypeFlag = ...,
      # TODO(wolfsonkin): Look into converting these to SymbolTableView.
      isymbols: Optional[SymbolTable] = ...,
      osymbols: Optional[SymbolTable] = ...,
      ssymbols: Optional[SymbolTable] = ...,
      acceptor: bool = ...,
      keep_isymbols: bool = ...,
      keep_osymbols: bool = ...,
      keep_state_numbering: bool = ...,
      allow_negative_labels: bool = ...) -> None: ...
  def compile(self) -> Fst: ...
  def write(self, expression: str) -> None: ...

## FarReader and FarWriter.

class FarReader:
  def __init__(self) -> None: ...
  def __repr__(self) -> str: ...
  @classmethod
  def open(cls, *sources: _Filename) -> FarReader: ...
  def arc_type(self) -> _ArcTypeFlag: ...
  def done(self) -> bool: ...
  def error(self) -> bool: ...
  def far_type(self) -> FarType: ...
  def find(self, key: str) -> bool: ...
  def get_fst(self) -> Fst: ...
  def get_key(self) -> str: ...
  def next(self) -> None: ...
  def reset(self) -> None: ...
  def __getitem__(self, key: str) -> Fst: ...
  def __next__(self) -> Tuple[str, Fst]: ...
  def __iter__(self) -> FarReader: ...

class FarWriter:
  def __init__(self) -> None: ...
  def __repr__(self) -> str: ...
  @classmethod
  def create(cls,
             source: _Filename,
             arc_type: _ArcTypeFlag = ...,
             far_type: FarType = ...) -> FarWriter: ...
  def add(self, key: str, ifst: Fst) -> None: ...
  def arc_type(self) -> _ArcTypeFlag: ...
  def error(self) -> bool: ...
  def far_type(self) -> FarType: ...
  def __setitem__(self, key: str, fst: Fst) -> None: ...

