a
    hB(                     @   s"  d Z ddlmZmZ ddlmZ g dZG dd dZe Ze Z	e
eje	
ejdd Ze
ejd	d
 Ze	
ejdd Ze
eje
eje	
eje	
ejdd Ze
eje
eje	
eje	
ejdd Ze
eje	
ejdd Ze
eje
eje	
eje	
ejdd Ze
ejdd Ze	
ejdd Ze	
ejdd Ze	
ej e	
ej!dd Z"e
ej#e	
ej#dd Z$e
ej%dd  Z&e	
ej%d!d" Z'e
ej(d#d$ Z)e	
ej(d%d& Z*d'S )(aF  
PyTorch provides two global :class:`ConstraintRegistry` objects that link
:class:`~torch.distributions.constraints.Constraint` objects to
:class:`~torch.distributions.transforms.Transform` objects. These objects both
input constraints and return transforms, but they have different guarantees on
bijectivity.

1. ``biject_to(constraint)`` looks up a bijective
   :class:`~torch.distributions.transforms.Transform` from ``constraints.real``
   to the given ``constraint``. The returned transform is guaranteed to have
   ``.bijective = True`` and should implement ``.log_abs_det_jacobian()``.
2. ``transform_to(constraint)`` looks up a not-necessarily bijective
   :class:`~torch.distributions.transforms.Transform` from ``constraints.real``
   to the given ``constraint``. The returned transform is not guaranteed to
   implement ``.log_abs_det_jacobian()``.

The ``transform_to()`` registry is useful for performing unconstrained
optimization on constrained parameters of probability distributions, which are
indicated by each distribution's ``.arg_constraints`` dict. These transforms often
overparameterize a space in order to avoid rotation; they are thus more
suitable for coordinate-wise optimization algorithms like Adam::

    loc = torch.zeros(100, requires_grad=True)
    unconstrained = torch.zeros(100, requires_grad=True)
    scale = transform_to(Normal.arg_constraints["scale"])(unconstrained)
    loss = -Normal(loc, scale).log_prob(data).sum()

The ``biject_to()`` registry is useful for Hamiltonian Monte Carlo, where
samples from a probability distribution with constrained ``.support`` are
propagated in an unconstrained space, and algorithms are typically rotation
invariant.::

    dist = Exponential(rate)
    unconstrained = torch.zeros(100, requires_grad=True)
    sample = biject_to(dist.support)(unconstrained)
    potential_energy = -dist.log_prob(sample).sum()

.. note::

    An example where ``transform_to`` and ``biject_to`` differ is
    ``constraints.simplex``: ``transform_to(constraints.simplex)`` returns a
    :class:`~torch.distributions.transforms.SoftmaxTransform` that simply
    exponentiates and normalizes its inputs; this is a cheap and mostly
    coordinate-wise operation appropriate for algorithms like SVI. In
    contrast, ``biject_to(constraints.simplex)`` returns a
    :class:`~torch.distributions.transforms.StickBreakingTransform` that
    bijects its input down to a one-fewer-dimensional space; this a more
    expensive less numerically stable transform but is needed for algorithms
    like HMC.

The ``biject_to`` and ``transform_to`` objects can be extended by user-defined
constraints and transforms using their ``.register()`` method either as a
function on singleton constraints::

    transform_to.register(my_constraint, my_transform)

or as a decorator on parameterized constraints::

    @transform_to.register(MyConstraintClass)
    def my_factory(constraint):
        assert isinstance(constraint, MyConstraintClass)
        return MyTransform(constraint.param1, constraint.param2)

You can create your own registry by creating a new :class:`ConstraintRegistry`
object.
    )constraints
transforms)_Number)ConstraintRegistry	biject_totransform_toc                       s2   e Zd ZdZ fddZd	ddZdd Z  ZS )
r   z5
    Registry to link constraints to transforms.
    c                    s   i | _ t   d S N)	_registrysuper__init__)self	__class__ U/var/www/auris/lib/python3.9/site-packages/torch/distributions/constraint_registry.pyr   U   s    zConstraintRegistry.__init__Nc                    s\   |du r fddS t  tjr*t  t  tr@t tjsNtd  |j < |S )a  
        Registers a :class:`~torch.distributions.constraints.Constraint`
        subclass in this registry. Usage::

            @my_registry.register(MyConstraintClass)
            def construct_transform(constraint):
                assert isinstance(constraint, MyConstraint)
                return MyTransform(constraint.arg_constraints)

        Args:
            constraint (subclass of :class:`~torch.distributions.constraints.Constraint`):
                A subclass of :class:`~torch.distributions.constraints.Constraint`, or
                a singleton object of the desired class.
            factory (Callable): A callable that inputs a constraint object and returns
                a  :class:`~torch.distributions.transforms.Transform` object.
        Nc                    s     | S r   )register)factory
