https://github.com/cran/ape
Raw File
Tip revision: 356688ebfa433690c15cc9a0958ce55a92e2cba7 authored by Emmanuel Paradis on 14 December 2006, 00:00:00 UTC
version 1.9-1
Tip revision: 356688e
mlphylo.c
/* mlphylo.c       2006-07-17 */

/* Copyright 2006 Emmanuel Paradis */

/* This file is part of the R-package `ape'. */
/* See the file ../COPYING for licensing issues. */

#include <R.h>
#include <Rmath.h>
#include <R_ext/Applic.h>
#include <R_ext/Lapack.h>

typedef struct {
  double *A, *C, *G, *T;
} dna_matrix;

typedef struct {
  int *s1, *s2, *a;
} matching;

typedef struct {
  int *n; int *limit; int *model; double *xi;
} part_dna;

typedef struct {
  double *para; int *n; int *pim;
} para_dna;

typedef struct {
  int *ncat; double *alpha; int *n; int *pim;
} gamma_dna;

typedef struct {
  double *I; int *n; int *pim;
} invar_dna;

typedef struct {
  int *n; int *s; dna_matrix X; double *w;
  matching match; double *edge_length;
  part_dna partition; para_dna PAR;
  gamma_dna GAMMA; invar_dna INV; double *BF;
} DNAdata;

typedef struct {
  DNAdata *D; int i;
} info;

void tQ_unbalBF(double *BF, double *P)
/* This function computes the rate matrix Q multiplied by */
/* time t in the case of unbalanced base frequencies. */
/* The arguments are: */
/*BF: the base frequencies */
/* P: (input) the matrix of substitution rates */
/*    (output) tQ */
/* NOTE: P must already be multiplied by t. */
{
   P[1] *= BF[0];  P[2] *= BF[0];  P[3] *= BF[0];
   P[4] *= BF[1];  P[6] *= BF[1];  P[7] *= BF[1];
   P[8] *= BF[2];  P[9] *= BF[2]; P[11] *= BF[2];
  P[12] *= BF[3]; P[13] *= BF[3]; P[14] *= BF[3];

   P[0] = -P[4] - P[8] - P[12];
   P[5] = -P[1] - P[9] - P[13];
  P[10] = -P[2] - P[6] - P[14];
  P[15] = -P[3] - P[7] - P[11];
}

void mat_expo4x4(double *P)
/* This function computes the exponential of a 4x4 matrix */
{
  double U[16], vl[4], WR[4], Uinv[16], WI[4], work[32];
  int i, j, info, ipiv[16], n = 4, lw = 32, ord[4];
  char yes = 'V', no = 'N';


  /* The matrix is not symmetric, so we use 'dgeev'. */
  /* We take the real part of the eigenvalues -> WR */
  /* and the right eigenvectors (vr) -> U */
  F77_CALL(dgeev)(&no, &yes, &n, P, &n, WR, WI, vl, &n,
		  U, &n, work, &lw, &info);

  /* It is not necessary to sort the eigenvalues... */

  /* Copy U -> P */
  for (i = 0; i < 16; i++) P[i] = U[i];

  /* For the inversion, we first make Uinv an identity matrix */
  for (i = 1; i < 15; i++) Uinv[i] = 0;
  Uinv[0] = Uinv[5] = Uinv[10] = Uinv[15] = 1;

  /* The matrix is not symmetric, so we use 'dgesv'. */
  /* This subroutine puts the result in Uinv (B) */
  /* (P [= U] is erased) */
  F77_CALL(dgesv)(&n, &n, P, &n, ipiv, Uinv, &n, &info);

  /* The matrix product of U with the eigenvalues diagonal matrix: */
  for (i = 0; i < 4; i++) U[i] *= exp(WR[0]);
  for (i = 4; i < 8; i++) U[i] *= exp(WR[1]);
  for (i = 8; i < 12; i++) U[i] *= exp(WR[2]);
  for (i = 12; i < 16; i++) U[i] *= exp(WR[3]);

  /* The second matrix product with U^-1 */
  P[1] = U[1]*Uinv[0] + U[5]*Uinv[1] + U[9]*Uinv[2] + U[13]*Uinv[3];
  P[2] = U[2]*Uinv[0] + U[6]*Uinv[1] + U[10]*Uinv[2] + U[14]*Uinv[3];
  P[3] = U[3]*Uinv[0] + U[7]*Uinv[1] + U[11]*Uinv[2] + U[15]*Uinv[3];
  P[0] = 1 - P[1] - P[2] - P[3];
  P[4] = U[0]*Uinv[4] + U[4]*Uinv[5] + U[8]*Uinv[6] + U[12]*Uinv[7];
  P[6] = U[2]*Uinv[4] + U[6]*Uinv[5] + U[10]*Uinv[6] + U[14]*Uinv[7];
  P[7] = U[3]*Uinv[4] + U[7]*Uinv[5] + U[11]*Uinv[6] + U[15]*Uinv[7];
  P[5] = 1 - P[4] - P[6] - P[7];
  P[8] = U[0]*Uinv[8] +  U[4]*Uinv[9] + U[8]*Uinv[10] + U[12]*Uinv[11];
  P[9] = U[1]*Uinv[8] +  U[5]*Uinv[9] + U[9]*Uinv[10] + U[13]*Uinv[11];
  P[11] = U[3]*Uinv[8] +  U[7]*Uinv[9] + U[11]*Uinv[10] + U[15]*Uinv[11];
  P[10] = 1 - P[8] - P[9] - P[11];
  P[12] = U[0]*Uinv[12] + U[4]*Uinv[13] + U[8]*Uinv[14] + U[12]*Uinv[15];
  P[13] = U[1]*Uinv[12] + U[5]*Uinv[13] + U[9]*Uinv[14] + U[13]*Uinv[15];
  P[14] = U[2]*Uinv[12] + U[6]*Uinv[13] + U[10]*Uinv[14] + U[14]*Uinv[15];
  P[15] = 1 - P[12] - P[13] - P[14];
}

