
    Owg[/                      d dl mZ d dlmZmZmZmZmZ d dlm	Z	 d dl
mZ d dlmZmZmZmZmZ d dlZd dlZd dlmZ d dlmZmZmZ d d	lmZ d d
lm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ d dl,m-Z. d dl/m0Z0m1Z1m2Z2 d dl3m4Z4m5Z5m6Z6 d dl7m8Z8 d dl9m:Z: d dl;m<Z<m=Z=m>Z>m?Z?m@Z@mAZAmBZBmCZCmDZD d dlEmFZFmGZG d dlHmIZImJZJ d dlKmLZL d dlMmNZNmOZO d dlPmQc mRZ d dlSmTZT d dlUmVZVmWZW d dlXmYZYmZZZ d dl[mQc m\Z] d dl^m_Z_ d dl`mQc mac mbZc d dl`mdZdmeZemfZfmgZg d dlhmiZi d dljmkZk d dllmmZmmnZn d dlompZpmqZq er
d dlrmsZsmtZtmuZu  evecj                        Zwewj                  dd d!        G d" d#ej                  ej                        Z{ G d$ d%ej                  ej                        Z}d.d&Z~ G d' ded      Zd/d(Zd0d1d)Zd2d*Zd3d+Zd4d5d,Zd6d-Zy)7    )annotations)
Collection	GeneratorHashableIterableSequence)wraps	getsizeof)TYPE_CHECKINGAnyCallableLiteralcastN)
get_option)algosindexlib)
duplicated)AnyAllAnyArrayLikeAxisDropKeepDtypeObjFIgnoreRaise
IndexLabelScalarSelfShapenpt)function)InvalidIndexErrorPerformanceWarningUnsortedIndexError)Appendercache_readonlydoc)find_stack_level)coerce_indexer_dtype)	ensure_int64ensure_platform_intis_hashable
is_integeris_iteratoris_list_likeis_object_dtype	is_scalarpandas_dtype)CategoricalDtypeExtensionDtype)ABCDataFrame	ABCSeries)is_array_like)array_equivalentisna)validate_putmask)CategoricalExtensionArray)factorize_from_iterablesrecode_for_categories)sanitize_array)Index_index_shared_docsensure_indexget_unanimous_names)
FrozenList)make_invalid_op)get_group_indexlexsort_indexer)get_adjustmentpprint_thing)CategoricalIndex	DataFrameSeries
MultiIndexzMultiIndex or list of tuples)klasstarget_klassc                  .    e Zd ZdZej
                  Zd Zy)MultiIndexUIntEngineza
    This class manages a MultiIndex by mapping label combinations to positive
    integers.
    c                    || j                   z  }|j                  dk(  rt        j                  j	                  |      S t        j                  j	                  |d      S )a  
        Transform combination(s) of uint64 in one uint64 (each), in a strictly
        monotonic way (i.e. respecting the lexicographic order of integer
        combinations): see BaseMultiIndexCodesEngine documentation.

        Parameters
        ----------
        codes : 1- or 2-dimensional array of dtype uint64
            Combinations of integers (one per row)

        Returns
        -------
        scalar or 1-dimensional array, of dtype uint64
            Integer(s) representing one combination (each).
           axis)offsetsndimnp
bitwise_orreduceselfcodess     P/var/www/horilla/myenv/lib/python3.12/site-packages/pandas/core/indexes/multi.py_codes_to_intsz#MultiIndexUIntEngine._codes_to_ints   sP    $ 	$,,
 ::?==''.. }}##E#22    N)__name__
__module____qualname____doc__libindexUInt64Engine_baser`    ra   r_   rR   rR      s    
 !!E3ra   rR   c                  .    e Zd ZdZej
                  Zd Zy)MultiIndexPyIntEnginez
    This class manages those (extreme) cases in which the number of possible
    label combinations overflows the 64 bits integers, and uses an ObjectEngine
    containing Python integers.
    c                    |j                  d      | j                  z  }|j                  dk(  rt        j                  j                  |      S t        j                  j                  |d      S )a  
        Transform combination(s) of uint64 in one Python integer (each), in a
        strictly monotonic way (i.e. respecting the lexicographic order of
        integer combinations): see BaseMultiIndexCodesEngine documentation.

        Parameters
        ----------
        codes : 1- or 2-dimensional array of dtype uint64
            Combinations of integers (one per row)

        Returns
        -------
        int, or 1-dimensional array of dtype object
            Integer(s) representing one combination (each).
        objectrT   rU   )astyperW   rX   rY   rZ   r[   r\   s     r_   r`   z$MultiIndexPyIntEngine._codes_to_ints   sY    & X&$,,6
 ::?==''.. }}##E#22ra   N)rb   rc   rd   re   rf   ObjectEnginerh   r`   ri   ra   r_   rk   rk      s     !!E3ra   rk   c                J     t                fd       }t        t        |      S )z
    A decorator to allow either `name` or `names` keyword but not both.

    This makes it easier to share code with base class.
    c                r    d|v rd|v rt        d      d|v r|j                  d      |d<    | g|i |S )Nnamenamesz*Can only provide one of `names` and `name`)	TypeErrorpop)self_or_clsargskwargsmeths      r_   new_methznames_compat.<locals>.new_meth   sM    V6 1HIIV$jj0F7OK1$1&11ra   )r	   r   r   )ry   rz   s   ` r_   names_compatr{      s*     4[2 2 8ra   c                  
    e Zd ZU dZej
                   e       z  ZdZg Zde	d<    e
       Z e
       ZdgZde	d<   	 	 	 	 	 	 	 	 d	 	 	 	 	 ddZddZ	 	 	 d	 	 	 	 	 ddZedej&                  f	 	 	 	 	 dd       Zee	 	 d	 	 	 	 	 	 	 dd              Zedej&                  f	 	 	 	 	 	 	 dd       Ze	 	 d	 	 	 	 	 	 	 dd       Zedd       Zedd       Zed        Zedd       ZddZedd       Z edd       Z!dd	d
d	d	 	 	 	 	 	 	 ddZ"dd
d	 	 	 ddZ#edd       Z$edd       Z%edd       Z&dd	d
d	d	 	 	 	 	 	 	 dd Z'dd
d	 	 	 dd!Z(ed"        Z)edd#       Z* e+ejX                        ej&                  fdd$       Z,dd%Z-	 	 	 d	 	 	 dd&Z.ddd'Z/ddd(Z0 e+ejb                        dd)       Z1edd*       Z2dd+Z3 e+ejh                        ddd,       Z4edd-       Z5ddd.Z6d/ Z7d0d1	 	 	 dd2Z8	 	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 dd3Z9dd4	 	 	 	 	 	 	 dd5Z:dd6Z;dd
d7dd8Z< ee<e;d9:      Z=edd;       Z>dd<Z?edd=       Z@edd>       ZAedd?       ZB e+ej                        ddd@       ZCeCZDddAZE e+ej                        dddB       ZFdddCZGddDZH e+ej                        ddE       ZId
ej&                  d	f	 	 	 	 	 ddFZJddGZKddHZLeddI       ZMdddJZNddKZOdL ZPdM ZQddNZR eSeTdO   eUz        	 	 	 d	 	 	 	 	 	 	 ddP       ZVdQ ZWdRdS	 	 	 ddTZX eSeTdU   eUz        dddV       ZY	 	 d	 	 	 	 	 ddWZZ	 d	 	 	 ddXZ[dddYZ\ddZZ]dd[Z^	 d	 	 	 dd\Z_dd]Z`	 	 	 	 d	 	 	 	 	 	 	 	 	 dd^Zadd_Zbdd`ZcddaZdeddb       Ze	 	 	 	 dԈ fdcZfdՈ fddZgddeZh	 	 	 	 	 	 ddfZidd؈ fdgZjdddhZkddiZldj ZmdddkZndddlZo	 d	 	 	 ddmZpddnZq	 	 	 	 	 	 ddoZrdddpZsddqZtddrZud fdsZvddtZwdduZxdv ZyddwZzddxZ{dy Z| e+ej                        dddz       Z}d{ Z~dd|Zdd}Zdd~Z e+ej                        ddd       Zej                  Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z ed      Z xZS )rN   a  
    A multi-level, or hierarchical, index object for pandas objects.

    Parameters
    ----------
    levels : sequence of arrays
        The unique labels for each level.
    codes : sequence of arrays
        Integers for each level designating which label at each location.
    sortorder : optional int
        Level of sortedness (must be lexicographically sorted by that
        level).
    names : optional sequence of objects
        Names for each of the index levels. (name is accepted for compat).
    copy : bool, default False
        Copy the meta-data.
    verify_integrity : bool, default True
        Check that the levels/codes are consistent and valid.

    Attributes
    ----------
    names
    levels
    codes
    nlevels
    levshape
    dtypes

    Methods
    -------
    from_arrays
    from_tuples
    from_product
    from_frame
    set_levels
    set_codes
    to_frame
    to_flat_index
    sortlevel
    droplevel
    swaplevel
    reorder_levels
    remove_unused_levels
    get_level_values
    get_indexer
    get_loc
    get_locs
    get_loc_level
    drop

    See Also
    --------
    MultiIndex.from_arrays  : Convert list of arrays to MultiIndex.
    MultiIndex.from_product : Create a MultiIndex from the cartesian product
                              of iterables.
    MultiIndex.from_tuples  : Convert list of tuples to a MultiIndex.
    MultiIndex.from_frame   : Make a MultiIndex from a DataFrame.
    Index : The base pandas Index type.

    Notes
    -----
    See the `user guide
    <https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html>`__
    for more.

    Examples
    --------
    A new ``MultiIndex`` is typically constructed using one of the helper
    methods :meth:`MultiIndex.from_arrays`, :meth:`MultiIndex.from_product`
    and :meth:`MultiIndex.from_tuples`. For example (using ``.from_arrays``):

    >>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
    >>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
    MultiIndex([(1,  'red'),
                (1, 'blue'),
                (2,  'red'),
                (2, 'blue')],
               names=['number', 'color'])

    See further examples for how to construct a MultiIndex in the doc strings
    of the mentioned helper methods.
    
multiindexzlist[Hashable | None]_namesrs   
int | None	sortorderNFTc	                   ||}||t        d      t        |      t        |      k7  rt        d      t        |      dk(  rt        d      t        j	                  |       }	i |	_        |	j                  ||d       |	j                  ||d       d gt        |      z  |	_        ||	j                  |       |t        |      |	_        n||	_        |r|	j                         }
|
|	_        |	j                          d |	_        |	S )NzMust pass both levels and codesz,Length of levels and codes must be the same.r   z)Must pass non-zero number of levels/codesF)copyvalidate)rt   len
ValueErrorrm   __new___cache_set_levels
_set_codesr~   
_set_namesintr   _verify_integrity_codes_reset_identity_references)clslevelsr^   r   rs   dtyper   rr   verify_integrityresult	new_codess              r_   r   zMultiIndex.__new__E  s
    E>U]=>>v;#e*$KLLv;!HII$ 	6u=%dU;V,e$ "9~F(F002I%FM !ra   c                z    t        |      }t        j                  |      rt        j                  ||   d|      }|S )a  
        Reassign code values as -1 if their corresponding levels are NaN.

        Parameters
        ----------
        code : list
            Code to reassign.
        level : list
            Level to check for missing values (NaN, NaT, None).

        Returns
        -------
        new code where code value = -1 if it corresponds
        to a level with missing values (NaN, NaT, None).
        )r:   rY   anywhere)r]   levelcode	null_masks       r_   _validate_codeszMultiIndex._validate_codest  s6      K	66) 88IdOR6Dra   c                   |xs | j                   }|xs | j                  }|t        t        |            }t        |      t        |      k7  rt	        d      t        |d         }|D ]  }||   }||   }t        |      |k7  r%t	        d|D cg c]  }t        |       c}       t        |      rH|j                         t        |      k\  r,t	        d| d|j                          dt        |       d      t        |      r3|j                         dk  r t	        d| d	|j                          d
      |j                  rt	        dt        |       d|        | j                  f| j                  t        | j                   | j                        kD  r9t	        d| j                   dt        | j                   | j                               g }	t        t        |            D ]B  }||v r(|	j                  | j                  ||   ||                /|	j                  ||          D t        |	      }
|
S c c}w )a  
        Parameters
        ----------
        codes : optional list
            Codes to check for validity. Defaults to current codes.
        levels : optional list
            Levels to check for validity. Defaults to current levels.
        levels_to_validate: optional list
            Specifies the levels to verify.

        Raises
        ------
        ValueError
            If length of levels and codes don't match, if the codes for any
            level would exceed level bounds, or there are any duplicate levels.

        Returns
        -------
        new codes where code value = -1 if it corresponds to a
        NaN level.
        zTLength of levels and codes must match. NOTE: this index is in an inconsistent state.r   zUnequal code lengths: z	On level z, code max (z) >= length of level (z/). NOTE: this index is in an inconsistent stater   z, code value (z) < -1zLevel values must be unique: z
 on level zQValue for sortorder must be inferior or equal to actual lexsort_depth: sortorder z with lexsort_depth )r^   r   ranger   r   maxmin	is_uniquelistr   _lexsort_depthnlevelsappendr   rE   )r]   r^   r   levels_to_verifycodes_lengthir   level_codescode_result_codesr   s              r_   r   zMultiIndex._verify_integrity  sN   : #&4;;#$S[1v;#e*$:  58}! 	A1IE(K;</ ,e-LUc%j-L,MN  ;KOO$5U$C s,{/@.A B!%j\ *)) 
 ;KOO$5$: 9QC~koo>O=PPV!WXX?? 3DK=
1#N #	( >>%~~tzz4<< HH 004/? @**8T\\*R)SU  s6{# 	.A$$##D$8$8E!H$MN##E!H-		. |,	= .Ms   H<c                   d}t        |      st        |      t        |      rt        |      }|D ]  }t        |      rt        |       t	        dt        |            D ]-  }t        ||         t        ||dz
           k7  s$t        d       t        |      \  }}|t        j                  u r|D 	cg c]  }	t        |	dd       }}	 | ||||d      S c c}	w )a  
        Convert arrays to MultiIndex.

        Parameters
        ----------
        arrays : list / sequence of array-likes
            Each array-like gives one level's value for each data point.
            len(arrays) is the number of levels.
        sortorder : int or None
            Level of sortedness (must be lexicographically sorted by that
            level).
        names : list / sequence of str, optional
            Names for the levels in the index.

        Returns
        -------
        MultiIndex

        See Also
        --------
        MultiIndex.from_tuples : Convert list of tuples to MultiIndex.
        MultiIndex.from_product : Make a MultiIndex from cartesian product
                                  of iterables.
        MultiIndex.from_frame : Make a MultiIndex from a DataFrame.

        Examples
        --------
        >>> arrays = [[1, 1, 2, 2], ['red', 'blue', 'red', 'blue']]
        >>> pd.MultiIndex.from_arrays(arrays, names=('number', 'color'))
        MultiIndex([(1,  'red'),
                    (1, 'blue'),
                    (2,  'red'),
                    (2, 'blue')],
                   names=['number', 'color'])
        z/Input must be a list / sequence of array-likes.rT   zall arrays must be same lengthrr   NFr   r^   r   rs   r   )r0   rt   r/   r   r   r   r   r>   r   
no_defaultgetattr)
r   arraysr   rs   	error_msgarrayr   r^   r   arrs
             r_   from_arrayszMultiIndex.from_arrays  s    T F	F#I&&v&\F  	+E&	**	+ q#f+& 	CA6!9~VAE]!33 !ABB	C 18vCNN";ABCWS&$/BEB"
 	
 Cs   5Cc                   t        |      st        d      t        |      rt        |      }t	        t
        t        t        df      |      }t        |      rrt        d |D              r`t        j                  t        |            g}t        t        j                  |t        j                  d                  g} | ||||d      S t        |      dk(  r|t        d	      g gt        |      z  }nt!        |t        j"                  t        f      rXt!        |t              rt        j$                  |j&                        }t        t)        j*                  |      j,                        }n_t!        |t              r)t        t)        j.                  |      j,                        }n&t1        | }t	        t        t2        t              |      }| j5                  |||
      S )a}  
        Convert list of tuples to MultiIndex.

        Parameters
        ----------
        tuples : list / sequence of tuple-likes
            Each tuple is the index of one row/column.
        sortorder : int or None
            Level of sortedness (must be lexicographically sorted by that
            level).
        names : list / sequence of str, optional
            Names for the levels in the index.

        Returns
        -------
        MultiIndex

        See Also
        --------
        MultiIndex.from_arrays : Convert list of arrays to MultiIndex.
        MultiIndex.from_product : Make a MultiIndex from cartesian product
                                  of iterables.
        MultiIndex.from_frame : Make a MultiIndex from a DataFrame.

        Examples
        --------
        >>> tuples = [(1, 'red'), (1, 'blue'),
        ...           (2, 'red'), (2, 'blue')]
        >>> pd.MultiIndex.from_tuples(tuples, names=('number', 'color'))
        MultiIndex([(1,  'red'),
                    (1, 'blue'),
                    (2,  'red'),
                    (2, 'blue')],
                   names=['number', 'color'])
        z/Input must be a list / sequence of tuple-likes..c              3  F   K   | ]  }t        |t              xr |   y wN)
