예제 #1
0
def f_updateg_pw(g_coef_curr, g_basis, var1_curr, q1, q2, SSE_curr,
                 propose_g_coef):
    g_coef_prop = propose_g_coef(g_coef_curr)

    tst = uf.f_exp1(
        uf.f_basistofunction(g_basis["x"], 0, g_coef_prop["prop"], g_basis))

    while tst.min() < 0:
        g_coef_prop = propose_g_coef(g_coef_curr)
        tst = uf.f_exp1(
            uf.f_basistofunction(g_basis["x"], 0, g_coef_prop["prop"],
                                 g_basis))

    if SSE_curr == 0:
        SSE_curr = f_SSEg_pw(
            uf.f_basistofunction(g_basis["x"], 0, g_coef_curr, g_basis), q1,
            q2)

    SSE_prop = f_SSEg_pw(
        uf.f_basistofunction(g_basis["x"], 0, g_coef_prop["prop"], g_basis),
        q1, q2)

    logl_curr = f_logl_pw(
        uf.f_basistofunction(g_basis["x"], 0, g_coef_curr, g_basis), q1, q2,
        var1_curr, SSE_curr)

    logl_prop = f_logl_pw(
        uf.f_basistofunction(g_basis["x"], 0, g_coef_prop["prop"], g_basis),
        q1, q2, var1_curr, SSE_prop)

    ratio = np.minimum(1, np.exp(logl_prop - logl_curr))

    u = np.random.rand()
    if u <= ratio:
        g_coef = g_coef_prop["prop"]
        logl = logl_prop
        SSE = SSE_prop
        accept = True
        zpcnInd = g_coef_prop["ind"]

    if u > ratio:
        g_coef = g_coef_curr
        logl = logl_curr
        SSE = SSE_curr
        accept = False
        zpcnInd = g_coef_prop["ind"]

    return g_coef, logl, SSE, accept, zpcnInd
예제 #2
0
def f_dlogl_pw(v_coef, v_basis, d_basis, sigma_curr, q1, q2):
    vec = uf.f_basistofunction(v_basis["x"], 0, v_coef, v_basis)
    psi = uf.f_exp1(vec)
    N = q1.shape[0]
    obs_domain = np.linspace(0, 1, N)
    binsize = np.diff(obs_domain)
    binsize = binsize.mean()
    gamma = uf.f_phiinv(psi)
    q2_warp = uf.warp_q_gamma(obs_domain, q2, gamma)
    q2_warp_grad = np.gradient(q2_warp, binsize)

    basismat = d_basis["matrix"]

    g = np.zeros(N)
    for i in range(0, basismat.shape[1]):
        ubar = cumtrapz(basismat[:, i], obs_domain, initial=0)
        integrand = (q1 - q2_warp) * (-2 * q2_warp_grad * ubar -
                                      q2_warp * basismat[:, i])
        tmp = 1 / sigma_curr * trapz(integrand, obs_domain)
        g += tmp * basismat[:, i]

    out, SSEv = f_vpostlogl_pw(vec, q1, q2, sigma_curr, 0)

    nll = -1 * out
    g_coef = v_basis["matrix"].T @ g

    return nll, g_coef, SSEv
예제 #3
0
def f_SSEg_pw(g, q1, q2):
    obs_domain = np.linspace(0, 1, g.shape[0])
    exp1g_temp = uf.f_predictfunction(uf.f_exp1(g), obs_domain, 0)
    pt = np.insert(bay.bcuL2norm2(obs_domain, exp1g_temp), 0, 0)
    tmp = uf.f_predictfunction(q2, pt, 0)
    vec = (q1 - tmp * exp1g_temp)**2
    out = vec.sum()
    return (out)
예제 #4
0
def f_warp_pw(v, q1, q2):
    obs_domain = np.linspace(0, 1, v.shape[0])
    exp1g_temp = uf.f_predictfunction(uf.f_exp1(v), obs_domain, 0)
    pt = np.insert(bay.bcuL2norm2(obs_domain, exp1g_temp), 0, 0)
    tmp = uf.f_predictfunction(q2, pt, 0)
    out = tmp * exp1g_temp

    return (out)
