o
    pi=                     @  s   d dl mZ d dl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mZmZ erLd d	lmZ d d
lmZ d dlmZ eejjeejjdZdd ZG dd dejZ dS )    )annotations)TYPE_CHECKINGN)
check_typeconvert_dtype)Variable)exponential_family)in_dynamic_mode) binary_cross_entropy_with_logitssigmoidsoftplus)Sequence)Tensor)_DTypeLiteral)float32float64c                 C  s$   t |}tj| |d| d|S )zClip probs from [0, 1] to (0, 1) with ``eps``.

    Args:
        probs (Tensor): probs of Bernoulli.
        dtype (str): data type.

    Returns:
        Tensor: Clipped probs.
       )minmax)EPSgetpaddleZclipZastype)probsdtypeeps r   d/home/app/PaddleOCR-VL/.venv_paddleocr/lib/python3.10/site-packages/paddle/distribution/bernoulli.py_clip_probs,   s   

r   c                      s   e Zd ZU dZded< ded< ded< ded< d)d* fddZed+ddZed+ddZg fd,ddZ	g dfd-ddZ
d.ddZd.d d!Zd.d"d#Zd+d$d%Zd/d'd(Z  ZS )0	Bernoullia  Bernoulli distribution parameterized by ``probs``, which is the probability of value 1.

    In probability theory and statistics, the Bernoulli distribution, named after Swiss
    mathematician Jacob Bernoulli, is the discrete probability distribution of a random
    variable which takes the value 1 with probability ``p`` and the value 0 with
    probability ``q=1-p``.

    The probability mass function of this distribution, over possible outcomes ``k``, is

    .. math::

        {\begin{cases}
        q=1-p & \text{if }value=0 \\
        p & \text{if }value=1
        \end{cases}}

    Args:
        probs (float|Tensor): The ``probs`` input of Bernoulli distribution. The data type is float32 or float64. The range must be in [0, 1].
        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 Bernoulli

            >>> # init `probs` with a float
            >>> rv = Bernoulli(probs=0.3)

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

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

            >>> print(rv.entropy())
            Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
            0.61086434)
    strnamer   r   logitsr   r   Nfloat | Tensor
str | NonereturnNonec                   s   |pd| _ t st|dtttjjf| j  | |r$|| _	t
|j| _n| |\| _	t | _t| j	| j| _	| j| j	dd| _t j| j	jdd d S )Nr   r   T)Z	is_binaryr   )Zbatch_shapeZevent_shape)r   r   r   floatr   r   pirValueZ_validate_argsr   r   r   Z
_to_tensorZget_default_dtyper   Z_probs_to_logitsr    super__init__shape)selfr   r   	__class__r   r   r)   k   s    


zBernoulli.__init__c                 C  s   | j S )zjMean of Bernoulli distribution.

        Returns:
            Tensor: Mean value of distribution.
        )r   r+   r   r   r   mean   s   zBernoulli.meanc                 C  s   t | jd| j S )zrVariance of Bernoulli distribution.

        Returns:
            Tensor: Variance value of distribution.
        r   )r   multiplyr   r.   r   r   r   variance   s   zBernoulli.variancer*   Sequence[int]c                 C  s   | j d }t st|dtjttttj	j
f| t|tr|nt|}| |}t  tj| j||dW  d   S 1 sAw   Y  dS )a  Sample from Bernoulli distribution.

        Args:
            shape (Sequence[int], optional): Sample shape.

        Returns:
            Tensor: Sampled data with shape `sample_shape` + `batch_shape` + `event_shape`.

        Examples:

            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Bernoulli

                >>> rv = Bernoulli(paddle.full([1], 0.3))
                >>> print(rv.sample([100]).shape)
                [100, 1]

                >>> rv = Bernoulli(paddle.to_tensor(0.3))
                >>> print(rv.sample([100]).shape)
                [100]

                >>> rv = Bernoulli(paddle.to_tensor([0.3, 0.5]))
                >>> print(rv.sample([100]).shape)
                [100, 2]

                >>> rv = Bernoulli(paddle.to_tensor([0.3, 0.5]))
                >>> print(rv.sample([100, 2]).shape)
                [100, 2, 2]
        Z_sampler*   r   N)r   r   r   npndarrayr   listtupler   r&   r'   
