def eval_f(Y):
    """ some reformulations to make eval_f_orig
        compatible with algopy

        missing: support for scipy.linalg.expm

        i.e., this function can't be differentiated with algopy

    """

    a, b, v = transform_params(Y)

    Q = algopy.zeros((4,4), dtype=Y)
    Q[0,0] = 0;    Q[0,1] = a;    Q[0,2] = b;    Q[0,3] = b;
    Q[1,0] = a;    Q[1,1] = 0;    Q[1,2] = b;    Q[1,3] = b;
    Q[2,0] = b;    Q[2,1] = b;    Q[2,2] = 0;    Q[2,3] = a;
    Q[3,0] = b;    Q[3,1] = b;    Q[3,2] = a;    Q[3,3] = 0;

    Q = Q * v
    Q -= algopy.diag(algopy.sum(Q, axis=1))
    #P = linalg.expm(Q)
    # XXX can I get rid of the 4 on the following line?
    P = algopy_expm(Q, 4)
    S = algopy.log(algopy.dot(algopy.diag(v), P))
    return -algopy.sum(S * g_data)
Example #2
0
def eval_f(Y):
    """ some reformulations to make eval_f_orig
        compatible with algopy

        missing: support for scipy.linalg.expm

        i.e., this function can't be differentiated with algopy

    """

    a, b, v = transform_params(Y)

    Q = algopy.zeros((4, 4), dtype=Y)
    Q[0, 0] = 0
    Q[0, 1] = a
    Q[0, 2] = b
    Q[0, 3] = b
    Q[1, 0] = a
    Q[1, 1] = 0
    Q[1, 2] = b
    Q[1, 3] = b
    Q[2, 0] = b
    Q[2, 1] = b
    Q[2, 2] = 0
    Q[2, 3] = a
    Q[3, 0] = b
    Q[3, 1] = b
    Q[3, 2] = a
    Q[3, 3] = 0

    Q = Q * v
    Q -= algopy.diag(algopy.sum(Q, axis=1))
    P = algopy.expm(Q)
    S = algopy.log(algopy.dot(algopy.diag(v), P))
    return -algopy.sum(S * g_data)
Example #3
0
def pre_Q_to_Q(pre_Q, stationary_distn, target_expected_rate):
    """
    Return a matrix with a different diagonal and a different scaling.
    """
    unscaled_Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    r = -algopy.dot(algopy.diag(unscaled_Q), stationary_distn)
    Q = (target_expected_rate / r) * unscaled_Q
    return Q
Example #4
0
def get_Q_unconstrained_kb(
        ts, tv, syn, nonsyn, compo, asym_compo,
        h,
        log_counts,
        log_mu, log_kappa, log_omega, d, log_kb, log_nt_weights):
    """
    This adds yet another parameter.
    """
    #FIXME: constructing this each time seems wasteful
    codon_neighbor_mask = ts + tv
    #FIXME: this is being hacked to use fixed-order quadrature
    #FIXME: and to disregard the h parameter
    mu = algopy.exp(log_mu)
    kappa = algopy.exp(log_kappa)
    omega = algopy.exp(log_omega)
    F = get_selection_F(log_counts, compo, log_nt_weights)
    S = get_selection_S(F)
    H = get_fixation_unconstrained_kb_fquad(
            S, d, log_kb, g_quad_x, g_quad_w, codon_neighbor_mask)
    #H = get_fixation_unconstrained_kb_fquad_cython(
            #S, d, log_kb, codon_neighbor_mask)
    pre_Q = mu * (kappa * ts + tv) * (omega * nonsyn + syn) * algopy.exp(
            algopy.dot(asym_compo, log_nt_weights)) * H
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    return Q
Example #5
0
def get_Q(
        ts, tv, syn, nonsyn, compo, asym_compo,
        h,
        log_counts,
        log_mu, log_kappa, log_omega, log_nt_weights):
    """
    Notation is from Yang and Nielsen 2008.
    The first group of args consists of precomputed ndarrays.
    The second group is only the fixation function.
    The third group consists of empirically (non-free) estimated parameters.
    The fourth group depends only on free parameters.
    @param ts: indicator for transition
    @param tv: indicator for transversion
    @param syn: indicator for synonymous codons
    @param nonsyn: indicator for nonsynonymous codons
    @param compo: site independent nucleotide composition per codon
    @param asym_compo: tensor from get_asym_compo function
    @param h: fixation function
    @param log_counts: empirically counted codons in the data set
    @param log_mu: free param for scaling
    @param log_kappa: free param for transition transversion rate distinction
    @param log_omega: free param for syn nonsyn rate distinction
    @param log_nt_weights: mostly free param array for mutation equilibrium
    @return: rate matrix
    """
    mu = algopy.exp(log_mu)
    kappa = algopy.exp(log_kappa)
    omega = algopy.exp(log_omega)
    F = get_selection_F(log_counts, compo, log_nt_weights)
    S = get_selection_S(F)
    pre_Q = mu * (kappa * ts + tv) * (omega * nonsyn + syn) * algopy.exp(
            algopy.dot(asym_compo, log_nt_weights)) * h(S)
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    return Q
def centered_tree_covariance(B, nleaves, v):
    """
    @param B: rows of this unweighted incidence matrix are edges
    @param nleaves: number of leaves
    @param v: vector of edge variances
    """
    #TODO: track the block multiplication through the schur complement
    W = diag(reciprocal(v))
    L = dot(B.T, dot(W, B))
    #print('full laplacian matrix:')
    #print(L)
    #print()
    nvertices = v.shape[0]
    ninternal = nvertices - nleaves
    Laa = L[:nleaves, :nleaves]
    Lab = L[:nleaves, nleaves:]
    Lba = L[nleaves:, :nleaves]
    Lbb = L[nleaves:, nleaves:]
    L_schur = Laa - dot(Lab, dot(inv(Lbb), Lba))
    L_schur_pinv = restored(inv(augmented(L_schur)))
    #print('schur laplacian matrix:')
    #print(L_schur)
    #print()
    #print('pinv of schur laplacian matrix:')
    #print(L_schur_pinv)
    #print()
    return L_schur_pinv
