# Path: revrand/utils/base.py
# def issequence(obj):
#     """
#     Test if an object is an iterable generator, list or tuple.
# 
#     Parameters
#     ----------
#     obj : object
#         object to test
# 
#     Returns
#     -------
#     bool :
#         True if :code:`obj` is a tuple, list or generator only.
# 
#     Examples
#     --------
#     >>> issequence([1, 2])
#     True
#     >>> issequence((1,))
#     True
#     >>> issequence((i for i in range(8)))
#     True
#     >>> issequence(np.array([1, 2, 3]))
#     False
#     """
#     return inspect.isgenerator(obj) or isinstance(obj, (list, tuple))
# 
# Path: revrand/utils/rand.py
# def endless_permutations(N, random_state=None):
#     """
#     Generate an endless sequence of random integers from permutations of the
#     set [0, ..., N).
# 
#     If we call this N times, we will sweep through the entire set without
#     replacement, on the (N+1)th call a new permutation will be created, etc.
# 
#     Parameters
#     ----------
#     N: int
#         the length of the set
#     random_state: int or RandomState, optional
#         random seed
# 
#     Yields
#     ------
#     int:
#         a random int from the set [0, ..., N)
#     """
#     generator = check_random_state(random_state)
#     while True:
#         batch_inds = generator.permutation(N)
#         for b in batch_inds:
#             yield b


from itertools import chain
from scipy.optimize import OptimizeResult
from ..utils import issequence, endless_permutations
import numpy as np
    min_, max_ = bound

    if min_ is None:
        min_ = -float('inf')

    if max_ is None:
        max_ = float('inf')

    return min_, max_


#
# Module Helpers
#

def _len_data(data):

    if not issequence(data):
        return data.shape[0]

    N = len(data[0])
    for d in data[1:]:
        if d.shape[0] != N:
            raise ValueError("Not all data is the same length!")

    return N


def _split_data(data, ind):


# Path: revrand/utils/base.py
# def issequence(obj):
#     """
#     Test if an object is an iterable generator, list or tuple.
# 
#     Parameters
#     ----------
#     obj : object
#         object to test
# 
#     Returns
#     -------
#     bool :
#         True if :code:`obj` is a tuple, list or generator only.
# 
#     Examples
#     --------
#     >>> issequence([1, 2])
#     True
#     >>> issequence((1,))
#     True
#     >>> issequence((i for i in range(8)))
#     True
#     >>> issequence(np.array([1, 2, 3]))
#     False
#     """
#     return inspect.isgenerator(obj) or isinstance(obj, (list, tuple))
# 
# Path: revrand/utils/rand.py
# def endless_permutations(N, random_state=None):
#     """
#     Generate an endless sequence of random integers from permutations of the
#     set [0, ..., N).
# 
#     If we call this N times, we will sweep through the entire set without
#     replacement, on the (N+1)th call a new permutation will be created, etc.
# 
#     Parameters
#     ----------
#     N: int
#         the length of the set
#     random_state: int or RandomState, optional
#         random seed
# 
#     Yields
#     ------
#     int:
#         a random int from the set [0, ..., N)
#     """
#     generator = check_random_state(random_state)
#     while True:
#         batch_inds = generator.permutation(N)
#         for b in batch_inds:
#             yield b


# Path: revrand/optimize/sgd.py
from itertools import chain
from scipy.optimize import OptimizeResult
from ..utils import issequence, endless_permutations
import numpy as np

    min_, max_ = bound

    if min_ is None:
        min_ = -float('inf')

    if max_ is None:
        max_ = float('inf')

    return min_, max_


#
# Module Helpers
#

def _len_data(data):

    if not issequence(data):
        return data.shape[0]

    N = len(data[0])
    for d in data[1:]:
        if d.shape[0] != N:
            raise ValueError("Not all data is the same length!")

    return N


def _split_data(data, ind):


    if not issequence(data):