
    i0e              *          d dl mZ d dlmZ d dlmZ d dlmZmZm	Z	 d dl
Z
d dl
mZmZ d dlmZ  ed      Z ed	      Zd
ededeeeef   eeef   eeef   eeef   eeef   eeef   f   fdZdededee   fdZdedee   fdZdedee   fdZdee   dedeeeeedf   ef   f   fdZded
ededededeeeeeedf   ef   f   eeeeedf   ef   f   eeef   eeef   f   fdZdeeeeedf   ef   f   deeeeedf   ef   f   deeef   fdZdeeef   deeef   deeef   fdZd eeef   d!eeef   d"eeef   d#eeef   d$eeef   d%eeef   d&e d'e defd(Z!d)ee   d*eeeeedf   ef   f   d+eeeeedf   ef   f   d,eeef   d-eeef   d
eded&e d'e dededeeeeef   eeef   eeef   eeef   f   fd.Z"	 d<d/e	eee   f   d0e	ee   eee      f   d1eeef   d2eeef   d3eeef   d4eeef   d5eeef   d6eeef   d
eded&e d'e deded7eee      deeeef   eeef   eeef   eeef   eeef   eeef   eee      f   f d8Z#d1eeef   d2eeef   d3eeef   d4eeef   d5eeef   d6eeef   d&e d'e defd9Z$	 	 	 	 	 	 d=d/e	eee   f   d0ee	eee   f      d
eded'e deded:ede	eeeef   f   fd;Z%y)>    defaultdict)Sequence)chain)ListOptionalUnionN)Tensortensor)_validate_inputsgؗҜ<z !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~n_char_ordern_word_orderreturnc                 
   t        |       D ci c]  }|dz   t        d       }}t        |      D ci c]  }|dz   t        d       }}t        |       D ci c]  }|dz   t        d       }}t        |      D ci c]  }|dz   t        d       }}t        |       D ci c]  }|dz   t        d       }}t        |      D ci c]  }|dz   t        d       }}||||||fS c c}w c c}w c c}w c c}w c c}w c c}w )ah  Prepare dictionaries with default zero values for total ref, hypothesis and matching character and word n-grams.

    Args:
        n_char_order: A character n-gram order.
        n_word_order: A word n-gram order.

    Return:
        Dictionaries with default zero values for total reference, hypothesis and matching character and word
        n-grams.

               )ranger   )	r   r   ntotal_preds_char_n_gramstotal_preds_word_n_gramstotal_target_char_n_gramstotal_target_word_n_gramstotal_matching_char_n_gramstotal_matching_word_n_gramss	            v/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/torchmetrics/functional/text/chrf.py_prepare_n_grams_dictsr   &   s5     PUUaOb2cOb!1q5&+3EOb2cOTUaOb2cOb!1q5&+3EOb2cPUVbPc3dPc1AE6#;4FPc3dPUVbPc3dPc1AE6#;4FPc3dRWXdRe5fReQa!eVC[6HRe5fRWXdRe5fReQa!eVC[6HRe5f 	! !!##  3d2c3d3d5f5fs"   C'C,C1=C6"C;D sentence