void PMAT_JC69(double t, double u, double *P)
{
  P[1]=P[2]=P[3]=P[4]=P[6]=P[7]=P[8]=P[9]=P[11]=P[12]=P[13]=P[14]=(1 - exp(-4*u*t))/4;
  P[0] = P[5] = P[10] = P[15] = 1 - 3*P[1];
}

void PMAT_K80(double t, double a, double b, double *P)
{
  double R, p;

  R = a/(2*b);
  p = exp(-2*t/(R + 1));

  P[1] = 0.5 * (1 - p); /* A -> C */
  P[2] = 0.25 - 0.5 * exp(-t*(2*R + 1)/(R + 1)) + 0.25 * p; /* A -> G */
  P[0] = P[5] = P[10] = P[15] = 1 - 2 * P[1] - P[2];
  P[3] = P[4] = P[6] = P[8] =  P[9] = P[12] = P[13] = P[1];
  P[7] = P[11] = P[14] = P[2];
}

void PMAT_F81(double t, double u, double *BF, double *P)
{
  double p;
  p = exp(-t*u);

  P[0] = p + (1 - p) * BF[0]; /* A->A */
  P[1] = P[9] = P[13] = (1 - p)*BF[1]; /* A->C, G->C, T->C */
  P[2] = P[6] = P[14] = (1 - p)*BF[2]; /* A->G, C->G, T->G */
  P[3] = P[7] = P[11] = (1 - p)*BF[3]; /* A->T, C->T, G->T */
  P[4] = P[8] = P[12] = (1 - p)*BF[0]; /* C->A, G->A, T->A */
  P[5] = p + P[1]; /* C->C */
  P[10] = p + P[2]; /* G->G */
  P[15] = p + P[3]; /* T->T */
}

void PMAT_F84(double t, double a, double b, double *BF, double *P)
{
  double pI, pII, B, x, y;

  B = exp(-b*t);
  pI = B * (1 - exp(-a*t)); /* probability of at least one event of type I */
  pII = 1 - B; /* probability of at least one event of type II */
  x = pI * (BF[0] + BF[2]);
  y = pI * (BF[1] + BF[3]);

  P[12] = P[4] = pII * BF[0];   /* C->A, T->A */
  P[14] = P[6] = pII * BF[2];   /* C->G, T->G */
  P[9] = P[1] = pII * BF[1];   /* A->C, G->C */
  P[2] = x + P[6];      /* A->G */
  P[11] = P[3] = pII * BF[3];   /* A->T, G->T*/
  P[0] = 1 - P[1] - P[2] - P[3];  /* A->A */
  P[7] = y +  P[3];     /* C->T */
  P[5] = 1 - P[4] - P[6] - P[7];  /* C->C */
  P[8] = x + P[4];      /* G->A */
  P[10] = 1 - P[8] - P[9] - P[11]; /* G->G */
  P[13] = y + P[1];     /* T->C */
  P[15] = 1 - P[12] - P[13] - P[14]; /* T->T */
}

void PMAT_HKY85(double t, double a, double b, double *BF, double *P)
{
  P[2] = P[7] = P[8] = P[13] = t*a;
  P[1] = P[3] = P[4] = P[6] = P[9] = P[11] = P[12] = P[14] = t*b;
  tQ_unbalBF(BF, P);
  mat_expo4x4(P);
}

void PMAT_T92(double t, double a, double b, double *BF, double *P)
{
  double theta, A, B1, B2, C, x, y;

  theta = BF[1] + BF[2];
  A = (1 - theta)/2;
  B1 = (1 + exp(-t));
  B2 = (1 - exp(-t));
  C = exp(-t * ((a/b + 1)/2));
  x = 0.5 * theta * B1;
  y = (1 - theta) * C;

  P[1] = P[6] = P[9] = P[14] = 0.5 * theta * B2; /* A->C, C->G, T->G, G->C */
  P[2] = P[13] = x - theta * C; /* A->G, T->C */
  P[3] = P[4] = P[11] = P[12] = A * B2; /* A->T, C->A, G->T, T->A */
  P[0] = P[15] = 1 - P[1] - P[2] - P[3]; /* A->A, T->T */
  P[5] = P[10] = x + y; /* C->C, G->G */
  P[7] = P[8] = A * B1 - y; /* C->T, G->A */
}

