o
    NeF[                     @   s   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Zd dlZ	d dl
Z
dd	lmZmZmZmZ g d
ZG dd deZG dd deZG dd deZG dd deZG dd deZdS )    )print_function   )control_flow)tensor)ops)nnN   )convert_dtypecheck_variable_and_dtype
check_typecheck_dtype)UniformNormalCategoricalMultivariateNormalDiagc                   @   s@   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dS )DistributionzP
    Distribution is the abstract base class for probability distributions.
    c                 C      t )zSampling from the distribution.NotImplementedErrorself r   QD:\Projects\ConvertPro\env\Lib\site-packages\paddle/fluid/layers/distributions.pysample#      zDistribution.samplec                 C   r   )z The entropy of the distribution.r   r   r   r   r   entropy'   r   zDistribution.entropyc                 C   r   )z7The KL-divergence between self distributions and other.r   )r   otherr   r   r   kl_divergence+   r   zDistribution.kl_divergencec                 C   r   )z&Log probability density/mass function.r   )r   valuer   r   r   log_prob/   r   zDistribution.log_probc                 G   s<   d}d}|D ]}t |tjrd}qd}q|r|rtd|S )z
        Argument validation for distribution args
        Args:
            value (float, list, numpy.ndarray, Variable)
        Raises
            ValueError: if one argument is Variable, all arguments should be Variable
        FTz=if one argument is Variable, all arguments should be Variable)
isinstancer   Variable
ValueError)r   argsZis_variableZ	is_numberargr   r   r   _validate_args3   s   zDistribution._validate_argsc                 G   s   g }g }d}|D ]K}d}t ttjtjfD ]}t||rd} nq|s&J dt|t r2td| }t|}|j	}	t
|	dvrJtd |d}|| }|| q|j	}
|D ]}t||\}}tj|
d	}t|| || qYt|S )
z
        Argument convert args to Variable

        Args:
            value (float, list, numpy.ndarray, Variable)
        Returns:
            Variable of args.
                FTzBtype of input args must be float, list, numpy.ndarray or Variable.r   )float32zUdata type of argument only support float32, your argument will be convert to float32.r'   dtype)floatlistnpndarrayr   r!   r    zerosarrayr)   strwarningswarnZastypeappendZbroadcast_arraysZcreate_tensorZassigntuple)r   r#   Z
numpy_argsZvariable_argstmpr$   Z	valid_argclsZarg_npZ	arg_dtyper)   Zarg_broadcasted_Zarg_variabler   r   r   _to_variableI   s:   	



zDistribution._to_variableN)
__name__
__module____qualname____doc__r   r   r   r   r%   r8   r   r   r   r   r      s    r   c                   @   s2   e Zd ZdZdd ZdddZdd Zd	d
 ZdS )r   a  Uniform distribution with `low` and `high` parameters.

    Mathematical Details

    The probability density function (pdf) is,

    .. math::

        pdf(x; a, b) = \\frac{1}{Z}, \ a <=x <b

    .. math::

        Z = b - a

    In the above equation:

    * :math:`low = a`,
    * :math:`high = b`,
    * :math:`Z`: is the normalizing constant.

    The parameters `low` and `high` must be shaped in a way that supports
    broadcasting (e.g., `high - low` is a valid operation).

    Args:
        low(float|list|numpy.ndarray|Variable): The lower boundary of uniform distribution.The data type is float32
        high(float|list|numpy.ndarray|Variable): The higher boundary of uniform distribution.The data type is float32

    Examples:
        .. code-block:: python

          import numpy as np
          from paddle.fluid import layers
          from paddle.fluid.layers import Uniform

          # Without broadcasting, a single uniform distribution [3, 4]:
          u1 = Uniform(low=3.0, high=4.0)
          # 2 distributions [1, 3], [2, 4]
          u2 = Uniform(low=[1.0, 2.0],
                        high=[3.0, 4.0])
          # 4 distributions
          u3 = Uniform(low=[[1.0, 2.0],
                    [3.0, 4.0]],
               high=[[1.5, 2.5],
                     [3.5, 4.5]])

          # With broadcasting:
          u4 = Uniform(low=3.0, high=[5.0, 6.0, 7.0])

          # Complete example
          value_npdata = np.array([0.8], dtype="float32")
          value_tensor = layers.create_tensor(dtype="float32")
          layers.assign(value_npdata, value_tensor)

          uniform = Uniform([0.], [2.])

          sample = uniform.sample([2])
          # a random tensor created by uniform distribution with shape: [2, 1]
          entropy = uniform.entropy()
          # [0.6931472] with shape: [1]
          lp = uniform.log_prob(value_tensor)
          # [-0.6931472] with shape: [1]
    c                 C   s   t |dttjtjtfd t |dttjtjtfd d| _d| _| 	||r1d| _|| _
