o
    .wiA                     @   s  d dl mZ d dlZd dlmZ d dlmZmZmZm	Z	 d dl
mZ d dlmZ d dlmZ dejd	ed
dfddZdejd
ejfddZ			d0dejdejdejd	ededee ded
eeejejejejf  fddZdeeejejejejf  d
eeejf fddZdeeejejejejf  d
eeejf fddZ			d0dejdejdejd	ededee ded
eeejf fddZdejd ejd!ejd"ejd
eeejf f
d#d$Z			d0dejdejdedee ded
eeejf fd%d&Zdejd ejd!ejd"ejd
eeejf f
d'd(Z 			d0dejdejdejdedee ded
eeejf fd)d*Z!	+			d1dejdejdejd,ed- dedee ded
eeejf fd.d/Z"dS )2    )OptionalN)Literal)"_binary_stat_scores_arg_validation_binary_stat_scores_format%_binary_stat_scores_tensor_validation_binary_stat_scores_update)rank_zero_warn)_safe_divide)_flexible_bincountgroups
num_groupsreturnc                 C   sP   t | |krtdt |  dd| d| jt jkr&td| j ddS )zValidate groups tensor.

    - The largest number in the tensor should not be larger than the number of groups. The group identifiers should
    be ``0, 1, ..., (num_groups - 1)``.
    - The group tensor should be dtype long.

    z+The largest number in the groups tensor is z$, which is larger than the specifiedznumber of groups zB. The group identifiers should be ``0, 1, ..., (num_groups - 1)``.z2Expected dtype of argument groups to be long, not .N)torchmax
ValueErrordtypelong)r   r    r   r/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/torchmetrics/functional/classification/group_fairness.py_groups_validation   s   
r   c                 C   s   |  | jd dS )z1Reshape groups to correspond to preds and target.r   )reshapeshape)r   r   r   r   _groups_format/   s   r         ?Tpredstarget	thresholdignore_indexvalidate_argsc                 C   s   |rt |d| t| |d| t|| t| |||\} }t|}t|d\}}| | } || }t|	 
  }	ttj| |	dd}
ttj||	dd}dd t|
|D S )zCompute the true/false positives and true/false negatives rates for binary classification by group.

    Related to `Type I and Type II errors`_.

    global   r   )dimc                 S   s   g | ]	\}}t ||qS r   )r   ).0group_pgroup_tr   r   r   
<listcomp>S   s    z._binary_groups_stat_scores.<locals>.<listcomp>)r   r   r   r   r   r   sortsqueezer
   detachcputolistlistsplitzip)r   r   r   r   r   r   r    indexesindicessplit_sizesgroup_predsgroup_targetr   r   r   _binary_groups_stat_scores4   s   
r5   group_statsc                 C   s   dd t | D S )z+Compute rates for all the group statistics.c                 S   s0   i | ]\}}d | t |t |  qS )group_)r   stacksum)r$   groupstatsr   r   r   
<dictcomp>Z   s   0 z"_groups_reduce.<locals>.<dictcomp>)	enumerater6   r   r   r   _groups_reduceV   s   r?   c                 C   sN   t dd | D t dd | D t dd | D t dd | D dS )zCTransform group statistics by creating a tensor for each statistic.c                 S      g | ]}|d  qS )r   r   r$   statr   r   r   r'   b       z*_groups_stat_transform.<locals>.<listcomp>c                 S   r@   )r"   r   rA   r   r   r   r'   c   rC   c                 S   r@   )   r   rA   r   r   r   r'   d   rC   c                 S   r@   )   r   rA   r   r   r   r'   e   rC   )tpfptnfn)r   r8   r>   r   r   r   _groups_stat_transform]   s
   rJ   c                 C   s   t | ||||||}t|S )a3	  Compute the true/false positives and true/false negatives rates for binary classification by group.

    Related to `Type I and Type II errors`_.

    Accepts the following input tensors:

    - ``preds`` (int or float tensor): ``(N, ...)``. If preds is a floating point tensor with values outside
      [0,1] range we consider the input to be logits and will auto apply sigmoid per element. Additionally,
      we convert to int tensor with thresholding using the value in ``threshold``.
    - ``target`` (int tensor): ``(N, ...)``.
    - ``groups`` (int tensor): ``(N, ...)``. The group identifiers should be ``0, 1, ..., (num_groups - 1)``.

    The additional dimensions are flatted along the batch dimension.

    Args:
        preds: Tensor with predictions.
        target: Tensor with true labels.
        groups: Tensor with group identifiers. The group identifiers should be ``0, 1, ..., (num_groups - 1)``.
        num_groups: The number of groups.
        threshold: Threshold for transforming probability to binary {0,1} predictions.
        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    Returns:
        The metric returns a dict with a group identifier as key and a tensor with the tp, fp, tn and fn rates as value.

    Example (preds is int tensor):
        >>> from torchmetrics.functional.classification import binary_groups_stat_rates
        >>> target = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> preds = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> groups = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> binary_groups_stat_rates(preds, target, groups, 2)
        {'group_0': tensor([0., 0., 1., 0.]), 'group_1': tensor([1., 0., 0., 0.])}

    Example (preds is float tensor):
        >>> from torchmetrics.functional.classification import binary_groups_stat_rates
        >>> target = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> preds = torch.tensor([0.11, 0.84, 0.22, 0.73, 0.33, 0.92])
        >>> groups = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> binary_groups_stat_rates(preds, target, groups, 2)
        {'group_0': tensor([0., 0., 1., 0.]), 'group_1': tensor([1., 0., 0., 0.])}

    )r5   r?   )r   r   r   r   r   r   r    r6   r   r   r   binary_groups_stat_ratesi   s   6rK   rF   rG   rH   rI   c                 C   sP   t | | | | | | }t|}t|}d| d| t || || iS )z5Compute demographic parity based on the binary stats.DP__r	   r   argminargmax)rF   rG   rH   rI   	pos_ratesmin_pos_rate_idmax_pos_rate_idr   r   r   "_compute_binary_demographic_parity   s
   

