B
    d+                 @   s   d 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Zdej	 Z
ej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dZdS )z&
A collection of iteration utilities.
    N)git_versionz"Kipp Cannon <kipp.cannon@ligo.org>z	git id %sc              g   sx   t | dkrVtdd | d D }xPt| dd  D ]}x|D ]}|| V  q>W q4W n| rtx| d D ]}|fV  qdW dS )a  
	A generator for iterating over the elements of multiple sequences
	simultaneously.  With N sequences given as input, the generator
	yields all possible distinct N-tuples that contain one element from
	each of the input sequences.

	Example:

	>>> x = MultiIter([0, 1, 2], [10, 11])
	>>> list(x)
	[(0, 10), (1, 10), (2, 10), (0, 11), (1, 11), (2, 11)]

	The elements in each output tuple are in the order of the input
	sequences, and the left-most input sequence is iterated over first.

	Internally, the input sequences themselves are each iterated over
	only once, so it is safe to pass generators as arguments.  Also,
	this generator is significantly faster if the longest input
	sequence is given as the first argument.  For example, this code

	>>> lengths = range(1, 12)
	>>> for x in MultiIter(*map(range, lengths)):
	...	pass
	...

	runs approximately 5 times faster if the lengths list is reversed.
	   c             s   s   | ]}|fV  qd S )N ).0xr   r   [/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/glue/iterutils.py	<genexpr>[   s    zMultiIter.<locals>.<genexpr>r   N)lentuple	MultiIter)	sequencesheadthr   r   r   r   8   s    
r   c             c   s   |t | krt| V  n|dkrz|d8 }xt| d|  D ]8\}}|f}x(t| |d d |D ]}|| V  qbW q<W n8|dkrx.| D ]}|fV  qW n|dkrdV  nt|dS )a2  
	A generator for iterating over all choices of n elements from the
	input sequence vals.  In each result returned, the original order
	of the values is preserved.

	Example:

	>>> x = choices(["a", "b", "c"], 2)
	>>> list(x)
	[('a', 'b'), ('a', 'c'), ('b', 'c')]

	The order of combinations in the output sequence is always the
	same, so if choices() is called twice with two different sequences
	of the same length the first combination in each of the two output
	sequences will contain elements from the same positions in the two
	different input sequences, and so on for each subsequent pair of
	output combinations.

	Example:

	>>> x = choices(["a", "b", "c"], 2)
	>>> y = choices(["1", "2", "3"], 2)
	>>> list(zip(x, y))
	[(('a', 'b'), ('1', '2')), (('a', 'c'), ('1', '3')), (('b', 'c'), ('2', '3'))]

	Furthermore, the order of combinations in the output sequence is
	such that if the input list has n elements, and one constructs the
	combinations choices(input, m), then each combination in
	choices(input, n-m).reverse() contains the elements discarded in
	forming the corresponding combination in the former.

	Example:

	>>> x = ["a", "b", "c", "d", "e"]
	>>> X = list(choices(x, 2))
	>>> Y = list(choices(x, len(x) - 2))
	>>> Y.reverse()
	>>> list(zip(X, Y))
	[(('a', 'b'), ('c', 'd', 'e')), (('a', 'c'), ('b', 'd', 'e')), (('a', 'd'), ('b', 'c', 'e')), (('a', 'e'), ('b', 'c', 'd')), (('b', 'c'), ('a', 'd', 'e')), (('b', 'd'), ('a', 'c', 'e')), (('b', 'e'), ('a', 'c', 'd')), (('c', 'd'), ('a', 'b', 'e')), (('c', 'e'), ('a', 'b', 'd')), (('d', 'e'), ('a', 'b', 'c'))]
	r   Nr   r   )r	   r
   	enumeratechoices
ValueError)valsnivcr   r   r   r   d   s    )
r   c             c   s,   i }x"| D ]}||kr
| ||V  q
W dS )z
	Yield the unique items of an iterable, preserving order.
	http://mail.python.org/pipermail/tutor/2002-March/012930.html

	Example:

	>>> x = uniq([0, 0, 2, 6, 2, 0, 5])
	>>> list(x)
	[0, 2, 6, 5]
	N)
setdefault)iterable	temp_dicter   r   r   uniq   s    
r   c             c   s0   i }x&| D ]}||kr|V  | || q
W dS )z
	Yield the non-unique items of an iterable, preserving order.  If an
	item occurs N > 0 times in the input sequence, it will occur N-1
	times in the output sequence.

	Example:

	>>> x = nonuniq([0, 0, 2, 6, 2, 0, 5])
	>>> list(x)
	[0, 2, 0]
	N)r   )r   r   r   r   r   r   nonuniq   s
    
r   r   c             c   sN   |dkrx@| D ]
}|V  qW n,x*| D ]"}xt ||d D ]
}|V  q8W q$W dS )zQ
	Example:
	>>> nested = [[1,2], [[3]]]
	>>> list(flatten(nested))
	[1, 2, [3]]
	r   r   N)flatten)sequenceZlevelsr   yr   r   r   r      s    

