
    is#                         d dl mZ d dlmZ 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 d d
lmZmZ d dlmZ esdgZ	 ddedede	j                  fdZ G d de      Zy)    )Sequence)deepcopy)AnyOptionalUnioncastN)apply_to_collection)Tensor)
ModuleList)Metric)_MATPLOTLIB_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPE)WrapperMetriczBootStrapper.plotsizesampling_strategyreturnc                 L   |dk(  ret         j                  j                  d      }|j                  | f      }t        j                  |       j                  |j                         d      S |dk(  r+t        j                  t        j                  |       | d      S t        d      )	zResample a tensor along its first dimension with replacement.

    Args:
        size: number of samples
        sampling_strategy: the strategy to use for sampling, either ``'poisson'`` or ``'multinomial'``

    Returns:
        resampled tensor

    poisson   r   dimmultinomialT)num_samplesreplacementzUnknown sampling strategy)
torchdistributionsPoissonsamplearangerepeat_interleavelongr   ones
ValueError)r   r   pns       x/Volumes/fast/ai/experiments/voice-extract-mac/.venv/lib/python3.12/site-packages/torchmetrics/wrappers/bootstrapping.py_bootstrap_samplerr(       s     I%''*HHdW||D!33AFFH!3DDM)  D!1tQUVV
0
11    c                        e Zd ZU dZdZee   ed<   	 	 	 	 	 	 ddede	deded	ee
eef      d
edededdf fdZdededdfdZdeeef   fdZdededef fdZd fdZ	 ddee
eee   f      dee   defdZ xZS )BootStrappera  Using `Turn a Metric into a Bootstrapped`_.

    That can automate the process of getting confidence intervals for metric values. This wrapper
    class basically keeps multiple copies of the same base metric in memory and whenever ``update`` or
    ``forward`` is called, all input tensors are resampled (with replacement) along the first dimension.

    Args:
        base_metric: base metric class to wrap
        num_bootstraps: number of copies to make of the base metric for bootstrapping
        mean: if ``True`` return the mean of the bootstraps
        std: if ``True`` return the standard deviation of the bootstraps
        quantile: if given, returns the quantile of the bootstraps. Can only be used with pytorch version 1.6 or higher
        raw: if ``True``, return all bootstrapped values
        sampling_strategy:
            Determines how to produce bootstrapped samplings. Either ``'poisson'`` or ``multinomial``.
            If ``'possion'`` is chosen, the number of times each sample will be included in the bootstrap
            will be given by :math:`n\sim Poisson(\lambda=1)`, which approximates the true bootstrap distribution
            when the number of samples is large. If ``'multinomial'`` is chosen, we will apply true bootstrapping
            at the batch level to approximate bootstrapping over the hole dataset.
        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Example::
        >>> from pprint import pprint
        >>> from torch import randint
        >>> from torchmetrics.wrappers import BootStrapper
        >>> from torchmetrics.classification import MulticlassAccuracy
        >>> base_metric = MulticlassAccuracy(num_classes=5, average='micro')
        >>> bootstrap = BootStrapper(base_metric, num_bootstraps=20)
        >>> bootstrap.update(randint(5, (20,)), randint(5, (20,)))
        >>> output = bootstrap.compute()
        >>> pprint(output)
        {'mean': tensor(0.2089), 'std': tensor(0.0772)}

    Tfull_state_updateNbase_metricnum_bootstrapsmeanstdquantilerawr   kwargsr   c                 L   t        |   di | t        |t              st	        d|       t        t        |      D 	cg c]  }	t        |       c}	      | _        || _	        || _
        || _        || _        || _        d}
||
vrt	        d|
 d|       || _        y c c}	w )NzKExpected base metric to be an instance of torchmetrics.Metric but received )r   r   z5Expected argument ``sampling_strategy`` to be one of z but received  )super__init__
isinstancer   r$   r   ranger   metricsr.   r/   r0   r1   r2   r   )selfr-   r.   r/   r0   r1   r2   r   r3   _allowed_sampling	__class__s              r'   r7   zBootStrapper.__init__]   s     	"6"+v.]^i]jk  "%BW"XBWQ8K#8BW"XY,	 5$44GHXGY !2 35  "3 #Ys   B!argsc                    t        |t        j                  t              }t        |t        j                  t              }t        |      dkD  r|d   }n<t        |      dkD  r#t	        t        |j                                     }nt        d      t        | j                        D ]  }t        || j                        j                  | j                        }|j                         dk(  rGt        |t        j                  t        j                  d|      }t        |t        j                  t        j                  d|      }	 | j                   |   j"                  |i |	  y)ztUpdate the state of the base metric.

        Any tensor passed in will be bootstrapped along dimension 0.

        r   zMNone of the input contained tensors, so could not determine the sampling size)r   )r   indexN)r	   r   r
   lennextitervaluesr$   r9   r.   r(   r   todevicenumelindex_selectr:   update)
