Exemplo n.º 1
0
likelihood_vector *copy_likelihood_vectors (tree *tr, nodeptr p)
{
  assert(tr->useRecom == FALSE);
  likelihood_vector *v = (likelihood_vector *) malloc(sizeof(likelihood_vector));  
  v->node_number = p->number; 
  v->num_partitions = tr->NumberOfModels; 
  v->partition_sizes = (size_t *)malloc(tr->NumberOfModels * sizeof(size_t));
  v->lh_values = (double **)malloc(tr->NumberOfModels * sizeof(double *));

  /* Compute LH vector sizes for each partition */
  size_t rateHet, states, width, vector_size;
  rateHet = discreteRateCategories(tr->rateHetModel);
  int model;
  for(model = 0; model < tr->NumberOfModels; model++)
  {
    width  = (size_t)tr->partitionData[model].width;
    states = (size_t)tr->partitionData[model].states;
    vector_size = virtual_width( width ) * rateHet * states * sizeof(double);
    v->lh_values[model] = (double *)malloc(sizeof(double) * vector_size);
    assert (v->lh_values[model] != NULL);
    v->partition_sizes[model] = vector_size;
    double *lh_vector_src = tr->partitionData[model].xVector[p->number - tr->mxtips - 1];
    assert (lh_vector_src != NULL);
    vector_size = v->partition_sizes[model];
    memcpy(v->lh_values[model], lh_vector_src, vector_size);
  }
  return v;
}
Exemplo n.º 2
0
void evaluateIterative(tree *tr)
{
  /* the branch lengths and node indices of the virtual root branch are always the first one that 
     are stored in the very important traversal array data structure that describes a partial or full tree traversal */

  /* get the branch length at the root */
  double 
    *pz = tr->td[0].ti[0].qz;   

  /* get the node number of the node to the left and right of the branch that defines the virtual rooting */

  int    
    pNumber = tr->td[0].ti[0].pNumber, 
    qNumber = tr->td[0].ti[0].qNumber, 
    model;
 
  /* before we can compute the likelihood at the virtual root, we need to do a partial or full tree traversal to compute 
     the conditional likelihoods of the vectors as specified in the traversal descriptor. Maintaining this tarversal descriptor consistent 
     will unfortunately be the responsibility of users. This is tricky, if as planned for here, we use a rooted view (described somewhere in Felsenstein's book)
     for the conditional vectors with respect to the tree
  */
     
  /* iterate over all valid entries in the traversal descriptor */

  newviewIterative(tr, 1);  

  /* after the above call we are sure that we have properly and consistently computed the 
     conditionals to the right and left of the virtual root and we can now invoke the 
     the log likelihood computation */

  /* we need to loop over all partitions. Note that we may have a mix of DNA, protein binary data etc partitions */

  for(model = 0; model < tr->NumberOfModels; model++)
    {    
      /* whats' the number of sites of this partition (at the current thread) */
      int 	    
	width = tr->partitionData[model].width;
        
      /* 
	 Important part of the tarversal descriptor: 
	 figure out if we need to recalculate the likelihood of this 
	 partition: 

	 The reasons why this is important in terms of performance are given in this paper 
	 here which you should actually read:
	 
	 A. Stamatakis, M. Ott: "Load Balance in the Phylogenetic Likelihood Kernel". Proceedings of ICPP 2009, accepted for publication, Vienna, Austria, September 2009
	 
	 The width > 0 check is for checking if under the cyclic data distribution of per-partition sites to threads this thread does indeed have a site 
	 of the current partition.

       */

      if(tr->td[0].executeModel[model] && width > 0)
	{	
	  int 
	    rateHet = (int)discreteRateCategories(tr->rateHetModel),
	    categories,
	    
	    /* get the number of states in the partition, e.g.: 4 = DNA, 20 = Protein */

	    states = tr->partitionData[model].states;
	  
	  double 
	    *rateCategories = (double*)NULL,
	    z, 
	    partitionLikelihood = 0.0, 	   
	    *x1_start   = (double*)NULL, 
	    *x2_start   = (double*)NULL,
	    *diagptable = (double*)NULL,  
	    *x1_gapColumn = (double*)NULL,
	    *x2_gapColumn = (double*)NULL;
	  	    	 	  
	  unsigned int
	    *x1_gap = (unsigned int*)NULL,
	    *x2_gap = (unsigned int*)NULL;	 
	  
	  unsigned char 
	    *tip = (unsigned char*)NULL;	  

	  /* 
	     figure out if we are using the CAT or GAMMA model of rate heterogeneity 
	     and set pointers to the rate heterogeneity rate arrays and also set the 
	     number of distinct rate categories appropriately.
	     
	     Under GAMMA this is constant and hard-coded as 4, weheras under CAT 
	     the number of site-wise rate categories can vary in the course of computations 
	     up to a user defined maximum value of site categories (default: 25)
	   */

	  if(tr->rateHetModel == CAT)
	    {	     
	      rateCategories = tr->partitionData[model].perSiteRates;
	      categories = tr->partitionData[model].numberOfCategories;
	    }
	  else
	    {	     
	      rateCategories = tr->partitionData[model].gammaRates;
	      categories = 4;
	    }
	  
	  /* set this pointer to the memory area where space has been reserved a priori for storing the 
	     P matrix at the root */

	  diagptable = tr->partitionData[model].left;

	  /* figure out if we need to address tip vectors (a char array that indexes into a precomputed tip likelihood 
	     value array or if we need to address inner vectors */

	  /* either node p or node q is a tip */
	  
	  if(isTip(pNumber, tr->mxtips) || isTip(qNumber, tr->mxtips))
	    {	        	    
	      /* q is a tip */

	      if(isTip(qNumber, tr->mxtips))
		{	
		  /* get the start address of the inner likelihood vector x2 for partition model,
		     note that inner nodes are enumerated/indexed starting at 0 to save allocating some 
		     space for additional pointers */
		  		 
		  x2_start = tr->partitionData[model].xVector[pNumber - tr->mxtips -1];		  

		  /* get the corresponding tip vector */

		  tip      = tr->partitionData[model].yVector[qNumber];	 

		  /* memory saving stuff, let's deal with this later or ask Fernando ;-) */

		  if(tr->saveMemory)
		    {
		      x2_gap         = &(tr->partitionData[model].gapVector[pNumber * tr->partitionData[model].gapVectorLength]);
		      x2_gapColumn   = &(tr->partitionData[model].gapColumn[(pNumber - tr->mxtips - 1) * states * rateHet]);
		    }
		}           
	      else
		{	
		  /* p is a tip, same as above */
	 
		  x2_start = tr->partitionData[model].xVector[qNumber - tr->mxtips - 1];		  		  
		  tip = tr->partitionData[model].yVector[pNumber];

		  if(tr->saveMemory)
		    {
		      x2_gap         = &(tr->partitionData[model].gapVector[qNumber * tr->partitionData[model].gapVectorLength]);
		      x2_gapColumn   = &(tr->partitionData[model].gapColumn[(qNumber - tr->mxtips - 1) * states * rateHet]);
		    }

		}
	    }
	  else
	    {  
	 
	      /* neither p nor q are tips, hence we need to get the addresses of two inner vectors */
    
	      x1_start = tr->partitionData[model].xVector[pNumber - tr->mxtips - 1];
	      x2_start = tr->partitionData[model].xVector[qNumber - tr->mxtips - 1];

	      /* memory saving option */

	      if(tr->saveMemory)
		{
		  x1_gap = &(tr->partitionData[model].gapVector[pNumber * tr->partitionData[model].gapVectorLength]);
		  x2_gap = &(tr->partitionData[model].gapVector[qNumber * tr->partitionData[model].gapVectorLength]);
		  x1_gapColumn   = &tr->partitionData[model].gapColumn[(pNumber - tr->mxtips - 1) * states * rateHet];
		  x2_gapColumn   = &tr->partitionData[model].gapColumn[(qNumber - tr->mxtips - 1) * states * rateHet];
		}
	
	    }

	 
	  

	  /* if we are using a per-partition branch length estimate, the branch has an index, otherwise, for a joint branch length
	     estimate over all partitions we just use the branch length value with index 0 */

	  if(tr->numBranches > 1)
	    z = pz[model];
	  else
	    z = pz[0];

	  /* calc P-Matrix at root for branch z connecting nodes p and q */

	  calcDiagptable(z, states, categories, rateCategories, tr->partitionData[model].EIGN, diagptable);	 

#ifndef _OPTIMIZED_FUNCTIONS

	  /* generic slow functions, memory saving option is not implemented for these */

	  assert(!tr->saveMemory);

	  /* decide wheter CAT or GAMMA is used and compute log like */

	  if(tr->rateHetModel == CAT)
	     partitionLikelihood = evaluateCAT_FLEX(tr->partitionData[model].rateCategory, tr->partitionData[model].wgt,
						    x1_start, x2_start, tr->partitionData[model].tipVector, 
						    tip, width, diagptable, states);
	  else
	    partitionLikelihood = evaluateGAMMA_FLEX(tr->partitionData[model].wgt,
						     x1_start, x2_start, tr->partitionData[model].tipVector,
						     tip, width, diagptable, states);
#else

	  /* for the optimized functions we have a dedicated, optimized function implementation 
	     for each rate heterogeneity and data type combination, we switch over the number of states 
	     and the rate heterogeneity model */
	  
	  switch(states)
	    { 	  
	    case 4: /* DNA */
	      {
		if(tr->rateHetModel == CAT)
		  {		  		  
		    if(tr->saveMemory)
		      partitionLikelihood =  evaluateGTRCAT_SAVE(tr->partitionData[model].rateCategory, tr->partitionData[model].wgt,
								 x1_start, x2_start, tr->partitionData[model].tipVector, 
								 tip, width, diagptable, x1_gapColumn, x2_gapColumn, x1_gap, x2_gap);
		    else
		      partitionLikelihood =  evaluateGTRCAT(tr->partitionData[model].rateCategory, tr->partitionData[model].wgt,
							    x1_start, x2_start, tr->partitionData[model].tipVector, 
							    tip, width, diagptable);
		  }
		else
		  {		
		    if(tr->saveMemory)		   
		      partitionLikelihood =  evaluateGTRGAMMA_GAPPED_SAVE(tr->partitionData[model].wgt,
									  x1_start, x2_start, tr->partitionData[model].tipVector,
									  tip, width, diagptable,
									  x1_gapColumn, x2_gapColumn, x1_gap, x2_gap);		    
		    else
		      partitionLikelihood =  evaluateGTRGAMMA(tr->partitionData[model].wgt,
							      x1_start, x2_start, tr->partitionData[model].tipVector,
							      tip, width, diagptable); 		    		  
		  }
	      }
	      break;	  	   		   
	    case 20: /* proteins */
	      {
		if(tr->rateHetModel == CAT)
		  {		   		  
		    if(tr->saveMemory)
		      partitionLikelihood = evaluateGTRCATPROT_SAVE(tr->partitionData[model].rateCategory, tr->partitionData[model].wgt,
								    x1_start, x2_start, tr->partitionData[model].tipVector,
								    tip, width, diagptable,  x1_gapColumn, x2_gapColumn, x1_gap, x2_gap);
		    else
		      partitionLikelihood = evaluateGTRCATPROT(tr->partitionData[model].rateCategory, tr->partitionData[model].wgt,
							       x1_start, x2_start, tr->partitionData[model].tipVector,
							       tip, width, diagptable);		  
		  }
		else
		  {		    		    		      
		    if(tr->saveMemory)
		      partitionLikelihood = evaluateGTRGAMMAPROT_GAPPED_SAVE(tr->partitionData[model].wgt,
									     x1_start, x2_start, tr->partitionData[model].tipVector,
									     tip, width, diagptable,
									     x1_gapColumn, x2_gapColumn, x1_gap, x2_gap);
		    
		    else
		      partitionLikelihood = evaluateGTRGAMMAPROT(tr->partitionData[model].wgt,
								 x1_start, x2_start, tr->partitionData[model].tipVector,
								 tip, width, diagptable);		         
		  }
	      }
	      break;	      		    
	    default:
	      assert(0);	    
	    }	
#endif
	  
	  /* check that there was no major numerical screw-up, the log likelihood should be < 0.0 always */
	 	  
	  assert(partitionLikelihood < 0.0);
	  	     		      
	  /* now here is a nasty part, for each partition and each node we maintain an integer counter to count how often 
	     how many entries per node were scaled by a constant factor. Here we use this information generated during Felsenstein's 
	     pruning algorithm by the newview() functions to undo the preceding scaling multiplications at the root, for mathematical details 
	     you should actually read:

	     A. Stamatakis: "Orchestrating the Phylogenetic Likelihood Function on Emerging Parallel Architectures". 
	     In B. Schmidt, editor, Bioinformatics: High Performance Parallel Computer Architectures, 85-115, CRC Press, Taylor & Francis, 2010.

	     There's a copy of this book in my office 
	  */
	     

	  partitionLikelihood += (tr->partitionData[model].globalScaler[pNumber] + tr->partitionData[model].globalScaler[qNumber]) * LOG(minlikelihood);	  

	  /* now we have the correct log likelihood for the current partition after undoing scaling multiplications */	  	 
	  
	  /* finally, we also store the per partition log likelihood which is important for optimizing the alpha parameter 
	     of this partition for example */

	  tr->perPartitionLH[model] = partitionLikelihood; 	  
	}
      else
	{
	  /* if the current thread does not have a single site of this partition
	     it is important to set the per partition log like to 0.0 because 
	     of the reduction operation that will take place later-on.
	     That is, the values of tr->perPartitionLH across all threads 
	     need to be in a consistent state, always !
	  */

	  if(width == 0)	    
	    tr->perPartitionLH[model] = 0.0;
	  else
	    assert(tr->td[0].executeModel[model] == FALSE && tr->perPartitionLH[model] < 0.0);
	}
    }
}