rT   c           	      C   sF   t |jd }t | j}t| ||||||}t|}tdi |S )a	  `Demographic parity`_ compares the positivity rates between all groups.

    If more than two groups are present, the disparity between the lowest and highest group is reported. The lowest
    positivity rate is divided by the highest, so a lower value means more discrimination against the numerator.
    In the results this is also indicated as the key of dict is DP_{identifier_low_group}_{identifier_high_group}.

    .. math::
        \text{DP} = \dfrac{\min_a PR_a}{\max_a PR_a}.

    where :math:`\text{PR}` represents the positivity rate for group :math:`\text{a}`.

    Accepts the following input tensors:

    - ``preds`` (int or float tensor): ``(N, ...)``. If preds is a floating point tensor with values outside
      [0,1] range we consider the input to be logits and will auto apply sigmoid per element. Additionally,
      we convert to int tensor with thresholding using the value in ``threshold``.
    - ``groups`` (int tensor): ``(N, ...)``. The group identifiers should be ``0, 1, ..., (num_groups - 1)``.
    - ``target`` (int tensor): ``(N, ...)``.

    The additional dimensions are flatted along the batch dimension.

    Args:
        preds: Tensor with predictions.
        groups: Tensor with group identifiers. The group identifiers should be ``0, 1, ..., (num_groups - 1)``.
        threshold: Threshold for transforming probability to binary {0,1} predictions.
        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    Returns:
        The metric returns a dict where the key identifies the group with the lowest and highest positivity rates
        as follows: DP_{identifier_low_group}_{identifier_high_group}. The value is a tensor with the DP rate.

    Example (preds is int tensor):
        >>> from torchmetrics.functional.classification import demographic_parity
        >>> preds = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> groups = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> demographic_parity(preds, groups)
        {'DP_0_1': tensor(0.)}

    Example (preds is float tensor):
        >>> from torchmetrics.functional.classification import demographic_parity
        >>> preds = torch.tensor([0.11, 0.84, 0.22, 0.73, 0.33, 0.92])
        >>> groups = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> demographic_parity(preds, groups)
        {'DP_0_1': tensor(0.)}

    r   Nr   )r   uniquer   zerosr5   rJ   rT   )	r   r   r   r   r    r   r   r6   transformed_group_statsr   r   r   demographic_parity   s
   8rX   c                 C   sD   t | | | }t|}t|}d| d| t || || iS )z4Compute equal opportunity based on the binary stats.EO_rM   rN   )rF   rG   rH   rI   true_pos_ratesrR   rS   r   r   r   !_compute_binary_equal_opportunity   s   