|| _d S t|tr>t|tr>d| _| ||\| _
| _d S )Nlowr   highFT)r   r*   r,   r-   r   r!   r+   all_arg_is_floatbatch_size_unknownr%   r=   r>   r    r8   )r   r=   r>   r   r   r   __init__      
zUniform.__init__r   c                 C   s   t |dtd t |dtd t| j| j j}| jrL|| }t| j| j || | jj	d}t
j||jdd|d}||| j | j  | j }t
||S || }t
j||dtj|| jj	d| j| j   | j }| jrrt
||S |S )	  Generate samples of the specified shape.

        Args:
          shape (list): 1D `int32`. Shape of the generated samples.
          seed (int): Python integer number.

        Returns:
          Variable: A tensor with prepended dimensions shape.The data type is float32.

        shaper   seedr&         ?)minmaxrE   )rE   r(   )r   r+   intr=   r>   rD   r@   r   fill_constant_batch_size_liker)   r   Zuniform_random_batch_size_likereshapeZuniform_randomr.   r?   )r   rD   rE   batch_shapeoutput_shapezero_tmpZuniform_random_tmpoutputr   r   r   r      s8   

zUniform.samplec                 C   sn   t |dddgd t| j|}t|| j}tj||jd}tj||jd}t	|| t	| j| j  S )Log probability density/mass function.

        Args:
          value (Variable): The input tensor.

        Returns:
          Variable: log probability.The data type is same with value.

        r   r'   float64r   r(   )
r
   r   	less_thanr=   r>   r   castr)   r   log)r   r   Zlb_boolZub_boolZlbZubr   r   r   r      s   
 zUniform.log_probc                 C   s   t | j| j S )zShannon entropy in nats.

        Returns:
          Variable: Shannon entropy of uniform distribution.The data type is float32.

        )r   rT   r>   r=   r   r   r   r   r      s   zUniform.entropyNr   )r9   r:   r;   r<   rA   r   r   r   r   r   r   r   r   s   s    ?
"r   c                   @   s:   e Zd ZdZdd ZdddZdd Zd	d
 Zdd ZdS )r   a  The Normal distribution with location `loc` and `scale` parameters.

    Mathematical details

    The probability density function (pdf) is,

    .. math::

        pdf(x; \mu, \sigma) = \\frac{1}{Z}e^{\\frac {-0.5 (x - \mu)^2}  {\sigma^2} }

    .. math::

        Z = (2 \pi \sigma^2)^{0.5}

    In the above equation:

    * :math:`loc = \mu`: is the mean.
    * :math:`scale = \sigma`: is the std.
    * :math:`Z`: is the normalization constant.

    Args:
        loc(float|list|numpy.ndarray|Variable): The mean of normal distribution.The data type is float32.
        scale(float|list|numpy.ndarray|Variable): The std of normal distribution.The data type is float32.

    Examples:
        .. code-block:: python
          
          import numpy as np
          from paddle.fluid import layers
          from paddle.fluid.layers import Normal

          # Define a single scalar Normal distribution.
          dist = Normal(loc=0., scale=3.)
          # Define a batch of two scalar valued Normals.
          # The first has mean 1 and standard deviation 11, the second 2 and 22.
          dist = Normal(loc=[1., 2.], scale=[11., 22.])
          # Get 3 samples, returning a 3 x 2 tensor.
          dist.sample([3])

          # Define a batch of two scalar valued Normals.
          # Both have mean 1, but different standard deviations.
          dist = Normal(loc=1., scale=[11., 22.])

          # Complete example
          value_npdata = np.array([0.8], dtype="float32")
          value_tensor = layers.create_tensor(dtype="float32")
          layers.assign(value_npdata, value_tensor)

          normal_a = Normal([0.], [1.])
          normal_b = Normal([0.5], [2.])

          sample = normal_a.sample([2])
          # a random tensor created by normal distribution with shape: [2, 1]
          entropy = normal_a.entropy()
          # [1.4189385] with shape: [1]
          lp = normal_a.log_prob(value_tensor)
          # [-1.2389386] with shape: [1]
          kl = normal_a.kl_divergence(normal_b)
          # [0.34939718] with shape: [1]
    c                 C   s   t |dttjtjtfd t |dttjtjtfd d| _d| _| 	||r1d| _|| _
