o
    yi?                     @   s  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 dl	m
Z
 d dlmZ d dlmZmZ d dlmZ G d	d
 d
eZG dd deZdededeeef fddZdedededefddZdededefddZdedededefddZdededefddZdGdededefdd Zdedeeeef fd!d"Zdeded#edeeeee ee ee ee ee ee ef	 fd$d%Zdeded&ed'ed(ed)ed*ee d+ee d#edefd,d-Zd.edefd/d0Zd(ed)ed*ee d1ee d2ee d+ee d3ee d4ee d#ed5ee defd6d7Z g g d8fdeded9ee d:ee d;edeee ee f fd<d=Z!	dHdeded#ed5ee deeee f f
d>d?Z"	@		AdIdeded#edB dCed5eedD  deeeeef f fdEdFZ#dS )J    )ListOptionalTupleUnionN)Tensor)Literal) _check_data_shape_to_num_outputs)_check_same_shape)	_bincountdim_zero_cat)EnumStrc                       >   e Zd ZdZdZdZdZeded dd f fdd	Z	  Z
S )
_MetricVariantzEnumerate for metric variants.abcvaluer   r   r   returnc                    sF   dd t jD }t |}|dur||v r|S td| d| d)z
        Raises:
            ValueError:
                If required metric variant is not among the supported options.
        c                 S   s   g | ]}|  qS  )lower.0imr   r   ^/home/ubuntu/.local/lib/python3.10/site-packages/torchmetrics/functional/regression/kendall.py
<listcomp>(   s    z+_MetricVariant.from_str.<locals>.<listcomp>Nz(Invalid metric variant. Expected one of 
, but got .)r   _member_names_superfrom_str
ValueError)clsr   _allowed_variantsenum_key	__class__r   r   r    !   s
   z_MetricVariant.from_str)__name__
__module____qualname____doc__ABCclassmethodr   r    __classcell__r   r   r%   r   r          $r   c                       r   )
_TestAlternativez&Enumerate for test altenative options.	two-sidedlessgreaterr   r2   r3   r4   r   c                    sN   dd t jD }t |dd}|dur||v r|S td| d| d)	z
        Raises:
            ValueError:
                If required test alternative is not among the supported options.
        c                 S   s   g | ]
}|  d dqS )_-)r   replacer   r   r   r   r   >   s    z-_TestAlternative.from_str.<locals>.<listcomp>r7   r6   Nz*Invalid test alternative. Expected one of r   r   )r1   r   r   r    r8   r!   )r"   r   _allowed_alternativesr$   r%   r   r   r    7   s
   z_TestAlternative.from_str)r'   r(   r)   r*   	TWO_SIDEDLESSGREATERr.   r   r    r/   r   r   r%   r   r1   0   r0   r1   xyr   c                 C   sX   t |}| j|j} }|  \} }t| jd D ]}|| ||  ||< q| j|jfS )zBSort sequences in an ascent order according to the sequence ``x``.r   )torchcloneTsortrangeshape)r=   r>   permir   r   r   _sort_on_first_sequenceF   s   
rG   rF   c                 C   s@   t | | | |d d k || ||d d k ddS )z>Count a total number of concordant pairs in a single sequence.   Nr   )r?   logical_andsum	unsqueezer=   r>   rF   r   r   r   _concordant_element_sumQ   s   @rM   predstargetc                    *   t  fddt jd D dS )z<Count a total number of concordant pairs in given sequences.c                       g | ]}t  |qS r   )rM   r   rF   rN   rO   r   r   r   X       z+_count_concordant_pairs.<locals>.<listcomp>r   r?   catrC   rD   rJ   rS   r   rS   r   _count_concordant_pairsV      *rW   c              
   C   sx   t t | | | |d d k|| ||d d k t | | | |d d k || ||d d kddS )z?Count a total number of discordant pairs in a single sequences.rH   Nr   )r?   
logical_orrI   rJ   rK   rL   r   r   r   _discordant_element_sum[   s   22rZ   c                    rP   )z<Count a total number of discordant pairs in given sequences.c                    rQ   r   )rZ   rR   rS   r   r   r   i   rT   z+_count_discordant_pairs.<locals>.<listcomp>r   rU   rS   r   rS   r   _count_discordant_pairsg   rX   r[   FrB   c                 C   s^   |r	| j ddj} tjd| jd tj| jd}tj|| dd | dd k gdd	dS )z&Convert a sequence to the rank tensor.r   )dimrH   dtypedeviceN)
rB   valuesr?   zerosrD   int32r_   rV   intcumsum)r=   rB   _onesr   r   r   _convert_sequence_to_dense_rankl   s   0rg   c                 C   s   t j| jd | j| jd}t j| jd | j| jd}t j| jd | j| jd}t| jd D ]<}t| dd|f }||dk }||d  d  ||< ||d  |d   ||< ||d  d| d   ||< q.|||fS )zWGet a total number of ties and staistics for p-value calculation for  a given sequence.rH   r]   N         ?   )r?   rb   rD   r^   r_   rC   r
   rJ   )r=   tiesties_p1ties_p2r\   n_tiesr   r   r   	_get_tiesu   s   "
