def HMC_w(prior, w, w0, beta, n, u, sigma, c, t, tau, z, gamma, p_ij, a_t, b_t, epsilon, R, accept, size, sum_n, adj, x, log_post, log_post_param, update_beta=True): temp1 = sum_n + u - sigma temp1_beta = sum_n - sigma * tau # first step: propose w0 and beta and auxiliary vars p_w0 p_beta normally distributed pw_outer = w * np.dot(p_ij, w) if gamma != 0 else w * sum(w) temp2 = (c + z) * w0 beta_prop = beta logbeta_prop = np.log(beta_prop) logw0_prop = np.log(w0) p_w0 = np.random.normal(0, 1, size) p_prop_w0 = p_w0 + epsilon * loggrad(temp1, temp2, pw_outer) / 2 if prior == 'doublepl' and update_beta is True: p_beta = np.random.normal(0, 1, size) p_prop_beta = p_beta + epsilon * loggrad(np.negative(temp1_beta), 0, np.negative(pw_outer)) / 2 # steps j=0...R-1 for j in range(R): logw0_prop = logw0_prop + epsilon * p_prop_w0 w0_prop = np.exp(logw0_prop) if prior == 'doublepl' and update_beta is True: logbeta_prop = logbeta_prop + epsilon * p_prop_beta beta_prop = np.exp(logbeta_prop) logw_prop = logw0_prop - logbeta_prop w_prop = np.exp(logw_prop) pw_outer_prop = w_prop * np.dot(p_ij, w_prop) if gamma != 0 else w_prop * sum(w_prop) temp2_prop = (c + z) * w0_prop p_prop_w0 = p_prop_w0 + epsilon * loggrad(temp1, temp2_prop, pw_outer_prop) if j != (R-1) else \ - p_prop_w0 - epsilon * loggrad(temp1, temp2_prop, pw_outer_prop) / 2 if update_beta is True: if j != (R-1): p_prop_beta = p_prop_beta + epsilon * loggrad(np.negative(temp1_beta), 0, np.negative(pw_outer_prop)) else: p_prop_beta = - p_prop_beta - epsilon * loggrad(np.negative(temp1_beta),0,np.negative(pw_outer_prop))/2 # compute log accept rate log_post_par_prop = aux.log_post_params(prior, sigma, c, t, tau, w0_prop, beta_prop, u, a_t, b_t) log_post_prop = aux.log_post_logwbeta_params(prior, sigma, c, t, tau, w_prop, w0_prop, beta_prop, n, u, p_ij, a_t, b_t, gamma, sum_n, adj, x, log_post_par=log_post_par_prop) log_r = log_post_prop - log_post - sum(p_prop_w0 ** 2 - p_w0 ** 2) / 2 if update_beta is True: log_r = log_r - sum(p_prop_beta ** 2 - p_beta ** 2) / 2 # accept step if log_r < 0: rate = min(1, np.exp(log_r)) if np.random.rand(1) < rate: w = w_prop w0 = w0_prop beta = beta_prop accept = accept + 1 log_post = log_post_prop log_post_param = log_post_par_prop else: rate = 1 w = w_prop w0 = w0_prop beta = beta_prop accept = accept + 1 log_post = log_post_prop log_post_param = log_post_par_prop return w, w0, beta, accept, rate, log_post, log_post_param
def update_params(prior, sigma_prev, c_prev, t_prev, tau_prev, z_prev, w0, beta, u, log_post, accept, sigma, c, t, tau, sigma_sigma, sigma_c, sigma_t, sigma_tau, a_t, b_t): size = len(w0) if sigma is True: # tilde_sigma = math.inf # while math.isinf(tilde_sigma) is True or math.isnan(tilde_sigma) is True or tilde_sigma == 0: l = np.exp( np.log(sigma_prev / (1 - sigma_prev)) + sigma_sigma * np.random.normal(0, 1)) tilde_sigma = l / (1 + l) else: tilde_sigma = sigma_prev # tilde_c = math.inf # while math.isinf(tilde_c) is True or math.isnan(tilde_c) is True or tilde_c == 0: tilde_c = np.exp(np.log(c_prev) + sigma_c * np.random.normal(0, 1)) if c is True else c_prev # tilde_t = math.inf # while math.isinf(tilde_t) is True or math.isnan(tilde_t) is True or tilde_t == 0: tilde_t = np.exp(np.log(t_prev) + sigma_t * np.random.normal(0, 1)) if t is True else t_prev tilde_tau = np.exp(np.log(tau_prev) + sigma_tau * np.random.normal(0, 1)) if tau is True else tau_prev tilde_log_post = aux.log_post_params(prior, tilde_sigma, tilde_c, tilde_t, tilde_tau, w0, beta, u, a_t, b_t) log_proposal = aux.log_proposal_MH(prior, sigma_prev, tilde_sigma, c_prev, tilde_c, t_prev, tilde_t, tau_prev, tilde_tau, sigma_sigma, sigma_c, sigma_t, sigma_tau, u, w0) tilde_log_proposal = aux.log_proposal_MH(prior, tilde_sigma, sigma_prev, tilde_c, c_prev, tilde_t, t_prev, tilde_tau, tau_prev, sigma_sigma, sigma_c, sigma_t, sigma_tau, u, w0) log_r = tilde_log_post - log_post + log_proposal - tilde_log_proposal if log_r < 0: if np.random.rand(1) < min(1, np.exp(log_r)): accept = accept + 1 tilde_z = (size * tilde_sigma / tilde_t) ** (1 / tilde_sigma) if prior == 'singlepl' else \ (size * tilde_tau * tilde_sigma ** 2 / ( tilde_t * tilde_c ** (tilde_sigma * (tilde_tau - 1)))) ** (1 / tilde_sigma) return np.array((tilde_sigma, tilde_c, tilde_t, tilde_tau, tilde_z, accept, tilde_log_post, np.exp(log_r))) else: return np.array((sigma_prev, c_prev, t_prev, tau_prev, z_prev, accept, log_post, np.exp(log_r))) else: accept = accept + 1 tilde_z = (size * tilde_sigma / tilde_t) ** (1 / tilde_sigma) if prior == 'singlepl' else \ (size * tilde_tau * tilde_sigma ** 2 / ( tilde_t * tilde_c ** (tilde_sigma * (tilde_tau - 1)))) ** (1 / tilde_sigma) return np.array((tilde_sigma, tilde_c, tilde_t, tilde_tau, tilde_z, accept, tilde_log_post, 1))
def update_x(x, w, gamma, p_ij, n, sigma_x, acc_distance, prior, sigma, c, t, tau, w0, beta, u, a_t, b_t, sum_n, adj, log_post, log_post_par, index): # tilde_x = np.exp(np.log(x) + sigma_x * np.random.normal(0, 1, len(x))) # log normal update # updating only x[index] tilde_x = x.copy() tilde_x[index] = np.random.normal(x[index], sigma_x) tilde_pij = aux.space_distance(tilde_x, gamma) # log posterior of the proposal tilde_logpost = aux.log_post_logwbeta_params(prior, sigma, c, t, tau, w, w0, beta, n, u, tilde_pij, a_t, b_t, gamma, sum_n, adj, log_post_par=log_post_par) # log acceptance rate log_r = tilde_logpost - log_post # + sum(np.log(tilde_x) - np.log(x)) # to add if log normal update if log_r < 0: if np.random.rand(1) < np.exp(log_r): x = tilde_x p_ij = tilde_pij acc_distance += 1 log_post = tilde_logpost else: x = tilde_x p_ij = tilde_pij acc_distance += 1 log_post = tilde_logpost return x, p_ij, acc_distance, log_post
def mcmc(G, iter, nburn, w0=False, beta=False, n=False, u=False, sigma=False, c=False, t=False, tau=False, x=False, hyperparams=False, wnu=False, all=False, sigma_sigma=0.01, sigma_c=0.01, sigma_t=0.01, sigma_tau=0.01, sigma_x=0.01, a_t=200, b_t=1, epsilon=0.01, R=5, w_inference='HMC', save_every=1000, init='none', index=None): size = G.number_of_nodes() prior = G.graph['prior'] if 'prior' in G.graph else print( 'You must specify a prior as attribute of G') gamma = G.graph['gamma'] if 'gamma' in G.graph else print( 'You must specify spatial exponent gamma as attribute of G') size_x = G.graph['size_x'] if 'size_x' in G.graph else print( 'You must specify size_x as attribute of G') if hyperparams is True or all is True: sigma = c = t = tau = True if prior == 'singlepl': tau = False if wnu is True or all is True: w0 = beta = n = u = x = True if prior == 'singlepl': beta = False if sigma is True: sigma_est = [init['sigma_init'] ] if 'sigma_init' in init else [float(np.random.rand(1))] else: sigma_est = [G.graph['sigma']] if c is True: c_est = [init['c_init'] ] if 'c_init' in init else [float(5 * np.random.rand(1) + 1)] else: c_est = [G.graph['c']] if t is True: t_est = [init['t_init']] if 't_init' in init else [ float(np.random.gamma(a_t, 1 / b_t)) ] else: t_est = [G.graph['t']] if prior == 'doublepl': if tau is True: tau_est = [init['tau_init']] if 'tau_init' in init else [ float(5 * np.random.rand(1) + 1) ] else: tau_est = [G.graph['tau']] else: tau_est = [0] z_est = [(size * sigma_est[0] / t_est[0]) ** (1 / sigma_est[0])] if G.graph['prior'] == 'singlepl' else \ [(size * tau_est[0] * sigma_est[0] ** 2 / (t_est[0] * c_est[0] ** (sigma_est[0] * (tau_est[0] - 1)))) ** \ (1 / sigma_est[0])] if w0 is True: if 'w0_init' in init: w0_est = [init['w0_init']] else: g = np.random.gamma(1 - sigma_est[0], 1, size) unif = np.random.rand(size) w0_est = [ np.multiply( g, np.power(((z_est[0] + c_est[0])**sigma_est[0]) * (1 - unif) + (c_est[0]**sigma_est[0]) * unif, -1 / sigma_est[0])) ] else: w0_est = [ np.array([G.nodes[i]['w0'] for i in range(G.number_of_nodes())]) ] if prior == 'doublepl' and beta is True: beta_est = [init['beta_init']] if 'beta_init' in init else [ float(np.random.beta(sigma_est[0] * tau_est[0], 1)) ] if prior == 'singlepl' or beta is False: beta_est = [np.array([G.nodes[i]['beta'] for i in range(G.number_of_nodes())])] if 'beta' in G.nodes[0] \ else [np.ones((size))] if u is True: u_est = [init['u_init']] if 'u_init' in init else [ tp.tpoissrnd(z_est[0] * w0_est[0]) ] else: u_est = [ np.array([G.nodes[i]['u'] for i in range(G.number_of_nodes())]) ] if x is True: x_est = [init['x_init'] ] if 'x_init' in init else [size_x * np.random.rand(size)] p_ij_est = [aux.space_distance(x_est[-1], gamma)] else: if gamma != 0: x_est = [ np.array([G.nodes[i]['x'] for i in range(G.number_of_nodes())]) ] p_ij_est = [aux.space_distance(x_est[-1], gamma)] else: p_ij_est = [np.ones((size, size))] if 'ind' in G.graph: ind = G.graph['ind'] else: ind = {k: [] for k in G.nodes} for i in G.nodes: for j in G.adj[i]: if j > i: ind[i].append(j) if 'selfedge' in G.graph: selfedge = G.graph['selfedge'] else: selfedge = [i in ind[i] for i in G.nodes] selfedge = list(compress(G.nodes, selfedge)) if n is True: if 'n_init' in init: n_est = [init['n_init']] else: out_n = up.update_n(w0_est[0], G, size, p_ij_est[-1], ind, selfedge) n_est = [out_n[0]] else: n_est = [G.graph['counts']] w_est = [np.exp(np.log(w0_est[0]) - np.log(beta_est[0]))] adj = n_est[-1] > 0 log_post_param_est = [ aux.log_post_params(prior, sigma_est[-1], c_est[-1], t_est[-1], tau_est[-1], w0_est[-1], beta_est[-1], u_est[-1], a_t, b_t) ] sum_n = np.array( csr_matrix.sum(n_est[-1], axis=0) + np.transpose(csr_matrix.sum(n_est[-1], axis=1)))[0] log_post_est = [ aux.log_post_logwbeta_params(prior, sigma_est[-1], c_est[-1], t_est[-1], tau_est[-1], w_est[-1], w0_est[-1], beta_est[-1], n_est[-1], u_est[-1], p_ij_est[-1], a_t, b_t, gamma, sum_n, adj, log_post_par=log_post_param_est[-1])[0] ] print('log post initial', log_post_est[-1]) accept_params = [0] accept_hmc = 0 accept_distance = [0] rate = [0] rate_p = [0] step = 100 nadapt = 1000 sigma_prev = sigma_est[-1] c_prev = c_est[-1] t_prev = t_est[-1] tau_prev = tau_est[-1] w_prev = w_est[-1] w0_prev = w0_est[-1] beta_prev = beta_est[-1] n_prev = n_est[-1] if gamma != 0: x_prev = x_est[-1] p_ij_prev = p_ij_est[-1] u_prev = u_est[-1] z_prev = z_est[-1] p = adj.multiply(p_ij_est[-1]) nlogp = coo_matrix.sum(n_est[-1].multiply( p._with_data(np.log(p.data), copy=True))) nlogw = sum(sum_n * np.log(w_est[-1])) wpw = sum(w_est[-1] * np.dot(p_ij_est[-1], w_est[-1])) uw0 = sum((u_est[-1] - 1) * np.log(w0_est[-1])) sumw0 = sum(np.log(w0_est[-1])) for i in range(iter): # update hyperparameters if at least one of them demands the update if sigma is True or c is True or t is True or tau is True: output_params = up.update_params(prior, sigma_prev, c_prev, t_prev, tau_prev, z_prev, w0_prev, beta_prev, u_prev, log_post_param_est[-1], accept_params[-1], sigma=sigma, c=c, t=t, tau=tau, sigma_sigma=sigma_sigma, sigma_c=sigma_c, sigma_t=sigma_t, sigma_tau=sigma_tau, a_t=a_t, b_t=b_t) sigma_prev = output_params[0] c_prev = output_params[1] t_prev = output_params[2] tau_prev = output_params[3] z_prev = output_params[4] accept_params.append(output_params[5]) log_post_param_est.append(output_params[6]) rate_p.append(output_params[7]) if (i + 1) % save_every == 0 and i != 0: sigma_est.append(sigma_prev) c_est.append(c_prev) t_est.append(t_prev) tau_est.append(tau_prev) z_est.append(z_prev) if i % 1000 == 0: print('update hyperparams iteration ', i) print('acceptance rate hyperparams = ', round(accept_params[-1] / (i + 1) * 100, 1), '%') if (i % step) == 0 and i != 0 and i < nburn: if sigma is True: sigma_sigma = aux.tune(accept_params, sigma_sigma, step) if c is True: sigma_c = aux.tune(accept_params, sigma_c, step) if t is True: sigma_t = aux.tune(accept_params, sigma_t, step) if tau is True: sigma_tau = aux.tune(accept_params, sigma_tau, step) # update w and beta if at least one of them is True if w0 is True: if accept_params[-1] == 0: log_post_est.append(log_post_est[-1]) if accept_params[-1] == 1: temp = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, log_post_par=log_post_param_est[-1], nlogp=nlogp, nlogw=nlogw, wpw=wpw, uw0=uw0, sumw0=sumw0) log_post_est.append(temp[0]) if w_inference == 'gibbs': output_gibbs = up.gibbs_w(w_prev, beta_prev, sigma_prev, c_prev, z_prev, u_prev, n_prev, p_ij_prev, gamma, sum_n) w_prev = output_gibbs[0] w0_prev = output_gibbs[1] log_post_param_est.append( aux.log_post_params(prior, sigma_prev, c_prev, t_prev, tau_prev, w0_prev, beta_prev, u_prev, a_t, b_t)) temp = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, log_post=log_post_param_est[-1], nlogp=nlogp) log_post_est.append(temp[0]) ## nlogw = temp[2] wpw = temp[3] uw0 = temp[4] sumw0 = temp[5] ## if i % 1000 == 0 and i != 0: print('update w (gibbs) iteration ', i) if w_inference == 'HMC': output_hmc = up.HMC_w(prior, w_prev, w0_prev, beta_prev, n_prev, u_prev, sigma_prev, c_prev, t_prev, tau_prev, z_prev, gamma, p_ij_prev, a_t, b_t, epsilon, R, accept_hmc, size, sum_n, adj, log_post_est[-1], log_post_param_est[-1], nlogp, nlogw, wpw, uw0, sumw0, update_beta=beta) w_prev = output_hmc[0] w0_prev = output_hmc[1] beta_prev = output_hmc[2] accept_hmc = output_hmc[3] rate.append(output_hmc[4]) log_post_est.append(output_hmc[5]) log_post_param_est.append(output_hmc[6]) ## nlogw = output_hmc[7] wpw = output_hmc[8] uw0 = output_hmc[9] sumw0 = output_hmc[10] ## if i % 100 == 0 and i != 0: # if i < nadapt: if i >= step: # epsilon = np.exp(np.log(epsilon) + 0.01 * (np.mean(rate) - 0.6)) epsilon = np.exp( np.log(epsilon) + 0.01 * (np.mean(rate[i - step:i]) - 0.6)) if i % 1000 == 0: print('update w and beta iteration ', i) print('acceptance rate HMC = ', round(accept_hmc / (i + 1) * 100, 1), '%') print('epsilon = ', epsilon) if (i + 1) % save_every == 0 and i != 0: w_est.append(w_prev) w0_est.append(w0_prev) beta_est.append(beta_prev) # update n step_n = 1 if n is True and (i + 1) % step_n == 0: n_prev = up.update_n(w_prev, G, size, p_ij_prev, ind, selfedge) sum_n = np.array( csr_matrix.sum(n_prev, axis=0) + np.transpose(csr_matrix.sum(n_prev, axis=1)))[0] log_post_param_est.append(log_post_param_est[-1]) temp = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, log_post_par=log_post_param_est[-1], wpw=wpw, uw0=uw0, sumw0=sumw0) log_post_est.append(temp[0]) ## nlogp = temp[1] nlogw = temp[2] ## if (i + 1) % save_every == 0 and i != 0: n_est.append(n_prev) if i % 1000 == 0: print('update n iteration ', i) # update u if u is True: u_prev = up.posterior_u(z_prev * w0_prev) log_post_param_est.append( aux.log_post_params(prior, sigma_prev, c_prev, t_prev, tau_prev, w0_prev, beta_prev, u_prev, a_t, b_t)) temp = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, log_post_par=log_post_param_est[-1], nlogp=nlogp, nlogw=nlogw, wpw=wpw, sumw0=sumw0) log_post_est.append(temp[0]) ## uw0 = temp[4] ## if (i + 1) % save_every == 0 and i != 0: u_est.append(u_prev) if i % 1000 == 0: print('update u iteration ', i) step_x = 1 if x is True and (i + 1) % step_x == 0: out_x = up.update_x(x_prev, w_prev, gamma, p_ij_prev, n_prev, sigma_x, accept_distance[-1], prior, sigma_prev, c_prev, t_prev, tau_prev, w0_prev, beta_prev, u_prev, a_t, b_t, sum_n, adj, log_post_est[-1], log_post_param_est[-1], index, nlogw, uw0, sumw0, nlogp, wpw) x_prev = out_x[0] p_ij_prev = out_x[1] accept_distance.append(out_x[2]) log_post_est.append(out_x[3]) ## nlogp = out_x[4] wpw = out_x[5] ## if (i + 1) % save_every == 0 and i != 0: p_ij_est.append(p_ij_prev) x_est.append(x_prev) if i % 1000 == 0: print('update x iteration ', i) print('acceptance rate x = ', round(accept_distance[-1] * 100 * step_x / iter, 1), '%') print('sigma_x = ', sigma_x) if (i % (step / step_x)) == 0 and i != 0 and i < nburn: sigma_x = aux.tune(accept_distance, sigma_x, int(step / step_x)) if gamma != 0: return w_est, w0_est, beta_est, sigma_est, c_est, t_est, tau_est, n_est, u_est, \ log_post_param_est, log_post_est, p_ij_est, x_est else: return w_est, w0_est, beta_est, sigma_est, c_est, t_est, tau_est, n_est, u_est, \ log_post_param_est, log_post_est, p_ij_est
def mcmc(G, iter, nburn, w0=False, beta=False, n=False, u=False, sigma=False, c=False, t=False, tau=False, x=False, hyperparams=False, wnu=False, all=False, sigma_sigma=0.01, sigma_c=0.01, sigma_t=0.01, sigma_tau=0.01, sigma_x=0.01, a_t=200, b_t=1, epsilon=0.01, R=5, w_inference='HMC', save_every=1000, init='none', index=None, type_prop_x='tNormal'): size = G.number_of_nodes() prior = G.graph['prior'] if 'prior' in G.graph else print( 'You must specify a prior as attribute of G') gamma = G.graph['gamma'] if 'gamma' in G.graph else print( 'You must specify spatial exponent gamma as G attribute') size_x = G.graph['size_x'] if 'size_x' in G.graph else print( 'You must specify size_x as attribute of G') sigma_est, c_est, t_est, tau_est, w_est, w0_est, beta_est, n_est, x_est, p_ij_est, u_est, z_est, ind, selfedge = \ init_var(G, size, gamma, init, w0, beta, n, u, sigma, c, t, tau, x, hyperparams, wnu, all, prior, a_t, b_t, size_x) accept_params = [0] accept_hmc = 0 accept_distance = [0] rate = [0] rate_p = [0] step = 100 nadapt = 1000 sigma_prev = sigma_est[-1] c_prev = c_est[-1] t_prev = t_est[-1] tau_prev = tau_est[-1] w_prev = w_est[-1] w0_prev = w0_est[-1] beta_prev = beta_est[-1] n_prev = n_est[-1] x_prev = x_est[-1] p_ij_prev = p_ij_est[-1] u_prev = u_est[-1] z_prev = z_est[-1] sum_n = np.array( csr_matrix.sum(n_prev, axis=0) + np.transpose(csr_matrix.sum(n_prev, axis=1)))[0] adj = n_prev > 0 log_post_param_prev = aux.log_post_params(prior, sigma_prev, c_prev, t_prev, tau_prev, w0_prev, beta_prev, u_prev, a_t, b_t) log_post_prev = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, x_prev, log_post_par=log_post_param_prev) log_post_param_est = [log_post_param_prev] log_post_est = [log_post_prev] for i in range(iter): # update hyperparameters if at least one of them demands the update if sigma is True or c is True or t is True or tau is True: sigma_prev, c_prev, t_prev, tau_prev, z_prev, accept_param_prev, log_post_param_prev, rate_p_prev \ = up.update_params(prior, sigma_prev, c_prev, t_prev, tau_prev, z_prev, w0_prev, beta_prev, u_prev, log_post_param_prev, accept_params[-1], sigma=sigma, c=c, t=t, tau=tau, sigma_sigma=sigma_sigma, sigma_c=sigma_c, sigma_t=sigma_t, sigma_tau=sigma_tau, a_t=a_t, b_t=b_t) accept_params.append(accept_param_prev) rate_p.append(rate_p_prev) # if you only have to update hyperparams, then log_post = log_post_param, otherwise you need to update that if w0 is True or n is True or u is True or x is True: log_post_prev = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, x_prev, log_post_par=log_post_param_prev) if (i + 1) % save_every == 0 and i != 0: sigma_est.append(sigma_prev) c_est.append(c_prev) t_est.append(t_prev) tau_est.append(tau_prev) z_est.append(z_prev) log_post_param_est.append(log_post_param_prev) if w0 is True or n is True or u is True or x is True: log_post_est.append(log_post_prev) if i % 1000 == 0: print('update hyperparams iteration ', i) print('acceptance rate hyperparams = ', round(accept_params[-1] / (i + 1) * 100, 1), '%') if (i % step) == 0 and i != 0 and i < nburn: if sigma is True: sigma_sigma = aux.tune(accept_params, sigma_sigma, step) if c is True: sigma_c = aux.tune(accept_params, sigma_c, step) if t is True: sigma_t = aux.tune(accept_params, sigma_t, step) if tau is True: sigma_tau = aux.tune(accept_params, sigma_tau, step) # update w and beta if at least one of them is True if w0 is True: if w_inference == 'gibbs': w_prev, w0_prev = up.gibbs_w(w_prev, beta_prev, sigma_prev, c_prev, z_prev, u_prev, n_prev, p_ij_prev, gamma, sum_n) log_post_param_prev = aux.log_post_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w0_prev, beta_prev, u_prev, a_t, b_t) log_post_prev = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, x_prev, log_post=log_post_param_prev) if (i + 1) % save_every == 0 and i != 0: w_est.append(w_prev) w0_est.append(w0_prev) beta_est.append(beta_prev) log_post_est.append(log_post_prev) log_post_param_est.append(log_post_param_prev) if i % 1000 == 0 and i != 0: print('update w iteration ', i) if w_inference == 'HMC': w_prev, w0_prev, beta_prev, accept_hmc, rate_prev, log_post_prev, log_post_param_prev \ = up.HMC_w(prior, w_prev, w0_prev, beta_prev, n_prev, u_prev, sigma_prev, c_prev, t_prev, tau_prev, z_prev, gamma, p_ij_prev, a_t, b_t, epsilon, R, accept_hmc, size, sum_n, adj, x_prev, log_post_prev, log_post_param_prev, update_beta=beta) rate.append(rate_prev) if (i + 1) % save_every == 0 and i != 0: w_est.append(w_prev) w0_est.append(w0_prev) beta_est.append(beta_prev) log_post_est.append(log_post_prev) log_post_param_est.append(log_post_param_prev) if i % 100 == 0 and i != 0: # if i < nadapt: if i >= step: # epsilon = np.exp(np.log(epsilon) + 0.01 * (np.mean(rate) - 0.6)) epsilon = np.exp( np.log(epsilon) + 0.01 * (np.mean(rate[i - step:i]) - 0.6)) if i % 1000 == 0: print('update w and beta iteration ', i) print('acceptance rate HMC = ', round(accept_hmc / (i + 1) * 100, 1), '%') print('epsilon = ', epsilon) # update n step_n = 25 if n is True and (i + 1) % step_n == 0: n_prev, rubbish = up.update_n(w_prev, G, size, p_ij_prev, ind, selfedge) sum_n = np.array( csr_matrix.sum(n_prev, axis=0) + np.transpose(csr_matrix.sum(n_prev, axis=1)))[0] log_post_prev = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, x_prev, log_post_par=log_post_param_prev) if (i + 1) % save_every == 0 and i != 0: n_est.append(n_prev) log_post_param_est.append(log_post_param_prev) log_post_est.append(log_post_prev) if i % 1000 == 0: print('update n iteration ', i) # update u if u is True: u_prev = up.posterior_u(z_prev * w0_prev) log_post_param_prev = aux.log_post_params(prior, sigma_prev, c_prev, t_prev, tau_prev, w0_prev, beta_prev, u_prev, a_t, b_t) log_post_prev = aux.log_post_logwbeta_params( prior, sigma_prev, c_prev, t_prev, tau_prev, w_prev, w0_prev, beta_prev, n_prev, u_prev, p_ij_prev, a_t, b_t, gamma, sum_n, adj, x_prev, log_post_par=log_post_param_prev) if (i + 1) % save_every == 0 and i != 0: u_est.append(u_prev) log_post_param_est.append(log_post_param_prev) log_post_est.append(log_post_prev) if i % 1000 == 0: print('update u iteration ', i) step_x = 1 if x is True and (i + 1) % step_x == 0: x_prev, p_ij_prev, accept_distance_prev, log_post_prev = \ up.update_x(x_prev, w_prev, gamma, p_ij_prev, n_prev, sigma_x, accept_distance[-1], prior, sigma_prev, c_prev, t_prev, tau_prev, w0_prev, beta_prev, u_prev, a_t, b_t, sum_n, adj, log_post_prev, log_post_param_prev, index, size_x, type_prop_x) accept_distance.append(accept_distance_prev) if (i + 1) % save_every == 0 and i != 0: p_ij_est.append(p_ij_prev) x_est.append(x_prev) log_post_param_est.append(log_post_param_prev) log_post_est.append(log_post_prev) if i % 1000 == 0: print('update x iteration ', i) print('acceptance rate x = ', round(accept_distance[-1] * 100 * step_x / (i + 1), 1), '%') print('sigma_x = ', sigma_x) if (i % (step / step_x)) == 0 and i != 0 and i < nburn: sigma_x = aux.tune(accept_distance, sigma_x, int(step / step_x)) if gamma != 0: return w_est, w0_est, beta_est, sigma_est, c_est, t_est, tau_est, n_est, u_est, \ log_post_param_est, log_post_est, p_ij_est, x_est else: return w_est, w0_est, beta_est, sigma_est, c_est, t_est, tau_est, n_est, u_est, \ log_post_param_est, log_post_est, p_ij_est
def init_var(G, size, gamma, init, w0, beta, n, u, sigma, c, t, tau, x, hyperparams, wnu, all, prior, a_t, b_t, size_x): if hyperparams is True or all is True: sigma = c = t = tau = True if prior == 'singlepl': tau = False if wnu is True or all is True: w0 = beta = n = u = x = True if prior == 'singlepl': beta = False if sigma is True: sigma_est = [init['sigma'] ] if 'sigma' in init else [float(np.random.rand(1))] else: sigma_est = [G.graph['sigma']] if c is True: c_est = [init['c'] ] if 'c' in init else [float(5 * np.random.rand(1) + 1)] else: c_est = [G.graph['c']] if t is True: t_est = [init['t'] ] if 't' in init else [float(np.random.gamma(a_t, 1 / b_t))] else: t_est = [G.graph['t']] if prior == 'doublepl': if tau is True: tau_est = [init['tau']] if 'tau' in init else [ float(5 * np.random.rand(1) + 1) ] else: tau_est = [G.graph['tau']] else: tau_est = [0] z_est = [(size * sigma_est[0] / t_est[0]) ** (1 / sigma_est[0])] if G.graph['prior'] == 'singlepl' else \ [(size * tau_est[0] * sigma_est[0] ** 2 / (t_est[0] * c_est[0] ** (sigma_est[0] * (tau_est[0] - 1)))) ** \ (1 / sigma_est[0])] if w0 is True: if 'w0' in init: w0_est = [init['w0']] else: g = np.random.gamma(1 - sigma_est[0], 1, size) unif = np.random.rand(size) w0_est = [ np.multiply( g, np.power(((z_est[0] + c_est[0])**sigma_est[0]) * (1 - unif) + (c_est[0]**sigma_est[0]) * unif, -1 / sigma_est[0])) ] else: w0_est = [ np.array([G.nodes[i]['w0'] for i in range(G.number_of_nodes())]) ] if prior == 'doublepl' and beta is True: beta_est = [init['beta']] if 'beta' in init else [ float(np.random.beta(sigma_est[0] * tau_est[0], 1)) ] if prior == 'singlepl' or beta is False: beta_est = [np.array([G.nodes[i]['beta'] for i in range(G.number_of_nodes())])] if 'beta' in G.nodes[0] \ else [np.ones((size))] if u is True: u_est = [init['u'] ] if 'u' in init else [tp.tpoissrnd(z_est[0] * w0_est[0])] else: u_est = [ np.array([G.nodes[i]['u'] for i in range(G.number_of_nodes())]) ] if x is True: x_est = [init['x'] ] if 'x' in init else [size_x * np.random.rand(size)] # uniform prior # x_est = [init['x']] if 'x' in init else [scipy.stats.norm.rvs(3, 0.1, size)] # normal prior p_ij_est = [aux.space_distance(x_est[-1], gamma)] else: if 'x' in G.nodes[0]: x_est = [ np.array([G.nodes[i]['x'] for i in range(G.number_of_nodes())]) ] if 'distances' in G.graph: p_ij_est = [G.graph['distances']] else: p_ij_est = aux.space_distance(x_est, gamma) else: x_est = [np.ones(G.number_of_nodes())] p_ij_est = [np.ones((G.number_of_nodes(), G.number_of_nodes()))] if 'ind' in G.graph: ind = G.graph['ind'] else: ind = {k: [] for k in G.nodes} for i in G.nodes: for j in G.adj[i]: if j >= i: ind[i].append(j) if 'selfedge' in G.graph: selfedge = G.graph['selfedge'] else: selfedge = [i in ind[i] for i in G.nodes] selfedge = list(compress(G.nodes, selfedge)) if n is True: if 'n' in init: n_est = [init['n']] else: out_n = up.update_n(w0_est[0], G, size, p_ij_est[-1], ind, selfedge) n_est = [out_n[0]] else: n_est = [G.graph['counts']] w_est = [np.exp(np.log(w0_est[0]) - np.log(beta_est[0]))] # ## speed up - only x # x_est = [x_est[-1][index]] # n_est = [n_est[-1][index, :]] # n_est = [n_est[-1][:, index]] # p_ij_est = [p_ij_est[-1][:, index]] # p_ij_est = [p_ij_est[-1][index, :]] # adj = adj[index, :] # adj = adj[:, index] # w_est = [w_est[-1][index]] # ## speed up - only x return sigma_est, c_est, t_est, tau_est, w_est, w0_est, beta_est, n_est, x_est, p_ij_est, u_est, z_est, ind, \ selfedge
def update_x(x, w, gamma, p_ij, n, sigma_x, acc_distance, prior, sigma, c, t, tau, w0, beta, u, a_t, b_t, sum_n, adj, log_post, log_post_par, index, size_x, type_prop_x): # updating only x[index] tilde_x = x.copy() if type_prop_x == 'normal': # GAUSSIAN proposal - works if prior has full support tilde_x[index] = np.random.normal(x[index], sigma_x) if type_prop_x == 'tNormal': # TRUNCATED NORMAL proposal - bounded prior if isinstance(x[0], float): lower = 0 upper = size_x tilde_x[index] = scipy.stats.truncnorm.rvs((lower - x[index]) / sigma_x, (upper - x[index]) / sigma_x, loc=x[index], scale=sigma_x, size=len(index)) logprop = sum(scipy.stats.truncnorm.logpdf(x[index], (lower - tilde_x[index]) / sigma_x, (upper - tilde_x[index]) / sigma_x, loc=tilde_x[index], scale=sigma_x)) tilde_logprop = sum(scipy.stats.truncnorm.logpdf(tilde_x[index], (lower - x[index]) / sigma_x, (upper - x[index]) / sigma_x, loc=x[index], scale=sigma_x)) else: # lower = 0 # upper = size_x # tilde_x[index] = scipy.stats.truncnorm.rvs((lower - x[index]) / sigma_x, (upper - x[index]) / sigma_x, # loc=x[index], scale=sigma_x*np.ones((len(index), len(x[0])))) lower = np.array((0.428576, -2.171336)) upper = np.array((0.851624, -1.187653)) tilde_x[index] = scipy.stats.truncnorm.rvs((lower - x[index]) / sigma_x, (upper - x[index]) / sigma_x, loc=x[index], scale=sigma_x*np.ones((len(index), len(x[0])))) logprop = 0 tilde_logprop = 0 for i in range(len(x[0])): logprop += sum(scipy.stats.truncnorm.logpdf(x[index][i], (lower - tilde_x[index][i]) / sigma_x, (upper - tilde_x[index][i]) / sigma_x, loc=tilde_x[index][i], scale=sigma_x * np.ones(len(x[0])))) tilde_logprop += sum(scipy.stats.truncnorm.logpdf(tilde_x[index][i], (lower - x[index][i]) / sigma_x, (upper - x[index][i]) / sigma_x, loc=x[index][i], scale=sigma_x * np.ones(len(x[0])))) # # if you want to speed up and not have to recompute p_ij for fixed nodes # tilde_x[j] = tilde_x[j] # tilde_pij = p_ij.copy() # row_idx = np.array(index) # col_idx = np.array(index) # tilde_pij[row_idx[:, None], col_idx] = aux.space_distance(a, gamma) tilde_pij = aux.space_distance(tilde_x, gamma) tilde_logpost = aux.log_post_logwbeta_params(prior, sigma, c, t, tau, w, w0, beta, n, u, tilde_pij, a_t, b_t, gamma, sum_n, adj, tilde_x, log_post_par=log_post_par) # log acceptance rate if type_prop_x == 'tNormal': log_r = tilde_logpost - log_post + logprop - tilde_logprop if type_prop_x == 'normal': log_r = tilde_logpost - log_post if log_r < 0: if np.random.rand(1) < np.exp(log_r): x = tilde_x p_ij = tilde_pij acc_distance += 1 log_post = tilde_logpost else: x = tilde_x p_ij = tilde_pij acc_distance += 1 log_post = tilde_logpost return x, p_ij, acc_distance, log_post
def GraphSampler(prior, approximation, typesampler, sigma, c, t, tau, gamma, size_x, type_prior_x, dim_x, a_t=200, b_t=1, print_=True, **kwargs): start = time.time() # sample weights w, w0, beta output = weight.WeightsSampler(prior, approximation, t, sigma, c, tau, **kwargs) w = kwargs['w'] if 'w' in kwargs else output[0] w0 = kwargs['w0'] if 'w0' in kwargs else output[1] beta = kwargs['beta'] if 'beta' in kwargs else output[2] size = len(w) # sample locations x = kwargs['x'] if 'x' in kwargs else loc.LocationsSampler( size_x, size, type_prior_x, dim_x) # sample graph if typesampler == "naive": [G, w, x, size] = NaiveSampler(w, x, gamma, dim_x) if typesampler == "layers": K = kwargs['K'] if 'K' in kwargs else 100 [G, w, x, size] = SamplerLayers_optim(w, x, gamma, size_x, K) end = time.time() deg = np.array(list(dict(G.degree()).values())) if print_ is True: print('time to produce sample: ', round((end - start) / 60, 2), ' min') print('number of active nodes: ', sum(deg > 0)) print('total number of nodes L: ', len(deg)) G.graph['prior'] = prior G.graph['sigma'] = sigma G.graph['c'] = c G.graph['t'] = t G.graph['tau'] = tau G.graph['gamma'] = gamma G.graph['size_x'] = size_x G.graph['a_t'] = a_t G.graph['b_t'] = b_t # set nodes attributes: w, w0, beta, x, u z = (size * sigma / t) ** (1 / sigma) if prior == 'singlepl' else \ (size * tau * sigma ** 2 / (t * c ** (sigma * (tau - 1)))) ** (1 / sigma) G.graph['z'] = z u = tp.tpoissrnd(z * w0) d = {k: [] for k in G.nodes} for i in G.nodes(): d[i] = {'w': w[i], 'w0': w0[i], 'beta': beta[i], 'x': x[i], 'u': u[i]} nx.set_node_attributes(G, d) # set graph attributes: ind (upper triangular matrix of neighbors of nodes) and selfedge (list of nodes w/ selfedge) ind = {k: [] for k in G.nodes} for i in G.nodes: for j in G.adj[i]: if j >= i: ind[i].append(j) selfedge = [i in ind[i] for i in G.nodes] selfedge = list(compress(G.nodes, selfedge)) G.graph['ind'] = ind G.graph['selfedge'] = selfedge # computing "distance" matrix p_ij = 1 / ((1 + |x_i-x_j|) ** gamma) p_ij = aux.space_distance(x, gamma) if gamma != 0 else np.ones( (size, size)) G.graph['distances'] = p_ij # computing counts upper triangular matrix n n_out = up.update_n(w, G, size, p_ij, ind, selfedge) n = n_out[0] G.graph[ 'counts'] = n # for the counts, it would be nice to set up a nx.MultiGraph, but some algorithms don't work # on these graphs, so for the moment I'll assign n as attribute to the whole graph rather then the single nodes sum_n = np.array( csr_matrix.sum(n, axis=0) + np.transpose(csr_matrix.sum(n, axis=1)))[0] G.graph['sum_n'] = sum_n sum_fact_n = n_out[1] G.graph['sum_fact_n'] = sum_fact_n # attach log posterior of the graph as attribute adj = n > 0 # ### SPEED UP - when updating x alone # ind = np.argsort(deg) # index = ind[0:len(ind) - 1] # log_post = aux.log_post_logwbeta_params(prior, sigma, c, t, tau, w, w0, beta, n, u, p_ij, a_t, b_t, gamma, sum_n, # adj, x, index=index) # ### SPEED UP - when updating x alone log_post_param = aux.log_post_params(prior, sigma, c, t, tau, w0, beta, u, a_t, b_t) log_post = aux.log_post_logwbeta_params(prior, sigma, c, t, tau, w, w0, beta, n, u, p_ij, a_t, b_t, gamma, sum_n, adj, x) G.graph['log_post'] = log_post G.graph['log_post_param'] = log_post_param return G