source: trunk/GDE/PHYML20130708/phyml/src/alrt.c

Last change on this file was 10307, checked in by aboeckma, 11 years ago

added most recent version of phyml

File size: 34.4 KB
Line 
1/*
2
3PHYML :  a program that  computes maximum likelihood  phylogenies from
4DNA or AA homologous sequences
5
6Copyright (C) Stephane Guindon. Oct 2003 onward
7
8All parts of  the source except where indicated  are distributed under
9the GNU public licence.  See http://www.opensource.org for details.
10
11*/
12
13/*
14
15Implementation of aLRT branch tests, and 5-branchs NNI research optimization.
16
17Authors : Jean-Francois Dufayard & Stephane Guindon.
18
19*/
20
21#include "alrt.h"
22
23//////////////////////////////////////////////////////////////
24//////////////////////////////////////////////////////////////
25
26
27/*
28* Check every testable branch of the tree,
29* check for NNIs, optimizing 5 branches,
30* param tree : the tree to check
31*/
32
33int Check_NNI_Five_Branches(t_tree *tree)
34{
35  int best_edge;
36  phydbl best_gain;
37  int best_config;
38  int i;
39  int better_found; /* = 1 if a phylogeny with greater likelihood than current one was found */
40  int result;
41  phydbl init_lnL;
42
43  init_lnL     = UNLIKELY;
44  better_found = 1;
45
46  //While there is at least one NNI to do...
47  while(better_found)
48    {
49      Update_Dirs(tree);
50
51      //Interface output
52      if((tree->mod->s_opt->print) && (!tree->io->quiet)) PhyML_Printf("\n\n. Checking for NNIs, optimizing five branches...\n");
53
54      better_found  =  0;
55      result        = -1;
56      best_edge     = -1;
57      best_gain     = 1.E+10;
58      best_config   = -1;
59
60      MIXT_Set_Alias_Subpatt(YES,tree);
61      Set_Both_Sides(YES,tree);     
62      init_lnL = Lk(NULL,tree);
63      MIXT_Set_Alias_Subpatt(NO,tree);
64
65      //For every branch
66      For(i,2*tree->n_otu-3)
67        {
68          //if this branch is not terminal
69          if((!tree->a_edges[i]->left->tax) && (!tree->a_edges[i]->rght->tax))
70            {
71              result = -1;
72
73              //Try every NNIs for the tested branch
74              result = NNI_Neigh_BL(tree->a_edges[i],tree);
75
76              //Look for possible NNI to do, and check if it is the best one
77              switch(result)
78                {
79                case 1 : /* lk1 > lk0 > lk2 */
80                  {
81                    if((tree->a_edges[i]->nni->lk0 - tree->a_edges[i]->nni->lk1) < best_gain)
82                      {
83                        better_found = 1;
84                        best_edge    = i;
85                        best_gain    = tree->a_edges[i]->nni->lk0-tree->a_edges[i]->nni->lk1;
86                        best_config  = 1;
87                      }
88                    break;
89                  }
90                case 2 : /* lk2 > lk0 > lk1 */
91                  {
92                    if((tree->a_edges[i]->nni->lk0 - tree->a_edges[i]->nni->lk2) < best_gain)
93                      {
94                        better_found = 1;
95                        best_edge    = i;
96                        best_gain    = tree->a_edges[i]->nni->lk0-tree->a_edges[i]->nni->lk2;
97                        best_config  = 2;
98                      }
99                    break;
100                  }
101                case 3 : /* lk1 > lk2 > lk0 */
102                  {
103                    if((tree->a_edges[i]->nni->lk2 - tree->a_edges[i]->nni->lk1) < best_gain)
104                      {
105                        better_found = 1;
106                        best_edge    = i;
107                        best_gain    = tree->a_edges[i]->nni->lk2-tree->a_edges[i]->nni->lk1;
108                        best_config  = 1;
109                      }
110                    break;
111                  }
112                case 4 : /* lk2 > lk1 > lk0 */
113                  {
114                    if((tree->a_edges[i]->nni->lk1 - tree->a_edges[i]->nni->lk2) < best_gain)
115                      {
116                        better_found = 1;
117                        best_edge    = i;
118                        best_gain    = tree->a_edges[i]->nni->lk1-tree->a_edges[i]->nni->lk2;
119                        best_config  = 2;
120                      }
121                    break;
122                  }
123                default : /* lk2 = lk1 = lk0 */
124                  {
125                    if(best_gain > .0) best_gain = .0;
126                    break;
127                  }
128                }
129            }
130        }
131
132      if((tree->c_lnL < init_lnL - tree->mod->s_opt->min_diff_lk_local) || (tree->c_lnL > init_lnL + tree->mod->s_opt->min_diff_lk_local))
133        {
134          PhyML_Printf("\n\n== tree->c_lnL = %f init_lnL = %f.",tree->c_lnL,init_lnL);
135          PhyML_Printf("\n== Err in file %s at line %d\n\n.\n",__FILE__,__LINE__);
136          Warn_And_Exit("\n");
137        }
138
139      //Don't do any NNI if the user doesn't want to optimize topology
140      if(!tree->mod->s_opt->opt_topo) better_found = 0;
141/*       if(FABS(best_gain) <= tree->mod->s_opt->min_diff_lk_move) better_found = 0; */
142
143      //If there is one swap to do, make the best one.
144      if(better_found)
145        {
146          Make_Target_Swap(tree,tree->a_edges[best_edge],best_config);
147
148          MIXT_Set_Alias_Subpatt(YES,tree);
149          Lk(NULL,tree);
150          MIXT_Set_Alias_Subpatt(YES,tree);
151
152          if(tree->c_lnL < init_lnL)
153            {
154              PhyML_Printf("\n\n== tree->c_lnL = %f init_lnL = %f.",tree->c_lnL,init_lnL);
155              PhyML_Printf("\n== Err. in file %s at line %d\n\n.\n",__FILE__,__LINE__);
156              Exit("\n");
157            }
158
159          if((tree->mod->s_opt->print) && (!tree->io->quiet)) Print_Lk(tree,"[Topology           ]");
160
161          if(FABS(tree->c_lnL - init_lnL) < tree->mod->s_opt->min_diff_lk_move) return 0;         
162          return 1;
163        }
164    }
165  return 0;
166}
167
168//////////////////////////////////////////////////////////////
169//////////////////////////////////////////////////////////////
170
171/* Compute aLRT supports */
172void aLRT(t_tree *tree)
173{
174  int i;
175  char *method;
176
177  Unscale_Br_Len_Multiplier_Tree(tree);
178  Br_Len_Not_Involving_Invar(tree);
179
180  /* aLRT support will label each internal branch */
181  tree->print_alrt_val = YES;
182
183  /* The topology will not be modified when assessing the branch support. We make sure that it will
184     not be modified afterwards by locking the topology */
185
186  method = (char *)mCalloc(100,sizeof(char));
187
188  switch(tree->io->ratio_test)
189    {
190    case ALRTCHI2:      { strcpy(method,"aLRT"); break; }
191    case MINALRTCHI2SH: { strcpy(method,"aLRT"); break; }
192    case ALRTSTAT:      { strcpy(method,"aLRT"); break; }
193    case SH:            { strcpy(method,"SH"); break; }
194    case ABAYES:        { strcpy(method,"aBayes"); break; }
195    default : return;
196    }
197
198  if(tree->io->quiet == NO) PhyML_Printf("\n\n. Calculating fast branch supports (using '%s').",method);
199  Free(method);
200
201  MIXT_Set_Alias_Subpatt(YES,tree);
202  Set_Both_Sides(YES,tree);     
203  Lk(NULL,tree);
204  MIXT_Set_Alias_Subpatt(NO,tree);
205
206  For(i,2*tree->n_otu-3)
207    if((!tree->a_edges[i]->left->tax) && (!tree->a_edges[i]->rght->tax)) 
208      {
209        /* Compute likelihoods for each of the three configuration */
210        NNI_Neigh_BL(tree->a_edges[i],tree);
211        /* Compute the corresponding statistical support */
212        Compute_Likelihood_Ratio_Test(tree->a_edges[i],tree);
213      }
214 
215  tree->lock_topo = YES;
216
217  Br_Len_Involving_Invar(tree);
218  Rescale_Br_Len_Multiplier_Tree(tree);
219
220}
221
222//////////////////////////////////////////////////////////////
223//////////////////////////////////////////////////////////////
224
225/*
226* Launch one branch testing,
227* analyse the result
228* and convert supports as wished by the user.
229* param tree : the tree to check
230* param tested_t_edge : the tested t_edge of the tree
231* param old_loglk : the initial likelihood, before any aLRT analysis
232* param isBoot : 1 if used from the Bootstrap procedure, 0 if not
233* return an integer, informative to analyse the results and potential NNIs to do
234*/
235int Compute_Likelihood_Ratio_Test(t_edge *tested_edge, t_tree *tree)
236{
237  int result=0;
238
239  tested_edge->ratio_test     =  0.0;
240  tested_edge->alrt_statistic = -1.0;
241 
242  if((tested_edge->nni->lk0 > tested_edge->nni->lk1) && (tested_edge->nni->lk0 > tested_edge->nni->lk2))
243    {
244      if(tested_edge->nni->lk1 < tested_edge->nni->lk2)
245        {
246          //lk0 > lk2 > lk1
247          tested_edge->alrt_statistic = 2*(tested_edge->nni->lk0 - tested_edge->nni->lk2);
248        }
249      else
250        {
251          //lk0 > lk1 >= lk2
252          tested_edge->alrt_statistic = 2*(tested_edge->nni->lk0 - tested_edge->nni->lk1);
253        }
254
255      if (tested_edge->alrt_statistic < 0.0)
256        {
257          tested_edge->alrt_statistic = 0.0;
258          tested_edge->ratio_test = 0.0;
259        }
260      else
261        {
262          //aLRT statistic is valid, compute the branch support
263          if (tree->io->ratio_test == ALRTCHI2)
264            {
265              tested_edge->ratio_test = Statistics_To_Probabilities(tested_edge->alrt_statistic);         
266            }
267          else if(tree->io->ratio_test == MINALRTCHI2SH)
268            {
269              phydbl sh_support;
270              phydbl param_support;
271             
272              sh_support    = Statistics_To_SH(tree);
273              param_support = Statistics_To_Probabilities(tested_edge->alrt_statistic);
274             
275              if(sh_support < param_support) tested_edge->ratio_test = sh_support;
276              else                           tested_edge->ratio_test = param_support;
277            }
278         
279          else if(tree->io->ratio_test == ALRTSTAT) 
280            {
281              tested_edge->ratio_test=tested_edge->alrt_statistic;
282            } 
283          else if(tree->io->ratio_test == SH) 
284            {
285              tested_edge->ratio_test = Statistics_To_SH(tree);
286            }
287          else if(tree->io->ratio_test == ABAYES)
288            {
289              phydbl Kp0,Kp1,Kp2,logK;
290             
291              logK = 1. - MAX(MAX(tested_edge->nni->lk0,tested_edge->nni->lk1),tested_edge->nni->lk2);
292
293              Kp0 = EXP(tested_edge->nni->lk0+logK);
294              Kp1 = EXP(tested_edge->nni->lk1+logK);
295              Kp2 = EXP(tested_edge->nni->lk2+logK);
296              tested_edge->ratio_test = Kp0/(Kp0+Kp1+Kp2);
297             
298            }
299        }
300    } 
301  //statistic is not valid, give the negative statistics if wished, or a zero support.
302  else if((tested_edge->nni->lk1 > tested_edge->nni->lk0) && (tested_edge->nni->lk1 > tested_edge->nni->lk2))
303    {
304/*       tested_edge->ratio_test = 2*(tested_edge->nni->lk0-tested_edge->nni->lk1); */
305      tested_edge->ratio_test = 0.0;
306      if(tree->io->ratio_test > 1) tested_edge->alrt_statistic = 0.0;
307    }
308  else if((tested_edge->nni->lk2 > tested_edge->nni->lk0) && (tested_edge->nni->lk2 > tested_edge->nni->lk1))
309    {
310/*       tested_edge->ratio_test = 2*(tested_edge->nni->lk0-tested_edge->nni->lk2); */
311      tested_edge->ratio_test = 0.0;
312      if(tree->io->ratio_test > 1) tested_edge->alrt_statistic = 0.0;
313    }
314  else // lk0 ~ lk1 ~ lk2
315    {
316      tested_edge->ratio_test = 0.0;
317      if(tree->io->ratio_test > 1) tested_edge->ratio_test = 0.0;
318    }
319  return result;
320}
321
322//////////////////////////////////////////////////////////////
323//////////////////////////////////////////////////////////////
324
325/*
326* Test the 3 NNI positions for one branch.
327* param tree : the tree to check
328* param tested_t_edge : the tested t_edge of the tree
329* param old_loglk : the initial likelihood, before any aLRT analysis
330* param isBoot : 1 if used from the Bootstrap procedure, 0 if not
331*/
332int NNI_Neigh_BL(t_edge *b_fcus, t_tree *tree)
333{
334  int site;
335  t_node *v1,*v2,*v3,*v4;
336  t_edge *e1,*e2,*e3,*e4;
337  phydbl *len_e1,*len_e2,*len_e3,*len_e4;
338  phydbl lk0, lk1, lk2;
339  phydbl *bl_init;
340  phydbl l_infa, l_infb;
341  phydbl lk_init, lk_temp;
342  int i;
343  int result,counter,wei;
344  void *buff;
345
346  if(tree->n_root || tree->e_root)
347    {
348      PhyML_Printf("\n== Err. in file %s at line %d\n\n",__FILE__,__LINE__);
349      Exit("");
350    }
351
352  result = 0;
353
354  /*! Initialization */
355  bl_init = MIXT_Get_Lengths_Of_This_Edge(b_fcus,tree);
356  lk_init = tree->c_lnL;
357  lk_temp = UNLIKELY;
358
359  b_fcus->nni->score = .0;
360
361  lk0 = lk1 = lk2    = UNLIKELY;
362  v1 = v2 = v3 = v4  = NULL;
363
364  /*! vertices */
365  v1 = b_fcus->left->v[b_fcus->l_v1];
366  v2 = b_fcus->left->v[b_fcus->l_v2];
367  v3 = b_fcus->rght->v[b_fcus->r_v1];
368  v4 = b_fcus->rght->v[b_fcus->r_v2];
369
370  if(v1->num < v2->num)
371    {
372      PhyML_Printf("\n== Err. in file %s at line %d\n\n",__FILE__,__LINE__);
373      Exit("");
374    }
375  if(v3->num < v4->num)
376    {
377      PhyML_Printf("\n== Err. in file %s at line %d\n\n",__FILE__,__LINE__);
378      Exit("");
379    }
380
381  /*! edges */
382  e1 = b_fcus->left->b[b_fcus->l_v1];
383  e2 = b_fcus->left->b[b_fcus->l_v2];
384  e3 = b_fcus->rght->b[b_fcus->r_v1];
385  e4 = b_fcus->rght->b[b_fcus->r_v2];
386
387  /*! record initial branch lengths */
388  len_e1 = MIXT_Get_Lengths_Of_This_Edge(e1,tree);
389  len_e2 = MIXT_Get_Lengths_Of_This_Edge(e2,tree);
390  len_e3 = MIXT_Get_Lengths_Of_This_Edge(e3,tree);
391  len_e4 = MIXT_Get_Lengths_Of_This_Edge(e4,tree);
392
393  /*! Optimize branch lengths and update likelihoods for
394    the original configuration.
395  */
396  do
397    {
398      lk0 = lk_temp;
399
400      For(i,3)
401        if(b_fcus->left->v[i] != b_fcus->rght)
402          {
403            Update_P_Lk(tree,b_fcus->left->b[i],b_fcus->left);
404
405            l_infa  = 10.;
406            l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->left->b[i]->l->v);
407
408            lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus->left->b[i],tree);
409          }
410
411      Update_P_Lk(tree,b_fcus,b_fcus->left);
412
413      l_infa  = 10.;
414      l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->l->v);
415      lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus,tree);
416
417
418      For(i,3)
419        if(b_fcus->rght->v[i] != b_fcus->left)
420          {
421            Update_P_Lk(tree,b_fcus->rght->b[i],b_fcus->rght);
422
423            l_infa  = 10.;
424            l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->rght->b[i]->l->v);
425
426            lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus->rght->b[i],tree);
427          }
428
429      Update_P_Lk(tree,b_fcus,b_fcus->rght);
430
431      if(lk_temp < lk0 - tree->mod->s_opt->min_diff_lk_local)
432        {
433          PhyML_Printf("\n== lk_temp = %f lk0 = %f\n",lk_temp,lk0);
434          PhyML_Printf("\n== Err. in file %s at line %d\n\n",__FILE__,__LINE__);
435          Exit("\n");
436        }
437    }
438  while(FABS(lk_temp-lk0) > tree->mod->s_opt->min_diff_lk_global);
439
440  lk0 = tree->c_lnL;
441
442  buff = (t_tree *)tree;
443  do
444    {     
445      counter=0;
446      For(site,tree->n_pattern)
447        {
448          wei=0;
449          For(wei,tree->data->wght[site])
450            {
451              tree->log_lks_aLRT[0][counter]= tree->c_lnL_sorted[site] / tree->data->wght[site];
452              counter++;
453            }
454        }
455      tree = tree->next_mixt;
456    }
457  while(tree);
458  tree = (t_tree *)buff;
459
460
461  /*! Go back to initial branch lengths */
462  MIXT_Set_Lengths_Of_This_Edge(len_e1,e1,tree);
463  MIXT_Set_Lengths_Of_This_Edge(len_e2,e2,tree);
464  MIXT_Set_Lengths_Of_This_Edge(len_e3,e3,tree);
465  MIXT_Set_Lengths_Of_This_Edge(len_e4,e4,tree);
466  MIXT_Set_Lengths_Of_This_Edge(bl_init,b_fcus,tree);
467  Update_PMat_At_Given_Edge(e1,tree);
468  Update_PMat_At_Given_Edge(e2,tree);
469  Update_PMat_At_Given_Edge(e3,tree);
470  Update_PMat_At_Given_Edge(e4,tree);
471  Update_PMat_At_Given_Edge(b_fcus,tree);
472
473
474  /* Sanity check */
475  MIXT_Set_Alias_Subpatt(YES,tree);
476  Update_P_Lk(tree,b_fcus,b_fcus->rght);
477  Update_P_Lk(tree,b_fcus,b_fcus->left);
478  lk_temp = Lk(b_fcus,tree);
479  MIXT_Set_Alias_Subpatt(NO,tree);
480  if((lk_temp > lk_init + tree->mod->s_opt->min_diff_lk_local) || (lk_temp < lk_init - tree->mod->s_opt->min_diff_lk_local))
481    {
482      PhyML_Printf("\n== lk_temp = %f lk_init = %f",lk_temp,lk_init);
483      PhyML_Printf("\n== Err. in file %s at line %d\n",__FILE__,__LINE__);
484      Exit("\n");
485    }
486
487
488  /*! Do first possible swap */
489  Swap(v2,b_fcus->left,b_fcus->rght,v3,tree);
490
491  MIXT_Set_Alias_Subpatt(YES,tree);
492  Set_Both_Sides(YES,tree);     
493  Update_P_Lk(tree,b_fcus,b_fcus->left);
494  Update_P_Lk(tree,b_fcus,b_fcus->rght);
495  lk1 = Lk(b_fcus,tree);
496  MIXT_Set_Alias_Subpatt(NO,tree);
497
498  For(i,3)
499    if(b_fcus->left->v[i] != b_fcus->rght)
500      Update_P_Lk(tree,b_fcus->left->b[i],b_fcus->left);
501
502  For(i,3)
503    if(b_fcus->rght->v[i] != b_fcus->left)
504      Update_P_Lk(tree,b_fcus->rght->b[i],b_fcus->rght);
505
506
507  /*! Optimize branch lengths and update likelihoods */
508  lk_temp = UNLIKELY;
509  do
510    {
511      lk1 = lk_temp;
512
513      For(i,3)
514        if(b_fcus->left->v[i] != b_fcus->rght)
515          {
516            Update_P_Lk(tree,b_fcus->left->b[i],b_fcus->left);
517            l_infa  = 10.;
518            l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->left->b[i]->l->v);
519            lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus->left->b[i],tree);
520          }
521
522      Update_P_Lk(tree,b_fcus,b_fcus->left);
523      l_infa  = 10.;
524      l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->l->v);
525      lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus,tree);
526
527      For(i,3)
528        if(b_fcus->rght->v[i] != b_fcus->left)
529          {
530            Update_P_Lk(tree,b_fcus->rght->b[i],b_fcus->rght);
531            l_infa  = 10.;
532            l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->rght->b[i]->l->v);
533            lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus->rght->b[i],tree);
534          }
535
536      Update_P_Lk(tree,b_fcus,b_fcus->rght);
537
538      if(lk_temp < lk1 - tree->mod->s_opt->min_diff_lk_local)
539        {
540          PhyML_Printf("\n== lk_temp = %f lk1 = %f\n",lk_temp,lk1);
541          PhyML_Printf("\n== Err in file %s at line %d\n\n",__FILE__,__LINE__);
542          Warn_And_Exit("");
543        }
544    }
545  while(FABS(lk_temp-lk1) > tree->mod->s_opt->min_diff_lk_global);
546  /*! until no significative improvement is detected */
547
548  lk1 = tree->c_lnL;
549
550  /*! save likelihood of each sites, in order to compute branch supports */
551
552  buff = (t_tree *)tree;
553  do
554    {     
555      counter=0;
556      For(site,tree->n_pattern)
557        {
558          wei=0;
559          For(wei,tree->data->wght[site])
560            {
561              tree->log_lks_aLRT[1][counter]= tree->c_lnL_sorted[site] / tree->data->wght[site];
562              counter++;
563            }
564        }
565      tree = tree->next_mixt;
566    }
567  while(tree);
568  tree = (t_tree *)buff;
569
570  /*! undo the swap */
571  Swap(v3,b_fcus->left,b_fcus->rght,v2,tree);
572
573  /*! Go back to initial branch lengths */
574  MIXT_Set_Lengths_Of_This_Edge(len_e1,e1,tree);
575  MIXT_Set_Lengths_Of_This_Edge(len_e2,e2,tree);
576  MIXT_Set_Lengths_Of_This_Edge(len_e3,e3,tree);
577  MIXT_Set_Lengths_Of_This_Edge(len_e4,e4,tree);
578  MIXT_Set_Lengths_Of_This_Edge(bl_init,b_fcus,tree);
579
580  Update_PMat_At_Given_Edge(e1,tree);
581  Update_PMat_At_Given_Edge(e2,tree);
582  Update_PMat_At_Given_Edge(e3,tree);
583  Update_PMat_At_Given_Edge(e4,tree);
584  Update_PMat_At_Given_Edge(b_fcus,tree);
585 
586  /* Sanity check */
587  MIXT_Set_Alias_Subpatt(YES,tree);
588  Update_P_Lk(tree,b_fcus,b_fcus->rght);
589  Update_P_Lk(tree,b_fcus,b_fcus->left);
590  lk_temp = Lk(b_fcus,tree);
591  MIXT_Set_Alias_Subpatt(NO,tree);
592  if((lk_temp > lk_init + tree->mod->s_opt->min_diff_lk_local) || (lk_temp < lk_init - tree->mod->s_opt->min_diff_lk_local))
593    {
594      PhyML_Printf("\n== lk_temp = %f lk_init = %f",lk_temp,lk_init);
595      PhyML_Printf("\n== Err. in file %s at line %d\n",__FILE__,__LINE__);
596      Warn_And_Exit("");
597    }
598
599  /*! do the second possible swap */
600  Swap(v2,b_fcus->left,b_fcus->rght,v4,tree);
601
602  Set_Both_Sides(YES,tree);
603  MIXT_Set_Alias_Subpatt(YES,tree);
604  Update_P_Lk(tree,b_fcus,b_fcus->left);
605  Update_P_Lk(tree,b_fcus,b_fcus->rght);   
606  lk2 = Lk(b_fcus,tree);
607  MIXT_Set_Alias_Subpatt(NO,tree);
608
609  For(i,3)
610    if(b_fcus->left->v[i] != b_fcus->rght)
611      Update_P_Lk(tree,b_fcus->left->b[i],b_fcus->left);
612
613  For(i,3)
614    if(b_fcus->rght->v[i] != b_fcus->left)
615      Update_P_Lk(tree,b_fcus->rght->b[i],b_fcus->rght);
616
617  /*! Optimize branch lengths and update likelihoods */
618  lk_temp = UNLIKELY;
619  do
620    {
621      lk2 = lk_temp;
622
623
624      For(i,3)
625        if(b_fcus->left->v[i] != b_fcus->rght)
626          {
627            Update_P_Lk(tree,b_fcus->left->b[i],b_fcus->left);
628
629            l_infa  = 10.;
630            l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->left->b[i]->l->v);
631            lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus->left->b[i],tree);
632
633            if(lk_temp < lk2 - tree->mod->s_opt->min_diff_lk_local)
634              {
635                PhyML_Printf("\n== l_infa: %f l_infb: %f l: %f var:%f",l_infa,l_infb,b_fcus->left->b[i]->l->v,b_fcus->left->b[i]->l_var->v);
636                PhyML_Printf("\n== lk_temp = %f lk2 = %f",lk_temp,lk2);
637                PhyML_Printf("\n== Err. in file %s at line %d",__FILE__,__LINE__);
638                Exit("\n");
639              }
640          }
641
642      Update_P_Lk(tree,b_fcus,b_fcus->left);
643
644      l_infa  = 10.;
645      l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->l->v);
646      lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus,tree);
647
648      if(lk_temp < lk2 - tree->mod->s_opt->min_diff_lk_local)
649        {
650          PhyML_Printf("\n== l_infa: %f l_infb: %f l: %f var:%f",l_infa,l_infb,b_fcus->l->v,b_fcus->l_var->v);
651          PhyML_Printf("\n== lk_temp = %f lk2 = %f",lk_temp,lk2);
652          PhyML_Printf("\n== Err. in file %s at line %d",__FILE__,__LINE__);
653          Exit("\n");
654        }
655
656      For(i,3)
657        if(b_fcus->rght->v[i] != b_fcus->left)
658          {
659            Update_P_Lk(tree,b_fcus->rght->b[i],b_fcus->rght);
660
661               
662            l_infa  = 10.;
663            l_infb  = MAX(0.0,tree->mod->l_min/b_fcus->rght->b[i]->l->v);
664            lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus->rght->b[i],tree);
665           
666
667            if(lk_temp < lk2 - tree->mod->s_opt->min_diff_lk_local)
668              {
669                Set_Both_Sides(YES,tree);
670                Lk(b_fcus,tree);
671                Check_Lk_At_Given_Edge(YES,tree);
672                PhyML_Printf("\n== l_infa: %f l_infb: %f l: %f var:%f",l_infa,l_infb,b_fcus->rght->b[i]->l->v,b_fcus->rght->b[i]->l_var->v);
673                PhyML_Printf("\n== lk_temp = %f lk2 = %f",lk_temp,lk2);
674                PhyML_Printf("\n== Err. in file %s at line %d",__FILE__,__LINE__);
675                Exit("\n");
676              }
677          }
678
679      Update_P_Lk(tree,b_fcus,b_fcus->rght);
680
681    }
682  while(FABS(lk_temp-lk2) > tree->mod->s_opt->min_diff_lk_global);
683  //until no significative improvement is detected
684
685  lk2 = tree->c_lnL;
686
687  /*! save likelihood of each sites, in order to compute branch supports */
688  buff = (t_tree *)tree; 
689  do
690    {
691      counter=0;
692      For(site,tree->n_pattern)
693        {
694          wei=0;
695          For(wei,tree->data->wght[site])
696            {
697              tree->log_lks_aLRT[2][counter]= tree->c_lnL_sorted[site] / tree->data->wght[site];
698              counter++;
699            }
700        }
701      tree = tree->next_mixt;
702    }
703  while(tree);
704  tree = (t_tree *)buff;
705
706
707  /*! undo the swap */
708  Swap(v4,b_fcus->left,b_fcus->rght,v2,tree);
709  /***********/
710
711  /*! restore the initial branch length values */
712  MIXT_Set_Lengths_Of_This_Edge(len_e1,e1,tree);
713  MIXT_Set_Lengths_Of_This_Edge(len_e2,e2,tree);
714  MIXT_Set_Lengths_Of_This_Edge(len_e3,e3,tree);
715  MIXT_Set_Lengths_Of_This_Edge(len_e4,e4,tree);
716  MIXT_Set_Lengths_Of_This_Edge(bl_init,b_fcus,tree);
717
718  /*! recompute likelihoods */
719  Update_PMat_At_Given_Edge(e1,tree);
720  Update_PMat_At_Given_Edge(e2,tree);
721  Update_PMat_At_Given_Edge(e3,tree);
722  Update_PMat_At_Given_Edge(e4,tree);
723  Update_PMat_At_Given_Edge(b_fcus,tree);
724
725  MIXT_Set_Alias_Subpatt(YES,tree);
726  Update_P_Lk(tree,b_fcus,b_fcus->left);
727  Update_P_Lk(tree,b_fcus,b_fcus->rght);
728
729  For(i,3)
730    if(b_fcus->left->v[i] != b_fcus->rght)
731      Update_P_Lk(tree,b_fcus->left->b[i],b_fcus->left);
732
733  For(i,3)
734    if(b_fcus->rght->v[i] != b_fcus->left)
735      Update_P_Lk(tree,b_fcus->rght->b[i],b_fcus->rght);
736
737  MIXT_Set_Alias_Subpatt(NO,tree);
738
739  lk_temp = Lk(b_fcus,tree);
740
741  if((lk_temp > lk_init + tree->mod->s_opt->min_diff_lk_local) || (lk_temp < lk_init - tree->mod->s_opt->min_diff_lk_local))
742    {
743      PhyML_Printf("\n== lk_temp = %f lk_init = %f",lk_temp,lk_init);
744      PhyML_Printf("\n== Err. in file %s at line %d\n",__FILE__,__LINE__);
745      Warn_And_Exit("");
746    }
747
748
749  //save likelihoods in NNI structures
750  b_fcus->nni->lk0 = lk0;
751  b_fcus->nni->lk1 = lk1;
752  b_fcus->nni->lk2 = lk2;
753
754  b_fcus->nni->score = lk0 - MAX(lk1,lk2);
755
756  if((b_fcus->nni->score <  tree->mod->s_opt->min_diff_lk_local) &&
757     (b_fcus->nni->score > -tree->mod->s_opt->min_diff_lk_local))
758    {
759      b_fcus->nni->score = .0;
760      b_fcus->nni->lk1 = b_fcus->nni->lk2 = b_fcus->nni->lk0;
761    }
762
763  if((b_fcus->nni->lk1 > b_fcus->nni->lk0) && (b_fcus->nni->lk1 > b_fcus->nni->lk2))
764    {
765      if(b_fcus->nni->lk0 > b_fcus->nni->lk2) result = 1; //lk1 > lk0 > lk2
766      else                                    result = 3; //lk1 > lk2 > lk0
767    }
768  else if((b_fcus->nni->lk2 > b_fcus->nni->lk0) && (b_fcus->nni->lk2 > b_fcus->nni->lk1))
769    {
770      if(b_fcus->nni->lk0 > b_fcus->nni->lk1) result = 2; //lk2 > lk0 > lk1
771      else                                    result = 4; //lk2 > lk1 > lk0
772    }
773
774  Free(len_e1);
775  Free(len_e2);
776  Free(len_e3);
777  Free(len_e4);
778  Free(bl_init);
779
780  return result;
781}
782
783//////////////////////////////////////////////////////////////
784//////////////////////////////////////////////////////////////
785
786/*
787* Make one target swap, optimizing five branches.
788* param tree : the tree to check
789* param tested_t_edge : the swaping t_edge of the tree
790* param swapToDo : 1 or 2, to select the first or the second swap to do
791*/
792
793void Make_Target_Swap(t_tree *tree, t_edge *b_fcus, int swaptodo)
794{
795  t_node *v1,*v2,*v3,*v4;
796  phydbl lktodo;
797  phydbl l_infa, l_infb;
798  phydbl lk_init, lk_temp;
799  int i;
800
801  if(swaptodo < 0)
802    {
803      PhyML_Printf("\n== Err in file %s at line %d\n\n",__FILE__,__LINE__);
804      Warn_And_Exit("");
805    }
806
807  //Initialization
808  lk_init = tree->c_lnL;
809
810  b_fcus->nni->score = .0;
811
812  lktodo = UNLIKELY;
813  v1 = v2 = v3 = v4 = NULL;
814
815  v1 = b_fcus->left->v[b_fcus->l_v1];
816  v2 = b_fcus->left->v[b_fcus->l_v2];
817  v3 = b_fcus->rght->v[b_fcus->r_v1];
818  v4 = b_fcus->rght->v[b_fcus->r_v2];
819
820  if(v1->num < v2->num)
821    {
822      PhyML_Printf("\n== Err in file %s at line %d\n\n",__FILE__,__LINE__);
823      Warn_And_Exit("");
824    }
825  if(v3->num < v4->num)
826    {
827      PhyML_Printf("\n. Err in file %s at line %d\n\n",__FILE__,__LINE__);
828      Warn_And_Exit("");
829    }
830
831
832  /***********/
833  //make the selected swap
834  if(swaptodo==1)
835    {
836      Swap(v2,b_fcus->left,b_fcus->rght,v3,tree);
837      if(!Check_Topo_Constraints(tree,tree->io->cstr_tree)) Swap(v3,b_fcus->left,b_fcus->rght,v2,tree);
838    }
839  else
840    {
841      Swap(v2,b_fcus->left,b_fcus->rght,v4,tree);
842      if(!Check_Topo_Constraints(tree,tree->io->cstr_tree)) Swap(v4,b_fcus->left,b_fcus->rght,v2,tree);
843    }
844
845  MIXT_Set_Alias_Subpatt(YES,tree);
846  Set_Both_Sides(YES,tree);     
847  lktodo = Update_Lk_At_Given_Edge(b_fcus,tree);
848
849  For(i,3)
850    if(b_fcus->left->v[i] != b_fcus->rght)
851      Update_P_Lk(tree,b_fcus->left->b[i],b_fcus->left);
852
853  For(i,3)
854    if(b_fcus->rght->v[i] != b_fcus->left)
855      Update_P_Lk(tree,b_fcus->rght->b[i],b_fcus->rght);
856
857  MIXT_Set_Alias_Subpatt(NO,tree);
858
859  //Optimize branch lengths and update likelihoods
860  lk_temp = UNLIKELY;
861  do
862    {
863      lktodo = lk_temp;
864
865      For(i,3)
866        if(b_fcus->left->v[i] != b_fcus->rght)
867          {
868            Update_P_Lk(tree,b_fcus->left->b[i],b_fcus->left);
869
870            l_infa  = 10.;
871            l_infb  = tree->mod->l_min/b_fcus->left->b[i]->l->v;
872            lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus->left->b[i],tree);
873          }
874
875
876      Update_P_Lk(tree,b_fcus,b_fcus->left);
877
878      l_infa  = 10.;
879      l_infb  = tree->mod->l_min/b_fcus->l->v;
880      lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus,tree);
881
882
883
884      For(i,3)
885        if(b_fcus->rght->v[i] != b_fcus->left)
886          {
887            Update_P_Lk(tree,b_fcus->rght->b[i],b_fcus->rght);
888
889            l_infa  = 10.;
890            l_infb  = tree->mod->l_min/b_fcus->rght->b[i]->l->v;
891            lk_temp = Br_Len_Brent(l_infb,l_infa,b_fcus->rght->b[i],tree);
892          }
893
894      Update_P_Lk(tree,b_fcus,b_fcus->rght);
895
896      if(lk_temp < lktodo - tree->mod->s_opt->min_diff_lk_local)
897        {
898          PhyML_Printf("\n. Edge %3d lk_temp = %f lktodo = %f\n",b_fcus->num,lk_temp,lktodo);
899          PhyML_Printf("\n. Err in file %s at line %d\n\n",__FILE__,__LINE__);
900          Warn_And_Exit("");
901        }
902    }
903  while(FABS(lk_temp-lktodo) > tree->mod->s_opt->min_diff_lk_global);
904  //until no significative improvement is detected
905
906
907/*   PhyML_Printf("\n.<< [%3d] l=%f lk_init=%f tree->c_lnL=%f score=%12f v1=%3d v2=%3d v3=%3d v4=%3d >>", */
908/*       b_fcus->num, */
909/*       b_fcus->l->v, */
910/*       lk_init, */
911/*       tree->c_lnL, */
912/*       lk_init-tree->c_lnL, */
913/*       v1->num,v2->num,v3->num,v4->num);       */
914
915
916  if(tree->c_lnL < lk_init - tree->mod->s_opt->min_diff_lk_global)
917    {
918      PhyML_Printf("\n. [%3d] v1=%d v2=%d v3=%d v4=%d",
919             b_fcus->num,v1->num,v2->num,v3->num,v4->num);
920      PhyML_Printf("\n. tree->c_lnL = %f lk_init = %f\n",tree->c_lnL,lk_init);
921      PhyML_Printf("\n. Err in file %s at line %d\n\n",__FILE__,__LINE__);
922      Warn_And_Exit("");
923    }
924}
925
926//////////////////////////////////////////////////////////////
927//////////////////////////////////////////////////////////////
928
929/**
930* Convert an aLRT statistic to a none parametric support
931* param in: the statistic
932*/
933
934phydbl Statistics_To_Probabilities(phydbl in)
935{
936  phydbl rough_value=0.0;
937  phydbl a=0.0;
938  phydbl b=0.0;
939  phydbl fa=0.0;
940  phydbl fb=0.0;
941
942  if(in>=0.000000393 && in<0.00000157)
943    {
944      a=0.000000393;
945      b=0.00000157;
946      fa=0.0005;
947      fb=0.001;
948    }
949  else if(in>=0.00000157 && in<0.0000393)
950    {
951      a=0.00000157;
952      b=0.0000393;
953      fa=0.001;
954      fb=0.005;
955    }
956  else if(in>=0.0000393 && in<0.000157)
957    {
958      a=0.0000393;
959      b=0.000157;
960      fa=0.005;
961      fb=0.01;
962    }
963  else if(in>=0.000157 && in<0.000982)
964    {
965      a=0.000157;
966      b=0.000982;
967      fa=0.01;
968      fb=0.025;
969    }
970  else if(in>0.000982 && in<0.00393)
971    {
972      a=0.000982;
973      b=0.00393;
974      fa=0.025;
975      fb=0.05;
976    }
977  else if(in>=0.00393 && in<0.0158)
978    {
979      a=0.00393;
980      b=0.0158;
981      fa=0.05;
982      fb=0.1;
983    }
984  else if(in>=0.0158 && in<0.0642)
985    {
986      a=0.0158;
987      b=0.0642;
988      fa=0.1;
989      fb=0.2;
990    }
991  else if(in>=0.0642 && in<0.148)
992    {
993      a=0.0642;
994      b=0.148;
995      fa=0.2;
996      fb=0.3;
997    }
998  else if(in>=0.148 && in<0.275)
999    {
1000      a=0.148;
1001      b=0.275;
1002      fa=0.3;
1003      fb=0.4;
1004    }
1005  else if(in>=0.275 && in<0.455)
1006    {
1007      a=0.275;
1008      b=0.455;
1009      fa=0.4;
1010      fb=0.5;
1011    }
1012  else if(in>=0.455 && in<0.708)
1013    {
1014      a=0.455;
1015      b=0.708;
1016      fa=0.5;
1017      fb=0.6;
1018    }
1019  else if(in>=0.708 && in<1.074)
1020    {
1021      a=0.708;
1022      b=1.074;
1023      fa=0.6;
1024      fb=0.7;
1025    }
1026  else if(in>=1.074 && in<1.642)
1027    {
1028      a=1.074;
1029      b=1.642;
1030      fa=0.7;
1031      fb=0.8;
1032    }
1033  else if(in>=1.642 && in<2.706)
1034    {
1035      a=1.642;
1036      b=2.706;
1037      fa=0.8;
1038      fb=0.9;
1039    }
1040  else if(in>=2.706 && in<3.841)
1041    {
1042      a=2.706;
1043      b=3.841;
1044      fa=0.9;
1045      fb=0.95;
1046    }
1047  else if(in>=3.841 && in<5.024)
1048    {
1049      a=3.841;
1050      b=5.024;
1051      fa=0.95;
1052      fb=0.975;
1053    }
1054  else if(in>=5.024 && in<6.635)
1055    {
1056      a=5.024;
1057      b=6.635;
1058      fa=0.975;
1059      fb=0.99;
1060    }
1061  else if(in>=6.635 && in<7.879)
1062    {
1063      a=6.635;
1064      b=7.879;
1065      fa=0.99;
1066      fb=0.995;
1067    }
1068  else if(in>=7.879 && in<10.828)
1069    {
1070      a=7.879;
1071      b=10.828;
1072      fa=0.995;
1073      fb=0.999;
1074    }
1075  else if(in>=10.828 && in<12.116)
1076    {
1077      a=10.828;
1078      b=12.116;
1079      fa=0.999;
1080      fb=0.9995;
1081    }
1082  if (in>=12.116)
1083    {
1084      rough_value=0.9999;
1085    }
1086  else if(in<0.000000393)
1087    {
1088      rough_value=0.0001;
1089    }
1090  else
1091    {
1092      rough_value=(b-in)/(b-a)*fa + (in - a)/(b-a)*fb;
1093    }
1094  rough_value=rough_value+(1.0-rough_value)/2.0;
1095  rough_value=rough_value*rough_value*rough_value;
1096  return rough_value;
1097}
1098
1099//////////////////////////////////////////////////////////////
1100//////////////////////////////////////////////////////////////
1101
1102/**
1103* deprecated
1104* Compute a RELL support, using the latest tested branch
1105* param tree: the tested tree
1106*/
1107phydbl Statistics_to_RELL(t_tree *tree)
1108{
1109  int i;
1110  int occurence=1000;
1111  phydbl nb=0.0;
1112  phydbl res;
1113  int site;
1114  phydbl lk0=0.0;
1115  phydbl lk1=0.0;
1116  phydbl lk2=0.0;
1117  phydbl buff = -1.;
1118  int position = -1;
1119  t_tree *buff_tree;
1120
1121  /*! 1000 times */
1122  For(i,occurence)
1123    {
1124      lk0=0.0;
1125      lk1=0.0;
1126      lk2=0.0;
1127
1128      /*! Shuffle the data and increment the support, if needed */
1129      buff_tree = tree;
1130      do
1131        {
1132          For(site, tree->data->init_len)
1133            {
1134              buff  = rand();
1135              buff /= (RAND_MAX+1.);
1136              buff *= tree->data->init_len;
1137              position = (int)FLOOR(buff);
1138             
1139              lk0+=tree->log_lks_aLRT[0][position];
1140              lk1+=tree->log_lks_aLRT[1][position];
1141              lk2+=tree->log_lks_aLRT[2][position];
1142            }
1143          if (lk0>=lk1 && lk0>=lk2) nb++;
1144          tree = tree->next_mixt;
1145        }
1146      while(tree);
1147      tree = buff_tree;
1148    }
1149
1150  res= nb/(phydbl)occurence;
1151
1152  return res;
1153}
1154//////////////////////////////////////////////////////////////
1155//////////////////////////////////////////////////////////////
1156
1157/*!
1158  Compute a SH-like support, using the latest tested branch
1159  param tree: the tested tree
1160*/
1161phydbl Statistics_To_SH(t_tree *tree)
1162{
1163  int i;
1164  int occurence=1000;
1165  phydbl nb=0.0;
1166  phydbl res;
1167  int site;
1168  phydbl lk0=0.0;
1169  phydbl lk1=0.0;
1170  phydbl lk2=0.0;
1171  phydbl c0=0.0;
1172  phydbl c1=0.0;
1173  phydbl c2=0.0;
1174  phydbl buff=-1.;
1175  int position=-1;
1176  phydbl delta_local=-1.;
1177  phydbl delta=0.0;
1178  t_tree *buff_tree;
1179
1180
1181  /*! Compute the total log-lk of each NNI position */
1182  buff_tree = tree;
1183  do
1184    {
1185      For(site, tree->data->init_len)
1186        {
1187          c0+=tree->log_lks_aLRT[0][site];
1188          c1+=tree->log_lks_aLRT[1][site];
1189          c2+=tree->log_lks_aLRT[2][site];
1190        }
1191      tree = tree->next_mixt;
1192    }
1193  while(tree);
1194  tree = buff_tree;
1195
1196 
1197  if (c0>=c1 && c0>=c2)
1198    {
1199      if (c1>=c2)
1200        {
1201          delta=c0-c1;
1202        }
1203      else
1204        {
1205          delta=c0-c2;
1206        }
1207    }
1208  else if(c1>=c0 && c1>=c2)
1209    {
1210      if (c0>=c2)
1211        {
1212          delta=c1-c0;
1213        }
1214      else
1215        {
1216          delta=c1-c2;
1217        }
1218    }
1219  else
1220    {
1221      if (c1>=c0)       
1222        {
1223          delta=c2-c1;
1224        }
1225      else
1226        {
1227          delta=c2-c0;
1228        }
1229    }
1230
1231  /*! 1000 times */
1232  For(i,occurence)
1233    {
1234      lk0=0.0;
1235      lk1=0.0;
1236      lk2=0.0;
1237     
1238      buff_tree = tree;
1239      do
1240        {
1241          /*! Shuffle the data */
1242          For(site, tree->data->init_len)
1243            {
1244              buff  = rand();
1245              buff /= (RAND_MAX+1.);
1246              buff *= tree->data->init_len;
1247              position = (int)FLOOR(buff);
1248             
1249              lk0+=tree->log_lks_aLRT[0][position];
1250              lk1+=tree->log_lks_aLRT[1][position];
1251              lk2+=tree->log_lks_aLRT[2][position];
1252            }
1253         
1254          tree = tree->next_mixt;
1255        }
1256      while(tree);
1257      tree = buff_tree;
1258
1259      /*! return to null hypothesis */
1260      lk0=lk0-c0;
1261      lk1=lk1-c1;
1262      lk2=lk2-c2;
1263     
1264      /*! compute results and increment if needed */
1265      delta_local=0.0;
1266      if (lk0>=lk1 && lk0>=lk2)
1267        {
1268          if (lk1>=lk2)
1269            {
1270              delta_local=lk0-lk1;
1271            }
1272          else
1273            {
1274              delta_local=lk0-lk2;
1275            }
1276        }
1277      else if(lk1>=lk0 && lk1>=lk2)
1278        {
1279          if (lk0>=lk2)
1280            {
1281              delta_local=lk1-lk0;
1282            }
1283          else
1284            {
1285              delta_local=lk1-lk2;
1286            }
1287        }
1288      else
1289        {
1290          if (lk1>=lk0)
1291           
1292            {
1293              delta_local=lk2-lk1;
1294            }
1295          else
1296            {
1297              delta_local=lk2-lk0;
1298            }
1299        }
1300     
1301      if (delta>(delta_local+0.1)) 
1302        {
1303          nb++;
1304        }
1305    }
1306 
1307  res= nb/occurence;
1308 
1309  return res;
1310}
1311
1312//////////////////////////////////////////////////////////////
1313//////////////////////////////////////////////////////////////
1314
1315/**
1316* deprecated
1317* Compute one side likelihood
1318* param b_fcus : concerned edge
1319* param tree : b_fcus tree
1320* param exclude :  side to exclude for computation
1321*/
1322phydbl Update_Lk_At_Given_Edge_Excluding(t_edge *b_fcus, t_tree *tree, t_node *exclude)
1323{
1324  if((!b_fcus->left->tax) && (exclude == NULL || exclude != b_fcus->left))
1325    Update_P_Lk(tree,b_fcus,b_fcus->left);
1326  if((!b_fcus->rght->tax) && (exclude == NULL || exclude != b_fcus->rght))
1327    Update_P_Lk(tree,b_fcus,b_fcus->rght);
1328
1329  tree->c_lnL = Lk(b_fcus,tree);
1330
1331  return tree->c_lnL;
1332}
1333
1334
1335//////////////////////////////////////////////////////////////
1336//////////////////////////////////////////////////////////////
1337
1338//////////////////////////////////////////////////////////////
1339//////////////////////////////////////////////////////////////
1340
1341//////////////////////////////////////////////////////////////
1342//////////////////////////////////////////////////////////////
1343
1344//////////////////////////////////////////////////////////////
1345//////////////////////////////////////////////////////////////
1346
1347//////////////////////////////////////////////////////////////
1348//////////////////////////////////////////////////////////////
1349
1350//////////////////////////////////////////////////////////////
1351//////////////////////////////////////////////////////////////
1352
Note: See TracBrowser for help on using the repository browser.