void PMAT_TN93(double t, double a1, double a2, double b,
	       double *BF, double *P)
{

  double A1, A2, B;

  A1 = (1 - exp(-a1*t)); /* transitions between purines (A <-> G) */
  A2 = (1 - exp(-a2*t)); /* transitions between pyrimidines (C <-> T) */
  B = (1 - exp(-b*t));

  P[1] = B * BF[1];                  /* A->C */
  P[2] = A1 * BF[2];                 /* A->G */
  P[3] = B * BF[3];                  /* A->T */
  P[0] = 1 - P[1] - P[2] - P[3];     /* A->A */
  P[4] = B * BF[0];                  /* C->A */
  P[6] = B * BF[2];                  /* C->G */
  P[7] = A2 * BF[3] ;                /* C->T */
  P[5] = 1 - P[4] - P[6] - P[7];     /* C->C */
  P[8] = A1 * BF[0];                 /* G->A */
  P[9] = B * BF[1];                  /* G->C */
  P[11] = B * BF[3];                 /* G->T */
  P[10] = 1 - P[8] - P[9] - P[11];   /* G->G */
  P[12] = B * BF[0];                 /* T->A */
  P[13] = A2 * BF[1];                /* T->C */
  P[14] = B * BF[2];                 /* T->G */
  P[15] = 1 - P[12] - P[13] - P[14]; /* T->T */
}

void PMAT_GTR(double t, double a, double b, double c, double d, double e,
	      double f, double *BF, double *P)
{
  P[1] = P[4] = t*a;
  P[2] = P[8] = t*b;
  P[3] = P[12] = t*c;
  P[6] = P[9] = t*d;
  P[7] = P[13] = t*e;
  P[11] = P[14] = t*f;
  tQ_unbalBF(BF, P);
  mat_expo4x4(P);
}

#define GET_DNA_PARAMETERS                                        \
    /* get the substitution parameters */                         \
    model = PART.model[k];                                        \
    /* If the model is not JC69 or F81: */                        \
    if (model != 1 && model != 3) {                               \
        ind = 0;                                                  \
        for(i = 0; i < *(PARA.n); i++) {                          \
            if (PARA.pim[i + *(PARA.n)*k]) {                      \
        	    u[ind] = PARA.para[i];                        \
        	    ind++;                                        \
	    }                                                     \
        }                                                         \
    }                                                             \
    /* get the shape parameter and calculate the coefficients */  \
    ncat = 1;                                                     \
    if (GAMMA.ncat[k] > 1) {                                      \
        ncat = GAMMA.ncat[k];                                     \
        /* use `tmp[0]' to store the mean of the coefficients */  \
        /* in order to rescale them */                            \
        tmp[0] = 0.;                                              \
	for(i = 0; i < *(GAMMA.n); i++) {                         \
	    if (GAMMA.pim[i + *(GAMMA.n)*k]) {                    \
	        for (j = 0; j < ncat; j++) {                      \
		    coef_gamma[j] = qgamma((0.5 + j)/ncat,        \
                                           GAMMA.alpha[i],        \
					   1/GAMMA.alpha[i],      \
					   1, 0);                 \
                    tmp[0] += coef_gamma[j];                      \
		}                                                 \
                tmp[0] /= ncat;                                   \
                for (j = 0; j < ncat; j++)                        \
                  coef_gamma[j] /= tmp[0];                        \
	    }                                                     \
	}                                                         \
    } else coef_gamma[0] = 1.;                                    \
    /* get the proportion of invariants */                        \
    I = 0;                                                        \
    for(i = 0; i < *(INV.n); i++) {                               \
        if (INV.pim[i + *(INV.n)*k]) {                            \
	    I = INV.I[i];                                         \
	    break;                                                \
	}                                                         \
    }

