o
    %ݫiA                    @   s&  d Z ddlZddlZddlZddlZddlmZ ddlmZm	Z	m
Z
mZmZmZ ddlZddlZddlmZ ddlmZ eeZG dd dZdd
dZdddZejG dd dZejG dd deZejG dd dZG dd dejjZ G dd de Z!G dd de Z"G dd dZ#dS )zDecoders and output normalization for CTC.

Authors
 * Mirco Ravanelli 2020
 * Aku Rouhe 2020
 * Sung-Lin Yeh 2020
 * Adel Moumen 2023, 2024
    N)groupby)AnyDictListOptionalTupleUnion)length_to_mask)
get_loggerc                   @   s4   e Zd ZdZd
ddZe dddZdd	 ZdS )CTCPrefixScorea  This class implements the CTC prefix score of Algorithm 2 in
    reference: https://www.merl.com/publications/docs/TR2017-190.pdf.
    Official implementation: https://github.com/espnet/espnet/blob/master/espnet/nets/ctc_prefix_score.py

    Arguments
    ---------
    x : torch.Tensor
        The encoder states.
    enc_lens : torch.Tensor
        The actual length of each enc_states sequence.
    blank_index : int
        The index of the blank token.
    eos_index : int
        The index of the end-of-sequence (eos) token.
    ctc_window_size: int
        Compute the ctc scores over the time frames using windowing based on attention peaks.
        If 0, no windowing applied.
    r   c           	      C   s.  || _ || _|d| _|d| _|d| _|j| _d| _|d | _|| _	d| _
dt| }|ddd|dd}||| j |d d d d df |d d d d df d|d d d d df< |dd}|d d d d | j f ddd| j}t||g| _tj| j| jd| _d S )Nr      g@x   device)blank_index	eos_indexsize
batch_sizemax_enc_len
vocab_sizer   	minus_inflast_frame_indexctc_window_sizeprefix_lengthr	   	unsqueezeexpandeqmasked_fill_	transposetorchstackxarangebatch_index)	selfr"   enc_lensr   r   r   maskxnbxb r*   L/home/ubuntu/.local/lib/python3.10/site-packages/speechbrain/decoders/ctc.py__init__.   s*   
 BzCTCPrefixScore.__init__Nc           "      C   s  | d}|| j }|}|  jd7  _|du r| jn| d| _|du rctj| jd| j|f| j| j	d}t
| jddddd| jf dd|dddf< |dd|}tj|| jfd| j	d}	n|\}}	|dur| j| j }
tj|| jfdtj| j	d}tj|| j	dd}tj| j| j	d|||f< ||
dd|dd d}t| jdd| j| j d|dd|| j}nd}| jd	ddd|ddd|| j}tj| jd|| jf| j| j	d}|| j | jdkr|d
 |d
< t|d}|ddd| j}|dur5t|D ] }|||| f }|dkr2|ddd|f |dd||f< qnt|D ]}|ddd|f |dd||| f< q9| jdksZ|du rdtd| j}| j}n0tj|dd\}}t| | j }t| | j }ttd| jt|}t| jt|}t||D ]7}||d df }||d df }t|||d  ||gdd|| j}t|d|dd|f  ||< q||d df d}tj|d d|dd fdd|d  }|dur)tj|| jf| j| j	d} tjtj||| |fdddd}!t|D ]}|!| | ||| f< qntjtj||| |fdddd} t|D ]}|| j||  |f | || jf< q?| j| jkrd| j| dd| jf< | |	 || |ffS )a  This method if one step of forwarding operation
        for the prefix ctc scorer.

        Arguments
        ---------
        inp_tokens : torch.Tensor
            The last chars of prefix label sequences g, where h = g + c.
        states : tuple
            Previous ctc states.
        candidates : torch.Tensor
            (batch_size * beam_size, ctc_beam_size), The topk candidates for rescoring.
            If given, performing partial ctc scoring.
        attn : torch.Tensor
            (batch_size * beam_size, max_enc_len), The attention weights.

        Returns
        -------
        new_psi : torch.Tensor
        (r, psi, scoring_table) : tuple
        r   r   Nr   r   r           )dtyper      )r   r   dim) r   r   r   r   num_candidatesr    fullr   r   r   cumsumr"   r   r   viewr$   longr#   repeatindex_selectfill_	logsumexpranger   maxitemminintr!   catr   r   )"r%   
