Example #1
0
    def on_start(self):
        msg_count, msg_size = 0, 0

        if self.is_leaf and not self.is_root:
            # If we are a leaf in the DFS Tree we can immediately compute
            # our util and send it to our parent.
            # Note: as a leaf, our separator is the union of our parents and
            # pseudo-parents
            self.logger.info('Leaf %s prepares init message %s -> %s  ',
                             self._variable.name, self._variable.name,
                             self._parent)
            util = self._compute_utils_msg()
            msg = DpopMessage('UTIL', util)
            self.post_msg(self._parent, msg)
            msg_count += 1
            msg_size += msg.size

        elif self.is_leaf:
            # we are both root and leaf : means we are a isolated variable we
            #  can select our own value alone:
            for r in self._constraints:
                self._joined_utils = join_utils(self._joined_utils, r)

            values, current_cost = find_arg_optimal(self._variable,
                                                    self._joined_utils,
                                                    self._mode)
            self.value_selection(values[0], float(current_cost))
            self.logger.info('Value selected at %s : %s - %s', self.name,
                             self.current_value, self.current_cost)
        return {
            'num_msg_out': msg_count,
            'size_msg_out': msg_size,
            'current_value': self.current_value
        }
Example #2
0
    def _compute_best_value(self):
        """
        Compute the best evaluation the variable can have wrt the current
        values of neighbors.

        :return: (list of values the variable that lead to the best
        evaluation, best evaluation)

        """
        reduced_cs = []
        concerned_vars = set()

        for c in self.utilities:
            asgt = filter_assignment_dict(self._neighbors_values, c.dimensions)
            reduced_cs.append(c.slice(asgt))
            concerned_vars.update(c.dimensions)
        var_val, rel_val = find_arg_optimal(
            self.variable, lambda x: functools.reduce(
                operator.add, [f(x) for f in reduced_cs]), self._mode)
        # Add the cost for each variable value if any
        for var in concerned_vars:
            if hasattr(var, 'cost_for_val'):
                if var.name == self.name:
                    rel_val += var.cost_for_val(self.current_value)
                else:
                    rel_val += var.cost_for_val(
                        self._neighbors_values[var.name])

        return var_val, rel_val
    def test_findargmin_several_values(self):
        v1 = Variable('v1', list(range(10)))
        f1 = UnaryFunctionRelation('f1', v1, lambda x: 2 if 3 < x < 6 else 10)

        values, c = algorithms.find_arg_optimal(v1, f1, mode='min')

        self.assertEqual(len(values), 2)
        self.assertIn(4, values)
        self.assertIn(5, values)
        self.assertEqual(c, 2)
    def test_findargmin_fct(self):

        v1 = Variable('v1', list(range(10)))
        f1 = UnaryFunctionRelation('f1', v1, lambda x: abs(x-5))

        m, c = algorithms.find_arg_optimal(v1, f1, mode='min')

        self.assertEqual(len(m), 1)
        self.assertEqual(m[0], 5)
        self.assertEqual(c, 0)
    def test_findargmin(self):
        # u1 is a relation with a single variable :
        x1 = Variable('x1', ['a', 'b', 'c'])
        u1 = pydcop.dcop.relations.NAryMatrixRelation([x1],
                                                      np.array([2, 4, 8],
                                                                     np.int8))

        # take the projection of u1 along x1
        m, c= algorithms.find_arg_optimal(x1, u1, mode='min')

        self.assertEqual(len(m), 1)
        self.assertEqual(m[0], 'a')
        self.assertEqual(c, 2)