constraintr   r   r   <lambda>l       z-ConstraintRegistry.register.<locals>.<lambda>zLExpected constraint to be either a Constraint subclass or instance, but got )
isinstancer   
Constrainttype
issubclass	TypeErrorr	   r   r   r   r   r   r   r   Y   s    
zConstraintRegistry.registerc                 C   sF   z| j t| }W n* ty<   tdt|j ddY n0 ||S )ah  
        Looks up a transform to constrained space, given a constraint object.
        Usage::

            constraint = Normal.arg_constraints["scale"]
            scale = transform_to(constraint)(torch.zeros(1))  # constrained
            u = transform_to(constraint).inv(scale)  # unconstrained

        Args:
            constraint (:class:`~torch.distributions.constraints.Constraint`):
                A constraint object.

        Returns:
            A :class:`~torch.distributions.transforms.Transform` object.

        Raises:
            `NotImplementedError` if no transform has been registered.
        zCannot transform z constraintsN)r	   r   KeyErrorNotImplementedError__name__r   r   r   r   __call__|   s    zConstraintRegistry.__call__)N)r   
__module____qualname____doc__r   r   r    __classcell__r   r   r   r   r   P   s   
#r   c                 C   s   t jS r   )r   Zidentity_transformr   r   r   r   _transform_to_real   s    r&   c                 C   s   t | j}t|| jS r   )r   base_constraintr   IndependentTransformreinterpreted_batch_ndimsr   Zbase_transformr   r   r   _biject_to_independent   s    
r+   c                 C   s   t | j}t|| jS r   )r   r'   r   r(   r)   r*   r   r   r   _transform_to_independent   s    
r,   c                 C   s   t  S r   )r   ExpTransformr%   r   r   r   _transform_to_positive   s    r.   c                 C   s   t t  t | jdgS )N   )r   ComposeTransformr-   AffineTransformlower_boundr%   r   r   r   _transform_to_greater_than   s
    r3   c                 C   s   t t  t | jdgS )N)r   r0   r-   r1   upper_boundr%   r   r   r   _transform_to_less_than   s
    r6   c                 C   sh   t | jto| jdk}t | jto*| jdk}|r<|r<t S | j}| j| j }tt t||gS )Nr   r/   )r   r2   r   r5   r   ZSigmoidTransformr0   r1   )r   Z
lower_is_0Z
upper_is_1locZscaler   r   r   _transform_to_interval   s    r8   c                 C   s   t  S r   )r   ZStickBreakingTransformr%   r   r   r   _biject_to_simplex   s    r9   c                 C   s   t  S r   )r   ZSoftmaxTransformr%   r   r   r   _transform_to_simplex   s    r:   c                 C   s   t  S r   )r   ZLowerCholeskyTransformr%   r   r   r   _transform_to_lower_cholesky   s    r;   c                 C   s   t  S r   )r   ZPositiveDefiniteTransformr%   r   r   r   _transform_to_positive_definite   s    r<   c                 C   s   t  S r   )r   ZCorrCholeskyTransformr%   r   r   r   _transform_to_corr_cholesky  s    r=   c                 C   s   t dd | jD | j| jS )Nc                 S   s   g | ]}t |qS r   r   .0cr   r   r   
<listcomp>  r   z"_biject_to_cat.<locals>.<listcomp>r   ZCatTransformcseqdimlengthsr%   r   r   r   _biject_to_cat
  s    rG   c                 C   s   t dd | jD | j| jS )Nc                 S   s   g | ]}t |qS r   r   r?   r   r   r   rB     r   z%_transform_to_cat.<locals>.<listcomp>rC   r%   r   r   r   _transform_to_cat  s    rI   c                 C   s   t dd | jD | jS )Nc                 S   s   g | ]}t |qS r   r>   r?   r   r   r   rB     r   z$_biject_to_stack.<locals>.<listcomp>r   ZStackTransformrD   rE   r%   r   r   r   _biject_to_stack  s    rK   c                 C   s   t dd | jD | jS )Nc                 S   s   g | ]}t |qS r   rH   r?   r   r   r   rB   "  r   z'_transform_to_stack.<locals>.<listcomp>rJ   r%   r   r   r   _transform_to_stack  s    rL   N)+r#   Ztorch.distributionsr   r   Ztorch.typesr   __all__r   r   r   r   realr&   Zindependentr+   r,   ZpositiveZnonnegativer.   greater_thanZgreater_than_eqr3   	less_thanr6   intervalZhalf_open_intervalr8   Zsimplexr9   r:   Zlower_choleskyr;   Zpositive_definiteZpositive_semidefiniter<   Zcorr_choleskyr=   catrG   rI   stackrK   rL   r   r   r   r   <module>   sf   CI













	

	




