inp_tokensstates
candidatesattnn_bh	beam_size	last_charr_prevpsi_prevcand_offsetscoring_table	col_indexscoring_index	x_inflaterr_sumphiiposstartend_	attn_peak	max_frame	min_frametrnb_prevrb_prevr_psi_initphixpsipsi_r*   r*   r+   forward_stepN   s   





 (
$,
zCTCPrefixScore.forward_stepc                 C   s  |\}}}| d}| j| }| j| }||d|| j  |}	tj|dd|	d}|dd	d| j|| j}tj
|| jdd|d| |}
|durr|| j d}||
|f }d||dk< ||
| j  }	tj|dd|| j d|	d}|dd|}||fS )	a~  This method permutes the CTC model memory
        to synchronize the memory index with the current output.

        Arguments
        ---------
        memory : No limit
            The memory variable to be permuted.
        index : torch.Tensor
            The index of the previous path.

        Return
        ------
        The variable of the memory being permuted.

        r   r   r   )r1   indexfloor)rounding_modeNr   )r   r   r$   r   	expand_asr   r5   r    r8   r7   divr2   )r%   memoryrc   rO   r`   rK   rF   rE   beam_offset
cand_index	hyp_indexselected_vocabscore_indexr*   r*   r+   permute_mem   s6   






zCTCPrefixScore.permute_memr   NN)	__name__
__module____qualname____doc__r,   r    no_gradrb   rn   r*   r*   r*   r+   r      s    
  %r   r   c                    s>   t | trdd t| D }tt fdd|}|S td)ac  Apply CTC output merge and filter rules.

    Removes the blank symbol and output repetitions.

    Arguments
    ---------
    string_pred : list
        A list containing the output strings/ints predicted by the CTC system.
    blank_id : int, string
        The id of the blank.

    Returns
    -------
    list
        The output predicted by CTC without the blank symbol and
        the repetitions.

    Example
    -------
    >>> string_pred = ['a','a','blank','b','b','blank','c']
    >>> string_out = filter_ctc_output(string_pred, blank_id='blank')
    >>> print(string_out)
    ['a', 'b', 'c']
    c                 S   s   g | ]}|d  qS ro   r*   ).0rR   r*   r*   r+   
<listcomp>F  s    z%filter_ctc_output.<locals>.<listcomp>c                    s   |  kS Nr*   )elemblank_idr*   r+   <lambda>I  s    z#filter_ctc_output.<locals>.<lambda>z+filter_ctc_out can only filter python lists)
isinstancelistr   filter
ValueError)string_predr{   
string_outr*   rz   r+   filter_ctc_output*  s
   
r   c                 C   s   t |tr|dk r| jd | }| jd }g }t| |D ](\}}tt|| }tj|dd|dd\}}	t|		 |d}
|
|
 q|S )aY  Greedy decode a batch of probabilities and apply CTC rules.

    Arguments
    ---------
    probabilities : torch.tensor
        Output probabilities (or log-probabilities) from the network with shape
        [batch, lengths, probabilities]
    seq_lens : torch.tensor
        Relative true sequence lengths (to deal with padded inputs),
        the longest sequence has length 1.0, others a value between zero and one
        shape [batch, lengths].
    blank_id : int, string
        The blank symbol/index. Default: -1. If a negative number is given,
        it is assumed to mean counting down from the maximum possible index,
        so that -1 refers to the maximum possible index.

    Returns
    -------
    list
        Outputs as Python list of lists, with "ragged" dimensions; padding
        has been removed.

    Example
    -------
    >>> import torch
    >>> probs = torch.tensor([[[0.3, 0.7], [0.0, 0.0]],
    ...                       [[0.2, 0.8], [0.9, 0.1]]])
    >>> lens = torch.tensor([0.51, 1.0])
    >>> blank_id = 0
    >>> ctc_greedy_decode(probs, lens, blank_id)
    [[1], [1]]
    r   r   r   r0   rz   )r}   r?   shapezipr    roundr<   narrowr   tolistappend)probabilitiesseq_lensr{   batch_max_lenbatch_outputsseqseq_lenactual_sizescorespredictionsoutr*   r*   r+   ctc_greedy_decodeO  s   !
r   c                   @   s   e Zd ZU dZeed< eed< eed< eed< ee ed< ee ed< ee	eef  ed< e	eef ed	< e
j Zeed
< e
j Zeed< e
j Zeed< e
j Zeed< e
j Zeed< e
j Zeed< e
j Zeed< edddZdddZdS )CTCBeamal  This class handle the CTC beam information during decoding.

    Arguments
    ---------
    text : str
        The current text of the beam.
    full_text : str
        The full text of the beam.
    next_word : str
        The next word to be added to the beam.
    partial_word : str
        The partial word being added to the beam.
    last_token : str, optional
        The last token of the beam.
    last_token_index : int, optional
        The index of the last token of the beam.
    text_frames : List[Tuple[int, int]]
        The start and end frame of the text.
    partial_frames : Tuple[int, int]
        The start and end frame of the partial word.
    p : float
        The probability of the beam.
    p_b : float
        The probability of the beam ending in a blank.
    p_nb : float
        The probability of the beam not ending in a blank.
    n_p_b : float
        The previous probability of the beam ending in a blank.
    n_p_nb : float
        The previous probability of the beam not ending in a blank.
    score : float
        The score of the beam (LM + CTC)
    score_ctc : float
        The CTC score computed.

    Example
    -------
    >>> beam = CTCBeam(
    ...     text="",
    ...     full_text="",
    ...     next_word="",
    ...     partial_word="",
    ...     last_token=None,
    ...     last_token_index=None,
    ...     text_frames=[(0, 0)],
    ...     partial_frames=(0, 0),
    ...     p=-math.inf,
    ...     p_b=-math.inf,
    ...     p_nb=-math.inf,
    ...     n_p_b=-math.inf,
    ...     n_p_nb=-math.inf,
    ...     score=-math.inf,
    ...     score_ctc=-math.inf,
    ... )
    text	full_text	next_wordpartial_word
last_tokenlast_token_indextext_framespartial_framespp_bp_nbn_p_bn_p_nbscore	score_ctclm_beam	LMCTCBeamreturnc                 C   sD   t |j|j|j|j|j|j|j|j|j	|j
|j|j|j|j|jdS )zCreate a CTCBeam from a LMCTCBeam

        Arguments
        ---------
        lm_beam : LMCTCBeam
            The LMCTCBeam to convert.

        Returns
        -------
        CTCBeam
            The CTCBeam converted.
        )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r%   r   r*   r*   r+   from_lm_beam  s"   zCTCBeam.from_lm_beamNc                 C   s@   | j | j| _| _tj  | _ | _t| j| j| _| j| _	dS )zUpdate the beam probabilities.N)
r   r   r   r   mathinfnp	logaddexpr   r   r%   r*   r*   r+   step  s   zCTCBeam.step)r   r   r   r   )r   N)rq   rr   rs   rt   str__annotations__r   r?   r   r   r   r   r   floatr   r   r   r   r   r   classmethodr   r   r*   r*   r*   r+   r   |  s(   
 8r   c                   @   s"   e Zd ZU dZej Zeed< dS )r   zThis class handle the LM scores during decoding.

    Arguments
    ---------
    lm_score: float
        The LM score of the beam.
    **kwargs
        See CTCBeam for the other arguments.
    lm_scoreN)	rq   rr   rs   rt   r   r   r   r   r   r*   r*   r*   r+   r     s   
 
r   c                   @   s>   e Zd ZU dZeed< ded< eed< eed< dZeed< dS )CTCHypothesisad  This class is a data handler over the generated hypotheses.

    This class is the default output of the CTC beam searchers.

    It can be re-used for other decoders if using
    the beam searchers in an online fashion.

    Arguments
    ---------
    text : str
        The text of the hypothesis.
    last_lm_state : None
        The last LM state of the hypothesis.
    score : float
        The score of the hypothesis.
    lm_score : float
        The LM score of the hypothesis.
    text_frames : List[Tuple[str, Tuple[int, int]]], optional
        The list of the text and the corresponding frames.
    r   Nlast_lm_stater   r   r   )	rq   rr   rs   rt   r   r   r   r   r~   r*   r*   r*   r+   r     s   
 r   c                !       s$  e Zd ZdZ													
		dDdedee dededef dedee f dededede	dededede	dedef dedef  fddZ
	dEd ejd!ee d"ed#ed$ef
d%d&Zd'ed(efd)d*Zd+ed,ed(efd-d.Zd!ee d(ee fd/d0Zd!ee d(ee fd1d2Zd!ee d3ed(ee fd4d5Z	6	6dFd!ee d"ed#ed(ee fd7d8Z		dGd ejd9eej d:ed(eee  fd;d<Z		dGd ejd9eej d:ed(eee  fd=d>Z	6	6dFd ejd"ed#ed!ee d$ed(ee fd?d@Z	dHd ejdAed:ee d(ee fdBdCZ  ZS )ICTCBaseSearcherur  CTCBaseSearcher class to be inherited by other
    CTC beam searchers.

    This class provides the basic functionalities for
    CTC beam search decoding.

    The space_token is required with a non-sentencepiece vocabulary list
    if your transcription is expecting to contain spaces.

    Arguments
    ---------
    blank_index : int
        The index of the blank token.
    vocab_list : list
        The list of the vocabulary tokens.
    space_token : int, optional
        The index of the space token. (default: -1)
    kenlm_model_path : str, optional
        The path to the kenlm model. Use .bin for a faster loading.
        If None, no language model will be used. (default: None)
    unigrams : list, optional
        The list of known word unigrams. (default: None)
    alpha : float
        Weight for language model during shallow fusion. (default: 0.5)
    beta : float
        Weight for length score adjustment of during scoring. (default: 1.5)
    unk_score_offset : float
        Amount of log score offset for unknown tokens. (default: -10.0)
    score_boundary : bool
        Whether to have kenlm respect boundaries when scoring. (default: True)
    beam_size : int, optional
        The width of the beam. (default: 100)
    beam_prune_logp : float, optional
        The pruning threshold for the beam. (default: -10.0)
    token_prune_min_logp : float, optional
        The pruning threshold for the tokens. (default: -5.0)
    prune_history : bool, optional
        Whether to prune the history. (default: True)
        Note: when using topk > 1, this should be set to False as
        it is pruning a lot of beams.
    blank_skip_threshold : float, optional
        Skip frames if log_prob(blank) > log(blank_skip_threshold), to speed up decoding.
        Note: This is only used when using the CUDA decoder, and it might worsen the WER/CER results. Use it at your own risk. (default: 1.0)
    topk : int, optional
        The number of top hypotheses to return. (default: 1)
    spm_token: str, optional
        The sentencepiece token. (default: "▁")

    Example
    -------
    >>> blank_index = 0
    >>> vocab_list = ['blank', 'a', 'b', 'c', ' ']
    >>> space_token = ' '
    >>> kenlm_model_path = None
    >>> unigrams = None
    >>> beam_size = 100
    >>> beam_prune_logp = -10.0
    >>> token_prune_min_logp = -5.0
    >>> prune_history = True
    >>> blank_skip_threshold = 1.0
    >>> topk = 1
    >>> searcher = CTCBaseSearcher(
    ...     blank_index=blank_index,
    ...     vocab_list=vocab_list,
    ...     space_token=space_token,
    ...     kenlm_model_path=kenlm_model_path,
    ...     unigrams=unigrams,
    ...     beam_size=beam_size,
    ...     beam_prune_logp=beam_prune_logp,
    ...     token_prune_min_logp=token_prune_min_logp,
    ...     prune_history=prune_history,
    ...     blank_skip_threshold=blank_skip_threshold,
    ...     topk=topk,
    ... )
     N      ?      ?      $Td               ?r      ▁r   
vocab_listspace_tokenkenlm_model_pathunigramsalphabetaunk_score_offsetscore_boundaryrF   beam_prune_logptoken_prune_min_logpprune_historyblank_skip_thresholdtopk	spm_tokenc                    s  t    | _| _| _| _| _| _| _| _	|	 _
|
 _| _| _| _t| _| _| _t fdd|D  _ jsoz|| _W n tyd   td| d d _Y nw td j d d  _|d urzdd l}dd	lm}m } W n t!y   t!d
w |"| _|d ur|#drtd |d u r|d ur|#dr||}ntd  jd ur| j| j j j	 j
d _$d S d  _$d S )Nc                    s   g | ]
}t | jqS r*   )r   
startswithr   )rv   sr   r*   r+   rw     s    z,CTCBaseSearcher.__init__.<locals>.<listcomp>zspace_token `z` not found in the vocabulary.Using value -1 as `space_index`.Note: If your transcription is not expected to contain spaces, you can ignore this warning.r   zFound `space_token` at index .r   )LanguageModelload_unigram_set_from_arpazwkenlm python bindings are not installed. To install it use: pip install https://github.com/kpu/kenlm/archive/master.zipz.arpazJUsing arpa instead of binary LM file, decoder instantiation might be slow.zUnigrams not provided and cannot be automatically determined from LM file (only arpa format). Decoding accuracy might be reduced.)kenlm_modelr   r   r   r   r   )%superr,   r   r   r   r   r   r   r   r   r   rF   r   r   r   r   logr   r   r   anyis_spmrc   space_indexr   loggerwarninginfor   kenlm#speechbrain.decoders.language_modelr   r   ImportErrorModelendswithlm)r%   r   r   r   r   r   r   r   r   r   rF   r   r   r   r   r   r   r   r   r   	__class__r   r+   r,   h  sz   






	zCTCBaseSearcher.__init__r   	log_probsbeamscached_lm_scorescached_p_lm_scoresprocessed_framesc                 C   s   t )a  Perform a single step of decoding.

        Arguments
        ---------
        log_probs : torch.Tensor
            The log probabilities of the CTC output.
        beams : list
            The list of the beams.
        cached_lm_scores : dict
            The cached language model scores.
        cached_p_lm_scores : dict
            The cached prefix language model scores.
        processed_frames : int, default: 0
            The start frame of the current decoding step.
        )NotImplementedError)r%   r   r   r   r   r   r*   r*   r+   partial_decoding  s   z CTCBaseSearcher.partial_decodingr   r   c                 C   s   d | S )zEfficiently normalize whitespace.

        Arguments
        ---------
        text : str
            The text to normalize.

        Returns
        -------
        str
            The normalized text.
        r   )joinsplit)r%   r   r*   r*   r+   normalize_whitespace  s   z$CTCBaseSearcher.normalize_whitespacetoken_1token_2c                 C   s8   t |dkr
|}|S t |dkr|}|S |d | }|S )aO  Merge two tokens, and avoid empty ones.

        Taken from: https://github.com/kensho-technologies/pyctcdecode

        Arguments
        ---------
        token_1 : str
            The first token.
        token_2 : str
            The second token.

        Returns
        -------
        str
            The merged token.
        r   r   )len)r%   r   r   r   r*   r*   r+   merge_tokens  s   zCTCBaseSearcher.merge_tokensc                 C   sl   i }|D ]+}|  |j|j}||j|jf}||vr|||< qtj|t|| j	|j	d||< qt
| S )a#  Merge beams with the same text.

        Taken from: https://github.com/kensho-technologies/pyctcdecode

        Arguments
        ---------
        beams : list
            The list of the beams.

        Returns
        -------
        list
            The list of CTCBeam merged.
        r   )r   r   r   r   r   dataclassesreplacer   r   r   r~   values)r%   r   	beam_dictbeamnew_texthash_idxr*   r*   r+   merge_beams  s   
zCTCBaseSearcher.merge_beamsc                 C   s   t j| j|dd dS )zSort beams by lm_score.

        Arguments
        ---------
        beams : list
            The list of CTCBeam.

        Returns
        -------
        list
            The list of CTCBeam sorted.
        c                 S   s   | j S rx   r   )r"   r*   r*   r+   r|   7  s    z,CTCBaseSearcher.sort_beams.<locals>.<lambda>)key)heapqnlargestrF   )r%   r   r*   r*   r+   
sort_beams*  s   zCTCBaseSearcher.sort_beamslm_orderc                 C   sj   t d|d }t }g }|D ]$}t|j | d |j|jf}||vr2|t	| |
| q|S )a5  Filter out beams that are the same over max_ngram history.

        Since n-gram language models have a finite history when scoring a new token, we can use that
        fact to prune beams that only differ early on (more than n tokens in the past) and keep only the
        higher scoring ones. Note that this helps speed up the decoding process but comes at the cost of
        some amount of beam diversity. If more than the top beam is used in the output it should
        potentially be disabled.

        Taken from: https://github.com/kensho-technologies/pyctcdecode

        Arguments
        ---------
        beams : list
            The list of the beams.
        lm_order : int
            The order of the language model.

        Returns
        -------
        list
            The list of CTCBeam.
        r   N)r<   settupler   r   r   r   r   r   r   add)r%   r   r   min_n_historyseen_hashesfiltered_beamsr   r   r*   r*   r+   _prune_history9  s   
zCTCBaseSearcher._prune_historyFc                    s   |s|r4g }|D ]%}|j dkr|jn|j|jg }|t|j|j|j ddd|d|jd	 q|}nt	|}
|||}	tdd |	D   fdd|	D }	|	}
|
S )ae  Finalize the decoding process by adding and scoring the last partial word.

        Arguments
        ---------
        beams : list
            The list of CTCBeam.
        cached_lm_scores : dict
            The cached language model scores.
        cached_p_lm_scores : dict
            The cached prefix language model scores.
        force_next_word : bool, default: False
            Whether to force the next word.
        is_end : bool, default: False
            Whether the end of the sequence has been reached.

        Returns
        -------
        list
            The list of the CTCBeam.
         Nr   r   	r   r   r   r   r   r   r   r   r   c                 S      g | ]}|j qS r*   r   rv   br*   r*   r+   rw         z5CTCBaseSearcher.finalize_decoding.<locals>.<listcomp>c                        g | ]}|j  j kr|qS r*   r   r   r  	max_scorer%   r*   r+   rw     
    )r   r   r   r   r   r   r   r   r   r~   get_lm_beamsr<   r   )r%   r   r   r   force_next_wordis_end	new_beamsr   new_token_timesscored_beamssorted_beamsr*   r  r+   finalize_decodingc  s>   

z!CTCBaseSearcher.finalize_decodingwav_lenslm_start_statec                    s   | dtjkrtd| d dtj d |dur1| d| }|  t}n| dg| d }|  } fdd	t	||D }|S )
a}  Decodes the input log probabilities of the CTC output.

        It automatically converts the SpeechBrain's relative length of the wav input
        to the absolute length.

        Make sure that the input are in the log domain. The decoder will fail to decode
        logits or probabilities. The input should be the log probabilities of the CTC output.

        Arguments
        ---------
        log_probs : torch.Tensor
            The log probabilities of the CTC output.
            The expected shape is [batch_size, seq_length, vocab_size].
        wav_lens : torch.Tensor, optional (default: None)
            The SpeechBrain's relative length of the wav input.
        lm_start_state : Any, optional (default: None)
            The start state of the language model.

        Returns
        -------
        list of list
            The list of topk list of CTCHypothesis.
        r   z,Vocab size mismatch: log_probs vocab dim is z while vocab_list is zQ. During decoding, going to truncate the log_probs vocab dim to match vocab_list.Nr   r   c                    s   g | ]\}} || qS r*   )decode_log_probs)rv   log_probwav_lenr  r%   r*   r+   rw     s    z0CTCBaseSearcher.decode_beams.<locals>.<listcomp>)
r   r   r   warningswarncpunumpyastyper?   r   )r%   r   r  r  hypsr*   r   r+   decode_beams  s   zCTCBaseSearcher.decode_beamsc                 C   s   |  |||S )a  Decodes the log probabilities of the CTC output.

        It automatically converts the SpeechBrain's relative length of the wav input
        to the absolute length.

        Each tensors is converted to numpy and CPU as it is faster and consumes less memory.

        Arguments
        ---------
        log_probs : torch.Tensor
            The log probabilities of the CTC output.
            The expected shape is [batch_size, seq_length, vocab_size].
        wav_lens : torch.Tensor, optional (default: None)
            The SpeechBrain's relative length of the wav input.
        lm_start_state : Any, optional (default: None)
            The start state of the language model.

        Returns
        -------
        list of list
            The list of topk list of CTCHypothesis.
        r'  )r%   r   r  r  r*   r*   r+   __call__  s   zCTCBaseSearcher.__call__c           	      C   s,   | j |||||d}| j|||||d}|S )a   Perform a single step of decoding.

        Arguments
        ---------
        log_probs : torch.Tensor
            The log probabilities of the CTC output.
        cached_lm_scores : dict
            The cached language model scores.
        cached_p_lm_scores : dict
            The cached prefix language model scores.
        beams : list
            The list of the beams.
        processed_frames : int
            The start frame of the current decoding step.
        force_next_word : bool, optional (default: False)
            Whether to force the next word.
        is_end : bool, optional (default: False)
            Whether the end of the sequence has been reached.

        Returns
        -------
        list
            The list of CTCBeam.
        )r   r  r  )r   r  )	r%   r   r   r   r   r   r  r  trimmed_beamsr*   r*   r+   partial_decode_beams  s   "z$CTCBaseSearcher.partial_decode_beamsr  c           
         s   j }|du r
i  n|du r| }n|}dd|fi i }tddddddg dddddg}||| |}j| |ddd} fd	d
|D dj }	|	S )a  Decodes the log probabilities of the CTC output.

        Arguments
        ---------
        log_probs : torch.Tensor
            The log probabilities of the CTC output.
            The expected shape is [seq_length, vocab_size].
        wav_len : int
            The length of the wav input.
        lm_start_state : Any, optional (default: None)
            The start state of the language model.

        Returns
        -------
        list
            The topk list of CTCHypothesis.
        N)r  Fr-   r  r  r   r   r   r   r   r   r   r   r   r   r   Tr*  c              	      s\   g | ]*}t |j|jd f v r |jd f d ndtt|j |j|j|jdqS )Tr   N)r   r   r   r   r   )	r   r   r   r~   r   r   r   r   r   )rv   r   r   r%   r*   r+   rw   o  s    
z4CTCBaseSearcher.decode_log_probs.<locals>.<listcomp>)r   get_start_stater   r   r  r   )
r%   r   r  r  language_modelstart_stater   r   r+  output_beamsr*   r.  r+   r  -  sL   

	z CTCBaseSearcher.decode_log_probs)r   NNr   r   r   Tr   r   r   Tr   r   r   ro   )FFrp   rx   )rq   rr   rs   rt   r?   r   r   r   r   boolr,   r    Tensorr   dictr   r   r   r   r   r  r  r   r   r   r'  r)  r,  r  __classcell__r*   r*   r   r+   r     s   P
	

j

/
G

7

%	
8r   c                   @   sj   e Zd ZdZ	ddee dededee fddZ		dd
e	j
dedee dedededee fddZdS )CTCBeamSearcheras  CTC Beam Search is a Beam Search for CTC which does not keep track of
    the blank and non-blank probabilities. Each new token probability is
    added to the general score, and each beams that share the same text are
    merged together.

    The implementation supports n-gram scoring on words and SentencePiece tokens. The input
    is expected to be a log-probabilities tensor of shape [batch, time, vocab_size].

    The main advantage of this CTCBeamSearcher over the CTCPrefixBeamSearcher is that it is
    relatively faster, and obtains slightly better results. However, the implementation is
    based on the one from the PyCTCDecode toolkit, adapted for the SpeechBrain's needs and does
    not follow a specific paper. We do recommend to use the CTCPrefixBeamSearcher if you want
    to cite the appropriate paper for the decoding method.

    Several heuristics are implemented to speed up the decoding process:
    - pruning of the beam : the beams are pruned if their score is lower than
        the best beam score minus the beam_prune_logp
    - pruning of the tokens : the tokens are pruned if their score is lower than
        the token_prune_min_logp
    - pruning of the history : the beams are pruned if they are the same over
        max_ngram history
    - skipping of the blank : the frame is skipped if the blank probability is
        higher than the blank_skip_threshold

    Note: if the Acoustic Model is not trained, the Beam Search will
    take a lot of time. We do recommend to use Greedy Search during validation
    until the model is fully trained and ready to be evaluated on test sets.

    Arguments
    ---------
    see CTCBaseSearcher, arguments are directly passed.

    Example
    -------
    >>> import torch
    >>> from speechbrain.decoders import CTCBeamSearcher
    >>> probs = torch.tensor([[[0.2, 0.0, 0.8],
    ...                   [0.4, 0.0, 0.6]]])
    >>> log_probs = torch.log(probs)
    >>> lens = torch.tensor([1.0])
    >>> blank_index = 2
    >>> vocab_list = ['a', 'b', '-']
    >>> searcher = CTCBeamSearcher(blank_index=blank_index, vocab_list=vocab_list)
    >>> hyps = searcher(probs, lens)
    Fr   r   cached_partial_token_scoresr   c                 C   sD  | j du r/g }|D ]#}| |j|j}|t||jd|j|j|j|j	|j
|j|jd
 q	|S g }|D ]l}| |j|j}||f}||vrd||jdf \}	}
| j j|
|j|d\}}|	| }||f||< || \}}|j}t|dkr||vr| j |||< ||| 7 }|t||jd||j|j|j	|j
|j|j| d
 q3|S )  Score the beams with the language model if not None, and
        return the new beams.

        This function is modified and adapted from
        https://github.com/kensho-technologies/pyctcdecode

        Arguments
        ---------
        beams : list
            The list of the beams.
        cached_lm_scores : dict
            The cached language model scores.
        cached_partial_token_scores : dict
            The cached partial token scores.
        is_eos : bool (default: False)
            Whether the end of the sequence has been reached.

        Returns
        -------
        new_beams : list
            The list of the new beams.
        Nr  )
r   r   r   r   r   r   r   r   r   r   Fis_last_wordr   )r   r   r   r   r   r   r   r   r   r   r   r   r   score_partial_tokenr%   r   r   r8  is_eosr  r   r   	cache_keyprev_raw_lm_scorer1  r   	end_stateraw_lm_scorer   rV   	word_partr*   r*   r+   r    sl   


zCTCBeamSearcher.get_lm_beamsr   r   r  r   r   c                    s  |d| }t ||dD ]_\}}|j jkrq| }	tt|jkd |	hB }
g }|
ttt	j
@ }
|
D ]}|| }j
| }|D ]}|jksU|j|kr|jkr`|jd }n|d }|jkrl|jn|jd |f}|t|j|j|j|j|||j||j| d	 qIjr|dd jkr|dd }|jdkr|jn|j|jg }|t|j|j|j||||||d f|j| d	 qIjs|jkr|jdkr|jn|j|jg }|t|j|j|jd|||d|j| d	 qI|jd dk r||d fn|jd |d f}|t|j|j|j|j| |||j||j| d	 qIq<|}|||}tdd	 |D   fd
d	|D }|}jrejdu rYdnjj}j||d}qdd	 |D }q|S )(  Perform CTC Prefix Beam Search decoding.

        If self.lm is not None, the language model scores are computed and added to the CTC scores.

        Arguments
        ---------
        log_probs : torch.Tensor
            The log probabilities of the CTC input.
            Shape: (seq_length, vocab_size)
        wav_len : int
            The length of the input sequence.
        beams : list
            The list of CTCBeam objects.
        cached_lm_scores : dict
            The cached language model scores.
        cached_p_lm_scores : dict
            The cached prefix language model scores.
        processed_frames : int
            The start frame of the current decoding step. (default: 0)

        Returns
        -------
        beams : list
            The list of CTCBeam objects.
        NrT   r   r   r	  r  r  c                 S   r
  r*   r   r  r*   r*   r+   rw     r  z4CTCBeamSearcher.partial_decoding.<locals>.<listcomp>c                    r  r*   r  r  r  r*   r+   rw     r  r   c                 S      g | ]}t |qS r*   r   r   r  r*   r*   r+   rw         ) 	enumerater   r   argmaxr   r   wherer   r;   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r<   r   r   r   orderr  )r%   r   r  r   r   r   r   frame_index	logit_col	max_indextokens_index_listr  token_indexp_tokentokenr   new_end_framenew_part_framesclean_tokennew_frame_listr  r+  r   r*   r  r+   r     s   #









