<commit_before>from operator import add
from collections import OrderedDict, defaultdict

from peri import util

#=============================================================================
# A base class for parameter groups (components and priors)
#=============================================================================
class ParameterGroup(object):
    category = 'param'

    def __init__(self, params=None, values=None, ordered=True):
        """
        Set up a parameter group, which is essentially an OrderedDict of param
        -> values. However, it is generalized so that this structure is not
        strictly enforced for all ParameterGroup subclasses.
        """
        gen = OrderedDict if ordered else dict

        if params is not None and values is not None:
            self.param_dict = gen()
            for p,v in zip(params, values):
                self.param_dict[p] = v
        elif params is not None and values is None:
            self.param_dict = params
        else:
            self.param_dict = gen()

    def update(self, params, values):
        """
        Update the a single (param, value) combination, or a list or tuple of
        params and corresponding values for the object.
        """
        self.set_values(params, values)
        return True

    def get_values(self, params):
        """ Get the value of a list or single parameter """
        values = util.delistify([self.param_dict[p] for p in util.listify(params)])
        return values

    def set_values(self, params, values):
        """
        Directly set a single (param, value) combination, or a list or tuple of
        params and corresponding values for the object.
        """
        for p, v in zip(util.listify(params), util.listify(values)):
            self.param_dict[p] = v

    @property
    def params(self):
        return self.param_dict.keys()

    @property
    def values(self):
        return self.param_dict.values()

    def __str__(self):
        return "{} [{}]".format(self.__class__.__name__, self.param_dict)

    def __repr__(self):
        return self.__str__()

    # Functions that begin with block_ will be passed through to the states and
    # other functions so that nice interfaces are present
    # def block_particle_positions(self):
    #   return parameters
    #
    # Also, functions that start with (unknown) will get passed through too

#=============================================================================
# Component class == model components for an image
#=============================================================================
class Component(ParameterGroup):
    category = 'comp'

    def __init__(self, params, values, ordered=True):
        super(Component, self).__init__(params, values, ordered=ordered)

    def initialize(self):
        """ Begin anew and initialize the component """
        pass

    def get_update_tile(self, params, values):
        """
        This method returns a `peri.util.Tile` object defining the region of
        a field that has to be modified by the update of (params, values).

        Parameters:
        -----------
        params : single param, list of params
            A single parameter or list of parameters to be updated

        values : single value, list of values
            The values corresponding to the params

        Returns:
        --------
        tile : `peri.util.Tile`
            A tile corresponding to the image region
        """
        pass

    def get_padding_size(self, tile):
        """
        Get the amount of padding required for this object when calculating
        about a tile `tile`. Padding size is the total size, so twice that
        on each side.

        Parameters:
        -----------
        tile : `peri.util.Tile`
            A tile defining the region of interest
        """
        pass

    def get_field(self):
        """ Return the current field as determined by self.set_tile """
        return self

    def set_tile(self, tile):
        """ Set the currently active tile region for the calculation """
        self.tile = tile

    def set_shape(self, shape, inner):
        """
        Set the overall shape of the calculation area. The total shape of that
        the calculation can possibly occupy, in pixels. The second, inner, is
        the region of interest within the image.
        """
        self.shape = shape
        self.inner = inner
        self.initialize()

    def execute(self, field):
        """ Perform its routine, whatever that may be """
        pass

    def get(self):
        """
        Return the `natural` part of the model. In the case of most elements it
        is the get_field method, for others it is the object itself.
        """
        return self.get_field()

    def __call__(self, field):
        return self.execute(field)

    # TODO make all components serializable via _getinitargs_

class GlobalScalarComponent(Component):
    category = 'scalar'

    def __init__(self, name, value, shape=None):
        self.shape = shape
        self.category = name
        super(GlobalScalarComponent, self).__init__([name], [value], ordered=False)

    def get(self):
        return self.values[0]

    def get_field(self):
        return self.values[0]

    def get_update_tile(self, params, values):
        return util.Tile(self.shape)