Example #7
0
def get_Q_slsqp(
        ts, tv, syn, nonsyn, compo, asym_compo,
        h,
        log_counts, v,
        theta):
    #FIXME: hardcoded for selection without recessivity parameters
    #
    # unpack theta
    branch_length = theta[0]
    kappa = theta[1]
    omega = theta[2]
    """
    nt_probs = algopy.zeros(4, dtype=theta)
    nt_probs[0] = theta[3]
    nt_probs[1] = theta[4]
    nt_probs[2] = theta[5]
    nt_probs[3] = 1.0 - algopy.sum(nt_probs)
    print nt_probs
    log_nt_weights = algopy.log(nt_probs)
    """
    log_nt_weights = theta[-4:]
    #
    F = get_selection_F(log_counts, compo, log_nt_weights)
    S = get_selection_S(F)
    pre_Q_exch = (kappa * ts + tv) * (omega * nonsyn + syn)
    pre_Q = pre_Q_exch * algopy.exp(
            algopy.dot(asym_compo, log_nt_weights)) * h(S)
    rates = algopy.sum(pre_Q, axis=1)
    Q = pre_Q - algopy.diag(rates)
    Q *= branch_length / algopy.dot(rates, v)
    return Q
Example #8
0
def get_Q(
        ts, tv, syn, nonsyn, compo, asym_compo,
        h,
        log_counts,
        log_mu, log_kappa, log_omega, log_nt_weights):
    """
    Notation is from Yang and Nielsen 2008.
    The first group of args consists of precomputed ndarrays.
    The second group is only the fixation function.
    The third group consists of empirically (non-free) estimated parameters.
    The fourth group depends only on free parameters.
    Speed matters.
    @param ts: indicator for transition
    @param tv: indicator for transversion
    @param syn: indicator for synonymous codons
    @param nonsyn: indicator for nonsynonymous codons
    @param compo: site independent nucleotide composition per codon
    @param asym_compo: tensor from get_asym_compo function
    @param h: fixation function
    @param log_counts: empirically counted codons in the data set
    @param log_mu: free param for scaling
    @param log_kappa: free param for transition transversion rate distinction
    @param log_omega: free param for syn nonsyn rate distinction
    @param log_nt_weights: mostly free param array for mutation equilibrium
    @return: rate matrix
    """
    mu = algopy.exp(log_mu)
    kappa = algopy.exp(log_kappa)
    omega = algopy.exp(log_omega)
    F = get_selection_F(log_counts, compo, log_nt_weights)
    S = get_selection_S(F)
    pre_Q = mu * (kappa * ts + tv) * (omega * nonsyn + syn) * algopy.exp(
            algopy.dot(asym_compo, log_nt_weights)) * h(S)
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    return Q
def get_log_likelihood(pre_Q_prefix, pre_Q_suffix, v, subs_counts):
    """
    The stationary distribution of P is empirically derived.
    It is proportional to the codon counts by construction.
    @param pre_Q_prefix: component of hadamard decomposition of pre_Q
    @param pre_Q_suffix: component of hadamard decomposition of pre_Q
    @param v: stationary distribution proportional to observed codon counts
    @param subs_counts: observed substitution counts
    """
    Q = get_Q(pre_Q_prefix, pre_Q_suffix)
    #
    P = algopy.expm(Q)
    #
    # This untested eigh approach is way too slow because of the algopy eigh.
    """
    Da = numpy.diag(numpy.sqrt(v))
    Db = numpy.diag(numpy.reciprocal(numpy.sqrt(v)))
    Q_symmetrized = algopy.dot(Da, algopy.dot(Q, Db))
    w, V = algopy.eigh(Q_symmetrized)
    W_exp = algopy.diag(algopy.exp(w))
    P_symmetrized = algopy.dot(V, algopy.dot(W_exp, V.T))
    P = algopy.dot(Db, algopy.dot(P_symmetrized, Da))
    """
    #
    log_score_matrix = algopy.log(algopy.dot(algopy.diag(v), P))
    log_likelihood = algopy.sum(log_score_matrix * subs_counts)
    return log_likelihood
