/* MIPoD 1.0 Neutral Module */ /* copyright 2008 Paul Hohenlohe */ /* permission is granted to use and modify this software _provided that_ any * publication resulting from use of this software or any part or modification thereof * contains at least one of the following citations: * * Hohenlohe, P.A. 2007. MIPoD: Microevolutionary Inference from Patterns of Divergence. * Software available at http://oregonstate.edu/~hohenlop/software * * Hohenlohe, P.A. & S.J. Arnold. 2008. MIPoD: A Hypothesis-Testing Framework for Microevolutionary * Inference from Patterns of Divergence. American Naturalist 171(3):366-385. * * questions/comments: hohenlop@science.oregonstate.edu */ #include #include #include #include #include "MatrixFunx.h" /* structures */ typedef struct { double branch; int parent; } node; typedef struct { char name[10]; double *trait; double branch; int parent; } taxon; /*functions: */ void getdata(); void output(); double lnlikelihood(double **Inv, double N, bn deter); double maxNe(double **Inv); double confN(double **Inv, double N, bn deter, int d); double est_sigma(double **ellipse, double **evecs, double N, int y); double est_epsilon(double **ellipse, double **evecs, double N, int which, int y); double est_phi(double **ellipse, double **evecs, double N, int which); int rotate(double **evecs, double phi, int k, int l, int n); double vecmatvec(double **Inv); int populate(double **G, double **Inv, bn *deter); int mattopar(double **mat, double **ellipse, double **evecs, int n); int partomat(double **mat, double **ellipse, double **evecs, int n); void memerror(); /*global variables -- these are the DATA from the user and don't change: */ int spp, traits, sizeA; double gens, Ne, acc, *testphi, *mean; taxon *taxa; node *nodes; double **Tree, **invTree; bn Treedeter; double **Gmat; int main() { acc = 3; printf("\n\n** MIPoD 1.0 Neutral Module **\n\n"); getdata(); /* Read files */ output(); /* Analyze and print to Outfile.txt */ return 0; } void getdata() { /*This function reads in the data and populates the global variables */ int i, j, k, l, q; double d, e, f; i=j=l=0; char *datafilename; FILE *fd; datafilename = (char *)malloc(20*sizeof(char)); printf ("\nWhat is the name of the data file?"); scanf ("%s", datafilename); fd = fopen (datafilename,"r"); if (!fd) { printf ("Can't find the file\n"); exit (0); } printf ("Reading data from the file %s ...\n", datafilename); fscanf (fd, "%d", &spp); fscanf (fd, "%d", &traits); fscanf (fd, "%lf", &Ne); fscanf (fd, "%lf", &gens); sizeA = spp*traits; /* Assign memory for global variables: */ node *tmpnode; if ((tmpnode = realloc(nodes, (spp - 1)*sizeof(node))) == NULL) memerror(); nodes = tmpnode; taxon *tmptaxa; if ((tmptaxa = realloc(taxa, spp*sizeof(taxon))) == NULL) memerror(); for(i=0; i (spp-1)) { printf ("Can't find the taxon %s in the tree\n\n", checkname); exit(0); } j++; } for(k=0; k 0) { if (mattopar(Gmat, ell[0], evecs[0], traits) == 1) { printf ("\nUnable to calculate eigenvectors of G\n\n\n"); exit(0); } if (Ne > 0) like[0] = est_sigma(ell[0], evecs[0], popsize, 0); printf ("Estimating size...\n"); for (i=0; i 0) { fprintf(f,"Direct\t\t%4.4lf\t%4.4lf\t%4.4lf\t\t",ell[0][0][1],ell[0][1][1],acos(evecs[0][0][0])); fprintf(f,"%4.2lf\t-\t-\t-\n",like[0]); tmpLR = 2*(like[1] - like[0]); fprintf(f,"1.Size\t\t%4.4lf\t%4.4lf\t%4.4lf\t\t",ell[1][0][1],ell[1][1][1],acos(evecs[0][0][0])); fprintf(f,"%4.2lf\t%4.2lf\t1\t%4.4lf\n",like[1],tmpLR,chisquare(tmpLR,1)); } else { fprintf(f,"1.Size\t\t%4.4lf\t%4.4lf\t%4.4lf\t\t",ell[1][0][1],ell[1][1][1],acos(evecs[0][0][0])); fprintf(f,"%4.2lf\t-\t-\t-\n",like[1]); } tmpLR = 2*(like[2] - like[1]); fprintf(f,"2.Shape\t\t%4.4lf\t%4.4lf\t%4.4lf\t\t",ell[2][0][1],ell[2][1][1],acos(evecs[0][0][0])); fprintf(f,"%4.2lf\t%4.2lf\t1\t%4.4lf\n",like[2],tmpLR,chisquare(tmpLR,1)); tmpLR = 2*(like[3] - like[2]); fprintf(f,"3.Orientation\t%4.4lf\t%4.4lf\t%4.4lf\t\t",ell[3][0][1],ell[3][1][1],acos(evecs[1][0][0])); fprintf(f,"%4.2lf\t%4.2lf\t1\t%4.4lf\n",like[3],tmpLR,chisquare(tmpLR,1)); } else if (Gmat[0][0] == 0) { fprintf(f,"ML best fit\t%4.4lf\t%4.4lf\t%4.4lf\t\t",ell[3][0][1],ell[3][1][1],acos(evecs[1][0][0])); fprintf(f,"%4.2lf\n",like[3]); } tmpLR = 2*(like[3] - like[4]); fprintf(f,"Test vector\t%4.4lf\t%4.4lf\t%4.4lf\t\t",ell[4][0][1],ell[4][1][1],acos(evecs[2][0][0])); fprintf(f,"%4.2lf\t%4.2lf\t1\t%4.4lf\n\n\n",like[4],tmpLR,chisquare(tmpLR,1)); } else if (traits > 2) { fprintf(f,"Step\t\tlnL\tLR\tdf\tp\n"); fprintf(f,"--------------------------------------------------------\n"); if (Gmat[0][0] != 0) { if (Ne > 0) { fprintf(f,"Direct\t\t%4.2lf\t-\t-\t-\n",like[0]); tmpLR = 2*(like[1] - like[0]); fprintf(f,"1.Size\t\t%4.2lf\t%4.2lf\t1\t%4.4lf\n",like[1],tmpLR,chisquare(tmpLR,1)); } else fprintf(f,"1.Size\t\t%4.2lf\t-\t-\t-\n",like[1]); for(i=1; i 0) { fprintf(f,"Direct:\nSigma = %4.4lf\n", ell[0][0][1]); tmpLR = 0; for(i=0; i<(traits-1); i++) { fprintf(f,"%4.4lf\t(",ell[0][i+1][1]); tmpLR += ell[0][i+1][1]; for(j=0; j<(traits-1); j++) fprintf(f,"%4.4lf , ",evecs[0][j][i]); fprintf(f,"%4.4lf)\n",evecs[0][traits-1][i]); } fprintf(f,"%4.4lf\t(", (1 - tmpLR)); for(j=0; j<(traits-1); j++) fprintf(f,"%4.4lf , ",evecs[0][j][traits-1]); fprintf(f,"%4.4lf)\n\n",evecs[0][traits-1][traits-1]); } fprintf(f,"1.Size (with Ne = %4.2lf):\nSigma = %4.4lf [%4.4lf to %4.4lf]\n", popsize, ell[1][0][1],ell[1][0][0],ell[1][0][2]); tmpLR = 0; for(i=0; i<(traits-1); i++) { fprintf(f,"%4.4lf\t(",ell[1][i+1][1]); tmpLR += ell[1][i+1][1]; for(j=0; j<(traits-1); j++) fprintf(f,"%4.4lf , ",evecs[0][j][i]); fprintf(f,"%4.4lf)\n",evecs[0][traits-1][i]); } fprintf(f,"%4.4lf\t(", (1 - tmpLR)); for(j=0; j<(traits-1); j++) fprintf(f,"%4.4lf , ",evecs[0][j][traits-1]); fprintf(f,"%4.4lf)\n\n",evecs[0][traits-1][traits-1]); for(k=2; k<(traits+1); k++) { fprintf(f,"%d.Shape(%d):\nSigma = %4.4lf [%4.4lf to %4.4lf]\n",k,(k-1), ell[k][0][1],ell[k][0][0],ell[k][0][2]); tmpLR = 0; for(i=0; i<(traits-1); i++) { fprintf(f,"%4.4lf\t(",ell[k][i+1][1]); tmpLR += ell[k][i+1][1]; for(j=0; j<(traits-1); j++) fprintf(f,"%4.4lf , ",evecs[0][j][i]); fprintf(f,"%4.4lf)\n",evecs[0][traits-1][i]); } if (traits == 2) fprintf(f,"[%4.4lf to %4.4lf]\n", ell[k][1][0], ell[k][1][2]); fprintf(f,"%4.4lf\t(", (1 - tmpLR)); for(j=0; j<(traits-1); j++) fprintf(f,"%4.4lf , ",evecs[0][j][traits-1]); fprintf(f,"%4.4lf)\n\n",evecs[0][traits-1][traits-1]); } for(k=1; k (pow(0.1,acc)))) { lr = adjmax - 0.5*(sizeA*log(tryN) - tryN*vmv); epsilon = 2*lr/(sizeA/tryN - vmv); if((tryN + epsilon) < 0) tryN *= 0.1; else if(d*epsilon < d*(N - tryN)) tryN = N + d*(N - tryN); else tryN += epsilon; if (tryN < 0.001) return 0; i++; } return tryN; } double est_sigma(double **ellipse, double **evecs, double N, int y) { int i, j; /* if y == 0, returns log likelihood for G-matrix parameter set in ellipse and evecs if y==1, re-estimates sigma and populates ellipse[0][1] if y==2, also estimates confidence limits for sigma into ellipse[0] */ bn *deter; double **tmpG, **tmpinvAmat, maxN, temp, like; if ((deter = malloc(sizeof(bn))) == NULL) memerror(); if ((tmpG = malloc(traits*sizeof(double *))) == NULL) memerror(); if ((tmpinvAmat = malloc(sizeA*sizeof(double *))) == NULL) memerror(); for (i=0; i 0) { /* Re-estimates sigma based on sigma/Ne functioning as a single parameter */ maxN = maxNe(tmpinvAmat); like = lnlikelihood(tmpinvAmat, maxN, deter[0]); ellipse[0][1] *= N/maxN; if (y == 2) { temp = confN(tmpinvAmat, maxN, deter[0], 1); ellipse[0][0] = ellipse[0][1]*maxN/temp; temp = confN(tmpinvAmat, maxN, deter[0], -1); ellipse[0][2] = ellipse[0][1]*maxN/temp; } } for(i=0; i< traits; i++) free(tmpG[i]); for(i=0; i pow(0.1,(acc - y)) && k < pow(5,(acc - y))) { /* estimation */ for (i=which; i= maxhere) ellipse[i][1] = maxhere - 0.6*dx[i]; err = maximum(-1*temp, err); dx[i] *= 0.5; } else if (like[2] > like[0]) {ellipse[i][1] += dx[i]; err = 1; } else if (like[2] < like[0]) {ellipse[i][1] -= dx[i]; err = 1; } } like[1] = est_sigma(ellipse, evecs, N, 1); k++; } if (traits == 2 && y == 0) { temp = ellipse[1][1]; for (j=-1; j<2; j += 2) { if (j == -1) dx[0] = 0.5*temp; else dx[0] = 0.5*(1 - temp); err = -1; k = 0; while (fabs(err) > pow(0.1,acc) && k < pow(5,acc)) { if (err > 0) ellipse[1][1] -= j*dx[0]; else ellipse[1][1] += j*dx[0]; like[0] = est_sigma(ellipse, evecs, N, 0); err = like[1] - like[0] - 1.92; dx[0] *= 0.5; k++; } ellipse[1][j + 1] = ellipse[1][1]; ellipse[1][1] = temp; } } temp = est_sigma(ellipse, evecs, N, 2); free(like); free(dx); return temp; } double est_phi(double **ellipse, double **evecs, double N, int which) { /* Estimates best fit for phi[which] and above, epsilons, sigma, with conf limits for epsilon; populates ellipse and evecs; returns likelihood model */ int i, j, k, l, m, yet; double dx, phi, temp, *like, **tmpevecs; if ((like = malloc(3*sizeof(double))) == NULL) memerror(); if ((tmpevecs = malloc((traits+1)*sizeof(double *))) == NULL) memerror(); for (i=0; i<(traits+1); i++) if ((tmpevecs[i] = malloc(traits*sizeof(double))) == NULL) memerror(); phi = 0.1*M_PI; for (k=which; k like[0]) { for (j=0; j 0 && like[0] > like[1] && like[2] > like[1]) { like[1] = est_epsilon(ellipse, evecs, N, 1, 0); /* calculate second derivatives wrt phi */ for (i=0; i like[0]) phi = dx; else if (like[2] < like[0]) phi = -dx; else phi = 0; rotate (evecs, phi, k, l, traits); } if ((like[1] - like[0]) < pow(0.1,acc) && (like[1] - like[2]) < pow(0.1,acc)) yet += 1; } m++; } if (which == 0) { /* If which==0, re-order eigenvectors according to eigenvalues */ temp = 0; for(i=0; i<(traits-1); i++) { evecs[traits][i] = ellipse[i+1][1]; temp += ellipse[i+1][1]; } evecs[traits][traits-1] = (1 - temp); j = ordereigen(evecs, traits); for(i=0; i<(traits-1); i++) ellipse[i+1][1] = evecs[traits][i]; } temp = est_epsilon(ellipse, evecs, N, 1, 0); for (i=0; i<(traits+1); i++) free(tmpevecs[i]); free (tmpevecs); free (like); return temp; } int rotate(double **evecs, double phi, int k, int l, int n) { int i; /* Rotates eigenvectors k and l by angle phi, doesn't change eigenvalues */ double c, s, **tmpevecs; if ((tmpevecs = malloc(n*sizeof(double *))) == NULL) memerror(); for (i=0; i 0) return 1; else return 0; } int mattopar(double **mat, double **ellipse, double **evecs, int n) { int i, zero; double tmp; zero = eigen(mat, evecs, n); tmp = 0; for(i=0; i