Exemple #1
0
    def on_pause(self, paused: bool):
        # When resuming a computation, send messages as for start
        if paused:
            return

        # test flush cost table when resuming
        self._costs.clear()
        self._prev_messages.clear()
        if len(self._factors) == 1 and self.start_messages == "leafs":

            # Only send costs if we are a leaf:
            single_factor = self._factors[0]
            costs_f = maxsum.costs_for_factor(self.variable, single_factor,
                                              self._factors, self._costs)
            self.logger.info(
                f"Sending resume msg from leaf variable {self.name} to single factor {single_factor} : {costs_f}"
            )
            self.post_msg(single_factor, maxsum.MaxSumMessage(costs_f))

        elif self.start_messages in ["leafs_vars", "all"]:
            self.logger.warning(
                f"Resuming computation {self.name}, send costs ")
            # in "leafs_vars" mode, send our costs to all the factors we depends on.
            for f in self._factors:
                costs_f = maxsum.costs_for_factor(self.variable, f,
                                                  self._factors, self._costs)
                self.logger.info(
                    f"Sending resume msg from variable {self.name} to factor {f} : {costs_f}"
                )
                self.post_msg(f, maxsum.MaxSumMessage(costs_f))
Exemple #2
0
 def on_pause(self, paused: bool):
     # When resuming a computation, send messages as for start
     if paused:
         return
     # flushing cost table when resuming
     self._costs.clear()
     self._prev_messages.clear()
     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 resume 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 resume messages from factor {self.name} -> {v.name} : {costs_v}"
             )
Exemple #3
0
    def on_start(self) -> None:
        """
        Startup handler for MaxSum variable computations.

        At startup, a variable select an initial value and send its cost to the factors
        it depends on.
        """

        # select our initial value
        if self.variable.initial_value is not None:
            self.value_selection(self.variable.initial_value, None)
        else:
            self.value_selection(
                *maxsum.select_value(self.variable, self._costs, self.mode))
        self.logger.info(f"Initial value selected {self.current_value}")

        if len(self._factors) == 1 and self.start_messages == "leafs":
            # Only send costs if we are a leaf:
            single_factor = self._factors[0]
            costs_f = maxsum.costs_for_factor(self.variable, single_factor,
                                              self._factors, self._costs)
            self.logger.info(
                f"Sending init msg from leaf variable {self.name} to single factor {single_factor} : {costs_f}"
            )
            self.post_msg(single_factor, maxsum.MaxSumMessage(costs_f))

        elif self.start_messages in ["leafs_vars", "all"]:
            # in "leafs_vars" mode, send our costs to all the factors we depends on.
            for f in self._factors:
                costs_f = maxsum.costs_for_factor(self.variable, f,
                                                  self._factors, self._costs)
                self.logger.info(
                    f"Sending init msg from variable {self.name} to factor {f} : {costs_f}"
                )
                self.post_msg(f, maxsum.MaxSumMessage(costs_f))
Exemple #4
0
    def _on_maxsum_msg(self, factor_name, msg, t):
        """
        Handling cost message from a neighbor factor.

        Parameters
        ----------
        factor_name: str
            the name of that factor that sent us this message.
        msg: MaxSumMessage
            a message whose content is a map { d -> cost } where:
            * d is a value from the domain of this variable
            * cost if the minimum cost of the factor when taking value d
        """
        self._costs[factor_name] = msg.costs

        # select our value
        self.value_selection(
            *maxsum.select_value(self.variable, self._costs, self.mode))

        # Compute and send our own costs to all other factors.
        # If our variable has his own costs, we must sent them back even
        # to the factor which sent us this message, as integrated costs are
        # similar to an unary factor and with an unary factor we would have
        # sent these costs back to the original sender:
        # factor -> variable -> unary_cost_factor -> variable -> factor
        for f_name in self._factors:
            if f_name == factor_name:
                continue
            costs_f = maxsum.costs_for_factor(self.variable, f_name,
                                              self._factors, self._costs)
            prev_costs, count = self._prev_messages[f_name]

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

            # Check if there was enough change to send the message
            if not maxsum.approx_match(costs_f, prev_costs,
                                       self.stability_coef):
                # Not same as previous : send
                self.logger.debug(
                    f"Sending first time from variable {self.name} -> {f_name} : {costs_f}"
                )
                self.post_msg(f_name, maxsum.MaxSumMessage(costs_f))
                self._prev_messages[f_name] = costs_f, 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} -> {f_name} : {costs_f}"
                )
                self.post_msg(f_name, maxsum.MaxSumMessage(costs_f))
                self._prev_messages[f_name] = costs_f, count + 1
            else:
                # Same and already sent SAME_COUNT times: no-send
                self.logger.debug(
                    f"Not sending (similar) from {self.name} -> {f_name} : {costs_f}"
                )
Exemple #5
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()}"
            )
Exemple #6
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}"
             )
Exemple #7
0
    def _on_maxsum_msg(self, factor_name, msg, t):
        """
        Handling cost message from a neighbor factor.

        Parameters
        ----------
        factor_name: str
            the name of that factor that sent us this message.
        msg: MaxSumMessage
            a message whose content is a map { d -> cost } where:
            * d is a value from the domain of this variable
            * cost if the minimum cost of the factor when taking value d
        """
        self._costs[factor_name] = msg.costs

        # select our value
        self.value_selection(
            *maxsum.select_value(self.variable, self._costs, self.mode))

        # Compute and send our own costs to all other factors.
        # If our variable has his own costs, we must sent them back even
        # to the factor which sent us this message, as integrated costs are
        # similar to an unary factor and with an unary factor we would have
        # sent these costs back to the original sender:
        # factor -> variable -> unary_cost_factor -> variable -> factor
        fs = self._factors.copy()
        fs.remove(factor_name)

        for f_name in fs:
            costs_f = maxsum.costs_for_factor(self.variable, f_name,
                                              self._factors, self._costs)

            same, same_count = self._match_previous(f_name, costs_f)
            if not same or same_count < SAME_COUNT:
                self.logger.debug(
                    f"Sending from variable {self.name} -> {f_name} : {costs_f}"
                )
                self.post_msg(f_name, maxsum.MaxSumMessage(costs_f))
                self._prev_messages[f_name] = costs_f, same_count + 1

            else:
                self.logger.debug(
                    f"Not sending (similar) from {self.name} -> {f_name} : {costs_f}"
                )
Exemple #8
0
    def on_start(self) -> None:
        """
        Startup handler for MaxSum variable computations.

        At startup, a variable select an initial value and send its cost to the factors
        it depends on.
        """

        # select our initial value
        if self.variable.initial_value:
            self.value_selection(self.variable.initial_value, None)
        else:
            self.value_selection(
                *maxsum.select_value(self.variable, self._costs, self.mode))
        self.logger.info(f"Initial value selected {self.current_value}")

        # Send our costs to the factors we depends on.
        for f in self._factors:
            costs_f = maxsum.costs_for_factor(self.variable, f, self._factors,
                                              self._costs)
            self.logger.info(
                f"Sending init msg from variable {self.name} to factor {f} : {costs_f}"
            )
            self.post_msg(f, maxsum.MaxSumMessage(costs_f))
Exemple #9
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()}"
            )