예제 #5
0
def pairwise_align_bayes(f1i, f2i, time, mcmcopts=None):
    """
    This function aligns two functions using Bayesian framework. It will align
    f2 to f1. It is based on mapping warping functions to a hypersphere, and a
    subsequent exponential mapping to a tangent space. In the tangent space,
    the Z-mixture pCN algorithm is used to explore both local and global
    structure in the posterior distribution.
   
    The Z-mixture pCN algorithm uses a mixture distribution for the proposal
    distribution, controlled by input parameter zpcn. The zpcn$betas must be
    between 0 and 1, and are the coefficients of the mixture components, with
    larger coefficients corresponding to larger shifts in parameter space. The
    zpcn["probs"] give the probability of each shift size.
   
    Usage:  out = pairwise_align_bayes(f1i, f2i, time)
            out = pairwise_align_bayes(f1i, f2i, time, mcmcopts)
    
    :param f1i: vector defining M samples of function 1
    :param f2i: vector defining M samples of function 2
    :param time: time vector of length M
    :param mcmopts: dict of mcmc parameters
    :type mcmcopts: dict
  
    default mcmc options:
    tmp = {"betas":np.array([0.5,0.5,0.005,0.0001]),"probs":np.array([0.1,0.1,0.7,0.1])}
    mcmcopts = {"iter":2*(10**4) ,"burnin":np.minimum(5*(10**3),2*(10**4)//2),
                "alpha0":0.1, "beta0":0.1,"zpcn":tmp,"propvar":1,
                "initcoef":np.repeat(0,20), "npoints":200, "extrainfo":True}
   
    :rtype collection containing
    :return f2_warped: aligned f2
    :return gamma: warping function
    :return g_coef: final g_coef
    :return psi: final psi
    :return sigma1: final sigma
    
    if extrainfo
    :return accept: accept of psi samples
    :return betas_ind
    :return logl: log likelihood
    :return gamma_mat: posterior gammas
    :return gamma_stats: posterior gamma stats
    :return xdist: phase distance posterior
    :return ydist: amplitude distance posterior)
    """

    if mcmcopts is None:
        tmp = {
            "betas": np.array([0.5, 0.5, 0.005, 0.0001]),
            "probs": np.array([0.1, 0.1, 0.7, 0.1])
        }
        mcmcopts = {
            "iter": 2 * (10**4),
            "burnin": np.minimum(5 * (10**3), 2 * (10**4) // 2),
            "alpha0": 0.1,
            "beta0": 0.1,
            "zpcn": tmp,
            "propvar": 1,
            "initcoef": np.repeat(0, 20),
            "npoints": 200,
            "extrainfo": True
        }

    if f1i.shape[0] != f2i.shape[0]:
        raise Exception('Length of f1 and f2 must be equal')

    if f1i.shape[0] != time.shape[0]:
        raise Exception('Length of f1 and time must be equal')

    if mcmcopts["zpcn"]["betas"].shape[0] != mcmcopts["zpcn"]["probs"].shape[0]:
        raise Exception('In zpcn, betas must equal length of probs')

    if np.mod(mcmcopts["initcoef"].shape[0], 2) != 0:
        raise Exception('Length of mcmcopts.initcoef must be even')

    # Number of sig figs to report in gamma_mat
    SIG_GAM = 13
    iter = mcmcopts["iter"]

    # parameter settings
    pw_sim_global_burnin = mcmcopts["burnin"]
    valid_index = np.arange(pw_sim_global_burnin - 1, iter)
    pw_sim_global_Mg = mcmcopts["initcoef"].shape[0] // 2
    g_coef_ini = mcmcopts["initcoef"]
    numSimPoints = mcmcopts["npoints"]
    pw_sim_global_domain_par = np.linspace(0, 1, numSimPoints)
    g_basis = uf.basis_fourier(pw_sim_global_domain_par, pw_sim_global_Mg, 1)
    sigma1_ini = 1
    zpcn = mcmcopts["zpcn"]
    pw_sim_global_sigma_g = mcmcopts["propvar"]

    def propose_g_coef(g_coef_curr):
        pCN_beta = zpcn["betas"]
        pCN_prob = zpcn["probs"]
        probm = np.insert(np.cumsum(pCN_prob), 0, 0)
        z = np.random.rand()
        result = {"prop": g_coef_curr, "ind": 1}
        for i in range(0, pCN_beta.shape[0]):
            if z <= probm[i + 1] and z > probm[i]:
                g_coef_new = normal(
                    0, pw_sim_global_sigma_g /
                    np.repeat(np.arange(1, pw_sim_global_Mg + 1), 2))
                result["prop"] = np.sqrt(
                    1 -
                    pCN_beta[i]**2) * g_coef_curr + pCN_beta[i] * g_coef_new
                result["ind"] = i

        return result

    # normalize time to [0,1]
    time = (time - time.min()) / (time.max() - time.min())
    timet = np.linspace(0, 1, numSimPoints)
    f1 = uf.f_predictfunction(f1i, timet, 0)
    f2 = uf.f_predictfunction(f2i, timet, 0)

    # srsf transformation
    q1 = uf.f_to_srsf(f1, timet)
    q1i = uf.f_to_srsf(f1i, time)
    q2 = uf.f_to_srsf(f2, timet)

    tmp = uf.f_exp1(uf.f_basistofunction(g_basis["x"], 0, g_coef_ini, g_basis))

    if tmp.min() < 0:
        raise Exception("Invalid initial value of g")

    # result vectors
    g_coef = np.zeros((iter, g_coef_ini.shape[0]))
    sigma1 = np.zeros(iter)
    logl = np.zeros(iter)
    SSE = np.zeros(iter)
    accept = np.zeros(iter, dtype=bool)
    accept_betas = np.zeros(iter)

    # init
    g_coef_curr = g_coef_ini
    sigma1_curr = sigma1_ini
    SSE_curr = f_SSEg_pw(
        uf.f_basistofunction(g_basis["x"], 0, g_coef_ini, g_basis), q1, q2)
    logl_curr = f_logl_pw(
        uf.f_basistofunction(g_basis["x"], 0, g_coef_ini, g_basis), q1, q2,
        sigma1_ini**2, SSE_curr)

    g_coef[0, :] = g_coef_ini
    sigma1[0] = sigma1_ini
    SSE[0] = SSE_curr
    logl[0] = logl_curr

    # update the chain for iter-1 times
    for m in tqdm(range(1, iter)):
        # update g
        g_coef_curr, tmp, SSE_curr, accepti, zpcnInd = f_updateg_pw(
            g_coef_curr, g_basis, sigma1_curr**2, q1, q2, SSE_curr,
            propose_g_coef)

        # update sigma1
        newshape = q1.shape[0] / 2 + mcmcopts["alpha0"]
        newscale = 1 / 2 * SSE_curr + mcmcopts["beta0"]
        sigma1_curr = np.sqrt(1 / np.random.gamma(newshape, 1 / newscale))
        logl_curr = f_logl_pw(
            uf.f_basistofunction(g_basis["x"], 0, g_coef_curr, g_basis), q1,
            q2, sigma1_curr**2, SSE_curr)

        # save updates to results
        g_coef[m, :] = g_coef_curr
        sigma1[m] = sigma1_curr
        SSE[m] = SSE_curr
        if mcmcopts["extrainfo"]:
            logl[m] = logl_curr
            accept[m] = accepti
            accept_betas[m] = zpcnInd

    # calculate posterior mean of psi
    pw_sim_est_psi_matrix = np.zeros((numSimPoints, valid_index.shape[0]))
    for k in range(0, valid_index.shape[0]):
        g_temp = uf.f_basistofunction(g_basis["x"], 0,
                                      g_coef[valid_index[k], :], g_basis)
        psi_temp = uf.f_exp1(g_temp)
        pw_sim_est_psi_matrix[:, k] = psi_temp

    result_posterior_psi_simDomain = uf.f_psimean(pw_sim_global_domain_par,
                                                  pw_sim_est_psi_matrix)

    # resample to same number of points as the input f1 and f2
    interp = interp1d(np.linspace(0, 1,
                                  result_posterior_psi_simDomain.shape[0]),
                      result_posterior_psi_simDomain,
                      fill_value="extrapolate")
    result_posterior_psi = interp(np.linspace(0, 1, f1i.shape[0]))

    # transform posterior mean of psi to gamma
    result_posterior_gamma = uf.f_phiinv(result_posterior_psi)
    result_posterior_gamma = uf.norm_gam(result_posterior_gamma)

    # warped f2
    f2_warped = uf.warp_f_gamma(time, f2i, result_posterior_gamma)

    if mcmcopts["extrainfo"]:
        M, N = pw_sim_est_psi_matrix.shape
        gamma_mat = np.zeros((time.shape[0], N))
        one_v = np.ones(M)
        Dx = np.zeros(N)
        Dy = Dx
        for ii in range(0, N):
            interp = interp1d(np.linspace(
                0, 1, result_posterior_psi_simDomain.shape[0]),
                              pw_sim_est_psi_matrix[:, ii],
                              fill_value="extrapolate")
            result_i = interp(time)
            tmp = uf.f_phiinv(result_i)
            gamma_mat[:, ii] = uf.norm_gam(tmp)
            v, theta = geo.inv_exp_map(one_v, pw_sim_est_psi_matrix[:, ii])
            Dx[ii] = np.sqrt(trapz(v**2, pw_sim_global_domain_par))
            q2warp = uf.warp_q_gamma(pw_sim_global_domain_par, q2,
                                     gamma_mat[:, ii])
            Dy[ii] = np.sqrt(trapz((q1i - q2warp)**2, time))

        gamma_stats = uf.statsFun(gamma_mat)

    results_o = collections.namedtuple('align_bayes', [
        'f2_warped', 'gamma', 'g_coef', 'psi', 'sigma1', 'accept', 'betas_ind',
        'logl', 'gamma_mat', 'gamma_stats', 'xdist', 'ydist'
    ])

    out = results_o(f2_warped, result_posterior_gamma, g_coef,
                    result_posterior_psi, sigma1, accept[1:], accept_betas[1:],
                    logl, gamma_mat, gamma_stats, Dx, Dy)

    return (out)