U
    e»{jb*  ã                   @   s^   d Z ddlmZ ddlmZmZ dddgZG dd„ deƒZG d	d„ deƒZG d
d„ deƒZ	dS )z 
Special models useful for complex compound models where control is needed over
which outputs from a source model are mapped to which inputs of a target model.
é    )ÚQuantityé   )ÚFittableModelÚModelÚMappingÚIdentityÚUnitsMappingc                       sf   e Zd ZdZdZd‡ fdd„	Zedd„ ƒZedd	„ ƒZed
d„ ƒZ	dd„ Z
dd„ Zedd„ ƒZ‡  ZS )r   a´  
    Allows inputs to be reordered, duplicated or dropped.

    Parameters
    ----------
    mapping : tuple
        A tuple of integers representing indices of the inputs to this model
        to return and in what order to return them.  See
        :ref:`astropy:compound-model-mappings` for more details.
    n_inputs : int
        Number of inputs; if `None` (default) then ``max(mapping) + 1`` is
        used (i.e. the highest input index used in the mapping).
    name : str, optional
        A human-friendly name associated with this model instance
        (particularly useful for identifying the individual components of a
        compound model).
    meta : dict-like
        Free-form metadata to associate with this model.

    Raises
    ------
    TypeError
        Raised when number of inputs is less that ``max(mapping)``.

    Examples
    --------

    >>> from astropy.modeling.models import Polynomial2D, Shift, Mapping
    >>> poly1 = Polynomial2D(1, c0_0=1, c1_0=2, c0_1=3)
    >>> poly2 = Polynomial2D(1, c0_0=1, c1_0=2.4, c0_1=2.1)
    >>> model = (Shift(1) & Shift(2)) | Mapping((0, 1, 0, 1)) | (poly1 & poly2)
    >>> model(1, 2)  # doctest: +FLOAT_CMP
    (17.0, 14.2)
    TNc                    s¦   d| _ d| _|d kr$t|ƒd | _n|| _t|ƒ| _tƒ j||d� tdd„ t	| jƒD ƒƒ| _
tdd„ t	| jƒD ƒƒ| _|| _dd„ | j D ƒ| _d	d„ | j D ƒ| _d S )
N© r   ©ÚnameÚmetac                 s   s   | ]}d t |ƒ V  qdS ©ÚxN©Ústr©Ú.0Úidxr	   r	   úX/var/www/html/bwave/python/venv/lib/python3.8/site-packages/astropy/modeling/mappings.pyÚ	<genexpr>?   s     z#Mapping.__init__.<locals>.<genexpr>c                 s   s   | ]}d t |ƒ V  qdS r   r   r   r	   r	   r   r   @   s     c                 S   s   i | ]
}|d “qS ©Fr	   ©r   Úkeyr	   r	   r   Ú
<dictcomp>C   s      z$Mapping.__init__.<locals>.<dictcomp>c                 S   s   i | ]
}|d “qS r   r	   r   r	   r	   r   r   D   s      )Ú_inputsÚ_outputsÚmaxÚ	_n_inputsÚlenÚ
_n_outputsÚsuperÚ__init__ÚtupleÚrangeÚinputsÚoutputsÚ_mappingÚ_input_units_strictÚ _input_units_allow_dimensionless)ÚselfÚmappingÚn_inputsr   r   ©Ú	__class__r	   r   r!   4   s    
zMapping.__init__c                 C   s   | j S ©N)r   ©r)   r	   r	   r   r+   F   s    zMapping.n_inputsc                 C   s   | j S r.   )r   r/   r	   r	   r   Ú	n_outputsJ   s    zMapping.n_outputsc                 C   s   | j S )z,Integers representing indices of the inputs.©r&   r/   r	   r	   r   r*   N   s    zMapping.mappingc                 C   s.   | j d krd| j› d�S d| j› d| j ›d�S )Nz	<Mapping(ú)>ú, name=©r   r*   r/   r	   r	   r   Ú__repr__S   s    
zMapping.__repr__c                    sn   t ˆ ƒ| jkr@| jd k	r| jnd}t|› d| j› dt ˆ ƒ› �ƒ‚t‡ fdd„| jD ƒƒ}| jdkrj|d S |S )Nr   z	 expects z inputs; got c                 3   s   | ]}ˆ | V  qd S r.   r	   r   ©Úargsr	   r   r   ^   s     z#Mapping.evaluate.<locals>.<genexpr>r   r   )r   r+   r   Ú	TypeErrorr"   r&   r0   )r)   r7   r   Úresultr	   r6   r   ÚevaluateX   s    
zMapping.evaluatec                    s~   z t ‡ fdd„tˆ jƒD ƒƒ}W n& tk
rF   tdˆ j› d�ƒ‚Y nX ˆ  |¡}ˆ j|_ˆ j|_t	|jƒ|_
t	|jƒ|_|S )a)  
        A `Mapping` representing the inverse of the current mapping.

        Raises
        ------
        `NotImplementedError`
            An inverse does no exist on mappings that drop some of its inputs
            (there is then no way to reconstruct the inputs that were dropped).
        c                 3   s   | ]}ˆ j  |¡V  qd S r.   )r*   Úindexr   r/   r	   r   r   r   s     z"Mapping.inverse.<locals>.<genexpr>zMappings such as zG that drop one or more of their inputs are not invertible at this time.)r"   r#   r+   Ú