whitespacec                 n    |rt        |       S t        | j                         j                  dd            S )a   Split sentence into individual characters.

    Args:
        sentence: An input sentence to split.
        whitespace: An indication whether to keep whitespaces during character n-gram extraction.

    Return:
        A list of separated characters.

      )liststripreplace)r   r   s     r   _get_charactersr%   G   s0     H~ ((b122    wordc                 ~    t        |       dk(  r| gS | d   t        v r
| dd | d   gS | d   t        v r
| d   | dd gS | gS )ax  Separates out punctuation from beginning and end of words for chrF.

    Adapted from https://github.com/m-popovic/chrF and
    https://github.com/mjpost/sacrebleu/blob/master/sacrebleu/metrics/chrf.py.

    Args:
        word: An input word to be separated from a punctuation if present.

    Return:
        A list of a single word or a separated word and punctuation.

    r   Nr   )len_PUNCTUATIONS)r'   s    r   _separate_word_and_punctuationr,   W   s_     4yA~vBx= Sb	48$$Aw-Qab""6Mr&   c                     t        t        j                  d | j                         j	                         D                    S )zSeparates out punctuation from beginning and end of words for chrF for all words in the sentence.

    Args:
        sentence: An input sentence to split

    Return:
        An aggregated list of separated words and punctuation.

    c              3   2   K   | ]  }t        |        y wN)r,   ).0r'   s     r   	<genexpr>z-_get_words_and_punctuation.<locals>.<genexpr>x   s     #nUmT$B4$HUms   )r"   r   from_iterabler#   split)r   s    r   _get_words_and_punctuationr4   n   s3     ###nU]UcUcUeUkUkUm#nnoor&   char_or_word_listn_gram_order.c                      t        d       }t        d|dz         D ]D   fdt        t               z
  dz         D        D ]  }|   |xx   t        d      z  cc<    F |S )zCalculate n-gram counts.

    Args:
        char_or_word_list: A list of characters of words
        n_gram_order: The largest number of n-gram.

    Return:
        A dictionary of dictionaries with a counts of given n-grams.

    c                      t        d       S )Nc                      t        d      S Nr   r    r&   r   <lambda>z1_ngram_counts.<locals>.<lambda>.<locals>.<lambda>   s    _efi_jr&   r   r<   r&   r   r=   z_ngram_counts.<locals>.<lambda>   s
    ;WjKkr&   r   c              3   @   K   | ]  }t        ||z            y wr/   )tuple)r0   ir5   r   s     r   r1   z _ngram_counts.<locals>.<genexpr>   s%     iChae-a!a%89Chs   )r   r   r*   r   )r5   r6   ngramsngramr   s   `   @r   _ngram_countsrC   {   sm     8CCk7lF1lQ&'i5M^I_bcIcfgIgChiE1Ieq	) j ( Mr&   	lowercasec                    dt         dt        dt        dt        dt        t        t        t        t        t         df   t
        f   f   t        t        t        t        t         df   t
        f   f   f   f
fd}dt        t        t        t        t         df   t
        f   f   dt        t        t
        f   fd	} || |||      \  }} ||      }	 ||      }
|||	|
fS )
a  Get n-grams and total n-grams.

    Args:
        sentence: An input sentence
        n_char_order: A character n-gram order.
        n_word_order: A word n-gram order.
        lowercase: An indication whether to enable case-insensitivity.
        whitespace: An indication whether to keep whitespaces during character n-gram extraction.

    Return:
        char_n_grams_counts: A dictionary of dictionaries with sentence character n-grams.
        word_n_grams_counts: A dictionary of dictionaries with sentence word n-grams.
        total_char_n_grams: A dictionary containing a total number of sentence character n-grams.
        total_word_n_grams: A dictionary containing a total number of sentence word n-grams.

    r   r   r   rD   r   .c                     |r| j                         } t        t        |       |      }t        t        |       |      }||fS )z@Get a dictionary of dictionaries with a counts of given n-grams.)lowerrC   r%   r4   )r   r   r   rD   char_n_grams_countsword_n_grams_countsr   s         r   _char_and_word_ngrams_countszJ_get_n_grams_counts_and_total_ngrams.<locals>._char_and_word_ngrams_counts   sI     ~~'H+OHj,QS_`+,Fx,PR^_"$777r&   n_grams_countsc                     t        d       }| D ]=  }t        | |   j                               j                         j	                         ||<   ? |S )z.Get total sum of n-grams over n-grams w.r.t n.c                      t        d      S r:   r;   r<   r&   r   r=   zQ_get_n_grams_counts_and_total_ngrams.<locals>._get_total_ngrams.<locals>.<lambda>   s    vc{r&   )r   sumvaluesdetachclone)rK   total_n_gramsr   s      r   _get_total_ngramsz?_get_n_grams_counts_and_total_ngrams.<locals>._get_total_ngrams   sL    +67J+KA">!#4#;#;#=>EEGMMOM!  r&   )strintboolr?   dictr
   )r   r   r   rD   r   rJ   rS   rH   rI   total_char_n_gramstotal_word_n_gramss       `      r   $_get_n_grams_counts_and_total_ngramsrZ      s    288%(88;8HL8	tCeCHov5667c4cSVhY_H_C`>`9aa	b8$sDsCx&9P4Q/Q*R W[\_ag\gWh  0L,i0,, ++>?*+>? 35GI[[[r&   hyp_n_grams_countsref_n_grams_countsc           	          t        d       }| D ]^  }| |   D cg c]$  }t        j                  ||   |   | |   |         & }}t        |      j	                         j                         ||<   ` |S c c}w )zGet a number of n-gram matches between reference and hypothesis n-grams.

    Args:
        hyp_n_grams_counts: n-grams counts for hypothesis
        ref_n_grams_counts: n-grams counts for reference

    Return:
        matching_n_grams

    c                      t        d      S r:   r;   r<   r&   r   r=   z$_get_ngram_matches.<locals>.<lambda>   s    fSkr&   )r   torchminrN   rP   rQ   )r[   r\   matching_n_gramsr   n_grammin_n_gramss         r   _get_ngram_matchesrd      s     +66I*Jbtuvbw
bwX^EII(+F35G5J65RSbw 	 
 "+.557==?	  
 	
s   )A2rR   n_gramsc                 4    |D ]  }| |xx   ||   z  cc<    | S )aB  Aggregate total n-grams to keep corpus-level statistics.

    Args:
        total_n_grams: A dictionary containing a total corpus-level number of n-grams.
        n_grams: A dictionary containing a sentence-level number of n-grams.

    Return:
        A dictionary containing a total corpus-level number of n-grams.

    r<   )rR   re   r   s      r   _sum_over_dictsrg      s(     aGAJ& r&   matching_char_n_gramsmatching_word_n_gramshyp_char_n_gramshyp_word_n_gramsref_char_n_gramsref_word_n_gramsn_orderbetac                 X   dt         t        t        f   dt         t        t        f   dt         t        t        f   dt        dt         t        t        f   f
d} || |||      }	 |||||      }
t	        |	j                               t	        |
j                               z   t        |      z  S )a  Calculate sentence-level chrF/chrF++ score.

    For given hypothesis and reference statistics (either sentence-level or corpus-level)
    the chrF/chrF++ score is returned.

    Args:
        matching_char_n_grams:
            A total number of matching character n-grams between the best matching reference and hypothesis.
        matching_word_n_grams:
            A total number of matching word n-grams between the best matching reference and hypothesis.
        hyp_char_n_grams: A total number of hypothesis character n-grams.
        hyp_word_n_grams: A total number of hypothesis word n-grams.
        ref_char_n_grams: A total number of reference character n-grams.
        ref_word_n_grams: A total number of reference word n-grams.
        n_order: A sum of character and word n-gram order.
        beta: A parameter determining an importance of recall w.r.t. precision. If `beta=1`, their importance is equal.

    Return:
        A chrF/chrF++ score. This function is universal both for sentence-level and corpus-level calculation.

    ra   ref_n_gramshyp_n_gramsro   r   c           	         | D ci c]!  }|||   dkD  r| |   ||   z  n
