o
    pi,<                     @  sb   d dl mZ d dlmZ d dlmZ d dlZd dlmZ er&d dlm	Z	m
Z
 G dd dejZdS )	    )annotations)Sequence)TYPE_CHECKINGN)distribution)Tensordtypec                      s   e Zd ZU dZded< ded< ded< 	d/d0 fddZd1ddZd2ddZd2ddZd3ddZ	d2ddZ
ed2ddZed2ddZg fd4ddZg fd4d d!Zd3d"d#Zd3d$d%Zd2d&d'Zd3d(d)Zd3d*d+Zd5d-d.Z  ZS )6ContinuousBernoullia   The Continuous Bernoulli distribution with parameter: `probs` characterizing the shape of the density function.
    The Continuous Bernoulli distribution is defined on [0, 1], and it can be viewed as a continuous version of the Bernoulli distribution.

    `The continuous Bernoulli: fixing a pervasive error in variational autoencoders. <https://arxiv.org/abs/1907.06845>`_

    Mathematical details

    The probability density function (pdf) is

    .. math::

        p(x;\lambda) = C(\lambda)\lambda^x (1-\lambda)^{1-x}

    In the above equation:

    * :math:`x`: is continuous between 0 and 1
    * :math:`probs = \lambda`: is the probability.
    * :math:`C(\lambda)`: is the normalizing constant factor

    .. math::

        C(\lambda) =
        \left\{
        \begin{aligned}
        &2 & \text{ if $\lambda = \frac{1}{2}$} \\
        &\frac{2\tanh^{-1}(1-2\lambda)}{1 - 2\lambda} & \text{ otherwise}
        \end{aligned}
        \right.

    Args:
        probs(int|float|Tensor): The probability of Continuous Bernoulli distribution between [0, 1],
            which characterize the shape of the pdf. If the input data type is int or float, the data type of
            `probs` will be convert to a 1-D Tensor the paddle global default dtype.
        lims(tuple): Specify the unstable calculation region near 0.5, where the calculation is approximated
            by talyor expansion. The default value is (0.499, 0.501).

    Examples:
        .. code-block:: python

            >>> import paddle
            >>> from paddle.distribution import ContinuousBernoulli
            >>> paddle.set_device("cpu")
            >>> paddle.seed(100)

            >>> rv = ContinuousBernoulli(paddle.to_tensor([0.2, 0.5]))

            >>> print(rv.sample([2]))
            Tensor(shape=[2, 2], dtype=float32, place=Place(cpu), stop_gradient=True,
            [[0.38694882, 0.20714243],
             [0.00631948, 0.51577556]])

            >>> print(rv.mean)
            Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.38801414, 0.50000000])

            >>> print(rv.variance)
            Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.07589778, 0.08333334])

            >>> print(rv.entropy())
            Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True,
            [-0.07641457,  0.        ])

            >>> print(rv.cdf(paddle.to_tensor(0.1)))
            Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.17259926, 0.10000000])

            >>> print(rv.icdf(paddle.to_tensor(0.1)))
            Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.05623737, 0.10000000])

            >>> rv1 = ContinuousBernoulli(paddle.to_tensor([0.2, 0.8]))
            >>> rv2 = ContinuousBernoulli(paddle.to_tensor([0.7, 0.5]))
            >>> print(rv1.kl_divergence(rv2))
            Tensor(shape=[2], dtype=float32, place=Place(cpu), stop_gradient=True,
            [0.20103608, 0.07641447])
    r   probslimsr   gV-?gx&1?float | Tensortuple[float]returnNonec                   sh   t  | _| || _t j|| jd| _t | jjj}t j	| j|d| d| _| jj
}t | d S )Nr      )minmax)paddleZget_default_dtyper   
_to_tensorr	   	to_tensorr
   finfoepsZclipshapesuper__init__)selfr	   r
   Zeps_probbatch_shape	__class__ o/home/app/PaddleOCR-VL/.venv_paddleocr/lib/python3.10/site-packages/paddle/distribution/continuous_bernoulli.pyr   n   s   
zContinuousBernoulli.__init__c                 C  s0   t |ttfrtj|g| jd}|S |j| _|S )zoConvert the input parameters into tensors

        Returns:
            Tensor: converted probability.
        r   )