ValueErrorÚNotImplementedErrorr*   r-   r   r   r   r   r   )r)   r*   Úinvr	   r/   r   Úinversee   s     ÿ

zMapping.inverse)NNN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Úlinearr!   Úpropertyr+   r0   r*   r5   r:   r?   Ú__classcell__r	   r	   r,   r   r      s   #


c                       s:   e Zd ZdZdZd
‡ fdd„	Zdd„ Zedd	„ ƒZ‡  Z	S )r   aá  
    Returns inputs unchanged.

    This class is useful in compound models when some of the inputs must be
    passed unchanged to the next model.

    Parameters
    ----------
    n_inputs : int
        Specifies the number of inputs this identity model accepts.
    name : str, optional
        A human-friendly name associated with this model instance
        (particularly useful for identifying the individual components of a
        compound model).
    meta : dict-like
        Free-form metadata to associate with this model.

    Examples
    --------

    Transform ``(x, y)`` by a shift in x, followed by scaling the two inputs::

        >>> from astropy.modeling.models import (Polynomial1D, Shift, Scale,
        ...                                      Identity)
        >>> model = (Shift(1) & Identity(1)) | Scale(1.2) & Scale(2)
        >>> model(1,1)  # doctest: +FLOAT_CMP
        (2.4, 2.0)
        >>> model.inverse(2.4, 2) # doctest: +FLOAT_CMP
        (1.0, 1.0)
    TNc                    s"   t t|ƒƒ}tƒ j|||d� d S )Nr
   )r"   r#   r    r!   )r)   r+   r   r   r*   r,   r	   r   r!   £   s    zIdentity.__init__c                 C   s.   | j d krd| j› d�S d| j› d| j ›d�S )Nz
<Identity(r2   r3   )r   r+   r/   r	   r	   r   r5   §   s    
zIdentity.__repr__c                 C   s   | S )zl
        The inverse transformation.

        In this case of `Identity`, ``self.inverse is self``.
        r	   r/   r	   r	   r   r?   ¬   s    zIdentity.inverse)NN)
r@   rA   rB   rC   rD   r!   r5   rE   r?   rF   r	   r	   r,   r   r   �   s   c                       s®   e Zd ZdZd‡ fdd„	Zdd„ Zedd	„ ƒZed
d„ ƒZe‡ fdd„ƒZ	e	j
‡ fdd„ƒZ	e‡ fdd„ƒZej
‡ fdd„ƒZedd„ ƒZedd„ ƒZdd„ Zdd„ Z‡  ZS )r   a‰
  
    Mapper that operates on the units of the input, first converting to
    canonical units, then assigning new units without further conversion.
    Used by Model.coerce_units to support units on otherwise unitless models
    such as Polynomial1D.

    Parameters
    ----------
    mapping : tuple
        A tuple of (input_unit, output_unit) pairs, one per input, matched to the
        inputs by position.  The first element of the each pair is the unit that
        the model will accept (specify ``dimensionless_unscaled``
        to accept dimensionless input).  The second element is the unit that the
        model will return.  Specify ``dimensionless_unscaled``
        to return dimensionless Quantity, and `None` to return raw values without
        Quantity.
    input_units_equivalencies : dict, optional
        Default equivalencies to apply to input values.  If set, this should be a
        dictionary where each key is a string that corresponds to one of the
        model inputs.
    input_units_allow_dimensionless : dict or bool, optional
        Allow dimensionless input. If this is True, input values to evaluate will
        gain the units specified in input_units. If this is a dictionary then it
        should map input name to a bool to allow dimensionless numbers for that
        input.
    name : str, optional
        A human-friendly name associated with this model instance
        (particularly useful for identifying the individual components of a
        compound model).
    meta : dict-like, optional
        Free-form metadata to associate with this model.

    Examples
    --------

    Wrapping a unitless model to require and convert units:

    >>> from astropy.modeling.models import Polynomial1D, UnitsMapping
    >>> from astropy import units as u
    >>> poly = Polynomial1D(1, c0=1, c1=2)
    >>> model = UnitsMapping(((u.m, None),)) | poly
    >>> model = model | UnitsMapping(((None, u.s),))
    >>> model(u.Quantity(10, u.m))  # doctest: +FLOAT_CMP
    <Quantity 21. s>
    >>> model(u.Quantity(1000, u.cm)) # doctest: +FLOAT_CMP
    <Quantity 21. s>
    >>> model(u.Quantity(10, u.cm)) # doctest: +FLOAT_CMP
    <Quantity 1.2 s>

    Wrapping a unitless model but still permitting unitless input:

    >>> from astropy.modeling.models import Polynomial1D, UnitsMapping
    >>> from astropy import units as u
    >>> poly = Polynomial1D(1, c0=1, c1=2)
    >>> model = UnitsMapping(((u.m, None),), input_units_allow_dimensionless=True) | poly
    >>> model = model | UnitsMapping(((None, u.s),))
    >>> model(u.Quantity(10, u.m))  # doctest: +FLOAT_CMP
    <Quantity 21. s>
    >>> model(10)  # doctest: +FLOAT_CMP
    <Quantity 21. s>
    NFc                    sb   || _ tdd„ |D ƒƒ}|dkr4|t|ƒkr4tdƒ‚d| _|| _|| _tƒ j||d� |  ¡  d S )Nc                 S   s   g | ]}|d  dkr|‘qS )éÿÿÿÿNr	   )r   Úmr	   r	   r   Ú
