# Path: pydigree/common.py
# def product(iter):
#     """
#     Reduces an iterable by multiplication. Analogous to sum, but with
#     multiplication instead of addition.
# 
#     :returns: overall product
#     :rtype: numeric
#     """
#     # This should really be a python builtiin
#     if not iter:
#         # sum([]) returns 0, so this will return 1
#         return 1
#     return reduce(multiply, iter)
# 
# def cumsum(iter):
#     """
#     Cumulative sum:
#     >>> pydigree.cumsum([0,1,2,3,4])
#     [0, 1, 3, 6, 10]
#     
# 
#     :param iter: the iterable to be cumsum'ed
#     
#     Returns: cumulative sums
#     :rtype: integer
#     """
#     if not iter:
#         return []
#     value = 0
#     g = [None] * len(iter)
#     for idx, x in enumerate(iter):
#         value += x
#         g[idx] = value
#     return g
# 
# def flatten(x):
#     """
#     Recursively flattens lists.
#     """
#     try:
#         it = iter(x)
#     except TypeError:
#         yield x
#     else:
#         for i in it:
#             for j in flatten(i):
#                 yield j
# 
# def invert_dict(d):
#     """
#     Makes the keys the values and the values the keys
#     
#     .. warning:: 
#         No guarantee of dictionary structure if mappings are not unique
#     
#     :param d: dictionary to be inverted
# 
#     :rtype: dict
#     """
#     return dict((y, x) for x, y in d.items())
# 
# def merge_dicts(*args):
#     ''' Merges two dictionaries into one bigger one '''
#     odict = {}
#     for d in args:
#         odict.update(d)
#     return odict
# 
# Path: pydigree/common.py
# def count(val, iterable):
#     """ 
#     Counts how many times a value (val) occurs in an iterable, excluding `None`
# 
#     
#     :param val: The value to be counted
#     :param iterable: values to be counted over
#     :type iterable: iterable  
# 
#     :return: the count of values
#     :rtype: int
#     """
#     return sum(1 for x in (y for y in iterable if y is not None) if val == x)
# 
# def grouper(iterable, n, fillvalue=None):
#     """
#     Collect data into fixed-length chunks or blocks
#     :param iterable: values to evaluate
#     :param n: size of the groups
#     :param fillvalue: Value to pad the last group with if len(iterable) % n != 0
#     
#     :type n: integer
#     :rtype: a generator
#     """
#     
#     # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
#     args = [iter(iterable)] * n
#     return zip_longest(fillvalue=fillvalue, *args)
# 
# def log_base_change(value, old, new):
#     ''' 
#     Changes the base of the logarithm used on `value` from `old` to `new`
# 
#     Arguments: 
#     value: the value to be converted
#     old: old base (numeric)
#     new: new base (numeric)
# 
#     :returns: log of value in new base  
#     :rtype: float
#     '''
#     return value / log(old, new) 
# 
# def mode(seq):
#     """ 
#     Returns the most common value in a sequence 
# 
#     :param seq: sequence of values to evaluate
#     """
# 
#     if not len(seq):
#         raise IndexError('Sequence is empty')
#     tab = table(seq)
#     return sorted(tab.items(), key=lambda x: x[1], reverse=True)[0][0]
# 
# Path: pydigree/common.py
# def count(val, iterable):
# def table(seq):
# def mode(seq):
# def random_choice(iterable):
# def flatten(x):
# def grouper(iterable, n, fillvalue=None):
# def invert_dict(d):
# def merge_dicts(*args):
# def log_base_change(value, old, new):
# def product(iter):
# def cumsum(iter):


from nose.tools import assert_raises
from pydigree.common import product, cumsum, flatten, invert_dict, merge_dicts
from pydigree.common import count, grouper, log_base_change, mode
from pydigree.common import runs, runs_gte, interleave, is_sorted
from pydigree.cydigree.cyfuncs import runs_gte_uint8
from math import log, log10, e
import numpy as np
    dregion = (10,20)
    i = [1 if dregion[0] <= x <= dregion[1] else 0 for x in range(100)] 
    assert runs(i, lambda x: x>0) == [dregion]
    assert runs_gte(i, 1) == [dregion]
    assert runs_gte(i, 1, 20) == []
    assert runs_gte([], 1) == []
    assert runs([], lambda x: True) == []
    

    i = [0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]
    ir = [(4,8), (14, 16)]
    assert runs(i, lambda x: x > 0) == ir
    assert runs_gte(i, 1) == ir
    assert runs_gte_uint8(np.array(i, dtype=np.uint8), 1) == ir

    i = [0] * 100
    assert runs(i, lambda x: x > 0) == []
    assert runs_gte(i, 1) == []
    assert runs_gte_uint8(np.uint8(i),1) == []

    i = [1] * 100
    ir = [(0,99)]
    assert runs(i, lambda x: x>0) == ir
    assert runs_gte(i, 1) == ir
    assert runs_gte_uint8(np.array(i, dtype=np.uint8), 1) == ir

def test_flatten():
    assert list(flatten([1,2,2,3,4,4,5])) == [1,2,2,3,4,4,5]
    assert list(flatten([(1,2),2,3,(4,4,5)])) == [1,2,2,3,4,4,5]
    assert list(flatten([(1,(2,(2,(3,4)))),4,5])) == [1,2,2,3,4,4,5]