isinstance_extend_shapeZno_gradZ	bernoullir   expand)r+   r*   r   r   r   r   sample   s   
 

$zBernoulli.sampleg      ?temperaturer%   c              
   C  s   | j d }t st|dtjttjjt	t
f| t|dtf| t|t
r&|nt
|}| |}tjd|| jd}| j|}tj|| jd}ttt| |  t| |  |S )a
  Sample from Bernoulli distribution (reparameterized).

        The `rsample` is a continuously approximate of Bernoulli distribution reparameterized sample method.
        [1] Chris J. Maddison, Andriy Mnih, and Yee Whye Teh. The Concrete Distribution: A Continuous Relaxation of Discrete Random Variables. 2016.
        [2] Eric Jang, Shixiang Gu, and Ben Poole. Categorical Reparameterization with Gumbel-Softmax. 2016.

        Note:
            `rsample` need to be followed by a `sigmoid`, which converts samples' value to unit interval (0, 1).

        Args:
            shape (Sequence[int], optional): Sample shape.
            temperature (float): temperature for rsample, must be positive.

        Returns:
            Tensor: Sampled data with shape `sample_shape` + `batch_shape` + `event_shape`.

        Examples:

            .. code-block:: python

                >>> import paddle
                >>> paddle.seed(1)
                >>> from paddle.distribution import Bernoulli

                >>> rv = Bernoulli(paddle.full([1], 0.3))
                >>> print(rv.sample([100]).shape)
                [100, 1]

                >>> rv = Bernoulli(0.3)
                >>> print(rv.rsample([100]).shape)
                [100]

                >>> rv = Bernoulli(paddle.to_tensor([0.3, 0.5]))
                >>> print(rv.rsample([100]).shape)
                [100, 2]

                >>> rv = Bernoulli(paddle.to_tensor([0.3, 0.5]))
                >>> print(rv.rsample([100, 2]).shape)
                [100, 2, 2]

                >>> # `rsample` has to be followed by a `sigmoid`
                >>> rv = Bernoulli(0.3)
                >>> rsample = rv.rsample([3, ])
                >>> rsample_sigmoid = paddle.nn.functional.sigmoid(rsample)
                >>> print(rsample)
                Tensor(shape=[3], dtype=float32, place=Place(cpu), stop_gradient=True,
                [-1.46112013, -0.01239836, -1.32765460])
                >>> print(rsample_sigmoid)
                Tensor(shape=[3], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.18829606, 0.49690047, 0.20954758])

                >>> # The smaller the `temperature`, the distribution of `rsample` closer to `sample`, with `probs` of 0.3.
                >>> print(paddle.nn.functional.sigmoid(rv.rsample([1000, ], temperature=1.0)).sum())
                >>> # doctest: +SKIP('output will be different')
                Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
                365.63122559)
                >>> # doctest: -SKIP

                >>> print(paddle.nn.functional.sigmoid(rv.rsample([1000, ], temperature=0.1)).sum())
                Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
                320.15057373)
        Z_rsampler*   r<   r   )r*   Z
fill_valuer   )r   )r   r   r   r4   r5   r   r   r&   r'   r6   r7   r%   r8   r9   fullr   r   r:   Zranddivideaddsubtractloglog1p)r+   r*   r<   r   r   Zuniformsr   r   r   rsample   s8   
A
zBernoulli.rsamplevaluec              
   C  s   | j d }t st|dttjjf| | | j|}t	| j|g\}}t
|}t|}tj|dk |t|dk t||||dS )a
  Cumulative distribution function(CDF) evaluated at value.

        .. math::

            { \begin{cases}
            0 & \text{if } value \lt  0 \\
            1 - p & \text{if } 0 \leq value \lt  1 \\
            1 & \text{if } value \geq 1
            \end{cases}
            }

        Args:
            value (Tensor): Value to be evaluated.

        Returns:
            Tensor: CDF evaluated at value.

        Examples:

            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Bernoulli

                >>> rv = Bernoulli(0.3)
                >>> print(rv.cdf(paddle.to_tensor([1.0])))
                Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
                [1.])
        Z_cdfrD   r   r   r3   )r   r   r   r   r   r&   r'   _check_values_dtype_in_probsr   broadcast_tensorsZ