#define LOOP_THROUGH_SITES                                             \
    for(j = start; j < end; j++) {                                     \
        i1 = d1 + j*nr;                                                \
        i2 = d2 + j*nr;                                                \
        tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0.0;                       \
	for(i = 0; i < ncat; i++) {                                    \
	    switch(model) {                                            \
	    case 1 : PMAT_JC69(l1, coef_gamma[i], P1);                 \
                     PMAT_JC69(l2, coef_gamma[i], P2); break;          \
	    case 2 : PMAT_K80(l1, coef_gamma[i], u[0], P1);            \
PMAT_K80(l2, coef_gamma[i], u[0], P2); break;                          \
	    case 3 : PMAT_F81(l1, coef_gamma[i], BF, P1);              \
PMAT_F81(l2, coef_gamma[i], BF, P2); break;                            \
	    case 4 : PMAT_F84(l1, coef_gamma[i], u[0], BF, P1);        \
PMAT_F84(l2, coef_gamma[i], u[0], BF, P2); break;                      \
	    case 5 : PMAT_HKY85(l1, coef_gamma[i], u[0], BF, P1);      \
PMAT_HKY85(l2, coef_gamma[i], u[0], BF, P2); break;                    \
	    case 6 : PMAT_T92(l1, coef_gamma[i], u[0], BF, P1);        \
PMAT_T92(l2, coef_gamma[i], u[0], BF, P2); break;                      \
	    case 7 : PMAT_TN93(l1, coef_gamma[i], u[0], u[1], BF, P1); \
PMAT_TN93(l2, coef_gamma[i], u[0], u[1], BF, P2); break;               \
	    case 8 : PMAT_GTR(l1, coef_gamma[i], u[0], u[1],           \
			      u[2], u[3], u[4], BF, P1);               \
PMAT_GTR(l2, coef_gamma[i], u[0], u[1],                                \
			      u[2], u[3], u[4], BF, P2); break;        \
	    }                                                          \
	    tmp[0] += (X.A[i1] * P1[0] + X.C[i1] * P1[1] +             \
		      X.G[i1] * P1[2] + X.T[i1] * P1[3]) *             \
                     (X.A[i2] * P2[0] + X.C[i2] * P2[1] +              \
		      X.G[i2] * P2[2] + X.T[i2] * P2[3]);              \
	    tmp[1] += (X.A[i1] * P1[4] + X.C[i1] * P1[5] +             \
		      X.G[i1] * P1[6] + X.T[i1] * P1[7]) *             \
                     (X.A[i2] * P2[4] + X.C[i2] * P2[5] +              \
		      X.G[i2] * P2[6] + X.T[i2] * P2[7]);              \
	    tmp[2] += (X.A[i1] * P1[8] + X.C[i1] * P1[9] +             \
		      X.G[i1] * P1[10] + X.T[i1] * P1[11]) *           \
                     (X.A[i2] * P2[8] + X.C[i2] * P2[9] +              \
		      X.G[i2] * P2[10] + X.T[i2] * P2[11]);            \
	    tmp[3] += (X.A[i1] * P1[12] + X.C[i1] * P1[13] +           \
		      X.G[i1] * P1[14] + X.T[i1] * P1[15]) *           \
                     (X.A[i2] * P2[12] + X.C[i2] * P2[13] +            \
		      X.G[i2] * P2[14] + X.T[i2] * P2[15]);            \
	}                                                              \
        if (ncat > 1) {                                                \
            tmp[0] /= ncat;                                            \
            tmp[1] /= ncat;                                            \
            tmp[2] /= ncat;                                            \
            tmp[3] /= ncat;                                            \
        }                                                              \
	if (I > 0) { /* maybe use a better comparison */               \
	    V = 1. - I;                                                \
            tmp[0] = V * tmp[0] + I * X.A[ind];                        \
            tmp[1] = V * tmp[1] + I * X.C[ind];                        \
            tmp[2] = V * tmp[2] + I * X.G[ind];                        \
            tmp[3] = V * tmp[3] + I * X.T[ind];                        \
	}                                                              \
        ind = anc + j*nr;                                              \
        X.A[ind] = tmp[0];                                             \
        X.C[ind] = tmp[1];                                             \
        X.G[ind] = tmp[2];                                             \
        X.T[ind] = tmp[3];                                             \
    }

void lik_dna_node(dna_matrix X, int d1, int d2, int anc,
		  double *edge_length, part_dna PART,
		  para_dna PARA, gamma_dna GAMMA,
		  invar_dna INV, double *BF, int nr)
/*
This function computes the likelihoods at a node for all
nucleotides.
*/
{
    int i, j, k, start, end, ind, i1, i2, ncat, model;
    double tmp[4], l1, l2, P1[16], P2[16], V, coef_gamma[10], u[6], I;

    /* change d1, d2, and anc to use them as indices */
    d1--; d2--; anc--;

    l1 = edge_length[d1];
    l2 = edge_length[d2];

    for(k = 0; k < *(PART.n); k++) {
        start = PART.limit[k*2] - 1;
        end = PART.limit[k*2 + 1];

        GET_DNA_PARAMETERS

	if (k > 0) {
	    l1 *= PART.xi[k - 1];
	    l2 *= PART.xi[k - 1];
	}

	LOOP_THROUGH_SITES
    }
} /* EOF lik_dna_node */

void lik_dna_root(dna_matrix X, int d1, int d2, int d3, int anc,
		  double *edge_length, part_dna PART,
		  para_dna PARA, gamma_dna GAMMA,
		  invar_dna INV, double *BF, int nr)
