U
    td,                     @   s   d Z ddlmZ ddlmZ ddlmZ ddlmZ ddl	Z	ddl
Z
dZdZd	d
 Zdd Zedd Zdd ZdddZd ddZG dd deZd!ddZd"ddZdd Ze ZdS )#z;Utility functions that cannot be categorised anywhere else.    )contextmanager)MutableMapping)chain)warnN)dbl_epsilon
deprecated	multidictnamed_temporary_filenumpy_to_contiguous_memoryviewrescalesafeminsafemaxzrestructuredtext enc                 C   s   t | tdd dS )zOPrints a warning message related to the deprecation of some igraph
    feature.   )
stacklevelN)r   DeprecationWarning)message r   E/home/sam/Atlas/atlas_env/lib/python3.8/site-packages/igraph/utils.pyr      s    r   c                  C   s4   zddl m}  |  dk	W S  tk
r.   Y dS X dS )zVInternal function that determines whether igraph is running inside
    IPython or not.r   get_ipythonNF)ZIPythonr   ImportErrorr   r   r   r   _is_running_in_ipython"   s
    r   c               	   o   s6   t j| |\}}t| z
|V  W 5 t| X dS )zContext manager that creates a named temporary file and
    returns its name.

    All parameters are passed on to ``tempfile.mkstemp``, see
    its documentation for more info.
    N)tempfilemkstemposcloseunlink)argskwdshandleZtmpfiler   r   r   r	   -   s
    

r	   c                 C   s^   ddl m}m}m} ddlm} |dkr.|}n|dkr<|}ntd| dt|| |dd	S )
zConverts a NumPy array or matrix into a contiguous memoryview object
    that is suitable to be forwarded to the Graph constructor.

    This is used internally to allow us to use a NumPy array or matrix
    directly when constructing a Graph.
    r   )int32int64require)INTEGER_SIZE@       z)size of igraph_integer_t in the C layer (z bits) is not supportedZAC)dtyperequirements)numpyr    r!   r"   Zigraph._igraphr#   	TypeError
memoryview)objr    r!   r"   r#   r&   r   r   r   r
   =   s    
r
   g              ?Fc                    s   dk	rfdd| D } |dkr6t | t|  }n"|\}dk	rX| }t| s|d |d  d gt|  S ttt|\    fdd| D }|r҇ fdd|D S |S dS )	a
  Rescales a list of numbers into a given range.

    ``out_range`` gives the range of the output values; by default, the minimum
    of the original numbers in the list will be mapped to the first element
    in the output range and the maximum will be mapped to the second element.
    Elements between the minimum and maximum values in the input list will be
    interpolated linearly between the first and second values of the output
    range.

    ``in_range`` may be used to override which numbers are mapped to the first
    and second values of the output range. This must also be a tuple, where
    the first element will be mapped to the first element of the output range
    and the second element to the second.

    If ``clamp`` is ``True``, elements which are outside the given ``out_range``
    after rescaling are clamped to the output range to ensure that no number
    will be outside ``out_range`` in the result.

    If ``scale`` is not ``None``, it will be called for every element of ``values``
    and the rescaling will take place on the results instead. This can be used,
    for instance, to transform the logarithm of the original values instead of
    the actual values. A typical use-case is to map a range of values to color
    identifiers on a logarithmic scale. Scaling also applies to the ``in_range``
    parameter if present.

    :param out_range: the range of output values
    :param in_range: the range of the input values; this is the range that is mapped
        to ``out_range``. ``None`` means to use the minimum and maximum of
        the input, respectively.
    :param clamp: specifies what to do when an input value falls outside ``in_range``.
        ``True`` means to clamp the value to the bounds of ``in_range``,
        ``False`` means not to clamp.
    :param scale: an optional transformation to perform on the input values before
        mapping them to the output range.

    Examples:

        >>> rescale(range(5), (0, 8))
        [0.0, 2.0, 4.0, 6.0, 8.0]
        >>> rescale(range(5), (2, 10))
        [2.0, 4.0, 6.0, 8.0, 10.0]
        >>> rescale(range(5), (0, 4), (1, 3))
        [-2.0, 0.0, 2.0, 4.0, 6.0]
        >>> rescale(range(5), (0, 4), (1, 3), clamp=True)
        [0.0, 0.0, 2.0, 4.0, 4.0]
        >>> rescale([0]*5, (1, 3))
        [2.0, 2.0, 2.0, 2.0, 2.0]
        >>> from math import log10
        >>> rescale([1, 10, 100, 1000, 10000], (0, 8), scale=log10)
        [0.0, 2.0, 4.0, 6.0, 8.0]
        >>> rescale([1, 10, 100, 1000, 10000], (0, 4), (10, 1000), scale=log10)
        [-2.0, 0.0, 2.0, 4.0, 6.0]
    Nc                    s   g | ]} |qS r   r   ).0value)scaler   r   