zeros_likeZ	ones_likewherer@   )r+   rD   r   r   ZzerosZonesr   r   r   cdf%  s   


zBernoulli.cdfc                 C  sZ   | j d }t st|dttjjf| | | j|}t	| j
|g\}}t||d|d S )a;  Log of probability density function.

        Args:
            value (Tensor): Value to be evaluated.

        Returns:
            Tensor: Log of probability density evaluated at value.

        Examples:

            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Bernoulli

                >>> rv = Bernoulli(0.3)
                >>> print(rv.log_prob(paddle.to_tensor([1.0])))
                Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
                [-1.20397282])
        Z	_log_probrD   noneZ	reductionr   )r   r   r   r   r   r&   r'   rE   r   rF   r    r	   )r+   rD   r   r    r   r   r   log_probT  s   
zBernoulli.log_probc                 C  s8   | j d }t st|dttjjf| | |j|dS )a  Probability density function(PDF) evaluated at value.

        .. math::

            { \begin{cases}
                q=1-p & \text{if }value=0 \\
                p & \text{if }value=1
                \end{cases}
            }

        Args:
            value (Tensor): Value to be evaluated.

        Returns:
            Tensor: PDF evaluated at value.

        Examples:

            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Bernoulli

                >>> rv = Bernoulli(0.3)
                >>> print(rv.prob(paddle.to_tensor([1.0])))
                Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True,
                [0.29999998])
        Z_probrD   r3   )	r   r   r   r   r   r&   r'   rK   exp)r+   rD   r   r   r   r   probs  s   
zBernoulli.probc                 C  s   | j d }t| j| jd|dS )a&  Entropy of Bernoulli distribution.

        .. math::

            {
                entropy = -(q \log q + p \log p)
            }

        Returns:
            Tensor: Entropy of distribution.

        Examples:

            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Bernoulli

                >>> rv = Bernoulli(0.3)
                >>> print(rv.entropy())
                Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
                0.61086434)
        Z_entropyrI   rJ   )r   r	   r    r   )r+   r   r   r   r   entropy  s   
zBernoulli.entropyotherc              
   C  s   | j d }t st|dt| | j}|j}t|  }t|  }t|}t| }t| }	t| }
tt	t
||t
||t	t
|	|t
|
|S )a  The KL-divergence between two Bernoulli distributions.

        .. math::

            {
                KL(a || b) = p_a \log(p_a / p_b) + (1 - p_a) \log((1 - p_a) / (1 - p_b))
            }

        Args:
            other (Bernoulli): instance of Bernoulli.

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

        Examples:

            .. code-block:: python

                >>> import paddle
                >>> from paddle.distribution import Bernoulli

                >>> rv = Bernoulli(0.3)
                >>> rv_other = Bernoulli(0.7)

                >>> print(rv.kl_divergence(rv_other))
                Tensor(shape=[], dtype=float32, place=Place(cpu), stop_gradient=True,
                0.33891910)
        Z_kl_divergencerO   )r   r   r   r   r    r   r
   r   r?   r@   r0   )r+   rO   r   Za_logitsZb_logitsZlog_paZlog_pbpaZone_minus_paZlog_one_minus_paZlog_one_minus_pbr   r   r   kl_divergence  s(   





zBernoulli.kl_divergence)N)r   r!   r   r"   r#   r$   )r#   r   )r*   r2   r#   r   )r*   r2   r<   r%   r#   r   )rD   r   r#   r   )rO   r   r#   r   )__name__
__module____qualname____doc____annotations__r)   propertyr/   r1   r;   rC   rH   rK   rM   rN   rQ   __classcell__r   r   r,   r   r   :   s&   
 +0
a
/

#r   )!
__future__r   typingr   numpyr4   r   Zpaddle.base.data_feederr   r   Zpaddle.base.frameworkr   Zpaddle.distributionr   Zpaddle.frameworkr   Zpaddle.nn.functionalr	   r
   r   collections.abcr   r   Zpaddle._typing.dtype_liker   Zfinfor   r   r   r   r   ZExponentialFamilyr   r   r   r   r   <module>   s$   