o
    * iO7                     @  s  U d dl mZ d dlmZmZ d dlZd dl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 ervd 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 eee ee ejeej ej!f  ef Z"de#d< G dd dej$Z%dS )    )annotations)TYPE_CHECKINGUnionN)
check_typeconvert_dtype)Variable)distribution)in_dynamic_mode)multinomial)Sequence)	TypeAlias)Tensor)NestedSequence)_DTypeLiteralr   _CategoricalBoundaryc                   @  sf   e Zd ZU dZded< ded< 	ddddZg fdddZdddZd ddZd!ddZ	d!ddZ
dS )"Categoricala	  
    Categorical distribution is a discrete probability distribution that
    describes the possible results of a random variable that can take on
    one of K possible categories, with the probability of each category
    separately specified.

    The probability mass function (pmf) is:

    .. math::

        pmf(k; p_i) = \prod_{i=1}^{k} p_i^{[x=i]}

    In the above equation:

    * :math:`[x=i]` : it evaluates to 1 if :math:`x==i` , 0 otherwise.

    Args:
        logits(list|tuple|numpy.ndarray|Tensor): The logits input of categorical distribution. The data type is float32 or float64.
        name(str|None, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.

    Examples:
        .. code-block:: python

            >>> import paddle
            >>> from paddle.distribution import Categorical

            >>> paddle.seed(100) # on CPU device
            >>> x = paddle.rand([6])
            >>> print(x)
            Tensor(shape=[6], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.55355281, 0.20714243, 0.01162981, 0.51577556, 0.36369765, 0.26091650])

            >>> paddle.seed(200) # on CPU device
            >>> y = paddle.rand([6])
            >>> print(y)
            Tensor(shape=[6], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.77663314, 0.90824795, 0.15685187, 0.04279523, 0.34468332, 0.79557180])

            >>> cat = Categorical(x)
            >>> cat2 = Categorical(y)

            >>> paddle.seed(1000) # on CPU device
            >>> print(cat.sample([2, 3]))
            Tensor(shape=[2, 3], dtype=int64, place=Place(cpu), stop_gradient=True,
            [[0, 1, 5],
            [3, 4, 5]])

            >>> print(cat.entropy())
            Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
            1.77528250)

            >>> print(cat.kl_divergence(cat2))
            Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.07195196])

            >>> value = paddle.to_tensor([2, 1, 3])
            >>> print(cat.probs(value))
            Tensor(shape=[3], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.00608027, 0.10829761, 0.26965630])

            >>> print(cat.log_prob(value))
            Tensor(shape=[3], dtype=float32, place=Place(cpu), stop_gradient=True,
            [-5.10270691, -2.22287226, -1.31060708])
    r   logitsr   dtypeNr   name
