o
    Me/                     @   s   d dl Z d dl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mZmZmZ d dlmZmZ d dlmZmZmZmZmZmZmZmZ d dlmZmZmZm Z  G d	d
 d
ej!Z"dS )    N)_C_ops_legacy_C_ops)distribution)core)check_dtype
check_typecheck_variable_and_dtypeconvert_dtype)_non_static_modein_dygraph_mode)control_flowelementwise_addelementwise_divelementwise_mulelementwise_subnnopstensor)arangeconcat	gather_ndmultinomialc                   @   sB   e Zd ZdZdddZdd Zdd Zd	d
 Zdd Z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, 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)
            # [0.5535528  0.20714243 0.01162981
            #  0.51577556 0.36369765 0.2609165 ]

            paddle.seed(200) # on CPU device
            y = paddle.rand([6])
            print(y)
            # [0.77663314 0.90824795 0.15685187
            #  0.04279523 0.34468332 0.7955718 ]

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

            paddle.seed(1000) # on CPU device
            cat.sample([2,3])
            # [[0, 0, 5],
            #  [3, 4, 5]]

            cat.entropy()
            # [1.77528]

            cat.kl_divergence(cat2)
            # [0.071952]

            value = paddle.to_tensor([2,1,3])
            cat.probs(value)
            # [0.00608027 0.108298 0.269656]

            cat.log_prob(value)
            # [-5.10271 -2.22287 -1.31061]

    Nc                 C   s   t  st|dtjtjttfd |dur|nd| _d| _	| 
|r+|| _t|j	| _	n,t|tjr<t|j	dv r<|j	| _	| |d | _| j	t| jj	krWt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`.
        logitsr   Nfloat32)r   Zfloat64r   )dtypeTaxiskeepdim)r
   r   npZndarrayr   Variablelisttuplenamer   Z_validate_argsr   r	   
isinstancestrZ
_to_tensorcastpaddlesum_prob)selfr   r$   Zdist_sum r,   OD:\Projects\ConvertPro\env\Lib\site-packages\paddle/distribution/categorical.py__init__^   s*   
zCategorical.__init__c           	      C   s   | j d }t st|dt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 (list): 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)
                # [0.5535528  0.20714243 0.01162981
                #  0.51577556 0.36369765 0.2609165 ]

                cat = Categorical(x)

                paddle.seed(1000) # on CPU device
                cat.sample([2,3])
                # [[0, 0, 5],
                #  [3, 4, 5]]

        Z_sampleshapesample   Nr   Tr   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-   r0   y   s&   

zCategorical.samplec                 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)
                # [0.5535528  0.20714243 0.01162981
                #  0.51577556 0.36369765 0.2609165 ]

                paddle.seed(200) # on CPU device
                y = paddle.rand([6])
                print(y)
                # [0.77663314 0.90824795 0.15685187
                #  0.04279523 0.34468332 0.7955718 ]

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

                cat.kl_divergence(cat2)
                # [0.071952]

        Z_kl_divergenceotherkl_divergencer   Tr   )r   r   r$   )r$   r
   r   r   r   r(   maxr   expr)   log)r+   r;   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 )aZ  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)
                # [0.5535528  0.20714243 0.01162981
                #  0.51577556 0.36369765 0.2609165 ]

                cat = Categorical(x)

                cat.entropy()
                # [1.77528]

        Z_entropyr   Tr   r   g      )scaler$   )	r$   r   r(   r=   r   r>   r)   r?   rE   )r+   r$   r   r@   rA   rB   Zneg_entropyentropyr,   r,   r-   rF      s   

zCategorical.entropyc                 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 ``vlaue`` 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)
                # [0.5535528  0.20714243 0.01162981
                #  0.51577556 0.36369765 0.2609165 ]

                cat = Categorical(x)

                value = paddle.to_tensor([2,1,3])
                cat.probs(value)
                # [0.00608027 0.108298 0.269656]

        Z_probsr1   r   r2   rD   )r$   r5   r*   r/   r(   gatherr6   Ztake_along_axisr+   valuer$   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)
                # [0.5535528  0.20714243 0.01162981
                #  0.51577556 0.36369765 0.2609165 ]

                cat = Categorical(x)

                value = paddle.to_tensor([2,1,3])
                cat.log_prob(value)
                # [-5.10271 -2.22287 -1.31061]

        Z	_log_probr2   )r$   r(   r?   rJ   rH   r,   r,   r-   log_prob>  s   
zCategorical.log_prob)N)
__name__
__module____qualname____doc__r.   r0   r<   rF   rJ   rK   r,   r,   r,   r-   r       s    
=78#3r   )#mathwarningsnumpyr    r(   r   r   Zpaddle.distributionr   Zpaddle.fluidr   Zpaddle.fluid.data_feederr   r   r   r	   Zpaddle.fluid.frameworkr
   r   Zpaddle.fluid.layersr   r   r   r   r   r   r   r   Zpaddle.tensorr   r   r   r   Distributionr   r,   r,   r,   r-   <module>   s   (