o
    Gicx                     @   sR  d dl mZ d dl mZ d dl mZ d dlZddlmZ ddlmZ ddl	m
Z
 d dlZd dlZd dlZdPd
ededefddZdPd
ededefddZd
edejfddZdQd
edee ddfddZdd Zeddddfdededed ed!ed"ed#edefd$d%Z		dRd&ejd'ejd(ejd)eeeef  d*ee f
d+d,Zd-ed.ejd/ejdefd0d1Z	dSd-ed.ejd/ejd2edef
d3d4Zd5ed6ed.ejd7ejd8ejdefd9d:Z		;	 	<dTd=ed>ed?ed@edef
dAdBZ		<		;	 	<dUdCedDed=ed>ed?ed@edefdEdFZ dGejdHejdIejdJedKedLedMedeejejejejf fdNdOZ!dS )V    )Optional)Tuple)UnionN   )Fsa)index_select)SymbolTableFfsaopenfstreturnc                 C   s   | j  dks	J g }g }t| jddD ]!\}}t|tjr+|jtjkr+|	| qt|t
jr6|	| qtj| j |||dS )a  Convert an Fsa to a string.  This version prints out all integer
    labels and integer ragged labels on the same line as each arc, the
    same format accepted by Fsa.from_str().

    Note:
      The returned string can be used to construct an Fsa with Fsa.from_str(),
      but you would need to know the names of the auxiliary labels and ragged
      labels.

    Args:
      openfst:
        Optional. If true, we negate the scores during the conversion.

    Returns:
      A string representation of the Fsa.
       Finclude_scores)r
   extra_labelsragged_labels)arcsnum_axessortednamed_tensor_attr
isinstancetorchTensordtypeint32appendk2RaggedTensor_k2
fsa_to_str)r	   r
   r   r   namevalue r!   </home/ubuntu/.local/lib/python3.10/site-packages/k2/utils.pyto_str    s   
r#   c                 C   sR   | j  dks	J t| drt| jtjr| jtjg}ng }t	
| j ||g S )a  Convert an Fsa to a string.  This is less complete than Fsa.to_str(),
    fsa.__str__(), or to_str_full(), meaning it prints only fsa.aux_labels and
    no ragged labels, not printing any other attributes.  This is used in
    testing.

    Note:
      The returned string can be used to construct an Fsa.  See also to_str().

    Args:
      openfst:
        Optional. If true, we negate the scores during the conversion.

    Returns:
      A string representation of the Fsa.
    r   
aux_labels)r   r   hasattrr   r$   r   r   tor   r   r   )r	   r
   r$   r!   r!   r"   to_str_simple@   s
   r'   c                 C   s   t | jS )a  Convert an Fsa to a Tensor.

    You can save the tensor to disk and read it later
    to construct an Fsa.

    Note:
      The returned Tensor contains only the transition rules, e.g.,
      arcs. You may want to save its aux_labels separately if any.

    Args:
      fsa:
        The input Fsa.
    Returns:
      A `torch.Tensor` of dtype `torch.int32`. It is a 2-D tensor
      if the input is a single FSA. It is a 1-D tensor if the input
      is a vector of FSAs.
    )r   fsa_to_tensorr   )r	   r!   r!   r"   	to_tensorX   s   r)   titleDigraphc              	   C   s^  zddl }W n ty   td  w t| jdksJ dt| dr)| j}d}nd}d}	d(dttj	t
jf d	td
tt dtfdd}ddddddd}|durU||d< dddd}dddd}d}	|j||d}
t }d}t| j ddddf | j D ]\}}|d7 }| \}}}t|}t|}t|}|dkr|}	||vr|
j|fd|i| || ||vr||	kr|
j|fd|i| n|
j|fd|i| || |durt| dr|||| j}n|||d}|dd }nd!}t| d"r|dkr| j|}|dkrd }|d#d$d%}|
j||| | d&| d' q|
S ))a  Visualize an Fsa via graphviz.

    Note:
      Graphviz is needed only when this function is called.

    Args:
      fsa:
        The input FSA to be visualized.

      title:
        Optional. The title of the resulting visualization.
    Returns:
      a Diagraph from grahpviz.
    r   NzAYou cannot use `to_dot` unless the graphviz package is installed.r   zFsaVec is not supportedr$   WFSTWFSA	arc_indexsymbolsr   c           	      S   s   t | tjrt| | }|dkr|dur|| }d| S t | tjs%J | jdks,J | jd	 }|| }||d  }||krDdS | j