g
z CTCBeamSearcher.partial_decodingNFro   )rq   rr   rs   rt   r   r   r5  r   r  r    r4  r?   r   r*   r*   r*   r+   r7    s8    3
fr7  c                   @   s   e Zd ZdZ	ddee dededee fddZd	e	d
e
de
de	dee dededefddZ	ddejde	dee dedede	dee fddZdS )CTCPrefixBeamSearcheraB  CTC Prefix Beam Search is based on the paper
    `First-Pass Large Vocabulary Continuous Speech Recognition using Bi-Directional Recurrent DNNs`
    by Awni Y. Hannun and al (https://arxiv.org/abs/1408.2873).

    The implementation keep tracks of the blank and non-blank probabilities.
    It also supports n-gram scoring on words and SentencePiece tokens. The input
    is expected to be a log-probabilities tensor of shape [batch, time, vocab_size].

    Several heuristics are implemented to speed up the decoding process:
    - pruning of the beam : the beams are pruned if their score is lower than
        the best beam score minus the beam_prune_logp
    - pruning of the tokens : the tokens are pruned if their score is lower than
        the token_prune_min_logp
    - pruning of the history : the beams are pruned if they are the same over
        max_ngram history
    - skipping of the blank : the frame is skipped if the blank probability is
        higher than the blank_skip_threshold

    Note: The CTCPrefixBeamSearcher can be more unstable than the CTCBeamSearcher
    or the TorchAudioCTCPrefixBeamSearch searcher. Please, use it with caution
    and check the results carefully.

    Note: if the Acoustic Model is not trained, the Beam Search will
    take a lot of time. We do recommend to use Greedy Search during validation
    until the model is fully trained and ready to be evaluated on test sets.

    Note: This implementation does not provide the time alignment of the
    hypothesis. If you need it, please use the CTCBeamSearcher.

    Arguments
    ---------
    see CTCBaseSearcher, arguments are directly passed.

    Example
    -------
    >>> import torch
    >>> from speechbrain.decoders import CTCPrefixBeamSearcher
    >>> probs = torch.tensor([[[0.2, 0.0, 0.8],
    ...                   [0.4, 0.0, 0.6]]])
    >>> log_probs = torch.log(probs)
    >>> lens = torch.tensor([1.0])
    >>> blank_index = 2
    >>> vocab_list = ['a', 'b', '-']
    >>> searcher = CTCPrefixBeamSearcher(blank_index=blank_index, vocab_list=vocab_list)
    >>> hyps = searcher(probs, lens)
    Fr   r   r8  r   c              	   C   s  | j du r\g }|D ]P}| |j|j}|tdi d|jd|ddd|jd|jd|j	d	|j