/*
This function computes the likelihoods at the root for all
nucleotides.
*/
{
    int i, j, k, start, end, ind, ncat, model, i1, i2, i3;
    double tmp[4], l1, l2, l3, P1[16], P2[16], P3[16], V,
      coef_gamma[10], u[6], I;

    /* change d1, d1, d3, and anc to use them as indices */
    d1--; d2--; d3--; anc--;

    l1 = edge_length[d1];
    l2 = edge_length[d2];
    l3 = edge_length[d3];

    for(k = 0; k < *(PART.n); k++) {
        start = PART.limit[k*2] - 1;
        end = PART.limit[k*2 + 1];

        GET_DNA_PARAMETERS

	if (k > 0) {
	    l1 *= PART.xi[k - 1];
	    l2 *= PART.xi[k - 1];
	    l3 *= PART.xi[k - 1];
	}

	for(j = start; j < end; j++) {
	    i1 = d1 + j*nr;
	    i2 = d2 + j*nr;
	    i3 = d3 + j*nr;
	    tmp[0] = tmp[1] = tmp[2] = tmp[3] = 0.;
	    for(i = 0; i < ncat; i++) {
	        switch(model) {
		case 1 : PMAT_JC69(l1, coef_gamma[i], P1);
		  PMAT_JC69(l2, coef_gamma[i], P2);
		  PMAT_JC69(l3, coef_gamma[i], P3); break;
		case 2 : PMAT_K80(l1, coef_gamma[i], u[0], P1);
		  PMAT_K80(l2, coef_gamma[i], u[0], P2);
		  PMAT_K80(l3, coef_gamma[i], u[0], P3); break;
		case 3 : PMAT_F81(l1, coef_gamma[i], BF, P1);
		  PMAT_F81(l2, coef_gamma[i], BF, P3);
		  PMAT_F81(l3, coef_gamma[i], BF, P3); break;
		case 4 : PMAT_F84(l1, coef_gamma[i], u[0], BF, P1);
		  PMAT_F84(l2, coef_gamma[i], u[0], BF, P2);
		  PMAT_F84(l3, coef_gamma[i], u[0], BF, P3); break;
		case 5 : PMAT_HKY85(l1, coef_gamma[i], u[0], BF, P1);
		  PMAT_HKY85(l2, coef_gamma[i], u[0], BF, P2);
		  PMAT_HKY85(l3, coef_gamma[i], u[0], BF, P3); break;
		case 6 : PMAT_T92(l1, coef_gamma[i], u[0], BF, P1);
		  PMAT_T92(l2, coef_gamma[i], u[0], BF, P2);
		  PMAT_T92(l3, coef_gamma[i], u[0], BF, P3); break;
		case 7 : PMAT_TN93(l1, coef_gamma[i], u[0], u[1], BF, P1);
		  PMAT_TN93(l2, coef_gamma[i], u[0], u[1], BF, P2);
		  PMAT_TN93(l3, coef_gamma[i], u[0], u[1], BF, P3);break;
		case 8 : PMAT_GTR(l1, coef_gamma[i], u[0], u[1],
				  u[2], u[3], u[4], BF, P1);
		  PMAT_GTR(l2, coef_gamma[i], u[0], u[1],
			   u[2], u[3], u[4], BF, P2);
		  PMAT_GTR(l3, coef_gamma[i], u[0], u[1],
			   u[2], u[3], u[4], BF, P3); break;
		}
		tmp[0] += (X.A[i1] * P1[0] + X.C[i1] * P1[1] +
			   X.G[i1] * P1[2] + X.T[i1] * P1[3]) *
		  (X.A[i2] * P2[0] + X.C[i2] * P2[1] +
		   X.G[i2] * P2[2] + X.T[i2] * P2[3]) *
		  (X.A[i3] * P3[0] + X.C[i3] * P3[1] +
		   X.G[i3] * P3[2] + X.T[i3] * P3[3]);
		tmp[1] += (X.A[i1] * P1[4] + X.C[i1] * P1[5] +
			   X.G[i1] * P1[6] + X.T[i1] * P1[7]) *
		  (X.A[i2] * P2[4] + X.C[i2] * P2[5] +
		   X.G[i2] * P2[6] + X.T[i2] * P2[7]) *
		  (X.A[i3] * P3[4] + X.C[i3] * P3[5] +
		   X.G[i3] * P3[6] + X.T[i3] * P3[7]);
		tmp[2] += (X.A[i1] * P1[8] + X.C[i1] * P1[9] +
			   X.G[i1] * P1[10] + X.T[i1] * P1[11]) *
		  (X.A[i2] * P2[8] + X.C[i2] * P2[9] +
		   X.G[i2] * P2[10] + X.T[i2] * P2[11]) *
		  (X.A[i3] * P3[8] + X.C[i3] * P3[9] +
		   X.G[i3] * P3[10] + X.T[i3] * P3[11]);
		tmp[3] += (X.A[i1] * P1[12] + X.C[i1] * P1[13] +
			   X.G[i1] * P1[14] + X.T[i1] * P1[15]) *
		  (X.A[i2] * P2[12] + X.C[i2] * P2[13] +
		   X.G[i2] * P2[14] + X.T[i2] * P2[15]) *
		  (X.A[i3] * P3[12] + X.C[i3] * P3[13] +
		   X.G[i3] * P3[14] + X.T[i3] * P3[15]);
	    }
	    if (ncat > 1) {
	        tmp[0] /= ncat;
		tmp[1] /= ncat;
		tmp[2] /= ncat;
		tmp[3] /= ncat;
	    }
	    if (I > 0) { /* maybe use a better comparison */
	        V = 1. - I;
		tmp[0] = V * tmp[0] + I * X.A[ind];
		tmp[1] = V * tmp[1] + I * X.C[ind];
		tmp[2] = V * tmp[2] + I * X.G[ind];
		tmp[3] = V * tmp[3] + I * X.T[ind];
	    }
	    ind = anc + j*nr;
	    X.A[ind] = tmp[0];
	    X.C[ind] = tmp[1];
	    X.G[ind] = tmp[2];
	    X.T[ind] = tmp[3];
	}
    }
} /* EOF lik_dna_root */

