o
    .wi?#                     @   s   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
 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sKdgZ	ddededejfddZG dd deZdS )    )Sequencedeepcopy)AnyOptionalUnionN)apply_to_collection)Tensor)
ModuleList)Metric)_MATPLOTLIB_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPE)WrapperMetricBootStrapper.plotpoissonsizesampling_strategyreturnc                 C   s^   |dkrt jd}|| f}t | j| ddS |dkr+t jt | | d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

    r      r   dimmultinomialT)num_samplesreplacementzUnknown sampling strategy)
torchdistributionsPoissonsamplearangerepeat_interleavelongr   ones
ValueError)r   r   pn r&   `/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/torchmetrics/wrappers/bootstrapping.py_bootstrap_sampler    s   r(   c                       s   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dZdededdfddZdeeef fddZdededef fddZd! fddZ	d"dee
eee f  dee defddZ  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_update
   NFr   base_metricnum_bootstrapsmeanstdquantilerawr   kwargsr   c           
         s   t  jdi | t tstd  t fddt|D | _|| _|| _	|| _
|| _|| _d}	||	vrBtd|	 d| || _d S )NzKExpected base metric to be an instance of torchmetrics.Metric but received c                    s   g | ]}t  qS r&   r   ).0_r,   r&   r'   
<listcomp>n       z)BootStrapper.__init__.<locals>.<listcomp>)r   r   z5Expected argument ``sampling_strategy`` to be one of z but received r&   )super__init__
isinstancer   r#   r
   rangemetricsr-   r.   r/   r0   r1   r   )
selfr,   r-   r.   r/   r0   r1   r   r2   allowed_sampling	__class__r5   r'   r9   ]   s&   

zBootStrapper.__init__argsc           
      O   s   t |tjt}t |tjt}t|dkr|d }nt|dkr(tt| }ntdt| j	D ]5}t
|| jd| j}| dkrEq1t |tjtjd|d}t |tjtjd|d}	| j| j|i |	 q1dS )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#   r;   r-   r(   r   todevicenumelindex_selectr<   update)
r=   rA   r2   
args_sizeskwargs_sizesr   idx
sample_idxnew_args
new_kwargsr&   r&   r'   rK   ~   s   
zBootStrapper.updatec                 C   sx   t jdd | jD dd}i }| jr|jdd|d< | jr%|jdd|d< | jdur3t || j|d< | jr:||d	< |S )
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.

        c                 S   s   g | ]}|  qS r&   )compute)r3   mr&   r&   r'   r6      r7   z(BootStrapper.compute.<locals>.<listcomp>r   r   r.   r/   Nr0   r1   )r   stackr<   r.   r/   r0   r1   )r=   computed_valsoutput_dictr&   r&   r'   rR      s   
zBootStrapper.computec                    s   t t| j|i |S )z9Use the original forward method of the base metric class.)r8   r   forward)r=   rA   r2   r?   r&   r'   rW      s   zBootStrapper.forwardc                    s"   | j D ]}|  qt   dS )z#Reset the state of the base metric.N)r<   resetr8   )r=   rS   r?   r&   r'   rX      s   

zBootStrapper.resetvalaxc                 C   s   |  ||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=   rY   rZ   r&   r&   r'   plot   s   *r   )r+   TTNFr   )r   N)NN)__name__
__module____qualname____doc__r*   r   bool__annotations__r   intr   floatr	   strr   r9   rK   dictrR   rW   rX   r   r   r   r\   __classcell__r&   r&   r?   r'   r)   7   sP   
 #	
!r)   )r   )collections.abcr   copyr   typingr   r   r   r   lightning_utilitiesr   r	   torch.nnr
   torchmetrics.metricr   torchmetrics.utilities.importsr   torchmetrics.utilities.plotr   r   torchmetrics.wrappers.abstractr   __doctest_skip__rc   re   r(   r)   r&   r&   r&   r'   <module>   s,   
