def backward_pass(self, var, normalize=False): w = self.weights[var] if self.get_child_factors(var): phi = factor_product(*self.get_child_factors(var)) else: phi = 1.0 if self.children[var]: phi = factor_product( *[phi], *[self.messages[(child, var)] for child in self.children[var]]) if self.parents[var]: phi = factor_product(*[phi], *[self.messages[(self.parents[var], var)]]) phi.abs() for child in self.children[var]: wc = self.weights[child] m = self.messages[(child, var)].copy() self.messages[(var, child)] = factor_product( m.power(-1.0, inplace=False), phi.power(wc / w, inplace=False)) self.messages[(var, child)].weightedsum( list(set(phi.variables) - set(m.variables)), wc) self.messages[(var, child)].name = "M_" + str(var) + "->" + str(child) if normalize: self.messages[(var, child)].normalize()
def update_reparam(self, ovar, method="projected_gradient"): if method == "projected_gradient": step_size = self.reparam_step_size b = { var: self.get_q(var).marginalize_except([ovar], inplace=False) for var in self.nvardict[ovar] } b_avg = np.sum( np.array([b[var].values for var in self.nvardict[ovar]]), 0) / len(self.nvardict[ovar]) for var in self.nvardict[ovar]: temp = b[var].copy() temp.values = np.exp(-step_size * (temp.values - b_avg)) factor = self.model.get_factor(self.adj_factor_names[var][0]) factor.product(temp) elif method == "fixedpoint": b = { var: self.get_q(var).marginalize_except([ovar], inplace=False) for var in self.nvardict[ovar] } b_avg = factor_product(*[ b[var].power(self.weights[var], inplace=False) for var in self.nvardict[ovar] ]) for var in self.nvardict[ovar]: temp = b[var].copy() temp.values = b_avg.values / b[var].values temp.power(self.weights[var]) factor = self.model.get_factor(self.adj_factor_names[var][0]) factor.product(temp)
def forward_pass(self, var, normalize=False): if self.parents[var]: w = self.weights[var] self.messages[(var, self.parents[var])] = factor_product( *self.get_child_factors(var), *[self.messages[(child, var)] for child in self.children[var]]) self.messages[(var, self.parents[var])].weightedsum( [self.ovardict[var]], w) if normalize: self.messages[(var, self.parents[var])].normalize()
def get_q(self, var): w = self.weights[var] if self.get_child_factors(var): phi = factor_product(*self.get_child_factors(var)) else: phi = 1.0 if self.children[var]: phi = factor_product( *[phi], *[self.messages[(child, var)] for child in self.children[var]]) if self.parents[var]: phi = factor_product(*[phi], *[self.messages[(self.parents[var], var)]]) phi.abs() phi.power(1 / w) phi.normalize() phi.name = "q_" + str(var) return phi.copy()
def compute_Z(self, add_time=False): if add_time: t = time() for ovar in self.model.variables: for var in self.nvardict[ovar]: self.forward_pass(var, normalize=False) Z = 1.0 for var in self.variables: w = self.weights[var] if not self.parents[var]: phi = factor_product( *self.get_child_factors(var), *[ self.messages[(child, var)] for child in self.children[var] ]) Z *= phi.weightedsum([self.ovardict[var]], w, inplace=False).values self.Z = Z * np.exp(self.baselogZ) self.logZ = np.log(Z) + self.baselogZ if add_time: self.elapsed_time += time() - t
def __init__(self, model, ibound): self.model = model.copy() self.logZ = 0.0 self.Z = 0.0 self.baselogZ = 0.0 self.messages = {} self.reparam = { var: np.zeros(model.get_nstate(var)) for var in model.variables } self.gauges = { var: Factor( "G" + str(var), [var + "_", var], [model.get_nstate(var), model.get_nstate(var)], np.eye(model.get_nstate(var)), ) for var in model.variables } self.build_cover_graph(ibound) for var in self.variables: if self.parents[var]: self.messages[(var, self.parents[var])] = factor_product( *self.get_child_factors(var), *[ self.messages[(child, var)] for child in self.children[var] ]) self.messages[(var, self.parents[var])].marginalize( [self.ovardict[var]]) self.messages[(var, self.parents[var])].values = np.full_like( self.messages[(var, self.parents[var])].values, 1.0) self.messages[(var, self.parents[var])].name = ( "M_" + str(var) + str(self.parents[var])) for var in reversed(self.variables): if self.get_child_factors(var): phi = factor_product(*self.get_child_factors(var)) else: phi = 1.0 if self.children[var]: phi = factor_product( *[phi], *[ self.messages[(child, var)] for child in self.children[var] ]) if self.parents[var]: phi = factor_product( *[phi], *[self.messages[(self.parents[var], var)]]) for child in self.children[var]: m = self.messages[(child, var)].copy() self.messages[(var, child)] = factor_product(phi, m) self.messages[(var, child)].marginalize( list(set(phi.variables) - set(m.variables))) self.messages[(var, child)].values = np.full_like( self.messages[(var, child)].values, 1.0) self.messages[( var, child)].name = "M_" + str(var) + "->" + str(child) self.reparam_step_size = 0.1 self.weight_step_size = 0.1 self.gauge_step_size = 0.005 self.elapsed_time = 0.0
def get_gauges_der_factor(self, ovariable, factor): factor_der = { gauge_idx: np.full_like(factor.values, 0.0) for gauge_idx, gauge_val in np.ndenumerate( self.gauges[ovariable].values) } temp = { gauge_idx: np.full_like(factor.values, 0.0) for gauge_idx, gauge_val in np.ndenumerate( self.gauges[ovariable].values) } gauge_list = {} if factor == self.model.get_adj_factors(ovariable)[0]: top_factor = factor.copy() factor_order = copy(factor.variables) for ovar in factor.variables: if ovar != ovariable: if self.model.get_adj_factors(ovar).index(factor) == 0: gauge = self.gauges[ovar].copy() elif self.model.get_adj_factors(ovar).index(factor) == 1: gauge = self.gauges[ovar].invT(inplace=False) top_factor = factor_product(top_factor, gauge) top_factor.marginalize([ovar]) top_factor.variables[top_factor.variables.index( ovar + "_")] = ovar top_factor.values = top_factor.values.transpose( [top_factor.variables.index(ovar) for ovar in factor_order]) top_factor.variables = copy(factor_order) for gauge_idx, gauge_val in np.ndenumerate( self.gauges[ovar].values): for factor_idx, factor_val in np.ndenumerate(factor.values): if gauge_idx[0] == factor_idx[factor.variables.index( ovariable)]: top_idx = list(copy(factor_idx)) top_idx[top_factor.variables.index( ovariable)] = gauge_idx[1] factor_der[gauge_idx][factor_idx] = top_factor.values[ tuple(top_idx)] return factor_der elif factor == self.model.get_adj_factors(ovariable)[1]: top_factor = factor.copy() factor_order = copy(factor.variables) for ovar in factor.variables: if ovar != ovariable: if self.model.get_adj_factors(ovar).index(factor) == 0: gauge = self.gauges[ovar].copy() elif self.model.get_adj_factors(ovar).index(factor) == 1: gauge = self.gauges[ovar].invT(inplace=False) top_factor = factor_product(top_factor, gauge) top_factor.marginalize([ovar]) top_factor.variables[top_factor.variables.index( ovar + "_")] = ovar top_factor.values = top_factor.values.transpose( [top_factor.variables.index(ovar) for ovar in factor_order]) top_factor.variables = copy(factor_order) for gauge_idx, gauge_val in np.ndenumerate( self.gauges[ovar].values): for factor_idx, factor_val in np.ndenumerate(factor.values): if gauge_idx[1] == factor_idx[factor.variables.index( ovariable)]: top_idx = list(copy(factor_idx)) top_idx[top_factor.variables.index( ovariable)] = gauge_idx[0] factor_der[gauge_idx][factor_idx] -= top_factor.values[ tuple(top_idx)] return factor_der else: print("Something wrong") return False