r[   c           	      C   s:   t |jd }t| ||||||}t|}tdi |S )a
  `Equal opportunity`_ compares the true positive rates between all groups.

    If more than two groups are present, the disparity between the lowest and highest group is reported. The lowest
    true positive rate is divided by the highest, so a lower value means more discrimination against the numerator.
    In the results this is also indicated as the key of dict is EO_{identifier_low_group}_{identifier_high_group}.

    .. math::
        \text{DP} = \dfrac{\min_a TPR_a}{\max_a TPR_a}.

    where :math:`\text{TPR}` represents the true positives rate for group :math:`\text{a}`.

    Accepts the following input tensors:

    - ``preds`` (int or float tensor): ``(N, ...)``. If preds is a floating point tensor with values outside
      [0,1] range we consider the input to be logits and will auto apply sigmoid per element. Additionally,
      we convert to int tensor with thresholding using the value in ``threshold``.
    - ``target`` (int tensor): ``(N, ...)``.
    - ``groups`` (int tensor): ``(N, ...)``. The group identifiers should be ``0, 1, ..., (num_groups - 1)``.

    The additional dimensions are flatted along the batch dimension.

    Args:
        preds: Tensor with predictions.
        target: Tensor with true labels.
        groups: Tensor with group identifiers. The group identifiers should be ``0, 1, ..., (num_groups - 1)``.
        threshold: Threshold for transforming probability to binary {0,1} predictions.
        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    Returns:
        The metric returns a dict where the key identifies the group with the lowest and highest true positives rates
        as follows: EO_{identifier_low_group}_{identifier_high_group}. The value is a tensor with the EO rate.

    Example (preds is int tensor):
        >>> from torchmetrics.functional.classification import equal_opportunity
        >>> target = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> preds = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> groups = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> equal_opportunity(preds, target, groups)
        {'EO_0_1': tensor(0.)}

    Example (preds is float tensor):
        >>> from torchmetrics.functional.classification import equal_opportunity
        >>> target = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> preds = torch.tensor([0.11, 0.84, 0.22, 0.73, 0.33, 0.92])
        >>> groups = torch.tensor([0, 1, 0, 1, 0, 1])
        >>> equal_opportunity(preds, target, groups)
        {'EO_0_1': tensor(0.)}

    r   Nr   )r   rU   r   r5   rJ   r[   )	r   r   r   r   r   r    r   r6   rW   r   r   r   equal_opportunity  s   <r\   alltaskrX   r\   r]   c           
      C   s   |dvrt d| d|dkr|durtdt t| j}t|jd }t| ||||||}t|}	|dkr@t	d
i |	S |dkrKt
d
i |	S |d	kr_i t	d
i |	t
d
i |	S dS )a  Compute either `Demographic parity`_ and `Equal opportunity`_ ratio for binary classification problems.

    This is done by setting the ``task`` argument to either ``'demographic_parity'``, ``'equal_opportunity'``
    or ``all``. See the documentation of
    :func:`~torchmetrics.functional.classification.demographic_parity`
    and :func:`~torchmetrics.functional.classification.equal_opportunity` for the specific details of
    each argument influence and examples.

    Args:
        preds: Tensor with predictions.
        target: Tensor with true labels (not required for demographic_parity).
        groups: Tensor with group identifiers. The group identifiers should be ``0, 1, ..., (num_groups - 1)``.
        task: The task to compute. Can be either ``demographic_parity`` or ``equal_opportunity`` or ``all``.
        threshold: Threshold for transforming probability to binary {0,1} predictions.
        ignore_index:
            Specifies a target value that is ignored and does not contribute to the metric calculation
        validate_args: bool indicating if input arguments and tensors should be validated for correctness.
            Set to ``False`` for faster computations.

    r_   zfExpected argument `task` to either be ``demographic_parity``,``equal_opportunity`` or ``all`` but got r   rX   Nz6The task demographic_parity does not require a target.r   r\   r]   r   )r   r   UserWarningr   rV   r   rU   r5   rJ   rT   r[   )
r   r   r   r^   r   r   r    r   r6   rW   r   r   r   binary_fairnessF  s0   
ra   )r   NT)r]   r   NT)#typingr   r   typing_extensionsr   2torchmetrics.functional.classification.stat_scoresr   r   r   r   torchmetrics.utilitiesr   torchmetrics.utilities.computer	   torchmetrics.utilities.datar
   Tensorintr   r   floatboolr-   tupler5   dictstrr?   rJ   rK   rT   rX   r[   r\   ra   r   r   r   r   <module>   s  

"


;

B

H