/*----------------------------------------------------*\
| Il faudra ajouter un moyen pour spécifier les noeuds |
|    ŕ partir desquels calculer la vraisemblance !!    |
\*----------------------------------------------------*/

void lik_dna_tree(int *n, int *s, int N, dna_matrix X, double *w,
		  matching match, double *edge_length, part_dna PART,
		  para_dna PARA, gamma_dna GAMMA, invar_dna INV,
		  double *BF, double *loglik)
{
    int i, j, k, nr, root;

    /* initialize before looping through the tree */
    /*-------------------------------------------------*\
    |     Cette boucle sera éventuellement ajustée      |
    | pour le calcul des vraisemblances conditionnelles |
    |      (sera męme faite une fonction ŕ part?)       |
    \*-------------------------------------------------*/
    nr = (*n*2 - 2);
    for(i = *n; i < *n*2 - 2; i++) { /* only for nodes */
        for(j = 0; j < *s; j++) {
	    k = i + j*nr;
	    X.A[k] = X.C[k] = X.G[k] = X.T[k] = 1.;
	}
    } /* end of initialization */

    /* loop through the matching */
    /*-------------------------------------------*\
    |  Ici aussi il faudra ajuster pour calculer  |
    | ŕ partir des vraisemblances conditionnelles |
    \*-------------------------------------------*/
    /* We don't do the root node here,
       so k goes between 0 and n - 3. */
    for(k = 0; k < *n - 3; k++) {
        lik_dna_node(X, match.s1[k], match.s2[k],
		     match.a[k], edge_length, PART,
		     PARA, GAMMA, INV, BF, nr);
    }

    /* We now do the root */
    root = match.s2[*n - 2];
    lik_dna_root(X, match.s1[*n - 3], match.s2[*n - 3],
		 match.s1[*n - 2], root, edge_length,
                 PART, PARA, GAMMA, INV, BF, nr);
    *loglik = 0.;
    root--; /* to use root as index */
    for(j = 0; j < *s; j++) {
        i = root + j*nr;
        *loglik += w[j]*log(BF[0]*X.A[i] + BF[1]*X.C[i] + BF[2]*X.G[i] + BF[3]*X.T[i]);
    }
} /* lik_dna_tree */

double fcn_mlphylo_invar(double I, info *INFO)
{
    double loglik;
    int N;

    N = *(INFO->D->n)*2 - 3;
    INFO->D->INV.I[INFO->i] = I;

    lik_dna_tree(INFO->D->n, INFO->D->s, N, INFO->D->X, INFO->D->w,
		 INFO->D->match, INFO->D->edge_length,
		 INFO->D->partition, INFO->D->PAR, INFO->D->GAMMA,
		 INFO->D->INV, INFO->D->BF, &loglik);

    return(-loglik);
}

void mlphylo_invar(int N, DNAdata *D, double *loglik)
/*
optimize proportion of invariants
*/
{
    int i;
    info INFO, *infptr;
    double I;

    infptr = &INFO;
    INFO.D = D;

    for(i = 0; i < N; i++) {
        infptr->i = i;
	I = Brent_fmin(0.0, 1.0,
		       (double (*)(double, void*)) fcn_mlphylo_invar,
		       infptr, 1.e-6);
	D->INV.I[i] = I;
    }
}

double fcn_mlphylo_gamma(double a, info *INFO)
{
    double loglik;
    int N;

    N = *(INFO->D->n)*2 - 3;
    INFO->D->GAMMA.alpha[INFO->i] = a;

    lik_dna_tree(INFO->D->n, INFO->D->s, N, INFO->D->X, INFO->D->w,
		 INFO->D->match, INFO->D->edge_length,
		 INFO->D->partition, INFO->D->PAR, INFO->D->GAMMA,
		 INFO->D->INV, INFO->D->BF, &loglik);

    return(-loglik);
}

void mlphylo_gamma(int N, DNAdata *D, double *loglik)
/*
optimize gamma (ISV) parameters
*/
{
    int i;
    info INFO, *infptr;
    double a;

    infptr = &INFO;
    INFO.D = D;

    for(i = 0; i < N; i++) {
        infptr->i = i;
	a = Brent_fmin(0.0, 1.e4,
		       (double (*)(double, void*)) fcn_mlphylo_gamma,
		       infptr, 1.e-6);
	D->GAMMA.alpha[i] = a;
    }
}