|| }g }| D ]}|dkr]|d qQ|duri|||  qQ||  qQdd| S )	a  Convert aux_label(s) to symbol(s).

        Args:
          aux_labels:
            The aux_labels of an FSA.
          arc_index:
            The index of the arc.
          symbols:
            Symbol table of the FSA associated with the `aux_labels`.
        Returns:
          If `aux_labels` is a torch.Tensor, it returns a single string.
          If `aux_labels` is a ragged tensor, it returns a string with symbols
          separated by a space.
        N:r   r   z:<eps>z-1 )r   r   r   intr   r   r   shape
row_splitscpuvaluestolistr   join)	r$   r.   r/   ansr5   beginendlabelslabelr!   r!   r"   convert_aux_label_to_symbol   s*   
z+to_dot.<locals>.convert_aux_label_to_symbolLRz8.5,111Portraitz0.4z0.25)rankdirsizecenterorientationranksepnodesepr>   circlebold14)r4   stylefontsizedoublecircler0   )r   
graph_attrr   aux_labels_symz<eps>u   ε 
labels_symz.2f0./)r>   N)graphviz	Exceptionprintlenr4   r%   r$   r   r   r   r   r   r3   r   r   strr+   setzipr   r7   scoresr8   nodeaddrP   replacerR   getrstripedge)r	   r*   rW   r$   r   r?   rO   default_node_attrfinal_state_attrfinal_statedotseeniarcweight	src_state	dst_stater>   	aux_labelr!   r!   r"   to_dotm   s   

+.



 rp   c                    sZ  t  } D ]}t|jdksJ ||j qt|}t|}t fdd|	 D }|D ]7}g } D ]
}|t
|| q5t|d tjrNt|}nt|d tjsXJ tjj|dd}t||| q/t }	 D ]}| D ]	\}}
|	| qrql|	D ]+}|dkrq D ]!}t
||d}|durt||rt
|||ksJ qt||| qq|S )a_  Create an FsaVec from a list of FSAs

    We use the following rules to set the attributes of the output FsaVec:

    - For tensor attributes, we assume that all input FSAs have the same
      attribute name and the values are concatenated.

    - For non-tensor attributes, if any two of the input FSAs have the same
      attribute name, then we assume that their attribute values are equal and
      the output FSA will inherit the attribute.

    Args:
      fsas:
        A list of `Fsa`. Each element must be a single FSA.

    Returns:
      An instance of :class:`Fsa` that represents a FsaVec.
    r   c                 3   s"    | ]\}} D ]}|V  qqd S rV   r!   ).0r   _r	   fsasr!   r"   	<genexpr>  s    z!create_fsa_vec.<locals>.<genexpr>r   )axis
