Example #1
0
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
Example #2
0
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))
Example #3
0
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
Example #4
0
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
Example #5
0
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
Example #6
0
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
Example #7
0
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
Example #8
0
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