|| _d S t|tr>t|tr>d| _| ||\| _
| _d S )Nlocr   scaleFT)r   r*   r,   r-   r   r!   r+   r@   r?   r%   rV   rW   r    r8   r   rV   rW   r   r   r   rA   A  rB   zNormal.__init__r   c           	      C   s   t |dtd t |dtd t| j| j j}| jrL|| }t| j| j || | jj	d}t
|}t
j|dd|d}||| j  | j }t
||S || }t
j|dd|dtj|| jj	d| j  | j }| jrqt
||S |S )rC   rD   r   rE   r&   rF   )meanZstdrE   r(   )r   r+   rI   rV   rW   rD   r@   r   rJ   r)   r   Zgaussian_randomrK   r.   r?   )	r   rD   rE   rL   rM   rN   Zzero_tmp_shapeZnormal_random_tmprO   r   r   r   r   R  s2   
zNormal.samplec                 C   sV   t | j| j j}t| j| j || jjd}ddtdtj	   t
| j|  S )zShannon entropy in nats.

        Returns:
          Variable: Shannon entropy of normal distribution.The data type is float32.

        r&         ?r   )r+   rV   rW   rD   r   rJ   r)   mathrT   pir   )r   rL   rN   r   r   r   r   w  s   zNormal.entropyc                 C   sd   t |dddgd | j| j }t| j}d|| j || j   d|  | ttdtj  S )rP   r   r'   rQ   r         g       @)r
   rW   r   rT   rV   r[   sqrtr\   )r   r   varZ	log_scaler   r   r   r     s    

zNormal.log_probc                 C   sV   t |dtd | j|j }|| }| j|j |j }|| }d|| d t|  S )zThe KL-divergence between two normal distributions.

        Args:
            other (Normal): instance of Normal.

        Returns:
            Variable: kl-divergence between two normal distributions.The data type is float32.

        r   r   rZ   rF   )r   r   rW   rV   r   rT   )r   r   Z	var_ratiot1r   r   r   r     s   zNormal.kl_divergenceNrU   )	r9   r:   r;   r<   rA   r   r   r   r   r   r   r   r   r     s    =
%r   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	r   a  
    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|numpy.ndarray|Variable): The logits input of categorical distribution. The data type is float32.

    Examples:
        .. code-block:: python

          import numpy as np
          from paddle.fluid import layers
          from paddle.fluid.layers import Categorical

          a_logits_npdata = np.array([-0.602,-0.602], dtype="float32")
          a_logits_tensor = layers.create_tensor(dtype="float32")
          layers.assign(a_logits_npdata, a_logits_tensor)

          b_logits_npdata = np.array([-0.102,-0.112], dtype="float32")
          b_logits_tensor = layers.create_tensor(dtype="float32")
          layers.assign(b_logits_npdata, b_logits_tensor)
          
          a = Categorical(a_logits_tensor)
          b = Categorical(b_logits_tensor)

          a.entropy()
          # [0.6931472] with shape: [1]

          b.entropy()
          # [0.6931347] with shape: [1]

          a.kl_divergence(b)
          # [1.2516975e-05] with shape: [1]

    c                 C   s@   t |dtjtjtfd | |r|| _dS | |d | _dS )z
        Args:
            logits(list|numpy.ndarray|Variable): The logits input of categorical distribution. The data type is float32.
        logitsr   r   N)	r   r,   r-   r   r!   r+   r%   ra   r8   )r   ra   r   r   r   rA     s   

zCategorical.__init__c           
      C   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:
            Variable: kl-divergence between two Categorical distributions.

        r   r   TdimZkeep_dim)	r   r   ra   r   
reduce_maxr   exp
reduce_sumrT   )
r   r   ra   Zother_logitse_logitsZother_e_logitszZother_zprobklr   r   r   r     s    