isinstancefloatintr   r   r   )r   r	   r    r    r!   r   |   s
   zContinuousBernoulli._to_tensorc                 C  s,   t t | j| jd t | j| jd S )zGenerate stable support region indicator (prob < self.lims[0] && prob >= self.lims[1] )

        Returns:
            Tensor: the element of the returned indicator tensor corresponding to stable region is True, and False otherwise
        r   r   )r   
logical_or
less_equalr	   r
   greater_thanr   r    r    r!   _cut_support_region   s   z'ContinuousBernoulli._cut_support_regionc                 C  s&   t |  | j| jd t | j S )zCut the probability parameter with stable support region

        Returns:
            Tensor: the element of the returned probability tensor corresponding to unstable region is set to be self.lims[0], and unchanged otherwise
        r   )r   wherer)   r	   r
   	ones_liker(   r    r    r!   
_cut_probs   s
   zContinuousBernoulli._cut_probsvaluec                 C  s   dt |t |   S )zCalculate the tanh inverse of value

        Args:
            value (Tensor)

        Returns:
            Tensor: tanh inverse of value
              ?)r   log1pr   r-   r    r    r!   _tanh_inverse   s   	z!ContinuousBernoulli._tanh_inversec              
   C  s   |   }tjd| jd}tt|||t|}tt|||t|}t	dt
| dd|   tt||td| t	d| d  }t| jd }t	tjd| jddd|  |  }t|  ||S )zCalculate the logarithm of the constant factor :math:`C(lambda)` in the pdf of the Continuous Bernoulli distribution

        Returns:
            Tensor: logarithm of the constant factor
        r.   r          @      ?g       gUUUUUU?g'}'}@)r,   r   r   r   r*   r&   
zeros_likegreater_equalr+   logabsr1   r/   squarer	   r)   )r   	cut_probsZhalfZcut_probs_below_halfZcut_probs_above_halfZlog_constant_proposextaylor_expansionr    r    r!   _log_constant   s:   



z!ContinuousBernoulli._log_constantc              
   C  s   |   }t|d| d }|ttjd| jdd| dd|    }| jd }dddt|  |  }t| 	 ||S )zeMean of Continuous Bernoulli distribution.

        Returns:
            Tensor: mean value.
        r2   r3   r   r.   gUUUUUU?gll?)
r,   r   divider   r   r1   r	   r8   r*   r)   r   r9   tmpZproposer:   r;   r    r    r!   mean   s   

zContinuousBernoulli.meanc              
   C  s   |   }t||d  tdd|  }|ttjd| jdtt| t|  }t| jd }ddd|  |  }t	| 
 ||S )zmVariance of Continuous Bernoulli distribution.

        Returns:
            Tensor: variance value.
        r3   r2   r   r.   gUUUUUU?g?ggjV?)r,   r   r=   r8   r   r   r/   r6   r	   r*   r)   r>   r    r    r!   variance   s   

zContinuousBernoulli.variancer   Sequence[int]c                 C  s6   t   | |W  d   S 1 sw   Y  dS )C  Generate Continuous Bernoulli samples of the specified shape. The final shape would be ``sample_shape + batch_shape``.

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

        Returns:
            Tensor, Sampled data with shape `sample_shape` + `batch_shape`.
        N)r   Zno_gradrsample)r   r   r    r    r!   sample   s   
	$zContinuousBernoulli.samplec                 C  sN   t |ts	tdt|}t| j}t|| }tj|| jddd}| |S )rC   z%sample shape must be Sequence object.r   r   )r   r   r   r   )	r"   r   	TypeErrortupler   r   uniformr   icdf)r   r   r   Zoutput_shapeur    r    r!   rD     s   
	

zContinuousBernoulli.rsamplec                 C  s`   t j|| jd}t | jjj}t j|t | j d| t d| j   | d}|  | S )zLog probability density function.

        Args:
          value (Tensor): The input tensor.

        Returns:
          Tensor: log probability. The data type is the same as `self.probs`.
        r   r3   r   )Zneginf)	r   castr   r   r	   r   Z
nan_to_numr6   r<   )r   r-   r   Zcross_entropyr    r    r!   log_prob  s   	zContinuousBernoulli.log_probc                 C  s   t | |S )zProbability density function.

        Args:
            value (Tensor): The input tensor.

        Returns:
            Tensor: probability. The data type is the same as `self.probs`.
        )r   exprL   r0   r    r    r!   prob'  s   	zContinuousBernoulli.probc              	   C  s`   t | j}t | j }t t | jt jd| jdt | jd| 	  | j