ro   variantc              	   C   s   t | |\} }t| |}t| |}tj| jd | jd}d }}d } }	 }
}|tjkrEt	| } t	|dd}t
| \}}}	t
|\}}
}|||||	||
||f	S )z,Obtain statistics to calculate metric value.r   )r_   NT)rB   )rG   rW   r[   r?   tensorrD   r_   r   r+   rg   ro   )rN   rO   rp   concordant_pairsdiscordant_pairsn_total
preds_tiestarget_tiespreds_ties_p1preds_ties_p2target_ties_p1target_ties_p2r   r   r   _get_metric_metadata   s*   


r{   rr   rs   con_min_dis_pairsrt   ru   rv   c	                 C   s   |t jkr|||  }	|	S |t jkr+||d  d }
|
| |
|  }|t| }	|	S tjdd | jD | j| jd}tjdd |jD |j|jd}t	||}d| |d | |d   }	|	S )z-Calculate Kendall's tau from metric metadata.rH   rh   c                 S      g | ]}t | qS r   lenunique)r   pr   r   r   r      rT   z"_calculate_tau.<locals>.<listcomp>r]   c                 S   r}   r   r~   )r   tr   r   r   r      rT   )
r   r+   r,   r?   sqrtrq   rA   r^   r_   minimum)rN   rO   rr   rs   r|   rt   ru   rv   rp   tautotal_combinationsdenominatorpreds_uniquetarget_uniquemin_classesr   r   r   _calculate_tau   s   

  r   t_valuec                 C   sl   | }t jjt dg|t dg|}|  }|  } || }|	| t jt
d|j|jdS )zObtain p-value for a given Tensor of t-values. Handle ``nan`` which cannot be passed into torch
    distributions.

    When t-value is ``nan``, a resulted p-value should be alson ``nan``.
    g        ri   nanr]   )r?   distributionsnormalNormalrq   toisnan
nan_to_numcdfwherefloatr^   r_   )r   r_   normal_distis_nanp_valuer   r   r   "_get_p_value_for_t_value_from_dist   s   ,
"r   rw   rx   ry   rz   alternativec
                 C   s   ||d  d| d  }
|t jkrd|  t|
d  }n-||d  }|
| | d }|d| | | 7 }||| d| |d   7 }| t| }|	tjkrTt|}|	tjtjfv r`|d9 }t|}|	tjkrm|d9 }|S )z9Calculate p-value for Kendall's tau from metric metadata.rH   rh   rj         	   r`   )	r   r+   r?   r   r1   r:   absr<   r   )r|   rt   ru   rw   rx   rv   ry   rz   rp   r   t_value_denominator_baser   mt_value_denominatorr   r   r   r   _calculate_p_value   s    



r   rH   concat_predsconcat_targetnum_outputsc                 C   sN   t | | t| || |dkr| d} |d}||  || ||fS )a  Update variables required to compute Kendall rank correlation coefficient.

    Args:
        preds: Sequence of data
        target: Sequence of data
        concat_preds: List of batches of preds sequence to be concatenated
        concat_target: List of batches of target sequence to be concatenated
        num_outputs: Number of outputs in multioutput setting

    Raises:
        RuntimeError: If ``preds`` and ``target`` do not have the same shape
    rH   )r	   r   rK   append)rN   rO   r   r   r   r   r   r   _kendall_corrcoef_update   s   




