7 *****************************************************************************
9 * Copyright (c) 2004, Luke Sheneman
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
16 * + Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * + Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in
20 * the documentation and/or other materials provided with the
22 * + The names of its contributors may not be used to endorse or promote
23 * products derived from this software without specific prior
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
38 *****************************************************************************
40 * Compute a distance matrix given a set of sequences
42 *****************************************************************************
47 * sheneman@cs.uidaho.edu
60 #include "distclearcut.h"
66 * NJ_build_distance_matrix() -
68 * Given a filename for an alignment, read the alignment
69 * into memory and then compute the distance matrix
70 * using the appropriate correction model
73 NJ_build_distance_matrix(NJ_ARGS *nj_args) {
76 NJ_alignment *alignment;
78 /* Read an alignment in FASTA format */
80 NJ_read_fasta(nj_args);
87 * Given a global multiple sequence alignment (MSA) and
88 * a specified distance correction model, compute a
89 * corrected distance matrix
91 * From proteins, we may want to allow users to specify
92 * a substitution matrix (feature)
95 NJ_compute_dmat(nj_args,
98 // NJ_print_taxanames(dmat);
101 fprintf(stderr, "Clearcut: Error computing distance matrix\n");
104 /* now free the memory associated with the alignment */
105 NJ_free_alignment(alignment);
115 * NJ_compute_dmat() -
117 * Given an alignment and a correction model, compute the
118 * distance matrix and return it
122 NJ_compute_dmat(NJ_ARGS *nj_args,
123 NJ_alignment *alignment) {
129 /* allocate distance matrix here */
130 dmat = (DMAT *)calloc(1, sizeof(DMAT));
132 fprintf(stderr, "Clearcut: Memory allocation error in NJ_compute_dmat()\n");
136 dmat->ntaxa = alignment->nseq;
137 dmat->size = alignment->nseq;
139 /* allocate memory to hold the taxa names */
140 dmat->taxaname = (char **)calloc(alignment->nseq, sizeof(char *));
141 if(!dmat->taxaname) {
142 fprintf(stderr, "Clearcut: Memory allocation error in NJ_compute_dmat()\n");
146 /* copy sequence titles */
147 for(i=0;i<alignment->nseq;i++) {
148 dmat->taxaname[i] = (char *)calloc(strlen(alignment->titles[i])+1, sizeof(char));
149 if(!dmat->taxaname[i]) {
150 fprintf(stderr, "Clearcut: Memory allocation error in NJ_compute_dmat()\n");
154 strncpy(dmat->taxaname[i], alignment->titles[i], strlen(alignment->titles[i]));
157 /* allocate val matrix in dmat */
158 dmat->val = (float *)calloc(dmat->ntaxa*dmat->ntaxa, sizeof(float));
160 fprintf(stderr, "Clearcut: Memory allocation error in NJ_compute_dmat()\n");
164 /* now lets allocate space for the r and r2 columns */
165 dmat->r = (float *)calloc(dmat->ntaxa, sizeof(float));
166 dmat->r2 = (float *)calloc(dmat->ntaxa, sizeof(float));
168 /* track some memory addresses */
169 dmat->rhandle = dmat->r;
170 dmat->r2handle = dmat->r2;
171 dmat->valhandle = dmat->val;
173 /* apply model correction to matrix */
174 switch(nj_args->correction_model) {
178 if(nj_args->dna_flag) {
179 NJ_DNA_jc_correction(dmat, alignment);
180 } else if(nj_args->protein_flag) {
181 NJ_PROTEIN_jc_correction(dmat, alignment);
183 fprintf(stderr, "Clearcut: Need to know sequence type for Jukes-Cantor model correction.\n");
189 case NJ_MODEL_KIMURA:
191 if(nj_args->dna_flag) {
192 NJ_DNA_k2p_correction(dmat, alignment);
193 } else if(nj_args->protein_flag) {
194 NJ_PROTEIN_kimura_correction(dmat, alignment);
196 fprintf(stderr, "Clearcut: Need to know sequence type for Kimura model correction.\n");
204 NJ_no_correction(dmat, alignment);
209 fprintf(stderr, "Clearcut: Invalid distance correction model.\n");
221 * NJ_no_correction() -
223 * Compute the distance matrix without correction
224 * (straight percent ID)
226 * Resolve ambiguities in sequence data by skipping
227 * those nucleotides/residues
231 NJ_no_correction(DMAT *dmat,
232 NJ_alignment *alignment) {
237 /* compute pairwise percent identity */
238 for(i=0;i<dmat->size;i++) {
239 for(j=i+1;j<dmat->size;j++) {
240 pdiff = 1.0 - NJ_pw_percentid(alignment, i, j);
241 dmat->val[NJ_MAP(i, j, dmat->size)] = pdiff;
252 * NJ_DNA_jc_correction() -
254 * Compute the distance matrix with jukes-cantor correction
255 * and assign high distance if sequence divergence exceeds
258 * Jukes, T.H. (1969), Evolution of protein molecules. In H.N. Munro (Ed.),
259 * Mammalian Protein Metabolism, Volume III, Chapter 24, pp. 21-132.
260 * New York: Academic Press
264 NJ_DNA_jc_correction(DMAT *dmat,
265 NJ_alignment *alignment) {
269 float d, cutoff, dist;
274 for(i=0;i<dmat->size;i++) {
275 for(j=i+1;j<dmat->size;j++) {
277 k = NJ_pw_differences(alignment, i, j, &residues);
278 d = 1.0 - NJ_pw_percentid(alignment, i, j);
283 dist = (-0.75) * log(1.0 - (4.0/3.0)*d);
286 if(fabs(dist) < FLT_EPSILON) {
287 dmat->val[NJ_MAP(i, j, dmat->size)] = 0.0;
289 dmat->val[NJ_MAP(i, j, dmat->size)] = dist;
305 * NJ_PROTEIN_jc_correction() -
307 * This function performs modified jukes/cantor correction on
308 * a protein alignment
310 * Jukes, T.H. (1969), Evolution of protein molecules. In H.N. Munro (Ed.),
311 * Mammalian Protein Metabolism, Volume III, Chapter 24, pp. 21-132.
312 * New York: Academic Press
316 NJ_PROTEIN_jc_correction(DMAT *dmat,
317 NJ_alignment *alignment) {
325 for(i=0;i<dmat->size;i++) {
326 for(j=i+1;j<dmat->size;j++) {
328 diff = NJ_pw_differences(alignment, i, j, &residues);
330 if(!diff || !residues) {
334 dist = (float)diff/(float)residues;
335 x = ((20.0/19.0)*dist);
337 if(NJ_FLT_GT(x, 1.0)) {
340 dist = -(19.0/20.0) * log(1.0 - x);
344 dmat->val[NJ_MAP(i, j, dmat->size)] = dist;
357 * NJ_DNA_k2p_correction() -
359 * Correct a distance matrix using k2p correction using
360 * cutoffs to avoid problems with logarithms.
362 * dist = -0.5ln(1-2P-Q) - 0.25ln(1-2Q)
364 * But due to the logarithms, this is only valid when
369 * So assign arbitary distances when these constraints are
370 * not strictly followed.
372 * Kimura, M. (1980), A simple method for estimating evolutionary
373 * rates of base substitutions through comparative studies of
374 * nucleotide sequences. J. Mol. Evol., 16, 111-120
378 NJ_DNA_k2p_correction(DMAT *dmat,
379 NJ_alignment *alignment) {
382 float P; /* proportion of transitions */
383 float Q; /* proportion of transversions */
384 long int nucleotides;
385 long int transitions, transversions;
387 float log_x = 0.0; /* the params for the first log */
388 float log_y = 0.0; /* the params for the second log */
390 int blowup; /* a flag to specify if we have a log blowup */
393 for(i=0;i<dmat->size;i++) {
394 for(j=i+1;j<dmat->size;j++) {
398 /* count the number of transitions and transversions */
399 NJ_DNA_count_tt(alignment, i, j, &transitions, &transversions, &nucleotides);
401 if(!nucleotides) { /* sequences have no non-ambiguous overlap in alignment */
405 P = (float)transitions / (float)nucleotides;
406 Q = (float)transversions / (float)nucleotides;
409 /* the first log blows up if 2*P+Q = 1.0 */
410 if(NJ_FLT_EQ((2.0 * P + Q), 1.0)) {
413 if( NJ_FLT_LT(1.0 - 2.0*P - Q, 0.0) ) {
416 log_x = log(1.0 - 2.0*P - Q);
420 /* the second log blows up if 2*Q >= 1.0 */
421 if( NJ_FLT_EQ((2.0 * Q), 1.0) ||
422 NJ_FLT_GT((2.0 * Q), 1.0) ) {
425 log_y = log(1.0 - 2.0*Q);
428 /* if our logarithms blow up, we just set the distance to the max */
432 dist = (-0.5)*log_x - 0.25*log_y;
435 if(fabs(dist) < FLT_EPSILON) {
436 dmat->val[NJ_MAP(i, j, dmat->size)] = 0.0;
438 dmat->val[NJ_MAP(i, j, dmat->size)] = dist;
450 * NJ_PROTEIN_kimura_correction() -
452 * Perform Kimura correction for distances derived from protein
455 * Kimura, M. (1983), The Neutral Theory of Molecular Evolution.
456 * p. 75., Cambridge University Press, Cambridge, England
460 NJ_PROTEIN_kimura_correction(DMAT *dmat,
461 NJ_alignment *alignment) {
469 printf("NJ_PROTEIN_kimura_correction()\n");
471 for(i=0;i<dmat->size;i++) {
472 for(j=i+1;j<dmat->size;j++) {
473 diff = NJ_pw_differences(alignment, i, j, &residues);
475 if(!diff || !residues) {
478 dist = (float)diff/(float)residues;
481 if(NJ_FLT_LT(dist, 0.75)) {
482 if(NJ_FLT_GT(dist, 0.0) ) {
483 dist = -log(1.0 - dist - (dist * dist/5.0) );
486 if(NJ_FLT_GT(dist, 0.93) ) {
489 dist = (float)NJ_dayhoff[ (int)((dist*1000.0)-750.0) ] / 100.0 ;
493 dmat->val[NJ_MAP(i, j, dmat->size)] = dist;
505 * NJ_DNA_count_tt() -
507 * Count the number of transitions and transversions
508 * between two aligned DNA sequences
510 * This routine automatically skips ambiguities when
511 * counting transitions and transversions.
515 NJ_DNA_count_tt(NJ_alignment *alignment,
518 long int *transitions,
519 long int *transversions,
520 long int *residues) {
522 long int tmp_transitions = 0;
523 long int tmp_transversions = 0;
524 long int tmp_residues = 0;
528 for(i=0;i<alignment->length;i++) {
530 a = toupper(alignment->data[x*alignment->length+i]);
531 b = toupper(alignment->data[y*alignment->length+i]);
533 if( (a == 'A' && b == 'T') ||
534 (a == 'T' && b == 'A') ||
535 (a == 'A' && b == 'C') ||
536 (a == 'C' && b == 'A') ||
537 (a == 'T' && b == 'G') ||
538 (a == 'G' && b == 'T') ||
539 (a == 'C' && b == 'G') ||
540 (a == 'G' && b == 'C') ) {
544 if( (a == 'C' && b == 'T') ||
545 (a == 'T' && b == 'C') ||
546 (a == 'G' && b == 'A') ||
547 (a == 'A' && b == 'G') ) {
551 /* count the number of residues */
552 if(a != NJ_AMBIGUITY_CHAR &&
553 b != NJ_AMBIGUITY_CHAR ) {
559 *transitions = tmp_transitions;
560 *transversions = tmp_transversions;
563 *residues = tmp_residues;
574 * NJ_pw_percentid() -
576 * Given an alignment and a specification
577 * for two rows, compute the pairwise
578 * percent identity between the two
582 NJ_pw_percentid(NJ_alignment *alignment,
594 for(i=0;i<alignment->length;i++) {
596 c1 = alignment->data[x*alignment->length+i];
597 c2 = alignment->data[y*alignment->length+i];
599 if( c1 != NJ_AMBIGUITY_CHAR ||
600 c2 != NJ_AMBIGUITY_CHAR ) {
611 pid = (float)same/(float)residues;
619 * NJ_pw_differences() -
621 * Given an alignment and a specification
622 * for two rows in the alignment, compute the
623 * number of differences between the two sequences
625 * With respect to ambiguity codes, we will want to
626 * disregard those sites entirely in our count.
630 NJ_pw_differences(NJ_alignment *alignment,
633 long int *residues) {
638 long int tmp_residues;
642 for(i=0;i<alignment->length;i++) {
644 c1 = alignment->data[x*alignment->length+i];
645 c2 = alignment->data[y*alignment->length+i];
647 if( c1 != NJ_AMBIGUITY_CHAR ||
648 c2 != NJ_AMBIGUITY_CHAR ) {
659 *residues = tmp_residues;