# Path: pydigree/common.py
# def product(iter):
#     """
#     Reduces an iterable by multiplication. Analogous to sum, but with
#     multiplication instead of addition.
# 
#     :returns: overall product
#     :rtype: numeric
#     """
#     # This should really be a python builtiin
#     if not iter:
#         # sum([]) returns 0, so this will return 1
#         return 1
#     return reduce(multiply, iter)
# 
# def cumsum(iter):
#     """
#     Cumulative sum:
#     >>> pydigree.cumsum([0,1,2,3,4])
#     [0, 1, 3, 6, 10]
#     
# 
#     :param iter: the iterable to be cumsum'ed
#     
#     Returns: cumulative sums
#     :rtype: integer
#     """
#     if not iter:
#         return []
#     value = 0
#     g = [None] * len(iter)
#     for idx, x in enumerate(iter):
#         value += x
#         g[idx] = value
#     return g
# 
# def flatten(x):
#     """
#     Recursively flattens lists.
#     """
#     try:
#         it = iter(x)
#     except TypeError:
#         yield x
#     else:
#         for i in it:
#             for j in flatten(i):
#                 yield j
# 
# def invert_dict(d):
#     """
#     Makes the keys the values and the values the keys
#     
#     .. warning:: 
#         No guarantee of dictionary structure if mappings are not unique
#     
#     :param d: dictionary to be inverted
# 
#     :rtype: dict
#     """
#     return dict((y, x) for x, y in d.items())
# 
# def merge_dicts(*args):
#     ''' Merges two dictionaries into one bigger one '''
#     odict = {}
#     for d in args:
#         odict.update(d)
#     return odict
# 
# Path: pydigree/common.py
# def count(val, iterable):
#     """ 
#     Counts how many times a value (val) occurs in an iterable, excluding `None`
# 
#     
#     :param val: The value to be counted
#     :param iterable: values to be counted over
#     :type iterable: iterable  
# 
#     :return: the count of values
#     :rtype: int
#     """
#     return sum(1 for x in (y for y in iterable if y is not None) if val == x)
# 
# def grouper(iterable, n, fillvalue=None):
#     """
#     Collect data into fixed-length chunks or blocks
#     :param iterable: values to evaluate
#     :param n: size of the groups
#     :param fillvalue: Value to pad the last group with if len(iterable) % n != 0
#     
#     :type n: integer
#     :rtype: a generator
#     """
#     
#     # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
#     args = [iter(iterable)] * n
#     return zip_longest(fillvalue=fillvalue, *args)
# 
# def log_base_change(value, old, new):
#     ''' 
#     Changes the base of the logarithm used on `value` from `old` to `new`
# 
#     Arguments: 
#     value: the value to be converted
#     old: old base (numeric)
#     new: new base (numeric)
# 
#     :returns: log of value in new base  
#     :rtype: float
#     '''
#     return value / log(old, new) 
# 
# def mode(seq):
#     """ 
#     Returns the most common value in a sequence 
# 
#     :param seq: sequence of values to evaluate
#     """
# 
#     if not len(seq):
#         raise IndexError('Sequence is empty')
#     tab = table(seq)
#     return sorted(tab.items(), key=lambda x: x[1], reverse=True)[0][0]
# 
# Path: pydigree/common.py
# def count(val, iterable):
# def table(seq):
# def mode(seq):
# def random_choice(iterable):
# def flatten(x):
# def grouper(iterable, n, fillvalue=None):
# def invert_dict(d):
# def merge_dicts(*args):
# def log_base_change(value, old, new):
# def product(iter):
# def cumsum(iter):


# Path: tests/test_common.py
from nose.tools import assert_raises
from pydigree.common import product, cumsum, flatten, invert_dict, merge_dicts
from pydigree.common import count, grouper, log_base_change, mode
from pydigree.common import runs, runs_gte, interleave, is_sorted
from pydigree.cydigree.cyfuncs import runs_gte_uint8
from math import log, log10, e
import numpy as np

    dregion = (10,20)
    i = [1 if dregion[0] <= x <= dregion[1] else 0 for x in range(100)] 
    assert runs(i, lambda x: x>0) == [dregion]
    assert runs_gte(i, 1) == [dregion]
    assert runs_gte(i, 1, 20) == []
    assert runs_gte([], 1) == []
    assert runs([], lambda x: True) == []
    

    i = [0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1]
    ir = [(4,8), (14, 16)]
    assert runs(i, lambda x: x > 0) == ir
    assert runs_gte(i, 1) == ir
    assert runs_gte_uint8(np.array(i, dtype=np.uint8), 1) == ir

    i = [0] * 100
    assert runs(i, lambda x: x > 0) == []
    assert runs_gte(i, 1) == []
    assert runs_gte_uint8(np.uint8(i),1) == []

    i = [1] * 100
    ir = [(0,99)]
    assert runs(i, lambda x: x>0) == ir
    assert runs_gte(i, 1) == ir
    assert runs_gte_uint8(np.array(i, dtype=np.uint8), 1) == ir

def test_flatten():
    assert list(flatten([1,2,2,3,4,4,5])) == [1,2,2,3,4,4,5]
    assert list(flatten([(1,2),2,3,(4,4,5)])) == [1,2,2,3,4,4,5]
    assert list(flatten([(1,(2,(2,(3,4)))),4,5])) == [1,2,2,3,4,4,5]

    assert list(flatten([])) == []