<commit_before>
import numpy as np

from six.moves import map, range, zip
from collections import namedtuple
from functools import partial
from itertools import tee


class Bunch(dict):
    """
    Container object for datasets: dictionary-like object that exposes
    its keys as attributes.

    Examples
    --------
    >>> b = Bunch(foo=42, bar=10)
    >>> b == {'foo': 42, 'bar': 10}
    True
    >>> b.foo
    42
    >>> b.bar
    10
    >>> b['foo']
    42
    >>> b.baz = 61
    >>> b.baz
    61
    >>> b['baz']
    61
    """
    def __init__(self, **kwargs):
        dict.__init__(self, kwargs)
        self.__dict__ = self


class Bound(namedtuple('Bound', ['lower', 'upper'])):
    """
    Define bounds on a variable for the optimiser. This defaults to all
    real values allowed (i.e. no bounds).

    Parameters
    ----------
    lower : float
        The lower bound.
    upper : float
        The upper bound.

    Attributes
    ----------
    lower : float
        The lower bound.
    upper : float
        The upper bound.

    Examples
    --------
    >>> b = Bound(1e-10, upper=1e-5)
    >>> b
    Bound(lower=1e-10, upper=1e-05)
    >>> b.lower
    1e-10
    >>> b.upper
    1e-05
    >>> isinstance(b, tuple)
    True
    >>> tuple(b)
    (1e-10, 1e-05)
    >>> lower, upper = b
    >>> lower
    1e-10
    >>> upper
    1e-05
    >>> Bound(42, 10)
    Traceback (most recent call last):
        ...
    ValueError: lower bound cannot be greater than upper bound!
    """

    def __new__(cls, lower=None, upper=None):

        if lower is not None and upper is not None:
            if lower > upper:
                raise ValueError('lower bound cannot be greater than upper '
                                 'bound!')

        return super(Bound, cls).__new__(cls, lower, upper)


class Positive(Bound):
    """
    Define a positive only bound for the optimiser. This may induce the
    'log trick' in the optimiser, which will ignore the 'smallest'
    value (but will stay above 0).

    Parameters
    ---------
    lower : float
        The smallest value allowed for the optimiser to evaluate (if
        not using the log trick).

    Examples
    --------
    >>> b = Positive()
    >>> b # doctest: +SKIP
    Positive(lower=1e-14, upper=None)

    Since ``tuple`` (and by extension its descendents) are immutable,
    the lower bound for all instances of ``Positive`` are guaranteed to
    be positive.

    .. admonition::

       Actually this is not totally true. Something like
       ``b._replace(lower=-42)`` would actually thwart this. Should
       delete this method from ``namedtuple`` when inheriting.

    >>> c = Positive(lower=-10)
    Traceback (most recent call last):
        ...
    ValueError: lower bound must be positive!
    """
    def __new__(cls, lower=1e-14, *args):

        if lower <= 0:
            raise ValueError('lower bound must be positive!')

        return super(Positive, cls).__new__(cls, lower, None)
        # return Bound.__new__(cls, lower, None)


def checktypes(sequence, checktype):
    """ Check if all types are the same in a sequence.

        Arguments<commit_msg>Make Bounds objects pickleable<commit_after>
import numpy as np

from six.moves import map, range, zip
from collections import namedtuple
from functools import partial
from itertools import tee


class Bunch(dict):
    """
    Container object for datasets: dictionary-like object that exposes
    its keys as attributes.

    Examples
    --------
    >>> b = Bunch(foo=42, bar=10)
    >>> b == {'foo': 42, 'bar': 10}
    True
    >>> b.foo
    42
    >>> b.bar
    10
    >>> b['foo']
    42
    >>> b.baz = 61
    >>> b.baz
    61
    >>> b['baz']
    61
    """
    def __init__(self, **kwargs):
        dict.__init__(self, kwargs)
        self.__dict__ = self


class Bound(namedtuple('Bound', ['lower', 'upper'])):
    """
    Define bounds on a variable for the optimiser. This defaults to all
    real values allowed (i.e. no bounds).

    Parameters
    ----------
    lower : float
        The lower bound.
    upper : float
        The upper bound.

    Attributes
    ----------
    lower : float
        The lower bound.
    upper : float
        The upper bound.

    Examples
    --------
    >>> b = Bound(1e-10, upper=1e-5)
    >>> b
    Bound(lower=1e-10, upper=1e-05)
    >>> b.lower
    1e-10
    >>> b.upper
    1e-05
    >>> isinstance(b, tuple)
    True
    >>> tuple(b)
    (1e-10, 1e-05)
    >>> lower, upper = b
    >>> lower
    1e-10
    >>> upper
    1e-05
    >>> Bound(42, 10)
    Traceback (most recent call last):
        ...
    ValueError: lower bound cannot be greater than upper bound!
    """

    def __new__(cls, lower=None, upper=None):

        if lower is not None and upper is not None:
            if lower > upper:
                raise ValueError('lower bound cannot be greater than upper '
                                 'bound!')

        return super(Bound, cls).__new__(cls, lower, upper)


class Positive(Bound):
    """
    Define a positive only bound for the optimiser. This may induce the
    'log trick' in the optimiser, which will ignore the 'smallest'
    value (but will stay above 0).

    Parameters
    ---------
    lower : float
        The smallest value allowed for the optimiser to evaluate (if
        not using the log trick).

    Examples
    --------
    >>> b = Positive()
    >>> b # doctest: +SKIP
    Positive(lower=1e-14, upper=None)

    Since ``tuple`` (and by extension its descendents) are immutable,
    the lower bound for all instances of ``Positive`` are guaranteed to
    be positive.

    .. admonition::

       Actually this is not totally true. Something like
       ``b._replace(lower=-42)`` would actually thwart this. Should
       delete this method from ``namedtuple`` when inheriting.

    >>> c = Positive(lower=-10)
    Traceback (most recent call last):
        ...
    ValueError: lower bound must be positive!
    """
    def __new__(cls, lower=1e-14, *args):

        if lower <= 0:
            raise ValueError('lower bound must be positive!')

        return super(Positive, cls).__new__(cls, lower, None)
        # return Bound.__new__(cls, lower, None)

    def __getnewargs__(self):
        """Required for pickling!"""
        return (self.lower, )


def checktypes(sequence, checktype):
    """ Check if all types are the same in a sequence.

        Arguments
{'fraction_non_alphanumeric': 0.12533043072617012, 'fraction_numerical': 0.02021458560099518, 'mean_word_length': 2.0282485875706215, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 131, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6162082', 'n_tokens_mistral': 1984, 'n_tokens_neox': 1848, 'n_words': 673}