t        d      # }}| D ci c]!  }|||   dkD  r| |   ||   z  n
t        d      # }}| D ci c],  }|t        j                  |dz  ||   z  ||   z   t              . }}| D ci c]  }|d|dz  z   ||   z  ||   z  ||   z   }}|S c c}w c c}w c c}w c c}w )zGet n-gram level f-score.r   r      r   )r   r_   max_EPS_SMOOTHING)	ra   rq   rr   ro   r   	precisionrecalldenominatorf_scores	            r   _get_n_gram_fscorez-_calculate_fscore.<locals>._get_n_gram_fscore  s>   
 eu(
dt_`A{1~7I"[^3vVY{Zdt 	 (
 eu%
dt_`A{1~7I"[^3vVY{Zdt 	 %
 Wg*
VfQRAuyyq9Q</&);^LLVf 	 *
 Sc&
RbQAD!Gy|+fQi7+a.HHRb 	 &
 (
%
*
&
s   &B:&B?1C"C	)rW   rU   r
   floatrN   rO   r   )rh   ri   rj   rk   rl   rm   rn   ro   r{   char_n_gram_f_scoreword_n_gram_f_scores              r   _calculate_fscorer      s    @sF{+:>sF{:KZ^_bdj_jZksx	c6k	& --BDTVfhlm,-BDTVfhlm#**,-4G4N4N4P0QQU[\cUdddr&   targetspred_char_n_grams_countspred_word_n_grams_countspred_char_n_gramspred_word_n_gramsc                 0   t        d      }t        d       }t        d       }t        d       }t        d       }| D ]P  }t        ||||	|
      \  }}}}t        ||      }t        ||      }t	        ||||||||      }||kD  sG|}|}|}|}|}R |||||fS )aS  Calculate the best sentence-level chrF/chrF++ score.

    For a given pre-processed hypothesis, all references are evaluated and score and statistics
    for the best matching reference is returned.

    Args:
        targets: An iterable of references.
        pred_char_n_grams_counts: A dictionary of dictionaries with hypothesis character n-grams.
        pred_word_n_grams_counts: A dictionary of dictionaries with hypothesis word n-grams.
        pred_char_n_grams: A total number of hypothesis character n-grams.
        pred_word_n_grams: A total number of hypothesis word n-grams.
        n_char_order: A character n-gram order.
        n_word_order: A word n-gram order.
        n_order: A sum of character and word n-gram order.
        beta: A parameter determining an importance of recall w.r.t. precision. If `beta=1`, their importance is equal.
        lowercase: An indication whether to enable case-insensitivity.
        whitespace: An indication whether to keep whitespaces during character n-gram extraction.

    Return:
        Return chrF/chrF++ score and statistics for the best matching hypothesis and reference.

        f_score: A sentence-level chrF/chrF++ score.
        matching_char_n_grams:
            A total number of matching character n-grams between the best matching reference and hypothesis.
        matching_word_n_grams:
            A total number of matching word n-grams between the best matching reference and hypothesis.
        target_char_n_grams: A total number of reference character n-grams.
        target_word_n_grams: A total number of reference word n-grams.

    r   c                      t        d      S r:   r;   r<   r&   r   r=   z6_calculate_sentence_level_chrf_score.<locals>.<lambda>L      sr&   c                      t        d      S r:   r;   r<   r&   r   r=   z6_calculate_sentence_level_chrf_score.<locals>.<lambda>M  r   r&   c                      t        d      S r:   r;   r<   r&   r   r=   z6_calculate_sentence_level_chrf_score.<locals>.<lambda>N      fSkr&   c                      t        d      S r:   r;   r<   r&   r   r=   z6_calculate_sentence_level_chrf_score.<locals>.<lambda>O  r   r&   )r   r   rZ   rd   r   )r   r   r   r   r   r   r   rn   ro   rD   r   best_f_scorebest_matching_char_n_gramsbest_matching_word_n_gramsbest_target_char_n_gramsbest_target_word_n_gramstargettarget_char_n_grams_countstarget_word_n_grams_countstarget_char_n_gramstarget_word_n_gramsrh   ri   rz   s                           r   $_calculate_sentence_level_chrf_scorer      s    V #;L4?@S4T4?@S4T2=>Q2R2=>Q2R 1|U^`jk	
