o
    EbbS                     @   s  d dl mZ d dlZd dlZd dlZd dlZd dlZd dlmZ d dl	Z	d dl
Z
d dlmZmZmZmZ d dlZeeejf Zeeejejf Zereeeeejjejjf  Zedeejjejjf dZzd dlmZ W n ey}   G dd	 d	ZY nw d7d
dZd8ddZ eddfddZ!dd Z"dd Z#dedefddZ$G dd dZ%dd Z&			d9dd Z'd:d!d"Z(ed#g d$Z)d%d& Z*G d'd( d(Z+G d)d* d*Z,	+	d;d,d-Z-ed<d/d0Z.d=d1d2Z/d3d4 Z0d>d5d6Z1dS )?    )contextmanagerN)
namedtuple)OptionalUnionTYPE_CHECKINGTypeVarGeneratorType)Zbound)	Generatorc                   @   s   e Zd ZdS )r	   N)__name__
__module____qualname__ r   r   2/usr/lib/python3/dist-packages/scipy/_lib/_util.pyr	   !   s    r	   c           	         s   t   |du r|du rtdt j}n|durtdt j g|R  }|d |dd  }t fdd|D }t dd	 |D }t jt |d ||d
}t 	| ||  |durut fdd|D }t 	|  ||  |S )a  
    np.where(cond, x, fillvalue) always evaluates x even where cond is False.
    This one only evaluates f(arr1[cond], arr2[cond], ...).

    Examples
    --------
    >>> a, b = np.array([1, 2, 3, 4]), np.array([5, 6, 7, 8])
    >>> def f(a, b):
    ...     return a*b
    >>> _lazywhere(a > 2, (a, b), f, np.nan)
    array([ nan,  nan,  21.,  32.])

    Notice, it assumes that all `arrays` are of the same shape, or can be
    broadcasted together.

    Nz%One of (fillvalue, f2) must be given.z)Only one of (fillvalue, f2) can be given.r      c                 3       | ]	}t  |V  qd S Nnpextract.0Zarrcondr   r   	<genexpr>B       z_lazywhere.<locals>.<genexpr>c                 S      g | ]}|j jqS r   dtypecharr   ar   r   r   
<listcomp>C       z_lazywhere.<locals>.<listcomp>Z
fill_valuer   c                 3   s    | ]
}t   |V  qd S r   r   r   r   r   r   r   G   s    )
r   asarray
ValueErrornanbroadcast_arraystuplemintypecodefullshapeplace)	r   arraysf	fillvaluef2argstemptcodeoutr   r   r   
_lazywhere%   s"   
r5   c           	         s   t j| }t dd |D }t jt |d ||d}t|| D ]*\} t  du r-q!t  |d \ }t fdd|D }t | ||  q!|S )a?  
    Mimic `np.select(condlist, choicelist)`.

    Notice, it assumes that all `arrays` are of the same shape or can be
    broadcasted together.

    All functions in `choicelist` must accept array arguments in the order
    given in `arrays` and must return an array of the same shape as broadcasted
    `arrays`.

    Examples
    --------
    >>> x = np.arange(6)
    >>> np.select([x <3, x > 3], [x**2, x**3], default=0)
    array([  0,   1,   4,   0,  64, 125])

    >>> _lazyselect([x < 3, x > 3], [lambda x: x**2, lambda x: x**3], (x,))
    array([   0.,    1.,    4.,   0.,   64.,  125.])

    >>> a = -np.ones_like(x)
    >>> _lazyselect([x < 3, x > 3],
    ...             [lambda x, a: x**2, lambda x, a: a * x**3],
    ...             (x, a), default=np.nan)
    array([   0.,    1.,    4.,   nan,  -64., -125.])

    c                 S   r   r   r   r   r   r   r   r!   i   r"   z_lazyselect.<locals>.<listcomp>r   r#   Fc                 3   r   r   r   r   r   r   r   r   o   r   z_lazyselect.<locals>.<genexpr>)	r   r'   r)   r*   r+   zipallr(   r,   )	ZcondlistZ
