
    IR-e@O                        d Z ddlmZ ddlZddlZddlmZmZm	Z	 dgZ
 ej        d          Zd Zd	 Z G d
 d          Z G d dej                  ZddZdS )z6
This module defines structured units and quantities.
    )annotationsN   )UNITYUnitUnitBaseStructuredUnitOc                    g }| j         D ][}| j        |         d         j        }|j         r%|                    |t	          |          g           F|                    |           \t          |          S )z-Recursively extract field names from a dtype.r   )namesfieldsbaseappend_names_from_dtypetuple)dtyper   namesubdtypes       8lib/python3.11/site-packages/astropy/units/structured.pyr   r      sz    E  <%a(-> 	LL$ 1( ; ;<====LL<<    c                2   g }| D ]}t          |t                    r)t          |          dk    r|                    |           At          |t                    rt          |          dk    rt          |d         t                    rt          |d                   dk    rft          |d         t
                    rKt          |d                   dk    r2|                    |d         t          |d                   g           t          |t
                    rZt          |          dk    rGt          |          }d                    d |D                       }|                    ||g           rt          d|d          t          |          S )a[  Recursively normalize, inferring upper level names for unadorned tuples.

    Generally, we want the field names to be organized like dtypes, as in
    ``(['pv', ('p', 'v')], 't')``.  But we automatically infer upper
    field names if the list is absent from items like ``(('p', 'v'), 't')``,
    by concatenating the names inside the tuple.
    r      r    c                L    g | ]!}t          |t                    r|d          n|"S r   )
isinstancelist.0is     r   
<listcomp>z$_normalize_names.<locals>.<listcomp>8   s/    TTTQZ4%8%8?QqTTaTTTr   zinvalid entry zY. Should be a name, tuple of names, or 2-element list of the form [name, tuple of names].)	r   strlenr   r   r   _normalize_namesjoin
ValueError)r   resultr   	new_tuples       r   r#   r#   !   s    F  dC   	SYY]]MM$tT""	D		Q47C(( DGq  47E** !DGq  MM47$4T!W$=$=>????e$$ 		TQ(..I77TT)TTTUUDMM4+,,,,/ / / /   ==r   c                  F    e Zd ZdZd" fd	Zd Zed             Zd Zd Z	d Z
d	 Zd
 Zd Zd" fd	Zd#dZed             Zed             Zd Zed             Z e            fdZg fdZg fdZej        g fdZd$dZd ZdZd Zd Zd Z d Z!d Z"d Z#d  Z$d! Z% xZ&S )%r   a	  Container for units for a structured Quantity.

    Parameters
    ----------
    units : unit-like, tuple of unit-like, or `~astropy.units.StructuredUnit`
        Tuples can be nested.  If a `~astropy.units.StructuredUnit` is passed
        in, it will be returned unchanged unless different names are requested.
    names : tuple of str, tuple or list; `~numpy.dtype`; or `~astropy.units.StructuredUnit`, optional
        Field names for the units, possibly nested. Can be inferred from a
        structured `~numpy.dtype` or another `~astropy.units.StructuredUnit`.
        For nested tuples, by default the name of the upper entry will be the
        concatenation of the names of the lower levels.  One can pass in a
        list with the upper-level name and a tuple of lower-level names to
        avoid this.  For tuples, not all levels have to be given; for any level
        not passed in, default field names of 'f0', 'f1', etc., will be used.

    Notes
    -----
    It is recommended to initialize the class indirectly, using
    `~astropy.units.Unit`.  E.g., ``u.Unit('AU,AU/day')``.

    When combined with a structured array to produce a structured
    `~astropy.units.Quantity`, array field names will take precedence.
    Generally, passing in ``names`` is needed only if the unit is used
    unattached to a `~astropy.units.Quantity` and one needs to access its
    fields.

    Examples
    --------
    Various ways to initialize a `~astropy.units.StructuredUnit`::

        >>> import astropy.units as u
        >>> su = u.Unit('(AU,AU/day),yr')
        >>> su
        Unit("((AU, AU / d), yr)")
        >>> su.field_names
        (['f0', ('f0', 'f1')], 'f1')
        >>> su['f1']
        Unit("yr")
        >>> su2 = u.StructuredUnit(((u.AU, u.AU/u.day), u.yr), names=(('p', 'v'), 't'))
        >>> su2 == su
        True
        >>> su2.field_names
        (['pv', ('p', 'v')], 't')
        >>> su3 = u.StructuredUnit((su2['pv'], u.day), names=(['p_v', ('p', 'v')], 't'))
        >>> su3.field_names
        (['p_v', ('p', 'v')], 't')
        >>> su3.keys()
        ('p_v', 't')
        >>> su3.values()
        (Unit("(AU, AU / d)"), Unit("d"))

    Structured units share most methods with regular units::

        >>> su.physical_type
        ((PhysicalType('length'), PhysicalType({'speed', 'velocity'})), PhysicalType('time'))
        >>> su.si
        Unit("((1.49598e+11 m, 1.73146e+06 m / s), 3.15576e+07 s)")

    Nc                    d }|t          |t                    r|j        j        }|j        }nt          |t
          j                  rI|j        st          d          t          j        d |j        D                       }t          |          }n't          |t                    s|f}t          |          }t          |t                    sKt          |          }t          |t                    r$||j        |k    r|S |                                }n|f}|4t          d t          t          |                    D                       }n/t          |          t          |          k    rt          d          g }t!          ||          D ]\  }}t          |t"                    r | ||d                   }|d         }n5t          |          }|$t          |t                    rt          d          |                    |           t'                                          |           }|t          j        d |D                       }t          j        t          |          |          d	         |_        |S )
