Example #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))
Example #2
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))
Example #3
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}"
                )
Example #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
        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}"
                )
Example #5
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))