o
    }oio?                     @   sR  d dl Z d dlZd dlmZ d dlmZmZmZmZ d dl	Z	d dl
mZ d dlmZ de	jde	jfdd	Zd
e	jde	jfddZde	jdefddZde	jde	jdedede	jf
ddZdejdee	j fddZdeddfddZdSdd ZdSd!d"Z		dTd
ee	j d#e	jd$eeeeef eeeef f  d%ee de	jf
d&d'Zd(e	jd)e	jdd*fd+d,Zd-ed d.efd/d0ZdUd2d3ZdVd1dd5ed6efd7d8Zd1dde	jfd9d:Zd;e	jd<edee	je	jf fd=d>Z 	?		@dWdAe	jdBe	jdCedDedEee dFe!de	jfdGdHZ"dIe	jdJe	jdKe	jdee	je	jf fdLdMZ#dXdOddPe$ddfdQdRZ%dS )Y    N)UnpicklingError)ListOptionalTupleUnion)k2)logginginput_lengthsreturnc                 C   sZ   t t t| jd t | jd |  fdjt jd}|t j	|dddf dd S )zwCreates a special supervisions tensor from input lengths.
    These supervisions are required for some k2 methods.
    r      dtypeNT)
descending)
torchstacktensorrangeshapezeroscputoint32argsort)r	   supervisions r   W/home/ubuntu/.local/lib/python3.10/site-packages/nemo/collections/asr/parts/k2/utils.pycreate_supervision(   s   	r   indicesc                 C   sD   t j| j| j| jd}t jd| jd | j| jd|| jt jd< |S )zProduces a tensor of reverse permutation for a given indices.

    Based on https://github.com/k2-fsa/snowfall/blob/master/snowfall/common.py
    )devicer   r   r   )r   r   r   r   r   aranger   long)r   ansr   r   r   invert_permutation8   s   *r#   seq_lenc                 C   sT   | j d }tjd|| jd}|d||}|   |jd}||k }|S )z=Converts input_lengths to a non-padding mask. The mask is 2D.r   r   r   )	r   r   r    r   	unsqueezeexpandclonedetachr   )r	   r$   
batch_size	seq_rangeseq_range_expandseq_length_expandmaskr   r   r   make_non_pad_maskB   s   
r/   	lengths_x	lengths_ymax_length_xmax_length_yc                 C   s4   |   |  ks
J t| |dt||d@ S )zLConverts two orthogonal input_lengths to a non-padding mask. The mask is 3D.   r   )sizer/   r&   )r0   r1   r2   r3   r   r   r   make_non_pad_mask_3dL   s   r6   rtc                 C   s^   |   }g }|D ]}t|dkr|d qt|dkr$||d  q dS tj|tjdS )zWConverts k2.RaggedTensor to torch.Tensor if the RaggedTensor is shallow (has two axes).r   r   Nr   )tolistlenappendr   r   r   )r7   rt_listresult_lister   r   r   ragged_to_tensor_2axes_simpleV   s   r>   
graph_pathk2.Fsac           	      C   s4  t j| rg }ztj| dd}tj|}|W S  ty } zj|	| t
| ddd}| }W d   n1 s;w   Y  tjjdftjjdftjjdffD ]/\}}z|||d	}|W   W  Y d}~S  tttfy } z|	| W Y d}~qQd}~ww W Y d}~t|d}~ww td
|  d dS )zLFsa graph loading helper function. Loads graphs stored in different formats.r   )map_locationr7   zutf-8)encodingNFT)acceptorzNo such file: '')ospathexistsr   loadr   Fsa	from_dictr   r:   openreadfrom_openfstfrom_str	TypeError
ValueErrorRuntimeError	Exceptionr   warning)	r?   errors
graph_dictgraphr=   f	graph_txtfuncrC   r   r   r   
load_graphd   s2   

