/*
 * Class:     beagle_BeagleJNIWrapper
 * Method:    updatePartials
 * Signature: ([II[III)I
 */
JNIEXPORT jint JNICALL Java_beagle_BeagleJNIWrapper_updatePartials
  (JNIEnv *env, jobject obj, jint instance, jintArray inOperations, jint operationCount, jint cumulativeScalingIndex)
{
    jint *operations = env->GetIntArrayElements(inOperations, NULL);

	jint errCode = (jint)beagleUpdatePartials(instance, (BeagleOperation*)operations, operationCount, cumulativeScalingIndex);

    env->ReleaseIntArrayElements(inOperations, operations, JNI_ABORT);

    return errCode;
}
Beispiel #2
0
int main( int argc, const char* argv[] )
{
    // print resource list
    BeagleResourceList* rList;
    rList = beagleGetResourceList();
    fprintf(stdout, "Available resources:\n");
    for (int i = 0; i < rList->length; i++) {
        fprintf(stdout, "\tResource %i:\n\t\tName : %s\n", i, rList->list[i].name);
        fprintf(stdout, "\t\tDesc : %s\n", rList->list[i].description);
        fprintf(stdout, "\t\tFlags:");
        printFlags(rList->list[i].supportFlags);
        fprintf(stdout, "\n");
    }    
    fprintf(stdout, "\n");    
    
    bool manualScaling = false;
    bool autoScaling = false;
	bool gRates = false; // generalized rate categories, separate root buffers
    
    // is nucleotides...
    int stateCount = 4;
	
    // get the number of site patterns
	int nPatterns = strlen(human);
    
    int rateCategoryCount = 4;
	
	int nRateCats = (gRates ? 1 : rateCategoryCount);
	int nRootCount = (!gRates ? 1 : rateCategoryCount);
	int nPartBuffs = 4 + nRootCount;
    int scaleCount = (manualScaling ? 2 + nRootCount : 0);
    
    // initialize the instance
    BeagleInstanceDetails instDetails;
    
    // create an instance of the BEAGLE library
	int instance = beagleCreateInstance(
                                  3,				/**< Number of tip data elements (input) */
                                  nPartBuffs,       /**< Number of partials buffers to create (input) */
                                  0,		        /**< Number of compact state representation buffers to create (input) */
                                  stateCount,		/**< Number of states in the continuous-time Markov chain (input) */
                                  nPatterns,		/**< Number of site patterns to be handled by the instance (input) */
                                  1,		        /**< Number of rate matrix eigen-decomposition buffers to allocate (input) */
                                  4,		        /**< Number of rate matrix buffers (input) */
								  nRateCats,		/**< Number of rate categories (input) */
                                  scaleCount,       /**< Number of scaling buffers */
                                  NULL,			    /**< List of potential resource on which this instance is allowed (input, NULL implies no restriction */
                                  0,			    /**< Length of resourceList list (input) */
                                  BEAGLE_FLAG_PRECISION_DOUBLE | BEAGLE_FLAG_PROCESSOR_GPU | (autoScaling ? BEAGLE_FLAG_SCALING_AUTO : 0),	/**< Bit-flags indicating preferred implementation charactertistics, see BeagleFlags (input) */
                                  0,                /**< Bit-flags indicating required implementation characteristics, see BeagleFlags (input) */
                                  &instDetails);
    if (instance < 0) {
	    fprintf(stderr, "Failed to obtain BEAGLE instance\n\n");
	    exit(1);
    }
        
    int rNumber = instDetails.resourceNumber;
    fprintf(stdout, "Using resource %i:\n", rNumber);
    fprintf(stdout, "\tRsrc Name : %s\n",instDetails.resourceName);
    fprintf(stdout, "\tImpl Name : %s\n", instDetails.implName);
    fprintf(stdout, "\tImpl Desc : %s\n", instDetails.implDescription);
    fprintf(stdout, "\tFlags:");
    printFlags(instDetails.flags);
    fprintf(stdout, "\n\n");
    
    if (!(instDetails.flags & BEAGLE_FLAG_SCALING_AUTO))
        autoScaling = false;
    
//    beagleSetTipStates(instance, 0, getStates(human));
//    beagleSetTipStates(instance, 1, getStates(chimp));
//    beagleSetTipStates(instance, 2, getStates(gorilla));
    
    // set the sequences for each tip using partial likelihood arrays
    double *humanPartials   = getPartials(human);
    double *chimpPartials   = getPartials(chimp);
    double *gorillaPartials = getPartials(gorilla);
    
	beagleSetTipPartials(instance, 0, humanPartials);
	beagleSetTipPartials(instance, 1, chimpPartials);
	beagleSetTipPartials(instance, 2, gorillaPartials);
    
//#ifdef _WIN32
//	std::vector<double> rates(rateCategoryCount);
//#else
//	double rates[rateCategoryCount];
//#endif
//    for (int i = 0; i < rateCategoryCount; i++) {
//        rates[i] = 1.0;
//    }
	double rates[4] = { 0.03338775, 0.25191592, 0.82026848, 2.89442785 };
    
	
    // create base frequency array
	double freqs[16] = { 0.25, 0.25, 0.25, 0.25,
						 0.25, 0.25, 0.25, 0.25,
						 0.25, 0.25, 0.25, 0.25,
		                 0.25, 0.25, 0.25, 0.25 };
    
    // create an array containing site category weights

	double* weights = (double*) malloc(sizeof(double) * rateCategoryCount);

    for (int i = 0; i < rateCategoryCount; i++) {
        weights[i] = 1.0/rateCategoryCount;
    }    

	double* patternWeights = (double*) malloc(sizeof(double) * nPatterns);
    
    for (int i = 0; i < nPatterns; i++) {
        patternWeights[i] = 1.0;
    }    
    
    
	// an eigen decomposition for the JC69 model
	double evec[4 * 4] = {
        1.0,  2.0,  0.0,  0.5,
        1.0,  -2.0,  0.5,  0.0,
        1.0,  2.0, 0.0,  -0.5,
        1.0,  -2.0,  -0.5,  0.0
	};
    
	double ivec[4 * 4] = {
        0.25,  0.25,  0.25,  0.25,
        0.125,  -0.125,  0.125,  -0.125,
        0.0,  1.0,  0.0,  -1.0,
        1.0,  0.0,  -1.0,  0.0
	};
    
	double eval[4] = { 0.0, -1.3333333333333333, -1.3333333333333333, -1.3333333333333333 };
    
    // set the Eigen decomposition
	beagleSetEigenDecomposition(instance, 0, evec, ivec, eval);
    
    beagleSetStateFrequencies(instance, 0, freqs);
    
    beagleSetCategoryWeights(instance, 0, weights);
    
    beagleSetPatternWeights(instance, patternWeights);
    
    // a list of indices and edge lengths
	int nodeIndices[4] = { 0, 1, 2, 3 };
	double edgeLengths[4] = { 0.1, 0.1, 0.2, 0.1 };
	
	int* rootIndices = (int*) malloc(sizeof(int) * nRootCount);
    int* categoryWeightsIndices = (int*) malloc(sizeof(int) * nRootCount);
    int* stateFrequencyIndices = (int*) malloc(sizeof(int) * nRootCount);
	int* cumulativeScalingIndices = (int*) malloc(sizeof(int) * nRootCount);
	
	for (int i = 0; i < nRootCount; i++) {
		
		rootIndices[i] = 4 + i;
        categoryWeightsIndices[i] = 0;
        stateFrequencyIndices[i] = 0;
		cumulativeScalingIndices[i] = (manualScaling ? 2 + i : BEAGLE_OP_NONE);
		
		beagleSetCategoryRates(instance, &rates[i]);
		
		// tell BEAGLE to populate the transition matrices for the above edge lengths
		beagleUpdateTransitionMatrices(instance,     // instance
								 0,             // eigenIndex
								 nodeIndices,   // probabilityIndices
								 NULL,          // firstDerivativeIndices
								 NULL,          // secondDerivativeIndices
								 edgeLengths,   // edgeLengths
								 4);            // count
		
		// create a list of partial likelihood update operations
		// the order is [dest, destScaling, source1, matrix1, source2, matrix2]
		BeagleOperation operations[2] = {
			3, (manualScaling ? 0 : BEAGLE_OP_NONE), BEAGLE_OP_NONE, 0, 0, 1, 1,
			rootIndices[i], (manualScaling ? 1 : BEAGLE_OP_NONE), BEAGLE_OP_NONE, 2, 2, 3, 3
		};
		
		if (manualScaling)
			beagleResetScaleFactors(instance, cumulativeScalingIndices[i]);
		
		// update the partials
		beagleUpdatePartials(instance,      // instance
					   operations,     // eigenIndex
					   2,              // operationCount
					   cumulativeScalingIndices[i]);// cumulative scaling index
	}
		 
    if (autoScaling) {
        int scaleIndices[2] = {3, 4};
        beagleAccumulateScaleFactors(instance, scaleIndices, 2, BEAGLE_OP_NONE);
    }
    
	double *patternLogLik = (double*)malloc(sizeof(double) * nPatterns);
	double logL = 0.0;    
    int returnCode = 0;
    
    // calculate the site likelihoods at the root node
	returnCode = beagleCalculateRootLogLikelihoods(instance,               // instance
	                            (const int *)rootIndices,// bufferIndices
	                            (const int *)categoryWeightsIndices,                // weights
	                            (const int *)stateFrequencyIndices,                  // stateFrequencies
								cumulativeScalingIndices,// cumulative scaling index
	                            nRootCount,                      // count
	                            &logL);         // outLogLikelihoods
    
    if (returnCode < 0) {
	    fprintf(stderr, "Failed to calculate root likelihood\n\n");
    } else {

        beagleGetSiteLogLikelihoods(instance, patternLogLik);
        double sumLogL = 0.0;
        for (int i = 0; i < nPatterns; i++) {
            sumLogL += patternLogLik[i] * patternWeights[i];
//            std::cerr << "site lnL[" << i << "] = " << patternLogLik[i] << '\n';
        }
      
        fprintf(stdout, "logL = %.5f (PAUP logL = -1498.89812)\n", logL);
        fprintf(stdout, "sumLogL = %.5f\n", sumLogL);  
    }
    
// no rate heterogeneity:	
//	fprintf(stdout, "logL = %.5f (PAUP logL = -1574.63623)\n\n", logL);
	
    free(weights);
    free(patternWeights);    
    free(rootIndices);
    free(categoryWeightsIndices);
    free(stateFrequencyIndices);
    free(cumulativeScalingIndices);    
    
	free(patternLogLik);
	free(humanPartials);
	free(chimpPartials);
	free(gorillaPartials);
    
    beagleFinalizeInstance(instance);

#ifdef _WIN32
    std::cout << "\nPress ENTER to exit...\n";
    fflush( stdout);
    fflush( stderr);
    getchar();
#endif
    
}
Beispiel #3
0
/* Update partial likelihood on edge b on the side of b where
   node d lies.
*/
void update_beagle_partials(t_tree* tree, t_edge* b, t_node* d)
{
    /*
               |
               |<- b
               |
               d
              / \
          b1 /   \ b2
            /     \
        n_v1     n_v2
    */

  if(d->tax) //Partial likelihoods are only calculated on internal nodes
    {
      PhyML_Printf("\n== t_node %d is a leaf...",d->num);
      PhyML_Printf("\n== Err. in file %s at line %d (function '%s')\n",__FILE__,__LINE__,__FUNCTION__);
      Warn_And_Exit("\n");
    }

  //Determine d's "left" and "right" neighbors.
  t_node *n_v1, *n_v2;//d's "left" and "right" neighbor nodes
  phydbl *p_lk,*p_lk_v1,*p_lk_v2;
  phydbl *Pij1,*Pij2;
  int *sum_scale, *sum_scale_v1, *sum_scale_v2;
  int *p_lk_loc;
  int dest_p_idx, child1_p_idx, child2_p_idx, Pij1_idx, Pij2_idx;
  n_v1 = n_v2                 = NULL;
  p_lk = p_lk_v1 = p_lk_v2    = NULL;
  Pij1 = Pij2                 = NULL;
  sum_scale_v1 = sum_scale_v2 = NULL;
  p_lk_loc                    = NULL;
  dest_p_idx = child1_p_idx = child2_p_idx = Pij1_idx = Pij2_idx = UNINITIALIZED;
  Set_All_P_Lk(&n_v1,&n_v2,
               &p_lk,&sum_scale,&p_lk_loc,
               &Pij1,&p_lk_v1,&sum_scale_v1,
               &Pij2,&p_lk_v2,&sum_scale_v2,
               d,b,tree,
               &dest_p_idx, &child1_p_idx, &child2_p_idx, &Pij1_idx, &Pij2_idx);
  
  
  //    fprintf(stdout, "\nUpdating partials on Branch %d (on the side where Node %d lies)\n",b->num,d->num);fflush(stdout);
  //    double* p_lk_v1_b = (double*)malloc(tree->mod->ras->n_catg*tree->mod->ns*tree->n_pattern*sizeof(double));if(NULL==p_lk_v1_b) Warn_And_Exit("Couldnt allocate memory");
  //    beagleGetPartials(tree->b_inst, child1_p_idx, BEAGLE_OP_NONE, (double*)p_lk_v1_b);
  //    double* p_lk_v2_b = (double*)malloc(tree->mod->ras->n_catg*tree->mod->ns*tree->n_pattern*sizeof(double));if(NULL==p_lk_v2_b) Warn_And_Exit("Couldnt allocate memory");
  //    beagleGetPartials(tree->b_inst, child2_p_idx, BEAGLE_OP_NONE, (double*)p_lk_v2_b);
  
  //    fprintf(stdout, "Left partials :");fflush(stdout);
  //    Dump_Arr_D(p_lk_v1_b,   tree->mod->ras->n_catg*tree->mod->ns*tree->n_pattern);
  //    fprintf(stdout, "Right partials:");fflush(stdout);
  //    Dump_Arr_D(p_lk_v2_b,   tree->mod->ras->n_catg*tree->mod->ns*tree->n_pattern);
  //    Free(p_lk_v1_b);
  //    Free(p_lk_v2_b);
  
  
  //Create the corresponding BEAGLE operation
  
  // fprintf(stderr,"%d, %d, %d, ", dest_p_idx, child1_p_idx, child2_p_idx);
  
  BeagleOperation operations[1] = {{dest_p_idx, BEAGLE_OP_NONE, BEAGLE_OP_NONE, child1_p_idx, Pij1_idx, child2_p_idx, Pij2_idx}};
  //Compute the partials
  int ret = beagleUpdatePartials(tree->b_inst, operations, 1, BEAGLE_OP_NONE);
  if(ret<0){
    fprintf(stderr, "beagleUpdatePartials() on instance %i failed:%i\n\n",tree->b_inst,ret);
    Exit("");
  }
  //Load the computed/updated partial partials
#ifndef CLEAN_BEAGLE_API
   ret = beagleGetPartials(tree->b_inst, dest_p_idx, BEAGLE_OP_NONE, (double*)p_lk);
   if(ret<0){
     fprintf(stderr, "beagleGetPartials() on instance %i failed:%i\n\n",tree->b_inst,ret);
     Exit("");
   }
#endif
  
  //    fprintf(stdout, "Updated partials:");fflush(stdout);
  //    Dump_Arr_D(p_lk, tree->mod->ras->n_catg*tree->mod->ns*tree->n_pattern);
}
int main( int argc, const char* argv[] )
{
    
    bool scaling = true;
    
    // is nucleotides...
    int stateCount = 4;
	
    // get the number of site patterns
	int nPatterns = strlen(human);
    
    int rateCategoryCount = 4;
    
    int scaleCount = (scaling ? 3 : 0);
    
    BeagleInstanceDetails instDetails;
    
    // create an instance of the BEAGLE library
	int instance = beagleCreateInstance(
                                  3,				/**< Number of tip data elements (input) */
                                  5,	            /**< Number of partials buffers to create (input) */
                                  0,		        /**< Number of compact state representation buffers to create (input) */
                                  stateCount,		/**< Number of states in the continuous-time Markov chain (input) */
                                  nPatterns,		/**< Number of site patterns to be handled by the instance (input) */
                                  1,		        /**< Number of rate matrix eigen-decomposition buffers to allocate (input) */
                                  4,		        /**< Number of rate matrix buffers (input) */
                                  rateCategoryCount,/**< Number of rate categories (input) */
                                  scaleCount,       /**< Number of scaling buffers */
                                  NULL,			    /**< List of potential resource on which this instance is allowed (input, NULL implies no restriction */
                                  0,			    /**< Length of resourceList list (input) */
                                  BEAGLE_FLAG_PROCESSOR_GPU,             	/**< Bit-flags indicating preferred implementation charactertistics, see BeagleFlags (input) */
                                  0
#ifndef JC
                                  | BEAGLE_FLAG_EIGEN_COMPLEX
#endif
                                  ,           /**< Bit-flags indicating required implementation characteristics, see BeagleFlags (input) */
                                  &instDetails);
    if (instance < 0) {
	    fprintf(stderr, "Failed to obtain BEAGLE instance\n\n");
	    exit(1);
    }
        
    int rNumber = instDetails.resourceNumber;
    fprintf(stdout, "Using resource %i:\n", rNumber);
    fprintf(stdout, "\tRsrc Name : %s\n",instDetails.resourceName);
    fprintf(stdout, "\tImpl : %s\n", instDetails.implName);
    fprintf(stdout, "\tImpl Desc : %s\n", instDetails.implDescription);
    fprintf(stdout, "\n");
    
    
    // set the sequences for each tip using partial likelihood arrays
    double *humanPartials   = getPartials(human);
    double *chimpPartials   = getPartials(chimp);
    double *gorillaPartials = getPartials(gorilla);
    
	beagleSetTipPartials(instance, 0, humanPartials);
	beagleSetTipPartials(instance, 1, chimpPartials);
	beagleSetTipPartials(instance, 2, gorillaPartials);
    
#ifdef _WIN32
	std::vector<double> rates(rateCategoryCount);
#else
	double rates[rateCategoryCount];
#endif
    for (int i = 0; i < rateCategoryCount; i++) {
        rates[i] = 1.0;
    }
    
	beagleSetCategoryRates(instance, &rates[0]);
	
	double* patternWeights = (double*) malloc(sizeof(double) * nPatterns);
    
    for (int i = 0; i < nPatterns; i++) {
        patternWeights[i] = 1.0;
    }    
    
    beagleSetPatternWeights(instance, patternWeights);
	
    // create base frequency array
	double freqs[4] = { 0.25, 0.25, 0.25, 0.25 };
    
    beagleSetStateFrequencies(instance, 0, freqs);
    
    // create an array containing site category weights
#ifdef _WIN32
	std::vector<double> weights(rateCategoryCount);
#else
	double weights[rateCategoryCount];
#endif
    for (int i = 0; i < rateCategoryCount; i++) {
        weights[i] = 1.0/rateCategoryCount;
    }    
    
    beagleSetCategoryWeights(instance, 0, &weights[0]);
    
#ifndef JC
	// an eigen decomposition for the 4-state 1-step circulant infinitesimal generator
	double evec[4 * 4] = {
			 -0.5,  0.6906786606674509,   0.15153543380548623, 0.5,
			  0.5, -0.15153543380548576,  0.6906786606674498,  0.5,
			 -0.5, -0.6906786606674498,  -0.15153543380548617, 0.5,
			  0.5,  0.15153543380548554, -0.6906786606674503,  0.5
	};

	double ivec[4 * 4] = {
			 -0.5,  0.5, -0.5,  0.5,
			  0.6906786606674505, -0.15153543380548617, -0.6906786606674507,   0.15153543380548645,
			  0.15153543380548568, 0.6906786606674509,  -0.15153543380548584, -0.6906786606674509,
			  0.5,  0.5,  0.5,  0.5
	};

	double eval[8] = { -2.0, -1.0, -1.0, 0, 0, 1, -1, 0 };
#else
	// an eigen decomposition for the JC69 model
	double evec[4 * 4] = {
        1.0,  2.0,  0.0,  0.5,
        1.0,  -2.0,  0.5,  0.0,
        1.0,  2.0, 0.0,  -0.5,
        1.0,  -2.0,  -0.5,  0.0
	};
    
	double ivec[4 * 4] = {
        0.25,  0.25,  0.25,  0.25,
        0.125,  -0.125,  0.125,  -0.125,
        0.0,  1.0,  0.0,  -1.0,
        1.0,  0.0,  -1.0,  0.0
	};
    
	double eval[8] = { 0.0, -1.3333333333333333, -1.3333333333333333, -1.3333333333333333, 0.0, 0.0, 0.0, 0.0 };
#endif

    // a list of indices and edge lengths
	int nodeIndices[4] = { 0, 1, 2, 3 };
	double edgeLengths[4] = { 0.1, 0.1, 0.2, 0.1 };

//	// set the Eigen decomposition
//	beagleSetEigenDecomposition(instance, 0, evec, ivec, eval);
//
//    // tell BEAGLE to populate the transition matrices for the above edge lengths
//	beagleUpdateTransitionMatrices(instance,     // instance
//	                         0,             // eigenIndex
//	                         nodeIndices,   // probabilityIndices
//	                         NULL,          // firstDerivativeIndices
//	                         NULL,          // secondDervativeIndices
//	                         edgeLengths,   // edgeLengths
//	                         4);            // count

	// set transitionMatrices
    
    double* transitionMatrix = (double*) malloc(4 * 4 * 4 * rateCategoryCount * sizeof(double));
    
    double* paddedValues = (double*) malloc(4*sizeof(double));
	
    for(int b=0; b<4; b++) {
        getTransitionMatrix(eval,
                           evec,
                           ivec,
                           4,
                           rateCategoryCount,
                           &rates[0],
                           edgeLengths[b],
                           transitionMatrix + b*4*4*rateCategoryCount);
        
        paddedValues[b] = 1.0;
	}

    beagleSetTransitionMatrices(instance,
                                nodeIndices,
                                transitionMatrix,
                                paddedValues,
                                4);
    free(transitionMatrix);
    
    
    // create a list of partial likelihood update operations
    // the order is [dest, destScaling, source1, matrix1, source2, matrix2]
	BeagleOperation operations[2] = {
		3, (scaling ? 0 : BEAGLE_OP_NONE), BEAGLE_OP_NONE, 0, 0, 1, 1,
		4, (scaling ? 1 : BEAGLE_OP_NONE), BEAGLE_OP_NONE, 2, 2, 3, 3
	};
	int rootIndex = 4;
    
    // update the partials
	beagleUpdatePartials(instance,      // instance
                   operations,     // eigenIndex
                   2,              // operationCount
                   BEAGLE_OP_NONE);          // cumulative scaling index
    
	double *patternLogLik = (double*)malloc(sizeof(double) * nPatterns);

    int cumulativeScalingIndex = (scaling ? 2 : BEAGLE_OP_NONE);
    
    if (scaling) {
        int scalingFactorsCount = 2;
        int scalingFactorsIndices[2] = {0, 1};
        
        beagleResetScaleFactors(instance,
                                cumulativeScalingIndex);
        
        beagleAccumulateScaleFactors(instance,
                                     scalingFactorsIndices,
                                     scalingFactorsCount,
                                     cumulativeScalingIndex);
    }
    
	int categoryWeightsIndex = 0;
    int stateFrequencyIndex = 0;
    
	double logL = 0.0;    
    
    // calculate the site likelihoods at the root node
	beagleCalculateRootLogLikelihoods(instance,               // instance
	                            (const int *)&rootIndex,// bufferIndices
                                  &categoryWeightsIndex,                // weights
                                  &stateFrequencyIndex,                  // stateFrequencies
                                &cumulativeScalingIndex,// cumulative scaling index
	                            1,                      // count
	                            &logL);         // outLogLikelihoods
        
#ifndef JC
	fprintf(stdout, "logL = %.5f (BEAST = -1665.38544)\n\n", logL);
#else
	fprintf(stdout, "logL = %.5f (PAUP = -1574.63623)\n\n", logL);
#endif
    
    free(patternWeights);
	
	free(patternLogLik);
	free(humanPartials);
	free(chimpPartials);
	free(gorillaPartials);
    
    beagleFinalizeInstance(instance);

#ifdef _WIN32
    std::cout << "\nPress ENTER to exit...\n";
    fflush( stdout);
    fflush( stderr);
    getchar();
#endif
    
}
Beispiel #5
0
/*-----------------------------------------------------------------------------
|	Calculates the log likelihood by calling the beagle functions
|	updateTransitionMatrices, updatePartials and calculateEdgeLogLikelihoods.
*/
double calcLnL(world_fmt *world, boolean instance)
{
  beagle_fmt *beagle = world->beagle;
  double logL = 0.0;
  unsigned long i;
  unsigned long j;
  //unsigned long z;
  long locus = world->locus;
  long ii;
  double *patternloglike = (double *) calloc(world->maxnumpattern[locus],sizeof(double));
   double *outlike = (double *) calloc(10*world->maxnumpattern[locus],sizeof(double));
  int rootIndex = beagle->operations[BEAGLE_PARTIALS * (beagle->numoperations-1)];//world->root->next->back->id;
  for(i=0; i<world->nummutationmodels[locus]; i++)
    {
      ii = world->sublocistarts[locus] + i;
      int code = beagleUpdateTransitionMatrices(beagle->instance_handle[i],		// instance,
					  0,					// eigenIndex,
					  (const int *) beagle->branch_indices,	// indicators transitionrates for each branch,
					  NULL, 			        // firstDerivativeIndices,
					  NULL,					// secondDervativeIndices,
					  beagle->branch_lengths,		// edgeLengths,
					  beagle->numbranches);			// number branches to update, count

	if (code != 0)
		usererror("updateTransitionMatrices encountered a problem");

	int cumulativeScalingFactorIndex = 0; //BEAGLE_OP_NONE; //this would be the index of the root scaling location 
	
	beagleResetScaleFactors(beagle->instance_handle[i],
			  cumulativeScalingFactorIndex);

	beagleAccumulateScaleFactors(beagle->instance_handle[i],
			       beagle->scalingfactorsindices,
			       beagle->scalingfactorscount,
			       cumulativeScalingFactorIndex);
	

	code = beagleUpdatePartials((const int *) &beagle->instance_handle[i],	// instance
			      1,					        // instanceCount
			      beagle->operations,		                // operations
			      beagle->numoperations,				// operationCount
				    cumulativeScalingFactorIndex);//BEAGLE_OP_NONE);					        // connected to accumulate....
#ifdef BEAGLEDEBUG
	for(j=0;j<2*(world->sumtips * 2 - 1); j++)
	  {
	    beagleGetPartials(beagle->instance_handle[i],j,BEAGLE_OP_NONE, outlike);
	    if(j==world->sumtips * 2 - 1)
	      printf("-----------------------\n");
	    printf("%li: {%f, %f, %f, %f}\n",j, outlike[0],outlike[1],outlike[2],outlike[3]);
	  }
#endif
	if (code != 0)
	  usererror("updatePartials encountered a problem");



	if(beagle->weights==NULL)
	  beagle->weights = (double *) mycalloc(1,sizeof(double));
	//	else
	//  beagle->weights = (double *) myrealloc(beagle->weights,beagle->numoperations * sizeof(double));

	beagle->weights[0]= 1.0;

	// calculate the site likelihoods at the root node
	code = beagleCalculateRootLogLikelihoods(beagle->instance_handle[i],         // instance
					   (const int *) &rootIndex, // bufferIndices
					   (const double *) world->mutationmodels[ii].siteprobs,   // weights
					   (const double *) world->mutationmodels[ii].basefreqs,// stateFrequencies
					   &cumulativeScalingFactorIndex, //scalingfactors index,
					   1,              // count is this correct
	                            patternloglike);         // outLogLikelihoods
	//trash from function above					   &beagle->scalingfactorscount,//size of the scaling factor index
	if (code != 0)
		usererror("calculateRootLogLikelihoods encountered a problem");

	for (j = 0; j < world->mutationmodels[ii].numsites; j++) 
	  {
		logL += beagle->allyweights[j] * patternloglike[j];
		//		printf("%.1f ",patternloglike[j]);
	}
    }
  printf("Log LnL=%f (instance=%li)\n",logL,(long) instance);
#ifdef BEAGLEDEBUG
  debug_beagle(beagle);
#endif
  myfree(patternloglike);
  myfree(outlike);
  return logL; 
}
void runBeagle(int resource, 
               int stateCount, 
               int ntaxa, 
               int nsites, 
               bool manualScaling, 
               bool autoScaling,
               bool dynamicScaling,
               int rateCategoryCount,
               int nreps,
               bool fullTiming,
               bool requireDoublePrecision,
               bool requireSSE,
               int compactTipCount,
               int randomSeed,
               int rescaleFrequency,
               bool unrooted,
               bool calcderivs,
               bool logscalers,
               int eigenCount,
               bool eigencomplex,
               bool ievectrans,
               bool setmatrix)
{
    
    int edgeCount = ntaxa*2-2;
    int internalCount = ntaxa-1;
    int partialCount = ((ntaxa+internalCount)-compactTipCount)*eigenCount;
    int scaleCount = ((manualScaling || dynamicScaling) ? ntaxa : 0);
    
    BeagleInstanceDetails instDetails;
    
    // create an instance of the BEAGLE library
	int instance = beagleCreateInstance(
			    ntaxa,			  /**< Number of tip data elements (input) */
				partialCount, /**< Number of partials buffers to create (input) */
                compactTipCount,	/**< Number of compact state representation buffers to create (input) */
				stateCount,		  /**< Number of states in the continuous-time Markov chain (input) */
				nsites,			  /**< Number of site patterns to be handled by the instance (input) */
				eigenCount,		          /**< Number of rate matrix eigen-decomposition buffers to allocate (input) */
                (calcderivs ? (3*edgeCount*eigenCount) : edgeCount*eigenCount),/**< Number of rate matrix buffers (input) */
                rateCategoryCount,/**< Number of rate categories */
                scaleCount*eigenCount,          /**< scaling buffers */
				&resource,		  /**< List of potential resource on which this instance is allowed (input, NULL implies no restriction */
				1,			      /**< Length of resourceList list (input) */
                0,         /**< Bit-flags indicating preferred implementation charactertistics, see BeagleFlags (input) */
                (ievectrans ? BEAGLE_FLAG_INVEVEC_TRANSPOSED : BEAGLE_FLAG_INVEVEC_STANDARD) |
                (logscalers ? BEAGLE_FLAG_SCALERS_LOG : BEAGLE_FLAG_SCALERS_RAW) |
                (eigencomplex ? BEAGLE_FLAG_EIGEN_COMPLEX : BEAGLE_FLAG_EIGEN_REAL) |
                (dynamicScaling ? BEAGLE_FLAG_SCALING_DYNAMIC : 0) | 
                (autoScaling ? BEAGLE_FLAG_SCALING_AUTO : 0) |
                (requireDoublePrecision ? BEAGLE_FLAG_PRECISION_DOUBLE : BEAGLE_FLAG_PRECISION_SINGLE) |
                (requireSSE ? BEAGLE_FLAG_VECTOR_SSE : BEAGLE_FLAG_VECTOR_NONE),	  /**< Bit-flags indicating required implementation characteristics, see BeagleFlags (input) */
				&instDetails);
    if (instance < 0) {
	    fprintf(stderr, "Failed to obtain BEAGLE instance\n\n");
	    return;
    }
        
    int rNumber = instDetails.resourceNumber;
    fprintf(stdout, "Using resource %i:\n", rNumber);
    fprintf(stdout, "\tRsrc Name : %s\n",instDetails.resourceName);
    fprintf(stdout, "\tImpl Name : %s\n", instDetails.implName);    
    
    if (!(instDetails.flags & BEAGLE_FLAG_SCALING_AUTO))
        autoScaling = false;
    
    // set the sequences for each tip using partial likelihood arrays
	gt_srand(randomSeed);	// fix the random seed...
    for(int i=0; i<ntaxa; i++)
    {
        if (i >= compactTipCount) {
            double* tmpPartials = getRandomTipPartials(nsites, stateCount);
            beagleSetTipPartials(instance, i, tmpPartials);
            free(tmpPartials);
        } else {
            int* tmpStates = getRandomTipStates(nsites, stateCount);
            beagleSetTipStates(instance, i, tmpStates);
            free(tmpStates);                
        }
    }
    
#ifdef _WIN32
	std::vector<double> rates(rateCategoryCount);
#else
    double rates[rateCategoryCount];
#endif
	
    for (int i = 0; i < rateCategoryCount; i++) {
        rates[i] = gt_rand() / (double) GT_RAND_MAX;
    }
    
	beagleSetCategoryRates(instance, &rates[0]);
    
	double* patternWeights = (double*) malloc(sizeof(double) * nsites);
    
    for (int i = 0; i < nsites; i++) {
        patternWeights[i] = gt_rand() / (double) GT_RAND_MAX;
    }    

    beagleSetPatternWeights(instance, patternWeights);
    
    free(patternWeights);
	
    // create base frequency array

#ifdef _WIN32
	std::vector<double> freqs(stateCount);
#else
    double freqs[stateCount];
#endif
    
    // create an array containing site category weights
#ifdef _WIN32
	std::vector<double> weights(rateCategoryCount);
#else
    double weights[rateCategoryCount];
#endif

    for (int eigenIndex=0; eigenIndex < eigenCount; eigenIndex++) {
        for (int i = 0; i < rateCategoryCount; i++) {
            weights[i] = gt_rand() / (double) GT_RAND_MAX;
        } 
    
        beagleSetCategoryWeights(instance, eigenIndex, &weights[0]);
    }
    
    double* eval;
    if (!eigencomplex)
        eval = (double*)malloc(sizeof(double)*stateCount);
    else
        eval = (double*)malloc(sizeof(double)*stateCount*2);
    double* evec = (double*)malloc(sizeof(double)*stateCount*stateCount);
    double* ivec = (double*)malloc(sizeof(double)*stateCount*stateCount);
    
    for (int eigenIndex=0; eigenIndex < eigenCount; eigenIndex++) {
        if (!eigencomplex && ((stateCount & (stateCount-1)) == 0)) {
            
            for (int i=0; i<stateCount; i++) {
                freqs[i] = 1.0 / stateCount;
            }

            // an eigen decomposition for the general state-space JC69 model
            // If stateCount = 2^n is a power-of-two, then Sylvester matrix H_n describes
            // the eigendecomposition of the infinitesimal rate matrix
             
            double* Hn = evec;
            Hn[0*stateCount+0] = 1.0; Hn[0*stateCount+1] =  1.0; 
            Hn[1*stateCount+0] = 1.0; Hn[1*stateCount+1] = -1.0; // H_1
         
            for (int k=2; k < stateCount; k <<= 1) {
                // H_n = H_1 (Kronecker product) H_{n-1}
                for (int i=0; i<k; i++) {
                    for (int j=i; j<k; j++) {
                        double Hijold = Hn[i*stateCount + j];
                        Hn[i    *stateCount + j + k] =  Hijold;
                        Hn[(i+k)*stateCount + j    ] =  Hijold;
                        Hn[(i+k)*stateCount + j + k] = -Hijold;
                        
                        Hn[j    *stateCount + i + k] = Hn[i    *stateCount + j + k];
                        Hn[(j+k)*stateCount + i    ] = Hn[(i+k)*stateCount + j    ];
                        Hn[(j+k)*stateCount + i + k] = Hn[(i+k)*stateCount + j + k];                                
                    }
                }        
            }
            
            // Since evec is Hadamard, ivec = (evec)^t / stateCount;    
            for (int i=0; i<stateCount; i++) {
                for (int j=i; j<stateCount; j++) {
                    ivec[i*stateCount+j] = evec[j*stateCount+i] / stateCount;
                    ivec[j*stateCount+i] = ivec[i*stateCount+j]; // Symmetric
                }
            }
           
            eval[0] = 0.0;
            for (int i=1; i<stateCount; i++) {
                eval[i] = -stateCount / (stateCount - 1.0);
            }
       
        } else if (!eigencomplex) {
            for (int i=0; i<stateCount; i++) {
                freqs[i] = gt_rand() / (double) GT_RAND_MAX;
            }
        
            double** qmat=New2DArray<double>(stateCount, stateCount);    
            double* relNucRates = new double[(stateCount * stateCount - stateCount) / 2];
            
            int rnum=0;
            for(int i=0;i<stateCount;i++){
                for(int j=i+1;j<stateCount;j++){
                    relNucRates[rnum] = gt_rand() / (double) GT_RAND_MAX;
                    qmat[i][j]=relNucRates[rnum] * freqs[j];
                    qmat[j][i]=relNucRates[rnum] * freqs[i];
                    rnum++;
                }
            }

            //set diags to sum rows to 0
            double sum;
            for(int x=0;x<stateCount;x++){
                sum=0.0;
                for(int y=0;y<stateCount;y++){
                    if(x!=y) sum+=qmat[x][y];
                        }
                qmat[x][x]=-sum;
            } 
            
            double* eigvalsimag=new double[stateCount];
            double** eigvecs=New2DArray<double>(stateCount, stateCount);//eigenvecs
            double** teigvecs=New2DArray<double>(stateCount, stateCount);//temp eigenvecs
            double** inveigvecs=New2DArray<double>(stateCount, stateCount);//inv eigenvecs    
            int* iwork=new int[stateCount];
            double* work=new double[stateCount];
            
            EigenRealGeneral(stateCount, qmat, eval, eigvalsimag, eigvecs, iwork, work);
            memcpy(*teigvecs, *eigvecs, stateCount*stateCount*sizeof(double));
            InvertMatrix(teigvecs, stateCount, work, iwork, inveigvecs);
            
            for(int x=0;x<stateCount;x++){
                for(int y=0;y<stateCount;y++){
                    evec[x * stateCount + y] = eigvecs[x][y];
                    if (ievectrans)
                        ivec[x * stateCount + y] = inveigvecs[y][x];
                    else
                        ivec[x * stateCount + y] = inveigvecs[x][y];
                }
            } 
            
            Delete2DArray(qmat);
            delete relNucRates;
            
            delete eigvalsimag;
            Delete2DArray(eigvecs);
            Delete2DArray(teigvecs);
            Delete2DArray(inveigvecs);
            delete iwork;
            delete work;
        } else if (eigencomplex && stateCount==4 && eigenCount==1) {
            // create base frequency array
            double temp_freqs[4] = { 0.25, 0.25, 0.25, 0.25 };
            
            // an eigen decomposition for the 4-state 1-step circulant infinitesimal generator
            double temp_evec[4 * 4] = {
                -0.5,  0.6906786606674509,   0.15153543380548623, 0.5,
                0.5, -0.15153543380548576,  0.6906786606674498,  0.5,
                -0.5, -0.6906786606674498,  -0.15153543380548617, 0.5,
                0.5,  0.15153543380548554, -0.6906786606674503,  0.5
            };
            
            double temp_ivec[4 * 4] = {
                -0.5,  0.5, -0.5,  0.5,
                0.6906786606674505, -0.15153543380548617, -0.6906786606674507,   0.15153543380548645,
                0.15153543380548568, 0.6906786606674509,  -0.15153543380548584, -0.6906786606674509,
                0.5,  0.5,  0.5,  0.5
            };
            
            double temp_eval[8] = { -2.0, -1.0, -1.0, 0, 0, 1, -1, 0 };
            
            for(int x=0;x<stateCount;x++){
                freqs[x] = temp_freqs[x];
                eval[x] = temp_eval[x];
                eval[x+stateCount] = temp_eval[x+stateCount];
                for(int y=0;y<stateCount;y++){
                    evec[x * stateCount + y] = temp_evec[x * stateCount + y];
                    if (ievectrans)
                        ivec[x * stateCount + y] = temp_ivec[x + y * stateCount];
                    else
                        ivec[x * stateCount + y] = temp_ivec[x * stateCount + y];
                }
            } 
        } else {
            abort("should not be here");
        }
            
        beagleSetStateFrequencies(instance, eigenIndex, &freqs[0]);
        
        if (!setmatrix) {
            // set the Eigen decomposition
            beagleSetEigenDecomposition(instance, eigenIndex, &evec[0], &ivec[0], &eval[0]);
        }
    }
    
    free(eval);
    free(evec);
    free(ivec);


    
    // a list of indices and edge lengths
	int* edgeIndices = new int[edgeCount*eigenCount];
	int* edgeIndicesD1 = new int[edgeCount*eigenCount];
	int* edgeIndicesD2 = new int[edgeCount*eigenCount];
	for(int i=0; i<edgeCount*eigenCount; i++) {
        edgeIndices[i]=i;
        edgeIndicesD1[i]=(edgeCount*eigenCount)+i;
        edgeIndicesD2[i]=2*(edgeCount*eigenCount)+i;
    }
	double* edgeLengths = new double[edgeCount];
	for(int i=0; i<edgeCount; i++) {
        edgeLengths[i]=gt_rand() / (double) GT_RAND_MAX;
    }
    
    // create a list of partial likelihood update operations
    // the order is [dest, destScaling, source1, matrix1, source2, matrix2]
	int* operations = new int[(internalCount)*BEAGLE_OP_COUNT*eigenCount];
    int* scalingFactorsIndices = new int[(internalCount)*eigenCount]; // internal nodes
	for(int i=0; i<internalCount*eigenCount; i++){
		operations[BEAGLE_OP_COUNT*i+0] = ntaxa+i;
        operations[BEAGLE_OP_COUNT*i+1] = (dynamicScaling ? i : BEAGLE_OP_NONE);
        operations[BEAGLE_OP_COUNT*i+2] = (dynamicScaling ? i : BEAGLE_OP_NONE);
        
        int child1Index;
        if (((i % internalCount)*2) < ntaxa)
            child1Index = (i % internalCount)*2;
        else
            child1Index = i*2 - internalCount * (int)(i / internalCount);
        operations[BEAGLE_OP_COUNT*i+3] = child1Index;
        operations[BEAGLE_OP_COUNT*i+4] = child1Index;

        int child2Index;
        if (((i % internalCount)*2+1) < ntaxa)
            child2Index = (i % internalCount)*2+1;
        else
            child2Index = i*2+1 - internalCount * (int)(i / internalCount);
		operations[BEAGLE_OP_COUNT*i+5] = child2Index;
		operations[BEAGLE_OP_COUNT*i+6] = child2Index;

        scalingFactorsIndices[i] = i;
        
//        printf("i %d dest %d c1 %d c2 %d\n", i, ntaxa+i, child1Index, child2Index);
        
        if (autoScaling)
            scalingFactorsIndices[i] += ntaxa;
	}	

    int* rootIndices = new int[eigenCount];
	int* lastTipIndices = new int[eigenCount];
    int* categoryWeightsIndices = new int[eigenCount];
    int* stateFrequencyIndices = new int[eigenCount];
    int* cumulativeScalingFactorIndices = new int[eigenCount];
    
    for (int eigenIndex=0; eigenIndex < eigenCount; eigenIndex++) {
        rootIndices[eigenIndex] = ntaxa+(internalCount*(eigenIndex+1))-1;//ntaxa*2-2;
        lastTipIndices[eigenIndex] = ntaxa-1;
        categoryWeightsIndices[eigenIndex] = eigenIndex;
        stateFrequencyIndices[eigenIndex] = 0;
        cumulativeScalingFactorIndices[eigenIndex] = ((manualScaling || dynamicScaling) ? (scaleCount*eigenCount-1)-eigenCount+eigenIndex+1 : BEAGLE_OP_NONE);
        
        if (dynamicScaling)
            beagleResetScaleFactors(instance, cumulativeScalingFactorIndices[eigenIndex]);
    }

    // start timing!
	struct timeval time1, time2, time3, time4, time5;
    double bestTimeUpdateTransitionMatrices, bestTimeUpdatePartials, bestTimeAccumulateScaleFactors, bestTimeCalculateRootLogLikelihoods, bestTimeTotal;
    
    double logL = 0.0;
    double deriv1 = 0.0;
    double deriv2 = 0.0;
    
    double previousLogL = 0.0;
    double previousDeriv1 = 0.0;
    double previousDeriv2 = 0.0;

    for (int i=0; i<nreps; i++){
        if (manualScaling && (!(i % rescaleFrequency) || !((i-1) % rescaleFrequency))) {
            for(int j=0; j<internalCount*eigenCount; j++){
                operations[BEAGLE_OP_COUNT*j+1] = (((manualScaling && !(i % rescaleFrequency))) ? j : BEAGLE_OP_NONE);
                operations[BEAGLE_OP_COUNT*j+2] = (((manualScaling && (i % rescaleFrequency))) ? j : BEAGLE_OP_NONE);
            }
        }
        
        gettimeofday(&time1,NULL);

        for (int eigenIndex=0; eigenIndex < eigenCount; eigenIndex++) {
            if (!setmatrix) {
                // tell BEAGLE to populate the transition matrices for the above edge lengths
                beagleUpdateTransitionMatrices(instance,     // instance
                                               eigenIndex,             // eigenIndex
                                               &edgeIndices[eigenIndex*edgeCount],   // probabilityIndices
                                               (calcderivs ? &edgeIndicesD1[eigenIndex*edgeCount] : NULL), // firstDerivativeIndices
                                               (calcderivs ? &edgeIndicesD2[eigenIndex*edgeCount] : NULL), // secondDerivativeIndices
                                               edgeLengths,   // edgeLengths
                                               edgeCount);            // count
            } else {
                double* inMatrix = new double[stateCount*stateCount*rateCategoryCount];
                for (int matrixIndex=0; matrixIndex < edgeCount; matrixIndex++) {
                    for(int z=0;z<rateCategoryCount;z++){
                        for(int x=0;x<stateCount;x++){
                            for(int y=0;y<stateCount;y++){
                                inMatrix[z*stateCount*stateCount + x*stateCount + y] = gt_rand() / (double) GT_RAND_MAX;
                            }
                        } 
                    }
                    beagleSetTransitionMatrix(instance, edgeIndices[eigenIndex*edgeCount + matrixIndex], inMatrix, 1);
                    if (calcderivs) {
                        beagleSetTransitionMatrix(instance, edgeIndicesD1[eigenIndex*edgeCount + matrixIndex], inMatrix, 0);
                        beagleSetTransitionMatrix(instance, edgeIndicesD2[eigenIndex*edgeCount + matrixIndex], inMatrix, 0);
                    }
                }
            }
        }

        gettimeofday(&time2, NULL);
        
        // update the partials
        beagleUpdatePartials( instance,      // instance
                        (BeagleOperation*)operations,     // eigenIndex
                        internalCount*eigenCount,              // operationCount
                        (dynamicScaling ? internalCount : BEAGLE_OP_NONE));             // cumulative scaling index

        gettimeofday(&time3, NULL);

        int scalingFactorsCount = internalCount;
                
        for (int eigenIndex=0; eigenIndex < eigenCount; eigenIndex++) {
            if (manualScaling && !(i % rescaleFrequency)) {
                beagleResetScaleFactors(instance,
                                        cumulativeScalingFactorIndices[eigenIndex]);
                
                beagleAccumulateScaleFactors(instance,
                                       &scalingFactorsIndices[eigenIndex*internalCount],
                                       scalingFactorsCount,
                                       cumulativeScalingFactorIndices[eigenIndex]);
            } else if (autoScaling) {
                beagleAccumulateScaleFactors(instance, &scalingFactorsIndices[eigenIndex*internalCount], scalingFactorsCount, BEAGLE_OP_NONE);
            }
        }
        
        gettimeofday(&time4, NULL);
                
        // calculate the site likelihoods at the root node
        if (!unrooted) {
            beagleCalculateRootLogLikelihoods(instance,               // instance
                                        rootIndices,// bufferIndices
                                        categoryWeightsIndices,                // weights
                                        stateFrequencyIndices,                 // stateFrequencies
                                        cumulativeScalingFactorIndices,
                                        eigenCount,                      // count
                                        &logL);         // outLogLikelihoods
        } else {
            // calculate the site likelihoods at the root node
            beagleCalculateEdgeLogLikelihoods(instance,               // instance
                                              rootIndices,// bufferIndices
                                              lastTipIndices,
                                              lastTipIndices,
                                              (calcderivs ? edgeIndicesD1 : NULL),
                                              (calcderivs ? edgeIndicesD2 : NULL),
                                              categoryWeightsIndices,                // weights
                                              stateFrequencyIndices,                 // stateFrequencies
                                              cumulativeScalingFactorIndices,
                                              eigenCount,                      // count
                                              &logL,    // outLogLikelihood
                                              (calcderivs ? &deriv1 : NULL),
                                              (calcderivs ? &deriv2 : NULL));
        }
        // end timing!
        gettimeofday(&time5,NULL);
        
        if (i == 0 || getTimeDiff(time1, time2) < bestTimeUpdateTransitionMatrices)
            bestTimeUpdateTransitionMatrices = getTimeDiff(time1, time2);
        if (i == 0 || getTimeDiff(time2, time3) < bestTimeUpdatePartials)
            bestTimeUpdatePartials = getTimeDiff(time2, time3);
        if (i == 0 || getTimeDiff(time3, time4) < bestTimeAccumulateScaleFactors)
            bestTimeAccumulateScaleFactors = getTimeDiff(time3, time4);
        if (i == 0 || getTimeDiff(time4, time5) < bestTimeUpdateTransitionMatrices)
            bestTimeCalculateRootLogLikelihoods = getTimeDiff(time4, time5);
        if (i == 0 || getTimeDiff(time1, time5) < bestTimeTotal)
            bestTimeTotal = getTimeDiff(time1, time5);
        
        if (!(logL - logL == 0.0))
            abort("error: invalid lnL");
        
        if (i > 0 && abs(logL - previousLogL) > MAX_DIFF)
            abort("error: large lnL difference between reps");
        
        if (calcderivs) {
            if (!(deriv1 - deriv1 == 0.0) || !(deriv2 - deriv2 == 0.0))
                abort("error: invalid deriv");
            
            if (i > 0 && ((abs(deriv1 - previousDeriv1) > MAX_DIFF) || (abs(deriv2 - previousDeriv2) > MAX_DIFF)) )
                abort("error: large deriv difference between reps");
        }

        previousLogL = logL;
        previousDeriv1 = deriv1;
        previousDeriv2 = deriv2;        
    }

    if (resource == 0) {
        cpuTimeUpdateTransitionMatrices = bestTimeUpdateTransitionMatrices;
        cpuTimeUpdatePartials = bestTimeUpdatePartials;
        cpuTimeAccumulateScaleFactors = bestTimeAccumulateScaleFactors;
        cpuTimeCalculateRootLogLikelihoods = bestTimeCalculateRootLogLikelihoods;
        cpuTimeTotal = bestTimeTotal;
    }
    
    if (!calcderivs)
        fprintf(stdout, "logL = %.5f \n", logL);
    else
        fprintf(stdout, "logL = %.5f d1 = %.5f d2 = %.5f\n", logL, deriv1, deriv2);
    
    std::cout.setf(std::ios::showpoint);
    std::cout.setf(std::ios::floatfield, std::ios::fixed);
    int timePrecision = 6;
    int speedupPrecision = 2;
    int percentPrecision = 2;
	std::cout << "best run: ";
    printTiming(bestTimeTotal, timePrecision, resource, cpuTimeTotal, speedupPrecision, 0, 0, 0);
    if (fullTiming) {
        std::cout << " transMats:  ";
        printTiming(bestTimeUpdateTransitionMatrices, timePrecision, resource, cpuTimeUpdateTransitionMatrices, speedupPrecision, 1, bestTimeTotal, percentPrecision);
        std::cout << " partials:   ";
        printTiming(bestTimeUpdatePartials, timePrecision, resource, cpuTimeUpdatePartials, speedupPrecision, 1, bestTimeTotal, percentPrecision);
        if (manualScaling || autoScaling) {
            std::cout << " accScalers: ";
            printTiming(bestTimeAccumulateScaleFactors, timePrecision, resource, cpuTimeAccumulateScaleFactors, speedupPrecision, 1, bestTimeTotal, percentPrecision);
        }
        std::cout << " rootLnL:    ";
        printTiming(bestTimeCalculateRootLogLikelihoods, timePrecision, resource, cpuTimeCalculateRootLogLikelihoods, speedupPrecision, 1, bestTimeTotal, percentPrecision);
    }
    std::cout << "\n";
    
	beagleFinalizeInstance(instance);
}
        double calc_ln_likelihood() {

            //////////////////////////////////////////////////////////////////////////////
            // Setup and initialze Beagle

            std::vector<PhylogeneticNode *> nodes;
            this->seed_node_->get_nodes_postorder(nodes);
            std::vector<PhylogeneticNode *> leaf_nodes;
            this->seed_node_->get_leaf_nodes(leaf_nodes);
            std::vector<PhylogeneticNode *> internal_nodes;
            this->seed_node_->get_internal_nodes_postorder(internal_nodes, true);
            int num_sites = leaf_nodes[0]->get_state_vector_len();
            int num_nodes = nodes.size();
            int num_tip_nodes = leaf_nodes.size();
            int num_int_nodes = internal_nodes.size() ;
            int num_partials = num_nodes;
            BeagleInstanceDetails * return_info = new BeagleInstanceDetails();
            int beagle_instance = beagleCreateInstance(
                num_tip_nodes,  // Number of tip data elements (input)
                num_partials,   // Number of partials buffers to create (input) -- internal node count
                num_tip_nodes,  // Number of compact state representation buffers to create -- for use with setTipStates (input)
                4,              // Number of states in the continuous-time Markov chain (input) -- DNA
                num_sites,      // Number of site patterns to be handled by the instance (input) -- not compressed in this case
                1,              // Number of eigen-decomposition buffers to allocate (input)
                num_nodes,      // Number of transition matrix buffers (input) -- one per edge
                1,              // Number of rate categories
                0,              // Number of scaling buffers -- can be zero if scaling is not needed
                NULL,           // List of potential resource on which this instance is allowed (input, NULL implies no restriction
                0,              // Length of resourceList list (input) -- not needed to use the default hardware config
                0,              // Bit-flags indicating preferred implementation charactertistics, see BeagleFlags (input)
                0,              // Bit-flags indicating required implementation characteristics, see BeagleFlags (input)
                return_info
                );
            if (beagle_instance < 0) {
                std::cerr << "\n\n***ERROR*** Failed to obtain BEAGLE instance\n" << std::endl;
                exit(1);
            }
            int ret_code = 0;
            for (int i; i < num_tip_nodes; ++i) {
                // ret_code = beagleSetTipPartials(
                //             beagle_instance,            // instance
                //             leaf_nodes[i]->get_index(),                          // bufferIndex
                //             leaf_nodes[i]->get_partials_data()            // inPartials
                // );
                ret_code = beagleSetTipStates(
                        beagle_instance,
                        leaf_nodes[i]->get_index(),
                        leaf_nodes[i]->get_state_vector_data()
                        );
                if (ret_code != 0) {
                    std::cerr << "\n\n***ERROR*** Failed to set tip data\n" << std::endl;
                    exit(1);
                }
            }

            // let all sites have equal weight
            std::vector<double> pattern_weights( num_sites, 1 );
            beagleSetPatternWeights(beagle_instance, pattern_weights.data());

            // create array of state background frequencies
            double freqs[4] = { 0.25, 0.25, 0.25, 0.25 };
            beagleSetStateFrequencies(beagle_instance, 0, freqs);

            // create an array containing site category weights and rates
            const double weights[1] = { 1.0 };
            const double rates[1] = { 1.0 };
            beagleSetCategoryWeights(beagle_instance, 0, weights);
            beagleSetCategoryRates(beagle_instance, rates);


            double evec[4 * 4] = {
                1.0,  2.0,  0.0,  0.5,
                1.0,  -2.0,  0.5,  0.0,
                1.0,  2.0, 0.0,  -0.5,
                1.0,  -2.0,  -0.5,  0.0
            };

            // JC69 model inverse eigenvector matrix
            double ivec[4 * 4] = {
                0.25,  0.25,  0.25,  0.25,
                0.125,  -0.125,  0.125,  -0.125,
                0.0,  1.0,  0.0,  -1.0,
                1.0,  0.0,  -1.0,  0.0
            };

            // JC69 model eigenvalues
            double eval[4] = { 0.0, -1.3333333333333333, -1.3333333333333333, -1.3333333333333333 };

            ret_code = beagleSetEigenDecomposition(
                    beagle_instance,                 // instance
                    0,                               // eigenIndex,
                    (const double *)evec,            // inEigenVectors,
                    (const double *)ivec,            // inInverseEigenVectors,
                    eval);                           // inEigenValues

            if (ret_code != 0) {
                std::cerr << "\n\n***ERROR*** Failed to set eigen decomposition\n" << std::endl;
                exit(1);
            }

            //////////////////////////////////////////////////////////////////////////////
            // Calculate log-likelihood

            // a list of indices and edge lengths
            // these get used to tell beagle which edge length goes with which node
            std::vector<int> node_indices;
            std::vector<double> edge_lens;
            for (auto &nd : nodes) {
                node_indices.push_back(nd->get_index());
                edge_lens.push_back(nd->get_edge_len());
            }
            // tell BEAGLE to populate the transition matrices for the above edge lengthss
            beagleUpdateTransitionMatrices(beagle_instance,     // instance
                    0,             // eigenIndex
                    node_indices.data(),   // probabilityIndices
                    NULL,          // firstDerivativeIndices
                    NULL,          // secondDervativeIndices
                    edge_lens.data(),   // edgeLengths
                    node_indices.size());            // count

            // create a list of partial likelihood update operations
            // the order is [dest, sourceScaling, destScaling, source1, matrix1, source2, matrix2]
            // these operations say: first peel node 0 and 1 to calculate the per-site partial likelihoods, and store them
            // in buffer 3.  Then peel node 2 and buffer 3 and store the per-site partial likelihoods in buffer 4.
            // BeagleOperation operations[2] = {
            //     {3, BEAGLE_OP_NONE, BEAGLE_OP_NONE, 0, 0, 1, 1},
            //     {4, BEAGLE_OP_NONE, BEAGLE_OP_NONE, 2, 2, 3, 3}
            // };
            std::vector<BeagleOperation> beagle_operations;
            int ch1_idx = 0;
            int ch2_idx = 0;
            for (auto &nd : internal_nodes) {
                ch1_idx = nd->get_child_node_index(0);
                ch2_idx = nd->get_child_node_index(1);
                std::cerr << nd->get_index() << ": " << ch1_idx << ", " << ch2_idx << std::endl;
                beagle_operations.push_back(
                        {nd->get_index(), BEAGLE_OP_NONE, BEAGLE_OP_NONE, ch1_idx, ch1_idx, ch2_idx, ch2_idx}
                        );
            }

            // this invokes all the math to carry out the likelihood calculation
            beagleUpdatePartials( beagle_instance,      // instance
                    beagle_operations.data(),     // eigenIndex
                    beagle_operations.size(),              // operationCount
                    BEAGLE_OP_NONE);             // cumulative scale index

            // for (auto &nd : nodes) {
            //     std::cerr << nd->get_index() << ":";
            //     for (unsigned int i = 0; i < 4; ++i) {
            //         std::cerr << "     " << nd->get_partial(i);
            //     }
            //     std::cerr << std::endl;
            // }

            double logL = 0;
            int root_index[1] = {this->seed_node_->get_index()};
            int category_weight_index[1] = {0};
            int state_freq_index[1] = {0};
            int cumulative_scale_index[1] = {BEAGLE_OP_NONE};

            // calculate the site likelihoods at the root node
            // this integrates the per-site root partial likelihoods across sites, background state frequencies, and rate categories
            // results in a single log likelihood, output here into logL
            beagleCalculateRootLogLikelihoods(beagle_instance,               // instance
                    root_index,// bufferIndices
                    category_weight_index,                // weights
                    state_freq_index,                 // stateFrequencies
                    cumulative_scale_index,     // scaleBuffer to use
                    1,                      // count
                    &logL);         // outLogLikelihoods

            return logL;
        }