Example #10
0
def get_Q(
        gtr, syn, nonsyn, compo, asym_compo,
        h,
        log_counts,
        log_mu, log_g, log_omega, log_nt_weights):
    """
    Most of the notation is from Yang and Nielsen 2008.
    The first group of args consists of precomputed ndarrays.
    The second group is only the fixation function.
    The third group consists of empirically (non-free) estimated parameters.
    The fourth group depends only on free parameters.
    @param gtr: ndim-3 ndarray indicating the nucleotide exchange type
    @param syn: indicator for synonymous codons
    @param nonsyn: indicator for nonsynonymous codons
    @param compo: site independent nucleotide composition per codon
    @param asym_compo: tensor from get_asym_compo function
    @param h: fixation function
    @param log_counts: empirically counted codons in the data set
    @param log_mu: free param for scaling
    @param log_g: logs of six exchangeabilities
    @param log_omega: free param for syn nonsyn rate distinction
    @param log_nt_weights: mostly free param array for mutation equilibrium
    @return: rate matrix
    """
    mu = algopy.exp(log_mu)
    g = algopy.exp(log_g)
    omega = algopy.exp(log_omega)
    F = get_selection_F(log_counts, compo, log_nt_weights)
    S = get_selection_S(F)
    pre_Q = mu * algopy.dot(gtr, g) * (omega * nonsyn + syn) * algopy.exp(
            algopy.dot(asym_compo, log_nt_weights)) * h(S)
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    return Q
Example #11
0
def create_transition_matrix_numeric(mu, d, v):
    """
    Use numerical integration.
    This is not so compatible with algopy because it goes through fortran.
    Note that d = 2*h - 1 following Kimura 1957.
    The rate mu is a catch-all scaling factor.
    The finite distribution v is assumed to be a stochastic vector.
    @param mu: scales the rate matrix
    @param d: dominance (as opposed to recessiveness) of preferred states.
    @param v: numpy array defining a distribution over states
    @return: transition matrix
    """

    # Construct the numpy matrix whose entries
    # are differences of log equilibrium probabilities.
    # Everything in this code block is pure numpy.
    F = numpy.log(v)
    e = numpy.ones_like(F)
    S = numpy.outer(e, F) - numpy.outer(F, e)

    # Create the rate matrix Q and return its matrix exponential.
    # Things in this code block may use algopy if mu and d
    # are bundled with truncated Taylor information.
    D = d * numpy.sign(S)
    pre_Q = numpy.vectorize(numeric_fixation)(0.5*S, D)
    pre_Q = mu * pre_Q
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    P = algopy.expm(Q)
    return P
Example #12
0
def create_transition_matrix_numeric(mu, d, v):
    """
    Use numerical integration.
    This is not so compatible with algopy because it goes through fortran.
    Note that d = 2*h - 1 following Kimura 1957.
    The rate mu is a catch-all scaling factor.
    The finite distribution v is assumed to be a stochastic vector.
    @param mu: scales the rate matrix
    @param d: dominance (as opposed to recessiveness) of preferred states.
    @param v: numpy array defining a distribution over states
    @return: transition matrix
    """

    # Construct the numpy matrix whose entries
    # are differences of log equilibrium probabilities.
    # Everything in this code block is pure numpy.
    F = numpy.log(v)
    e = numpy.ones_like(F)
    S = numpy.outer(e, F) - numpy.outer(F, e)

    # Create the rate matrix Q and return its matrix exponential.
    # Things in this code block may use algopy if mu and d
    # are bundled with truncated Taylor information.
    D = d * numpy.sign(S)
    pre_Q = numpy.vectorize(numeric_fixation)(0.5 * S, D)
    pre_Q = mu * pre_Q
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    P = algopy.expm(Q)
    return P
Example #13
0
def clever_cross_entropy_trees(B, nleaves, va, vb):
    """
    Try being a little more clever.

    @param B: augmented incidence matrix
    @param nleaves: number of leaves
    @param va: augmented reference point edge variances
    @param vb: augmented test point edge variances
    """

    # deduce some quantities assuming an unrooted bifurcating tree
    ninternal = nleaves - 2
    nvertices = nleaves + ninternal
    nedges = nvertices - 1

    # define an index for taking schur complements
    n = nvertices
    k = nleaves + 1

    # Construct the full Laplacian matrix plus J/n.
    # Take a block of the diagonal, corresponding to the inverse
    # of a schur complement.
    Wa = diag(reciprocal(va))
    La_plus = dot(B.T, dot(Wa, B))
    print(La_plus)
    print(scipy.linalg.eigh(La_plus))
    Laa = La_plus[:k, :k]
    Lab = La_plus[:k, k:]
    Lba = La_plus[k:, :k]
    Lbb = La_plus[k:, k:]
    L_schur_plus = Laa - dot(Lab, dot(inv(Lbb), Lba))
    assert_allclose(inv(L_schur_plus), inv(La_plus)[:k, :k])
    A = inv(La_plus)[:k, :k]
    print(scipy.linalg.eigh(A))

    # Construct the Schur complement of the test point matrix.
    Wb = diag(reciprocal(vb))
    L_plus = dot(B.T, dot(Wb, B))
    Laa = L_plus[:k, :k]
    Lab = L_plus[:k, k:]
    Lba = L_plus[k:, :k]
    Lbb = L_plus[k:, k:]
    L_schur_plus = Laa - dot(Lab, dot(inv(Lbb), Lba))
    B_inv = L_schur_plus
    #return 0.5 * ((n-1) * LOG2PI + trace(dot(B_inv, A)) - log(det(B_inv)))
    return 0.5 * (n * LOG2PI + trace(dot(B_inv, A) - 1) - log(det(B_inv)))
