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