d
|jd|jd|jd|jd|jd|jd|jd|jd|j q	|S g }|D ]}| |j|j}||f}||vr||jdf \}	}
| j j|
|j|d\}}|	| }||f||< || \}}|j}t|dkr||vr| j |||< ||| 7 }|tdi d|jd|ddd|jd|jd|j	d	|j
d
|jd|jd|jd|jd|jd|jd|jd|jd|j|  q`|S )r9  Nr   r   r   r  r   r   r   r   r   r   r   r   r   r   r   r   r   Fr:  r   r*   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r<  r=  r*   r*   r+   r    s   
	


	

z"CTCPrefixBeamSearcher.get_lm_beamsrN  
new_prefix	new_tokennew_token_indexr   previous_beamc                 C   s  |D ]}|j |kr|r||jkr||_|  S q| jsG|| jkrG|jdkr(|jn|j|jg }	t||j|jd|||	dt	j
 t	j
 t	j
 d}
n| jr|dd | jkr|dd }|jdkra|jn|j|jg }	|j d | }t||j|j||||	||d ft	j
 t	j
 t	j
 d}
na||jkr|d }|| jkr|jn|jd |f}t||jd|j|||j|t	j
 t	j
 t	j
 d}
n0|jd dk r||d fn|jd |d f}t||jd|j| |||j|t	j
 t	j
 t	j
 d}
||
 |r|j|
_|
S )a]  Create a new beam and add it to the list of beams.

        Arguments
        ---------
        frame_index : int
            The index of the current frame.
        new_prefix : str
            The new prefix.
        new_token : str
            The new token.
        new_token_index : int
            The index of the new token.
        beams : list
            The list of beams.
        p : float
            The probability of the new token.
        previous_beam : CTCBeam
            The previous beam.

        Returns
        -------
        new_beam : CTCBeam
            The new beam.
        r  r  r-  Nr   r   r   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   )r%   rN  r[  r\  r]  r   r   r^  r   rX  new_beamrW  rU  rV  r*   r*   r+   _get_new_beamj  s   "







z#CTCPrefixBeamSearcher._get_new_beamr   r   r  r   r   c                    s  |d| }t ||dD ]\}}|j jkrq| }	tt|jkd |	hB }
| }|
tt	t
j@ }
|
D ]p}|| }j| }|D ]b}|j|j}}|jkrdt|j|j| |_qJ||jkrst|j|| |_|j| }j|||||||d}|j}||jkr|tj krt||| }n||jkrt||j| }||_qJq=|D ]}|  q|||}tdd |D   fdd|D }|}jrjdu rdnjj}j||d	}qd
d |D }q|S )rD  NrE  r   )r   r^  c                 S   r
  r*   r   r  r*   r*   r+   rw   ^  r  z:CTCPrefixBeamSearcher.partial_decoding.<locals>.<listcomp>c                    r  r*   r  r  r  r*   r+   rw   _  r  r   rF  c                 S   rG  r*   rH  r  r*   r*   r+   rw   j  rI  ) rJ  r   r   rK  r   r   rL  r   copyr;   r   r   r   r   r   r   r   r   r   r   r`  r   r   r   r   r  r<   r   r   r   rM  r  )r%   r   r  r   r   r   r   rN  rO  rP  rQ  