str | NonereturnNonec                 C  s   t  st|dtjttjjtt	fd |dur|nd| _
d| _| |r-|| _t|j| _n.t|tjr@t|jdv r@t|j| _| |d | _| jt| jjkr[tj| j| jd| _tj| jdd	d
}| j| | _dS )a1  
        Args:
            logits(list|tuple|numpy.ndarray|Tensor): The logits input of categorical distribution. The data type is float32 or float64.
            name(str, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`.
        r   r   Nfloat32)r   float64r   )r   Taxiskeepdim)r	   r   npZndarrayr   paddleZpirValuelisttupler   r   Z_validate_argsr   r   
isinstancestrZ
_to_tensorcastsum_prob)selfr   r   Zdist_sum r)   k/home/app/PaddleOCR-VL-test/.venv_paddleocr/lib/python3.10/site-packages/paddle/distribution/categorical.py__init__s   s&   

zCategorical.__init__shapeSequence[int]c           	      C  s   | j d }t st|dttfd tt|}t| jj	}t
|dkr@||dd  }t| jt|dd |d g}n|}| j}t| ||d}tt| }|d|d ||}tj|||d	S )
a  Generate samples of the specified shape.

        Args:
            shape (Sequence[int], optional): Shape of the generated samples.

        Returns:
            Tensor: A tensor with prepended dimensions shape.

        Examples:
            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Categorical

                >>> paddle.seed(100) # on CPU device
                >>> x = paddle.rand([6])
                >>> print(x)
                Tensor(shape=[6], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.55355281, 0.20714243, 0.01162981, 0.51577556, 0.36369765, 0.26091650])

                >>> # doctest: +SKIP('Random output')
                >>> cat = Categorical(x)
                >>> paddle.seed(1000) # on CPU device
                >>> print(cat.sample([2, 3]))
                Tensor(shape=[2, 3], dtype=int64, place=Place(cpu), stop_gradient=True,
                [[0, 1, 5],
                [3, 4, 5]])
        Z_sampler,   sample   Nr   Tr   r   )r   r	   r   r!   r"   r   prodarrayr   r,   lenr   reshaper
   Z_logits_to_probsrangediminsertpopZ	transpose)	r(   r,   r   Znum_samplesZlogits_shapeZsample_shaper   Zsample_indexZpermuter)   r)   r*   r.      s&   

zCategorical.sampleotherc                 C  s   | j d }t st|dtd | jtj| jddd }|jtj|jddd }t|}t|}tj|ddd}tj|ddd}|| }	tj|	|t	| | t	|  dd|d}
|
S )a  The KL-divergence between two Categorical distributions.

        Args:
            other (Categorical): instance of Categorical. The data type is float32.

        Returns:
            Tensor: kl-divergence between two Categorical distributions.

        Examples:
            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Categorical

                >>> paddle.seed(100) # on CPU device
                >>> x = paddle.rand([6])
                >>> print(x)
                Tensor(shape=[6], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.55355281, 0.20714243, 0.01162981, 0.51577556, 0.36369765, 0.26091650])

                >>> paddle.seed(200) # on CPU device
                >>> y = paddle.rand([6])
                >>> print(y)
                Tensor(shape=[6], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.77663314, 0.90824795, 0.15685187, 0.04279523, 0.34468332, 0.79557180])

                >>> cat = Categorical(x)
                >>> cat2 = Categorical(y)

                >>> print(cat.kl_divergence(cat2))
                Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.07195196])
        Z_kl_divergencer9   kl_divergencer   Tr   )r   r   r   )
r   r	   r   r   r   r   maxexpr&   log)r(   r9   r   r   Zother_logitse_logitsZother_e_logitszZother_zprobklr)   r)   r*   r:      s*   
"

zCategorical.kl_divergencec                 C  st   | j d }| jtj| jddd }t|}tj|ddd}|| }tj||t|  dd}tj|d|d}|S )a  Shannon entropy in nats.

        Returns:
            Tensor: Shannon entropy of Categorical distribution. The data type is float32.

        Examples:
            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Categorical

                >>> paddle.seed(100) # on CPU device
                >>> x = paddle.rand([6])
                >>> print(x)
                Tensor(shape=[6], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.55355281, 0.20714243, 0.01162981, 0.51577556, 0.36369765, 0.26091650])

                >>> cat = Categorical(x)

                >>> print(cat.entropy())
                Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
                1.77528250)
        Z_entropyr   Tr   r   g      )scaler   )r   r   r   r;   r<   r&   r=   rC   )r(   r   r   r>   r?   r@   Zneg_entropyentropyr)   r)   r*   rD   	  s   

zCategorical.entropyvaluec                 C  s   | j d }t| jjdkr"tj| j|jdg|d|dj|j|dS t|jdkrDtj| jtj|t| jjd dg dg |dddS tj| j|ddS )a  Probabilities of the given category (``value``).

        If ``logits`` is 2-D or higher dimension, the last dimension will be regarded as
        category, and the others represents the different distributions.
        At the same time, if ``value`` is 1-D Tensor, ``value`` will be broadcast to the
        same number of distributions as ``logits``.
        If ``value`` is not 1-D Tensor, ``value`` should have the same number distributions
        with ``logits. That is, ``value[:-1] = logits[:-1]``.

        Args:
            value (Tensor): The input tensor represents the selected category index.

        Returns:
            Tensor: probability according to the category index.

        Examples:
            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Categorical

                >>> paddle.seed(100) # on CPU device
                >>> x = paddle.rand([6])
                >>> print(x)
                Tensor(shape=[6], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.55355281, 0.20714243, 0.01162981, 0.51577556, 0.36369765, 0.26091650])

                >>> cat = Categorical(x)

                >>> value = paddle.to_tensor([2, 1, 3])
                >>> print(cat.probs(value))
                Tensor(shape=[3], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.00608027, 0.10829761, 0.26965630])
        Z_probsr/   r   r0   rB   )r   r3   r'   r,   r   gatherr4   Ztake_along_axisr(   rE   r   r)   r)   r*   probs+  s$   
#
zCategorical.probsc                 C  s   | j d }tj| ||dS )a  Log probabilities of the given category. Refer to ``probs`` method.

        Args:
            value (Tensor): The input tensor represents the selected category index.

        Returns:
            Tensor: Log probability.

        Examples:
            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Categorical

                >>> paddle.seed(100) # on CPU device
                >>> x = paddle.rand([6])
                >>> print(x)
                Tensor(shape=[6], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.55355281, 0.20714243, 0.01162981, 0.51577556, 0.36369765, 0.26091650])

                >>> cat = Categorical(x)

                >>> value = paddle.to_tensor([2, 1, 3])
                >>> print(cat.log_prob(value))
                Tensor(shape=[3], dtype=float32, place=Place(cpu), stop_gradient=True,
                [-5.10270691, -2.22287226, -1.31060708])
        Z	_log_probr0   )r   r   r=   rH   rG   r)   r)   r*   log_proba  s   
zCategorical.log_prob)N)r   r   r   r   r   r   )r,   r-   r   r   )r9   r   r   r   )r   r   )rE   r   r   r   )__name__
__module____qualname____doc____annotations__r+   r.   r:   rD   rH   rI   r)   r)   r)   r*   r   .   s   
 A$
9
9
"6r   )&
__future__r   typingr   r   numpyr   r   Zpaddle.base.data_feederr   r   Zpaddle.base.frameworkr   Zpaddle.distributionr   Zpaddle.frameworkr	   Zpaddle.tensorr
   collections.abcr   Znumpy.typingZnptZtyping_extensionsr   r   Zpaddle._typingr   Zpaddle._typing.dtype_liker   floatZNDArrayr   r   r   rN   Distributionr   r)   r)   r)   r*   <module>   s0   