
    IR-e]*                         d Z ddlmZ ddlmZmZ g dZ G d de          Z G d d	e          Z G 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                        e Zd ZdZdZd fd	Zed             Zed             Zed             Z	d Z
d	 Zed
             Z x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                    d| _         d| _        |t          |          dz   | _        n|| _        t	          |          | _        t                                          ||           t          d t          | j                  D                       | _
        t          d t          | j                  D                       | _        || _        d | j         D             | _        d | j         D             | _        d S )N r   namemetac              3   :   K   | ]}d t          |          z   V  dS xNstr.0idxs     9lib/python3.11/site-packages/astropy/modeling/mappings.py	<genexpr>z#Mapping.__init__.<locals>.<genexpr>>   s,      LLsC#c((NLLLLLL    c              3   :   K   | ]}d t          |          z   V  dS r   r   r   s     r   r   z#Mapping.__init__.<locals>.<genexpr>?   s,      NNS3s88^NNNNNNr   c                     i | ]}|d S Fr   r   keys     r   
<dictcomp>z$Mapping.__init__.<locals>.<dictcomp>B   s    #G#G#G3C#G#G#Gr   c                     i | ]}|d S r   r   r   s     r   r    z$Mapping.__init__.<locals>.<dictcomp>C   s    0T0T0Te0T0T0Tr   )_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__s        r   r)   zMapping.__init__3   s     \\A-DNN%DNg,,d...LLeDN6K6KLLLLLNNuT_7M7MNNNNN#G#G$,#G#G#G 0T0Tt|0T0T0T---r   c                     | j         S N)r%   r1   s    r   r3   zMapping.n_inputsE   s
    ~r   c                     | j         S r6   )r'   r7   s    r   	n_outputszMapping.n_outputsI   s
    r   c                     | j         S )z,Integers representing indices of the inputs.r.   r7   s    r   r2   zMapping.mappingM   s     }r   c                 L    | j         d| j         dS d| j         d| j         dS )Nz	<Mapping()>, name=r   r2   r7   s    r   __repr__zMapping.__repr__R   s:    9/t|////?4<??	????r   c           	         t                    | j        k    r9| j        | j        nd}t          | d| j         dt                               t	          fd| j        D                       }| j        dk    r|d         S |S )Nr   z	 expects z inputs; got c              3   (   K   | ]}|         V  d S r6   r   )r   r   argss     r   r   z#Mapping.evaluate.<locals>.<genexpr>]   s'      ::StCy::::::r   r   r   )r&   r3   r   	TypeErrorr*   r.   r9   )r1   rC   r   results    `  r   evaluatezMapping.evaluateW   s    t99%% $	 54999DtUUdmUU#d))UUVVV::::DM:::::>Q!9r   c                 p    	 t           fdt           j                  D                       }n&# t          $ r t	          d j         d          w xY w                     |          } 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   L   K   | ]}j                             |          V  d S r6   )r2   index)r   r   r1   s     r   r   z"Mapping.inverse.<locals>.<genexpr>p   s3      TTDL..s33TTTTTTr   zMappings such as zG that drop one or more of their inputs are not invertible at this time.)r*   r+   r3   
ValueErrorNotImplementedErrorr2   r4   r#   r"   r&   r%   r'   )r1   r2   invs   `  r   inversezMapping.inversed   s    	TTTTuT]?S?STTTTTGG 	 	 	%4DL 4 4 4  	 nnW%%m|CK((S\**
s	   -1 #A)NNN)__name__
__module____qualname____doc__linearr)   propertyr3   r9   r2   r@   rF   rM   __classcell__r4   s   @r   r   r      s           D FU U U U U U$   X   X   X@ @ @
     X    r   r   c                   D     e Zd ZdZdZd fd	Zd Zed             Z x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                     t          t          |                    }t                                          |||           d S )Nr   )r*   r+   r(   r)   )r1   r3   r   r   r2   r4   s        r   r)   zIdentity.__init__   s;    h((t$77777r   c                 L    | j         d| j         dS d| j         d| j         dS )Nz
<Identity(r=   r>   )r   r3   r7   s    r   r@   zIdentity.__repr__   s:    911111ADMAA$)AAAAr   c                     | S )zl
        The inverse transformation.

        In this case of `Identity`, ``self.inverse is self``.
        r   r7   s    r   rM   zIdentity.inverse   s	     r   )NN)