isinstancetuple).0es     r_   	<genexpr>z)MultiIndex.from_tuples.<locals>.<genexpr>S  s!     N!z!U3=A=Ns   !rm   r   Fr   r   z-Cannot infer number of levels from empty listr   rs   )r0   rt   r/   r   r   r   r   r   r   allrY   zerosrA   comasarray_tuplesafer   r   ndarrayasarray_valuesr   tuples_to_object_arrayTto_object_array_tupleszipr   r   )r   tuplesr   rs   r^   r   r   arrss           r_   from_tupleszMultiIndex.from_tuples!  s   V F#MNNv&\Fjx}!56? v;3NvNNXXc&k*+EC11&@RSTUF#!&  v;!} OPP TCJ&FU 34&%(FNN3#44V<>>?F%#44V<>>?F<D$x12D9Fv%HHra   c                   ddl m} t        |      st        d      t	        |      rt        |      }t        |      \  }}|t        j                  u r|D cg c]  }t        |dd       }} ||      } | ||||      S c c}w )at  
        Make a MultiIndex from the cartesian product of multiple iterables.

        Parameters
        ----------
        iterables : list / sequence of iterables
            Each iterable has unique labels for each level of the index.
        sortorder : int or None
            Level of sortedness (must be lexicographically sorted by that
            level).
        names : list / sequence of str, optional
            Names for the levels in the index.
            If not explicitly provided, names will be inferred from the
            elements of iterables if an element has a name attribute.

        Returns
        -------
        MultiIndex

        See Also
        --------
        MultiIndex.from_arrays : Convert list of arrays to MultiIndex.
        MultiIndex.from_tuples : Convert list of tuples to MultiIndex.
        MultiIndex.from_frame : Make a MultiIndex from a DataFrame.

        Examples
        --------
        >>> numbers = [0, 1, 2]
        >>> colors = ['green', 'purple']
        >>> pd.MultiIndex.from_product([numbers, colors],
        ...                            names=['number', 'color'])
        MultiIndex([(0,  'green'),
                    (0, 'purple'),
                    (1,  'green'),
                    (1, 'purple'),
                    (2,  'green'),
                    (2, 'purple')],
                   names=['number', 'color'])
        r   )cartesian_productz-Input must be a list / sequence of iterables.rr   Nr   )
pandas.core.reshape.utilr   r0   rt   r/   r   r>   r   r   r   )r   	iterablesr   rs   r   r^   r   its           r_   from_productzMultiIndex.from_productr  s    \ 	?I&KLLy!YI0;vCNN"9BC2WR.CEC "%(65IUCC	 Ds   Bc                    t        |t              st        d      t        |j	                          \  }}||n|}| j                  |||      S )aK  
        Make a MultiIndex from a DataFrame.

        Parameters
        ----------
        df : DataFrame
            DataFrame to be converted to MultiIndex.
        sortorder : int, optional
            Level of sortedness (must be lexicographically sorted by that
            level).
        names : list-like, optional
            If no names are provided, use the column names, or tuple of column
            names if the columns is a MultiIndex. If a sequence, overwrite
            names with the given sequence.

        Returns
        -------
        MultiIndex
            The MultiIndex representation of the given DataFrame.

        See Also
        --------
        MultiIndex.from_arrays : Convert list of arrays to MultiIndex.
        MultiIndex.from_tuples : Convert list of tuples to MultiIndex.
        MultiIndex.from_product : Make a MultiIndex from cartesian product
                                  of iterables.

        Examples
        --------
        >>> df = pd.DataFrame([['HI', 'Temp'], ['HI', 'Precip'],
        ...                    ['NJ', 'Temp'], ['NJ', 'Precip']],
        ...                   columns=['a', 'b'])
        >>> df
              a       b
        0    HI    Temp
        1    HI  Precip
        2    NJ    Temp
        3    NJ  Precip

        >>> pd.MultiIndex.from_frame(df)
        MultiIndex([('HI',   'Temp'),
                    ('HI', 'Precip'),
                    ('NJ',   'Temp'),
                    ('NJ', 'Precip')],
                   names=['a', 'b'])

        Using explicit names, instead of the column names

        >>> pd.MultiIndex.from_frame(df, names=['state', 'observation'])
        MultiIndex([('HI',   'Temp'),
                    ('HI', 'Precip'),
                    ('NJ',   'Temp'),
                    ('NJ', 'Precip')],
                   names=['state', 'observation'])
        zInput must be a DataFramer   )r   r6   rt   r   itemsr   )r   dfr   rs   column_namescolumnss         r_   
from_framezMultiIndex.from_frame  sP    | "l+788 #RXXZ 0g %5w)5IIra   c                V   g }t        | j                        D ]  }| j                  |   }| j                  |   }|}t	        |j
                  t              r&t        d|      }|j                  j                         }t	        |j
                  t              s t        j                  |j
                  d      r|j                  t              }t        j                   |      }t#        j$                  |||j&                        }|j)                  |        t        j*                  |      }|S )NrK   mM
fill_value)r   r   r   r^   r   r   r4   r   _data_internal_get_valuesr5   r   is_np_dtypern   rm   rY   r   r   take_nd	_na_valuer   fast_zip)r]   valuesr   r   r^   valsr   s          r_   r   zMultiIndex._values  s     t||$ 	 AKKNEJJqMED$**&67.5zz668$**n5

D: {{6*::d#D==uIDMM$!	 $ ll6"
ra   c                    | j                   S r   r   r]   s    r_   r   zMultiIndex.values  s    ||ra   c                    t        d      )z
        Raises a ValueError for `MultiIndex` because there's no single
        array backing a MultiIndex.

        Raises
        ------
        ValueError
        zcMultiIndex has no single backing array. Use 'MultiIndex.to_numpy()' to get a NumPy array of tuples.)r   r   s    r_   r   zMultiIndex.array  s     F
 	
ra   c                    ddl m} t        j                  | j                  D cg c]  }|j
                   c}      } || j                  D cg c]  }|j                   c}t        |            S c c}w c c}w )ax  
        Return the dtypes as a Series for the underlying MultiIndex.

        Examples
        --------
        >>> idx = pd.MultiIndex.from_product([(0, 1, 2), ('green', 'purple')],
        ...                                  names=['number', 'color'])
        >>> idx
        MultiIndex([(0,  'green'),
                    (0, 'purple'),
                    (1,  'green'),
                    (1, 'purple'),
                    (2,  'green'),
                    (2, 'purple')],
                   names=['number', 'color'])
        >>> idx.dtypes
        number     int64
        color     object
        dtype: object
        r   )rM   )r   )pandasrM   r   fill_missing_namesr   rr   r   rA   )r]   rM   r   rs   s       r_   dtypeszMultiIndex.dtypes#  sW    , 	"&&'Lu

'LM<uu{{<E%LQQ (M<s   A3A8c                2    t        | j                  d         S Nr   )r   r^   r   s    r_   __len__zMultiIndex.__len__>  s    4::a=!!ra   c                    t        |       S )zG
        Return the number of elements in the underlying data.
        r   r   s    r_   sizezMultiIndex.sizeA  s     4yra   c                    t        | j                  | j                        D cg c]  \  }}|j                  |       }}}|D ]	  }d|_         t        |      S c c}}w )aA  
        Levels of the MultiIndex.

        Levels refer to the different hierarchical levels or layers in a MultiIndex.
        In a MultiIndex, each level represents a distinct dimension or category of
        the index.

        To access the levels, you can use the levels attribute of the MultiIndex,
        which returns a tuple of Index objects. Each Index object represents a
        level in the MultiIndex and contains the unique values found in that
        specific level.

        If a MultiIndex is created with levels A, B, C, and the DataFrame using
        it filters out all rows of the level C, MultiIndex.levels will still
        return A, B, C.

        Examples
        --------
        >>> index = pd.MultiIndex.from_product([['mammal'],
        ...                                     ('goat', 'human', 'cat', 'dog')],
        ...                                    names=['Category', 'Animals'])
        >>> leg_num = pd.DataFrame(data=(4, 2, 4, 4), index=index, columns=['Legs'])
        >>> leg_num
                          Legs
        Category Animals
        mammal   goat        4
                 human       2
                 cat         4
                 dog         4

        >>> leg_num.index.levels
        FrozenList([['mammal'], ['cat', 'dog', 'goat', 'human']])

        MultiIndex levels will not change even if the DataFrame using the MultiIndex
        does not contain all them anymore.
        See how "human" is not in the DataFrame, but it is still in levels:

        >>> large_leg_num = leg_num[leg_num.Legs > 2]
        >>> large_leg_num
                          Legs
        Category Animals
        mammal   goat        4
                 cat         4
                 dog         4

        >>> large_leg_num.index.levels
        FrozenList([['mammal'], ['cat', 'dog', 'goat', 'human']])
        rr   T)r   _levelsr~   _rename_no_setting_namerE   )r]   xrr   r   r   s        r_   r   zMultiIndex.levelsL  s`    j 7:$,,6TU71d!)))&UU 	*E%)E"	* &!!	 Vs   A)r   r   r   r   c                  |rbt        |      dk(  rt        d      |#t        |      | j                  k7  rt        d      |"t        |      t        |      k7  rt        d      |2t        fd|D              }t	        t        t        |                  }np|D cg c]  }| j                  |       }}t	        | j                        }	t        ||      D ]#  \  }
}t        |      j                         |	|
<   % t        |	      }|r| j                  ||      }|| _        | j                  }|| _        t        |      r| j                  |       | j!                          y c c}w )Nr   z#Must set non-zero number of levels.z-Length of levels must match number of levels.z,Length of levels must match length of level.c              3  T   K   | ]  }t        |       j                          ! ywr   N)rC   _view)r   levr   s     r_   r   z)MultiIndex._set_levels.<locals>.<genexpr>  s&      $9<St,224$s   %(r   )r   r   )r   r   r   rE   r   r   _get_level_numberr   r   rC   r   r   r   rs   r   r   _reset_cache)r]   r   r   r   r   r   
new_levelslevel_numbersr   new_levels_listlev_numr   rs   s      `         r_   r   zMultiIndex._set_levels  sY    6{a !FGG}V!< !PQQ S[CJ%> !OPP=# $@F$ J !s:!78MDIJST33C8JMJ"4<<0O #M6 : P+7$+G+M+M+O(P#O4J..!M / I $DK

!u:OOE"# Ks   E&r   r   c                  t        |t              rn-t        |      rt        |      }nt        |      rt	        |      }t        ||d      \  }}| j                         }|j                          |j                  ||d|       |S )a	  
        Set new levels on MultiIndex. Defaults to returning new index.

        Parameters
        ----------
        levels : sequence or list of sequence
            New level(s) to apply.
        level : int, level name, or sequence of int/level names (default None)
            Level(s) to set (None for all levels).
        verify_integrity : bool, default True
            If True, checks that levels and codes are compatible.

        Returns
        -------
        MultiIndex

        Examples
        --------
        >>> idx = pd.MultiIndex.from_tuples(
        ...     [
        ...         (1, "one"),
        ...         (1, "two"),
        ...         (2, "one"),
        ...         (2, "two"),
        ...         (3, "one"),
        ...         (3, "two")
        ...     ],
        ...     names=["foo", "bar"]
        ... )
        >>> idx
        MultiIndex([(1, 'one'),
            (1, 'two'),
            (2, 'one'),
            (2, 'two'),
            (3, 'one'),
            (3, 'two')],
           names=['foo', 'bar'])

        >>> idx.set_levels([['a', 'b', 'c'], [1, 2]])
        MultiIndex([('a', 1),
                    ('a', 2),
                    ('b', 1),
                    ('b', 2),
                    ('c', 1),
                    ('c', 2)],
                   names=['foo', 'bar'])
        >>> idx.set_levels(['a', 'b', 'c'], level=0)
        MultiIndex([('a', 'one'),
                    ('a', 'two'),
                    ('b', 'one'),
                    ('b', 'two'),
                    ('c', 'one'),
                    ('c', 'two')],
                   names=['foo', 'bar'])
        >>> idx.set_levels(['a', 'b'], level='bar')
        MultiIndex([(1, 'a'),
                    (1, 'b'),
                    (2, 'a'),
                    (2, 'b'),
                    (3, 'a'),
                    (3, 'b')],
                   names=['foo', 'bar'])

        If any of the levels passed to ``set_levels()`` exceeds the
        existing length, all of the values from that argument will
        be stored in the MultiIndex levels, though the values will
        be truncated in the MultiIndex output.

        >>> idx.set_levels([['a', 'b', 'c'], [1, 2, 3, 4]], level=[0, 1])
        MultiIndex([('a', 1),
            ('a', 2),
            ('b', 1),
            ('b', 2),
            ('c', 1),
            ('c', 2)],
           names=['foo', 'bar'])
        >>> idx.set_levels([['a', 'b', 'c'], [1, 2, 3, 4]], level=[0, 1]).levels
        FrozenList([['a', 'b', 'c'], [1, 2, 3, 4]])
        LevelsT)r   r   r   )	r   rA   r8   r0   r   _require_listliker   r   r   )r]   r   r   r   idxs        r_   