r   c                 C   s   t | ||\	}}}}}}	}
}}|| }t| |||||||	|	}|r.t||||||	|
|||
nd}|jd dkrE| }|durC| nd}|dd|fS )a.  Compute Kendall rank correlation coefficient, and optionally p-value of corresponding statistical test.

    Args:
        Args:
        preds: Sequence of data
        target: Sequence of data
        variant: Indication of which variant of Kendall's tau to be used
        alternative: Alternative hypothesis for for t-test. Possible values:
            - 'two-sided': the rank correlation is nonzero
            - 'less': the rank correlation is negative (less than zero)
            - 'greater':  the rank correlation is positive (greater than zero)
    Nr   rH   r`   )r{   r   r   rD   squeezeclamp)rN   rO   rp   r   rr   rs   ru   rw   rx   rv   ry   rz   rt   r|   r   r   r   r   r   _kendall_corrcoef_compute  sD   
r   r   r2   r   t_testr5   c                 C   s   t |tstdt| d|r|du rtdt|}|r'|r't|nd}t| |g g | jdkr5dn| j	d d\}}t
t|t|||\}	}
|
durS|	|
fS |	S )a  Computes `Kendall Rank Correlation Coefficient`_.

    .. math::
        tau_a = \frac{C - D}{C + D}

    where :math:`C` represents concordant pairs, :math:`D` stands for discordant pairs.

    .. math::
        tau_b = \frac{C - D}{\sqrt{(C + D + T_{preds}) * (C + D + T_{target})}}

    where :math:`C` represents concordant pairs, :math:`D` stands for discordant pairs and :math:`T` represents
    a total number of ties.

    .. math::
        tau_c = 2 * \frac{C - D}{n^2 * \frac{m - 1}{m}}

    where :math:`C` represents concordant pairs, :math:`D` stands for discordant pairs, :math:`n` is a total number
    of observations and :math:`m` is a ``min`` of unique values in ``preds`` and ``target`` sequence.

    Definitions according to Definition according to `The Treatment of Ties in Ranking Problems`_.

    Args:
        preds: Sequence of data of either shape ``(N,)`` or ``(N,d)``
        target: Sequence of data of either shape ``(N,)`` or ``(N,d)``
        variant: Indication of which variant of Kendall's tau to be used
        t_test: Indication whether to run t-test
        alternative: Alternative hypothesis for t-test. Possible values:
            - 'two-sided': the rank correlation is nonzero
            - 'less': the rank correlation is negative (less than zero)
            - 'greater':  the rank correlation is positive (greater than zero)

    Return:
        Correlation tau statistic
        (Optional) p-value of corresponding statistical test (asymptotic)

    Raises:
        ValueError: If ``t_test`` is not of a type bool
        ValueError: If ``t_test=True`` and ``alternative=None``

    Example (single output regression):
        >>> from torchmetrics.functional.regression import kendall_rank_corrcoef
        >>> preds = torch.tensor([2.5, 0.0, 2, 8])
        >>> target = torch.tensor([3, -0.5, 2, 1])
        >>> kendall_rank_corrcoef(preds, target)
        tensor(0.3333)

    Example (multi output regression):
        >>> from torchmetrics.functional.regression import kendall_rank_corrcoef
        >>> preds = torch.tensor([[2.5, 0.0], [2, 8]])
        >>> target = torch.tensor([[3, -0.5], [2, 1]])
        >>> kendall_rank_corrcoef(preds, target)
        tensor([1., 1.])

    Example (single output regression with t-test)
        >>> from torchmetrics.functional.regression import kendall_rank_corrcoef
        >>> preds = torch.tensor([2.5, 0.0, 2, 8])
        >>> target = torch.tensor([3, -0.5, 2, 1])
        >>> kendall_rank_corrcoef(preds, target, t_test=True, alternative='two-sided')
        (tensor(0.3333), tensor(0.4969))

    Example (multi output regression with t-test):
        >>> from torchmetrics.functional.regression import kendall_rank_corrcoef
        >>> preds = torch.tensor([[2.5, 0.0], [2, 8]])
        >>> target = torch.tensor([[3, -0.5], [2, 1]])
        >>> kendall_rank_corrcoef(preds, target, t_test=True, alternative='two-sided')
            (tensor([1., 1.]), tensor([nan, nan]))
    z>Argument `t_test` is expected to be of a type `bool`, but got r   NzCArgument `alternative` is required if `t_test=True` but got `None`.rH   r`   )r   )
isinstanceboolr!   typer   r    r1   r   ndimrD   r   r   )rN   rO   rp   r   r   _variant_alternative_preds_targetr   r   r   r   r   kendall_rank_corrcoefS  s   
J

r   )F)N)r   Fr2   )$typingr   r   r   r   r?   r   typing_extensionsr   (torchmetrics.functional.regression.utilsr   torchmetrics.utilities.checksr	   torchmetrics.utilities.datar
   r   torchmetrics.utilities.enumsr   r   r1   rG   rd   rM   rW   rZ   r[   r   rg   ro   r{   r   r   r   r   r   r   r   r   r   r   <module>   s   	
(	

	

$
%
>