*
rZ   
base_graph	aux_graphc                 C   s\   t | dsJ t |drJ tt|| j}tjt| |dd}t|d|j |S )zIntersection helper function.
aux_labelsF)treat_epsilons_speciallyphones)	hasattrr   arc_sortadd_epsilon_self_loopsr   r   	intersectsetattrlabels)r[   r\   aux_graph_with_self_loopsresultr   r   r   intersect_with_self_loops}   s   rh   c                 C   s*   t t || j}t j| |dddS )zComposition helper function.Fr_   )r^   inner_labels)r   ra   rb   r   r   compose)r[   r\   rf   r   r   r   compose_with_self_loops   s   rk   valuesr5   min_col_indexc                    sZ  |du st | t |ksJ t | dkr"tj| d | d |||dS t | dkr| d j| d j  krA| d j  krAdksDJ  J | d  | d    krb| d    krb| kseJ  J |durt|tspJ | d |k  fdd	| D } |  }|durtjt	| |||j
|jd
S tjt	| ||j
|jdS tdt |  )zGWraps up k2.create_sparse to create 2- or 3-dimensional sparse tensors.Nr4   r   r   )rowscolsrl   r5   rm      r   c                    s   g | ]}|  qS r   r   ).0ikept_indicesr   r   
<listcomp>   s    z)create_sparse_wrapped.<locals>.<listcomp>)r5   r   requires_grad)r   rv   zlen(indices) = )r9   r   create_sparsendimnumel
isinstanceintr   sparse_coo_tensorr   r   rv   rP   )r   rl   r5   rm   r   rs   r   create_sparse_wrapped   s@   8Br}   log_softmaxr   zk2.DenseFsaVecc                 C   s   t j| t j| jd | jd dftd | jdgdd}t j|jd |jd d |jd f| jd}||dddddf< | }|dddf  d9  < t	||}|S )	zVPerforms special epsilon-padding required for composition with some of the topologies.r   r   infr%   r   )axisr4   N)
r   catfullr   floatr   r   r(   r   DenseFsaVec)r~   r   log_softmax_epslog_softmax_paddedsupervisions_paddeddense_log_softmax_paddedr   r   r   prep_padded_densefsavec   s,   r   latticesshiftc                 C   sT   | D ]#}|j dk}|j |  |7  < t|dr%|jdk}|j|  |7  < qt| S )zyShifts lattice labels and aux_labels by a given number.
    This is an in-place operation, if the lattice is on GPU.
    r   r]   )re   r`   r]   reset_properties_fsa)r   r   latticer.   r   r   r   shift_labels_inpl   s   


r   rV   c                 C   s(   d| j d< | jtdkrt| } | S )zResets properties of a graph.
    In-place (does not create a new graph) if the graph is on GPU.
    Use this every time you alter a graph in-place.
    See https://github.com/k2-fsa/k2/issues/978 for more information.N_propertiesr   )__dict__r   r   r   ra   )rV   r   r   r   r      s   

r   autolabelmodec                 C   sz   |dv sJ d|dkst | dsJ dtj| dd\}}|dkr)||j|dk< |d	kr9t | dr9||j|dk< t|S )
zAdds self-loops with given label to a graph.
    Supported modes are ``input``, ``output``, and ``auto``,
    Where ``input`` leaves aux_labels zeroes, if present, ``output`` leaves labels zeroes)inputoutputr   z?Supported modes are ``input``, ``output``, and ``auto``: {mode}r   r]   z.Graph must have aux_labels for mode ``output``Tret_arc_mapr   r   )r`   r   rb   re   r]   r   )rV   r   r   	new_grapharc_mapr   r   r   add_self_loops   s   r   c                 C   sd   t | jdkrtd| j dddf  }tdt | tjdt | g|R  }t	
|S )z:Returns 1d torch.Tensor with arc weights of a given graph.r4   z&FsaVec is not supported at the moment.Nr   z%sfz%si)r9   r   NotImplementedErrorarcsrl   r8   structunpackpackr   Tensor)rV   weights_intweights_floatr   r   r   get_arc_weights   s
   *
