o
    ,h"                     @   s   d dl mZ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
 d dlmZmZ d dlmZ d d	lmZ d
gZG dd
 d
eZdS )    )OptionalUnionN)Tensor)constraints)Distribution)Independent)ComposeTransform	Transform)_sum_rightmost)_sizeTransformedDistributionc                	       s   e Zd ZU dZi Zeeejf e	d< 	dde
deeee f dee ddf fdd	Zd fd
d	Zejdddd ZedefddZe fddZe fded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_constraintsNbase_distribution
transformsvalidate_argsreturnc                    sb  t |tr
|g| _nt |tr tdd |D std|| _ntd| |j|j }t|j}t	| j}t||j
jk rLtd|j
j d| d||}||}||kri|d t||  }	||	}|j
j| }
|
dkrxt||
}|| _|jj|j
j }t|jj|| }t||ksJ t|| }|d | }||d  }t j|||d	 d S )
Nc                 s   s    | ]}t |tV  qd S N)
isinstancer	   ).0t r   g/var/www/html/scripts/venv/lib/python3.10/site-packages/torch/distributions/transformed_distribution.py	<genexpr>@   s    z3TransformedDistribution.__init__.<locals>.<genexpr>z6transforms must be a Transform or a list of Transformsz0transforms must be a Transform or list, but was z9base_distribution needs to have shape with size at least z
, but got .r   r   )r   r	   r   listall
ValueErrorbatch_shapeevent_shapelenr   domain	event_dimforward_shapeinverse_shapeexpandr   	base_distcodomainmaxsuper__init__)selfr   r   r   
base_shapebase_event_dim	transformr#   expanded_base_shapebase_batch_shapereinterpreted_batch_ndimstransform_change_in_event_dimr"   cutr   r   	__class__r   r   r*   5   sV   






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   )_get_checked_instancer   torchSizer   reversedr   r$   r    r&   r%   r)   r*   _validate_args)r+   r   	_instancenewshaper   r0   r4   r   r   r%   n   s   


zTransformedDistribution.expandF)is_discretec                 C   sF   | j s| jjS | j d j}t| j|jkr!t|t| j|j }|S )N)	r   r&   supportr'   r    r   r"   r   independent)r+   r@   r   r   r   r@   }   s   zTransformedDistribution.supportc                 C   s   | j jS r   )r&   has_rsample)r+   r   r   r   rB      s   z#TransformedDistribution.has_rsamplec                 C   sP   t   | j|}| jD ]}||}q|W  d   S 1 s!w   Y  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)r7   no_gradr&   sampler   r+   sample_shapexr.   r   r   r   rD      s   


$zTransformedDistribution.samplerF   c                 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   rE   r   r   r   rH      s   

zTransformedDistribution.rsamplec                 C   s   | j r| | t| j}d}|}t| j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        )r:   _validate_sampler    r   r9   r   invr!   r"   r'   r
   log_abs_det_jacobianr&   log_prob)r+   valuer"   rL   yr.   rG   r   r   r   rL      s"   




z TransformedDistribution.log_probc                 C   s@   d}| j D ]}||j }qt|tr|dkr|S ||d  d S )zu
        This conditionally flips ``value -> 1-value`` to ensure :meth:`cdf` is
        monotone increasing.
           g      ?)r   signr   int)r+   rM   rP   r.   r   r   r   _monotonize_cdf   s   
z'TransformedDistribution._monotonize_cdfc                 C   sL   | j ddd D ]}||}q| jr| j| | j|}| |}|S )z
        Computes the cumulative distribution function by inverting the
        transform(s) and computing the score of the base distribution.
        Nr?   )r   rJ   r:   r&   rI   cdfrR   r+   rM   r.   r   r   r   rS      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.
        )rR   r&   icdfr   rT   r   r   r   rU      s
   


zTransformedDistribution.icdfr   )!__name__
__module____qualname____doc__r   dictstrr   
Constraint__annotations__r   r   r	   r   r   boolr*   r%   dependent_propertyr@   propertyrB   r7   r8   rD   r   r   rH   rL   rR   rS   rU   __classcell__r   r   r4   r   r      s0   
 !9


)typingr   r   r7   r   torch.distributionsr    torch.distributions.distributionr   torch.distributions.independentr   torch.distributions.transformsr   r	   torch.distributions.utilsr
   torch.typesr   __all__r   r   r   r   r   <module>   s   