<listcomp>   s     zrescale.<locals>.<listcomp>r             @c                    s   g | ]}|    qS r   r   r.   x)mimin_outratior   r   r1      s     c                    s   g | ]}t t| qS r   )maxminr4   )max_outr7   r   r   r1      s     )r:   r9   floatlenlistmap)valuesZ	out_rangeZin_rangeclampr0   maresultr   )r;   r6   r7   r8   r0   r   r   T   s     6r   c                 c   s~   t | }zt|}W n tk
r*   Y dS X |}|D ]}||fV  |}q4|rzz||fV  W n tk
rx   ||fV  Y nX dS )as  Returns consecutive pairs of items from the given iterable.

    When ``circular`` is ``True``, the pair consisting of the last
    and first elements is also returned.

    Example:

        >>> list(consecutive_pairs(range(5)))
        [(0, 1), (1, 2), (2, 3), (3, 4)]
        >>> list(consecutive_pairs(range(5), circular=True))
        [(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)]
        >>> list(consecutive_pairs([]))
        []
        >>> list(consecutive_pairs([], circular=True))
        []
        >>> list(consecutive_pairs([0]))
        []
        >>> list(consecutive_pairs([0], circular=True))
        [(0, 0)]
    N)iternextStopIterationUnboundLocalError)iterableZcircularitprevfirstitemr   r   r   consecutive_pairs   s    
rM   c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd ZdddZdd Zdd Zdd Zdd ZdS ) r   am  A dictionary-like object that is customized to deal with multiple
    values for the same key.

    Each value in this dictionary will be a list. Methods which emulate
    the methods of a standard Python ``dict`` object will return or manipulate
    the first items of the lists only. Special methods are provided to
    deal with keys having multiple values.
    c                 O   sN   i | _ t|dkr*td| jjt|f |r@|d }| | | | d S )Nr2   z&%r expected at most 1 argument, got %dr   )_dictr=   
ValueError	__class____name__update)selfr   r   r   r   r   __init__   s    
zmultidict.__init__c                 C   s0   zt | j| dkW S  tk
r*   Y dS X dS )zLReturns whether there are any items associated to the given
        ``key``.r   FN)r=   rN   KeyErrorrS   keyr   r   r   __contains__   s    zmultidict.__contains__c                 C   s   | j |= dS )z6Removes all the items associated to the given ``key``.NrN   rV   r   r   r   __delitem__   s    zmultidict.__delitem__c                 C   s2   z| j | d W S  tk
r,   t|Y nX dS )zReturns an arbitrary item associated to the given key. Raises ``KeyError``
        if no such key exists.

        Example:

            >>> d = multidict([("spam", "eggs"), ("spam", "bacon")])
            >>> d["spam"]
            'eggs'
        r   N)rN   