propertiesN)listrZ   r4   r   r   r   create_fsa_vecr   r\   r   getattrr   r   r   catr   r   raggedsetattrnamed_non_tensor_attrr`   r%   )rt   ragged_arc_listr	   ragged_arcsfsa_vectensor_attr_namesr   r7   r    non_tensor_attr_namesrr   r!   rs   r"   ry      sF   

ry   infTgư>d   ablog_semiringbeamtreat_epsilons_speciallydeltanpathc              	   C   s   t | j|j|||||S )a  Check if the Fsa `a` appears to be equivalent to `b` by
    randomly checking some symbol sequences in them.

    Caution:
      It works only on CPU.

    Args:
      a:
        One of the input FSA. It can be either a single FSA or an FsaVec.
        Must be top-sorted and on CPU.
      b:
        The other input FSA. It must have the same NumAxes() as a.
        Must be top-sorted and on CPU.
      log_semiring:
        The semiring to be used for all weight measurements;
        if false then we use 'max' on alternative paths; if
        true we use 'log-add'.
      beam:
         beam > 0 that affects pruning; the algorithm will only check
         paths within `beam` of the total score of the lattice (for
         tropical semiring, it's max weight over all paths from start
         state to final state; for log semiring, it's log-sum probs over
         all paths) in `a` or `b`.
      treat_epsilons_specially:
         We'll do `intersection` between generated path and a or b when
         check equivalence. Generally, if it's true, we will treat
         epsilons as epsilon when doing intersection; Otherwise, epsilons
         will just be treated as any other symbol.
      delta:
         Tolerance for path weights to check the equivalence.
         If abs(weights_a, weights_b) <= delta, we say the two
         paths are equivalent.
      npath:
         The number of paths will be generated to check the
         equivalence of `a` and `b`
    Returns:
       True if the Fsa `a` appears to be equivalent to `b` by randomly
       generating `npath` paths from one of them and then checking if the symbol
       sequence exists in the other one and if the total weight for that symbol
       sequence is the same in both FSAs.
    )r   is_rand_equivalentr   )r   r   r   r   r   r   r   r!   r!   r"   r   5  s   0r   rowscolsr7   rD   min_col_indexc                 C   s   | j |j   krdksJ  J |  |   kr!| ks$J  J |dur?t|ts/J ||k}| | } || }|| }|durTtjt| |g|||j|jdS tjt| |g||j|jdS )a1  This is a utility function that creates a (torch) sparse matrix likely
    intended to represent posteriors.  The likely usage is something like
    (for example)::

        post = k2.create_sparse(fsa.seqframe, fsa.phones,
                                fsa.get_arc_post(True,True).exp(),
                                min_col_index=1)

    (assuming `seqframe` and `phones` were integer-valued attributes of `fsa`).

    Args:
      rows:
        Row indexes of the sparse matrix (a torch.Tensor), which must have
        values >= 0; likely `fsa.seqframe`.   Must have row_indexes.dim == 1.
        Will be converted to `dtype=torch.long`
      cols:
        Column indexes of the sparse matrix, with the same shape as `rows`.
        Will be converted to `dtype=torch.long`
      values:
        Values of the sparse matrix, likely of dtype float or double, with
        the same shape as `rows` and `cols`.
      size:
        Optional. If not None, it is assumed to be a tuple containing
        `(num_frames, highest_phone_plus_one)`
      min_col_index:
        If provided, before the sparse tensor is constructed we will filter out
        elements with `cols[i] < min_col_index`.  Will likely be 0 or 1, if
        set.  This is necessary if `col_indexes` may have values less than 0,
        or if you want to filter out 0 values (e.g. as representing blanks).

    Returns:
      Returns a torch.Tensor that is sparse with coo (coordinate) format,
      i.e. `layout=torch.sparse_coo` (which is actually the only sparse format
      that torch currently supports).
    r   N)rD   devicerequires_grad)r   r   )	ndimnumelr   r3   r   sparse_coo_tensorstackr   r   )r   r   r7   rD   r   kept_indexesr!   r!   r"   create_sparsei  s(    ((r   src	dest_arcsarc_mapc           	      C   s   t |}| jddD ]?\}}t|tjr)t| |}t|||d}t||| q
t|t	j
s1J |jtjks9J |j|ddd\}}t||| q
|  D ]
\}}t||| qNt	j|| j| |S )a  Create an Fsa object, including autograd logic and propagating
    properties from the source FSA.

    This is intended to be called from unary functions on FSAs where the arc_map
    is a Tensor of int32 (i.e. not ragged).

    Args:
      src:
        The source Fsa, i.e. the arg to the unary function.
      dest_arcs:
        The raw output of the unary function, as output by whatever C++
        algorithm we used.
      arc_map:
        A map from arcs in `dest_arcs` to the corresponding arc-index in `src`,
        or -1 if the arc had no source arc (e.g. added epsilon self-loops).
    Returns:
      Returns the resulting Fsa, with properties propagated appropriately, and
      autograd handled.
    Fr   default_valuer   rv   need_value_indexes)r   r   r   r   r   float
get_fillerr   r}   r   r   r   r   indexr~   autograd_utilsphantom_index_select_scoresr^   )	r   r   r   destr   r    filler	new_valuerr   r!   r!   r"   fsa_from_unary_function_tensor  s"   
r   remove_fillerc           	   
   C   sn  t |}| jddD ]\}}|r`t|tjr`|jtjkr`| |}|dkrM| }t	tdr?||t