Example #6
0
    def _on_value_message(self, variable_name, recv_msg, t):
        self.logger.debug('{}: on value message from {} : "{}"'.format(
            self.name, variable_name, recv_msg))

        value = recv_msg.content
        msg_count, msg_size = 0, 0

        # Value msg contains the optimal assignment for all variables in our
        # separator : sep_vars, sep_values = value
        value_dict = {k.name: v for k, v in zip(*value)}
        self.logger.debug('Slicing relation on %s', value_dict)

        # as the value msg contains values for all variables in our
        # separator, slicing the util on these variables produces a relation
        # with a single dimension, our own variable.
        rel = self._joined_utils.slice(value_dict)

        self.logger.debug('Relation after slicing %s', rel)

        values, current_cost = find_arg_optimal(self._variable, rel,
                                                self._mode)
        self.value_selection(values[0], float(current_cost))
        self.logger.info('on VALUE msg from %s, %s select value %s cost=%s',
                         variable_name, self.name, self.current_value,
                         self.current_cost)

        for c in self._children:
            variables_msg = [self._variable]
            values_msg = [self.current_value]

            # own_separator intersection child_separator union
            # self.current_value
            for v in self._children_separator[c]:
                try:
                    values_msg.append(value_dict[v.name])
                    variables_msg.append(v)
                except KeyError:
                    # we want an intersection, we can ignore the variable if
                    # not in value_dict
                    pass
            msg = DpopMessage('VALUE', (variables_msg, values_msg))
            msg_count += 1
            msg_size += msg.size
            self.post_msg(c, msg)

        return {
            'num_msg_out': msg_count,
            'size_msg_out': msg_size,
            'current_value': self.current_value
        }
Example #7
0
    def _compute_best_value(self):

        reduced_cs = []
        concerned_vars = set()
        for c in self.constraints:
            asgt = filter_assignment_dict(self._neighbors_values, c.dimensions)
            reduced_cs.append(c.slice(asgt))
            concerned_vars.update(c.dimensions)

        var_val, rel_val = find_arg_optimal(
            self.variable, lambda x: functools.reduce(
                operator.add, [f(x) for f in reduced_cs]), self.mode)
        for var in concerned_vars:
            if hasattr(var, 'cost_for_val'):
                if var.name == self.name:
                    rel_val += var.cost_for_val(self.current_value)
                else:
                    rel_val += var.cost_for_val(
                        self._neighbors_values[var.name])

        return var_val, rel_val
Example #8
0
    def _on_util_message(self, variable_name, recv_msg, t):
        self.logger.debug('Util message from %s : %r ', variable_name,
                          recv_msg.content)
        utils = recv_msg.content
        msg_count, msg_size = 0, 0

        # accumulate util messages until we got the UTIL from all our children
        self._joined_utils = join_utils(self._joined_utils, utils)
        try:
            self._waited_children.remove(variable_name)
        except ValueError as e:
            self.logger.error('Unexpected UTIL message from %s on %s : %r ',
                              variable_name, self.name, recv_msg)
            raise e
        # keep a reference of the separator of this children, we need it when
        # computing the value message
        self._children_separator[variable_name] = utils.dimensions

        if len(self._waited_children) == 0:

            if self.is_root:
                # We are the root of the DFS tree and have received all utils
                # we can select our own value and start the VALUE phase.

                # The root obviously has no parent nor pseudo parent, yet it
                # may have unary relations (with it-self!)
                for r in self._constraints:
                    self._joined_utils = join_utils(self._joined_utils, r)

                values, current_cost = find_arg_optimal(
                    self._variable, self._joined_utils, self._mode)
                self.value_selection(values[0], float(current_cost))
                self.logger.info('Value selected : %s - %s',
                                 self.current_value, self.current_cost)

                self.logger.info(
                    'ROOT: On UNTIL message from %s, send value '
                    'msg to childrens %s ', variable_name, self._children)
                for c in self._children:
                    msg = DpopMessage('VALUE',
                                      ([self._variable], [self.current_value]))
                    self.post_msg(c, msg)
                    msg_count += 1
                    msg_size += msg.size
            else:
                # We have received the Utils msg from all our children, we can
                # now compute our own utils relation by joining the accumulated
                # util with the relations with our parent and pseudo_parents.
                util = self._compute_utils_msg()
                msg = DpopMessage('UTIL', util)
                self.logger.info(
                    'On UTIL message from %s, send UTILS msg '
                    'to parent %s ', variable_name, self._children)
                self.post_msg(self._parent, msg)
                msg_count += 1
                msg_size += msg.size

        return {
            'num_msg_out': msg_count,
            'size_msg_out': msg_size,
            'current_value': self.current_value
        }