IndexErrorrU   rV   r   r   r   __getitem__   s    
zmultidict.__getitem__c                 C   s
   t | jS )z(Iterates over the keys of the multidict.)rD   rN   rS   r   r   r   __iter__   s    zmultidict.__iter__c                 C   s
   t | jS )z6Returns the number of distinct keys in this multidict.)r=   rN   r]   r   r   r   __len__   s    zmultidict.__len__c                 C   s   |g| j |< dS )a,  Sets the item associated to the given ``key``. Any values associated to the
        key will be erased and replaced by ``value``.

        Example:

           >>> d = multidict([("spam", "eggs"), ("spam", "bacon")])
           >>> d["spam"] = "ham"
           >>> d["spam"]
           'ham'
        NrY   rS   rW   r/   r   r   r   __setitem__  s    zmultidict.__setitem__c                 C   s:   z| j | | W n  tk
r4   |g| j |< Y nX dS )a)  Adds `value` to the list of items associated to ``key``.

        Example:

            >>> d = multidict()
            >>> d.add("spam", "ham")
            >>> d["spam"]
            'ham'
            >>> d.add("spam", "eggs")
            >>> d.getlist("spam")
            ['ham', 'eggs']
        N)rN   appendrU   r`   r   r   r   add  s    zmultidict.addc                 C   s   | j   dS )z)Removes all the items from the multidict.N)rN   clearr]   r   r   r   rd   "  s    zmultidict.clearNc              	   C   s6   z| j | }|d W S  ttfk
r0   | Y S X dS )zReturns an arbitrary item associated to the given ``key``. If ``key``
        does not exist or has zero associated items, ``default`` will be
        returned.r   N)rN   rU   r[   )rS   rW   defaultitemsr   r   r   get&  s
    

zmultidict.getc                 C   s*   z| j | W S  tk
r$   g  Y S X dS )zqReturns the list of values for the given ``key``. An empty list will
        be returned if there is no such key.N)rN   rU   rV   r   r   r   getlist0  s    zmultidict.getlistc                 C   s   t | j S )zmIterates over ``(key, values)`` pairs where ``values`` is the list
        of values associated with ``key``.)rD   rN   rf   r]   r   r   r   	iterlists8  s    zmultidict.iterlistsc                 C   s   t | j S )zqReturns a list of ``(key, values)`` pairs where ``values`` is the list
        of values associated with ``key``.)r>   rN   rf   r]   r   r   r   lists=  s    zmultidict.listsc                 K   sp   t |dr4t|jr4| D ]}| |||  qn|D ]\}}| || q8| D ]\}}| || qVd S )Nkeys)hasattrcallablerk   rc   rf   )rS   argr   rW   r/   r   r   r   rR   B  s    zmultidict.update)N)rQ   
__module____qualname____doc__rT   rX   rZ   r\   r^   r_   ra   rc   rd   rg   rh   ri   rj   rR   r   r   r   r   r      s   	

r   c                 C   sB   t | }zt|}W n tk
r,   | Y S X tt|g|S dS )zSafer variant of ``max()`` that returns a default value if the iterable
    is empty.

    Example:

        >>> safemax([-5, 6, 4])
        6
        >>> safemax([])
        0
        >>> safemax((), 2)
        2
    N)rD   rE   rF   r9   r   rH   re   rI   rK   r   r   r   r   M  s    
r   c                 C   sB   t | }zt|}W n tk
r,   | Y S X tt|g|S dS )zSafer variant of ``min()`` that returns a default value if the iterable
    is empty.

    Example:

        >>> safemin([-5, 6, 4])
        -5
        >>> safemin([])
        0
        >>> safemin((), 2)
        2
    N)rD   rE   rF   r:   r   rr   r   r   r   r   c  s    
r   c                  C   s"   d} d| d  dkr| d } q| S )z3Approximates the machine epsilon value for doubles.r-   r3      r   )epsilonr   r   r   r   y  s    
r   )r,   NFN)F)r   )r   )rq   
contextlibr   collections.abcr   	itertoolsr   warningsr   r   r   __all____docformat__r   r   r	   r
   r   rM   r   r   r   r   r   r   r   r   <module>   s*   

N
( 