t| jdk|dk< n||t
| jdk|dk@ < tjj|||d}t|||| q
t|tjry|jtjtjfv sqJ tj||}nt|tjsJ |jtjksJ ||}||jd }t||| q
|  D ]
\}}t||| qtj|| j| |S )a  Create an Fsa object, including autograd logic and propagating
    properties from the source FSA.

    This is intended to be called from unary functions on FSAs where the arc_map
    is an instance of k2.RaggedTensor (with dtype torch.int32).

    Args:
      src:
        The source Fsa, i.e. the arg to the unary function.
      dest_arcs:
        The raw output of the unary function, as output by whatever C++
        algorithm we used.
      arc_map:
        A map from arcs in `dest_arcs` to the corresponding arc-index in `src`,
        or -1 if the arc had no source arc (e.g. :func:`remove_epsilon`).
      remove_filler:
        If true, for each attribute that is linear in `src` and ragged
        in the result, after turning it into a ragged tensor we will
        remove all items that are equal to the filler for that attribute
        (0 by default; see Fsa.get_filler()).  Attribute values on final-arcs
        that are equal to -1 will also be treated as fillers and removed,
        if remove_filler==True.
    Returns:
        Returns the resulting Fsa, with properties propagated appropriately, and
        autograd handled.
    Fr   r0   logical_andr   r   )r   r   r   r   r   r   r   r   cloner%   wherer   r=   r   r|   r   r}   remove_values_eqfloat32float64index_and_sumr   remove_axisr   r~   r   phantom_index_and_sum_scoresr^   )	r   r   r   r   r   r   r    r   r   r!   r!   r"   fsa_from_unary_function_ragged  s@   


r   a_fsab_fsa	a_arc_map	b_arc_mapc                 C   s  t |}|  D ]l\}}t| |}t||rF|jtjkr$td| t	||}	|	jtjks1J t
|||dt
|	||d }
t|||
 qt|tjrTt
|||d}
nt|tjs\J |jtjksdJ |j|ddd\}
}t|||
 q| D ]>\}}	t||st|	tjrt||}t
|	||d}
nt|	tjsJ |	jtjksJ |	j|ddd\}
}t|||
 qy|  D ]
\}}t||| q| D ]\}}	t||st|||	 q|S )aB  Create an Fsa object, including autograd logic and propagating
    properties from the source FSAs.

    This is intended to be called from binary functions on FSAs where the
    arc_map is a Tensor of int32 (i.e. not ragged).

    Caution: Only the attributes with dtype `torch.float32` will be merged,
             other kinds of attributes with the same name are discarded.

    Args:
      a_fsa:
        The source Fsa, i.e. the arg to the binary function.
      b_fsa:
        The other source Fsa.
      dest_arcs:
        The raw output of the binary function, as output by whatever C++
        algorithm we used.
      a_arc_map:
        A map from arcs in `dest_arcs` to the corresponding arc-index in `a_fsa`
        or -1 if the arc had no source arc (e.g. added epsilon self-loops).
      a_arc_map:
        A map from arcs in `dest_arcs` to the corresponding arc-index in `b_fsa`
        or -1 if the arc had no source arc (e.g. added epsilon self-loops).
    Returns:
      Returns the resulting Fsa, with properties propagated appropriately, and
      autograd handled.
    zjWe don't support propagating two attributes with the same name that are not real-valued, in intersection: r   r   Fr   )r   r   r   r   r%   r   r   r   AttributeErrorrz   r   r}   r   r   r   r   r   r   r~   )r   r   r   r   r   out_fsar   a_valuer   b_valuer    rr   r!   r!   r"   fsa_from_binary_function_tensor(  sV    





r   2     acyclic
max_symbolmin_num_arcsmax_num_arcsc                 C   s   t | |||}t|S )a  Generate a random Fsa.

    Args:
      acyclic:
        If true, generated Fsa will be acyclic.
      max_symbol:
        Maximum symbol on arcs. Generated arc symbols will be in range
        [-1,max_symbol], note -1 is kFinalSymbol; must be at least 0;
       min_num_arcs:
         Minimum number of arcs; must be at least 0.
       max_num_arcs:
         Maximum number of arcs; must be >= min_num_arcs.
    )r   