choicelistr-   defaultr3   r4   func_r2   r   r   r   _lazyselectM   s   
r;   Cc                 C   s   t |}|du r|j}t| ds| f} ttj| |j }t 	|| d t j
}|jd d | }|dkr:|| }|||| d  dd }t j| |||d}|d |S )zAllocate a new ndarray with aligned memory.

    Primary use case for this currently is working around a f2py issue
    in NumPy 1.9.1, where dtype.alignment is such that np.zeros() does
    not necessarily create arrays aligned up to it.

    N__len__r   datar   )order)r   r   Z	alignmenthasattr	functoolsreduceoperatormulitemsizeemptyZuint8Z__array_interface__Zndarrayfill)r+   r   r@   Zalignsizebufoffsetr>   r   r   r   _aligned_zerost   s   


rL   c                 C   s(   | j dur| j| j jd k r|  S | S )zReturn an array equivalent to the input array. If the input
    array is a view of a much larger array, copy its contents to a
    newly allocated array. Otherwise, return the input unchanged.
    N   )baserI   copy)Zarrayr   r   r   _prune_array   s   rP   c                 C   s   d}| D ]}||9 }q|S )z
    Product of a sequence of numbers.

    Faster than np.prod for short lists like array shapes, and does
    not overflow if using Python integers.
    r   r   )iterableproductxr   r   r   prod   s   
rT   nreturnc                 C   s   | dk rt t| S tjS )zlCompute the factorial and return as a float

    Returns infinity when result is too large for a double
       )floatmathZ	factorialr   inf)rU   r   r   r   float_factorial   s   r[   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	DeprecatedImporta3  
    Deprecated import with redirection and warning.

    Examples
    --------
    Suppose you previously had in some module::

        from foo import spam

    If this has to be deprecated, do::

        spam = DeprecatedImport("foo.spam", "baz")

    to redirect users to use "baz" module instead.

    c                 C   s(   || _ || _t| j tj| j | _d S r   )	_old_name	_new_name
__import__sysmodules_mod)selfZold_module_nameZnew_module_namer   r   r   __init__   s   
zDeprecatedImport.__init__c                 C   s
   t | jS r   )dirrb   rc   r   r   r   __dir__   s   