r;   r?   r3   
args_sizeskwargs_sizesr   idx
sample_idxnew_args
new_kwargss
             r'   rJ   zBootStrapper.update~   s    )u||SA
*65<<Ez?Qa=D"\00234Dlmm,,-C+DDDZDZ[^^_c_j_jkJ!Q&*4u?Q?QWX`jkH,VU\\5CUCU[\dnoJ$DLL$$h=*= .r)   c           	         t        j                  | j                  D cg c]   }t        t        |      j                         " c}d      }i }| j                  r|j                  d      |d<   | j                  r|j                  d      |d<   | j                  #t        j                  || j                        |d<   | j                  r||d<   |S c c}w )zCompute the bootstrapped metric values.

        Always returns a dict of tensors, which can contain the following keys: ``mean``, ``std``, ``quantile`` and
        ``raw`` depending on how the class was initialized.

        r   r   r/   r0   r1   r2   )
r   stackr:   r   r   computer/   r0   r1   r2   )r;   mcomputed_valsoutput_dicts       r'   rS   zBootStrapper.compute   s     $U1T&!_%<%<%>$U[\]99"/"4"4"4";K88!.!2!2q!2!9K==$&+nn]DMM&RK
#88!.K %Vs   %Cc                 *    t        t        | 
  |i |S )z9Use the original forward method of the base metric class.)r6   r   forward)r;   r?   r3   r>   s      r'   rX   zBootStrapper.forward   s    ]D14B6BBr)   c                     | j                   D ]"  }t        t        |      }|j                          $ t        |           y)z#Reset the state of the base metric.N)r:   r   r   resetr6   )r;   rT   r>   s     r'   rZ   zBootStrapper.reset   s0    AVQAGGI  	r)   valaxc                 &    | j                  ||      S )a  Plot a single or multiple values from the metric.

        Args:
            val: Either a single result from calling `metric.forward` or `metric.compute` or a list of these results.
                If no value is provided, will automatically call `metric.compute` and plot that result.
            ax: An matplotlib axis object. If provided will add plot to that axis

        Returns:
            Figure and Axes object

        Raises:
            ModuleNotFoundError:
                If `matplotlib` is not installed

        .. plot::
            :scale: 75

            >>> # Example plotting a single value
            >>> import torch
            >>> from torchmetrics.wrappers import BootStrapper
            >>> from torchmetrics.regression import MeanSquaredError
            >>> metric = BootStrapper(MeanSquaredError(), num_bootstraps=20)
            >>> metric.update(torch.randn(100,), torch.randn(100,))
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> import torch
            >>> from torchmetrics.wrappers import BootStrapper
            >>> from torchmetrics.regression import MeanSquaredError
            >>> metric = BootStrapper(MeanSquaredError(), num_bootstraps=20)
            >>> values = [ ]
            >>> for _ in range(3):
            ...     values.append(metric(torch.randn(100,), torch.randn(100,)))
            >>> fig_, ax_ = metric.plot(values)

        )_plot)r;   r[   r\   s      r'   plotzBootStrapper.plot   s    T zz#r""r)   )
   TTNFr   )r   N)NN)__name__
__module____qualname____doc__r,   r   bool__annotations__r   intr   floatr
   strr   r7   rJ   dictrS   rX   rZ   r   r   r   r_   __classcell__)r>   s   @r'   r+   r+   7   s*   !F )-x~,
 !37!*33 3 	3
 3 5/03 3 3 3 
3B>C >3 >4 >.c6k* &CS CC CC C _c*#E&(6*:":;<*#IQRZI[*#	*#r)   r+   )r   )collections.abcr   copyr   typingr   r   r   r   r   lightning_utilitiesr	   r
   torch.nnr   torchmetrics.metricr   torchmetrics.utilities.importsr   torchmetrics.utilities.plotr   r   torchmetrics.wrappers.abstractr   __doctest_skip__rg   ri   r(   r+   r5   r)   r'   <module>rv      sm    %  - -  3   & @ @ 8+,
 '2
22 \\2.f#= f#r)   