Example #14
0
def get_Q(pre_Q_prefix, pre_Q_suffix):
    """
    @param pre_Q_prefix: this is an algopy aware ndarray
    @param pre_Q_suffix: this is a numpy ndarray
    @return: an algopy aware ndarray
    """
    pre_Q = pre_Q_prefix * pre_Q_suffix
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    return Q
Example #15
0
def guess_branch_length(subs_counts):
    """
    Make a very crude guess of expected number of changes along a branch.
    @param subs_counts: an (nstates, nstates) ndarray of observed substitutions
    @return: crude guess of expected number of changes along the branch
    """
    total_count = algopy.sum(subs_counts)
    diag_count = algopy.sum(algopy.diag(subs_counts))
    crude_estimate = (total_count - diag_count) / float(total_count)
    return crude_estimate
Example #16
0
def get_Q_unconstrained(gtr, syn, nonsyn, compo, asym_compo, h, log_counts,
                        log_mu, log_g, log_omega, d, log_nt_weights):
    mu = algopy.exp(log_mu)
    g = algopy.exp(log_g)
    omega = algopy.exp(log_omega)
    F = get_selection_F(log_counts, compo, log_nt_weights)
    S = get_selection_S(F)
    pre_Q = mu * algopy.dot(gtr, g) * (omega * nonsyn + syn) * algopy.exp(
        algopy.dot(asym_compo, log_nt_weights)) * h(S, d)
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    return Q
Example #17
0
def get_branch_mix(probs, pre_Qs, eq_distns, branch_length):
    """
    This log likelihood calculation function is compatible with algopy.
    Note that the word 'mix' in the function name
    does not refer to a mix of branch lengths,
    but rather to a mixture of unscaled parameterized rate matrices.
    @param probs: discrete distribution of mixture probabilities
    @param pre_Qs: rates with arbitrary scaling and arbitrary diagonals
    @param eq_distns: equilibrium distributions
    @param branch_length: expected number of changes
    @return: transition matrices
    """

    # Subtract diagonals to give the unscaled rate matrices.
    # Also compute the expected rates of the unscaled rate matrices.
    # Use an unnecessarily explicit-looking calculation,
    # because the entries inside the probs list
    # and the entries inside the observed expected rates list
    # each have taylor information,
    # but the lists themselves are not taylor-aware.
    # The code could be re-orgainized later so that we are using
    # more explicitly taylor-aware lists.
    unscaled_Qs = []
    r = 0
    for p, pre_Q, eq_distn in zip(probs, pre_Qs, eq_distns):
        unscaled_Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
        unscaled_Qs.append(unscaled_Q)
        observed_r = -algopy.dot(algopy.diag(unscaled_Q), eq_distn)
        r = r + p * observed_r

    # Compute the correctly scaled rate matrices
    # so that the expected rate of the mixture is equal
    # to the branch length that has been passed as an argument
    # to this function.
    Qs = []
    for unscaled_Q in unscaled_Qs:
        Q = (branch_length / r) * unscaled_Q
        Qs.append(Q)

    # Return the appropriately time-scaled transition matrices.
    return [algopy.expm(Q) for Q in Qs]
Example #18
0
def eval_f_eigh(Y):
    """ some reformulations to make eval_f_orig
        compatible with algopy

        replaced scipy.linalg.expm by a symmetric eigenvalue decomposition

        this function **can** be differentiated with algopy

    """
    a, b, v = transform_params(Y)

    Q = algopy.zeros((4,4), dtype=Y)
    Q[0,0] = 0;    Q[0,1] = a;    Q[0,2] = b;    Q[0,3] = b;
    Q[1,0] = a;    Q[1,1] = 0;    Q[1,2] = b;    Q[1,3] = b;
    Q[2,0] = b;    Q[2,1] = b;    Q[2,2] = 0;    Q[2,3] = a;
    Q[3,0] = b;    Q[3,1] = b;    Q[3,2] = a;    Q[3,3] = 0;

    Q = algopy.dot(Q, algopy.diag(v))
    Q -= algopy.diag(algopy.sum(Q, axis=1))
    va = algopy.diag(algopy.sqrt(v))
    vb = algopy.diag(1./algopy.sqrt(v))
    W, U = algopy.eigh(algopy.dot(algopy.dot(va, Q), vb))
    M = algopy.dot(U, algopy.dot(algopy.diag(algopy.exp(W)), U.T))
    P = algopy.dot(vb, algopy.dot(M, va))
    S = algopy.log(algopy.dot(algopy.diag(v), P))
    return -algopy.sum(S * g_data)