Nz(dtype should be structured, with fields.c                     g | ]}|t           fS  )DTYPE_OBJECTr   r   s     r   r    z*StructuredUnit.__new__.<locals>.<listcomp>   s    !O!O!O44"6!O!O!Or   c              3      K   | ]	}d | V  
dS )fNr+   r   s     r   	<genexpr>z)StructuredUnit.__new__.<locals>.<genexpr>   s(      ==a'a''======r   z,lengths of units and field names must match.r   r   zKunits do not match in depth with field names from dtype or structured unit.c                Z    g | ](}t          |t                    r|d          n|t          f)S r   )r   r   r,   r-   s     r   r    z*StructuredUnit.__new__.<locals>.<listcomp>   sD        ",D$!7!7Ad1ggTLQ  r   r+   )r   r   _unitsr   field_namesnpr   r%   r   r   r   r#   r   valuesranger"   zipr   r   super__new__array)	clsunitsr   r   	convertedunitr   self	__class__s	           r   r9   zStructuredUnit.__new__   s   %00 0*)E28,, 0| Q$%OPPP!O!O5;!O!O!OPP)%00!%// %"HE(//%'' 	!KKE%00 
! =E$5$>$> L  ===5U+<+<=====EEZZ3u::%%KLLL	eU++ 	# 	#JD$$%%  s4a))Aw Dzz$D.)I)I$$?  
 T""""wws##=H  %   E huY//77;r   c                    dS )z?When de-serializing, e.g. pickle, start with a blank structure.)r+   Nr+   r?   s    r   __getnewargs__zStructuredUnit.__getnewargs__   s    xr   c                X    t          d |                                 D                       S )z6Possibly nested tuple of the field names of the parts.c              3  \   K   | ]'\  }}t          |t                    r	||j        gn|V  (d S N)r   r   r3   )r   r   r>   s      r   r0   z-StructuredUnit.field_names.<locals>.<genexpr>   sV       
 
d *4D.)I)ISdD$%%t
 
 
 
 
 
r   )r   itemsrB   s    r   r3   zStructuredUnit.field_names   s:      
 
"jjll
 
 
 
 
 	
r   c                >    t          | j        j        j                  S rF   )r"   r2   r   r   rB   s    r   __len__zStructuredUnit.__len__   s    4;$*+++r   c                    | j         |         S rF   )r2   )r?   items     r   __getitem__zStructuredUnit.__getitem__   s    {4  r   c                4    | j                                         S rF   )r2   rK   rB   s    r   r5   zStructuredUnit.values   s    {!!!r   c                $    | j         j        j        S rF   r2   r   r   rB   s    r   keyszStructuredUnit.keys   s    { &&r   c                    t          t          | j        j        j        | j                                                            S rF   )r   r7   r2   r   r   rK   rB   s    r   rG   zStructuredUnit.items   s0    S*0$+2B2B2D2DEEFFFr   c              #  8   K   | j         j        j        E d {V  d S rF   rO   rB   s    r   __iter__zStructuredUnit.__iter__   s,      ;$**********r   c                D   t          fd|                                 D                       }t          j        || j        j                  d         }||                    ||j        f          S t                                          | j	                  }||_        |S )aq  Apply func recursively.

        Parameters
        ----------
        func : callable
            Function to apply to all parts of the structured unit,
            recursing as needed.
        cls : type, optional
            If given, should be a subclass of `~numpy.void`. By default,
            will return a new `~astropy.units.StructuredUnit` instance.
        c              3  .   K   | ]} |          V  d S rF   r+   )r   partfuncs     r   r0   z4StructuredUnit._recursively_apply.<locals>.<genexpr>   s+      ==tT

======r   r+   )
r   r5   r4   r:   r2   r   viewr8   r9   r@   )r?   rW   r;   appliedresultsr&   r@   s    `    r   _recursively_applyz!StructuredUnit._recursively_apply   s     ====t{{}}=====(7DK$566r:?<<gm 4555 00r   Tc                   |r2t          |t                    r|d         }t          |t                    |t          u rt          ft          |           z  }nKt          |t                    r t          |           t          |          k    rt          d| d|  d          g }t          |                                 |          D ]\  \  }}}t          |t                    r-|	                    ||
                    |d          f           Jt          j        |          }|j        }|j        dv rt          j        t                    }|	                    |||j        f           t          j        |          S )a  Get structured dtype according to value, using our field names.

        This is useful since ``np.array(value)`` would treat tuples as lower
        levels of the array, rather than as elements of a structured array.
        The routine does presume that the type of the first tuple is
        representative of the rest.  Used in ``_get_converter``.

        For the special value of ``UNITY``, all fields are assumed to be 1.0,
        and hence this will return an all-float dtype.

        r   zcannot interpret value z
 for unit .F)enter_listsiu)r   r   r   r"   r   r%   r7   rG   r   r   _recursively_get_dtyper4   r:   r   kindfloatshape)r?   valuer^   descrr   r>   rV   
part_dtypes           r   r`   z%StructuredUnit._recursively_get_dtype   sv     	!UD)) !a UD)) !E>>Hs4yy(EEE5)) 	QSYY#e**-D-DOuOOOOOPPP"%djjllE":": 	= 	=LT4$$// =466t6OOP    x~~!Z
?d**!#%JdJ
;<<<<xr   c                P    |                      t          j        d                    S )z*The `StructuredUnit` instance in SI units.sir[   operator
attrgetterrB   s    r   rh   zStructuredUnit.si  s#     &&x':4'@'@AAAr   c                P    |                      t          j        d                    S )z+The `StructuredUnit` instance in cgs units.cgsri   rB   s    r   rm   zStructuredUnit.cgs$  s#     &&x':5'A'ABBBr   c                ^    |                      t          j        d          t                    S )N_get_physical_type_idr;   )r[   rj   methodcaller	StructurerB   s    r   ro   z$StructuredUnit._get_physical_type_id*  s0    &&!"9::	 ' 
 
 	
r   c                ^    |                      t          j        d          t                    S )z!Physical types of all the fields.physical_typerp   )r[   rj   rk   rr   rB   s    r   rt   zStructuredUnit.physical_type/  s1     &&00i ' 
 
 	
r   c                T    |                      t          j        d|                    S )a\  The `StructuredUnit` composed of only irreducible units.

        Parameters
        ----------
        bases : sequence of `~astropy.units.UnitBase`, optional
            The bases to decompose into.  When not provided,
            decomposes down to any irreducible units.  When provided,
            the decomposed result will only contain the given units.
            This will raises a `UnitsError` if it's not possible
            to do so.

        Returns
        -------
        `~astropy.units.StructuredUnit`
            With the unit for each field containing only irreducible units.
        	decompose)bases)r[   rj   rq   )r?   rw   s     r   rv   zStructuredUnit.decompose6  s)    " &&x'<[PU'V'V'VWWWr   c                6   	 t          |          }n# t          $ r Y dS w xY wt          |           t          |          k    rdS t          |                                 |                                          D ]\  }}|                    ||          s dS  dS )a  `True` if all fields are equivalent to the other's fields.

        Parameters
        ----------
        other : `~astropy.units.StructuredUnit`
            The structured unit to compare with, or what can initialize one.
        equivalencies : list of tuple, optional
            A list of equivalence pairs to try if the units are not
            directly convertible.  See :ref:`unit_equivalencies`.
            The list will be applied to all fields.

        Returns
        -------
        bool
        FequivalenciesT)r   	Exceptionr"   r7   r5   is_equivalent)r?   otherrz   	self_part
other_parts        r   r|   zStructuredUnit.is_equivalentI  s     	"5))EE 	 	 	55	 t99E

""5%(%G%G 	 	!Iz**:]*SS uu ts    
  c                     t          |t                               s                     |           }fdt                                           |                                          D              fd}|S )Nr   c                D    g | ]\  }}|                     |           S )ry   )_get_converter)r   r~   r   rz   s      r   r    z1StructuredUnit._get_converter.<locals>.<listcomp>k  s@     
 
 
'J $$Z}$MM
 
 
r   c                &   t          | d          s(t          j        |                     |                     } t          j        |           }t          |j        j                  D ]\  }} || |                   ||<   |j        r|n|d         S )Nr   r+   )	hasattrr4   r:   r`   
empty_liker7   r   r   rc   )rd   r&   r   
converter_
convertersr?   s       r   	converterz0StructuredUnit._get_converter.<locals>.converterp  s    5'** L(C(CE(J(JKK]5))F$'(:J$G$G 7 7 j)z%+66t#\966vbz9r   )r   typer@   r7   r5   )r?   r}   rz   r   r   s   ` ` @r   r   zStructuredUnit._get_converterg  s    %d,, 	6NN5N55E
 
 
 
+.t{{}}ellnn+M+M
 
 


	: 	: 	: 	: 	: 	: r   c                l    |t           j        u rt          } |                     ||          |          S )a  Return values converted to the specified unit.

        Parameters
        ----------
        other : `~astropy.units.StructuredUnit`
            The unit to convert to.  If necessary, will be converted to
            a `~astropy.units.StructuredUnit` using the dtype of ``value``.
        value : array-like, optional
            Value(s) in the current unit to be converted to the
            specified unit.  If a sequence, the first element must have
            entries of the correct type to represent all elements (i.e.,
            not have, e.g., a ``float`` where other elements have ``complex``).
            If not given, assumed to have 1. in all fields.
        equivalencies : list of tuple, optional
            A list of equivalence pairs to try if the units are not
            directly convertible.  See :ref:`unit_equivalencies`.
            This list is in addition to possible global defaults set by, e.g.,
            `set_enabled_equivalencies`.
            Use `None` to turn off all equivalencies.

        Returns
        -------
        values : scalar or array
            Converted value(s).

        Raises
        ------
        UnitsError
            If units are inconsistent
        ry   )r4   _NoValuer   r   )r?   r}   rd   rz   s       r   tozStructuredUnit.to{  s;    > BK EFt""5"FFuMMMr   genericc                   fd|                                  D             }t          |           dk    rdnd}                    d          rd |D             }d|z   dz   }|                    d                    |                    S )	a  Output the unit in the given format as a string.

        Units are separated by commas.

        Parameters
        ----------
        format : `astropy.units.format.Base` instance or str
            The name of a format or a formatter object.  If not
            provided, defaults to the generic format.

        Notes
        -----
        Structured units can be written to all formats, but can be
        re-read only with 'generic'.

        c                :    g | ]}|                               S r+   	to_string)r   rV   formats     r   r    z,StructuredUnit.to_string.<locals>.<listcomp>  s%    BBBD''BBBr   r   z({})z({},)latexc                "    g | ]}|d d         S )r   r+   )r   rV   s     r   r    z,StructuredUnit.to_string.<locals>.<listcomp>  s     222DT!B$Z222r   $z, )r5   r"   
startswithr   r$   )r?   r   partsout_fmts    `  r   r   zStructuredUnit.to_string  s    " CBBBDKKMMBBBIIMM&&wW%% 	*22E222EGmc)G~~dii..///r   c                ,    |                      d          S )Nr   r   rB   s    r   _repr_latex_zStructuredUnit._repr_latex_  s    ~~g&&&r   c                   t          t                    r*	 t          d          n# t          $ r
 t          cY S w xY wt          t
                    rDt          fd|                                 D                       }|                     ||           S t          t                    rt          S 	 ddl
m}  ||           S # t          $ r
 t          cY S w xY w)Nsilentparse_strictc              3  "   K   | ]	}|z  V  
d S rF   r+   r   rV   r}   s     r   r0   z)StructuredUnit.__mul__.<locals>.<genexpr>  '      EEtdUlEEEEEEr   r   r   Quantity)r>   )r   r!   r   r{   NotImplementedr   r   r5   r@   r   quantityr   )r?   r}   	new_unitsr   s    `  r   __mul__zStructuredUnit.__mul__  s   eS!! 	&&U::: & & &%%%%&eX&& 	9EEEEt{{}}EEEEEI>>)4>888e^,, 	"!!	"******8E---- 	" 	" 	"!!!!	"s   * >>7C
 
CCc                ,    |                      |          S rF   )r   r?   r}   s     r   __rmul__zStructuredUnit.__rmul__  s    ||E"""r   c                B   t          t                    r*	 t          d          n# t          $ r
 t          cY S w xY wt          t
                    rDt          fd|                                 D                       }|                     ||           S t          S )Nr   r   c              3  "   K   | ]	}|z  V  