rN   rO   rP   rQ   rR   r)   r@   rS   rM   rT   rU   s   @r   r   r      s{         < F8 8 8 8 8 8B B B
   X    r   r   c                       e Zd ZdZ	 	 	 	 d fd	Zd Zed             Zed             Ze fd            Z	e	j
         fd	            Z	e fd
            Zej
         fd            Zed             Zed             Zd Zd Z x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                 0   || _         t          d |D                       }|dk    r"|t          |          k    rt          d          d| _        || _        || _        t                                          ||           |                                  d S )Nc                 "    g | ]}|d          
|S )r   )r   ms     r   
<listcomp>z)UnitsMapping.__init__.<locals>.<listcomp>   s    !F!F!F"!r   r   z1If one return unit is None, then all must be NoneTr   )	r.   r&   rJ   r/   input_units_equivalenciesr0   r(   r)   _rebuild_units)r1   r2   r`   input_units_allow_dimensionlessr   r   none_mapping_countr4   s          r   r)   zUnitsMapping.__init__   s       !F!FW!F!F!FGG!!&8CLL&H&HPQQQ $( )B&0O-d... 	r   c                 X    d t          | j        | j                  D             | _        d S )Nc                      i | ]\  }\  }}||S r   r   )r   
input_name
input_unit_s       r   r    z/UnitsMapping._rebuild_units.<locals>.<dictcomp>  s2     
 
 
+
OZ 

 
 
r   )zipr,   r2   _input_unitsr7   s    r   ra   zUnitsMapping._rebuild_units
  s7    
 
/24;/M/M
 
 
r   c                 *    t          | j                  S r6   r&   r.   r7   s    r   r3   zUnitsMapping.n_inputs      4=!!!r   c                 *    t          | j                  S r6   rl   r7   s    r   r9   zUnitsMapping.n_outputs  rm   r   c                 *    t                      j        S r6   )r(   r,   r1   r4   s    r   r,   zUnitsMapping.inputs  s    ww~r   c                     t          t          | j                  j                            | |           |                                  d S r6   )r(   r	   r4   r,   fsetra   r1   valuer4   s     r   r,   zUnitsMapping.inputs  s@    lDN++277eDDDr   c                 *    t                      j        S r6   )r(   r-   rp   s    r   r-   zUnitsMapping.outputs!  s    wwr   c                     t          t          | j                  j                            | |           |                                  d S r6   )r(   r	   r4   r-   rr   ra   rs   s     r   r-   zUnitsMapping.outputs%  s@    lDN++388uEEEr   c                     | j         S r6   )rj   r7   s    r   input_unitszUnitsMapping.input_units*  s      r   c                     | j         S r6   r;   r7   s    r   r2   zUnitsMapping.mapping.  s
    }r   c                 >   g }t          || j                  D ]d\  }\  }}t          |t                    r|j        }n|}||                    |           ?|                    t          ||d                     e| j        dk    r|d         S t          |          S )NT)subokr   r   )ri   r2   
isinstancer   rt   appendr9   r*   )r1   rC   rE   argrh   return_unitrt   s          r   rF   zUnitsMapping.evaluate2  s    %(t|%<%< 	H 	H!C!![#x(( 	"e$$$$hukFFFGGGG>Q!9== r   c                 L    | j         d| j         dS d| j         d| j         dS )Nz<UnitsMapping(r=   r>   r?   r7   s    r   r@   zUnitsMapping.__repr__C  s:    94DL4444HDLHHHHHHr   )NFNN)rN   rO   rP   rQ   r)   ra   rS   r3   r9   r,   setterr-   rx   r2   rF   r@   rT   rU   s   @r   r	   r	      s       ; ;@ #'(-     2
 
 
 " " X" " " X"     X ]    ]     X ^    ^ ! ! X!   X! ! !"I I I I I I Ir   r	   N)
rQ   astropy.unitsr   corer   r   __all__r   r   r	   r   r   r   <module>r      s     # " " " " " & & & & & & & &
1
1
1n n n n nm n n nb1 1 1 1 1w 1 1 1hTI TI TI TI TI5 TI TI TI TI TIr   