Example #19
0
    def test_svd(self):
        D, P, M, N = 3, 1, 5, 2
        A = UTPM(numpy.random.random((D, P, M, N)))

        U, s, V = svd(A)

        S = zeros((M, N), dtype=A)
        S[:N, :N] = diag(s)

        assert_array_almost_equal((dot(dot(U, S), V.T) - A).data, 0.)
        assert_array_almost_equal((dot(U.T, U) - numpy.eye(M)).data, 0.)
        assert_array_almost_equal((dot(U, U.T) - numpy.eye(M)).data, 0.)
        assert_array_almost_equal((dot(V.T, V) - numpy.eye(N)).data, 0.)
        assert_array_almost_equal((dot(V, V.T) - numpy.eye(N)).data, 0.)
Example #20
0
def get_Q_unconstrained_kb(
        gtr, syn, nonsyn, compo, asym_compo,
        h,
        log_counts,
        log_mu, log_g, log_omega, d, log_kb, log_nt_weights):
    mu = algopy.exp(log_mu)
    g = algopy.exp(log_g)
    omega = algopy.exp(log_omega)
    F = get_selection_F(log_counts, compo, log_nt_weights)
    S = get_selection_S(F)
    pre_Q = mu * algopy.dot(gtr, g) * (omega * nonsyn + syn) * algopy.exp(
            algopy.dot(asym_compo, log_nt_weights)) * h(S, d, log_kb)
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    return Q
Example #21
0
    def test_svd(self):
        D,P,M,N = 3,1,5,2
        A = UTPM(numpy.random.random((D,P,M,N)))

        U,s,V = svd(A)

        S = zeros((M,N),dtype=A)
        S[:N,:N] = diag(s)

        assert_array_almost_equal( (dot(dot(U, S), V.T) - A).data, 0.)
        assert_array_almost_equal( (dot(U.T, U) - numpy.eye(M)).data, 0.)
        assert_array_almost_equal( (dot(U, U.T) - numpy.eye(M)).data, 0.)
        assert_array_almost_equal( (dot(V.T, V) - numpy.eye(N)).data, 0.)
        assert_array_almost_equal( (dot(V, V.T) - numpy.eye(N)).data, 0.)
Example #22
0
def eval_f_explicit(subs_counts, v, Y):
    """
    Note that Y is last for compatibility with functools.partial.
    It is convenient for usage with numdifftools, although this parameter
    ordering is the opposite of the convention of scipy.optimize.
    @return: negative log likelihood
    @param Y: parameters to jointly estimate
    @param subs_counts: observed data
    @param v: fixed equilibrium probabilities for states
    """
    P = create_transition_matrix_explicit(Y, v)
    vdiag = algopy.diag(v)
    J = algopy.dot(vdiag, P)
    S = algopy.log(J)
    return -algopy.sum(S * subs_counts)
Example #23
0
def eval_f_explicit(subs_counts, v, Y):
    """
    Note that Y is last for compatibility with functools.partial.
    It is convenient for usage with numdifftools, although this parameter
    ordering is the opposite of the convention of scipy.optimize.
    @return: negative log likelihood
    @param Y: parameters to jointly estimate
    @param subs_counts: observed data
    @param v: fixed equilibrium probabilities for states
    """
    P = create_transition_matrix_explicit(Y, v)
    vdiag = algopy.diag(v)
    J = algopy.dot(vdiag, P)
    S = algopy.log(J)
    return -algopy.sum(S * subs_counts)
Example #24
0
def create_transition_matrix_explicit(Y, v):
    """
    Use hypergeometric functions.
    Note that d = 2*h - 1 following Kimura 1957.
    The rate mu is a catch-all scaling factor.
    The finite distribution v is assumed to be a stochastic vector.
    @param Y: vector of parameters to optimize
    @param v: numpy array defining a distribution over states
    @return: transition matrix
    """

    n = len(v)
    mu, d = transform_params(Y)

    # Construct the numpy matrix whose entries
    # are differences of log equilibrium probabilities.
    # Everything in this code block is pure numpy.
    F = numpy.log(v)
    e = numpy.ones_like(F)
    S = numpy.outer(e, F) - numpy.outer(F, e)

    # Create the rate matrix Q and return its matrix exponential.
    # Things in this code block may use algopy if mu and d
    # are bundled with truncated Taylor information.
    D = d * numpy.sign(S)

    #FIXME: I would like to further vectorize this block,
    # and also it may currently give subtly wrong results
    # because denom_piecewise may not vectorize correctly.
    pre_Q = algopy.zeros((n, n), dtype=Y)
    for i in range(n):
        for j in range(n):
            pre_Q[i, j] = 1. / denom_piecewise(0.5 * S[i, j], D[i, j])

    pre_Q = mu * pre_Q
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    P = algopy.expm(Q)
    return P
