U
    ©Ê¹jÔ!  ã                   @   sn   d dl m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
mZ d dlmZ dgZG d	d„ deƒZdS )
é    )ÚDictN)Úconstraints)ÚDistribution)ÚIndependent)ÚComposeTransformÚ	Transform)Ú_sum_rightmostÚTransformedDistributionc                       s¨   e Zd ZU dZi Zeeejf e	d< d‡ fdd„	Z
d‡ fdd„	Zejdd	�d
d„ ƒZedd„ ƒZe ¡ fdd„Ze ¡ fdd„Zdd„ Zdd„ Zdd„ Zdd„ Z‡  ZS )r	   a±  
    Extension of the Distribution class, which applies a sequence of Transforms
    to a base distribution.  Let f be the composition of transforms applied::

        X ~ BaseDistribution
        Y = f(X) ~ TransformedDistribution(BaseDistribution, f)
        log p(Y) = log p(X) + log |det (dX/dY)|

    Note that the ``.event_shape`` of a :class:`TransformedDistribution` is the
    maximum shape of its base distribution and its transforms, since transforms
    can introduce correlations among events.

    An example for the usage of :class:`TransformedDistribution` would be::

        # Building a Logistic Distribution
        # X ~ Uniform(0, 1)
        # f = a + b * logit(X)
        # Y ~ f(X) ~ Logistic(a, b)
        base_distribution = Uniform(0, 1)
        transforms = [SigmoidTransform().inv, AffineTransform(loc=a, scale=b)]
        logistic = TransformedDistribution(base_distribution, transforms)

    For more examples, please look at the implementations of
    :class:`~torch.distributions.gumbel.Gumbel`,
    :class:`~torch.distributions.half_cauchy.HalfCauchy`,
    :class:`~torch.distributions.half_normal.HalfNormal`,
    :class:`~torch.distributions.log_normal.LogNormal`,
    :class:`~torch.distributions.pareto.Pareto`,
    :class:`~torch.distributions.weibull.Weibull`,
    :class:`~torch.distributions.relaxed_bernoulli.RelaxedBernoulli` and
    :class:`~torch.distributions.relaxed_categorical.RelaxedOneHotCategorical`
    Úarg_constraintsNc                    s^  t |tƒr|g| _n:t |tƒr@tdd„ |D ƒƒs8tdƒ‚|| _ntd|› �ƒ‚|j|j }t|jƒ}t	| jƒ}t|ƒ|j
jk r’td |j
j|¡ƒ‚| |¡}| |¡}||krÌ|d t|ƒ| … }	| |	¡}|j
j| }
|
dkrêt||
ƒ}|| _|jj|j
j }t|jj|| ƒ}t|ƒ|k�s$t‚t|ƒ| }|d |… }||d … }tƒ j|||d� d S )Nc                 s   s   | ]}t |tƒV  qd S ©N)Ú
isinstancer   )Ú.0Út© r   úk/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/distributions/transformed_distribution.pyÚ	<genexpr>6   s     z3TransformedDistribution.__init__.<locals>.<genexpr>z6transforms must be a Transform or a list of Transformsz0transforms must be a Transform or list, but was zHbase_distribution needs to have shape with size at least {}, but got {}.r   ©Úvalidate_args)r   r   Ú
transformsÚlistÚallÚ
ValueErrorÚbatch_shapeÚevent_shapeÚlenr   ÚdomainÚ	event_dimÚformatÚforward_shapeÚinverse_shapeÚexpandr   Ú	base_distÚcodomainÚmaxÚAssertionErrorÚsuperÚ__init__)ÚselfZbase_distributionr   r   Z
base_shapeZbase_event_dimÚ	transformr   Zexpanded_base_shapeÚbase_batch_shapeZreinterpreted_batch_ndimsZtransform_change_in_event_dimr   Úcutr   r   ©Ú	__class__r   r   r&   0   s^    
ÿ
ÿÿ

 ÿÿ


ÿ
 ÿÿþz TransformedDistribution.__init__c                    s�   |   t|¡}t |¡}|| j }t| jƒD ]}| |¡}q*|d t|ƒt| j	jƒ … }| j	 