d S rF   r+   r   s     r   r0   z-StructuredUnit.__truediv__.<locals>.<genexpr>  r   r   r   )	r   r!   r   r{   r   r   r   r5   r@   )r?   r}   r   s    ` r   __truediv__zStructuredUnit.__truediv__  s    eS!! 	&&U::: & & &%%%%& eX&& 	9EEEEt{{}}EEEEEI>>)4>888s   * >>c                \    	 ddl m}  ||| dd          S # t          $ r
 t          cY S w xY w)Nr   r   FT)copysubok)r   r   r{   r   )r?   mr   s      r   __rlshift__zStructuredUnit.__rlshift__  sY    	"******8At%t<<<< 	" 	" 	"!!!!	"s    ++c                *    |                                  S rF   r   rB   s    r   __str__zStructuredUnit.__str__  s    ~~r   c                2    d|                                   dS )NzUnit("z")r   rB   s    r   __repr__zStructuredUnit.__repr__  s    ,((,,,,r   c                    	 t          |          }n# t          $ r
 t          cY S w xY w|                                 |                                k    S rF   )r   r{   r   r5   r   s     r   __eq__zStructuredUnit.__eq__  sZ    	""5))EE 	" 	" 	"!!!!	" {{}}..s    &&c                    t          |t          |                     s(	 t          |          }n# t          $ r
 t          cY S w xY w|                                 |                                k    S rF   )r   r   r   r{   r   r5   r   s     r   __ne__zStructuredUnit.__ne__  sr    %d,, 	&&&u-- & & &%%%%& {{}}..s   / AArF   )T)r   )'__name__
__module____qualname____doc__r9   rC   propertyr3   rI   rL   r5   rP   rG   rS   r[   r`   rh   rm   ro   rt   setrv   r|   r   r4   r   r   r   r   __array_ufunc__r   r   r   r   r   r   r   r   __classcell__)r@   s   @r   r   r   D   s       ; ;z@ @ @ @ @ @D   
 
 X