Example #25
0
def create_transition_matrix_explicit(Y, v):
    """
    Use hypergeometric functions.
    Note that d = 2*h - 1 following Kimura 1957.
    The rate mu is a catch-all scaling factor.
    The finite distribution v is assumed to be a stochastic vector.
    @param Y: vector of parameters to optimize
    @param v: numpy array defining a distribution over states
    @return: transition matrix
    """

    n = len(v)
    mu, d = transform_params(Y)

    # Construct the numpy matrix whose entries
    # are differences of log equilibrium probabilities.
    # Everything in this code block is pure numpy.
    F = numpy.log(v)
    e = numpy.ones_like(F)
    S = numpy.outer(e, F) - numpy.outer(F, e)

    # Create the rate matrix Q and return its matrix exponential.
    # Things in this code block may use algopy if mu and d
    # are bundled with truncated Taylor information.
    D = d * numpy.sign(S)

    #FIXME: I would like to further vectorize this block,
    # and also it may currently give subtly wrong results
    # because denom_piecewise may not vectorize correctly.
    pre_Q = algopy.zeros((n,n), dtype=Y)
    for i in range(n):
        for j in range(n):
            pre_Q[i, j] = 1. / denom_piecewise(0.5*S[i, j], D[i, j])

    pre_Q = mu * pre_Q
    Q = pre_Q - algopy.diag(algopy.sum(pre_Q, axis=1))
    P = algopy.expm(Q)
    return P
Example #26
0
def eval_f_eigh(Y):
    """ some reformulations to make eval_f_orig
        compatible with algopy

        replaced scipy.linalg.expm by a symmetric eigenvalue decomposition

        this function **can** be differentiated with algopy

    """
    a, b, v = transform_params(Y)

    Q = algopy.zeros((4, 4), dtype=Y)
    Q[0, 0] = 0
    Q[0, 1] = a
    Q[0, 2] = b
    Q[0, 3] = b
    Q[1, 0] = a
    Q[1, 1] = 0
    Q[1, 2] = b
    Q[1, 3] = b
    Q[2, 0] = b
    Q[2, 1] = b
    Q[2, 2] = 0
    Q[2, 3] = a
    Q[3, 0] = b
    Q[3, 1] = b
    Q[3, 2] = a
    Q[3, 3] = 0

    Q = algopy.dot(Q, algopy.diag(v))
    Q -= algopy.diag(algopy.sum(Q, axis=1))
    va = algopy.diag(algopy.sqrt(v))
    vb = algopy.diag(1. / algopy.sqrt(v))
    W, U = algopy.eigh(algopy.dot(algopy.dot(va, Q), vb))
    M = algopy.dot(U, algopy.dot(algopy.diag(algopy.exp(W)), U.T))
    P = algopy.dot(vb, algopy.dot(M, va))
    S = algopy.log(algopy.dot(algopy.diag(v), P))
    return -algopy.sum(S * g_data)
Example #27
0
def submain_constrained_dominance(args):
    #
    # Precompute some ndarrays
    # according to properties of DNA and the genetic code.
    if args.mtdna or args.force_mtcode:
        code = npcodon.g_code_mito
        stop = npcodon.g_stop_mito
    else:
        code = npcodon.g_code
        stop = npcodon.g_stop
    #
    all_codons = npcodon.enum_codons(stop)
    codons = all_codons[:-len(stop)]
    ts, tv = npcodon.get_ts_tv(codons)
    syn, nonsyn = npcodon.get_syn_nonsyn(code, codons)
    compo = npcodon.get_compo(codons)
    asym_compo = npcodon.get_asym_compo(codons)
    ham = npcodon.get_hamming(codons)
    #
    subs_counts = yangdata.get_subs_counts_from_data_files(args)
    codon_counts = numpy.sum(subs_counts, axis=0) + numpy.sum(
            subs_counts, axis=1)
    for a, b in zip(codons, codon_counts):
        print a, ':', b
    print 'raw codon total:', numpy.sum(codon_counts)
    print 'raw codon counts:', codon_counts
    codon_counts = codon_counts[:len(codons)]
    print 'non-stop codon total:', numpy.sum(codon_counts)
    subs_counts = subs_counts[:len(codons), :len(codons)]
    v = codon_counts / float(numpy.sum(codon_counts))
    log_counts = numpy.log(codon_counts)
    #
    if args.disease == 'genic':
        h = get_fixation_genic
    elif args.disease == 'recessive':
        h = get_fixation_recessive_disease
    elif args.disease == 'dominant':
        h = get_fixation_dominant_disease
    else:
        raise Exception
    #
    # initialize parameter values
    mu_r = 1.0
    kappa = 2.0
    omega = 0.1
    #pA = 0.25
    #pC = 0.25
    #pG = 0.25
    #pT = 0.25
    theta = numpy.array([mu_r, kappa, omega, 0, 0, 0, 0])
    #
    # adjust the expected rate parameter
    Q = get_Q_slsqp(
            ts, tv, syn, nonsyn, compo, asym_compo,
            h,
            log_counts, v,
            theta)
    expected_rate = -algopy.dot(algopy.diag(Q), v)
    mu_n = 1. / expected_rate
    mu_r = npcodon.get_lb_expected_subs(ham, subs_counts)
    theta = numpy.array([mu_r, kappa, omega, 0, 0, 0, 0])
    #
    # get the log likelihood associated with the initial guess
    fmin_args = (
            subs_counts, log_counts, v,
            h,
            ts, tv, syn, nonsyn, compo, asym_compo,
            )
    initial_cost = eval_f(theta, *fmin_args)
    print 'negative log likelihood of initial guess:',
    print initial_cost
    print
    print 'entropy bound on negative log likelihood:',
    print npcodon.get_lb_neg_ll(subs_counts)
    print
    do_opt(args, eval_f, theta, fmin_args)