&& 23MOg h 23MOg h#!!	
 \!"L)>&)>&':$':$5 : 	""   r&   predsr   r   r   r   r   r   r   sentence_chrf_scorec                    t        ||       \  }} t        | |      D ]  \  }}t        |||	||      \  }}}}t        ||      }t        ||      }t	        |||||||	|
|||      \  }}}}}| |j                  |j                  d             t        ||      }t        ||      }t        ||      }t        ||      } |||||||fS )a  Update function for chrf score.

    Args:
        preds: An iterable of hypothesis corpus.
        target: An iterable of iterables of reference corpus.
        total_preds_char_n_grams: A dictionary containing a total number of hypothesis character n-grams.
        total_preds_word_n_grams: A dictionary containing a total number of hypothesis word n-grams.
        total_target_char_n_grams: A dictionary containing a total number of reference character n-grams.
        total_target_word_n_grams: A dictionary containing a total number of reference word n-grams.
        total_matching_char_n_grams:
            A dictionary containing a total number of matching character n-grams between references and hypotheses.
        total_matching_word_n_grams:
            A dictionary containing a total number of total matching word n-grams between references and hypotheses.
        n_char_order: A character n-gram order.
        n_word_order: A word n-gram order.
        n_order: Sum of character and word n-gram order.
        beta: A parameter determining an importance of recall w.r.t. precision. If `beta=1`, their importance is equal.
        lowercase: An indication whether to enable case-insensitivity.
        whitespace: An indication whether to keep whitespaces during character n-gram extraction.
        sentence_chrf_score: A list of sentence-level chrF/chrF++ scores.

    Return:
        total_target_char_n_grams: number of reference character n-grams.
        total_target_word_n_grams: number of reference word n-grams.
        total_preds_char_n_grams: number of hypothesis character n-grams.
        total_preds_word_n_grams: number of hypothesis word n-grams.
        total_matching_char_n_grams: number of matching character n-grams between references and hypotheses.
        total_matching_word_n_grams: number of total matching word n-grams between references and hypotheses.
        sentence_chrf_score: A list of sentence-level chrF/chrF++ scores.

    Raises:
        ValueError:
            If length of ``preds`` and ``target`` differs.

    r   )r   ziprZ   rg   r   append	unsqueeze)r   r   r   r   r   r   r   r   r   r   rn   ro   rD   r   r   target_corpuspredr   r   r   r   r   sentence_level_f_scorerh   ri   r   r   s                              r   _chrf_score_updater   v  s.   x ,FE:M5UM2g 1|\S\^hi	