||   | S )a  Shannon entropy in nats.

        The entropy is

        .. math::

            \mathcal{H}(X) = -\log C + \left[ \log (1 - \lambda) -\log \lambda \right] \mathbb{E}(X)  - \log(1 - \lambda)

        In the above equation:

        * :math:`\Omega`: is the support of the distribution.

        Returns:
            Tensor, Shannon entropy of Continuous Bernoulli distribution.
        r.   r           )r   r6   r	   r/   r*   equalr   r   Z	full_liker<   r@   )r   Zlog_pZlog_1_minus_pr    r    r!   entropy2  s   zContinuousBernoulli.entropyc                 C  s   t j|| jd}|  }t ||t d| d|  | d d| d  }t |  ||}t t |t jd| jdt 	|t t 
|t jd| jdt ||S )a>  Cumulative distribution function

        .. math::

            {   P(X \le t; \lambda) =
                F(t;\lambda) =
                \left\{
                \begin{aligned}
                &t & \text{ if $\lambda = \frac{1}{2}$} \\
                &\frac{\lambda^t (1 - \lambda)^{1 - t} + \lambda - 1}{2\lambda - 1} & \text{ otherwise}
                \end{aligned}
                \right. }

        Args:
            value (Tensor): The input tensor.

        Returns:
            Tensor: quantile of :attr:`value`. The data type is the same as `self.probs`.
        r   r3   r2   rO   )r   rK   r   r,   powr*   r)   r&   r   r4   r5   r+   )r   r-   r9   ZcdfsZunbounded_cdfsr    r    r!   cdfO  s.   

zContinuousBernoulli.cdfc              	   C  sd   t j|| jd}|  }t |  t | |d| d   t |  t |t |   |S )af  Inverse cumulative distribution function

        .. math::

            {   F^{-1}(x;\lambda) =
                \left\{
                \begin{aligned}
                &x & \text{ if $\lambda = \frac{1}{2}$} \\
                &\frac{\log(1+(\frac{2\lambda - 1}{1 - \lambda})x)}{\log(\frac{\lambda}{1-\lambda})} & \text{ otherwise}
                \end{aligned}
                \right. }

        Args:
            value (Tensor): The input tensor, meaning the quantile.

        Returns:
            Tensor: the value of the r.v. corresponding to the quantile. The data type is the same as `self.probs`.
        r   r2   r3   )r   rK   r   r,   r*   r)   r/   r6   )r   r-   r9   r    r    r!   rI   x  s   
zContinuousBernoulli.icdfotherc                 C  s\   | j |j kr
td|   }t|j}t|j }| | j||   |  }|| S )a  The KL-divergence between two Continuous Bernoulli distributions with the same `batch_shape`.

        The probability density function (pdf) is

        .. math::

            KL\_divergence(\lambda_1, \lambda_2) = - H - \{\log C_2 + [\log \lambda_2 -  \log (1-\lambda_2)]  \mathbb{E}_1(X) +  \log (1-\lambda_2)  \}

        Args:
            other (ContinuousBernoulli): instance of Continuous Bernoulli.

        Returns:
            Tensor, kl-divergence between two Continuous Bernoulli distributions.

        z\KL divergence of two Continuous Bernoulli distributions should share the same `batch_shape`.)	r   
ValueErrorrQ   r   r6   r	   r/   r<   r@   )r   rT   Zpart1Zlog_qZlog_1_minus_qZpart2r    r    r!   kl_divergence  s   
z!ContinuousBernoulli.kl_divergence)r   )r	   r   r
   r   r   r   )r	   r   r   r   )r   r   )r-   r   r   r   )r   rB   r   r   )rT   r   r   r   )__name__
__module____qualname____doc____annotations__r   r   r)   r,   r1   r<   propertyr@   rA   rE   rD   rL   rN   rQ   rS   rI   rV   __classcell__r    r    r   r!   r      s0   
 N




"




)r   )
__future__r   collections.abcr   typingr   r   Zpaddle.distributionr   r   r   Distributionr   r    r    r    r!   <module>   s   