def _update_messages(self, damp_ratio): temp_messages = dict() factor_order = copy(self.model.factors) random.shuffle(factor_order) for fac in factor_order: for var in fac.variables: next_message = (product_over_( fac, *[ msg for msg in self._message_to_(fac, except_objs=[var]) ]).marginalize_except_( [var], inplace=False).normalize(inplace=False)) self.messages[( fac, var)] = (damp_ratio * self.messages[(fac, var)] + (1 - damp_ratio) * next_message) variable_order = copy(self.model.variables) random.shuffle(variable_order) for var in variable_order: for fac in self.factors_adj_to_[var]: messages_to_var_except_fac = self._message_to_( var, except_objs=[fac]) if messages_to_var_except_fac: next_message = product_over_( *messages_to_var_except_fac).normalize(inplace=False) self.messages[( var, fac)] = (damp_ratio * self.messages[(var, fac)] + (1 - damp_ratio) * next_message)
def _is_converged(self, converge_thr, messages, new_messages): for var in self.model.variables: blf = (product_over_( *[messages[(fac, var)] for fac in self.factors_adj_to_[var]]).normalize( inplace=False)) new_blf = (product_over_(*[ new_messages[(fac, var)] for fac in self.factors_adj_to_[var] ]).normalize(inplace=False)) if np.sum(np.abs(blf.values - new_blf.values)) > converge_thr: return False return True
def get_marginal_factor(self, elimination_order_method="random", **kwargs): if elimination_order_method == "random": elimination_order = copy(self.model.variables) random.shuffle(elimination_order) elif elimination_order_method == "not_random": elimination_order = copy(self.model.variables) elif elimination_order_method == "given": elimination_order = kwargs["elimination_order"] if "exception_variables" in kwargs: exception_variables = kwargs["exception_variables"] else: exception_variables = [] eliminated_model = self.model.copy() max_ibound = 0 for var in elimination_order: if var not in exception_variables: max_ibound = max( max_ibound, get_bucket_size([ fac for fac in eliminated_model.get_adj_factors(var) ]), ) eliminated_model.contract_variable(var) final_factor = product_over_(*eliminated_model.factors) if "exception_variables" in kwargs: final_factor.transpose_by_(exception_variables) return final_factor
def _backward_pass_for_(self, variable, lower_variable): message = product_over_(self.factor_upper_to_[variable], *self._messages_to_(variable)) message.pow(self.holder_weights_for_[lower_variable] / self.holder_weights_for_[variable]) message.div(self.messages[(lower_variable, variable)]) #variables_in_factor_upper_to_lower_variable = copy(self.factor_upper_to_[lower_variable].variables) #variables_to_marginalize = list(set(message.variables) # - set(variables_in_factor_upper_to_lower_variable)) #message.marginalize(variables_to_marginalize, # operator = 'weighted_sum', # weight = self.holder_weights_for_[lower_variable]) lower_upper_factor = self.factor_upper_to_[lower_variable] variables_to_marginalize = list( set(message.variables) - set(lower_upper_factor.variables)) message.marginalize(variables_to_marginalize, operator='weighted_sum', weight=self.holder_weights_for_[lower_variable]) #variables_not_to_marginalize = self.upper_candidate_for_[lower_variable] #message.marginalize_except_(variables_not_to_marginalize, # operator = 'weighted_sum', # weight = self.holder_weights_for_[lower_variable]) message.name = 'M_{}<-{}'.format(lower_variable, variable) self.messages[(variable, lower_variable)] = message
def get_marginals_upper_to_(self, variable): marginal = product_over_(self.factor_upper_to_[variable], *self._messages_to_(variable)) marginal.pow(1 / self.holder_weights_for_[variable]) marginal.normalize() marginal.name = 'q_c_{}'.format(variable) return marginal
def _forward_pass_for_(self, variable): upper_variable = self.variable_upper_to_[variable] message = product_over_(self.factor_upper_to_[variable], *self._upper_messages_to_(variable)) message.marginalize([variable], operator='weighted_sum', weight=self.holder_weights_for_[variable]) message.name = 'M_{}->{}'.format(variable, upper_variable) self.messages[(variable, upper_variable)] = message
def contract_variable(self, variable, operator="sum", **kwargs): adj_factors = self.get_adj_factors(variable) new_factor = product_over_(*adj_factors).copy(rename=True) new_factor.marginalize([variable], operator=operator, **kwargs) for factor in adj_factors: self.remove_factor(factor) self.remove_variable(variable) self.add_factor(new_factor) return new_factor
def get_logZ(self): logZ = 0 for var in self.model.variables: logZ += entropy(self.mean_fields[var]) for fac in self.model.factors: m = product_over_(*[self.mean_fields[var] for var in fac.variables]) index_to_keep = m.values != 0 logZ += np.sum(m.values[index_to_keep] * fac.log_values[index_to_keep]) return logZ
def run(self, max_iter=1000, converge_thr=1e-5, damp_ratio=0.1): for t in range(max_iter): old_messages = { key: item.copy() for key, item in self.messages.items() } self._update_messages(damp_ratio) if self._is_converged(converge_thr, self.messages, old_messages): break self.belief = {} for var in self.model.variables: self.belief[var] = (product_over_( *self._message_to_(var)).normalize(inplace=False)) for fac in self.model.factors: self.belief[fac] = (product_over_( fac, *self._message_to_(fac)).normalize(inplace=False)) return self.get_logZ()
def _update_mean_fields(self): variable_order = np.random.permutation(self.model.variables) for var in variable_order: next_mean_field = Factor.full_like_(self.mean_fields[var], 0.0) for fac in self.model.get_adj_factors(var): tmp = Factor(name = 'tmp', variables = [var], values = np.ones(self.model.get_cardinality_for_(var))) tmp = product_over_(tmp, *[self.mean_fields[var1] for var1 in fac.variables if var1 != var]) tmp.transpose_by_(fac.variables) tmp.log_values = fac.log_values * tmp.values next_mean_field = next_mean_field + tmp.marginalize_except_([var], inplace = False) self.mean_fields[var] = next_mean_field.exp(inplace = False).normalize(inplace = False) self.mean_fields[var].log_values = np.nan_to_num(self.mean_fields[var].log_values)
def __init__(self, model, ibound): self.org_model = model.copy() model = model.copy() unelminated_variables = copy(model.variables) while unelminated_variables: def get_bucket_size(facs): adj_adj_vars = [fac.variables for fac in facs] a = set() for vars in adj_adj_vars: a = a.union(vars) return len(a) get_key = lambda var: get_bucket_size(model.get_adj_factors(var)) var = min(unelminated_variables, key=get_key) unelminated_variables.pop(unelminated_variables.index(var)) if get_key(var) == 1: pass elif get_key(var) < ibound: model.contract_variable(var) else: facs = model.get_adj_factors(var) model.remove_factors_from(facs) mini_buckets = [] for fac in facs: mini_bucket = next( (mb for mb in mini_buckets if get_bucket_size(mb + [fac]) < ibound), False) if mini_bucket: mini_bucket.append(fac) else: mini_buckets.append([fac]) for mini_bucket in mini_buckets: if mini_bucket: model.add_factor(product_over_(*mini_bucket)) else: print('empty mini-bucket') super(IterativeJoinGraphPropagation, self).__init__(model)
def initialize_projectors(self): replications = dict() working_model = self.renormalized_model.copy() for var in self.elimination_order: main_rvar = self.variables_replicated_from_[var][-1] main_projectors = [] for (i, rvar) in enumerate(self.variables_replicated_from_[var]): if i < len(self.variables_replicated_from_[var]) - 1: fac = product_over_(*working_model.get_adj_factors(rvar)) replicated_projector = self._get_svd_projector(fac, rvar) replicated_projector.name = "RP_{}".format(rvar) projector = replicated_projector.copy() projector.variables = [main_rvar] projector.name = "P_{}".format(rvar) replications[rvar] = (main_rvar, replicated_projector, projector) main_projectors.append(projector) working_model.add_factors_from([replicated_projector.copy(), projector.copy()]) self.renormalized_model.add_factors_from([replicated_projector, projector]) working_model.contract_variable(rvar) self.replications = replications
def renormalize_model(self, **kwargs): ibound = kwargs['ibound'] if 'elimination_order_method' in kwargs: if kwargs['elimination_order_method'] == 'random': elimination_order = copy(self.model.variables) use_min_fill = False random.shuffle(elimination_order) elif kwargs['elimination_order_method'] == 'not_random': elimination_order = copy(self.model.variables) use_min_fill = False elif kwargs['elimination_order_method'] == 'min_fill': elimination_order = [] use_min_fill = True elif 'elimination_order' in kwargs: elimination_order = copy(kwargs['elimination_order']) use_min_fill = False else: elimination_order = copy(self.model.variables) use_min_fill = False random.shuffle(elimination_order) #elimination_order = [] #use_min_fill = True renormalized_model = self.model.copy() renormalized_elimination_order = [] variables_replicated_from_ = {var: [] for var in self.model.variables} factors_adj_to_ = dict() working_factorss = [[fac] for fac in renormalized_model.factors] eliminated_variables = [] for t in range(len(self.model.variables)): uneliminated_variables = sorted( set(self.model.variables) - set(eliminated_variables)) candidate_mini_buckets_for_ = dict() bucket_for_ = {cand_var: [] for cand_var in uneliminated_variables} for facs in working_factorss: for cand_var in self.get_variables_in_( [[fac] for fac in facs], eliminated=eliminated_variables): bucket_for_[cand_var].append(facs) for cand_var in uneliminated_variables: candidate_mini_buckets_for_[cand_var] = [] for facs in bucket_for_[cand_var]: mini_bucket = next( (mb for mb in candidate_mini_buckets_for_[cand_var] if self.get_bucket_size(mb + [facs], eliminated=eliminated_variables + [cand_var]) < ibound), False) if mini_bucket: mini_bucket.append(facs) else: candidate_mini_buckets_for_[cand_var].append([facs]) if use_min_fill: var, mini_buckets = min(candidate_mini_buckets_for_.items(), key=lambda x: len(x[1])) elimination_order.append(var) else: var = elimination_order[t] mini_buckets = candidate_mini_buckets_for_[var] eliminated_variables.append(var) mini_buckets.sort(key=lambda mb: self.get_bucket_size( mb, eliminated=eliminated_variables)) remove_idx = [] for working_facs_idx, working_facs in enumerate(working_factorss): if var in self.get_variables_in_([[fac] for fac in working_facs]): remove_idx.append(working_facs_idx) for i in reversed(sorted(remove_idx)): working_factorss.pop(i) for (i, mb) in enumerate(mini_buckets): mb_facs = [fac for facs in mb for fac in facs] working_factorss.append(mb_facs) replicated_var = var + '_' + str(i) variables_replicated_from_[var].append(replicated_var) factors_adj_to_[replicated_var] = [ fac for fac in mb_facs if var in fac.variables ] for var in elimination_order: for replicated_var in variables_replicated_from_[var]: renormalized_model.add_variable(replicated_var) renormalized_elimination_order.append(replicated_var) for fac in factors_adj_to_[replicated_var]: fac.variables[fac.variables.index(var)] = replicated_var renormalized_model.remove_variable(var) factors_upper_to_ = {var: [] for var in renormalized_model.variables} for fac in renormalized_model.factors: lower_var = min(fac.variables, key=renormalized_elimination_order.index) factors_upper_to_[lower_var].append(fac) for var, facs in factors_upper_to_.items(): if facs: new_fac = product_over_(*facs) for fac in facs: renormalized_model.remove_factor(fac) renormalized_model.add_factor(new_fac) base_logZ = 0.0 for fac in renormalized_model.factors: base_logZ += np.max(fac.log_values) fac.log_values -= np.max(fac.log_values) self.elimination_order = elimination_order self.renormalized_model = renormalized_model self.renormalized_elimination_order = renormalized_elimination_order self.variables_replicated_from_ = variables_replicated_from_ self.base_logZ = base_logZ