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))
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))
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}" )
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}" )
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))