$$#23KM^#_ #23KM^#_  1$$
	
"!! *&&'='G'G'JK$34MOb$c!$34MOb$c!&56QSh&i#&56QSh&i#I 3N 	! !!## r&   c           
      &    t        ||| |||||      S )ak  Compute chrF/chrF++ score based on pre-computed target, prediction and matching character and word n-grams.

    Args:
        total_preds_char_n_grams: number of hypothesis character n-grams.
        total_preds_word_n_grams: number of hypothesis word n-grams.
        total_target_char_n_grams: number of reference character n-grams.
        total_target_word_n_grams: number of reference word n-grams.
        total_matching_char_n_grams: number of matching character n-grams between references and hypotheses.
        total_matching_word_n_grams: number of total matching word n-grams between references and hypotheses.
        n_order: A sum of character and word n-gram order.
        beta:
            A parameter determining an importance of recall w.r.t. precision. If `beta=1`, their importance is equal.

    Return:
        A corpus-level chrF/chrF++ score.

    )r   )r   r   r   r   r   r   rn   ro   s           r   _chrf_score_computer     s)    6 ##  !!	 	r&   return_sentence_level_scorec                    t        |t              r|dk  rt        d      t        |t              r|dk  rt        d      |dk  rt        d      t        ||z         }t	        ||      \  }	}
}}}}|rg nd}t        | ||	|
|||||||||||      \  }	}
}}}}}t        |	|
||||||      }|r|t        j                  |      fS |S )ua  Calculate `chrF score`_  of machine translated text with one or more references.

    This implementation supports both chrF score computation introduced in [1] and chrF++ score introduced in
    `chrF++ score`_. This implementation follows the implementations from https://github.com/m-popovic/chrF and
    https://github.com/mjpost/sacrebleu/blob/master/sacrebleu/metrics/chrf.py.

    Args:
        preds: An iterable of hypothesis corpus.
        target: An iterable of iterables of reference corpus.
        n_char_order:
            A character n-gram order. If `n_char_order=6`, the metrics refers to the official chrF/chrF++.
        n_word_order:
            A word n-gram order. If `n_word_order=2`, the metric refers to the official chrF++. If `n_word_order=0`, the
            metric is equivalent to the original chrF.
        beta:
            A parameter determining an importance of recall w.r.t. precision. If `beta=1`, their importance is equal.
        lowercase: An indication whether to enable case-insensitivity.
        whitespace: An indication whether to keep whitespaces during character n-gram extraction.
        return_sentence_level_score: An indication whether a sentence-level chrF/chrF++ score to be returned.

    Return:
        A corpus-level chrF/chrF++ score.
        (Optionally) A list of sentence-level chrF/chrF++ scores if `return_sentence_level_score=True`.

    Raises:
        ValueError:
            If ``n_char_order`` is not an integer greater than or equal to 1.
        ValueError:
            If ``n_word_order`` is not an integer greater than or equal to 0.
        ValueError:
            If ``beta`` is smaller than 0.

    Example:
        >>> from torchmetrics.functional.text import chrf_score
        >>> preds = ['the cat is on the mat']
        >>> target = [['there is a cat on the mat', 'a cat is on the mat']]
        >>> chrf_score(preds, target)
        tensor(0.8640)

    References:
        [1] chrF: character n-gram F-score for automatic MT evaluation by Maja Popović `chrF score`_

        [2] chrF++: words helping character n-grams by Maja Popović `chrF++ score`_

    r   zMExpected argument `n_char_order` to be an integer greater than or equal to 1.r   zMExpected argument `n_word_order` to be an integer greater than or equal to 0.z.Expected argument `beta` to be greater than 0.N)	
