NCBI C++ ToolKit
bNNI.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: bNNI.cpp 84094 2018-10-16 15:39:20Z ucko $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Richard Desper
27 *
28 * File Description: bNNI.cpp
29 *
30 * A part of the Miminum Evolution algorithm
31 *
32 */
33 
34 #include <ncbi_pch.hpp>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <math.h>
38 #include "graph.h"
39 #include "fastme.h"
40 
41 
43 BEGIN_SCOPE(fastme)
44 
45 boolean leaf(meNode *v);
51 void WFext(meEdge *e, double **A);
52 void WFint(meEdge *e, double **A);
53 
54 void limitedFillTableUp(meEdge *e, meEdge *f, double **A, meEdge *trigger);
55 void assignBalWeights(meTree *T, double **A);
56 void updateAveragesMatrix(meTree *T, double **A, meNode *v,int direction);
57 void bNNItopSwitch(meTree *T, meEdge *e, int direction, double **A);
58 int bNNIEdgeTest(meEdge *e, meTree *T, double **A, double *weight);
59 void updatePair(double **A, meEdge *nearEdge, meEdge *farEdge, meNode *closer, meNode *further, double dcoeff, int direction);
60 
61 int *initPerm(int size);
62 
63 void reHeapElement(int *p, int *q, double *v, int length, int i);
64 void pushHeap(int *p, int *q, double *v, int length, int i);
65 void popHeap(int *p, int *q, double *v, int length, int i);
66 
67 
68 void bNNIRetestEdge(int *p, int *q, meEdge *e,meTree *T, double **avgDistArray,
69  double *weights, int *location, int *possibleSwaps)
70 {
71  int tloc;
72  tloc = location[e->head->index+1];
73  location[e->head->index+1] =
74  bNNIEdgeTest(e,T,avgDistArray,weights + e->head->index+1);
75  if (NONE == location[e->head->index+1])
76  {
77  if (NONE != tloc)
78  popHeap(p,q,weights,(*possibleSwaps)--,q[e->head->index+1]);
79  }
80  else
81  {
82  if (NONE == tloc)
83  pushHeap(p,q,weights,(*possibleSwaps)++,q[e->head->index+1]);
84  else
85  reHeapElement(p,q,weights,*possibleSwaps,q[e->head->index+1]);
86  }
87 }
88 
89 int makeThreshHeap(int *p, int *q, double *v, int arraySize, double thresh);
90 
91 void permInverse(int *p, int *q, int length);
92 
93 void printMatrix(double **M, int dim, FILE *ofile,meTree *T)
94 {
95  meEdge *e,*f;
96  fprintf(ofile,"%d\n",dim-1);
98  {
99  fprintf(ofile,"%s ",e->head->label);
101  fprintf(ofile,"%lf ",M[e->head->index][f->head->index]);
102  fprintf(ofile,"\n");
103  }
104 }
105 
107 {
108  meEdge *e;
109  T->weight = 0;
111  T->weight += e->distance;
112 }
113 
114 void bNNI(meTree *T, double **avgDistArray, int *count)
115 {
116  meEdge *e, *centerEdge;
117  meEdge **edgeArray;
118  int *p, *location, *q;
119  int i;
120  int possibleSwaps;
121  double *weights;
122  p = initPerm(T->size+1);
123  q = initPerm(T->size+1);
124  edgeArray = (meEdge **) malloc((T->size+1)*sizeof(meEdge*));
125  weights = (double *) malloc((T->size+1)*sizeof(double));
126  location = (int *) malloc((T->size+1)*sizeof(int));
127  for (i=0;i<T->size+1;i++)
128  {
129  weights[i] = 0.0;
130  location[i] = NONE;
131  }
132  if (verbose)
133  {
134  assignBalWeights(T,avgDistArray);
135  weighTree(T);
136  }
137  e = findBottomLeft(T->root->leftEdge);
138  while (NULL != e)
139  {
140  edgeArray[e->head->index+1] = e;
141  location[e->head->index+1] =
142  bNNIEdgeTest(e,T,avgDistArray,weights + e->head->index + 1);
143  e = depthFirstTraverse(T,e);
144  }
145  possibleSwaps = makeThreshHeap(p,q,weights,T->size+1,0.0);
146  permInverse(p,q,T->size+1);
147  /*we put the negative values of weights into a heap, indexed by p
148  with the minimum value pointed to by p[1]*/
149  /*p[i] is index (in edgeArray) of edge with i-th position
150  in the heap, q[j] is the position of edge j in the heap */
151  /*NOTE: the loop below should test that weights[p[1]] < 0, but
152  if compiled with optimization it is possible that weights[p[1]]
153  ends up negative and very small, so that changes to the heap
154  become cyclic and the loop becomes infinite. To avoid this
155  behavior, stop the loop short of 0.0. This is a workaround
156  until the roundoff sensitivity is removed algorithmically */
157  while (weights[p[1]] < -1e-8)
158  {
159  centerEdge = edgeArray[p[1]];
160  (*count)++;
161  if (verbose)
162  {
163  T->weight = T->weight + weights[p[1]];
164  printf("New tree weight is %lf.\n",T->weight);
165  }
166  bNNItopSwitch(T,edgeArray[p[1]],location[p[1]],avgDistArray);
167  location[p[1]] = NONE;
168  weights[p[1]] = 0.0; /*after the bNNI, this edge is in optimal
169  configuration*/
170  popHeap(p,q,weights,possibleSwaps--,1);
171  /*but we must retest the other edges of T*/
172  /*CHANGE 2/28/2003 expanding retesting to _all_ edges of T*/
174  while (NULL != e)
175  {
176  bNNIRetestEdge(p,q,e,T,avgDistArray,weights,location,&possibleSwaps);
177  e = depthFirstTraverse(T,e);
178  }
179  }
180  free(p);
181  free(q);
182  free(location);
183  free(edgeArray);
184  free(weights);
185  assignBalWeights(T,avgDistArray);
186 }
187 
188 
189 
190 /*This function is the meat of the average distance matrix recalculation*/
191 /*Idea is: we are looking at the subtree rooted at rootEdge. The subtree
192 rooted at closer is closer to rootEdge after the NNI, while the subtree
193 rooted at further is further to rootEdge after the NNI. direction tells
194 the direction of the NNI with respect to rootEdge*/
195 void updateSubTreeAfterNNI(double **A, meNode *v, meEdge *rootEdge, meNode *closer, meNode *further,
196  double dcoeff, int direction)
197 {
198  meEdge *sib;
199  switch(direction)
200  {
201  case UP: /*rootEdge is below the center edge of the NNI*/
202  /*recursive calls to subtrees, if necessary*/
203  if (NULL != rootEdge->head->leftEdge)
204  updateSubTreeAfterNNI(A, v, rootEdge->head->leftEdge, closer, further, 0.5*dcoeff,UP);
205  if (NULL != rootEdge->head->rightEdge)
206  updateSubTreeAfterNNI(A, v, rootEdge->head->rightEdge, closer, further, 0.5*dcoeff,UP);
207  updatePair(A, rootEdge, rootEdge, closer, further, dcoeff, UP);
208  sib = siblingEdge(v->parentEdge);
209  A[rootEdge->head->index][v->index] =
210  A[v->index][rootEdge->head->index] =
211  0.5*A[rootEdge->head->index][sib->head->index] +
212  0.5*A[rootEdge->head->index][v->parentEdge->tail->index];
213  break;
214  case DOWN: /*rootEdge is above the center edge of the NNI*/
215  sib = siblingEdge(rootEdge);
216  if (NULL != sib)
217  updateSubTreeAfterNNI(A, v, sib, closer, further, 0.5*dcoeff, SKEW);
218  if (NULL != rootEdge->tail->parentEdge)
219  updateSubTreeAfterNNI(A, v, rootEdge->tail->parentEdge, closer, further, 0.5*dcoeff, DOWN);
220  updatePair(A, rootEdge, rootEdge, closer, further, dcoeff, DOWN);
221  A[rootEdge->head->index][v->index] =
222  A[v->index][rootEdge->head->index] =
223  0.5*A[rootEdge->head->index][v->leftEdge->head->index] +
224  0.5*A[rootEdge->head->index][v->rightEdge->head->index];
225  break;
226  case SKEW: /*rootEdge is in subtree skew to v*/
227  if (NULL != rootEdge->head->leftEdge)
228  updateSubTreeAfterNNI(A, v, rootEdge->head->leftEdge, closer, further, 0.5*dcoeff,SKEW);
229  if (NULL != rootEdge->head->rightEdge)
230  updateSubTreeAfterNNI(A, v, rootEdge->head->rightEdge, closer, further, 0.5*dcoeff,SKEW);
231  updatePair(A, rootEdge, rootEdge, closer, further, dcoeff, UP);
232  A[rootEdge->head->index][v->index] =
233  A[v->index][rootEdge->head->index] =
234  0.5*A[rootEdge->head->index][v->leftEdge->head->index] +
235  0.5*A[rootEdge->head->index][v->rightEdge->head->index];
236  break;
237  }
238 }
239 
240 
241 /*swapping across edge whose head is v*/
242 void bNNIupdateAverages(double **A, meNode *v, meEdge *par, meEdge *skew,
243  meEdge *swap, meEdge *fixed)
244 {
245  A[v->index][v->index] = 0.25*(A[fixed->head->index][par->head->index] +
246  A[fixed->head->index][swap->head->index] +
247  A[skew->head->index][par->head->index] +
248  A[skew->head->index][swap->head->index]);
249  updateSubTreeAfterNNI(A, v, fixed, skew->head, swap->head, 0.25, UP);
250  updateSubTreeAfterNNI(A, v, par, swap->head, skew->head, 0.25, DOWN);
251  updateSubTreeAfterNNI(A, v, skew, fixed->head, par->head, 0.25, UP);
252  updateSubTreeAfterNNI(A, v, swap, par->head, fixed->head, 0.25, SKEW);
253 
254 }
255 
256 
257 
258 void bNNItopSwitch(meTree *T, meEdge *e, int direction, double **A)
259 {
260  meEdge *down, *swap, *fixed;
261  meNode *u, *v;
262  if (verbose)
263  {
264  printf("Performing branch swap across edge %s ",e->label);
265  printf("with ");
266  if (LEFT == direction)
267  printf("left ");
268  else printf("right ");
269  printf("subtree.\n");
270  }
271  down = siblingEdge(e);
272  u = e->tail;
273  v = e->head;
274  if (LEFT == direction)
275  {
276  swap = e->head->leftEdge;
277  fixed = e->head->rightEdge;
278  v->leftEdge = down;
279  }
280  else
281  {
282  swap = e->head->rightEdge;
283  fixed = e->head->leftEdge;
284  v->rightEdge = down;
285  }
286  swap->tail = u;
287  down->tail = v;
288  if(e->tail->leftEdge == e)
289  u->rightEdge = swap;
290  else
291  u->leftEdge = swap;
292  bNNIupdateAverages(A, v, e->tail->parentEdge, down, swap, fixed);
293 }
294 
295 double wf5(double D_AD, double D_BC, double D_AC, double D_BD,
296  double D_AB, double D_CD)
297 {
298  double weight;
299  weight = 0.25*(D_AC + D_BD + D_AD + D_BC) + 0.5*(D_AB + D_CD);
300  return(weight);
301 }
302 
303 int bNNIEdgeTest(meEdge *e, meTree *T, double **A, double *weight)
304 {
305  meEdge *f;
306  double D_LR, D_LU, D_LD, D_RD, D_RU, D_DU;
307  double w1,w2,w0;
308  /*if (verbose)
309  printf("Branch swap: testing edge %s.\n",e->label);*/
310  if ((leaf(e->tail)) || (leaf(e->head)))
311  return(NONE);
312 
313  f = siblingEdge(e);
314 
315  D_LR = A[e->head->leftEdge->head->index][e->head->rightEdge->head->index];
316  D_LU = A[e->head->leftEdge->head->index][e->tail->index];
317  D_LD = A[e->head->leftEdge->head->index][f->head->index];
318  D_RU = A[e->head->rightEdge->head->index][e->tail->index];
319  D_RD = A[e->head->rightEdge->head->index][f->head->index];
320  D_DU = A[e->tail->index][f->head->index];
321 
322  w0 = wf5(D_RU,D_LD,D_LU,D_RD,D_DU,D_LR); /*weight of current config*/
323  w1 = wf5(D_RU,D_LD,D_DU,D_LR,D_LU,D_RD); /*weight with L<->D switch*/
324  w2 = wf5(D_DU,D_LR,D_LU,D_RD,D_RU,D_LD); /*weight with R<->D switch*/
325  if (w0 <= w1)
326  {
327  if (w0 <= w2) /*w0 <= w1,w2*/
328  {
329  *weight = 0.0;
330  return(NONE);
331  }
332  else /*w2 < w0 <= w1 */
333  {
334  *weight = w2 - w0;
335  if (verbose)
336  {
337  printf("Possible swap across %s. ",e->label);
338  printf("Weight dropping by %lf.\n",w0 - w2);
339  printf("New weight would be %lf.\n",T->weight + w2 - w0);
340  }
341  return(RIGHT);
342  }
343  }
344  else if (w2 <= w1) /*w2 <= w1 < w0*/
345  {
346  *weight = w2 - w0;
347  if (verbose)
348  {
349  printf("Possible swap across %s. ",e->label);
350  printf("Weight dropping by %lf.\n",w0 - w2);
351  printf("New weight should be %lf.\n",T->weight + w2 - w0);
352  }
353  return(RIGHT);
354  }
355  else /*w1 < w2, w0*/
356  {
357  *weight = w1 - w0;
358  if (verbose)
359  {
360  printf("Possible swap across %s. ",e->label);
361  printf("Weight dropping by %lf.\n",w0 - w1);
362  printf("New weight should be %lf.\n",T->weight + w1 - w0);
363  }
364  return(LEFT);
365  }
366 }
367 
368 
369 
370 /*limitedFillTableUp fills all the entries in D associated with
371  e->head,f->head and those edges g->head above e->head, working
372  recursively and stopping when trigger is reached*/
373 void limitedFillTableUp(meEdge *e, meEdge *f, double **A, meEdge *trigger)
374 {
375  meEdge *g,*h;
376  g = f->tail->parentEdge;
377  if (f != trigger)
378  limitedFillTableUp(e,g,A,trigger);
379  h = siblingEdge(f);
380  A[e->head->index][f->head->index] =
381  A[f->head->index][e->head->index] =
382  0.5*(A[e->head->index][g->head->index] + A[e->head->index][h->head->index]);
383 }
384 
385 void WFext(meEdge *e, double **A) /*works except when e is the one edge
386  inserted to new vertex v by firstInsert*/
387 {
388  meEdge *f, *g;
389  if ((leaf(e->head)) && (leaf(e->tail)))
390  e->distance = A[e->head->index][e->head->index];
391  else if (leaf(e->head))
392  {
393  f = e->tail->parentEdge;
394  g = siblingEdge(e);
395  e->distance = 0.5*(A[e->head->index][g->head->index]
396  + A[e->head->index][f->head->index]
397  - A[g->head->index][f->head->index]);
398  }
399  else
400  {
401  f = e->head->leftEdge;
402  g = e->head->rightEdge;
403  e->distance = 0.5*(A[g->head->index][e->head->index]
404  + A[f->head->index][e->head->index]
405  - A[f->head->index][g->head->index]);
406  }
407 }
408 
409 void WFint(meEdge *e, double **A)
410 {
411  int up, down, left, right;
412  up = e->tail->index;
413  down = (siblingEdge(e))->head->index;
414  left = e->head->leftEdge->head->index;
415  right = e->head->rightEdge->head->index;
416  e->distance = 0.25*(A[up][left] + A[up][right] + A[left][down] + A[right][down]) - 0.5*(A[down][up] + A[left][right]);
417 }
418 
419 
420 
421 void assignBalWeights(meTree *T, double **A)
422 {
423  meEdge *e;
425  while (NULL != e) {
426  if ((leaf(e->head)) || (leaf(e->tail)))
427  WFext(e,A);
428  else
429  WFint(e,A);
430  e = depthFirstTraverse(T,e);
431  }
432 }
433 
434 
435 END_SCOPE(fastme)
double wf5(double D_AD, double D_BC, double D_AC, double D_BD, double D_AB, double D_CD)
Definition: bNNI.cpp:295
void printMatrix(double **M, int dim, FILE *ofile, meTree *T)
Definition: bNNI.cpp:93
void bNNI(meTree *T, double **avgDistArray, int *count)
Definition: bNNI.cpp:114
void updateSubTreeAfterNNI(double **A, meNode *v, meEdge *rootEdge, meNode *closer, meNode *further, double dcoeff, int direction)
Definition: bNNI.cpp:195
void bNNIRetestEdge(int *p, int *q, meEdge *e, meTree *T, double **avgDistArray, double *weights, int *location, int *possibleSwaps)
Definition: bNNI.cpp:68
void limitedFillTableUp(meEdge *e, meEdge *f, double **A, meEdge *trigger)
Definition: bNNI.cpp:373
meEdge * findBottomLeft(meEdge *e)
Definition: traverse.cpp:44
boolean leaf(meNode *v)
Definition: graph.cpp:44
meEdge * siblingEdge(meEdge *e)
Definition: graph.cpp:210
void updatePair(double **A, meEdge *nearEdge, meEdge *farEdge, meNode *closer, meNode *further, double dcoeff, int direction)
Definition: bme.cpp:158
void pushHeap(int *p, int *q, double *v, int length, int i)
Definition: heap.cpp:131
void bNNItopSwitch(meTree *T, meEdge *e, int direction, double **A)
Definition: bNNI.cpp:258
void WFint(meEdge *e, double **A)
Definition: bNNI.cpp:409
void reHeapElement(int *p, int *q, double *v, int length, int i)
Definition: heap.cpp:108
int makeThreshHeap(int *p, int *q, double *v, int arraySize, double thresh)
Definition: heap.cpp:139
meEdge * moveUpRight(meEdge *e)
Definition: traverse.cpp:91
void weighTree(meTree *T)
Definition: bNNI.cpp:106
void updateAveragesMatrix(meTree *T, double **A, meNode *v, int direction)
void popHeap(int *p, int *q, double *v, int length, int i)
Definition: heap.cpp:125
meEdge * depthFirstTraverse(meTree *T, meEdge *e)
Definition: traverse.cpp:65
meEdge * topFirstTraverse(meTree *T, meEdge *e)
Definition: traverse.cpp:107
void WFext(meEdge *e, double **A)
Definition: bNNI.cpp:385
void bNNIupdateAverages(double **A, meNode *v, meEdge *par, meEdge *skew, meEdge *swap, meEdge *fixed)
Definition: bNNI.cpp:242
int bNNIEdgeTest(meEdge *e, meTree *T, double **A, double *weight)
Definition: bNNI.cpp:303
int * initPerm(int size)
Definition: heap.cpp:45
void permInverse(int *p, int *q, int length)
Definition: heap.cpp:55
void assignBalWeights(meTree *T, double **A)
Definition: bNNI.cpp:421
static const char location[]
Definition: config.c:97
#define head
Definition: ct_nlmzip_i.h:138
#define T(s)
Definition: common.h:230
#define A(i)
Definition: ecp_curves.c:948
#define UP
Definition: fastme.h:50
#define SKEW
Definition: fastme.h:54
#define DOWN
Definition: fastme.h:51
#define LEFT
Definition: fastme.h:52
#define NONE
Definition: fastme.h:49
#define RIGHT
Definition: fastme.h:53
void swap(NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair1, NCBI_NS_NCBI::pair_base_member< T1, T2 > &pair2)
Definition: ncbimisc.hpp:1508
#define NULL
Definition: ncbistd.hpp:225
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define END_SCOPE(ns)
End the previously defined scope.
Definition: ncbistl.hpp:75
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define BEGIN_SCOPE(ns)
Define a new scope.
Definition: ncbistl.hpp:72
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
n font weight
int i
const struct ncbi::grid::netcache::search::fields::SIZE size
double f(double x_, const double &y_)
Definition: njn_root.hpp:188
true_type verbose
Definition: processing.cpp:902
Definition: graph.h:84
struct meNode * tail
Definition: graph.h:86
double distance
Definition: graph.h:90
char label[50]
Definition: graph.h:85
struct meNode * head
Definition: graph.h:87
Definition: graph.h:74
struct meEdge * rightEdge
Definition: graph.h:79
struct meEdge * parentEdge
Definition: graph.h:76
char label[50]
Definition: graph.h:75
struct meEdge * leftEdge
Definition: graph.h:77
int index
Definition: graph.h:80
Definition: graph.h:94
int g(Seg_Gsm *spe, Seq_Mtf *psm, Thd_Gsm *tdg)
Definition: thrddgri.c:44
void free(voidpf ptr)
voidp malloc(uInt size)
Modified on Sat Dec 02 09:20:28 2023 by modify_doxy.py rev. 669887