curr_beamsrR  rS  rT  r   r   r   r   r_  r   r  r+  r   r*   r  r+   r     sx   #





"

z&CTCPrefixBeamSearcher.partial_decodingNrY  ro   )rq   rr   rs   rt   r   r   r5  r   r  r?   r   r   r`  r    r4  r   r*   r*   r*   r+   rZ    s\    4
l	
 rZ  c                %   @   s  e Zd ZdZdddddddddedddddd	d
dfdeeef dee dee dee de	de	dee	 dededededede
deee	f deee	f dede
def$ddZ	d'd ejd!eejdf d"eee  fd#d$Z	d'd ejd!eejdf d"eee  fd%d&ZdS )(TorchAudioCTCPrefixBeamSearcheraJ  TorchAudio CTC Prefix Beam Search Decoder.

    This class is a wrapper around the CTC decoder from TorchAudio. It provides a simple interface
    where you can either use the CPU or CUDA CTC decoder.

    The CPU decoder is slower but uses less memory. The CUDA decoder is faster but uses more memory.
    The CUDA decoder is also only available in the nightly version of torchaudio.

    A lot of features are missing in the CUDA decoder, such as the ability to use a language model,
    constraint search, and more. If you want to use those features, you have to use the CPU decoder.

    For more information about the CPU decoder, please refer to the documentation of TorchAudio:
    https://pytorch.org/audio/main/generated/torchaudio.models.decoder.ctc_decoder.html

    For more information about the CUDA decoder, please refer to the documentation of TorchAudio:
    https://pytorch.org/audio/main/generated/torchaudio.models.decoder.cuda_ctc_decoder.html#torchaudio.models.decoder.cuda_ctc_decoder

    If you want to use the language model, or the lexicon search, please make sure that your
    tokenizer/acoustic model uses the same tokens as the language model/lexicon. Otherwise, the decoding will fail.

    The implementation is compatible with SentencePiece Tokens.

    Note: When using CUDA CTC decoder, the blank_index has to be 0. Furthermore, using CUDA CTC decoder
    requires the nightly version of torchaudio and a lot of VRAM memory (if you want to use a lot of beams).
    Overall, we do recommend to use the CTCBeamSearcher or CTCPrefixBeamSearcher in SpeechBrain if you wants to use
    n-gram + beam search decoding. If you wants to have constraint search, please use the CPU version of torchaudio,
    and if you want to speedup as much as possible the decoding, please use the CUDA version.

    Arguments
    ---------
    tokens : list or str
        The list of tokens or the path to the tokens file.
        If this is a path, then the file should contain one token per line.
    lexicon : str, default: None
        Lexicon file containing the possible words and corresponding spellings. Each line consists of a word and its space separated spelling.
        If None, uses lexicon-free decoding. (default: None)
    lm : str, optional
        A path containing KenLM language model or None if not using a language model. (default: None)
    lm_dict : str, optional
        File consisting of the dictionary used for the LM, with a word per line sorted by LM index.
        If decoding with a lexicon, entries in lm_dict must also occur in the lexicon file.
        If None, dictionary for LM is constructed using the lexicon file. (default: None)
    topk : int, optional
        Number of top CTCHypothesis to return. (default: 1)
    beam_size : int, optional
        Numbers of hypotheses to hold after each decode step. (default: 50)
    beam_size_token : int, optional
        Max number of tokens to consider at each decode step. If None, it is set to the total number of tokens. (default: None)
    beam_threshold : float, optional
        Threshold for pruning hypothesis. (default: 50)
    lm_weight : float, optional
        Weight of language model. (default: 2)
    word_score : float, optional
        Word insertion score. (default: 0)
    unk_score : float, optional
        Unknown word insertion score. (default: float("-inf"))
    sil_score : float, optional
        Silence insertion score. (default: 0)
    log_add : bool, optional
        Whether to use use logadd when merging hypotheses. (default: False)
    blank_index : int or str, optional
        Index of the blank token. If tokens is a file path, then this should be an str. Otherwise, this should be a int. (default: 0)
    sil_index : int or str, optional
        Index of the silence token. If tokens is a file path, then this should be an str. Otherwise, this should be a int. (default: 0)
    unk_word : str, optional
        Unknown word token. (default: "<unk>")
    using_cpu_decoder : bool, optional
        Whether to use the CPU searcher. If False, then the CUDA decoder is used. (default: True)
    blank_skip_threshold : float, optional
        Skip frames if log_prob(blank) > log(blank_skip_threshold), to speed up decoding (default: 1.0).
        Note: This is only used when using the CUDA decoder, and it might worsen the WER/CER results. Use it at your own risk.

    Example
    -------
    >>> import torch
    >>> from speechbrain.decoders import TorchAudioCTCPrefixBeamSearcher
    >>> probs = torch.tensor([[[0.2, 0.0, 0.8],
    ...                   [0.4, 0.0, 0.6]]])
    >>> log_probs = torch.log(probs)
    >>> lens = torch.tensor([1.0])
    >>> blank_index = 2
    >>> vocab_list = ['a', 'b', '-']
    >>> searcher = TorchAudioCTCPrefixBeamSearcher(tokens=vocab_list, blank_index=blank_index, sil_index=blank_index) # doctest: +SKIP
    >>> hyps = searcher(probs, lens) # doctest: +SKIP
    Nr   2   r   r   z-infFz<unk>Tr   tokenslexiconr   lm_dictr   rF   beam_size_tokenbeam_threshold	lm_weight
word_score	unk_score	sil_scorelog_addr   	sil_indexunk_wordusing_cpu_decoderr   c                 C   s  || _ || _|| _|| _|| _|| _|| _|| _|	| _|
| _	|| _
|| _|| _|| _|| _|| _|| _|| _| jrzddlm} W n tyL   tdw t| jtrZ| j}| j}n| j| j }| j| j }|di d| j d| jd| jd| jd| jd	| jd
| jd| jd| jd| j	d| j
d| jd| jd|d|d| j| _d S zddlm} W n ty   tdw | jdksJ d|| j| j| j| jd| _d S )Nr   )ctc_decoderzTctc_decoder not found. Please install torchaudio and flashlight to use this decoder.rf  re  r   rg  nbestrF   rh  ri  rj  rk  rl  rm  rn  blank_token	sil_tokenrp  )cuda_ctc_decoderz`cuda_ctc_decoder not found. Please install the latest version of torchaudio to use this decoder.z=Index of blank token has to be 0 when using CUDA CTC decoder.)re  rs  rF   r   r*   )rf  re  r   rg  r   rF   rh  ri  rj  rk  rl  rm  rn  r   ro  rp  rq  r   torchaudio.models.decoderrr  r   r}   r   _ctc_decoderrv  )r%   re  rf  r   rg  r   rF   rh  ri  rj  rk  rl  rm  rn  r   ro  rp  rq  r   rr  rt  ru  rv  r*   r*   r+   r,     s   	