Example #28
0
def rhfenergy(alpha_old, coef2, xyz, l, charges, xyz_atom, natoms, nbasis,
              contr_list, ne, max_scf, max_d, log, eigen, printguess,
              readguess, name, write, dtype):
    '''
    This function returns the rhf function

    Parameters:
     alpha_old : array
                Gaussian exponents
     coef2     : array
                Contraction coeffients
     xyz       : array 3N
                Gaussian centers
     l         : array 3N
                Angular momentum each entry is a vector
                eg. s orbital (0,0,0) or pz (1,0,0)
     charges   : array
                Atom charges
     nbasis    : int
                Number of basis
     contr_list: list of integers
                Specify the number of orbitals in each atom
     ne        : int
                Number of electrons
     max_scf   : int
                maximum number of scf cycles
     log       : bool
                The exponents are given in log
     printguess: str or None
                File to print coeff matrix initial guess
     readguess : str or None
                File that contains coeff matrix initial guess
     name      : str
                Output file name
     write     : bool
                True if printing
     dtype     : type of output
                This is the directive to know if algopy will be used or not
                np.float64(1.0) if it is a single point calculation
                otherwise, it specify the size of the UTMP, autodifferentiation
    Returns:
       energy    : float
                RHF energy
    '''
    tool_D = 1e-8
    tool = 1e-8

    if log:
        alpha = algopy.exp(alpha_old)
    else:
        alpha = alpha_old

    if type(xyz_atom) != np.ndarray:  ## Cover the case of diff xyz atom
        coef = normalization(alpha,
                             coef2,
                             l,
                             contr_list,
                             dtype=np.float64(1.0))
        V = nuclearmatrix(alpha,
                          coef,
                          xyz,
                          l,
                          nbasis,
                          charges,
                          xyz_atom,
                          natoms,
                          contr_list,
                          dtype=dtype)
        S = overlapmatrix(alpha,
                          coef,
                          xyz,
                          l,
                          nbasis,
                          contr_list,
                          dtype=np.float64(1.0))
        T = kineticmatrix(alpha,
                          coef,
                          xyz,
                          l,
                          nbasis,
                          contr_list,
                          dtype=np.float64(1.0))
        Eri = erivector(alpha,
                        coef,
                        xyz,
                        l,
                        nbasis,
                        contr_list,
                        dtype=np.float(1.0))
    else:
        coef = normalization(alpha, coef2, l, contr_list, dtype=dtype)
        S = overlapmatrix(alpha, coef, xyz, l, nbasis, contr_list, dtype=dtype)
        V = nuclearmatrix(alpha,
                          coef,
                          xyz,
                          l,
                          nbasis,
                          charges,
                          xyz_atom,
                          natoms,
                          contr_list,
                          dtype=dtype)
        T = kineticmatrix(alpha, coef, xyz, l, nbasis, contr_list, dtype=dtype)
        Eri = erivector(alpha, coef, xyz, l, nbasis, contr_list, dtype=dtype)
    Hcore = T + V
    if eigen:
        eigsys = eigensolver(S)
        SqrtLambda = algopy.diag(1. / algopy.sqrt(eigsys[0]))
        L = eigsys[1]
        LT = algopy.transpose(L)
        SqrtS = algopy.dot(algopy.dot(L, SqrtLambda), LT)
        SqrtST = algopy.transpose(SqrtS)
    else:
        Sinv = np.linalg.inv(S)

    if readguess != None:
        C = np.load(readguess)
        D = np.zeros((nbasis, nbasis))
        for i in range(nbasis):
            for j in range(nbasis):
                tmp = 0.0
                for k in range(ne):
                    tmp = tmp + C[i, k] * C[j, k]
                D[i, j] = tmp
        F = fockmatrix(Hcore, Eri, D, nbasis, alpha, dtype)
    else:
        F = Hcore
    OldE = 1e8

    status = False
    E_step = []
    for scf_iter in range(max_scf):
        if eigen:
            Fprime = algopy.dot(algopy.dot(SqrtST, F), SqrtS)
            eigsysFockOp = eigensolver(Fprime)
            Cprime = eigsysFockOp[1]
            C = algopy.dot(SqrtS, Cprime)
            Fprime = algopy.dot(algopy.dot(SqrtST, F), SqrtS)
            eigsysFockOp = eigensolver(Fprime)
            Cprime = eigsysFockOp[1]
            C = algopy.dot(SqrtS, Cprime)
            D = algopy.zeros((nbasis, nbasis), dtype=dtype)
            for i in range(nbasis):
                for j in range(nbasis):
                    tmp = 0.0
                    for k in range(ne):
                        tmp = tmp + C[i, k] * C[j, k]
                    D[i, j] = tmp
        else:
            D = newdensity(F, Sinv, nbasis, ne)
            for i in range(max_d):
                D = cannonicalputication(D, S)
                err = np.linalg.norm(D - np.dot(np.dot(D, S), D))
                if err < tool_D:
                    break
        F = fockmatrix(Hcore, Eri, D, nbasis, alpha, dtype)
        E_elec = algopy.sum(np.multiply(D, Hcore + F))
        E_step.append(E_elec)
        E_nuc = nuclearrepulsion(xyz_atom, charges, natoms)
        if np.absolute(E_elec - OldE) < tool:
            status = True
            break
        OldE = E_elec
    E_nuc = nuclearrepulsion(xyz_atom, charges, natoms)
    if printguess != None:
        np.save(printguess, C)

    def update_system():
        mol.energy = E_elec + E_nuc
        mol.erepulsion = Eri
        mol.hcore = Hcore
        mol.mo_coeff = C
        return

    def write_molden():
        import Data
        from Data import select_atom
        ## Details of calculation
        tape.write('[Energy] \n')
        tape.write('E_elec: ' + str(E_elec) + '\n')
        tape.write('E_nuc: ' + str(E_nuc) + '\n')
        tape.write('E_tot: ' + str(E_nuc + E_elec) + '\n')
        tape.write('SCF Details\n')
        line = 'Eigen: '
        if eigen:
            tape.write(line + 'True')
        else:
            tape.write(line + 'False')
        tape.write('\n')
        for i, step in enumerate(E_step):
            line = 'Step: ' + str(i) + ' ' + str(step)
            tape.write(line + '\n')

        ### C Matrix
        tape.write('[CM] \n')
        tape.write('C AO times MO\n')
        printmatrix(C, tape)

        ### D Matrix
        tape.write('[DM] \n')
        tape.write('D \n')
        printmatrix(D, tape)

        ### D Matrix
        tape.write('[NMO] \n')
        tape.write('NMO \n')
        printmatrix(mo_naturalorbital(D), tape)

        ### MO energies
        tape.write('[MOE] \n')
        tape.write('MOE \n')
        for i, energ in enumerate(eigsysFockOp[0]):
            tape.write(str(i) + ' ' + str(energ) + '\n')

        ### MO energies
        tape.write('[INPUT] \n')
        line = 'mol = ['
        for i, coord in enumerate(xyz_atom):
            line += '(' + str(charges[i]) + ','
            line += '(' + str(coord[0]) + ',' + str(coord[1]) + ',' + str(
                coord[2]) + ')),\n'
        tape.write(line)
        cont = 0
        line = 'basis = ['
        for i, ci in enumerate(contr_list):
            line += '['
            line += '(' + str(l[i][0]) + ',' + str(l[i][1]) + ',' + str(
                l[i][2]) + '),'
            for ii in range(ci):
                line += str(alpha[cont]) + ',' + str(coef[i])
                line += ',(' + str(xyz[i, 0]) + ',' + str(
                    xyz[i, 1]) + ',' + str(xyz[i, 2]) + ')],\n'
                cont += 1
            line += ']\n'
        tape.write(line)

        ### Atom coordinates
        tape.write('[Atoms]\n')
        for i, coord in enumerate(xyz_atom):
            line = select_atom.get(charges[i])
            line += ' ' + str(i + 1) + ' ' + str(charges[i])
            line += ' ' + str(coord[0]) + ' ' + str(coord[1]) + ' ' + str(
                coord[2]) + '\n'
            tape.write(line)
        ### Basis coordinates
        for i, coord in enumerate(xyz):
            line = 'XX'
            line += ' ' + str(i + natoms + 1) + ' ' + str(0)
            line += ' ' + str(coord[0]) + ' ' + str(coord[1]) + ' ' + str(
                coord[2]) + '\n'
            tape.write(line)

        ### Basis set
        cont = 0
        tape.write('[GTO]\n')
        for i, ci in enumerate(contr_list):
            tape.write('  ' + str(i + 1 + natoms) + '  0\n')
            if np.sum(l[i]) == 0:
                tape.write(' s   ' + str(ci) + ' 1.0 ' + str(l[i][0]) + ' ' +
                           str(l[i][1]) + ' ' + str(l[i][2]) + '\n')
            else:
                tape.write(' p   ' + str(ci) + ' 1.0 ' + str(l[i][0]) + ' ' +
                           str(l[i][1]) + ' ' + str(l[i][2]) + '\n')
                #tape.write(' p   '+str(1)+' 1.0 '+ str(l[i])+'\n')
            for ii in range(ci):
                line = '  ' + str(alpha[cont]) + ' ' + str(coef[cont]) + '\n'
                tape.write(line)
                cont += 1
            line = '  \n'
            tape.write(line)
        ### MOs
        tape.write('[MO]\n')
        for j in range(nbasis):
            tape.write('  Sym=  None\n')
            tape.write('  Ene=      ' + str(eigsysFockOp[0][j]) + '\n')
            tape.write('  Spin= Alpha\n')
            if j > ne:
                tape.write('  Occup=    0.0\n')
            else:
                tape.write('  Occup=    2.0\n')
            for i in range(nbasis):
                tape.write(str(i + 1 + natoms) + ' ' + str(C[i, j]) + '\n')

    if status:
        if write:
            tape = open(name + '.molden', "w")
            write_molden()
            tape.close()
            return E_elec + E_nuc
    else:
        print('E_elec: ' + str(E_elec) + '\n')
        print('E_nuc: ' + str(E_nuc) + '\n')
        print('E_tot: ' + str(E_nuc + E_elec) + '\n')
        print('SCF DID NOT CONVERGED')
        return 99999

    return E_elec + E_nuc