set_levelszMultiIndex.set_levels  s    f fe$6"6]F&!&\F)%Bvjjl%$AQ 	 	
 
ra   c                ,    t        | j                        S )a  
        Integer number of levels in this MultiIndex.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a'], ['b'], ['c']])
        >>> mi
        MultiIndex([('a', 'b', 'c')],
                   )
        >>> mi.nlevels
        3
        )r   r   r   s    r_   r   zMultiIndex.nlevels  s     4<<  ra   c                :    t        d | j                  D              S )a  
        A tuple with the length of each level.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a'], ['b'], ['c']])
        >>> mi
        MultiIndex([('a', 'b', 'c')],
                   )
        >>> mi.levshape
        (1, 1, 1)
        c              3  2   K   | ]  }t        |        y wr   r   r   r   s     r_   r   z&MultiIndex.levshape.<locals>.<genexpr>4  s     1SV1   )r   r   r   s    r_   levshapezMultiIndex.levshape&  s     1T[[111ra   c                    | j                   S r   )r   r   s    r_   r^   zMultiIndex.codes9      {{ra   c               `   |rI|#t        |      | j                  k7  rt        d      |"t        |      t        |      k7  rt        d      |=t        fdt	        | j
                  |      D              }t        t        |            }nr|D cg c]  }| j                  |       }}t        | j                        }	t	        ||      D ]%  \  }
}| j                  |
   }t        ||      |	|
<   ' t        |	      }|r| j                  ||      }|| _	        | j                          y c c}w )Nz+Length of codes must match number of levelsz,Length of codes must match length of levels.c              3  \   K   | ]#  \  }}t        ||       j                          % ywr   )_coerce_indexer_frozenview)r   r   r   r   s      r_   r   z(MultiIndex._set_codes.<locals>.<genexpr>N  s/      #$C '{CdCHHJ#s   ),r   )r^   r   )r   r   r   rE   r   r   r   r   r   r   r   r  r   r  )r]   r^   r   r   r   r   r   r  r   new_codes_listr  r   s      `        r_   r   zMultiIndex._set_codes=  s1    }Ut||!; !NOO SZ3u:%= !OPP =" #(+DLL%(@# I "#i.1MDIJST33C8JMJ!$++.N(+M5(A $kk'**@4+w'
 #>2I..- / I  ! Ks   D+c                   t        ||d      \  }}| j                         }|j                          |j                  |||       |S )a0  
        Set new codes on MultiIndex. Defaults to returning new index.

        Parameters
        ----------
        codes : sequence or list of sequence
            New codes to apply.
        level : int, level name, or sequence of int/level names (default None)
            Level(s) to set (None for all levels).
        verify_integrity : bool, default True
            If True, checks that levels and codes are compatible.

        Returns
        -------
        new index (of same type and class...etc) or None
            The same type as the caller or None if ``inplace=True``.

        Examples
        --------
        >>> idx = pd.MultiIndex.from_tuples(
        ...     [(1, "one"), (1, "two"), (2, "one"), (2, "two")], names=["foo", "bar"]
        ... )
        >>> idx
        MultiIndex([(1, 'one'),
            (1, 'two'),
            (2, 'one'),
            (2, 'two')],
           names=['foo', 'bar'])

        >>> idx.set_codes([[1, 0, 1, 0], [0, 0, 1, 1]])
        MultiIndex([(2, 'one'),
                    (1, 'one'),
                    (2, 'two'),
                    (1, 'two')],
                   names=['foo', 'bar'])
        >>> idx.set_codes([1, 0, 1, 0], level=0)
        MultiIndex([(2, 'one'),
                    (1, 'two'),
                    (2, 'one'),
                    (1, 'two')],
                   names=['foo', 'bar'])
        >>> idx.set_codes([0, 0, 1, 1], level='bar')
        MultiIndex([(1, 'one'),
                    (1, 'one'),
                    (2, 'two'),
                    (2, 'two')],
                   names=['foo', 'bar'])
        >>> idx.set_codes([[1, 0, 1, 0], [0, 0, 1, 1]], level=[0, 1])
        MultiIndex([(2, 'one'),
                    (1, 'one'),
                    (2, 'two'),
                    (1, 'two')],
                   names=['foo', 'bar'])
        Codesr  )r	  r   r   r   )r]   r^   r   r   r
  s        r_   	set_codeszMultiIndex.set_codesf  sF    t )w?ujjluE<LM
ra   c           
        t        j                  t        j                  | j                  D cg c]  }t	        |      t
        j                  z     c}            }t        j                  |d d d         d d d   }t        j                  |dd  dgg      j                  d      }|d   dkD  r!t        | j                  | j                  |      S t        | j                  | j                  |      S c c}w )Nr   rT   r   uint64@   )rY   ceillog2r   r   rf   multiindex_nulls_shiftcumsumconcatenatern   rk   r^   rR   )r]   r   sizeslev_bitsrW   s        r_   _enginezMultiIndex._engine  s     GGKO;;W%Uh===W
 99U4R4[)$B$/ ..(12,!45<<XF A;(djj'JJ#DKKWEE% Xs   #C0c                ,    t        |       j                  S r   )typer   r   s    r_   _constructorzMultiIndex._constructor  s    Dz%%%ra   c                |    |t         j                  ur|n| j                  }t        |       j	                  |d |      S )Nr   )r   r   rs   r(  r   )r]   r   rr   rs   s       r_   _shallow_copyzMultiIndex._shallow_copy  s4    CNN2

Dz%%fE%JJra   c                     t        |       | j                  | j                  | j                  | j                  d      }| j
                  j                         |_        |j
                  j                  dd        |S )NFr   r   )r(  r   r^   r   rs   r   r   ru   )r]   r   s     r_   r   zMultiIndex._view  s`    d;;**nn**"
 ((*(D)ra   c                   | j                  |||      }| }d\  }}|r*ddlm}  || j                        } || j                        }||n| j                  }||n| j                  } t        |       ||| j                  |d      }| j                  j                         |_        |j                  j                  dd       |r| j                  |_	        |S )	a  
        Make a copy of this object.

        Names, dtype, levels and codes can be passed and will be set on new copy.

        Parameters
        ----------
        names : sequence, optional
        deep : bool, default False
        name : Label
            Kept for compatibility with 1-dimensional Index. Should not be used.

        Returns
        -------
        MultiIndex

        Notes
        -----
        In most cases, there should be no functional difference from using
        ``deep``, but if ``deep`` is passed it will attempt to deepcopy.
        This could be potentially expensive on large MultiIndex objects.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a'], ['b'], ['c']])
        >>> mi
        MultiIndex([('a', 'b', 'c')],
                   )
        >>> mi.copy()
        MultiIndex([('a', 'b', 'c')],
                   )
        )rr   rs   deepNNr   )deepcopyNFr   r   )
_validate_namesr   r0  r   r^   r(  r   r   ru   _id)	r]   rs   r.  rr   keep_idr   r^   r0  	new_indexs	            r_   r   zMultiIndex.copy  s    L $$$e$$G("%dkk*FTZZ(E!-4;;*

DJnn"
	  ;;++-	Xt, HHIMra   c                    | j                   S )z%the array interface, return my values)r   )r]   r   r   s      r_   	__array__zMultiIndex.__array__   r  ra   c                H    | j                         }| j                  |_        |S )z0this is defined as a copy with the same identity)r   r2  )r]   r   r   s      r_   r  zMultiIndex.view$  s    XX
ra   c                r    t        |       	 | j                  |       y# t        t        t        f$ r Y yw xY w)NTF)hashget_locLookupErrorrt   r   r]   keys     r_   __contains__zMultiIndex.__contains__*  s6    S		LLY
3 		s    66c                ,    t        j                  d      S )NO)rY   r   r   s    r_   r   zMultiIndex.dtype3  s    xx}ra   c                H    ddt        fd| j                  D              S )z5return a boolean if we need a qualified .info displayc                "    d| v xs
 d| v xs d| v S )Nmixedstringunicoderi   r   s    r_   fz0MultiIndex._is_memory_usage_qualified.<locals>.f:  s!    e#Nx5'8NI<NNra   c              3  .   K   | ]  } |        y wr   ri   )r   r   rG  s     r_   r   z8MultiIndex._is_memory_usage_qualified.<locals>.<genexpr>=  s     D1U8Ds   returnbool)r   _inferred_type_levels)r]   rG  s    @r_   _is_memory_usage_qualifiedz%MultiIndex._is_memory_usage_qualified7  s"    	O D)C)CDDDra   c                $    | j                  |      S r   _nbytes)r]   r.  s     r_   memory_usagezMultiIndex.memory_usage@  s    
 ||D!!ra   c                $    | j                  d      S )z1return the number of bytes in the underlying dataFrO  r   s    r_   nbyteszMultiIndex.nbytesG  s     ||E""ra   c                   dt        fd| j                  D              }t        d | j                  D              }t        fd| j                  D              }||z   |z   }|| j                  j                        z  }|S )z
        return the number of bytes in the underlying data
        deeply introspect the level data if deep=True

        include the engine hashtable

        *this is in internal routine*

           c              3  B   K   | ]  }|j                           yw)r.  N)rQ  )r   r   r.  s     r_   r   z%MultiIndex._nbytes.<locals>.<genexpr>Y  s     J1>>t>4J   c              3  4   K   | ]  }|j                     y wr   )rS  )r   r   s     r_   r   z%MultiIndex._nbytes.<locals>.<genexpr>Z  s     81888   c              3  6   K   | ]  }t        |        y wr   r
   )r   r   objsizes     r_   r   z%MultiIndex._nbytes.<locals>.<genexpr>[  s     EQ9Q0Es   rW  )sumr   r^   rs   r&  sizeof)r]   r.  level_nbyteslabel_nbytesnames_nbytesr   r\  s    `    @r_   rP  zMultiIndex._nbytesL  sx     JdkkJJ8TZZ88E$**EE,|; 	$,,%%4%00ra   c                    | j                   D cg c]  }|j                   }}t        d t        ||      D              S c c}w )zW
        Formats each item in tup according to its level's formatter function.
        c              3  2   K   | ]  \  }} ||        y wr   ri   )r   funcvals      r_   r   z-MultiIndex._formatter_func.<locals>.<genexpr>j  s     J94T#YJr  )r   _formatter_funcr   r   )r]   tupr   formatter_funcss       r_   rf  zMultiIndex._formatter_funce  s@     ?CkkJU500JJJOS0IJJJ Ks   A nan)na_repc                  g }g }t        | j                  | j                        D ]  \  }} |j                  dd|i|}|dk(  }|j	                         rct        |      }	|j                  t              }t        j                  ||      }|j                  j                  rJ |j                         }|	||<   |j                  |       |j                  |        t        |      dk(  r.t        |d   j                  |d               j                         S t        ||| j                   | j"                  d      }
|
j$                  S )Nrj  r   rT   r   Fr   r^   rs   r   r   ri   )r   r   r^   _get_values_for_csvr   r   rn   strrY   r   flags	writeabler   rA   takerN   rs   r   r   )r]   rj  rx   r  r   r   r   
level_strsmask	nan_indexmis              r_   rm  zMultiIndex._get_values_for_csvl  s6    
	 #&dkk4::"> 	*E;222K&KFKJ"$Dxxz
O	'..s3
YYz6:
&,,6666)..0$-D!j)[)	* z?aA++IaL9:NNPP !jj..!&B ::ra   c           	        t        j                  t        |       j                   dt        t                      ||}t        |       dk(  rg S g }t        | j                  | j                        D ]  \  }	}
||nt        |	j                        }t        |	      dkD  rg|	j                  |
      j                  |      }|
dk(  }|j                         rvt        j                   |t"              }|||<   |j%                         }nEt'        j(                  |	j*                  |
      D cg c]  }t-        t/        |      r|n|d       }}|j1                  |        g }t        || j2                        D ]d  \  }	}g }|r |j1                  |t-        |d      nd	       |j5                  t        j                   |	t"                     |j1                  |       f |t7        d
      }|rSd	}t9        |t:              s|t<        j>                  u sJ |dt<        j>                  fv r|}tA        |tC        |      |      }|r,tE               } |jF                  |g| jI                  d      S |S c c}w )Nz.format is deprecated and will be removed in a future version. Convert using index.astype(str) or index.map(formatter) instead.
stacklevelr   	formatterr   r   	
escape_chars display.multi_sparseFstartsentinelr~  )%warningswarnr(  rb   FutureWarningr)   r   r   r   r^   _get_na_repr   rq  formatr   rY   r   rm   tolistr   r   r   rJ   r:   r   rs   extendr   r   rK  r   r   sparsify_labelsr   rI   adjoinsplit)r]   rr   rz  rj  rs   spacesparsifyr  stringified_levelsr   r   na	formattedrs  r   result_levelslev_namer   r  adjs                       r_   r  zMultiIndex.format  sS    	Dz""# $, , ')	
 Et9>I #DKK < 	1C!-;syy3IB3x!|HH[18898M	 #b(88: "& AI&(IdO ) 0 0 2I #]]3;;D !tAwADVW	  %%i0'	1*  !3TZZ@ 	(MCE+ !8JK LL#V45  '	( !"89H;=Hh-S^^1KKKE3>>22#+SZ(M  "C3::e4m4::4@@  Ms   '!I.ry  c          	        t        |       dk(  rg S g }t        | j                  | j                        D ]  \  }}t	        |j
                        }t        |      dkD  rl|j                  |      x}}	|j                  d|      }	|dk(  }
|
j                         rvt        j                  |	t              }	||	|
<   |	j                         }	nEt        j                  |j                  |      D cg c]  }t!        t#        |      r|n|d       }	}|j%                  |	        g }t        || j&                        D ]d  \  }}g }|r |j%                  |t!        |d      nd       |j)                  t        j                  |t                     |j%                  |       f |t+        d	      }|rQd}t-        |t.              s|t0        j2                  u sJ |t0        j2                  u r|}t5        |t7        |      |
      }|S c c}w )Nr   F)include_namerz  r   r   r{  r  r  r  r  )r   r   r   r^   r  r   rq  _format_flatr   rY   r   rm   r  r   r   r   rJ   r:   r   rs   r  r   r   rK  r   r   r  r   )r]   include_namesr  rz  r  r   r   r  takenr  rs  r   r  r  r   r  s                   r_   _format_multizMultiIndex._format_multi  s    t9>I #DKK < 	1CSYY'B3x!|$'HH[$99	!..EY.W	 #b(88: "& AI&(IdO ) 0 0 2I #]]3;;D !tAwADVW	  %%i0)	1,  !3TZZ@ 	(MCE+ !8JK LL#V45  '	( !"89H;=Hh-S^^1KKK3>>)#+S%7(M Es   *!Hc                ,    t        | j                        S r   )rE   r~   r   s    r_   