zDeprecatedImport.__dir__c                 C   s$   t d| j| jf t t| j|S )Nz'Module %s is deprecated, use %s instead)warningswarnr]   r^   DeprecationWarninggetattrrb   )rc   namer   r   r   __getattr__   s   
zDeprecatedImport.__getattr__N)r
   r   r   __doc__rd   rg   rm   r   r   r   r   r\      s
    r\   c                 C   s`   | du s	| t ju rt jjjS t| tjt jfrt j| S t| t jjt jj	fr*| S t
d|  )am  Turn `seed` into a `np.random.RandomState` instance.

    Parameters
    ----------
    seed : {None, int, `numpy.random.Generator`,
            `numpy.random.RandomState`}, optional

        If `seed` is None (or `np.random`), the `numpy.random.RandomState`
        singleton is used.
        If `seed` is an int, a new ``RandomState`` instance is used,
        seeded with `seed`.
        If `seed` is already a ``Generator`` or ``RandomState`` instance then
        that instance is used.

    Returns
    -------
    seed : {`numpy.random.Generator`, `numpy.random.RandomState`}
        Random number generator.

    Nz=%r cannot be used to seed a numpy.random.RandomState instance)r   randommtrand_rand
isinstancenumbersZIntegralintegerRandomStater	   r%   Zseedr   r   r   check_random_state   s   
rw   TFc           	      C   s   |sddl }|j| rd}t||stj| rtd|r#tjntj}|| } |s8| j	t	du r8td|rIt
| j	tjsI|| tjd} | S )aA  
    Helper function for SciPy argument validation.

    Many SciPy linear algebra functions do support arbitrary array-like
    input arguments. Examples of commonly unsupported inputs include
    matrices containing inf/nan, sparse matrix representations, and
    matrices with complicated elements.

    Parameters
    ----------
    a : array_like
        The array-like input.
    check_finite : bool, optional
        Whether to check that the input matrices contain only finite numbers.
        Disabling may give a performance gain, but may result in problems
        (crashes, non-termination) if the inputs do contain infinities or NaNs.
        Default: True
    sparse_ok : bool, optional
        True if scipy sparse matrices are allowed.
    objects_ok : bool, optional
        True if arrays with dype('O') are allowed.
    mask_ok : bool, optional
        True if masked arrays are allowed.
    as_inexact : bool, optional
        True to convert the input array to a np.inexact dtype.

    Returns
    -------
    ret : ndarray
        The converted validated array.

    r   NzxSparse matrices are not supported by this function. Perhaps one of the scipy.sparse.linalg functions would work instead.zmasked arrays are not supportedOzobject arrays are not supported)r   )Zscipy.sparseZsparseZissparser%   r   ZmaZisMaskedArrayZasarray_chkfiniter$   r   Z
issubdtypeZinexactZfloat_)	r    Zcheck_finiteZ	sparse_okZ
objects_okZmask_okZ
as_inexactZscipymsgZtoarrayr   r   r   _asarray_validated   s"   #rz   c                 C   sV   zt | } W n ty   t| ddw |dur)| |k r)t| d| d| S )a  
    Validate a scalar integer.

    This functon can be used to validate an argument to a function
    that expects the value to be an integer.  It uses `operator.index`
    to validate the value (so, for example, k=2.0 results in a
    TypeError).

    Parameters
    ----------
    k : int
        The value to be validated.
    name : str
        The name of the parameter.
    minimum : int, optional
        An optional lower bound.
    z must be an integer.Nz" must be an integer not less than )rD   index	TypeErrorr%   )krl   Zminimumr   r   r   _validate_int)  s   r~   FullArgSpec)r1   varargsvarkwdefaults
kwonlyargsZkwonlydefaultsannotationsc           	      C   s   t | }dd |j D }dd |j D }|r|d nd}dd |j D }|r1|d nd}tdd |j D p@d}d	d |j D }d
d |j D }dd |j D }t||||||phd|S )as  inspect.getfullargspec replacement using inspect.signature.

    If func is a bound method, do not list the 'self' parameter.

    Parameters
    ----------
    func : callable
        A callable to inspect

    Returns
    -------
    fullargspec : FullArgSpec(args, varargs, varkw, defaults, kwonlyargs,
                              kwonlydefaults, annotations)

        NOTE: if the first argument of `func` is self, it is *not*, I repeat
        *not*, included in fullargspec.args.
        This is done for consistency between inspect.getargspec() under
        Python 2.x, and inspect.signature() under Python 3.x.

    c                 S   s(   g | ]}|j tjjtjjfv r|jqS r   )kindinspect	ParameterPOSITIONAL_OR_KEYWORDZPOSITIONAL_ONLYrl   r   pr   r   r   r!   m  s    
z*getfullargspec_no_self.<locals>.<listcomp>c                 S       g | ]}|j tjjkr|jqS r   )r   r   r   ZVAR_POSITIONALrl   r   r   r   r   r!   r      r   Nc                 S   r   r   )r   r   r   ZVAR_KEYWORDrl   r   r   r   r   r!   w  r   c                 s   s0    | ]}|j tjjkr|j|jur|jV  qd S r   )r   r   r   r   r8   rG   r   r   r   r   r   |  s    

z)getfullargspec_no_self.<locals>.<genexpr>c                 S   r   r   )r   r   r   KEYWORD_ONLYrl   r   r   r   r   r!     r   c                 S   s0   i | ]}|j tjjkr|j|jur|j|jqS r   )r   r   r   r   r8   rG   rl   r   r   r   r   
<dictcomp>  s
    
z*getfullargspec_no_self.<locals>.<dictcomp>c                 S   s"   i | ]}|j |jur|j|j qS r   )
annotationrG   rl   r   r   r   r   r     s    
)r   Z	signatureZ
parametersvaluesr(   r   )	r9   Zsigr1   r   r   r   r   Z
kwdefaultsr   r   r   r   getfullargspec_no_selfW  s2   
r   c                   @   s    e Zd ZdZdd Zdd ZdS )_FunctionWrapperz?
    Object to wrap user's function, allowing picklability
    c                 C   s"   || _ |d u rg | _d S || _d S r   r.   r1   )rc   r.   r1   r   r   r   rd     s   z_FunctionWrapper.__init__c                 C   s   | j |g| jR  S r   r   )rc   rS   r   r   r   __call__  s   z_FunctionWrapper.__call__N)r
   r   r   rn   rd   r   r   r   r   r   r     s    r   c                   @   sJ   e Zd ZdZdddZdd Zdd Zd	d
 Zdd Zdd Z	dd Z
dS )
MapWrapperav  
    Parallelisation wrapper for working with map-like callables, such as
    `multiprocessing.Pool.map`.

    Parameters
    ----------
    pool : int or map-like callable
        If `pool` is an integer, then it specifies the number of threads to
        use for parallelization. If ``int(pool) == 1``, then no parallel
        processing is used and the map builtin is used.
        If ``pool == -1``, then the pool will utilize all available CPUs.
        If `pool` is a map-like callable that follows the same
        calling sequence as the built-in map function, then this callable is
        used for parallelization.
    r   c                 C   s   d | _ t| _d| _t|r|| _ | j | _d S ddlm} t|dkr0| | _ | j j| _d| _d S t|dkr8d S t|dkrP|t|d| _ | j j| _d| _d S td)	NFr   )Poolr?   Tr   )Z	processeszUNumber of workers specified must be -1, an int >= 1, or an object with a 'map' method)	poolmap_mapfunc	_own_poolcallableZmultiprocessingr   intRuntimeError)rc   r   r   r   r   r   rd     s$   



zMapWrapper.__init__c                 C   s   | S r   r   rf   r   r   r   	__enter__  s   zMapWrapper.__enter__c                 C      | j r
| j  d S d S r   )r   r   	terminaterf   r   r   r   r        zMapWrapper.terminatec                 C   r   r   )r   r   joinrf   r   r   r   r     r   zMapWrapper.joinc                 C   r   r   )r   r   closerf   r   r   r   r     r   zMapWrapper.closec                 C   s"   | j r| j  | j  d S d S r   )r   r   r   r   )rc   exc_type	exc_value	tracebackr   r   r   __exit__  s   
zMapWrapper.__exit__c              
   C   s2   z|  ||W S  ty } ztd|d }~ww )Nz;The map-like callable must be of the form f(func, iterable))r   r|   )rc   r9   rQ   er   r   r   r     s   zMapWrapper.__call__Nr   )r
   r   r   rn   rd   r   r   r   r   r   r   r   r   r   r   r     s    
r   int64c                 C   s   t | tr| j|||||dS | du rtjjj} |r7|du r(| j|d ||dS |dur7| j||d ||dS | j||||dS )al  
    Return random integers from low (inclusive) to high (exclusive), or if
    endpoint=True, low (inclusive) to high (inclusive). Replaces
    `RandomState.randint` (with endpoint=False) and
    `RandomState.random_integers` (with endpoint=True).

    Return random integers from the "discrete uniform" distribution of the
    specified dtype. If high is None (the default), then results are from
    0 to low.

    Parameters
    ----------
    gen : {None, np.random.RandomState, np.random.Generator}
        Random number generator. If None, then the np.random.RandomState
        singleton is used.
    low : int or array-like of ints
        Lowest (signed) integers to be drawn from the distribution (unless
        high=None, in which case this parameter is 0 and this value is used
        for high).
    high : int or array-like of ints
        If provided, one above the largest (signed) integer to be drawn from
        the distribution (see above for behavior if high=None). If array-like,
        must contain integer values.
    size : array-like of ints, optional
        Output shape. If the given shape is, e.g., (m, n, k), then m * n * k
        samples are drawn. Default is None, in which case a single value is
        returned.
    dtype : {str, dtype}, optional
        Desired dtype of the result. All dtypes are determined by their name,
        i.e., 'int64', 'int', etc, so byteorder is not available and a specific
        precision may have different C types depending on the platform.
        The default value is np.int_.
    endpoint : bool, optional
        If True, sample from the interval [low, high] instead of the default
        [low, high) Defaults to False.

    Returns
    -------
    out: int or ndarray of ints
        size-shaped array of random integers from the appropriate distribution,
        or a single such random int if size not provided.
    )highrI   r   endpointNr   )rI   r   )r   rI   r   )rr   r	   Zintegersr   ro   rp   rq   Zrandint)genZlowr   rI   r   r   r   r   r   rng_integers  s   
,
r   	   !E^1cuBn c                 #   s>    t jj | f fdd	t j_z
dV  W  t j_dS  t j_w )z0Context with a fixed np.random.default_rng seed.c                    s    | S r   r   rv   Zorig_funr   r   <lambda>(  s    z$_fixed_default_rng.<locals>.<lambda>N)r   ro   Zdefault_rngrv   r   r   r   _fixed_default_rng$  s   r   c                 C   s,   t j| |d}|r|durt j||d}|S )z
    argmin with a `keepdims` parameter.

    See https://github.com/numpy/numpy/issues/8710

    If axis is not None, a.shape[axis] must be greater than 0.
    axisN)r   ZargminZexpand_dims)r    keepdimsr   resr   r   r   _argmin/  s   r   c                 C   s$   t t| |dd}tj| ||dS )a  
    Return the first non-nan value along the given axis.

    If a slice is all nan, nan is returned for that slice.

    The shape of the return value corresponds to ``keepdims=True``.

    Examples
    --------
    >>> nan = np.nan
    >>> a = np.array([[ 3.,  3., nan,  3.],
                      [ 1., nan,  2.,  4.],
                      [nan, nan,  9., -1.],
                      [nan,  5.,  4.,  3.],
                      [ 2.,  2.,  2.,  2.],
                      [nan, nan, nan, nan]])
    >>> _first_nonnan(a, axis=0)
    array([[3., 3., 2., 3.]])
    >>> _first_nonnan(a, axis=1)
    array([[ 3.],
           [ 1.],
           [ 9.],
           [ 5.],
           [ 2.],
           [nan]])
    Tr   r   r   )r   r   isnanZtake_along_axis)r    r   r}   r   r   r   _first_nonnan=  s   r   c                 C   s   |du r| j dkrdS |  } d}n#| j}|| dkr5|d| d|  ||d d  }tj|dtdS t| |d}|| kt| B j||dS )	a  
    Determine if the values along an axis are all the same.

    nan values are ignored.

    `a` must be a numpy array.

    `axis` is assumed to be normalized; that is, 0 <= axis < a.ndim.

    For an axis of length 0, the result is True.  That is, we adopt the
    convention that ``allsame([])`` is True. (There are no values in the
    input that are different.)

    `True` is returned for slices that are all nan--not because all the
    values are the same, but because this is equivalent to ``allsame([])``.

    Examples
    --------
    >>> a
    array([[ 3.,  3., nan,  3.],
           [ 1., nan,  2.,  4.],
           [nan, nan,  9., -1.],
           [nan,  5.,  4.,  3.],
           [ 2.,  2.,  2.,  2.],
           [nan, nan, nan, nan]])
    >>> _nan_allsame(a, axis=1, keepdims=True)
    array([[ True],
           [False],
           [False],
           [False],
           [ True],
           [ True]])
    Nr   Tr   r   r#   r   r   )	rI   Zravelr+   r   r*   boolr   r   r7   )r    r   r   ZshpZa0r   r   r   _nan_allsame\  s   "
$r   )NN)r   )TFFFFr   )NNr   F)r   )FN)F)2
contextlibr   rB   rD   r`   rh   rs   collectionsr   r   rY   typingr   r   r   r   Znumpyr   r   rt   Z	IntNumberrX   ZfloatingZDecimalNumberro   r	   ru   ZSeedTyper   Znumpy.randomImportErrorr5   r;   rL   rP   rT   r[   r\   rw   rz   r~   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sh    


('
$ 

8)7J
@

