U
    ©Ê¹j=(  ã                   @   s   d Z ddlZddlmZmZ dddg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.
é    N)ÚconstraintsÚ
transformsÚ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__© úf/var/www/html/bwave/python/venv/lib/python3.8/site-packages/torch/distributions/constraint_registry.pyr
   T   s    zConstraintRegistry.__init__Nc                    s\   |dk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>k   ó    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   X   s     ÿÿ
zConstraintRegistry.registerc                 C   sH   z| j t|ƒ }W n, tk
r>   tdt|ƒj› d�ƒd‚Y nX ||ƒS )aq  
        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   O   s   
#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
    þÿr2   c                 C   s   t  t  ¡ t  | jd¡g¡S )Néÿÿÿÿ)r   r/   r,   r0   Úupper_boundr$   r   r   r   Ú_transform_to_less_thanÌ   s
    þÿr5   c                 C   sl   t | jtjƒo| jdk}t | jtjƒo.| jdk}|r@|r@t ¡ S | j}| j| j }t t ¡ t ||¡g¡S )Nr   r.   )	r   r1   ÚnumbersÚNumberr4   r   ZSigmoidTransformr/   r0   )r   Z
lower_is_0Z
upper_is_1ÚlocÚscaler   r   r   Ú_transform_to_interval×   s    þþÿr:   c                 C   s   t  ¡ S r   )r   ZStickBreakingTransformr$   r   r   r   Ú_biject_to_simplexï   s    r;   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>  s     z"_biject_to_cat.<locals>.<listcomp>©r   ZCatTransformÚcseqÚdimÚlengthsr$   r   r   r   Ú_biject_to_cat  s
      ÿrI   c                 C   s   t  dd„ | jD ƒ| j| j¡S )Nc                 S   s   g | ]}t |ƒ‘qS r   ©r   rA   r   r   r   rD     s     z%_transform_to_cat.<locals>.<listcomp>rE   r$   r   r   r   Ú_transform_to_cat  s
      ÿrK   c                 C   s   t  dd„ | jD ƒ| j¡S )Nc                 S   s   g | ]}t |ƒ‘qS r   r@   rA   r   r   r   rD     s     z$_biject_to_stack.<locals>.<listcomp>©r   ZStackTransformrF   rG   r$   r   r   r   Ú_biject_to_stack  s     ÿrM   c                 C   s   t  dd„ | jD ƒ| j¡S )Nc                 S   s   g | ]}t |ƒ‘qS r   rJ   rA   r   r   r   rD   #  s     z'_transform_to_stack.<locals>.<listcomp>rL   r$   r   r   r   Ú_transform_to_stack   s     ÿrN   )*r"   r6   Ztorch.distributionsr   r   Ú__all__r   r   r   r   Úrealr%   Zindependentr*   r+   ZpositiveZnonnegativer-   Úgreater_thanZgreater_than_eqr2   Ú	less_thanr5   ÚintervalZhalf_open_intervalr:   Zsimplexr;   r<   Zlower_choleskyr=   Zpositive_definiteZpositive_semidefiniter>   Zcorr_choleskyr?   ÚcatrI   rK   ÚstackrM   rN   r   r   r   r   Ú<module>   sl   CýI













	

	




