double fcn_mlphylo_para(double p, info *INFO)
{
    double loglik;
    int N;

    N = *(INFO->D->n)*2 - 3;
    INFO->D->PAR.para[INFO->i] = p;

    lik_dna_tree(INFO->D->n, INFO->D->s, N, INFO->D->X, INFO->D->w,
		 INFO->D->match, INFO->D->edge_length,
		 INFO->D->partition, INFO->D->PAR, INFO->D->GAMMA,
		 INFO->D->INV, INFO->D->BF, &loglik);

    return(-loglik);
}

void mlphylo_para(int N, DNAdata *D, double *loglik)
/*
optimize the contrast parameter(s) xi
*/
{
    int i;
    info INFO, *infptr;
    double p;

    infptr = &INFO;
    INFO.D = D;

    for(i = 0; i < N; i++) {
        infptr->i = i;
	p = Brent_fmin(0, 1.e3,
		       (double (*)(double, void*)) fcn_mlphylo_para,
		       infptr, 1.e-6);
	D->PAR.para[i] = p;
    }
}

double fcn_mlphylo_xi(double XI, info *INFO)
{
    double loglik;
    int N;

    N = *(INFO->D->n)*2 - 3;
    INFO->D->partition.xi[INFO->i] = XI;

    lik_dna_tree(INFO->D->n, INFO->D->s, N, INFO->D->X, INFO->D->w,
		 INFO->D->match, INFO->D->edge_length,
		 INFO->D->partition, INFO->D->PAR, INFO->D->GAMMA,
		 INFO->D->INV, INFO->D->BF, &loglik);

    return(-loglik);
}

void mlphylo_xi(int N, DNAdata *D, double *loglik)
/*
optimize the contrast parameter(s) xi
*/
{
    int i;
    info INFO, *infptr;
    double XI;

    infptr = &INFO;
    INFO.D = D;

    /* In the following, the range of the search algo was changed from */
    /* 0-1000 to 0-100 to avoid infinite looping. (2006-04-15) */

    /* This was changed again to 0-20. (2006-07-17) */

    for(i = 0; i < N; i++) {
        infptr->i = i;
	XI = Brent_fmin(0.0, 2.e1,
		       (double (*)(double, void*)) fcn_mlphylo_xi,
		       infptr, 1.e-4);
	D->partition.xi[i] = XI;
    }
}

double fcn_mlphylo_edgelength(double l, info *INFO)
{
    double loglik;
    int N;

    N = *(INFO->D->n)*2 - 3;
    INFO->D->edge_length[INFO->i] = l;

    lik_dna_tree(INFO->D->n, INFO->D->s, N, INFO->D->X, INFO->D->w,
		 INFO->D->match, INFO->D->edge_length,
		 INFO->D->partition, INFO->D->PAR, INFO->D->GAMMA,
		 INFO->D->INV, INFO->D->BF, &loglik);
    return(-loglik);
}

void mlphylo_edgelength(int N, DNAdata *D, double *loglik)
/*
optimize branch lengths
*/
{
    int i;
    info INFO, *infptr;
    double l;

/*     int tmp; */

/*     tmp = D->GAMMA.ncat[0]; */
/*     D->GAMMA.ncat[0] = 1; */

    infptr = &INFO;
    INFO.D = D;

    for(i = 0; i < N; i++) {
        infptr->i = i;
	l = Brent_fmin(0.0, 0.1,
		       (double (*)(double, void*)) fcn_mlphylo_edgelength,
		       infptr, 1.e-6);
	D->edge_length[i] = l;
    }

/*     D->GAMMA.ncat[0] = tmp; */
}

/* void nni_matching(int *sib1, int *sib2, int *ancestor, */
/* 		  int node1, int node2, int crossed) */
/* { */
/*   int i, j, tmp; */

/*   /\* find the line with 'node1' as the ancestor *\/ */
/*   i = 0; */
/*   while (ancestor[i] != node1) i++; */
/*   /\* same thing for 'node2' *\/ */
/*   j = 0; */
/*   while (ancestor[j] != node1) j++; */

/*   /\* now do the inversion *\/ */
/*   if (crossed) { */
/*     tmp = sib2[i]; */
/*     sib2[i] = sib1[j]; */
/*     sib1[j] = tmp; */
/*   } else { */
/*     tmp = sib2[i]; */
/*     sib2[i] = sib2[j]; */
/*     sib2[j] = tmp; */
/*   } */

/*   /\* we check that both new pairs are correctly ordered *\/ */
/*   /\* (is this really needed?? or more checks??) *\/ */
/*   if (sib1[i] > sib2[i]) { */
/*     tmp = sib1[i]; */
/*     sib1[i] = sib2[i]; */
/*     sib2[i] = tmp; */
/*   } */
/*   if (sib1[j] > sib2[j]) { */
/*     tmp = sib1[j]; */
/*     sib1[j] = sib2[j]; */
/*     sib2[j] = tmp; */
/*   } */
/* } /\* nni_matching *\/ */

/* void mlphylo_topology(int n, DNAdata *D, double *loglik) */
/* { */
/*   int i, j, new_sib1, new_sib2, new_ancestor, *ns1, *ns2, *na; */
/*   double oldlik, newlik; */