random_fsar   )r   r   r   r   random_arcsr!   r!   r"   r     s   
r   min_num_fsasmax_num_fsasc                 C   s   t | |||||}t|S )a  Generate a random FsaVec.

    Args:
      min_num_fsas:
        Minimum number of fsas we'll generated in the returned FsaVec;
        must be at least 1.
      max_num_fsas:
        Maximum number of fsas we'll generated in the returned FsaVec;
        must be >= min_num_fsas.
      acyclic:
        If true, generated Fsas will be acyclic.
      max_symbol:
        Maximum symbol on arcs. Generated arcs' symbols will be in range
        [-1,max_symbol], note -1 is kFinalSymbol; must be at least 0;
      min_num_arcs:
        Minimum number of arcs in each Fsa; must be at least 0.
      max_num_arcs:
        Maximum number of arcs in each Fsa; must be >= min_num_arcs.
    )r   random_fsa_vecr   )r   r   r   r   r   r   r   r!   r!   r"   r     s   
r   tokensr^   countseos	min_token	max_token	max_orderc              	   C   s   t | ||||||S )a	  For "query" sentences, this function gets the mean and variance of
    scores from the best matching words-in-context in a set of provided "key"
    sentences. This matching process matches the word and the words preceding
    it, looking for the highest-order match it can find (it's intended for
    approximating the scores of models that see only left-context,
    like language models). The intended application is in estimating the scores
    of hypothesized transcripts, when we have actually computed the scores for
    only a subset of the hypotheses.

    CAUTION:
      This function only runs on CPU for now.

    Args:
      tokens:
        A ragged tensor of int32_t with 2 or 3 axes. If 2 axes, this represents
        a collection of key and query sequences. If 3 axes, this represents a
        set of such collections.

          2-axis example::

            [ [ the, cat, said, eos ], [ the, cat, fed, eos ] ]

          3-axis example::

            [ [ [ the, cat, said, eos ], [ the, cat, fed, eos ] ],
              [ [ hi, my, name, is, eos ], [ bye, my, name, is, eos ] ], ... ]

        where the words would actually be represented as integers,
        The eos symbol is required if this code is to work as intended
        (otherwise this code will not be able to recognize when we have reached
        the beginnings of sentences when comparing histories).
        bos symbols are allowed but not required.

      scores:
        A one dim torch.tensor with scores.size() == tokens.NumElements(),
        this is the item for which we are requesting best-matching values
        (as means and variances in case there are multiple best matches).
        In our anticipated use, these would represent scores of words in the
        sentences, but they could represent anything.
      counts:
        An one dim torch.tensor with counts.size() == tokens.NumElements(),
        containing 1 for words that are considered "keys" and 0 for
        words that are considered "queries".  Typically some entire
        sentences will be keys and others will be queries.
      eos:
        The value of the eos (end of sentence) symbol; internally, this
        is used as an extra padding value before the first sentence in each
        collection, so that it can act like a "bos" symbol.
      min_token:
        The lowest possible token value, including the bos
        symbol (e.g., might be -1).
      max_token:
        The maximum possible token value.  Be careful not to
        set this too large the implementation contains a part which
        takes time and space O(max_token - min_token).
      max_order:
        The maximum n-gram order to ever return in the
        `ngram_order` output; the output will be the minimum of max_order
        and the actual order matched; or max_order if we matched all the
        way to the beginning of both sentences. The main reason this is
        needed is that we need a finite number to return at the
        beginning of sentences.

    Returns:
      Returns a tuple of four torch.tensor (mean, var, counts_out, ngram_order)
        mean:
          For query positions, will contain the mean of the scores at the
          best matching key positions, or zero if that is undefined because
          there are no key positions at all.  For key positions,
          you can treat the output as being undefined (actually they
          are treated the same as queries, but won't match with only
          themselves because we don't match at singleton intervals).
        var:
          Like `mean`, but contains the (centered) variance
          of the best matching positions.
        counts_out:
          The number of key positions that contributed to the `mean`
          and `var` statistics.  This should only be zero if `counts`
          was all zero.
        ngram_order:
          The n-gram order corresponding to the best matching
          positions found at each query position, up to a maximum of
          `max_order`; will be `max_order` if we matched all
          the way to the beginning of a sentence.
    )r   get_best_matching_stats)r   r^   r   r   r   r   r   r!   r!   r"   r     s   Yr   )FrV   )NN)T)Tr   r   r   )r   r   Tr   r   r   )"typingr   r   r   r   r	   r   opsr   symbol_tabler   r   	k2.raggedr   boolr[   r#   r'   r   r)   rp   ry   r   r3   r   r   	RaggedArcr   r   r   r   r   r   r   r!   r!   r!   r"   <module>   s     >
7

>
/

U
\