r   
tot_scores	reductionc                 C   sV   t |  t | td @ }|dkr| |  } | |fS |dkr'| |  } | |fS )a  Figures out the total score(log-prob) over all successful supervision segments
    (i.e. those for which the total score wasn't -infinity).
        Args:
            tot_scores: a Torch tensor of shape (num_segments,) containing total scores
                       from forward-backward
            reduction: a reduction type ('mean', 'sum' or 'none')
        Returns:
             Returns a tuple of 2 scalar tensors: (tot_score, finite_mask)
        where finite_mask is a tensor containing successful segment mask.

    Based on get_tot_objf_and_num_frames
    from https://github.com/k2-fsa/snowfall/blob/master/snowfall/objectives/common.py
    r   meansum)r   isnanner   r   r   )r   r   finite_maskr   r   r   get_tot_objf_and_finite_mask  s   r   r   Fencoded_lengthstarget_lengthswindow_size_with_blankstepmax_seq_len
begin_onlyc           
      C   sB  |dksJ |dksJ ||ksJ t | t |ksJ tjt | |du r)|  nt||  ftjd}||kjddd D ]N}| | }tt|| | | d | }	|| | d |	d< tjj	j
|	dddjtjd|d	d
jtjd||d|f< |||d f |||df< q?|r|S |ddd|t| S )aI  Creates the pruning ranges for the Encoder and Predictor of RNNT.
    The ranges are similar to https://k2-fsa.github.io/k2/python_api/api.html#k2.get_rnnt_prune_ranges
    but they are constructed under the assumption of the uniform distribution token activations across time frames
    and without any posterior knowledge.
    r   Nr   T)as_tupler   r4   r   znearest-exact)r   )r9   r   r   maxr!   nonzeror    r{   nn
functionalinterpolatereshaper   r   r&   repeat)
r   r   r   r   r   r   ranges_beginrr   encoded_lenranges_begin_rawr   r   r   get_uniform_rnnt_prune_ranges  s2   "r   encoder_outputsdecoder_outputsrangesc              	   C   s   |  \}}}|  d}|  \}}}	||  dksJ ||  dks%J || dks.J | d||||f}
tj|d||||	fd||||df||||	fd}|
|fS )ztPrepares pruned encoder and decoder outputs according to the prune ranges.
    Based on k2.do_rnnt_pruning(...)
    r   r   r   r4   )dimindex)r5   r&   r'   r   gatherr   )r   r   r   BTr   D1_UD2encoder_outputs_pruneddecoder_outputs_prunedr   r   r   apply_rnnt_prune_rangesD  s   
r   x&1fsains_del_scorec                    s  d}t dt d|d }| j }| jdk }tjt	|d t
d }| }d||d d	 < | }d
|d	dd< || }tt	|d| }	||	  t||d dddf< t	| jdkr| j d|	jtjd\}
}|
d|
d	 }t fddt|dd |d	d D }nt }|j |_|j }d||< ||_d|jd< tj|d
d\}}|j }|||dk< ||_d|jd< t|}|S )a  Construct the levenshtein graph from a k2-type WFST or a lattice.

    See also levenshtein_graph from k2.

    Args:
      fst:
        K2-type source WFST or lattice.

      ins_del_score:
        Insertion and deletion penalty.
        Should be more than 0.5 for substitutions to be preferred over insertions/deletions, or less otherwise.

    Returns:
      K2-type levenshtein WFST.
    g      z@iz@fr   r   r4   r   Fr   TNrp   c                    s"   g | ]\}}t  || qS r   )r   rI   )rq   rr   jnew_arcsr   r   ru   z  s   " z(levenshtein_graph_k2.<locals>.<listcomp>r   r   )r   r   r   r   rl   re   r   r   r   r9   boolr(   r    repeat_interleavewherer   r   r   r   
row_splitsr   create_fsa_vecziprI   r]   r   rb   scoresra   )r   r   	sub_scoresub_score_intr   final_indicestemplate_maskno_duplicate_final_masknew_maskduplicate_indices	new_shaper   
new_splitslevenshtein_fsare   r   r   r   r   r   levenshtein_graph_k2Y  s<   
 0





r   )r[   r@   r\   r@   r
   r@   )NN)rV   r@   )r   r   )r   NF)r   )&rE   r   pickler   typingr   r   r   r   r   nemo.core.utils.k2_guardr   
nemo.utilsr   r   r   r#   r{   r/   r6   RaggedTensorr>   strrZ   rh   rk   r}   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s   






	 
-
$	
'