isinstancerU   
ValueErrorr|   r   r   r   r_   cat)r   r   r   r   ro   rD   r   r   rn   r   r   r   r   r   r   r   chrf_f_scores                    r   
chrf_scorer     s'   n lC(L1,<hiilC(L1,<hiiaxIJJL</0G 	|\:  !!## 9T"Y] 	  !!##	  !!##& '  !!##	L UYY':;;;r&   r/   )   rt   g       @FFF)&collectionsr   collections.abcr   	itertoolsr   typingr   r   r	   r_   r
   r   #torchmetrics.functional.text.helperr   rv   setr+   rU   r?   rW   r   rT   rV   r"   r%   r,   r4   rC   rZ   rd   rg   r|   r   r   r   r   r   r<   r&   r   <module>r      s  . $ $  ( (    @89%(
ftCK($sF{*;T#v+=NPTUXZ`U`PacghkmshscttB3c 3t 3S	 3  c .
p 
pc 
pT#Y c d3PTUZ[^`c[cUdflUlPmKmFn $0\0\!$0\470\DH0\VZ0\
d5c?F*+	+,d5c?F*+	+,ff0\fS$uS#X'>"??@S$uS#X'>"??@ 
#v+.4V#4 tCK?P UYZ]_eZeUf  6eV,6eV,6e 3;'6e 3;'	6e
 3;'6e 3;'6e 6e 6e 6erS#YS"3U38_f-D(E#EFS #3U38_f-D(E#EFS CK(	S
 CK(S S S S S S S 64V$d3;&7c6k9JDQTV\Q\L]]^SJ 37lhsm#$l(3-(3-!889l #3;/l #3;/	l
  $CK0l  $CK0l "&c6k!2l "&c6k!2l l l l l l l "$v,/l  ffffffT&\!l^$"3;/$"3;/$  $CK0$  $CK0	$
 "&c6k!2$ "&c6k!2$ $ $ $T (-rhsm#$rU3-./r r 	r
 r r r "&r 65(()rr&   