z(TorchAudioCTCPrefixBeamSearcher.__init__r   r  r   c                    sb  |dur| d| }ntj| dg| d |jtjd}|jtjkr+|tj}|jtjkr5tdj	r?|j
r?| }j	rI|j
rI| }| sQtd||g }g }g }g }ttD ] j	r fddtt  D }fd	d|D }||  fd
dtt  D }|| n0dd tt  D }||  fddtt  D }fdd|D }||  fddtt  D }	||	  fddtt  D }
||
 qeg }tt|||D ]+\}\}}}|g  t|||D ]\}}}|| td|d|||d qq|S )a-  Decode log_probs using TorchAudio CTC decoder.

        If `using_cpu_decoder=True` then log_probs and wav_len are moved to CPU before decoding.
        When using CUDA CTC decoder, the timestep information is not available. Therefore, the timesteps
        in the returned hypotheses are set to None.

        Make sure that the input are in the log domain. The decoder will fail to decode
        logits or probabilities. The input should be the log probabilities of the CTC output.

        Arguments
        ---------
        log_probs : torch.Tensor
            The log probabilities of the input audio.
            Shape: (batch_size, seq_length, vocab_size)
        wav_len : torch.Tensor, default: None
            The speechbrain-style relative length. Shape: (batch_size,)
            If None, then the length of each audio is assumed to be seq_length.

        Returns
        -------
        list of list of CTCHypothesis
            The decoded hypotheses. The outer list is over the batch dimension, and the inner list is over the topk dimension.
        Nr   r   )r   r.   zlog_probs must be float32.zlog_probs must be contiguous.c                       g | ]}  | j  qS r*   )re  r   rv   jrR   resultsr*   r+   rw   `      z@TorchAudioCTCPrefixBeamSearcher.decode_beams.<locals>.<listcomp>c                       g | ]} fd d|D qS )c                       g | ]} j | qS r*   re  rv   rT  r   r*   r+   rw   e  rI  KTorchAudioCTCPrefixBeamSearcher.decode_beams.<locals>.<listcomp>.<listcomp>r*   rv   re  r   r*   r+   rw   d      c                    ry  r*   )	timestepsr   rz  r|  r*   r+   rw   i  r~  c                 S   s   g | ]}d qS rx   r*   )rv   rV   r*   r*   r+   rw   q  s    c                       g | ]	}  | j qS r*   r  rz  r|  r*   r+   rw   t      c                    r  )c                    r  r*   r  r  r   r*   r+   rw   v  rI  r  r*   r  r   r*   r+   rw   u  r  c                    r  r*   )wordsrz  r|  r*   r+   rw   z  r  c                    r  r*   r   rz  r|  r*   r+   rw   }  r  r  )r   r   r   r   r   )r   r    tensorr   int32r.   tofloat32r   rq  is_cudar#  is_contiguousRuntimeErrorrx  r;   r   r   rJ  r   r   r   )r%   r   r  tokens_predswords_predsscores_predstimesteps_predspredsr  r  r   r&  r$   
batch_textbatch_scorebatch_timestepsr   r   timestepr*   )rR   r}  r%   r+   r'  #  s   


 

 
 
z,TorchAudioCTCPrefixBeamSearcher.decode_beamsc                 C   s   |  ||S )av  Decode log_probs using TorchAudio CTC decoder.

        If `using_cpu_decoder=True` then log_probs and wav_len are moved to CPU before decoding.
        When using CUDA CTC decoder, the timestep information is not available. Therefore, the timesteps
        in the returned hypotheses are set to None.

        Arguments
        ---------
        log_probs : torch.Tensor
            The log probabilities of the input audio.
            Shape: (batch_size, seq_length, vocab_size)
        wav_len : torch.Tensor, default: None
            The speechbrain-style relative length. Shape: (batch_size,)
            If None, then the length of each audio is assumed to be seq_length.

        Returns
        -------
        list of list of CTCHypothesis
            The decoded hypotheses. The outer list is over the batch dimension, and the inner list is over the topk dimension.
        r(  )r%   r   r  r*   r*   r+   r)    s   z(TorchAudioCTCPrefixBeamSearcher.__call__rx   )rq   rr   rs   rt   r   r   r~   r   r   r?   r3  r,   r    r4  r   r   r'  r)  r*   r*   r*   r+   rc  o  s    Y
	



^

r
rc  )r   )$rt   r   r   r   r!  	itertoolsr   typingr   r   r   r   r   r   r$  r   r    speechbrain.dataio.dataior	   speechbrain.utils.loggerr
   rq   r   r   r   r   	dataclassr   r   r   nnModuler   r7  rZ  rc  r*   r*   r*   r+   <module>   sH    	   

%-q    k  N   $