#=============================================================================
# Component class == model components for an image
#=============================================================================
class ComponentCollection(Component):
    def __init__(self, comps, field_reduce_func=None):
        """
        Group a number of components into a single coherent object which a
        single interface for each function. Obvious reductions are performed in
        places such as get_update_tile which takes the bounding tile of all
        constituent get_update_tile.  The only reduction which is not
        straight-forward is get_field, but by default it adds all fields. This
        class has the same interface as Component itself.

        Parameters:
        -----------
        comps : list of `peri.comp.Component`
            The components to group together

        field_reduce_func : function (list of ndarrays)
            Reduction function for get_field object of collection
        """
        comps = comps
        pmap = defaultdict(set)
        lmap = defaultdict(list)

        for c in comps:
            for p in c.params:
                pmap[p].update([c])
                lmap[p].extend([c])

        self.comps = comps
        self.pmap = pmap
        self.lmap = lmap

        if not field_reduce_func:
            field_reduce_func = lambda x: reduce(add, x)
        self.field_reduce_func = field_reduce_func

    def initialize(self):
        for c in self.comps:
            c.initialize()

    def split_params(self, params, values=None):
        """
        Split params, values into groups that correspond to the ordering in
        self.comps. For example, given a sphere collection and slab,
<commit_msg>check that component collections actually have components<commit_after>from operator import add
from collections import OrderedDict, defaultdict

from peri import util

#=============================================================================
# A base class for parameter groups (components and priors)
#=============================================================================
class ParameterGroup(object):
    category = 'param'

    def __init__(self, params=None, values=None, ordered=True):
        """
        Set up a parameter group, which is essentially an OrderedDict of param
        -> values. However, it is generalized so that this structure is not
        strictly enforced for all ParameterGroup subclasses.
        """
        gen = OrderedDict if ordered else dict

        if params is not None and values is not None:
            self.param_dict = gen()
            for p,v in zip(params, values):
                self.param_dict[p] = v
        elif params is not None and values is None:
            self.param_dict = params
        else:
            self.param_dict = gen()

    def update(self, params, values):
        """
        Update the a single (param, value) combination, or a list or tuple of
        params and corresponding values for the object.
        """
        self.set_values(params, values)
        return True

    def get_values(self, params):
        """ Get the value of a list or single parameter """
        values = util.delistify([self.param_dict[p] for p in util.listify(params)])
        return values

    def set_values(self, params, values):
        """
        Directly set a single (param, value) combination, or a list or tuple of
        params and corresponding values for the object.
        """
        for p, v in zip(util.listify(params), util.listify(values)):
            self.param_dict[p] = v

    @property
    def params(self):
        return self.param_dict.keys()

    @property
    def values(self):
        return self.param_dict.values()

    def __str__(self):
        return "{} [{}]".format(self.__class__.__name__, self.param_dict)

    def __repr__(self):
        return self.__str__()

    # Functions that begin with block_ will be passed through to the states and
    # other functions so that nice interfaces are present
    # def block_particle_positions(self):
    #   return parameters
    #
    # Also, functions that start with (unknown) will get passed through too

#=============================================================================
# Component class == model components for an image
#=============================================================================
class Component(ParameterGroup):
    category = 'comp'

    def __init__(self, params, values, ordered=True):
        super(Component, self).__init__(params, values, ordered=ordered)

    def initialize(self):
        """ Begin anew and initialize the component """
        pass

    def get_update_tile(self, params, values):
        """
        This method returns a `peri.util.Tile` object defining the region of
        a field that has to be modified by the update of (params, values).

        Parameters:
        -----------
        params : single param, list of params
            A single parameter or list of parameters to be updated

        values : single value, list of values
            The values corresponding to the params

        Returns:
        --------
        tile : `peri.util.Tile`
            A tile corresponding to the image region
        """
        pass

    def get_padding_size(self, tile):
        """
        Get the amount of padding required for this object when calculating
        about a tile `tile`. Padding size is the total size, so twice that
        on each side.

        Parameters:
        -----------
        tile : `peri.util.Tile`
            A tile defining the region of interest
        """
        pass

    def get_field(self):
        """ Return the current field as determined by self.set_tile """
        return self

    def set_tile(self, tile):
        """ Set the currently active tile region for the calculation """
        self.tile = tile

    def set_shape(self, shape, inner):
        """
        Set the overall shape of the calculation area. The total shape of that
        the calculation can possibly occupy, in pixels. The second, inner, is
        the region of interest within the image.
        """
        self.shape = shape
        self.inner = inner
        self.initialize()

    def execute(self, field):
        """ Perform its routine, whatever that may be """
        pass

    def get(self):
        """
        Return the `natural` part of the model. In the case of most elements it
        is the get_field method, for others it is the object itself.
        """
        return self.get_field()

    def __call__(self, field):
        return self.execute(field)

    # TODO make all components serializable via _getinitargs_

class GlobalScalarComponent(Component):
    category = 'scalar'

    def __init__(self, name, value, shape=None):
        self.shape = shape
        self.category = name
        super(GlobalScalarComponent, self).__init__([name], [value], ordered=False)

    def get(self):
        return self.values[0]

    def get_field(self):
        return self.values[0]

    def get_update_tile(self, params, values):
        return util.Tile(self.shape)

#=============================================================================
# Component class == model components for an image
#=============================================================================
class ComponentCollection(Component):
    def __init__(self, comps, field_reduce_func=None):
        """
        Group a number of components into a single coherent object which a
        single interface for each function. Obvious reductions are performed in
        places such as get_update_tile which takes the bounding tile of all
        constituent get_update_tile.  The only reduction which is not
        straight-forward is get_field, but by default it adds all fields. This
        class has the same interface as Component itself.

        Parameters:
        -----------
        comps : list of `peri.comp.Component`
            The components to group together

        field_reduce_func : function (list of ndarrays)
            Reduction function for get_field object of collection
        """
        comps = comps
        pmap = defaultdict(set)
        lmap = defaultdict(list)

        for c in comps:
            if not isinstance(c, (Component, ComponentCollection)):
                raise AttributeError("%r is not a valid Component or ComponentCollection" % c)
            for p in c.params:
                pmap[p].update([c])
                lmap[p].extend([c])

        self.comps = comps
        self.pmap = pmap
        self.lmap = lmap

        if not field_reduce_func:
            field_reduce_func = lambda x: reduce(add, x)
        self.field_reduce_func = field_reduce_func

    def initialize(self):
        for c in self.comps:
            c.initialize()

    def split_params(self, params, values=None):
        """
        Split params, values into groups that correspond to the ordering in
        self.comps. For example, given a sphere collection and slab,

{'fraction_non_alphanumeric': 0.1392859609143015, 'fraction_numerical': 0.00027622401767833714, 'mean_word_length': 2.4147606696533837, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2594189', 'n_tokens_mistral': 3595, 'n_tokens_neox': 3441, 'n_words': 1377}