_get_nameszMultiIndex._get_names#  s    $++&&ra   )r   r   c                  |t        |      st        d      t        |      }|rI|"t        |      t        |      k7  rt        d      |#t        |      | j                  k7  rt        d      |t        | j                        }n|D cg c]  }| j                  |       }}t        ||      D ]B  \  }}|,t        |      s!t        t        |       j                   d      || j                  |<   D | j                          yc c}w )a  
        Set new names on index. Each name has to be a hashable type.

        Parameters
        ----------
        values : str or sequence
            name(s) to set
        level : int, level name, or sequence of int/level names (default None)
            If the index is a MultiIndex (hierarchical), level(s) to set (None
            for all levels).  Otherwise level must be None
        validate : bool, default True
            validate that the names match level lengths

        Raises
        ------
        TypeError if each name is not hashable.

        Notes
        -----
        sets names on levels. WARNING: mutates!

        Note that you generally want to set this *after* changing levels, so
        that it only acts on copies
        Nz*Names should be list-like for a MultiIndexz+Length of names must match length of level.z:Length of names must match number of levels in MultiIndex.z.name must be a hashable type)r0   r   r   r   r   r   r   r   r-   rt   r(  rb   r~   r  )r]   rs   r   r   r   rr   s         r_   r   zMultiIndex._set_names&  s   6 \%%8IJJU SZ3u:%= !NOO}Ut||!; P  =$,,'E<ABST++C0BEB UE* 	$IC #4(#:..//LM   $DKK	$ 	 Cs   Dam  
        Names of levels in MultiIndex.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays(
        ... [[1, 2], [3, 4], [5, 6]], names=['x', 'y', 'z'])
        >>> mi
        MultiIndex([(1, 3, 5),
                    (2, 4, 6)],
                   names=['x', 'y', 'z'])
        >>> mi.names
        FrozenList(['x', 'y', 'z'])
        )fsetfgetr(   c                     y)NrC  ri   r   s    r_   inferred_typezMultiIndex.inferred_typeu  s    ra   c                   | j                   j                  |      }|dkD  rt        |      st        d| d      	 | j                   j	                  |      }|S # t        $ r}t        |      st        d| d      ||dk  r@|| j                  z  }|dk  rZ|| j                  z
  }t        d| j                   d| d	      ||| j                  k\  rt        d| j                   d
|dz          |Y d }~|S d }~ww xY w)NrT   z	The name z* occurs multiple times, use a level numberzLevel z
 not foundr   z Too many levels: Index has only z	 levels, z is not a valid level numberz levels, not )rs   countr.   r   r   KeyErrorr   
IndexError)r]   r   r  err
orig_levels        r_   r   zMultiIndex._get_level_numbery  s,   

  'AIz%0E7"LM 	JJ$$U+E$ #  	e$wj9:Cqy%19!&!5J$:4<<.	%,&BD 
 $,,& 6t||n E 19+'  #	s   A 	C;"BC66C;c           	     P   t        d | j                  D              ryt        d | j                  D              r>t	        j
                  | j                  D cg c]  }|j                  dd       c}      S t        t        t        | j                                    D cg c]  }| j                  |      j                   }}	 t        j                  |      }t        |      j                  S c c}w c c}w # t         $ r" t        | j                        j                  cY S w xY w)zI
        Return a boolean if the values are equal or increasing.
        c              3  $   K   | ]  }d |v  
 yw)r   Nri   )r   r   s     r_   r   z5MultiIndex.is_monotonic_increasing.<locals>.<genexpr>  s     1drTz1s   Fc              3  4   K   | ]  }|j                     y wr   is_monotonic_increasing)r   r   s     r_   r   z5MultiIndex.is_monotonic_increasing.<locals>.<genexpr>  s     Fu,,FrZ  int64r   )r   r^   r   r   libalgosis_lexsortedrn   reversedr   r   _get_level_valuesr   rY   lexsortrA   r  rt   )r]   r   r   r   
sort_orders        r_   r  z"MultiIndex.is_monotonic_increasing  s    
 1djj11F$++FF((8<

C1'.C  8@c$++FV@W7X
23D""1%--
 
	? F+J$<<< D
  	?&>>>	?s   C0!"C5)C: :(D%$D%c                &    | ddd   j                   S )zI
        Return a boolean if the values are equal or decreasing.
        Nr   r  r   s    r_   is_monotonic_decreasingz"MultiIndex.is_monotonic_decreasing  s     DbDz111ra   c                T    | j                   D cg c]  }|j                   c}S c c}w )z7return a list of the inferred types, one for each level)r   r  )r]   r   s     r_   rL  z MultiIndex._inferred_type_levels  s      *.5A555s   %c                    t        d | j                  D              }t        | j                  |dd      }t	        ||      S )Nc              3  2   K   | ]  }t        |        y wr   r   )r   r   s     r_   r   z(MultiIndex.duplicated.<locals>.<genexpr>  s     63c#h6r  F)sortxnull)r   r   rG   r^   r   )r]   keepshapeidss       r_   r   zMultiIndex.duplicated  s7    6$++66djj%e5I#t$$ra   c                    t        d      )z:
        fillna is not implemented for MultiIndex
        z"isna is not defined for MultiIndex)NotImplementedError)r]   valuedowncasts      r_   fillnazMultiIndex.fillna  s     ""FGGra   c                <   | j                   D cg c]  }|dk(  	 }}|dk(  rt        j                  |d      }n+|dk(  rt        j                  |d      }nt	        d|       | j                   D cg c]  }||    
 }}| j                  |      S c c}w c c}w )Nr   r   r   rU   r   zinvalid how option: )r^   )r^   rY   r   r   r   r  )r]   howr   nansindexerr   s         r_   dropnazMultiIndex.dropna  s    59ZZ@kr!@@%<ffT*GE\ffT*G3C59::>BjjI{['*I	I~~I~.. A Js   B3Bc                   | j                   |   }| j                  |   }| j                  |   }|rt        j                  |      }t        j
                  |j                  ||j                        }|j                  ||      S )aP  
        Return vector of label values for requested level,
        equal to the length of the index

        **this is an internal method**

        Parameters
        ----------
        level : int
        unique : bool, default False
            if True, drop duplicated values

        Returns
        -------
        Index
        r   r   )	r   r^   r~   r   uniquer   r   r   r+  )r]   r   r  r   r   rr   filleds          r_   r  zMultiIndex._get_level_values  so    " kk% jj'{{5!,,{3Ks{{KCMMR  d 33ra   c                J    | j                  |      }| j                  |      }|S )a(  
        Return vector of label values for requested level.

        Length of returned vector is equal to the length of the index.

        Parameters
        ----------
        level : int or str
            ``level`` is either the integer position of the level in the
            MultiIndex, or the name of the level.

        Returns
        -------
        Index
            Values is a level of this MultiIndex converted to
            a single :class:`Index` (or subclass thereof).

        Notes
        -----
        If the level contains missing values, the result may be casted to
        ``float`` with missing values specified as ``NaN``. This is because
        the level is converted to a regular ``Index``.

        Examples
        --------
        Create a MultiIndex:

        >>> mi = pd.MultiIndex.from_arrays((list('abc'), list('def')))
        >>> mi.names = ['level_1', 'level_2']

        Get level values by supplying level as either integer or name:

        >>> mi.get_level_values(0)
        Index(['a', 'b', 'c'], dtype='object', name='level_1')
        >>> mi.get_level_values('level_2')
        Index(['d', 'e', 'f'], dtype='object', name='level_2')

        If a level contains missing values, the return type of the level
        may be cast to ``float``.

        >>> pd.MultiIndex.from_arrays([[1, None, 2], [3, 4, 5]]).dtypes
        level_0    int64
        level_1    int64
        dtype: object
        >>> pd.MultiIndex.from_arrays([[1, None, 2], [3, 4, 5]]).get_level_values(0)
        Index([1.0, nan, 2.0], dtype='float64')
        )r   r  )r]   r   r   s      r_   get_level_valueszMultiIndex.get_level_values  s*    ` &&u-''.ra   c                n    || j                         S | j                  |      }| j                  |d      S )NT)r   r  )drop_duplicatesr   r  )r]   r   s     r_   r  zMultiIndex.unique,  s<    =''))**51E))d)CCra   c           	        ddl m} |t        j                  urEt	        |      st        d      t        |      t        | j                        k7  rt        d      |}n| j                         }|s+t        t        |            t        |      k7  rt        d       |t        t        | j                              D ci c]  }|| j                  |       c}d      }||_        |r| |_        |S c c}w )a$  
        Create a DataFrame with the levels of the MultiIndex as columns.

        Column ordering is determined by the DataFrame constructor with data as
        a dict.

        Parameters
        ----------
        index : bool, default True
            Set the index of the returned DataFrame as the original MultiIndex.

        name : list / sequence of str, optional
            The passed names should substitute index level names.

        allow_duplicates : bool, optional default False
            Allow duplicate column labels to be created.

            .. versionadded:: 1.5.0

        Returns
        -------
        DataFrame

        See Also
        --------
        DataFrame : Two-dimensional, size-mutable, potentially heterogeneous
            tabular data.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a', 'b'], ['c', 'd']])
        >>> mi
        MultiIndex([('a', 'c'),
                    ('b', 'd')],
                   )

        >>> df = mi.to_frame()
        >>> df
             0  1
        a c  a  c
        b d  b  d

        >>> df = mi.to_frame(index=False)
        >>> df
           0  1
        0  a  c
        1  b  d

        >>> df = mi.to_frame(name=['x', 'y'])
        >>> df
             x  y
        a c  a  c
        b d  b  d
        r   )rL   z1'name' must be a list / sequence of column names.z<'name' should have same length as number of levels on index.zBCannot create duplicate column labels if allow_duplicates is FalseFr   )r   rL   r   r   r0   rt   r   r   r   _get_level_namessetr   r  r   r   )r]   r   rr   allow_duplicatesrL   	idx_namesr   r   s           r_   to_framezMultiIndex.to_frame4  s    x 	%s~~%% STT4yC,, R  I--/ICI$73y>$IT 
 ?DSEU?VWeUD**511W
 #FL Xs   =C1c                0    t        | j                  d      S )a  
        Convert a MultiIndex to an Index of Tuples containing the level values.

        Returns
        -------
        pd.Index
            Index with the MultiIndex data represented in Tuples.

        See Also
        --------
        MultiIndex.from_tuples : Convert flat index back to MultiIndex.

        Notes
        -----
        This method will simply return the caller if called by anything other
        than a MultiIndex.

        Examples
        --------
        >>> index = pd.MultiIndex.from_product(
        ...     [['foo', 'bar'], ['baz', 'qux']],
        ...     names=['a', 'b'])
        >>> index.to_flat_index()
        Index([('foo', 'baz'), ('foo', 'qux'),
               ('bar', 'baz'), ('bar', 'qux')],
              dtype='object')
        F)tupleize_cols)rA   r   r   s    r_   to_flat_indexzMultiIndex.to_flat_index  s    8 T\\77ra   c                4    | j                   | j                  k(  S )a  
        Return True if the codes are lexicographically sorted.

        Returns
        -------
        bool

        Examples
        --------
        In the below examples, the first level of the MultiIndex is sorted because
        a<b<c, so there is no need to look at the next level.

        >>> pd.MultiIndex.from_arrays([['a', 'b', 'c'],
        ...                            ['d', 'e', 'f']])._is_lexsorted()
        True
        >>> pd.MultiIndex.from_arrays([['a', 'b', 'c'],
        ...                            ['d', 'f', 'e']])._is_lexsorted()
        True

        In case there is a tie, the lexicographical sorting looks
        at the next level of the MultiIndex.

        >>> pd.MultiIndex.from_arrays([[0, 1, 1], ['a', 'b', 'c']])._is_lexsorted()
        True
        >>> pd.MultiIndex.from_arrays([[0, 1, 1], ['a', 'c', 'b']])._is_lexsorted()
        False
        >>> pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'],
        ...                            ['aa', 'bb', 'aa', 'bb']])._is_lexsorted()
        True
        >>> pd.MultiIndex.from_arrays([['a', 'a', 'b', 'b'],
        ...                            ['bb', 'aa', 'aa', 'bb']])._is_lexsorted()
        False
        )r   r   r   s    r_   _is_lexsortedzMultiIndex._is_lexsorted  s    D ""dll22ra   c                r    | j                   | j                   S t        | j                  | j                        S )z
        Compute and return the lexsort_depth, the number of levels of the
        MultiIndex that are sorted lexically

        Returns
        -------
        int
        )r   r   r^   r   r   s    r_   r   zMultiIndex._lexsort_depth  s-     >>%>>!djj$,,77ra   c                &   | j                         r| j                  r| S g }g }t        | j                  | j                        D ]  \  }}|j                  sd	 |j                         }|j                  |      }t        |      }t        j                  |t        |            }t        j                  ||d      }|j                  |       |j                  |        t        ||| j                   | j"                  d      S # t        $ r |r Y Vw xY w)a  
        This is an *internal* function.

        Create a new MultiIndex from the current to monotonically sorted
        items IN the levels. This does not actually make the entire MultiIndex
        monotonic, JUST the levels.

        The resulting MultiIndex will have the same outward
        appearance, meaning the same .values and ordering. It will also
        be .equals() to the original.

        Returns
        -------
        MultiIndex

        Examples
        --------
        >>> mi = pd.MultiIndex(levels=[['a', 'b'], ['bb', 'aa']],
        ...                    codes=[[0, 0, 1, 1], [0, 1, 0, 1]])
        >>> mi
        MultiIndex([('a', 'bb'),
                    ('a', 'aa'),
                    ('b', 'bb'),
                    ('b', 'aa')],
                   )

        >>> mi.sort_values()
        MultiIndex([('a', 'aa'),
                    ('a', 'bb'),
                    ('b', 'aa'),
                    ('b', 'bb')],
                   )
        r   r   F)rs   r   r   )r  r  r   r   r^   argsortrq  r,   r   get_reverse_indexerr   r   r   rt   r   rN   rs   r   )r]   raise_if_incomparabler  r   r   r   r  ris           r_   _sort_levels_monotonicz!MultiIndex._sort_levels_monotonic  s   D D$@$@K
	 #DKK < 	*C..P!kkmG
 ((7+C 2':G00#g,GB"'--KB"OKc"[)#	*& **nn"
 	
 ! , -s   DDDc                   g }g }d}t        | j                  | j                        D ]o  \  }}t        j                  t        j
                  |dz         dkD        d   dz
  }t        t        |      xr |d   dk(        }t        |      t        |      |z   k7  r|j                         j                         rt        |      t        |      k(  r nd}t        j                  |      }|r-t        j                  |dk(        d   }||d   dg   |d|d   g<   t        j                  t        |      |z         }	t        j                  t        |            |z
  |	|<   |	|   }|j                  ||d       }|j                  |       |j                  |       r | j!                         }
|r6|
j#                          |
j%                  |d       |
j'                  |d       |
S )a  
        Create new MultiIndex from current that removes unused levels.

        Unused level(s) means levels that are not expressed in the
        labels. The resulting MultiIndex will have the same outward
        appearance, meaning the same .values and ordering. It will
        also be .equals() to the original.

        Returns
        -------
        MultiIndex

        Examples
        --------
        >>> mi = pd.MultiIndex.from_product([range(2), list('ab')])
        >>> mi
        MultiIndex([(0, 'a'),
                    (0, 'b'),
                    (1, 'a'),
                    (1, 'b')],
                   )

        >>> mi[2:]
        MultiIndex([(1, 'a'),
                    (1, 'b')],
                   )

        The 0 from the first level is not represented
        and can be removed

        >>> mi2 = mi[2:].remove_unused_levels()
        >>> mi2.levels
        FrozenList([[1], ['a', 'b']])
        FrT   r   r   TNr   )r   r   r^   rY   r   bincountr   r   r:   r   r   r  r   arangerq  r   r  r   r   r   )r]   r  r   changedr   r   uniqueshas_nana_idxcode_mappingr   s              r_   remove_unused_levelszMultiIndex.remove_unused_levels#  s   F 
	 #DKK < #	*C hhr{{;?;a?@CaGGW<71:+;=F7|s3x&0088:>>#GC(@  ,,{3XXgm4Q7F.5vay!n.EGQq	N+  "xxC6(9:(*		#g,(?&(HW%*;7 hhwvw/0c"[)G#	*J ""$zE:i%8ra   c                    t        | j                        t        | j                        | j                  t        | j                        d}t
        j                  t        |       |fdfS )z*Necessary for making this object picklable)r   r^   r   rs   N)r   r   r^   r   rs   ibase
_new_Indexr(  )r]   ds     r_   
__reduce__zMultiIndex.__reduce__{  sS     4;;'$**%$**%	
 $t*a$66ra   c                   t        |      rt        j                  |      }g }t        | j                  | j
                        D ]D  \  }}||   dk(  r |j                  t        j                         .|j                  |||             F t        |      S d }t        j                  |      r(t        j                  |t              }| j                  }n]t        |t              r(|j                   |j                   dkD  r2| j                  }n%t        |t"              rt        j                  |      }| j
                  D cg c]  }||   	 }}t%        | j                  || j&                  |d      S c c}w )Nr   r   r   Frl  )r2   r   cast_scalar_indexerr   r   r^   r   rY   ri  r   is_bool_indexerr   rK  r   r   slicesteprA   rN   rs   )r]   r=  retvalr   r   r   r   s          r_   __getitem__zMultiIndex.__getitem__  s2   S>))#.CF$'TZZ$@ 9 [s#r)MM"&&)MM#k#&6"78	9 =  I""3'jjD1 NN	C'88#sxx!| $IC'jjo=AZZHkS)HIH{{jj#!&  Is   ?E1c                    d}|j                   |j                   dkD  r| j                  }| j                  D cg c]  }||   	 }} t        |       | j                  || j
                  |d      S c c}w )zH
        Fastpath for __getitem__ when we know we have a slice.
        Nr   Frl  )r  r   r^   r(  r   r~   )r]   slobjr   r   r   s        r_   _getitem_slicezMultiIndex._getitem_slice  sr     	::aI;?::FK['F	FtDz;;++"
 	
 Gs   A0rq  c                   t        j                  d|       t        |      }| j                  |||      }d}| j                  D cg c]  }|j                  |       }}|rK|dk(  }	|	j                         r6g }
|D ]-  }|}|||	<   |
j                  t        j                  |             / |
}t        | j                  || j                  d      S c c}w )Nri   r   Fr   r^   rs   r   )nvvalidate_taker,   _maybe_disallow_fillr^   rq  r   r   rY   r   rN   r   rs   )r]   indicesrV   
allow_fillr   rx   na_valuelabr  rs  masked	new_labellabel_valuess                r_   rq  zMultiIndex.take  s     	V$%g. ..z:wO
.2jj9s'"99b=Dxxz!& <I#,L)1L&MM"**\":;< ;;e4::PU
 	
 :s   Cc           
     T   
 t        |t        t        f      s|g}t         fd|D              rg }g }g }t	         j
                        D ]  
 j                  
   }|D ]   }|j                  |j                  
         }"  g|D cg c]+  }t        |j                  
   |j                  
   |d      - }} j                  
   t        
fd|D              rd|j                  t        j                  |             |j                  |       |j                          t        |||d      S  j                   ft        d |D              z   }t        j                  |      }		 t        j#                  |	      S c c}w # t$        t&        f$ r t)        |	      cY S w xY w)a  
        Append a collection of Index options together.

        Parameters
        ----------
        other : Index or list/tuple of indices

        Returns
        -------
        Index
            The combined index.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a'], ['b']])
        >>> mi
        MultiIndex([('a', 'b')],
                   )
        >>> mi.append(mi)
        MultiIndex([('a', 'b'), ('a', 'b')],
                   )
        c              3  t   K   | ]/  }t        |t              xr |j                  j                  k\   1 y wr   )r   rN   r   )r   or]   s     r_   r   z$MultiIndex.append.<locals>.<genexpr>  s2      
JKZ:&D199+DD
s   58Fr   c              3  B   K   | ]  }|j                      k7    y wr   rs   )r   ru  r   
level_names     r_   r   z$MultiIndex.append.<locals>.<genexpr>	  s     ARrxx{j0ArX  N)r^   r   rs   r   c              3  4   K   | ]  }|j                     y wr   r   r   ks     r_   r   z$MultiIndex.append.<locals>.<genexpr>	  s     +E!AII+ErZ  )r   r   r   r   r   r   r   unionr?   r^   rs   r   r   rY   r#  rN   r   r   rt   r  rA   )r]   otherr^   r   rs   level_valuesru  r   	to_concat
new_tuplesr   r  s   `         @@r_   r   zMultiIndex.append  s   . %$/GE 
OT
 
 EFE4<<( )#{{1~ DB#/#5#5biil#CLD !%~u~	  *RYYq\<e  "ZZ]