zCategorical.kl_divergencec                 C   s`   | j tj| j ddd }t|}tj|ddd}|| }dtj||t|  ddd }|S )zShannon entropy in nats.

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

        rb   Trc   r]   )ra   r   re   r   rf   rg   rT   )r   ra   rh   ri   rj   r   r   r   r   r     s   
zCategorical.entropyN)r9   r:   r;   r<   rA   r   r   r   r   r   r   r     s
    0r   c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )r   a  
    A multivariate normal (also called Gaussian) distribution parameterized by a mean vector
    and a covariance matrix.

    The probability density function (pdf) is:

    .. math::

        pdf(x; loc, scale) = \\frac{e^{-\\frac{||y||^2}{2}}}{Z}

    where:
    .. math::

        y = inv(scale) @ (x - loc)
        Z = (2\\pi)^{0.5k} |det(scale)|


    In the above equation:

    * :math:`inv` : denotes to take the inverse of the matrix.
    * :math:`@` : denotes matrix multiplication.
    * :math:`det` : denotes to evaluate the determinant.

    Args:
        loc(list|numpy.ndarray|Variable): The mean of multivariateNormal distribution with shape :math:`[k]` .
            The data type is float32.
        scale(list|numpy.ndarray|Variable): The positive definite diagonal covariance matrix of multivariateNormal
            distribution  with shape :math:`[k, k]` . All elements are 0 except diagonal elements. The data type is
            float32.

    Examples:
        .. code-block:: python
    
            import numpy as np
            from paddle.fluid import layers
            from paddle.fluid.layers import MultivariateNormalDiag

            a_loc_npdata = np.array([0.3,0.5],dtype="float32")
            a_loc_tensor = layers.create_tensor(dtype="float32")
            layers.assign(a_loc_npdata, a_loc_tensor)


            a_scale_npdata = np.array([[0.4,0],[0,0.5]],dtype="float32")
            a_scale_tensor = layers.create_tensor(dtype="float32")
            layers.assign(a_scale_npdata, a_scale_tensor)

            b_loc_npdata = np.array([0.2,0.4],dtype="float32")
            b_loc_tensor = layers.create_tensor(dtype="float32")
            layers.assign(b_loc_npdata, b_loc_tensor)

            b_scale_npdata = np.array([[0.3,0],[0,0.4]],dtype="float32")
            b_scale_tensor = layers.create_tensor(dtype="float32")
            layers.assign(b_scale_npdata, b_scale_tensor)

            a = MultivariateNormalDiag(a_loc_tensor, a_scale_tensor)
            b = MultivariateNormalDiag(b_loc_tensor, b_scale_tensor)
            
            a.entropy()
            # [2.033158] with shape: [1]
            b.entropy()
            # [1.7777451] with shape: [1]

            a.kl_divergence(b)
            # [0.06542051] with shape: [1]
       
    c                 C   sd   t |dtjtjtfd t |dtjtjtfd | ||r&|| _|| _d S | 	||\| _| _d S )NrV   r   rW   )
r   r,   r-   r   r!   r+   r%   rV   rW   r8   rX   r   r   r   rA   Z  s   
zMultivariateNormalDiag.__init__c                 C   sP   t |j}tj|| jjd}ttj|d g| jjd}t|| | }|S )NrD   r)   r   )	r+   rD   r   onesrV   r)   diagr   Zreduce_prod)r   r   rL   one_allone_diagZdet_diagr   r   r   _detf  s   
zMultivariateNormalDiag._detc                 C   sR   t |j}tj|| jjd}ttj|d g| jjd}t||d|  }|S )Nrl   r   r   )	r+   rD   r   rm   rV   r)   rn   r   Zelementwise_pow)r   r   rL   ro   rp   Zinv_diagr   r   r   _invp  s   
zMultivariateNormalDiag._invc                 C   s:   d| j jd dtdtj   t| | j   }|S )zShannon entropy in nats.

        Returns:
          Variable: Shannon entropy of Multivariate Normal distribution. The data type is float32.

        rZ   r   rF   r   )rW   rD   r[   rT   r\   r   rq   )r   r   r   r   r   r   z  s    zMultivariateNormalDiag.entropyc                 C   s   t |dtd t| |j| j }t|j| j | |j}t||j| j }t| jj	d }t
| |jt
| | j }d|| | |  }|S )a%  The KL-divergence between two Multivariate Normal distributions.

        Args:
            other (MultivariateNormalDiag): instance of Multivariate Normal.

        Returns:
            Variable: kl-divergence between two Multivariate Normal distributions. The data type is float32.

        r   r   r   rZ   )r   r   r   rg   rr   rW   matmulrV   r+   rD   rT   rq   )r   r   Ztr_cov_matmulZloc_matmul_covZ
tri_matmulkZln_covrk   r   r   r   r     s   

$z$MultivariateNormalDiag.kl_divergenceN)	r9   r:   r;   r<   rA   rq   rr   r   r   r   r   r   r   r     s    C

r   )
__future__r    r   r   r   r   r[   numpyr,   r1   Zdata_feederr	   r
   r   r   __all__objectr   r   r   r   r   r   r   r   r   <module>   s"   U  *j