o
    Mez                     @   s.  d dl Z d dlZd dl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 d dlmZ d dlmZ d d	lmZmZ d
dgZi Zdd Zdd
 Zdd Ze jG dd deZeeedd Zeeedd Zeeedd Zeeedd Zeeedd Z eeedd Z!dd Z"dS )     N)Beta)Categorical)	Dirichlet)Distribution)ExponentialFamily)Normal)Uniform)_non_static_modein_dygraph_moderegister_klkl_divergencec                 C   s   t t| t|| |S )a)  
    Kullback-Leibler divergence between distribution p and q.

    .. math::

        KL(p||q) = \int p(x)log\frac{p(x)}{q(x)} \mathrm{d}x

    Args:
        p (Distribution): ``Distribution`` object. Inherits from the Distribution Base class.
        q (Distribution): ``Distribution`` object. Inherits from the Distribution Base class.

    Returns:
        Tensor, Batchwise KL-divergence between distribution p and q.

    Examples:

        .. code-block:: python

            import paddle

            p = paddle.distribution.Beta(alpha=0.5, beta=0.5)
            q = paddle.distribution.Beta(alpha=0.3, beta=0.7)

            print(paddle.distribution.kl_divergence(p, q))
            # Tensor(shape=[1], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
            #        [0.21193528])

    )	_dispatchtypepq r   FD:\Projects\ConvertPro\env\Lib\site-packages\paddle/distribution/kl.pyr       s   c                    s.   t  tr
t tstd fdd}|S )a  Decorator for register a KL divergence implemention function.

    The ``kl_divergence(p, q)`` function will search concrete implemention
    functions registered by ``register_kl``, according to multi-dispatch pattern.
    If an implemention function is found, it will return the result, otherwise,
    it will raise ``NotImplementError`` exception. Users can register
    implemention funciton by the decorator.

    Args:
        cls_p (Distribution): The Distribution type of Instance p. Subclass derived from ``Distribution``.
        cls_q (Distribution): The Distribution type of Instance q. Subclass derived from ``Distribution``.

    Examples:
        .. code-block:: python

            import paddle

            @paddle.distribution.register_kl(paddle.distribution.Beta, paddle.distribution.Beta)
            def kl_beta_beta():
                pass # insert implementation here
    z0cls_p and cls_q must be subclass of Distributionc                    s   | t  f< | S N)_REGISTER_TABLE)fcls_pcls_qr   r   	decorator[   s   zregister_kl.<locals>.decorator)
issubclassr   	TypeError)r   r   r   r   r   r   r   @   s   c                    s    fddt D }|sttdd |D j\}}tdd |D j\}}t ||f t ||f urBtd jj|j|jt t ||f S )z2Multiple dispatch into concrete implement functionc                    s,   g | ]\}}t  |rt |r||fqS r   )r   ).0Zsuper_pZsuper_qr   r   r   
<listcomp>f   s    z_dispatch.<locals>.<listcomp>c                 s   s    | ]}t | V  qd S r   )_Comparer   mr   r   r   	<genexpr>n   s    z_dispatch.<locals>.<genexpr>c                 s   s    | ]	}t t| V  qd S r   )r   reversedr    r   r   r   r"   o   s    z;Ambiguous kl_divergence({}, {}). Please register_kl({}, {}))	r   NotImplementedErrorminclasseswarningswarnformat__name__RuntimeWarning)r   r   ZmatchsZleft_pZleft_qZright_pZright_qr   r   r   r   b   s$   
r   c                   @   s$   e Zd Zdd Zdd Zdd ZdS )r   c                 G   s
   || _ d S r   r&   )selfr&   r   r   r   __init__   s   
z_Compare.__init__c                 C   s   | j |j kS r   r,   )r-   otherr   r   r   __eq__   s   z_Compare.__eq__c                 C   s:   t | j|jD ]\}}t||s dS ||ur dS qdS )NFT)zipr&   r   )r-   r/   Zcls_xZcls_yr   r   r   __le__   s   
z_Compare.__le__N)r*   
__module____qualname__r.   r0   r2   r   r   r   r   r      s    r   c                 C   s   |j  |j  | j | j   | j  | j  |j |j    | j |j  | j    | j|j | j   |j |j | j | j  | j | j    S r   )alphalgammabetadigammar   r   r   r   _kl_beta_beta   s   ""r9   c                 C   sl   | j d |j d  | j  |j   d | j |j  | j  | j d d  d S )N)Zconcentrationsumr6   r8   Z	unsqueezer   r   r   r   _kl_dirichlet_dirichlet   s   
r<   c                 C   
   |  |S r   r   r   r   r   r   _kl_categorical_categorical      
r?   c                 C   r=   r   r>   r   r   r   r   _kl_normal_normal   r@   rA   c                 C   r=   r   r>   r   r   r   r   _kl_uniform_uniform   r@   rB   c              
   C   s   t | t |ks
tg }| jD ]}| }d|_|| q|j}| j| }zt r3tj	||dd}ntj
||}W n tyW } ztdjt | jt |jd|d}~ww |j| | }t|||D ]\}	}
}|
|	 | }|t|t|j8 }qe|S )zuCompute kl-divergence using `Bregman divergences <https://www.lix.polytechnique.fr/~nielsen/EntropyEF-ICIP2010.pdf>`_FT)Zcreate_graphzlCann't compute kl_divergence({cls_p}, {cls_q}) use bregman divergence. Please register_kl({cls_p}, {cls_q}).r   N)r   r$   Z_natural_parametersdetachZstop_gradientappendZ_log_normalizerr	   paddleZgradZstaticZ	gradientsRuntimeErrorr   r)   r*   r1   _sum_rightmostlenZevent_shape)r   r   Zp_natural_paramsparamZq_natural_paramsZ
p_log_normZp_gradseklZp_paramZq_paramZp_gradtermr   r   r   _kl_expfamily_expfamily   sB   

rM   c                 C   s"   |dkr|  tt| dS | S )Nr   )r;   listrange)valuenr   r   r   rG      s   "rG   )#	functoolsr'   rE   Zpaddle.distribution.betar   Zpaddle.distribution.categoricalr   Zpaddle.distribution.dirichletr   Z paddle.distribution.distributionr   Z&paddle.distribution.exponential_familyr   Zpaddle.distribution.normalr   Zpaddle.distribution.uniformr   Zpaddle.fluid.frameworkr	   r
   __all__r   r   r   r   total_orderingobjectr   r9   r<   r?   rA   rB   rM   rG   r   r   r   r   <module>   s>    "





'