A5AA!%JR^^K89l+Z()  F%%  \\Oe+Eu+E&EE	^^I.
	% ))*55/0 :& 	%$$	%s   0F0F
 
F'&F'last)na_positionc                   | j                  d      }|j                         D cg c]  }|j                   }}t        ||d      S c c}w )NT)r  )r  codes_given)r  _get_codes_for_sortingr^   rH   )r]   r  rw   rx   targetr   keyss          r_   r  zMultiIndex.argsort	  sL     ,,4,H%+%B%B%DEc		EEt$OO Fs   Arepeatc           
     t   t        j                  dd|i       t        |      }t        | j                  | j
                  D cg c]O  }|j                  t        j                        j                  t        j                  d      j                  |      Q c}| j                  | j                  d      S c c}w )Nri   rV   Fr   rl  )r  validate_repeatr,   rN   r   r^   r  rY   r   rn   intpr  rs   r   )r]   repeatsrV   r   s       r_   r  zMultiIndex.repeat!	  s    
2~. &g.;; $(::   ,33BGG%3HOOPWX **nn"	
 		
s   AB5
c                p   || j                  |||      S t        |t        j                  t        f      s+	 t        j                  |t        j                  d            }g }|D ]  }	 | j                  |      }t        |t              r|j                  |       nt        |t              rK|j                  |j                  nd}|j                  t        |j                   |j"                  |             nt        j$                  |      rX| j&                  dk(  r$t)        j*                  dt,        t/                      |j1                         d   }|j                  |       ndt3        |       }t5        |       | j9                  |      S # t        $ r Y =w xY w# t6        $ r
 |dk7  r Y Ow xY w)	a  
        Make a new :class:`pandas.MultiIndex` with the passed list of codes deleted.

        Parameters
        ----------
        codes : array-like
            Must be a list of tuples when ``level`` is not specified.
        level : int or level name, default None
        errors : str, default 'raise'

        Returns
        -------
        MultiIndex

        Examples
        --------
        >>> idx = pd.MultiIndex.from_product([(0, 1, 2), ('green', 'purple')],
        ...                                  names=["number", "color"])
        >>> idx
        MultiIndex([(0,  'green'),
                    (0, 'purple'),
                    (1,  'green'),
                    (1, 'purple'),
                    (2,  'green'),
                    (2, 'purple')],
                   names=['number', 'color'])
        >>> idx.drop([(1, 'green'), (2, 'purple')])
        MultiIndex([(0,  'green'),
                    (0, 'purple'),
                    (1, 'purple'),
                    (2,  'green')],
                   names=['number', 'color'])

        We can also drop from a specific level.

        >>> idx.drop('green', level='color')
        MultiIndex([(0, 'purple'),
                    (1, 'purple'),
                    (2, 'purple')],
                   names=['number', 'color'])

        >>> idx.drop([1, 2], level=0)
        MultiIndex([(0,  'green'),
                    (0, 'purple')],
                   names=['number', 'color'])
        rm   r   rT   r   zYdropping on a non-lexsorted multi-index without a level parameter may impact performance.rw  zunsupported indexer of type ignore)_drop_from_levelr   rY   r   rA   r   index_labels_to_arrayr   r   r:  r   r   r  r  r  r   r  stopr  r   r  r  r$   r)   nonzeror(  AssertionErrorr  delete)	r]   r^   r   errorsindsr   locr  msgs	            r_   dropzMultiIndex.drop3	  s   h ((v>>%"**e!4511%rxx?QR   	Kll;/ c3'KK$U+'*xx';388DKKcii4 @A((-**a/ P.'7'9	 ++-*CKK$8cDC(---	6 {{4  ?  6  X% &s$   *F *DF"	FF"F54F5c                   t        j                  |      }| j                  |      }| j                  |   }|j	                  |      }t        |      }d|t        j                  |d      |dk(  z  <   |j                  d   | j                  d   k(  rd|t        j                  |d      <   ||dk(     }t        |      dk7  r|dk7  rt        d| d      t        j                  | j                  |   |       }	| |	   S )	NFr   r   Tr$  zlabels z not found in level)r   r&  r   r   get_indexerr:   rY   equalr  r   r  r   isinr^   )
r]   r^   r   r+  r   r   r   	nan_codes	not_foundrs  s
             r_   r%  zMultiIndex._drop_from_level	  s     ))%0""5)A""5) K	@BE*v|<=;;q>TZZ]*02F288It,-&B,'	y>Q6X#5WYK/BCDD

4::a=&11Dzra   c                H   t        | j                        }t        | j                        }t        | j                        }| j	                  |      }| j	                  |      }||   ||   c||<   ||<   ||   ||   c||<   ||<   ||   ||   c||<   ||<   t        |||d      S )a  
        Swap level i with level j.

        Calling this method does not change the ordering of the values.

        Parameters
        ----------
        i : int, str, default -2
            First level of index to be swapped. Can pass level name as string.
            Type of parameters can be mixed.
        j : int, str, default -1
            Second level of index to be swapped. Can pass level name as string.
            Type of parameters can be mixed.

        Returns
        -------
        MultiIndex
            A new MultiIndex.

        See Also
        --------
        Series.swaplevel : Swap levels i and j in a MultiIndex.
        DataFrame.swaplevel : Swap levels i and j in a MultiIndex on a
            particular axis.

        Examples
        --------
        >>> mi = pd.MultiIndex(levels=[['a', 'b'], ['bb', 'aa']],
        ...                    codes=[[0, 0, 1, 1], [0, 1, 0, 1]])
        >>> mi
        MultiIndex([('a', 'bb'),
                    ('a', 'aa'),
                    ('b', 'bb'),
                    ('b', 'aa')],
                   )
        >>> mi.swaplevel(0, 1)
        MultiIndex([('bb', 'a'),
                    ('aa', 'a'),
                    ('bb', 'b'),
                    ('aa', 'b')],
                   )
        Fr  )r   r   r^   rs   r   rN   )r]   r   jr  r   	new_namess         r_   	swaplevelzMultiIndex.swaplevel	  s    V $++&
$	$	""1%""1%'1!}jm$
1z!}%.q\9Q<"	!il%.q\9Q<"	!ilYiRW
 	
ra   c                n    |D cg c]  }| j                  |       }}| j                  |      }|S c c}w )aI  
        Rearrange levels using input order. May not drop or duplicate levels.

        Parameters
        ----------
        order : list of int or list of str
            List representing new level order. Reference level by number
            (position) or by key (label).

        Returns
        -------
        MultiIndex

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([[1, 2], [3, 4]], names=['x', 'y'])
        >>> mi
        MultiIndex([(1, 3),
                    (2, 4)],
                   names=['x', 'y'])

        >>> mi.reorder_levels(order=[1, 0])
        MultiIndex([(3, 1),
                    (4, 2)],
                   names=['y', 'x'])

        >>> mi.reorder_levels(order=['y', 'x'])
        MultiIndex([(3, 1),
                    (4, 2)],
                   names=['y', 'x'])
        )r   _reorder_ilevels)r]   orderr   r   s       r_   reorder_levelszMultiIndex.reorder_levels	  s=    @ 5::q''*::&&u- ;s   2c                ^   t        |      | j                  k7  r$t        d| j                   dt        |             |D cg c]  }| j                  |    }}|D cg c]  }| j                  |    }}|D cg c]  }| j
                  |    }}t        |||d      S c c}w c c}w c c}w )Nz2Length of order must be same as number of levels (z), got Fr  )r   r   r)  r   r^   rs   rN   )r]   r=  r   r  r   r9  s         r_   r<  zMultiIndex._reorder_ilevels
  s    u:% DT\\N S5zl$  /44dkk!n4
4,12qTZZ]2	2,12qTZZ]2	2YiRW
 	
	 522s   B B%9B*c              #    K   t        |      | j                  kD  r%t        dt        |       d| j                   d      t        t        |            D ]0  }t	        | j
                  |   | j                  |   ||   |       2 y w)NzLength of new_levels (z) must be <= self.nlevels ()r   )r   r   r)  r   r?   r^   r   )r]   r  r   r   s       r_   _recode_for_new_levelsz!MultiIndex._recode_for_new_levels
  s      z?T\\) (Z(9 :,,0LL><  s:' 	A'

1t{{1~z!}4 	s   BBc           	         d }| j                   D cg c]!  }t        j                  | ||      dd      # c}S c c}w )a
  
        we are categorizing our codes by using the
        available categories (all, not just observed)
        excluding any missing ones (-1); this is in preparation
        for sorting, where we need to disambiguate that -1 is not
        a valid valid
        c                    t        j                  t        |       r&t        j                  |       j	                         dz   nd| j
                        S )NrT   r   r   )rY   r  r   r   r   r   )r   s    r_   catsz/MultiIndex._get_codes_for_sorting.<locals>.cats%
  s?    9936{3C%))+a/!'' ra   TFr  )r^   r<   
