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	m
Z
 d dlmZ d dlmZmZ d dlmZ d d	lmZ d d
lmZ d dlmZmZ esOdgZG dd deZdS )    )Sequence)partial)AnyOptionalUnionN)Tensortensor)Literal)_psnr_compute_psnr_update)Metric)rank_zero_warn)_MATPLOTLIB_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPEPeakSignalNoiseRatio.plotc                       s  e Zd ZU dZdZeed< dZeed< dZeed< dZ	e
ed< eed	< eed
< 				d"deee
ee
e
f f  de
ded deeeeedf f  deddf fddZdededdfddZdefddZ	d#deeeee f  dee defd d!Z  ZS )$PeakSignalNoiseRatioa
  `Compute Peak Signal-to-Noise Ratio`_ (PSNR).

    .. math:: \text{PSNR}(I, J) = 10 * \log_{10} \left(\frac{\max(I)^2}{\text{MSE}(I, J)}\right)

    Where :math:`\text{MSE}` denotes the `mean-squared-error`_ function.

    As input to ``forward`` and ``update`` the metric accepts the following input

    - ``preds`` (:class:`~torch.Tensor`): Predictions from model of shape ``(N,C,H,W)``
    - ``target`` (:class:`~torch.Tensor`): Ground truth values of shape ``(N,C,H,W)``

    As output of `forward` and `compute` the metric returns the following output

    - ``psnr`` (:class:`~torch.Tensor`): if ``reduction!='none'`` returns float scalar tensor with average PSNR value
      over sample else returns tensor of shape ``(N,)`` with PSNR values per sample

    Args:
        data_range:
            the range of the data. If None, it is determined from the data (max - min). If a tuple is provided then
            the range is calculated as the difference and input is clamped between the values.
            The ``data_range`` must be given when ``dim`` is not None.
        base: a base of a logarithm to use.
        reduction: a method to reduce metric score over labels.

            - ``'elementwise_mean'``: takes the mean (default)
            - ``'sum'``: takes the sum
            - ``'none'`` or ``None``: no reduction will be applied

        dim:
            Dimensions to reduce PSNR scores over, provided as either an integer or a list of integers. Default is
            None meaning scores will be reduced across all dimensions and all batches.
        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Raises:
        ValueError:
            If ``dim`` is not ``None`` and ``data_range`` is not given.

    Example:
        >>> from torchmetrics.image import PeakSignalNoiseRatio
        >>> psnr = PeakSignalNoiseRatio()
        >>> preds = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
        >>> target = torch.tensor([[3.0, 2.0], [1.0, 0.0]])
        >>> psnr(preds, target)
        tensor(2.5527)

    Tis_differentiablehigher_is_betterFfull_state_update        plot_lower_bound
min_target
max_targetN      $@elementwise_mean
data_rangebase	reduction)r   sumnoneNdim.kwargsreturnc                    sb  t  jdi | |d u r|dkrtd| d |d u r2| jdtddd | jdtd	dd n| jdg d
d | jdg d
d d | _|d u rk|d urQtdd | _| jdtdtj	d | jdtdtj
d n/t|tr| jdt|d |d	  dd ttj|d	 |d d| _n| jdtt|dd || _|| _t|trt|| _d S || _d S )Nr   zThe `reduction=z.` will not have any effect when `dim` is None.sum_squared_errorr   r   )defaultdist_reduce_fxtotalr   catz6The `data_range` must be given when `dim` is not None.r   r   r      mean)minmax )super__init__r   	add_stater   clamping_fn
ValueErrorr   torchr+   r,   
isinstancetupler   clampfloatr   r   r   r!   )selfr   r   r   r!   r"   	__class__r-   T/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/torchmetrics/image/psnr.pyr/   X   s,   
 "zPeakSignalNoiseRatio.__init__predstargetc                 C   s*  | j dur|  |}|  |}t||| jd\}}| jdu rg| jdu r7t| | j| _t|	 | j
| _
t| jtsGtdt| j t| jtsWtdt| j |  j|7  _|  j|7  _dS t| jtswtdt| j t| jtstdt| j | j| | j| dS )z*Update state with predictions and targets.N)r!   z:Expected `self.sum_squared_error` to be a Tensor, but got z.Expected `self.total` to be a Tensor, but got z8Expected `self.sum_squared_error` to be a list, but got z,Expected `self.total` to be a list, but got )r1   r   r!   r   r3   minimumr+   r   maximumr,   r   r4   r$   r   	TypeErrortyper'   listappend)r8   r<   r=   r$   num_obsr-   r-   r;   update   s0   




zPeakSignalNoiseRatio.updatec                 C   s   | j dur| j n| j| j }t| jtjr| j}nt| jtr+tdd | jD }nt	dt| j
tjr:| j
}nt| j
trLtdd | j
D }nt	dt|||| j| jdS )z.Compute peak signal-to-noise ratio over state.Nc                 S      g | ]}|  qS r-   flatten.0valuer-   r-   r;   
<listcomp>       z0PeakSignalNoiseRatio.compute.<locals>.<listcomp>z>Expected sum_squared_error to be a Tensor or a list of Tensorsc                 S   rF   r-   rG   rI   r-   r-   r;   rL      rM   z2Expected total to be a Tensor or a list of Tensors)r   r   )r   r   r   r4   r$   r3   r   rB   r(   r@   r'   r
   r   r   )r8   r   r$   r'   r-   r-   r;   compute   s   zPeakSignalNoiseRatio.compute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.image import PeakSignalNoiseRatio
            >>> metric = PeakSignalNoiseRatio()
            >>> preds = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
            >>> target = torch.tensor([[3.0, 2.0], [1.0, 0.0]])
            >>> metric.update(preds, target)
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> import torch
            >>> from torchmetrics.image import PeakSignalNoiseRatio
            >>> metric = PeakSignalNoiseRatio()
            >>> preds = torch.tensor([[0.0, 1.0], [2.0, 3.0]])
            >>> target = torch.tensor([[3.0, 2.0], [1.0, 0.0]])
            >>> values = [ ]
            >>> for _ in range(10):
            ...     values.append(metric(preds, target))
            >>> fig_, ax_ = metric.plot(values)

        )_plot)r8   rO   rP   r-   r-   r;   plot   s   ,r   )Nr   r   N)NN)__name__
__module____qualname____doc__r   bool__annotations__r   r   r   r7   r   r   r   r5   r	   intr   r/   rE   rN   r   r   r   rR   __classcell__r-   r-   r9   r;   r       sF   
 /' r   )collections.abcr   	functoolsr   typingr   r   r   r3   r   r   typing_extensionsr	   "torchmetrics.functional.image.psnrr
   r   torchmetrics.metricr   torchmetrics.utilitiesr   torchmetrics.utilities.importsr   torchmetrics.utilities.plotr   r   __doctest_skip__r   r-   r-   r-   r;   <module>   s   