def test_compute_factor_cost_at_start():
    d = Domain("d", "", ["R", "G"])
    v1 = Variable("v1", d)
    v2 = Variable("v2", d)
    c1 = constraint_from_str("c1", "10 if v1 == v2 else 0", [v1, v2])

    obtained = factor_costs_for_var(c1, v1, {}, "min")
    assert obtained["R"] == 0
    assert obtained["G"] == 0
    assert len(obtained) == 2
Exemplo n.º 2
0
    def _on_maxsum_msg(self, var_name, msg, t):
        """
        Handling messages from variables nodes.

        :param var_name: name of the variable node that sent this messages
        :param msg: the cost sent by the variable var_name
        a d -> cost table, where
          * d is a value from the domain of var_name
          * cost is the sum of the costs received from all other factors
            except f for this value d for the domain.
        """
        self._costs[var_name] = msg.costs

        # Wait until we received costs from all our variables before sending
        # our own costs (if works without doing that, but results are worse)
        if len(self._costs) == len(self.factor.dimensions):
            for v in self.variables:
                if v.name != var_name:
                    costs_v = maxsum.factor_costs_for_var(
                        self.factor, v, self._costs, self.mode)

                    prev_costs, count = self._prev_messages[v.name]

                    # Apply damping to computed costs:
                    if self.damping_nodes in ["factors", "both"]:
                        costs_v = maxsum.apply_damping(costs_v, prev_costs,
                                                       self.damping)

                    # Check if there was enough change to send the message
                    if not maxsum.approx_match(costs_v, prev_costs,
                                               self.stability_coef):
                        # Not same as previous : send
                        self.logger.debug(
                            f"Sending first time from factor {self.name} -> {v.name} : {costs_v}"
                        )
                        self.post_msg(v.name, maxsum.MaxSumMessage(costs_v))
                        self._prev_messages[v.name] = costs_v, 1

                    elif count < maxsum.SAME_COUNT:
                        # Same as previous, but not yet sent SAME_COUNT times: send
                        self.logger.debug(
                            f"Sending {count} time from variable {self.name} -> {v.name} : {costs_v}"
                        )
                        self.post_msg(v.name, maxsum.MaxSumMessage(costs_v))
                        self._prev_messages[v.name] = costs_v, count + 1
                    else:
                        # Same and already sent SAME_COUNT times: no-send
                        self.logger.debug(
                            f"Not sending (similar) from {self.name} -> {v.name} : {costs_v}"
                        )

        else:
            self.logger.debug(
                f" Still waiting for costs from all  the variables {self._costs.keys()}"
            )
Exemplo n.º 3
0
 def on_start(self):
     # Only unary factors (leaf in the graph) needs to send their costs at
     # init.Each leaf factor sends his costs to its only variable.
     # When possible it is better to use a variable with integrated costs
     # instead of a variable with an unary relation representing costs.
     if len(self.variables) == 1:
         for v in self.variables:
             costs_v = maxsum.factor_costs_for_var(self.factor, v,
                                                   self._costs, self.mode)
             self.post_msg(v.name, maxsum.MaxSumMessage(costs_v))
             self.logger.info(
                 f"Sending init messages from factor {self.name} -> {v.name} : {costs_v}"
             )
Exemplo n.º 4
0
 def on_pause(self, paused: bool):
     # When resuming a computation, send messages as for start
     if paused:
         return
     if len(self.variables) == 1 and self.start_messages in [
             "leafs", "leafs_vars"
     ]:
         for v in self.variables:
             costs_v = maxsum.factor_costs_for_var(self.factor, v,
                                                   self._costs, self.mode)
             self.post_msg(v.name, maxsum.MaxSumMessage(costs_v))
             self.logger.info(
                 f"Sending init messages from factor {self.name} -> {v.name} : {costs_v}"
             )
     elif self.start_messages == "all":
         for v in self.variables:
             costs_v = maxsum.factor_costs_for_var(self.factor, v,
                                                   self._costs, self.mode)
             self.post_msg(v.name, maxsum.MaxSumMessage(costs_v))
             self.logger.info(
                 f"Sending init messages from factor {self.name} -> {v.name} : {costs_v}"
             )
Exemplo n.º 5
0
def test_cost_for_1var():
    domain = list(range(10))
    x1 = Variable("x1", domain)

    @AsNAryFunctionRelation(x1)
    def cost(x1_):
        return x1_ * 2

    comp_def = MagicMock()
    comp_def.algo.algo = "amaxsum"
    comp_def.algo.mode = "min"
    comp_def.node.factor = cost
    f = MaxSumFactorComputation(comp_def=comp_def)

    costs = factor_costs_for_var(cost, x1, f._costs, f.mode)
    # costs = f._costs_for_var(x1)

    # in the max-sum algorithm, for an unary factor the costs is simply
    # the result of the factor function
    assert costs[0] == 0
    assert costs[5] == 10
Exemplo n.º 6
0
    def _on_maxsum_msg(self, var_name, msg, t):
        """
        Handling messages from variables nodes.

        :param var_name: name of the variable node that sent this messages
        :param msg: the cost sent by the variable var_name
        a d -> cost table, where
          * d is a value from the domain of var_name
          * cost is the sum of the costs received from all other factors
            except f for this value d for the domain.
        """
        self._costs[var_name] = msg.costs

        # Wait until we received costs from all our variables before sending
        # our own costs
        if len(self._costs) == len(self.factor.dimensions):
            for v in self.variables:
                if v.name != var_name:
                    costs_v = maxsum.factor_costs_for_var(
                        self.factor, v, self._costs, self.mode)
                    same, same_count = self._match_previous(v.name, costs_v)
                    if not same or same_count < SAME_COUNT:
                        self.logger.debug(
                            f"Sending from factor {self.name} -> {v.name} : {costs_v}"
                        )
                        self.post_msg(v.name, maxsum.MaxSumMessage(costs_v))
                        self._prev_messages[v.name] = costs_v, same_count + 1
                    else:
                        self.logger.debug(
                            f"Not sending (same) from factor {self.name} -> {v.name} : {costs_v}"
                        )

        else:
            self.logger.debug(
                f" Still waiting for costs from all  the variables {self._costs.keys()}"
            )