/*   ns1 = &new_sib1; */
/*   ns2 = &new_sib2; */
/*   na = &new_ancestor; */

/*   ns1 = (int*)R_alloc(n - 1, sizeof(int)); */
/*   ns2 = (int*)R_alloc(n - 1, sizeof(int)); */
/*   na = (int*)R_alloc(n - 1, sizeof(int)); */

/*   oldlik = *loglik; */

/*   for (i = 0; i < n - 1; i++) { */
/*     ns1[i] = D->sib1[i]; */
/*     ns2[i] = D->sib2[i]; */
/*     na[i] = D->ancestor[i]; */
/*   } */

/*   for (i = 0; i < n - 3; i++) { */
/*     j = 0; */
/*     while (ns1[j] != na[i] || ns2[j] != na[i]) j++; */
/*     /\* peut-etre pas la pein de faire l'appel de fonction ou */
/*        alors, on peut le simplifier en passant juste le */
/*        numero de la ligne du matching *\/ */
/*     nni_matching(ns1, ns2, na, ns1[j], ns2[j], 0); */

/*     /\* In the followng, all the likelihood is re-computed: this *\/ */
/*     /\* may be speeded up by just re-computing the relevant part *\/ */
/*     /\* of the likelihood *\/ */
/*     lik_dna_tree(D->n, D->s, D->XA, D->XC, D->XG, D->XT, D->w, ns1, ns2, na, */
/* 		 D->edge_length, D->npart, D->partition, D->model, D->xi, D->para, */
/* 		 D->npara, D->pim_para, D->ncat, D->alpha, D->nalpha, D->pim_alpha, */
/* 		 D->invar, D->ninvar, D->pim_invar, D->BF, &newlik); */

/*     if (newlik < oldlik) { */
/*       for (i = 0; i < n - 1; i++) { */
/* 	ns1[i] = D->sib1[i]; */
/* 	ns2[i] = D->sib2[i]; */
/* 	na[i] = D->ancestor[i]; */
/*       } */
/*     } */
/*   } */
/* } /\* mlphylo_topology *\/ */

void mlphylo_DNAmodel(int *n, int *s, double *XA, double *XC, double *XG,
		     double *XT, double *w, int *sib1, int *sib2,
		     int *ancestor, double *edge_length, int *npart,
		     int *partition, int *model, double *xi, double *para,
		     int *npara, int *pim_para, double *alpha, int *nalpha,
		     int *pim_alpha, int *ncat, double *invar, int *ninvar,
		     int *pim_invar, double *BF, int *search_tree,
		     double *loglik)
/*
This function iterates to find the MLEs of the substitution
paramaters and of the branch lengths for a given tree.
*/
{
    int N, i, j, k;
    DNAdata *D, data;

    D = &data;
    N = *n*2 - 3;      /* the tree is unrooted */

    D->n = n;
    D->s = s;

    D->X.A = XA;
    D->X.C = XC;
    D->X.G = XG;
    D->X.T = XT;

    D->w = w;

    D->match.s1 = sib1;
    D->match.s2 = sib2;
    D->match.a = ancestor;

    D->edge_length = edge_length;

    D->partition.n = npart;
    D->partition.limit = partition;
    D->partition.model = model;
    D->partition.xi = xi;

    D->PAR.para = para;
    D->PAR.n = npara;
    D->PAR.pim = pim_para;

    D->GAMMA.ncat = ncat;
    D->GAMMA.alpha = alpha;
    D->GAMMA.n = nalpha;
    D->GAMMA.pim = pim_alpha;

    D->INV.I = invar;
    D->INV.n = ninvar;
    D->INV.pim = pim_invar;

    D->BF = BF;

    lik_dna_tree(D->n, D->s, N, D->X, D->w, D->match,
 		 D->edge_length, D->partition, D->PAR,
		 D->GAMMA, D->INV, D->BF, loglik);

/*     for (i = 0; i < 10; i++) { */
    if (*npart > 1) mlphylo_xi(*npart - 1, D, loglik);
    if (*npara) mlphylo_para(*npara, D, loglik);
    if (*nalpha) mlphylo_gamma(*nalpha, D, loglik);
    if (*ninvar) mlphylo_invar(*ninvar, D, loglik);
/*     mlphylo_edgelength(N, D, loglik); */

    lik_dna_tree(D->n, D->s, N, D->X, D->w, D->match,
 		 D->edge_length, D->partition, D->PAR,
		 D->GAMMA, D->INV, D->BF, loglik);

/*     if (*search_tree) mlphylo_topology(*n, D, loglik); */
/*     } */
} /* mlphylo_DNAmodel */

/*---------------------------------------------------------------*/

/* Exemples de "C-wrappers" pour obtenir la matrice */
/* de probabilité de transition. */

/* void titijc(double *t, double *u, double *P) */
/* { */
/*   PMAT_JC69(*t, *u, P); */
/* } */

/* void titihky(double *t, double *a, double *b, double *BF, double *P) */
/* { */
/*   PMAT_HKY85(*t, *a, *b, BF, P); */
/* } */
back to top