|¡|_	| j|_tt|ƒj|| jdd� | j|_|S )NFr   )Z_get_checked_instancer	   ÚtorchÚSizer   Úreversedr   r   r   r!   r    r%   r&   Ú_validate_args)r'   r   Z	_instanceÚnewÚshaper   r)   r+   r   r   r    f   s    


  ÿzTransformedDistribution.expandF)Zis_discretec                 C   sF   | j s| jjS | j d j}t| jƒ|jkrBt |t| jƒ|j ¡}|S )Néÿÿÿÿ)	r   r!   Úsupportr"   r   r   r   r   Zindependent)r'   r4   r   r   r   r4   u   s     ÿzTransformedDistribution.supportc                 C   s   | j jS r   )r!   Úhas_rsample)r'   r   r   r   r5   €   s    z#TransformedDistribution.has_rsamplec              
   C   sD   t  ¡ �2 | j |¡}| jD ]}||ƒ}q|W  5 Q R £ S Q R X dS )a  
        Generates a sample_shape shaped sample or sample_shape shaped batch of
        samples if the distribution parameters are batched. Samples first from
        base distribution and applies `transform()` for every transform in the
        list.
        N)r-   Zno_gradr!   Úsampler   ©r'   Zsample_shapeÚxr(   r   r   r   r6   „   s
    


zTransformedDistribution.samplec                 C   s$   | j  |¡}| jD ]}||ƒ}q|S )a$  
        Generates a sample_shape shaped reparameterized sample or sample_shape
        shaped batch of reparameterized samples if the distribution parameters
        are batched. Samples first from base distribution and applies
        `transform()` for every transform in the list.
        )r!   Úrsampler   r7   r   r   r   r9   ‘   s    

zTransformedDistribution.rsamplec                 C   s˜   | j r|  |¡ t| jƒ}d}|}t| jƒD ]D}| |¡}||jj|j	j 7 }|t
| ||¡||jj ƒ }|}q,|t
| j |¡|t| jjƒ ƒ }|S )z¨
        Scores the sample by inverting the transform(s) and computing the score
        using the score of the base distribution and the log abs det jacobian.
        g        )r0   Ú_validate_sampler   r   r/   r   Úinvr   r   r"   r   Zlog_abs_det_jacobianr!   Úlog_prob)r'   Úvaluer   r<   Úyr(   r8   r   r   r   r<   �   s$    




þ
 ÿz TransformedDistribution.log_probc                 C   s@   d}| j D ]}||j }q
t|tƒr0|dkr0|S ||d  d S )zu
        This conditionally flips ``value -> 1-value`` to ensure :meth:`cdf` is
        monotone increasing.
        é   g      à?)r   Úsignr   Úint)r'   r=   r@   r(   r   r   r   Ú_monotonize_cdfµ   s    
z'TransformedDistribution._monotonize_cdfc                 C   sL   | j ddd… D ]}| |¡}q| jr2| j |¡ | j |¡}|  |¡}|S )z—
        Computes the cumulative distribution function by inverting the
        transform(s) and computing the score of the base distribution.
        Nr3   )r   r;   r0   r!   r:   ÚcdfrB   ©r'   r=   r(   r   r   r   rC   Á   s    
zTransformedDistribution.cdfc                 C   s.   |   |¡}| j |¡}| jD ]}||ƒ}q|S )z”
        Computes the inverse cumulative distribution function using
        transform(s) and computing the score of the base distribution.
        )rB   r!   Úicdfr   rD   r   r   r   rE   Î   s
    


zTransformedDistribution.icdf)N)N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r
   r   Ústrr   Ú
ConstraintÚ__annotations__r&   r    Zdependent_propertyr4   Úpropertyr5   r-   r.   r6   r9   r<   rB   rC   rE   Ú__classcell__r   r   r+   r   r	      s   
 6



)Útypingr   r-   Ztorch.distributionsr   Z torch.distributions.distributionr   Ztorch.distributions.independentr   Ztorch.distributions.transformsr   r   Ztorch.distributions.utilsr   Ú__all__r	   r   r   r   r   Ú<module>   s   