o
    .wi                     @   s   d dl mZ d dlmZmZmZm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 d d
lmZmZ esMdgZG dd deZdS )    )Sequence)AnyListOptionalUnion)Tensortensor)Literal)_sam_compute_sam_update)Metric)rank_zero_warn)dim_zero_cat)_MATPLOTLIB_AVAILABLE)_AX_TYPE_PLOT_OUT_TYPESpectralAngleMapper.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< d	Ze
ed
< ee ed< ee ed< eed< eed< 	ddeed  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 )!SpectralAngleMappera  `Spectral Angle Mapper`_ determines the spectral similarity between image spectra and reference spectra.

    It works by calculating the angle between the spectra, where small angles between indicate high similarity and
    high angles indicate low similarity.

    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

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

    Args:
        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

        kwargs: Additional keyword arguments, see :ref:`Metric kwargs` for more info.

    Return:
        Tensor with SpectralAngleMapper score

    Example:
        >>> from torch import rand
        >>> from torchmetrics.image import SpectralAngleMapper
        >>> preds = rand([16, 3, 16, 16])
        >>> target = rand([16, 3, 16, 16])
        >>> sam = SpectralAngleMapper()
        >>> sam(preds, target)
        tensor(0.5914)

    Fhigher_is_betterTis_differentiablefull_state_update        plot_lower_boundg      ?plot_upper_boundpredstargetsum_samnumelelementwise_mean	reduction)r   sumnonekwargsreturnNc                    s   t  jdi | |dvrtd| d|dks|d u r2td | jdg dd | jd	g dd n| jd
tddd | jdtddd || _d S )N)r   r    r!   NzThe `reduction` zI is not valid. Valid options are `elementwise_mean`, `sum`, `none`, None.r!   zMetric `SpectralAngleMapper` will save all targets and predictions in the buffer when using`reduction=None` or `reduction='none'. For large datasets, this may lead to a large memory footprint.r   cat)defaultdist_reduce_fxr   r   r   r    )r&   r   r    )super__init__
ValueErrorr   	add_stater   r   )selfr   r"   	__class__r'   S/home/ubuntu/sommelier/.venv/lib/python3.10/site-packages/torchmetrics/image/sam.pyr)   Q   s   

zSpectralAngleMapper.__init__c                 C   s   t ||\}}| jdks| jdu r| j| | j| dS t||dd}|  j|7  _|j}|  j|d |d  |d  7  _dS )z*Update state with predictions and targets.r!   Nr    )r   r         )	r   r   r   appendr   r
   r   shaper   )r,   r   r   	sam_scorep_shaper'   r'   r/   updateg   s   &zSpectralAngleMapper.updatec                 C   sR   | j dks
| j du rt| j}t| j}t||| j S | j dkr&| j| j S | jS )zCompute spectra over state.r!   Nr   )r   r   r   r   r
   r   r   )r,   r   r   r'   r'   r/   computes   s
   

zSpectralAngleMapper.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 single value
            >>> from torch import rand
            >>> from torchmetrics.image import SpectralAngleMapper
            >>> preds = rand([16, 3, 16, 16])
            >>> target = rand([16, 3, 16, 16])
            >>> metric = SpectralAngleMapper()
            >>> metric.update(preds, target)
            >>> fig_, ax_ = metric.plot()

        .. plot::
            :scale: 75

            >>> # Example plotting multiple values
            >>> from torch import rand
            >>> from torchmetrics.image import SpectralAngleMapper
            >>> preds = rand([16, 3, 16, 16])
            >>> target = rand([16, 3, 16, 16])
            >>> metric = SpectralAngleMapper()
            >>> values = [ ]
            >>> for _ in range(10):
            ...     values.append(metric(preds, target))
            >>> fig_, ax_ = metric.plot(values)

        )_plot)r,   r8   r9   r'   r'   r/   plot{   s   ,r   )r   )NN)__name__
__module____qualname____doc__r   bool__annotations__r   r   r   floatr   r   r   r   r	   r   r)   r6   r7   r   r   r   r   r;   __classcell__r'   r'   r-   r/   r      s:   
 &
	r   N)collections.abcr   typingr   r   r   r   torchr   r   typing_extensionsr	   !torchmetrics.functional.image.samr
   r   torchmetrics.metricr   torchmetrics.utilitiesr   torchmetrics.utilities.datar   torchmetrics.utilities.importsr   torchmetrics.utilities.plotr   r   __doctest_skip__r   r'   r'   r'   r/   <module>   s   