o
    ei                     @   s.   d Z ddlZ	dddZdd	 ZdddZdS )zU
N-gram counting, discounting, interpolation, and backoff

Authors
 * Aku Rouhe 2020
    NT<s></s>c                 C   s,   |rt |ft| |fS t t| |fS )a  
    Pad sentence ends with start- and end-of-sentence tokens

    In speech recognition, it is important to predict the end of sentence
    and use the start of sentence to condition predictions. Typically this
    is done by adding special tokens (usually <s> and </s>) at the ends of
    each sentence. The <s> token should not be predicted, so some special
    care needs to be taken for unigrams.

    Arguments
    ---------
    sequence : iterator
        The sequence (any iterable type) to pad.
    pad_left : bool
        Whether to pad on the left side as well. True by default.
    left_pad_symbol : any
        The token to use for left side padding. "<s>" by default.
    right_pad_symbol : any
        The token to use for right side padding. "</s>" by default.

    Returns
    -------
    generator
        A generator that yields the padded sequence.

    Example
    -------
    >>> for token in pad_ends(["Speech", "Brain"]):
    ...     print(token)
    <s>
    Speech
    Brain
    </s>

    )	itertoolschaintuple)sequencepad_leftleft_pad_symbolright_pad_symbol r   U/home/ubuntu/transcripts/venv/lib/python3.10/site-packages/speechbrain/lm/counting.pypad_ends   s
   &r   c                 c   s    |dkr	t d|dkr| D ]}|fV  qdS t| }g }t|ddD ]\}}|| ||d kr5 nq$dS |D ]}t||f V  || |d= q:dS )a  
    Produce all Nth order N-grams from the sequence.

    This will generally be used in an N-gram counting pipeline.

    Arguments
    ---------
    sequence : iterator
        The sequence from which to produce N-grams.
    n : int
        The order of N-grams to produce

    Yields
    ------
    tuple
        Yields each ngram as a tuple.

    Returns
    -------
    None

    Example
    -------
    >>> for ngram in ngrams("Brain", 3):
    ...     print(ngram)
    ('B', 'r', 'a')
    ('r', 'a', 'i')
    ('a', 'i', 'n')

    r   zN must be >=1   N)start)
ValueErroriter	enumerateappendr   )r   ntokeniteratorhistoryhist_lengthr   r   r   ngrams?   s(   


r   Fc                 c   sh    |dkr	t dt| }g }|s|t| |D ]}t||kr%|d= |t|fV  || qdS )ao  
    Produce each token with the appropriate context.

    The function produces as large N-grams as possible, so growing from
    unigrams/bigrams to max_n.

    E.G. when your model is a trigram model, you'll still only have one token
    of context (the start of sentence) for the first token.

    In general this is useful when evaluating an N-gram model.

    Arguments
    ---------
    sequence : iterator
        The sequence to produce tokens and context from.
    max_n : int
        The maximum N-gram length to produce.
    predict_first : bool
        To produce the first token in the sequence to predict (without
        context) or not. Essentially this should be False when the start of
        sentence symbol is the first in the sequence.

    Yields
    ------
    Any
        The token to predict
    tuple
        The context to predict conditional on.

    Example
    -------
    >>> for token, context in ngrams_for_evaluation("Brain", 3, True):
    ...     print(f"p( {token} |{' ' if context else ''}{' '.join(context)} )")
    p( B | )
    p( r | B )
    p( a | B r )
    p( i | r a )
    p( n | a i )
    r   zMax N must be >=1N)r   r   r   nextlenr   )r   max_npredict_firstr   r   r   r   r   r   ngrams_for_evaluationt   s   (r   )Tr   r   )F)__doc__r   r   r   r   r   r   r   r   <module>   s    

.5