from_codes)r]   rE  r   s      r_   r  z!MultiIndex._get_codes_for_sorting
  sD    	  $zz
 "";[0A4RWX
 	
 
s   &;c                   t        |      s|g}|D cg c]  }| j                  |       }}d}|D cg c]  }| j                  |    }}t        |t              r"t        |      t        |      k(  s`t        d      |rN|j                  t        t        | j                              D cg c]  }||vs| j                  |    c}       n|d   }t        |||d      }t        |      }| j                  D 	cg c]  }	|	j                  |       }
}	t        |
| j                  | j                  |d      }||fS c c}w c c}w c c}w c c}	w )a  
        Sort MultiIndex at the requested level.

        The result will respect the original ordering of the associated
        factor at that level.

        Parameters
        ----------
        level : list-like, int or str, default 0
            If a string is given, must be a name of the level.
            If list-like must be names or ints of levels.
        ascending : bool, default True
            False to sort in descending order.
            Can also be a list to specify a directed ordering.
        sort_remaining : sort by the remaining levels after level
        na_position : {'first' or 'last'}, default 'first'
            Argument 'first' puts NaNs at the beginning, 'last' puts NaNs at
            the end.

            .. versionadded:: 2.1.0

        Returns
        -------
        sorted_index : pd.MultiIndex
            Resulting index.
        indexer : np.ndarray[np.intp]
            Indices of output values in original index.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([[0, 0], [2, 1]])
        >>> mi
        MultiIndex([(0, 2),
                    (0, 1)],
                   )

        >>> mi.sortlevel()
        (MultiIndex([(0, 1),
                    (0, 2)],
                   ), array([1, 0]))

        >>> mi.sortlevel(sort_remaining=False)
        (MultiIndex([(0, 2),
                    (0, 1)],
                   ), array([0, 1]))

        >>> mi.sortlevel(1)
        (MultiIndex([(0, 1),
                    (0, 2)],
                   ), array([1, 0]))

        >>> mi.sortlevel(1, ascending=False)
        (MultiIndex([(0, 2),
                    (0, 1)],
                   ), array([0, 1]))
        Nz(level must have same length as ascendingr   T)ordersr  r  F)r^   r   rs   r   r   )r0   r   r^   r   r   r   r   r  r   r   rH   r,   rq  rN   rs   )r]   r   	ascendingsort_remainingr  r   r   r^   r  r   r   r4  s               r_   	sortlevelzMultiIndex.sortlevel0
  sO   ~ E"GE 49
,/D""3'
 
 	,12SC22i&u:Y/ !KLLLL,1#dkk2B,CXSsRWGWCX aI!)$
 &g.BF**M;[%%g.M	M;;**"
	 '!!A

 3 Y Ns   D<E*	E4E:Ec                    t        |t              s@|| }n;|dk\  j                         r| j                  |      }n	 t        j	                  |      }| j                  ||      }|S # t
        $ r |cY S w xY wr   )r   rN   r   rq  r   rt   _maybe_preserve_names)r]   r  r  preserve_namess       r_   _wrap_reindex_resultzMultiIndex._wrap_reindex_result
  sx    &*-Q,##%7+"'33F;F
 ++FNC ! "!M"s   A% %A32A3c                    |rU|j                   | j                   k(  r<|j                  | j                  k7  r#|j                  d      }| j                  |_        |S )NFrW  )r   rs   r   )r]   r  rN  s      r_   rM  z MultiIndex._maybe_preserve_names
  sE    $,,.

*[[e[,F::FLra   c                F    t        |      rt        |      rt        |      y r   )r-   r/   r#   r<  s     r_   _check_indexing_errorz MultiIndex._check_indexing_error
  s#    3;s#3 $C((	 $4ra   c                4    | j                   d   j                  S )zA
        Should integer key(s) be treated as positional?
        r   )r   _should_fallback_to_positionalr   s    r_   rT  z)MultiIndex._should_fallback_to_positional
  s     {{1~<<<ra   c                   |}t        |t              st        j                  |      }t	        |      r>t        |d   t
              s+| j                  |      }| j                  |||       | |   |fS t        | %  ||      S r   )
r   rA   r   r   r   r   _get_indexer_level_0_raise_if_missingsuper_get_indexer_strict)r]   r=  	axis_namekeyarrr  	__class__s        r_   rY  zMultiIndex._get_indexer_strict
  s{     &%(**62Fv;z&)U;//7G""3;='))w*3	::ra   c                   |}t        |t              st        j                  |      }t	        |      r{t        |d   t
              sh|dk(  }|j                         rR| j                  d   j                  |      }|dk(  }|j                         rt        ||    d      t        | d      y t        | -  |||      S )Nr   r   z not in index)r   rA   r   r   r   r   r   r   r2  r  rX  rW  )	r]   r=  r  rZ  r[  rs  checkcmaskr\  s	           r_   rW  zMultiIndex._raise_if_missing
  s    #u%**3/Fv;z&)U; b=DxxzA226:99;"fUm_M#BCC &788  7,S'9EEra   c                    | j                   d   }| j                  d   }t        j                  ||d      }t	        |      }|j                  |      S )z]
        Optimized equivalent to `self.get_level_values(0).get_indexer_for(target)`.
        r   F)r^   
categoriesr   )r   r   r<   rF  rA   get_indexer_for)r]   r  r   r^   catcis         r_   rV  zMultiIndex._get_indexer_level_0
  sL     kk!nA$$5S5Q3Z!!&))ra   c                N    t        |t              s|f}| j                  ||      S )a  
        For an ordered MultiIndex, compute slice bound
        that corresponds to given label.

        Returns leftmost (one-past-the-rightmost if `side=='right') position
        of given label.

        Parameters
        ----------
        label : object or tuple of objects
        side : {'left', 'right'}

        Returns
        -------
        int
            Index of label.

        Notes
        -----
        This method only works if level 0 index of the MultiIndex is lexsorted.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abbc'), list('gefd')])

        Get the locations from the leftmost 'b' in the first level
        until the end of the multiindex:

        >>> mi.get_slice_bound('b', side="left")
        1

        Like above, but if you get the locations from the rightmost
        'b' in the first level and 'f' in the second level:

        >>> mi.get_slice_bound(('b','f'), side="right")
        3

        See Also
        --------
        MultiIndex.get_loc : Get location for a label or a tuple of labels.
        MultiIndex.get_locs : Get location for a label/slice/list/mask or a
                              sequence of such.
        side)r   r   _partial_tup_index)r]   labelrg  s      r_   get_slice_boundzMultiIndex.get_slice_bound
  s,    ` %'HE&&u4&88ra   c                &    t         |   |||      S )aL  
        For an ordered MultiIndex, compute the slice locations for input
        labels.

        The input labels can be tuples representing partial levels, e.g. for a
        MultiIndex with 3 levels, you can pass a single value (corresponding to
        the first level), or a 1-, 2-, or 3-tuple.

        Parameters
        ----------
        start : label or tuple, default None
            If None, defaults to the beginning
        end : label or tuple
            If None, defaults to the end
        step : int or None
            Slice step

        Returns
        -------
        (start, end) : (int, int)

        Notes
        -----
        This method only works if the MultiIndex is properly lexsorted. So,
        if only the first 2 levels of a 3-level MultiIndex are lexsorted,
        you can only pass two levels to ``.slice_locs``.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abbd'), list('deff')],
        ...                                names=['A', 'B'])

        Get the slice locations from the beginning of 'b' in the first level
        until the end of the multiindex:

        >>> mi.slice_locs(start='b')
        (1, 4)

        Like above, but stop at the end of 'b' in the first level and 'f' in
        the second level:

        >>> mi.slice_locs(start='b', end=('b', 'f'))
        (1, 3)

        See Also
        --------
        MultiIndex.get_loc : Get location for a label or a tuple of labels.
        MultiIndex.get_locs : Get location for a label/slice/list/mask or a
                              sequence of such.
        )rX  
slice_locs)r]   r  endr  r\  s       r_   rl  zMultiIndex.slice_locs#  s    j w!%d33ra   c                   t        |      | j                  kD  r%t        dt        |       d| j                   d      t        |      }dt        |       }}t        || j                  | j
                        }t        |      D ]R  \  }\  }}	}
|
|| }||	vrit        |      s^	 t        j                  |	||      }t        |      st        d|       |dk(  r
|dk\  r|dz  }|t        j                  |||      z   c S | j                  |	|      }t        |t              r!||dz
  k  r|j                  }|j                   }||dz
  k  r7|t        j                  ||d      z   }|t        j                  ||d	      z   }t        |t              r)|j                  }|t        j                  |||      z   c S |t        j                  |||      z   c S  y # t        $ r}t        d|       |d }~ww xY w)
NKey length (z-) was greater than MultiIndex lexsort depth (rA  r   rf  zLevel type mismatch: rightrT   left)r   r   r%   r   r   r^   	enumerater:   r   searchsortedrt   r.   _get_loc_single_level_indexr   r  r  r'  )r]   rg  rg  nr  rm  zippedr  r  r   r   sectionr-  r  r
  s                  r_   rh  zMultiIndex._partial_tup_indexZ  s   s8d)))$s3xj )''(+ 
 HD	sS$++tzz2*3F*; '	K&A&S+!%,G #~d3iL,,S#DAC "##&;C5$ABB7?sax1HCu11'3TJJJ223<C#u%!a!e) 		hhQU e00Sw 
  2 2Sv!  C'iiu11'3TJJJu11'3TJJJO'	K ! L#&;C5$ABKLs   "G	G6"G11G6c                R    t        |      rt        |      ry|j                  |      S )a  
        If key is NA value, location of index unify as -1.

        Parameters
        ----------
        level_index: Index
        key : label

        Returns
        -------
        loc : int
            If key is NA value, loc is -1
            Else, location of key in index.

        See Also
        --------
        Index.get_loc : The get_loc method for (single-level) index.
        r   )r2   r:   r:  )r]   level_indexr=  s      r_   rt  z&MultiIndex._get_loc_single_level_index  s%    & S>d3i&&s++ra   c           	          j                  |        fd}t        |t              s j                  |d      } ||      S t	        |      } j
                  |k  rt        d| d j
                   d      | j
                  k(  r( j                  r	  j                  j                  |      S  j                  }|d| ||d }	}|sd}
t	               }n	  j                  ||      \  }
}|
|k(  rt        |      |	st!        |
|      S t#        j$                  dt&        t)               	       t+        j,                  |
|t*        j.                  
      }t1        |	t	        |            D ]b  \  }} j2                  |   |    j5                   j6                  |   |      k(  }|j9                         s||   }t	        |      rYt        |       t	        |      ||
z
  k7  r ||      S t!        |
|      S # t        $ r}t        |      |d}~wt        $ r6  j                  |t        t         j
                                    \  }}|cY S w xY w# t        $ r}t        |      |d}~ww xY w)a  
        Get location for a label or a tuple of labels.

        The location is returned as an integer/slice or boolean
        mask.

        Parameters
        ----------
        key : label or tuple of labels (one for each level)

        Returns
        -------
        int, slice object or boolean mask
            If the key is past the lexsort depth, the return may be a
            boolean mask array, otherwise it is always a slice or int.

        See Also
        --------
        Index.get_loc : The get_loc method for (single-level) index.
        MultiIndex.slice_locs : Get slice location given start label(s) and
                                end label(s).
        MultiIndex.get_locs : Get location for a label/slice/list/mask or a
                              sequence of such.

        Notes
        -----
        The key cannot be a slice, list of same-level labels, a boolean mask,
        or a sequence of such. If you want to use those, use
        :meth:`MultiIndex.get_locs` instead.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abb'), list('def')])

        >>> mi.get_loc('b')
        slice(1, 3, None)

        >>> mi.get_loc(('b', 'e'))
        1
        c                H   t        | t        j                        r| j                  t        j                  k7  r| S t        j                  | t                    } t        | t              r| S t        j                  t              d      }|j                  d       d|| <   |S )z<convert integer indexer to boolean mask or slice if possiblerK  r   FT)r   rY   r   r   r!  r   maybe_indices_to_slicer   r  emptyfill)r-  rs  r]   s     r_   _maybe_to_slicez+MultiIndex.get_loc.<locals>._maybe_to_slice  sx    c2::.#))rww2F
,,S#d)<C#u%
88CIV4DIIeDIKra   r   rF  ro  z) exceeds index depth (rA  Nz3indexing past lexsort depth may impact performance.rw  r   )rR  r   r   _get_level_indexerr   r   r  r   r&  r:  rt   get_loc_levelr   r   r   rl  r  r  r  r$   r)   rY   r  r!  rr  r^   rt  r   r   )r]   r=  r  r-  keylenr  _r   lead_key
follow_keyr  r'  r  rs  s   `             r_   r:  zMultiIndex.get_loc  sW   R 	""3'	 #u%))#Q)7C"3''S<<& vh&=dll^1M  T\\!dnn||++C00 "2AwAB*Et9D-"oohAt D=3-%%A')	
 iit2773j#h-8 	$DAq::a=%)I)IA* D 88:$is8sm#	$ (+3x4%<'?s#WU5RVEWWa  -sm, ++CeDLL6I1JKQ
$  - sm,-s6   G3 I 3	I
<H?I
	I
	I'I""I'c                   t        |t        t        f      s| j                  |      }n|D cg c]  }| j                  |       }}| j	                  ||      \  }}|s&t        j                  |      r| ||dz    }||fS | |   }||fS c c}w )a  
        Get location and sliced index for requested label(s)/level(s).

        Parameters
        ----------
        key : label or sequence of labels
        level : int/level name or list thereof, optional
        drop_level : bool, default True
            If ``False``, the resulting index will not drop any level.

        Returns
        -------
        tuple
            A 2-tuple where the elements :

            Element 0: int, slice object or boolean array.

            Element 1: The resulting sliced multiindex/index. If the key
            contains all levels, this will be ``None``.

        See Also
        --------
        MultiIndex.get_loc  : Get location for a label or a tuple of labels.
        MultiIndex.get_locs : Get location for a label/slice/list/mask or a
                              sequence of such.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abb'), list('def')],
        ...                                names=['A', 'B'])

        >>> mi.get_loc_level('b')
        (slice(1, 3, None), Index(['e', 'f'], dtype='object', name='B'))

        >>> mi.get_loc_level('e', level='B')
        (array([False,  True, False]), Index(['b'], dtype='object', name='A'))

        >>> mi.get_loc_level(['b', 'e'])
        (1, None)
        rF  rT   )r   r   r   r   _get_loc_levelr   r.   )r]   r=  r   