r   c             C   sH   d}x4t t|D ]$}| || r|| ||< |d7 }qW ||d= dS )a  
	Like Python's filter() builtin, but modifies the sequence in place.

	Example:

	>>> l = list(range(10))
	>>> inplace_filter(lambda x: x > 5, l)
	>>> l
	[6, 7, 8, 9]

	Performance considerations:  the function iterates over the
	sequence, shuffling surviving members down and deleting whatever
	top part of the sequence is left empty at the end, so sequences
	whose surviving members are predominantly at the bottom will be
	processed faster.
	r   r   N)ranger	   )funcr   targetsourcer   r   r   inplace_filter   s    r%   c           	   o   sp  | dd}| ddd }|r8tdt| d  i }xN| D ]F}ttt|}y| }||||f||< W qB tk
r   Y qBX qBW |sdS |rd	d }nd
d }tt	j
|}	t|dkr,xd||	 \}
}}|V  y| }||||f||< W q tk
r&   ||= t|dk r"P Y qX qW |	 \\}
}}|V  yx| V  qDW W n tk
rj   Y nX dS )aX  
	A generator that yields the values from several ordered iterables
	in order.

	Example:

	>>> x = [0, 1, 2, 3]
	>>> y = [1.5, 2.5, 3.5, 4.5]
	>>> z = [1.75, 2.25, 3.75, 4.25]
	>>> list(inorder(x, y, z))
	[0, 1, 1.5, 1.75, 2, 2.25, 2.5, 3, 3.5, 3.75, 4.25, 4.5]
	>>> list(inorder(x, y, z, key=lambda x: x * x))
	[0, 1, 1.5, 1.75, 2, 2.25, 2.5, 3, 3.5, 3.75, 4.25, 4.5]

	>>> x.sort(key=lambda x: abs(x-3))
	>>> y.sort(key=lambda x: abs(x-3))
	>>> z.sort(key=lambda x: abs(x-3))
	>>> list(inorder(x, y, z, key=lambda x: abs(x - 3)))
	[3, 2.5, 3.5, 2.25, 3.75, 2, 1.75, 4.25, 1.5, 4.5, 1, 0]

	>>> x = [3, 2, 1, 0]
	>>> y = [4.5, 3.5, 2.5, 1.5]
	>>> z = [4.25, 3.75, 2.25, 1.75]
	>>> list(inorder(x, y, z, reverse = True))
	[4.5, 4.25, 3.75, 3.5, 3, 2.5, 2.25, 2, 1.75, 1.5, 1, 0]
	>>> list(inorder(x, y, z, key = lambda x: -x))
	[4.5, 4.25, 3.75, 3.5, 3, 2.5, 2.25, 2, 1.75, 1.5, 1, 0]

	NOTE:  this function will never reverse the order of elements in
	the input iterables.  If the reverse keyword argument is False (the
	default) then the input sequences must yield elements in increasing
	order, likewise if the keyword argument is True then the input
	sequences must yield elements in decreasing order.  Failure to
	adhere to this yields undefined results, and for performance
	reasons no check is performed to validate the element order in the
	input sequences.
	reverseFkeyc             S   s   | S )Nr   )r   r   r   r   <lambda>%      zinorder.<locals>.<lambda>zinvalid keyword argument '%s'r   Nc             S   s   t | dd dS )Nc             S   s   | d S )Nr   r   )elemr   r   r   r(   4  r)   z+inorder.<locals>.<lambda>.<locals>.<lambda>)r'   )max)seqr   r   r   r(   4  r)   c             S   s   t | dd dS )Nc             S   s   | d S )Nr   r   )r*   r   r   r   r(   6  r)   z+inorder.<locals>.<lambda>.<locals>.<lambda>)r'   )min)r,   r   r   r   r(   6  r)   r      )pop	TypeErrorlistkeys	functoolspartialnextiterStopIterationsix
itervaluesr	   )	iterableskwargsr&   ZkeyfuncZnextvalsr   Znext_Znextvalselectvalues_valr   r   r   inorder   sH    &


r@         ?c       	      c   s  d|   kr|k s&n t d| |f |dkr<t d| n`|dkrytd||   }W n t k
rv   t dY nX |d8 }tj}x|| ||fV  qW tj| |d dd	| }||d 8 }||d
  }tt|dd |dd
  }t|	 rt d| | || | |   }d| }|d| |  }tj
}tj}x@t||| | |  }|| kslt||||   fV  qDW dS )a  
	Yields integers in the range [lo, hi) where 0 <= lo < hi.  Each
	return value is a two-element tuple.  The first element is the
	random integer, the second is the natural logarithm of the
	probability with which that integer will be chosen.

	The CDF for the distribution from which the integers are drawn goes
	as [integer]^{n}, where n > 0.  Specifically, it's

		CDF(x) = (x^{n} - lo^{n}) / (hi^{n} - lo^{n})

	n = 1 yields a uniform distribution;  n > 1 favours larger
	integers, n < 1 favours smaller integers.
	r   z&require 0 <= lo < hi: lo = %d, hi = %dg        z
n <= 0: %gg      ?z[lo, hi) domain errorr   double)ZdtypeN)r   mathlograndomrandintnumpyZaranger
   isinfanyfloorintAssertionError)	lohir   ZlnPZrndbetaalphaZflrindexr   r   r   	randindexX  s8    "rS   )r   )rA   )__doc__r3   rD   rH   rF   r8   Zgluer   
__author__id__version__date__date__r   r   r   r   r   r%   r@   rS   r   r   r   r   <module>   s"   
,;
"Z