Beispiel #1
0
def test_find_optimal_single_unary_constraint():
    v1 = Variable('a', [0, 1, 2, 3, 4])
    c1 = UnaryFunctionRelation('c1', v1, lambda x: abs(x - 2))

    vals, cost = find_optimal(v1, {}, [c1], "min")
    assert vals == [2]
    assert cost == 0
Beispiel #2
0
    def on_new_cycle(self, messages, cycle_id) -> Optional[List]:

        assignment = {self.variable.name: self.current_value}
        for sender, (message, t) in messages.items():
            assignment[sender] = message.value

        self.logger.debug(
            f"Full neighbors assignment for cycle {self.cycle_count} : {assignment}"
        )

        current_cost = assignment_cost(assignment, self.constraints)
        # Compute best local cost, based on current neighbors values:
        arg_min, min_cost = find_optimal(self.variable, assignment,
                                         self.constraints, self.mode)

        self.logger.debug(
            f"Evaluate cycle {self.cycle_count}: current cost {current_cost} - best cost {min_cost}"
        )

        if current_cost - min_cost > 0 and 0.5 > random.random():
            self.value_selection(arg_min[0])
            self.logger.debug(
                f"Select new value {arg_min} for better cost {min_cost} ")
        else:
            self.logger.debug(f"Do not change value {self.current_value}")

        self.post_to_all_neighbors(DsaMessage(self.current_value))
Beispiel #3
0
def test_find_optimal_2_unary_constraints():
    variable = Variable('a', [0, 1, 2, 3, 4])
    c1 = UnaryFunctionRelation('c1', variable, lambda x: abs(x - 3))
    c2 = UnaryFunctionRelation('c1', variable, lambda x: abs(x - 1) * 2)

    val, sum_costs = find_optimal(variable, {}, [c1, c2], "min")
    assert val == [1]
    assert sum_costs == 2
Beispiel #4
0
def test_find_optimal_one_binary_constraint():
    v1 = Variable('v1', [0, 1, 2, 3, 4])
    v2 = Variable('v2', [0, 1, 2, 3, 4])

    @AsNAryFunctionRelation(v1, v2)
    def c1(v1_, v2_):
        return abs(v1_ - v2_)

    val, sum_costs = find_optimal(v1, {"v2": 1}, [c1], "min")
    assert val == [1]
    assert sum_costs == 0
Beispiel #5
0
def test_find_optimal_several_best_values():
    #  With this constraints definition, the value 0 and 3 returns the same
    #  optimal cost of 0, find_best_values must return both values.

    v1 = Variable('v1', [0, 1, 2, 3, 4])
    v2 = Variable('v2', [0, 1, 2, 3, 4])

    @AsNAryFunctionRelation(v1, v2)
    def c1(v1_, v2_):
        return abs((v2_ - v1_) % 3)

    val, sum_costs = find_optimal(v1, {'v2': 3}, [c1], "min")
    assert val == [0, 3]
    assert sum_costs == 0
Beispiel #6
0
    def evaluate_cycle(self):

        if len(self.current_cycle) == len(self.neighbors):

            self.logger.debug(
                "Full neighbors assignment for cycle %s : %s ",
                self.cycle_count,
                self.current_cycle,
            )

            self.current_cycle[self.variable.name] = self.current_value
            assignment = self.current_cycle.copy()
            args_best, best_cost = find_optimal(self.variable, assignment,
                                                self.constraints, self.mode)
            current_cost = assignment_cost(self.current_cycle,
                                           self.constraints)
            delta = abs(current_cost - best_cost)
            self.logger.debug(
                f"Current cost {current_cost}, best cost {best_cost} "
                f"delta {delta}")

            if self.variant == "A":
                self.variant_a(delta, best_cost, args_best)
            elif self.variant == "B":
                self.variant_b(delta, best_cost, args_best)
            elif self.variant == "C":
                self.variant_c(delta, best_cost, args_best)

            self.new_cycle()
            self.current_cycle, self.next_cycle = self.next_cycle, {}

            # Check if this was the last cycle
            if self.stop_cycle and self.cycle_count >= self.stop_cycle:
                self.finished()
                self.stop()
                return

            self.post_to_all_neighbors(DsaMessage(self.current_value))
Beispiel #7
0
    def value_phase(self, sender, value):

        if sender not in self._ancestors:
            raise ComputationException(
                f"Received at {self.name} value from {sender}, "
                f"which is not an ancestor: {self._ancestors}")

        # Init phase: select a value and send down the tree
        # as value messages are sent by parent and pseudo-parents,
        # they might arrive in several cycles and must be accumulated before we
        # can select our value.
        self._parents_values[sender] = value

        if len(self._parents_values) == len(self._ancestors):
            # Select our own value greedily.
            # For this, we only take into account the constraints with our ancestrors
            ancestors_constraints = []
            for c in self._constraints:
                for v in c.scope_names:
                    if v in self._ancestors:
                        ancestors_constraints.append(c)
                        break
            values, cost = find_optimal(self.variable, self._parents_values,
                                        ancestors_constraints, self._mode)
            self.value_selection(values[0])
            self._upper_bound = cost

            # Send our value to our children.
            if not self.is_leaf:
                for child in self._descendants:
                    self.post_msg(child, ValueMessage(self.current_value))
            else:
                # At leafs, we initiate cost message (sent up) as we don't have to wait
                # for costs from our children.
                for ancestor in self._ancestors:
                    self.post_msg(ancestor, CostMessage(cost))