drop_levelr   r-  ru  s          r_   r  zMultiIndex.get_loc_level   s    R %$/**51E<ABST++C0BEB%%c%7R~~c"#a( Bw #YBw Cs   B	c                	     fd}t        |t        t        f      rt        |      t        |      k7  rt	        d      d}t        ||      D ]_  \  }} j                  ||      \  }}t        |t              r+t        j                  t               t              }	d|	|<   |	}||n||z  }a 	  |||      }
||
fS t        |t              rt        |      }t        |t              r|dk(  r	 | j                  d   v r! j                  ||      } ||dg      }||fS 	 t!        d |D              s2t        |       j"                  k(  r* j$                  r	  j&                  j)                  |      dfS  j)                  |      }t-        t        |            D cg c]  }||   t        dd      k7  s| }}t        |       j"                  k(  rt/        |      r|dfS t-        t        |            D cg c]B  }t        ||   t0              r j                  |   j2                  s||   t        dd      k7  r|D }}t        |       j"                  k(  rg }| |||      fS d}t5        |      D ]  \  }}t        |t              s j                  ||      }t        |t              r_t7        j8                  |      st7        j:                  |t                     rnt        j                  t               t              }d||<   n'|}n$t7        j8                  |      rt        d	|       ||}||z  } |t        dd      }t-        t        |            D cg c]  }||   t        dd      k7  s| }}| |||      fS  j                  ||      }t        |t0              rI j                  |   j2                  r0 j                  |   j)                  |      }t/        |      s| |   fS 	  |||g      }||fS # t        $ r  |   }
Y ||
fS w xY w# t        t        f$ r Y w xY w# t*        $ r}t+        |      |d}~wt        $ r Y w xY wc c}w c c}w c c}w # t        $ r  |   }Y ||fS w xY w)
zX
        get_loc_level but with `level` known to be positional, not name-based.
        c                Z    |    }t        |d      D ]  }|j                  |g      } |S )z
            If level does not exist or all levels were dropped, the exception
            has to be handled outside.
            T)reverse)sorted_drop_level_numbers)r  r   r4  r   r]   s       r_   maybe_mi_droplevelsz6MultiIndex._get_loc_level.<locals>.maybe_mi_droplevels]  s>    
 WIFD1 ?%991#>	? ra   z:Key for location must have same length as number of levelsNrF  r   Tr   c              3  <   K   | ]  }t        |t                y wr   )r   r  r  s     r_   r   z,MultiIndex._get_loc_level.<locals>.<genexpr>  s     9z!U+9s   z'Expected label or tuple of labels, got )r   r   r   r   r)  r   r  r  rY   r   rK  r   r   r  rt   r#   r   r   r   r&  r:  r  r   r.   rn  !_supports_partial_string_indexingrr  r   is_null_sliceis_full_slice)r]   r=  r   r  r   r   r  r-  r4  rs  ru  r  r  r   ilevels	loc_levelk_indexr^  result_indexs   `                  r_   r  zMultiIndex._get_loc_levelW  s   
	 eeT]+3x3u:%$P  FeS/ AQ!%!4!4Qc!4!BYc5)88CIT:D $DIC &FSLA" )7 2: c4 *Cc5!eqj$++a.("55c5GG 3GaS AI"I-- ) 9S99s8t||+ $ 4 4S 94@@ ,,s+&+CHoUQ5tCT9T1UUw<4<</!'*&}, "'s3x *3q63 7#';;q>#S#SFeD$&77 G  7|t||3"$ 3GW EEE %cN +DAq%a/$($;$;AQ$;$G	%i7"00;s?P?P )3t9@ !) ')hhs4y&EG15GI. '0G**1- 
 (*QRUQV(WXX")7*;+< ?#D$/G&+CHoUQ5tCT9T1UU 3GW EEE--c-?G3$KK&HH E*2237!%("DM11-27UGD L((_  " &\2:"$ 01  $ 5&sm4$   V` V   -#G}L((-ss   0	P 01P P5 Q7Q:AQ"$Q'<Q':
Q, PPP21P25	Q>Q

QQ,R ?R c                   | j                   |   }| j                  |   }||fd}t        |t              rW|j                  }|d uxr |dk  }	 |j
                  |j                  |j
                        }	n|rt        |      dz
  }	nd}	|j                  |j                  |j                        }
n/|rd}
n*t        |	t              rt        |      }
nt        |      dz
  }
t        |	t              st        |
t              r$t        |	d|	      }	t        |
d|
      }
 ||	|
|      S |dkD  s| j                  dk(  s||r|
dz
  n|
dz   }
 ||	|
|      S t        j                  ||	d      }t        j                  ||
d      }t        |||      S | j                  ||      }|dkD  s| j                  dk(  rlt        |t              r!||j
                  k\  ||j                  k  z  }|S t!        j"                  ||k(  t$        	      }|j'                         st        |      |S t        |t              rEt        j                  ||j
                  d      }	t        j                  ||j                  d      }n0t        j                  ||d      }	t        j                  ||d      }|	|k(  rt        |      t        |	|      S # t        $ rC |j                  |j
                  |j                  |j                        x}	}
|	j                  }Y +w xY w)
Nc                    |||   }||dk(  r|| k\  ||k  z  }n9t        j                  | |||j                        }t        j                  ||      }||S |j                         }|||<   |S )NrT   r   )rY   r  r   r   r4  r   )r  r'  r  r  r^   new_indexerrs          r_   convert_indexerz6MultiIndex._get_level_indexer.<locals>.convert_indexer  s     " g|tqy$~%$,?IIeT4u{{C#jj2""llnG*GGNra   r   rT   r  r'  rq  rf  rp  r   )r   r^   r   r  r  r  r:  r   r'  r  slice_indexerr   r   r   rs  rt  rY   r   rK  r   )r]   r=  r   r  ry  r   r  r  is_negative_stepr  r'  r   r8  r
  locsrm  s                   r_   r  zMultiIndex._get_level_indexer  s    kk%(jj'7>k 	, c5! 88D#4/<D1H"99('//		:E%,q0EE88'&..sxx8D%Du-{+D{+a/D %':dE+B
  w6tVT2&udD99d11Q6$:J &6qD1H&udD99 &&{EG&&{DwGQ4(( 22;DCqyD//14c5)'3994sxx9OPDKzz+"4DAxxz"3-'#u%**;		O((chhVL**;&I((cH|sm#$$q  "  +88CHHchhWWzz	"s   BK   ALLc                t   t        t        j                  |            D cg c]
  \  }}|s	| }}}|r-|d   | j                  k\  rt	        d| d| j                         t        d |D              rt        d      t        |       dfd}d}t        |      D ]U  \  }}d}t        j                  |      rAt        |      k7  rt        d      t        j                  |      }||j                         }nt        |      r>	 | j                  |||	      }|t        j*                  g t        j,                        c S t        j.                  |      r;|8|t        |      dz
  k(  r't        j0                  t        j,                        c S | j                  |||	      } ||      }||}||z  }t        j
                  |      r6t        j
                  |      sMt#        |       |%t        j*                  g t        j,                        S |j3                         d   }| j5                  ||      S c c}}w # t        t         t"        f$ rY}	|D ]I  }
t%        |
      s|	| j                  |
||	      }|	 ||      }/t'        |t(              rd
||<   E||z  }K Y d}	~	d}	~	ww xY w)a  
        Get location for a sequence of labels.

        Parameters
        ----------
        seq : label, slice, list, mask or a sequence of such
           You should use one of the above for each level.
           If a level should not be used, set it to ``slice(None)``.

        Returns
        -------
        numpy.ndarray
            NumPy array of integers suitable for passing to iloc.

        See Also
        --------
        MultiIndex.get_loc : Get location for a label or a tuple of labels.
        MultiIndex.slice_locs : Get slice location given start label(s) and
                                end label(s).

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([list('abb'), list('def')])

        >>> mi.get_locs('b')  # doctest: +SKIP
        array([1, 2], dtype=int64)

        >>> mi.get_locs([slice(None), ['e', 'f']])  # doctest: +SKIP
        array([1, 2], dtype=int64)

        >>> mi.get_locs([[True, False, True], slice('e', 'f')])  # doctest: +SKIP
        array([2], dtype=int64)
        r   zIMultiIndex slicing requires the index to be lexsorted: slicing on levels z, lexsort depth c              3  ,   K   | ]  }|t         u   y wr   )Ellipsisr  s     r_   r   z&MultiIndex.get_locs.<locals>.<genexpr>  s     *qH}*s   z2MultiIndex does not support indexing with Ellipsisc                    t        | t              r,t        j                  t        j                        }d|| <   |S | S )Nr   T)r   r  rY   r   bool_)r  r  ru  s     r_   _to_bool_indexerz-MultiIndex.get_locs.<locals>._to_bool_indexer  s6    '5) hhq9'+G$""Nra   NzLcannot index with a boolean indexer that is not the same length as the index)r   r  Tr   rT   r   rJ  npt.NDArray[np.bool_])rr  r   is_true_slicesr   r%   r   r  r   r  r   rY   r   r   r0   r  r#   rt   r  r-   r   r  r   r!  r  r  r(  _reorder_indexer)r]   seqr   strue_slicesr  r  r  lvl_indexerr  r   item_indexerpos_indexerru  s                @r_   get_locszMultiIndex.get_locs]  s   H (11C1CC1H'IOVaQqOO;r?d.A.AA$(M)9$:M:M9NP 
 *c**%D  I	 15cN @	(DAq@DK""1%q6Q;$>  !jjm?"-"2"2"4Ka8"&"9"9!1g"9"VK0 & 88Bbgg66""1%?qCHqL'899Qbgg66 #55aq'5R +;7K%;&vvg266++>"3-'A@	(F ?88Bbgg..oo'*$$S+66 PV *9h? 8  8*1~"%I (,'>'>Q (? ( '.*:<*HK'e<8<K5'<7K88s#   
II
I

J7AJ22J7c                   d}t        |      D ]  \  }}t        j                  |      s t        j                  |      st	        |      rnt        |      rbt        |      dk  rn| j                         r@| j                  |   j                  |      }||dk\     }|dd |dd kD  j                         }nHd}nEt        |t              r3| j                         r |j                  duxr |j                  dk  }nd}nd}|s n |s|S t        |       }d}t        |      D ]  \  }}t	        |      r|g}t        j                  |      rt        j                  |      |   }	nt        |      rt        |t        j                   t"        t$        t&        f      st)        |d      }t+        j,                  |      }t        j.                  t        | j                  |         t        j0                        t        | j                  |         z  }
| j                  |   j                  |      }||dk\     }t        j                  t        |            |
|<   |
| j2                  |   |      }	nt        |t              r:|j                  .|j                  dk  rt        j                  |      ddd   |   }	njt        |t              rB|j4                  6|j6                  *t        j.                  |ft        j8                        |   }	nt        j                  |      |   }	|	f|z   } t        j:                  |      }||   S )	am  
        Reorder an indexer of a MultiIndex (self) so that the labels are in the
        same order as given in seq

        Parameters
        ----------
        seq : label/slice/list/mask or a sequence of such
        indexer: a position indexer of self

        Returns
        -------
        indexer : a sorted position indexer of self ordered as seq
        FrT   r   Nr   Tri   r   )rr  r   r  r  r2   r0   r   r  r   r2  r   r   r  r  rY   r  r   r=   rA   r7   r@   r   r  onesr  r^   r  r'  r!  r  )r]   r  r  	need_sortr   r  k_codesru  r  	new_orderkey_order_maplevel_indexerinds                r_   r  zMultiIndex._reorder_indexer  s   ( 	cN 	DAq  #s':':1'=1aq6Q;'') #kk!n88;G%gl3G!("!; @ @ BI $IAu%%%' !d 2 AqvvzI $I 	/	0 NI') cN 	'DAq|C""1%IIaL1	a!!bjj.%%ST&q$/ALLO "DKKN(;299 MPSKKNQ ! !%A : :1 = -mq.@ A/1yy]9K/Lm,)$**Q-*@A	Au%!&&*<!IIaL2.w7	Au%!''/affnGGQD8A	 IIaL1	<$&D;	'@ jjs|ra   c                b   |r|r||k  rt        d      | j                  d   j                  ||      \  }}| j                  ||      \  }}t        | j                        }|d   || |d<   | j                  D cg c]  }||| 	 }	}|	d   |z
  |	d<   t        ||	| j                  d      S c c}w )a  
        Slice index between two labels / tuples, return new MultiIndex.

        Parameters
        ----------
        before : label or tuple, can be partial. Default None
            None defaults to start.
        after : label or tuple, can be partial. Default None
            None defaults to end.

        Returns
        -------
        MultiIndex
            The truncated MultiIndex.

        Examples
        --------
        >>> mi = pd.MultiIndex.from_arrays([['a', 'b', 'c'], ['x', 'y', 'z']])
        >>> mi
        MultiIndex([('a', 'x'), ('b', 'y'), ('c', 'z')],
                   )
        >>> mi.truncate(before='a', after='b')
        MultiIndex([('a', 'x'), ('b', 'y')],
                   )
        zafter < beforer   Fr  )r   r   rl  r   r^   rN   r~   )
r]   beforeafterr   r8  rq  rp  r  r   r   s
             r_   truncatezMultiIndex.truncate<  s    4 V-..{{1~((71oofe4e$++&
"1a*
1@D

K[e,K	K |a'	!++"	
 	
 Ls   :B,c                   | j                  |      ryt        |t              syt        |       t        |      k7  ryt        |t              s2| j                  |      syt        | j                  |j                        S | j                  |j                  k7  ryt        | j                        D ]'  }| j                  |   }|j                  |   }|dk(  }|dk(  }t        j                  ||      s y||    }| j                  |   j                  j                  |      }||    }|j                  |   j                  j                  |      }t        |      dk(  rt        |      dk(  rt        |t        j                        s|j!                  |      r yt        |t        j                        s|j!                  |      r yt        ||      r( y y)z
        Determines if two MultiIndex objects have the same labeling information
        (the levels themselves do not necessarily have to be the same)

        See Also
        --------
        equal_levels
        TFr   r   )is_r   rA   r   rN   _should_comparer9   r   r   r   r^   rY   array_equalr   rq  r   equals)	r]   r  r   
self_codesother_codes	self_mask
other_maskself_valuesother_valuess	            r_   r  zMultiIndex.equalsi  s    88E?%'t9E
"%,''.#DLL%--@@<<5==(t||$ 	!AAJ++a.K"b(I$*J>>)Z8#YJ/J++a.0055jAK%zk2K <<?2277DL ;1$\):a)?k2::6")),7 bjj9#**;7 '\B =	!@ ra   c                    | j                   |j                   k7  ryt        | j                         D ]/  }| j                  |   j                  |j                  |         r/ y y)zT
        Return True if the levels of both MultiIndex objects are the same

        FT)r   r   r   r  )r]   r  r   s      r_   equal_levelszMultiIndex.equal_levels  sU    
 <<5==(t||$ 	A;;q>((a9	 ra   c                   | j                  |      \  }}|j                  r@t        |   ||      }t	        |t
              r|S t
        j                  t        | d |      S |j                  | d      }t        |      r| j                  |      }n| j                  |      }|dur	 |j                         }|S |S # t        $ r- |du r t        j                  dt         t#                      Y |S w xY w)Nr   Fr  TzTThe values in the array are unorderable. Pass `sort=False` to suppress this warning.rw  )_convert_can_do_setophas_duplicatesrX  _unionr   rN   r   r   
differencer   r   _get_reconciled_name_objectsort_valuesrt   r  r  RuntimeWarningr)   )r]   r  r  result_namesr   right_missingr\  s         r_   r  zMultiIndex._union  s   "88?| W^E40F&*-))VL *  
 ",,T,>M=!]399%@5 
#//1F M6M ! t|MMF&#3#5	 Ms   (B< <2C21C2c                    t        |      S r   )r1   )r]   r   s     r_   _is_comparable_dtypezMultiIndex._is_comparable_dtype  s    u%%ra   c                h    | j                  |      }| j                  |k7  r| j                  |      S | S )z
        If the result of a set operation will be self,
        return self, unless the names change, in which
        case make a shallow copy of self.
        )_maybe_match_namesrs   rename)r]   r  rs   s      r_   r  z&MultiIndex._get_reconciled_name_object  s4     ''.::;;u%%ra   c                2   t        | j                        t        |j                        k7  rdgt        | j                        z  S g }t        | j                  |j                        D ]-  \  }}||k(  r|j                  |       |j                  d       / |S )z
        Try to find common names to attach to the result of an operation between
        a and b. Return a consensus list of names if they match at least partly
        or list of None if they have completely different names.
        N)r   rs   r   r   )r]   r  rs   a_nameb_names        r_   r  zMultiIndex._maybe_match_names  s     tzz?c%++..6C

O++!$**ekk: 	#NFFV$ T"	# ra   c                L    | j                  |      \  }}|j                  |      S r   )r  	set_namesr]   r  r   r  r  s        r_   _wrap_intersection_resultz$MultiIndex._wrap_intersection_result  s'    44U;<--ra   c                    | j                  |      \  }}t        |      dk(  r|j                         j                  |      S |j                  |      S r   )r  r   r  r  r  s        r_   _wrap_difference_resultz"MultiIndex._wrap_difference_result  sM    44U;<v;!..0::<HH##L11ra   c                .   | j                   }t        |t              sGt        |      dk(  r| d d | j                   fS d}	 t        j                  || j                         }||fS t        | |      }||fS # t        t        f$ r}t        |      |d }~ww xY w)Nr   z.other must be a MultiIndex or a list of tuplesr  )	rs   r   rA   r   rN   r   r   rt   rD   )r]   r  r  r.  r  s        r_   r  z MultiIndex._convert_can_do_setop  s    zz%'5zQBQx++F2&225

2KE l"" /tU;Ll"" #I. 2 $C.c12s   !A4 4BBBc                    t        |      }t        |t              rd}t        |      t	        |      st        d      |du r| j                         S | S )Nz3> 1 ndim Categorical are not supported at this timezISetting a MultiIndex dtype to anything other than object is not supportedT)r3   r   r4   r  r1   rt   r   )r]   r   r   r.  s       r_   rn   zMultiIndex.astype  s[    U#e-.GC%c**u%#  4<::<ra   c                   t        |t              r0|j                  | j                  k7  rt        d      |j                  S t        |t
              s|fd| j                  dz
  z  z   }|S t        |      | j                  k7  rt        d      |S )Nz0Item must have length equal to number of levels.)r  rT   )r   rN   r   r   r   r   r   )r]   items     r_   _validate_fill_valuezMultiIndex._validate_fill_value)  s    dJ'||t||+ !STT<<D%( 7UdllQ&677D  Y$,,&OPPra   c                >   t        | |      \  }}|r| j                         S t        |      t        |      k(  r||   j                         }n|j                         }g }g }t	        t        |j                  | j                  | j                              D ]n  \  }\  }}	}
|	j                  |d      }|j                  |j                  |            }t        |
      }|||<   |j                  |       |j                  |       p t        ||| j                  d      S )a  
        Return a new MultiIndex of the values set with the mask.

        Parameters
        ----------
        mask : array like
        value : MultiIndex
            Must either be the same length as self or length one

        Returns
        -------
        MultiIndex
        Fr  r  )r;   r   r   r  rr  r   r   r^   r  rb  r  r+   r   rN   rs   )r]   rs  r  noopsubsetr  r   r   value_levelr   r   	new_levelvalue_codesnew_codes                 r_   putmaskzMultiIndex.putmask7  s    &dD1
d99;t9E
"4[557F//1F
	4=t{{DJJ75
 	'0A0UK Ke<I#33F4K4KA4NOK#K0H(HTNi(X&	' YdjjSX
 	
ra   c                   | j                  |      }g }g }t        || j                  | j                        D ]y  \  }}}||vrt	        |      }|j                  ||      }n|j                  |      }|j                  |       |j                  t        j
                  t        |      ||             { t        ||| j                  d      S )a  
        Make new MultiIndex inserting new item at location

        Parameters
        ----------
        loc : int
        item : tuple
            Must be same length as number of levels in the MultiIndex

        Returns
        -------
        new_index : Index
        Fr  )r  r   r   r^   r   insertr:  r   rY   r+   rN   rs   )	r]   r-  r  r  r   r  r   r   lev_locs	            r_   r  zMultiIndex.insert_  s     ((.
	%(t{{DJJ%G 	Q!Auk~ e*Wa0--*e$RYY|K'@#wOP	Q YdjjSX
 	
ra   c                    | j                   D cg c]  }t        j                  ||       }}t        | j                  || j
                  d      S c c}w )z}
        Make new index with passed location deleted

        Returns
        -------
        new_index : MultiIndex
        Fr  )r^   rY   r*  rN   r   rs   )r]   r-  r   r   s       r_   r*  zMultiIndex.delete  sO     EIJJO[RYY{C0O	O;;**"	
 	
 Ps   Ac                $   t        |t              rt        |      }|t        |      dk(  r/t	        j
                  t        |       ft        j                        S t        |t              st        j                  |      }|j                         j                  |       dk7  S | j                  |      }| j                  |      }|j                  dk(  r.t	        j
                  t        |      t        j                        S |j                  |      S )Nr   r   r   )r   r   r   r   rY   r   r  rN   r   r  rb  r   r  r   r4  )r]   r   r   numlevss        r_   r4  zMultiIndex.isin  s    fi(&\F=6{axxTBHH==fj1#//7==?2248B>>((/C((-DyyA~xxD	::99V$$ra   __add____radd____iadd____sub____rsub____isub____pow____rpow____mul____rmul____floordiv____rfloordiv____truediv____rtruediv____mod____rmod__
__divmod____rdivmod____neg____pos____abs__
__invert__)NNNNNFNT)r   rK  r   rK  rJ  r   )r   r   r   r   )NNN)r^   list | Noner   r  r   zlist[int] | range | None)r   r   rs   -Sequence[Hashable] | Hashable | lib.NoDefaultrJ  rN   r/  )r   zIterable[tuple[Hashable, ...]]r   r   rs   $Sequence[Hashable] | Hashable | NonerJ  rN   )r   zSequence[Iterable[Hashable]]r   r   rs   r  rJ  rN   )r   rL   r   r   rs   r  rJ  rN   )rJ  
np.ndarray)rJ  rM   )rJ  r   )rJ  rE   )r   rK  r   rK  r   rK  rJ  None)r   rK  rJ  rN   )rJ  r    )rJ  zCallable[..., MultiIndex])r   r  rJ  rN   )rJ  rN   )NFN)r.  rK  rJ  r   r   )rJ  r   )r=  r   rJ  rK  )rJ  znp.dtyperI  F)r.  rK  rJ  r   )rj  rn  rJ  znpt.NDArray[np.object_])NNNF   NT)rr   zbool | Nonerz  Callable | Nonerj  z
str | Noners   rK  r  r   r  rK  rJ  r   )r  rK  r  zbool | None | lib.NoDefaultrz  r  rJ  r   )r   rK  )rJ  rn  )rJ  z	list[str])first)r  r   rJ  r  )r   )r  r   rJ  rN   )r   r   r  rK  rJ  rA   )rJ  rA   )r   rK  r  rK  rJ  rL   )r  rK  rJ  rN   )r]   rN   r  r  rJ  rN   )r   TN)r]   rN   rV   r   r  rK  rJ  rN   )r  rn  rJ  npt.NDArray[np.intp])r"  r   rJ  rN   )Nraise)r   z.Index | np.ndarray | Iterable[Hashable] | Noner+  r   rJ  rN   )r  )r+  r   rJ  rN   )r1  r   )T)r   rK  rJ  z!Generator[np.ndarray, None, None])rJ  zlist[Categorical])r   TTr  )
r   r   rI  zbool | list[bool]rJ  rK  r  rn  rJ  z'tuple[MultiIndex, npt.NDArray[np.intp]])rN  rK  )r  rA   rN  rK  rJ  rA   )rJ  r  )rZ  rn  rJ  z"tuple[Index, npt.NDArray[np.intp]])rZ  rn  rJ  r  )rJ  r  )ri  zHashable | Sequence[Hashable]rg  Literal['left', 'right']rJ  r   )rJ  ztuple[int, int])rq  )rg  r   rg  r  )ry  rA   r=  r   rJ  r   )r   T)r   r   r  rK  )r   )r   zint | list[int])r   N)r   r   r  znpt.NDArray[np.bool_] | None)r  z,tuple[Scalar | Iterable | AnyArrayLike, ...]r  r  rJ  r  )r  rm   rJ  rK  )r  rN   rJ  rK  )r   r   rJ  rK  )r   rN   rJ  rN   )r   rK  )r  rN   rJ  rN   )r-  r   rJ  rN   r  )rb   rc   rd   re   rA   _hidden_attrs	frozenset_typr~   __annotations__rE   r   r   _comparablesr   r   r   classmethodr   r   r   r{   r   r   r   r'   r   propertyr   r   r   r   r   r   r   r  r   r  r^   r   r  r&  r)  r(   r+  r   r   r6  r  r>  r   rM  rQ  rS  rP  rf  rm  r  r  r  r   rs   r  r   r  r  rL  r   _duplicatedr  r  r  r  r  r  r  r  r   r  r  r  r  r  r&   rB   _index_doc_kwargsrq  r   r  r  r/  r%  r:  r>  r<  rB  r  rK  rO  rM  rR  rT  rY  rW  rV  rj  rl  rh  rt  r:  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rn   r  r  r  r*  r4  r  r  rF   r  r  r  r  r  r  r  r  r  r  r   r  r  r  r  r  r  r  r  r	  r
  r  __classcell__)r\  s   @r_   rN   rN      s)
   Qf '')+5M D$&F!&lG\F9L !%- - - 
-^4 ""59	LL L 3	L\  !%?B~~	D
 D
 =	D

 
D
 D
L  !%6:	MI.MI MI 4	MI
 
MI  MI^  !%?B~~	:D/:D :D =	:D
 
:D :Dx  !%6:	BJBJ BJ 4	BJ
 
BJ BJL  2   
 
 R R4"   8" 8"| !&+
 + + + 
+\  $d`7;`	`D ! ! 2 2$   !&'
 ' ' ' 
'T #T>6:>	>F F F: & & 			58^^ K K

" 	> >
 
>@ 			   E 			" " # #2K  %""	 "L !%)!O!O! #O! 	O!
 O! O! O! 
O!l &*= = .	=
 #= 
=D' *. 8t E*  6 ? ?< 2 2 6 6 			% % KH 	
/ 
/442h 	D D ^^!&	XX 	X
 
Xx8<"3H 8 8A
FSp7 D
$  (+<<= 

 
 	
 

 >
>=%@ )/P"%P	P  *->>?
 @
( AE%	Y! >Y! 	Y!
 
Y!x 3:$/	*8
t"H
 (, $	*
, '+#"c"c" %c" 	c"
 c" 
1c"J ) = =;!;	+;F(*29,29 '29 
	29j54n1Kf,2xXt5nS)l LPo%o%,Ho%bC7NV9V &V 
	Vp+
Z<|  D&
".2#* 	 &
P!
F
  	_% %( __F
 i(Gz*Hz*Hi(Gz*Hz*Hi(Gz*Hi(Gz*H">2L#O4M!-0K">2Li(Gz*H .J!-0Ki(Gi(Gi(G .Jra   c                    | D cg c]  }t        |       }}t        |dd      D ]  }t        j                  |d|       s|c S  yc c}w )zJCount depth (up to a maximum of `nlevels`) with which codes are lexsorted.r   r   N)r+   r   r  r  )r^   r   r   int64_codesr  s        r_   r   r     sV    @EF<,FKF7Ar"   Ra1H 	 Gs   Ac                   t        t        |        }t        |       }|d |dz    }||   }||dz   d  D ]  }g }t        t        ||            D ]q  \  }	\  }
}|	|dz
  k(  r$|j	                  |       |j	                  |        n?|
|k(  r|j	                  |       L|j                  ||	d         |j	                  |        n |} t        t        |       S )NrT   )r   r   r   rr  r   r  )
label_listr  r  pivotedr  r   prevcur
sparse_curr   pts               r_   r  r    s    3
#$GJA[uqy!F5>Duqy{# 
"3tS>2 	IAv1AEz!!!$ j)Av!!(+!!#ab'* j)	" ), Vra   c                    t        | t              r| j                   S | j                  }t        j
                  dt        j                  dij                  |d      S )NNaTNaN)r   r5   r  r(  rY   
datetime64timedelta64get)r   
dtype_types     r_   r  r    sF    %(..!"ZZ
MM5"..%8<<ZOOra   c                    | }t        |t              r|D ]  }	 | j                  dg      }  | S 	 | j                  dg      } | S # t        $ r |cY c S w xY w# t        $ r Y | S w xY w)z
    Attempt to drop level or levels from the given index.

    Parameters
    ----------
    index: Index
    key : scalar or tuple

    Returns
    -------
    Index
    r   )r   r   r  r   )r   r=  original_indexr  s       r_   maybe_droplevelsr5    s     N#u  	&A&111#6	& L	--qc2E L  &%%&  	L	s"   AA AA	A$#A$c                d    t        | |      } |r| j                         } d| j                  _        | S )a  
    Coerce the array-like indexer to the smallest integer dtype that can encode all
    of the given categories.

    Parameters
    ----------
    array_like : array-like
    categories : array-like
    copy : bool

    Returns
    -------
    np.ndarray
        Non-writeable.
    F)r*   r   ro  rp  )
array_likera  r   s      r_   r  r    s3      &j*=J__&
!&Jra   c                &   | Xt        |       sMt        |      st        | d      t        |      dkD  rt        |d         rt        | d      | g} |g}| |fS | t        |       r't        |      rt        |d         st        | d      | |fS )zT
    Ensure that level is either None or listlike, and arr is list-of-listlike.
    z must be list-liker   z must be list of lists-like)r0   rt   r   )r   r   arrnames      r_   r	  r	  /  s     e!4C wi'9:;;s8a<LQ0wi'9:;;e #: 
,u-C SV(<wi'BCDD#:ra   )ry   r   rJ  r   )r^   zlist[np.ndarray]r   r   rJ  r   )r   r  )r  r   r  rm   )r   r   rJ  rn  )r   rA   rJ  rA   r  )r   rK  rJ  r  )r9  rn  )
__future__r   collections.abcr   r   r   r   r   	functoolsr	   sysr   typingr   r   r   r   r   r  numpyrY   pandas._configr   pandas._libsr   r  r   rf   r   pandas._libs.hashtabler   pandas._typingr   r   r   r   r   r   r   r   r   r   r    r!   pandas.compat.numpyr"   r  pandas.errorsr#   r$   r%   pandas.util._decoratorsr&   r'   r(   pandas.util._exceptionsr)   pandas.core.dtypes.castr*   pandas.core.dtypes.commonr+   r,   r-   r.   r/   r0   r1   r2   r3   pandas.core.dtypes.dtypesr4   r5   pandas.core.dtypes.genericr6   r7   pandas.core.dtypes.inferencer8   pandas.core.dtypes.missingr9   r:   pandas.core.algorithmscore
algorithmspandas.core.array_algos.putmaskr;   pandas.core.arraysr<   r=   pandas.core.arrays.categoricalr>   r?   pandas.core.commoncommonr   pandas.core.constructionr@   pandas.core.indexes.baseindexesbaser  rA   rB   rC   rD   pandas.core.indexes.frozenrE   pandas.core.ops.invalidrF   pandas.core.sortingrG   rH   pandas.io.formats.printingrI   rJ   r   rK   rL   rM   dictr   updateBaseMultiIndexCodesEnginerg   rR   ro   rk   r{   rN   r   r  r  r5  r  r	  ri   ra   r_   <module>ra     s}   "       % 
 .    / 
 
 5 8
 
 
 7
 ' & < !   3 ( (  2 3

   001    ,JK
$38==x?T?T $3N&3H>>@U@U &3R&_;/ _;/Dw@PB.ra   