<listcomp>   s      z)UnitsMapping.__init__.<locals>.<listcomp>r   z1If one return unit is None, then all must be NoneTr
   )	r&   r   r<   r'   Úinput_units_equivalenciesr(   r    r!   Ú_rebuild_units)r)   r*   rJ   Zinput_units_allow_dimensionlessr   r   Znone_mapping_countr,   r	   r   r!   ö   s    zUnitsMapping.__init__c                 C   s   dd„ t | j| jƒD ƒ| _d S )Nc                 S   s   i | ]\}\}}||“qS r	   r	   )r   Z
input_nameZ
input_unitÚ_r	   r	   r   r     s   
ÿ z/UnitsMapping._rebuild_units.<locals>.<dictcomp>)Úzipr$   r*   Ú_input_unitsr/   r	   r	   r   rK     s    þzUnitsMapping._rebuild_unitsc                 C   s
   t | jƒS r.   ©r   r&   r/   r	   r	   r   r+     s    zUnitsMapping.n_inputsc                 C   s
   t | jƒS r.   rO   r/   r	   r	   r   r0     s    zUnitsMapping.n_outputsc                    s   t ƒ jS r.   )r    r$   r/   r,   r	   r   r$     s    zUnitsMapping.inputsc                    s"   t t| jƒj | |¡ |  ¡  d S r.   )r    r   r-   r$   ÚfsetrK   ©r)   Úvaluer,   r	   r   r$   !  s    c                    s   t ƒ jS r.   )r    r%   r/   r,   r	   r   r%   &  s    zUnitsMapping.outputsc                    s"   t t| jƒj | |¡ |  ¡  d S r.   )r    r   r-   r%   rP   rK   rQ   r,   r	   r   r%   *  s    c                 C   s   | j S r.   )rN   r/   r	   r	   r   Úinput_units/  s    zUnitsMapping.input_unitsc                 C   s   | j S r.   r1   r/   r	   r	   r   r*   3  s    zUnitsMapping.mappingc                 G   sz   g }t || jƒD ]J\}\}}t|tƒr.|j}n|}|d krF| |¡ q| t||dd�¡ q| jdkrn|d S t|ƒS d S )NT)Zsubokr   r   )rM   r*   Ú
isinstancer   rR   Úappendr0   r"   )r)   r7   r9   ÚargrL   Zreturn_unitrR   r	   r	   r   r:   7  s    

zUnitsMapping.evaluatec                 C   s2   | j d krd| j› d�S d| j› d| j ›d�S d S )Nz<UnitsMapping(r2   r3   r4   r/   r	   r	   r   r5   H  s    
zUnitsMapping.__repr__)NFNN)r@   rA   rB   rC   r!   rK   rE   r+   r0   r$   Úsetterr%   rS   r*   r:   r5   rF   r	   r	   r,   r   r   ·   s2   A    ú



N)
rC   Zastropy.unitsr   Úcorer   r   Ú__all__r   r   r   r	   r	   r	   r   Ú<module>   s   
s6