, , ,! ! !" " "' ' 'G G G+ + +     .! ! ! !F B B XB C C XC

 
 

 
 
 X
 "cee X X X X& 24    < 35    ( !k #N #N #N #NJ0 0 0 02' ' ' O" " "(# # #
 
 
" " "     - - -/ / // / / / / / /r   c                      e Zd ZdZd Zd ZdS )rr   aR  Single element structure for physical type IDs, etc.

    Behaves like a `~numpy.void` and thus mostly like a tuple which can also
    be indexed with field names, but overrides ``__eq__`` and ``__ne__`` to
    compare only the contents, not the field names.  Furthermore, this way no
    `FutureWarning` about comparisons is given.

    c                    t          |t          j                  r|                                }|                                 |k    S rF   r   r4   voidrK   r   s     r   r   zStructure.__eq__  6    eRW%% 	!JJLLEyy{{e##r   c                    t          |t          j                  r|                                }|                                 |k    S rF   r   r   s     r   r   zStructure.__ne__  r   r   N)r   r   r   r   r   r   r+   r   r   rr   rr     s<         $ $ $$ $ $ $ $r   rr   r>   UnitBase | StructuredUnitr   np.dtypereturnc                4   t          | t                    r| S g }|j        D ]U}|j        |         d         }|j        $|                    t          | |                     @|                    |            Vt          t          |          |j                  S )a0  Make a `StructuredUnit` of one unit, with the structure of a `numpy.dtype`.

    Parameters
    ----------
    unit : UnitBase
        The unit that will be filled into the structure.
    dtype : `numpy.dtype`
        The structure for the StructuredUnit.

    Returns
    -------
    StructuredUnit
    r   Nr   )r   r   r   r   r   _structured_unit_like_dtyper   )r>   r   r<   r   r   s        r   r   r     s      $''   E  <%a(>%LL4T8DDEEEELL%,,ek::::r   )r>   r   r   r   r   r   )r   
__future__r   rj   numpyr4   corer   r   r   __all__r   r,   r   r#   r   r   rr   r   r+   r   r   <module>r      s    # " " " " "      ' ' ' ' ' ' ' ' ' '
 rx}}	 	 	     Fz/ z/ z/ z/ z/ z/ z/ z/z$ $ $ $ $ $ $ $8; ; ; ; ; ;r   