Plan 9 from Bell Labs’s /usr/web/sources/contrib/pac/sys/src/ape/cmd/bio/MrBayes_2.01/mcmc.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
 *  MrBayes 2.0
 *
 *  John P. Huelsenbeck
 *  Department of Biology
 *  University of Rochester
 *  Rochester, NY 14627
 *
 *  johnh@brahms.biology.rochester.edu
 *
 *	Fredrik Ronquist
 *  Dept. Systematic Zoology
 *  Evolutionary Biology Centre
 *	Uppsala University
 *	Norbyv. 18D, SE-752 36 Uppsala, Sweden
 *
 *  fredrik.ronquist@ebc.uu.se
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <string.h>
#include <ctype.h>
#include "jph.h"
#include "tree.h"
#include "mcmc.h"
#include "command.h"
#include "gamma.h"
#include "linalg.h"
#include "matrices.h"
#include "complex.h"

#define MORPH

#if defined (MORPH)
#define	NUM_ALLOCS					45
#else
#define NUM_ALLOCS					44
#endif
#define	ALLOC_KAPPA					0
#define	ALLOC_SUBPARAMS				1
#define	ALLOC_BASEFREQS				2
#define	ALLOC_GAMMA_SHAPE			3
#define	ALLOC_SITE_RATES			4
#define	ALLOC_UNSCALED_SITE_RATES	5
#define	ALLOC_NSITES_IN_PART		6
#define	ALLOC_MATRIX				7
#define	ALLOC_N_SITE_PATS			8
#define	ALLOC_PART_ID				9
#define	ALLOC_NODES					10
#define	ALLOC_ROOT					11
#define	ALLOC_ALLDOWNPASS			12
#define	ALLOC_INTDOWNPASS			13
#define	ALLOC_CLUPDATE_FLAG			14
#define	ALLOC_COND_LIKES			15
#define	ALLOC_COND_SCALER			16
#define	ALLOC_DISTANCES				17
#define	ALLOC_TREE_HEIGHT			18
#define	ALLOC_ANC_STATES			19
#define	ALLOC_TEMP_ANC_STATES		20
#define	ALLOC_PAT_IDS				21
#define	ALLOC_SP_RATE				22
#define	ALLOC_EX_RATE				23
#define	ALLOC_OMEGA					24
#define	ALLOC_PUR					25
#define	ALLOC_NEU					26
#define	ALLOC_POS					27
#define	ALLOC_AUTO_GAMMA			28
#define	ALLOC_AUTO_GAMMA2			29
#define	ALLOC_LAG					30
#define	ALLOC_INV_P					31
#define	ALLOC_SWITCH_RATE			32
#define	ALLOC_SWITCH_PI				33
#define	ALLOC_GC1					34
#define	ALLOC_GC2					35
#define	ALLOC_FRAC_A				36
#define	ALLOC_FRAC_G				37
#define ALLOC_LN_SITE_SCALER		38
#define ALLOC_SCALER_UPDATE_FLAG	39
#define ALLOC_TERM_STATES			40
#define	ALLOC_TI_PROBS				41
#define	ALLOC_TI_FLAGS				42
#define	ALLOC_STATE_SET				43
#if defined (MORPH)
#define ALLOC_BETA					44
#endif

#define MAX_PROPOSAL_SIZE			33
#if defined (MORPH)
#define	NUM_PROPOSAL_TYPES			24
#else
#define NUM_PROPOSAL_TYPES			23
#endif
#define	CHANGE_QMAT					0
#define	CHANGE_BASEFREQS			1
#define	CHANGE_GAMMA_SHAPE			2
#define	CHANGE_SITE_RATES			3
#define	CHANGE_UNROOT_LOCAL			4
#define	CHANGE_CLOCK_LOCAL			5
#define	CHANGE_CLOCK_TIME_LOCAL		6
#define	CHANGE_TREE_HEIGHT			7
#define	CHANGE_WORM					8
#define	CHANGE_NODE_TIME			9
#define	CHANGE_BD_PARAMS			10
#define	CHANGE_OMEGA				11
#define	CHANGE_OMEGA_PROBS			12
#define	CHANGE_AUTO_CORR			13
#define	CHANGE_LAG					14
#define	CHANGE_TREE_SPR				15
#define	CHANGE_INV_P				16
#define	CHANGE_SWITCH_RATE			17
#define	CHANGE_UNROOT_TBR			18
#define	CHANGE_GCSWITCH				19
#define	CHANGE_TREE_FTBR			20
#define	CHANGE_BRLEN				21
#define	CHANGE_ERASER				22
#if defined (MORPH)
#define	CHANGE_BETA_SHAPE			23
#endif

#define LIKE_EPSILON				1.0e-300
#define BRLEN_EPSILON				1.0e-8
#define RESCALE_FREQ				5
#define	MAX_COVARIATES				20000
#define	A							0
#define	C							1
#define	G							2
#define	T							3
#define	AA							0
#define	AC							1
#define	AG							2
#define	AT							3
#define	CA							4
#define	CC							5
#define	CG							6
#define	CT							7
#define	GA							8
#define	GC							9
#define	GG							10
#define	GT							11
#define	TA							12
#define	TC							13
#define	TG							14
#define	TT							15

#define	ROOTED						0
#define	UNROOTED					1

#define	SCREENWIDTH					60
#define	SCREENWIDTH2				61

#undef	DEBUG_START_TREE
#undef	DEBUG_LOCAL
#undef	DEBUG_LOCAL_CLOCK
#undef	DEBUG_LOCAL_TIME_CLOCK
#undef	SHOW_MOVE_WORM
#undef	DEBUG_SPR
#undef	DEBUG_TBR
#undef  DEBUG_FTBR
#undef  DEBUG_BRLENMOVE
#undef  DEBUG_INITCONDLIKES
#undef  TOPOLOGY_MOVE_STATS
#undef  DEBUG_LNLIKEBIN

#undef  TRANSLATE_TO_AA
#define	SUPER_FAST
#define	SMART_TI_PROBS
/*-pac- #define MORPH		//NB! MORPH also defined earlier in this file to fix #define statements */


void   BetaBreaks (double alpha, double beta, double *values, double *probs, int K);
double BetaCf (double a, double b, double x);
double BetaQuantile (double alpha, double beta, double x);
int    BuildStartingTree (int numTaxa, int numChars, long int *seed, int showStartTree);
void   CalcCijk (double *c_ijk, int n, double **u, double **v);
void   CalcPij (double *c_ijk, int n, double *eigenValues, double v, double r, double **p);
void   CalcPFSij (double *c_ijk, int n, double *eigenValues, double v, double r, double **p, double **f_p, double **s_p);
#      if defined (SMART_TI_PROBS)
int    CalcTransitionProbs (int whichState, int whichChain, int numRateCats);
int    CalcTransAA (int whichState, int whichChain, int numRateCats);
int    CalcTransCodon (int whichState, int whichChain);
int    CalcTransCovarion (int whichState, int whichChain, int numRateCats);
int    CalcTransDNA (int whichState, int whichChain, int numRateCats);
#      endif
int    CheckConstraints (void);
int    ComplexChangeMatrix (double *eigenValues, double *eigvalsImag, complex **Ceigvecs, 
          complex **CinverseEigvecs, int n, double **p, double t, double r);
int    ComplexDerivativesMatrix (double *eigenValues, double *eigvalsImag, complex **Ceigvecs, 
          complex **CinverseEigvecs, int n, double **f, double **s, double t, double r);
int    CompressMatrix (int *numTaxa, int *numChars);
int    CompressMatrixPars (int *numTaxa, int *numChars);
void   CopyConditionalLikelihoods (int from, int to, int whichChain, int numTaxa, int numChars, int numRateCats);
void   CopyTree (int from, int to, int whichChain);
void   DirichletRandomVariable (double *alp, double *z, int n, long int *seed);
void   FreeMemory (void);
double GetTreeLength (int whichState, int whichChain);
int    GetDistances (int numTaxa, int numChars);
void   GetDownPassSeq (TreeNode *p, int whichTree, int whichChain, int numTaxa, int *i, int *j);
int    GetEigens (int n, double **q, double *eigenValues, double *eigvalsImag, double **eigvecs, 
          double **inverseEigvecs, complex **Ceigvecs, complex **CinverseEigvecs);
void   GetEmpiricalAAFreqs (void);
void   GetEmpiricalBaseFreqs (void);
void   GetPossibleAAs (int nucCode, int nuc[]);
void   GetPossibleNucs (int nucCode, int nuc[]);
void   GetTempDownPassSeq (TreeNode *p, int *i, TreeNode **dp);
void   HkyChangeMat (double **ch_prob, double time, double k, double r, double piA, double piC, double piG, double piT);
void   HkyFirstMat (double **ch_prob, double time, double k, double r, double piA, double piC, double piG, double piT);
void   HkySecondMat (double **ch_prob, double time, double k, double r, double piA, double piC, double piG, double piT);
double IncompleteBetaFunction (double alpha, double beta, double x);
int    InitializeConditionalLikes (int numTaxa, int numChars, int numRateCats);
int    InitializeTipStates (int numTaxa, int numChars);
int    InitTiMatrix (double m[3][3], double x, double y, double z, double pPurifying, double pNeutral, double pPositive, int model);
int    IsKink (TreeNode *p);
int    IsLeaf (TreeNode *p);
int    LnBDPrior (int whichState, int whichChain, int numTaxa, double *prob);
double LnGamma (double alp);
int    LnLike (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers);
int    LnLikeAA (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers);
int    LnLikeCodon (int whichState, int whichChain, int numChars, double *lnL, int refreshScalers);
int    LnLikeCovarion (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers);
int    LnLikeDNA (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers);
int    LnLikeRestriction (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers);
int    LnLikeStandardBin (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers);
int    LnLikeStandardMk (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers);
double lnP1 (double t, double l, double m, double r);
double lnVt (double t, double l, double m, double r);
int    MarkovChain (int numTaxa, int numChars, int numRateCats, long int *seed);
int    MarkovChainPars (int numTaxa, int numChars, long int *seed);
void   MarkPathDown (TreeNode *p, TreeNode *q);
int    Move_ChangeAutoCorr (int proposedState, int whichChain, long int *seed, double *lnPriorRatio);
int    Move_ChangeBaseFreqs (int proposedState, int whichChain, long int *seed, double *lnPriorRatio, double *lnProposalRatio);
int    Move_ChangeBetaShape (int proposedState, int whichChain, long int *seed, double *lnPriorRatio);
int    Move_ChangeBD (int proposedState, int whichChain, long int *seed);
int    Move_ChangeBrLen (int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_ChangeClockWithLocal (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_ChangeEraser (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_ChangeGammaShape (int proposedState, int whichChain, long int *seed, double *lnPriorRatio);
int    Move_ChangeGCSwitch (int proposedState, int whichChain, long int *seed, double *lnPriorRatio, double *lnProposalRatio);
int    Move_ChangeLag (int proposedState, int whichChain, long int *seed, double *lnPriorRatio, double *lnProposalRatio);
int    Move_ChangeNNI (int numTaxa, int proposedState, int whichChain, long int *seed);
int    Move_ChangeQMatrix (int proposedState, int whichChain, long int *seed, double *lnPriorRatio);
int    Move_ChangeSiteRates (int proposedState, int whichChain, long int *seed, double *lnPriorRatio);
int    Move_ChangeNodeTime (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_ChangeOmega (int proposedState, int whichChain, long int *seed, double *lnPriorRatio);
int    Move_ChangeOmegaProbs (int proposedState, int whichChain, long int *seed, double *lnPriorRatio, double *lnProposalRatio);
int    Move_ChangePropInv (int proposedState, int whichChain, long int *seed, double *lnPriorRatio);
int    Move_ChangeSwitchRate (int proposedState, int whichChain, long int *seed, double *lnPriorRatio);
int    Move_ChangeTimeClockWithLocal (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_ChangeTreeHeight (int proposedState, int whichChain, long int *seed, double *lnProposalRatio);
int    Move_ChangeUnrootedWithLocal (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_SingleWorm (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_ChangeUnrootedWithSPR (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_ChangeTBR (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    Move_ChangeFTBR (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio);
int    NumAdjacentMarked (TreeNode *p);
FILE  *OpenFile(char *filename, int isNexus);
double ParsimonyLength (int whichState, int whichChain, int numChars);
int    PerturnStartingTree (int numTaxa, long int *seed);
int	   PrepareOutputFiles (void);		
int	   PrepareParsOutputFiles (void);		
int    PrintAncStatesAA (int whichState, int whichChain, int numChars, int numRateCats, int whichGen);
int    PrintAncStatesDNA (int whichState, int whichChain, int numChars, int numRateCats, int whichGen);
int    PrintPosSelProbs (int whichState, int whichChain, int numChars, int numRateCats, int whichGen);
int    PrintRateFactors (int whichState, int whichChain, int numChars, int numRateCats, int whichGen);
int    PrintStatesToFile (int n, int coldId, int whichState, double logLike, double *constrainedNodes, double *calibratedNodes);
int    ProposeNewState (long int *seed);
double RandomNumber (long int *seed);
double RndGamma (double s, long int *seed);
double RndGamma1 (double s, long int *seed);
double RndGamma2 (double s, long int *seed);
int    SetAARates (void);
void   SetCode (void);
int    SetModel (int *numRateCats);
int    SetAAQMatrix (double **a, int whichTree, int whichChain);
int    SetCodonQMatrix (double **a, int whichTree, int whichChain, double nonsyn, double kap);
int    SetCodonSwitchQMatrix (double **a, int whichTree, int whichChain, double nonsyn, double kap, double sr);
int    SetAACovQMatrix (double **a, int whichTree, int whichChain, double r);
int    SetDNACovQMatrix (double **a, int whichTree, int whichChain, double r);
int    SetGCSwitchQMatrix (double **a, int whichTree, int whichChain, double r);
int    SetQMatrix (double **a, int whichTree, int whichChain);
#      if defined (SMART_TI_PROBS)
int    SetUpTransitionProbs (int numRateCats);
#      endif
int    SetUpTrees (int numTaxa);
int    ShowStartTree (TreeNode *r, int nt, int isThisTreeRooted);
#if	   defined (TRANSLATE_TO_AA)
void   TranslateToAA (void);
#	   endif
void   UpDateAllCls (int whichState, int whichChain);
void   UpDateAllTIs (int whichState, int whichChain);
char   WhichAA (int x);
void   WriteTreeToFile (TreeNode *p, FILE *fp, int showBrlens);
void   WriteTreeToScreen (TreeNode *p, int showBrlens);
int    YesNo (void);


static int			nStates, nst, isStartingTreeRandom, allocatedMemory[NUM_ALLOCS], *nSitesInPartition,
					*matrix, *numSitesOfPat, *partitionId, treeModel, intNodeNum, localOutgroup,
					numNodes, numIntNodes, *clUpdateFlag, *patternId, nSampled, *numCovEvents, aaJones[20][20], 
					aaDayhoff[20][20], codon[64], transCodon[64], codonNucs[64][3], *lag, nExcluded,
					numDummyChars, numBetaCats, *scalerUpdateFlag;
#if defined (TRANSLATE_TO_AA)
static int			treatAsAA;	// temporary solution, should be declared as global instead
#endif
static unsigned int	*stateSet;
static double		*kappa, *subParams, *baseFreq, *alpha, relProposalProbs[NUM_PROPOSAL_TYPES], *rateCorrelation,
					chainMins[NUM_PROPOSAL_TYPES], chainMaxs[NUM_PROPOSAL_TYPES],
					*scaledRates, *unscaledRates, *condLike, *distances, *treeHeight, *clScaler, *ancStatesProbs,
					*tempStateProbs, *covInvariable, *covLambda, *spRate, *exRate, *posSelProbs, *rateCorrelation2,
					dayhoffPi[20], jonesPi[20], *omega, *probPur, *probNeu, *probPos, *invP, *rateFactors, 
					*switchRate, *switchPi, *rateProbs, *gc1, *gc2, *fracA, *fracG, *lnSiteScaler, EigValexp[200];
static char			proposalName[NUM_PROPOSAL_TYPES][MAX_PROPOSAL_SIZE] = 
						{"changes to Q matrix",
						 "changes to base frequencies",
						 "changes to gamma shape",
						 "changes to site rates",
						 "changes to tree (stochastic NNI)",
						 "changes to clock tree",
						 "changes to tree",
						 "changes to tree height",
						 "changes to tree (one worm)",
						 "changes to node time",
						 "changes to bd parameters",
						 "changes to omega",
						 "changes to omega probabilities",
						 "changes to auto correlation",
						 "changes to lag",
						 "changes to tree (stochastic SPR)",
						 "changes to proportion invariant",
						 "changes to covarion parameter",
						 "changes to tree (TBR1)",
						 "changes to GC swith parameters",
						 "changes to tree (TBR2)",
						 "changes to a branch length",
						 "changes to tree (eraser)",
						 "changes to beta/dirichlet shape"};
static TreeNode		*nodes, **root, *tempNodes, **intNodeDownPassSeq, **allNodesDownPassSeq;
FILE				*tFile, *pFile, *bpFile;

extern int			nTaxa, nChar, *origDataMatrix, dataType, isUserTreeDefined, isTreeRooted, 
					numChains, *excludedTaxa, *excludedSites, isPartitionDefined, nPartitions, *sitePartitions,
					nRateCats, enforceConstraints, enforceCalibrations, inferAncStates, *constraints, nConstraints,
					*calibrations, nCalibrations, outgroupNum, nGen, printFreq, sampleFreq, saveBrlens, autoclose,
					nPerturbations, userBrlensDef, aaModelType, saveAncFiles, enforceCodonModel, aaCode,
					inferPoseSel, lagNumber, inferRates, useCovarion, mcmcBurn, cycleFreq, calcPseudoBf, useParsCriterion;
extern long int		randomSeed;
extern double		tRatio, revRates[6], nonRevRates[12], qmatprExp, qmatprUni[2], basefreqprDir,
					shape, shapeprUni[2], shapeprExp, siteRates[50], siterateprExp, siterateprUni[2],
					brlenprExp, brlenprUni[2], chainTemp, calibrationTimes[32][2], seqErrorProb,
					speciationRate, extinctionRate, samplingFraction, omegaRatio, omegaprUni[2], omegaprExp, 
					lagprUni[2], lagprExp, qMatWinProp, piAlphaProp, rateWinProp, tuningProp, clockTuneProp, timeTuneProp, mTuneProp, 
					extendPProp, wormTuneProp, bdWinProp, omegaWinProp, rhoWinProp, omegaAlphaProp, invSlideProp, 
					switchWinProp, alphaWinProp, nodeTimeTuneProp, reconLimProp, tbrExtendPProp, tbrTuneProp, 
					blTuneProp, statefreqprDir, moveRates[100];
extern char			startingTreeModel[20], subModel[20], baseFreqModel[20], ratesModel[20],
					qmatprModel[20], basefreqprModel[20], shapeModel[20], shapeprModel[20],
					defPartitionName[50], partitionName[50], siterateprModel[20], clockModel[20], covarionModelType[20],
					brlenprModel[20], *taxonLabels, calibrationLabels[32][100], constraintLabels[32][100],
					outFile[100], codonModelType[20], omegaRatioModel[20], omegaprModel[20], lagModel[20], 
					lagprModel[20], codingType[20], stateFreqPrModel[20];
extern TreeNode		*userTree, *userTreeRoot;

#					if defined (TOPOLOGY_MOVE_STATS)
int					gTopologyHasChanged, gNodeMoves, nAcceptedTopology[NUM_PROPOSAL_TYPES],
					nProposedTopology[NUM_PROPOSAL_TYPES], nProposedNodes[NUM_PROPOSAL_TYPES],
					nAcceptedNodes[NUM_PROPOSAL_TYPES];
#					endif

#					if defined (MORPH)
double				pObserved, *statefreqP;
#					endif

// termState: vector with terminal state code, multiplied with 4 to give suitable index
// isPartAmbig: flag signalling if terminal is partly ambiguous for some sites
#					if defined (SUPER_FAST)
int					*termState, *isPartAmbig;
#					endif
#					if defined (SMART_TI_PROBS)
int					*updateTiFlag, nodeTiSize;
double				*transitionProbs;
#					endif


void BetaBreaks (double alpha, double beta, double *values, double *probs, int K)

{

	int				i;
	double			r, quantile, lower, upper;
			
	r = (1.0 / K) * 0.5;
	lower = 0.0;
	upper = (1.0 / K);
	r = (upper - lower) * 0.5 + lower;
	for (i=0; i<K; i++)
		{
		quantile = BetaQuantile (alpha, beta, r);
		values[i] = quantile;
		probs[i]  = upper - lower;
		lower += (1.0/K);
		upper += (1.0/K);
		r += (1.0/K);
		}
#	if 0
	for (i=0; i<K; i++)
		{
		printf ("%4d %lf %lf\n", i, values[i], probs[i]);
		}
#	endif

}





double BetaCf (double a, double b, double x)

{

	int			m, m2;
	double		aa, c, d, del, h, qab, qam, qap;
	
	qab = a + b;
	qap = a + 1.0;
	qam = a - 1.0;
	c = 1.0;
	d = 1.0 - qab * x / qap;
	if (fabs(d) < (1.0e-30))
		d = (1.0e-30);
	d = 1.0 / d;
	h = d;
	for (m=1; m<=100; m++)
		{
		m2 = 2 * m;
		aa = m * (b-m) * x / ((qam+m2) * (a+m2));
		d = 1.0 + aa * d;
		if (fabs(d) < (1.0e-30))
			d = (1.0e-30);
		c = 1.0 + aa / c;
		if (fabs(c) < (1.0e-30))
			c = (1.0e-30);
		d = 1.0 / d;
		h *= d * c;
		aa = -(a+m) * (qab+m) * x / ((a+m2) * (qap+m2));
		d = 1.0 + aa * d;
		if (fabs(d) < (1.0e-30))
			d = (1.0e-30);
		c = 1.0 + aa / c;
		if (fabs(c) < (1.0e-30))
			c = (1.0e-30);
		d = 1.0 / d;
		del = d * c;
		h *= del;
		if (fabs(del - 1.0) < (3.0e-7))
			break;
		}
	if (m > 100)
		{
		printf ("Error in BetaCf.\n");
		exit (-1);
		}
	return (h);
	
}





double BetaQuantile (double alpha, double beta, double x)

{

	int		i, stopIter, direction, nswitches;
	double	curPos, curFraction, increment;
	
	i = nswitches = 0;
	curPos = 0.5;
	stopIter = NO;
	increment = 0.25;
	curFraction = IncompleteBetaFunction (alpha, beta, curPos);
	if (curFraction > x)
		direction = DOWN;
	else
		direction = UP;

	while (stopIter == NO)
		{
		curFraction = IncompleteBetaFunction (alpha, beta, curPos);
		if (curFraction > x && direction == DOWN)
			{
			/* continue going down */
			while (curPos - increment <= 0.0)
				{
				increment /= 2.0;
				}
			curPos -= increment;
			}
		else if (curFraction > x && direction == UP)
			{
			/* switch directions, and go down */
			nswitches++;
			direction = DOWN;
			while (curPos - increment <= 0.0)
				{
				increment /= 2.0;
				}
			increment /= 2.0;
			curPos -= increment;
			}
		else if (curFraction < x && direction == UP)
			{
			/* continue going up */
			while (curPos + increment >= 1.0)
				{
				increment /= 2.0;
				}
			curPos += increment;
			}
		else if (curFraction < x && direction == DOWN)
			{
			/* switch directions, and go up */
			nswitches++;
			direction = UP;
			while (curPos + increment >= 1.0)
				{
				increment /= 2.0;
				}
			increment /= 2.0;
			curPos += increment;
			}
		else
			{
			stopIter = YES;
			}
		if (i > 1000 || nswitches > 20)
			stopIter = YES;
		i++;
		}
		
	return (curPos);
		
}





int BuildStartingTree (int numTaxa, int numChars, long int *seed, int showStartTree)

{

	int				i, j, k, n, tSize, nNodes, nTips, nInts, nextTip, nextInt,
					nPotentialPlaces, whichNode, consistentNode, uniqueBipart1[32],
					uniqueBipart2[32], isMarked, nId, nLftId, nRhtId, nAncId, nUserNodes, tempLength;
	unsigned int	conLft, conRht, conAnc, conNde, conNum1, conNum2, *localConstraints, *localCalibrations;
	double			treeLength, sum, oldestAbove, oldestBelow;
	TreeNode		*p, *a, *b, *c, *d, *e, **availTips, **availInts, **tempDP, *tempRoot,
					**potentialPlaces, *lft, *m1, *m2, *um1, *um2, *out;
	
	if (enforceConstraints == YES || enforceCalibrations == YES)
		{
		if (CheckConstraints () == NO)
			{
			printf ("\n   ERROR: Constraints and/or calibrations are inconsistent with a single tree\n");
			FreeMemory ();
			return (ERROR);
			}
		}
		
	printf ("      Making starting trees\n");

	if (treeModel == ROOTED)
		{
		tSize = 2*numTaxa;
		printf ("         Starting tree(s) are rooted\n");
		}
	else if (treeModel == UNROOTED)
		{
		tSize = 2*numTaxa-2;
		printf ("         Starting tree(s) are unrooted\n");
		}
	else
		{
		printf ("\n   ERROR: Cannot decide if the tree is rooted or unrooted\n");
		FreeMemory ();
		return (ERROR);
		}
	
	/* allocate memory for nodes */
	nodes = (TreeNode *)malloc(sizeof(TreeNode) * numChains * 2 * tSize);
	if (!nodes)
		{
		printf ("\n   ERROR: Could not allocate nodes\n");
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_NODES] = YES;		
	root = (TreeNode **)malloc(sizeof(TreeNode *) * numChains * 2);
	if (!root)
		{
		printf ("\n   ERROR: Could not allocate root\n");
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_ROOT] = YES;
	printf ("         Allocated memory for trees\n");

	/* set the tree pointers to null */
	for (i=0; i<numChains*2*tSize; i++)
		{
		nodes[i].left  = NULL;
		nodes[i].right = NULL;
		nodes[i].anc   = NULL;
		nodes[i].index = -1;
		nodes[i].length = 0.0;
		nodes[i].nodeTime = 0.0;
		nodes[i].isConstrained = NO;
		nodes[i].isCalibrated = NO;
		for (j=0; j<99; j++)
			nodes[i].label[j] = ' ';
		nodes[i].label[99] = '\0';
		for (j=0; j<99; j++)
			nodes[i].calibrationName[j] = ' ';
		nodes[i].calibrationName[99] = '\0';
		for (j=0; j<99; j++)
			nodes[i].constraintName[j] = ' ';
		nodes[i].constraintName[99] = '\0';
		}

	availTips = (TreeNode **)malloc(sizeof(TreeNode *) * nTaxa);
	if (!availTips)
		{
		printf ("\n   ERROR: Could not allocate availTips\n");
		FreeMemory ();
		return (ERROR);
		}
	availInts = (TreeNode **)malloc(sizeof(TreeNode *) * nTaxa);
	if (!availInts)
		{
		printf ("\n   ERROR: Could not allocate availInts\n");
		free (availTips);
		FreeMemory ();
		return (ERROR);
		}
	tempDP = (TreeNode **)malloc(sizeof(TreeNode *) * 2*nTaxa);
	if (!tempDP)
		{
		printf ("\n   ERROR: Could not allocate tempDP\n");
		free (availTips);
		free (availInts);
		FreeMemory ();
		return (ERROR);
		}
	potentialPlaces = (TreeNode **)malloc(sizeof(TreeNode *) * 2*nTaxa);
	if (!potentialPlaces)
		{
		printf ("\n   ERROR: Could not allocate potentialPlaces\n");
		free (availTips);
		free (availInts);
		free (tempDP);
		FreeMemory ();
		return (ERROR);
		}
	tempNodes = (TreeNode *)malloc(sizeof(TreeNode) * 2*nTaxa);
	if (!tempNodes)
		{
		printf ("\n   ERROR: Could not allocate tempNodes\n");
		free (availTips);
		free (availInts);
		free (tempDP);
		free (potentialPlaces);
		FreeMemory ();
		return (ERROR);
		}
	localConstraints = (unsigned int *)malloc(sizeof(unsigned int) * nTaxa);
	if (!localConstraints)
		{
		printf ("\n   ERROR: Could not allocate localConstraints\n");
		free (availTips);
		free (availInts);
		free (tempDP);
		free (potentialPlaces);
		free (tempNodes);
		FreeMemory ();
		return (ERROR);
		}
	localCalibrations = (unsigned int *)malloc(sizeof(unsigned int) * nTaxa);
	if (!localCalibrations)
		{
		printf ("\n   ERROR: Could not allocate localCalibrations\n");
		free (availTips);
		free (availInts);
		free (tempDP);
		free (potentialPlaces);
		free (tempNodes);
		free (localConstraints);
		FreeMemory ();
		return (ERROR);
		}
		
	/* set up constraints */
	if (enforceConstraints == YES)
		{
		printf ("         Setting up constraints\n");
		/* look for unique constraints and remove them */
		for (i=0; i<nTaxa; i++)
			localConstraints[i] = (unsigned int)constraints[i];
		for (i=0; i<nConstraints; i++)
			uniqueBipart1[i] = 0;
		for (i=0; i<nConstraints; i++)
			{
			conNde = (unsigned int)pow(2.0, (double)i);
			for (j=0; j<nTaxa; j++)
				{
				if (excludedTaxa[j] == NO)
					{
					conLft = conNde & (unsigned int)constraints[j];
					if (conNde == conLft)
						uniqueBipart1[i]++;
					}
				}
			if (uniqueBipart1[i] <= 1)
				{
				for (j=0; j<nTaxa; j++)
					{
					conLft = conNde & (unsigned int)constraints[j];
					if (conNde == conLft)
						localConstraints[j] -= conNde;
					}
				}
#			if defined (DEBUG_START_TREE)
			printf ("Taxon bipartition %d found %d times for this constraint\n", conNde, uniqueBipart1[i]);
#			endif
			}
#		if defined (DEBUG_START_TREE)
		printf ("cons: ");
		for (i=0; i<nTaxa; i++)
			{
			if (excludedTaxa[i] == NO)
				printf ("%2d ", localConstraints[i]);
			}
		printf ("\n");
#		endif
		}
		
	/* set up calibrations */
	if (enforceCalibrations == YES)
		{
		printf ("         Setting up calibrations\n");
		/* look for unique calibrations and remove them */
		for (i=0; i<nTaxa; i++)
			localCalibrations[i] = (unsigned int)calibrations[i];
		for (i=0; i<nCalibrations; i++)
			uniqueBipart2[i] = 0;
		for (i=0; i<nCalibrations; i++)
			{
			conNde = (unsigned int)pow(2.0, (double)i);
			for (j=0; j<nTaxa; j++)
				{
				if (excludedTaxa[j] == NO)
					{
					conLft = conNde & (unsigned int)calibrations[j];
					if (conNde == conLft)
						uniqueBipart2[i]++;
					}
				}
			if (uniqueBipart2[i] <= 1)
				{
				for (j=0; j<nTaxa; j++)
					{
					conLft = conNde & (unsigned int)calibrations[j];
					if (conNde == conLft)
						localCalibrations[j] -= conNde;
					}
				}
#			if defined (DEBUG_START_TREE)
			printf ("Taxon bipartition %d found %d times for this calibration\n", conNde, uniqueBipart2[i]);
#			endif
			}
#		if defined (DEBUG_START_TREE)
		printf ("cals: ");
		for (i=0; i<nTaxa; i++)
			{
			if (excludedTaxa[i] == NO)
				printf ("%2d ", localCalibrations[i]);
			}
		printf ("\n");
#		endif
		}

		
	if (!strcmp(startingTreeModel, "random"))
		{
		/* random tree(s) start chain */
		printf ("         Starting tree(s) are random\n");
		
		for (n=0; n<numChains; n++)
			{
			/* set everything to null */
			for (i=0; i<2*numTaxa; i++)
				{
				tempNodes[i].left  = NULL;
				tempNodes[i].right = NULL;
				tempNodes[i].anc   = NULL;
				tempNodes[i].index = -1;
				tempNodes[i].length = 0.0;
				for (j=0; j<100; j++)
					tempNodes[i].label[j] = ' ';
				}
			/* set up available nodes */
			j = 0;
			for (i=0; i<nTaxa; i++)
				{
				if (excludedTaxa[i] == NO)
					{
					p = &tempNodes[j];
					availTips[j] = p;
					p->index = j;
					p->memoryIndex = j;
					if (enforceConstraints == YES)
						p->constraints = localConstraints[i];
					if (enforceCalibrations == YES)
						p->calibrations = localCalibrations[i];
					k = 0;
					while (taxonLabels[i*100+k] != '|')
						{
						p->label[k] = taxonLabels[i*100+k];
						k++;
						}
					p->label[k] = '\0';
					j++;
					}
				}
			k = 0;
			for (i=numTaxa; i<2*numTaxa; i++)
				{
				p = &tempNodes[j];
				availInts[k] = p;
				p->index = j;
				p->memoryIndex = j;
				j++;
				k++;
				}				
			
			/* set up initial split at base with two taxa */
			a = availTips[0];
			b = availTips[1];
			c = availInts[0];
			d = availInts[1];
			a->anc = b->anc = c;
			c->left = a;
			c->right = b;
			c->anc = d;
			d->left = c;
			tempRoot = d;
			nNodes = 4;
			nTips = 2;
			nInts = 2;
			nextTip = 2;
			nextInt = 2;

			if (enforceConstraints == YES)
				{
				for (i=0; i<nConstraints; i++)
					{
					uniqueBipart1[i] = YES;
					conNde = (unsigned int)pow(2.0, (double)i);
					conLft = conNde & a->constraints;
					conRht = conNde & b->constraints;
					if (conLft == conNde)
						uniqueBipart1[i] = NO;
					if (conRht == conNde)
						uniqueBipart1[i] = NO;
					}
#				if defined (DEBUG_START_TREE)
				printf ("unique bipartitions: ");
				for (i=0; i<nConstraints; i++)
					printf ("%d ", uniqueBipart1[i]);
				printf ("\n");
#				endif
				}
			if (enforceCalibrations == YES)
				{
				for (i=0; i<nCalibrations; i++)
					{
					uniqueBipart2[i] = YES;
					conNde = (unsigned int)pow(2.0, (double)i);
					conLft = conNde & a->calibrations;
					conRht = conNde & b->calibrations;
					if (conLft == conNde)
						uniqueBipart2[i] = NO;
					if (conRht == conNde)
						uniqueBipart2[i] = NO;
					}
#				if defined (DEBUG_START_TREE)
				printf ("unique bipartitions: ");
				for (i=0; i<nCalibrations; i++)
					printf ("%d ", uniqueBipart2[i]);
				printf ("\n");
#				endif
				}
			
			
			while (nTips < numTaxa)
				{
				
#				if defined (DEBUG_START_TREE)
				printf ("intermediate tree\n");
				ShowNodes (tempRoot, 2, YES);
				//ShowStartTree (tempRoot, nTips, YES);
#				endif
				
				/* get down pass sequence for partial tree */
				i = 0;
				GetTempDownPassSeq (tempRoot, &i, tempDP);
				if (enforceConstraints == YES)
					{
					for (i=0; i<nNodes; i++)
						{
						p = tempDP[i];
						if (p->left != NULL && p->right != NULL)
							{
							conLft = p->left->constraints;
							conRht = p->right->constraints;
							conNde = conLft & conRht;
							p->constraints = conNde;
							}
						else if (p->left != NULL && p->right == NULL && p->anc == NULL)
							p->constraints = 0;
#						if defined (DEBUG_START_TREE)
						printf ("%4d -- %d\n", p->index, p->constraints);
#						endif
						}
					}
				if (enforceCalibrations == YES)
					{
					for (i=0; i<nNodes; i++)
						{
						p = tempDP[i];
						if (p->left != NULL && p->right != NULL)
							{
							conLft = p->left->calibrations;
							conRht = p->right->calibrations;
							conNde = conLft & conRht;
							p->calibrations = conNde;
							}
						else if (p->left != NULL && p->right == NULL && p->anc == NULL)
							p->calibrations = 0;
#						if defined (DEBUG_START_TREE)
						printf ("%4d -- %d\n", p->index, p->calibrations);
#						endif
						}
					}
					
				/* make list of acceptable nodes */
				a = availTips[nextTip];
#				if defined (DEBUG_START_TREE)
				printf ("adding taxon %s\n", a->label);
#				endif
				if (enforceConstraints == YES)
					{
					conNum1 = a->constraints;
					for (j=0; j<nConstraints; j++)
						{
						conNde = conNum1 & (int)pow(2.0, (double)j);
						if (conNde > 0 && uniqueBipart1[j] == YES)
							{
							conNum1 -= (int)pow(2.0, (double)j);
							uniqueBipart1[j] = NO;
							}
						}
#					if defined (DEBUG_START_TREE)
					printf ("conNum1 = %d\n", conNum1);
#					endif
					}
				if (enforceCalibrations == YES)
					{
					conNum2 = a->calibrations;
					for (j=0; j<nCalibrations; j++)
						{
						conNde = conNum2 & (int)pow(2.0, (double)j);
						if (conNde > 0 && uniqueBipart2[j] == YES)
							{
							conNum2 -= (int)pow(2.0, (double)j);
							uniqueBipart2[j] = NO;
							}
						}
#					if defined (DEBUG_START_TREE)
					printf ("conNum2 = %d\n", conNum2);
#					endif
					}
						
				nPotentialPlaces = 0;
				if (enforceConstraints == YES || enforceCalibrations == YES)
					{
					for (i=0; i<nNodes; i++)
						{
						p = tempDP[i];
						if (p->anc != NULL)
							{
							consistentNode = YES;
							if (enforceConstraints == YES)
								{
								for (j=0; j<nConstraints; j++)
									{
									conLft = p->constraints & (int)pow(2.0, (double)j);
									conRht = p->anc->constraints & (int)pow(2.0, (double)j);
									conNde = conNum1 & (int)pow(2.0, (double)j);
									if (conNde != conLft && conNde != conRht)
										consistentNode = NO;
									}
								}
							if (enforceCalibrations == YES)
								{
								for (j=0; j<nCalibrations; j++)
									{
									conLft = p->calibrations & (int)pow(2.0, (double)j);
									conRht = p->anc->calibrations & (int)pow(2.0, (double)j);
									conNde = conNum2 & (int)pow(2.0, (double)j);
									if (conNde != conLft && conNde != conRht)
										consistentNode = NO;
									}
								}
							if (consistentNode == YES)
								potentialPlaces[nPotentialPlaces++] = p;
							}
						}
					}
				else
					{
					for (i=0; i<nNodes; i++)
						{
						p = tempDP[i];
						if (p->anc != NULL)
							potentialPlaces[nPotentialPlaces++] = p;
						}
					}
#				if defined (DEBUG_START_TREE)
				printf ("potential nodes = ");
				for (i=0; i<nPotentialPlaces; i++)
					{
					p = potentialPlaces[i];
					printf ("%d ", p->index);
					}
				printf ("\n");
#				endif
					
				if (nPotentialPlaces <= 0)
					{
					free (availTips);
					free (availInts);
					free (tempDP);
					free (potentialPlaces);
					free (tempNodes);
					free (localConstraints);
					free (localCalibrations);
					printf ("\n   ERROR: Could not add tip to tree\n");
					return (ERROR);
					}
				
				/* randomly choose node from acceptable list */
				whichNode = (int)(RandomNumber (seed) * nPotentialPlaces);
				p = potentialPlaces[whichNode];
				
				/* add next tip taxon to tree */
				b = availInts[nextInt];
				c = p->anc;
				if (c->left == p)
					{
					b->anc = c;
					b->left = p;
					b->right = a;
					c->left = b;
					a->anc = b;
					p->anc = b;
					}
				else
					{
					b->anc = c;
					b->left = a;
					b->right = p;
					c->right = b;
					a->anc = b;
					p->anc = b;
					}
				
				/* increment nTips, etc. */
				nTips++;
				nInts++;
				nextTip++;
				nextInt++;
				nNodes += 2;
				}
				
			/* clean tree up */
			if (treeModel == UNROOTED)
				{
				i = 0;
				GetTempDownPassSeq (tempRoot, &i, tempDP);
				isMarked = NO;
				for (i=0; i<nNodes; i++)
					{
					p = tempDP[i];
					if (p->left == NULL && p->right == NULL)
						{
						if (p->index == localOutgroup)
							{
							p->marked = YES;
							isMarked = YES;
							}
						else
							p->marked = NO;
						}
					else if (p->left != NULL && p->right != NULL && p->anc != NULL)
						{
						if (p->left->marked == YES || p->right->marked == YES)
							p->marked = YES;
						else
							p->marked = NO;
						}
					else
						{
						p->marked = YES;
						}
					}
				if (isMarked == NO)
					{
					printf ("\n   ERROR: Could not find outgroup taxon\n");
					free (availTips);
					free (availInts);
					free (tempDP);
					free (potentialPlaces);
					free (tempNodes);
					free (localConstraints);
					free (localCalibrations);
					return (ERROR);
					}
				lft = tempRoot->left;
				while (lft->left->index != localOutgroup && lft->right->index != localOutgroup)
					{
					if (lft->left->marked == YES && lft->right->marked == NO)
						{
						m1 = lft->left;
						um1 = lft->right;
						if (m1->left != NULL && m1->right != NULL)
							{
							if (m1->left->marked == YES)
								{
								m2 = m1->left;
								um2 = m1->right;
								}
							else
								{
								m2 = m1->right;
								um2 = m1->left;
								}
							lft->left = m2;
							lft->right = m1;
							m2->anc = lft;
							m1->left = um2;
							m1->right = um1;
							m1->anc = lft;
							um1->anc = m1;
							um2->anc = m1;
							m1->marked = NO;
							}
						else
							{
							printf ("\n   ERROR: Rooting routine is lost\n");
							free (availTips);
							free (availInts);
							free (tempDP);
							free (potentialPlaces);
							free (tempNodes);
							free (localConstraints);
							free (localCalibrations);
							return (ERROR);
							}
						}
					else if (lft->left->marked == NO && lft->right->marked == YES)
						{
						m1 = lft->right;
						um1 = lft->left;
						if (m1->left != NULL && m1->right != NULL)
							{
							if (m1->left->marked == YES)
								{
								m2 = m1->left;
								um2 = m1->right;
								}
							else
								{
								m2 = m1->right;
								um2 = m1->left;
								}
							lft->left = m1;
							lft->right = m2;
							m2->anc = lft;
							m1->left = um1;
							m1->right = um2;
							m1->anc = lft;
							um1->anc = m1;
							um2->anc = m1;
							m1->marked = NO;
							}
						else
							{
							printf ("\n   ERROR: Rooting routine is lost\n");
							free (availTips);
							free (availInts);
							free (tempDP);
							free (potentialPlaces);
							free (tempNodes);
							free (localConstraints);
							free (localCalibrations);
							return (ERROR);
							}
						}
					else
						{
						printf ("   ERROR: Rooting routine is lost\n");
						free (availTips);
						free (availInts);
						free (tempDP);
						free (potentialPlaces);
						free (tempNodes);
						free (localConstraints);
						free (localCalibrations);
						return (ERROR);
						}
					}
								
				/* make certain outgroup is to the right of the root */
				if (tempRoot->left->left->index == localOutgroup)
					{
					m1 = tempRoot->left->left;
					m2 = tempRoot->left->right;
					lft = tempRoot->left;
					lft->left = m2;
					lft->right = m1;
					}
				
				/* now, take outgroup and make it point down */
				m1 = tempRoot;
				m2 = tempRoot->left;
				lft = tempRoot->left->left;
				out = tempRoot->left->right;
				lft->anc = out;
				out->left = lft;
				out->right = NULL;
				out->anc = NULL;
				m1->left = NULL;
				m2->left = NULL;
				m1->right = NULL;
				m2->right = NULL;
				m1->anc = NULL;
				m2->anc = NULL;
				tempRoot = out;
				}
			
			i = numTaxa;
			if (treeModel == UNROOTED)
				FinishTree (tempRoot, &i, NO);
			else
				FinishTree (tempRoot, &i, YES);
			
#			if defined (DEBUG_START_TREE)
			printf ("final tree for chain %d (before copy)\n",n);
			ShowNodes (tempRoot, 2, YES);
			//ShowStartTree (tempRoot, nTips, YES);
#			endif

			/* copy this tree into nodes */
			i = 0;
			GetTempDownPassSeq (tempRoot, &i, tempDP);
			for (i=0; i<tSize; i++)
				{
				p = tempDP[i];
				
				nId = p->index;
				a = &nodes[n*2*tSize+nId];
				a->index = nId;
				a->memoryIndex = nId;
				a->length = 0.1; /* TEMP: May decide to use different starting branch lengths later */
				
				if (p->left != NULL)
					{
					nLftId = p->left->index;
					b = &nodes[n*2*tSize+nLftId];
					a->left = b;
					}
				else
					a->left = NULL;
				if (p->right != NULL)
					{
					nRhtId = p->right->index;
					c = &nodes[n*2*tSize+nRhtId];
					a->right = c;
					}
				else
					a->right = NULL;
				if (p->anc != NULL)
					{
					nAncId = p->anc->index;
					d = &nodes[n*2*tSize+nAncId];
					a->anc = d;
					}
				else
					a->anc = NULL;
					
				if (a->left == NULL && a->right == NULL)
					strcpy (a->label, p->label);
				if (treeModel == UNROOTED && a->left != NULL && a->right == NULL && a->anc == NULL)
					strcpy (a->label, p->label);
				}
			nId = tempRoot->index;
			root[n*2+0] = &nodes[n*2*tSize+nId];
			
#			if defined (DEBUG_START_TREE)
			printf ("final tree for chain %d (copied version)\n",n);
			ShowNodes (root[n*2+0], 2, YES);
			//ShowStartTree (tempRoot, nTips, YES);
#			endif
			
			}
		}
	else 
		{
		/* user tree starts chain */
		printf ("         Starting tree(s) are user-specified\n");

		if (treeModel == ROOTED && isTreeRooted == NO)
			{
			printf ("         Rooting user tree\n");
			if (RootTree (userTreeRoot) == ERROR)
				{
				FreeMemory ();
				free (availTips);
				free (availInts);
				free (tempDP);
				free (potentialPlaces);
				free (tempNodes);
				free (localConstraints);
				free (localCalibrations);
				return (ERROR);
				}
			isTreeRooted = YES;
			}
		else if (treeModel == UNROOTED && isTreeRooted == YES)
			{
			printf ("         Derooting user tree\n");
			if (DerootTree (userTreeRoot) == ERROR)
				{
				FreeMemory ();
				free (availTips);
				free (availInts);
				free (tempDP);
				free (potentialPlaces);
				free (tempNodes);
				free (localConstraints);
				free (localCalibrations);
				return (ERROR);
				}
			isTreeRooted = NO;
			}

		for (n=0; n<numChains; n++)
			{
			/* get down pass for user tree */
			i = 0;
			GetTempDownPassSeq (userTreeRoot, &i, tempDP);
			if (isTreeRooted == YES)
				{
				nNodes = 2*numTaxa;
				nUserNodes = 2*nTaxa;
				}
			else
				{
				nNodes = 2*numTaxa-2;
				nUserNodes = 2*nTaxa-2;
				}
				
			/* read user tree into temporary nodes */
			for (i=0; i<2*nTaxa; i++)
				{
				tempNodes[i].left  = NULL;
				tempNodes[i].right = NULL;
				tempNodes[i].anc   = NULL;
				tempNodes[i].index = -1;
				tempNodes[i].length = 0.0;
				for (j=0; j<100; j++)
					tempNodes[i].label[j] = ' ';
				}
			for (i=0; i<nUserNodes; i++)
				{
				p = tempDP[i];
				
				nId = p->index;
				a = &tempNodes[nId];
				a->index = nId;
				a->memoryIndex = nId;
				a->length = p->length;
				
				if (p->left != NULL)
					{
					nLftId = p->left->index;
					b = &tempNodes[nLftId];
					a->left = b;
					}
				else
					a->left = NULL;
				if (p->right != NULL)
					{
					nRhtId = p->right->index;
					c = &tempNodes[nRhtId];
					a->right = c;
					}
				else
					a->right = NULL;
				if (p->anc != NULL)
					{
					nAncId = p->anc->index;
					d = &tempNodes[nAncId];
					a->anc = d;
					}
				else
					a->anc = NULL;
					
				if (a->left == NULL && a->right == NULL)
					strcpy (a->label, p->label);
				if (treeModel == UNROOTED && a->left != NULL && a->right == NULL && a->anc == NULL)
					strcpy (a->label, p->label);
				}
			nId = userTreeRoot->index;
			tempRoot = &tempNodes[nId];
				
			/* delete unused nodes from temporary nodes*/
			i = 0;
			GetTempDownPassSeq (tempRoot, &i, tempDP);
			for (i=0; i<nUserNodes; i++)
				{
				p = tempDP[i];
				p->marked = NO;
				if (p->left == NULL && p->right == NULL && p->anc != NULL && excludedTaxa[p->index] == YES)
					{
					p->marked = YES;
					}
				else if (p->left != NULL && p->right == NULL && p->anc == NULL)
					{
					if (isTreeRooted == NO && excludedTaxa[p->index] == YES)
						{
						p->marked = YES;
						}
					}
				}
			for (i=0; i<nUserNodes; i++)
				{
				p = tempDP[i];
				if (p->marked == YES)
					{
					if (p->anc != NULL)
						{
						b = p->anc;
						if (b->left == p)
							a = b->right;
						else
							a = b->left;
						c = b->anc;
						if (c->left == b)
							c->left = a;
						else
							c->right = a;
						a->anc = c;
						a->length += b->length;
						p->anc = p->left = p->right = NULL;
						b->anc = b->left = b->right = NULL;
						p->marked = NO;
						b->marked = NO;
						}
					else
						{
						/* first rotate tree so that left, left is a tip */
						a = p->left;
						b = a->left;
						while (b->left != NULL && b->right != NULL)
							{
							c = b->left;
							d = b->right;
							e = a->right;
							c->anc = a;
							a->left = c;
							a->right = b;
							b->left = d;
							b->right = e;
							b->anc = a;
							d->anc = e->anc = b;
							e->length += b->length;
							b->length = c->length / 2.0;
							c->length = b->length;
							a = p->left;
							b = a->left;
							}
						if (treeModel == ROOTED)
							ShowNodes (tempRoot, 2, YES);
						else
							ShowNodes (tempRoot, 2, NO);
						/* now that the tree is rotated around the root, remove the root */
						a = p->left;
						b = a->left;
						c = a->right;
						c->anc = b;
						c->length += b->length;
						b->left = c;
						b->right = b->anc = NULL;
						a->left = a->right = a->anc = NULL;
						p->left = p->right = p->anc = NULL;
						tempRoot = b;
						}
					}
				}
				
			/* if constraints are enforced, check that the user tree is consistent with the constraints */
			i = 0;
			GetTempDownPassSeq (tempRoot, &i, tempDP);
			if (enforceConstraints == YES)
				{ 
				for (j=0; j<nConstraints; j++)
					{
					/* downpass first */
					for (i=0; i<tSize; i++)
						{
						p = tempDP[i];
						if (p->left == NULL && p->right == NULL && p->anc != NULL)
							{
							conLft = (unsigned int)pow(2.0, (double)j);
							nId = 0;
							for (k=0; k<nTaxa; k++)
								{
								if (excludedTaxa[k] == NO)
									{
									if (nId == p->index)
										break;
									nId++;
									}
								} 
							conNde = conLft & (unsigned int)constraints[k];
							if (conNde > 0)
								p->constraints = 2;
							else
								p->constraints = 1;
							}
						else if (p->left != NULL && p->right != NULL && p->anc != NULL)
							{
							conLft = p->left->constraints;
							conRht = p->right->constraints;
							conNde = conLft & conRht;
							if (conNde == 0)
								p->constraints = conLft | conRht;
							else
								p->constraints = conNde;
							}
						else
							{
							if (treeModel == UNROOTED)
								{
								conLft = (unsigned int)pow(2.0, (double)j);
								nId = 0;
								for (k=0; k<nTaxa; k++)
									{
									if (excludedTaxa[k] == NO)
										{
										if (nId == p->index)
											break;
										nId++;
										}
									} 
								conNde = conLft & (unsigned int)constraints[k];
								if (conNde > 0)
									p->constraints = 2;
								else
									p->constraints = 1;
								}
							else
								p->constraints = 0;
							}
						}
					/* now pass up tree and count changes */
					consistentNode = 0;
					for (i=tSize-1; i>=0; i--)
						{
						p = tempDP[i];
						if (p->left != NULL && p->right != NULL && p->anc != NULL)
							{
							conLft = p->constraints;
							conRht = p->anc->constraints;
							conNde = conLft & conRht;
							if (conNde > 0)
								p->constraints = conNde;
							}
						if (p->anc != NULL)
							{
							if (p->anc->anc == NULL)
								{
								if (p->constraints != p->anc->constraints && treeModel == UNROOTED)
									consistentNode++;
								}
							else
								{
								if (p->constraints != p->anc->constraints)
									consistentNode++;
								}
							}
						}
					if (consistentNode > 1)
						{
						printf ("\n   ERROR: User tree is inconsistent with the specied constraints\n");
						free (availTips);
						free (availInts);
						free (tempDP);
						free (potentialPlaces);
						free (tempNodes);
						free (localConstraints);
						free (localCalibrations);
						return (ERROR);
						}
					}
				}
				
			/* if calibrations are enforced, check that the user tree is consistent with the constraints */
			if (enforceCalibrations == YES)
				{
				for (j=0; j<nCalibrations; j++)
					{
					/* downpass first */
					for (i=0; i<tSize; i++)
						{
						p = tempDP[i];
						if (p->left == NULL && p->right == NULL && p->anc != NULL)
							{
							conLft = (unsigned int)pow(2.0, (double)j);
							nId = 0;
							for (k=0; k<nTaxa; k++)
								{
								if (excludedTaxa[k] == NO)
									{
									if (nId == p->index)
										break;
									nId++;
									}
								} 
							conNde = conLft & (unsigned int)calibrations[k];
							if (conNde > 0)
								p->calibrations = 2;
							else
								p->calibrations = 1;
							}
						else if (p->left != NULL && p->right != NULL && p->anc != NULL)
							{
							conLft = p->left->calibrations;
							conRht = p->right->calibrations;
							conNde = conLft & conRht;
							if (conNde == 0)
								p->calibrations = conLft | conRht;
							else
								p->calibrations = conNde;
							}
						else
							{
							if (treeModel == UNROOTED)
								{
								conLft = (unsigned int)pow(2.0, (double)j);
								nId = 0;
								for (k=0; k<nTaxa; k++)
									{
									if (excludedTaxa[k] == NO)
										{
										if (nId == p->index)
											break;
										nId++;
										}
									} 
								conNde = conLft & (unsigned int)calibrations[k];
								if (conNde > 0)
									p->calibrations = 2;
								else
									p->calibrations = 1;
								}
							else
								p->calibrations = 0;
							}
						}
					/* now pass up tree and count changes */
					consistentNode = 0;
					for (i=tSize-1; i>=0; i--)
						{
						p = tempDP[i];
						if (p->left != NULL && p->right != NULL && p->anc != NULL)
							{
							conLft = p->calibrations;
							conRht = p->anc->calibrations;
							conNde = conLft & conRht;
							if (conNde > 0)
								p->calibrations = conNde;
							}
						if (p->anc != NULL)
							{
							if (p->anc->anc == NULL)
								{
								if (p->calibrations != p->anc->calibrations && treeModel == UNROOTED)
									consistentNode++;
								}
							else
								{
								if (p->calibrations != p->anc->calibrations)
									consistentNode++;
								}
							}
						}
					if (consistentNode > 1)
						{
						printf ("\n   ERROR: User tree is inconsistent with the specied calibrations\n");
						free (availTips);
						free (availInts);
						free (tempDP);
						free (potentialPlaces);
						free (tempNodes);
						free (localConstraints);
						free (localCalibrations);
						return (ERROR);
						}
					}
				}

			/* relabel nodes */
			i = 0;
			GetTempDownPassSeq (tempRoot, &i, tempDP);
			if (treeModel == ROOTED)
				nUserNodes = 2*numTaxa;
			else 
				nUserNodes = 2*numTaxa-2;
			for (i=0; i<nUserNodes; i++)
				{
				p = tempDP[i];
				if (p->left == NULL && p->right == NULL && p->anc != NULL)
					{
					k = 0;
					for (j=0; j<p->index; j++)
						{
						if (excludedTaxa[j] == NO)
							k++;
						}
					p->index = k;
					}
				else if (p->left != NULL && p->right == NULL && p->anc == NULL)
					{
					if (treeModel == UNROOTED)
						{
						k = 0;
						for (j=0; j<p->index; j++)
							{
							if (excludedTaxa[j] == NO)
								k++;
							}
						p->index = k;
						}
					}
				}
			i = numTaxa;
			if (treeModel == UNROOTED)
				FinishTree (tempRoot, &i, NO);
			else
				FinishTree (tempRoot, &i, YES);
			
			/* copy tree into nodes */
			for (i=0; i<tSize; i++)
				{
				p = tempDP[i];
				
				nId = p->index;
				a = &nodes[n*2*tSize+nId];
				a->index = nId;
				a->memoryIndex = nId;
				a->length = p->length;
				
				if (p->left != NULL)
					{
					nLftId = p->left->index;
					b = &nodes[n*2*tSize+nLftId];
					a->left = b;
					}
				else
					a->left = NULL;
				if (p->right != NULL)
					{
					nRhtId = p->right->index;
					c = &nodes[n*2*tSize+nRhtId];
					a->right = c;
					}
				else
					a->right = NULL;
				if (p->anc != NULL)
					{
					nAncId = p->anc->index;
					d = &nodes[n*2*tSize+nAncId];
					a->anc = d;
					}
				else
					a->anc = NULL;
					
				if (a->left == NULL && a->right == NULL)
					strcpy (a->label, p->label);
				if (treeModel == UNROOTED && a->left != NULL && a->right == NULL && a->anc == NULL)
					strcpy (a->label, p->label);
				}
			nId = tempRoot->index;
			root[n*2+0] = &nodes[n*2*tSize+nId];
			
			

#			if defined (DEBUG_START_TREE)
			printf ("final tree for chain %d (copied version)\n",n);
			if (treeModel == ROOTED)
				ShowNodes (root[n*2+0], 2, YES);
			else
				ShowNodes (root[n*2+0], 2, NO);
			//ShowStartTree (tempRoot, nTips, YES);
#			endif
			}
		
		}

#	if defined (DEBUG_START_TREE)
	printf ("tidying up trees\n");
#	endif

	/* tidy up trees, assigning constraints, calibrations, and branch lengths */
	printf ("         Setting branch lengths\n");
	for (n=0; n<numChains; n++)
		{
		i = 0;
		GetTempDownPassSeq (root[n*2+0], &i, tempDP);

		/* set constraints */
		if (enforceConstraints == YES)
			{
			for (j=0; j<tSize; j++)
				{
				p = tempDP[j];
				p->constraints = 0;
				p->isConstrained = NO;
				p->constraintNum = 0;
				}
			for (i=0; i<nConstraints; i++)
				{
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					p->constraints = 0;
					}
				conNde = (unsigned int)pow(2.0, (double)i);
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					if (p->left == NULL && p->right == NULL && p->anc != NULL)
						{
						nId = 0;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO)
								{
								if (nId == p->index)
									break;
								nId++;
								}
							} 
						conLft = conNde & (unsigned int)constraints[k];
						if (conNde == conLft)
							p->constraints = conNde;
						else
							p->constraints = 0;
						}
					else if (p->left != NULL && p->right == NULL && p->anc == NULL && treeModel == UNROOTED)
						{
						nId = 0;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO)
								{
								if (nId == p->index)
									break;
								nId++;
								}
							} 
						conLft = conNde & (unsigned int)constraints[k];
						if (conNde == conLft)
							p->constraints = conNde;
						else
							p->constraints = 0;
						}
					}
				/* pass down */
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					if (p->left != NULL && p->right != NULL && p->anc != NULL)
						{
						conLft = p->left->constraints;
						conRht = p->right->constraints;
						conNum1 = conLft & conRht;
						if (conNum1 == conNde)
							p->constraints = conNde;
						}
					}
				/* pass up */
				for (j=tSize-1; j>=0; j--)
					{
					p = tempDP[j];
					if (p->left != NULL && p->right != NULL && p->anc != NULL)
						{
						conAnc = p->anc->constraints;
						conLft = p->left->constraints;
						conRht = p->right->constraints;
						conNum1 = conAnc & conLft;
						conNum2 = conAnc & conRht;
						if (conNum1 == conNde || conNum2 == conNde)
							p->constraints = conNde;
						}
					}
					
				/* assign constraints */
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					if (p->anc != NULL)
						{
						if (p->constraints == conNde && p->anc->constraints == 0)
							{
							p->isConstrained = YES;
							p->constraintNum = i+1;
							k = 0;
							while (constraintLabels[p->constraintNum-1][k] != '|' && k < 99)
								{
								p->constraintName[k] = constraintLabels[p->constraintNum-1][k];
								k++;
								}
							p->constraintName[k] = '\0';
							}
						else if (p->anc->constraints == conNde && p->constraints == 0)
							{
							p->anc->isConstrained = YES;
							p->anc->constraintNum = i+1;
							k = 0;
							while (constraintLabels[p->anc->constraintNum-1][k] != '|' && k < 99)
								{
								p->anc->constraintName[k] = constraintLabels[p->anc->constraintNum-1][k];
								k++;
								}
							p->anc->constraintName[k] = '\0';
							}
						}
					else
						{
						if (p->constraints == conNde && p->left->constraints == 0 && treeModel == UNROOTED)
							{
							p->isConstrained = YES;
							p->constraintNum = i+1;
							k = 0;
							while (constraintLabels[p->constraintNum-1][k] != '|' && k < 99)
								{
								p->constraintName[k] = constraintLabels[p->constraintNum-1][k];
								k++;
								}
							p->constraintName[k] = '\0';
							}
						}
					}
					
				}
#			if 0
			for (j=0; j<tSize; j++)
				{
				p = tempDP[j];
				if (p->isConstrained == YES)
					printf ("%2d %4d -- %d (%s)\n", conNde, p->index, p->constraintNum, p->constraintName);
				else
					printf ("%2d %4d --\n", conNde, p->index);
				}
#			endif				
			}
		
		/* set calibrations */
		if (enforceCalibrations == YES)
			{
			for (j=0; j<tSize; j++)
				{
				p = tempDP[j];
				p->calibrations = 0;
				p->isCalibrated = NO;
				p->calibrationNum = 0;
				p->calTime[0] = p->calTime[1] = 0.0;
				}
			for (i=0; i<nCalibrations; i++)
				{
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					p->calibrations = 0;
					}
				conNde = (unsigned int)pow(2.0, (double)i);
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					if (p->left == NULL && p->right == NULL && p->anc != NULL)
						{
						nId = 0;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO)
								{
								if (nId == p->index)
									break;
								nId++;
								}
							} 
						conLft = conNde & (unsigned int)calibrations[k];
						if (conNde == conLft)
							p->calibrations = conNde;
						else
							p->calibrations = 0;
						}
					else if (p->left != NULL && p->right == NULL && p->anc == NULL && treeModel == UNROOTED)
						{
						nId = 0;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO)
								{
								if (nId == p->index)
									break;
								nId++;
								}
							} 
						conLft = conNde & (unsigned int)calibrations[k];
						if (conNde == conLft)
							p->calibrations = conNde;
						else
							p->calibrations = 0;
						}
					}
				/* pass down */
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					if (p->left != NULL && p->right != NULL && p->anc != NULL)
						{
						conLft = p->left->calibrations;
						conRht = p->right->calibrations;
						conNum1 = conLft & conRht;
						if (conNum1 == conNde)
							p->calibrations = conNde;
						}
					}
				/* pass up */
				for (j=tSize-1; j>=0; j--)
					{
					p = tempDP[j];
					if (p->left != NULL && p->right != NULL && p->anc != NULL)
						{
						conAnc = p->anc->calibrations;
						conLft = p->left->calibrations;
						conRht = p->right->calibrations;
						conNum1 = conAnc & conLft;
						conNum2 = conAnc & conRht;
						if (conNum1 == conNde || conNum2 == conNde)
							p->calibrations = conNde;
						}
					}
					
				/* assign calibrations */
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					if (p->anc != NULL)
						{
						if (p->calibrations == conNde && p->anc->calibrations == 0)
							{
							p->isCalibrated = YES;
							p->calibrationNum = i+1;
							k = 0;
							while (calibrationLabels[p->calibrationNum-1][k] != '|' && k < 99)
								{
								p->calibrationName[k] = calibrationLabels[p->calibrationNum-1][k];
								k++;
								}
							p->calibrationName[k] = '\0';
							p->calTime[0] = calibrationTimes[p->calibrationNum-1][0];
							p->calTime[1] = calibrationTimes[p->calibrationNum-1][1];
							}
						else if (p->anc->calibrations == conNde && p->calibrations == 0)
							{
							p->anc->isCalibrated = YES;
							p->anc->calibrationNum = i+1;
							k = 0;
							while (calibrationLabels[p->anc->calibrationNum-1][k] != '|' && k < 99)
								{
								p->anc->calibrationName[k] = calibrationLabels[p->anc->calibrationNum-1][k];
								k++;
								}
							p->anc->calibrationName[k] = '\0';
							p->anc->calTime[0] = calibrationTimes[p->calibrationNum-1][0];
							p->anc->calTime[1] = calibrationTimes[p->calibrationNum-1][1];
							}
						}
					else
						{
						if (p->calibrations == conNde && p->left->calibrations == 0 && treeModel == UNROOTED)
							{
							p->isCalibrated = YES;
							p->calibrationNum = i+1;
							k = 0;
							while (calibrationLabels[p->calibrationNum-1][k] != '|' && k < 99)
								{
								p->calibrationName[k] = calibrationLabels[p->calibrationNum-1][k];
								k++;
								}
							p->calibrationName[k] = '\0';
							p->calTime[0] = calibrationTimes[p->calibrationNum-1][0];
							p->calTime[1] = calibrationTimes[p->calibrationNum-1][1];
							}
						}
					}
					
				}
#			if 0
			for (j=0; j<tSize; j++)
				{
				p = tempDP[j];
				if (p->isCalibrated == YES)
					printf ("%2d %4d -- %d (%s) (%lf %lf)\n", conNde, p->index, p->calibrationNum, p->calibrationName, p->calTime[0], p->calTime[1]);
				else
					printf ("%2d %4d --\n", conNde, p->index);
				}
#			endif				
			}
		
		/* set branch lengths */
		/* get parsimony tree length */
		treeLength = 0.0;
		sum = 0.0;
		for (i=0; i<numChars; i++)
			{
			tempLength = 0;
			for (j=0; j<tSize; j++)
				{
				p = tempDP[j];
				if (p->left == NULL && p->right == NULL && p->anc != NULL)
					{
					p->farrisSet = matrix[pos(p->index,i,numChars)];
					}
				else if (p->left != NULL && p->right != NULL && p->anc != NULL)
					{
					conLft = p->left->farrisSet;
					conRht = p->right->farrisSet;
					conNde = conLft & conRht;
					if (conNde == 0)
						{
						conNde = conLft | conRht;
						tempLength++;
						}
					p->farrisSet = conNde;
					}
				else
					{
					if (treeModel == UNROOTED)
						{
						p->farrisSet = matrix[pos(p->index,i,numChars)];
						conLft = p->left->farrisSet;
						conRht = p->farrisSet;
						conNde = conLft & conRht;
						if (conNde == 0)
							{
							tempLength++;
							}
						}
					}
				}	
			sum += (double)numSitesOfPat[i];
			treeLength += tempLength * numSitesOfPat[i];
			}	
		if (treeLength <= 0.0)
			treeLength = 0.01;
		else
			treeLength /= sum;
		//printf ("tree length = %lf\n", treeLength);
		
		if (treeModel == UNROOTED)
			{
			if (!strcmp(startingTreeModel, "random") || (!strcmp(startingTreeModel, "user") && userBrlensDef == NO))
				{
				sum = 0.0;
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					if (p->anc != NULL)
						{
						p->length = RandomNumber (seed);
						sum += p->length;
						}
					}
				for (j=0; j<tSize; j++)
					{
					p = tempDP[j];
					if (p->anc != NULL)
						p->length /= treeLength;
					}
				}
			}
		else
			{
			if (!strcmp(clockModel, "relaxed") || !strcmp(clockModel, "strict"))
				{
				if (enforceCalibrations == YES)
					{
					/* get node times under the clock constraint with calibrations*/
					for (j=0; j<tSize; j++)
						{
						p = tempDP[j];
						if (p->left == NULL && p->right == NULL && p->anc != NULL)
							{
							if (p->isCalibrated == YES)
								{
								p->nodeTime = p->calTime[0];
								}
							else
								p->nodeTime = 0.0;
							}
						else if (p->left != NULL && p->right != NULL && p->anc != NULL)
							{
							oldestAbove = p->left->nodeTime;
							if (p->right->nodeTime > oldestAbove)
								oldestAbove = p->right->nodeTime;
							if (p->isCalibrated == YES)
								{
								if (oldestAbove > p->calTime[0] + p->calTime[1])
									{
									printf ("\n   ERROR: Inconsistent times for calibrations\n");
									free (availTips);
									free (availInts);
									free (tempDP);
									free (potentialPlaces);
									free (tempNodes);
									free (localConstraints);
									free (localCalibrations);
									return (ERROR);
									}
								else if (oldestAbove > p->calTime[0] && oldestAbove < p->calTime[0] + p->calTime[1])
									{
									p->nodeTime = oldestAbove + 0.0001;
									}
								else
									{
									p->nodeTime = p->calTime[0];
									}
								}
							else
								{
								p->nodeTime = oldestAbove + 0.0001;
								}
							}
						}
					for (i=0; i<10; i++)
						{
						for (j=0; j<tSize; j++)
							{
							p = tempDP[j];
							if (p->anc != NULL)
								{
								if (p->isCalibrated == NO)
									{
									if (p->left == NULL && p->right == NULL && p->anc != NULL)
										{
										oldestAbove = 0.0;
										}
									else 
										{
										oldestAbove = p->left->nodeTime;
										if (p->right->nodeTime > oldestAbove)
											oldestAbove = p->right->nodeTime;
										}
									if (p->anc->anc != NULL)
										oldestBelow = p->anc->nodeTime;
									else
										oldestBelow = 2 * p->nodeTime;
									if (p->left != NULL && p->right != NULL)
										p->nodeTime = oldestAbove + (oldestBelow - oldestAbove) * RandomNumber(seed);
									}
								}
							}	
						}		
					if (GetDistances (numTaxa, numChars) == ERROR)
						{
						printf ("\n   ERROR: Could not calculate distances\n");
						free (availTips);
						free (availInts);
						free (tempDP);
						free (potentialPlaces);
						free (tempNodes);
						free (localConstraints);
						free (localCalibrations);
						return (ERROR);
						}
					else
						allocatedMemory[ALLOC_DISTANCES] = YES;	
					sum = 0.0;
					for (i=0; i<numTaxa-1; i++)
						for (j=i; j<numTaxa; j++)
							if (distances[pos(i,j,numTaxa)] > sum)
								sum = distances[pos(i,j,numTaxa)];
					free (distances);
					allocatedMemory[ALLOC_DISTANCES] = NO;	
					//treeHeight[n*2+0] = sum * 0.5;
					treeHeight[n*2+0] = 0.0005; /* TEMP */
					for (j=0; j<tSize; j++)
						{
						p = tempDP[j];
						if (p->anc != NULL)
							{
							if (p->anc->anc != NULL)
								{
								p->length = treeHeight[n*2+0] * (p->anc->nodeTime - p->nodeTime);
								if (p->length < BRLEN_EPSILON)
									p->length = BRLEN_EPSILON;
								}
							else
								{
								p->length = 0.0;
								}
							}
						else
							{
							p->length = 0.0;
							}
						}		
					}
				else
					{
					/* get node times under the clock constraint without calibrations*/
					for (j=0; j<tSize; j++)
						{
						p = tempDP[j];
						if (p->left == NULL && p->right == NULL && p->anc != NULL)
							{
							p->nodeTime = 0.0;
							}
						else if (p->left != NULL && p->right != NULL && p->anc != NULL)
							{
							oldestAbove = p->left->nodeTime;
							if (p->right->nodeTime > oldestAbove)
								oldestAbove = p->right->nodeTime;
							p->nodeTime = oldestAbove + 0.0001;
							}
						}
					sum = root[n*2+0]->left->nodeTime;
					for (j=0; j<tSize; j++)
						{
						p = tempDP[j];
						if (p->anc != NULL)
							p->nodeTime /= sum;
						}
					if (GetDistances (numTaxa, numChars) == ERROR)
						{
						printf ("\n   ERROR: Could not calculate distances\n");
						free (availTips);
						free (availInts);
						free (tempDP);
						free (potentialPlaces);
						free (tempNodes);
						free (localConstraints);
						free (localCalibrations);
						return (ERROR);
						}
					else
						allocatedMemory[ALLOC_DISTANCES] = YES;	
					sum = 0.0;
					for (i=0; i<numTaxa-1; i++)
						for (j=i; j<numTaxa; j++)
							if (distances[pos(i,j,numTaxa)] > sum)
								sum = distances[pos(i,j,numTaxa)];
					free (distances);
					allocatedMemory[ALLOC_DISTANCES] = NO;	
					sum *= 0.5;
					for (j=0; j<tSize; j++)
						{
						p = tempDP[j];
						if (p->anc != NULL)
							{
							if (p->anc->anc != NULL)
								p->length = sum * (p->anc->nodeTime - p->nodeTime);
							else
								p->length = 0.0;
							}
						else
							p->length = 0.0;
						}
					}
					
				}
			else
				{
				if (!strcmp(startingTreeModel, "random") || (!strcmp(startingTreeModel, "user") && userBrlensDef == NO))
					{
					sum = 0.0;
					for (j=0; j<tSize; j++)
						{
						p = tempDP[j];
						if (p->anc != NULL)
							{
							if (p->anc->anc != NULL)
								{
								p->length = RandomNumber (seed);
								sum += p->length;
								}
							}
						}
					for (j=0; j<tSize; j++)
						{
						p = tempDP[j];
						if (p->anc != NULL)
							if (p->anc->anc != NULL)
								p->length /= treeLength;
						}
					}
				}
			}

#		if 0
		if (treeModel == ROOTED)
			{
			printf ("nodes for rooted tree:\n");
			ShowNodes (root[n*2+0], 2, YES);
			//ShowStartTree (root[n*2+0], numTaxa, YES);
			}
		else
			{
			printf ("nodes for unrooted tree:\n");
			ShowNodes (root[n*2+0], 2, NO);
			//ShowStartTree (root[n*2+0], numTaxa, NO);
			}
#		endif

		}
		
	if (showStartTree == YES)
		{
		for (n=0; n<numChains; n++)
			{
			printf ("\n         Starting tree for chain %d:\n", n+1);
			if (treeModel == ROOTED)
				{
				ShowNodes (root[n*2+0], 2, YES);
				//ShowStartTree (root[n*2+0], numTaxa, YES);
				}
			else
				{
				ShowNodes (root[n*2+0], 2, NO);
				//ShowStartTree (root[n*2+0], numTaxa, NO);
				}
			}
		}
#	if 0
	for (n=0; n<numChains; n++)
		{
		printf ("\n         Starting tree for chain %d:\n", n+1);
		if (treeModel == ROOTED)
			{
			ShowNodes (root[n*2+0], 2, YES);
			}
		else
			{
			ShowNodes (root[n*2+0], 2, NO);
			}
		}
#	endif
		
	free (availTips);
	free (availInts);
	free (tempDP);
	free (potentialPlaces);
	free (tempNodes);
	free (localConstraints);
	free (localCalibrations);
	
	return (NO_ERROR);
	
}





void CalcCijk (double *c_ijk, int n, double **u, double **v)

{

	register int 	i, j, k;
	double 			*pc;

		/* precalculate values for faster matrix mult in GTRChangeMatrix and GTRDerivatives */
		pc = c_ijk;
		for (i=0; i<n; i++)
			for (j=0; j<n; j++)
				for (k=0; k<n; k++)
				 	*pc++ = u[i][k] * v[k][j];	/* (note: pc = &c[i][j][k]) */

}





void CalcPij (double *c_ijk, int n, double *eigenValues, double v, double r, double **p)

{

	register int		i, j, k;
	double				vr, *ptr, *g, sum;

	vr = v * r;
	g = EigValexp;
	for (k=0; k<n; k++)
		*g++ = exp(*eigenValues++ * vr);

	ptr = c_ijk;
	for(i=0; i<n; i++)
		{
		for(j=0; j<n; j++)
			{
			g = EigValexp;
			sum = 0.0;
			for(k=0; k<n; k++)
				sum += (*ptr++) * (*g++);
			p[i][j] = (sum < 0.0) ? 0.0 : sum;
			}
		}
		
#	if 0
	printf ("v = %lf, r = %lf\n", v, r);
	for (i=0; i<n; i++)
		{
		for (j=0; j<n; j++)
			{
			printf ("%1.3lf ", p[i][j]);
			}
		printf ("\n");
		}
	printf ("\n");
#	endif

}





void CalcPFSij (double *c_ijk, int n, double *eigenValues, double v, double r, double **p, double **f_p, double **s_p)

{

	int		i, j, k;
	
	/* P(t) = U * exp{Root*t} * V */	
	for (i=0; i<n; i++)
		{
		for (j=0; j<n; j++)
			{
			p[i][j] = f_p[i][j] = s_p[i][j] = 0.0;
			for (k=0; k<n; k++)
				{
				p[i][j]   += c_ijk[i*n*n+j*n+k]*exp(eigenValues[k]*v*r);
				f_p[i][j] += c_ijk[i*n*n+j*n+k]*eigenValues[k]*r*exp(eigenValues[k]*v*r);
				s_p[i][j] += c_ijk[i*n*n+j*n+k]*eigenValues[k]*eigenValues[k]*r*r*exp(eigenValues[k]*v*r);
				}
			if (p[i][j] < 0.0)
				p[i][j] = 0.0;
			}
		}

}





#if defined (SMART_TI_PROBS)
int CalcTransitionProbs (int whichState, int whichChain, int numRateCats)

{

	
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == NO)
		{
		if (useCovarion == NO)
			{
			if (CalcTransDNA (whichState, whichChain, numRateCats) == ERROR)
				{
				return (ERROR);
				}
			}
		else
			{
			if (CalcTransCovarion (whichState, whichChain, numRateCats) == ERROR)
				{
				return (ERROR);
				}
			}
		}
	else if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		if (useCovarion == NO)
			{
			if (CalcTransCodon (whichState, whichChain) == ERROR)
				{
				return (ERROR);
				}
			}
		else
			{
			return (ERROR);
			}
		}
	else if (dataType == PROTEIN)
		{
		if (useCovarion == NO)
			{
			if (CalcTransAA (whichState, whichChain, numRateCats) == ERROR)
				{
				return (ERROR);
				}
			}
		else
			{
			if (CalcTransCovarion (whichState, whichChain, numRateCats) == ERROR)
				{
				return (ERROR);
				}
			}
		}
	else if (dataType == RESTRICTION)
		{
		if (useCovarion == NO)
			{

			}
		else
			{
			return (ERROR);
			}
		}
	else if (dataType == STANDARD)
		{
		if (useCovarion == NO)
			{

			}
		else
			{
			return (ERROR);
			}
		}
	else
		return (ERROR);
		
	return (NO_ERROR);
	
}





int CalcTransAA (int whichState, int whichChain, int numRateCats)

{

	register int		i, j, k, m, index;
	int					n, lnStates, lnStatesCubed, nRates, lnPartitions, lnumRateCats, isComplex,
						allNodesPointer, allNodesStop, nForOneState;
	double				**probs, *catFreq, *catRate, *partRate,
						**q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk,
						correlation, **markovTi, theRate, bs[20], *ptr;
	complex 			**Ceigvecs, **CinverseEigvecs;	
	TreeNode			*p;

	allNodesPointer = whichChain*2*numNodes + whichState*numNodes;
	allNodesStop = allNodesPointer + numNodes;
	
	/* standard 4 X 4 model of DNA substitution ***************************************************************************/
	lnStates = 20;
	lnStatesCubed = 8000;

	/* base frequencies */
	index = whichChain*2*lnStates + whichState*lnStates;
	for (i=0; i<lnStates; i++)
		bs[i] = baseFreq[index + i];

	/* allocate memory for transition probabilities along a single branch */
	probs = psdmatrix (lnStates);
			
	/* get eigenvalues and eigenvectors */
	q = psdmatrix (lnStates);
	eigenValues = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + lnStates;
	eigvecs = psdmatrix (lnStates);
	inverseEigvecs = psdmatrix (lnStates);
	Ceigvecs = pscmatrix (lnStates);
	CinverseEigvecs = pscmatrix (lnStates);
	if (SetAAQMatrix (q, whichState, whichChain) == ERROR)
		goto error_exit;
	isComplex = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
	if (isComplex == NO)
		{
		c_ijk = (double *)malloc((size_t) (lnStatesCubed * sizeof(double)));
		if (!c_ijk)
			{
			printf ("\n   ERROR: Problem allocating c_ijk.\n");
			goto error_exit;
			}
		CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
		}
		
	/* how many rates are there? */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;
	nRates = lnPartitions * lnumRateCats;
	
	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate  = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;
	
	/* fill in rate categories with frequencies and rates */
	if (!strcmp(ratesModel,"gamma") || !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* calculate transtition probabilities */
	nForOneState = numNodes*nodeTiSize;
	for (n=allNodesPointer; n<allNodesStop; n++)
		{
		p = allNodesDownPassSeq[n];
		updateTiFlag[p->index] = NO;
		if (p->anc != NULL)
			{
			if ((p->anc->anc != NULL || (p->anc->anc == NULL && treeModel == UNROOTED)) && p->upDateTi == YES)
				{
				p->upDateTi = NO;
				updateTiFlag[p->index] = YES;
				ptr = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
				for (m=index=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						if (isComplex == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								ptr[index++] = probs[i][j];
						}
					}
				}
			}
		}
	
	/* free memory */
	free_psdmatrix (probs);
	free (catFreq);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		free_psdmatrix(markovTi);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	if (isComplex != YES)
		free (c_ijk);
	return (NO_ERROR);
	
	error_exit:
		return (ERROR);
	
}





int CalcTransCodon (int whichState, int whichChain)

{

	register int		i, j, k, index;
	int					n, lnStates, lnStatesSquared, lnStatesCube, nOmegaCats, isComplex,
						allNodesPointer, allNodesStop, nForOneState, index1;
	double				**probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk,
						*bs, *ptr;
	complex 			**Ceigvecs, **CinverseEigvecs;	
	TreeNode			*p;

	allNodesPointer = whichChain*2*numNodes + whichState*numNodes;
	allNodesStop = allNodesPointer + numNodes;

	/* number of states */
	if (!strcmp(codonModelType, "covny98"))
		lnStates = 3 * nStates;
	else
		lnStates = nStates;
	lnStatesSquared = lnStates * lnStates;
	lnStatesCube = lnStatesSquared * lnStates;
	
	/* load codon frequencies */
	bs = (double *)malloc((size_t) (lnStates * sizeof(double)));
	if (!bs)
		{
		printf ("\n   ERROR: Problem allocating bs.\n");
		goto error_exit;
		}
	index = whichChain*2*nStates + whichState*nStates;
	if (!strcmp(codonModelType, "covny98"))
		{
		k = 0;
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probPur[whichChain*2 + whichState];
			k++;
			}
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probNeu[whichChain*2 + whichState];
			k++;
			}
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probPos[whichChain*2 + whichState];
			k++;
			}
		}
	else
		{
		for (i=0; i<nStates; i++)
			bs[i] = baseFreq[index + i];
		}

	/* how many different omega categories */
	if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		nOmegaCats = 3;
	else
		nOmegaCats = 1;

	/* allocate memory for transition probabilities along a single branch */
	probs = psdmatrix (lnStates);

	/* allocate memory for eigenvalues and eigenvectors */
	q = psdmatrix (lnStates);
	eigenValues = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + lnStates;
	c_ijk = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
	if (!c_ijk)
		{
		printf ("\n   ERROR: Problem allocating c_ijk.\n");
		goto error_exit;
		}
	eigvecs = psdmatrix (lnStates);
	inverseEigvecs = psdmatrix (lnStates);
	Ceigvecs = pscmatrix (lnStates);
	CinverseEigvecs = pscmatrix (lnStates);

	/* get eigenvalues and eigenvectors for covarion matrices */
	nForOneState = numNodes*nodeTiSize;
	index1 = whichChain*2*nForOneState + whichState*nForOneState;

	/* always calculate at least one transition matrix */
	if (!strcmp(codonModelType, "covny98"))
		{
		if (SetCodonSwitchQMatrix (q, whichState, whichChain, omega[whichChain*2 + whichState], kappa[whichChain*2 + whichState], switchRate[whichChain*4 + whichState*2 + 0]) == ERROR)
			goto error_exit;
		}
	else
		{
		if (SetCodonQMatrix (q, whichState, whichChain, omega[whichChain*2 + whichState], kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		}
	isComplex = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
	if (isComplex == NO)
		{
		CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
		}
	for (n=allNodesPointer; n<allNodesStop; n++)
		{
		p = allNodesDownPassSeq[n];
		if (p->anc != NULL)
			{
			if ((p->anc->anc != NULL || (p->anc->anc == NULL && treeModel == UNROOTED)) && p->upDateTi == YES)
				{
				ptr = transitionProbs + (index1 + (p->index)*nodeTiSize);
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->length, 1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				index = 0;
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						ptr[index++] = probs[i][j];
				}
			}
		}

	/* here if Nielsen and Yang like model is used */
	if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		/* strong purifying selection */
		if (SetCodonQMatrix (q, whichState, whichChain, 0.0, kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		isComplex = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
		if (isComplex == NO)
			{
			CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
			}
		for (n=allNodesPointer; n<allNodesStop; n++)
			{
			p = allNodesDownPassSeq[n];
			if (p->anc != NULL)
				{
				if ((p->anc->anc != NULL || (p->anc->anc == NULL && treeModel == UNROOTED)) && p->upDateTi == YES)
					{
					ptr = transitionProbs + (index1 + (p->index)*nodeTiSize + lnStatesSquared);
					if (isComplex == NO)
						CalcPij (c_ijk, lnStates, eigenValues, p->length, 1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, 1.0) == ERROR) 
							{
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
							goto error_exit;
							}
					index = 0;
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							ptr[index++] = probs[i][j];
					}
				}
			}
		
		/* neutral class */
		if (SetCodonQMatrix (q, whichState, whichChain, 1.0, kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		isComplex = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
		if (isComplex == NO)
			{
			CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
			}
		for (n=allNodesPointer; n<allNodesStop; n++)
			{
			p = allNodesDownPassSeq[n];
			if (p->anc != NULL)
				{
				if ((p->anc->anc != NULL || (p->anc->anc == NULL && treeModel == UNROOTED)) && p->upDateTi == YES)
					{
					ptr = transitionProbs + (index1 + (p->index)*nodeTiSize + 2*lnStatesSquared);
					if (isComplex == NO)
						CalcPij (c_ijk, lnStates, eigenValues, p->length, 1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, 1.0) == ERROR) 
							{
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
							goto error_exit;
							}
					index = 0;
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							ptr[index++] = probs[i][j];
					}
				}
			}
		}		
		
	/* update flags */
	for (n=allNodesPointer; n<allNodesStop; n++)
		{
		p = allNodesDownPassSeq[n];
		updateTiFlag[p->index] = NO;
		if (p->anc != NULL)
			{
			if ((p->anc->anc != NULL || (p->anc->anc == NULL && treeModel == UNROOTED)) && p->upDateTi == YES)
				{
				p->upDateTi = NO;
				updateTiFlag[p->index] = YES;
				}
			}
		}

	/* free memory */
	free (bs);
	free_psdmatrix (probs);
	free_psdmatrix (q);
	free (eigenValues);
	free (c_ijk);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	return (NO_ERROR);
	
	error_exit:
		return (ERROR);

}





int CalcTransCovarion (int whichState, int whichChain, int numRateCats)

{

	register int		i, j, k, m, b, index;
	int					n, lnStates, lnStatesSquared, lnStatesCube, nRates, lnPartitions, lnumRateCats, isComplex,
						allNodesPointer, allNodesStop, nForOneState, index1, index2;
	double				**probs, *catFreq, *catRate, *partRate,
						**q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk,
						correlation, **markovTi, *bs, *ptr, s01, s10, prob0, prob1;
	complex 			**Ceigvecs, **CinverseEigvecs;	
	TreeNode			*p;

	allNodesPointer = whichChain*2*numNodes + whichState*numNodes;
	allNodesStop = allNodesPointer + numNodes;

	/* twice nStates because matrix is doubled */
	lnStates = 2 * nStates;
	lnStatesSquared = lnStates * lnStates;
	lnStatesCube = lnStates * lnStatesSquared;
	
	/* load base frequencies */
	index = whichChain*2*lnStates + whichState*lnStates;
	index1 = whichChain*4 + whichState*2;
	index2 = whichChain*2 + whichState;
	bs = (double *)malloc((size_t) (lnStates * sizeof(double)));
	if (!bs)
		{
		printf ("\n   ERROR: Problem allocating bs.\n");
		goto error_exit;
		}
	if (!strcmp(covarionModelType, "ts98"))
		{
		k = 0;
		for (j=0; j<2; j++)
			{
			for (i=0; i<nStates; i++)
				{
				bs[k] = baseFreq[whichChain*2*nStates + whichState*nStates + i] * switchPi[whichChain*4 + whichState*2 + j];
				k++;
				}
			}
		}
	else if (!strcmp(covarionModelType, "gcswitch"))
		{
		s01 = switchRate[index1 + 0];
		s10 = switchRate[index1 + 1];
		prob0 = s10 / (s01+s10);
		prob1 = s01 / (s01+s10);
		bs[0] = (1.0 - gc1[index2]) * (fracA[index2])       * prob0;
		bs[1] = (gc1[index2])       * (1.0 - fracG[index2]) * prob0;
		bs[2] = (gc1[index2])       * (fracG[index2])       * prob0;
		bs[3] = (1.0 - gc1[index2]) * (1.0 - fracA[index2]) * prob0;
		bs[4] = (1.0 - gc2[index2]) * (fracA[index2])       * prob1;
		bs[5] = (gc2[index2])       * (1.0 - fracG[index2]) * prob1;
		bs[6] = (gc2[index2])       * (fracG[index2])       * prob1;
		bs[7] = (1.0 - gc2[index2]) * (1.0 - fracA[index2]) * prob1;
		}

	/* how many different rates? */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;
	nRates = lnPartitions * lnumRateCats;

	/* allocate memory for transition probabilities along a single branch */
	probs = psdmatrix (lnStates);

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* fill in rate categories with frequencies and rates by dividing the */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* allocate memory for eigenvalues and eigenvectors */
	q = psdmatrix (lnStates);
	eigenValues = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + lnStates;
	c_ijk = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
	if (!c_ijk)
		{
		printf ("\n   ERROR: Problem allocating c_ijk.\n");
		goto error_exit;
		}
	eigvecs = psdmatrix (lnStates);
	inverseEigvecs = psdmatrix (lnStates);
	Ceigvecs = pscmatrix (lnStates);
	CinverseEigvecs = pscmatrix (lnStates);

	/* get eigenvalues and eigenvectors for covarion matrices */
	nForOneState = numNodes*nodeTiSize;
	for (m=b=0; m<lnPartitions; m++)
		{
		for (k=0; k<lnumRateCats; k++)
			{
			if (dataType == DNA || dataType == RNA)
				{
				if (!strcmp(covarionModelType, "ts98"))
					{
					if (SetDNACovQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
						goto error_exit;
					}
				else if (!strcmp(covarionModelType, "gcswitch"))
					{
					if (SetGCSwitchQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
						goto error_exit;
					}
				else
					{
					goto error_exit;
					}
				}
			else
				{
				if (SetAACovQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
					goto error_exit;
				}
			isComplex = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
			if (isComplex == NO)
				{
				CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
				}
				
			index1 = whichChain*2*nForOneState + whichState*nForOneState;
			for (n=allNodesPointer; n<allNodesStop; n++)
				{
				p = allNodesDownPassSeq[n];
				if (p->anc != NULL)
					{
					if ((p->anc->anc != NULL || (p->anc->anc == NULL && treeModel == UNROOTED)) && p->upDateTi == YES)
						{
						ptr = transitionProbs + (index1 + (p->index)*nodeTiSize + b*lnStatesSquared);
						if (isComplex == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						index = 0;
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								ptr[index++] = probs[i][j];
						}
					}
				}
			b++;
			}
		}
		
	/* update flags */
	for (n=allNodesPointer; n<allNodesStop; n++)
		{
		p = allNodesDownPassSeq[n];
		updateTiFlag[p->index] = NO;
		if (p->anc != NULL)
			{
			if ((p->anc->anc != NULL || (p->anc->anc == NULL && treeModel == UNROOTED)) && p->upDateTi == YES)
				{
				p->upDateTi = NO;
				updateTiFlag[p->index] = YES;
				}
			}
		}


	/* free memory */
	free (bs);
	free (catFreq);
	free_psdmatrix (probs);
	free_psdmatrix (q);
	free (eigenValues);
	free (c_ijk);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		free_psdmatrix(markovTi);
	return (NO_ERROR);
	
	error_exit:
		return (ERROR);

}





int CalcTransDNA (int whichState, int whichChain, int numRateCats)

{

	register int		i, j, k, m, index;
	int					n, lnStates, lnStatesCubed, nRates, lnPartitions, lnumRateCats, isComplex,
						allNodesPointer, allNodesStop, nForOneState;
	double				**probs, *catFreq, *catRate, *partRate, lkappa,
						**q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk,
						correlation, **markovTi, theRate, bs[4], *ptr;
	complex 			**Ceigvecs, **CinverseEigvecs;	
	TreeNode			*p;

	allNodesPointer = whichChain*2*numNodes + whichState*numNodes;
	allNodesStop = allNodesPointer + numNodes;
	
	/* standard 4 X 4 model of DNA substitution ***************************************************************************/
	lnStates = 4;
	lnStatesCubed = 64;

	/* base frequencies */
	index = whichChain*2*nStates + whichState*nStates;
	bs[A] = baseFreq[index + A];
	bs[C] = baseFreq[index + C];
	bs[G] = baseFreq[index + G];
	bs[T] = baseFreq[index + T];

	/* allocate memory for transition probabilities along a single branch */
	probs = psdmatrix (lnStates);
	
	/* find kappa if nst == 1 or nst == 2 */
	if (nst == 1)
		lkappa = 1.0;
	else if (nst == 2)
		lkappa = kappa[whichChain*2 + whichState];
		
	/* get eigenvalues and eigenvectors if nst=6 or nst=12 */
	if (nst == 6 || nst == 12)
		{
		q = psdmatrix (lnStates);
		eigenValues = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
		if (!eigenValues)
			{
			printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
			goto error_exit;
			}
		eigvalsImag = eigenValues + lnStates;
		eigvecs = psdmatrix (lnStates);
		inverseEigvecs = psdmatrix (lnStates);
		Ceigvecs = pscmatrix (lnStates);
		CinverseEigvecs = pscmatrix (lnStates);
		if (SetQMatrix (q, whichState, whichChain) == ERROR)
			goto error_exit;
		isComplex = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
		if (isComplex == NO)
			{
			c_ijk = (double *)malloc((size_t) (lnStatesCubed * sizeof(double)));
			if (!c_ijk)
				{
				printf ("\n   ERROR: Problem allocating c_ijk.\n");
				goto error_exit;
				}
			CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
			}
		}
		
	/* how many rates are there? */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;
	nRates = lnPartitions * lnumRateCats;
	
	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate  = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;
	
	/* fill in rate categories with frequencies and rates by dividing the */
	if (!strcmp(ratesModel,"gamma") || !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* calculate transtition probabilities */
	nForOneState = numNodes*nodeTiSize;
	for (n=allNodesPointer; n<allNodesStop; n++)
		{
		p = allNodesDownPassSeq[n];
		updateTiFlag[p->index] = NO;
		if (p->anc != NULL)
			{
			if ((p->anc->anc != NULL || (p->anc->anc == NULL && treeModel == UNROOTED)) && p->upDateTi == YES)
				{
				//printf (" updating %d\n", p->index);
				p->upDateTi = NO;
				updateTiFlag[p->index] = YES;
				ptr = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
				if (nst == 1 || nst == 2)
					{
					for (m=index=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							/* calculate transition probabilities for left branch */
							HkyChangeMat (probs, p->length, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<lnStates; i++)
								for (j=0; j<lnStates; j++)
									ptr[index++] = probs[i][j];
							}
						}
					}
				else // nst == 6 or nst == 12
					{
					for (m=index=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for left branch
							if (isComplex == NO)
								CalcPij (c_ijk, lnStates, eigenValues, p->length, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<lnStates; i++)
								for (j=0; j<lnStates; j++)
									ptr[index++] = probs[i][j];
							}
						}
					}
				}
			}
		}
		
	/* free memory */
	free_psdmatrix (probs);
	free (catFreq);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		free_psdmatrix(markovTi);
	if (nst == 6 || nst == 12)
		{
		free_psdmatrix (q);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex != YES)
			free (c_ijk);
		}
	return (NO_ERROR);
	
	error_exit:
		return (ERROR);
	
}

#endif


int CheckConstraints (void)

{

	int				i, j, k, x, y, consAreConsistent, n1, n2, iCon, jCon,
					foundLft, foundRht, nLftOverlap, nRhtOverlap, nBothOverlap;
	unsigned int	lftPart, rhtPart, conNde;
	
	consAreConsistent = YES;
	n1 = nConstraints;
	n2 = nCalibrations;
	
	if (enforceConstraints == YES && enforceCalibrations == YES)
		{
		for (i=0; i<n1+n2-1; i++)
			{
			if (i < n1)
				{
				x = i;
				iCon = YES;
				}
			else
				{
				x = i - n1;
				iCon = NO;
				}
			for (j=i+1; j<n1+n2; j++)
				{
				if (j < n1)
					{
					y = j;
					jCon = YES;
					}
				else
					{
					y = j - n1;
					jCon = NO;
					}
					
				//printf ("Comparing %d (%d) to %d (%d)\n", x, iCon, y, jCon);
				nBothOverlap = nLftOverlap = nRhtOverlap = 0;
				for (k=0; k<nTaxa; k++)
					{
					if (excludedTaxa[k] == NO)
						{
						if (iCon == YES)
							lftPart = constraints[k];
						else
							lftPart = calibrations[k];
						if (jCon == YES)
							rhtPart = constraints[k];
						else
							rhtPart = calibrations[k];
						conNde = lftPart & (unsigned int)pow(2.0, (double)x);
						if (conNde > 0)
							foundLft = YES;
						else
							foundLft = NO;
						conNde = rhtPart & (unsigned int)pow(2.0, (double)y);
						if (conNde > 0)
							foundRht = YES;
						else
							foundRht = NO;
						if (foundLft == YES && foundRht == YES)
							nBothOverlap++;
						if (foundLft == YES && foundRht == NO)
							nRhtOverlap++;
						else if (foundLft == NO && foundRht == YES)
							nLftOverlap++;
						}
					}
				//printf ("   nlftover = %d nrhtover = %d\n", nLftOverlap, nRhtOverlap);
				if (nBothOverlap > 0 && nLftOverlap > 0 && nRhtOverlap > 0)
					{
					consAreConsistent = NO;
					return (consAreConsistent);
					}


				}
			}
		}
	else if (enforceConstraints == YES && enforceCalibrations == NO)
		{
		for (i=0; i<n1-1; i++)
			{
			x = i;
			for (j=i+1; j<n1; j++)
				{
				y = j;
					
				//printf ("Comparing %d (%d) to %d (%d)\n", x, iCon, y, jCon);
				nBothOverlap = nLftOverlap = nRhtOverlap = 0;
				for (k=0; k<nTaxa; k++)
					{
					if (excludedTaxa[k] == NO)
						{
						lftPart = constraints[k];
						rhtPart = constraints[k];
						conNde = lftPart & (unsigned int)pow(2.0, (double)x);
						if (conNde > 0)
							foundLft = YES;
						else
							foundLft = NO;
						conNde = rhtPart & (unsigned int)pow(2.0, (double)y);
						if (conNde > 0)
							foundRht = YES;
						else
							foundRht = NO;
						if (foundLft == YES && foundRht == YES)
							nBothOverlap++;
						if (foundLft == YES && foundRht == NO)
							nRhtOverlap++;
						else if (foundLft == NO && foundRht == YES)
							nLftOverlap++;
						}
					}
				//printf ("   nlftover = %d nrhtover = %d\n", nLftOverlap, nRhtOverlap);
				if (nBothOverlap > 0 && nLftOverlap > 0 && nRhtOverlap > 0)
					{
					consAreConsistent = NO;
					return (consAreConsistent);
					}
				}
			}
		}
	else if (enforceConstraints == NO && enforceCalibrations == YES)
		{
		for (i=0; i<n1-1; i++)
			{
			x = i;
			for (j=i+1; j<n1; j++)
				{
				y = j;
					
				//printf ("Comparing %d (%d) to %d (%d)\n", x, iCon, y, jCon);
				nBothOverlap = nLftOverlap = nRhtOverlap = 0;
				for (k=0; k<nTaxa; k++)
					{
					if (excludedTaxa[k] == NO)
						{
						lftPart = calibrations[k];
						rhtPart = calibrations[k];
						conNde = lftPart & (unsigned int)pow(2.0, (double)x);
						if (conNde > 0)
							foundLft = YES;
						else
							foundLft = NO;
						conNde = rhtPart & (unsigned int)pow(2.0, (double)y);
						if (conNde > 0)
							foundRht = YES;
						else
							foundRht = NO;
						if (foundLft == YES && foundRht == YES)
							nBothOverlap++;
						if (foundLft == YES && foundRht == NO)
							nRhtOverlap++;
						else if (foundLft == NO && foundRht == YES)
							nLftOverlap++;
						}
					}
				//printf ("   nlftover = %d nrhtover = %d\n", nLftOverlap, nRhtOverlap);
				if (nBothOverlap > 0 && nLftOverlap > 0 && nRhtOverlap > 0)
					{
					consAreConsistent = NO;
					return (consAreConsistent);
					}
				}
			}
		}
	
	return (consAreConsistent);
	
}





int ComplexChangeMatrix (double *eigenValues, double *eigvalsImag, complex **Ceigvecs, complex **CinverseEigvecs, int n, double **p, double t, double r)

{

	int			i, j, k, rc;
	complex		**Cwork;

	rc = NO_ERROR;
	Cwork = pscmatrix(n);
	for(i=0; i<n; i++)
		{
		for(j=0; j<n; j++)
			{
			Cwork[i][j].re = 0.0;
			Cwork[i][j].im = 0.0;
			for(k = 0; k < n; k++)
				{
				Cwork[i][j] = Cadd(Cwork[i][j], Cmul(Ceigvecs[i][k], Cmul(CinverseEigvecs[k][j], Cexp(RCmul(t*r, Complex(eigenValues[k], eigvalsImag[k]))))));
				}
			}
		}
	for(i=0; i<n; i++)
		{
		for(j=0; j<n; j++)
			{
			p[i][j] = Cwork[i][j].re;
			if (p[i][j] < 0.0)
				p[i][j] = 0.0;
			if(fabs(Cwork[i][j].im) > 0.1)
				{
				printf ("i = %lf\n", Cwork[i][j].im);
	    		rc = ERROR;
				}
			}
		}
	free_pscmatrix (Cwork);
	return (rc);

}





int ComplexDerivativesMatrix (double *eigenValues, double *eigvalsImag, complex **Ceigvecs, complex **CinverseEigvecs, int n, double **f, double **s, double t, double r)

{

	int			i, j, k, rc;
	complex		ceval, **Cwork1, **Cwork2, rate;

	rc = NO_ERROR;
	rate.re = r;
	rate.im = 0.0;
	Cwork1 = pscmatrix(n);
	Cwork2 = pscmatrix(n);
	for(i=0; i<n; i++)
		{
		for(j=0; j<n; j++)
			{
			Cwork1[i][j].re = Cwork2[i][j].re = 0.0;
			Cwork1[i][j].im = Cwork2[i][j].im = 0.0;
			for(k = 0; k < n; k++)
				{
				ceval = Complex(eigenValues[k], eigvalsImag[k]);
				Cwork1[i][j] = Cadd(Cwork1[i][j], Cmul(rate, Cmul(Ceigvecs[i][k], Cmul(CinverseEigvecs[k][j], Cmul(ceval, Cexp(RCmul(t * r, ceval)))))));
				Cwork2[i][j] = Cadd(Cwork2[i][j], Cmul(rate, Cmul(rate, Cmul(Ceigvecs[i][k], Cmul(CinverseEigvecs[k][j], Cmul(ceval, Cmul(ceval, Cexp(RCmul(t * r, ceval)))))))));
				}
			}
		}
	for(i=0; i<n; i++)
		{
		for(j=0; j<n; j++)
			{
			f[i][j] = Cwork1[i][j].re;
			s[i][j] = Cwork2[i][j].re;
			if(fabs(Cwork1[i][j].im) > 0.000000000001 || fabs(Cwork2[i][j].im) > 0.000000000001)
				{
	    		rc = ERROR;
				}
			}
		}
	free_pscmatrix (Cwork1);
	free_pscmatrix (Cwork2);
	return (rc);

}





int CompressMatrix (int *numTaxa, int *numChars)

{

	int			i, j, k, *numOfThisPat, isSame, nPat, nt, siteNum, taxNum, *tempMatrix, *tempNumSitePats, *tempPartId, nOnes, nTwos;

#if defined (MORPH)
	int			index;
#endif

	nExcluded = 0;
	for (i=0; i<nChar; i++)
		if (excludedSites[i] == YES)
			nExcluded++;
			
	numDummyChars = 0;

	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		printf ("      Compressing codon matrix\n");
		/* 61 X 61 substitution model */
		if (nChar % 3 != 0)
			{
			printf ("\n   ERROR: Number of sites in data matrix must be divisable\n");
			printf ("          by 3 for codon models.\n");
			FreeMemory ();
			return (ERROR);
			}
		patternId = (int *)malloc((size_t) ((nChar / 3) * sizeof(int)));
		if (!patternId)
			{
			printf ("ERROR: Problem allocating patternId\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PAT_IDS] = YES;
		for (i=0; i<nChar/3; i++)
			patternId[i] = -1;
		numOfThisPat = (int *)malloc((size_t) ((nChar / 3) * sizeof(int)));
		if (!numOfThisPat)
			{
			printf ("\n   ERROR: Problem allocating numOfThisPat.\n");
			FreeMemory ();
			return (ERROR);
			}
		for (i=0; i<nChar/3; i++)
			{
			if (excludedSites[i*3] == YES || excludedSites[i*3+1] == YES || excludedSites[i*3+2] == YES)
				numOfThisPat[i] = 0;
			else
				numOfThisPat[i] = 1;
			}
		siteNum = 0;
		for (i=0; i<(nChar/3)-1; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				patternId[i] = siteNum;
				for (j=i+1; j<(nChar/3); j++)
					{
					if (numOfThisPat[j] > 0)
						{
						isSame = YES;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i*3]   != origDataMatrix[k*nChar+j*3])
								isSame = NO;
							if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i*3+1] != origDataMatrix[k*nChar+j*3+1])
								isSame = NO;
							if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i*3+2] != origDataMatrix[k*nChar+j*3+2])
								isSame = NO;
							}
						if (isSame == YES)
							{
							numOfThisPat[i]++;
							numOfThisPat[j] = 0;
							patternId[j] = patternId[i] = siteNum;
							}
						}
					}
				siteNum++;
				}
			}	
		if (patternId[nChar/3 - 1] == -1)
			patternId[nChar/3 - 1] = siteNum++;
#		if 0
		k = 0;
		for (i=0; i<nChar/3; i++)
			{
			k++;
			printf ("%4d -- ", k);
			for (j=0; j<nTaxa; j++)
				{
				printf ("%2d ", origDataMatrix[j*nChar + i*3]);
				printf ("%2d ", origDataMatrix[j*nChar + i*3+1]);
				printf ("%2d ", origDataMatrix[j*nChar + i*3+2]);
				}
			printf (" -- %d %d\n", patternId[i], numOfThisPat[i]);
			}
#		endif
		nPat = 0;
		for (i=0; i<nChar/3; i++)
			{
			if (numOfThisPat[i] > 0)
				nPat++;
			}
		nt = 0;
		for (j=0; j<nTaxa; j++)
			{
			if (excludedTaxa[j] == NO)
				nt++;
			}
		printf ("         Data matrix has %d taxa and %d site patterns\n", nt, nPat);
		(*numTaxa) = nt;
		(*numChars) = nPat;
		matrix = (int *)malloc((size_t) (nt * nPat * 3 * sizeof(int)));
		if (!matrix)
			{
			printf ("\n   ERROR: Problem allocating matrix.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_MATRIX] = YES;
		numSitesOfPat = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!numSitesOfPat)
			{
			printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_N_SITE_PATS] = YES;
		partitionId = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!partitionId)
			{
			printf ("\n   ERROR: Problem allocating partitionId.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PART_ID] = YES;
		for (i=0; i<nPat; i++)
			partitionId[i] = 0;
		siteNum = 0;
		for (i=0; i<nChar/3; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				numSitesOfPat[siteNum] = numOfThisPat[i];
				taxNum = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (excludedTaxa[j] == NO)
						{
						matrix[pos(taxNum,siteNum*3,  (*numChars)*3)] = origDataMatrix[j*nChar+i*3];
						matrix[pos(taxNum,siteNum*3+1,(*numChars)*3)] = origDataMatrix[j*nChar+i*3+1];
						matrix[pos(taxNum,siteNum*3+2,(*numChars)*3)] = origDataMatrix[j*nChar+i*3+2];
						taxNum++;
						}
					}
				siteNum++;
				}
			}	
		free (numOfThisPat);
#		if 0
		for (i=0; i<(*numChars); i++)
			{
			printf ("%4d -- ", i+1);
			for (j=0; j<(*numTaxa); j++)
				{
				printf ("%2d ", matrix[pos(j,i*3,  (*numChars)*3)]);
				printf ("%2d ", matrix[pos(j,i*3+1,(*numChars)*3)]);
				printf ("%2d ", matrix[pos(j,i*3+2,(*numChars)*3)]);
				}
			printf ("-- %3d %3d\n", numSitesOfPat[i], partitionId[i]);
			}
#		endif
		}
	else if (((dataType == DNA || dataType == RNA) && enforceCodonModel == NO) || dataType == PROTEIN)
		{
		printf ("      Compressing data matrix\n");
		/* 4 X 4 or 20 X 20 substitution model */
		patternId = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!patternId)
			{
			printf ("ERROR: Problem allocating patternId\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PAT_IDS] = YES;
		for (i=0; i<nChar; i++)
			patternId[i] = -1;

		if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			/* compress for site-specific rates */
			numOfThisPat = (int *)malloc((size_t) (nChar * sizeof(int)));
			if (!numOfThisPat)
				{
				printf ("\n   ERROR: Problem allocating numOfThisPat.\n");
				FreeMemory ();
				return (ERROR);
				}
			for (i=0; i<nChar; i++)
				{
				if (excludedSites[i] == YES)
					numOfThisPat[i] = 0;
				else
					numOfThisPat[i] = 1;
				}
			siteNum = 0;
			for (i=0; i<nChar-1; i++)
				{
				if (numOfThisPat[i] > 0)
					{
					patternId[i] = siteNum;
					for (j=i+1; j<nChar; j++)
						{
						if (numOfThisPat[j] > 0)
							{
							isSame = YES;
							for (k=0; k<nTaxa; k++)
								{
								if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i] != origDataMatrix[k*nChar+j])
									{
									isSame = NO;
									}
								}
							if (isSame == YES && sitePartitions[i] == sitePartitions[j])
								{
								numOfThisPat[i]++;
								numOfThisPat[j] = 0;
								patternId[j] = siteNum;
								}
							}
						}
					siteNum++;
					}
				}		
			if (patternId[nChar - 1] == -1)
				patternId[nChar - 1] = siteNum++;
			nPat = 0;
			for (i=0; i<nChar; i++)
				{
				if (numOfThisPat[i] > 0)
					nPat++;
				}
			nt = 0;
			for (j=0; j<nTaxa; j++)
				{
				if (excludedTaxa[j] == NO)
					nt++;
				}
			printf ("         Data matrix has %d taxa and %d site patterns\n", nt, nPat);
			(*numTaxa) = nt;
			(*numChars) = nPat;
			matrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
			if (!matrix)
				{
				printf ("\n   ERROR: Problem allocating matrix.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_MATRIX] = YES;
			numSitesOfPat = (int *)malloc((size_t) (nPat * sizeof(int)));
			if (!numSitesOfPat)
				{
				printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_N_SITE_PATS] = YES;
			partitionId = (int *)malloc((size_t) (nPat * sizeof(int)));
			if (!partitionId)
				{
				printf ("\n   ERROR: Problem allocating partitionId.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_PART_ID] = YES;
				
			siteNum = 0;
			for (i=0; i<nChar; i++)
				{
				if (numOfThisPat[i] > 0)
					{
					patternId[i] = siteNum;
					taxNum = 0;
					for (j=0; j<nTaxa; j++)
						{
						if (excludedTaxa[j] == NO)
							{
							matrix[pos(taxNum,siteNum,(*numChars))] = origDataMatrix[j*nChar+i];
							taxNum++;
							}
						}
					numSitesOfPat[siteNum] = numOfThisPat[i];
					partitionId[siteNum] = sitePartitions[i] - 1;
					if (sitePartitions[i] - 1 < 0 && sitePartitions[i] >= nPartitions)
						{
						printf ("\n   ERROR: Invalid partition ID.\n");
						free (numOfThisPat);
						FreeMemory ();
						return (ERROR);
						}
					siteNum++;
					}
				}			
			free (numOfThisPat);
			}
		else
			{
			/* compress for other types of rate models */
			numOfThisPat = (int *)malloc((size_t) (nChar * sizeof(int)));
			if (!numOfThisPat)
				{
				printf ("\n   ERROR: Problem allocating numOfThisPat.\n");
				FreeMemory ();
				return (ERROR);
				}
			for (i=0; i<nChar; i++)
				{
				if (excludedSites[i] == YES)
					numOfThisPat[i] = 0;
				else
					numOfThisPat[i] = 1;
				}
			siteNum = 0;
			for (i=0; i<nChar-1; i++)
				{
				if (numOfThisPat[i] > 0)
					{
					patternId[i] = siteNum;
					for (j=i+1; j<nChar; j++)
						{
						if (numOfThisPat[j] > 0)
							{
							isSame = YES;
							for (k=0; k<nTaxa; k++)
								{
								if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i] != origDataMatrix[k*nChar+j])
									{
									isSame = NO;
									}
								}
							if (isSame == YES)
								{
								numOfThisPat[i]++;
								numOfThisPat[j] = 0;
								patternId[j] = patternId[i] = siteNum;
								}
							}
						}
					siteNum++;
					}
				}		
			if (patternId[nChar - 1] == -1)
				patternId[nChar - 1] = siteNum++;
			nPat = 0;
			for (i=0; i<nChar; i++)
				{
				if (numOfThisPat[i] > 0)
					nPat++;
				}
			nt = 0;
			for (j=0; j<nTaxa; j++)
				{
				if (excludedTaxa[j] == NO)
					nt++;
				}
			printf ("         Data matrix has %d taxa and %d site patterns\n", nt, nPat);
			(*numTaxa) = nt;
			(*numChars) = nPat;
			matrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
			if (!matrix)
				{
				printf ("\n   ERROR: Problem allocating matrix.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_MATRIX] = YES;
			numSitesOfPat = (int *)malloc((size_t) (nPat * sizeof(int)));
			if (!numSitesOfPat)
				{
				printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_N_SITE_PATS] = YES;
			partitionId = (int *)malloc((size_t) (nPat * sizeof(int)));
			if (!partitionId)
				{
				printf ("\n   ERROR: Problem allocating partitionId.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_PART_ID] = YES;
			siteNum = 0;
			for (i=0; i<nChar; i++)
				{
				if (numOfThisPat[i] > 0)
					{
					taxNum = 0;
					for (j=0; j<nTaxa; j++)
						{
						if (excludedTaxa[j] == NO)
							{
							matrix[pos(taxNum,siteNum,(*numChars))] = origDataMatrix[j*nChar+i];
							taxNum++;
							}
						}
					numSitesOfPat[siteNum] = numOfThisPat[i];
					partitionId[siteNum] = 0;
					siteNum++;
					}
				}			
			free (numOfThisPat);
			}

#		if 0
		for (i=0; i<(*numChars); i++)
			{
			printf ("%4d -- ", i+1);
			for (j=0; j<(*numTaxa); j++)
				{
				printf ("%2d ", matrix[pos(j,i,(*numChars))]);
				}
			printf ("-- %3d %3d\n", numSitesOfPat[i], partitionId[i]);
			}
#		endif
		}
	else if (dataType == RESTRICTION)
		{
		printf ("      Compressing data matrix\n");
		/* 2 X 2 substitution model */
		patternId = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!patternId)
			{
			printf ("ERROR: Problem allocating patternId\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PAT_IDS] = YES;
		for (i=0; i<nChar; i++)
			patternId[i] = -1;

		numOfThisPat = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!numOfThisPat)
			{
			printf ("\n   ERROR: Problem allocating numOfThisPat.\n");
			FreeMemory ();
			return (ERROR);
			}
		for (i=0; i<nChar; i++)
			{
			if (excludedSites[i] == YES)
				numOfThisPat[i] = 0;
			else
				numOfThisPat[i] = 1;
			}
		siteNum = 0;
		for (i=0; i<nChar-1; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				patternId[i] = siteNum;
				for (j=i+1; j<nChar; j++)
					{
					if (numOfThisPat[j] > 0)
						{
						isSame = YES;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i] != origDataMatrix[k*nChar+j])
								{
								isSame = NO;
								}
							}
						if (isSame == YES)
							{
							numOfThisPat[i]++;
							numOfThisPat[j] = 0;
							patternId[j] = patternId[i] = siteNum;
							}
						}
					}
				siteNum++;
				}
			}		
		if (patternId[nChar - 1] == -1)
			patternId[nChar - 1] = siteNum++;
		nPat = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				nPat++;
			}
		nt = 0;
		for (j=0; j<nTaxa; j++)
			{
			if (excludedTaxa[j] == NO)
				nt++;
			}
		printf ("         Data matrix has %d taxa and %d site patterns\n", nt, nPat);
		(*numTaxa) = nt;
		(*numChars) = nPat;
		matrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
		if (!matrix)
			{
			printf ("\n   ERROR: Problem allocating matrix.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_MATRIX] = YES;
		numSitesOfPat = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!numSitesOfPat)
			{
			printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_N_SITE_PATS] = YES;
		partitionId = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!partitionId)
			{
			printf ("\n   ERROR: Problem allocating partitionId.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PART_ID] = YES;
		siteNum = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				taxNum = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (excludedTaxa[j] == NO)
						{
						matrix[pos(taxNum,siteNum,(*numChars))] = origDataMatrix[j*nChar+i];
						taxNum++;
						}
					}
				numSitesOfPat[siteNum] = numOfThisPat[i];
				partitionId[siteNum] = 0;
				siteNum++;
				}
			}	
		if (!strcmp(codingType, "variable") || !strcmp(codingType, "noabsence") || !strcmp(codingType, "nopresence"))
			{
			printf ("         Adding dummy %s character(s)\n", codingType);
			tempMatrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
			if (!tempMatrix)
				{
				printf ("\n   ERROR: Problem allocating tempMatrix.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			tempNumSitePats = (int *)malloc((size_t) (nPat * sizeof(int)));
			if (!tempNumSitePats)
				{
				printf ("\n   ERROR: Problem allocating tempNumSitePats.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			tempPartId = (int *)malloc((size_t) (nPat * sizeof(int)));
			if (!tempPartId)
				{
				printf ("\n   ERROR: Problem allocating tempPartId.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			for (i=0; i<nPat; i++)
				{
				for (j=0; j<nTaxa; j++)
					{
					tempMatrix[pos(j,i,(*numChars))] = matrix[pos(j,i,(*numChars))];
					}
				tempNumSitePats[i] = numSitesOfPat[i];
				tempPartId[i] = partitionId[i];
				}	
			free (matrix);
			free (numSitesOfPat);
			free (partitionId);
			allocatedMemory[ALLOC_MATRIX] = NO;
			allocatedMemory[ALLOC_N_SITE_PATS] = NO;
			allocatedMemory[ALLOC_PART_ID] = NO;
			
			if (!strcmp(codingType, "variable"))
				numDummyChars = 2;
			else if (!strcmp(codingType, "noabsence") || !strcmp(codingType, "nopresence"))
				numDummyChars = 1;

			matrix = (int *)malloc((size_t) (nt * (nPat+numDummyChars) * sizeof(int)));
			if (!matrix)
				{
				printf ("\n   ERROR: Problem allocating matrix.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_MATRIX] = YES;
			numSitesOfPat = (int *)malloc((size_t) ((nPat+numDummyChars) * sizeof(int)));
			if (!numSitesOfPat)
				{
				printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_N_SITE_PATS] = YES;
			partitionId = (int *)malloc((size_t) ((nPat+numDummyChars) * sizeof(int)));
			if (!partitionId)
				{
				printf ("\n   ERROR: Problem allocating partitionId.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_PART_ID] = YES;
				
			for (i=0; i<nPat; i++)
				{
				for (j=0; j<nTaxa; j++)
					{
					matrix[pos(j,i+numDummyChars,(*numChars)+numDummyChars)] = tempMatrix[pos(j,i,(*numChars))];
					}
				numSitesOfPat[i+numDummyChars] = tempNumSitePats[i];
				partitionId[i+numDummyChars] = tempPartId[i];
				}	
			
			nPat += numDummyChars;
			(*numChars) = nPat;
			
			if (!strcmp(codingType, "variable"))
				{
				numSitesOfPat[0] = 0;
				partitionId[0] = 0;
				numSitesOfPat[1] = 0;
				partitionId[1] = 0;
				for (j=0; j<nTaxa; j++)
					{
					matrix[pos(j,0,(*numChars))] = 1;
					matrix[pos(j,1,(*numChars))] = 2;
					}
				}
			else
				{
				numSitesOfPat[0] = 0;
				partitionId[0] = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (!strcmp(codingType, "noabsence"))
						matrix[pos(j,0,(*numChars))] = 1;
					else if (!strcmp(codingType, "nopresence"))
						matrix[pos(j,0,(*numChars))] = 2;
					}
				}

			free (tempMatrix);
			free (tempNumSitePats);
			free (tempPartId);

			
			/* check to see if the dummy characters are present elsewhere */
			for (i=numDummyChars; i<nPat; i++)
				{
				nOnes = nTwos = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (matrix[pos(j,i,(*numChars))] == 1)
						nOnes++;
					else if (matrix[pos(j,i,(*numChars))] == 2)
						nTwos++;
					}
				if (nOnes == nTaxa && (!strcmp(codingType, "variable") || !strcmp(codingType, "noabsence")))
					{
					printf ("\n      Warning: Not expecting all absence characters with this coding (%d).\n", i-numDummyChars+1);
					printf ("\n      Continue with chain? (yes/no): ");
					if (YesNo() == YES)
						{
						printf ("          Continuing with chain, even if it is not a good idea... \n\n");
						break;
						}
					else
						{
						FreeMemory ();
						free (numOfThisPat);
						return (ERROR);
						}
					}
				else if (nTwos == nTaxa && (!strcmp(codingType, "variable") || !strcmp(codingType, "nopresence")))
					{
					printf ("\n      Warning: Not expecting all presence characters with this coding (%d).\n", i-numDummyChars+1);
					printf ("\n      Continue with chain? (yes/no): ");
					if (YesNo() == YES)
						{
						printf ("          Continuing with chain, even if it is not a good idea... \n\n");
						break;
						}
					else
						{
						FreeMemory ();
						free (numOfThisPat);
						return (ERROR);
						}
					}
				}	
				
				
			}
			
		free (numOfThisPat);
		
#		if 0
		for (i=0; i<(*numChars); i++)
			{
			printf ("%4d -- ", i+1);
			for (j=0; j<(*numTaxa); j++)
				{
				printf ("%d", matrix[pos(j,i,(*numChars))]);
				}
			printf ("-- %3d %3d\n", numSitesOfPat[i], partitionId[i]);
			}
#		endif
		}
	else if (dataType == STANDARD)
		{
		printf ("      Compressing data matrix\n");
		/* 2 X 2 substitution model */
		patternId = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!patternId)
			{
			printf ("ERROR: Problem allocating patternId\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PAT_IDS] = YES;
		for (i=0; i<nChar; i++)
			patternId[i] = -1;

		numOfThisPat = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!numOfThisPat)
			{
			printf ("\n   ERROR: Problem allocating numOfThisPat.\n");
			FreeMemory ();
			return (ERROR);
			}
		for (i=0; i<nChar; i++)
			{
			if (excludedSites[i] == YES)
				numOfThisPat[i] = 0;
			else
				numOfThisPat[i] = 1;
			}
		siteNum = 0;
		for (i=0; i<nChar-1; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				patternId[i] = siteNum;
				for (j=i+1; j<nChar; j++)
					{
					if (numOfThisPat[j] > 0)
						{
						isSame = YES;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i] != origDataMatrix[k*nChar+j])
								{
								isSame = NO;
								}
							}
#						if !defined (MORPH)
						if (isSame == YES/* && isSame == NO*/) /* NOTE: I am simply fooling the compression part of the algorithm */
												/* so that no compression occurs. */
#						else
						if (isSame == YES)
#						endif
							{
							numOfThisPat[i]++;
							numOfThisPat[j] = 0;
							patternId[j] = patternId[i] = siteNum;
							}
						}
					}
				siteNum++;
				}
			}		
		if (patternId[nChar - 1] == -1)
			patternId[nChar - 1] = siteNum++;
		nPat = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				nPat++;
			}
		nt = 0;
		for (j=0; j<nTaxa; j++)
			{
			if (excludedTaxa[j] == NO)
				nt++;
			}
		printf ("         Data matrix has %d taxa and %d site patterns\n", nt, nPat);
		(*numTaxa) = nt;
		(*numChars) = nPat;
		matrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
		if (!matrix)
			{
			printf ("\n   ERROR: Problem allocating matrix.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_MATRIX] = YES;
		numSitesOfPat = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!numSitesOfPat)
			{
			printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_N_SITE_PATS] = YES;
		partitionId = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!partitionId)
			{
			printf ("\n   ERROR: Problem allocating partitionId.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PART_ID] = YES;
		siteNum = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				taxNum = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (excludedTaxa[j] == NO)
						{
						matrix[pos(taxNum,siteNum,(*numChars))] = origDataMatrix[j*nChar+i];
						taxNum++;
						}
					}
				numSitesOfPat[siteNum] = numOfThisPat[i];
				partitionId[siteNum] = 0;
				siteNum++;
				}
			}	
		if (!strcmp(codingType, "variable") || !strcmp(codingType, "informative"))
			{
#if defined (MORPH)
			printf ("         Adding dummy characters that are not %s\n", codingType);
#else
			printf ("         Adding dummy %s character(s)\n", codingType);
#endif
			tempMatrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
			if (!tempMatrix)
				{
				printf ("\n   ERROR: Problem allocating tempMatrix.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			tempNumSitePats = (int *)malloc((size_t) (nPat * sizeof(int)));
			if (!tempNumSitePats)
				{
				printf ("\n   ERROR: Problem allocating tempNumSitePats.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			tempPartId = (int *)malloc((size_t) (nPat * sizeof(int)));
			if (!tempPartId)
				{
				printf ("\n   ERROR: Problem allocating tempPartId.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			for (i=0; i<nPat; i++)
				{
				for (j=0; j<nTaxa; j++)
					{
					tempMatrix[pos(j,i,(*numChars))] = matrix[pos(j,i,(*numChars))];
					}
				tempNumSitePats[i] = numSitesOfPat[i];
				tempPartId[i] = partitionId[i];
				}	
			free (matrix);
			free (numSitesOfPat);
			free (partitionId);
			allocatedMemory[ALLOC_MATRIX] = NO;
			allocatedMemory[ALLOC_N_SITE_PATS] = NO;
			allocatedMemory[ALLOC_PART_ID] = NO;
			
			if (!strcmp(codingType, "variable"))
				numDummyChars = 2;
			else if (!strcmp(codingType, "informative"))
#if !defined (MORPH)
				numDummyChars = 1; /* this will be 2 + 2*ntax when properly implemented */
#else
				numDummyChars = 2 + 2*nTaxa;
#endif

			matrix = (int *)malloc((size_t) (nt * (nPat+numDummyChars) * sizeof(int)));
			if (!matrix)
				{
				printf ("\n   ERROR: Problem allocating matrix.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_MATRIX] = YES;
			numSitesOfPat = (int *)malloc((size_t) ((nPat+numDummyChars) * sizeof(int)));
			if (!numSitesOfPat)
				{
				printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_N_SITE_PATS] = YES;
			partitionId = (int *)malloc((size_t) ((nPat+numDummyChars) * sizeof(int)));
			if (!partitionId)
				{
				printf ("\n   ERROR: Problem allocating partitionId.\n");
				FreeMemory ();
				free (numOfThisPat);
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_PART_ID] = YES;
				
			for (i=0; i<nPat; i++)
				{
				for (j=0; j<nTaxa; j++)
					{
					matrix[pos(j,i+numDummyChars,(*numChars)+numDummyChars)] = tempMatrix[pos(j,i,(*numChars))];
					}
				numSitesOfPat[i+numDummyChars] = tempNumSitePats[i];
				partitionId[i+numDummyChars] = tempPartId[i];
				}	
			
			nPat += numDummyChars;
			(*numChars) = nPat;
			
#if defined (MORPH)
			index = 0;
			if (!strcmp(codingType, "variable") || !strcmp(codingType, "informative"))
				{
				// put in constant patterns
				for (k=0; k<2; k++)
					{
					numSitesOfPat[index] = 0;
					partitionId[index] = 0;
					for (j=0; j<nTaxa; j++)
						matrix[j*(*numChars)+index] = k + 1;
					index++;
					}
				}
			if (!strcmp(codingType, "informative"))
				{
				// put in uninformative patterns
				for (k=0; k<2; k++)
					{
					for (i=0; i< nTaxa; i++)
						{
						numSitesOfPat[index] = 0;
						partitionId[index] = 0;
						for (j=0; j<nTaxa; j++)
							{
							if(j == i)
								matrix[j*(*numChars)+index] = (k + 1) ^ 3;
							else
								matrix[j*(*numChars)+index] = k + 1;
							}
						index++;
						}
					}
				}
#endif

			free (tempMatrix);
			free (tempNumSitePats);
			free (tempPartId);

			
#			if defined (MORPH)			
			/* check to see if the dummy characters are present elsewhere */
			if (!strcmp(codingType, "variable"))
				index = nTaxa;
			else if (!strcmp (codingType, "informative"))
				index = nTaxa - 1;
			else
				index = nTaxa + 1;
			for (i=numDummyChars; i<nPat; i++)
				{
				nOnes = nTwos = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (matrix[pos(j,i,(*numChars))] == 1)
						nOnes++;
					else if (matrix[pos(j,i,(*numChars))] == 2)
						nTwos++;
					}
				if (nOnes >= index || nTwos >= index)
					{
					printf ("\n      Warning: Not expecting this character pattern under the chosen coding (%d).\n", i-numDummyChars+1);
					printf ("\n      Continue with chain? (yes/no): ");
					if (YesNo() == YES)
						{
						printf ("          Continuing with chain, even if it is not a good idea... \n\n");
						break;
						}
					else
						{
						FreeMemory ();
						free (numOfThisPat);
						return (ERROR);
						}
					}
				}
#			else
			/* check to see if the dummy characters are present elsewhere */
			for (i=numDummyChars; i<nPat; i++)
				{
				nOnes = nTwos = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (matrix[pos(j,i,(*numChars))] == 1)
						nOnes++;
					else if (matrix[pos(j,i,(*numChars))] == 2)
						nTwos++;
					}
				if (nOnes == nTaxa && !strcmp(codingType, "variable"))
					{
					printf ("\n      Warning: Not expecting all absence characters with this coding (%d).\n", i-numDummyChars+1);
					printf ("\n      Continue with chain? (yes/no): ");
					if (YesNo() == YES)
						{
						printf ("          Continuing with chain, even if it is not a good idea... \n\n");
						break;
						}
					else
						{
						FreeMemory ();
						free (numOfThisPat);
						return (ERROR);
						}
					}
				if (nTwos == nTaxa && !strcmp(codingType, "variable"))
					{
					printf ("\n      Warning: Not expecting all presence characters with this coding (%d).\n", i-numDummyChars+1);
					printf ("\n      Continue with chain? (yes/no): ");
					if (YesNo() == YES)
						{
						printf ("          Continuing with chain, even if it is not a good idea... \n\n");
						break;
						}
					else
						{
						FreeMemory ();
						free (numOfThisPat);
						return (ERROR);
						}
					}
				}	
#endif				
			}

		free (numOfThisPat);
		
#		if 0
		for (i=0; i<(*numChars); i++)
			{
			printf ("%4d -- ", i+1);
			for (j=0; j<(*numTaxa); j++)
				{
				printf ("%d", matrix[pos(j,i,(*numChars))]);
				}
			printf ("-- %3d %3d\n", numSitesOfPat[i], partitionId[i]);
			}
#		endif
		}
	else
		{
		printf ("\n   ERROR: Unknown datatype when compressing.\n");
		FreeMemory ();
		return (ERROR);
		}
		
	return (NO_ERROR);
	
}





int CompressMatrixPars (int *numTaxa, int *numChars)

{

	int			i, j, k, *numOfThisPat, isSame, nPat, nt, siteNum, taxNum;

	nExcluded = 0;
	for (i=0; i<nChar; i++)
		if (excludedSites[i] == YES)
			nExcluded++;
			
	numDummyChars = 0;

	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		printf ("ERROR: Codon models not supported with parsimony criterion.\n");
		return (ERROR);
		}
	else if (((dataType == DNA || dataType == RNA) && enforceCodonModel == NO) || dataType == PROTEIN)
		{
		nStates = 4;
		if (dataType == PROTEIN)
			nStates = 20;
		printf ("      Compressing data matrix\n");
		/* 4 X 4 or 20 X 20 substitution model */
		patternId = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!patternId)
			{
			printf ("ERROR: Problem allocating patternId\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PAT_IDS] = YES;
		for (i=0; i<nChar; i++)
			patternId[i] = -1;

		/* compress for other types of rate models */
		numOfThisPat = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!numOfThisPat)
			{
			printf ("\n   ERROR: Problem allocating numOfThisPat.\n");
			FreeMemory ();
			return (ERROR);
			}
		for (i=0; i<nChar; i++)
			{
			if (excludedSites[i] == YES)
				numOfThisPat[i] = 0;
			else
				numOfThisPat[i] = 1;
			}
		siteNum = 0;
		for (i=0; i<nChar-1; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				patternId[i] = siteNum;
				for (j=i+1; j<nChar; j++)
					{
					if (numOfThisPat[j] > 0)
						{
						isSame = YES;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i] != origDataMatrix[k*nChar+j])
								{
								isSame = NO;
								}
							}
						if (isSame == YES)
							{
							numOfThisPat[i]++;
							numOfThisPat[j] = 0;
							patternId[j] = patternId[i] = siteNum;
							}
						}
					}
				siteNum++;
				}
			}		
		if (patternId[nChar - 1] == -1)
			patternId[nChar - 1] = siteNum++;
		nPat = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				nPat++;
			}
		nt = 0;
		for (j=0; j<nTaxa; j++)
			{
			if (excludedTaxa[j] == NO)
				nt++;
			}
		printf ("         Data matrix has %d taxa and %d site patterns\n", nt, nPat);
		(*numTaxa) = nt;
		(*numChars) = nPat;
		matrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
		if (!matrix)
			{
			printf ("\n   ERROR: Problem allocating matrix.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_MATRIX] = YES;
		numSitesOfPat = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!numSitesOfPat)
			{
			printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_N_SITE_PATS] = YES;
		partitionId = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!partitionId)
			{
			printf ("\n   ERROR: Problem allocating partitionId.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PART_ID] = YES;
		siteNum = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				taxNum = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (excludedTaxa[j] == NO)
						{
						matrix[pos(taxNum,siteNum,(*numChars))] = origDataMatrix[j*nChar+i];
						taxNum++;
						}
					}
				numSitesOfPat[siteNum] = numOfThisPat[i];
				partitionId[siteNum] = 0;
				siteNum++;
				}
			}			
		free (numOfThisPat);

#		if 0
		for (i=0; i<(*numChars); i++)
			{
			printf ("%4d -- ", i+1);
			for (j=0; j<(*numTaxa); j++)
				{
				printf ("%2d ", matrix[pos(j,i,(*numChars))]);
				}
			printf ("-- %3d %3d\n", numSitesOfPat[i], partitionId[i]);
			}
#		endif
		}
	else if (dataType == RESTRICTION)
		{
		nStates = 2;
		printf ("      Compressing data matrix\n");
		/* 2 X 2 substitution model */
		patternId = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!patternId)
			{
			printf ("ERROR: Problem allocating patternId\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PAT_IDS] = YES;
		for (i=0; i<nChar; i++)
			patternId[i] = -1;

		numOfThisPat = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!numOfThisPat)
			{
			printf ("\n   ERROR: Problem allocating numOfThisPat.\n");
			FreeMemory ();
			return (ERROR);
			}
		for (i=0; i<nChar; i++)
			{
			if (excludedSites[i] == YES)
				numOfThisPat[i] = 0;
			else
				numOfThisPat[i] = 1;
			}
		siteNum = 0;
		for (i=0; i<nChar-1; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				patternId[i] = siteNum;
				for (j=i+1; j<nChar; j++)
					{
					if (numOfThisPat[j] > 0)
						{
						isSame = YES;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i] != origDataMatrix[k*nChar+j])
								{
								isSame = NO;
								}
							}
						if (isSame == YES)
							{
							numOfThisPat[i]++;
							numOfThisPat[j] = 0;
							patternId[j] = patternId[i] = siteNum;
							}
						}
					}
				siteNum++;
				}
			}		
		if (patternId[nChar - 1] == -1)
			patternId[nChar - 1] = siteNum++;
		nPat = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				nPat++;
			}
		nt = 0;
		for (j=0; j<nTaxa; j++)
			{
			if (excludedTaxa[j] == NO)
				nt++;
			}
		printf ("         Data matrix has %d taxa and %d site patterns\n", nt, nPat);
		(*numTaxa) = nt;
		(*numChars) = nPat;
		matrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
		if (!matrix)
			{
			printf ("\n   ERROR: Problem allocating matrix.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_MATRIX] = YES;
		numSitesOfPat = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!numSitesOfPat)
			{
			printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_N_SITE_PATS] = YES;
		partitionId = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!partitionId)
			{
			printf ("\n   ERROR: Problem allocating partitionId.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PART_ID] = YES;
		siteNum = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				taxNum = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (excludedTaxa[j] == NO)
						{
						matrix[pos(taxNum,siteNum,(*numChars))] = origDataMatrix[j*nChar+i];
						taxNum++;
						}
					}
				numSitesOfPat[siteNum] = numOfThisPat[i];
				partitionId[siteNum] = 0;
				siteNum++;
				}
			}	
		free (numOfThisPat);
		
#		if 0
		for (i=0; i<(*numChars); i++)
			{
			printf ("%4d -- ", i+1);
			for (j=0; j<(*numTaxa); j++)
				{
				printf ("%d", matrix[pos(j,i,(*numChars))]);
				}
			printf ("-- %3d %3d\n", numSitesOfPat[i], partitionId[i]);
			}
#		endif
		}
	else if (dataType == STANDARD)
		{
		nStates = 2;
		printf ("      Compressing data matrix\n");
		/* 2 X 2 substitution model */
		patternId = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!patternId)
			{
			printf ("ERROR: Problem allocating patternId\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PAT_IDS] = YES;
		for (i=0; i<nChar; i++)
			patternId[i] = -1;

		numOfThisPat = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!numOfThisPat)
			{
			printf ("\n   ERROR: Problem allocating numOfThisPat.\n");
			FreeMemory ();
			return (ERROR);
			}
		for (i=0; i<nChar; i++)
			{
			if (excludedSites[i] == YES)
				numOfThisPat[i] = 0;
			else
				numOfThisPat[i] = 1;
			}
		siteNum = 0;
		for (i=0; i<nChar-1; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				patternId[i] = siteNum;
				for (j=i+1; j<nChar; j++)
					{
					if (numOfThisPat[j] > 0)
						{
						isSame = YES;
						for (k=0; k<nTaxa; k++)
							{
							if (excludedTaxa[k] == NO && origDataMatrix[k*nChar+i] != origDataMatrix[k*nChar+j])
								{
								isSame = NO;
								}
							}
						if (isSame == YES/* && isSame == NO*/) /* NOTE: I am simply fooling the compression part of the algorithm */
							{                              /* so that no compression occurs. */
							numOfThisPat[i]++;
							numOfThisPat[j] = 0;
							patternId[j] = patternId[i] = siteNum;
							}
						}
					}
				siteNum++;
				}
			}		
		if (patternId[nChar - 1] == -1)
			patternId[nChar - 1] = siteNum++;
		nPat = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				nPat++;
			}
		nt = 0;
		for (j=0; j<nTaxa; j++)
			{
			if (excludedTaxa[j] == NO)
				nt++;
			}
		printf ("         Data matrix has %d taxa and %d site patterns\n", nt, nPat);
		(*numTaxa) = nt;
		(*numChars) = nPat;
		matrix = (int *)malloc((size_t) (nt * nPat * sizeof(int)));
		if (!matrix)
			{
			printf ("\n   ERROR: Problem allocating matrix.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_MATRIX] = YES;
		numSitesOfPat = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!numSitesOfPat)
			{
			printf ("\n   ERROR: Problem allocating numSitesOfPat.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_N_SITE_PATS] = YES;
		partitionId = (int *)malloc((size_t) (nPat * sizeof(int)));
		if (!partitionId)
			{
			printf ("\n   ERROR: Problem allocating partitionId.\n");
			FreeMemory ();
			free (numOfThisPat);
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_PART_ID] = YES;
		siteNum = 0;
		for (i=0; i<nChar; i++)
			{
			if (numOfThisPat[i] > 0)
				{
				taxNum = 0;
				for (j=0; j<nTaxa; j++)
					{
					if (excludedTaxa[j] == NO)
						{
						matrix[pos(taxNum,siteNum,(*numChars))] = origDataMatrix[j*nChar+i];
						taxNum++;
						}
					}
				numSitesOfPat[siteNum] = numOfThisPat[i];
				partitionId[siteNum] = 0;
				siteNum++;
				}
			}	
		free (numOfThisPat);
		
#		if 0
		for (i=0; i<(*numChars); i++)
			{
			printf ("%4d -- ", i+1);
			for (j=0; j<(*numTaxa); j++)
				{
				printf ("%d", matrix[pos(j,i,(*numChars))]);
				}
			printf ("-- %3d %3d\n", numSitesOfPat[i], partitionId[i]);
			}
#		endif
		}
	else
		{
		printf ("\n   ERROR: Unknown datatype when compressing.\n");
		FreeMemory ();
		return (ERROR);
		}
		
	return (NO_ERROR);
	
}





void CopyConditionalLikelihoods (int from, int to, int whichChain, int numTaxa, int numChars, int numRateCats)

{

	register int		c, i, s, oneMatSize, kTimesC, nLocalStates;
	double				*clTo, *clFrom, *scTo, *scFrom;
	
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		if (!strcmp(codonModelType, "covny98"))
			nLocalStates = 3 * nStates;
		else
			nLocalStates = nStates;
		}
	else
		{
		if (useCovarion == YES)
			nLocalStates = 2 * nStates;
		else
			nLocalStates = nStates;
		}
	
	oneMatSize = numNodes * numChars * numRateCats * numBetaCats * nLocalStates;
	kTimesC = nLocalStates * numRateCats * numBetaCats;
	
	/* copy conditional likelihoods */
	for (i=numTaxa; i<numNodes; i++)
		{
		if (clUpdateFlag[i] == YES)
			{
			clTo =   &condLike[whichChain*2*oneMatSize + to*oneMatSize   + i*numChars*kTimesC];
			clFrom = &condLike[whichChain*2*oneMatSize + from*oneMatSize + i*numChars*kTimesC];
			for (c=0; c<numChars; c++, *(clTo+=kTimesC), *(clFrom+=kTimesC))
				{
				for (s=0; s<kTimesC; s++)
					clTo[s] = clFrom[s];
				}
			clUpdateFlag[i] = NO;
			}
		}

	/* copy node scalers */
	for (i=0; i<numIntNodes; i++)
		{
		if (scalerUpdateFlag[i] == YES)
			{
			scTo   = &clScaler[whichChain*2*numIntNodes*numChars + to*numIntNodes*numChars + i*numChars];
			scFrom = &clScaler[whichChain*2*numIntNodes*numChars + from*numIntNodes*numChars + i*numChars];
			for (c=0; c<numChars; c++)
				{
				scTo[c] = scFrom[c];
				}
			scalerUpdateFlag[i] = NO;
			}
		}

	// copy lnSiteScaler
	// will almost always be touched, so always update
	scTo   = &lnSiteScaler[whichChain*2*numChars + to*numChars];
	scFrom = &lnSiteScaler[whichChain*2*numChars + from*numChars];
	for (i=0; i<numChars; i++)
		{
		scTo[i] = scFrom[i];
		}
		
#	if defined (SMART_TI_PROBS)
	for (i=0; i<numNodes; i++)
		{
		if (updateTiFlag[i] == YES)
			{
			scTo   = &transitionProbs[whichChain*2*numNodes*nodeTiSize +   to*numNodes*nodeTiSize + i*nodeTiSize];
			scFrom = &transitionProbs[whichChain*2*numNodes*nodeTiSize + from*numNodes*nodeTiSize + i*nodeTiSize];
			for (s=0; s<nodeTiSize; s++)
				scTo[s] = scFrom[s];
			}
		updateTiFlag[i] = NO;
		}
#	endif

}





void CopyTree (int from, int to, int whichChain)

{

	int			i, iA, iL, iR;
	TreeNode	*p, *pA, *pL, *pR, *q, *qA, *qL, *qR, *r;

	r = root[whichChain*2+from];
	for (i=0; i<numNodes; i++)
		{
		/* get from pointers */
		p  = nodes + (whichChain*2*numNodes + from * numNodes + i);
		if (p->anc != NULL)
			{
			pA = p->anc;
			iA = pA->memoryIndex;
			}
		if (p->left != NULL)
			{
			pL = p->left;
			iL = pL->memoryIndex;
			}
		if (p->right != NULL)
			{
			pR = p->right;
			iR = pR->memoryIndex;
			}

		/* to pointers should be offset sizeOfTree from from pointers */
		q  = nodes + (whichChain*2*numNodes + to * numNodes + i);
		if (p->anc != NULL)
			{
			qA = nodes + (whichChain*2*numNodes + to * numNodes + iA);
			q->anc = qA;
			}
		else
			{
			q->anc = NULL;
			}
		if (p->left != NULL)	
			{
			qL = nodes + (whichChain*2*numNodes + to * numNodes + iL);
			q->left = qL;
			}
		else
			{
			q->left = NULL;
			}
		if (p->right != NULL)	
			{
			qR = nodes + (whichChain*2*numNodes + to * numNodes + iR);
			q->right = qR;
			}
		else
			{
			q->right = NULL;
			}
		q->memoryIndex            = p->memoryIndex; 
		q->index                  = p->index; 
		q->upDateCl               = p->upDateCl; 
		q->marked                 = p->marked;
		q->x                      = p->x;
		q->y                      = p->y;
		q->constraints            = p->constraints;
		q->calibrations           = p->calibrations;
		q->scaler                 = p->scaler;
		q->scalerNode             = p->scalerNode;
		q->flag                   = p->flag;
		q->isCalibrated           = p->isCalibrated;
		q->isConstrained          = p->isConstrained;
		q->constraintNum          = p->constraintNum;
		q->calibrationNum         = p->calibrationNum;
		q->farrisSet              = p->farrisSet;
		q->length                 = p->length;
		q->nodeTime               = p->nodeTime;
		q->calTime[0]             = p->calTime[0];
		q->calTime[1]             = p->calTime[1];
		q->scalerIndex			  = p->scalerIndex;
#		if defined (SMART_TI_PROBS)
		q->upDateTi			      = p->upDateTi;
#		endif
		strcpy (q->label, p->label);
		strcpy (q->calibrationName, p->calibrationName);
		strcpy (q->constraintName, p->constraintName);
		if (p == r)
			root[whichChain*2 + to] = q;
		}
		
	for (i=0; i<numIntNodes; i++)
		{
		p = intNodeDownPassSeq[whichChain*2*numIntNodes + from * numIntNodes + i];
		q = nodes + (whichChain*2*numNodes + to * numNodes + p->memoryIndex);
		intNodeDownPassSeq[whichChain*2*numIntNodes + to * numIntNodes + i] = q;
		}
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + from * numNodes + i];
		q = nodes + (whichChain*2*numNodes + to * numNodes + p->memoryIndex);
		allNodesDownPassSeq[whichChain*2*numNodes + to * numNodes + i] = q;
		}

	if (allocatedMemory[ALLOC_TREE_HEIGHT] == YES)
		treeHeight[whichChain*2 + to] = treeHeight[whichChain*2 + from];
	
	if (allocatedMemory[ALLOC_KAPPA] == YES)
		kappa[whichChain*2 + to] = kappa[whichChain*2 + from];

	if (allocatedMemory[ALLOC_OMEGA] == YES)
		omega[whichChain*2 + to] = omega[whichChain*2 + from];

	if (allocatedMemory[ALLOC_PUR] == YES)
		probPur[whichChain*2 + to] = probPur[whichChain*2 + from];

	if (allocatedMemory[ALLOC_NEU] == YES)
		probNeu[whichChain*2 + to] = probNeu[whichChain*2 + from];

	if (allocatedMemory[ALLOC_POS] == YES)
		probPos[whichChain*2 + to] = probPos[whichChain*2 + from];

	if (allocatedMemory[ALLOC_GAMMA_SHAPE] == YES)
		alpha[whichChain*2 + to] = alpha[whichChain*2 + from]; 

	if (allocatedMemory[ALLOC_INV_P] == YES)
		invP[whichChain*2 + to] = invP[whichChain*2 + from]; 
		
	if (allocatedMemory[ALLOC_AUTO_GAMMA] == YES)
		rateCorrelation[whichChain*2 + to] = rateCorrelation[whichChain*2 + from]; 

	if (allocatedMemory[ALLOC_AUTO_GAMMA2] == YES)
		{
		for (i=0; i<2; i++)
			rateCorrelation2[whichChain*4 + to*2 + i] = rateCorrelation2[whichChain*4 + from*2 + i]; 
		}

	if (allocatedMemory[ALLOC_LAG] == YES)
		lag[whichChain*2 + to] = lag[whichChain*2 + from]; 

	if (allocatedMemory[ALLOC_SUBPARAMS] == YES)
		{
		for (i=0; i<nst; i++)
			subParams[whichChain*2*nst + to*nst + i] = subParams[whichChain*2*nst + from*nst + i];
		}
		
	if (allocatedMemory[ALLOC_BASEFREQS] == YES)
		{
		for (i=0; i<nStates; i++)
			baseFreq[whichChain*2*nStates + to*nStates + i] = baseFreq[whichChain*2*nStates + from*nStates + i];
		}
		
	if (allocatedMemory[ALLOC_UNSCALED_SITE_RATES] == YES)
		{
		for (i=0; i<nPartitions; i++)
			unscaledRates[whichChain*2*nPartitions + to*nPartitions + i] = unscaledRates[whichChain*2*nPartitions + from*nPartitions + i];
		}
		
	if (allocatedMemory[ALLOC_SITE_RATES] == YES)
		{
		for (i=0; i<nPartitions; i++)
			scaledRates[whichChain*2*nPartitions + to*nPartitions + i]   = scaledRates[whichChain*2*nPartitions + from*nPartitions + i];
		}
		
	if (allocatedMemory[ALLOC_SP_RATE] == YES)
		spRate[whichChain*2 + to] = spRate[whichChain*2 + from];

	if (allocatedMemory[ALLOC_EX_RATE] == YES)
		exRate[whichChain*2 + to] = exRate[whichChain*2 + from];
		
	if (allocatedMemory[ALLOC_SWITCH_RATE] == YES)
		{
		for (i=0; i<2; i++)
			switchRate[whichChain*2*2 + to*2 + i] = switchRate[whichChain*2*2 + from*2 + i];
		}

	if (allocatedMemory[ALLOC_SWITCH_PI] == YES)
		{
		for (i=0; i<2; i++)
			switchPi[whichChain*2*2 + to*2 + i] = switchPi[whichChain*2*2 + from*2 + i];
		}

	if (allocatedMemory[ALLOC_GC1] == YES)
		gc1[whichChain*2 + to] = gc1[whichChain*2 + from];

	if (allocatedMemory[ALLOC_GC2] == YES)
		gc2[whichChain*2 + to] = gc2[whichChain*2 + from];

	if (allocatedMemory[ALLOC_FRAC_A] == YES)
		fracA[whichChain*2 + to] = fracA[whichChain*2 + from];

	if (allocatedMemory[ALLOC_FRAC_G] == YES)
		fracG[whichChain*2 + to] = fracG[whichChain*2 + from];

	if (allocatedMemory[ALLOC_BETA] == YES)
		statefreqP[whichChain*2 + to] = statefreqP[whichChain*2 + from];
		
}





void DirichletRandomVariable (double *alp, double *z, int n, long int *seed)

{

	int		i;
	double	sum;

	sum = 0.0;
	for(i=0; i<n; i++)
		{
		z[i] = RndGamma (alp[i], seed) / 1.0;
		sum += z[i];
		}
	for(i=0; i<n; i++)
		z[i] /= sum;
	
}





void FreeMemory (void)

{

	if (allocatedMemory[ALLOC_KAPPA] == YES)
		{
		free (kappa);
		allocatedMemory[ALLOC_KAPPA] = NO;
		}
	if (allocatedMemory[ALLOC_SUBPARAMS] == YES)
		{
		free (subParams);
		allocatedMemory[ALLOC_SUBPARAMS] = NO;
		}
	if (allocatedMemory[ALLOC_BASEFREQS] == YES)
		{
		free (baseFreq);
		allocatedMemory[ALLOC_BASEFREQS] = NO;
		}
	if (allocatedMemory[ALLOC_GAMMA_SHAPE] == YES)
		{
		free (alpha);
		allocatedMemory[ALLOC_GAMMA_SHAPE] = NO;
		}
	if (allocatedMemory[ALLOC_SITE_RATES] == YES)
		{
		free (scaledRates);
		allocatedMemory[ALLOC_SITE_RATES] = NO;
		}
	if (allocatedMemory[ALLOC_UNSCALED_SITE_RATES] == YES)
		{
		free (unscaledRates);
		allocatedMemory[ALLOC_UNSCALED_SITE_RATES] = NO;
		}
	if (allocatedMemory[ALLOC_NSITES_IN_PART] == YES)
		{
		free (nSitesInPartition);
		allocatedMemory[ALLOC_NSITES_IN_PART] = NO;
		}
	if (allocatedMemory[ALLOC_MATRIX] == YES)
		{
		free (matrix);
		allocatedMemory[ALLOC_MATRIX] = NO;
		}
	if (allocatedMemory[ALLOC_N_SITE_PATS] == YES)
		{
		free (numSitesOfPat);
		allocatedMemory[ALLOC_N_SITE_PATS] = NO;
		}
	if (allocatedMemory[ALLOC_PART_ID] == YES)
		{
		free (partitionId);
		allocatedMemory[ALLOC_PART_ID] = NO;
		}
	if (allocatedMemory[ALLOC_NODES] == YES)
		{
		free (nodes);
		allocatedMemory[ALLOC_NODES] = NO;
		}
	if (allocatedMemory[ALLOC_ROOT] == YES)
		{
		free (root);
		allocatedMemory[ALLOC_ROOT] = NO;
		}
	if (allocatedMemory[ALLOC_ALLDOWNPASS] == YES)
		{
		free (allNodesDownPassSeq);
		allocatedMemory[ALLOC_ALLDOWNPASS] = NO;
		}
	if (allocatedMemory[ALLOC_INTDOWNPASS] == YES)
		{
		free (intNodeDownPassSeq);
		allocatedMemory[ALLOC_INTDOWNPASS] = NO;
		}
	if (allocatedMemory[ALLOC_CLUPDATE_FLAG] == YES)
		{
		free (clUpdateFlag);
		allocatedMemory[ALLOC_CLUPDATE_FLAG] = NO;
		}
	if (allocatedMemory[ALLOC_COND_LIKES] == YES)
		{
		free (condLike);
		allocatedMemory[ALLOC_COND_LIKES] = NO;
		}
	if (allocatedMemory[ALLOC_COND_SCALER] == YES)
		{
		free (clScaler);
		allocatedMemory[ALLOC_COND_SCALER] = NO;
		}
	if (allocatedMemory[ALLOC_DISTANCES] == YES)
		{
		free (distances);
		allocatedMemory[ALLOC_DISTANCES] = NO;
		}
	if (allocatedMemory[ALLOC_TREE_HEIGHT] == YES)
		{
		free (treeHeight);
		allocatedMemory[ALLOC_TREE_HEIGHT] = NO;
		}
	if (allocatedMemory[ALLOC_ANC_STATES] == YES)
		{
		free (ancStatesProbs);
		allocatedMemory[ALLOC_ANC_STATES] = NO;
		}
	if (allocatedMemory[ALLOC_TEMP_ANC_STATES] == YES)
		{
		free (tempStateProbs);
		allocatedMemory[ALLOC_TEMP_ANC_STATES] = NO;
		}
	if (allocatedMemory[ALLOC_PAT_IDS] == YES)
		{
		free (patternId);
		allocatedMemory[ALLOC_PAT_IDS] = NO;
		}
	if (allocatedMemory[ALLOC_SP_RATE] == YES)
		{
		free (spRate);
		allocatedMemory[ALLOC_SP_RATE] = NO;
		}
	if (allocatedMemory[ALLOC_EX_RATE] == YES)
		{
		free (exRate);
		allocatedMemory[ALLOC_EX_RATE] = NO;
		}
	if (allocatedMemory[ALLOC_OMEGA] == YES)
		{
		free (omega);
		allocatedMemory[ALLOC_OMEGA] = NO;
		}
	if (allocatedMemory[ALLOC_PUR] == YES)
		{
		free (probPur);
		allocatedMemory[ALLOC_PUR] = NO;
		}
	if (allocatedMemory[ALLOC_NEU] == YES)
		{
		free (probNeu);
		allocatedMemory[ALLOC_NEU] = NO;
		}
	if (allocatedMemory[ALLOC_POS] == YES)
		{
		free (probPos);
		allocatedMemory[ALLOC_POS] = NO;
		}
	if (allocatedMemory[ALLOC_AUTO_GAMMA] == YES)
		{
		free (rateCorrelation);
		allocatedMemory[ALLOC_AUTO_GAMMA] = NO;
		}
	if (allocatedMemory[ALLOC_AUTO_GAMMA2] == YES)
		{
		free (rateCorrelation2);
		allocatedMemory[ALLOC_AUTO_GAMMA2] = NO;
		}
	if (allocatedMemory[ALLOC_LAG] == YES)
		{
		free (lag);
		allocatedMemory[ALLOC_LAG] = NO;
		}
	if (allocatedMemory[ALLOC_INV_P] == YES)
		{
		free (invP);
		allocatedMemory[ALLOC_INV_P] = NO;
		}
	if (allocatedMemory[ALLOC_SWITCH_RATE] == YES)
		{
		free (switchRate);
		allocatedMemory[ALLOC_SWITCH_RATE] = NO;
		}
	if (allocatedMemory[ALLOC_SWITCH_PI] == YES)
		{
		free (switchPi);
		allocatedMemory[ALLOC_SWITCH_PI] = NO;
		}
	if (allocatedMemory[ALLOC_GC1] == YES)
		{
		free (gc1);
		allocatedMemory[ALLOC_GC1] = NO;
		}
	if (allocatedMemory[ALLOC_GC2] == YES)
		{
		free (gc2);
		allocatedMemory[ALLOC_GC2] = NO;
		}
	if (allocatedMemory[ALLOC_FRAC_A] == YES)
		{
		free (fracA);
		allocatedMemory[ALLOC_FRAC_A] = NO;
		}
	if (allocatedMemory[ALLOC_FRAC_G] == YES)
		{
		free (fracG);
		allocatedMemory[ALLOC_FRAC_G] = NO;
		}
	if (allocatedMemory[ALLOC_LN_SITE_SCALER] == YES)
		{
		free (lnSiteScaler);
		allocatedMemory[ALLOC_LN_SITE_SCALER] = NO;
		}
	if (allocatedMemory[ALLOC_SCALER_UPDATE_FLAG] == YES)
		{
		free (scalerUpdateFlag);
		allocatedMemory[ALLOC_SCALER_UPDATE_FLAG] = NO;
		}
#	if defined (SUPER_FAST)
	if (allocatedMemory[ALLOC_TERM_STATES] == YES)
		{
		free (isPartAmbig);
		allocatedMemory[ALLOC_TERM_STATES] = NO;
		}
#	endif
#	if defined (SMART_TI_PROBS)
	if (allocatedMemory[ALLOC_TI_PROBS] == YES)
		{
		free (transitionProbs);
		allocatedMemory[ALLOC_TI_PROBS] = NO;
		}
	if (allocatedMemory[ALLOC_TI_FLAGS] == YES)
		{
		free (updateTiFlag);
		allocatedMemory[ALLOC_TI_FLAGS] = NO;
		}
#	endif
	if (allocatedMemory[ALLOC_STATE_SET] == YES)
		{
		free (stateSet);
		allocatedMemory[ALLOC_STATE_SET] = NO;
		}
#if defined (MORPH)
	if (allocatedMemory[ALLOC_BETA] == YES)
		{
		free (statefreqP);
		allocatedMemory[ALLOC_BETA] = NO;
		}
#endif
}





double GetTreeLength (int whichState, int whichChain)

{

	int			i;
	double		sum;
	TreeNode	*p;

	sum = 0.0;
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + whichState*numNodes + i];
		if (p->anc != NULL)
			{
			if (p->anc->anc != NULL)
				sum += p->length;
			else if (treeModel == UNROOTED)
				sum += p->length;
			}
		}
		
	return (sum);

}





int GetDistances (int numTaxa, int numChars)

{

	int			i, j, k, x, y;
	double		nSame, nDiff, d, p;

	distances = (double *)malloc(sizeof(double) * numTaxa * numTaxa);
	if (!distances)
		{
		printf ("\n   ERROR: Could not allocate distances\n");
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_DISTANCES] = YES;	
	
	x = 0;
	for (i=0; i<nTaxa; i++)
		{
		if (excludedTaxa[i] == NO)
			{
			y = 0;
			for (j=0; j<nTaxa; j++)
				{
				if (excludedTaxa[j] == NO)
					{
					/* get distance for taxa x and y */
					if (x == y)
						distances[pos(x,y,numTaxa)] = 0.0;
					else
						{
						nSame = nDiff = 0.0;
						for (k=0; k<numChars; k++)
							{
							if ((matrix[pos(x,k,numChars)] == 1 || matrix[pos(x,k,numChars)] == 2 || matrix[pos(x,k,numChars)] == 4 ||
							     matrix[pos(x,k,numChars)] == 8) && 
							    (matrix[pos(y,k,numChars)] == 1 || matrix[pos(y,k,numChars)] == 2 || matrix[pos(y,k,numChars)] == 4 ||
							     matrix[pos(y,k,numChars)] == 8))
							     {
								if (matrix[pos(x,k,numChars)] == matrix[pos(y,k,numChars)])
									nSame += (double)numSitesOfPat[k];
								else
									nDiff += (double)numSitesOfPat[k];
								}
							}
						p = (nDiff/(nSame+nDiff));
						if (p >= 0.74999)
							d = 9.999999999;
						else
							d = -0.75 * log (1.0 - (4.0/3.0) * p);
						distances[pos(x,y,numTaxa)] = d;
						}
					y++;
					}
				}
			x++;
			}
		}	
	for (i=0; i<numTaxa; i++)
		distances[pos(i,i,numTaxa)] = 0.0;
	
#	if 0
	printf ("Jukes-Cantor (1969) distance matrix:\n");
	for (i=0; i<numTaxa; i++)
		{
		for (j=0; j<numTaxa; j++)
			printf ("%1.4lf ", distances[pos(i,j,numTaxa)]);
		printf ("\n");
		}
	printf ("\n");
#	endif

	return (NO_ERROR);
}





void GetDownPassSeq (TreeNode *p, int whichTree, int whichChain, int numTaxa, int *i, int *j)

{
	
	if (p != NULL)
		{
		GetDownPassSeq (p->left,  whichTree, whichChain, numTaxa, i, j);
		GetDownPassSeq (p->right, whichTree, whichChain, numTaxa, i, j);
		
		if (p->left != NULL && p->right != NULL && p->anc != NULL)
			{
			intNodeDownPassSeq[whichChain*2*numIntNodes + whichTree*numIntNodes + (*i)++] = p;
			allNodesDownPassSeq[whichChain*2*numNodes + whichTree*numNodes + (*j)++] = p;
			}
		else if (p->left == NULL && p->right == NULL && p->anc != NULL)
			{
			allNodesDownPassSeq[whichChain*2*numNodes + whichTree*numNodes + (*j)++] = p;
			}
		else if (p->left != NULL && p->right == NULL && p->anc == NULL)
			{
			allNodesDownPassSeq[whichChain*2*numNodes + whichTree*numNodes + (*j)++] = p;
			}
		}
		
}





int GetEigens (int n, double **q, double *eigenValues, double *eigvalsImag, double **eigvecs, double **inverseEigvecs, complex **Ceigvecs, complex **CinverseEigvecs)

{

	int			i, j, rc, *iwork, isComplex;
	double		**mwork, *dwork;
	complex 	**Cwork, *Ccol;

	/* allocate memory */
	dwork           = (double *)malloc((size_t) (n * sizeof(double)));
	iwork           = (int *)malloc((size_t) (n * sizeof(int)));

	/* calculate eigenvalues and eigenvectors */
	isComplex = NO;
	rc = EigenRealGeneral (n, q, eigenValues, eigvalsImag, eigvecs, iwork, dwork);
	if (rc != NO_ERROR)
		{
		if (rc == RC_COMPLEX_EVAL)
			{
			isComplex = YES;
			}
		}

	/* invert U = eigenvectors (InvertMatrix destroys its input matrix, so copy U to temp) */
	if (isComplex == NO)
		{
		mwork = psdmatrix (n);
		copy_psdmatrix (eigvecs, mwork, n);
		InvertMatrix (mwork, n, dwork, iwork, inverseEigvecs);
		free_psdmatrix (mwork);
		}
	else
		{
		for(i=0; i<n; i++)
			{
			if (eigvalsImag[i] == 0.0)
				{ 
				for(j=0; j<n; j++)
					{
					Ceigvecs[j][i].re = eigvecs[j][i];
					Ceigvecs[j][i].im = 0.0;
					}
				}
			else if (eigvalsImag[i] > 0.0)
				{ 
				for (j=0; j<n; j++)
					{
					Ceigvecs[j][i].re = eigvecs[j][i];
					Ceigvecs[j][i].im = eigvecs[j][i + 1];
					}
				}
			else if (eigvalsImag[i] < 0.0)
				{ 
				for (j=0; j<n; j++)
					{
					Ceigvecs[j][i].re =  eigvecs[j][i-1];
					Ceigvecs[j][i].im = -eigvecs[j][i];
					}
				}
			}
		Ccol = (complex *)malloc((size_t) (n * sizeof(complex)));
		Cwork = pscmatrix (n);
		copy_pscmatrix (Ceigvecs, Cwork, n);
		ComplexInvertMatrix (Cwork, n, dwork, iwork, CinverseEigvecs, Ccol);
		free (Ccol);
		free_pscmatrix (Cwork);
		}

	free (dwork);
	free (iwork);
	return (isComplex);

}





void GetEmpiricalAAFreqs (void)

{

	int				i, j, k, m, aa[20], chain;
	double			freq[20], sum, sumAA[20];

	for (i=0; i<20; i++)
		freq[i] = 0.05;
	
	for (k=0; k<8; k++)
		{
		for (i=0; i<20; i++)
			sumAA[i] = 0.0;
		for (i=0; i<nTaxa; i++)
			{
			if (excludedTaxa[i] == NO)
				{
				for (j=0; j<nChar; j++)
					{
					if (excludedSites[j] == NO)
						{
						GetPossibleAAs (origDataMatrix[i*nChar+j], aa);
						sum = 0.0;
						for (m=0; m<20; m++)
							sum += freq[m] * aa[m];
						for (m=0; m<20; m++)
							sumAA[m] += freq[m] * aa[m] / sum;
						}
					}
				}
			}
		sum = 0.0;
		for (m=0; m<20; m++)
			sum += sumAA[m];
		for (m=0; m<20; m++)
			freq[m] = sumAA[m] / sum;			
		}
		
	for (chain=0; chain<numChains; chain++)
		{
		for (m=0; m<20; m++)
			{
			baseFreq[chain*8 + 0*nStates + m] = freq[m];
			baseFreq[chain*8 + 1*nStates + m] = freq[m];
			}
		}

}





void GetEmpiricalBaseFreqs (void)

{

	int				i, j, k, nuc[4], chain;
	double			freqA, freqC, freqG, freqT, sum, sumA, sumC, sumG, sumT;

	freqA = 0.25;
	freqC = 0.25;
	freqG = 0.25;
	freqT = 0.25;
	
	for (k=0; k<8; k++)
		{
		sumA = 0.0;
		sumC = 0.0;
		sumG = 0.0;
		sumT = 0.0;
		for (i=0; i<nTaxa; i++)
			{
			if (excludedTaxa[i] == NO)
				{
				for (j=0; j<nChar; j++)
					{
					if (excludedSites[j] == NO)
						{
						GetPossibleNucs (origDataMatrix[i*nChar+j], nuc);
						sum  = freqA * nuc[0];
						sum += freqC * nuc[1];
						sum += freqG * nuc[2];
						sum += freqT * nuc[3];
						sumA += freqA * nuc[0] / sum;
						sumC += freqC * nuc[1] / sum;
						sumG += freqG * nuc[2] / sum;
						sumT += freqT * nuc[3] / sum;
						}
					}
				}
			}
		sum = sumA + sumC + sumG + sumT;
		freqA = sumA / sum;
		freqC = sumC / sum;
		freqG = sumG / sum;
		freqT = sumT / sum;
		}
		
	for (chain=0; chain<numChains; chain++)
		{
		baseFreq[chain*8 + 0*nStates + A] = freqA;
		baseFreq[chain*8 + 0*nStates + C] = freqC;
		baseFreq[chain*8 + 0*nStates + G] = freqG;
		baseFreq[chain*8 + 0*nStates + T] = freqT;
		baseFreq[chain*8 + 1*nStates + A] = freqA;
		baseFreq[chain*8 + 1*nStates + C] = freqC;
		baseFreq[chain*8 + 1*nStates + G] = freqG;
		baseFreq[chain*8 + 1*nStates + T] = freqT;
		}

}





void GetPossibleAAs (int aaCode, int aa[])

{

	int		m;
	
	for (m=0; m<20; m++)
		aa[m] = 0;
		
	if (aaCode > 0 && aaCode <= 20)
		aa[aaCode-1] = 1;
	else
		{
		for (m=0; m<20; m++)
			aa[m] = 1;
		}
#	if 0
	printf ("%2d -- ", aaCode);
	for (m=0; m<20; m++)
		printf("%d", aa[m]);
	printf ("\n");
#	endif

}





void GetPossibleNucs (int nucCode, int nuc[])

{


	if (nucCode == 1)
		{
		nuc[0] = 1;
		nuc[1] = 0;
		nuc[2] = 0;
		nuc[3] = 0;
		}
	else if (nucCode == 2)
		{
		nuc[0] = 0;
		nuc[1] = 1;
		nuc[2] = 0;
		nuc[3] = 0;
		}
	else if (nucCode == 3)
		{
		nuc[0] = 1;
		nuc[1] = 1;
		nuc[2] = 0;
		nuc[3] = 0;
		}
	else if (nucCode == 4)
		{
		nuc[0] = 0;
		nuc[1] = 0;
		nuc[2] = 1;
		nuc[3] = 0;
		}
	else if (nucCode == 5)
		{
		nuc[0] = 1;
		nuc[1] = 0;
		nuc[2] = 1;
		nuc[3] = 0;
		}
	else if (nucCode == 6)
		{
		nuc[0] = 0;
		nuc[1] = 1;
		nuc[2] = 1;
		nuc[3] = 0;
		}
	else if (nucCode == 7)
		{
		nuc[0] = 1;
		nuc[1] = 1;
		nuc[2] = 1;
		nuc[3] = 0;
		}
	else if (nucCode == 8)
		{
		nuc[0] = 0;
		nuc[1] = 0;
		nuc[2] = 0;
		nuc[3] = 1;
		}
	else if (nucCode == 9)
		{
		nuc[0] = 1;
		nuc[1] = 0;
		nuc[2] = 0;
		nuc[3] = 1;
		}
	else if (nucCode == 10)
		{
		nuc[0] = 0;
		nuc[1] = 1;
		nuc[2] = 0;
		nuc[3] = 1;
		}
	else if (nucCode == 11)
		{
		nuc[0] = 1;
		nuc[1] = 1;
		nuc[2] = 0;
		nuc[3] = 1;
		}
	else if (nucCode == 12)
		{
		nuc[0] = 0;
		nuc[1] = 0;
		nuc[2] = 1;
		nuc[3] = 1;
		}
	else if (nucCode == 13)
		{
		nuc[0] = 1;
		nuc[1] = 0;
		nuc[2] = 1;
		nuc[3] = 1;
		}
	else if (nucCode == 14)
		{
		nuc[0] = 0;
		nuc[1] = 1;
		nuc[2] = 1;
		nuc[3] = 1;
		}
	else if (nucCode == 15)
		{
		nuc[0] = 1;
		nuc[1] = 1;
		nuc[2] = 1;
		nuc[3] = 1;
		}

}





void GetTempDownPassSeq (TreeNode *p, int *i, TreeNode **dp)

{
	
	if (p != NULL)
		{
		GetTempDownPassSeq (p->left,  i, dp);
		GetTempDownPassSeq (p->right, i, dp);
		dp[(*i)++] = p;
		}
		
}





void HkyChangeMat (double **ch_prob, double time, double k, double r, double piA, double piC, double piG, double piT)

{

	int		i, j;
	double	t, u, w, x, y, z, beta, bigPi_j[4], pij, bigPij, pis[4];

	/* rescale beta */
	pis[0] = piA;
	pis[1] = piC;
	pis[2] = piG;
	pis[3] = piT;
	beta = 0.5 / ((piA + piG)*(piC + piT) + k*((piA*piG) + (piC*piT)));

	bigPi_j[0] = piA + piG;
	bigPi_j[1] = piC + piT;
	bigPi_j[2] = piA + piG;
	bigPi_j[3] = piC + piT;

	t = time * r;

	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			bigPij = bigPi_j[j];
			pij = pis[j];
			u = 1.0/bigPij - 1.0;
			w = -beta * (1.0 + bigPij * (k - 1.0));
			x = exp(-beta * t);
			y = exp(w * t);
			z = (bigPij - pij) / bigPij;
			if (i == j)
				ch_prob[i][j] = pij + pij * u * x + z * y;
			else if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 3) || (i == 3 && j == 1))
				ch_prob[i][j] = pij + pij * u * x - (pij/bigPij) * y;
			else
				ch_prob[i][j] = pij * (1.0 - x);
			}
		}
		
#	if 0
	printf ("Change probabilities (HKY 85, v = %lf):\n", time);
	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			printf ("%lf ", ch_prob[i][j]);
			}
		printf ("\n");
		}
#	endif

}





void HkyFirstMat (double **ch_prob, double time, double k, double r, double piA, double piC, double piG, double piT)

{

	int		i, j;
	double	t, u, w, x, y, z, beta, bigPi_j[4], pij, bigPij, pis[4];

	pis[0] = piA;
	pis[1] = piC;
	pis[2] = piG;
	pis[3] = piT;
	beta = 0.5 / ((piA + piG)*(piC + piT) + k*((piA*piG) + (piC*piT)));

	bigPi_j[0] = piA + piG;
	bigPi_j[1] = piC + piT;
	bigPi_j[2] = piA + piG;
	bigPi_j[3] = piC + piT;

	t = time * r;

	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			bigPij = bigPi_j[j];
			pij = pis[j];
			u = 1.0/bigPij - 1.0;
			w = -beta * (1.0 + bigPij * (k - 1.0));
			x = exp(-beta * t);
			y = exp(w * t);
			z = (bigPij - pij) / bigPij;
			if (i == j)
				ch_prob[i][j] = pij * u * (-beta) * r * x + z * w * r * y;
			else if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 3) || (i == 3 && j == 1))
				ch_prob[i][j] = pij * u * (-beta) * r * x - (pij/bigPij) * w * r * y;
			else
				ch_prob[i][j] = (beta) * pij * r * x;
			}
		}

#	if defined (SHOWTIPROBS)
	printf ("Change probabilities (first dv) (HKY 85, time = %lf):\n", time);
	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			printf ("%lf ", ch_prob[i][j]);
			}
		printf ("\n");
		}
#	endif

}





void HkySecondMat (double **ch_prob, double time, double k, double r, double piA, double piC, double piG, double piT)

{

	int		i, j;
	double	t, u, w, x, y, z, beta, bigPi_j[4], pij, bigPij, pis[4];

	pis[0] = piA;
	pis[1] = piC;
	pis[2] = piG;
	pis[3] = piT;
	beta = 0.5 / ((piA + piG)*(piC + piT) + k*((piA*piG) + (piC*piT)));

	bigPi_j[0] = piA + piG;
	bigPi_j[1] = piC + piT;
	bigPi_j[2] = piA + piG;
	bigPi_j[3] = piC + piT;

	t = time * r;

	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			bigPij = bigPi_j[j];
			pij = pis[j];
			u = 1.0/bigPij - 1.0;
			w = -beta * (1.0 + bigPij * (k - 1.0));
			x = exp(-beta * t);
			y = exp(w * t);
			z = (bigPij - pij) / bigPij;
			if (i == j)
				ch_prob[i][j] = pij * u * beta * beta * r * r* x + z * w * w * r * r * y;
			else if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 3) || (i == 3 && j == 1))
				ch_prob[i][j] = pij * u * beta * beta * r * r * x - (pij/bigPij) * w * w * r * r * y;
			else
				ch_prob[i][j] = - beta * beta * pij * r * r * x;
			}
		}

#	if defined (SHOWTIPROBS)
	printf ("Change probabilities (first dv) (HKY 85, time = %lf):\n", time);
	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			printf ("%lf ", ch_prob[i][j]);
			}
		printf ("\n");
		}
#	endif

}





double IncompleteBetaFunction (double alpha, double beta, double x)

{

	double		bt, gm1, gm2, gm3, temp;
	
	if (x < 0.0 || x > 1.0)
		{
		printf ("Error in IncompleteBetaFunction.\n");
		exit (-1);
		}
	if (x == 0.0 || x == 1.0)
		{
		bt = 0.0;
		}
	else
		{
		gm1 = LnGamma (alpha + beta);
		gm2 = LnGamma (alpha);
		gm3 = LnGamma (beta);
		temp = gm1 - gm2 - gm3 + (alpha) * log(x) + (beta) * log(1.0 - x);
		bt = exp(temp);
		}
	if (x < (alpha + 1.0)/(alpha + beta + 2.0))
		return (bt * BetaCf(alpha, beta, x) / alpha);
	else
		return (1.0 - bt * BetaCf(beta, alpha, 1.0-x) / beta);

}





int InitializeConditionalLikes (int numTaxa, int numChars, int numRateCats)

{

	int		i, b, c, s, s1, s2, s3, k, n, *nuc1, cd1[4], cd2[4], cd3[4], 
	        oneMatSize, nNucs, aaId, rsId, foundCodon, nLocalStates;
	double	*cl0, *cl1, uncertObs, uncertUnobs;
	
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		if (!strcmp(codonModelType, "covny98"))
			nLocalStates = 3 * nStates;
		else
			nLocalStates = nStates;
		}
	else
		{
		if (useCovarion == YES)
			nLocalStates = 2 * nStates;
		else
			nLocalStates = nStates;
		}
		
	printf ("      Initializing conditional likelihoods\n");
	oneMatSize = numNodes * numChars * numRateCats * nLocalStates * numBetaCats;

	nuc1 = (int *)malloc((size_t) (nStates * sizeof(int)));
	if (!nuc1)
		{
		printf ("ERROR: Problem allocating nuc1\n");
		return (ERROR);
		}

	condLike = (double *)malloc((size_t) (numChains * 2 * oneMatSize * sizeof(double)));
	if (!condLike)
		{
		printf ("\n   ERROR: Problem allocating conditional likelihoods.\n");
		printf ("          Try allocating more memory to the program or\n");
		printf ("          running the program on a computer with more\n");
		printf ("          memory.\n");
		free (nuc1);
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_COND_LIKES] = YES;
				
#	if defined (SUPER_FAST)
	isPartAmbig = (int *)malloc((size_t) ((numTaxa + numTaxa * numChars) * sizeof(int)));
	if (!isPartAmbig)
		{
		printf ("ERROR: Problem allocating isPartAmbig and termStates\n");
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_TERM_STATES] = YES;
	termState = isPartAmbig + numTaxa;
#	endif

	for (i=0; i<numChains*2*oneMatSize; i++)
		condLike[i] = 0.0;
		
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		/* 61 X 61 model of DNA substitution */
		for (n=0; n<numChains; n++)
			{
			for (i=0; i<numTaxa; i++)
				{
				cl0 = &condLike[n*2*oneMatSize + 0*oneMatSize + i*numChars*numRateCats*nLocalStates];
				cl1 = &condLike[n*2*oneMatSize + 1*oneMatSize + i*numChars*numRateCats*nLocalStates];
				for (c=0; c<numChars; c++, *(cl0+=(numRateCats*nLocalStates)), *(cl1+=(numRateCats*nLocalStates)))
					{
					GetPossibleNucs (matrix[pos(i,c*3  ,numChars*3)], cd1);
					GetPossibleNucs (matrix[pos(i,c*3+1,numChars*3)], cd2);
					GetPossibleNucs (matrix[pos(i,c*3+2,numChars*3)], cd3);
										
					s = 0;
					foundCodon = NO;
					for (s1=0; s1<4; s1++)
						{
						for (s2=0; s2<4; s2++)
							{
							for (s3=0; s3<4; s3++)
								{
								if (cd1[s1] == 1 && cd2[s2] == 1 && cd3[s3] == 1 && codon[16*s1 + 4*s2 + s3] != 21)
									{
									for (k=0; k<numRateCats; k++)
										{
										cl0[k*nLocalStates+s] = 1.0;
										cl1[k*nLocalStates+s] = 1.0;
										if (!strcmp(codonModelType, "covny98"))
											{
											cl0[k*nLocalStates+(nStates + s)] = 1.0;
											cl1[k*nLocalStates+(nStates + s)] = 1.0;
											cl0[k*nLocalStates+(2*nStates + s)] = 1.0;
											cl1[k*nLocalStates+(2*nStates + s)] = 1.0;
											}
										}
									foundCodon = YES;
									}
								if (codon[16*s1 + 4*s2 + s3] != 21)
									s++;
								}
							}
						}
						
					if (foundCodon == NO)
						{
						printf ("\n   ERROR: Found stop codon at taxon %d and sites %d, %d, and %d\n", i+1, c*3+1, c*3+2, c*3+3);
						printf ("%d%d%d%d %d%d%d%d %d%d%d%d\n", cd1[0], cd1[1], cd1[2], cd1[3], cd2[0], cd2[1], cd2[2], cd2[3], cd3[0], cd3[1], cd3[2], cd3[3]);
						free (nuc1);
						FreeMemory ();
						return (ERROR);
						}
					
					}
				}
			}
		}
	else
		{
		/* 2 X 2 or 4 X 4 or 20 X 20 model of substitution */
		for (n=0; n<numChains; n++)
			{
			for (i=0; i<numTaxa; i++)
				{
				cl0 = &condLike[n*2*oneMatSize + 0*oneMatSize + i*numChars*numRateCats*numBetaCats*nLocalStates];
				cl1 = &condLike[n*2*oneMatSize + 1*oneMatSize + i*numChars*numRateCats*numBetaCats*nLocalStates];
				for (c=0; c<numChars; c++, *(cl0+=(numRateCats*nLocalStates*numBetaCats)), *(cl1+=(numRateCats*nLocalStates*numBetaCats)))
					{
					if (dataType == DNA || dataType == RNA)
						{
						GetPossibleNucs (matrix[pos(i,c,numChars)], nuc1);
						nNucs = 0;
						for (s=0; s<nStates; s++)
							if (nuc1[s] == 1)
								nNucs++;
						uncertObs   = 1.0;
						uncertUnobs = 0.0;
						if (nNucs == 1)
							{
							uncertObs   = 1.0 - seqErrorProb;
							uncertUnobs = seqErrorProb / 3.0;
							}
						else if (nNucs == 2)
							{
							uncertObs   = 1.0 - (2.0 * seqErrorProb / 3.0);
							uncertUnobs = 2.0 * seqErrorProb / 3.0;
							}
						else if (nNucs == 3)
							{
							uncertObs   = 1.0 - (seqErrorProb / 3.0);
							uncertUnobs = seqErrorProb;
							}
						
						for (s=0; s<nStates; s++)
							{
							if (nuc1[s] == 1)
								{
								for (k=0; k<numRateCats; k++)
									{
									cl0[k*nLocalStates+s] = uncertObs;
									cl1[k*nLocalStates+s] = uncertObs;
									}
								}
							else
								{
								for (k=0; k<numRateCats; k++)
									{
									cl0[k*nLocalStates+s] = uncertUnobs;
									cl1[k*nLocalStates+s] = uncertUnobs;
									}
								}
							}
						if (useCovarion == YES)
							{
							for (s=0; s<nStates; s++)
								{
								if (nuc1[s] == 1)
									{
									for (k=0; k<numRateCats; k++)
										{
										cl0[k*nLocalStates+(nStates+s)] = uncertObs;
										cl1[k*nLocalStates+(nStates+s)] = uncertObs;
										}
									}
								else
									{
									for (k=0; k<numRateCats; k++)
										{
										cl0[k*nLocalStates+(nStates+s)] = uncertUnobs;
										cl1[k*nLocalStates+(nStates+s)] = uncertUnobs;
										}
									}
								}
							}
							
						}
					else if (dataType == PROTEIN)
						{
						uncertObs   = 1.0 - seqErrorProb;
						uncertUnobs = seqErrorProb / 19.0;
						aaId = matrix[pos(i,c,numChars)];
						for (k=0; k<numRateCats; k++)
							{
							for (s=0; s<nStates; s++)
								{
								cl0[k*nLocalStates+s] = uncertUnobs;
								cl1[k*nLocalStates+s] = uncertUnobs;
								}
							}
						if (aaId > 0 && aaId <= 20)
							{
							for (k=0; k<numRateCats; k++)
								{
								cl0[k*nLocalStates + (aaId-1)] = uncertObs;
								cl1[k*nLocalStates + (aaId-1)] = uncertObs;
								}
							}
						else
							{
							for (k=0; k<numRateCats; k++)
								{
								for (s=0; s<nStates; s++)
									{
									cl0[k*nLocalStates+s] = 1.0;
									cl1[k*nLocalStates+s] = 1.0;
									}
								}
							}
						if (useCovarion == YES)
							{
							for (k=0; k<numRateCats; k++)
								{
								for (s=0; s<nStates; s++)
									{
									cl0[k*nLocalStates+(nStates+s)] = uncertUnobs;
									cl1[k*nLocalStates+(nStates+s)] = uncertUnobs;
									}
								}
							if (aaId > 0 && aaId <= 20)
								{
								for (k=0; k<numRateCats; k++)
									{
									cl0[k*nLocalStates + nStates+(aaId-1)] = uncertObs;
									cl1[k*nLocalStates + nStates+(aaId-1)] = uncertObs;
									}
								}
							else
								{
								for (k=0; k<numRateCats; k++)
									{
									for (s=0; s<nStates; s++)
										{
										cl0[k*nLocalStates+(nStates+s)] = 1.0;
										cl1[k*nLocalStates+(nStates+s)] = 1.0;
										}
									}
								}
							}
						}
					else if (dataType == RESTRICTION)
						{
						rsId = matrix[pos(i,c,numChars)];
						uncertObs   = 1.0;
						uncertUnobs = 0.0;
						for (k=0; k<numRateCats; k++)
							{
							if (rsId == 1)
								{
								cl0[k*nLocalStates+0] = uncertObs;
								cl0[k*nLocalStates+1] = uncertUnobs;
								cl1[k*nLocalStates+0] = uncertObs;
								cl1[k*nLocalStates+1] = uncertUnobs;
								}
							else if (rsId == 2)
								{
								cl0[k*nLocalStates+0] = uncertUnobs;
								cl0[k*nLocalStates+1] = uncertObs;
								cl1[k*nLocalStates+0] = uncertUnobs;
								cl1[k*nLocalStates+1] = uncertObs;
								}
							else
								{
								cl0[k*nLocalStates+0] = 1.0;
								cl0[k*nLocalStates+1] = 1.0;
								cl1[k*nLocalStates+0] = 1.0;
								cl1[k*nLocalStates+1] = 1.0;
								}
							}
						}
					else if (dataType == STANDARD)
						{
						rsId = matrix[pos(i,c,numChars)];
						uncertObs   = 1.0;
						uncertUnobs = 0.0;
						for (k=0; k<numRateCats; k++)
							{
							for (b=0; b<numBetaCats; b++)
								{
								if (rsId == 1)
									{
									cl0[k*numBetaCats*nLocalStates + b*nLocalStates + 0] = uncertObs;
									cl0[k*numBetaCats*nLocalStates + b*nLocalStates + 1] = uncertUnobs;
									cl1[k*numBetaCats*nLocalStates + b*nLocalStates + 0] = uncertObs;
									cl1[k*numBetaCats*nLocalStates + b*nLocalStates + 1] = uncertUnobs;
									}
								else if (rsId == 2)
									{
									cl0[k*numBetaCats*nLocalStates + b*nLocalStates + 0] = uncertUnobs;
									cl0[k*numBetaCats*nLocalStates + b*nLocalStates + 1] = uncertObs;
									cl1[k*numBetaCats*nLocalStates + b*nLocalStates + 0] = uncertUnobs;
									cl1[k*numBetaCats*nLocalStates + b*nLocalStates + 1] = uncertObs;
									}
								else
									{
									cl0[k*numBetaCats*nLocalStates + b*nLocalStates + 0] = 1.0;
									cl0[k*numBetaCats*nLocalStates + b*nLocalStates + 1] = 1.0;
									cl1[k*numBetaCats*nLocalStates + b*nLocalStates + 0] = 1.0;
									cl1[k*numBetaCats*nLocalStates + b*nLocalStates + 1] = 1.0;
									}
								}
							}
						}
					}
				}
			}
		}

#	if defined (SUPER_FAST)
	/*set termStates and isPartAmbig */
	for (i=0; i<numTaxa; i++)
		isPartAmbig[i] = NO;

	/* find the right pointer values depending on terminal state and model */
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		/* 61 x 61 codon models and derivatives (switch models) */
		{
		b = 0;
		for (i=0; i<numTaxa; i++)
			{
			for (c=0; c<numChars; c++)
				{
				GetPossibleNucs (matrix[pos(i,c*3  ,numChars*3)], cd1);
				GetPossibleNucs (matrix[pos(i,c*3+1,numChars*3)], cd2);
				GetPossibleNucs (matrix[pos(i,c*3+2,numChars*3)], cd3);
									
				s = 0;
				nNucs = 0;
				for (s1=0; s1<4; s1++)
					{
					for (s2=0; s2<4; s2++)
						{
						for (s3=0; s3<4; s3++)
							{
							if (cd1[s1] == 1 && cd2[s2] == 1 && cd3[s3] == 1)
								{
								termState[b] = s * nLocalStates;
								nNucs ++;
								}
							if (codon[16*s1 + 4*s2 + s3] != 21)
								s++;
							}
						}
					}
				if (nNucs > 1)
					{
					if (nNucs == 64)	//all states are possible
						termState[b] = nStates * nLocalStates;
					else
						isPartAmbig[i] = YES;
					}
				b++;
				}
			}
		}
	else if (dataType == DNA || dataType == RNA) 
		/* 4 x 4 DNA or RNA model */
		{
		b = 0;
		for (i=0; i<numTaxa; i++)
			{
			for (c=0; c<numChars; c++)
				{
				GetPossibleNucs(matrix[b],nuc1);
				nNucs = 0;
				for (s=0; s<nStates; s++)
					if (nuc1[s] == 1)
						nNucs++;
				if (nNucs == 2 || nNucs == 3)
					isPartAmbig[i] = YES;
				else if (nNucs == 0 || nNucs == 4)
					termState[b] = 16;
				else if (nNucs == 1)
					{
					if (nuc1[A] == 1)
						termState[b] = 0;
					if (nuc1[C] == 1)
						termState[b] = 4;
					if (nuc1[G] == 1)
						termState[b] = 8;
					if (nuc1[T] == 1)
						termState[b] = 12;
					}
				b++;
				}
			}
		}
	else if (dataType == PROTEIN)
		{
		for (i=b=0; i<numTaxa; i++)
			{
			for (c=0; c<numChars; c++)
				{
				aaId = matrix[pos(i,c,numChars)];
				if (aaId > 0 && aaId <= 20)
					termState[b] = (aaId - 1) * 20;
				else
					termState[b] = 20 * 20;
				b++;
				}
			}
		}

	if (useCovarion == YES)		// nStates is doubled if covarion model is used
		{
		for (i=b=0; i<numTaxa; i++)
			{
			for (c=0; c<numChars; c++)
				{
				termState[b++] *= 2;
				}
			}
		}

#	endif

	/* allocate space for clScaler */
	clScaler = (double *)calloc(numChains * 2 * numIntNodes * numChars, sizeof(double));
	if (!clScaler)
		{
		printf ("\n   ERROR: Problem allocating clScaler\n");
		free (nuc1);
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_COND_SCALER] = YES;

	/* allocate space for lnSiteScaler */
	lnSiteScaler = (double *)calloc(numChains * 2 * numChars, sizeof(double));		
	if (!lnSiteScaler)
		{
		printf ("\n   ERROR: Problem allocating lnSiteScaler\n");
		free (nuc1);
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_LN_SITE_SCALER] = YES;

	free (nuc1);

#	if defined (DEBUG_INITCONDLIKES)
	for (c=0; c<numChars; c++)
		{
		int j;
		printf ("%3d: ", c);
		for (i=0; i<numTaxa; i++)
			{
			cl0 = &condLike[0*2*oneMatSize + 0*oneMatSize + i*numChars*numRateCats*nLocalStates];
			cl0 += nLocalStates*numRateCats*c;
			for (k=0; k<numRateCats; k++)
				{
				for (j=0; j<nLocalStates; j++)
					printf("%1.0lf", cl0[k*nLocalStates + j]);
				}
			printf ("\n     ");
			}
		}
#	endif
	
	return (NO_ERROR);
		
}





int InitializeTipStates (int numTaxa, int numChars)

{

	int				i, c, s, n, 
	        		oneMatSize, aaId, rsId;
	unsigned int	st, *cl, x;
			
	printf ("      Initializing tip states\n");
	oneMatSize = numNodes * numChars;

	stateSet = (unsigned int *)malloc((size_t) (numChains * oneMatSize * sizeof(unsigned int)));
	if (!stateSet)
		{
		printf ("\n   ERROR: Problem allocating state set.\n");
		printf ("          Try allocating more memory to the program or\n");
		printf ("          running the program on a computer with more\n");
		printf ("          memory.\n");
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_COND_LIKES] = YES;
	for (i=0; i<numChains*oneMatSize; i++)
		stateSet[i] = 0;
		
	/* 2 X 2 or 4 X 4 or 20 X 20 model of substitution */
	for (n=0; n<numChains; n++)
		{
		for (i=0; i<numTaxa; i++)
			{
			cl = &stateSet[n*oneMatSize + i*numChars];
			for (c=0; c<numChars; c++)
				{
				if (dataType == DNA || dataType == RNA)
					{
					cl[c] = matrix[pos(i,c,numChars)];
					}
				else if (dataType == PROTEIN)
					{
					aaId = matrix[pos(i,c,numChars)];
					st = 0;

					if (aaId > 0 && aaId <= 20)
						{
						x = 1 << (aaId-1);
						cl[c] = x;
						//printf ("%d -> %d\n", aaId, cl[c]);
						}
					else
						{
						cl[c] = 0;
						for (s=0; s<20; s++)
							{
							x = 1 << s;
							cl[c] |= x;
							}
						//printf ("%d -> %d\n", aaId, cl[c]);
						}
					}
				else if (dataType == RESTRICTION)
					{
					rsId = matrix[pos(i,c,numChars)];
					if (rsId == 1)
						{
						cl[c] = 1;
						}
					else if (rsId == 2)
						{
						cl[c] = 2;
						}
					else
						{
						cl[c] = 3;
						}
					}
				else if (dataType == STANDARD)
					{
					rsId = matrix[pos(i,c,numChars)];
					if (rsId == 1)
						{
						cl[c] = 1;
						}
					else if (rsId == 2)
						{
						cl[c] = 2;
						}
					else
						{
						cl[c] = 3;
						}
					}
				}
			}
		}

	return (NO_ERROR);
		
}





int InitTiMatrix (double m[3][3], double x, double y, double z, double pPurifying, double pNeutral, double pPositive, int model)

{

	if (model == 1)
		{
		m[0][1] = (1.0 - x) * pNeutral;
		m[0][2] = (1.0 - x) * pPositive;
		m[1][0] = (1.0 - x) * pPurifying;
		m[1][2] = (1.0 - x) * pPositive;
		m[2][0] = (1.0 - x) * pPurifying;
		m[2][1] = (1.0 - x) * pNeutral;
		m[0][0] = 1.0 - (m[0][1] + m[0][2]);
		m[1][1] = 1.0 - (m[1][0] + m[1][2]);
		m[2][2] = 1.0 - (m[2][0] + m[2][1]);
		}
	else if (model == 2)
		{
		m[0][1] = (1.0 - x) * pNeutral;
		m[0][2] = (1.0 - y) * pPositive;
		m[1][0] = (1.0 - x) * pPurifying;
		m[1][2] = (1.0 - z) * pPositive;
		m[2][0] = (1.0 - y) * pPurifying;
		m[2][1] = (1.0 - z) * pNeutral;
		m[0][0] = 1.0 - (m[0][1] + m[0][2]);
		m[1][1] = 1.0 - (m[1][0] + m[1][2]);
		m[2][2] = 1.0 - (m[2][0] + m[2][1]);
		}
	else
		{
		return (ERROR);
		}
		
#	if 0
	{
	int		i, j;
	printf ("%lf %lf %lf %lf %lf %lf (%d)\n", x, y, z, pPurifying, pNeutral, pPositive, model);
	for (i=0; i<3; i++)
		{
		for (j=0; j<3; j++)
			{
			printf ("%lf ", m[i][j]);
			}
		printf ("\n");
		}
	}
#	endif

	return (NO_ERROR);

}





int IsKink (TreeNode *p)

{

	int		numMarked;

	if (p->anc == NULL)
		return (YES);
		
	if (p->anc->marked == NO) /* added 4/20/00 */
		return (YES);
		
	numMarked = 0;
	if (p->left != NULL)
		if (p->left->marked == YES)
			numMarked++;
	if (p->right != NULL)
		if (p->right->marked == YES)
			numMarked++;
	
	if (numMarked == 2)
		return (YES);
	
	return (NO);

}




int IsLeaf (TreeNode *p)

{

	if (p->left == NULL || p->right == NULL || p->anc == NULL)
		return (YES);
	
	return (NO);

}





int LnBDPrior (int whichState, int whichChain, int numTaxa, double *prob)

{

	int			i, j;
	double		sR, eR, sF, rootTime, *nt;
	TreeNode	*p;

	sR = spRate[whichChain*2 + whichState];
	eR = exRate[whichChain*2 + whichState];
	sF = samplingFraction;

	rootTime = root[whichChain*2+whichState]->left->nodeTime;
	if (enforceCalibrations == NO)
		{
		/* get node times */
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + whichState*numNodes + i];
			if (p->left == NULL && p->right == NULL)
				p->nodeTime = 0.0;
			else
				p->nodeTime += p->left->nodeTime + p->left->length;
			}
		
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + whichState*numNodes + i];
			if (p->left == NULL && p->right == NULL)
				p->nodeTime = 0.0;
			else
				p->nodeTime /= rootTime;
			}
		}
					
	/* allocate memory */
	nt = (double *)malloc((size_t) (numTaxa-1) * sizeof(double));
	if (!nt)
		{
		printf ("\n   ERROR: Problem allocating nt\n");
		return (ERROR);
		}

	/* put node times into vector */
	j = 0;
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + whichState*numNodes + i];
		if (p->left != NULL && p->right != NULL && p->anc != NULL)
			{
			nt[j] = p->nodeTime;
			j++;
			}
		}
#	if 0
	for (i=0; i<numTaxa-1; i++)
		printf ("%d %lf\n", i, nt[i]);
	printf ("sr = %lf er = %lf sf = %lf rt = %lf\n", sR, eR, sF, rootTime);
#	endif
		
	/* calculate probabilities of tree */
	(*prob) = (numTaxa-2)*log(sR);
	for (i=0; i<numTaxa-2; i++)
		{
		(*prob) += lnP1(nt[i], sR, eR, sF) - lnVt(rootTime, sR, eR, sF);
		}
		
	free (nt);
	
	return (NO_ERROR);
		
}





double LnGamma (double alp)

{

	double 		x = alp, f = 0.0, z;
	
	if (x < 7) 
		{
		f = 1.0;  
		z = x-1.0;
		while (++z < 7.0)  
			f *= z;
		x = z;   
		f = -log(f);
		}
	z = 1.0/(x*x);
	return  (f + (x-0.5)*log(x) - x + 0.918938533204673 + 
			(((-0.000595238095238*z+0.000793650793651)*z-0.002777777777778)*z +
			0.083333333333333)/x);  

}





int LnLike (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)

{

	double		x;
	
	x = 0.0;
	
#	if defined (SMART_TI_PROBS)
	//UpDateAllTIs (whichState, whichChain); 
	if (CalcTransitionProbs (whichState, whichChain, numRateCats) == ERROR)
		return (ERROR);
#	endif

	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == NO)
		{
		if (useCovarion == NO)
			{
			if (LnLikeDNA (whichState, whichChain, numChars, numRateCats, &x, refreshScalers) == ERROR)
				return (ERROR);
			}
		else
			{
			if (LnLikeCovarion (whichState, whichChain, numChars, numRateCats, &x, refreshScalers) == ERROR)
				return (ERROR);
			}
		}
	else if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		if (useCovarion == NO)
			{
			if (LnLikeCodon (whichState, whichChain, numChars, &x, refreshScalers) == ERROR)
				return (ERROR);
			}
		else
			{
			return (ERROR);
			}
		}
	else if (dataType == PROTEIN)
		{
		if (useCovarion == NO)
			{
			if (LnLikeAA (whichState, whichChain, numChars, numRateCats, &x, refreshScalers) == ERROR)
				return (ERROR);
			}
		else
			{
			if (LnLikeCovarion (whichState, whichChain, numChars, numRateCats, &x, refreshScalers) == ERROR)
				return (ERROR);
			}
		}
	else if (dataType == RESTRICTION)
		{
		if (useCovarion == NO)
			{
			if (LnLikeRestriction (whichState, whichChain, numChars, numRateCats, &x, refreshScalers) == ERROR)
				return (ERROR);
			}
		else
			{
			return (ERROR);
			}
		}
	else if (dataType == STANDARD)
		{
		if (useCovarion == NO)
			{
			// TODO: split this between LnLikeStandardBinF and LnLikeStandardMkF
			if (LnLikeStandardBin (whichState, whichChain, numChars, numRateCats, &x, refreshScalers) == ERROR)
				return (ERROR);
			}
		else
			{
			return (ERROR);
			}
		}
	else
		return (ERROR);
		
	(*lnL) = x;
		
	return (NO_ERROR);
	
}



# if !defined (SUPER_FAST)

/*-----------------------------------------------------------
LnLikeAA: 'Fast' version, core written 2001-03-12
------------------------------------------------------------*/
int LnLikeAA (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
#	define N_STATES_SQUARED 400
#	define N_STATES 20

	register int	i, j, k, c, n, m, cn, h;
	int				lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					index, nRates, pat, localLag, *usedBin,
					intNodeOffset, condLikeOffset, scalerOffset;
	double			bs[N_STATES], *catFreq, *catRate, *partRate,
					*clL, *clR, *clA, *clP, *scP, *pL, *pR, *pA,
					*lnScaler, scaler, like, lnC, *biN, max, temp, correlation,
					*ratePr, **markovTi, likeL, likeR, likeA;
	TreeNode		*p;
#	if !defined (SMART_TI_PROBS)
	int				nPij, isComplex, indexL, indexR, indexA;
	double			theRate, **probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk;
	complex 		**Ceigvecs, **CinverseEigvecs;	
#	else
	int				nForOneState;
#	endif

	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* initialize intNodeOffset */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;

	/* load base frequencies */
	index = whichChain*2*N_STATES + whichState*N_STATES;
	for (i=0; i<N_STATES; i++)
		bs[i] = baseFreq[index + i];
		
	/* how many different rates? */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1 */
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1 */
	/* the code introduced here only makes sure that the number of partitions */
	/* or rate categories is set to 1 when appropriate, in case the global variables */
	/* are not set to 1 when they are not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;

	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible rate */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (N_STATES);
	nPij = nRates * N_STATES_SQUARED;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for autocorrelated gamma models */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		ratePr = (double *)malloc((size_t) (lnumRateCats * (numChars + nChar) * sizeof(double)));
		if (!ratePr)
			{
			printf ("\n   ERROR: Problem allocating ratePr and biN.\n");
			goto error_exit;
			}
		biN = ratePr + lnumRateCats * numChars;
		usedBin = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!usedBin)
			{
			printf ("\n   ERROR: Problem allocating usedBin.\n");
			goto error_exit;
			}
		}

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* get eigenvalues and eigenvectors for AAQ matrix */
#	if !defined (SMART_TI_PROBS)
	q = psdmatrix (N_STATES);
	eigenValues = (double *)malloc((size_t) (2 * N_STATES * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + N_STATES;
	eigvecs = psdmatrix (N_STATES);
	inverseEigvecs = psdmatrix (N_STATES);
	Ceigvecs = pscmatrix (N_STATES);
	CinverseEigvecs = pscmatrix (N_STATES);
	if (SetAAQMatrix (q, whichState, whichChain) == ERROR)
		goto error_exit;
	isComplex = GetEigens (N_STATES, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
	if (isComplex == NO)
		{
		c_ijk = (double *)malloc((size_t) (8000 * sizeof(double)));
		if (!c_ijk)
			{
			printf ("\n   ERROR: Problem allocating c_ijk.\n");
			goto error_exit;
			}
		CalcCijk (c_ijk, N_STATES, eigvecs, inverseEigvecs);
		}
#	endif
		
	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * N_STATES;
	oneNodeSize = numChars * lnumRateCats * N_STATES;

	/* calculate indices */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
#				else
				for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						// calculate transition probabilities for left branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->left->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->left->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->right->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->right->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pR[indexR++] = probs[i][j];

						// calculate transition probabilities for ancestral branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pA[indexA++] = probs[i][j];
						}
					}
#				endif

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(ratesModel, "equal"))
					{
					for (c=0; c<numChars; c++)
						{
						for (i=m=0; i<N_STATES; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (j=0; j<N_STATES; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m]*clR[j];
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						clL += N_STATES;
						clR += N_STATES;
						clA += N_STATES;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=h=0; c<numChars; c++)
						{
						for (k=m=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								clP[h++] = likeL * likeR * likeA;
								}
							clL += N_STATES;
							clR += N_STATES;
							clA += N_STATES;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += N_STATES;
							clR += N_STATES;
							clA += N_STATES;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*N_STATES_SQUARED;
						for (i=0; i<N_STATES; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (j=0; j<N_STATES; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m]*clR[j];
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						clL += N_STATES;
						clR += N_STATES;
						clA += N_STATES;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for internal root node
			}	// done with internal root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting interior node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
#				else
				for (m=indexL=indexR=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						// calculate transition probabilities for left branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->left->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->left->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->right->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->right->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pR[indexR++] = probs[i][j];						
						}
					}
#				endif

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(ratesModel, "equal"))
					{
					for (c=0; c<numChars; c++)
						{
						for (i=m=0; i<N_STATES; i++)
							{
							likeL = likeR = 0.0;
							for (j=0; j<N_STATES; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m++]*clR[j];
								}
							*(clP++) = likeL * likeR;
							}
						clL += N_STATES;
						clR += N_STATES;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=h=0; c<numChars; c++)
						{
						for (k=m=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								clP[h++] = likeL * likeR;
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						}
					for (c=h=0; c<numChars; c++)
						{
						for (k=m=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								if (clP[h] < 0 || clP[h] >1.0)
									printf("");
								h++;
								}
							}
						}

					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*N_STATES_SQUARED;
						for (i=0; i<N_STATES; i++)
							{
							likeL = likeR = 0.0;
							for (j=0; j<N_STATES; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m++]*clR[j];
								}
							*(clP++) = likeL * likeR;
							}
						clL += N_STATES;
						clR += N_STATES;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		
		// deal with scaling
		// first check if we need to refresh scalers and potentially shift scaler nodes
		// we have to remember scalerIndex because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0) 
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<N_STATES; m++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}
					}
				
				 for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<N_STATES; m++)
						clP[j++] /= scaler;
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}
			
		}	// next node
		
	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	(*lnL) = 0.0;	// reset lnL
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (i=0; i<N_STATES; i++)
				like += ((*(clP++)) * bs[i]);

			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				for (i=0; i<N_STATES; i++)
					like += ((*(clP++)) * bs[i]) * catFreq[k];
				}
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		/* initialize usedBin */	
		for (i=0; i<nChar; i++)
			usedBin[i] = NO;
		
		lnC = 0.0;
		m = j = 0;
		for (c=0; c<numChars; c++)
			{
			for (k=0; k<lnumRateCats; k++)
				{
				like = 0.0;
				for (i=0; i<N_STATES; i++)
					like += clP[j++] * bs[i];
				ratePr[m++] = like;
				}
			lnC += (lnScaler[c] * numSitesOfPat[c]);
			}
		localLag = lag[whichChain*2 + whichState];

		for (c=nChar-1; c>=0; c--)
			{
			cn = c*lnumRateCats;
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				if (c + localLag >= nChar)
					{
					max = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						biN[cn + k] = ratePr[pat*lnumRateCats + k];
						if (biN[cn + k] > max)
							max = biN[cn + k];
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}				
				else
					{
					for (i=0; i<lnumRateCats; i++)
						{
						temp = max = 0.0;
						for (j=0; j<lnumRateCats; j++)
							temp += markovTi[i][j] * biN[(c+localLag)*lnumRateCats + j];
						biN[cn + i] = ratePr[pat*lnumRateCats+i] * temp;
						if (biN[cn + i] > max)
							max = biN[cn + i];
						usedBin[c+localLag] = YES;
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				}
			else
				{
				printf ("   ERROR: Unidentified pattern\n");
				goto error_exit;
				}
			}
		(*lnL) = lnC;
		for (c=0; c<nChar; c++)
			{
			if (usedBin[c] == NO)
				{
				temp = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					temp += (catFreq[k] * biN[c*lnumRateCats + k]);
					}
				(*lnL) += log(temp);
				usedBin[c] = YES;
				}
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	if (isComplex != YES)
		free (c_ijk);
#	endif
	free (catFreq);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (ratePr);
		free (usedBin);
		}
	return (NO_ERROR);
	
	error_exit:
#		if !defined (SMART_TI_PROBS)
		free_psdmatrix (probs);
		free (pL);
		free_psdmatrix (q);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex != YES)
			free (c_ijk);
#		endif
		free (catFreq);
		if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			free_psdmatrix(markovTi);
			free (ratePr);
			free (usedBin);
			}
		return (ERROR);

#	undef N_STATES_SQUARED
#	undef N_STATES
}





/*-----------------------------------------------------------
LnLikeCodon: 'Fast' version, core written 2001-03-21
------------------------------------------------------------*/
int LnLikeCodon (int whichState, int whichChain, int numChars, double *lnL, int refreshScalers)

{

	register int	i, j, k, c, n, m, cn;
	int				nOmegaCats, oneMatSize, oneNodeSize,
					index, pat, isFirst,
					intNodeOffset, condLikeOffset, scalerOffset,
					lnStates, lnStatesSquared, lnStatesCube;
	double			*bs, *pL, *pR, *pA, *clL, *clR, *clA, *clP, *scP,
					*lnScaler, scaler, like, lnC, *biN, max, temp, *omegaPr, markovTi[3][3],
					likeL, likeR, likeA, likePos, likeNeu, likePur;
	TreeNode		*p;
#	if defined (SMART_TI_PROBS)
	int				nForOneState;
#	else
	int				nPij, isComplex, indexL, indexR, indexA, isComplex2, isComplex3;
	double			lkappa, theRate, **probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk,
					*eigenValues2, *eigvalsImag2, **eigvecs2, **inverseEigvecs2, *c_ijk2,
					*eigenValues3, *eigvalsImag3, **eigvecs3, **inverseEigvecs3, *c_ijk3;
	complex 		**Ceigvecs, **CinverseEigvecs, **Ceigvecs2, **CinverseEigvecs2,
					**Ceigvecs3, **CinverseEigvecs3;	
#	endif

	/* set number of states */
	if (!strcmp(codonModelType, "covny98"))
		lnStates = 3 * nStates;
	else
		lnStates = nStates;
	lnStatesSquared = lnStates * lnStates;
	lnStatesCube = lnStatesSquared * lnStates;
		
	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* load codon frequencies */
	bs = (double *)malloc((size_t) (lnStates * sizeof(double)));
	if (!bs)
		{
		printf ("\n   ERROR: Problem allocating bs.\n");
		goto error_exit;
		}
	index = whichChain*2*nStates + whichState*nStates;
	if (!strcmp(codonModelType, "covny98"))
		{
		k = 0;
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probPur[whichChain*2 + whichState];
			k++;
			}
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probNeu[whichChain*2 + whichState];
			k++;
			}
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probPos[whichChain*2 + whichState];
			k++;
			}
		}
	else
		{
		for (i=0; i<nStates; i++)
			bs[i] = baseFreq[index + i];
		}

	/* how many different omega categories */
	if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		nOmegaCats = 3;
	else
		nOmegaCats = 1;
						
	/* allocate memory for autocorrelated codon models */
	if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		omegaPr = (double *)malloc((size_t) (nOmegaCats * (numChars + nChar) * sizeof(double)));
		if (!omegaPr)
			{
			printf ("\n   ERROR: Problem allocating omegaPr and biN.\n");
			goto error_exit;
			}
		biN = omegaPr + nOmegaCats * numChars;
		}

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible omega value */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (lnStates);
	nPij = nOmegaCats * lnStatesSquared;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* allocate memory for eigenvalues and eigenvectors */
#	if !defined (SMART_TI_PROBS)
	q = psdmatrix (lnStates);
	eigenValues = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + lnStates;
	eigvecs = psdmatrix (lnStates);
	inverseEigvecs = psdmatrix (lnStates);
	Ceigvecs = pscmatrix (lnStates);
	CinverseEigvecs = pscmatrix (lnStates);

	/* get eigenvalues and eigenvectors for codon Q matrix */
	if (!strcmp(codonModelType, "covny98"))
		{
		if (SetCodonSwitchQMatrix (q, whichState, whichChain, omega[whichChain*2 + whichState], kappa[whichChain*2 + whichState], switchRate[whichChain*4 + whichState*2 + 0]) == ERROR)
			goto error_exit;
		}
	else
		{
		if (SetCodonQMatrix (q, whichState, whichChain, omega[whichChain*2 + whichState], kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		}
	isComplex = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
	if (isComplex == NO)
		{
		c_ijk = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
		if (!c_ijk)
			{
			printf ("\n   ERROR: Problem allocating c_ijk.\n");
			goto error_exit;
			}
		CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
		}
	if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		/* these models use several omega categories, one Q matrix needed for each */
		/* first set Q matrix for synonymous changes (negative selection) */
		eigenValues2 = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
		if (!eigenValues2)
			{
			printf ("\n   ERROR: Problem allocating eigenValues2 and eigvalsImag2.\n");
			goto error_exit;
			}
		eigvalsImag2 = eigenValues2 + lnStates;

		eigvecs2 = psdmatrix (lnStates);
		inverseEigvecs2 = psdmatrix (lnStates);
		Ceigvecs2 = pscmatrix (lnStates);
		CinverseEigvecs2 = pscmatrix (lnStates);

		if (SetCodonQMatrix (q, whichState, whichChain, 0.0, kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		isComplex2 = GetEigens (lnStates, q, eigenValues2, eigvalsImag2, eigvecs2, inverseEigvecs2, Ceigvecs2, CinverseEigvecs2);
		if (isComplex2 == NO)
			{
			c_ijk2 = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
			if (!c_ijk2)
				{
				printf ("\n   ERROR: Problem allocating c_ijk2.\n");
				goto error_exit;
				}
			CalcCijk (c_ijk2, lnStates, eigvecs2, inverseEigvecs2);
			}
		
		/* then set Q matrix for nonsynonymous changes (positive selection) */
		eigenValues3 = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
		if (!eigenValues2)
			{
			printf ("\n   ERROR: Problem allocating eigenValues2 and eigvalsImag2.\n");
			goto error_exit;
			}
		eigvalsImag3 = eigenValues2 + lnStates;

		eigvecs3 = psdmatrix (lnStates);
		inverseEigvecs3 = psdmatrix (lnStates);
		Ceigvecs3 = pscmatrix (lnStates);
		CinverseEigvecs3 = pscmatrix (lnStates);

		if (SetCodonQMatrix (q, whichState, whichChain, 1.0, kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		isComplex3 = GetEigens (lnStates, q, eigenValues3, eigvalsImag3, eigvecs3, inverseEigvecs3, Ceigvecs3, CinverseEigvecs3);
		if (isComplex3 == NO)
			{
			c_ijk3 = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
			if (!c_ijk3)
				{
				printf ("\n   ERROR: Problem allocating c_ijk3.\n");
				goto error_exit;
				}
			CalcCijk (c_ijk3, lnStates, eigvecs3, inverseEigvecs3);
			}
		}
#	endif
		
	/* how large is the information for one tree and one node */
	oneMatSize = numNodes * numChars * nOmegaCats * lnStates;
	oneNodeSize = numChars * nOmegaCats * lnStates;

	/* calculate index offsets */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
#				else
				indexL = indexR = indexA = 0;
				// calculate transition probabilities for left branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->left->length,  1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->left->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						pL[indexL++] = probs[i][j];
				
				// calculate transition probabilities for right branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->right->length, 1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->right->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						pR[indexR++] = probs[i][j];

				// calculate transition probabilities for ancestral branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->length, 1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
								pA[indexA++] = probs[i][j];
												
				if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
					{
					/* set transition probabilities for synonymous changes */
					// left branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->left->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->left->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pL[indexL++] = probs[i][j];
					// right branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->right->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->right->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pR[indexR++] = probs[i][j];
					// ancestral branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pA[indexA++] = probs[i][j];

					/* set transition probabilities for nonsynonymous changes */
					// left branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->left->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->left->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pL[indexL++] = probs[i][j];
					// right branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->right->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->right->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pR[indexR++] = probs[i][j];
					// ancestral branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pA[indexA++] = probs[i][j];
					}
#				endif

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
					{
					for (c=0; c<numChars; c++)
						{
						for (k=m=0; k<nOmegaCats; k++)
							{
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += lnStates;
							clR += lnStates;
							clA += lnStates;
							}
						}
					}
				else /* no omega variation or omega switch model */
					{
					for (c=0; c<numChars; c++)
						{
						for (i=m=0; i<lnStates; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (j=0; j<lnStates; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m]*clR[j];
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						clL += lnStates;
						clR += lnStates;
						clA += lnStates;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for internal root node
			}	// done with internal root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting interior node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
#				else
				indexL = indexR = 0;
				// calculate transition probabilities for left branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->left->length,  1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->left->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						pL[indexL++] = probs[i][j];
				
				// calculate transition probabilities for right branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->right->length, 1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->right->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						pR[indexR++] = probs[i][j];
						
				if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
					{
					/* set transition probabilities for synonymous changes */
					// left branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->left->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->left->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pL[indexL++] = probs[i][j];
					// right branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->right->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->right->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pR[indexR++] = probs[i][j];

					/* set transition probabilities for nonsynonymous changes */
					// left branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->left->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->left->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pL[indexL++] = probs[i][j];
					// right branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->right->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->right->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pR[indexR++] = probs[i][j];
					}
#				endif

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
					{
					for (c=0; c<numChars; c++)
						{
						for (k=m=0; k<nOmegaCats; k++)
							{
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += lnStates;
							clR += lnStates;
							}
						}
					}
				else /* no omega variation or omega switch model */
					{
					for (c=0; c<numChars; c++)
						{
						for (i=m=0; i<lnStates; i++)
							{
							likeL = likeR = 0.0;
							for (j=0; j<lnStates; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m++]*clR[j];
								}
							*(clP++) = likeL * likeR;
							}
						clL += lnStates;
						clR += lnStates;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		// deal with scaling
		// first check if we need to refresh scalers and potentially shift scaler nodes
		// we have to remember scalerIndex because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0)
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<nOmegaCats; k++)
					{
					for (m=0; m<lnStates; m++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}
					}
				for (k=0; k<nOmegaCats; k++)
					{
					for (m=0; m<lnStates; m++)
						clP[j++] /= scaler;
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}
		}	// next node
		
	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	(*lnL) = 0.0;	// reset lnL
	if (!strcmp(codonModelType, "ny98"))
		{
		for (c=0; c<numChars; c++)
			{
			likePur = likeNeu = likePos = 0.0;
			
			for (i=0; i<lnStates; i++)
				likePos += (*(clP++)) * bs[i];
			for (i=0; i<lnStates; i++)
				likePur += (*(clP++)) * bs[i];
			for (i=0; i<lnStates; i++)
				likeNeu += (*(clP++)) * bs[i];
				
			//printf ("%4d -- %lf %lf %lf (%lf)\n", c, likePur, likeNeu, likePos, like);
			like = likePos * probPos[whichChain*2 + whichState] + likePur * probPur[whichChain*2 + whichState] + likeNeu * probNeu[whichChain*2 + whichState];
								
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		if (!strcmp(codonModelType, "ac1ny98"))
			InitTiMatrix (markovTi, rateCorrelation[whichChain*2 + whichState], 0.0, 0.0, probPur[whichChain*2 + whichState], probNeu[whichChain*2 + whichState], probPos[whichChain*2 + whichState], 1);
		else
			InitTiMatrix (markovTi, rateCorrelation[whichChain*2 + whichState], rateCorrelation2[whichChain*4 + whichState*2 + 0], rateCorrelation2[whichChain*4 + whichState*2 + 1], probPur[whichChain*2 + whichState], probNeu[whichChain*2 + whichState], probPos[whichChain*2 + whichState], 2);

		lnC = 0.0;
		m = j = 0;
		for (c=0; c<numChars; c++)
			{
			likePur = likeNeu = likePos = 0.0;
			for (i=0; i<lnStates; i++)
				likePos += clP[j++] * bs[i];
			for (i=0; i<lnStates; i++)
				likePur += clP[j++] * bs[i];
			for (i=0; i<lnStates; i++)
				likeNeu += clP[j++] * bs[i];
			omegaPr[m++] = likePur;
			omegaPr[m++] = likeNeu;
			omegaPr[m++] = likePos;
			lnC += (lnScaler[c] * numSitesOfPat[c]);
			}
		isFirst = YES;
		for (c=(nChar/3)-1; c>=0; c--)
			{
			cn = c*3;
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				if (isFirst == YES)
					{
					max = 0.0;
					for (k=0; k<3; k++)
						{
						biN[cn + k] = omegaPr[pat*3 + k];
						if (biN[cn + k] > max)
							max = biN[cn + k];
						}
					if (max > 0.0)
						{
						for (k=0; k<3; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for ac1ny98 or ac2ny98 model is less than 0\n");
						goto error_exit;
						}
					isFirst = NO;
					}				
				else		// isFirst == NO
					{
					for (i=0; i<3; i++)
						{
						temp = max = 0.0;
						for (j=0; j<3; j++)
							temp += markovTi[i][j] * biN[(c+1)*3 + j];
						biN[cn + i] = omegaPr[pat*3+i] * temp;
						if (biN[cn + i] > max)
							max = biN[cn + i];
						}
					if (max > 0.0)
						{
						for (k=0; k<3; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				}
			else
				{
				printf ("   ERROR: Unidentified pattern\n");
				goto error_exit;
				}
			}
		temp  = biN[0] * probPur[whichChain*2 + whichState];
		temp += biN[1] * probNeu[whichChain*2 + whichState];
		temp += biN[2] * probPos[whichChain*2 + whichState];
		(*lnL) = lnC + log(temp);
		}
	else /* no omega variation or covarion-like model */
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (i=0; i<lnStates; i++)
				like += ((*(clP++)) * bs[i]);

			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");

				printf ("c %d like %f \n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free_psdmatrix (q);
	free (pL);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	if (isComplex != YES)
		free (c_ijk);
	if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		free (eigenValues2);
		free_psdmatrix (eigvecs2);
		free_psdmatrix (inverseEigvecs2);
		free_pscmatrix (Ceigvecs2);
		free_pscmatrix (CinverseEigvecs2);
		if (isComplex2 != YES)
			free (c_ijk2);
		free (eigenValues3);
		free_psdmatrix (eigvecs3);
		free_psdmatrix (inverseEigvecs3);
		free_pscmatrix (Ceigvecs3);
		free_pscmatrix (CinverseEigvecs3);
		if (isComplex3 != YES)
			free (c_ijk3);
		}
#	endif
	free (bs);
	if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		free (omegaPr);
	return (NO_ERROR);
	
	error_exit:
#		if !defined (SMART_TI_PROBS)
		free_psdmatrix (probs);
		free_psdmatrix (q);
		free (pL);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex != YES)
			free (c_ijk);
		if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
			{
			free (eigenValues2);
			free_psdmatrix (eigvecs2);
			free_psdmatrix (inverseEigvecs2);
			free_pscmatrix (Ceigvecs2);
			free_pscmatrix (CinverseEigvecs2);
			if (isComplex2 != YES)
				free (c_ijk2);
			free (eigenValues3);
			free_psdmatrix (eigvecs3);
			free_psdmatrix (inverseEigvecs3);
			free_pscmatrix (Ceigvecs3);
			free_pscmatrix (CinverseEigvecs3);
			if (isComplex3 != YES)
				free (c_ijk3);
			}
#		endif
		free (bs);
		if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
			free (omegaPr);
	return (ERROR);

}





/*---------------------------------------------------------------------
LnLikeCovarion: 'Fast' version, core written 2001-03-20
-----------------------------------------------------------------------*/
int LnLikeCovarion (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
	register int	i, j, k, c, n, m, cn;
	int				lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					index, index1, index2, nRates, pat, localLag, *usedBin,
					intNodeOffset, condLikeOffset, scalerOffset,
					lnStates, lnStatesSquared, lnStatesCube;
	double			*bs, *pL, *pR, *pA, *catFreq, *catRate, *partRate,
					*clL, *clR, *clA, *clP, *scP, s01, s10, prob0, prob1,
					*lnScaler, scaler, like, lnC, *biN, max, temp, correlation,
					*ratePr, **markovTi, likeL, likeR, likeA;
	TreeNode		*p;
#	if defined (SMART_TI_PROBS)
	int				nForOneState;
#	else
	register int	a, b;
	int				nPij, *isComplex, indexL, indexR, indexA;
	double			**probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk,
					*eigenValuesP, *eigvalsImagP, *eigvecsP, *inverseEigvecsP, *c_ijkP;
	complex 		**Ceigvecs, **CinverseEigvecs, *CeigvecsP, *CinverseEigvecsP;	
#	endif

	/* calculate local number of states */
	/* twice nStates because matrix is doubled */
	lnStates = 2 * nStates;
	lnStatesSquared = lnStates * lnStates;
	lnStatesCube = lnStates * lnStatesSquared;
	
	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* load base frequencies */
	index = whichChain*2*lnStates + whichState*lnStates;
	index1 = whichChain*4 + whichState*2;
	index2 = whichChain*2 + whichState;
	bs = (double *)malloc((size_t) (lnStates * sizeof(double)));
	if (!bs)
		{
		printf ("\n   ERROR: Problem allocating bs.\n");
		goto error_exit;
		}
	if (!strcmp(covarionModelType, "ts98"))
		{
		k = 0;
		for (j=0; j<2; j++)
			{
			for (i=0; i<nStates; i++)
				{
				bs[k] = baseFreq[whichChain*2*nStates + whichState*nStates + i] * switchPi[whichChain*4 + whichState*2 + j];
				k++;
				}
			}
		}
	else if (!strcmp(covarionModelType, "gcswitch"))
		{
		s01 = switchRate[index1 + 0];
		s10 = switchRate[index1 + 1];
		prob0 = s10 / (s01+s10);
		prob1 = s01 / (s01+s10);
		bs[0] = (1.0 - gc1[index2]) * (fracA[index2])       * prob0;
		bs[1] = (gc1[index2])       * (1.0 - fracG[index2]) * prob0;
		bs[2] = (gc1[index2])       * (fracG[index2])       * prob0;
		bs[3] = (1.0 - gc1[index2]) * (1.0 - fracA[index2]) * prob0;
		bs[4] = (1.0 - gc2[index2]) * (fracA[index2])       * prob1;
		bs[5] = (gc2[index2])       * (1.0 - fracG[index2]) * prob1;
		bs[6] = (gc2[index2])       * (fracG[index2])       * prob1;
		bs[7] = (1.0 - gc2[index2]) * (1.0 - fracA[index2]) * prob1;
		}

	/* how many different rates? */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1 */
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1 */
	/* the code introduced here only makes sure that the number of partitions */
	/* or rate categories is set to 1 when appropriate, in case the global variables */
	/* are not set to 1 when they are not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;
	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible rate */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (lnStates);
	nPij = nRates * lnStatesSquared;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for autocorrelated gamma models */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		ratePr = (double *)malloc((size_t) (lnumRateCats * (numChars + nChar) * sizeof(double)));
		if (!ratePr)
			{
			printf ("\n   ERROR: Problem allocating ratePr and biN.\n");
			goto error_exit;
			}
		biN = ratePr + lnumRateCats * numChars;
		usedBin = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!usedBin)
			{
			printf ("\n   ERROR: Problem allocating usedBin.\n");
			goto error_exit;
			}
		}

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* allocate memory for eigenvalues and eigenvectors */
	/* first for base matrix */
#	if !defined (SMART_TI_PROBS)
	q = psdmatrix (lnStates);
	eigenValues = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + lnStates;
	c_ijk = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
	if (!c_ijk)
		{
		printf ("\n   ERROR: Problem allocating c_ijk.\n");
		goto error_exit;
		}
	eigvecs = psdmatrix (lnStates);
	inverseEigvecs = psdmatrix (lnStates);
	Ceigvecs = pscmatrix (lnStates);
	CinverseEigvecs = pscmatrix (lnStates);

	/* then for partitions */
	isComplex = (int *)malloc((size_t) (nRates * sizeof(int)));
	if (!isComplex)
		{
		printf ("\n   ERROR: Problem allocating isComplex.\n");
		goto error_exit;
		}
	eigenValuesP = (double *)malloc((size_t) (2 * nRates * lnStates * sizeof(double)));
	if (!eigenValuesP)
		{
		printf ("\n   ERROR: Problem allocating eigenValuesP and eigvalsImagP.\n");
		goto error_exit;
		}
	eigvalsImagP = eigenValuesP + nRates * lnStates;
	eigvecsP = (double *)malloc((size_t) (2 * nRates * lnStatesSquared * sizeof(double)));
	if (!eigvecsP)
		{
		printf ("\n   ERROR: Problem allocating eigvecsP and inverseEigvecsP.\n");
		goto error_exit;
		}
	inverseEigvecsP = eigvecsP + nRates * lnStatesSquared;
	CeigvecsP = (complex *)malloc((size_t) (2 * nRates * lnStatesSquared * sizeof(complex)));
	if (!CeigvecsP)
		{
		printf ("\n   ERROR: Problem allocating CeigvecsP and CinverseEigvecsP.\n");
		goto error_exit;
		}
	CinverseEigvecsP = CeigvecsP + nRates * lnStatesSquared;
	c_ijkP = (double *)malloc((size_t) (nRates * lnStatesCube * sizeof(double)));
	if (!c_ijkP)
		{
		printf ("\n   ERROR: Problem allocating c_ijkP.\n");
		goto error_exit;
		}

	/* get eigenvalues and eigenvectors for covarion matrices */
	/* one matrix needed for each rate because catrates and partrates
	   affect only part of the matrix */
	// a is index to rate eigenvectors, b is index to rates
	for (m=a=b=0; m<lnPartitions; m++)
		{
		for (k=0; k<lnumRateCats; k++)
			{
			if (dataType == DNA || dataType == RNA)
				{
				if (!strcmp(covarionModelType, "ts98"))
					{
					if (SetDNACovQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
						goto error_exit;
					}
				else if (!strcmp(covarionModelType, "gcswitch"))
					{
					if (SetGCSwitchQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
						goto error_exit;
					}
				else
					{
					goto error_exit;
					}
				}
			else
				{
				if (SetAACovQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
					goto error_exit;
				}
			isComplex[b] = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
			if (isComplex[b] == NO)
				{
				CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
				}
			for (i=0; i<lnStates; i++)
				{
				eigenValuesP[b*lnStates + i] = eigenValues[i];
				eigvalsImagP[b*lnStates + i] = eigvalsImag[i];
				}
			for (i=0; i<lnStates; i++)
				{
				for (j=0; j<lnStates; j++)
					{
					eigvecsP[a]            = eigvecs[i][j];
					inverseEigvecsP[a]     = inverseEigvecs[i][j];
					CeigvecsP[a].re        = Ceigvecs[i][j].re;
					CinverseEigvecsP[a].re = CinverseEigvecs[i][j].re;
					CeigvecsP[a].im        = Ceigvecs[i][j].im;
					CinverseEigvecsP[a].im = CinverseEigvecs[i][j].im;
					a++;
					}
				}
			for (i=0; i<lnStatesCube; i++)
				c_ijkP[b*lnStatesCube + i] = c_ijk[i];
			b++;
			}
		}
#	endif
		
	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * lnStates;
	oneNodeSize = numChars * lnumRateCats * lnStates;

	/* calculate index offsets */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */					
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
#				else
				for (m=indexL=indexR=indexA=b=a=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						// fetch eigenvalues and eigenvectors for this rate
						// the rate itself is not needed because it has
						// been taken care of in the diagonalized matrices
						for (i=0; i<lnStates; i++)
							{
							eigenValues[i] = eigenValuesP[b*lnStates + i];
							eigvalsImag[i] = eigvalsImagP[b*lnStates + i];
							}
						for (i=0; i<lnStates; i++)
							{
							for (j=0; j<lnStates; j++)
								{
								eigvecs[i][j]            = eigvecsP[a];
								inverseEigvecs[i][j]     = inverseEigvecsP[a];
								Ceigvecs[i][j].re        = CeigvecsP[a].re;
								CinverseEigvecs[i][j].re = CinverseEigvecsP[a].re;
								Ceigvecs[i][j].im        = CeigvecsP[a].im;
								CinverseEigvecs[i][j].im = CinverseEigvecsP[a].im;
								a++;
								}
							}
						// fetch c_ijk for this rate
						for (i=0; i<lnStatesCube; i++)
							c_ijk[i] = c_ijkP[b*lnStatesCube + i];

						// calculate transition probabilities for left branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->left->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->left->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->right->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->right->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pR[indexR++] = probs[i][j];

						// calculate transition probabilities for ancestral branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pA[indexA++] = probs[i][j];
						b++;
						}
					}
#				endif

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(ratesModel, "equal"))
					{
					for (c=0; c<numChars; c++)
						{
						for (i=m=0; i<lnStates; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (j=0; j<lnStates; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m]*clR[j];
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						clL += lnStates;
						clR += lnStates;
						clA += lnStates;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						for (k=m=0; k<lnumRateCats; k++)
							{
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += lnStates;
							clR += lnStates;
							clA += lnStates;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*lnumRateCats*lnStatesSquared;
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += lnStates;
							clR += lnStates;
							clA += lnStates;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*lnStatesSquared;
						for (i=0; i<lnStates; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (j=0; j<lnStates; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m]*clR[j];
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						clL += lnStates;
						clR += lnStates;
						clA += lnStates;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for internal root node
			}	// done with internal root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting interior node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
#				else
				for (m=indexL=indexR=b=a=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						// fetch eigenvalues and eigenvectors for this rate
						// the rate itself is not needed because it has
						// been taken care of in the diagonalized matrices
						for (i=0; i<lnStates; i++)
							{
							eigenValues[i] = eigenValuesP[b*lnStates + i];
							eigvalsImag[i] = eigvalsImagP[b*lnStates + i];
							}
						for (i=0; i<lnStates; i++)
							{
							for (j=0; j<lnStates; j++)
								{
								eigvecs[i][j]            = eigvecsP[a];
								inverseEigvecs[i][j]     = inverseEigvecsP[a];
								Ceigvecs[i][j].re        = CeigvecsP[a].re;
								CinverseEigvecs[i][j].re = CinverseEigvecsP[a].re;
								Ceigvecs[i][j].im        = CeigvecsP[a].im;
								CinverseEigvecs[i][j].im = CinverseEigvecsP[a].im;
								a++;
								}
							}
						// fetch c_ijk for this rate
						for (i=0; i<lnStatesCube; i++)
							c_ijk[i] = c_ijkP[b*lnStatesCube + i];

						// calculate transition probabilities for left branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->left->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->left->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->right->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->right->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pR[indexR++] = probs[i][j];
						b++;
						}
					}
#				endif

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(ratesModel, "equal"))
					{
					for (c=0; c<numChars; c++)
						{
						for (i=m=0; i<lnStates; i++)
							{
							likeL = likeR = 0.0;
							for (j=0; j<lnStates; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m++]*clR[j];
								}
							*(clP++) = likeL * likeR;
							}
						clL += lnStates;
						clR += lnStates;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						for (k=m=0; k<lnumRateCats; k++)
							{
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += lnStates;
							clR += lnStates;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*lnumRateCats*lnStatesSquared;
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += lnStates;
							clR += lnStates;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*lnStatesSquared;
						for (i=0; i<lnStates; i++)
							{
							likeL = likeR = 0.0;
							for (j=0; j<lnStates; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m++]*clR[j];
								}
							*(clP++) = likeL * likeR;
							}
						clL += lnStates;
						clR += lnStates;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		// deal with scaling
		// first check if we need to refresh scalers and potentially shift scaler nodes
		// we have to remember scalerIndex because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0) 
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<lnStates; m++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}
					}
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<lnStates; m++)
						clP[j++] /= scaler;
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}
		}	// next node
		
	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	(*lnL) = 0.0;	// reset lnL
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (i=0; i<lnStates; i++)
				like += ((*(clP++)) * bs[i]);

			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				for (i=0; i<lnStates; i++)
					like += ((*(clP++)) * bs[i]) * catFreq[k];
				}
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		/* initialize usedBin */	
		for (i=0; i<nChar; i++)
			usedBin[i] = NO;
		lnC = 0.0;
		m = j = 0;
		for (c=0; c<numChars; c++)
			{
			for (k=0; k<lnumRateCats; k++)
				{
				like = 0.0;
				for (i=0; i<lnStates; i++)
					like += clP[j++] * bs[i];
				ratePr[m++] = like;
				}
			lnC += (lnScaler[c] * numSitesOfPat[c]);
			}
		localLag = lag[whichChain*2 + whichState];

		for (c=nChar-1; c>=0; c--)
			{
			cn = c*lnumRateCats;
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				if (c + localLag >= nChar)
					{
					max = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						biN[cn + k] = ratePr[pat*lnumRateCats + k];
						if (biN[cn + k] > max)
							max = biN[cn + k];
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}				
				else
					{
					for (i=0; i<lnumRateCats; i++)
						{
						temp = max = 0.0;
						for (j=0; j<lnumRateCats; j++)
							temp += markovTi[i][j] * biN[(c+localLag)*lnumRateCats + j];
						biN[cn + i] = ratePr[pat*lnumRateCats+i] * temp;
						if (biN[cn + i] > max)
							max = biN[cn + i];
						usedBin[c+localLag] = YES;
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				}
			else
				{
				printf ("   ERROR: Unidentified pattern\n");
				goto error_exit;
				}
			}
		(*lnL) = lnC;
		for (c=0; c<nChar; c++)
			{
			if (usedBin[c] == NO)
				{
				temp = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					temp += (catFreq[k] * biN[c*lnumRateCats + k]);
					}
				(*lnL) += log(temp);
				usedBin[c] = YES;
				}
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	free (c_ijk);
	free (isComplex);
	free (eigenValuesP);
	free (eigvecsP);
	free (CeigvecsP);
	free (c_ijkP);
#	endif
	free (catFreq);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (ratePr);
		free (usedBin);
		}

	return (NO_ERROR);
	
	error_exit:
#		if !defined (SMART_TI_PROBS)
		free_psdmatrix (probs);
		free (pL);
		free_psdmatrix (q);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		free (c_ijk);
		free (isComplex);
		free (eigenValuesP);
		free (eigvecsP);
		free (CeigvecsP);
		free (c_ijkP);
#		endif
		free (catFreq);
		if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			free_psdmatrix(markovTi);
			free (ratePr);
			free (usedBin);
			}

	return (ERROR);

}



/*-----------------------------------------------------------
LnLikeDNA: 'Fast' version, core written 2001-03-10--11
------------------------------------------------------------*/
int LnLikeDNA (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
#	define N_STATES 4
#	define N_STATES_SQUARED 16
#	define N_STATES_CUBE 64

	register int	i, j, k, c, n, cn;
	int				lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					index, pat, localLag, *usedBin, nRates,
					intNodeOffset, condLikeOffset, scalerOffset;
	double			bs[N_STATES], *pL, *pR, *pA, *catFreq, *catRate, *partRate,
					*clL, *clR, *clA, *clP, *tiPL, *tiPR, *tiPA, *scP,
					*lnScaler, scaler, like, lnC, *biN, max, temp, correlation,
					*ratePr, **markovTi;
	TreeNode		*p;
#	if defined (SMART_TI_PROBS)
	int				nForOneState;
#	else
	register int	m;
	int				nPij, *isComplex, indexL, indexR, indexA;
	double			lkappa, **probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk, theRate;
	complex 		**Ceigvecs, **CinverseEigvecs;	
#	endif

	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* initialize intNodeOffset */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;

	/* load base frequencies */
	index = whichChain*2*nStates + whichState*nStates;
	bs[A] = baseFreq[index + A];
	bs[C] = baseFreq[index + C];
	bs[G] = baseFreq[index + G];
	bs[T] = baseFreq[index + T];
	
	/* how many different rates? */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1 */
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1 */
	/* the code introduced here only makes sure that the number of partitions */
	/* or rate categories is set to 1 when appropriate, in case the global variables */
	/* are not set to 1 when they are not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;
	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible rate */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (nStates);
	nPij = nRates * N_STATES_SQUARED;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for autocorrelated gamma models */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		ratePr = (double *)malloc((size_t) (lnumRateCats * (numChars + nChar) * sizeof(double)));
		if (!ratePr)
			{
			printf ("\n   ERROR: Problem allocating ratePr and biN.\n");
			goto error_exit;
			}
		biN = ratePr + lnumRateCats * numChars;
		usedBin = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!usedBin)
			{
			printf ("\n   ERROR: Problem allocating usedBin.\n");
			goto error_exit;
			}
		}

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

#	if !defined (SMART_TI_PROBS)
	/* find kappa if nst == 1 or nst == 2 */
	if (nst == 1)
		lkappa = 1.0;
	else if (nst == 2)
		lkappa = kappa[whichChain*2 + whichState];
		
	/* get eigenvalues and eigenvectors if nst=6 or nst=12 */
	if (nst == 6 || nst == 12)
		{
		q = psdmatrix (4);
		eigenValues = (double *)malloc((size_t) (2 * N_STATES * sizeof(double)));
		if (!eigenValues)
			{
			printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
			goto error_exit;
			}
		eigvalsImag = eigenValues + N_STATES;
		eigvecs = psdmatrix (N_STATES);
		inverseEigvecs = psdmatrix (N_STATES);
		Ceigvecs = pscmatrix (N_STATES);
		CinverseEigvecs = pscmatrix (N_STATES);
		if (SetQMatrix (q, whichState, whichChain) == ERROR)
			goto error_exit;
		isComplex = GetEigens (N_STATES, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
		if (isComplex == NO)
			{
			c_ijk = (double *)malloc((size_t) (N_STATES_CUBE * sizeof(double)));
			if (!c_ijk)
				{
				printf ("\n   ERROR: Problem allocating c_ijk.\n");
				goto error_exit;
				}
			CalcCijk (c_ijk, N_STATES, eigvecs, inverseEigvecs);
			}
		}
#	endif

	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * nStates;
	oneNodeSize = numChars * lnumRateCats * nStates;

	/* calculate indices */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
#				else
				if (nst == 1 || nst == 2)
					{
					for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							/* calculate transition probabilities for left branch */
							HkyChangeMat (probs, p->left->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							/* calculate transition probabilities for right branch */
							HkyChangeMat (probs, p->right->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];

							/* calculate transition probabilities for ancestral branch */
							HkyChangeMat (probs, p->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pA[indexA++] = probs[i][j];
							
							}
						}
					}
				else // nst == 6 or nst == 12
					{
					for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for left branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->left->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->left->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							// calculate transition probabilities for right branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->right->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->right->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];

							// calculate transition probabilities for ancestral branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pA[indexA++] = probs[i][j];
							}
						}
					}
#				endif

				/* calculate conditional likelihoods */

				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];

				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					tiPA = pA;
					for (c=0; c<numChars; c++)
						{
						clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
						          *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
						          *(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
						clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
						          *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
						          *(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
						clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
						          *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
						          *(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
						clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
						          *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
						          *(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
						clP += 4;
						clL += 4;
						clR += 4;
						clA += 4;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						tiPA = pA;
						for (k=0; k<lnumRateCats; k++)
							{
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
									  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
									  *(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
									  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
									  *(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
									  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
									  *(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
									  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
									  *(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							clA += 4;
							tiPL += 16;
							tiPR += 16;
							tiPA += 16;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						for (k=0; k<lnumRateCats; k++)
							{
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
									  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
									  *(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
									  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
									  *(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
									  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
									  *(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
									  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
									  *(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							clA += 4;
							tiPL += 16;
							tiPR += 16;
							tiPA += 16;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
								  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
								  *(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
						clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
								  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
								  *(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
						clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
								  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
								  *(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
						clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
								  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
								  *(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
						clP += 4;
						clL += 4;
						clR += 4;
						clA += 4;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for internal root node
			}	// done with internal root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting interior node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
#				else
				if (nst == 1 || nst == 2)
					{
					for (m=indexL=indexR=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							/* calculate transition probabilities for left branch */
							HkyChangeMat (probs, p->left->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							/* calculate transition probabilities for right branch */
							HkyChangeMat (probs, p->right->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];
							}
						}
					}
				else // nst == 6 or nst == 12
					{
					for (m=indexL=indexR=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for left branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->left->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->left->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							// calculate transition probabilities for right branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->right->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->right->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];							
							}
						}
					}
#				endif

				/* calculate conditional likelihoods */

				/* first set pointers to cond likes of left, right and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];

				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					for (c=0; c<numChars; c++)
						{
						clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
						          *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
						clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
						          *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
						clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
						          *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
						clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
						          *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
						clP += 4;
						clL += 4;
						clR += 4;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						for (k=0; k<lnumRateCats; k++)
							{
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
									  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
									  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
									  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
									  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							tiPL += 16;
							tiPR += 16;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						for (k=0; k<lnumRateCats; k++)
							{
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
									  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
									  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
									  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
									  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							tiPL += 16;
							tiPR += 16;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
								  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
						clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
								  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
						clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
								  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
						clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
								  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
						clP += 4;
						clL += 4;
						clR += 4;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		// deal with scaling
		// first check if we need to refresh scalers and potentially shift scaler nodes
		// we have to remember scalerIndex because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0) 
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			if (lnumRateCats > 1)
				{
				for (c=0; c<numChars; c++)
					{
					scaler = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}

					for (k=0; k<lnumRateCats; k++)
						{
						clP[j++] /= scaler;
						clP[j++] /= scaler;
						clP[j++] /= scaler;
						clP[j++] /= scaler;
						}

					lnScaler[c] -= scP[c];	//subtract old value
					scP[c] = log(scaler);
					lnScaler[c] += scP[c]; //add new value
					}
				}
			else	// lnumRateCats == 1
				{
				for (c=0; c<numChars; c++)
					{
					scaler = clP[i++];
					if (clP[i] > scaler)
						scaler = clP[i];
					i++;
					if (clP[i] > scaler)
						scaler = clP[i];
					i++;
					if (clP[i] > scaler)
						scaler = clP[i];
					i++;

					clP[j++] /= scaler;
					clP[j++] /= scaler;
					clP[j++] /= scaler;
					clP[j++] /= scaler;

					lnScaler[c] -= scP[c];	//subtract old value
					scP[c] = log(scaler);
					lnScaler[c] += scP[c]; //add new value
					}
				}
			}
		}	// next node
		
	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	(*lnL) = 0.0;	// reset lnL
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=0; c<numChars; c++)
			{
			like = clP[A] * bs[A] + clP[C] * bs[C] + clP[G] * bs[G] + clP[T] * bs[T];
			clP += 4;
			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				like += (clP[A] * bs[A] + clP[C] * bs[C] + clP[G] * bs[G] + clP[T] * bs[T]) * catFreq[k];
				clP += 4;
				}
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		/* initialize usedBin */	
		for (i=0; i<nChar; i++)
			usedBin[i] = NO;
		
		lnC = 0.0;
		i = 0;
		for (c=0; c<numChars; c++)
			{
			for (k=0; k<lnumRateCats; k++)
				{
				ratePr[i++] = (clP[A] * bs[A] + clP[C] * bs[C] + clP[G] * bs[G] + clP[T] * bs[T]);
				clP += 4;
				}
			lnC += (lnScaler[c] * numSitesOfPat[c]);
			}
		localLag = lag[whichChain*2 + whichState];
		for (c=nChar-1; c>=0; c--)
			{
			cn = c*lnumRateCats;
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				if (c + localLag >= nChar)
					{
					max = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						biN[cn + k] = ratePr[pat*lnumRateCats + k];
						if (biN[cn + k] > max)
							max = biN[cn + k];
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				else
					{
					for (i=0; i<lnumRateCats; i++)
						{
						temp = max = 0.0;
						for (j=0; j<lnumRateCats; j++)
							temp += markovTi[i][j] * biN[(c+localLag)*lnumRateCats + j];
						biN[cn + i] = ratePr[pat*lnumRateCats+i] * temp;
						if (biN[cn + i] > max)
							max = biN[cn + i];
						usedBin[c+localLag] = YES;
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				}
			else
				{
				printf ("   ERROR: Unidentified pattern\n");
				goto error_exit;
				}
			}
		(*lnL) = lnC;
		for (c=0; c<nChar; c++)
			{
			if (usedBin[c] == NO)
				{
				temp = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					temp += (catFreq[k] * biN[c*lnumRateCats + k]);
					}
				(*lnL) += log(temp);
				usedBin[c] = YES;
				}
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	if (nst == 6 || nst == 12)
		{
		free_psdmatrix (q);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex != YES)
			free (c_ijk);
		}
#	endif
	free (catFreq);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (ratePr);
		free (usedBin);
		}
	return (NO_ERROR);
	
	error_exit:
#		if !defined (SMART_TI_PROBS)
		free_psdmatrix (probs);
		free (pL);
		if (nst == 6 || nst == 12)
			{
			free_psdmatrix (q);
			free (eigenValues);
			free_psdmatrix (eigvecs);
			free_psdmatrix (inverseEigvecs);
			free_pscmatrix (Ceigvecs);
			free_pscmatrix (CinverseEigvecs);
			if (isComplex != YES)
				free (c_ijk);
			}
#		endif
		free (catFreq);
		if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			free_psdmatrix(markovTi);
			free (ratePr);
			free (usedBin);
			}
		return (ERROR);

#	undef N_STATES
#	undef N_STATES_SQUARED
#	undef N_STATES_CUBE
}


#else
// SUPER_FAST versions of the above functions
/*-----------------------------------------------------------
LnLikeDNA: 'Superfast' version - improves the speed of expensive
moves by using local compression on terminal branches
------------------------------------------------------------*/
int LnLikeDNA (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
#define N_STATES 4
#define N_STATES_SQUARED 16
#define N_STATES_CUBE 64

	register int	h, i, j, k, c, n, m, cn;
	int				lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					index, nRates, pat, localLag, *usedBin,
					intNodeOffset, condLikeOffset, scalerOffset;
	double			bs[N_STATES], *pL, *pR, *pA, *catFreq, *catRate, *partRate,
					*clL, *clR, *clA, *clP, *tiPL, *tiPR, *tiPA, *scP,
					*lnScaler, scaler, like, lnC, *biN, max, temp, correlation,
					*ratePr, **markovTi, *likeL, *likeR, *likeA;
	int				shortCut, indexMultiplier1, indexMultiplier2,
					*lState, *rState, *aState;
	TreeNode		*p;
#	if defined (SMART_TI_PROBS)
	int				nForOneState;
#	else
	int				nPij, isComplex, indexL, indexR, indexA;
	double			lkappa, theRate, **probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk;
	complex 		**Ceigvecs, **CinverseEigvecs;	
#	endif

	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* initialize intNodeOffset */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;

	/* load base frequencies */
	index = whichChain*2*nStates + whichState*nStates;
	bs[A] = baseFreq[index + A];
	bs[C] = baseFreq[index + C];
	bs[G] = baseFreq[index + G];
	bs[T] = baseFreq[index + T];
	
	/* how many different rates? */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1 */
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1 */
	/* the code introduced here only makes sure that the number of partitions */
	/* or rate categories is set to 1 when appropriate, in case the global variables */
	/* are not set to 1 when they are not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;

	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible rate */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (nStates);
	nPij = nRates * N_STATES_SQUARED;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating pL, pR and pA\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* likeL, likeR and likeA will contain the cond likelihoods for Left, Right and Anc */
	/* if any of them is a terminal with states A C G T or ambiguous/gap */
	likeL = (double *)malloc((size_t)(3 * nRates * 20 * sizeof(double)));
	if (!likeL)
		{
		printf ("\n   ERROR: Problem allocating likeL, likeR and likeA\n");
		goto error_exit;
		}
	likeR = likeL + nRates * 20;
	likeA = likeR + nRates * 20;

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate  = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for autocorrelated gamma models */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		ratePr = (double *)malloc((size_t) (lnumRateCats * (numChars + nChar) * sizeof(double)));
		if (!ratePr)
			{
			printf ("\n   ERROR: Problem allocating ratePr and biN.\n");
			goto error_exit;
			}
		biN = ratePr + lnumRateCats * numChars;
		usedBin = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!usedBin)
			{
			printf ("\n   ERROR: Problem allocating usedBin.\n");
			goto error_exit;
			}
		}

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* find kappa if nst == 1 or nst == 2 */
#	if !defined (SMART_TI_PROBS)
	if (nst == 1)
		lkappa = 1.0;
	else if (nst == 2)
		lkappa = kappa[whichChain*2 + whichState];
		
	/* get eigenvalues and eigenvectors if nst=6 or nst=12 */
	if (nst == 6 || nst == 12)
		{
		q = psdmatrix (N_STATES);
		eigenValues = (double *)malloc((size_t) (2 * N_STATES * sizeof(double)));
		if (!eigenValues)
			{
			printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
			goto error_exit;
			}
		eigvalsImag = eigenValues + N_STATES;
		eigvecs = psdmatrix (N_STATES);
		inverseEigvecs = psdmatrix (N_STATES);
		Ceigvecs = pscmatrix (N_STATES);
		CinverseEigvecs = pscmatrix (N_STATES);
		if (SetQMatrix (q, whichState, whichChain) == ERROR)
			goto error_exit;
		isComplex = GetEigens (N_STATES, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
		if (isComplex == NO)
			{
			c_ijk = (double *)malloc((size_t) (N_STATES_CUBE * sizeof(double)));
			if (!c_ijk)
				{
				printf ("\n   ERROR: Problem allocating c_ijk.\n");
				goto error_exit;
				}
			CalcCijk (c_ijk, N_STATES, eigvecs, inverseEigvecs);
			}
		}
#	endif

	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * nStates;
	oneNodeSize = numChars * lnumRateCats * nStates;

	/* calculate indices */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
#				else
				if (nst == 1 || nst == 2)
					{
					for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							/* calculate transition probabilities for left branch */
							HkyChangeMat (probs, p->left->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							/* calculate transition probabilities for right branch */
							HkyChangeMat (probs, p->right->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];

							/* calculate transition probabilities for ancestral branch */
							HkyChangeMat (probs, p->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pA[indexA++] = probs[i][j];
							}
						}
					}
				else // nst == 6 or nst == 12
					{
					for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for left branch
							if (isComplex == NO)
								CalcPij (c_ijk, N_STATES, eigenValues, p->left->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->left->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							// calculate transition probabilities for right branch
							if (isComplex == NO)
								CalcPij (c_ijk, N_STATES, eigenValues, p->right->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->right->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];

							// calculate transition probabilities for ancestral branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pA[indexA++] = probs[i][j];
							}
						}
					}
#				endif

				if (!strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (i=0; i<nodeTiSize; i++)
						{
						if (pL[i] < 0.0)
							pL[i] = 0.0;
						if (pR[i] < 0.0)
							pR[i] = 0.0;
						if (pA[i] < 0.0)
							pA[i] = 0.0;
						}
					}
				
				shortCut = 0;
				/* calculate likelihoods of site patterns for left branch if terminal */
				if (p->left->left == NULL && isPartAmbig[p->left->index] == NO)
					{
					shortCut |= 1;
					lState = termState + p->left->index * numChars;
					tiPL = pL;
					for (m=j=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<4; i++)
								{
								likeL[j++] = tiPL[0] + ((seqErrorProb - 4.0*seqErrorProb*tiPL[0])/3.0);
								likeL[j++] = tiPL[4] + ((seqErrorProb - 4.0*seqErrorProb*tiPL[4])/3.0);
								likeL[j++] = tiPL[8] + ((seqErrorProb - 4.0*seqErrorProb*tiPL[8])/3.0);
								likeL[j++] = tiPL[12] + ((seqErrorProb - 4.0*seqErrorProb*tiPL[12])/3.0);
								tiPL++;
								}
							/* for ambiguous */
							for (i=0; i<4; i++)
								likeL[j++] = 1.0;
							tiPL += 12;
							}
						}
					}

				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->right->left == NULL && isPartAmbig[p->right->index] == NO)
					{
					shortCut |= 2;
					rState = termState + p->right->index * numChars;
					tiPR = pR;
					for (m=j=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<4; i++)
								{
								likeR[j++] = tiPR[0] + ((seqErrorProb - 4.0*seqErrorProb*tiPR[0])/3.0);
								likeR[j++] = tiPR[4] + ((seqErrorProb - 4.0*seqErrorProb*tiPR[4])/3.0);
								likeR[j++] = tiPR[8] + ((seqErrorProb - 4.0*seqErrorProb*tiPR[8])/3.0);
								likeR[j++] = tiPR[12] + ((seqErrorProb - 4.0*seqErrorProb*tiPR[12])/3.0);
								tiPR++;
								}
							/* for ambiguous */
							for (i=0; i<4; i++)
								likeR[j++] = 1.0;
							tiPR += 12;
							}
						}
					}

				/* calculate likelihoods of site patterns for anc branch, always terminal */
				if (isPartAmbig[p->anc->index] == YES)
					{
					shortCut = 4;
					}
				else 
					{
					aState = termState + p->anc->index * numChars;
					tiPA = pA;
					for (m=j=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<4; i++)
								{
								likeA[j++] = tiPA[0] + ((seqErrorProb - 4.0*seqErrorProb*tiPA[0])/3.0);
								likeA[j++] = tiPA[4] + ((seqErrorProb - 4.0*seqErrorProb*tiPA[4])/3.0);
								likeA[j++] = tiPA[8] + ((seqErrorProb - 4.0*seqErrorProb*tiPA[8])/3.0);
								likeA[j++] = tiPA[12] + ((seqErrorProb - 4.0*seqErrorProb*tiPA[12])/3.0);
								tiPA++;
								}
							/* for ambiguous */
							for (i=0; i<4; i++)
								likeA[j++] = 1.0;
							tiPA += 12;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to model */
				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					tiPA = pA;
					switch (shortCut)
						{
						case 4:	// anc is partially ambiguous
							for (c=h=0; c<numChars; c++)
								{
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
								clL += 4;
								clR += 4;
								clA += 4;
								}
							break;
						case 0:
						case 3:	// if both left and right are terminal, this is a 4-taxon tree and no shortcut is necessary
							for (c=h=0; c<numChars; c++)
								{
								i = aState[c];
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*likeA[i];
								clL += 4;
								clR += 4;
								}
							break;
						case 1:
							for (c=h=0; c<numChars; c++)
								{
								i = lState[c];
								j = aState[c];
								clP[h++] =   likeL[i++]*likeA[j++]
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
								clP[h++] =   likeL[i++]*likeA[j++]
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
								clP[h++] =   likeL[i++]*likeA[j++]
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
								clP[h++] =   likeL[i]*likeA[j]
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
								clR += 4;
								}
							break;
						case 2:
							for (c=h=0; c<numChars; c++)
								{
								i = rState[c];
								j = aState[c];
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*likeR[i]*likeA[j];
								clL += 4;
								}
							break;
							}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					switch (shortCut)
						{
					case 4:
						for (c=h=0; c<numChars; c++)
							{
							tiPL = pL;
							tiPR = pR;
							tiPA = pA;
							for (k=0; k<lnumRateCats; k++)
								{
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
								clL += 4;
								clR += 4;
								clA += 4;
								tiPL += 16;
								tiPR += 16;
								tiPA += 16;
								}
							}
						break;

					case 0:
					case 3:
						for (c=h=0; c<numChars; c++)
							{
							tiPL = pL;
							tiPR = pR;
							i = aState[c];
							for (k=0; k<lnumRateCats; k++)
								{
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*likeA[i++];
								clL += 4;
								clR += 4;
								tiPL += 16;
								tiPR += 16;
								i += 16;
								}
							}
						break;

					case 1:
						for (c=h=0; c<numChars; c++)
							{
							tiPR = pR;
							i = lState[c];
							j = aState[c];
							for (k=0; k<lnumRateCats; k++)
								{
								clP[h++] =   (tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*likeL[i++]*likeA[j++];
								clP[h++] =   (tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*likeL[i++]*likeA[j++];
								clP[h++] =   (tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*likeL[i++]*likeA[j++];
								clP[h++] =   (tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*likeL[i++]*likeA[j++];
								clR += 4;
								tiPR += 16;
								i += 16;
								j += 16;
								}
							}
						break;

					case 2:
						for (c=h=0; c<numChars; c++)
							{
							tiPL = pL;
							i = rState[c];
							j = aState[c];
							for (k=0; k<lnumRateCats; k++)
								{
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*likeR[i++]*likeA[j++];
								clL += 4;
								tiPL += 16;
								i += 16;
								j += 16;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					indexMultiplier1 = lnumRateCats * N_STATES_SQUARED;
					indexMultiplier2 = lnumRateCats * 20;
					switch (shortCut)
						{
					case 4:
						for (c=h=0; c<numChars; c++)
							{
							index = partitionId[c] * indexMultiplier1;
							tiPL = &pL[index];
							tiPR = &pR[index];
							tiPA = &pA[index];
							for (k=0; k<lnumRateCats; k++)
								{
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
								clL += 4;
								clR += 4;
								clA += 4;
								tiPL += 16;
								tiPR += 16;
								tiPA += 16;
								}
							}
						break;

					case 0:
					case 3:
						for (c=h=0; c<numChars; c++)
							{
							index = partitionId[c] * indexMultiplier1;
							tiPL = &pL[index];
							tiPR = &pR[index];
							i = aState[c] + (partitionId[c] * indexMultiplier2);
							for (k=0; k<lnumRateCats; k++)
								{
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*likeA[i++];
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*likeA[i++];
								clL += 4;
								clR += 4;
								tiPL += 16;
								tiPR += 16;
								i += 16;
								}
							}
						break;

					case 1:
						for (c=h=0; c<numChars; c++)
							{
							tiPR = &pR[partitionId[c] * indexMultiplier1];
							index = partitionId[c] * indexMultiplier2;
							i = index + lState[c];
							j = index + aState[c];
							for (k=0; k<lnumRateCats; k++)
								{
								clP[h++] =   (tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*likeL[i++]*likeA[j++];
								clP[h++] =   (tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*likeL[i++]*likeA[j++];
								clP[h++] =   (tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*likeL[i++]*likeA[j++];
								clP[h++] =   (tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*likeL[i++]*likeA[j++];
								clR += 4;
								tiPR += 16;
								i += 16;
								j += 16;
								}
							}
						break;

					case 2:
						for (c=h=0; c<numChars; c++)
							{
							tiPL = &pL[partitionId[c] * indexMultiplier1];
							index = partitionId[c] * indexMultiplier2;
							i = index + rState[c];
							j = index + aState[c];
							for (k=0; k<lnumRateCats; k++)
								{
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*likeR[i++]*likeA[j++];
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*likeR[i++]*likeA[j++];
								clL += 4;
								tiPL += 16;
								i += 16;
								j += 16;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					indexMultiplier1 = lnumRateCats * N_STATES_SQUARED;
					indexMultiplier2 = lnumRateCats * 20;
					switch (shortCut)
						{
					case 4:
						for (c=h=0; c<numChars; c++)
							{
							index = partitionId[c] * indexMultiplier1;
							tiPL = &pL[index];
							tiPR = &pR[index];
							tiPA = &pA[index];
							clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
										*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
										*(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
							clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
										*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
										*(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
							clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
										*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
										*(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
							clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
										*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
										*(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
							clL += 4;
							clR += 4;
							clA += 4;
							}
						break;

					case 0:
					case 3:
						for (c=h=0; c<numChars; c++)
							{
							index = partitionId[c] * indexMultiplier1;
							tiPL = &pL[index];
							tiPR = &pR[index];
							i = (partitionId[c] * indexMultiplier2) + aState[c];
							clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
										*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
										*likeA[i++];
							clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
										*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
										*likeA[i++];
							clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
										*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
										*likeA[i++];
							clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
										*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
										*likeA[i];
							clL += 4;
							clR += 4;
							}
						break;

					case 1:
						for (c=h=0; c<numChars; c++)
							{
							tiPR = &pR[partitionId[c] * indexMultiplier1];
							index = partitionId[c] * indexMultiplier2;
							i = index + lState[c];
							j = index + aState[c];
							clP[h++] =   (tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
										*likeL[i++]*likeA[j++];
							clP[h++] =   (tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
										*likeL[i++]*likeA[j++];
							clP[h++] =   (tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
										*likeL[i++]*likeA[j++];
							clP[h++] =   (tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
										*likeL[i]*likeA[j];
							clR += 4;
							}
						break;

					case 2:
						for (c=h=0; c<numChars; c++)
							{
							tiPL = &pL[partitionId[c] * indexMultiplier1];
							index = partitionId[c] * indexMultiplier2;
							i = index + rState[c];
							j = index + aState[c];
							clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
										*likeR[i++]*likeA[j++];
							clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
										*likeR[i++]*likeA[j++];
							clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
										*likeR[i++]*likeA[j++];
							clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
										*likeR[i]*likeA[j];
							clL += 4;
							}
						break;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for internal root node
			}	// done with internal root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting interior node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
#				else
				if (nst == 1 || nst == 2)
					{
					for (m=indexL=indexR=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							/* calculate transition probabilities for left branch */
							HkyChangeMat (probs, p->left->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							/* calculate transition probabilities for right branch */
							HkyChangeMat (probs, p->right->length,  lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];
							}
						}
					}
				else // nst == 6 or nst == 12
					{
					for (m=indexL=indexR=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for left branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->left->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->left->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							// calculate transition probabilities for right branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->right->length,  theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->right->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];							
							}
						}
					}
#				endif

				if (!strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (i=0; i<nodeTiSize; i++)
						{
						if (pL[i] < 0.0)
							pL[i] = 0.0;
						if (pR[i] < 0.0)
							pR[i] = 0.0;
						}
					}
				/*
				for (i=0; i<nodeTiSize; i++)
					if (pL[i] < 0.0 || pR[i] < 0.0) {
						printf ("      WARNING! Ti prob negative\n");
						getchar();
					}
				*/
				
				shortCut = 0;
				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->left->left == NULL && isPartAmbig[p->left->index] == NO)
					{
					shortCut |= 1;
					lState = termState + p->left->index * numChars;
					tiPL = pL;
					for (m=j=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<4; i++)
								{
								likeL[j++] = tiPL[0] + ((seqErrorProb - 4.0*seqErrorProb*tiPL[0])/3.0);
								likeL[j++] = tiPL[4] + ((seqErrorProb - 4.0*seqErrorProb*tiPL[4])/3.0);
								likeL[j++] = tiPL[8] + ((seqErrorProb - 4.0*seqErrorProb*tiPL[8])/3.0);
								likeL[j++] = tiPL[12] + ((seqErrorProb - 4.0*seqErrorProb*tiPL[12])/3.0);
								tiPL++;
								}
							/* for ambiguous */
							for (i=0; i<4; i++)
								likeL[j++] = 1.0;
							tiPL += 12;
							}
						}
					}

				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->right->left == NULL && isPartAmbig[p->right->index] == NO)
					{
					shortCut |= 2;
					rState = termState + p->right->index * numChars;
					tiPR = pR;
					for (m=j=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<4; i++)
								{
								likeR[j++] = tiPR[0] + ((seqErrorProb - 4.0*seqErrorProb*tiPR[0])/3.0);
								likeR[j++] = tiPR[4] + ((seqErrorProb - 4.0*seqErrorProb*tiPR[4])/3.0);
								likeR[j++] = tiPR[8] + ((seqErrorProb - 4.0*seqErrorProb*tiPR[8])/3.0);
								likeR[j++] = tiPR[12] + ((seqErrorProb - 4.0*seqErrorProb*tiPR[12])/3.0);
								tiPR++;
								}
							/* for ambiguous */
							for (i=0; i<4; i++)
								likeR[j++] = 1.0;
							tiPR += 12;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to model */
				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					switch (shortCut)
						{
						case 0:
							for (c=h=0; c<numChars; c++)
								{
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
								clL += 4;
								clR += 4;
								}
							break;
						case 1:
							for (c=h=0; c<numChars; c++)
								{
								i = lState[c];
								clP[h++] =   likeL[i++]
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
								clP[h++] =   likeL[i++]
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
								clP[h++] =   likeL[i++]
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
								clP[h++] =   likeL[i]
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
								clR += 4;
								}
							break;
						case 2:
							for (c=h=0; c<numChars; c++)
								{
								i = rState[c];
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*likeR[i++];
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*likeR[i++];
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*likeR[i++];
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*likeR[i];
								clL += 4;
								}
							break;
						case 3:
							for (c=h=0; c<numChars; c++)
								{
								i = lState[c];
								j = rState[c];
								clP[h++] =   likeL[i++]*likeR[j++];
								clP[h++] =   likeL[i++]*likeR[j++];
								clP[h++] =   likeL[i++]*likeR[j++];
								clP[h++] =   likeL[i]*likeR[j];
								}
							}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					switch (shortCut)
						{
						case 0:
							for (c=h=0; c<numChars; c++)
								{
								tiPL = pL;
								tiPR = pR;
								for (k=0; k<lnumRateCats; k++)
									{
									clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
												*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
									clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
												*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
									clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
												*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
									clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
												*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
									clL += 4;
									clR += 4;
									tiPL += 16;
									tiPR += 16;
									}
								}
							break;

						case 1:
							for (c=h=0; c<numChars; c++)
								{
								tiPR = pR;
								i = lState[c];
								for (k=0; k<lnumRateCats; k++)
									{
									clP[h++] =   (tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
												*likeL[i++];
									clP[h++] =   (tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
												*likeL[i++];
									clP[h++] =   (tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
												*likeL[i++];
									clP[h++] =   (tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
												*likeL[i++];
									clR += 4;
									tiPR += 16;
									i += 16;
									}
								}
							break;

						case 2:
							for (c=h=0; c<numChars; c++)
								{
								tiPL = pL;
								i = rState[c];
								for (k=0; k<lnumRateCats; k++)
									{
									clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
												*likeR[i++];
									clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
												*likeR[i++];
									clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
												*likeR[i++];
									clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
												*likeR[i++];
									clL += 4;
									tiPL += 16;
									i += 16;
									}
								}
							break;

						case 3:
							for (c=h=0; c<numChars; c++)
								{
								i = lState[c];
								j = rState[c];
								for (k=0; k<lnumRateCats; k++)
									{
									clP[h++] =   likeL[i++]*likeR[j++];
									clP[h++] =   likeL[i++]*likeR[j++];
									clP[h++] =   likeL[i++]*likeR[j++];
									clP[h++] =   likeL[i++]*likeR[j++];
									i += 16;
									j += 16;
									}
								}
							break;

						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					indexMultiplier1 = lnumRateCats * N_STATES_SQUARED;
					indexMultiplier2 = lnumRateCats * 20;
					switch (shortCut)
						{
						case 0:
							for (c=h=0; c<numChars; c++)
								{
								index = partitionId[c] * indexMultiplier1;
								tiPL = &pL[index];
								tiPR = &pR[index];
								for (k=0; k<lnumRateCats; k++)
									{
									clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
												*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
									clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
												*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
									clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
												*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
									clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
												*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
									clL += 4;
									clR += 4;
									tiPL += 16;
									tiPR += 16;
									}
								}
							break;

						case 1:
							for (c=h=0; c<numChars; c++)
								{
								tiPR = &pR[partitionId[c] * indexMultiplier1];
								i = (partitionId[c] * indexMultiplier2) + lState[c];
								for (k=0; k<lnumRateCats; k++)
									{
									clP[h++] =   (tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
												*likeL[i++];
									clP[h++] =   (tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
												*likeL[i++];
									clP[h++] =   (tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
												*likeL[i++];
									clP[h++] =   (tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
												*likeL[i++];
									clR += 4;
									tiPR += 16;
									i += 16;
									}
								}
							break;

						case 2:
							for (c=h=0; c<numChars; c++)
								{
								tiPL = &pL[partitionId[c] * indexMultiplier1];
								i = (partitionId[c] * indexMultiplier2) + rState[c];
								for (k=0; k<lnumRateCats; k++)
									{
									clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
												*likeR[i++];
									clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
												*likeR[i++];
									clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
												*likeR[i++];
									clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
												*likeR[i++];
									clL += 4;
									tiPL += 16;
									i += 16;
									}
								}
							break;

						case 3:
							for (c=h=0; c<numChars; c++)
								{
								index = partitionId[c] * indexMultiplier2;
								i = index + lState[c];
								j = index + rState[c];
								for (k=0; k<lnumRateCats; k++)
									{
									clP[h++] =   likeL[i++]*likeR[j++];
									clP[h++] =   likeL[i++]*likeR[j++];
									clP[h++] =   likeL[i++]*likeR[j++];
									clP[h++] =   likeL[i++]*likeR[j++];
									i += 16;
									j += 16;
									}
								}
							break;

						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					indexMultiplier1 = lnumRateCats * N_STATES_SQUARED;
					indexMultiplier2 = lnumRateCats * 20;
					switch (shortCut)
						{
						case 0:
							for (c=h=0; c<numChars; c++)
								{
								index = partitionId[c] * indexMultiplier1;
								tiPL = &pL[index];
								tiPR = &pR[index];
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
								clL += 4;
								clR += 4;
								}
							break;

						case 1:
							for (c=h=0; c<numChars; c++)
								{
								tiPR = &pR[partitionId[c] * indexMultiplier1];
								i = (partitionId[c] * indexMultiplier2) + lState[c];
								clP[h++] =   (tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
											*likeL[i++];
								clP[h++] =   (tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
											*likeL[i++];
								clP[h++] =   (tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
											*likeL[i++];
								clP[h++] =   (tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
											*likeL[i++];
								clR += 4;
								}
							break;

						case 2:
							for (c=h=0; c<numChars; c++)
								{
								tiPL = &pL[partitionId[c] * indexMultiplier1];
								i = (partitionId[c] * indexMultiplier2) + rState[c];
								clP[h++] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
											*likeR[i++];
								clP[h++] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
											*likeR[i++];
								clP[h++] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
											*likeR[i++];
								clP[h++] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
											*likeR[i++];
								clL += 4;
								}
							break;

						case 3:
							for (c=h=0; c<numChars; c++)
								{
								index = partitionId[c] * indexMultiplier2;
								i = index + lState[c];
								j = index + rState[c];
								clP[h++] =   likeL[i++]*likeR[j++];
								clP[h++] =   likeL[i++]*likeR[j++];
								clP[h++] =   likeL[i++]*likeR[j++];
								clP[h++] =   likeL[i++]*likeR[j++];
								}
							break;

						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		// deal with scaling
		// first check if we need to refresh scalers and potentially shift scaler nodes
		// we have to remember scalerIndex because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0) 
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			if (lnumRateCats > 1)
				{
				for (c=0; c<numChars; c++)
					{
					scaler = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}

					for (k=0; k<lnumRateCats; k++)
						{
						clP[j++] /= scaler;
						clP[j++] /= scaler;
						clP[j++] /= scaler;
						clP[j++] /= scaler;
						}

					lnScaler[c] -= scP[c];	//subtract old value
					scP[c] = log(scaler);
					lnScaler[c] += scP[c]; //add new value
					}
				}
			else	// lnumRateCats == 1
				{
				for (c=0; c<numChars; c++)
					{
					scaler = clP[i++];
					if (clP[i] > scaler)
						scaler = clP[i];
					i++;
					if (clP[i] > scaler)
						scaler = clP[i];
					i++;
					if (clP[i] > scaler)
						scaler = clP[i];
					i++;

					clP[j++] /= scaler;
					clP[j++] /= scaler;
					clP[j++] /= scaler;
					clP[j++] /= scaler;

					lnScaler[c] -= scP[c];	//subtract old value
					scP[c] = log(scaler);
					lnScaler[c] += scP[c]; //add new value
					}
				}
			}
		}	// next node
		
	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	(*lnL) = 0.0;	// reset lnL
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=0; c<numChars; c++)
			{
			like = clP[A] * bs[A] + clP[C] * bs[C] + clP[G] * bs[G] + clP[T] * bs[T];
			clP += 4;
			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				like += (clP[A] * bs[A] + clP[C] * bs[C] + clP[G] * bs[G] + clP[T] * bs[T]) * catFreq[k];
				clP += 4;
				}
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		/* initialize usedBin */	
		for (i=0; i<nChar; i++)
			usedBin[i] = NO;
		
		lnC = 0.0;
		i = 0;
		for (c=0; c<numChars; c++)
			{
			for (k=0; k<lnumRateCats; k++)
				{
				ratePr[i++] = (clP[A] * bs[A] + clP[C] * bs[C] + clP[G] * bs[G] + clP[T] * bs[T]);
				clP += 4;
				}
			lnC += (lnScaler[c] * numSitesOfPat[c]);
			}
		localLag = lag[whichChain*2 + whichState];
		for (c=nChar-1; c>=0; c--)
			{
			cn = c*lnumRateCats;
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				if (c + localLag >= nChar)
					{
					max = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						biN[cn + k] = ratePr[pat*lnumRateCats + k];
						if (biN[cn + k] > max)
							max = biN[cn + k];
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				else
					{
					for (i=0; i<lnumRateCats; i++)
						{
						temp = max = 0.0;
						for (j=0; j<lnumRateCats; j++)
							temp += markovTi[i][j] * biN[(c+localLag)*lnumRateCats + j];
						biN[cn + i] = ratePr[pat*lnumRateCats+i] * temp;
						if (biN[cn + i] > max)
							max = biN[cn + i];
						usedBin[c+localLag] = YES;
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				}
			else
				{
				printf ("   ERROR: Unidentified pattern\n");
				goto error_exit;
				}
			}
		(*lnL) = lnC;
		for (c=0; c<nChar; c++)
			{
			if (usedBin[c] == NO)
				{
				temp = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					temp += (catFreq[k] * biN[c*lnumRateCats + k]);
					}
				(*lnL) += log(temp);
				usedBin[c] = YES;
				}
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	if (nst == 6 || nst == 12)
		{
		free_psdmatrix (q);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex != YES)
			free (c_ijk);
		}
#	endif
	free (catFreq);
	free (likeL);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (ratePr);
		free (usedBin);
		}

	return (NO_ERROR);
	
	error_exit:
#		if !defined (SMART_TI_PROBS)
		free_psdmatrix (probs);
		free (pL);
		if (nst == 6 || nst == 12)
			{
			free_psdmatrix (q);
			free (eigenValues);
			free_psdmatrix (eigvecs);
			free_psdmatrix (inverseEigvecs);
			free_pscmatrix (Ceigvecs);
			free_pscmatrix (CinverseEigvecs);
			if (isComplex != YES)
				free (c_ijk);
			}
#		endif
		free (catFreq);
		free (likeL);
		if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			free_psdmatrix(markovTi);
			free (ratePr);
			free (usedBin);
			}
		return (ERROR);

#undef N_STATES
#undef N_STATES_SQUARED
#undef N_STATES_CUBE
}


/*-----------------------------------------------------------
LnLikeAA: Superfast version. Core written 2001-04-22
------------------------------------------------------------*/
#define N_STATES_SQUARED 400
#define N_STATES 20

int LnLikeAA (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
	register int	a, b, i, j, k, c, n, m, cn;
	int				lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					index, nRates, pat, localLag, *usedBin,
					intNodeOffset, condLikeOffset, scalerOffset,
					indexMultiplier1, indexMultiplier2, *aState, *lState, *rState, shortCut;
	double			bs[N_STATES], *pL, *pR, *pA, *catFreq, *catRate, *partRate,
					*clL, *clR, *clA, *clP, *scP, *preLikeL, *preLikeR, *preLikeA,
					*lnScaler, scaler, like, lnC, *biN, max, temp, correlation,
					*ratePr, **markovTi, likeL, likeR, likeA;
	TreeNode		*p;

#	if !defined (SMART_TI_PROBS)
	int				nPij, isComplex, indexL, indexR, indexA;
	double			theRate, **probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk;
	complex 		**Ceigvecs, **CinverseEigvecs;	
#	else
	int				nForOneState;
#	endif

	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* initialize intNodeOffset */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;

	/* load base frequencies */
	index = whichChain*2*nStates + whichState*nStates;
	for (i=0; i<N_STATES; i++)
		bs[i] = baseFreq[index + i];
		
	/* how many different rates? */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1 */
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1 */
	/* the code introduced here only makes sure that the number of partitions */
	/* or rate categories is set to 1 when appropriate, in case the global variables */
	/* are not set to 1 when they are not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;

	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* preLikeL, preLikeR and preLikeA will contain the cond likelihoods for */
	/* Left, Right and Anc if any of them is a terminal */
	preLikeL = (double *)malloc((size_t)(3 * nRates * (N_STATES_SQUARED + N_STATES) * sizeof(double)));
	if (!preLikeL)
		{
		printf ("\n   ERROR: Problem allocating preLikeL, preLikeR and preLikeA\n");
		goto error_exit;
		}
	preLikeR = preLikeL + nRates * (N_STATES_SQUARED + N_STATES);
	preLikeA = preLikeR + nRates * (N_STATES_SQUARED + N_STATES);

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible rate */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (nStates);
	nPij = nRates * N_STATES_SQUARED;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for autocorrelated gamma models */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		ratePr = (double *)malloc((size_t) (lnumRateCats * (numChars + nChar) * sizeof(double)));
		if (!ratePr)
			{
			printf ("\n   ERROR: Problem allocating ratePr and biN.\n");
			goto error_exit;
			}
		biN = ratePr + lnumRateCats * numChars;
		usedBin = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!usedBin)
			{
			printf ("\n   ERROR: Problem allocating usedBin.\n");
			goto error_exit;
			}
		}

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* get eigenvalues and eigenvectors for AAQ matrix */
#	if !defined (SMART_TI_PROBS)
	q = psdmatrix (N_STATES);
	eigenValues = (double *)malloc((size_t) (2 * N_STATES * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + N_STATES;

	eigvecs = psdmatrix (N_STATES);
	inverseEigvecs = psdmatrix (N_STATES);
	Ceigvecs = pscmatrix (N_STATES);
	CinverseEigvecs = pscmatrix (N_STATES);

	if (SetAAQMatrix (q, whichState, whichChain) == ERROR)
		goto error_exit;
	isComplex = GetEigens (N_STATES, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
	if (isComplex == NO)
		{
		c_ijk = (double *)malloc((size_t) (8000 * sizeof(double)));
		if (!c_ijk)
			{
			printf ("\n   ERROR: Problem allocating c_ijk.\n");
			goto error_exit;
			}
		CalcCijk (c_ijk, N_STATES, eigvecs, inverseEigvecs);
		}
#	endif
	
	/* how large is the information for one tree and one node ?*/
	oneMatSize = numNodes * numChars * lnumRateCats * N_STATES;
	oneNodeSize = numChars * lnumRateCats * N_STATES;

	/* calculate indices */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
#				else
				for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						// calculate transition probabilities for left branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->left->length,  theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->left->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->right->length,  theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->right->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pR[indexR++] = probs[i][j];

						// calculate transition probabilities for ancestral branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->length,  theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pA[indexA++] = probs[i][j];
						
						}
					}
#				endif

				if (!strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (i=0; i<nodeTiSize; i++)
						{
						if (pL[i] < 0.0)
							pL[i] = 0.0;
						if (pR[i] < 0.0)
							pR[i] = 0.0;
						if (pA[i] < 0.0)
							pA[i] = 0.0;
						}
					}

				shortCut = 0;
				/* calculate likelihoods of site patterns for left branch if terminal */
				if (p->left->left == NULL && isPartAmbig[p->left->index] == NO)
					{
					shortCut |= 1;
					lState = termState + p->left->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								for (j=i+b; j<N_STATES_SQUARED+b; j+=N_STATES)
									preLikeL[a++] = pL[j] + ((seqErrorProb - N_STATES*seqErrorProb*pL[j])/19.0);

							/* for ambiguous */
							for (i=0; i<N_STATES; i++)
								preLikeL[a++] = 1.0;

							b += N_STATES_SQUARED;
							}
						}
					}

				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->right->left == NULL && isPartAmbig[p->right->index] == NO)
					{
					shortCut |= 2;
					rState = termState + p->right->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								for (j=i+b; j<N_STATES_SQUARED+b; j+=N_STATES)
									preLikeR[a++] = pR[j] + ((seqErrorProb - N_STATES*seqErrorProb*pR[j])/19.0);

							/* for ambiguous */
							for (i=0; i<N_STATES; i++)
								preLikeR[a++] = 1.0;

							b += N_STATES_SQUARED;
							}
						}
					}

				/* calculate likelihoods of site patterns for anc branch, always terminal */
				if (isPartAmbig[p->anc->index] == YES)
					{
					shortCut = 4;
					}
				else 
					{
					aState = termState + p->anc->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								for (j=i+b; j<N_STATES_SQUARED+b; j+=N_STATES)
									preLikeA[a++] = pA[j] + ((seqErrorProb - N_STATES*seqErrorProb*pA[j])/19.0);

							/* for ambiguous */
							for (i=0; i<N_STATES; i++)
								preLikeA[a++] = 1.0;

							b += N_STATES_SQUARED;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(ratesModel, "equal"))
					{
					switch (shortCut)
						{
					case 4:		// anc is partially ambiguous, do not use any shortcut
						for (c=0; c<numChars; c++)
							{
							for (i=m=0; i<N_STATES; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += N_STATES;
							clR += N_STATES;
							clA += N_STATES;
							}
						break;

					case 0:		// only anc is terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							for (i=m=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR * preLikeA[a++];
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						break;

					case 1:		// left is terminal
					case 3:		// both left and right are terminal; this is a 3-taxon tree
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = lState[c];
							for (i=m=0; i<N_STATES; i++)
								{
								likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
								}
							clR += N_STATES;
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = rState[c];
							for (i=m=0; i<N_STATES; i++)
								{
								likeL = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
								}
							clL += N_STATES;
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					switch (shortCut)
						{
					case 4:		// anc is partially ambiguous, do not use any shortcut
						for (c=0; c<numChars; c++)
							{
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = likeA = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m]*clR[j];
										likeA += pA[m++]*clA[j];
										}
									*(clP++) = likeL * likeR * likeA;
									}
								clL += N_STATES;
								clR += N_STATES;
								clA += N_STATES;
								}
							}
						break;

					case 0:		// only anc is terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR * preLikeA[a++];
									}
								clL += N_STATES;
								clR += N_STATES;
								a += N_STATES_SQUARED;
								}
							}
						break;

					case 1:		// left is terminal
					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = lState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
									}
								clR += N_STATES;
								a += N_STATES_SQUARED;
								b += N_STATES_SQUARED;
								}
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = rState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
									}
								clL += N_STATES;
								a += N_STATES_SQUARED;
								b += N_STATES_SQUARED;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					indexMultiplier1 = lnumRateCats * N_STATES_SQUARED;
					indexMultiplier2 = lnumRateCats * (N_STATES_SQUARED + N_STATES);
					switch (shortCut)
						{
					case 4:		// anc is partially ambiguous, do not use any shortcut
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = likeA = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m]*clR[j];
										likeA += pA[m++]*clA[j];
										}
									*(clP++) = likeL * likeR * likeA;
									}
								clL += N_STATES;
								clR += N_STATES;
								clA += N_STATES;
								}
							}
						break;

					case 0:		// only anc is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = aState[c] + (partitionId[c]*indexMultiplier2);
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR * preLikeA[a++];
									}
								clL += N_STATES;
								clR += N_STATES;
								a += N_STATES_SQUARED;
								}
							}
						break;

					case 1:		// left is terminal
					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = aState[c] + index;
							b = lState[c] + index;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
									}
								clR += N_STATES;
								a += N_STATES_SQUARED;
								b += N_STATES_SQUARED;
								}
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = aState[c] + index;
							b = rState[c] + index;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
									}
								clL += N_STATES;
								a += N_STATES_SQUARED;
								b += N_STATES_SQUARED;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					indexMultiplier1 = N_STATES_SQUARED;
					indexMultiplier2 = (N_STATES_SQUARED + N_STATES);
					switch (shortCut)
						{
					case 4:		// anc is partially ambiguous, do not use any shortcut
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += N_STATES;
							clR += N_STATES;
							clA += N_STATES;
							}
						break;

					case 0:		// only anc is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = aState[c] + (partitionId[c]*indexMultiplier2);
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR * preLikeA[a++];
								}
							clL += N_STATES;
							clR += N_STATES;
							a += N_STATES_SQUARED;
							}
						break;

					case 1:		// left is terminal
					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c]*indexMultiplier2;
							a = aState[c] + index;
							b = lState[c] + index;
							for (i=0; i<N_STATES; i++)
								{
								likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
								}
							clR += N_STATES;
							a += N_STATES_SQUARED;
							b += N_STATES_SQUARED;
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c]*indexMultiplier2;
							a = aState[c] + index;
							b = rState[c] + index;
							for (i=0; i<N_STATES; i++)
								{
								likeL = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
								}
							clL += N_STATES;
							a += N_STATES_SQUARED;
							b += N_STATES_SQUARED;
							}
						break;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for internal root node
			}	// done with internal root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting interior node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
#				else
				for (m=indexL=indexR=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						// calculate transition probabilities for left branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->left->length,  theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->left->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->right->length,  theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->right->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pR[indexR++] = probs[i][j];						
						}
					}
#				endif

				if (!strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (i=0; i<nodeTiSize; i++)
						{
						if (pL[i] < 0.0)
							pL[i] = 0.0;
						if (pR[i] < 0.0)
							pR[i] = 0.0;
						}
					}

				shortCut = 0;
				/* calculate likelihoods of site patterns for left branch if terminal */
				if (p->left->left == NULL && isPartAmbig[p->left->index] == NO)
					{
					shortCut |= 1;
					lState = termState + p->left->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								for (j=i+b; j<N_STATES_SQUARED+b; j+=N_STATES)
									preLikeL[a++] = pL[j] + ((seqErrorProb - N_STATES*seqErrorProb*pL[j])/19.0);

							/* for ambiguous */
							for (i=0; i<N_STATES; i++)
								preLikeL[a++] = 1.0;

							b += N_STATES_SQUARED;
							}
						}
					}

				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->right->left == NULL && isPartAmbig[p->right->index] == NO)
					{
					shortCut |= 2;
					rState = termState + p->right->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								for (j=i+b; j<N_STATES_SQUARED+b; j+=N_STATES)
									preLikeR[a++] = pR[j] + ((seqErrorProb - N_STATES*seqErrorProb*pR[j])/19.0);

							/* for ambiguous */
							for (i=0; i<N_STATES; i++)
								preLikeR[a++] = 1.0;

							b += N_STATES_SQUARED;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(ratesModel, "equal"))
					{
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							for (i=m=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						break;

					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							for (i=m=0; i<N_STATES; i++)
								{
								likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[a++] * likeR;
								}
							clR += N_STATES;
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = rState[c];
							for (i=m=0; i<N_STATES; i++)
								{
								likeL = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[a++];
								}
							clL += N_STATES;
							}
						break;

					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							b = rState[c];
							for (i=m=0; i<N_STATES; i++)
								{
								*(clP++) = preLikeL[a++] * preLikeR[b++];
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += N_STATES;
								clR += N_STATES;
								}
							}
						break;

					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[a++] * likeR;
									}
								clR += N_STATES;
								a += N_STATES_SQUARED;
								}
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = rState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[a++];
									}
								clL += N_STATES;
								a += N_STATES_SQUARED;
								}
							}
						break;

					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							b = rState[c];
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									*(clP++) = preLikeL[a++] * preLikeR[b++];
									}
								a += N_STATES_SQUARED;
								b += N_STATES_SQUARED;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					indexMultiplier1 = lnumRateCats * N_STATES_SQUARED;
					indexMultiplier2 = lnumRateCats * (N_STATES_SQUARED + N_STATES);
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += N_STATES;
								clR += N_STATES;
								}
							}
						break;

					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = lState[c] + (partitionId[c]*indexMultiplier2);
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[a++] * likeR;
									}
								clR += N_STATES;
								a += N_STATES_SQUARED;
								}
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = rState[c] + partitionId[c] * indexMultiplier2;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[a++];
									}
								clL += N_STATES;
								a += N_STATES_SQUARED;
								}
							}
						break;

					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = lState[c] + index;
							b = rState[c] + index;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									*(clP++) = preLikeL[a++] * preLikeR[b++];
									}
								a += N_STATES_SQUARED;
								b += N_STATES_SQUARED;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					indexMultiplier1 = N_STATES_SQUARED;
					indexMultiplier2 = (N_STATES_SQUARED + N_STATES);
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						break;

					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = lState[c] + (partitionId[c]*indexMultiplier2);
							for (i=0; i<N_STATES; i++)
								{
								likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[a++] * likeR;
								}
							clR += N_STATES;
							a += N_STATES_SQUARED;
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = rState[c] + (partitionId[c] * indexMultiplier2);
							for (i=0; i<N_STATES; i++)
								{
								likeL = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[a++];
								}
							clL += N_STATES;
							a += N_STATES_SQUARED;
							}
						break;

					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = lState[c] + index;
							b = rState[c] + index;
							for (i=0; i<N_STATES; i++)
								{
								*(clP++) = preLikeL[a++] * preLikeR[b++];
								}
							a += N_STATES_SQUARED;
							b += N_STATES_SQUARED;
							}
						break;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		// deal with scaling
		// first check if we need to refresh scalers and potentially shift scaler nodes
		// we have to remember scalerIndex because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0) 
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<N_STATES; m++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}
					}
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<N_STATES; m++)
						clP[j++] /= scaler;
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}
		}	// next node
		
	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	(*lnL) = 0.0;	// reset lnL
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (i=0; i<N_STATES; i++)
				like += ((*(clP++)) * bs[i]);

			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				for (i=0; i<N_STATES; i++)
					like += ((*(clP++)) * bs[i]) * catFreq[k];
				}
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		/* initialize usedBin */	
		for (i=0; i<nChar; i++)
			usedBin[i] = NO;
		
		lnC = 0.0;
		m = j = 0;
		for (c=0; c<numChars; c++)
			{
			for (k=0; k<lnumRateCats; k++)
				{
				like = 0.0;
				for (i=0; i<N_STATES; i++)
					like += clP[j++] * bs[i];
				ratePr[m++] = like;
				}
			lnC += (lnScaler[c] * numSitesOfPat[c]);
			}
		localLag = lag[whichChain*2 + whichState];

		for (c=nChar-1; c>=0; c--)
			{
			cn = c*lnumRateCats;
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				if (c + localLag >= nChar)
					{
					max = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						biN[cn + k] = ratePr[pat*lnumRateCats + k];
						if (biN[cn + k] > max)
							max = biN[cn + k];
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}				
				else
					{
					for (i=0; i<lnumRateCats; i++)
						{
						temp = max = 0.0;
						for (j=0; j<lnumRateCats; j++)
							temp += markovTi[i][j] * biN[(c+localLag)*lnumRateCats + j];
						biN[cn + i] = ratePr[pat*lnumRateCats+i] * temp;
						if (biN[cn + i] > max)
							max = biN[cn + i];
						usedBin[c+localLag] = YES;
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				}
			else
				{
				printf ("   ERROR: Unidentified pattern\n");
				goto error_exit;
				}
			}
		(*lnL) = lnC;
		for (c=0; c<nChar; c++)
			{
			if (usedBin[c] == NO)
				{
				temp = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					temp += (catFreq[k] * biN[c*lnumRateCats + k]);
					}
				(*lnL) += log(temp);
				usedBin[c] = YES;
				}
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	if (isComplex != YES)
		free (c_ijk);
#	endif

	free (catFreq);
	free (preLikeL);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (ratePr);
		free (usedBin);
		}

	return (NO_ERROR);
	
error_exit:
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	if (isComplex != YES)
		free (c_ijk);
#	endif

	free (catFreq);
	free (preLikeL);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (ratePr);
		free (usedBin);
		}

	return (ERROR);

#undef N_STATES_SQUARED
#undef N_STATES
}



/*-----------------------------------------------------------
LnLikeCodon: Superfast version of the codon likelihood function
Written 2001-04-04
------------------------------------------------------------*/
int LnLikeCodon (int whichState, int whichChain, int numChars, double *lnL, int refreshScalers)
{
	register int	i, j, k, c, n, m, cn, a, b;
	int				nOmegaCats, oneMatSize, oneNodeSize,
					index, pat, isFirst,
					intNodeOffset, condLikeOffset, scalerOffset,
					lnStates, lnStatesSquared, lnStatesCube, shortCut, *lState, *rState, *aState;
	double			*bs, *pL, *pR, *pA, *clL, *clR, *clA, *clP, *scP,
					*lnScaler, scaler, like, lnC, *biN, max, temp, *omegaPr, markovTi[3][3],
					likeL, likeR, likeA, likePos, likeNeu, likePur, *preLikeL, *preLikeR, *preLikeA;
	TreeNode		*p;
#	if defined (SMART_TI_PROBS)
	int				nForOneState;
#	else
	int				nPij, isComplex, indexL, indexR, indexA, isComplex2, isComplex3;
	double			lkappa, theRate, **probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk,
					*eigenValues2, *eigvalsImag2, **eigvecs2, **inverseEigvecs2, *c_ijk2,
					*eigenValues3, *eigvalsImag3, **eigvecs3, **inverseEigvecs3, *c_ijk3;
	complex 		**Ceigvecs, **CinverseEigvecs, **Ceigvecs2, **CinverseEigvecs2,
					**Ceigvecs3, **CinverseEigvecs3;	
#	endif

	/* set number of states */
	if (!strcmp(codonModelType, "covny98"))
		lnStates = 3 * nStates;
	else
		lnStates = nStates;
	lnStatesSquared = lnStates * lnStates;
	lnStatesCube = lnStatesSquared * lnStates;
		
	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* load codon frequencies */
	bs = (double *)malloc((size_t) (lnStates * sizeof(double)));
	if (!bs)
		{
		printf ("\n   ERROR: Problem allocating bs.\n");
		goto error_exit;
		}
	index = whichChain*2*nStates + whichState*nStates;
	if (!strcmp(codonModelType, "covny98"))
		{
		k = 0;
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probPur[whichChain*2 + whichState];
			k++;
			}
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probNeu[whichChain*2 + whichState];
			k++;
			}
		for (i=0; i<nStates; i++)
			{
			bs[k] = baseFreq[index + i] * probPos[whichChain*2 + whichState];
			k++;
			}
		}
	else
		{
		for (i=0; i<nStates; i++)
			bs[i] = baseFreq[index + i];
		}

	/* how many different omega categories */
	if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		nOmegaCats = 3;
	else
		nOmegaCats = 1;
						
	/* allocate memory for autocorrelated codon models */
	if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		omegaPr = (double *)malloc((size_t) (nOmegaCats * (numChars + nChar) * sizeof(double)));
		if (!omegaPr)
			{
			printf ("\n   ERROR: Problem allocating omegaPr and biN.\n");
			goto error_exit;
			}
		biN = omegaPr + nOmegaCats * numChars;
		}

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible omega value */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (lnStates);
	nPij = nOmegaCats * lnStatesSquared;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* preLikeL, preLikeR and preLikeA will contain the cond likelihoods for Left, Right and Anc */
	/* if any of them is a terminal with unambiguous codon states or completely ambiguous/gap */
	preLikeL = (double *)malloc((size_t)(3 * nOmegaCats * (nStates + 1) * lnStates * sizeof(double)));
	if (!preLikeL)
		{
		printf ("\n   ERROR: Problem allocating preLikeL, preLikeR and preLikeA\n");
		goto error_exit;
		}
	preLikeR = preLikeL + nOmegaCats * (nStates + 1) * lnStates;
	preLikeA = preLikeR + nOmegaCats * (nStates + 1) * lnStates;

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* allocate memory for eigenvalues and eigenvectors */
#	if !defined (SMART_TI_PROBS)
	q = psdmatrix (lnStates);
	eigenValues = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + lnStates;

	eigvecs = psdmatrix (lnStates);
	inverseEigvecs = psdmatrix (lnStates);
	Ceigvecs = pscmatrix (lnStates);
	CinverseEigvecs = pscmatrix (lnStates);

	/* get eigenvalues and eigenvectors for codon Q matrix */
	if (!strcmp(codonModelType, "covny98"))
		{
		if (SetCodonSwitchQMatrix (q, whichState, whichChain, omega[whichChain*2 + whichState], kappa[whichChain*2 + whichState], switchRate[whichChain*4 + whichState*2 + 0]) == ERROR)
			goto error_exit;
		}
	else
		{
		if (SetCodonQMatrix (q, whichState, whichChain, omega[whichChain*2 + whichState], kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		}
	isComplex = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
	if (isComplex == NO)
		{
		c_ijk = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
		if (!c_ijk)
			{
			printf ("\n   ERROR: Problem allocating c_ijk.\n");
			goto error_exit;
			}
		CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
		}
	if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		/* these models use several omega categories, one Q matrix needed for each */
		/* first set Q matrix for synonymous changes (negative selection) */
		eigenValues2 = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
		if (!eigenValues2)
			{
			printf ("\n   ERROR: Problem allocating eigenValues2 and eigvalsImag2.\n");
			goto error_exit;
			}
		eigvalsImag2 = eigenValues2 + lnStates;

		eigvecs2 = psdmatrix (lnStates);
		inverseEigvecs2 = psdmatrix (lnStates);
		Ceigvecs2 = pscmatrix (lnStates);
		CinverseEigvecs2 = pscmatrix (lnStates);

		if (SetCodonQMatrix (q, whichState, whichChain, 0.0, kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		isComplex2 = GetEigens (lnStates, q, eigenValues2, eigvalsImag2, eigvecs2, inverseEigvecs2, Ceigvecs2, CinverseEigvecs2);
		if (isComplex2 == NO)
			{
			c_ijk2 = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
			if (!c_ijk2)
				{
				printf ("\n   ERROR: Problem allocating c_ijk2.\n");
				goto error_exit;
				}
			CalcCijk (c_ijk2, lnStates, eigvecs2, inverseEigvecs2);
			}
		
		/* then set Q matrix for nonsynonymous changes (positive selection) */
		eigenValues3 = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
		if (!eigenValues2)
			{
			printf ("\n   ERROR: Problem allocating eigenValues2 and eigvalsImag2.\n");
			goto error_exit;
			}
		eigvalsImag3 = eigenValues2 + lnStates;
		eigvecs3 = psdmatrix (lnStates);
		inverseEigvecs3 = psdmatrix (lnStates);
		Ceigvecs3 = pscmatrix (lnStates);
		CinverseEigvecs3 = pscmatrix (lnStates);
		if (SetCodonQMatrix (q, whichState, whichChain, 1.0, kappa[whichChain*2 + whichState]) == ERROR)
			goto error_exit;
		isComplex3 = GetEigens (lnStates, q, eigenValues3, eigvalsImag3, eigvecs3, inverseEigvecs3, Ceigvecs3, CinverseEigvecs3);
		if (isComplex3 == NO)
			{
			c_ijk3 = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
			if (!c_ijk3)
				{
				printf ("\n   ERROR: Problem allocating c_ijk3.\n");
				goto error_exit;
				}
			CalcCijk (c_ijk3, lnStates, eigvecs3, inverseEigvecs3);
			}
		}
#	endif
		
	/* how large is the information for one tree and one node */
	oneMatSize = numNodes * numChars * nOmegaCats * lnStates;
	oneNodeSize = numChars * nOmegaCats * lnStates;

	/* calculate index offsets */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
#				else
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */
				indexL = indexR = indexA = 0;
				// calculate transition probabilities for left branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->left->length,  1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->left->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						pL[indexL++] = probs[i][j];
				
				// calculate transition probabilities for right branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->right->length, 1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->right->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						pR[indexR++] = probs[i][j];

				// calculate transition probabilities for ancestral branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->length, 1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
								pA[indexA++] = probs[i][j];
												
				if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
					{
					/* set transition probabilities for synonymous changes */
					// left branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->left->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->left->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pL[indexL++] = probs[i][j];
					// right branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->right->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->right->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pR[indexR++] = probs[i][j];
					// ancestral branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pA[indexA++] = probs[i][j];

					/* set transition probabilities for nonsynonymous changes */
					// left branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->left->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->left->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pL[indexL++] = probs[i][j];
					// right branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->right->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->right->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pR[indexR++] = probs[i][j];
					// ancestral branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pA[indexA++] = probs[i][j];
					}
#				endif

				shortCut = 0;
				/* calculate likelihoods of site patterns for left branch if terminal */
				if (p->left->left == NULL && isPartAmbig[p->left->index] == NO)
					{
					shortCut |= 1;
					lState = termState + p->left->index * numChars;
					for (k=m=0; k<nOmegaCats; k++)
						{
						if (!strcmp(codonModelType, "covny98"))
							{
							// 183 x 183 model, only first third of matrix needed
							for (i=0; i<nStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeL[m++] = pL[j] + pL[j+nStates] + pL[j+(2*nStates)];
							}
						else	// 61 x 61 model
							{
							a = k*lnStatesSquared;
							for (i=0; i<lnStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeL[m++] = pL[j+a];
							}
						/* for completely ambiguous */
						for (i=0; i<lnStates; i++)
							{ 
							preLikeL[m++] = 1.0;
							}
						}
					}

				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->right->left == NULL && isPartAmbig[p->right->index] == NO)
					{
					shortCut |= 2;
					rState = termState + p->right->index * numChars;
					for (k=m=0; k<nOmegaCats; k++)
						{
						if (!strcmp(codonModelType, "covny98"))
							{
							// 183 x 183 model
							for (i=0; i<nStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeR[m++] = pR[j] + pR[j+nStates] + pR[j+(2*nStates)];
							}
						else	// 61 x 61 model
							{
							a = k*lnStatesSquared;
							for (i=0; i<lnStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeR[m++] = pR[j+a];
							}

						/* for completely ambiguous */
						for (i=0; i<lnStates; i++)
							{ 
							preLikeR[m++] = 1.0;
							}
						}
					}

				/* calculate likelihoods of site patterns for ancestral branch, always terminal */
				if (isPartAmbig[p->anc->index] == YES)
					{
					shortCut = 4;
					}
				else 
					{
					aState = termState + p->anc->index * numChars;
					for (k=m=0; k<nOmegaCats; k++)
						{
						if (!strcmp(codonModelType, "covny98"))
							{
							// 183 x 183 model
							for (i=0; i<nStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeA[m++] = pA[j] + pA[j+nStates] + pA[j+(2*nStates)];
							}
						else	// 61 x 61 model
							{
							a = k*lnStatesSquared;
							for (i=0; i<lnStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeA[m++] = pA[j+a];
							}

						/* for completely ambiguous */
						for (i=0; i<lnStates; i++)
							{ 
							preLikeA[m++] = 1.0;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
					{
					switch (shortCut)
						{
					case 4:	// anc is partially ambiguous
						for (c=0; c<numChars; c++)
							{
							for (k=m=0; k<nOmegaCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = likeA = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m]*clR[j];
										likeA += pA[m++]*clA[j];
										}
									*(clP++) = likeL * likeR * likeA;
									}
								clL += lnStates;
								clR += lnStates;
								clA += lnStates;
								}
							}
						break;
					case 0:
					case 3:	// if both left and right are terminal, this is a 3-taxon tree and no shortcut is necessary
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							for (k=m=0; k<nOmegaCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR * preLikeA[a++];
									}
								clL += lnStates;
								clR += lnStates;
								a += lnStatesSquared;
								}
							}
						break;
					case 1:
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = lState[c];
							for (k=m=0; k<nOmegaCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
									}
								clR += lnStates;
								a += lnStatesSquared;
								b += lnStatesSquared;
								}
							}
						break;
					case 2:
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = rState[c];
							for (k=m=0; k<nOmegaCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
									}
								clL += lnStates;
								a += lnStatesSquared;
								b += lnStatesSquared;
								}
							}
						break;
						}
					}
				else /* no omega variation or omega switch model */
					{
					switch (shortCut)
						{
					case 4:	// anc is partially ambiguous
						for (c=0; c<numChars; c++)
							{
							for (i=m=0; i<lnStates; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += lnStates;
							clR += lnStates;
							clA += lnStates;
							}
						break;
					case 0:		// only anc is terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR * preLikeA[a++];
								}
							clL += lnStates;
							clR += lnStates;
							}
						break;
					case 1:		// left terminal
					case 3:		// both right and left terminal - this is a three-taxon tree
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = lState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
								}
							clR += lnStates;
							}
						break;
					case 2:		// right terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = rState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeL = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
								}
							clL += lnStates;
							}
						break;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for internal root node
			}	// done with internal root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting interior node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
#				else
				indexL = indexR = 0;

				// calculate transition probabilities for left branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->left->length,  1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->left->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						pL[indexL++] = probs[i][j];
				
				// calculate transition probabilities for right branch
				if (isComplex == NO)
					CalcPij (c_ijk, lnStates, eigenValues, p->right->length, 1.0, probs);
				else
					if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->right->length, 1.0) == ERROR) 
						{
						printf ("Problem calculating transition probabilities for complex eigen values.\n");
						goto error_exit;
						}
				for (i=0; i<lnStates; i++)
					for (j=0; j<lnStates; j++)
						pR[indexR++] = probs[i][j];
						
				if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
					{
					/* set transition probabilities for synonymous changes */

					// left branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->left->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->left->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pL[indexL++] = probs[i][j];
					// right branch
					if (isComplex2 == NO)
						CalcPij (c_ijk2, lnStates, eigenValues2, p->right->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues2, eigvalsImag2, Ceigvecs2, CinverseEigvecs2, lnStates, probs, p->right->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pR[indexR++] = probs[i][j];

					/* set transition probabilities for nonsynonymous changes */
					// left branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->left->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->left->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pL[indexL++] = probs[i][j];
					// right branch
					if (isComplex3 == NO)
						CalcPij (c_ijk3, lnStates, eigenValues3, p->right->length,  1.0, probs);
					else
						if (ComplexChangeMatrix (eigenValues3, eigvalsImag3, Ceigvecs3, CinverseEigvecs3, lnStates, probs, p->right->length, 1.0) == ERROR)
							printf ("Problem calculating transition probabilities for complex eigen values.\n");
					for (i=0; i<lnStates; i++)
						for (j=0; j<lnStates; j++)
							pR[indexR++] = probs[i][j];
					}
#				endif

				shortCut = 0;
				/* calculate likelihoods of site patterns for left branch if terminal */
				if (p->left->left == NULL && isPartAmbig[p->left->index] == NO)
					{
					shortCut |= 1;
					lState = termState + p->left->index * numChars;
					for (k=m=0; k<nOmegaCats; k++)
						{
						if (!strcmp(codonModelType, "covny98"))
							{
							// 183 x 183 model, only first third of matrix needed
							for (i=0; i<nStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeL[m++] = pL[j] + pL[j+nStates] + pL[j+(2*nStates)];
							}
						else	// 61 x 61 model
							{
							a = k*lnStatesSquared;
							for (i=0; i<lnStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeL[m++] = pL[j+a];
							}

						/* for completely ambiguous */
						for (i=0; i<lnStates; i++)
							{ 
							preLikeL[m++] = 1.0;
							}
						}
					}

				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->right->left == NULL && isPartAmbig[p->right->index] == NO)
					{
					shortCut |= 2;
					rState = termState + p->right->index * numChars;
					for (k=m=0; k<nOmegaCats; k++)
						{
						if (!strcmp(codonModelType, "covny98"))
							{
							// 183 x 183 model
							for (i=0; i<nStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeR[m++] = pR[j] + pR[j+nStates] + pR[j+(2*nStates)];
							}
						else	// 61 x 61 model
							{
							a = k*lnStatesSquared;
							for (i=0; i<lnStates; i++)
								for (j=i; j<lnStatesSquared; j+=lnStates)
									preLikeR[m++] = pR[j+a];
							}

						/* for completely ambiguous */
						for (i=0; i<lnStates; i++)
							{ 
							preLikeR[m++] = 1.0;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
					{
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							for (k=m=0; k<nOmegaCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += lnStates;
								clR += lnStates;
								}
							}
						break;
					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							for (k=m=0; k<nOmegaCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[a++] * likeR;
									}
								clR += lnStates;
								a += lnStatesSquared;
								}
							}
						break;
					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = rState[c];
							for (k=m=0; k<nOmegaCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[a++];
									}
								clL += lnStates;
								a += lnStatesSquared;
								}
							}
						break;
					case 3:		// both right and left are terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							b = rState[c];
							for (k=m=0; k<nOmegaCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									*(clP++) = preLikeL[a++] * preLikeR[b++];
									}
								a += lnStatesSquared;
								b += lnStatesSquared;
								}
							}
						break;
						}
					}
				else /* no omega variation or omega switch model */
					{
					switch (shortCut)
						{
					case 0:
						for (c=0; c<numChars; c++)
							{
							for (i=m=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += lnStates;
							clR += lnStates;
							}
						break;
					case 1:
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[a++] * likeR;
								}
							clR += lnStates;
							}
						break;
					case 2:
						for (c=0; c<numChars; c++)
							{
							a = rState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeL = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[a++];
								}
							clL += lnStates;
							}
						break;
					case 3:
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							b = rState[c];
							for (i=0; i<lnStates; i++)
								{
								*(clP++) = preLikeL[a++] * preLikeR[b++];
								}
							}
						break;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		// deal with scaling
		// first check if we need to refresh scalers and potentially shift scaler nodes
		// we have to remember scalerIndex because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0)
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<nOmegaCats; k++)
					{
					for (m=0; m<lnStates; m++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}
					}
				for (k=0; k<nOmegaCats; k++)
					{
					for (m=0; m<lnStates; m++)
						clP[j++] /= scaler;
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}
		}	// next node
		
	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	(*lnL) = 0.0;	// reset lnL
	if (!strcmp(codonModelType, "ny98"))
		{
		for (c=0; c<numChars; c++)
			{
			likePur = likeNeu = likePos = 0.0;
			
			for (i=0; i<lnStates; i++)
				likePos += (*(clP++)) * bs[i];
			for (i=0; i<lnStates; i++)
				likePur += (*(clP++)) * bs[i];
			for (i=0; i<lnStates; i++)
				likeNeu += (*(clP++)) * bs[i];
				
			//printf ("%4d -- %lf %lf %lf (%lf)\n", c, likePur, likeNeu, likePos, like);
			like = likePos * probPos[whichChain*2 + whichState] + likePur * probPur[whichChain*2 + whichState] + likeNeu * probNeu[whichChain*2 + whichState];
								
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		if (!strcmp(codonModelType, "ac1ny98"))
			InitTiMatrix (markovTi, rateCorrelation[whichChain*2 + whichState], 0.0, 0.0, probPur[whichChain*2 + whichState], probNeu[whichChain*2 + whichState], probPos[whichChain*2 + whichState], 1);
		else
			InitTiMatrix (markovTi, rateCorrelation[whichChain*2 + whichState], rateCorrelation2[whichChain*4 + whichState*2 + 0], rateCorrelation2[whichChain*4 + whichState*2 + 1], probPur[whichChain*2 + whichState], probNeu[whichChain*2 + whichState], probPos[whichChain*2 + whichState], 2);

		lnC = 0.0;
		m = j = 0;
		for (c=0; c<numChars; c++)
			{
			likePur = likeNeu = likePos = 0.0;
			for (i=0; i<lnStates; i++)
				likePos += clP[j++] * bs[i];
			for (i=0; i<lnStates; i++)
				likePur += clP[j++] * bs[i];
			for (i=0; i<lnStates; i++)
				likeNeu += clP[j++] * bs[i];
			omegaPr[m++] = likePur;
			omegaPr[m++] = likeNeu;
			omegaPr[m++] = likePos;
			lnC += (lnScaler[c] * numSitesOfPat[c]);
			}
		isFirst = YES;
		for (c=(nChar/3)-1; c>=0; c--)
			{
			cn = c*3;
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				if (isFirst == YES)
					{
					max = 0.0;
					for (k=0; k<3; k++)
						{
						biN[cn + k] = omegaPr[pat*3 + k];
						if (biN[cn + k] > max)
							max = biN[cn + k];
						}
					if (max > 0.0)
						{
						for (k=0; k<3; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for ac1ny98 or ac2ny98 model is less than 0\n");
						goto error_exit;
						}
					isFirst = NO;
					}				
				else		// isFirst == NO
					{
					for (i=0; i<3; i++)
						{
						temp = max = 0.0;
						for (j=0; j<3; j++)
							temp += markovTi[i][j] * biN[(c+1)*3 + j];
						biN[cn + i] = omegaPr[pat*3+i] * temp;
						if (biN[cn + i] > max)
							max = biN[cn + i];
						}
					if (max > 0.0)
						{
						for (k=0; k<3; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				}
			else
				{
				printf ("   ERROR: Unidentified pattern\n");
				goto error_exit;
				}
			}
		temp  = biN[0] * probPur[whichChain*2 + whichState];
		temp += biN[1] * probNeu[whichChain*2 + whichState];
		temp += biN[2] * probPos[whichChain*2 + whichState];
		(*lnL) = lnC + log(temp);
		}
	else /* no omega variation or covarion-like model */
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (i=0; i<lnStates; i++)
				like += ((*(clP++)) * bs[i]);

			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				printf ("c %d like %f \n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	if (isComplex != YES)
		free (c_ijk);
	if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		free (eigenValues2);
		free_psdmatrix (eigvecs2);
		free_psdmatrix (inverseEigvecs2);
		free_pscmatrix (Ceigvecs2);
		free_pscmatrix (CinverseEigvecs2);
		if (isComplex2 != YES)
			free (c_ijk2);
		free (eigenValues3);
		free_psdmatrix (eigvecs3);
		free_psdmatrix (inverseEigvecs3);
		free_pscmatrix (Ceigvecs3);
		free_pscmatrix (CinverseEigvecs3);
		if (isComplex3 != YES)
			free (c_ijk3);
		}
#	endif
	free (bs);
	free (preLikeL);
	if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		free (omegaPr);
	return (NO_ERROR);

	error_exit:
#		if !defined (SMART_TI_PROBS)
		free_psdmatrix (probs);
		free (pL);
		free_psdmatrix (q);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex != YES)
			free (c_ijk);
		if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
			{
			free (eigenValues2);
			free_psdmatrix (eigvecs2);
			free_psdmatrix (inverseEigvecs2);
			free_pscmatrix (Ceigvecs2);
			free_pscmatrix (CinverseEigvecs2);
			if (isComplex2 != YES)
				free (c_ijk2);
			free (eigenValues3);
			free_psdmatrix (eigvecs3);
			free_psdmatrix (inverseEigvecs3);
			free_pscmatrix (Ceigvecs3);
			free_pscmatrix (CinverseEigvecs3);
			if (isComplex3 != YES)
				free (c_ijk3);
			}
#		endif
		free (bs);
		free (preLikeL);
		if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
			free (omegaPr);
		return (ERROR);

}


/*---------------------------------------------------------------------
LnLikeCovarion: 'Superfast' version of likelihood function for covariotide
or covarion models. Core written 2001-04-20
-----------------------------------------------------------------------*/
int LnLikeCovarion (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
	register int	a, b, i, j, k, c, n, m, cn;
	int				lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					index, index1, index2, nRates, pat, localLag, *usedBin,
					intNodeOffset, condLikeOffset, scalerOffset, preLikeIncrement,
					lnStates, lnStatesSquared, lnStatesCube, shortCut, 
					*aState, *lState, *rState, indexMultiplier1, indexMultiplier2;
	double			*bs, *pL, *pR, *pA, *catFreq, *catRate, *partRate,
					*clL, *clR, *clA, *clP, *scP, s01, s10, prob0, prob1,
					*lnScaler, scaler, like, lnC, *biN, max, temp, correlation,
					*ratePr, **markovTi, likeL, likeR, likeA, *preLikeL, *preLikeR, *preLikeA;
	TreeNode		*p;

#	if defined (SMART_TI_PROBS)
	int				nForOneState;
#	else
	int				nPij, *isComplex, indexL, indexR, indexA;
	double			**probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk,
					*eigenValuesP, *eigvalsImagP, *eigvecsP, *inverseEigvecsP, *c_ijkP;
	complex 		**Ceigvecs, **CinverseEigvecs, *CeigvecsP, *CinverseEigvecsP;	
#	endif
	
	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* calculate local number of states */
	/* twice nStates because matrix is doubled */
	/* calculate increment for precalculated likelihoods */
	lnStates = 2 * nStates;
	lnStatesSquared = lnStates * lnStates;
	lnStatesCube = lnStates * lnStatesSquared;
	preLikeIncrement = nStates * lnStates;
	
	/* load base frequencies */
	index = whichChain*2*lnStates + whichState*lnStates;
	index1 = whichChain*4 + whichState*2;
	index2 = whichChain*2 + whichState;
	bs = (double *)malloc((size_t) (lnStates * sizeof(double)));
	if (!bs)
		{
		printf ("\n   ERROR: Problem allocating bs.\n");
		goto error_exit;
		}
	if (!strcmp(covarionModelType, "ts98"))
		{
		k = 0;
		for (j=0; j<2; j++)
			{
			for (i=0; i<nStates; i++)
				{
				bs[k] = baseFreq[whichChain*2*nStates + whichState*nStates + i] * switchPi[whichChain*4 + whichState*2 + j];
				//bs[k] = baseFreq[index + i] * switchPi[index1 + j];
				k++;
				}
			}
		}
	else if (!strcmp(covarionModelType, "gcswitch"))
		{
		s01 = switchRate[index1 + 0];
		s10 = switchRate[index1 + 1];
		prob0 = s10 / (s01+s10);
		prob1 = s01 / (s01+s10);
		bs[0] = (1.0 - gc1[index2]) * (fracA[index2])       * prob0;
		bs[1] = (gc1[index2])       * (1.0 - fracG[index2]) * prob0;
		bs[2] = (gc1[index2])       * (fracG[index2])       * prob0;
		bs[3] = (1.0 - gc1[index2]) * (1.0 - fracA[index2]) * prob0;
		bs[4] = (1.0 - gc2[index2]) * (fracA[index2])       * prob1;
		bs[5] = (gc2[index2])       * (1.0 - fracG[index2]) * prob1;
		bs[6] = (gc2[index2])       * (fracG[index2])       * prob1;
		bs[7] = (1.0 - gc2[index2]) * (1.0 - fracA[index2]) * prob1;
		}
	/*for (i=0; i<lnStates; i++)
		printf ("%lf ", bs[i]);
	printf ("\n");*/

	/* how many different rates? */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1
	/* the code introduced here only makes sure that the number of partitions
	/* or rate categories is set to 1 when appropriate, in case the global variables
	/* are not set to 1 when they are not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;

	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* preLikeL, preLikeR and preLikeA will contain the cond likelihoods for */
	/* Left, Right and Anc if any of them is a terminal */
	preLikeL = (double *)malloc((size_t)(3 * nRates * (nStates + 1) * lnStates * sizeof(double)));
	if (!preLikeL)
		{
		printf ("\n   ERROR: Problem allocating preLikeL, preLikeR and preLikeA\n");
		goto error_exit;
		}
	preLikeR = preLikeL + nRates * (nStates + 1) * lnStates;
	preLikeA = preLikeR + nRates * (nStates + 1) * lnStates;

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible rate */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (lnStates);
	nPij = nRates * lnStatesSquared;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for autocorrelated gamma models */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		ratePr = (double *)malloc((size_t) (lnumRateCats * (numChars + nChar) * sizeof(double)));
		if (!ratePr)
			{
			printf ("\n   ERROR: Problem allocating ratePr and biN.\n");
			goto error_exit;
			}
		biN = ratePr + lnumRateCats * numChars;
		usedBin = (int *)malloc((size_t) (nChar * sizeof(int)));
		if (!usedBin)
			{
			printf ("\n   ERROR: Problem allocating usedBin.\n");
			goto error_exit;
			}
		}

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* allocate memory for eigenvalues and eigenvectors */
	/* first for base matrix */
#	if !defined (SMART_TI_PROBS)
	q = psdmatrix (lnStates);
	eigenValues = (double *)malloc((size_t) (2 * lnStates * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + lnStates;
	c_ijk = (double *)malloc((size_t) (lnStatesCube * sizeof(double)));
	if (!c_ijk)
		{
		printf ("\n   ERROR: Problem allocating c_ijk.\n");
		goto error_exit;
		}
	eigvecs = psdmatrix (lnStates);
	inverseEigvecs = psdmatrix (lnStates);
	Ceigvecs = pscmatrix (lnStates);
	CinverseEigvecs = pscmatrix (lnStates);

	/* then for partitions */
	isComplex = (int *)malloc((size_t) (nRates * sizeof(int)));
	if (!isComplex)
		{
		printf ("\n   ERROR: Problem allocating isComplex.\n");
		goto error_exit;
		}
	eigenValuesP = (double *)malloc((size_t) (2 * nRates * lnStates * sizeof(double)));
	if (!eigenValuesP)
		{
		printf ("\n   ERROR: Problem allocating eigenValuesP and eigvalsImagP.\n");
		goto error_exit;
		}
	eigvalsImagP = eigenValuesP + nRates * lnStates;
	eigvecsP = (double *)malloc((size_t) (2 * nRates * lnStatesSquared * sizeof(double)));
	if (!eigvecsP)
		{
		printf ("\n   ERROR: Problem allocating eigvecsP and inverseEigvecsP.\n");
		goto error_exit;
		}
	inverseEigvecsP = eigvecsP + nRates * lnStatesSquared;
	CeigvecsP = (complex *)malloc((size_t) (2 * nRates * lnStatesSquared * sizeof(complex)));
	if (!CeigvecsP)
		{
		printf ("\n   ERROR: Problem allocating CeigvecsP and CinverseEigvecsP.\n");
		goto error_exit;
		}
	CinverseEigvecsP = CeigvecsP + nRates * lnStatesSquared;
	c_ijkP = (double *)malloc((size_t) (nRates * lnStatesCube * sizeof(double)));
	if (!c_ijkP)
		{
		printf ("\n   ERROR: Problem allocating c_ijkP.\n");
		goto error_exit;
		}

	/* get eigenvalues and eigenvectors for covarion matrices */
	/* one matrix needed for each rate because catrates and partrates
	   affect only part of the matrix */
	// a is index to rate eigenvectors, b is index to rates
	for (m=a=b=0; m<lnPartitions; m++)
		{
		for (k=0; k<lnumRateCats; k++)
			{
			if (dataType == DNA || dataType == RNA)
				{
				if (!strcmp(covarionModelType, "ts98"))
					{
					if (SetDNACovQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
						goto error_exit;
					}
				else if (!strcmp(covarionModelType, "gcswitch"))
					{
					if (SetGCSwitchQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
						goto error_exit;
					}
				else
					{
					goto error_exit;
					}
				}
			else
				{
				if (SetAACovQMatrix (q, whichState, whichChain, catRate[k]*partRate[m]) == ERROR)
					goto error_exit;
				}
			isComplex[b] = GetEigens (lnStates, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
			if (isComplex[b] == NO)
				{
				CalcCijk (c_ijk, lnStates, eigvecs, inverseEigvecs);
				}
			for (i=0; i<lnStates; i++)
				{
				eigenValuesP[b*lnStates + i] = eigenValues[i];
				eigvalsImagP[b*lnStates + i] = eigvalsImag[i];
				}
			for (i=0; i<lnStates; i++)
				{
				for (j=0; j<lnStates; j++)
					{
					eigvecsP[a]            = eigvecs[i][j];
					inverseEigvecsP[a]     = inverseEigvecs[i][j];
					CeigvecsP[a].re        = Ceigvecs[i][j].re;
					CinverseEigvecsP[a].re = CinverseEigvecs[i][j].re;
					CeigvecsP[a].im        = Ceigvecs[i][j].im;
					CinverseEigvecsP[a].im = CinverseEigvecs[i][j].im;
					a++;
					}
				}
			for (i=0; i<lnStatesCube; i++)
				c_ijkP[b*lnStatesCube + i] = c_ijk[i];
			b++;
			}
		}
#	endif
	
	/* how large is the information for one tree and one node ?*/
	oneMatSize = numNodes * numChars * lnumRateCats * lnStates;
	oneNodeSize = numChars * lnumRateCats * lnStates;

	/* calculate index offsets */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */					
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
#				else
				for (m=indexL=indexR=indexA=b=a=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						// fetch eigenvalues and eigenvectors for this rate
						// the rate itself is not needed because it has
						// been taken care of in the diagonalized matrices
						for (i=0; i<lnStates; i++)
							{
							eigenValues[i] = eigenValuesP[b*lnStates + i];
							eigvalsImag[i] = eigvalsImagP[b*lnStates + i];
							}
						for (i=0; i<lnStates; i++)
							{
							for (j=0; j<lnStates; j++)
								{
								eigvecs[i][j]            = eigvecsP[a];
								inverseEigvecs[i][j]     = inverseEigvecsP[a];
								Ceigvecs[i][j].re        = CeigvecsP[a].re;
								CinverseEigvecs[i][j].re = CinverseEigvecsP[a].re;
								Ceigvecs[i][j].im        = CeigvecsP[a].im;
								CinverseEigvecs[i][j].im = CinverseEigvecsP[a].im;
								a++;
								}
							}
						// fetch c_ijk for this rate
						for (i=0; i<lnStatesCube; i++)
							c_ijk[i] = c_ijkP[b*lnStatesCube + i];

						// calculate transition probabilities for left branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->left->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->left->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->right->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->right->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pR[indexR++] = probs[i][j];

						// calculate transition probabilities for ancestral branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pA[indexA++] = probs[i][j];
						b++;
						}
					}
#				endif

				if (!strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (i=0; i<nodeTiSize; i++)
						{
						if (pL[i] < 0.0)
							pL[i] = 0.0;
						if (pR[i] < 0.0)
							pR[i] = 0.0;
						if (pA[i] < 0.0)
							pA[i] = 0.0;
						}
					}

				shortCut = 0;
				/* calculate likelihoods of site patterns for left branch if terminal */
				if (p->left->left == NULL && isPartAmbig[p->left->index] == NO)
					{
					shortCut |= 1;
					lState = termState + p->left->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates; i++)
								for (j=i+b; j<lnStatesSquared+b; j+=lnStates)
									{
									temp = pL[j] + pL[j+nStates];
									preLikeL[a++] = temp + ((seqErrorProb - nStates*seqErrorProb*temp)/(nStates-1.0));
									}

							/* for ambiguous */
							for (i=0; i<lnStates; i++)
								preLikeL[a++] = 1.0;

							b += lnStatesSquared;
							}
						}
					}

				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->right->left == NULL && isPartAmbig[p->right->index] == NO)
					{
					shortCut |= 2;
					rState = termState + p->right->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates; i++)
								for (j=i+b; j<lnStatesSquared+b; j+=lnStates)
									{
									temp = pR[j] + pR[j+nStates];
									preLikeR[a++] = temp + ((seqErrorProb - nStates*seqErrorProb*temp)/(nStates-1.0));
									}

							/* for ambiguous */
							for (i=0; i<lnStates; i++)
								preLikeR[a++] = 1.0;

							b += lnStatesSquared;
							}
						}
					}

				/* calculate likelihoods of site patterns for anc branch, always terminal */
				if (isPartAmbig[p->anc->index] == YES)
					{
					shortCut = 4;
					}
				else 
					{
					aState = termState + p->anc->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates; i++)
								for (j=i+b; j<lnStatesSquared+b; j+=lnStates)
									{
									temp = pA[j] + pA[j+nStates];
									preLikeA[a++] = temp + ((seqErrorProb - nStates*seqErrorProb*temp)/(nStates-1.0));
									}

							/* for ambiguous */
							for (i=0; i<lnStates; i++)
								preLikeA[a++] = 1.0;

							b += lnStatesSquared;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(ratesModel, "equal"))
					{
					switch (shortCut)
						{
					case 4:		// anc is partially ambiguous, do not use any shortcut
						for (c=0; c<numChars; c++)
							{
							for (i=m=0; i<lnStates; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += lnStates;
							clR += lnStates;
							clA += lnStates;
							}
						break;

					case 0:
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR * preLikeA[a++];
								}
							clL += lnStates;
							clR += lnStates;
							}
						break;

					case 1:		// left is terminal
					case 3:		// both left and right are terminal; this is a 3-taxon tree
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = lState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
								}
							clR += lnStates;
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = rState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeL = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
								}
							clL += lnStates;
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					switch (shortCut)
						{
					case 4:		// anc is partially ambiguous, do not use any shortcut
						for (c=0; c<numChars; c++)
							{
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = likeA = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m]*clR[j];
										likeA += pA[m++]*clA[j];
										}
									*(clP++) = likeL * likeR * likeA;
									}
								clL += lnStates;
								clR += lnStates;
								clA += lnStates;
								}
							}
						break;

					case 0:		// only anc is terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR * preLikeA[a++];
									}
								clL += lnStates;
								clR += lnStates;
								a += preLikeIncrement;
								}
							}
						break;

					case 1:		// left is terminal
					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = lState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
									}
								clR += lnStates;
								a += preLikeIncrement;
								b += preLikeIncrement;
								}
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = aState[c];
							b = rState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
									}
								clL += lnStates;
								a += preLikeIncrement;
								b += preLikeIncrement;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					indexMultiplier1 = lnumRateCats * lnStatesSquared;
					indexMultiplier2 = lnumRateCats * (nStates + 1) * lnStates;
					switch (shortCut)
						{
					case 4:		// anc is partially ambiguous, do not use any shortcut
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = likeA = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m]*clR[j];
										likeA += pA[m++]*clA[j];
										}
									*(clP++) = likeL * likeR * likeA;
									}
								clL += lnStates;
								clR += lnStates;
								clA += lnStates;
								}
							}
						break;

					case 0:		// only anc is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = aState[c] + (partitionId[c]*indexMultiplier2);
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR * preLikeA[a++];
									}
								clL += lnStates;
								clR += lnStates;
								a += preLikeIncrement;
								}
							}
						break;

					case 1:		// left is terminal
					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = aState[c] + index;
							b = lState[c] + index;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
									}
								clR += lnStates;
								a += preLikeIncrement;
								b += preLikeIncrement;
								}
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = aState[c] + index;
							b = rState[c] + index;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
									}
								clL += lnStates;
								a += preLikeIncrement;
								b += preLikeIncrement;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					indexMultiplier1 = lnStatesSquared;
					indexMultiplier2 = (nStates + 1) * lnStates;
					switch (shortCut)
						{
					case 4:		// anc is partially ambiguous, do not use any shortcut
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += lnStates;
							clR += lnStates;
							clA += lnStates;
							}
						break;

					case 0:		// only anc is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = aState[c] + (partitionId[c]*indexMultiplier2);
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR * preLikeA[a++];
								}
							clL += lnStates;
							clR += lnStates;
							}
						break;

					case 1:		// left is terminal
					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = aState[c] + index;
							b = lState[c] + index;
							for (i=0; i<lnStates; i++)
								{
								likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[b++] * likeR * preLikeA[a++];
								}
							clR += lnStates;
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = aState[c] + index;
							b = rState[c] + index;
							for (i=0; i<lnStates; i++)
								{
								likeL = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[b++] * preLikeA[a++];
								}
							clL += lnStates;
							}
						break;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for internal root node
			}	// done with internal root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting interior node %d\n", p->index);
				/* get transition probabilities */
#				if defined (SMART_TI_PROBS)
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
#				else
				for (m=indexL=indexR=b=a=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						// fetch eigenvalues and eigenvectors for this rate
						// the rate itself is not needed because it has
						// been taken care of in the diagonalized matrices
						for (i=0; i<lnStates; i++)
							{
							eigenValues[i] = eigenValuesP[b*lnStates + i];
							eigvalsImag[i] = eigvalsImagP[b*lnStates + i];
							}
						for (i=0; i<lnStates; i++)
							{
							for (j=0; j<lnStates; j++)
								{
								eigvecs[i][j]            = eigvecsP[a];
								inverseEigvecs[i][j]     = inverseEigvecsP[a];
								Ceigvecs[i][j].re        = CeigvecsP[a].re;
								CinverseEigvecs[i][j].re = CinverseEigvecsP[a].re;
								Ceigvecs[i][j].im        = CeigvecsP[a].im;
								CinverseEigvecs[i][j].im = CinverseEigvecsP[a].im;
								a++;
								}
							}
						// fetch c_ijk for this rate
						for (i=0; i<lnStatesCube; i++)
							c_ijk[i] = c_ijkP[b*lnStatesCube + i];

						// calculate transition probabilities for left branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->left->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->left->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex[b] == NO)
							CalcPij (c_ijk, lnStates, eigenValues, p->right->length, 1.0, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, lnStates, probs, p->right->length, 1.0) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<lnStates; i++)
							for (j=0; j<lnStates; j++)
								pR[indexR++] = probs[i][j];
						b++;
						}
					}
#				endif

				if (!strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (i=0; i<nodeTiSize; i++)
						{
						if (pL[i] < 0.0)
							pL[i] = 0.0;
						if (pR[i] < 0.0)
							pR[i] = 0.0;
						}
					}

				shortCut = 0;
				/* calculate likelihoods of site patterns for left branch if terminal */
				if (p->left->left == NULL && isPartAmbig[p->left->index] == NO)
					{
					shortCut |= 1;
					lState = termState + p->left->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates; i++)
								for (j=i+b; j<lnStatesSquared+b; j+=lnStates)
									{
									temp = pL[j] + pL[j+nStates];
									preLikeL[a++] = temp + ((seqErrorProb - nStates*seqErrorProb*temp)/(nStates-1.0));
									}

							/* for ambiguous */
							for (i=0; i<lnStates; i++)
								preLikeL[a++] = 1.0;

							b += lnStatesSquared;
							}
						}
					}

				/* calculate likelihoods of site patterns for right branch if terminal */
				if (p->right->left == NULL && isPartAmbig[p->right->index] == NO)
					{
					shortCut |= 2;
					rState = termState + p->right->index * numChars;
					for (m=a=b=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates; i++)
								for (j=i+b; j<lnStatesSquared+b; j+=lnStates)
									{
									temp = pR[j] + pR[j+nStates];
									preLikeR[a++] = temp + ((seqErrorProb - nStates*seqErrorProb*temp)/(nStates-1.0));
									}

							/* for ambiguous */
							for (i=0; i<lnStates; i++)
								preLikeR[a++] = 1.0;

							b += lnStatesSquared;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				/* then branch to models */
				if (!strcmp(ratesModel, "equal"))
					{
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							for (i=m=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += lnStates;
							clR += lnStates;
							}
						break;

					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[a++] * likeR;
								}
							clR += lnStates;
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = rState[c];
							for (i=m=0; i<lnStates; i++)
								{
								likeL = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[a++];
								}
							clL += lnStates;
							}
						break;

					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							b = rState[c];
							for (i=m=0; i<lnStates; i++)
								{
								*(clP++) = preLikeL[a++] * preLikeR[b++];
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += lnStates;
								clR += lnStates;
								}
							}
						break;

					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[a++] * likeR;
									}
								clR += lnStates;
								a += preLikeIncrement;
								}
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							a = rState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[a++];
									}
								clL += lnStates;
								a += preLikeIncrement;
								}
							}
						break;

					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							a = lState[c];
							b = rState[c];
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									*(clP++) = preLikeL[a++] * preLikeR[b++];
									}
								a += preLikeIncrement;
								b += preLikeIncrement;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					indexMultiplier1 = lnumRateCats * lnStatesSquared;
					indexMultiplier2 = lnumRateCats * (nStates + 1) * lnStates;
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += lnStates;
								clR += lnStates;
								}
							}
						break;

					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = lState[c] + (partitionId[c]*indexMultiplier2);
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeR = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = preLikeL[a++] * likeR;
									}
								clR += lnStates;
								a += preLikeIncrement;
								}
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = rState[c] + (partitionId[c] * indexMultiplier2);
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									likeL = 0.0;
									for (j=0; j<lnStates; j++)
										{
										likeL += pL[m++]*clL[j];
										}
									*(clP++) = likeL * preLikeR[a++];
									}
								clL += lnStates;
								a += preLikeIncrement;
								}
							}
						break;

					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = lState[c] + index;
							b = rState[c] + index;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<lnStates; i++)
									{
									*(clP++) = preLikeL[a++] * preLikeR[b++];
									}
								a += preLikeIncrement;
								b += preLikeIncrement;
								}
							}
						break;
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					indexMultiplier1 = lnStatesSquared;
					indexMultiplier2 = (nStates + 1) * lnStates;
					switch (shortCut)
						{
					case 0:		// none is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							for (i=0; i<lnStates; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += lnStates;
							clR += lnStates;
							}
						break;

					case 1:		// left is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = lState[c] + (partitionId[c]*indexMultiplier2);
							for (i=0; i<lnStates; i++)
								{
								likeR = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = preLikeL[a++] * likeR;
								}
							clR += lnStates;
							}
						break;

					case 2:		// right is terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							a = rState[c] + (partitionId[c] * indexMultiplier2);
							for (i=0; i<lnStates; i++)
								{
								likeL = 0.0;
								for (j=0; j<lnStates; j++)
									{
									likeL += pL[m++]*clL[j];
									}
								*(clP++) = likeL * preLikeR[a++];
								}
							clL += lnStates;
							}
						break;

					case 3:		// both left and right are terminal
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*indexMultiplier1;
							index = partitionId[c] * indexMultiplier2;
							a = lState[c] + index;
							b = rState[c] + index;
							for (i=0; i<lnStates; i++)
								{
								*(clP++) = preLikeL[a++] * preLikeR[b++];
								}
							}
						break;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		// deal with scaling
		// first check if we need to refresh scalers and potentially shift scaler nodes
		// we have to remember scalerIndex because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0) 
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<lnStates; m++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}
					}
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<lnStates; m++)
						clP[j++] /= scaler;
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}
		}	// next node
		
	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	(*lnL) = 0.0;	// reset lnL
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (i=0; i<lnStates; i++)
				like += ((*(clP++)) * bs[i]);

			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				for (i=0; i<lnStates; i++)
					like += ((*(clP++)) * bs[i]) * catFreq[k];
				}
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		/* initialize usedBin */	
		for (i=0; i<nChar; i++)
			usedBin[i] = NO;
		lnC = 0.0;
		m = j = 0;
		for (c=0; c<numChars; c++)
			{
			for (k=0; k<lnumRateCats; k++)
				{
				like = 0.0;
				for (i=0; i<lnStates; i++)
					like += clP[j++] * bs[i];
				ratePr[m++] = like;
				}
			lnC += (lnScaler[c] * numSitesOfPat[c]);
			}
		localLag = lag[whichChain*2 + whichState];

		for (c=nChar-1; c>=0; c--)
			{
			cn = c*lnumRateCats;
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				if (c + localLag >= nChar)
					{
					max = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						biN[cn + k] = ratePr[pat*lnumRateCats + k];
						if (biN[cn + k] > max)
							max = biN[cn + k];
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}				
				else
					{
					for (i=0; i<lnumRateCats; i++)
						{
						temp = max = 0.0;
						for (j=0; j<lnumRateCats; j++)
							temp += markovTi[i][j] * biN[(c+localLag)*lnumRateCats + j];
						biN[cn + i] = ratePr[pat*lnumRateCats+i] * temp;
						if (biN[cn + i] > max)
							max = biN[cn + i];
						usedBin[c+localLag] = YES;
						}
					if (max > 0.0)
						{
						for (k=0; k<lnumRateCats; k++)
							biN[cn + k] /= max;
						lnC += log(max);
						}
					else
						{
						printf ("   ERROR: Scaling factor for adgamma model is less than 0\n");
						goto error_exit;
						}
					}
				}
			else
				{
				printf ("   ERROR: Unidentified pattern\n");
				goto error_exit;
				}
			}
		(*lnL) = lnC;
		for (c=0; c<nChar; c++)
			{
			if (usedBin[c] == NO)
				{
				temp = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					temp += (catFreq[k] * biN[c*lnumRateCats + k]);
					}
				(*lnL) += log(temp);
				usedBin[c] = YES;
				}
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	free (c_ijk);
	free (isComplex);
	free (eigenValuesP);
	free (eigvecsP);
	free (CeigvecsP);
	free (c_ijkP);
#	endif
	free (catFreq);
	free (bs);
	free (preLikeL);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (ratePr);
		free (usedBin);
		}

	return (NO_ERROR);
	
error_exit:
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	free (c_ijk);
	free (isComplex);
	free (eigenValuesP);
	free (eigvecsP);
	free (CeigvecsP);
	free (c_ijkP);
#	endif
	free (catFreq);
	free (bs);
	free (preLikeL);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (ratePr);
		free (usedBin);
		}

	return (ERROR);

}


#endif




/*-----------------------------------------------------------
LnLikeRestriction: 'Fast' version, core written 2001-03-12
------------------------------------------------------------*/
int LnLikeRestriction (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
	register int	i, j, k, b, c, n, m;
	int				nPij, lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					condLikeOffset, scalerOffset, indexL, indexR, indexA,
					index, intNodeOffset, nRates;
	double			bs[2], *pL, *pR, *pA, *catFreq, *catRate, alp, bet, x, v, eV,
					*clL, *clR, *clA, *clP, *tiPL, *tiPR, *tiPA, like, theRate,
					*lnScaler, *scP, *partRate, scaler;

	TreeNode		*p;
	
#	define N_STATES_SQUARED 4
#	define N_STATES 2

	/* initialize intNodeOffset */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;
	
	/* how many different rate categories?
	/* deal with relevant models
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1
	/* this is to make sure that these variables are set locally to 1 if not
	/* relevant for the model specified for the data						*/
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "ssgamma"))
		lnumRateCats = numRateCats;
	nRates = lnPartitions * lnumRateCats;	// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* one trans prob matrix needed for each possible rate */
	nPij = nRates * numBetaCats * N_STATES_SQUARED;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;

	/* allocate memory for rates and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (lnumRateCats > 1)
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else {
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;
			
	/* set forward/backward ratio */
	x = kappa[whichChain*2 + whichState];
	alp = (x*x + x) / (2*x);
	bet = (x + 1.0) / (2*x);

	/* fill in stationary frequencies */
	bs[0] = bet / (alp + bet);
	bs[1] = alp / (alp + bet);
		
	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * numBetaCats * N_STATES;
	oneNodeSize = numChars * lnumRateCats * numBetaCats * N_STATES;

	/* calculate indices */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */
				for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
							
						v = p->left->length * theRate;
						eV = exp(-(alp+bet)*v);
						pL[indexL++]  = bs[0] + bs[1] * eV;
						pL[indexL++]  = bs[1] - bs[1] * eV;
						pL[indexL++]  = bs[0] - bs[0] * eV;
						pL[indexL++]  = bs[1] + bs[0] * eV;

						v = p->right->length * theRate;
						eV = exp(-(alp+bet)*v);
						pR[indexR++]  = bs[0] + bs[1] * eV;
						pR[indexR++]  = bs[1] - bs[1] * eV;
						pR[indexR++]  = bs[0] - bs[0] * eV;
						pR[indexR++]  = bs[1] + bs[0] * eV;

						v = p->length * theRate;
						eV = exp(-(alp+bet)*v);
						pA[indexA++]  = bs[0] + bs[1] * eV;
						pA[indexA++]  = bs[1] - bs[1] * eV;
						pA[indexA++]  = bs[0] - bs[0] * eV;
						pA[indexA++]  = bs[1] + bs[0] * eV;
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					tiPA = pA;
					for (c=0; c<numChars; c++)
						{
						*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
									*(tiPR[0]*clR[0] + tiPR[1]*clR[1])
									*(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
						*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
									*(tiPR[2]*clR[0] + tiPR[3]*clR[1])
									*(tiPA[2]*clA[0] + tiPA[3]*clA[1]);
						clL += 2;
						clR += 2;
						clA += 2;
						}
					}
				else if (!strcmp(ratesModel, "gamma"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						tiPA = pA;
						for (k=0; k<lnumRateCats; k++)
							{
							*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
										*(tiPR[0]*clR[0] + tiPR[1]*clR[1])
										*(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
							*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
										*(tiPR[2]*clR[0] + tiPR[3]*clR[1])
										*(tiPA[2]*clA[0] + tiPA[3]*clA[1]);
							tiPL += 4;
							tiPR += 4;
							tiPA += 4;
							clL += 2;
							clR += 2;
							clA += 2;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]* lnumRateCats * numBetaCats * N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						for (k=0; k<lnumRateCats; k++)
							{
							*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
										*(tiPR[0]*clR[0] + tiPR[1]*clR[1])
										*(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
							*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
										*(tiPR[2]*clR[0] + tiPR[3]*clR[1])
										*(tiPA[2]*clA[0] + tiPA[3]*clA[1]);
							tiPL += 4;
							tiPR += 4;
							tiPA += 4;
							clL += 2;
							clR += 2;
							clA += 2;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c] * numBetaCats * N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
									*(tiPR[0]*clR[0] + tiPR[1]*clR[1])
									*(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
						*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
									*(tiPR[2]*clR[0] + tiPR[3]*clR[1])
									*(tiPA[2]*clA[0] + tiPA[3]*clA[1]);
						clL += 2;
						clR += 2;
						clA += 2;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for root node
			}	// done with root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting internal node %d\n", p->index);
				/* get transition probabilities */
				for (m=indexL=indexR=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
							
						v = p->left->length * theRate;
						eV = exp(-(alp+bet)*v);
						pL[indexL++]  = bs[0] + bs[1] * eV;
						pL[indexL++]  = bs[1] - bs[1] * eV;
						pL[indexL++]  = bs[0] - bs[0] * eV;
						pL[indexL++]  = bs[1] + bs[0] * eV;

						v = p->right->length * theRate;
						eV = exp(-(alp+bet)*v);
						pR[indexR++]  = bs[0] + bs[1] * eV;
						pR[indexR++]  = bs[1] - bs[1] * eV;
						pR[indexR++]  = bs[0] - bs[0] * eV;
						pR[indexR++]  = bs[1] + bs[0] * eV;
						}
					}
					
				/* calculate conditional likelihoods */
				/* first assign pointers to right, left and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					for (c=0; c<numChars; c++)
						{
						*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
									*(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
						*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
									*(tiPR[2]*clR[0] + tiPR[3]*clR[1]);
						clL += 2;
						clR += 2;
						}
					}
				else if (!strcmp(ratesModel, "gamma"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						for (k=0; k<lnumRateCats; k++)
							{
							*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
										*(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
							*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
										*(tiPR[2]*clR[0] + tiPR[3]*clR[1]);
							tiPL += 4;
							tiPR += 4;
							clL += 2;
							clR += 2;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c] * lnumRateCats * numBetaCats * N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						for (k=0; k<lnumRateCats; k++)
							{
							*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
										*(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
							*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
										*(tiPR[2]*clR[0] + tiPR[3]*clR[1]);
							tiPL += 4;
							tiPR += 4;
							clL += 2;
							clR += 2;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c] * numBetaCats * N_STATES_SQUARED ;
						tiPL = &pL[index];
						tiPR = &pR[index];
						*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
									*(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
						*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
									*(tiPR[2]*clR[0] + tiPR[3]*clR[1]);
						clL += 2;
						clR += 2;
						}
					}

				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node
			
		// deal with scaling
		// first check if we need to refresh scalers
		// and potentially shift scaler nodes
		// we have to remember scalerIndex
		// because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0) 
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					for (b=0; b<numBetaCats; b++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}
					}
				for (k=0; k<lnumRateCats; k++)
					{
					for (b=0; b<numBetaCats; b++)
						{
						clP[j++] /= scaler;
						clP[j++] /= scaler;
						}
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}

		}	// next node
		
	/* get likelihood at base of tree */
	/* deal with conditioning by dividing like with pObserved */
	p = root[whichChain*2+whichState]->left;
	(*lnL) = 0.0;
	for (k=0; k<lnumRateCats; k++)
		pObserved = 0.0;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=j=0; c<numDummyChars; c++)
			{
			like  = (clP[j++] * bs[0]);
			like += (clP[j++] * bs[1]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				pObserved += exp(lnScaler[c]) * like;
			}

		pObserved = 1.0 - pObserved;

		for (c=numDummyChars; c<numChars; c++)
			{
			like  = (clP[j++] * bs[0]);
			like += (clP[j++] * bs[1]);
			like /= pObserved;
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=j=0; c<numDummyChars; c++)
			{
			like=0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				like += clP[j++] * bs[0] * catFreq[k];
				like += clP[j++] * bs[1] * catFreq[k];
				}
			pObserved += like * exp(lnScaler[c]);
			}

		pObserved = 1.0 - pObserved;
		if (pObserved < LIKE_EPSILON)
			pObserved = LIKE_EPSILON;

		for (c=numDummyChars; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				like += (clP[j++] * bs[0] * catFreq[k]);
				like += (clP[j++] * bs[1] * catFreq[k]);
				}
			like /= pObserved;
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
			}
		}

	/* free memory */
	free (pL);
	free (catFreq);

	return (NO_ERROR);
	
	error_exit:
		free (pL);
		free (catFreq);

		return (ERROR);
	
#	undef N_STATES_SQUARED
#	undef N_STATES

}


/*----------------------------------------------------------------------
LnLikeStandardBin: Likelihood function for standard binary data
This function deals with conditioning on coding type and different independent
stationary frequencies determined by a discrete beta function
Rate var dealt with according to equal, sitespec, gamma or ssgamma models
Core written 2001-03-11
------------------------------------------------------------------------*/
int LnLikeStandardBin (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
	register int	i, j, k, b, c, n, m;
	int				nPij, lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					condLikeOffset, scalerOffset, indexL, indexR, indexA,
					index, intNodeOffset, nRates;
	double			*bs, *pL, *pR, *pA, *catFreq, *catRate, alp, bet, x, v, eV,
					*clL, *clR, *clA, *clP, *tiPL, *tiPR, *tiPA, like, theRate,
					*lnScaler, *scP, *partRate, scaler, *betaFreq, *betaValues,
					bs0, bs1;

	TreeNode		*p;
	
#	define N_STATES_SQUARED 4
#	define N_STATES 2

	/* initialize intNodeOffset */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;
	
	/* how many different rate categories?
	/* deal with relevant models
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1
	/* this is to make sure that these variables are set locally to 1 if not
	/* relevant for the model specified for the data						*/
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "ssgamma"))
		lnumRateCats = numRateCats;

	nRates = lnPartitions * lnumRateCats;	// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* one trans prob matrix needed for each possible rate */
	nPij = nRates * numBetaCats * N_STATES_SQUARED;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;

	/* allocate memory for rates and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for the discrete beta values */
	betaFreq = (double *)malloc((size_t) (4 * numBetaCats * sizeof(double)));
	if (!betaFreq)
		{
		printf ("\n   ERROR: Problem allocating betaValues, betaFreq and bs.\n");
		goto error_exit;
		}
	betaValues = betaFreq + numBetaCats;
	bs = betaValues + numBetaCats;

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (lnumRateCats > 1)
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else {
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;
			
	/* fill in beta categories */
	if (!strcmp(stateFreqPrModel, "fixed"))
		{
		betaValues[0] = 0.5;
		betaFreq[0] = 1.0;
		}
	else if (!strcmp(stateFreqPrModel, "dirichlet"))
		{
		BetaBreaks (statefreqP[whichChain*2 + whichState], statefreqP[whichChain*2 + whichState], betaValues, betaFreq, numBetaCats);
#		if defined (DEBUG_LNLIKEBIN)
		for (i=0; i<numBetaCats; i++)
			printf ("%4d -- %lf %lf\n", i+1, betaValues[i], betaFreq[i]);
#		endif
		}

	/* fill in stationary frequencies */
	for (b=j=0; b<numBetaCats; b++)
		{
		x = (1.0 / betaValues[b]) - 1.0;
		alp = (x*x + x) / (2*x);
		bet = (x + 1.0) / (2*x);
		bs[j++] = bet / (alp + bet);
		bs[j++] = alp / (alp + bet);
		}
#		if defined (DEBUG_LNLIKEBIN)
		for (i=0; i<numBetaCats; i++)
			printf ("%4d -- %lf %lf\n", i+1, bs[2*i], bs[2*i+1]);
#		endif
		
	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * numBetaCats * N_STATES;
	oneNodeSize = numChars * lnumRateCats * numBetaCats * N_STATES;

	/* calculate indices */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities */
				for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						for (b=j=0; b<numBetaCats; b++)
							{
							bs0 = bs[j++];
							bs1 = bs[j++];
							x = (1.0 / betaValues[b]) - 1.0;
							alp = (x*x + x) / (2*x);
							bet = (x + 1.0) / (2*x);
							
							v = p->left->length * theRate;
							eV = exp(-(alp+bet)*v);
							pL[indexL++]  = (bs0) + (bs1) * eV;
							pL[indexL++]  = (bs1) - (bs1) * eV;
							pL[indexL++]  = (bs0) - (bs0) * eV;
							pL[indexL++]  = (bs1) + (bs0) * eV;

							v = p->right->length * theRate;
							eV = exp(-(alp+bet)*v);
							pR[indexR++]  = (bs0) + (bs1) * eV;
							pR[indexR++]  = (bs1) - (bs1) * eV;
							pR[indexR++]  = (bs0) - (bs0) * eV;
							pR[indexR++]  = (bs1) + (bs0) * eV;

							v = p->length * theRate;
							eV = exp(-(alp+bet)*v);
							pA[indexA++]  = (bs0) + (bs1) * eV;
							pA[indexA++]  = (bs1) - (bs1) * eV;
							pA[indexA++]  = (bs0) - (bs0) * eV;
							pA[indexA++]  = (bs1) + (bs0) * eV;
							}
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				if (!strcmp(ratesModel, "equal"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						tiPA = pA;
						for (b=0; b<numBetaCats; b++)
							{
							*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
										*(tiPR[0]*clR[0] + tiPR[1]*clR[1])
										*(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
							*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
										*(tiPR[2]*clR[0] + tiPR[3]*clR[1])
										*(tiPA[2]*clA[0] + tiPA[3]*clA[1]);
							tiPL += 4;
							tiPR += 4;
							tiPA += 4;
							clL += 2;
							clR += 2;
							clA += 2;
							}
						}
					}
				else if (!strcmp(ratesModel, "gamma"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						tiPA = pA;
						for (k=0; k<lnumRateCats; k++)
							{
							for (b=0; b<numBetaCats; b++)
								{
								*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
											*(tiPR[0]*clR[0] + tiPR[1]*clR[1])
											*(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
								*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
											*(tiPR[2]*clR[0] + tiPR[3]*clR[1])
											*(tiPA[2]*clA[0] + tiPA[3]*clA[1]);
								tiPL += 4;
								tiPR += 4;
								tiPA += 4;
								clL += 2;
								clR += 2;
								clA += 2;
								}
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]* lnumRateCats * numBetaCats * N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						for (k=0; k<lnumRateCats; k++)
							{
							for (b=0; b<numBetaCats; b++)
								{
								*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
											*(tiPR[0]*clR[0] + tiPR[1]*clR[1])
											*(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
								*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
											*(tiPR[2]*clR[0] + tiPR[3]*clR[1])
											*(tiPA[2]*clA[0] + tiPA[3]*clA[1]);
								tiPL += 4;
								tiPR += 4;
								tiPA += 4;
								clL += 2;
								clR += 2;
								clA += 2;
								}
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c] * numBetaCats * N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						for (b=0; b<numBetaCats; b++)
							{
							*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
										*(tiPR[0]*clR[0] + tiPR[1]*clR[1])
										*(tiPA[0]*clA[0] + tiPA[1]*clA[1]);
							*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
										*(tiPR[2]*clR[0] + tiPR[3]*clR[1])
										*(tiPA[2]*clA[0] + tiPA[3]*clA[1]);
							tiPL += 4;
							tiPR += 4;
							tiPA += 4;
							clL += 2;
							clR += 2;
							clA += 2;
							}
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for root node
			}	// done with root node
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting internal node %d\n", p->index);

				/* get transition probabilities */
				for (m=indexL=indexR=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						for (b=j=0; b<numBetaCats; b++)
							{
							bs0 = bs[j++];
							bs1 = bs[j++];
							x = (1.0 / betaValues[b]) - 1.0;
							alp = (x*x + x) / (2*x);
							bet = (x + 1.0) / (2*x);
							
							v = p->left->length * theRate;
							eV = exp(-(alp+bet)*v);
							pL[indexL++]  = (bs0) + (bs1) * eV;
							pL[indexL++]  = (bs1) - (bs1) * eV;
							pL[indexL++]  = (bs0) - (bs0) * eV;
							pL[indexL++]  = (bs1) + (bs0) * eV;

							v = p->right->length * theRate;
							eV = exp(-(alp+bet)*v);
							pR[indexR++]  = (bs0) + (bs1) * eV;
							pR[indexR++]  = (bs1) - (bs1) * eV;
							pR[indexR++]  = (bs0) - (bs0) * eV;
							pR[indexR++]  = (bs1) + (bs0) * eV;
							}
						}
					}
					
				/* calculate conditional likelihoods */
				/* first assign pointers to right, left and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				if (!strcmp(ratesModel, "equal"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						for (b=0; b<numBetaCats; b++)
							{
							*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
										*(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
							*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
										*(tiPR[2]*clR[0] + tiPR[3]*clR[1]);
							tiPL += 4;
							tiPR += 4;
							clL += 2;
							clR += 2;
							}
						}
					}
				else if (!strcmp(ratesModel, "gamma"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						for (k=0; k<lnumRateCats; k++)
							{
							for (b=0; b<numBetaCats; b++)
								{
								*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
											*(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
								*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
											*(tiPR[2]*clR[0] + tiPR[3]*clR[1]);
								tiPL += 4;
								tiPR += 4;
								clL += 2;
								clR += 2;
								}
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c] * lnumRateCats * numBetaCats * N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						for (k=0; k<lnumRateCats; k++)
							{
							for (b=0; b<numBetaCats; b++)
								{
								*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
											*(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
								*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
											*(tiPR[2]*clR[0] + tiPR[3]*clR[1]);
								tiPL += 4;
								tiPR += 4;
								clL += 2;
								clR += 2;
								}
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c] * numBetaCats * N_STATES_SQUARED ;
						tiPL = &pL[index];
						tiPR = &pR[index];
						for (b=0; b<numBetaCats; b++)
							{
							*(clP++) =	 (tiPL[0]*clL[0] + tiPL[1]*clL[1])
										*(tiPR[0]*clR[0] + tiPR[1]*clR[1]);
							*(clP++) =	 (tiPL[2]*clL[0] + tiPL[3]*clL[1])
										*(tiPR[2]*clR[0] + tiPR[3]*clR[1]);
							tiPL += 4;
							tiPR += 4;
							clL += 2;
							clR += 2;
							}
						}
					}

				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node
			
		// deal with scaling
		// first check if we need to refresh scalers
		// and potentially shift scaler nodes
		// we have to remember scalerIndex
		// because the node may move in the tree
		if (refreshScalers == YES) 
			{
			if (n % RESCALE_FREQ == 0) 
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}
		
		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			m = lnumRateCats * numBetaCats;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<m; k++)
					{
					if (clP[i] > scaler)
						scaler = clP[i];
					i++;
					if (clP[i] > scaler)
						scaler = clP[i];
					i++;
					}
				for (k=0; k<m; k++)
					{
					clP[j++] /= scaler;
					clP[j++] /= scaler;
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}

		}	// next node
		
	/* get likelihood at base of tree */
	/* deal with conditioning by dividing like with pObserved */
	p = root[whichChain*2+whichState]->left;
	(*lnL) = 0.0;
	pObserved = 0.0;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=j=0; c<numDummyChars; c++)
			{
			like = 0.0;
			for (b=m=0; b<numBetaCats; b++)
				{
				like += clP[j++] * bs[m++] * betaFreq[b];
				like += clP[j++] * bs[m++] * betaFreq[b];
				}
			pObserved += like * exp(lnScaler[c]);
			}

		pObserved = 1.0 - pObserved;
		if (pObserved < LIKE_EPSILON)
			pObserved = LIKE_EPSILON;

		for (c=numDummyChars; c<numChars; c++)
			{
			like = 0.0;
			for (b=m=0; b<numBetaCats; b++)
				{
				like += clP[j++] * bs[m++] * betaFreq[b];
				like += clP[j++] * bs[m++] * betaFreq[b];
				}
			if (like * exp(lnScaler[c]) > pObserved)
				{
				printf ("      WARNING: Character likelihood > p(observed)\n");
				goto error_exit;
				}
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=j=0; c<numDummyChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				for (b=m=0; b<numBetaCats; b++)
					{
					like += clP[j++] * bs[m++] * catFreq[k] * betaFreq[b];
					like += clP[j++] * bs[m++] * catFreq[k] * betaFreq[b];
					}
				}
			pObserved += like * exp(lnScaler[c]);
			}

		pObserved = 1.0 - pObserved;
		if (pObserved < LIKE_EPSILON)
			pObserved = LIKE_EPSILON;
		
		for (c=numDummyChars; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				for (b=m=0; b<numBetaCats; b++)
					{
					like += clP[j++] * bs[m++] * catFreq[k] * betaFreq[b];
					like += clP[j++] * bs[m++] * catFreq[k] * betaFreq[b];
					}
				}
			if (like * exp (lnScaler[c]) > pObserved)
				{
				printf ("      WARNING: Character likelihood > p(observed)\n");
				goto error_exit;
				}
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
			}
		}

	/* correct for absent characters */
	(*lnL) -= log(pObserved) * (nChar);

	/* free memory */
	free (pL);
	free (catFreq);
	free (betaFreq);

	return (NO_ERROR);
	
	error_exit:
		free (pL);
		free (catFreq);
		free (betaFreq);

		return (ERROR);
	
#	undef N_STATES_SQUARED
#	undef N_STATES

}




/*----------------------------------------------------------------------
LnLikeStandardMk: Likelihood function for standard data
This function is prepared for dealing with varying number of states
It needs help by a vector array indicating the number of states for each
site pattern, instead of relying on the global nStates, as in the present code,
and a help function that sets up the Q and P matrices
It uses 1/nStates as the probability of the state at the root
It deals with ordered/unordered chars given suitable help functions
It deals with gamma, ssgamma, sitespec and equal models of rate variation
Core written 2001-03-11
------------------------------------------------------------------------*/
int LnLikeStandardMk (int whichState, int whichChain, int numChars, int numRateCats, double *lnL, int refreshScalers)
{
	register int	i, j, k, c, n, m;
	int				nPij, lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					intNodeOffset, nStatesSquared, index, nRates,
					condLikeOffset, scalerOffset, indexL, indexR, indexA;
	double			**probs, *stateFreq, *pL, *pR, *pA, *catFreq, *catRate,
					*clL, *clR, *clA, *clP, *tiPL, *tiPR, *tiPA, like, theRate,
					*lnScaler, *scP, *partRate, scaler;
	double			likeA, likeL, likeR;

	TreeNode		*p;
	
	/* initialize intNodeOffset and nStatesSquared*/
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;
	nStatesSquared = nStates * nStates;

	/* load state frequencies */
	stateFreq = (double *)malloc((size_t) (nStates * sizeof(double)));
	if (!stateFreq)
		{
		printf ("\n   ERROR: Problem allocating stateFreq\n");
		goto error_exit;
		}
	index = whichChain*2*nStates + whichState*nStates;
	for (i = 0; i < nStates; i++)
		stateFreq[i] = 1.0 / nStates;
	
	/* how many different rate categories */
	/* deal with relevant models */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1 */
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1 */
	/* this is to make sure that these variables are set to 1 even if not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "ssgamma"))
		lnumRateCats = numRateCats;

	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* one trans prob matrix needed for each possible rate */
	nPij = nRates * nStatesSquared;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	probs = (double **) malloc ((size_t) (nStates * sizeof(double *)));
	if (!probs)
		{
		printf ("\n   ERROR: Problem allocating space for transition matrices\n");
		goto error_exit;
		}

	probs[0] = (double *) malloc ((size_t) (nStatesSquared * sizeof(double)));
	if (!probs[0])
		{
		printf ("\n   ERROR: Problem allocating space for transition matrices\n");
		goto error_exit;
		}
	for (i=1; i<nStates; i++)
		probs[i] = probs[i-1] + nStates;

	// pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (lnumRateCats > 1)
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else
		{
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;
			
	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * nStates;
	oneNodeSize = numChars * lnumRateCats * nStates;

	/* calculate indices */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;
	scalerOffset = whichChain*2*numIntNodes*numChars + whichState*numIntNodes*numChars;

	/* pass down tree */
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		// for debugging purposes
		// set all nodes to update
		// p->upDateCl = YES;
		clUpdateFlag[p->index] = NO;
		if (p->anc->anc == NULL && treeModel == UNROOTED)
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting basal node %d\n", p->index);
				/* get transition probabilities, currently only for M2 model */
				/* replace this with call to suitable function(s) setting up */
				/* ordered and unordered transition matrices for 2-5 states */
				for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						// calculate transition probabilities for left branch
						probs[1][1] = probs[0][0] = 0.5 + 0.5 * exp(-(p->left->length*theRate));
						probs[0][1] = probs[1][0] = 0.5 - 0.5 * exp(-(p->left->length*theRate));
						for (i=0; i<nStates; i++)
							for (j=0; j<nStates; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						probs[1][1] = probs[0][0] = 0.5 + 0.5 * exp(-(p->right->length*theRate));
						probs[0][1] = probs[1][0] = 0.5 - 0.5 * exp(-(p->right->length*theRate));
						for (i=0; i<nStates; i++)
							for (j=0; j<nStates; j++)
								pR[indexR++] = probs[i][j];

						// calculate transition probabilities for ancestral branch
						probs[1][1] = probs[0][0] = 0.5 + 0.5 * exp(-(p->length*theRate));
						probs[0][1] = probs[1][0] = 0.5 - 0.5 * exp(-(p->length*theRate));
						for (i=0; i<nStates; i++)
							for (j=0; j<nStates; j++)
								pA[indexA++] = probs[i][j];
						
						}
					}

				/* calculate conditional likelihoods */
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					tiPA = pA;
					for (c=0; c<numChars; c++)
						{
						for (i=j=0; i<nStates-1; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (m=0; m<nStates; m++)
								{
								likeL += tiPL[j]*clL[m];
								likeR += tiPR[j]*clR[m];
								likeA += tiPA[j++]*clA[m];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						likeL = likeR = likeA = 0.0;
						for (m=0; m<nStates; m++)
							{
							likeL += tiPL[j]*(*(clL++));
							likeR += tiPR[j]*(*(clR++));
							likeA += tiPA[j++]*(*(clA++));
							}
						*(clP++) = likeL * likeR * likeA;
						}
					}
				else if (!strcmp(ratesModel, "gamma"))
					{
					tiPL = pL;
					tiPR = pR;
					tiPA = pA;
					for (c=0; c<numChars; c++)
						{
						for (k=j=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates-1; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (m=0; m<nStates; m++)
									{
									likeL += tiPL[j]*clL[m];
									likeR += tiPR[j]*clR[m];
									likeA += tiPA[j++]*clA[m];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							likeL = likeR = likeA = 0.0;
							for (m=0; m<nStates; m++)
								{
								likeL += tiPL[j]*(*(clL++));
								likeR += tiPR[j]*(*(clR++));
								likeA += tiPA[j++]*(*(clA++));
								}
							*(clP++) = likeL * likeR * likeA;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*lnumRateCats*nStatesSquared;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						for (k=j=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates-1; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (m=0; m<nStates; m++)
									{
									likeL += tiPL[j]*clL[m];
									likeR += tiPR[j]*clR[m];
									likeA += tiPA[j++]*clA[m];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							likeL = likeR = likeA = 0.0;
							for (m=0; m<nStates; m++)
								{
								likeL += tiPL[j]*(*(clL++));
								likeR += tiPR[j]*(*(clR++));
								likeA += tiPA[j++]*(*(clA++));
								}
							*(clP++) = likeL * likeR * likeA;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*nStatesSquared;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						for (i=j=0; i<nStates-1; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (m=0; m<nStates; m++)
								{
								likeL += tiPL[j]*clL[m];
								likeR += tiPR[j]*clR[m];
								likeA += tiPA[j++]*clA[m];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						likeL = likeR = likeA = 0.0;
						for (m=0; m<nStates; m++)
							{
							likeL += tiPL[j]*(*(clL++));
							likeR += tiPR[j]*(*(clR++));
							likeA += tiPA[j++]*(*(clA++));
							}
						*(clP++) = likeL * likeR * likeA;
						}
					}
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done if p->upDateCl == YES for interior root
			}	// done with interior root
		else
			{
			if (p->upDateCl == YES)
				{
				//printf ("visiting internal node %d\n", p->index);

				/* get transition probabilities */
				/* currently only for M2 model */
				/* replace this with call to function(s) setting up */
				/* the necessary transition probability matrices */
				for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						// calculate transition probabilities for left branch
						probs[1][1] = probs[0][0] = 0.5 + 0.5 * exp(-(p->left->length*theRate));
						probs[0][1] = probs[1][0] = 0.5 - 0.5 * exp(-(p->left->length*theRate));
						for (i=0; i<nStates; i++)
							for (j=0; j<nStates; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						probs[1][1] = probs[0][0] = 0.5 + 0.5 * exp(-(p->right->length*theRate));
						probs[0][1] = probs[1][0] = 0.5 - 0.5 * exp(-(p->right->length*theRate));
						for (i=0; i<nStates; i++)
							for (j=0; j<nStates; j++)
								pR[indexR++] = probs[i][j];

						// calculate transition probabilities for ancestral branch
						probs[1][1] = probs[0][0] = 0.5 + 0.5 * exp(-(p->length*theRate));
						probs[0][1] = probs[1][0] = 0.5 - 0.5 * exp(-(p->length*theRate));
						for (i=0; i<nStates; i++)
							for (j=0; j<nStates; j++)
								pA[indexA++] = probs[i][j];
						}
					}

				/* calculate conditional likelihoods */
				/* first assign pointers to right, left and p */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					for (c=0; c<numChars; c++)
						{
						for (i=j=0; i<nStates-1; i++)
							{
							likeL = likeR = 0.0;
							for (m=0; m<nStates; m++)
								{
								likeL += tiPL[j]*clL[m];
								likeR += tiPR[j++]*clR[m];
								}
							*(clP++) = likeL * likeR;
							}
						likeL = likeR = 0.0;
						for (m=0; m<nStates; m++)
							{
							likeL += tiPL[j]*(*(clL++));
							likeR += tiPR[j++]*(*(clR++));
							}
						*(clP++) = likeL * likeR;
						}
					}
				else if (!strcmp(ratesModel, "gamma"))
					{
					tiPL = pL;
					tiPR = pR;
					for (c=0; c<numChars; c++)
						{
						for (k=j=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates-1; i++)
								{
								likeL = likeR = 0.0;
								for (m=0; m<nStates; m++)
									{
									likeL += tiPL[j]*clL[m];
									likeR += tiPR[j++]*clR[m];
									}
								*(clP++) = likeL * likeR;
								}
							likeL = likeR = 0.0;
							for (m=0; m<nStates; m++)
								{
								likeL += tiPL[j]*(*(clL++));
								likeR += tiPR[j++]*(*(clR++));
								}
							*(clP++) = likeL * likeR;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*lnumRateCats*nStatesSquared;
						tiPL = &pL[index];
						tiPR = &pR[index];
						for (k=j=0; k<lnumRateCats; k++)
							{
							for (i=0; i<nStates-1; i++)
								{
								likeL = likeR = 0.0;
								for (m=0; m<nStates; m++)
									{
									likeL += tiPL[j]*clL[m];
									likeR += tiPR[j++]*clR[m];
									}
								*(clP++) = likeL * likeR;
								}
							likeL = likeR = 0.0;
							for (m=0; m<nStates; m++)
								{
								likeL += tiPL[j]*(*(clL++));
								likeR += tiPR[j++]*(*(clR++));
								}
							*(clP++) = likeL * likeR;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*nStatesSquared;
						tiPL = &pL[index];
						tiPR = &pR[index];
						for (i=j=0; i<nStates-1; i++)
							{
							likeL = likeR = 0.0;
							for (m=0; m<nStates; m++)
								{
								likeL += tiPL[j]*clL[m];
								likeR += tiPR[j++]*clR[m];
								}
							*(clP++) = likeL * likeR;
							}
						likeL = likeR = 0.0;
						for (m=0; m<nStates; m++)
							{
							likeL += tiPL[j]*(*(clL++));
							likeR += tiPR[j++]*(*(clR++));
							}
						*(clP++) = likeL * likeR;
						}
					}
				// done with models
				p->upDateCl = NO;
				clUpdateFlag[p->index] = YES;
				}	// done with interior node if p->upDateCl == YES
			}	// done with interior node

		// deal with scaling
		// first check if we need to refresh scalers
		// and potentially shift scaler nodes
		// we have to remember scalerIndex
		// because the node may move in the tree
		if (refreshScalers == YES)
			{
			if (n % RESCALE_FREQ == 0)
				{
				p->scalerNode = YES;
				p->scalerIndex = n;
				}
			else
				p->scalerNode = NO;
			}

		if (p->scalerNode == YES && clUpdateFlag[p->index] == YES)
			{
			scalerUpdateFlag[p->scalerIndex] = YES;
			scP = &clScaler[scalerOffset + (p->scalerIndex)*numChars];
			clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			i = j = 0;
			for (c=0; c<numChars; c++)
				{
				scaler = 0.0;
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<nStates; m++)
						{
						if (clP[i] > scaler)
							scaler = clP[i];
						i++;
						}
					}
				for (k=0; k<lnumRateCats; k++)
					{
					for (m=0; m<nStates; m++)
						clP[j++] /= scaler;
					}
				lnScaler[c] -= scP[c];	//subtract old value
				scP[c] = log(scaler);
				lnScaler[c] += scP[c]; //add new value
				}
			}
		}// next node

	/* get likelihood at base of tree */
	p = root[whichChain*2+whichState]->left;
	(*lnL) = 0.0;
	clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (i=0; i<nStates; i++)
				like += *(clP++) * stateFreq[i];
			//printf ("%d: %1.25lf %lf %d\n", c, like, log(like), numSitesOfPat[c]);
			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON\n");
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "ssgamma"))
		{
		for (c=0; c<numChars; c++)
			{
			like = 0.0;
			for (k=0; k<lnumRateCats; k++)
				{
				for (m=0; m<nStates; m++)
					like += ((*(clP++)) * stateFreq[m]);
				like *= catFreq[k];
				}

			if (like < LIKE_EPSILON)   /* likelihood for a site can go to zero when        */
				{                      /* two adjacent terminal branches have zero length. */
				printf ("      WARNING: In LIKE_EPSILON (%d) %1.30lf\n", c, like);
				goto error_exit;
				}
			else	
				{
				(*lnL) += (lnScaler[c] + log(like)) * numSitesOfPat[c];
				}
			}
		}

	/* free memory */
	free (pL);
	free (catFreq);
	free (stateFreq);
	free (probs[0]);
	free (probs);

	return (NO_ERROR);
	
	error_exit:
		free (pL);
		free (catFreq);
		free (stateFreq);
		free (probs[0]);
		free (probs);

	return (ERROR);	
}




double lnP1 (double t, double l, double m, double r)

{

	double		p0t;
	
	/*printf ("l = %lf, m = %lf, t = %lf, r = %lf\n", l, m, t, r);*/
	
	p0t = r*(l-m) / (r*l + (l*(1.0-r)-m)*exp((m-l)*t) );
	
	return (log(1.0/r) + 2.0*log(p0t) + (m-l)*t);

}





double lnVt (double t, double l, double m, double r)

{

	double		p0t;
	
	p0t = r*(l-m) / (r*l + (l*(1.0-r)-m)*exp((m-l)*t) );
	
	return (log(1.0 - (1.0/r) * p0t * exp((m-l)*t)));

}





int MarkovChain (int numTaxa, int numChars, int numRateCats, long int *seed)

{

	int				i, n, chain, *curS, *newS, move, acceptMove, chain1, chain2,
					tempInt, *chainTempId, tempId, coldId, nProposed[NUM_PROPOSAL_TYPES], 
					nAccepted[NUM_PROPOSAL_TYPES], nSwapsProposed, nSwapsAccepted,
					nHours, nMins, nSecs;
	double			*lnL, lnR, x, lnLikelihoodRatio, lnPriorRatio, lnProposalRatio, r,
					*constrainedNodes, *calibratedNodes, sum, timePerGen;
	time_t			startingT, endingT, stoppingT1, stoppingT2;
	clock_t			startCPUTime, endCPUTime;

	/* allocate memory for chain */
	lnL = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
	if (!lnL)
		{
		printf ("\n   ERROR: Problem allocating lnL.\n");
		return (ERROR);
		}
	curS = (int *)malloc((size_t) (numChains * sizeof(int)));
	if (!curS)
		{
		printf ("\n   ERROR: Problem allocating curS.\n");
		free (lnL);
		return (ERROR);
		}
	newS = (int *)malloc((size_t) (numChains * sizeof(int)));
	if (!newS)
		{
		printf ("\n   ERROR: Problem allocating newS.\n");
		free (lnL);
		free (curS);
		return (ERROR);
		}
	chainTempId = (int *)malloc((size_t) (numChains * sizeof(int)));
	if (!chainTempId)
		{
		printf ("\n   ERROR: Problem allocating chainTempId.\n");
		free (lnL);
		free (curS);
		free (newS);
		return (ERROR);
		}
	for (i=0; i<numChains; i++)
		chainTempId[i] = i;
	if (enforceCalibrations == YES)
		{
		if (nConstraints > 0)
			{
			constrainedNodes = (double *)malloc((size_t) (nConstraints * sizeof(double)));
			if (!constrainedNodes)
				{
				printf ("\n   ERROR: Problem allocating constrainedNodes.\n");
				free (lnL);
				free (curS);
				free (newS);
				free (chainTempId);
				return (ERROR);
				}
			}
		calibratedNodes = (double *)malloc((size_t) (nCalibrations * sizeof(double)));
		if (!calibratedNodes)
			{
			printf ("\n   ERROR: Problem allocating calibratedNodes.\n");
			free (lnL);
			free (curS);
			free (newS);
			free (chainTempId);
			free (constrainedNodes);
			return (ERROR);
			}
		}
	if (inferAncStates == YES)
		{
		ancStatesProbs = (double *)malloc((size_t) (nConstraints * nChar * nStates * sizeof(double)));
		if (!ancStatesProbs)
			{
			printf ("ERROR: Problem allocating ancStatesProbs\n");
			free (lnL);
			free (curS);
			free (newS);
			free (chainTempId);
			if (enforceCalibrations == YES)
				{
				free (constrainedNodes);
				free (calibratedNodes);
				}
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_ANC_STATES] = YES;
		for (i=0; i<nConstraints*nChar*nStates; i++)
			ancStatesProbs[i] = 0.0;
		tempStateProbs = (double *)malloc((size_t) (nConstraints * nChar * nStates * sizeof(double)));
		if (!tempStateProbs)
			{
			printf ("ERROR: Problem allocating ancStatesProbs\n");
			free (lnL);
			free (curS);
			free (newS);
			free (chainTempId);
			if (enforceCalibrations == YES)
				{
				free (constrainedNodes);
				free (calibratedNodes);
				}
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_TEMP_ANC_STATES] = YES;
		}
			
	/* set information for acceptance rates */
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		nProposed[i] = nAccepted[i] = 0;
	nSwapsProposed = nSwapsAccepted = 0;

#	if defined (TOPOLOGY_MOVE_STATS)
	for (i=0; i<NUM_PROPOSAL_TYPES; i++) 
		{
		nProposedTopology[i] = nAcceptedTopology[i] = 0;
		nProposedNodes[i] = nAcceptedNodes[i] = 0;
		}
#	endif
	/* initialize likelihoods for chain */
	printf ("      Starting likelihoods\n");
	for (chain=0; chain<numChains; chain++)
		{		
#		if defined (SMART_TI_PROBS)
		UpDateAllTIs (0, chain);
		UpDateAllTIs (1, chain);
#		endif
		UpDateAllCls (0, chain);
		if (LnLike (0, chain, numChars, numRateCats, &x, YES) == ERROR)
			goto error_exit;
		lnL[chain*2+0] = x;

		UpDateAllCls (1, chain);
		if (LnLike (1, chain, numChars, numRateCats, &x, YES) == ERROR)
			goto error_exit;
		lnL[chain*2+1] = x;
		printf ("      %2d -- %1.3lf %1.3lf\n", chain+1, lnL[chain*2+0], lnL[chain*2+1]);
		}
		
	/* open output files and write headers */
	if (PrepareOutputFiles() == ERROR)
		goto error_exit;

	/* run chain */
	for (chain=0; chain<numChains; chain++)
		curS[chain] = 0;
	for (chain=0; chain<numChains; chain++)
		newS[chain] = 1;
	
	startingT = time(NULL);
	startCPUTime = clock();
	nSampled = 0;
	for (n=1; n<=nGen; n++)
		{
			
		/* loop through the chains */
		for (chain=0; chain<numChains; chain++)
			{
			/* pick a move type */
			move = ProposeNewState (seed);
			nProposed[move]++;
			
			/* make the move */
			lnPriorRatio = 0.0;
			lnProposalRatio = 0.0;
			if (move == CHANGE_QMAT)
				{
				/* change Q matrix */
				if (Move_ChangeQMatrix (newS[chain], chain, seed, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_GAMMA_SHAPE)
				{
				/* change shape parameter of gamma distribution */
				if (Move_ChangeGammaShape (newS[chain], chain, seed, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_SITE_RATES)
				{
				/* change site rates */
				if (Move_ChangeSiteRates (newS[chain], chain, seed, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_BASEFREQS)
				{
				/* change base frequencies */
				if (Move_ChangeBaseFreqs (newS[chain], chain, seed, &lnPriorRatio, &lnProposalRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_GCSWITCH)
				{
				/* change gc switch parameters */
				if (Move_ChangeGCSwitch (newS[chain], chain, seed, &lnPriorRatio, &lnProposalRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_UNROOT_LOCAL)
				{
				/* change topology of unrooted tree or rooted and unconstrained tree using LOCAL */
				if (Move_ChangeUnrootedWithLocal (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_ERASER)
				{
				/* change topology of rooted tree using eraser */
				if (Move_ChangeEraser (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_UNROOT_TBR)
				{
				/* change topology of unrooted and unconstrained tree using TBR */
				if (Move_ChangeTBR (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_TREE_FTBR)
				{
				/* change topology of unrooted and unconstrained tree using Fredrik Ronquist's TBR */
				if (Move_ChangeFTBR (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_BRLEN)
				{
				/* change topology of unrooted and unconstrained tree using Fredrik Ronquist's TBR */
				if (Move_ChangeBrLen (newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_CLOCK_LOCAL)
				{
				/* change topology of rooted tree with clock constraint using LOCAL */
				if (Move_ChangeClockWithLocal (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_CLOCK_TIME_LOCAL)
				{
				/* change topology and times of rooted tree with clock constraint using LOCAL (divergence time estimation) */
				if (Move_ChangeTimeClockWithLocal (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_TREE_HEIGHT)
				{
				/* change m, the tree height (only implemented with divergence time estimation) */
				if (Move_ChangeTreeHeight (newS[chain], chain, seed, &lnProposalRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_WORM)
				{
				/* change topology using the growing worm mechanism */
				if (Move_SingleWorm (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_TREE_SPR)
				{
				/* change topology using the growing worm mechanism */
				if (Move_ChangeUnrootedWithSPR (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_NODE_TIME)
				{
				/* change topology using the growing worm mechanism */
				if (Move_ChangeNodeTime (numTaxa, newS[chain], chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, NO) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_BD_PARAMS)
				{
				/* change parameters of the birth-death process */
				if (Move_ChangeBD (newS[chain], chain, seed) == ERROR)
					goto error_exit;
				if (LnBDPrior (newS[chain], chain, numTaxa, &x) == ERROR)
					goto error_exit;
				lnPriorRatio = x;
				if (LnBDPrior (curS[chain], chain, numTaxa, &x) == ERROR)
					goto error_exit;
				lnPriorRatio -= x;
				lnLikelihoodRatio = 0.0;
				}
			else if (move == CHANGE_OMEGA)
				{
				/* change omega */
				if (Move_ChangeOmega (newS[chain], chain, seed, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_OMEGA_PROBS)
				{
				/* change base frequencies */
				if (Move_ChangeOmegaProbs (newS[chain], chain, seed, &lnPriorRatio, &lnProposalRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_AUTO_CORR)
				{
				/* change auto correlation across sites */
				if (Move_ChangeAutoCorr (newS[chain], chain, seed, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_LAG)
				{
				/* change lag for auto correlation across sites */
				if (Move_ChangeLag (newS[chain], chain, seed, &lnPriorRatio, &lnProposalRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_INV_P)
				{
				/* change proportion of invariant sites */
				if (Move_ChangePropInv (newS[chain], chain, seed, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
			else if (move == CHANGE_SWITCH_RATE)
				{
				/* change covarion parameter */
				if (Move_ChangeSwitchRate (newS[chain], chain, seed, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
#if defined (MORPH)
			else if (move == CHANGE_BETA_SHAPE)
				{
				/* change beta/dir shape */
				if (Move_ChangeBetaShape (newS[chain], chain, seed, &lnPriorRatio) == ERROR)
					goto error_exit;
				if (LnLike (newS[chain], chain, numChars, numRateCats, &x, YES) == ERROR)
					goto error_exit;
				lnL[chain*2+newS[chain]] = x;
				lnLikelihoodRatio = lnL[chain*2 + newS[chain]] - lnL[chain*2 + curS[chain]];
				}
#endif

			/* heat */
			lnLikelihoodRatio *= (1.0 / (1.0 + chainTemp*(double)chainTempId[chain]));
			lnPriorRatio      *= (1.0 / (1.0 + chainTemp*(double)chainTempId[chain]));

			/* calculate the acceptance probability */
			if (lnLikelihoodRatio + lnPriorRatio + lnProposalRatio < -100.0)
				r = 0.0;
			else if (lnLikelihoodRatio + lnPriorRatio + lnProposalRatio > 0.0)
				r = 1.0;
			else
				r = exp(lnLikelihoodRatio + lnPriorRatio + lnProposalRatio);
			
			/* decide to accept or reject the move */
			acceptMove = NO;
			if (RandomNumber(seed) < r)
				acceptMove = YES;

#			if defined (TOPOLOGY_MOVE_STATS)
			/* record diagnostics for topology moves */
			switch (move) 
				{
				case CHANGE_UNROOT_LOCAL:
				case CHANGE_CLOCK_LOCAL:
				case CHANGE_CLOCK_TIME_LOCAL:
				case CHANGE_TREE_SPR:
				case CHANGE_WORM:
				case CHANGE_UNROOT_TBR:
				case CHANGE_TREE_FTBR:
				case CHANGE_ERASER:
					if (gTopologyHasChanged == YES) 
						{
						nProposedNodes[move] += gNodeMoves;
						nProposedTopology[move]++;
						if (acceptMove == YES) 
							{
							nAcceptedNodes[move] += gNodeMoves;
							nAcceptedTopology[move]++;
							}
						}
				}
#			endif
			/* update the chain */
			if (acceptMove == YES)
				{
				curS[chain] = newS[chain];
				if (curS[chain] == 1)
					newS[chain] = 0;
				else
					newS[chain] = 1;
				nAccepted[move]++;
				}
			lnL[chain*2 + newS[chain]] = lnL[chain*2 + curS[chain]];
			CopyTree (curS[chain], newS[chain], chain);
			CopyConditionalLikelihoods (curS[chain], newS[chain], chain, numTaxa, numChars, numRateCats);
			}
			
		/* attemp to swap states for two chains */
		if (numChains > 1)
			{    
			nSwapsProposed++;
			
			chain1 = RandomNumber(seed) * numChains;
			do
				{
				chain2 = RandomNumber(seed) * numChains;
				} while (chain1 == chain2);
			
			lnR  = (1.0 / (1.0 + chainTemp*(double)chainTempId[chain1])) * lnL[chain2*2 + curS[chain2]];
			lnR += (1.0 / (1.0 + chainTemp*(double)chainTempId[chain2])) * lnL[chain1*2 + curS[chain1]];
			lnR -= (1.0 / (1.0 + chainTemp*(double)chainTempId[chain1])) * lnL[chain1*2 + curS[chain1]];
			lnR -= (1.0 / (1.0 + chainTemp*(double)chainTempId[chain2])) * lnL[chain2*2 + curS[chain2]];

			if (lnR < -100.0)
				r = 0.0;
			else if (lnR > 0.0)
				r = 1.0;
			else
				r = exp(lnR);
			
			acceptMove = NO;
			if (RandomNumber(seed) < r)
				{
				acceptMove = YES;
				}
				
			if (acceptMove == YES)
				{
			 	nSwapsAccepted++;
				tempId = chainTempId[chain1];
				chainTempId[chain1] = chainTempId[chain2];
				chainTempId[chain2] = tempId;
				}
			
			/* print update to screen */
			endingT = time(NULL);
			if (n % printFreq == 0)
				{
				timePerGen = (double)(difftime (endingT, startingT) / n);
				nSecs = (int)((nGen - n) * timePerGen);
				nHours = (int)nSecs / 3600;
				nSecs -= nHours * 3600;
				nMins = nSecs / 60; 
				nSecs -= nMins * 60;
				printf ("      %4d -- ", n);
				sum = 0.0;
				for (chain=0; chain<numChains; chain++)
					sum += lnL[chain*2 + curS[chain]] * (1.0 / (1.0 + chainTemp*(double)chainTempId[chain]));
				printf ("%1.2lf -- ", sum);
				for (chain=0; chain<numChains; chain++)
					{
					if (chainTempId[chain] == 0)
						printf ("[%1.2lf] ", lnL[chain*2 + curS[chain]]);
					else
						printf ("(%1.2lf) ", lnL[chain*2 + curS[chain]]);
					}
				printf ("-- %d:", nHours);
				if (nMins > 9)
					printf ("%d:", nMins);
				else
					printf ("0%d:", nMins);
				if (nSecs > 9)
					printf ("%d", nSecs);
				else
					printf ("0%d", nSecs);
				if (acceptMove == YES)
					printf (" (%d~%d)\n", chain1+1, chain2+1);
				else
					printf ("\n");
				}
			}
		else
			{
			endingT = time(NULL);
			/* print update to screen */
			if (n % printFreq == 0)
				{
				timePerGen = (double)(difftime (endingT, startingT) / n);
				nSecs = (int)((nGen - n) * timePerGen);
				nHours = (int)nSecs / 3600;
				nSecs -= nHours * 3600;
				nMins = nSecs / 60; 
				nSecs -= nMins * 60;
				printf ("      %4d -- %1.2lf ", n, lnL[curS[0]]);
				printf ("-- %d:", nHours);
				if (nMins > 9)
					printf ("%d:", nMins);
				else
					printf ("0%d:", nMins);
				if (nSecs > 9)
					printf ("%d\n", nSecs);
				else
					printf ("0%d\n", nSecs);
				}
			}
		
		/* check to see if we should continue chain */
		if (n == nGen && autoclose == NO)
			{
			stoppingT1 = time(NULL);
			printf ("\n      Continue with chain? (yes/no): ");
			if (YesNo() == YES)
				{
				tempInt = 0;
				do
					{
					if (tempInt < 0)
						printf ("      Number must be greater than or equal to 0: ");
					else
						printf ("      Additional number of generations: ");
					tempInt = (int)EnterNum ();
					} while (tempInt < 0);
				nGen += tempInt;
				}
			printf ("\n");
			stoppingT2 = time(NULL);
			startingT -= (stoppingT2 - stoppingT1);
			}

		/* print states to file */
		if (n % sampleFreq == 0 || n == 1 || n == nGen)
			{
			for (i=0; i<numChains; i++)
				{
				if (chainTempId[i] == 0)
					{
					coldId = i;
					break;
					}
				}
			chain = 0;
			if (PrintStatesToFile (n, coldId, curS[coldId], lnL[coldId*2 + curS[coldId]], constrainedNodes, calibratedNodes) == ERROR)
				{
				printf ("   ERROR: Problem printing states to file\n");
				goto error_exit;
				}
			if (n >= mcmcBurn)
				nSampled++;
			if (inferAncStates == YES && n >= mcmcBurn)
				{
				if ((dataType == DNA || dataType == RNA) && enforceCodonModel == NO)
					{
					if (PrintAncStatesDNA (curS[coldId], coldId, numChars, numRateCats, n) == ERROR)
						goto error_exit;
					UpDateAllCls (0, coldId);
					if (LnLikeDNA (0, coldId, numChars, numRateCats, &x, YES) == ERROR)
						goto error_exit;
					UpDateAllCls (1, coldId);
					if (LnLikeDNA (1, coldId, numChars, numRateCats, &x, YES) == ERROR)
						goto error_exit;
					}
				else if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
					{
					printf ("\n   ERROR: Cannot calculate ancestral states for codon models (yet)\n");
					goto error_exit;
					}
				else if (dataType == PROTEIN)
					{
					PrintAncStatesAA (curS[coldId], coldId, numChars, numRateCats, n);
					UpDateAllCls (0, coldId);
					if (LnLikeAA (0, coldId, numChars, numRateCats, &x, YES) == ERROR)
						goto error_exit;
					UpDateAllCls (1, coldId);
					if (LnLikeAA (1, coldId, numChars, numRateCats, &x, YES) == ERROR)
						goto error_exit;
					}
				}
			if (inferPoseSel == YES && n >= mcmcBurn)
				{
				if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES && (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98")))
					{
					PrintPosSelProbs (curS[coldId], coldId, numChars, numRateCats, n);
					}
				}
				
			if (inferRates == YES && nExcluded == 0 && n >= mcmcBurn)
				{
				if (((dataType == DNA || dataType == RNA) && enforceCodonModel == NO) || dataType == PROTEIN)
					{
					PrintRateFactors (curS[coldId], coldId, numChars, numRateCats, n);
					}
				}
			else if (inferRates == YES && nExcluded > 0 && n == 1 && n >= mcmcBurn)
				{
				printf ("      Warning: You requested that site rates be estimated. However, this option\n");
				printf ("               does not currently work when sites are excluded. Site rates will not\n");
				printf ("               be estimated in this run.\n");
				}
			}
			

		}
	endingT = time(NULL);
	endCPUTime = clock();
	
	printf ("      Chain completed in %1.0f seconds\n", difftime (endingT, startingT));
	printf ("      Chain used %1.2f seconds of CPU time\n", (endCPUTime - startCPUTime)/(float)CLOCKS_PER_SEC);

	printf ("      Acceptance rates for proposal mechanisms\n");
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		{
		if (nProposed[i] > 0)
			printf ("         %1.2lf percent of the time accepted %s\n", ((double)nAccepted[i]/nProposed[i])*100.0, proposalName[i]);
		}
	if (nSwapsProposed > 0)
		{
		printf ("         %1.2lf percent of the time accepted a swap of the states for two chains\n", ((double)nSwapsAccepted/nSwapsProposed)*100.0);
		}
		
#	if defined (TOPOLOGY_MOVE_STATS)
	printf ("      Detailed statistics for moves that change tree topology\n");
	for (i = 0; i<NUM_PROPOSAL_TYPES; i++) 
		{
		if (nProposed[i] == 0)
			continue;
		switch(i) 
			{
			case CHANGE_UNROOT_LOCAL:
			case CHANGE_CLOCK_LOCAL:
			case CHANGE_CLOCK_TIME_LOCAL:
			case CHANGE_ERASER:
				printf ("         %s\n", proposalName[i]);
				printf ("            %d moves were proposed\n", nProposed[i]);
				printf ("            %d moves were accepted\n",nAccepted[i]);
				printf ("            %d topology changes were proposed\n",nProposedTopology[i]);
				printf ("            %d topology changes were accepted\n",nAcceptedTopology[i]);
				if (nProposedTopology[i] > 0)
					printf ("            %1.2f percent of proposed topology changes were accepted\n", 
						(float)nAcceptedTopology[i]/(float)nProposedTopology[i] * 100.0);
				printf ("            Proposed topology changes by definition break 1 partition\n");
				break;

			case CHANGE_TREE_SPR:
			case CHANGE_WORM:
			case CHANGE_UNROOT_TBR:
			case CHANGE_TREE_FTBR:
				printf ("         %s\n", proposalName[i]);
				printf ("            %d moves were proposed\n", nProposed[i]);
				printf ("            %d moves were accepted\n",nAccepted[i]);
				printf ("            %d topology changes were proposed\n",nProposedTopology[i]);
				printf ("            %d topology changes were accepted\n",nAcceptedTopology[i]);
				if (nProposedTopology[i] > 0) {
					printf ("            %1.2f percent of proposed topology changes were accepted\n", 
						(float)nAcceptedTopology[i]/(float)nProposedTopology[i] * 100.0);
					printf ("            Proposed topology changes on average broke %f partitions\n",
						(float)nProposedNodes[i] / (float)nProposedTopology[i]);
					if (nAcceptedTopology[i] > 0) {
						printf ("            Accepted topology changes on average broke %f partitions\n",
						nAcceptedNodes[i] / (float)nAcceptedTopology[i]);
					}
				}
			}
		}
#	endif

#	if defined (MORPH)
	if (numDummyChars > 0)
		{
		printf ("      Probability of unobserved characters in ending state of chain");
		LnLike (curS[coldId], coldId, numChars, numRateCats, &x, YES);
		printf (": %1.8f\n",1.0 - pObserved);
		}
#	endif

	/* free memory and leave */
	free (lnL);
	free (curS);
	free (newS);
	free (chainTempId);
	if (enforceCalibrations == YES)
		{
		free (constrainedNodes);
		free (calibratedNodes);
		}
	/* close output files */
	fclose (pFile);
	fclose (bpFile);
	fclose (tFile);

	return (NO_ERROR);

	error_exit:
		free (lnL);
		free (curS);
		free (newS);
		free (chainTempId);
		if (enforceCalibrations == YES)
			{
			free (constrainedNodes);
			free (calibratedNodes);
			}
		/* close output files */
		if (pFile != NULL)
			fclose (pFile);
		if (bpFile != NULL)
			fclose (bpFile);
		if (tFile != NULL)
			fclose (tFile);
		printf ("\n   ERROR: Problem running Markov chain\n");
		return (ERROR);
	
}





int MarkovChainPars (int numTaxa, int numChars, long int *seed)

{

	int				i, n, chain, *curS, *newS, acceptMove, chain1, chain2,
					tempInt, *chainTempId, tempId, coldId, 
					nHours, nMins, nSecs;
	double			*lnL, lnR, lnLikelihoodRatio, lnPriorRatio, lnProposalRatio, r,
					sum, timePerGen, nk, lnK;
	time_t			startingT, endingT, stoppingT1, stoppingT2;
	clock_t			startCPUTime, endCPUTime;
	FILE			*fp1, *fp2;

	/* get number of characters */
	nk = 0.0;
	for (i=0; i<numChars; i++)
		nk += numSitesOfPat[i];
		
	/* calculate log of number of states */
	lnK = log((double)nStates);
		
	/* print information to the screen about run */
	if (dataType == DNA)
		printf ("      Data type = DNA\n");
	else if (dataType == RNA)
		printf ("      Data type = RNA\n");
	else if (dataType == PROTEIN)
		printf ("      Data type = protein\n");
	else if (dataType == RESTRICTION)
		printf ("      Data type = restriction site\n");
	else if (dataType == STANDARD)
		printf ("      Data type = standard\n");
	printf ("      Substitution model\n");
	printf ("         You have selected the \"Parsimony model\" of\n");
	printf ("         Tuffley and Steel (1997). This model is also\n");
	printf ("         known as the \"no common mechanism\" model as\n");
	printf ("         it allows each branch and site to have a separ-\n");
	printf ("         ate transition matrix. You should note that this\n");
	printf ("         is an over-parameterized model; the number of\n");
	printf ("         parameters grows faster than the number of obs-\n");
	printf ("         ervations. You use this model at your own risk.\n");
	printf ("         (You should also note that this model is anything\n");
	printf ("         but parsimonious.)\n");

	/* allocate memory for chain */
	lnL = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
	if (!lnL)
		{
		printf ("\n   ERROR: Problem allocating lnL.\n");
		return (ERROR);
		}
	curS = (int *)malloc((size_t) (numChains * sizeof(int)));
	if (!curS)
		{
		printf ("\n   ERROR: Problem allocating curS.\n");
		free (lnL);
		return (ERROR);
		}
	newS = (int *)malloc((size_t) (numChains * sizeof(int)));
	if (!newS)
		{
		printf ("\n   ERROR: Problem allocating newS.\n");
		free (lnL);
		free (curS);
		return (ERROR);
		}
	chainTempId = (int *)malloc((size_t) (numChains * sizeof(int)));
	if (!chainTempId)
		{
		printf ("\n   ERROR: Problem allocating chainTempId.\n");
		free (lnL);
		free (curS);
		free (newS);
		return (ERROR);
		}
	for (i=0; i<numChains; i++)
		chainTempId[i] = i;
			
	/* initialize likelihoods for chain */
	//printf ("      Starting likelihoods\n");
	for (chain=0; chain<numChains; chain++)
		{		
		lnL[chain*2+0] = ParsimonyLength (0, chain, numChars);
		lnL[chain*2+1] = ParsimonyLength (1, chain, numChars);
		//printf ("%4d: %lf %lf\n", chain+1, lnL[chain*2+0], lnL[chain*2+1]);
		}
		
	/* run chain */
	for (chain=0; chain<numChains; chain++)
		curS[chain] = 0;
	for (chain=0; chain<numChains; chain++)
		newS[chain] = 1;
	
	/* open output files and write headers */
	if (PrepareParsOutputFiles() == ERROR)
		goto error_exit;

	startingT = time(NULL);
	startCPUTime = clock();
	for (n=1; n<=nGen; n++)
		{
			
		/* loop through the chains */
		for (chain=0; chain<numChains; chain++)
			{
			/* make the move */
			lnLikelihoodRatio = 0.0;
			lnPriorRatio = 0.0;
			lnProposalRatio = 0.0;
			if (Move_ChangeNNI (numTaxa, newS[chain], chain, seed) == ERROR)
				goto error_exit;
			lnL[chain*2+newS[chain]] = ParsimonyLength (newS[chain], chain, numChars);
			lnLikelihoodRatio = -(lnL[chain*2 + newS[chain]] + nk) * lnK + (lnL[chain*2 + curS[chain]] + nk) * lnK;
			//printf ("   %lf -> %lf\n", lnL[chain*2+curS[chain]], lnL[chain*2+newS[chain]]);

			/* heat */
			lnLikelihoodRatio *= (1.0 / (1.0 + chainTemp*(double)chainTempId[chain]));
			lnPriorRatio      *= (1.0 / (1.0 + chainTemp*(double)chainTempId[chain]));

			/* calculate the acceptance probability */
			if (lnLikelihoodRatio + lnPriorRatio + lnProposalRatio < -100.0)
				r = 0.0;
			else if (lnLikelihoodRatio + lnPriorRatio + lnProposalRatio > 0.0)
				r = 1.0;
			else
				r = exp(lnLikelihoodRatio + lnPriorRatio + lnProposalRatio);
			
			/* decide to accept or reject the move */
			acceptMove = NO;
			if (RandomNumber(seed) < r)
				acceptMove = YES;

			/* update the chain */
			if (acceptMove == YES)
				{
				curS[chain] = newS[chain];
				if (curS[chain] == 1)
					newS[chain] = 0;
				else
					newS[chain] = 1;
				}
			lnL[chain*2 + newS[chain]] = lnL[chain*2 + curS[chain]];
			CopyTree (curS[chain], newS[chain], chain);
			}
			
		/* attemp to swap states for two chains */
		if (numChains > 1)
			{    			
			chain1 = RandomNumber(seed) * numChains;
			do
				{
				chain2 = RandomNumber(seed) * numChains;
				} while (chain1 == chain2);
			
			lnR  = (1.0 / (1.0 + chainTemp*(double)chainTempId[chain1])) * (-(lnL[chain2*2 + curS[chain2]] + nk) * lnK);
			lnR += (1.0 / (1.0 + chainTemp*(double)chainTempId[chain2])) * (-(lnL[chain1*2 + curS[chain1]] + nk) * lnK);
			lnR -= (1.0 / (1.0 + chainTemp*(double)chainTempId[chain1])) * (-(lnL[chain1*2 + curS[chain1]] + nk) * lnK);
			lnR -= (1.0 / (1.0 + chainTemp*(double)chainTempId[chain2])) * (-(lnL[chain2*2 + curS[chain2]] + nk) * lnK);

			if (lnR < -100.0)
				r = 0.0;
			else if (lnR > 0.0)
				r = 1.0;
			else
				r = exp(lnR);
			
			acceptMove = NO;
			if (RandomNumber(seed) < r)
				{
				acceptMove = YES;
				}
				
			if (acceptMove == YES)
				{
				tempId = chainTempId[chain1];
				chainTempId[chain1] = chainTempId[chain2];
				chainTempId[chain2] = tempId;
				}
			
			/* print update to screen */
			endingT = time(NULL);
			if (n % printFreq == 0)
				{
				timePerGen = (double)(difftime (endingT, startingT) / n);
				nSecs = (int)((nGen - n) * timePerGen);
				nHours = (int)nSecs / 3600;
				nSecs -= nHours * 3600;
				nMins = nSecs / 60; 
				nSecs -= nMins * 60;
				printf ("      %4d -- ", n);
				sum = 0.0;
				for (chain=0; chain<numChains; chain++)
					sum += (-(lnL[chain*2 + curS[chain]] + nk) * lnK) * (1.0 / (1.0 + chainTemp*(double)chainTempId[chain]));
				printf ("%1.2lf -- ", sum);
				for (chain=0; chain<numChains; chain++)
					{
					if (chainTempId[chain] == 0)
						printf ("[%1.2lf] ", (-(lnL[chain*2 + curS[chain]] + nk) * lnK));
					else
						printf ("(%1.2lf) ", (-(lnL[chain*2 + curS[chain]] + nk) * lnK));
					}
				printf ("-- %d:", nHours);
				if (nMins > 9)
					printf ("%d:", nMins);
				else
					printf ("0%d:", nMins);
				if (nSecs > 9)
					printf ("%d", nSecs);
				else
					printf ("0%d", nSecs);
				if (acceptMove == YES)
					printf (" (%d~%d)\n", chain1+1, chain2+1);
				else
					printf ("\n");
				}
			}
		else
			{
			endingT = time(NULL);
			/* print update to screen */
			if (n % printFreq == 0)
				{
				timePerGen = (double)(difftime (endingT, startingT) / n);
				nSecs = (int)((nGen - n) * timePerGen);
				nHours = (int)nSecs / 3600;
				nSecs -= nHours * 3600;
				nMins = nSecs / 60; 
				nSecs -= nMins * 60;
				printf ("      %4d -- %1.2lf ", n, lnL[curS[0]]);
				printf ("-- %d:", nHours);
				if (nMins > 9)
					printf ("%d:", nMins);
				else
					printf ("0%d:", nMins);
				if (nSecs > 9)
					printf ("%d\n", nSecs);
				else
					printf ("0%d\n", nSecs);
				}
			}
		
		/* check to see if we should continue chain */
		if (n == nGen && autoclose == NO)
			{
			stoppingT1 = time(NULL);
			printf ("\n      Continue with chain? (yes/no): ");
			if (YesNo() == YES)
				{
				tempInt = 0;
				do
					{
					if (tempInt < 0)
						printf ("      Number must be greater than or equal to 0: ");
					else
						printf ("      Additional number of generations: ");
					tempInt = (int)EnterNum ();
					} while (tempInt < 0);
				nGen += tempInt;
				}
			printf ("\n");
			stoppingT2 = time(NULL);
			startingT -= (stoppingT2 - stoppingT1);
			}

		/* print states to file */
		if (n % sampleFreq == 0 || n == 1 || n == nGen)
			{
			for (i=0; i<numChains; i++)
				{
				if (chainTempId[i] == 0)
					{
					coldId = i;
					
					fp1 = pFile;
					fp2 = bpFile;

					fprintf (fp1, "%d\t%lf\t", n, -(lnL[coldId*2 + curS[coldId]] + nk) * lnK  );
					fprintf (fp2, "   data %d, %1.2lf", n, -(lnL[coldId*2 + curS[coldId]] + nk) * lnK);
					fprintf (fp1, "%lf\t", lnL[coldId*2 + curS[coldId]]);		
					fprintf (fp2, ", %lf", lnL[coldId*2 + curS[coldId]]);	
					
					fprintf (fp1, "\n");
					fprintf (fp2, ";\n");
					if (n == nGen)
						fprintf (fp2, "end;\n");
					fflush (fp1);
					fflush (fp2);
					
					fp2 = tFile;

					fprintf (fp2, "   tree rep.%d = ", n);
					WriteTreeToFile (root[coldId*2 + curS[coldId]]->left, fp2, saveBrlens);
					if (n == nGen)
						fprintf (fp2, "end;\n");
					fflush (fp2);
					
					break;
					}
				}

			}
			

		}
	endingT = time(NULL);
	endCPUTime = clock();
	
	printf ("      Chain completed in %1.0f seconds\n", difftime (endingT, startingT));
	printf ("      Chain used %1.2f seconds of CPU time\n", (endCPUTime - startCPUTime)/(float)CLOCKS_PER_SEC);


	/* free memory and leave */
	free (lnL);
	free (curS);
	free (newS);
	free (chainTempId);
	
	/* close output files */
	fclose (pFile);
	fclose (bpFile);
	fclose (tFile);

	return (NO_ERROR);

	error_exit:
		free (lnL);
		free (curS);
		free (newS);
		free (chainTempId);

		/* close output files */
		if (pFile != NULL)
			fclose (pFile);
		if (bpFile != NULL)
			fclose (bpFile);
		if (tFile != NULL)
			fclose (tFile);
		printf ("\n   ERROR: Problem running Markov chain\n");
		return (ERROR);
	
}





void MarkPathDown (TreeNode *p, TreeNode *q)

{
	
	if (p != NULL)
		{
		MarkPathDown (p->left,  q);
		MarkPathDown (p->right, q);
		p->flag = NO;
		if (p == q)
			{
			p->flag = YES;
			}
		if (p->left != NULL && p->right != NULL)
			{
			if (p->left->flag == YES || p->right->flag == YES)
				p->flag = YES;
			}
		else if (p->left != NULL && p->right == NULL)
			{
			if (p->left->flag == YES)
				p->flag = YES;
			}
		/*printf ("node %d %d\n", p->index, p->flag);*/
		}
		
}





/* change auto correlation parameter */
int Move_ChangeAutoCorr (int proposedState, int whichChain, long int *seed, double *lnPriorRatio)

{

	int			whichToChange;
	double		oldP, newP, ran, pSlide, minP, maxP;

	minP = chainMins[CHANGE_AUTO_CORR];
	maxP = chainMaxs[CHANGE_AUTO_CORR];
	pSlide = rhoWinProp;

	if (allocatedMemory[ALLOC_AUTO_GAMMA2] == NO)
		{
		oldP = rateCorrelation[whichChain*2 + proposedState];
		ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
		newP = oldP + ran;
		if (newP < minP)
			newP = (minP - newP) + minP;
		if (newP > maxP)
			newP = maxP - (newP - maxP);
		rateCorrelation[whichChain*2 + proposedState] = newP;
		}
	else
		{
		whichToChange = RandomNumber(seed) * 3;
		if (whichToChange == 0)
			{
			oldP = rateCorrelation[whichChain*2 + proposedState];
			ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
			newP = oldP + ran;
			if (newP < minP)
				newP = (minP - newP) + minP;
			if (newP > maxP)
				newP = maxP - (newP - maxP);
			rateCorrelation[whichChain*2 + proposedState] = newP;
			}
		else
			{
			oldP = rateCorrelation2[whichChain*4 + proposedState*2 + (whichToChange-1)];
			ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
			newP = oldP + ran;
			if (newP < minP)
				newP = (minP - newP) + minP;
			if (newP > maxP)
				newP = maxP - (newP - maxP);
			rateCorrelation2[whichChain*4 + proposedState*2 + (whichToChange-1)] = newP;
			}
		}
		
	/* set prior ratio */
	(*lnPriorRatio) = 0.0;
		
	UpDateAllCls (proposedState, whichChain);

#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change pi */
int Move_ChangeBaseFreqs (int proposedState, int whichChain, long int *seed, double *lnPriorRatio, double *lnProposalRatio)

{

	int			i;
	double		*dirichletParameters, *newPi, *oldPi, sum, alphaPi, priorPi, x, y, oneOverS;
	
	oneOverS = 1.0 / nStates;

	dirichletParameters = (double *)malloc((size_t) (nStates * sizeof(double)));
	if (!dirichletParameters)
		goto error_exit;
	newPi = (double *)malloc((size_t) (nStates * sizeof(double)));
	if (!newPi)
		goto error_exit;
	oldPi = (double *)malloc((size_t) (nStates * sizeof(double)));
	if (!oldPi)
		goto error_exit;

	alphaPi = piAlphaProp;
	priorPi = basefreqprDir;

	for (i=0; i<nStates; i++)
		{
		oldPi[i] = baseFreq[whichChain*2*nStates + proposedState*nStates + i];
		dirichletParameters[i] = oldPi[i] * alphaPi;
		}
	DirichletRandomVariable (dirichletParameters, newPi, nStates, seed);

	sum = 0.0;
	for (i=0; i<nStates; i++)
		{
		if (newPi[i] < 0.0001)
			newPi[i] = 0.0001;
		sum += newPi[i];
		}
	for (i=0; i<nStates; i++)
		newPi[i] = newPi[i] / sum;

	for (i=0; i<nStates; i++)
		baseFreq[whichChain*2*nStates + proposedState*nStates + i] = newPi[i];

	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<nStates; i++)
		sum += newPi[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<nStates; i++)
		x -= LnGamma(newPi[i]*alphaPi);
	for (i=0; i<nStates; i++)
		x += (newPi[i]*alphaPi-1.0)*log(oldPi[i]);
	sum = 0.0;
	for (i=0; i<nStates; i++)
		sum += oldPi[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<nStates; i++)
		y -= LnGamma(oldPi[i]*alphaPi);
	for (i=0; i<nStates; i++)
		y += (oldPi[i]*alphaPi-1.0)*log(newPi[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	x = LnGamma(priorPi);
	for (i=0; i<nStates; i++)
		x -= LnGamma(oneOverS*priorPi);
	for (i=0; i<nStates; i++)
		x += (oneOverS*priorPi-1.0)*log(newPi[i]);
	y = LnGamma(priorPi);
	for (i=0; i<nStates; i++)
		y -= LnGamma(oneOverS*priorPi);
	for (i=0; i<nStates; i++)
		y += (oneOverS*priorPi-1.0)*log(oldPi[i]);
	(*lnPriorRatio) = x - y;
	
	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	free (dirichletParameters);
	free (newPi);
	free (oldPi);

	return (NO_ERROR);
	
	error_exit:
		free (dirichletParameters);
		free (newPi);
		free (oldPi);
		return (ERROR);
	
}


#if defined (MORPH)
/* change Beta/Dirichlet parameters for standard data */
int Move_ChangeBetaShape (int proposedState, int whichChain, long int *seed, double *lnPriorRatio)

{

	double		oldP, newP, ran, pSlide, minP, maxP;

	// it should be possible for the user to set the following parameters
	minP = chainMins[CHANGE_BETA_SHAPE];
	maxP = chainMaxs[CHANGE_BETA_SHAPE];
	pSlide = 10.0;
	
	// find new value
	oldP = statefreqP[whichChain*2 + proposedState];
	ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
	newP = oldP + ran;

	// reflect in if new value passed given boundaries
	if (newP < minP)
		newP = (minP - newP) + minP;
	if (newP > maxP)
		newP = maxP - (newP - maxP);

	// set new value
	statefreqP[whichChain*2 + proposedState] = newP;

	/* set prior ratio */
	// this is only for uniform prior, exponential prior also reasonable?
	(*lnPriorRatio) = 0.0;

	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	// SMART_TI_PROBS not implemented for binary and restriction data?
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}
#endif



/* change branch lengths and topology (potentially) using eraser */
#undef	MULTIPLE_BR_HIT
int Move_ChangeEraser (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int			i, j, topologyHasChanged;
	double		ran, tuning,
#	if !defined (MULTIPLE_BR_HIT)
				rndUM[5], oldM, newM, 
#	endif
				lnOldBrlenPr,lnNewBrlenPr;
	TreeNode	*p, *a, *b, *c, *d, *u, *v;

	tuning = tuningProp;
	topologyHasChanged = NO;

#	if defined (DEBUG_ERASER)
	printf ("Before:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif
	
	/* set all updates to "NO" */		
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		p->upDateCl = NO;
		}
		
	/* initialize proposal ratio to 0.0 */
	(*lnProposalRatio) = 0.0;
	lnNewBrlenPr = lnOldBrlenPr = 0.0;

	/* pick an internal branch */
	do
		{
		p = intNodeDownPassSeq[whichChain*2*numIntNodes + proposedState*numIntNodes + (int)(RandomNumber(seed)*numIntNodes)];
		} while (p->anc->anc == NULL);

	if (!strcmp(clockModel, "unconstrained") && treeModel == UNROOTED)
		{
		/* if tree is unrooted and the branch lengths are unconstrained */
		u = p;
		v = p->anc;
		a = p->left;
		b = p->right;
		c = v->anc;
		if (v->left == u)
			d = v->right;
		else
			d = v->left;
#		if !defined (MULTIPLE_BR_HIT)
		oldM = a->length + b->length + u->length + d->length + v->length;
		newM = oldM * exp(tuning *(RandomNumber(seed) - 0.5));
#		endif
		if (!strcmp(brlenprModel, "exponential"))
			{
			lnOldBrlenPr  = log(brlenprExp) - brlenprExp * (a->length);
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (b->length);
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (u->length);
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (d->length);
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (v->length);
			}
#		if defined (MULTIPLE_BR_HIT)
		(*lnProposalRatio) -= (a->length + b->length + u->length + d->length + v->length);
		a->length *= exp(tuning * (RandomNumber(seed) - 0.5));
		b->length *= exp(tuning * (RandomNumber(seed) - 0.5));
		u->length *= exp(tuning * (RandomNumber(seed) - 0.5));
		d->length *= exp(tuning * (RandomNumber(seed) - 0.5));
		v->length *= exp(tuning * (RandomNumber(seed) - 0.5));
		(*lnProposalRatio) += (a->length + b->length + u->length + d->length + v->length);
#		else
		for (i=0; i<4; i++)
			rndUM[i] = RandomNumber(seed) * newM;
		SortVector (rndUM, 4);
		a->length = rndUM[0];
		b->length = rndUM[1] - rndUM[0];
		u->length = rndUM[2] - rndUM[1];
		d->length = rndUM[3] - rndUM[2];
		v->length = newM - rndUM[3];
#		endif
		if (u->isConstrained == YES || v->isConstrained == YES)
			ran = 1.0;
		else
			ran = RandomNumber(seed);
		if (ran < 0.333)
			{
			u->left = a;
			u->right = d;
			a->anc = d->anc = u;
			v->left = u;
			v->right = b;
			u->anc = b->anc = v;
			topologyHasChanged = YES;
			}
		else if (ran >= 0.333 && ran < 0.666)
			{
			u->left = b;
			u->right = d;
			b->anc = d->anc = u;
			v->left = u;
			v->right = a;
			u->anc = a->anc = v;
			topologyHasChanged = YES;
			}
		if (!strcmp(brlenprModel, "exponential"))
			{
			lnNewBrlenPr  = log(brlenprExp) - brlenprExp * (a->length);
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (b->length);
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (u->length);
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (d->length);
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (v->length);
			}
#		if !defined (MULTIPLE_BR_HIT)
		(*lnProposalRatio) = 5.0 * (log(newM) - log(oldM));
#		endif
		a->upDateCl = YES;
		b->upDateCl = YES;
		u->upDateCl = YES;
		d->upDateCl = YES;
		v->upDateCl = YES;
		c->upDateCl = YES;
		p = c;
		while (p->anc != NULL)
			{
			p = p->anc;
			p->upDateCl = YES;
			}
#		if defined (SMART_TI_PROBS)
		a->upDateTi = YES;
		b->upDateTi = YES;
		u->upDateTi = YES;
		d->upDateTi = YES;
		v->upDateTi = YES;
#		endif	
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		i = j = 0;
		GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);
		}

#	if defined (DEBUG_ERASER)
	printf ("After:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif
		
	(*lnPriorRatio) = lnNewBrlenPr - lnOldBrlenPr;

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
	gNodeMoves = 1;
#	endif
	
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	

	return (NO_ERROR);

}





/* change gc switch params */
int Move_ChangeGCSwitch (int proposedState, int whichChain, long int *seed, double *lnPriorRatio, double *lnProposalRatio)

{

	double		ran, ran1, maxP, minP, newP, oldP, pSlide;
	
	ran1 = RandomNumber(seed);
	
	if (ran1 < 0.25)
		{
		minP = 0.0;
		maxP = 0.5;
		pSlide = 0.1;
		oldP = gc1[whichChain*2 + proposedState];
		ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
		newP = oldP + ran;
		if (newP < minP)
			newP = (minP - newP) + minP;
		if (newP > maxP)
			newP = maxP - (newP - maxP);
		gc1[whichChain*2 + proposedState] = newP;
		}
	else if (ran1 >= 0.25 && ran1 < 0.50)
		{
		minP = 0.5;
		maxP = 1.0;
		pSlide = 0.1;
		oldP = gc2[whichChain*2 + proposedState];
		ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
		newP = oldP + ran;
		if (newP < minP)
			newP = (minP - newP) + minP;
		if (newP > maxP)
			newP = maxP - (newP - maxP);
		gc2[whichChain*2 + proposedState] = newP;
		}
	else if (ran1 >= 0.50 && ran1 < 0.75)
		{
		minP = 0.0;
		maxP = 1.0;
		pSlide = 0.1;
		oldP = fracA[whichChain*2 + proposedState];
		ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
		newP = oldP + ran;
		if (newP < minP)
			newP = (minP - newP) + minP;
		if (newP > maxP)
			newP = maxP - (newP - maxP);
		fracA[whichChain*2 + proposedState] = newP;
		}
	else
		{
		minP = 0.0;
		maxP = 1.0;
		pSlide = 0.1;
		oldP = fracG[whichChain*2 + proposedState];
		ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
		newP = oldP + ran;
		if (newP < minP)
			newP = (minP - newP) + minP;
		if (newP > maxP)
			newP = maxP - (newP - maxP);
		fracG[whichChain*2 + proposedState] = newP;
		}
	
	(*lnPriorRatio) = (*lnProposalRatio) = 0.0;
	UpDateAllCls (proposedState, whichChain);

#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);
	
}





/* change branch lengths and topology (potentially) using BAMBE's LOCAL (unrooted) */
int Move_ChangeClockWithLocal (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int			i, j, topologyHasChanged, isAtRoot, isTreeConstrained,
				isForcedBackMove, isForcedForwardMove, dID[3], dTemp;
	double		ran, x, tuning, y,
				dAW, dBW, dCW, dAV, dBV, dCV, h[3], oldH1, newH1, temp,
				newDAW, newDBW, newDCW, newDAV, newDBV, newDCV, lnNewBrlenPr, lnOldBrlenPr, *nt, rootTime, sR, eR, sF;
	TreeNode	*p, *q, *a, *b, *c, *u, *v, *w;

	lnNewBrlenPr = lnOldBrlenPr = 0.0;

	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (q->length);
			}
		}
	else if (!strcmp(brlenprModel, "birth-death"))
		{
		sR = spRate[whichChain*2 + proposedState];
		eR = exRate[whichChain*2 + proposedState];
		sF = samplingFraction;
		/* allocate memory */
		nt = (double *)malloc((size_t) (numTaxa-1) * sizeof(double));
		if (!nt)
			{
			printf ("\n   ERROR: Problem allocating nt\n");
			return (ERROR);
			}
			
		/* get node times */
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left == NULL && q->right == NULL)
				q->nodeTime = 0.0;
			else
				q->nodeTime += q->left->nodeTime + q->left->length;
			}
		rootTime = root[whichChain*2+proposedState]->left->nodeTime;
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left == NULL && q->right == NULL)
				q->nodeTime = 0.0;
			else
				q->nodeTime /= rootTime;
			}
					
		/* put node times into vector */
		j = 0;
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left != NULL && q->right != NULL && q->anc != NULL)
				{
				nt[j] = q->nodeTime;
				j++;
				}
			}
			
		/* calculate probabilities of tree */
		lnOldBrlenPr = (numTaxa-2)*log(sR);
		for (i=0; i<numTaxa-2; i++)
			{
			lnOldBrlenPr += lnP1(nt[i], sR, eR, sF) - lnVt(rootTime, sR, eR, sF);
			}
		}

#	if defined (DEBUG_LOCAL_CLOCK)
	printf ("Before:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, YES);
#	endif
	
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		p->upDateCl = NO;
		}
		
	(*lnProposalRatio) = 0.0;

	/* pick an internal branch */
	do
		{
		p = intNodeDownPassSeq[whichChain*2*numIntNodes + proposedState*numIntNodes + (int)(RandomNumber(seed)*numIntNodes)];
		} while (p->anc->anc == NULL);
		
	isTreeConstrained = NO;
	if (p->isConstrained == YES)
		isTreeConstrained = YES;
	
	isAtRoot = NO;
	if (p->anc->anc->anc == NULL)
		isAtRoot = YES;

	if (isAtRoot == NO)
		{

		/* initialize pointers */
		u = p;
		v = u->anc;
		w = v->anc;
		a = u->left;
		b = u->right;
		if (v->left == u)
			c = v->right;
		else
			c = v->left;
			
		dAW = a->length + u->length + v->length;
		dBW = b->length + u->length + v->length;
		dCW = c->length + v->length;
		h[0] = dAW;
		h[1] = dBW;
		h[2] = dCW;
		dID[0] = 0;
		dID[1] = 1;
		dID[2] = 2;
		if (h[0] > h[1])
			{
			temp = h[0];
			h[0] = h[1];
			h[1] = temp;
			dTemp = dID[0];
			dID[0] = dID[1];
			dID[1] = dTemp;
			}
		if (h[0] > h[2])
			{
			temp = h[0];
			h[0] = h[2];
			h[2] = temp;
			dTemp = dID[0];
			dID[0] = dID[2];
			dID[2] = dTemp;
			}
		if (h[1] > h[2])
			{
			temp = h[1];
			h[1] = h[2];
			h[2] = temp;
			dTemp = dID[1];
			dID[1] = dID[2];
			dID[2] = dTemp;
			}
			
		for (i=0; i<3; i++)
			{
			if (dID[i] == 0)
				newDAW = h[i];
			else if (dID[i] == 1)
				newDBW = h[i];
			else
				newDCW = h[i];
			}
#		if defined (DEBUG_LOCAL_CLOCK)
		printf ("newDAW = %lf newDBW = %lf newDCW = %lf\n", newDAW, newDBW, newDCW);
#		endif
		if (isTreeConstrained == NO)
			{
			x = RandomNumber(seed) * h[0];
			y = RandomNumber(seed) * h[1];
			if (y > x)
				{
				temp = y;
				y = x;
				x = temp;
				}
			}
		else
			{
			if (dAW < dBW)
				temp = dAW;
			else
				temp = dBW;
			x = RandomNumber(seed) * temp;
			if (dCW < temp)
				y = RandomNumber(seed) * dCW;
			else
				y = RandomNumber(seed) * temp;
			if (y > x)
				{
				temp = y;
				y = x;
				x = temp;
				}
			}
#		if defined (DEBUG_LOCAL_CLOCK)
		printf ("x = %lf y = %lf\n", x, y);
#		endif


		if (isTreeConstrained == NO)
			{		
			/* tree is not constrained at u */
			if (x < h[0])
				{
				/* topology is free to vary */
				ran = RandomNumber(seed);
				if (ran <= 0.3333)
					{
					a->anc = b->anc = u;
					u->left = a;
					u->right = b;
					v->left = u;
					v->right = c;
					c->anc = v;
					a->length = newDAW - x;
					b->length = newDBW - x;
					c->length = newDCW - y;
					u->length = x - y;
					v->length = y;
					}
				else if (ran > 0.3333 && ran <= 0.6666)
					{
					a->anc = c->anc = u;
					u->left = a;
					u->right = c;
					v->left = u;
					v->right = b;
					b->anc = v;
					a->length = newDAW - x;
					c->length = newDCW - x;
					b->length = newDBW - y;
					u->length = x - y;
					v->length = y;
					}
				else
					{
					b->anc = c->anc = u;
					u->left = b;
					u->right = c;
					v->left = u;
					v->right = a;
					a->anc = v;
					b->length = newDBW - x;
					c->length = newDCW - x;
					a->length = newDAW - y;
					u->length = x - y;
					v->length = y;
					}
				}
			else
				{
				/* topology forced */
				if (dID[0] == 0)
					{
					/* a + b */
					b->anc = c->anc = u;
					u->left = b;
					u->right = c;
					v->left = u;
					v->right = a;
					a->anc = v;
					b->length = newDBW - x;
					c->length = newDCW - x;
					a->length = newDAW - y;
					u->length = x - y;
					v->length = y;
					}
				else if (dID[0] == 1)
					{
					/* a + c */
					a->anc = c->anc = u;
					u->left = a;
					u->right = c;
					v->left = u;
					v->right = b;
					b->anc = v;
					a->length = newDAW - x;
					c->length = newDCW - x;
					b->length = newDBW - y;
					u->length = x - y;
					v->length = y;
					}
				else
					{
					/* b + c */
					a->anc = b->anc = u;
					u->left = a;
					u->right = b;
					v->left = u;
					v->right = c;
					c->anc = v;
					a->length = newDAW - x;
					b->length = newDBW - x;
					c->length = newDCW - y;
					u->length = x - y;
					v->length = y;
					}
				}
				
			/* get hastings ratio here */
			if (u->length > c->length && x < h[0])
				(*lnProposalRatio) += log(3.0);
			else if (u->length < c->length && x > h[0])
				(*lnProposalRatio) += log(1.0/3.0);
			else
				(*lnProposalRatio) += 0.0;
			}
		else
			{
			/* tree is constrained at u */
			a->length = newDAW - x;
			b->length = newDBW - x;
			c->length = newDCW - y;
			u->length = x - y;
			v->length = y;
			}
#		if defined (SMART_TI_PROBS)
		a->upDateTi = YES;
		b->upDateTi = YES;
		u->upDateTi = YES;
		c->upDateTi = YES;
		v->upDateTi = YES;
#		endif
		}
	else
		{
		/* deal with root of tree differently if this is a rooted and uncontrained tree */
		
		/* initialize pointers */
		u = p;
		v = p->anc;
		a = u->left;
		b = u->right;
		if (v->left == u)
			c = v->right;
		else
			c = v->left;
			
		/* v is at root of tree */
		if (u->length < c->length)
			isForcedBackMove = NO;
		else
			isForcedBackMove = YES; 
		dAV = a->length + u->length;
		dBV = b->length + u->length;
		dCV = c->length;
		if (dAV < dBV && dAV < dCV)
			oldH1 = dAV;
		else if (dBV < dAV && dBV < dCV)
			oldH1 = dBV;
		else
			oldH1 = dCV;
		tuning = clockTuneProp;
		newH1 = oldH1 * exp(tuning*(RandomNumber(seed) - 0.5));
		dAV = dAV + (newH1 - oldH1);
		dBV = dBV + (newH1 - oldH1);
		dCV = dCV + (newH1 - oldH1);
		h[0] = dAV;
		h[1] = dBV;
		h[2] = dCV;
		dID[0] = 0;
		dID[1] = 1;
		dID[2] = 2;
		if (h[0] > h[1])
			{
			temp = h[0];
			h[0] = h[1];
			h[1] = temp;
			dTemp = dID[0];
			dID[0] = dID[1];
			dID[1] = dTemp;
			}
		if (h[0] > h[2])
			{
			temp = h[0];
			h[0] = h[2];
			h[2] = temp;
			dTemp = dID[0];
			dID[0] = dID[2];
			dID[2] = dTemp;
			}
		if (h[1] > h[2])
			{
			temp = h[1];
			h[1] = h[2];
			h[2] = temp;
			dTemp = dID[1];
			dID[1] = dID[2];
			dID[2] = dTemp;
			}
			
		for (i=0; i<3; i++)
			{
			if (dID[i] == 0)
				newDAV = h[i];
			else if (dID[i] == 1)
				newDBV = h[i];
			else
				newDCV = h[i];
			}
		
#		if defined (DEBUG_LOCAL_CLOCK)
		printf ("h[0] = %lf h[1] = %lf h[2] = %lf (%d %d %d)\n", h[0], h[1], h[2], dID[0], dID[1], dID[2]);
		printf ("x = %lf\n", x);
#		endif

		(*lnProposalRatio) += 2.0 * (log(newH1) - log(oldH1));

		if (isTreeConstrained == NO)
			x = RandomNumber(seed) * h[1];
		else
			{
			if (newDAV < newDBV)
				x = RandomNumber(seed) * newDAV;
			else
				x = RandomNumber(seed) * newDBV;
			}

		if (isTreeConstrained == NO)
			{
			/* tree is not constrained */
			if (x > h[0])
				{
				isForcedForwardMove = YES;
				if (dID[0] == 0)
					{
					/* a is shortest, (b,c) forced */
					u->left = b;
					u->right = c;
					u->anc = v;
					a->anc = v;
					b->anc = u;
					c->anc = u;
					v->left = a;
					v->right = u;
					u->length = x;
					a->length = dAV;
					b->length = dBV - x;
					c->length = dCV - x;
					}
				else if (dID[0] == 1)
					{
					/* b is shortest, (a,c) forced */
					u->left = a;
					u->right = c;
					u->anc = v;
					a->anc = u;
					b->anc = v;
					c->anc = u;
					v->left = b;
					v->right = u;
					u->length = x;
					a->length = dAV - x;
					b->length = dBV;
					c->length = dCV - x;
					}
				else
					{
					/* c is shortest, (a,b) forced */
					u->left = a;
					u->right = b;
					u->anc = v;
					a->anc = u;
					b->anc = u;
					c->anc = v;
					v->left = c;
					v->right = u;
					u->length = x;
					a->length = dAV - x;
					b->length = dBV - x;
					c->length = dCV;
					}
				}
			else
				{
				isForcedForwardMove = NO;
				ran = RandomNumber(seed);
				if (ran <= 0.33333)
					{
					/* a with c */
					u->right = c;
					b->anc = v;
					c->anc = u;
					if (v->left == u)
						v->right = b;
					else
						v->left = b;
					u->length = x;
					a->length = newDAV - x;
					b->length = newDBV;
					c->length = newDCV - x;
					}
				else if (ran > 0.33333 && ran <= 0.66666)
					{
					/* b with c */
					u->left = c;
					a->anc = v;
					c->anc = u;
					if (v->left == u)
						v->right = a;
					else
						v->left = a;
					a->length += u->length;
					c->length -= u->length;
					u->length = x;
					a->length = newDAV;
					b->length = newDBV - x;
					c->length = newDCV - x;
					}
				else
					{
					/* no change */
					u->length = x;
					a->length = newDAV - x;
					b->length = newDBV - x;
					c->length = newDCV;
					}
				}		
			
			/* get hastings ratio here */
			if (isForcedForwardMove == NO && isForcedBackMove == YES)
				(*lnProposalRatio) += log(3.0);
			else if (isForcedForwardMove == YES && isForcedBackMove == NO)
				(*lnProposalRatio) += log(1.0/3.0);
			
			}
		else
			{
			/* tree is constrained at node u */
			u->length = x;
			a->length = dAV - x;
			b->length = dBV - x;
			c->length = dCV;
			}
#		if defined (SMART_TI_PROBS)
		a->upDateTi = YES;
		b->upDateTi = YES;
		u->upDateTi = YES;
		c->upDateTi = YES;
#		endif
		}

	p = u;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}
	
	topologyHasChanged = YES;

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		i = j = 0;
		GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);
		}

#	if defined (DEBUG_LOCAL_CLOCK)
	printf ("After:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, YES);
#	endif

	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (q->length);
			}
		}
	else if (!strcmp(brlenprModel, "birth-death"))
		{
		/* get node times */
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left == NULL && q->right == NULL)
				q->nodeTime = 0.0;
			else
				q->nodeTime += q->left->nodeTime + q->left->length;
			}
		rootTime = root[whichChain*2+proposedState]->left->nodeTime;
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left == NULL && q->right == NULL)
				q->nodeTime = 0.0;
			else
				q->nodeTime /= rootTime;
			}
					
		/* put node times into vector */
		j = 0;
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left != NULL && q->right != NULL && q->anc != NULL)
				{
				nt[j] = q->nodeTime;
				j++;
				}
			}
			
		/* calculate probabilities of tree */
		lnNewBrlenPr = (numTaxa-2)*log(sR);
		for (i=0; i<numTaxa-2; i++)
			{
			lnNewBrlenPr += lnP1(nt[i], sR, eR, sF) - lnVt(rootTime, sR, eR, sF);
			}
		
		free (nt);
		}
		
	(*lnPriorRatio) = lnNewBrlenPr - lnOldBrlenPr;

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
	gNodeMoves = 1;
#	endif

#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	

	return (NO_ERROR);

}





/* change gamma shape parameter */
int Move_ChangeGammaShape (int proposedState, int whichChain, long int *seed, double *lnPriorRatio)

{

	double		oldA, newA, ran, alphaSlide, minAlpha, maxAlpha;

	if (!strcmp(shapeprModel, "exponential"))
		{
		minAlpha = 0.01;
		maxAlpha = 100.0;
		}
	else if (!strcmp(shapeprModel, "uniform"))
		{
		minAlpha = shapeprUni[0];
		maxAlpha = shapeprUni[1];
		}
	alphaSlide = alphaWinProp;
	
	oldA = alpha[whichChain*2 + proposedState];
	ran = (RandomNumber(seed) * alphaSlide) - (alphaSlide/2.0);
	newA = oldA + ran;
	if (newA < minAlpha)
		newA = (minAlpha - newA) + minAlpha;
	if (newA > maxAlpha)
		newA = maxAlpha - (newA - maxAlpha);
	alpha[whichChain*2 + proposedState] = newA;

	/* set prior ratio */
	if (!strcmp(qmatprModel, "exponential"))
		(*lnPriorRatio) = (shapeprExp*oldA - shapeprExp*newA);
	else if (!strcmp(qmatprModel, "uniform"))
		(*lnPriorRatio) = 0.0;

	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}


/* change lag parameter */
int Move_ChangeLag (int proposedState, int whichChain, long int *seed, double *lnPriorRatio, double *lnProposalRatio)

{

	int			minLag, maxLag, oldLag, newLag, jumpSize;
	double		ran;

	minLag = (int)chainMins[CHANGE_LAG];
	maxLag = (int)chainMaxs[CHANGE_LAG];

#	if 0
	if (oldLag == 1)
		{
		newLag = 2;
		(*lnProposalRatio) = log(0.5);
		}
	else if (oldLag == maxLag)
		{
		newLag = maxLag - 1;
		(*lnProposalRatio) = log(0.5);
		}
	else
		{
		if (RandomNumber(seed) < 0.5)
			newLag = oldLag + 1;
		else
			newLag = oldLag - 1;
		(*lnProposalRatio) = 0.0;
		}
	if (newLag == 1)
		(*lnProposalRatio) = log(2.0);
	else if (newLag == maxLag)
		(*lnProposalRatio) = log(2.0);
	lag[whichChain*2 + proposedState] = newLag;
#	else
	ran = RandomNumber(seed);
	if (ran <= (5.0 / 15.0))
		jumpSize = 1;
	else if (ran > (5.0 / 15.0) && ran <= (9.0 / 15.0))
		jumpSize = 2;
	else if (ran > (9.0 / 15.0) && ran <= (12.0 / 15.0))
		jumpSize = 3;
	else if (ran > (12.0 / 15.0) && ran <= (14.0 / 15.0))
		jumpSize = 4;
	else
		jumpSize = 5;
	oldLag = lag[whichChain*2 + proposedState];
	if (oldLag - jumpSize < 1)
		{
		newLag = oldLag + jumpSize;
		(*lnProposalRatio) = log(0.5);
		}
	else if (oldLag + jumpSize > maxLag)
		{
		newLag = oldLag - jumpSize;
		(*lnProposalRatio) = log(0.5);
		}
	else
		{
		if (RandomNumber(seed) < 0.5)
			newLag = oldLag + jumpSize;
		else
			newLag = oldLag - jumpSize;
		(*lnProposalRatio) = 0.0;
		}
	if (newLag <= jumpSize)
		(*lnProposalRatio) = log(2.0);
	else if (newLag > maxLag - jumpSize)
		(*lnProposalRatio) = log(2.0);
	lag[whichChain*2 + proposedState] = newLag;
#	endif
		
	/* set prior ratio */
	(*lnPriorRatio) = 0.0;
	if (!strcmp(lagprModel, "exponential"))
		{
		(*lnPriorRatio)  = log(exp(-(newLag-0.5)) - exp(-(newLag+0.5)));
		(*lnPriorRatio) -= log(exp(-(oldLag-0.5)) - exp(-(oldLag+0.5)));
		}
		
	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change Q matrix */
int Move_ChangeQMatrix (int proposedState, int whichChain, long int *seed, double *lnPriorRatio)

{

	int			param;
	double		oldK, newK, ran, kappaSlide, minKappa, maxKappa;

	if (!strcmp(qmatprModel, "exponential"))
		{
		minKappa = 0.0000001;
		maxKappa = 1000.0;
		}
	else if (!strcmp(qmatprModel, "uniform"))
		{
		minKappa = qmatprUni[0];
		maxKappa = qmatprUni[1];
		}
	kappaSlide = qMatWinProp;

	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == NO)
		{
		if (nst == 2)
			{
			oldK = kappa[whichChain*2 + proposedState];
			ran = (RandomNumber(seed) * kappaSlide) - (kappaSlide/2.0);
			newK = oldK + ran;
			if (newK < minKappa)
				newK = (minKappa - newK) + minKappa;
			if (newK > maxKappa)
				newK = maxKappa - (newK - maxKappa);
			kappa[whichChain*2 + proposedState] = newK;
			}
		else if (nst == 6)
			{
			ran = RandomNumber(seed);
			if (ran > 0 && ran <= 0.2)
				param = 1;
			else if (ran > 0.2 && ran <= 0.4)
				param = 2;
			else if (ran > 0.4 && ran <= 0.6)
				param = 3;
			else if (ran > 0.6 && ran <= 0.8)
				param = 4;
			else if (ran > 0.8 && ran <= 1.0)
				param = 5;
			oldK = subParams[whichChain*12 + proposedState*6 + param];
			ran = (RandomNumber(seed) * kappaSlide) - (kappaSlide/2.0);
			newK = oldK + ran;
			if (newK < 0.0)
				newK = -newK;
			if (newK > maxKappa)
				newK = maxKappa - (newK - maxKappa);
			subParams[whichChain*12 + proposedState*6 + param] = newK;
			}
		else if (nst == 12)
			{
			ran = RandomNumber(seed);
			if (ran > 0.0 && ran <= 1.0/11.0)
				param = 1;
			else if (ran > 1.0/11.0 && ran <= 2.0/11.0)
				param = 2;
			else if (ran > 2.0/11.0 && ran <= 3.0/11.0)
				param = 3;
			else if (ran > 3.0/11.0 && ran <= 4.0/11.0)
				param = 4;
			else if (ran > 4.0/11.0 && ran <= 5.0/11.0)
				param = 5;
			else if (ran > 5.0/11.0 && ran <= 6.0/11.0)
				param = 6;
			else if (ran > 6.0/11.0 && ran <= 7.0/11.0)
				param = 7;
			else if (ran > 7.0/11.0 && ran <= 8.0/11.0)
				param = 8;
			else if (ran > 8.0/11.0 && ran <= 9.0/11.0)
				param = 9;
			else if (ran > 9.0/11.0 && ran <= 10.0/11.0)
				param = 10;
			else if (ran > 10.0/11.0 && ran <= 1.0)
				param = 11;
			oldK = subParams[whichChain*24 + proposedState*12 + param];
			ran = (RandomNumber(seed) * kappaSlide) - (kappaSlide/2.0);
			newK = oldK + ran;
			if (newK < 0.0)
				newK = -newK;
			if (newK > maxKappa)
				newK = maxKappa - (newK - maxKappa);
			subParams[whichChain*24 + proposedState*12 + param] = newK;
			}
		else
			{
			printf ("\n   ERROR: Should not be in this move\n");
			return (ERROR);
			}
		}
	else if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		oldK = kappa[whichChain*2 + proposedState];
		ran = (RandomNumber(seed) * kappaSlide) - (kappaSlide/2.0);
		newK = oldK + ran;
		if (newK < minKappa)
			newK = (minKappa - newK) + minKappa;
		if (newK > maxKappa)
			newK = maxKappa - (newK - maxKappa);
		kappa[whichChain*2 + proposedState] = newK;
		}
	else if (dataType == PROTEIN)
		{
		param = RandomNumber(seed) * 189;
		param++;
		if (param < 1 || param >= 190)
			{
			printf ("\n   ERROR: parameter to be changed is invalid \n");
			return (ERROR);
			}
		oldK = subParams[whichChain*2*190 + proposedState*190 + param];
		ran = (RandomNumber(seed) * kappaSlide) - (kappaSlide/2.0);
		newK = oldK + ran;
		if (newK < 0.0)
			newK = -newK;
		if (newK > maxKappa)
			newK = maxKappa - (newK - maxKappa);
		subParams[whichChain*2*190 + proposedState*190 + param] = newK;
		}		
	else if (dataType == RESTRICTION)
		{
		oldK = kappa[whichChain*2 + proposedState];
		ran = (RandomNumber(seed) * kappaSlide) - (kappaSlide/2.0);
		newK = oldK + ran;
		if (newK < minKappa)
			newK = (minKappa - newK) + minKappa;
		if (newK > maxKappa)
			newK = maxKappa - (newK - maxKappa);
		kappa[whichChain*2 + proposedState] = newK;
		//kappa[whichChain*2 + proposedState] = 1.0;
		}		
		
	/* set prior ratio */
	if (!strcmp(qmatprModel, "exponential"))
		(*lnPriorRatio) = (qmatprExp*oldK - qmatprExp*newK);
	else if (!strcmp(qmatprModel, "uniform"))
		(*lnPriorRatio) = 0.0;
		
	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change rates of rate categories */
int Move_ChangeSiteRates (int proposedState, int whichChain, long int *seed, double *lnPriorRatio)

{

	int			i, nIncludedChars;
	double		oldA, newA, ran, alphaSlide, minAlpha, maxAlpha, scaler;

	if (!strcmp(siterateprModel, "exponential"))
		{
		minAlpha = 0.01;
		maxAlpha = 100.0;
		}
	else if (!strcmp(siterateprModel, "uniform"))
		{
		minAlpha = siterateprUni[0];
		maxAlpha = siterateprUni[1];
		}
	alphaSlide = rateWinProp;

	(*lnPriorRatio) = 0.0;
	for (i=0; i<nPartitions-1; i++)
		{
		oldA = unscaledRates[whichChain*2*nPartitions + proposedState*nPartitions + i];
		ran = (RandomNumber(seed) * alphaSlide) - (alphaSlide/2.0);
		newA = oldA + ran;
		if (newA < minAlpha)
			newA = (minAlpha - newA) + minAlpha;
		if (newA > maxAlpha)
			newA = maxAlpha - (newA - maxAlpha);
		unscaledRates[whichChain*2*nPartitions + proposedState*nPartitions + i] = newA;

		/* set prior ratio */
		if (!strcmp(qmatprModel, "exponential"))
			(*lnPriorRatio) += (siterateprExp*oldA - siterateprExp*newA);
		}

	scaler = 0.0;
	nIncludedChars = 0;
	for (i=0; i<nPartitions; i++)
		{
		scaler += unscaledRates[whichChain*2*nPartitions + proposedState*nPartitions + i] * nSitesInPartition[i];
		nIncludedChars += nSitesInPartition[i];
		}
	scaler = (double)nIncludedChars / scaler;
	for (i=0; i<nPartitions; i++)
		{
		scaledRates[whichChain*2*nPartitions + proposedState*nPartitions + i] = 
			unscaledRates[whichChain*2*nPartitions + proposedState*nPartitions + i] * scaler;
		}

	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change branch lengths and topology (potentially) using BAMBE's LOCAL (unrooted) */
int Move_ChangeUnrootedWithLocal (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int			i, j, isAUp, topologyHasChanged, specialRoot, isTreeConstrained,
				isForcedBackMove, isForcedForwardMove, dID[3], dTemp;
	double		ran, m, newM, x, newX, y, newY, tuning, maxV,
				dAV, dBV, dCV, h[3], oldH1, newH1, temp,
				newDAV, newDBV, newDCV, lnOldBrlenPr,lnNewBrlenPr;
	TreeNode	*p, *a, *b, *c, *d, *u, *v;

	tuning = tuningProp;

#	if defined (DEBUG_LOCAL)
	printf ("Before:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif
	
	lnNewBrlenPr = lnOldBrlenPr = 0.0;
	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
			}
		}
		
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		p->upDateCl = NO;
		}
		
	(*lnProposalRatio) = 0.0;

	/* pick an internal branch */
	do
		{
		p = intNodeDownPassSeq[whichChain*2*numIntNodes + proposedState*numIntNodes + (int)(RandomNumber(seed)*numIntNodes)];
		} while (p->anc->anc == NULL);
		
	isTreeConstrained = NO;
	if (p->isConstrained == YES || p->anc->isConstrained == YES)
		isTreeConstrained = YES;

	specialRoot = NO;
	if (p->anc->anc->anc == NULL && treeModel == ROOTED)
		specialRoot = YES;

#	if defined (DEBUG_LOCAL)
	if (isTreeConstrained == YES)
		printf ("node (%d %d) is constrained\n", p->isConstrained, p->anc->isConstrained);
#	endif

	if (specialRoot == NO)
		{
		/* set up pointers according to Larget and Simon (MBE, 1999: 754) */
		v = p;
		u = p->anc;
		u->upDateCl = YES;
		v->upDateCl = YES;
		if (RandomNumber(seed) < 0.5)
			{
			c = v->left;
			d = v->right;
			}
		else
			{
			c = v->right;
			d = v->left;
			}
		if (RandomNumber(seed) < 0.5)
			{
			if (u->left == v)
				a = u->right;
			else
				a = u->left;
			b = u->anc;
			isAUp = YES;
			}
		else
			{
			if (u->left == v)
				b = u->right;
			else
				b = u->left;
			a = u->anc;
			isAUp = NO;
			}
#		if defined (DEBUG_LOCAL)
		printf ("%d %d %d %d %d %d (%d)\n", u->index, v->index, a->index, b->index, c->index, d->index, isAUp);
#		endif

		/* get lengths of paths */
		m = c->length + v->length;
		if (isAUp == YES)
			{
			m += a->length;
			x = a->length;
			}
		else
			{
			m += u->length;
			x = u->length;
			}
		y = v->length + x;
		
		/* change m */
		ran = RandomNumber(seed);
		newM = m * exp(tuning * (ran - 0.5));
#		if defined (DEBUG_LOCAL)
		printf ("m = %lf newM = %lf tuning = %lf\n", m, newM, tuning);
#		endif

		/* calculate proposal ratio */
		(*lnProposalRatio) += (log(newM) - log(m));
		
		/* change branch length proportions */
		if (RandomNumber(seed) < 0.5)
			{
			/* detach u */
			ran = RandomNumber(seed);
			if (isTreeConstrained == NO)
				{
				newY = y * (newM / m);
				newX = ran * newM;
				(*lnProposalRatio) += (log(newM) - log(m));
				}
			else
				{
				newY = y * (newM / m);
				newX = ran * newY;
				(*lnProposalRatio) += (log(newY) - log(y));
				}
			}
		else
			{
			/* detach v */
			ran = RandomNumber(seed);
			if (isTreeConstrained == NO)
				{
				newX = x * (newM / m);
				newY = ran * newM;
				(*lnProposalRatio) += (log(newM) - log(m));
				}
			else
				{
				newX = x * (newM / m);
				newY = newX + ran * (newM - newX);
				(*lnProposalRatio) += (log(newM - newX) - log(m - x));
				}
			}
			
		/* check to see if topology changed */
		if (newX > newY)
			topologyHasChanged = YES;
		else
			topologyHasChanged = NO;
		
		/* update pointers and branch lengths of tree */
		if (topologyHasChanged == YES)
			{
			if (isAUp == YES)
				{
				if (v->left == c)
					v->right = a;
				else
					v->left = a;
				if (u->left == v)
					u->right = d;
				else
					u->left = d;
				a->anc = v;
				d->anc = u;
				c->length = newM - newX;
				v->length = newX - newY;
				a->length = newY;
				}
			else	
				{
				if (v->left == c)
					v->right = b;
				else
					v->left = b;
				if (u->left == v)
					u->right = d;
				else
					u->left = d;
				b->anc = v;
				d->anc = u;
				c->length = newM - newX;
				u->length = newY;
				v->length = newX - newY;
				}
			}
		else
			{
			if (isAUp == YES)
				{
				c->length = newM - newY;
				u->length = newY - newX;
				a->length = newX;
				}
			else	
				{
				c->length = newM - newY;
				v->length = newY - newX;
				u->length = newX;
				}
			}
		
		/* check branch lengths */
		maxV = chainMaxs[CHANGE_UNROOT_LOCAL];
		if (isAUp == YES)
			{
			if (c->length < BRLEN_EPSILON)
				c->length = BRLEN_EPSILON;
			if (a->length < BRLEN_EPSILON)
				a->length = BRLEN_EPSILON;
			if (d->length < BRLEN_EPSILON)
				d->length = BRLEN_EPSILON;
			if (u->length < BRLEN_EPSILON)
				u->length = BRLEN_EPSILON;
			if (v->length < BRLEN_EPSILON)
				v->length = BRLEN_EPSILON;
			if (c->length > maxV)
				c->length = maxV;
			if (a->length > maxV)
				a->length = maxV;
			if (d->length > maxV)
				d->length = maxV;
			if (u->length > maxV)
				u->length = maxV;
			if (v->length > maxV)
				v->length = maxV;
				
			}
		else
			{
			if (c->length < BRLEN_EPSILON)
				c->length = BRLEN_EPSILON;
			if (b->length < BRLEN_EPSILON)
				b->length = BRLEN_EPSILON;
			if (d->length < BRLEN_EPSILON)
				d->length = BRLEN_EPSILON;
			if (u->length < BRLEN_EPSILON)
				u->length = BRLEN_EPSILON;
			if (v->length < BRLEN_EPSILON)
				v->length = BRLEN_EPSILON;
			if (c->length > maxV)
				c->length = maxV;
			if (b->length > maxV)
				b->length = maxV;
			if (d->length > maxV)
				d->length = maxV;
			if (u->length > maxV)
				u->length = maxV;
			if (v->length > maxV)
				v->length = maxV;
			}
			
		v->upDateCl = YES;
		p = u;
		while (p->anc != NULL)
			{
			p->upDateCl = YES;
			p = p->anc;
			}
#		if defined (SMART_TI_PROBS)
		c->upDateTi = YES;
		v->upDateTi = YES;
		if (isAUp == YES)
			a->upDateTi = YES;
		else
			u->upDateTi = YES;
		a->upDateTi = YES;
		u->upDateTi = YES;
#		endif
		}
	else
		{
		/* deal with root of tree differently if this is a rooted and uncontrained tree */
		
		/* check constraints again */
		if (isTreeConstrained == YES)
			{
			if (p->isConstrained == NO && p->anc->isConstrained == YES)
				isTreeConstrained = NO;
			}
		
		/* initialize pointers */
		u = p;
		v = p->anc;
		a = u->left;
		b = u->right;
		if (v->left == u)
			c = v->right;
		else
			c = v->left;
	
		if (isTreeConstrained == NO)
			{
			/* node is unconstrained */
			if (u->length < c->length)
				isForcedBackMove = NO;
			else
				isForcedBackMove = YES; 
			dAV = a->length + u->length;
			dBV = b->length + u->length;
			dCV = c->length;
			if (dAV < dBV && dAV < dCV)
				oldH1 = dAV;
			else if (dBV < dAV && dBV < dCV)
				oldH1 = dBV;
			else
				oldH1 = dCV;
			tuning = tuning;
			newH1 = oldH1 * exp(tuning*(RandomNumber(seed) - 0.5));
			dAV = dAV + (newH1 - oldH1);
			dBV = dBV + (newH1 - oldH1);
			dCV = dCV + (newH1 - oldH1);
			h[0] = dAV;
			h[1] = dBV;
			h[2] = dCV;
			dID[0] = 0;
			dID[1] = 1;
			dID[2] = 2;
			if (h[0] > h[1])
				{
				temp = h[0];
				h[0] = h[1];
				h[1] = temp;
				dTemp = dID[0];
				dID[0] = dID[1];
				dID[1] = dTemp;
				}
			if (h[0] > h[2])
				{
				temp = h[0];
				h[0] = h[2];
				h[2] = temp;
				dTemp = dID[0];
				dID[0] = dID[2];
				dID[2] = dTemp;
				}
			if (h[1] > h[2])
				{
				temp = h[1];
				h[1] = h[2];
				h[2] = temp;
				dTemp = dID[1];
				dID[1] = dID[2];
				dID[2] = dTemp;
				}
				
			for (i=0; i<3; i++)
				{
				if (dID[i] == 0)
					newDAV = h[i];
				else if (dID[i] == 1)
					newDBV = h[i];
				else
					newDCV = h[i];
				}
			
			x = RandomNumber(seed) * h[1];
#			if defined (DEBUG_LOCAL)
			printf ("h[0] = %lf h[1] = %lf h[2] = %lf (%d %d %d)\n", h[0], h[1], h[2], dID[0], dID[1], dID[2]);
			printf ("x = %lf\n", x);
#			endif

			(*lnProposalRatio) += 2.0 * (log(newH1) - log(oldH1));
			
			if (x > h[0])
				{
				isForcedForwardMove = YES;
				if (dID[0] == 0)
					{
					/* a is shortest, (b,c) forced */
					u->left = b;
					u->right = c;
					u->anc = v;
					a->anc = v;
					b->anc = u;
					c->anc = u;
					v->left = a;
					v->right = u;
					u->length = x;
					a->length = dAV;
					b->length = dBV - x;
					c->length = dCV - x;
					}
				else if (dID[0] == 1)
					{
					/* b is shortest, (a,c) forced */
					u->left = a;
					u->right = c;
					u->anc = v;
					a->anc = u;
					b->anc = v;
					c->anc = u;
					v->left = b;
					v->right = u;
					u->length = x;
					a->length = dAV - x;
					b->length = dBV;
					c->length = dCV - x;
					}
				else
					{
					/* c is shortest, (a,b) forced */
					u->left = a;
					u->right = b;
					u->anc = v;
					a->anc = u;
					b->anc = u;
					c->anc = v;
					v->left = c;
					v->right = u;
					u->length = x;
					a->length = dAV - x;
					b->length = dBV - x;
					c->length = dCV;
					}
				}
			else
				{
				isForcedForwardMove = NO;
				ran = RandomNumber(seed);
				if (ran <= 0.33333)
					{
					/* a with c */
					u->right = c;
					b->anc = v;
					c->anc = u;
					if (v->left == u)
						v->right = b;
					else
						v->left = b;
					u->length = x;
					a->length = newDAV - x;
					b->length = newDBV;
					c->length = newDCV - x;
					}
				else if (ran > 0.33333 && ran <= 0.66666)
					{
					/* b with c */
					u->left = c;
					a->anc = v;
					c->anc = u;
					if (v->left == u)
						v->right = a;
					else
						v->left = a;
					a->length += u->length;
					c->length -= u->length;
					u->length = x;
					a->length = newDAV;
					b->length = newDBV - x;
					c->length = newDCV - x;
					}
				else
					{
					/* no change */
					u->length = x;
					a->length = newDAV - x;
					b->length = newDBV - x;
					c->length = newDCV;
					}
				
				}		
			
			/* get hastings ratio here */
			if (isForcedForwardMove == NO && isForcedBackMove == YES)
				(*lnProposalRatio) += log(3.0);
			else if (isForcedForwardMove == YES && isForcedBackMove == NO)
				(*lnProposalRatio) += log(1.0/3.0);
				
			}
		else
			{
			/* node is constrained */
			dAV = a->length + u->length;
			dBV = b->length + u->length;
			dCV = c->length;
			if (dAV < dBV)
				oldH1 = dAV;
			else
				oldH1 = dBV;
			tuning = tuning;
			newH1 = oldH1 * exp(tuning*(RandomNumber(seed) - 0.5));
			dAV = dAV + (newH1 - oldH1);
			dBV = dBV + (newH1 - oldH1);
			dCV = dCV + (newH1 - oldH1);

			(*lnProposalRatio) += 2.0 * (log(newH1) - log(oldH1));

			x = RandomNumber(seed) * newH1;			

			u->length = x;
			a->length = dAV - x;
			b->length = dBV - x;
			c->length = dCV;
			}
			
		p = u;
		while (p->anc != NULL)
			{
			p->upDateCl = YES;
			p = p->anc;
			}
		
		topologyHasChanged = YES;
		
#		if defined (SMART_TI_PROBS)
		a->upDateTi = YES;
		b->upDateTi = YES;
		c->upDateTi = YES;
		u->upDateTi = YES;
#		endif
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		i = j = 0;
		GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);
		}

#	if defined (DEBUG_LOCAL)
	printf ("After:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif

	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
			}
		}
		
	(*lnPriorRatio) = lnNewBrlenPr - lnOldBrlenPr;

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
	gNodeMoves = 1;
#	endif
	
#	if defined (SMART_TI_PROBS)
	//UpDateAllTIs (proposedState, whichChain);
#	endif	

	return (NO_ERROR);

}





/* change branch lengths and topology (potentially) using BAMBE's LOCAL (rooted with calibrations) */
int Move_ChangeTimeClockWithLocal (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int			i, j, isAtRoot, dID[3], dTemp, topologyHasChanged, forceAB;
	double		h[3], temp, maxTime1, maxTime2, minTime1, minTime2, x, y, ran, tuning,
				lnNewBrlenPr, lnOldBrlenPr, *nt, rootTime, sR, eR, sF;
	TreeNode	*p, *q, *a, *b, *c, *u, *v, *w;

	lnNewBrlenPr = lnOldBrlenPr = 0.0;

	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (q->length);
			}
		}
	else if (!strcmp(brlenprModel, "birth-death"))
		{
		sR = spRate[whichChain*2 + proposedState];
		eR = exRate[whichChain*2 + proposedState];
		sF = samplingFraction;
		
		/* allocate memory */
		nt = (double *)malloc((size_t) (numTaxa-1) * sizeof(double));
		if (!nt)
			{
			printf ("\n   ERROR: Problem allocating nt\n");
			return (ERROR);
			}
			
		/* get root time */
		rootTime = root[whichChain*2+proposedState]->left->nodeTime;
					
		/* put node times into vector */
		j = 0;
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left != NULL && q->right != NULL && q->anc != NULL)
				{
				nt[j] = q->nodeTime;
				j++;
				}
			}
			
		/* calculate probabilities of tree */
		lnOldBrlenPr = (numTaxa-2)*log(sR);
		for (i=0; i<numTaxa-2; i++)
			{
			lnOldBrlenPr += lnP1(nt[i], sR, eR, sF) - lnVt(rootTime, sR, eR, sF);
			}
		}

#	if defined (DEBUG_LOCAL_TIME_CLOCK)
	printf ("Before:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, YES);
#	endif

	/* set update flags to NO */
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		p->upDateCl = NO;
		}
		
	/* initialize proposal ratio */
	(*lnProposalRatio) = 0.0;

	/* pick an internal branch and assign pointers */
	do
		{
		p = intNodeDownPassSeq[whichChain*2*numIntNodes + proposedState*numIntNodes + (int)(RandomNumber(seed)*numIntNodes)];
		} while (p->anc->anc == NULL);
	u = p;
	v = u->anc;
	if (u->anc->anc->anc == NULL)
		isAtRoot = YES;
	else
		{
		isAtRoot = NO;
		w = v->anc;
		}
	a = u->left;
	b = u->right;
	if (v->left == u)
		c = v->right;
	else
		c = v->left;
#	if defined (DEBUG_LOCAL_TIME_CLOCK)
	if (isAtRoot == NO)
		printf ("u=%d v=%d w=%d (%d %d %d)\n", Dex2(u), Dex2(v), Dex2(w), Dex2(a), Dex2(b), Dex2(c));
	else
		printf ("u=%d v=%d (%d %d %d)\n", Dex2(u), Dex2(v), Dex2(a), Dex2(b), Dex2(c));
#	endif
		
	/* sort times of nodes a, b, and c */
	h[0] = a->nodeTime;
	h[1] = b->nodeTime;
	h[2] = c->nodeTime;
	dID[0] = 0;
	dID[1] = 1;
	dID[2] = 2;
	if (h[0] < h[1])
		{
		temp = h[0];
		h[0] = h[1];
		h[1] = temp;
		dTemp = dID[0];
		dID[0] = dID[1];
		dID[1] = dTemp;
		}
	if (h[0] < h[2])
		{
		temp = h[0];
		h[0] = h[2];
		h[2] = temp;
		dTemp = dID[0];
		dID[0] = dID[2];
		dID[2] = dTemp;
		}
	if (h[1] < h[2])
		{
		temp = h[1];
		h[1] = h[2];
		h[2] = temp;
		dTemp = dID[1];
		dID[1] = dID[2];
		dID[2] = dTemp;
		}
#	if defined (DEBUG_LOCAL_TIME_CLOCK)
	printf ("%lf %lf %lf (%d %d %d)\n", h[0], h[1], h[2], dID[0], dID[1], dID[2]);
#	endif

	topologyHasChanged = NO;
		
	/* no constraints or calibrations in area of move (except, v can be constrained) */
	if (isAtRoot == NO)
		{
		/* at internal node of tree */
		forceAB = NO;
		
		maxTime1 = maxTime2 = w->nodeTime;
		minTime1 = h[0];
		minTime2 = h[1];
		
		if (u->isConstrained == YES && u->isCalibrated == NO)
			{
			forceAB = YES;
			if (a->nodeTime > b->nodeTime)
				minTime1 = minTime2 = a->nodeTime;
			else
				minTime1 = minTime2 = b->nodeTime;
			minTime2 = h[0];
			}
		else if (u->isCalibrated == YES)
			{
			forceAB = YES;
			if (a->nodeTime > b->nodeTime)
				minTime1 = minTime2 = a->nodeTime;
			else
				minTime1 = minTime2 = b->nodeTime;
			minTime2 = h[0];

			if (u->calTime[0] > minTime1)
				minTime1 = minTime2 = u->calTime[0];
			if (u->calTime[0] + u->calTime[1] < maxTime1)
				maxTime1 = u->calTime[0] + u->calTime[1];
			if (minTime2 < h[0])
				minTime2 = h[0];
			}
			
		if (v->isCalibrated == YES)
			{
			if (v->calTime[0] > minTime2)
				minTime2 = v->calTime[0];
			if (v->calTime[0] + v->calTime[1] < maxTime2)
				maxTime2 = v->calTime[0] + v->calTime[1];
			if (maxTime1 > maxTime2)
				maxTime1 = maxTime2;
			}
			
		x = RandomNumber(seed) * (maxTime1 - minTime1) + minTime1;
		y = RandomNumber(seed) * (maxTime2 - minTime2) + minTime2;
		if (x > y)
			{
			temp = x;
			x = y;
			y = temp;
			}
		if (x > minTime1 && forceAB == NO)
			{
			/* topology not forced */
			ran = RandomNumber(seed);
			if (ran < 0.333)
				{
				u->left = a;
				u->right = c;
				a->anc = c->anc = u;
				if (v->left == u)
					v->right = b;
				else
					v->left = b;
				b->anc = v;
				topologyHasChanged = YES;
				}
			else if (ran >= 0.333 && ran < 0.666)
				{
				u->left = b;
				u->right = c;
				b->anc = c->anc = u;
				if (v->left == u)
					v->right = a;
				else
					v->left = a;
				a->anc = v;
				topologyHasChanged = YES;
				}
			u->nodeTime = x;
			v->nodeTime = y;
			}
		else
			{
			/* topology forced */
			if (forceAB == NO)
				{
				if ((dID[1] == 0 && dID[2] == 2) || (dID[1] == 2 && dID[2] == 0))
					{
					u->left = a;
					u->right = c;
					a->anc = c->anc = u;
					if (v->left == u)
						v->right = b;
					else
						v->left = b;
					b->anc = v;
					topologyHasChanged = YES;
					}
				else if ((dID[1] == 1 && dID[2] == 2) || (dID[1] == 2 && dID[2] == 1))
					{
					u->left = b;
					u->right = c;
					b->anc = c->anc = u;
					if (v->left == u)
						v->right = a;
					else
						v->left = a;
					a->anc = v;
					topologyHasChanged = YES;
					}
				}
			u->nodeTime = x;
			v->nodeTime = y;
			}
		if (forceAB == NO)
			{
			if (u->nodeTime < c->nodeTime && x < h[0])
				(*lnProposalRatio) += log(3.0);
			else if (u->nodeTime > c->nodeTime && x > h[0])
				(*lnProposalRatio) += log(1.0/3.0);
			}
#		if defined (DEBUG_LOCAL_TIME_CLOCK)
		printf ("max1 = %lf max2 = %lf min = %lf %lf (%lf %lf)\n", maxTime1, maxTime2, minTime1, minTime2, x, y);
#		endif
		}
	else
		{
		/* at root of tree */
		forceAB = NO;

		maxTime1 = maxTime2 = v->nodeTime;
		minTime1 = h[0];
		minTime2 = h[1];
		tuning = timeTuneProp;
		
		if (u->isCalibrated == NO && v->isCalibrated == NO)
			{
			y = minTime1 + (maxTime1 - minTime1) * exp(tuning*(RandomNumber(seed)-0.5));
			(*lnProposalRatio) += log((y-minTime1) / (maxTime1-minTime1));
			if (u->isConstrained == YES)
				{
				forceAB = YES;
				minTime2 = minTime1;
				}
			x = minTime2 + RandomNumber(seed) * (y - minTime2);
			}
		else if (u->isCalibrated == YES && v->isCalibrated == NO)
			{
			forceAB = YES;
			minTime2 = minTime1;
			if (u->calTime[0] > minTime1)
				minTime1 = minTime2 = u->calTime[0];
			if (minTime1 > maxTime1)
				{
				printf ("\n   ERROR: problem with order of nodes\n");
				return (ERROR);
				}
			y = minTime1 + (maxTime1 - minTime1) * exp(tuning*(RandomNumber(seed)-0.5));
			(*lnProposalRatio) += log((y-minTime1) / (maxTime1-minTime1));
			
			if (u->calTime[0] + u->calTime[1] < y)
				maxTime2 = u->calTime[0] + u->calTime[1];
			else
				maxTime2 = y;
			x = minTime2 + RandomNumber(seed) * (maxTime2 - minTime2);
			if (x > y)
				{
				temp = x;
				x = y;
				y = temp;
				}
			}
		else if (u->isCalibrated == NO && v->isCalibrated == YES)
			{
			if (v->calTime[0] < minTime1)
				minTime1 = v->calTime[0];
			maxTime1 = v->calTime[0] + v->calTime[1];
			y = minTime1 + RandomNumber(seed) * (maxTime1 - minTime1);
			if (u->isConstrained == YES)
				{
				forceAB = YES;
				minTime2 = minTime1;
				}
			maxTime2 = maxTime1;
			x = minTime2 + RandomNumber(seed) * (maxTime2 - minTime2);
			if (x > y)
				{
				temp = x;
				x = y;
				y = temp;
				}
			}
		else if (u->isCalibrated == YES && v->isCalibrated == YES)
			{
			forceAB = YES;
			minTime2 = minTime1;
			if (u->calTime[0] > minTime1)
				minTime1 = u->calTime[0];
			maxTime1 = u->calTime[0] + u->calTime[1];
			if (v->calTime[0] > minTime2)
				minTime2 = v->calTime[0];
			maxTime2 = v->calTime[0] + v->calTime[1];
			x = minTime1 + RandomNumber(seed) * (maxTime1 - minTime1);
			y = minTime2 + RandomNumber(seed) * (maxTime2 - minTime2);
			if (x > y)
				{
				temp = x;
				x = y;
				y = temp;
				}
			}		

		if (x > minTime1 && forceAB == NO)
			{
			/* topology not forced */
			ran = RandomNumber(seed);
			if (ran < 0.333)
				{
				u->left = a;
				u->right = c;
				a->anc = c->anc = u;
				if (v->left == u)
					v->right = b;
				else
					v->left = b;
				b->anc = v;
				topologyHasChanged = YES;
				}
			else if (ran >= 0.333 && ran < 0.666)
				{
				u->left = b;
				u->right = c;
				b->anc = c->anc = u;
				if (v->left == u)
					v->right = a;
				else
					v->left = a;
				a->anc = v;
				topologyHasChanged = YES;
				}
			u->nodeTime = x;
			v->nodeTime = y;
			}
		else
			{
			if (forceAB == NO)
				{
				/* topology forced to ac or bc */
				if ((dID[1] == 0 && dID[2] == 2) || (dID[1] == 2 && dID[2] == 0))
					{
					u->left = a;
					u->right = c;
					a->anc = c->anc = u;
					if (v->left == u)
						v->right = b;
					else
						v->left = b;
					b->anc = v;
					topologyHasChanged = YES;
					}
				else if ((dID[1] == 1 && dID[2] == 2) || (dID[1] == 2 && dID[2] == 1))
					{
					u->left = b;
					u->right = c;
					b->anc = c->anc = u;
					if (v->left == u)
						v->right = a;
					else
						v->left = a;
					a->anc = v;
					topologyHasChanged = YES;
					}
				}
			u->nodeTime = x;
			v->nodeTime = y;
			}
		if (forceAB == NO)
			{
			if (u->nodeTime < c->nodeTime && x < h[2])
				(*lnProposalRatio) += log(3.0);
			else if (u->nodeTime > c->nodeTime && x > h[2])
				(*lnProposalRatio) += log(1.0/3.0);
			}
		}
		
	/* set update flags to YES */
	p = u;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence */
	if (topologyHasChanged == YES)
		{
		i = j = 0;
		GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);
		}

	/* get branch lengths on tree */
	//printf ("m = %lf\n", treeHeight[whichChain*2+proposedState]);
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		p->length = 0.0;
		if (p->anc != NULL)
			if (p->anc->anc != NULL)
				p->length = (p->anc->nodeTime - p->nodeTime) * treeHeight[whichChain*2+proposedState];
		if (p->length < 0.0)
			{
			printf ("\n   ERROR: negative branch length\n");
			ShowNodes (root[whichChain*2+proposedState], 2, YES);
			return (ERROR);
			}
		if (p->length < BRLEN_EPSILON)
			p->length = BRLEN_EPSILON;
		}
		
#	if defined (DEBUG_LOCAL_TIME_CLOCK)
	printf ("After:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, YES);
#	endif

	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
			}
		}
	else if (!strcmp(brlenprModel, "birth-death"))
		{
		/* get root time */
		rootTime = root[whichChain*2+proposedState]->left->nodeTime;
					
		/* put node times into vector */
		j = 0;
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (p->left != NULL && p->right != NULL && p->anc != NULL)
				{
				nt[j] = p->nodeTime;
				j++;
				}
			}
			
		/* calculate probabilities of tree */
		lnNewBrlenPr = (numTaxa-2)*log(sR);
		for (i=0; i<numTaxa-2; i++)
			{
			lnNewBrlenPr += lnP1(nt[i], sR, eR, sF) - lnVt(rootTime, sR, eR, sF);
			}
			
		free (nt);
		}
		
	(*lnPriorRatio) = lnNewBrlenPr - lnOldBrlenPr;

	/* TEMP */
	//UpDateAllCls (proposedState, whichChain);

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
	gNodeMoves = 1;
#	endif

#	if defined (SMART_TI_PROBS)
	/* NOTE: This could be made better, but this function probably will go, so don't bother. */
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change topology using NNI */
int Move_ChangeNNI (int numTaxa, int proposedState, int whichChain, long int *seed)

{

	int			i, j;
	TreeNode	*p, *u, *v, *a, *b, *c;
		
	/* pick an internal branch that is not constrained */
	do
		{
		p = intNodeDownPassSeq[whichChain*2*numIntNodes + proposedState*numIntNodes + (int)(RandomNumber(seed)*numIntNodes)];
		} while (p->anc->anc == NULL || p->isConstrained == YES);
		
	/* set up area of rearrangement */
	u = p;
	v = u->anc;
	a = u->left;
	b = u->right;
	if (v->left == u)
		c = v->right;
	else
		c = v->left;
		
	/* change topology */
	if (RandomNumber(seed) < 0.5)
		{
		if (v->left == u)
			v->right = b;
		else
			v->left = b;
		u->left = a;
		u->right = c;
		a->anc = c->anc = u;
		b->anc = v;
		}
	else
		{
		if (v->left == u)
			v->right = a;
		else
			v->left = a;
		u->left = b;
		u->right = c;
		b->anc = c->anc = u;
		a->anc = v;
		}
		
	i = j = 0;
	GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);
	
	return (NO_ERROR);

}





int Move_ChangeNodeTime (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int				i, j, isRoot;
	double			minTime, maxTime, newT, oldT, tuning, lnNewBrlenPr, lnOldBrlenPr, *nt, rootTime, sR, eR, sF;
	TreeNode		*p, *q;
	
	(*lnPriorRatio) = 0.0;
	(*lnProposalRatio) = 0.0;

	/* pick an internal branch */
	do
		{
		p = intNodeDownPassSeq[whichChain*2*numIntNodes + proposedState*numIntNodes + (int)(RandomNumber(seed)*numIntNodes)];
		} while (p->anc->anc == NULL);
	isRoot = NO;
	if (p->anc->anc == NULL)
		isRoot = YES;
	oldT = p->nodeTime;
	
	/* get prior probability of beginning branch lengths */
	if (!strcmp(brlenprModel, "exponential"))
		{
		lnOldBrlenPr  = log(brlenprExp) - brlenprExp * (p->left->length);
		lnOldBrlenPr += log(brlenprExp) - brlenprExp * (p->right->length);
		lnOldBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
		}
	else if (!strcmp(brlenprModel, "birth-death"))
		{
		sR = spRate[whichChain*2 + proposedState];
		eR = exRate[whichChain*2 + proposedState];
		sF = samplingFraction;
		
		/* allocate memory */
		nt = (double *)malloc((size_t) (numTaxa-1) * sizeof(double));
		if (!nt)
			{
			printf ("\n   ERROR: Problem allocating nt\n");
			return (ERROR);
			}
			
		/* get root time */
		rootTime = root[whichChain*2+proposedState]->left->nodeTime;
					
		/* put node times into vector */
		j = 0;
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left != NULL && q->right != NULL && q->anc != NULL)
				{
				nt[j] = q->nodeTime;
				j++;
				}
			}
			
		/* calculate probabilities of tree */
		lnOldBrlenPr = (numTaxa-2)*log(sR);
		for (i=0; i<numTaxa-2; i++)
			{
			lnOldBrlenPr += lnP1(nt[i], sR, eR, sF) - lnVt(rootTime, sR, eR, sF);
			}
		}
		
	/* pick an upper and lower time for the node */
	if (p->left->nodeTime > p->right->nodeTime)
		minTime = p->left->nodeTime;
	else
		minTime = p->right->nodeTime;
	if (isRoot == NO)
		{
		maxTime = p->anc->nodeTime;
		}
	if (p->isCalibrated == YES)
		{
		if (p->calTime[0] > minTime)
			minTime = p->calTime[0];
		if (p->calTime[0] + p->calTime[1] < maxTime && isRoot == NO)
			maxTime = p->calTime[0] + p->calTime[1];
		}
		
	/* choose new node time */
	if (isRoot == NO)
		{
		newT = minTime + RandomNumber(seed) * (maxTime - minTime);
		p->nodeTime = newT;
		p->left->length  = (p->nodeTime - p->left->nodeTime) * treeHeight[whichChain*2+proposedState];
		p->right->length = (p->nodeTime - p->right->nodeTime) * treeHeight[whichChain*2+proposedState];
		p->length        = (p->anc->nodeTime - p->nodeTime) * treeHeight[whichChain*2+proposedState];
		}
	else
		{
		tuning = nodeTimeTuneProp;
		newT = minTime + (maxTime - minTime) * exp(tuning*(RandomNumber(seed)-0.5));
		p->nodeTime = newT;
		p->left->length  = (p->nodeTime - p->left->nodeTime) * treeHeight[whichChain*2+proposedState];
		p->right->length = (p->nodeTime - p->right->nodeTime) * treeHeight[whichChain*2+proposedState];
		(*lnProposalRatio) = log((newT-minTime) / (oldT - minTime));
		}
	
	/* get prior probability of ending branch lengths */
	if (!strcmp(brlenprModel, "exponential"))
		{
		lnNewBrlenPr  = log(brlenprExp) - brlenprExp * (p->left->length);
		lnNewBrlenPr += log(brlenprExp) - brlenprExp * (p->right->length);
		lnNewBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
		(*lnPriorRatio) = lnNewBrlenPr - lnOldBrlenPr;
		}
	else if (!strcmp(brlenprModel, "birth-death"))
		{
		/* get root time */
		rootTime = root[whichChain*2+proposedState]->left->nodeTime;
					
		/* put node times into vector */
		j = 0;
		for (i=0; i<numNodes; i++)
			{
			q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (q->left != NULL && q->right != NULL && q->anc != NULL)
				{
				nt[j] = q->nodeTime;
				j++;
				}
			}
			
		/* calculate probabilities of tree */
		lnNewBrlenPr = (numTaxa-2)*log(sR);
		for (i=0; i<numTaxa-2; i++)
			{
			lnNewBrlenPr += lnP1(nt[i], sR, eR, sF) - lnVt(rootTime, sR, eR, sF);
			}
		(*lnPriorRatio) = lnNewBrlenPr - lnOldBrlenPr;
		
		free (nt);
		}

	/* update conditional likelihoods */
	p->upDateCl = YES;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}
		
	/* TEMP */
	//UpDateAllCls (proposedState, whichChain);

#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);	/* NOTE: This could be made better, but this function probably will go, so don't bother. */
#	endif	
	
	return (NO_ERROR);

}





/* change omega */
int Move_ChangeOmega (int proposedState, int whichChain, long int *seed, double *lnPriorRatio)

{

	double		oldW, newW, ran, omegaSlide, minOmega, maxOmega;

	minOmega = chainMins[CHANGE_OMEGA];
	maxOmega = chainMaxs[CHANGE_OMEGA];
	omegaSlide = omegaWinProp;

	oldW = omega[whichChain*2 + proposedState];
	ran = (RandomNumber(seed) * omegaSlide) - (omegaSlide/2.0);
	newW = oldW + ran;
	if (newW < minOmega)
		newW = (minOmega - newW) + minOmega;
	if (newW > maxOmega)
		newW = maxOmega - (newW - maxOmega);
	omega[whichChain*2 + proposedState] = newW;
		
	/* set prior ratio */
	if (!strcmp(qmatprModel, "exponential"))
		(*lnPriorRatio) = (omegaprExp*oldW - omegaprExp*newW);
	else if (!strcmp(qmatprModel, "uniform"))
		(*lnPriorRatio) = 0.0;
		
	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change omega pi */
int Move_ChangeOmegaProbs (int proposedState, int whichChain, long int *seed, double *lnPriorRatio, double *lnProposalRatio)

{

	int			i;
	double		*dirichletParameters, *newPi, *oldPi, sum, alphaPi, priorPi, x, y;
	
	dirichletParameters = (double *)malloc((size_t) (3 * sizeof(double)));
	if (!dirichletParameters)
		goto error_exit;
	newPi = (double *)malloc((size_t) (3 * sizeof(double)));
	if (!newPi)
		goto error_exit;
	oldPi = (double *)malloc((size_t) (3 * sizeof(double)));
	if (!oldPi)
		goto error_exit;

	alphaPi = omegaAlphaProp;
	priorPi = 3.0;

	oldPi[0] = probPos[whichChain*2 + proposedState];
	oldPi[1] = probPur[whichChain*2 + proposedState];
	oldPi[2] = probNeu[whichChain*2 + proposedState];
	dirichletParameters[0] = oldPi[0] * alphaPi;
	dirichletParameters[1] = oldPi[1] * alphaPi;
	dirichletParameters[2] = oldPi[2] * alphaPi;

	DirichletRandomVariable (dirichletParameters, newPi, 3, seed);

	sum = 0.0;
	for (i=0; i<3; i++)
		{
		if (newPi[i] < 0.0001)
			newPi[i] = 0.0001;
		sum += newPi[i];
		}
	for (i=0; i<3; i++)
		newPi[i] = newPi[i] / sum;

	probPos[whichChain*2 + proposedState] = newPi[0];
	probPur[whichChain*2 + proposedState] = newPi[1];
	probNeu[whichChain*2 + proposedState] = newPi[2];

	/* get proposal ratio */
	sum = 0.0;
	for (i=0; i<3; i++)
		sum += newPi[i]*alphaPi;
	x = LnGamma(sum);
	for (i=0; i<3; i++)
		x -= LnGamma(newPi[i]*alphaPi);
	for (i=0; i<3; i++)
		x += (newPi[i]*alphaPi-1.0)*log(oldPi[i]);
	sum = 0.0;
	for (i=0; i<3; i++)
		sum += oldPi[i]*alphaPi;
	y = LnGamma(sum);
	for (i=0; i<3; i++)
		y -= LnGamma(oldPi[i]*alphaPi);
	for (i=0; i<3; i++)
		y += (oldPi[i]*alphaPi-1.0)*log(newPi[i]);
	(*lnProposalRatio) = x - y;

	/* get prior ratio */
	x = LnGamma(priorPi);
	for (i=0; i<3; i++)
		x -= LnGamma(0.33333*priorPi);
	for (i=0; i<3; i++)
		x += (0.33333*priorPi-1.0)*log(newPi[i]);
	y = LnGamma(priorPi);
	for (i=0; i<3; i++)
		y -= LnGamma(0.33333*priorPi);
	for (i=0; i<3; i++)
		y += (0.33333*priorPi-1.0)*log(oldPi[i]);
	(*lnPriorRatio) = x - y;
	
	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	if (!strcmp(codonModelType, "covny98"))
		UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	free (dirichletParameters);
	free (newPi);
	free (oldPi);

	return (NO_ERROR);
	
	error_exit:
		free (dirichletParameters);
		free (newPi);
		free (oldPi);
		return (ERROR);
	
}





/* change proportion of invariant sites */
int Move_ChangePropInv (int proposedState, int whichChain, long int *seed, double *lnPriorRatio)

{

	double		oldP, newP, ran, pSlide, minP, maxP;

	minP = 0.0;
	maxP = 1.0;
	pSlide = invSlideProp;
	
	oldP = invP[whichChain*2 + proposedState];
	ran = (RandomNumber(seed) * pSlide) - (pSlide/2.0);
	newP = oldP + ran;
	if (newP < minP)
		newP = (minP - newP) + minP;
	if (newP > maxP)
		newP = maxP - (newP - maxP);
	invP[whichChain*2 + proposedState] = newP;
	
	(*lnPriorRatio) = 0.0;

	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





int Move_ChangeTreeHeight (int proposedState, int whichChain, long int *seed, double *lnProposalRatio)

{

	double		tuning, oldM, newM;

	tuning = mTuneProp;
	oldM = treeHeight[whichChain*2+proposedState];
	newM = oldM * exp(tuning*(RandomNumber(seed)-0.5));
	treeHeight[whichChain*2+proposedState] = newM;
	(*lnProposalRatio) = log(newM / oldM);
	UpDateAllCls (proposedState, whichChain);
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change branch lengths and topology (potentially) using the growing worm mechanism (unrooted) */
int Move_SingleWorm (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int			i, j, n, numBackbone, numExtendable, numDanglies, whichAnchor, isDanglyUp;
	double		ran, oldM, newM, tuning, extensionProb, newPoint, sum, lnNewBrlenPr, lnOldBrlenPr;
	TreeNode	*p, *q, *r, *a, *aa, *b, *c, *d, **backbone, *extendable[4], **danglies, *anchors[2];


	lnNewBrlenPr = lnOldBrlenPr = 0.0;

	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
			}
		}

	extensionProb = extendPProp;
	tuning        = wormTuneProp;

	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		p->upDateCl = NO;
 		p->marked = NO;
#		if defined (TOPOLOGY_MOVE_STATS)
		p->flag = NO;
#		endif
		}
	
#	if defined (SHOW_MOVE_WORM)
	printf ("Before:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif

	(*lnProposalRatio) = 0.0;

	backbone = (TreeNode **)malloc((size_t) (numNodes) * sizeof(TreeNode *));
	if (!backbone)
		{
		printf ("Could not allocate backbone (%d)\n", sizeof(TreeNode *) * (numNodes));
		return (ERROR);
		}
	danglies = (TreeNode **)malloc((size_t) (numNodes) * sizeof(TreeNode *));
	if (!danglies)
		{
		printf ("Could not allocate danglies (%d)\n", sizeof(TreeNode *) * (numNodes));
		free (backbone);
		return (ERROR);
		}
	for (i=0; i<numIntNodes; i++)
		{
		backbone[i] = NULL;
		danglies[i] = NULL;
		}

	/* pick an internal node to start with */
	p = intNodeDownPassSeq[whichChain*2*numIntNodes + proposedState*numIntNodes + (int)(RandomNumber(seed)*numIntNodes)];

#	if defined (SHOW_MOVE_WORM)
	printf ("Starting node = %d\n", p->index);
#	endif

	backbone[0] = p;
	numBackbone = 1;
	numExtendable = 0;
	if (IsLeaf(p->anc) == NO)
		extendable[numExtendable++] = p->anc;
	if (IsLeaf(p->left) == NO)
		extendable[numExtendable++] = p->left;
	if (IsLeaf(p->right) == NO)
		extendable[numExtendable++] = p->right;
	backbone[0]->marked = YES;

#	if defined (SHOW_MOVE_WORM)
	printf (" %d -- ", numExtendable);
	for (i=0; i<numExtendable; i++)
		printf ("%d ", extendable[i]->index);
	printf ("\n");
#	endif	

	/* get backbone */
	while (RandomNumber(seed) < extensionProb && numExtendable >= 1)
		{
		p = extendable[(int)(RandomNumber(seed) * numExtendable)];
		backbone[numBackbone] = p;
		p->marked = YES;
		numBackbone++;
#		if defined (SHOW_MOVE_WORM)
		printf ("extended backbone to %d\n", p->index);
#		endif
		numExtendable = 0;
		for (i=0; i<numBackbone; i++)
			{
#			if defined (SHOW_MOVE_WORM)
			printf ("  at backbone %d (%d) %d%d%d\n", backbone[i]->index, NumAdjacentMarked (backbone[i]), backbone[i]->left->marked, backbone[i]->right->marked, backbone[i]->anc->marked);
#			endif
			if (NumAdjacentMarked (backbone[i]) == 1)
				{
				if (backbone[i]->anc->marked == NO && IsLeaf(backbone[i]->anc) == NO)
					extendable[numExtendable++] = backbone[i]->anc;
				if (backbone[i]->left->marked == NO && IsLeaf(backbone[i]->left) == NO)
					extendable[numExtendable++] = backbone[i]->left;
				if (backbone[i]->right->marked == NO && IsLeaf(backbone[i]->right) == NO)
					extendable[numExtendable++] = backbone[i]->right;
				}
			}
#		if defined (SHOW_MOVE_WORM)
		printf (" %d -- ", numExtendable);
		for (i=0; i<numExtendable; i++)
			printf ("%d ", extendable[i]->index);
		printf ("\n");
#		endif	
		}
		
	/* get anchors and danglies */
	numDanglies = 0;
	whichAnchor = 0;
	for (i=0; i<numBackbone; i++)
		{
		p = backbone[i];
		n = NumAdjacentMarked (p);
		if (n == 0)
			{
			ran = RandomNumber(seed);
			if (ran < 0.3333)
				{
				anchors[0] = p->left;
				anchors[1] = p->right;
				danglies[numDanglies++] = p->anc;
				}
			else if (ran >= 0.3333 && ran < 0.6666)
				{
				anchors[0] = p->anc;
				anchors[1] = p->right;
				danglies[numDanglies++] = p->left;
				}
			else
				{
				anchors[0] = p->left;
				anchors[1] = p->anc;
				danglies[numDanglies++] = p->right;
				}
			}
		else if (n == 1)
			{
			numExtendable = 0;
			if (p->anc->marked == NO)
				extendable[numExtendable++] = p->anc;
			if (p->left->marked == NO)
				extendable[numExtendable++] = p->left;
			if (p->right->marked == NO)
				extendable[numExtendable++] = p->right;
			if (RandomNumber(seed) < 0.5)
				{
				anchors[whichAnchor++] = extendable[0];
				danglies[numDanglies++] = extendable[1];
				}
			else
				{
				anchors[whichAnchor++] = extendable[1];
				danglies[numDanglies++] = extendable[0];
				}
			}
		else if (n == 2)
			{
			if (p->anc->marked == NO)
				danglies[numDanglies++] = p->anc;
			else if (p->left->marked == NO)
				danglies[numDanglies++] = p->left;
			else if (p->right->marked == NO)
				danglies[numDanglies++] = p->right;
			else
				{
				printf ("ERROR: Should have at least one dangly!\n");
				free (backbone);
				free (danglies);
				return (ERROR);
				}
			}
		else
			{
			printf ("ERROR: Too many marked neighbors!\n");
			free (backbone);
			free (danglies);
			return (ERROR);
			}
		}
		
	/* add the anchors to the backbone */
	backbone[numBackbone++] = anchors[0];
	backbone[numBackbone++] = anchors[1];

#	if defined (SHOW_MOVE_WORM)
	printf ("Backbone and danglies:\n");
	printf (" %d -- ", numBackbone);
	for (i=0; i<numBackbone; i++)
		printf ("%d ", backbone[i]->index);
	printf ("\n");
	printf (" %d -- ", numDanglies);
	for (i=0; i<numDanglies; i++)
		printf ("%d ", danglies[i]->index);
	printf ("\n");
#	endif	

	/* get path length */
	oldM = 0;
	for (i=0; i<numBackbone; i++)
		if (IsKink(backbone[i]) == NO)
			oldM += backbone[i]->length;	

#	if defined (SMART_TI_PROBS)
	for (i=0; i<numBackbone; i++)
		if (IsKink(backbone[i]) == NO)
			backbone[i]->upDateTi = YES;	
#	endif

	/* change path length */
	ran = RandomNumber(seed);
	newM = oldM * exp(tuning * (ran - 0.5));
	for (i=0; i<numBackbone; i++)
		if (IsKink(backbone[i]) == NO)
			backbone[i]->length *= (newM/oldM);

	/* calculate proposal ratio */
	(*lnProposalRatio) += 2.0 * (log(newM) - log(oldM));

	/* pick a dangly to detach */
	p = danglies[(int)(RandomNumber(seed)*numDanglies)];

	/* pick a new attachment point */
	newPoint = RandomNumber(seed) * newM;
	sum = 0.0;
	for (i=0; i<numBackbone; i++)
		{
		if (IsKink(backbone[i]) == NO)
			{
			sum += backbone[i]->length;
			if (sum > newPoint)
				r = backbone[i];
			}
		}

	/* see if chosen dangly is up or down with reference to the backbone */
	if (p->anc == NULL)
		isDanglyUp = NO;
	else
		{
		if (p->anc->marked == YES)
			isDanglyUp = YES;
		else
			isDanglyUp = NO;
		}

#	if defined (SHOW_MOVE_WORM)
	printf ("Dangly to detach = %d\n", p->index);
	printf ("New attachment pt = %d\n", r->index);
	printf ("isDanglyUp = %d\n", isDanglyUp);
#	endif
		
#	if defined (TOPOLOGY_MOVE_STATS)
	gNodeMoves = 0;
	if (isDanglyUp == YES)
		a = p->anc;
	else
		a = p;
	while (a->anc != NULL) 
		{
		a = a->anc;
		a->flag = YES;
		gNodeMoves++;
		}
	a = r;
	while (a->anc != NULL) 
		{
		if (a->anc->left == a)
			q = a->anc->right;
		else
			q = a->anc->left;
		a = a->anc;
		if (a->flag == NO && a != p)
			gNodeMoves++;
		else if (a->anc == NULL)	// root; q == NULL
			gNodeMoves--;
		else if (a->flag == YES && q->flag != YES)
			gNodeMoves--;
		}
#	endif
	
	/* adjust topology */
	if (isDanglyUp == YES)
		{
		/* dangly is up */
		a = p->anc;
		aa = a->anc;
		if (a->left == p)
			q = a->right;
		else
			q = a->left;
			
		if (aa->left == a)
			aa->left = q;
		else
			aa->right = q;
		q->anc = aa;
		q->length += a->length;
		a->anc = NULL;
#		if defined (SMART_TI_PROBS)
		q->upDateTi = YES;
#		endif

		aa = r->anc;
		if (aa->left == r)
			aa->left = a;
		else
			aa->right = a;
		a->anc = aa;
		r->anc = a;
		p->anc = a;
		a->left = r;
		a->right = p;
		ran = RandomNumber(seed) * r->length;
		a->length = r->length - ran;
		r->length = ran;
#		if defined (SMART_TI_PROBS)
		r->upDateTi = YES;
		a->upDateTi = YES;
#		endif
		}
	else
		{
		/* dangly is down */
		if (p->anc != NULL)
			{
			if (p->left->marked == YES && p->right->marked == NO)
				p = p->left;
			else if (p->left->marked == NO && p->right->marked == YES)
				p = p->right;
			else
				{
				printf ("ERROR: Problem determining dangly\n");
				free (backbone);
				free (danglies);
				return (ERROR);
				}
			}
		else
			{
			p = p->left;
			}
	 	for (i=0; i<numNodes; i++)
			{
	 		q = nodes + (whichChain*2*numNodes + proposedState*numNodes + i);
	 		q->flag = NO;
	 		}
	 	q = r;
	 	do
			{
			q->flag = YES;
			q = q->anc;
			} while (q->anc != NULL);

		while (p->left != r && p->right != r)
			{
			if (p->left->flag == YES && p->right->flag == NO)
				{
				a = p->left;
				c = p->right;
				}
			else if (p->left->flag == NO && p->right->flag == YES)
				{
				a = p->right;
				c = p->left;
				}
			else
				{
				printf ("ERROR: Problem shifting tree!\n");
				free (backbone);
				free (danglies);
				return (ERROR);
				}
			if (a->left == NULL || a->right == NULL)	
				{
				printf ("ERROR: Problem trying to shift subtree to nonexistent branch\n");
				free (backbone);
				free (danglies);
				return (ERROR);
				}
			if (a->left->flag == YES && a->right->flag == NO)
				{
				b = a->left;
				d = a->right;
				}
			else if (a->left->flag == NO && a->right->flag == YES)
				{
				b = a->right;
				d = a->left;
				}
			else
				{
				printf ("ERROR: Problem shifting tree!\n");
				ShowNodes (root[whichChain*2+proposedState], 2, NO);
				printf ("p = %d, a = %d r = %d c = %d \n", p->index, a->index, r->index, c->index);
				for (i=0; i<numNodes; i++)
					{
				 	q = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
					printf ("%4d %d\n", q->index, q->flag);
					}
				for (i=0; i<numBackbone; i++)
					printf ("%d ", backbone[i]->index);
				printf ("\n");
				free (backbone);
				free (danglies);
				return (ERROR);
				}
			p->left = a;
			p->right = b;
			a->left = c;
			a->right = d;
			a->anc = p;
			b->anc = p;
			c->anc = a;
			d->anc = a;
			c->length += a->length;
			b->length /= 2.0;
			a->length = b->length;
			ran = RandomNumber(seed) * (a->length + b->length);
			a->length = (a->length + b->length) - ran;
			b->length = ran;
			a->flag = NO;
#			if defined (SMART_TI_PROBS)
			c->upDateTi = YES;	
			b->upDateTi = YES;	
			a->upDateTi = YES;	
#			endif

			}
		}

	i = j = 0;
	GetDownPassSeq (root[whichChain*2+proposedState], proposedState, whichChain, numTaxa, &i, &j);
	
	/* check for very small branches */
	for (i=0; i<numNodes; i++)
		{
	 	p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (p->length < BRLEN_EPSILON)
			p->length = BRLEN_EPSILON;
		}
		
	/* mark branches to update */
	UpDateAllCls (proposedState, whichChain);

	free (backbone);
	free (danglies);

#	if defined (SHOW_MOVE_WORM)
	printf ("After:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif

	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
			}
		}
		
	(*lnPriorRatio) = lnNewBrlenPr - lnOldBrlenPr;

#	if defined (TOPOLOGY_MOVE_STATS)
	if (gNodeMoves > 0)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
#	endif

	return (NO_ERROR);
	
}





/* change switching rate for covarion model */
int Move_ChangeSwitchRate (int proposedState, int whichChain, long int *seed, double *lnPriorRatio)

{

	int			whichS;
	double		oldS, newS, ran, sSlide, minS, maxS, sum;

	/* There are two rates for the covarion model. One rate is from on -> off and the other from off ->on.
	   The first rate (on -> off) is 0 and the other is 1 in the vectors, below */
	   
	minS = chainMins[CHANGE_SWITCH_RATE];
	maxS = chainMaxs[CHANGE_SWITCH_RATE];
	sSlide = switchWinProp;

#	if 0
	if (RandomNumber(seed) < 0.5)
		whichS = 0;
	else
		whichS = 1;

	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES && !strcmp(codonModelType, "covny98"))
		whichS = 0;

	oldS = switchRate[whichChain*4 + proposedState*2 + whichS];
	ran = (RandomNumber(seed) * sSlide) - (sSlide/2.0);
	newS = oldS + ran;
	if (newS < minS)
		newS = (minS - newS) + minS;
	if (newS > maxS)
		newS = maxS - (newS - maxS);
	switchRate[whichChain*4 + proposedState*2 + whichS] = newS;
#	else
	whichS = 0;

	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES && !strcmp(codonModelType, "covny98"))
		whichS = 0;

	oldS = switchRate[whichChain*4 + proposedState*2 + whichS];
	ran = (RandomNumber(seed) * sSlide) - (sSlide/2.0);
	newS = oldS + ran;
	if (newS < minS)
		newS = (minS - newS) + minS;
	if (newS > maxS)
		newS = maxS - (newS - maxS);
	switchRate[whichChain*4 + proposedState*2 + whichS] = newS;

	whichS = 1;

	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES && !strcmp(codonModelType, "covny98"))
		{
		whichS = 0;
		}
	else
		{
		oldS = switchRate[whichChain*4 + proposedState*2 + whichS];
		ran = (RandomNumber(seed) * sSlide) - (sSlide/2.0);
		newS = oldS + ran;
		if (newS < minS)
			newS = (minS - newS) + minS;
		if (newS > maxS)
			newS = maxS - (newS - maxS);
		switchRate[whichChain*4 + proposedState*2 + whichS] = newS;
		}
#	endif
	
	/* set stationary frequencies of on and off */
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES && !strcmp(codonModelType, "covny98"))
		{
		if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES && !strcmp(codonModelType, "covny98"))
			switchRate[whichChain*4 + proposedState*2 + 1] = newS;
		}
	else
		{
		sum = switchRate[whichChain*4 + proposedState*2 + 0] + switchRate[whichChain*4 + proposedState*2 + 1];
		switchPi[whichChain*4 + proposedState*2 + 0] = switchRate[whichChain*4 + proposedState*2 + 1] / sum; /* stationary prob that it is on  */
		switchPi[whichChain*4 + proposedState*2 + 1] = switchRate[whichChain*4 + proposedState*2 + 0] / sum; /* stationary prob that it is off */
		}
		
	/* set switch prior ratio */
	(*lnPriorRatio) = 0.0;
	/* do this later */
		
	UpDateAllCls (proposedState, whichChain);
		
#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change branch lengths and topology using SPR (unrooted, unconstrained, uncalibrated) */
int Move_ChangeUnrootedWithSPR (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int			i, j, stopLoop, nNodesSubTree1;
	double		v1, v2, v1a, v1b, v2a, v2b;
	TreeNode	*p, *q, *a, *b, *c, *d, *subRoot1, *subRoot2, **subTree1DP;

#	if defined (DEBUG_SPR)
	printf ("Before:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif
	
	subTree1DP = (TreeNode **)malloc(sizeof(TreeNode *) * 2 * numTaxa);
	if (!subTree1DP)
		{
		printf ("\n   ERROR: Could not allocate subTree1DP\n");
		FreeMemory ();
		return (ERROR);
		}
		
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		p->upDateCl = NO;
		}

	/* pick a branch at random */
	stopLoop = NO;
	do
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + (int)(RandomNumber(seed)*numNodes)];
		stopLoop = YES;
		if (p->anc != NULL)
			{
			if (p->anc->anc == NULL)
				stopLoop = NO;
			}
		} while (stopLoop == NO);

#	if defined (TOPOLOGY_MOVE_STATS)
	gNodeMoves = 0;
	for (i=0; i<numNodes; i++) 
		{
		a = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		a->marked = NO;
		}
	a = p;
	if (a->anc != NULL) 
		{
		a = a->anc;
		while (a->anc!=NULL) 
			{
			a = a->anc;
			a->marked = YES;
			gNodeMoves++;
			}
		}
	else 
		{
		a = a->left;
		while (a->left!=NULL) 
			{
			a = a->left;
			a->marked = YES;
			gNodeMoves++;
			}
		}
#	endif
		
	/* now detach the chosen branch from the tree */
	if (p->anc == NULL)
		{
		q = p->left;
		v1 = q->left->length + q->right->length;
		v1a = q->left->length;
		v1b = q->right->length;
		/* now shift tree such that that tip is sister to everyone else */
		stopLoop = NO;
		while (stopLoop == NO)
			{
			q = p->left;
			a = q->left;
			b = q->right;
			a->upDateCl = YES;
#			if defined (TOPOLOGY_MOVE_STATS)
			a->marked = YES;
#			endif
			if (a->left != NULL && a->right != NULL)
				{
				c = a->left;
				d = a->right;
				q->left = c;
				q->right = a;
				c->anc = q;
				a->anc = q;
				a->left = d;
				a->right = b;
				d->anc = a;
				b->anc = a;
				b->length += a->length;
				c->length *= 0.5;
				a->length = c->length;
				}
			else
				{
				stopLoop = YES;
				}
			}
		/* now reroot tree at left-most tip and detach old root */
		p->left = q;
		subRoot1 = q->left;
		subRoot1->upDateCl = YES;
		a = q->right;
		a->anc = subRoot1;
		subRoot1->left = a;
		subRoot1->right = subRoot1->anc = NULL;
		a->length += subRoot1->length;
		subRoot1->length = 0.0;
		subRoot2 = q;
		subRoot2->left = p;
		p->anc = subRoot2;
		p->left = p->right = NULL;
		subRoot2->right = subRoot2->anc = NULL;
		subRoot2->upDateCl = p->upDateCl = YES;
		}
	else
		{
		q = p;
		while (q->anc != NULL)
			{
			q->upDateCl = YES;
			q = q->anc;
			q->upDateCl = YES;
			}
		v1 = p->length;
		v1a = p->anc->length;
		if (p->anc->left == p)
			v1b = p->anc->right->length;
		else
			v1b = p->anc->left->length;
		subRoot1 = root[whichChain*2 + proposedState];
		subRoot2 = p->anc;
		if (subRoot2->left == p)
			a = subRoot2->right;
		else
			a = subRoot2->left;
		b = subRoot2->anc;
		if (b->left == subRoot2)
			b->left = a;
		else
			b->right = a;
		a->anc = b;
		a->length += subRoot2->length;
		subRoot2->left = p;
		subRoot2->right = subRoot2->anc = NULL;
		subRoot2->length = 0.0;
		}

	/* We now have two subtrees. One is rooted at subRoot1. The other, which is the detached portion, is rooted
	   at subRoot2. We want to pick a branch at random on the tree rooted at subRoot1 and put subRoot2 on that
	   branch. */
	i = 0;
	GetTempDownPassSeq (subRoot1, &i, subTree1DP);
	nNodesSubTree1 = i;
	do
		{
		p = subTree1DP[(int)(RandomNumber(seed)*nNodesSubTree1)];
		} while (p->anc == NULL);
	v2 = p->length;
	q = p->anc;
	b = subRoot2->left;
	if (q->left == p)
		{
		q->left = subRoot2;
		subRoot2->left = p;
		p->anc = subRoot2;
		subRoot2->anc = q;
		subRoot2->right = b;
		}
	else
		{
		q->right = subRoot2;
		subRoot2->right = p;
		p->anc = subRoot2;
		subRoot2->anc = q;
		subRoot2->left = b;
		}
	v2a = v2 * RandomNumber(seed);
	v2b = v2 - v2a;
	subRoot2->length = v2a;
	p->length = v2b;
	q = p;
	q->upDateCl = YES;
	while (q->anc != NULL)
		{
		q->upDateCl = YES;
		q = q->anc;
		q->upDateCl = YES;
		}

	/* get down pass sequence if tree topology has changed */
	root[whichChain*2 + proposedState] = subRoot1;
	i = j = 0;
	GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);

	/* get proposal and prior ratios */
	(*lnProposalRatio) = log(v2) - log(v1);
	(*lnPriorRatio) = 0.0;
	if (!strcmp(brlenprModel, "exponential"))
		{
		(*lnPriorRatio) = (log(brlenprExp) - brlenprExp * (v1a)) + (log(brlenprExp) - brlenprExp * (v1b)) -
		                  (log(brlenprExp) - brlenprExp * (v2a)) - (log(brlenprExp) - brlenprExp * (v2b));
		}

	//UpDateAllCls (proposedState, whichChain);

#	if defined (DEBUG_SPR)
	printf ("After:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	a = subRoot2;
	while (a->anc!=NULL) {
		if (a->anc->left == a)
			b = a->anc->right;
		else
			b = a->anc->left;
		a = a->anc;
		if (a->marked == NO)
			gNodeMoves++;
		else if (a->anc == NULL)
			gNodeMoves--;
		else if (a->marked == YES && b->marked == NO)
			gNodeMoves--;
	}
	if (gNodeMoves > 0)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
#	endif

#	if defined (SMART_TI_PROBS)
	// TO DO: Figure out exactly which branches need their transition matrices updated.
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	free (subTree1DP);
	
	return (NO_ERROR);

}





int Move_ChangeBD (int proposedState, int whichChain, long int *seed)

{

	double		oldEx, newEx, oldSp, newSp, ran, rateSlide, minExRate, minSpRate, maxExRate, maxSpRate;

	rateSlide = bdWinProp;
	
	minExRate = chainMins[CHANGE_BD_PARAMS];
	maxExRate = chainMaxs[CHANGE_BD_PARAMS];
	oldEx = exRate[whichChain*2 + proposedState];
	ran = (RandomNumber(seed) * rateSlide) - (rateSlide/2.0);
	newEx = oldEx + ran;
	if (newEx < minExRate)
		newEx = (minExRate - newEx) + minExRate;
	if (newEx > maxExRate)
		newEx = maxExRate - (newEx - maxExRate);
	exRate[whichChain*2 + proposedState] = newEx;

	minSpRate = exRate[whichChain*2 + proposedState];
	maxSpRate = chainMaxs[CHANGE_BD_PARAMS];
	oldSp = spRate[whichChain*2 + proposedState];
	ran = (RandomNumber(seed) * rateSlide) - (rateSlide/2.0);
	newSp = oldSp + ran;
	if (newSp < minSpRate)
		newSp = (minSpRate - newSp) + minSpRate;
	if (newSp > maxSpRate)
		newSp = maxSpRate - (newSp - maxSpRate);
	spRate[whichChain*2 + proposedState] = newSp;
	
	return (NO_ERROR);
		
}





/* Change branch lengths and possibly topology using probabilistic TBR branch swapping. */
int Move_ChangeTBR (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int			i, j, reconLimit, nMarkedAbove, nMarkedBelow, whichBranch, nVisited, stopLoop, hasTopologyChanged;
	double		tempLength, newLength, tuning, mult, forwardP, backwardP, oldM, newM, lnNewBrlenPr, lnOldBrlenPr;
	TreeNode	*p, *q, *u, *a, *b0, *b1, *b11, *b10;

#	if defined (DEBUG_TBR)
	printf ("Before:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif
	
	/* Set paramters of move. */
	*lnProposalRatio = *lnPriorRatio = 0.0;
	reconLimit = (int)reconLimProp;
	tuning = wormTuneProp;
	mult = exp(tuning*(RandomNumber(seed)-0.5));
	forwardP = backwardP = 1.0;
	oldM = newM = 0.0;
	
	lnNewBrlenPr = lnOldBrlenPr = 0.0;
	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnOldBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
			}
		}

	/* Set flags for updating conditional likelihoods to NO (meaning don't update CL). */
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		p->upDateCl = NO;
		}

	/* Pick a branch at random. This is the branch that is "removed". */
	do
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + (int)(RandomNumber(seed)*numNodes)];
		} while (p->anc == NULL);
	q = p->anc;
	oldM += p->length;
	p->length *= mult;
	newM += p->length;
	
	/* Mark all branches with distance from removed branch (p). */
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		u->flag = -1;
		u->marked = NO;
		}	
	p->flag = 0;
	for (i=numNodes-1; i>=0; i--)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u != p && u != q && u->anc != NULL && u->flag == -1)
			{
			if (u->anc->flag >= 0)
				u->flag = u->anc->flag + 1;
			}
		}
		
	/* mark branches above p that are within reconnection limit of p */
	nMarkedAbove = 0;
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u != p && u->flag <= reconLimit && u->flag >= 0)
			{
			u->marked = YES;
			nMarkedAbove++;
			}
		}	
	if (p->left != NULL && p->right != NULL)
		{
		if (p->right->marked == YES)
			{
			p->right->marked = NO;
			nMarkedAbove--;
			}
		}
		
	/* now pick one of the branches above p to be the new point of attachment */
	if (nMarkedAbove > 0)
		{
		whichBranch = RandomNumber(seed) * nMarkedAbove;
		nVisited = 0;
		for (i=0; i<numNodes; i++)
			{
			u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (u->marked == YES)
				{
				if (whichBranch == nVisited)
					break;
				nVisited++;
				}
			}
		a = u;
		}
	else
		a = p;
		
	/* update proposal probabilities */
	if (nMarkedAbove > 0)
		forwardP *= (1.0 / (double)(nMarkedAbove));
	if (p->left != NULL && p->right != NULL)
		backwardP *= 1.0 / (p->left->length + p->right->length);
		
	/* rotate tree above p until a is just to the left or right of p */
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		u->marked = NO;
		}
	u = a;
	u->marked = YES;
	while (u != p && u->anc != NULL)
		{
		oldM += u->length;
		u->length *= mult;
		newM += u->length;
		u->marked = YES;
		u = u->anc;
		}
	if (a != p)                          /* update proposal */
		forwardP *= 1.0 / (a->length);   /* probabilities   */
	stopLoop = NO;
	hasTopologyChanged = NO;
#	if defined (TOPOLOGY_MOVE_STATS)
	gNodeMoves = 0;
#	endif
	while (stopLoop == NO)
		{
		if (p->left != NULL && p->right != NULL)
			{
			if (p == a)
				stopLoop = YES;
			else if (p->left == a || p->right == a)
				stopLoop = YES;
			else
				{
				if (p->left->marked == YES)
					{
					b1 = p->left;
					b0 = p->right;
					}
				else
					{
					b1 = p->right;
					b0 = p->left;
					}
				if (b1->left != NULL && b1->right != NULL)
					{
					if (b1->left->marked == YES && b1->right->marked == NO)
						{
						b11 = b1->left;
						b10 = b1->right;
						}
					else if (b1->left->marked == NO && b1->right->marked == YES)
						{
						b11 = b1->right;
						b10 = b1->left;
						}
					else
						{
						b11 = b1->left;
						b10 = b1->right;
						}
					}
				else
					stopLoop = YES;
				if (stopLoop == NO)
					{
					if (p->right == b1)
						{
						p->left = b1;
						p->right = b11;
						b1->anc = b11->anc = p;
						b1->left = b0;
						b1->right = b10;
						b0->anc = b10->anc = b1;
						b0->length += b1->length;
						tempLength = b11->length;
						newLength = RandomNumber(seed) * tempLength;
						b1->length = newLength;
						b11->length = tempLength - newLength;
						b1->marked = NO;
						}
					else
						{
						p->left = b11;
						p->right = b1;
						b1->anc = b11->anc = p;
						b1->left = b0;
						b1->right = b10;
						b0->anc = b10->anc = b1;
						b0->length += b1->length;
						tempLength = b11->length;
						newLength = RandomNumber(seed) * tempLength;
						b1->length = newLength;
						b11->length = tempLength - newLength;
						b1->marked = NO;
						}
					hasTopologyChanged = YES;
#					if defined (TOPOLOGY_MOVE_STATS)
					gNodeMoves++;
#					endif
					}
				}
			}
		else
			stopLoop = YES;
		}
		
#	if defined (DEBUG_TBR)
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		printf ("%4d %d %d (p=%d q=%d)\n", u->index, u->flag, u->marked, p->index, q->index);
		}		
	printf ("nMarkedAbove = %d, %d\n", nMarkedAbove, a->index);
	printf ("Middle:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
#	endif

	/* update downpass sequence, if the topology has changed */
	if (hasTopologyChanged == YES)
		{
		i = j = 0;
		GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);
		}

	/* mark all branches with distance from removed branch (q) */
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		u->flag = -1;
		u->marked = NO;
		}	
	q->flag = 0;
	u = q;
	while (u->anc != NULL)
		{
		u->anc->flag = u->flag + 1;
		u = u->anc;
		}
	for (i=numNodes-1; i>=0; i--)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u != p && u != q && u->anc != NULL && u->flag == -1 && u->anc->flag >= 0)
			{
			u->flag = u->anc->flag + 1;
			}
		}
		
	/* mark branches above q that are within reconnection limit of q */
	nMarkedBelow = 0;
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u != q && u->flag <= reconLimit && u->flag >= 0 && u->anc != NULL)
			{
			u->marked = YES;
			nMarkedBelow++;
			}
		}	

	/* now pick one of the branches marked around q to be the new point of attachment */
	if (nMarkedBelow > 0)
		{
		whichBranch = RandomNumber(seed) * nMarkedBelow;
		nVisited = 0;
		for (i=0; i<numNodes; i++)
			{
			u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			if (u->marked == YES)
				{
				if (whichBranch == nVisited)
					break;
				nVisited++;
				}
			}
		a = u;
		}
	else
		a = q;

	/* update proposal probabilities */
	if (nMarkedBelow > 0)
		forwardP *= (1.0 / (double)(nMarkedBelow));
	if (q->anc != NULL)
		{
		tempLength = q->length;
		if (q->left == p)
			tempLength += q->right->length;
		else
			tempLength += q->left->length;
		backwardP *= 1.0 / tempLength;
		}
	if (a != q)
		{
		forwardP *= 1.0 / (a->length*mult);
		}
		
	/* multiply branches on path between a and q by mult */
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		u->marked = NO;
		if (u == a || u == q)
			u->marked = YES;
		}		
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u->left != NULL && u->right != NULL)
			{
			if (u->left->marked == YES && u->right->marked == NO)
				u->marked = YES;
			else if (u->left->marked == NO && u->right->marked == YES)
				u->marked = YES;
			}
		if (u->marked == YES)
			{

#			if defined (TOPOLOGY_MOVE_STATS)
			if (u != q)
				gNodeMoves++;
#			endif

			oldM += u->length;
			u->length *= mult;
			newM += u->length;
			}
		}
				
	/* move q to new position at branch a */
	if (q->anc == NULL || nMarkedBelow == 0)
		{
		/* don't do anything, as q is at the root of the tree */
		}
	else 
		{
		if (q->left == p)
			b1 = q->right;
		else
			b1 = q->left;
		b0 = q->anc;
		
		if (b0->left == q)
			{
			b0->left = b1;
			b1->anc = b0;
			b1->length += q->length;
			q->length = 0.0;
			q->anc = NULL;
			}
		else if (b0->right != NULL)
			{
			if (b0->right == q)
				{
				b0->right = b1;
				b1->anc = b0;
				b1->length += q->length;
				q->length = 0.0;
				q->anc = NULL;
				}
			else
				{
				printf ("problems in tbr\n");
				}
			}
		if (a->anc == NULL)
			printf ("problem in tbr\n");
		else
			{
			b1 = a->anc;
			if (b1->left == a)
				b1->left = q;
			else
				b1->right = q;
			q->anc = b1;
			q->left = p;
			q->right = a;
			p->anc = a->anc = q;
			tempLength = a->length;
			newLength = tempLength * RandomNumber(seed);
			a->length = newLength;
			q->length = tempLength - newLength;
			}
		}
		
	/* update downpass sequence */
	i = j = 0;
	GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);
	
	/* update conditional likelihoods */	
	UpDateAllCls (proposedState, whichChain);
	
	/* update proposal probabilities */
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		u->flag = -1;
		u->marked = NO;
		}	
	p->flag = 0;
	for (i=numNodes-1; i>=0; i--)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u != p && u != q && u->anc != NULL && u->flag == -1)
			{
			if (u->anc->flag >= 0)
				u->flag = u->anc->flag + 1;
			}
		}
	nMarkedAbove = 0;
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u != p && u->flag <= reconLimit && u->flag >= 0)
			{
			u->marked = YES;
			nMarkedAbove++;
			}
		}	
	if (p->left != NULL && p->right != NULL)
		{
		if (p->right->marked == YES)
			{
			p->right->marked = NO;
			nMarkedAbove--;
			}
		}
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		u->flag = -1;
		u->marked = NO;
		}	
	q->flag = 0;
	u = q;
	while (u->anc != NULL)
		{
		u->anc->flag = u->flag + 1;
		u = u->anc;
		}
	for (i=numNodes-1; i>=0; i--)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u != p && u != q && u->anc != NULL && u->flag == -1 && u->anc->flag >= 0)
			{
			u->flag = u->anc->flag + 1;
			}
		}
	nMarkedBelow = 0;
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		if (u != q && u->flag <= reconLimit && u->flag >= 0 && u->anc != NULL)
			{
			u->marked = YES;
			nMarkedBelow++;
			}
		}	
	if (nMarkedAbove > 0)
		backwardP *= (1.0 / (double)nMarkedAbove);
	if (nMarkedBelow > 0)
		backwardP *= (1.0 / (double)nMarkedBelow);
	forwardP *= oldM;
	backwardP *= newM;
	
	*lnProposalRatio = log(backwardP) - log(forwardP);
	//printf ("%lf %lf \n", log(backwardP), log(forwardP));
		
#	if defined (DEBUG_TBR)
	for (i=0; i<numNodes; i++)
		{
		u = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
		printf ("%4d %d %d (p=%d q=%d)\n", u->index, u->flag, u->marked, p->index, q->index);
		}		
	printf ("nMarkedBelow = %d, %d\n", nMarkedBelow, a->index);
	printf ("End:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
	//exit (0);
#	endif

	if (!strcmp(brlenprModel, "exponential"))
		{
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[whichChain*2*numNodes + proposedState*numNodes + i];
			lnNewBrlenPr += log(brlenprExp) - brlenprExp * (p->length);
			}
		}
		
	(*lnPriorRatio) = lnNewBrlenPr - lnOldBrlenPr;

#	if defined (TOPOLOGY_MOVE_STATS)
	if (hasTopologyChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;
#	endif

#	if defined (SMART_TI_PROBS)
	// TO DO: Figure out exactly which branches need their transition matrices updated.
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);

}





/* change branch lengths and topology (potentially) using TBR (unrooted) */
int Move_ChangeFTBR (int numTaxa, int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)
{
	/* this move type picks a branch and two "danglies", modifies their length
	     independently according to the method of Larget & Simon (1999: MBE); it then
	     moves the danglies away from their original position one node at a time with
	     a probability determined by the extensionProb parameter

              when the danglies are moved, their direction is changed
	     this "reflection" is necessary to enable the back move

             As of 5 March 2001 06:00 the move type has been tested extensively
             on unrooted and unconstrained trees (replicase.nex and adh.nex) and gives
	     similar results to BAMBE's local
	     However, convergence in branch lengths may be slow unless it is combined
	     with a move that changes single branchlengths or the proportionality of
	     adjacent branches, like BAMBE's local
	     The move type should work also for rooted or constrained trees
*/	
	int			i, j, topologyHasChanged, nCrownNodes, nRootNodes, directionLeft, directionUp;
	int			allNodesPointer, intNodePointer, allNodesStop;
	double		m, x, y, tuning, maxV, extensionProb;
	TreeNode	*p, *a, *b, *c, *d, *u, *v;

	// these parameters should be possible to set by user
	extensionProb = tbrExtendPProp;	// extension probability
	tuning = tbrTuneProp; /* Larget & Simon's tuning parameter lambda */
	
	// max brlen
	maxV = chainMaxs[CHANGE_UNROOT_LOCAL];

	topologyHasChanged = NO;

	// set pointers
	allNodesPointer = whichChain*2*numNodes + proposedState*numNodes;
	intNodePointer = whichChain*2*numIntNodes + proposedState*numIntNodes;
	allNodesStop = allNodesPointer + numNodes;
	
	// unmark all nodes with respect to update
	for (i=allNodesPointer; i<allNodesStop; i++)
		{
		p = allNodesDownPassSeq[i];
		p->upDateCl = NO;
		}
		
#	if defined (DEBUG_FTBR)
	printf ("Before:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
	getchar();
#	endif
	
	/* pick an internal branch */
	do
		{
		p = intNodeDownPassSeq[intNodePointer + (int)(RandomNumber(seed)*numIntNodes)];
		} while (p->anc->anc == NULL);
		
	/* set up pointers for nodes around the picked branch */
	/* cut the tree into crown, root and attachment part */
	/* change the relevant lengths in the attachment part */
	/* the lengths of a and v are automatically contained in the */
	/* "attachment" part but the length of c has to be stored in x */
	v = p;
	u = p->anc;

	/* set up pointers for crown part */
	/* this also determines direction of move in crown part */
	if (RandomNumber(seed) < 0.5)
		{
		c = v->left;
		d = v->right;
		directionLeft = YES;
		}
	else
		{
		c = v->right;
		d = v->left;
		directionLeft = NO;
		}

	/* cut and reconnect crown part */
	c->anc = d;
	d->anc = c;
	
	/* record c length and adjust */
	m = c->length;
	x = c->length * exp(tuning * (RandomNumber(seed) - 0.5));		// save the modified dangling branch for later use
	if (x < BRLEN_EPSILON)
		x = BRLEN_EPSILON;
	if (x > maxV)
		x = maxV;

	/* calculate proposal and prior ratio based on length modification */
	(*lnProposalRatio) = (log(x) - log(m));
	if (!strcmp(brlenprModel, "exponential"))
		(*lnPriorRatio) += brlenprExp * m - brlenprExp * x;

	/* record v length and adjust */
	m = v->length;
	v->length *= exp(tuning * (RandomNumber(seed) - 0.5));
	if (v->length < BRLEN_EPSILON)
		v->length = BRLEN_EPSILON;
	if (v->length > maxV)
		v->length = maxV;

	/* adjust proposal and prior ratio based on length modification */
	(*lnProposalRatio) += (log(v->length) - log(m));
	if (!strcmp(brlenprModel, "exponential"))
		(*lnPriorRatio) += brlenprExp * m - brlenprExp * v->length;

	/* mark nodes in root part */
	/* also determines direction of move in root part */
	if (RandomNumber(seed) < 0.5)
		{
		if (u->left == v)
			a = u->right;
		else
			a = u->left;
		b = u->anc;
		directionUp = YES;
		}
	else
		{
		if (u->left == v)
			b = u->right;
		else
			b = u->left;
		a = u->anc;
		directionUp = NO;
		}

	/* cut root part*/
	/* store branch to be modified in u->length */
	if (directionUp == NO) 
		{
		b->anc = a;
		if (a->left == u)
			a->left = b;
		else
			a->right = b;
		}
	else 
		{
		a->anc = b;
		if (b->left == u)
			b->left = a;
		else
			b->right = a;
		y = a->length;
		a->length = u->length;
		u->length = y;
		}
	/* adjust length of branch to be modified */
	/* if it is not the root branch of a rooted tree */
	if (!(treeModel == ROOTED && u->anc->anc == NULL)) 
		{
		m = u->length;
		u->length *= exp(tuning * (RandomNumber(seed) - 0.5));
		if (u->length < BRLEN_EPSILON)
			u->length = BRLEN_EPSILON;
		if (u->length > maxV)
			u->length = maxV;
		/* adjust proposal and prior ratio based on length modification */
		(*lnProposalRatio) += (log(u->length) - log(m));
		if (!strcmp(brlenprModel, "exponential"))
			(*lnPriorRatio) += brlenprExp * m - brlenprExp * u->length;
		}
		
	// adjust proposal ratio for backward move in root subtree
	// if starting from interior, unconstrained branch
	// double test needed to capture the case of no move
	if (directionUp == NO && b->left!=NULL && b->isConstrained == NO &&
		a->anc!=NULL && a->isConstrained == NO)
		(*lnProposalRatio) += log(1-extensionProb);
	if (directionUp == YES && a->left!=NULL && a->isConstrained == NO &&
		b->anc!=NULL && b->isConstrained == NO)
		(*lnProposalRatio) += log(1-extensionProb);

	// adjust proposal ratio for backward move in crown subtree
	// if starting from interior, unconstrained branch
	// double test is needed to capture the case of no move
	if (c->left!=NULL && c->isConstrained == NO &&
		d->left!=NULL && d->isConstrained == NO)
		(*lnProposalRatio) += log(1-extensionProb);

	// move around in root subtree
	nRootNodes = 0;
	if (u->isConstrained == NO) 
		{
		for (; RandomNumber(seed)<extensionProb; nRootNodes++) 
			{
			if (directionUp == YES) 
				{	//going up tree
				if (a->left == NULL || a->isConstrained == YES)
					break;		/* can't go further */
				topologyHasChanged = YES;
				b = a;
				if (RandomNumber(seed)<0.5)
					a = a->left;
				else
					a = a->right;
				}
			else 
				{	// going down tree
				if (a->anc == NULL || a->isConstrained == YES)
					break;		/*can't go further */
				topologyHasChanged = YES;
				if (RandomNumber(seed)<0.5) 
					{
					directionUp = YES; // switch direction
					// find sister of a
					if (a->left == b) 
						{
						b = a;
						a = a->right;
						}
					else 
						{  
						b = a;
						a = a->left;
						}
					// as long as we are moving upwards
					// the cond likes to update will be
					// flagged by the last pass from u to the root
					}	
				else 
					{	// continue down
					b = a;
					a = a->anc;
					b->upDateCl = YES;
					}
				}
			}
		}
		
	// adjust proposal ratio for forward move if stop branch is interior & unconstrained
	// test of both ends makes sure that no adjustment is made if no move was made
	if (directionUp == YES) 
		{
		if (a->left != NULL && a->isConstrained == NO &&
			b->anc != NULL && b->isConstrained == NO)
			(*lnProposalRatio) -= log(1-extensionProb);
		}
	else 
		{
		if (a->anc != NULL && a->isConstrained == NO &&
			b->left != NULL && b->isConstrained == NO)
			(*lnProposalRatio) -= log(1-extensionProb);
		}

	// move around in crown subtree
	nCrownNodes = 0;
	if (v->isConstrained == NO) 
		{
		for (; RandomNumber(seed)<extensionProb; nCrownNodes++) 
			{
			if (c->left == NULL || c->isConstrained == YES)
				break;	/* can't go further */
			topologyHasChanged = YES;
			if (RandomNumber(seed)<0.5) 
				{
				// rotate c anticlockwise - prepare pointers for move left
				c->anc = c->left;  // the root will be in the direction we are heading
				c->left = c->right;
				c->right = d;
				}
			else 
				{
				// rotate c clockwise - prepare pointers for move right
				c->anc = c->right;	// the root will be in the direction we are heading
				c->right = c->left;
				c->left = d;  
				}
			/* OK - let's move!; c->anc points in the right direction
			     don't forget to move the branch lengths as well */
			d = c;
			c = c->anc;
			d->length = c->length;
			d->upDateCl = YES;
			}
		}

	// adjust proposal ratio for forward move if stop branch is interior & unconstrained
	// double test makes sure that no adjustment is made if no move was made
	if (c->left != NULL && c->isConstrained == NO && 
		d->left != NULL && d->isConstrained == NO)
		(*lnProposalRatio) -= log(1-extensionProb);

	// combine the subtrees
	c->anc = v;
	d->anc = v;
	if (directionLeft == YES) 
		{
		v->left = c;
		v->right = d;
		}
	else 
		{
		v->left = d;
		v->right = c;
		}

	// the dangling branch is inserted in reverted position
	// such that the back move will be possible
	// if we have moved around in crown subtree
	// otherwise it is left in its original position
	if (nCrownNodes > 0)
		d->length = x;
	else
		c->length = x;

	if (directionUp == YES) 
		{
		u->anc = b;
		if (u->left == v)
			u->right = a;
		else 
			u->left = a;
		a->anc = u;
		if (b->left == a)
			b->left = u;
		else
			b->right = u;
		/* the dangling branch is contained in u->length
		     and will automatically be inserted in the right position
		     to enable the back move regardless of whether it was
		     initially directed upwards or downwards
		     BUT if we haven't moved in root subtree, it is advantageous (necessary
		     for rooted trees) to avoid switching branches, which occurs otherwise */
		// if directionUp == YES
		if (nRootNodes == 0) 
			{
			x = u->length;
			u->length = a->length;
			a->length = x;
			}
		}
	else 
		{
		u->anc = a;
		if (u->left == v)
			u->right = b;
		else 
			u->left = b;
		b->anc = u;
		if (a->left == b)
			a->left = u;
		else
			a->right = u;
		/* the modified branch contained in u->length will have
		 to be moved to b->length to enable back move
		 BUT if we haven't moved, it is better to keep it in place
		 (necessary for rooted trees) */
		if (nRootNodes > 0) 
			{
			x = u->length;
			u->length = b->length;
			b->length = x;
			}
		}
		
	/* set flags for update of cond likes from v and down to root */
	p = v;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* get down pass sequence if tree topology has changed */
	if (topologyHasChanged == YES)
		{
		i = j = 0;
		GetDownPassSeq (root[whichChain*2 + proposedState], proposedState, whichChain, numTaxa, &i, &j);
		}

#	if defined (DEBUG_FTBR)
	printf ("After:\n");
	ShowNodes (root[whichChain*2+proposedState], 2, NO);
	getchar();
	printf ("Proposal ratio: %f\n",(*lnProposalRatio));
	printf ("v: %d  u: %d  c: %d  d: %d  a: %d  b: %d\n",v->index, u->index, 
		c->index, d->index, a->index, b->index);
	printf ("No. nodes moved in root subtree: %d\n",nRootNodes);
	printf ("No. nodes moved in crown subtree: %d\n",nCrownNodes);
	printf ("Has topology changed? %d\n",topologyHasChanged);
	getchar();
#	endif

#	if defined (TOPOLOGY_MOVE_STATS)
	if (topologyHasChanged == YES)
		gTopologyHasChanged = YES;
	else
		gTopologyHasChanged = NO;

	gNodeMoves = nCrownNodes + nRootNodes;
#	endif

#	if defined (SMART_TI_PROBS)
	// TO DO: Figure out exactly which branches need their transition matrices updated.
	UpDateAllTIs (proposedState, whichChain);
#	endif	
	
	return (NO_ERROR);
	
}




/* change one branch length */
int Move_ChangeBrLen (int proposedState, int whichChain, long int *seed, double *lnProposalRatio, double *lnPriorRatio)

{

	int			i, allNodesPointer, allNodesStop;
	double		lenFactor, tuning, maxV, m;
	TreeNode	*p;

	/* this parameter should be possible to set by user
	 For the dataset adh.nex, multiplying Larget & Simon's suggested
	 tuning parameter (0.19) with 10.0 results in acceptance
	 probability around 50%, which is, arguably, optimal */
	tuning = blTuneProp; /* Larget & Simon's tuning parameter lambda */

	// max brlen
	maxV = chainMaxs[CHANGE_UNROOT_LOCAL];

	// set up pointers
	allNodesPointer = whichChain*2*numNodes + proposedState*numNodes;
	allNodesStop = allNodesPointer + numNodes;

	// unmark all nodes with respect to update
	for (i=allNodesPointer; i<allNodesStop; i++)
		{
		p = allNodesDownPassSeq[i];
		p->upDateCl = NO;
		}

	/* pick a branch */
	do
		{
		p = allNodesDownPassSeq[allNodesPointer + (int)(RandomNumber(seed)*numNodes)];
		} while (p->anc == NULL || (treeModel == ROOTED && p->anc->anc == NULL));

	/* determine length multiplication factor */
	lenFactor = exp(tuning * (RandomNumber(seed) - 0.5));

	m = p->length;
	p->length *= lenFactor;

	// check new length of p
	if (p->length < BRLEN_EPSILON)
		p->length = BRLEN_EPSILON;
	if (p->length > maxV)
		p->length = maxV;

	/* set flags for update of cond likes from p->anc and down to root */
	p->upDateCl = YES;
	while (p->anc != NULL)
		{
		p->upDateCl = YES;
		p = p->anc;
		}

	/* set flags for update of transition probabilities at p */
#	if defined (SMART_TI_PROBS)
	p->upDateTi = YES;
#	endif

	/* calculate proposal ratio */
	(*lnProposalRatio) = (log(m * lenFactor) - log(m));

	/* calculate prior ratio if exponential prior on branch lengths */
	/* if birth-death prior we should not be in this move type */
	if (!strcmp(brlenprModel, "exponential"))
		(*lnPriorRatio) = brlenprExp * m - brlenprExp * m * lenFactor;
	else
		(*lnPriorRatio) = 0.0;

#	if defined (SMART_TI_PROBS)
	UpDateAllTIs (proposedState, whichChain);
#	endif	

	return (NO_ERROR);
}



/*------------------------------------------------------------
|  OpenFile: open a file, print #NEXUS if a new NEXUS file,
|       print appropriate error message if operation failed
\-----------------------------------------------------------*/
FILE *OpenFile (char *filename, int isNexus)

{

	FILE *fp;

	if ((fp = fopen (filename, "r")) == NULL)
		{
		fp = fopen (filename, "w");
		if (fp != NULL)
			{
			printf ("      Creating output file %s\n", filename);
#if defined (MORPH)
			if (isNexus == YES)
				fprintf (fp, "#NEXUS\n");
			}
#endif
		}
	else
		{
		fclose (fp);
		if (autoclose == YES)
			{
			printf ("      Appending information to file %s\n", filename);
			fp = fopen (filename, "a+"); 
			}
		else
			{
			printf ("\n      File \"%s\" already exists.\n      Overwrite? (yes/no): ", filename);
			if (YesNo() == YES)
				{
				printf ("      Overwriting information to file %s\n", filename);
				fp = fopen (filename, "w+"); 
				}
			else
				{
				printf ("      Appending information to file %s\n", filename);
				fp = fopen (filename, "a+"); 
				}
			}
		}

	if (fp == NULL)
		{
		printf ("\n   ERROR: Could not open file (%s).\n", filename);
		}

	return fp;

}





int NumAdjacentMarked (TreeNode *p)

{

	int		i;
	
	i = 0;
	if (p->left != NULL)
		{
		if (p->left->marked == YES)
			i++;
		}
	if (p->right != NULL)
		{
		if (p->right->marked == YES)
			i++;
		}
	if (p->anc != NULL)
		{
		if (p->anc->marked == YES)
			i++;
		}
		
	return (i);
	
}





double ParsimonyLength (int whichState, int whichChain, int numChars)

{

	register int	c;
	int				n, intNodeOffset, oneMatSize;
	unsigned int	*cl, *clL, *clR, *clA, x, y, z;
	double			pLength;
	TreeNode		*p;
	
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;
	oneMatSize = numNodes * numChars;

	pLength = 0.0;
	for (n=0; n<numIntNodes; n++)
		{
		p = intNodeDownPassSeq[intNodeOffset + n];
		//printf ("visiting node %d\n", p->index);
		cl = &stateSet[whichChain*oneMatSize + (p->index)*numChars];
		if (p->anc->anc == NULL)
			{
			clL = &stateSet[whichChain*oneMatSize + (p->left->index)*numChars];
			clR = &stateSet[whichChain*oneMatSize + (p->right->index)*numChars];
			clA = &stateSet[whichChain*oneMatSize + (p->anc->index)*numChars];
			for (c=0; c<numChars; c++)
				{
				x = clL[c];
				y = clR[c];
				z = x & y;
				if (z == 0)
					{
					cl[c] = x | y;
					pLength += numSitesOfPat[c];
					}
				else
					cl[c] = z;
					
				x = cl[c];
				y = clA[c];
				z = x & y;
				if (z == 0)
					pLength += numSitesOfPat[c];
				}
			}
		else
			{
			clL = &stateSet[whichChain*oneMatSize + (p->left->index)*numChars];
			clR = &stateSet[whichChain*oneMatSize + (p->right->index)*numChars];
			for (c=0; c<numChars; c++)
				{
				x = clL[c];
				y = clR[c];
				z = x & y;
				if (z == 0)
					{
					cl[c] = x | y;
					pLength += numSitesOfPat[c];
					}
				else
					cl[c] = z;
				}
			}
		}
		
	return (pLength);
	
}





int PerturnStartingTree (int numTaxa, long int *seed)

{

	int		i, n, chain, move;
	double	sum, tempPropProbs[NUM_PROPOSAL_TYPES] ,cumProposalProbs[NUM_PROPOSAL_TYPES], ran, lnPriorRatio, lnProposalRatio;
	
	/* set up proposal probabilities */
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		{
		tempPropProbs[i] = relProposalProbs[i];
		if (i != CHANGE_UNROOT_LOCAL && i != CHANGE_CLOCK_LOCAL && i != CHANGE_CLOCK_TIME_LOCAL)
			tempPropProbs[i] = 0.0;
		}
	sum = 0.0;
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		sum += tempPropProbs[i];
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		tempPropProbs[i] /= sum;
	cumProposalProbs[0] = tempPropProbs[0];
	for (i=1; i<NUM_PROPOSAL_TYPES; i++)
		cumProposalProbs[i] = cumProposalProbs[i-1] + tempPropProbs[i];
		
	for (n=0; n<nPerturbations; n++)
		{
		for (chain=0; chain<numChains; chain++)
			{
			/* propose move */
			ran = RandomNumber(seed);
			if (ran >= 0.0 && ran <= cumProposalProbs[0])
				move = CHANGE_QMAT;
			else if (ran >cumProposalProbs[0] && ran <= cumProposalProbs[1])
				move = CHANGE_BASEFREQS;
			else if (ran >cumProposalProbs[1] && ran <= cumProposalProbs[2])
				move = CHANGE_GAMMA_SHAPE;
			else if (ran >cumProposalProbs[2] && ran <= cumProposalProbs[3])
				move = CHANGE_SITE_RATES;
			else if (ran >cumProposalProbs[3] && ran <= cumProposalProbs[4])
				move = CHANGE_UNROOT_LOCAL;
			else if (ran >cumProposalProbs[4] && ran <= cumProposalProbs[5])
				move = CHANGE_CLOCK_LOCAL;
			else if (ran >cumProposalProbs[5] && ran <= cumProposalProbs[6])
				move = CHANGE_CLOCK_TIME_LOCAL;
			else if (ran >cumProposalProbs[6] && ran <= cumProposalProbs[7])
				move = CHANGE_TREE_HEIGHT;
			else if (ran >cumProposalProbs[7] && ran <= cumProposalProbs[8])
				move = CHANGE_WORM;
			else if (ran >cumProposalProbs[8] && ran <= cumProposalProbs[9])
				move = CHANGE_NODE_TIME;
			else if (ran >cumProposalProbs[9] && ran <= cumProposalProbs[10])
				move = CHANGE_BD_PARAMS;

			/* make perturbation */
			lnPriorRatio = lnProposalRatio = 0.0;
			if (move == CHANGE_UNROOT_LOCAL)
				{
				/* change topology of unrooted tree or rooted and unconstrained tree using LOCAL */
				if (Move_ChangeUnrootedWithLocal (numTaxa, 0, chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					return (ERROR);
				}
			else if (move == CHANGE_CLOCK_LOCAL)
				{
				/* change topology of rooted tree with clock constraint using LOCAL */
				if (Move_ChangeClockWithLocal (numTaxa, 0, chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					return (ERROR);
				}
			else if (move == CHANGE_CLOCK_TIME_LOCAL)
				{
				/* change topology and times of rooted tree with clock constraint using LOCAL (divergence time estimation) */
				if (Move_ChangeTimeClockWithLocal (numTaxa, 0, chain, seed, &lnProposalRatio, &lnPriorRatio) == ERROR)
					return (ERROR);
				}
			else
				{
				printf ("   ERROR: Unknown perturbation\n");
				return (ERROR);
				}
			
			/* copy information */
			CopyTree (0, 1, chain);
			
			}
		}

#	if 0
	for (n=0; n<numChains; n++)
		{
		printf ("\n         Starting tree for chain %d:\n", n+1);
		if (treeModel == ROOTED)
			{
			//ShowNodes (root[n*2+0], 2, YES);
			ShowStartTree (root[n*2+0], numTaxa, YES);
			}
		else
			{
			//ShowNodes (root[n*2+0], 2, NO);
			ShowStartTree (root[n*2+0], numTaxa, NO);
			}
		}
#	endif

	return (NO_ERROR);

}





/*--------------------------------------------------------------
| PrepareOutputFiles: open output files, write headers
|    return ERROR and close all files if error encountered
---------------------------------------------------------------*/
int PrepareOutputFiles (void)

{

	int				i, j, k, isFirst;
	char			pFilename[100], bpFilename[100], tFilename[100];
	TreeNode		*p;
	FILE			*fp1, *fp2;
	
	/* prepare output file names */
	strcpy (pFilename, outFile);
	strcpy (bpFilename, outFile);
	strcpy (tFilename, outFile);
	strcat (pFilename, ".p");
	strcat (bpFilename, ".bp");
	strcat (tFilename, ".t");

	/* reset output file pointers */
	pFile = bpFile = tFile = NULL;
	
	/* open files */
	if ((pFile = OpenFile(pFilename, NO))==NULL)
		goto error_exit;

	if ((bpFile = OpenFile(bpFilename, YES))==NULL)
		goto error_exit;

	if ((tFile = OpenFile(tFilename, YES))==NULL)
		goto error_exit;

	fp1 = pFile;
	fp2 = bpFile;

	/* print headers to pFile and bpFile */
	fprintf (fp2, "begin bayesparams;\n");
	fprintf (fp1, "Gen\tlnL\t");
	fprintf (fp1, "TL\t");
	fprintf (fp2, "   header Gen, lnL");
	fprintf (fp2, ", TL");
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == NO)
		{
		if (nst == 2)
			{
			fprintf (fp1, "kappa\t");
			fprintf (fp2, ", kappa");
			}
		else if (nst == 6)
			{
			fprintf (fp1, "R(GT)\tR(CT)\tR(CG)\tR(AT)\tR(AG)\tR(AC)\t");
			fprintf (fp2, ", rGT, rCT, rCG, rAT, rAG, rAC");
			}
		else if (nst == 12)
			{
			fprintf (fp1, "R(AC)\tR(AG)\tR(AT)\tR(CG)\tR(CT)\tR(GT)\tR(CA)\tR(GA)\tR(TA)\tR(GC)\tR(TC)\tR(TG)\t");
			fprintf (fp2, ", rAC, rAG, rAT, rCG, rCT, rGT, rCA, rGA, rTA, rGC, rTC, rTG");
			}
		if (dataType == DNA)
			{
			if (useCovarion == YES && !strcmp(covarionModelType, "gcswitch"))
				{
				fprintf (fp1, "pi(A1)\tpi(C1)\tpi(G1)\tpi(T1)\tpi(A2)\tpi(C2)\tpi(G2)\tpi(T2)\t");
				fprintf (fp2, ", piA1, piC1, piG1, piT1, piA2, piC2, piG2, piT2");
				}
			else
				{
				fprintf (fp1, "pi(A)\tpi(C)\tpi(G)\tpi(T)\t");
				fprintf (fp2, ", piA, piC, piG, piT");
				}
			}
		else if (dataType == RNA)
			{
			if (useCovarion == YES && !strcmp(covarionModelType, "gcswitch"))
				{
				fprintf (fp1, "pi(A1)\tpi(C1)\tpi(G1)\tpi(U1)\tpi(A2)\tpi(C2)\tpi(G2)\tpi(U2)\t");
				fprintf (fp2, ", piA1, piC1, piG1, piU1, piA2, piC2, piG2, piU2");
				}
			else
				{
				fprintf (fp1, "pi(A)\tpi(C)\tpi(G)\tpi(U)\t");
				fprintf (fp2, ", piA, piC, piG, piU");
				}
			}
		if (useCovarion == YES)
			{
			if (!strcmp(covarionModelType, "gcswitch"))
				{
				fprintf (fp1, "gc1gc2\tgc2gc1\t");
				fprintf (fp2, ", gc1gc2, gc2gc1");
				}
			else if (!strcmp(covarionModelType, "ts98"))
				{
				fprintf (fp1, "onOff\toffOn\t");
				fprintf (fp2, ", onOff, offOn");
				}
			}
		}
	else if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		fprintf (fp1, "kappa\t");
		fprintf (fp2, ", kappa");
		fprintf (fp1, "nonsyn_syn\t");
		fprintf (fp2, ", nonsyn_syn");
		if (!strcmp(codonModelType, "ny98"))
			{
			fprintf (fp1, "pPur\t");
			fprintf (fp2, ", pPur");
			fprintf (fp1, "pNeu\t");
			fprintf (fp2, ", pNeu");
			fprintf (fp1, "pPos\t");
			fprintf (fp2, ", pPos");
			}
		else if (!strcmp(codonModelType, "ac1ny98"))
			{
			fprintf (fp1, "pPur\t");
			fprintf (fp2, ", pPur");
			fprintf (fp1, "pNeu\t");
			fprintf (fp2, ", pNeu");
			fprintf (fp1, "pPos\t");
			fprintf (fp2, ", pPos");
			fprintf (fp1, "rho\t");
			fprintf (fp2, ", rho");
			}
		else if (!strcmp(codonModelType, "ac2ny98"))
			{
			fprintf (fp1, "pPur\t");
			fprintf (fp2, ", pPur");
			fprintf (fp1, "pNeu\t");
			fprintf (fp2, ", pNeu");
			fprintf (fp1, "pPos\t");
			fprintf (fp2, ", pPos");
			fprintf (fp1, "rho1\t");
			fprintf (fp2, ", rho1");
			fprintf (fp1, "rho2\t");
			fprintf (fp2, ", rho2");
			fprintf (fp1, "rho3\t");
			fprintf (fp2, ", rho3");
			}
		else if (!strcmp(codonModelType, "covny98"))
			{
			fprintf (fp1, "pPur\t");
			fprintf (fp2, ", pPur");
			fprintf (fp1, "pNeu\t");
			fprintf (fp2, ", pNeu");
			fprintf (fp1, "pPos\t");
			fprintf (fp2, ", pPos");
			fprintf (fp1, "sr\t");
			fprintf (fp2, ", sr");
			}
		for (i=0; i<nStates; i++)
			{
			fprintf (fp1, "pi(%d)\t", i+1);
			fprintf (fp2, ", pi%d", i+1);
			}
		}
	else if (dataType == PROTEIN && (aaModelType == EQUALIN || aaModelType == GTR))
		{
		fprintf (fp1, "pi(A)\tpi(R)\tpi(N)\tpi(D)\tpi(C)\tpi(Q)\tpi(E)\tpi(G)\tpi(H)\tpi(I)\tpi(L)\tpi(K)\tpi(M)\tpi(F)\tpi(P)\tpi(S)\tpi(T)\tpi(W)\tpi(Y)\tpi(V)\t");
		fprintf (fp2, ", piA, piR, piN, piD, piC, piQ, piE, piG, piH, piI, piL, piK, piM, piF, piP, piS, piT, piW, piY, piV");
		if (useCovarion == YES)
			{
			fprintf (fp1, "onOff\toffOn\t");
			fprintf (fp2, ", onOff, offOn");
			}
		}
	else if (dataType == RESTRICTION)
		{
		fprintf (fp1, "r(01)\t");
		fprintf (fp2, ", r01");
		}
#if defined (MORPH)
	else if (dataType == STANDARD && numBetaCats > 1)
		{
		fprintf (fp1, "alpha\t");	// TODO: change header to something more suitable
		fprintf (fp2, ", alpha");
		}
#endif		
	if (((dataType == DNA || dataType == RNA) && enforceCodonModel == NO) || dataType == PROTEIN || dataType == RESTRICTION)
		{
		if (!strcmp(ratesModel, "gamma"))
			{
			fprintf (fp1, "alpha\t");
			fprintf (fp2, ", alpha");
			}
		else if (!strcmp(ratesModel, "adgamma"))
			{
			fprintf (fp1, "alpha\t");
			fprintf (fp2, ", alpha");
			fprintf (fp1, "rho\t");
			fprintf (fp2, ", rho");
			if (!strcmp(lagprModel, "uniform") || !strcmp(lagprModel, "exponential"))
				{
				fprintf (fp1, "offset\t");
				fprintf (fp2, ", offset");
				}
			}
		else if (!strcmp(ratesModel, "sitespec"))
			{
			for (i=0; i<nPartitions; i++)
				{
				fprintf (fp1, "SS(%d)\t", i+1);
				fprintf (fp2, ", SS%d", i+1);
				}
			}
		else if (!strcmp(ratesModel, "invariant"))
			{
			fprintf (fp1, "iP\t");
			fprintf (fp2, ", iP");
			}
		else if (!strcmp(ratesModel, "invgamma"))
			{
			fprintf (fp1, "alpha\t");
			fprintf (fp2, ", alpha");
			fprintf (fp1, "iP\t");
			fprintf (fp2, ", iP");
			}
		else if (!strcmp(ratesModel, "ssgamma"))
			{
			fprintf (fp1, "alpha\t");
			fprintf (fp2, ", alpha");
			for (i=0; i<nPartitions; i++)
				{
				fprintf (fp1, "SS(%d)\t", i+1);
				fprintf (fp2, ", SS%d", i+1);
				}
			}
		else if (!strcmp(ratesModel, "ssadgamma"))
			{
			fprintf (fp1, "alpha\t");
			fprintf (fp2, ", alpha");
			fprintf (fp1, "rho\t");
			fprintf (fp2, ", rho");
			if (!strcmp(lagprModel, "uniform") || !strcmp(lagprModel, "exponential"))
				{
				fprintf (fp1, "offset\t");
				fprintf (fp2, ", offset");
				}
			for (i=0; i<nPartitions; i++)
				{
				fprintf (fp1, "SS(%d)\t", i+1);
				fprintf (fp2, ", SS%d", i+1);
				}
			}
		}
	if (!strcmp(brlenprModel, "birth-death"))
		{
		fprintf (fp1, "lambda\tmu\t");
		fprintf (fp2, ", lambda, mu");
		}
	if (enforceCalibrations == YES)
		{
		fprintf (fp1, "m\t");
		fprintf (fp2, ", m");
		for (i=0; i<nConstraints; i++)
			{
			fprintf (fp2, ", ");
			k = 0;
			while (constraintLabels[i][k] != '|' && k < 99)
				{
				fprintf (fp1, "%c", constraintLabels[i][k]);
				fprintf (fp2, "%c", constraintLabels[i][k]);
				k++;
				}
			fprintf (fp1, "\t");
			}
		for (i=0; i<nCalibrations; i++)
			{
			fprintf (fp2, ", ");
			k = 0;
			while (calibrationLabels[i][k] != '|' && k < 99)
				{
				fprintf (fp1, "%c", calibrationLabels[i][k]);
				fprintf (fp2, "%c", calibrationLabels[i][k]);
				k++;
				}
			fprintf (fp1, "\t");
			}
		}
	
	fprintf (fp1, "\n");
	fprintf (fp2, ";\n");
	fflush(fp1);
	fflush(fp2);

	fp2 = tFile;

	fprintf (fp2, "begin trees;\n");
	fprintf (fp2, "   translate\n");
	isFirst = YES;
	j = 0;
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[i];		// print any tree, they are identical
		if (p->left == NULL || p->right == NULL || (treeModel == UNROOTED && p->anc == NULL))
			{
			if (isFirst == NO)
				fprintf (fp2, ",\n");
			if (treeModel == ROOTED && p->anc != NULL)
				fprintf (fp2, "   %4d %s", p->index + 1, p->label);
			else if (treeModel == UNROOTED)
				fprintf (fp2, "   %4d %s", p->index + 1, p->label);
			isFirst = NO;
			}
		}
	fprintf (fp2, ";\n");
	fflush (fp2);

	return NO_ERROR;

	error_exit:
		if (pFile!=NULL)
			fclose(pFile);
		if (bpFile!=NULL)
			fclose(bpFile);
		if (tFile!=NULL)
			fclose(tFile);
		return ERROR;

}





int PrepareParsOutputFiles (void)

{

	int				i, j, isFirst;
	char			pFilename[100], bpFilename[100], tFilename[100];
	TreeNode		*p;
	FILE			*fp1, *fp2;
	
	/* prepare output file names */
	strcpy (pFilename, outFile);
	strcpy (bpFilename, outFile);
	strcpy (tFilename, outFile);
	strcat (pFilename, ".p");
	strcat (bpFilename, ".bp");
	strcat (tFilename, ".t");

	/* reset output file pointers */
	pFile = bpFile = tFile = NULL;
	
	/* open files */
	if ((pFile = OpenFile(pFilename, NO))==NULL)
		goto error_exit;

	if ((bpFile = OpenFile(bpFilename, YES))==NULL)
		goto error_exit;

	if ((tFile = OpenFile(tFilename, YES))==NULL)
		goto error_exit;

	fp1 = pFile;
	fp2 = bpFile;

	/* print headers to pFile and bpFile */
	fprintf (fp2, "#NEXUS\n\n");
	fprintf (fp2, "begin bayesparams;\n");
	fprintf (fp1, "Gen\tlnL\t");
	fprintf (fp1, "TL\t");
	fprintf (fp2, "   header Gen, lnL");
	fprintf (fp2, ", TL");

	fprintf (fp1, "\n");
	fprintf (fp2, ";\n");
	fflush(fp1);
	fflush(fp2);

	fp2 = tFile;

	fprintf (fp2, "begin trees;\n");
	fprintf (fp2, "   translate\n");
	isFirst = YES;
	j = 0;
	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[i];		// print any tree, they are identical
		if (p->left == NULL || p->right == NULL || (treeModel == UNROOTED && p->anc == NULL))
			{
			if (isFirst == NO)
				fprintf (fp2, ",\n");
			if (treeModel == ROOTED && p->anc != NULL)
				fprintf (fp2, "   %4d %s", p->index + 1, p->label);
			else if (treeModel == UNROOTED)
				fprintf (fp2, "   %4d %s", p->index + 1, p->label);
			isFirst = NO;
			}
		}
	fprintf (fp2, ";\n");
	fflush (fp2);

	return NO_ERROR;

	error_exit:
		if (pFile!=NULL)
			fclose(pFile);
		if (bpFile!=NULL)
			fclose(bpFile);
		if (tFile!=NULL)
			fclose(tFile);
		return ERROR;
		
}





int PrintAncStatesDNA (int whichState, int whichChain, int numChars, int numRateCats, int whichGen)

{
#define N_STATES 4
#define N_STATES_SQUARED 16
#define N_STATES_CUBE 64

	register int	i, j, k, c, n, n1, l, startingJ;
	int				lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					index, nRates, pat,
					intNodeOffset, allNodeOffset, condLikeOffset;
	double			bs[N_STATES], *pL, *pR, *pA, *catFreq, *catRate, *partRate,
					*clL, *clR, *clA, *clP, *tiPL, *tiPR, *tiPA,
					*lnScaler, correlation, lnSeqProb, maxProb,
					**markovTi, like[4], sum, postProb[4], *f, *b, *expPr, *logCf, 
					*logCb, *tempRatePr, *rateProbs, logC, temp, logLike, *ancCls;
	char			tempFile[100], tempFileA[100], tempFileC[100], tempFileG[100], tempFileT[100], bestNuc;
	TreeNode		*p, *r, *rDn, *rUp;
	FILE			*fp, *fopen();
#	if defined (SMART_TI_PROBS)
	int				nForOneState;
#	else
	register int	m;
	int				isComplex, indexL, indexR, indexA, nPij;
	double			v, lkappa, theRate, **probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk;
	complex 		**Ceigvecs, **CinverseEigvecs;	
#	endif

	/* initialize intNodeOffset */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;
	allNodeOffset = whichChain*2*numNodes    + whichState*numNodes;

	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* load base frequencies */
	index = whichChain*2*N_STATES + whichState*N_STATES;
	bs[A] = baseFreq[index + A];
	bs[C] = baseFreq[index + C];
	bs[G] = baseFreq[index + G];
	bs[T] = baseFreq[index + T];
	
	/* how many different rates? */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1 */
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1 */
	/* the code introduced here only makes sure that the number of partitions */
	/* or rate categories is set to 1 when appropriate, in case the global variables */
	/* are not set to 1 when they are not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;
	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible rate */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (N_STATES);
	nPij = nRates * N_STATES_SQUARED;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* allocate memory for ancestral conditional likelihoods (it may be a tip, and we don't want to overwrite these cls) */
	ancCls = (double *)malloc((size_t) (lnumRateCats * numChars * N_STATES * sizeof(double)));
	if (!ancCls)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for autocorrelated gamma models */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		f = (double *)malloc((size_t) (((lnumRateCats * nChar) * 2 + lnumRateCats + nChar*2) * sizeof(double)));
		if (!f)
			{
			printf ("\n   ERROR: Problem allocating f.\n");
			goto error_exit;
			}
		b     = f + lnumRateCats * nChar;
		expPr = b + lnumRateCats * nChar;
		logCf = expPr + lnumRateCats;
		logCb = logCf + nChar;
		for (i=0; i<lnumRateCats*nChar; i++)
			f[i] = b[i] = 0.0;
		for (i=0; i<lnumRateCats; i++)
			expPr[i] = 0.0;
		for (i=0; i<nChar; i++)
			logCf[i] = logCb[i] = 0.0;
		tempRatePr = (double *)malloc((size_t) ((numChars * lnumRateCats + nChar * lnumRateCats) * sizeof(double)));
		if (!tempRatePr)
			{
			printf ("\n   ERROR: Problem allocating tempRatePr.\n");
			goto error_exit;
			}
		rateProbs = tempRatePr + numChars * lnumRateCats;
		for (i=0; i<nChar * lnumRateCats; i++)
			rateProbs[i] = 0.0;
		}

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;

	/* find kappa if nst == 1 or nst == 2 */
#	if !defined (SMART_TI_PROBS)
	if (nst == 1)
		lkappa = 1.0;
	else if (nst == 2)
		lkappa = kappa[whichChain*2 + whichState];
		
	/* get eigenvalues and eigenvectors if nst=6 or nst=12 */
	if (nst == 6 || nst == 12)
		{
		q = psdmatrix (N_STATES);
		eigenValues = (double *)malloc((size_t) (2 * N_STATES * sizeof(double)));
		if (!eigenValues)
			{
			printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
			goto error_exit;
			}
		eigvalsImag = eigenValues + N_STATES;
		eigvecs = psdmatrix (N_STATES);
		inverseEigvecs = psdmatrix (N_STATES);
		Ceigvecs = pscmatrix (N_STATES);
		CinverseEigvecs = pscmatrix (N_STATES);
		if (SetQMatrix (q, whichState, whichChain) == ERROR)
			goto error_exit;
		isComplex = GetEigens (N_STATES, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
		if (isComplex == NO)
			{
			c_ijk = (double *)malloc((size_t) (N_STATES_CUBE * sizeof(double)));
			if (!c_ijk)
				{
				printf ("\n   ERROR: Problem allocating c_ijk.\n");
				goto error_exit;
				}
			CalcCijk (c_ijk, N_STATES, eigvecs, inverseEigvecs);
			}
		}
#	endif

	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * N_STATES;
	oneNodeSize = numChars * lnumRateCats * N_STATES;

	/* offset for conditional likelihoods */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;

	/* pass down tree, finding nodes that are to have ancestral states estimated */
	for (n=0; n<numNodes; n++)
		{
		p = allNodesDownPassSeq[allNodeOffset + n];
		
		if (p->isConstrained == YES)
			{

			/* mark nodes below p */
			for (n1=0; n1<numNodes; n1++)
				{
				r = allNodesDownPassSeq[allNodeOffset + n1];
				r->flag = 0;
				if (r == p)
					r->flag = 1;
				if (r->left != NULL && r->right != NULL)
					{
					if (r->left->flag == 1 || r->right->flag == 1)
						r->flag = 1;
					}
				}		
			
			/* get conditional likelihoods down tree */
			for (n1=0; n1<numIntNodes; n1++)
				{
				r = intNodeDownPassSeq[intNodeOffset + n1];
				if (r->flag != 1)
					{
					//printf ("visiting interior node %d dn\n", r->index);
					/* get transition probabilities */
#					if defined (SMART_TI_PROBS)
					pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->left->index)*nodeTiSize);
					pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->right->index)*nodeTiSize);
#					else
					if (nst == 1 || nst == 2)
						{
						for (m=indexL=indexR=0; m<lnPartitions; m++)
							{
							for (k=0; k<lnumRateCats; k++)
								{
								theRate = partRate[m] * catRate[k];
								/* calculate transition probabilities for left branch */
								HkyChangeMat (probs, r->left->length, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
								for (i=0; i<4; i++)
									for (j=0; j<4; j++)
										pL[indexL++] = probs[i][j];
								
								/* calculate transition probabilities for right branch */
								HkyChangeMat (probs, r->right->length, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
								for (i=0; i<4; i++)
									for (j=0; j<4; j++)
										pR[indexR++] = probs[i][j];
								}
							}
						}
					else // nst == 6 or nst == 12
						{
						for (m=indexL=indexR=0; m<lnPartitions; m++)
							{
							for (k=0; k<lnumRateCats; k++)
								{
								theRate = partRate[m] * catRate[k];
								// calculate transition probabilities for left branch
								if (isComplex == NO)
									CalcPij (c_ijk, 4, eigenValues, r->left->length,  theRate, probs);
								else
									if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, r->left->length, theRate) == ERROR) 
										{
										printf ("Problem calculating transition probabilities for complex eigen values.\n");
										goto error_exit;
										}
								for (i=0; i<4; i++)
									for (j=0; j<4; j++)
										pL[indexL++] = probs[i][j];
								
								// calculate transition probabilities for right branch
								if (isComplex == NO)
									CalcPij (c_ijk, 4, eigenValues, r->right->length,  theRate, probs);
								else
									if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, r->right->length, theRate) == ERROR) 
										{
										printf ("Problem calculating transition probabilities for complex eigen values.\n");
										goto error_exit;
										}
								for (i=0; i<4; i++)
									for (j=0; j<4; j++)
										pR[indexR++] = probs[i][j];							
								}
							}
						}
#					endif

					/* first set pointers to cond likes of left, right and p */
					clL = &condLike[condLikeOffset + (r->left->index)*oneNodeSize];
					clR = &condLike[condLikeOffset + (r->right->index)*oneNodeSize];
					clP = &condLike[condLikeOffset + (r->index)*oneNodeSize];

					if (!strcmp(ratesModel, "equal"))
						{
						tiPL = pL;
						tiPR = pR;
						for (c=0; c<numChars; c++)
							{
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
							          *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
							          *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
							          *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
							          *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							}
						}
					else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
						{
						for (c=0; c<numChars; c++)
							{
							tiPL = pL;
							tiPR = pR;
							for (k=0; k<lnumRateCats; k++)
								{
								clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
										  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
								clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
										  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
								clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
										  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
								clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
										  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
								clP += 4;
								clL += 4;
								clR += 4;
								tiPL += 16;
								tiPR += 16;
								}
							}
						}
					else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
						{
						for (c=0; c<numChars; c++)
							{
							index = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
							tiPL = &pL[index];
							tiPR = &pR[index];
							for (k=0; k<lnumRateCats; k++)
								{
								clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
										  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
								clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
										  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
								clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
										  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
								clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
										  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
								clP += 4;
								clL += 4;
								clR += 4;
								tiPL += 16;
								tiPR += 16;
								}
							}
						}
					else if (!strcmp(ratesModel, "sitespec"))
						{
						for (c=0; c<numChars; c++)
							{
							index = partitionId[c]*N_STATES_SQUARED;
							tiPL = &pL[index];
							tiPR = &pR[index];
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
									  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
									  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
									  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
									  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							}
						}
					}
				}
			
			/* get conditional likelihoods up tree */
			for (n1=numIntNodes-1; n1>=0; n1--)
				{
				r = intNodeDownPassSeq[intNodeOffset + n1];
				if (r->flag == 1 && p != r)
					{
					rDn = r->anc;
					if (r->left->flag == 0)
						rUp = r->left;
					else
						rUp = r->right;

					//printf ("visiting interior node %d up\n", r->index);
					/* get transition probabilities */
#					if defined (SMART_TI_PROBS)
					pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (rUp->index)*nodeTiSize);
					pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->index)*nodeTiSize);
#					else
					if (nst == 1 || nst == 2)
						{
						for (m=indexL=indexR=0; m<lnPartitions; m++)
							{
							for (k=0; k<lnumRateCats; k++)
								{
								theRate = partRate[m] * catRate[k];
								/* calculate transition probabilities for left branch */
								HkyChangeMat (probs, rUp->length, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
								for (i=0; i<4; i++)
									for (j=0; j<4; j++)
										pL[indexL++] = probs[i][j];
								
								/* calculate transition probabilities for right branch */
								HkyChangeMat (probs, r->length, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
								for (i=0; i<4; i++)
									for (j=0; j<4; j++)
										pR[indexR++] = probs[i][j];
								}
							}
						}
					else // nst == 6 or nst == 12
						{
						for (m=indexL=indexR=0; m<lnPartitions; m++)
							{
							for (k=0; k<lnumRateCats; k++)
								{
								theRate = partRate[m] * catRate[k];
								// calculate transition probabilities for left branch
								if (isComplex == NO)
									CalcPij (c_ijk, 4, eigenValues, rUp->length, theRate, probs);
								else
									if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, rUp->length, theRate) == ERROR) 
										{
										printf ("Problem calculating transition probabilities for complex eigen values.\n");
										goto error_exit;
										}
								for (i=0; i<4; i++)
									for (j=0; j<4; j++)
										pL[indexL++] = probs[i][j];
								
								// calculate transition probabilities for right branch
								if (isComplex == NO)
									CalcPij (c_ijk, 4, eigenValues, r->length,  theRate, probs);
								else
									if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, r->length, theRate) == ERROR) 
										{
										printf ("Problem calculating transition probabilities for complex eigen values.\n");
										goto error_exit;
										}
								for (i=0; i<4; i++)
									for (j=0; j<4; j++)
										pR[indexR++] = probs[i][j];							
								}
							}
						}
#					endif

					/* first set pointers to cond likes of left, right and p */
					clL = &condLike[condLikeOffset + (rUp->index)*oneNodeSize];
					clR = &condLike[condLikeOffset + (rDn->index)*oneNodeSize];
					clP = &condLike[condLikeOffset + (r->index)*oneNodeSize];

					if (!strcmp(ratesModel, "equal"))
						{
						tiPL = pL;
						tiPR = pR;
						for (c=0; c<numChars; c++)
							{
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
							          *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
							          *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
							          *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
							          *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							}
						}
					else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
						{
						for (c=0; c<numChars; c++)
							{
							tiPL = pL;
							tiPR = pR;
							for (k=0; k<lnumRateCats; k++)
								{
								clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
										  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
								clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
										  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
								clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
										  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
								clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
										  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
								clP += 4;
								clL += 4;
								clR += 4;
								tiPL += 16;
								tiPR += 16;
								}
							}
						}
					else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
						{
						for (c=0; c<numChars; c++)
							{
							index = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
							tiPL = &pL[index];
							tiPR = &pR[index];
							for (k=0; k<lnumRateCats; k++)
								{
								clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
										  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
								clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
										  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
								clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
										  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
								clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
										  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
								clP += 4;
								clL += 4;
								clR += 4;
								tiPL += 16;
								tiPR += 16;
								}
							}
						}
					else if (!strcmp(ratesModel, "sitespec"))
						{
						for (c=0; c<numChars; c++)
							{
							index = partitionId[c]*N_STATES_SQUARED;
							tiPL = &pL[index];
							tiPR = &pR[index];
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
									  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
									  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
									  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
									  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							}
						}
					}
				}
			
			/* get conditional probabilities of states at p */
			//printf ("getting condlikes at p %d\n", p->index);
			/* get transition probabilities */
#			if defined (SMART_TI_PROBS)
			if (p->left == NULL || p->right == NULL || p->anc == NULL)
				{
				if (p->anc == NULL)
					pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				else
					pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
				}
			else
				{
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
				}
#			else
			if (nst == 1 || nst == 2)
				{
				if (p->left == NULL || p->right == NULL || p->anc == NULL)
					{
					if (p->anc == NULL)
						v = p->left->length;
					else
						v = p->length;
					for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							/* calculate transition probabilities for ancestral branch */
							HkyChangeMat (probs, v, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pA[indexA++] = probs[i][j];
							}
						}
					}
				else
					{
					for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							/* calculate transition probabilities for left branch */
							HkyChangeMat (probs, p->left->length, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							/* calculate transition probabilities for right branch */
							HkyChangeMat (probs, p->right->length, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];

							/* calculate transition probabilities for ancestral branch */
							HkyChangeMat (probs, p->length, lkappa, theRate, bs[A], bs[C], bs[G], bs[T]);
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pA[indexA++] = probs[i][j];
							}
						}
					}
				}
			else // nst == 6 or nst == 12
				{
				if (p->left == NULL || p->right == NULL || p->anc == NULL)
					{
					if (p->anc == NULL)
						v = p->left->length;
					else
						v = p->length;
					for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for ancestral branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, v, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, v, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pA[indexA++] = probs[i][j];
							}
						}
					}
				else
					{
					for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for left branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->left->length, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->left->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pL[indexL++] = probs[i][j];
							
							// calculate transition probabilities for right branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->right->length, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->right->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pR[indexR++] = probs[i][j];

							// calculate transition probabilities for ancestral branch
							if (isComplex == NO)
								CalcPij (c_ijk, 4, eigenValues, p->length, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, p->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<4; i++)
								for (j=0; j<4; j++)
									pA[indexA++] = probs[i][j];
							}
						}
					}				
				}
#			endif
			if (p->left == NULL || p->right == NULL || p->anc == NULL)
				{
				//clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				clP = ancCls;
				if (p->anc == NULL)
					clA = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				else
					clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];

				if (!strcmp(ratesModel, "equal"))
					{
					tiPA = pA;
					for (c=0; c<numChars; c++)
						{
						clP[A] =  (tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
						clP[C] =  (tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
						clP[G] =  (tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
						clP[T] =  (tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
						clP += 4;
						clA += 4;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPA = pA;
						for (k=0; k<lnumRateCats; k++)
							{
							clP[A] =  (tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
							clP[C] =  (tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
							clP[G] =  (tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
							clP[T] =  (tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
							clP += 4;
							clA += 4;
							tiPA += 16;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
						tiPA = &pA[index];
						for (k=0; k<lnumRateCats; k++)
							{
							clP[A] =  (tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
							clP[C] =  (tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
							clP[G] =  (tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
							clP[T] =  (tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
							clP += 4;
							clA += 4;
							tiPA += 16;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*N_STATES_SQUARED;
						tiPA = &pA[index];
						clP[A] =  (tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
						clP[C] =  (tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
						clP[G] =  (tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
						clP[T] =  (tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
						clP += 4;
						clA += 4;
						}
					}

				}
			else
				{
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				//clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				clP = ancCls;

				if (!strcmp(ratesModel, "equal"))
					{
					tiPL = pL;
					tiPR = pR;
					tiPA = pA;
					for (c=0; c<numChars; c++)
						{
						clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
						          *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
						          *(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
						clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
						          *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
						          *(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
						clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
						          *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
						          *(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
						clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
						          *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
						          *(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
						clP += 4;
						clL += 4;
						clR += 4;
						clA += 4;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						tiPL = pL;
						tiPR = pR;
						tiPA = pA;
						for (k=0; k<lnumRateCats; k++)
							{
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
									  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
									  *(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
									  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
									  *(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
									  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
									  *(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
									  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
									  *(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							clA += 4;
							tiPL += 16;
							tiPR += 16;
							tiPA += 16;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						for (k=0; k<lnumRateCats; k++)
							{
							clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
									  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
									  *(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
							clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
									  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
									  *(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
							clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
									  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
									  *(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
							clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
									  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
									  *(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
							clP += 4;
							clL += 4;
							clR += 4;
							clA += 4;
							tiPL += 16;
							tiPR += 16;
							tiPA += 16;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						index = partitionId[c]*N_STATES_SQUARED;
						tiPL = &pL[index];
						tiPR = &pR[index];
						tiPA = &pA[index];
						clP[A] =   (tiPL[AA]*clL[A] + tiPL[AC]*clL[C] + tiPL[AG]*clL[G] + tiPL[AT]*clL[T])
								  *(tiPR[AA]*clR[A] + tiPR[AC]*clR[C] + tiPR[AG]*clR[G] + tiPR[AT]*clR[T])
								  *(tiPA[AA]*clA[A] + tiPA[AC]*clA[C] + tiPA[AG]*clA[G] + tiPA[AT]*clA[T]);
						clP[C] =   (tiPL[CA]*clL[A] + tiPL[CC]*clL[C] + tiPL[CG]*clL[G] + tiPL[CT]*clL[T])
								  *(tiPR[CA]*clR[A] + tiPR[CC]*clR[C] + tiPR[CG]*clR[G] + tiPR[CT]*clR[T])
								  *(tiPA[CA]*clA[A] + tiPA[CC]*clA[C] + tiPA[CG]*clA[G] + tiPA[CT]*clA[T]);
						clP[G] =   (tiPL[GA]*clL[A] + tiPL[GC]*clL[C] + tiPL[GG]*clL[G] + tiPL[GT]*clL[T])
								  *(tiPR[GA]*clR[A] + tiPR[GC]*clR[C] + tiPR[GG]*clR[G] + tiPR[GT]*clR[T])
								  *(tiPA[GA]*clA[A] + tiPA[GC]*clA[C] + tiPA[GG]*clA[G] + tiPA[GT]*clA[T]);
						clP[T] =   (tiPL[TA]*clL[A] + tiPL[TC]*clL[C] + tiPL[TG]*clL[G] + tiPL[TT]*clL[T])
								  *(tiPR[TA]*clR[A] + tiPR[TC]*clR[C] + tiPR[TG]*clR[G] + tiPR[TT]*clR[T])
								  *(tiPA[TA]*clA[A] + tiPA[TC]*clA[C] + tiPA[TG]*clA[G] + tiPA[TT]*clA[T]);
						clP += 4;
						clL += 4;
						clR += 4;
						clA += 4;
						}
					}
				}						
			
			/* calculate posterior probability of states at p */
			//clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			clP = ancCls;
			if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
				{
				for (c=0; c<nChar; c++)
					{
					pat = patternId[c];
					if (pat >= 0)
						{
						like[A] = clP[pat*4 + A];
						like[C] = clP[pat*4 + C];
						like[G] = clP[pat*4 + G];
						like[T] = clP[pat*4 + T];
						sum = like[A] * bs[A] + like[C] * bs[C] + like[G] * bs[G] + like[T] * bs[T];
						postProb[A] = (like[A] * bs[A]) / sum;
						postProb[C] = (like[C] * bs[C]) / sum;
						postProb[G] = (like[G] * bs[G]) / sum;
						postProb[T] = (like[T] * bs[T]) / sum;
						tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + A] = postProb[A];
						tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + C] = postProb[C];
						tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + G] = postProb[G];
						tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + T] = postProb[T];
						ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + A] += postProb[A];
						ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + C] += postProb[C];
						ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + G] += postProb[G];
						ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + T] += postProb[T];
						}
					}
				}
			else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
				{
				for (c=0; c<nChar; c++)
					{
					pat = patternId[c];
					if (pat >= 0)
						{
						like[A] = like[C] = like[G] = like[T] = 0.0;
						for (k=0; k<lnumRateCats; k++)
							{
							like[A] += clP[pat*lnumRateCats*4 + k*4 + A] * catFreq[k];
							like[C] += clP[pat*lnumRateCats*4 + k*4 + C] * catFreq[k];
							like[G] += clP[pat*lnumRateCats*4 + k*4 + G] * catFreq[k];
							like[T] += clP[pat*lnumRateCats*4 + k*4 + T] * catFreq[k];
							}
						sum = like[A] * bs[A] + like[C] * bs[C] + like[G] * bs[G] + like[T] * bs[T];
						postProb[A] = (like[A] * bs[A]) / sum;
						postProb[C] = (like[C] * bs[C]) / sum;
						postProb[G] = (like[G] * bs[G]) / sum;
						postProb[T] = (like[T] * bs[T]) / sum;
						tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + A] = postProb[A];
						tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + C] = postProb[C];
						tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + G] = postProb[G];
						tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + T] = postProb[T];
						ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + A] += postProb[A];
						ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + C] += postProb[C];
						ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + G] += postProb[G];
						ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + T] += postProb[T];
						}
					}
				}
			else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
				{
				/* get probabilities of observations conditioned on each category */
				for (c=0; c<numChars; c++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						tempRatePr[k * numChars + c] = clP[A]*bs[A] + clP[C]*bs[C] + clP[G]*bs[G] + clP[T]*bs[T];
						clP += 4;
						}
					}

				/* forward algorithm */
				logC = 0.0;
				for (c=0; c<nChar; c++)
					{
					if (patternId[c] >= 0)
						{
						pat = patternId[c];
						if (c == 0)
							{
							for (k=0; k<lnumRateCats; k++)
								f[k*nChar + c] = tempRatePr[k * numChars + pat];
							}
						else
							{
							for (l=0; l<lnumRateCats; l++)
								{
								temp = 0.0;
								for (k=0; k<lnumRateCats; k++)
									temp += f[k * nChar + (c-1)] * markovTi[k][l];
								f[l * nChar + c] = temp * tempRatePr[l * numChars + pat];
								}
							}
						sum = 0.0;
						for (k=0; k<lnumRateCats; k++)
							sum += f[k*nChar + c];
						for (k=0; k<lnumRateCats; k++)
							f[k*nChar+c] /= sum;
						logC += log(sum);
						logCf[c] = logC;
						}
					else
						{
						
						}
					}

				/* backward algorithm */
				logC = 0.0;
				for (c=nChar-1; c>=0; c--)
					{
					if (patternId[c] >= 0)
						{
						if (c == nChar - 1)
							{
							for (k=0; k<lnumRateCats; k++)
								b[k * nChar + c] = catFreq[k];
							}
						else
							{
							pat = patternId[c+1];
							for (k=0; k<lnumRateCats; k++)
								{
								temp = 0.0;
								for (l=0; l<lnumRateCats; l++)
									temp += markovTi[k][l] * tempRatePr[l * numChars + pat] * b[l * nChar + (c+1)];
								b[k * nChar + c] = temp;
								}
							}
						sum = 0.0;
						for (k=0; k<lnumRateCats; k++)
							sum += b[k*nChar + c];
						for (k=0; k<lnumRateCats; k++)
							b[k*nChar+c] /= sum;
						logC += log(sum);
						logCb[c] = logC;
						}
					else
						{
						
						}
					}
				temp = 0.0;
				pat = patternId[0];
				for (l=0; l<lnumRateCats; l++)
					temp += tempRatePr[l * numChars + pat] * b[l * nChar + 0];
				logLike = log (temp) + logC;

				/* posterior probabilities of individual categories at site c */
				for (c=0; c<nChar; c++)
					{
					/*printf ("%d ", c+1);*/
					for (k=0; k<lnumRateCats; k++)
						{
						temp = (log(f[k * nChar + c]) + logCf[c] + log(b[k * nChar + c]) + logCb[c]) - logLike;
						if (temp > 0.0)
							expPr[k] = 1.0;
						else if (temp < -100.0)
							expPr[k] = 0.0;
						else
							expPr[k] = exp(temp);
						}
						
						
					for (k=0; k<lnumRateCats; k++)
						{
						rateProbs[c*lnumRateCats + k] += expPr[k];
						}
					}

				//clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				clP = ancCls;
				for (c=0; c<nChar; c++)
					{
					pat = patternId[c];
					like[A] = like[C] = like[G] = like[T] = 0.0;
					for (k=0; k<lnumRateCats; k++)
						{
						like[A] += clP[pat*lnumRateCats*4 + k*4 + A] * rateProbs[c*lnumRateCats + k];
						like[C] += clP[pat*lnumRateCats*4 + k*4 + C] * rateProbs[c*lnumRateCats + k];
						like[G] += clP[pat*lnumRateCats*4 + k*4 + G] * rateProbs[c*lnumRateCats + k];
						like[T] += clP[pat*lnumRateCats*4 + k*4 + T] * rateProbs[c*lnumRateCats + k];
						}
					sum = like[A] * bs[A] + like[C] * bs[C] + like[G] * bs[G] + like[T] * bs[T];
					postProb[A] = (like[A] * bs[A]) / sum;
					postProb[C] = (like[C] * bs[C]) / sum;
					postProb[G] = (like[G] * bs[G]) / sum;
					postProb[T] = (like[T] * bs[T]) / sum;
					tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + A] = postProb[A];
					tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + C] = postProb[C];
					tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + G] = postProb[G];
					tempStateProbs[(p->constraintNum-1)*nChar*4 + c*4 + T] = postProb[T];
					ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + A] += postProb[A];
					ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + C] += postProb[C];
					ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + G] += postProb[G];
					ancStatesProbs[(p->constraintNum-1)*nChar*4 + c*4 + T] += postProb[T];
					}

				}
			}
		}
	
	/* summarize states */
	/* print probabilities to a file */
	strcpy (tempFileA, outFile);
	strcpy (tempFileC, outFile);
	strcpy (tempFileG, outFile);
	strcpy (tempFileT, outFile);
	strcat (tempFileA, ".A.");
	strcat (tempFileC, ".C.");
	strcat (tempFileG, ".G.");
	strcat (tempFileT, ".T.");

	if (nSampled == 1)
		{
		if (saveAncFiles == YES)
			startingJ = 0;
		else
			startingJ = 4;
		for (j=startingJ; j<5; j++)
			{
			if (j == 0)
				strcpy (tempFile, tempFileA);
			else if (j == 1)
				strcpy (tempFile, tempFileC);
			else if (j == 2)
				strcpy (tempFile, tempFileG);
			else if (j == 3)
				strcpy (tempFile, tempFileT);
			else
				{
				strcpy (tempFile, outFile);
				strcat (tempFile, ".sum.");
				}
			for (i=0; i<nConstraints; i++)
				{
				strcat (tempFile, "1");
#if defined (MORPH)
				fp = OpenFile(tempFile, NO);
				if (fp == NULL)
					{
					printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
					goto error_exit;
					}
#else
				if ((fp = fopen (tempFile, "r")) == NULL)  
					{
					if ((fp = fopen (tempFile, "w")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
						goto error_exit;
						}
					}
				else
					{
					fclose (fp);
					if (autoclose == YES)
						{
						printf ("      Overwriting information to file %s\n", tempFile);
						if ((fp = fopen (tempFile, "w+")) == NULL)  
							{
							printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
							goto error_exit;
							}
						}
					else
						{
						printf ("\n      File \"%s\" already exists.\n      Overwrite? (yes/no): ", tempFile);
						if (YesNo() == YES)
							{
							printf ("      Overwriting information to file %s\n", tempFile);
							if ((fp = fopen (tempFile, "w+")) == NULL)  
								{
								printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
								goto error_exit;
								}
							}
						else
							{
							printf ("      Appending information to file %s\n", tempFile);
							if ((fp = fopen (tempFile, "a+")) == NULL)  
								{
								printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
								goto error_exit;
								}
							}
						}
					}
#endif
				fclose (fp);
				}
			}
		}

	/* A */
	if (saveAncFiles == YES)
		{
		strcpy (tempFile, tempFileA);
		for (i=0; i<nConstraints; i++)
			{
			strcat (tempFile, "1");
			if ((fp = fopen (tempFile, "a+")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
				goto error_exit;
				}
			if (whichGen == 1)
				{
				fprintf (fp, "Ancestral states for nucleotide A at constraint \"");
				k = 0;
				while (constraintLabels[i][k] != '|' && k < 99)
					{
					fprintf (fp, "%c", constraintLabels[i][k]);
					k++;
					}
				fprintf (fp, "\"\n");
				}
			for (c=0; c<nChar; c++)
				{
				if (patternId[c] >= 0)
					{
					pat = patternId[c];
					fprintf (fp, "%lf\t", tempStateProbs[i*nChar*4 + c*4 + A]);
					}
				}
			fprintf (fp, "\n");
			fclose (fp);
			}

		/* C */
		strcpy (tempFile, tempFileC);
		for (i=0; i<nConstraints; i++)
			{
			strcat (tempFile, "1");
			if ((fp = fopen (tempFile, "a+")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
				goto error_exit;
				}
			if (whichGen == 1)
				{
				fprintf (fp, "Ancestral states for nucleotide C at constraint \"");
				k = 0;
				while (constraintLabels[i][k] != '|' && k < 99)
					{
					fprintf (fp, "%c", constraintLabels[i][k]);
					k++;
					}
				fprintf (fp, "\"\n");
				}
			for (c=0; c<nChar; c++)
				{
				if (patternId[c] >= 0)
					{
					pat = patternId[c];
					fprintf (fp, "%lf\t", tempStateProbs[i*nChar*4 + c*4 + C]);
					}
				}
			fprintf (fp, "\n");
			fclose (fp);
			}

		/* G */
		strcpy (tempFile, tempFileG);
		for (i=0; i<nConstraints; i++)
			{
			strcat (tempFile, "1");
			if ((fp = fopen (tempFile, "a+")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
				goto error_exit;
				}
			if (whichGen == 1)
				{
				fprintf (fp, "Ancestral states for nucleotide G at constraint \"");
				k = 0;
				while (constraintLabels[i][k] != '|' && k < 99)
					{
					fprintf (fp, "%c", constraintLabels[i][k]);
					k++;
					}
				fprintf (fp, "\"\n");
				}
			for (c=0; c<nChar; c++)
				{
				if (patternId[c] >= 0)
					{
					pat = patternId[c];
					fprintf (fp, "%lf\t", tempStateProbs[i*nChar*4 + c*4 + G]);
					}
				}
			fprintf (fp, "\n");
			fclose (fp);
			}

		/* T */
		strcpy (tempFile, tempFileT);
		for (i=0; i<nConstraints; i++)
			{
			strcat (tempFile, "1");
			if ((fp = fopen (tempFile, "a+")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
				goto error_exit;
				}
			if (whichGen == 1)
				{
				fprintf (fp, "Ancestral states for nucleotide T at constraint \"");
				k = 0;
				while (constraintLabels[i][k] != '|' && k < 99)
					{
					fprintf (fp, "%c", constraintLabels[i][k]);
					k++;
					}
				fprintf (fp, "\"\n");
				}
			for (c=0; c<nChar; c++)
				{
				if (patternId[c] >= 0)
					{
					pat = patternId[c];
					fprintf (fp, "%lf\t", tempStateProbs[i*nChar*4 + c*4 + T]);
					}
				}
			fprintf (fp, "\n");
			fclose (fp);
			}
		}
		
	/* summarize states */
	if (whichGen == nGen && nSampled >= 1)
		{
		strcpy (tempFile, outFile);
		strcat (tempFile, ".sum.");
		for (i=0; i<nConstraints; i++)
			{
			strcat (tempFile, "1");
			if ((fp = fopen (tempFile, "a+")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
				goto error_exit;
				}
			fprintf (fp, "Summary of ancestral states at constraint \"");
			k = 0;
			while (constraintLabels[i][k] != '|' && k < 99)
				{
				fprintf (fp, "%c", constraintLabels[i][k]);
				k++;
				}
			fprintf (fp, "\"\n");

			lnSeqProb = 0.0;
			for (c=0; c<nChar; c++)
				{
				if (patternId[c] >= 0)
					{
					pat = patternId[c];
					fprintf (fp, "%4d %4d -- ", c+1, pat);
					fprintf (fp, "%lf %lf %lf %lf ", 
						ancStatesProbs[i*nChar*4 + c*4 + A] / nSampled, ancStatesProbs[i*nChar*4 + c*4 + C] / nSampled,
						ancStatesProbs[i*nChar*4 + c*4 + G] / nSampled, ancStatesProbs[i*nChar*4 + c*4 + T] / nSampled);
					maxProb = -1.0;
					bestNuc = 'N';
					if (ancStatesProbs[i*nChar*4 + c*4 + A] > maxProb)
						{
						maxProb = ancStatesProbs[i*nChar*4 + c*4 + A];
						bestNuc = 'A';
						}
					if (ancStatesProbs[i*nChar*4 + c*4 + C] > maxProb)
						{
						maxProb = ancStatesProbs[i*nChar*4 + c*4 + C];
						bestNuc = 'C';
						}
					if (ancStatesProbs[i*nChar*4 + c*4 + G] > maxProb)
						{
						maxProb = ancStatesProbs[i*nChar*4 + c*4 + G];
						bestNuc = 'G';
						}
					if (ancStatesProbs[i*nChar*4 + c*4 + T] > maxProb)
						{
						maxProb = ancStatesProbs[i*nChar*4 + c*4 + T];
						bestNuc = 'T';
						}
					lnSeqProb += log(maxProb/nSampled);
					fprintf (fp, "%c\n", bestNuc); 						
						
					}
				}
				
			fprintf (fp, "Most probable sequence [ln(Probability) = %lf]:\n", lnSeqProb);
			for (c=0; c<nChar; c++)
				{
				if (patternId[c] >= 0)
					{
					pat = patternId[c];
					maxProb = -1.0;
					bestNuc = 'N';
					if (ancStatesProbs[i*nChar*4 + c*4 + A] > maxProb)
						{
						maxProb = ancStatesProbs[i*nChar*4 + c*4 + A];
						bestNuc = 'A';
						}
					if (ancStatesProbs[i*nChar*4 + c*4 + C] > maxProb)
						{
						maxProb = ancStatesProbs[i*nChar*4 + c*4 + C];
						bestNuc = 'C';
						}
					if (ancStatesProbs[i*nChar*4 + c*4 + G] > maxProb)
						{
						maxProb = ancStatesProbs[i*nChar*4 + c*4 + G];
						bestNuc = 'G';
						}
					if (ancStatesProbs[i*nChar*4 + c*4 + T] > maxProb)
						{
						maxProb = ancStatesProbs[i*nChar*4 + c*4 + T];
						bestNuc = 'T';
						}
					fprintf (fp, "%c", bestNuc); 						
					}
				}
			fprintf (fp, "\n");
			fclose (fp);
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	if (nst == 6 || nst == 12)
		{
		free_psdmatrix (q);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex != YES)
			free (c_ijk);
		}
#	endif
	free (catFreq);
	free (ancCls);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (f);
		free (tempRatePr);
		}
	return (NO_ERROR);
	
	error_exit:
#		if !defined (SMART_TI_PROBS)
		free_psdmatrix (probs);
		free (pL);
		if (nst == 6 || nst == 12)
			{
			free_psdmatrix (q);
			free (eigenValues);
			free_psdmatrix (eigvecs);
			free_psdmatrix (inverseEigvecs);
			free_pscmatrix (Ceigvecs);
			free_pscmatrix (CinverseEigvecs);
			if (isComplex != YES)
				free (c_ijk);
			}
#		endif
		free (catFreq);
		free (ancCls);
		if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			free_psdmatrix(markovTi);
			free (f);
			free (tempRatePr);
			}
		return (ERROR);

#undef N_STATES
#undef N_STATES_SQUARED
#undef N_STATES_CUBE
}





int PrintAncStatesAA (int whichState, int whichChain, int numChars, int numRateCats, int whichGen)

{
#define N_STATES 20
#define N_STATES_SQUARED 400
#define N_STATES_CUBE 8000

	register int	i, j, k, c, m, n, n1, l;
	int				lnumRateCats, lnPartitions, oneMatSize, oneNodeSize,
					index, nRates, pat,
					intNodeOffset, allNodeOffset, condLikeOffset;
	double			bs[N_STATES], *pL, *pR, *pA, *catFreq, *catRate, *partRate,
					*clL, *clR, *clA, *clP, *ancCls,
					*lnScaler, correlation, lnSeqProb, maxProb,
					**markovTi, like[N_STATES], sum, postProb[N_STATES], *f, *b, *expPr, *logCf, 
					*logCb, *tempRatePr, *rateProbs, logC, temp, logLike, likeL, likeR, likeA;
	char			tempFile[100], bestNuc;
	TreeNode		*p, *r, *rDn, *rUp;
	FILE			*fp, *fopen();
#	if defined (SMART_TI_PROBS)
	int				nForOneState;
#	else
	int				isComplex, indexL, indexR, indexA, nPij;
	double			v, theRate, **probs, **q, *eigenValues, *eigvalsImag, **eigvecs, **inverseEigvecs, *c_ijk;
	complex 		**Ceigvecs, **CinverseEigvecs;	
#	endif

	/* initialize intNodeOffset */
	intNodeOffset = whichChain*2*numIntNodes + whichState*numIntNodes;
	allNodeOffset = whichChain*2*numNodes    + whichState*numNodes;

	/* initialize offset for transition probabilities */
#	if defined (SMART_TI_PROBS)
	nForOneState = numNodes*nodeTiSize;
#	endif

	/* load base frequencies */
	index = whichChain*2*N_STATES + whichState*N_STATES;
	for (i=0; i<N_STATES; i++)
		bs[i] = baseFreq[index + i];
	
	/* how many different rates? */
	/* lnumRateCats contains a local copy of numRateCats if appropriate, else 1 */
	/* lnPartitions contains a local copy of nPartitions if appropriate, else 1 */
	/* the code introduced here only makes sure that the number of partitions */
	/* or rate categories is set to 1 when appropriate, in case the global variables */
	/* are not set to 1 when they are not "in use" */
	if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		lnPartitions = nPartitions;
	else
		lnPartitions = 1;

	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		lnumRateCats = 1;
	else
		lnumRateCats = numRateCats;
	nRates = lnPartitions * lnumRateCats;		// number of rates needing P matrices

	/* allocate memory for the calculations */
	/* pL, pR and pA will contain the transition probs for Left, Right and Anc */
	/* One transition probability matrix is needed for each possible rate */
#	if !defined (SMART_TI_PROBS)
	probs = psdmatrix (N_STATES);
	nPij = nRates * N_STATES_SQUARED;
	pL = (double *)malloc((size_t)(3 * nPij * sizeof(double)));
	if (!pL)
		{
		printf ("\n   ERROR: Problem allocating Pij\n");
		goto error_exit;
		}
	pR = pL + nPij;
	pA = pR + nPij;
#	endif

	/* allocate memory for rate and rate category frequencies */
	catFreq = (double *)malloc((size_t) ((2 * lnumRateCats + lnPartitions) * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}
	catRate = catFreq + lnumRateCats;
	partRate = catRate + lnumRateCats;

	/* allocate memory for ancestral conditional likelihoods (it may be a tip, and we don't want to overwrite these cls) */
	ancCls = (double *)malloc((size_t) (lnumRateCats * numChars * N_STATES * sizeof(double)));
	if (!ancCls)
		{
		printf ("\n   ERROR: Problem allocating space for rate multipliers and rate category freqs.\n");
		goto error_exit;
		}

	/* allocate memory for autocorrelated gamma models */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		f = (double *)malloc((size_t) (((lnumRateCats * nChar) * 2 + lnumRateCats + nChar*2) * sizeof(double)));
		if (!f)
			{
			printf ("\n   ERROR: Problem allocating f.\n");
			goto error_exit;
			}
		b     = f + lnumRateCats * nChar;
		expPr = b + lnumRateCats * nChar;
		logCf = expPr + lnumRateCats;
		logCb = logCf + nChar;
		for (i=0; i<lnumRateCats*nChar; i++)
			f[i] = b[i] = 0.0;
		for (i=0; i<lnumRateCats; i++)
			expPr[i] = 0.0;
		for (i=0; i<nChar; i++)
			logCf[i] = logCb[i] = 0.0;
		tempRatePr = (double *)malloc((size_t) ((numChars * lnumRateCats + nChar * lnumRateCats) * sizeof(double)));
		if (!tempRatePr)
			{
			printf ("\n   ERROR: Problem allocating tempRatePr.\n");
			goto error_exit;
			}
		rateProbs = tempRatePr + numChars * lnumRateCats;
		for (i=0; i<nChar * lnumRateCats; i++)
			rateProbs[i] = 0.0;
		}

	// set pointer to the lnSiteScaler for this tree
	lnScaler = &lnSiteScaler[whichChain * 2 * numChars + whichState * numChars];
			
	/* fill in rate categories with frequencies and rates by dividing the */
	/* gamma distribution into discrete categories, if appropriate */
	/* NB! this is inefficient; store values instead */
	if (!strcmp(ratesModel,"gamma")|| !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		markovTi = psdmatrix (lnumRateCats);
		AutodGamma (markovTi, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], lnumRateCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], lnumRateCats-1, 0);
		catRate[lnumRateCats-1] = 0.0;
		catFreq[lnumRateCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<lnumRateCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else {		// "sitespec" or "equal"
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}

	/* initialize partition rates, if appropriate */
	if (lnPartitions > 1)
		{
		for (i=0; i<lnPartitions; i++)
			partRate[i] = scaledRates[whichChain*2*lnPartitions + whichState*lnPartitions + i];
		}
	else
		partRate[0] = 1.0;
		
	/* get eigenvalues and eigenvectors if nst=6 or nst=12 */
#	if !defined (SMART_TI_PROBS)
	q = psdmatrix (N_STATES);
	eigenValues = (double *)malloc((size_t) (2 * N_STATES * sizeof(double)));
	if (!eigenValues)
		{
		printf ("\n   ERROR: Problem allocating eigenValues and eigvalsImag.\n");
		goto error_exit;
		}
	eigvalsImag = eigenValues + N_STATES;
	eigvecs = psdmatrix (N_STATES);
	inverseEigvecs = psdmatrix (N_STATES);
	Ceigvecs = pscmatrix (N_STATES);
	CinverseEigvecs = pscmatrix (N_STATES);
	if (SetAAQMatrix (q, whichState, whichChain) == ERROR)
		goto error_exit;
	isComplex = GetEigens (N_STATES, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
	if (isComplex == NO)
		{
		c_ijk = (double *)malloc((size_t) (N_STATES_CUBE * sizeof(double)));
		if (!c_ijk)
			{
			printf ("\n   ERROR: Problem allocating c_ijk.\n");
			goto error_exit;
			}
		CalcCijk (c_ijk, N_STATES, eigvecs, inverseEigvecs);
		}
#	endif

	/* how large is the information for one tree and one node*/
	oneMatSize = numNodes * numChars * lnumRateCats * N_STATES;
	oneNodeSize = numChars * lnumRateCats * N_STATES;

	/* offset for conditional likelihoods */
	condLikeOffset = whichChain*2*oneMatSize + whichState*oneMatSize;

	/* pass down tree, finding nodes that are to have ancestral states estimated */
	for (n=0; n<numNodes; n++)
		{
		p = allNodesDownPassSeq[allNodeOffset + n];
		
		if (p->isConstrained == YES)
			{
			/* mark nodes below p */
			for (n1=0; n1<numNodes; n1++)
				{
				r = allNodesDownPassSeq[allNodeOffset + n1];
				r->flag = 0;
				if (r == p)
					r->flag = 1;
				if (r->left != NULL && r->right != NULL)
					{
					if (r->left->flag == 1 || r->right->flag == 1)
						r->flag = 1;
					}
				}		
			
			/* get conditional likelihoods down tree */
			for (n1=0; n1<numIntNodes; n1++)
				{
				r = intNodeDownPassSeq[intNodeOffset + n1];
				if (r->flag != 1)
					{
					//printf ("visiting interior node %d dn\n", r->index);
					/* get transition probabilities */
#					if defined (SMART_TI_PROBS)
					pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->left->index)*nodeTiSize);
					pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->right->index)*nodeTiSize);
#					else
					for (m=indexL=indexR=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for left branch
							if (isComplex == NO)
								CalcPij (c_ijk, N_STATES, eigenValues, r->left->length, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, r->left->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<N_STATES; i++)
								for (j=0; j<N_STATES; j++)
									pL[indexL++] = probs[i][j];
							
							// calculate transition probabilities for right branch
							if (isComplex == NO)
								CalcPij (c_ijk, N_STATES, eigenValues, r->right->length, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, r->right->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<N_STATES; i++)
								for (j=0; j<N_STATES; j++)
									pR[indexR++] = probs[i][j];							
							}
						}
#					endif

					/* first set pointers to cond likes of left, right and p */
					clL = &condLike[condLikeOffset + (r->left->index)*oneNodeSize];
					clR = &condLike[condLikeOffset + (r->right->index)*oneNodeSize];
					clP = &condLike[condLikeOffset + (r->index)*oneNodeSize];

					if (!strcmp(ratesModel, "equal"))
						{
						for (c=0; c<numChars; c++)
							{
							for (i=m=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						}
					else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
						{
						for (c=0; c<numChars; c++)
							{
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += N_STATES;
								clR += N_STATES;
								}
							}
						}
					else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
						{
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += N_STATES;
								clR += N_STATES;
								}
							}
						}
					else if (!strcmp(ratesModel, "sitespec"))
						{
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*N_STATES_SQUARED;
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						}
					}
				}
			
			/* get conditional likelihoods up tree */
			for (n1=numIntNodes-1; n1>=0; n1--)
				{
				r = intNodeDownPassSeq[intNodeOffset + n1];
				if (r->flag == 1 && p != r)
					{
					rDn = r->anc;
					if (r->left->flag == 0)
						rUp = r->left;
					else
						rUp = r->right;

					//printf ("visiting interior node %d up\n", r->index);
					/* get transition probabilities */
#					if defined (SMART_TI_PROBS)
					pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (rUp->index)*nodeTiSize);
					pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->index)*nodeTiSize);
#					else
					for (m=indexL=indexR=0; m<lnPartitions; m++)
						{
						for (k=0; k<lnumRateCats; k++)
							{
							theRate = partRate[m] * catRate[k];
							// calculate transition probabilities for left branch
							if (isComplex == NO)
								CalcPij (c_ijk, N_STATES, eigenValues, rUp->length, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, rUp->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<N_STATES; i++)
								for (j=0; j<N_STATES; j++)
									pL[indexL++] = probs[i][j];
							
							// calculate transition probabilities for right branch
							if (isComplex == NO)
								CalcPij (c_ijk, N_STATES, eigenValues, r->length, theRate, probs);
							else
								if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, r->length, theRate) == ERROR) 
									{
									printf ("Problem calculating transition probabilities for complex eigen values.\n");
									goto error_exit;
									}
							for (i=0; i<N_STATES; i++)
								for (j=0; j<N_STATES; j++)
									pR[indexR++] = probs[i][j];							
							}
						}
#					endif

					/* first set pointers to cond likes of left, right and p */
					clL = &condLike[condLikeOffset + (rUp->index)*oneNodeSize];
					clR = &condLike[condLikeOffset + (rDn->index)*oneNodeSize];
					clP = &condLike[condLikeOffset + (r->index)*oneNodeSize];

					if (!strcmp(ratesModel, "equal"))
						{
						for (c=0; c<numChars; c++)
							{
							for (i=m=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						}
					else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
						{
						for (c=0; c<numChars; c++)
							{
							for (k=m=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += N_STATES;
								clR += N_STATES;
								}
							}
						}
					else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
						{
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
							for (k=0; k<lnumRateCats; k++)
								{
								for (i=0; i<N_STATES; i++)
									{
									likeL = likeR = 0.0;
									for (j=0; j<N_STATES; j++)
										{
										likeL += pL[m]*clL[j];
										likeR += pR[m++]*clR[j];
										}
									*(clP++) = likeL * likeR;
									}
								clL += N_STATES;
								clR += N_STATES;
								}
							}
						}
					else if (!strcmp(ratesModel, "sitespec"))
						{
						for (c=0; c<numChars; c++)
							{
							m = partitionId[c]*N_STATES_SQUARED;
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m++]*clR[j];
									}
								*(clP++) = likeL * likeR;
								}
							clL += N_STATES;
							clR += N_STATES;
							}
						}
					}
				}
			
			/* get conditional probabilities of states at p */
			//printf ("getting condlikes at p %d\n", p->index);
			/* get transition probabilities */
#			if defined (SMART_TI_PROBS)
			if (p->left == NULL || p->right == NULL || p->anc == NULL)
				{
				if (p->anc == NULL)
					pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->left->index)*nodeTiSize);
				else
					pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (p->index)*nodeTiSize);
				}
			else
				{
				pL = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->left->index)*nodeTiSize);
				pR = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->right->index)*nodeTiSize);
				pA = transitionProbs + (whichChain*2*nForOneState + whichState*nForOneState + (r->index)*nodeTiSize);
				}
#			else
			if (p->left == NULL || p->right == NULL || p->anc == NULL)
				{
				if (p->anc == NULL)
					v = p->left->length;
				else
					v = p->length;
				for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						// calculate transition probabilities for ancestral branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, v, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, v, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pA[indexA++] = probs[i][j];
						}
					}
				}
			else
				{
				for (m=indexL=indexR=indexA=0; m<lnPartitions; m++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						theRate = partRate[m] * catRate[k];
						// calculate transition probabilities for left branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->left->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->left->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pL[indexL++] = probs[i][j];
						
						// calculate transition probabilities for right branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->right->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->right->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pR[indexR++] = probs[i][j];

						// calculate transition probabilities for ancestral branch
						if (isComplex == NO)
							CalcPij (c_ijk, N_STATES, eigenValues, p->length, theRate, probs);
						else
							if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, N_STATES, probs, p->length, theRate) == ERROR) 
								{
								printf ("Problem calculating transition probabilities for complex eigen values.\n");
								goto error_exit;
								}
						for (i=0; i<N_STATES; i++)
							for (j=0; j<N_STATES; j++)
								pA[indexA++] = probs[i][j];
						}
					}
				}				
#			endif

			if (p->left == NULL || p->right == NULL || p->anc == NULL)
				{
				//clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				clP = ancCls;
				if (p->anc == NULL)
					clA = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				else
					clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];

				if (!strcmp(ratesModel, "equal"))
					{
					for (c=0; c<numChars; c++)
						{
						for (i=m=0; i<N_STATES; i++)
							{
							likeA = 0.0;
							for (j=0; j<N_STATES; j++)
								{
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeA;
							}
						clA += N_STATES;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						for (k=m=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								likeA = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeA;
								}
							clA += N_STATES;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								likeA = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeA;
								}
							clA += N_STATES;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*N_STATES_SQUARED;
						for (i=0; i<N_STATES; i++)
							{
							likeA = 0.0;
							for (j=0; j<N_STATES; j++)
								{
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeA;
							}
						clA += N_STATES;
						}
					}
				}
			else
				{
				/* first set pointers to cond likes of left, right, p and anc */
				clL = &condLike[condLikeOffset + (p->left->index)*oneNodeSize];
				clR = &condLike[condLikeOffset + (p->right->index)*oneNodeSize];
				clA = &condLike[condLikeOffset + (p->anc->index)*oneNodeSize];
				//clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				clP = ancCls;

				if (!strcmp(ratesModel, "equal"))
					{
					for (c=0; c<numChars; c++)
						{
						for (i=m=0; i<N_STATES; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (j=0; j<N_STATES; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m]*clR[j];
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						clL += N_STATES;
						clR += N_STATES;
						clA += N_STATES;
						}
					}
				else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						for (k=m=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += N_STATES;
							clR += N_STATES;
							clA += N_STATES;
							}
						}
					}
				else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*lnumRateCats*N_STATES_SQUARED;
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								{
								likeL = likeR = likeA = 0.0;
								for (j=0; j<N_STATES; j++)
									{
									likeL += pL[m]*clL[j];
									likeR += pR[m]*clR[j];
									likeA += pA[m++]*clA[j];
									}
								*(clP++) = likeL * likeR * likeA;
								}
							clL += N_STATES;
							clR += N_STATES;
							clA += N_STATES;
							}
						}
					}
				else if (!strcmp(ratesModel, "sitespec"))
					{
					for (c=0; c<numChars; c++)
						{
						m = partitionId[c]*N_STATES_SQUARED;
						for (i=0; i<N_STATES; i++)
							{
							likeL = likeR = likeA = 0.0;
							for (j=0; j<N_STATES; j++)
								{
								likeL += pL[m]*clL[j];
								likeR += pR[m]*clR[j];
								likeA += pA[m++]*clA[j];
								}
							*(clP++) = likeL * likeR * likeA;
							}
						clL += N_STATES;
						clR += N_STATES;
						clA += N_STATES;
						}
					}
				}						
			
			/* calculate posterior probability of states at p */
			//clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
			clP = ancCls;
			if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
				{
				for (c=0; c<nChar; c++)
					{
					pat = patternId[c];
					if (pat >= 0)
						{
						sum = 0.0;
						for (i=0; i<N_STATES; i++)
							{
							like[i] = clP[pat*N_STATES + i];
							sum += like[i] * bs[i];
							}
						for (i=0; i<N_STATES; i++)
							{
							postProb[i] = (like[i] * bs[i]) / sum;
							tempStateProbs[(p->constraintNum-1)*nChar*N_STATES + c*N_STATES + i] = postProb[i];
							ancStatesProbs[(p->constraintNum-1)*nChar*N_STATES + c*N_STATES + i] += postProb[i];
							}
						}
					}
				}
			else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
				{
				for (c=0; c<nChar; c++)
					{
					pat = patternId[c];
					if (pat >= 0)
						{
						for (i=0; i<N_STATES; i++)
							like[i] = 0.0;
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								like[i] += clP[pat*lnumRateCats*N_STATES + k*N_STATES + i] * catFreq[k];
							}
						sum = 0.0;
						for (i=0; i<N_STATES; i++)
							sum += like[i] * bs[i];
						for (i=0; i<N_STATES; i++)
							{
							postProb[i] = (like[i] * bs[i]) / sum;
							tempStateProbs[(p->constraintNum-1)*nChar*N_STATES + c*N_STATES + i] = postProb[i];
							ancStatesProbs[(p->constraintNum-1)*nChar*N_STATES + c*N_STATES + i] += postProb[i];
							}
						}
					}
				}
			else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
				{
				/* get probabilities of observations conditioned on each category */
				for (c=0; c<numChars; c++)
					{
					for (k=0; k<lnumRateCats; k++)
						{
						tempRatePr[k * numChars + c] = 0.0;
						for (i=0; i<N_STATES; i++)
							tempRatePr[k * numChars + c] += clP[i] * bs[i];
						clP += N_STATES;
						}
					}

				/* forward algorithm */
				logC = 0.0;
				for (c=0; c<nChar; c++)
					{
					if (patternId[c] >= 0)
						{
						pat = patternId[c];
						if (c == 0)
							{
							for (k=0; k<lnumRateCats; k++)
								f[k*nChar + c] = tempRatePr[k * numChars + pat];
							}
						else
							{
							for (l=0; l<lnumRateCats; l++)
								{
								temp = 0.0;
								for (k=0; k<lnumRateCats; k++)
									temp += f[k * nChar + (c-1)] * markovTi[k][l];
								f[l * nChar + c] = temp * tempRatePr[l * numChars + pat];
								}
							}
						sum = 0.0;
						for (k=0; k<lnumRateCats; k++)
							sum += f[k*nChar + c];
						for (k=0; k<lnumRateCats; k++)
							f[k*nChar+c] /= sum;
						logC += log(sum);
						logCf[c] = logC;
						}
					else
						{
						
						}
					}

				/* backward algorithm */
				logC = 0.0;
				for (c=nChar-1; c>=0; c--)
					{
					if (patternId[c] >= 0)
						{
						if (c == nChar - 1)
							{
							for (k=0; k<lnumRateCats; k++)
								b[k * nChar + c] = catFreq[k];
							}
						else
							{
							pat = patternId[c+1];
							for (k=0; k<lnumRateCats; k++)
								{
								temp = 0.0;
								for (l=0; l<lnumRateCats; l++)
									temp += markovTi[k][l] * tempRatePr[l * numChars + pat] * b[l * nChar + (c+1)];
								b[k * nChar + c] = temp;
								}
							}
						sum = 0.0;
						for (k=0; k<lnumRateCats; k++)
							sum += b[k*nChar + c];
						for (k=0; k<lnumRateCats; k++)
							b[k*nChar+c] /= sum;
						logC += log(sum);
						logCb[c] = logC;
						}
					else
						{
						
						}
					}
				temp = 0.0;
				pat = patternId[0];
				for (l=0; l<lnumRateCats; l++)
					temp += tempRatePr[l * numChars + pat] * b[l * nChar + 0];
				logLike = log (temp) + logC;

				/* posterior probabilities of individual categories at site c */
				for (c=0; c<nChar; c++)
					{
					/*printf ("%d ", c+1);*/
					for (k=0; k<lnumRateCats; k++)
						{
						temp = (log(f[k * nChar + c]) + logCf[c] + log(b[k * nChar + c]) + logCb[c]) - logLike;
						if (temp > 0.0)
							expPr[k] = 1.0;
						else if (temp < -100.0)
							expPr[k] = 0.0;
						else
							expPr[k] = exp(temp);
						}
						
						
					for (k=0; k<lnumRateCats; k++)
						{
						rateProbs[c*lnumRateCats + k] += expPr[k];
						}
					}

				//clP = &condLike[condLikeOffset + (p->index)*oneNodeSize];
				clP = ancCls;
				for (c=0; c<nChar; c++)
					{
					pat = patternId[c];
					if (pat >= 0)
						{
						for (i=0; i<N_STATES; i++)
							like[i] = 0.0;
						for (k=0; k<lnumRateCats; k++)
							{
							for (i=0; i<N_STATES; i++)
								like[i] += clP[pat*lnumRateCats*N_STATES + k*N_STATES + i] * rateProbs[c*lnumRateCats + k];
							}
						sum = 0.0;
						for (i=0; i<N_STATES; i++)
							sum += like[i] * bs[i];
						for (i=0; i<N_STATES; i++)
							{
							postProb[i] = (like[i] * bs[i]) / sum;
							tempStateProbs[(p->constraintNum-1)*nChar*N_STATES + c*N_STATES + i] = postProb[i];
							ancStatesProbs[(p->constraintNum-1)*nChar*N_STATES + c*N_STATES + i] += postProb[i];
							}
						}
					}
				}
			}
		}
	
	/* summarize states */
	/* print probabilities to a file */
	if (nSampled == 1)
		{
		strcpy (tempFile, outFile);
		strcat (tempFile, ".sum.");
		for (i=0; i<nConstraints; i++)
			{
			strcat (tempFile, "1");
			if ((fp = fopen (tempFile, "r")) == NULL)  
				{
				if ((fp = fopen (tempFile, "w")) == NULL)  
					{
					printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
					goto error_exit;
					}
				}
			else
				{
				fclose (fp);
				if (autoclose == YES)
					{
					printf ("      Overwriting information to file %s\n", tempFile);
					if ((fp = fopen (tempFile, "w+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
						goto error_exit;
						}
					}
				else
					{
					printf ("\n      File \"%s\" already exists.\n      Overwrite? (yes/no): ", tempFile);
					if (YesNo() == YES)
						{
						printf ("      Overwriting information to file %s\n", tempFile);
						if ((fp = fopen (tempFile, "w+")) == NULL)  
							{
							printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
							goto error_exit;
							}
						}
					else
						{
						printf ("      Appending information to file %s\n", tempFile);
						if ((fp = fopen (tempFile, "a+")) == NULL)  
							{
							printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
							goto error_exit;
							}
						}
					}
				}
			fclose (fp);
			}
		}
		
	/* summarize states */
	if (whichGen == nGen && nSampled >= 1)
		{
		strcpy (tempFile, outFile);
		strcat (tempFile, ".sum.");
		for (i=0; i<nConstraints; i++)
			{
			strcat (tempFile, "1");
			if ((fp = fopen (tempFile, "a+")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile);
				goto error_exit;
				}
			fprintf (fp, "Summary of ancestral states at constraint \"");
			k = 0;
			while (constraintLabels[i][k] != '|' && k < 99)
				{
				fprintf (fp, "%c", constraintLabels[i][k]);
				k++;
				}
			fprintf (fp, "\"\n");

			lnSeqProb = 0.0;
			for (c=0; c<nChar; c++)
				{
				if (patternId[c] >= 0)
					{
					pat = patternId[c];
					fprintf (fp, "%4d %4d -- ", c+1, pat);
					for (j=0; j<N_STATES; j++)
						fprintf (fp, "%lf ", ancStatesProbs[i*nChar*N_STATES + c*N_STATES + j] / nSampled);
					maxProb = -1.0;
					bestNuc = 'N';
					for (j=0; j<N_STATES; j++)
						{
						if (ancStatesProbs[i*nChar*N_STATES + c*N_STATES + j] > maxProb)
							{
							maxProb = ancStatesProbs[i*nChar*N_STATES + c*N_STATES + j];
							bestNuc = WhichAA (j);
							}
						}
					lnSeqProb += log(maxProb/nSampled);
					fprintf (fp, "%c\n", bestNuc); 						
					}
				}
				
			fprintf (fp, "Most probable sequence [ln(Probability) = %lf]:\n", lnSeqProb);
			for (c=0; c<nChar; c++)
				{
				if (patternId[c] >= 0)
					{
					pat = patternId[c];
					maxProb = -1.0;
					bestNuc = 'N';
					for (j=0; j<N_STATES; j++)
						{
						if (ancStatesProbs[i*nChar*N_STATES + c*N_STATES + j] > maxProb)
							{
							maxProb = ancStatesProbs[i*nChar*N_STATES + c*N_STATES + j];
							bestNuc = WhichAA (j);
							}
						}
					fprintf (fp, "%c", bestNuc); 						
					}
				}
			fprintf (fp, "\n");
			fclose (fp);
			}
		}

	/* free memory */
#	if !defined (SMART_TI_PROBS)
	free_psdmatrix (probs);
	free (pL);
	free_psdmatrix (q);
	free (eigenValues);
	free_psdmatrix (eigvecs);
	free_psdmatrix (inverseEigvecs);
	free_pscmatrix (Ceigvecs);
	free_pscmatrix (CinverseEigvecs);
	if (isComplex != YES)
		free (c_ijk);
#	endif
	free (catFreq);
	free (ancCls);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free_psdmatrix(markovTi);
		free (f);
		free (tempRatePr);
		}
	return (NO_ERROR);
	
	error_exit:
#		if !defined (SMART_TI_PROBS)
		free_psdmatrix (probs);
		free (pL);
		free_psdmatrix (q);
		free (eigenValues);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex != YES)
			free (c_ijk);
#		endif
		free (catFreq);
		free (ancCls);
		if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			free_psdmatrix(markovTi);
			free (f);
			free (tempRatePr);
			}
		return (ERROR);

#undef N_STATES
#undef N_STATES_SQUARED
#undef N_STATES_CUBE
}





int PrintPosSelProbs (int whichState, int whichChain, int numChars, int numRateCats, int whichGen)

{

	int				i, k, c, l, oneMatSize, nLocalCats, nOff, kTimesS, pat;
	double			likePur, likeNeu, likePos, *clP, *bs, *tempProb, a[3][3], 
					*f, *b, *e, sum, logC, *logCf, *logCb, temp, logLike, x;
	char			tempFile1[100], tempFile2[100];
	FILE			*fp1, *fp2, *fopen();
	TreeNode		*p;
	
	/* open files, allocate some memory */
	strcpy (tempFile1, outFile);
	strcpy (tempFile2, outFile);
	strcat (tempFile1, ".possummary");
	strcat (tempFile2, ".posexhaust");
	if (nSampled == 1)
		{
		if ((fp1 = fopen (tempFile1, "r")) == NULL)  
			{
			if ((fp1 = fopen (tempFile1, "w")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
				goto error_exit;
				}
			}
		else
			{
			fclose (fp1);
			if (autoclose == YES)
				{
				printf ("      Overwriting information to file %s\n", tempFile1);
				if ((fp1 = fopen (tempFile1, "w+")) == NULL)  
					{
					printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
					goto error_exit;
					}
				}
			else
				{
				printf ("\n      File \"%s\" already exists.\n      Overwrite? (yes/no): ", tempFile1);
				if (YesNo() == YES)
					{
					printf ("      Overwriting information to file %s\n", tempFile1);
					if ((fp1 = fopen (tempFile1, "w+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
						goto error_exit;
						}
					}
				else
					{
					printf ("      Appending information to file %s\n", tempFile1);
					if ((fp1 = fopen (tempFile1, "a+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
						goto error_exit;
						}
					}
				}
			}
		if ((fp2 = fopen (tempFile2, "r")) == NULL)  
			{
			if ((fp2 = fopen (tempFile2, "w")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
				goto error_exit;
				}
			}
		else
			{
			fclose (fp2);
			if (autoclose == YES)
				{
				printf ("      Overwriting information to file %s\n", tempFile2);
				if ((fp2 = fopen (tempFile2, "w+")) == NULL)  
					{
					printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
					goto error_exit;
					}
				}
			else
				{
				printf ("\n      File \"%s\" already exists.\n      Overwrite? (yes/no): ", tempFile2);
				if (YesNo() == YES)
					{
					printf ("      Overwriting information to file %s\n", tempFile2);
					if ((fp2 = fopen (tempFile2, "w+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
						goto error_exit;
						}
					}
				else
					{
					printf ("      Appending information to file %s\n", tempFile2);
					if ((fp2 = fopen (tempFile2, "a+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
						goto error_exit;
						}
					}
				}
			}
			
		fprintf (fp2, "Probability that each site is in the positively selected category\n");
		for (i=0; i<(nChar/3); i++)
			{
			if (patternId[i] >= 0)
				{
				fprintf (fp2, "%d\t", i+1);
				}
			}
		fprintf (fp2, "\n");

		posSelProbs = (double *)malloc((size_t) ((nChar/3) * sizeof(double)));
		if (!posSelProbs)
			{
			printf ("\n   ERROR: Problem allocating posSelProbs.\n");
			goto error_exit;
			}
		for (i=0; i<(nChar/3); i++)
			posSelProbs[i] = 0.0;
		}
	else
		{
		if ((fp1 = fopen (tempFile1, "a+")) == NULL)  
			{
			printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
			goto error_exit;
			}
		if ((fp2 = fopen (tempFile2, "a+")) == NULL)  
			{
			printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
			goto error_exit;
			}
		}
		
		
	/* start calculations of posterior probabilities by initializing necessary variables*/
	if (!strcmp(codonModelType, "ac1ny98"))
		InitTiMatrix (a, rateCorrelation[whichChain*2 + whichState], 0.0, 0.0, probPur[whichChain*2 + whichState], probNeu[whichChain*2 + whichState], probPos[whichChain*2 + whichState], 1);
	else if (!strcmp(codonModelType, "ac2ny98"))
		InitTiMatrix (a, rateCorrelation[whichChain*2 + whichState], rateCorrelation2[whichChain*4 + whichState*2 + 0], rateCorrelation2[whichChain*4 + whichState*2 + 1], probPur[whichChain*2 + whichState], probNeu[whichChain*2 + whichState], probPos[whichChain*2 + whichState], 2);
	if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		f = (double *)malloc((size_t) (3 * (nChar/3) * sizeof(double)));
		if (!f)
			{
			printf ("\n   ERROR: Problem allocating f.\n");
			goto error_exit;
			}
		for (i=0; i<3*(nChar/3); i++)
			f[i] = 0.0;
		b = (double *)malloc((size_t) (3 * (nChar/3) * sizeof(double)));
		if (!b)
			{
			printf ("\n   ERROR: Problem allocating b.\n");
			goto error_exit;
			}
		for (i=0; i<3*(nChar/3); i++)
			b[i] = 0.0;
		e = (double *)malloc((size_t) (3 * (nChar/3) * sizeof(double)));
		if (!e)
			{
			printf ("\n   ERROR: Problem allocating e.\n");
			goto error_exit;
			}
		for (i=0; i<3*(nChar/3); i++)
			e[i] = 0.0;
		logCf = (double *)malloc((size_t) ((nChar/3) * sizeof(double)));
		if (!logCf)
			{
			printf ("\n   ERROR: Problem allocating f.\n");
			goto error_exit;
			}
		for (i=0; i<(nChar/3); i++)
			logCf[i] = 0.0;
		logCb = (double *)malloc((size_t) ((nChar/3) * sizeof(double)));
		if (!logCb)
			{
			printf ("\n   ERROR: Problem allocating b.\n");
			goto error_exit;
			}
		for (i=0; i<(nChar/3); i++)
			logCb[i] = 0.0;
		}
	bs = (double *)malloc((size_t) (nStates * sizeof(double)));
	if (!bs)
		{
		printf ("\n   ERROR: Problem allocating bs.\n");
		goto error_exit;
		}
	for (i=0; i<nStates; i++)
		bs[i] = baseFreq[whichChain*2*nStates + whichState*nStates + i];
	if (!strcmp(codonModelType, "ny98"))
		{
		tempProb = (double *)malloc((size_t) (numChars * sizeof(double)));
		if (!tempProb)
			{
			printf ("\n   ERROR: Problem allocating tempProb.\n");
			goto error_exit;
			}
		}
	else
		{
		tempProb = (double *)malloc((size_t) (3 * numChars * sizeof(double)));
		if (!tempProb)
			{
			printf ("\n   ERROR: Problem allocating tempProb.\n");
			goto error_exit;
			}
		}

	/* calculate posterior probabilities */
	if (!strcmp(codonModelType, "ny98"))
		{
		nLocalCats = numRateCats;
		oneMatSize = numNodes * numChars * nLocalCats * nStates;
		p = root[whichChain*2 + whichState]->left;
		clP = &condLike[whichChain*2*oneMatSize + whichState*oneMatSize + (p->index)*numChars*numRateCats*nStates];
		nOff = numRateCats*nStates;
		for (c=0; c<numChars; c++, *(clP+=nOff))
			{
			likePur = likeNeu = likePos = 0.0;
			
			for (i=0; i<nStates; i++)
				likePos += clP[i] * bs[i];
			for (i=0; i<nStates; i++)
				likePur += clP[nStates + i] * bs[i];
			kTimesS = 2 * nStates;
			for (i=0; i<nStates; i++)
				likeNeu += clP[kTimesS + i] * bs[i];
				
			//printf ("%4d -- %lf %lf %lf\n", c, likePos, likePur, likeNeu);
				
			tempProb[c] = (likePos * probPos[whichChain*2 + whichState]) / (likePos * probPos[whichChain*2 + whichState] + likePur * probPur[whichChain*2 + whichState] + likeNeu * probNeu[whichChain*2 + whichState]);
			}

		for (i=0; i<(nChar/3); i++)
			{
			if (patternId[i] >= 0)
				{
				pat = patternId[i];
				fprintf (fp2, "%1.4lf\t", tempProb[pat]);
				
				posSelProbs[i] += tempProb[pat];
				}
			}
		fprintf (fp2, "\n");
		}
	else if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		/* get emission probabilities */
		nLocalCats = numRateCats;
		oneMatSize = numNodes * numChars * nLocalCats * nStates;
		p = root[whichChain*2 + whichState]->left;
		clP = &condLike[whichChain*2*oneMatSize + whichState*oneMatSize + (p->index)*numChars*numRateCats*nStates];
		nOff = numRateCats * nStates;
		for (c=0; c<numChars; c++, *(clP+=nOff))
			{
			likePur = likeNeu = likePos = 0.0;
			
			for (i=0; i<nStates; i++)
				likePos += clP[i] * bs[i];
			for (i=0; i<nStates; i++)
				likePur += clP[nStates + i] * bs[i];
			kTimesS = 2 * nStates;
			for (i=0; i<nStates; i++)
				likeNeu += clP[kTimesS + i] * bs[i];
			tempProb[0 * numChars + c] = likePur;
			tempProb[1 * numChars + c] = likeNeu;
			tempProb[2 * numChars + c] = likePos;
			}
		for (i=0; i<(nChar/3); i++)
			{
			if (patternId[i] >= 0)
				{
				pat = patternId[i];
				e[0 * (nChar/3) + i] = tempProb[0 * numChars + pat];
				e[1 * (nChar/3) + i] = tempProb[1 * numChars + pat];
				e[2 * (nChar/3) + i] = tempProb[2 * numChars + pat];
				}
			}
		/* forward algorithm */
		logC = 0.0;
		for (i=0; i<(nChar/3); i++)
			{
			if (i == 0)
				{
				for (k=0; k<3; k++)
					f[k * (nChar/3) + i] = e[k * (nChar/3) + i];
				}
			else
				{
				for (l=0; l<3; l++)
					{
					temp = 0.0;
					for (k=0; k<3; k++)
						temp += f[k * (nChar/3) + (i-1)] * a[k][l];
					f[l * (nChar/3) + i] = temp * e[l * (nChar/3) + i];
					}
				}
			sum = 0.0;
			for (k=0; k<3; k++)
				sum += f[k * (nChar/3) + i];
			for (k=0; k<3; k++)
				f[k * (nChar/3)+i] /= sum;
			logC += log(sum);
			logCf[i] = logC;
			}
		temp =  f[0 * (nChar/3) + ((nChar/3)-1)] * probPur[whichChain*2 + whichState];
		temp += f[1 * (nChar/3) + ((nChar/3)-1)] * probNeu[whichChain*2 + whichState];
		temp += f[2 * (nChar/3) + ((nChar/3)-1)] * probPos[whichChain*2 + whichState];
		logLike = log(temp) + logC;

		/* backward algorithm */
		logC = 0.0;
		for (i=(nChar/3)-1; i>=0; i--)
			{
			if (i == (nChar/3) - 1)
				{
				b[0 * (nChar/3) + i] = probPur[whichChain*2 + whichState];
				b[1 * (nChar/3) + i] = probNeu[whichChain*2 + whichState];
				b[2 * (nChar/3) + i] = probPos[whichChain*2 + whichState];
				}
			else
				{
				for (k=0; k<3; k++)
					{
					temp = 0.0;
					for (l=0; l<3; l++)
						temp += a[k][l] * e[l * (nChar/3) + (i+1)] * b[l * (nChar/3) + (i+1)];
					b[k * (nChar/3) + i] = temp;
					}
				}
			sum = 0.0;
			for (k=0; k<3; k++)
				sum += b[k * (nChar/3) + i];
			for (k=0; k<3; k++)
				b[k * (nChar/3) + i] /= sum;
			logC += log(sum);
			logCb[i] = logC;
			}
			
		temp = 0.0;
		for (l=0; l<3; l++)
			temp += e[l * (nChar/3) + 0] * b[l * (nChar/3) + 0];
		logLike = log (temp) + logC;

		for (i=0; i<(nChar/3); i++)
			{
			temp = (log(f[2 * (nChar/3) + i]) + logCf[i] + log(b[2 * (nChar/3) + i]) + logCb[i]) - logLike;
			if (temp > 0.0)
				x = 1.0;
			else if (temp < -100.0)
				x = 0.0;
			else
				x = exp(temp);
			fprintf (fp2, "%1.4lf\t", x);
			posSelProbs[i] += x;
			//printf ("%4d -- %lf %lf\n", i+1, temp, x);
			}
		fprintf (fp2, "\n");
		}
	else
		{
		printf ("\n   ERROR: Unknown model for positive selection.\n");
		goto error_exit;
		}
		

	/* print summary of probabilities to a file */
	if (whichGen == nGen && nSampled >= 1)
		{
		fprintf (fp1, "Summary of posterior probability of being in positively selected class\n");
		for (i=0; i<(nChar/3); i++)
			{
			fprintf (fp1, "%d\t%1.4lf\n", i+1, posSelProbs[i] / nSampled);
			}
		free (posSelProbs);
		}
				
	free (bs);
	free (tempProb);
	fclose (fp1);
	fclose (fp2);
	if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
		{
		free (f);
		free (b);
		free (e);
		free (logCf);
		free (logCb);
		}
	return (NO_ERROR);
	
	error_exit:
		free (bs);
		free (tempProb);
#if defined (MORPH)
		if (fp1 != NULL)
			fclose (fp1);
		if (fp2 != NULL)
			fclose (fp2);
#else
		fclose (fp1);
		fclose (fp2);
#endif
		free (posSelProbs);
		if (!strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
			{
			free (f);
			free (b);
			free (e);
			free (logCf);
			free (logCb);
			}
		return (ERROR);
	
}





int PrintRateFactors (int whichState, int whichChain, int numChars, int numRateCats, int whichGen)

{

	int				i, k, c, l, oneMatSize, nLocalCats, nOff, kTimesS, pat;
	double			*clP, *bs, *tempRatePr, **a, correlation, like, *aveRate,
					*f, *b, *expPr, sum, logC, *logCf, *logCb, temp, logLike, x, mult, *catFreq, *catRate;
	char			tempFile1[100], tempFile2[100];
	FILE			*fp1, *fp2, *fopen();
	TreeNode		*p;

	/* calculate number of rate categories */
	if (!strcmp(ratesModel, "equal"))
		nLocalCats = 1;
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
		nLocalCats = numRateCats;
	else if (!strcmp(ratesModel, "sitespec"))
		nLocalCats = nPartitions;
	else if (!strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
		nLocalCats = numRateCats;
	
	/* open files, allocate some memory */
	strcpy (tempFile1, outFile);
	strcat (tempFile1, ".ratesummary");
	strcpy (tempFile2, outFile);
	strcat (tempFile2, ".exhaustrates");
	if (nSampled == 1)
		{
		if ((fp1 = fopen (tempFile1, "r")) == NULL)  
			{
			if ((fp1 = fopen (tempFile1, "w")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
				goto error_exit;
				}
			}
		else
			{
			fclose (fp1);
			if (autoclose == YES)
				{
				printf ("      Overwriting information to file %s\n", tempFile1);
				if ((fp1 = fopen (tempFile1, "w+")) == NULL)  
					{
					printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
					goto error_exit;
					}
				}
			else
				{
				printf ("\n      File \"%s\" already exists.\n      Overwrite? (yes/no): ", tempFile1);
				if (YesNo() == YES)
					{
					printf ("      Overwriting information to file %s\n", tempFile1);
					if ((fp1 = fopen (tempFile1, "w+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
						goto error_exit;
						}
					}
				else
					{
					printf ("      Appending information to file %s\n", tempFile1);
					if ((fp1 = fopen (tempFile1, "a+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
						goto error_exit;
						}
					}
				}
			}
		if ((fp2 = fopen (tempFile2, "r")) == NULL)  
			{
			if ((fp2 = fopen (tempFile2, "w")) == NULL)  
				{
				printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
				goto error_exit;
				}
			}
		else
			{
			fclose (fp2);
			if (autoclose == YES)
				{
				printf ("      Overwriting information to file %s\n", tempFile2);
				if ((fp2 = fopen (tempFile2, "w+")) == NULL)  
					{
					printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
					goto error_exit;
					}
				}
			else
				{
				printf ("\n      File \"%s\" already exists.\n      Overwrite? (yes/no): ", tempFile2);
				if (YesNo() == YES)
					{
					printf ("      Overwriting information to file %s\n", tempFile2);
					if ((fp2 = fopen (tempFile2, "w+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
						goto error_exit;
						}
					}
				else
					{
					printf ("      Appending information to file %s\n", tempFile2);
					if ((fp2 = fopen (tempFile2, "a+")) == NULL)  
						{
						printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
						goto error_exit;
						}
					}
				}
			}
			
		fprintf (fp2, "Rate factor for each site\n");
		for (i=0; i<nChar; i++)
			{
			if (patternId[i] >= 0)
				{
				fprintf (fp2, "%d\t", i+1);
				}
			}
		fprintf (fp2, "\n");

		rateFactors = (double *)malloc((size_t) (nChar * sizeof(double)));
		if (!rateFactors)
			{
			printf ("\n   ERROR: Problem allocating rateFactors.\n");
			goto error_exit;
			}
		for (i=0; i<nChar; i++)
			rateFactors[i] = 0.0;

		if (!strcmp(ratesModel, "sitespec"))
			{
			rateProbs = (double *)malloc((size_t) (nChar * sizeof(double)));
			if (!rateProbs)
				{
				printf ("\n   ERROR: Problem allocating rateFactors.\n");
				goto error_exit;
				}
			for (i=0; i<nChar; i++)
				rateProbs[i] = 0.0;
			}
		else
			{
			rateProbs = (double *)malloc((size_t) (nChar * nLocalCats * sizeof(double)));
			if (!rateProbs)
				{
				printf ("\n   ERROR: Problem allocating rateFactors.\n");
				goto error_exit;
				}
			for (i=0; i<nChar*nLocalCats; i++)
				rateProbs[i] = 0.0;
			}
			
		}
	else
		{
		if ((fp1 = fopen (tempFile1, "a+")) == NULL)  
			{
			printf ("\n   ERROR: Could not open file (%s).\n", tempFile1);
			goto error_exit;
			}
		if ((fp2 = fopen (tempFile2, "a+")) == NULL)  
			{
			printf ("\n   ERROR: Could not open file (%s).\n", tempFile2);
			goto error_exit;
			}
		}
		
	/* start calculations of rate factors by initializing necessary variables*/
	catFreq = (double *)malloc((size_t) (nLocalCats * sizeof(double)));
	if (!catFreq)
		{
		printf ("\n   ERROR: Problem allocating catFreq.\n");
		goto error_exit;
		}
	catRate = (double *)malloc((size_t) (nLocalCats * sizeof(double)));
	if (!catRate)
		{
		printf ("\n   ERROR: Problem allocating catRate.\n");
		goto error_exit;
		}

	/* fill in rate categories */
	if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "ssgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], nLocalCats, 0);
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		a = psdmatrix (nLocalCats);
		AutodGamma (a, catFreq, catRate, &correlation, alpha[whichChain*2 + whichState], rateCorrelation[whichChain*2 + whichState], nLocalCats);
		}
	else if (!strcmp(ratesModel, "invgamma"))
		{
		DiscreteGamma (catFreq, catRate, alpha[whichChain*2 + whichState], alpha[whichChain*2 + whichState], nLocalCats-1, 0);
		catRate[nLocalCats-1] = 0.0;
		catFreq[nLocalCats-1] = invP[whichChain*2 + whichState];
		for (i=0; i<nLocalCats-1; i++)
			{
			catRate[i] *= 1.0 / (1.0 - invP[whichChain*2 + whichState]);
			catFreq[i] *= (1.0 - invP[whichChain*2 + whichState]);
			}
		}
	else if (!strcmp(ratesModel, "invariant"))
		{
		catRate[0] = 0.0;
		catRate[1] = 1.0 / (1.0 - invP[whichChain*2 + whichState]);
		catFreq[0] = invP[whichChain*2 + whichState];
		catFreq[1] = 1.0 - invP[whichChain*2 + whichState];
		}
	else if (!strcmp(ratesModel, "sitespec"))
		{
		for (i=0; i<nLocalCats; i++)
			{
			catRate[i] = scaledRates[whichChain*2*nLocalCats + whichState*nLocalCats + i];
			catFreq[i] = 1.0;
			}
		}
	else
		{
		catRate[0] = 1.0;
		catFreq[0] = 1.0;
		}
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		f = (double *)malloc((size_t) (nLocalCats * nChar * sizeof(double)));
		if (!f)
			{
			printf ("\n   ERROR: Problem allocating f.\n");
			goto error_exit;
			}
		for (i=0; i<nLocalCats*nChar; i++)
			f[i] = 0.0;
		b = (double *)malloc((size_t) (nLocalCats * nChar * sizeof(double)));
		if (!b)
			{
			printf ("\n   ERROR: Problem allocating b.\n");
			goto error_exit;
			}
		for (i=0; i<nLocalCats*nChar; i++)
			b[i] = 0.0;
		expPr = (double *)malloc((size_t) (nLocalCats * sizeof(double)));
		if (!expPr)
			{
			printf ("\n   ERROR: Problem allocating expPr.\n");
			goto error_exit;
			}
		for (i=0; i<nLocalCats; i++)
			expPr[i] = 0.0;
		logCf = (double *)malloc((size_t) (nChar * sizeof(double)));
		if (!logCf)
			{
			printf ("\n   ERROR: Problem allocating f.\n");
			goto error_exit;
			}
		for (i=0; i<nChar; i++)
			logCf[i] = 0.0;
		logCb = (double *)malloc((size_t) (nChar * sizeof(double)));
		if (!logCb)
			{
			printf ("\n   ERROR: Problem allocating b.\n");
			goto error_exit;
			}
		for (i=0; i<nChar; i++)
			logCb[i] = 0.0;
		}
	bs = (double *)malloc((size_t) (nStates * sizeof(double)));
	if (!bs)
		{
		printf ("\n   ERROR: Problem allocating bs.\n");
		goto error_exit;
		}
	for (i=0; i<nStates; i++)
		bs[i] = baseFreq[whichChain*2*nStates + whichState*nStates + i];
	tempRatePr = (double *)malloc((size_t) (numChars * nLocalCats * sizeof(double)));
	if (!tempRatePr)
		{
		printf ("\n   ERROR: Problem allocating tempRatePr.\n");
		goto error_exit;
		}
	aveRate = (double *)malloc((size_t) (nChar * nLocalCats * sizeof(double)));
	if (!aveRate)
		{
		printf ("\n   ERROR: Problem allocating aveRate.\n");
		goto error_exit;
		}

	oneMatSize = numNodes * numChars * numRateCats * nStates;

	/* calculate conditional probabilites at base of tree...f(x | r) */
	p = root[whichChain*2+whichState]->left;
	if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
		{
		clP = &condLike[whichChain*2*oneMatSize + whichState*oneMatSize + (p->index)*numChars*nStates];
		for (c=0; c<numChars; c++, *(clP+=nStates))
			{
			like = 0.0;
			for (i=0; i<nStates; i++)
				like += clP[i] * bs[i];
			tempRatePr[0 * numChars + c] = like;
			}
		}
	else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma"))
		{
		clP = &condLike[whichChain*2*oneMatSize + whichState*oneMatSize + (p->index)*numChars*nLocalCats*nStates];
		nOff = nLocalCats * nStates;
		for (c=0; c<numChars; c++, *(clP+=nOff))
			{
			for (k=0; k<nLocalCats; k++)
				{
				kTimesS = k * nStates;
				like = 0.0;
				for (i=0; i<nStates; i++)
					like += clP[kTimesS + i] * bs[i];
				tempRatePr[k * numChars + c] = like;
				}
			}
		}
	else if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		clP = &condLike[whichChain*2*oneMatSize + whichState*oneMatSize + (p->index)*numChars*nLocalCats*nStates];
		nOff = nLocalCats * nStates;
		for (c=0; c<numChars; c++, *(clP+=nOff))
			{
			for (k=0; k<nLocalCats; k++)
				{
				kTimesS = k * nStates;
				like = 0.0;
				for (i=0; i<nStates; i++)
					like += clP[kTimesS + i] * bs[i];
				tempRatePr[k * numChars + c] = like;
				}
			}
		}
		
	/* get average rates */
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{

		/* forward algorithm */
		logC = 0.0;
		for (c=0; c<nChar; c++)
			{
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
			
				if (c == 0)
					{
					for (k=0; k<nLocalCats; k++)
						f[k*nChar + c] = tempRatePr[k * numChars + pat];
					}
				else
					{
					for (l=0; l<nLocalCats; l++)
						{
						temp = 0.0;
						for (k=0; k<nLocalCats; k++)
							temp += f[k * nChar + (c-1)] * a[k][l];
						f[l * nChar + c] = temp * tempRatePr[l * numChars + pat];
						}
					}
				sum = 0.0;
				for (k=0; k<nLocalCats; k++)
					sum += f[k*nChar + c];
				for (k=0; k<nLocalCats; k++)
					f[k*nChar+c] /= sum;
				logC += log(sum);
				logCf[c] = logC;
				}
			else
				{
				
				}
			}

		/* backward algorithm */
		logC = 0.0;
		for (c=nChar-1; c>=0; c--)
			{
			if (patternId[c] >= 0)
				{
			
				if (c == nChar - 1)
					{
					for (k=0; k<nLocalCats; k++)
						b[k * nChar + c] = catFreq[k];
					}
				else
					{
					pat = patternId[c+1];
					for (k=0; k<nLocalCats; k++)
						{
						temp = 0.0;
						for (l=0; l<nLocalCats; l++)
							temp += a[k][l] * tempRatePr[l * numChars + pat] * b[l * nChar + (c+1)];
						b[k * nChar + c] = temp;
						}
					}
				sum = 0.0;
				for (k=0; k<nLocalCats; k++)
					sum += b[k*nChar + c];
				for (k=0; k<nLocalCats; k++)
					b[k*nChar+c] /= sum;
				logC += log(sum);
				logCb[c] = logC;
				}
			else
				{
				
				}
			}
		temp = 0.0;
		pat = patternId[0];
		for (l=0; l<nLocalCats; l++)
			temp += tempRatePr[l * numChars + pat] * b[l * nChar + 0];
		logLike = log (temp) + logC;

		/* posterior probabilities of individual categories at site c */
		for (c=0; c<nChar; c++)
			{
			/*printf ("%d ", c+1);*/
			for (k=0; k<nLocalCats; k++)
				{
				temp = (log(f[k * nChar + c]) + logCf[c] + log(b[k * nChar + c]) + logCb[c]) - logLike;
				/*if (temp > 0.0)
					printf ("x.xxxxxx ");
				else if (temp < -100.0)
					printf ("%lf ", 0.0);
				else
					printf ("%lf ", exp(temp));*/
				if (temp > 0.0)
					expPr[k] = 1.0;
				else if (temp < -100.0)
					expPr[k] = 0.0;
				else
					expPr[k] = exp(temp);
				}
				
			if (!strcmp(ratesModel, "adgamma"))
				{
				x = 0.0;
				for (k=0; k<nLocalCats; k++)
					{
					x += expPr[k] * catRate[k];
					rateProbs[c*nLocalCats + k] += expPr[k];
					}
				aveRate[c] = x;
				}
			else
				{
				pat = patternId[c];
				mult = scaledRates[whichChain*2*nPartitions + whichState*nPartitions + partitionId[pat]];
				x = 0.0;
				for (k=0; k<nLocalCats; k++)
					{
					x += expPr[k] * catRate[k];
					rateProbs[c*nLocalCats + k] += expPr[k];
					}
				aveRate[c] = x * mult;
				fprintf (fp2, "%1.4lf\t", x);
				}
			fprintf (fp2, "%1.4lf\t", aveRate[c]);
			/*printf ("\n");*/
			}
		}
	else if (!strcmp(ratesModel, "sitespec"))
		{
		for (c=0; c<nChar; c++)
			{
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				aveRate[c] = catRate[partitionId[pat]];
				rateProbs[c] = 1.0;
				fprintf (fp2, "%1.4lf\t", aveRate[c]);
				}
			}
		}
	else if (!strcmp(ratesModel, "ssgamma"))
		{
		for (c=0; c<nChar; c++)
			{
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				mult = scaledRates[whichChain*2*nPartitions + whichState*nPartitions + partitionId[pat]];

				sum = 0.0;
				for (k=0; k<nLocalCats; k++)
					sum += tempRatePr[k * numChars + pat] * catFreq[k];
				x = 0.0;
				for (k=0; k<nLocalCats; k++)
					{
					x += (tempRatePr[k * numChars + pat] * catFreq[k] / sum) * catRate[k];
					rateProbs[c*nLocalCats + k] += (tempRatePr[k * numChars + pat] * catFreq[k] / sum);
					}
				aveRate[c] = x * mult;
				fprintf (fp2, "%1.4lf\t", aveRate[c]);
				}
			}
		}
	else
		{
		for (c=0; c<nChar; c++)
			{
			if (patternId[c] >= 0)
				{
				pat = patternId[c];
				sum = 0.0;
				for (k=0; k<nLocalCats; k++)
					sum += tempRatePr[k * numChars + pat] * catFreq[k];
				x = 0.0;
				for (k=0; k<nLocalCats; k++)
					{
					x += (tempRatePr[k * numChars + pat] * catFreq[k] / sum) * catRate[k];
					rateProbs[c*nLocalCats + k] += (tempRatePr[k * numChars + pat] * catFreq[k] / sum);
					}
				aveRate[c] = x;
				fprintf (fp2, "%1.4lf\t", x);
				}
			}
		}
	fprintf (fp2, "\n");
	for (c=0; c<nChar; c++)
		rateFactors[c] += aveRate[c];
		

	/* print summary of probabilities to a file */
	if (whichGen == nGen && nSampled >= 1)
		{
		fprintf (fp1, "Summary of rate factors for each site\n");
		for (i=0; i<nChar; i++)
			{
			fprintf (fp1, "%d\t%1.4lf\t", i+1, rateFactors[i] / nSampled);
			if (!strcmp(ratesModel, "sitespec"))
				{
				fprintf (fp1, "%1.4lf\t", 1.0);
				}
			else
				{
				for (k=0; k<nLocalCats; k++)
					fprintf (fp1, "%1.4lf\t", rateProbs[i*nLocalCats + k] / nSampled);
				}
			fprintf (fp1, "\n");
			}
		free (rateFactors);
		free (rateProbs);
		}
				
	free (bs);
	free (tempRatePr);
	free (aveRate);
	fclose (fp1);
	fclose (fp2);
	if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
		{
		free (f);
		free (b);
		free (expPr);
		free (logCf);
		free (logCb);
		free_psdmatrix(a);
		}
	return (NO_ERROR);
	
	error_exit:
		free (bs);
		free (tempRatePr);

#if defined (MORPH)
		if (fp1 != NULL)
			fclose (fp1);
		if (fp2 != NULL)
			fclose (fp2);
#else
		fclose(fp1);
		fclose(fp2);
#endif
		free (rateFactors);
		free (aveRate);
		if (!strcmp(ratesModel, "adgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			free (f);
			free (b);
			free (expPr);
			free (logCf);
			free (logCb);
			free_psdmatrix(a);
			}
		return (ERROR);

}





int PrintStatesToFile (int n, int coldId, int whichState, double logLike, double *constrainedNodes, double *calibratedNodes)

{

	int				i;
	double			tl, bs[8];
	TreeNode		*p;
	FILE			*fp1, *fp2;
	
	/* set pointers for first part */
	fp1 = pFile;
	fp2 = bpFile;

	fprintf (fp1, "%d\t%lf\t", n, logLike);
	fprintf (fp2, "   data %d, %1.2lf", n, logLike);
	tl = GetTreeLength (whichState, coldId);
	fprintf (fp1, "%lf\t", tl);		
	fprintf (fp2, ", %lf", tl);	
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == NO)
		{
		if (nst == 2)
			{
			fprintf (fp1, "%lf\t", kappa[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", kappa[coldId*2 + whichState]);
			}
		else if (nst == 6)
			{
			for (i=0; i<6; i++)
				{
				fprintf (fp1, "%lf\t", subParams[coldId*12 + whichState*6 + i]);
				fprintf (fp2, ", %lf", subParams[coldId*12 + whichState*6 + i]);
				}
			}
		else if (nst == 12)
			{
			for (i=0; i<12; i++)
				{
				fprintf (fp1, "%lf\t", subParams[coldId*24 + whichState*12 + i]);
				fprintf (fp2, ", %lf", subParams[coldId*24 + whichState*12 + i]);
				}
			}
				
		if (dataType == DNA || dataType == RNA)
			{
			if (useCovarion == YES && !strcmp(covarionModelType, "gcswitch"))
				{
				bs[0] = (1.0 - gc1[coldId*2 + whichState]) * (fracA[coldId*2 + whichState]);
				bs[1] = (gc1[coldId*2 + whichState])       * (1.0 - fracG[coldId*2 + whichState]);
				bs[2] = (gc1[coldId*2 + whichState])       * (fracG[coldId*2 + whichState]);
				bs[3] = (1.0 - gc1[coldId*2 + whichState]) * (1.0 - fracA[coldId*2 + whichState]);
				bs[4] = (1.0 - gc2[coldId*2 + whichState]) * (fracA[coldId*2 + whichState]);
				bs[5] = (gc2[coldId*2 + whichState])       * (1.0 - fracG[coldId*2 + whichState]);
				bs[6] = (gc2[coldId*2 + whichState])       * (fracG[coldId*2 + whichState]);
				bs[7] = (1.0 - gc2[coldId*2 + whichState]) * (1.0 - fracA[coldId*2 + whichState]);
				for (i=0; i<8; i++)
					{
					fprintf (fp1, "%lf\t", bs[i]);
					fprintf (fp2, ", %lf", bs[i]);
					}
				}
			else
				{
				for (i=0; i<nStates; i++)
					{
					fprintf (fp1, "%lf\t", baseFreq[coldId*2*nStates + whichState*nStates + i]);
					fprintf (fp2, ", %lf", baseFreq[coldId*2*nStates + whichState*nStates + i]);
					}
				}
			}
		if (useCovarion == YES)
			{
			fprintf (fp1, "%lf\t%lf\t", switchRate[coldId*4 + whichState*2 + 0], switchRate[coldId*4 + whichState*2 + 1]);
			fprintf (fp2, ", %lf, %lf", switchRate[coldId*4 + whichState*2 + 0], switchRate[coldId*4 + whichState*2 + 1]);
			}
		}
	else if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		fprintf (fp1, "%lf\t", kappa[coldId*2 + whichState]);
		fprintf (fp2, ", %lf", kappa[coldId*2 + whichState]);
		fprintf (fp1, "%lf\t", omega[coldId*2 + whichState]);
		fprintf (fp2, ", %lf", omega[coldId*2 + whichState]);
		if (!strcmp(codonModelType, "ny98"))
			{
			fprintf (fp1, "%lf\t", probPur[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probPur[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", probNeu[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probNeu[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", probPos[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probPos[coldId*2 + whichState]);
			}
		else if (!strcmp(codonModelType, "ac1ny98"))
			{
			fprintf (fp1, "%lf\t", probPur[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probPur[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", probNeu[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probNeu[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", probPos[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probPos[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", rateCorrelation[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", rateCorrelation[coldId*2 + whichState]);
			}
		else if (!strcmp(codonModelType, "ac2ny98"))
			{
			fprintf (fp1, "%lf\t", probPur[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probPur[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", probNeu[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probNeu[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", probPos[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probPos[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", rateCorrelation[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", rateCorrelation[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", rateCorrelation2[coldId*4 + whichState*2 + 0]);
			fprintf (fp2, ", %lf", rateCorrelation2[coldId*4 + whichState*2 + 0]);
			fprintf (fp1, "%lf\t", rateCorrelation2[coldId*4 + whichState*2 + 1]);
			fprintf (fp2, ", %lf", rateCorrelation2[coldId*4 + whichState*2 + 1]);
			}
		else if (!strcmp(codonModelType, "covny98"))
			{
			fprintf (fp1, "%lf\t", probPur[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probPur[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", probNeu[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probNeu[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", probPos[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", probPos[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", switchRate[coldId*4 + whichState*2 + 0]);
			fprintf (fp2, ", %lf", switchRate[coldId*4 + whichState*2 + 0]);
			}
		for (i=0; i<nStates; i++)
			{
			fprintf (fp1, "%lf\t", baseFreq[coldId*2*nStates + whichState*nStates + i]);
			fprintf (fp2, ", %lf", baseFreq[coldId*2*nStates + whichState*nStates + i]);
			}
		}
	else if (dataType == PROTEIN)
		{
		if (aaModelType == EQUALIN || aaModelType == GTR)
			{
			for (i=0; i<nStates; i++)
				{
				fprintf (fp1, "%lf\t", baseFreq[coldId*2*nStates + whichState*nStates + i]);
				fprintf (fp2, ", %lf", baseFreq[coldId*2*nStates + whichState*nStates + i]);
				}
			}
		if (useCovarion == YES)
			{
			fprintf (fp1, "%lf\t%lf\t", switchRate[coldId*4 + whichState*2 + 0], switchRate[coldId*4 + whichState*2 + 1]);
			fprintf (fp2, ", %lf, %lf", switchRate[coldId*4 + whichState*2 + 0], switchRate[coldId*4 + whichState*2 + 1]);
			}
		}
	else if (dataType == RESTRICTION)
		{
		fprintf (fp1, "%lf\t", kappa[coldId*2 + whichState]);
		fprintf (fp2, ", %lf", kappa[coldId*2 + whichState]);
		}
#if defined (MORPH)
	else if (dataType == STANDARD && numBetaCats > 1)
		{
		fprintf (fp1, "%lf\t", statefreqP[coldId*2 + whichState]);
		fprintf (fp2, ", %lf", statefreqP[coldId*2 + whichState]);
		}
#endif
	if (((dataType == DNA || dataType == RNA) && enforceCodonModel == NO) || dataType == PROTEIN || dataType == RESTRICTION)
		{
		if (!strcmp(ratesModel, "gamma"))
			{
			fprintf (fp1, "%lf\t", alpha[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", alpha[coldId*2 + whichState]);
			}
		else if (!strcmp(ratesModel, "adgamma"))
			{
			fprintf (fp1, "%lf\t", alpha[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", alpha[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", rateCorrelation[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", rateCorrelation[coldId*2 + whichState]);
			if (!strcmp(lagprModel, "uniform") || !strcmp(lagprModel, "exponential"))
				{
				fprintf (fp1, "%d\t", lag[coldId*2 + whichState]);
				fprintf (fp2, ", %d", lag[coldId*2 + whichState]);
				}
			}
		else if (!strcmp(ratesModel, "sitespec"))
			{
			for (i=0; i<nPartitions; i++)
				{
				fprintf (fp1, "%lf\t", scaledRates[coldId*2*nPartitions + whichState*nPartitions + i]);
				fprintf (fp2, ", %lf", scaledRates[coldId*2*nPartitions + whichState*nPartitions + i]);
				}
			}
		else if (!strcmp(ratesModel, "invariant"))
			{
			fprintf (fp1, "%lf\t", invP[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", invP[coldId*2 + whichState]);
			}
		else if (!strcmp(ratesModel, "invgamma"))
			{
			fprintf (fp1, "%lf\t", alpha[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", alpha[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", invP[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", invP[coldId*2 + whichState]);
			}
		else if (!strcmp(ratesModel, "ssgamma"))
			{
			fprintf (fp1, "%lf\t", alpha[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", alpha[coldId*2 + whichState]);
			for (i=0; i<nPartitions; i++)
				{
				fprintf (fp1, "%lf\t", scaledRates[coldId*2*nPartitions + whichState*nPartitions + i]);
				fprintf (fp2, ", %lf", scaledRates[coldId*2*nPartitions + whichState*nPartitions + i]);
				}
			}
		else if (!strcmp(ratesModel, "ssadgamma"))
			{
			fprintf (fp1, "%lf\t", alpha[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", alpha[coldId*2 + whichState]);
			fprintf (fp1, "%lf\t", rateCorrelation[coldId*2 + whichState]);
			fprintf (fp2, ", %lf", rateCorrelation[coldId*2 + whichState]);
			if (!strcmp(lagprModel, "uniform") || !strcmp(lagprModel, "exponential"))
				{
				fprintf (fp1, "%d\t", lag[coldId*2 + whichState]);
				fprintf (fp2, ", %d", lag[coldId*2 + whichState]);
				}
			for (i=0; i<nPartitions; i++)
				{
				fprintf (fp1, "%lf\t", scaledRates[coldId*2*nPartitions + whichState*nPartitions + i]);
				fprintf (fp2, ", %lf", scaledRates[coldId*2*nPartitions + whichState*nPartitions + i]);
				}
			}
		}
			
	if (!strcmp(brlenprModel, "birth-death"))
		{
		fprintf (fp1, "%lf\t%lf\t", spRate[coldId*2 + whichState], exRate[coldId*2 + whichState]);
		fprintf (fp2, ", %lf, %lf", spRate[coldId*2 + whichState], exRate[coldId*2 + whichState]);
		}
	if (enforceCalibrations == YES)
		{
		fprintf (fp1, "%lf\t", treeHeight[coldId*2 + whichState]);
		fprintf (fp2, ", %lf", treeHeight[coldId*2 + whichState]);
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[coldId*2*numNodes + whichState*numNodes + i];
			if (p->isConstrained == YES)
				{
				if (p->constraintNum-1 >= nConstraints)
					{
					printf ("\n   ERROR: Constraint out of bounds\n");
					return ERROR;
					}
				else
					constrainedNodes[p->constraintNum-1] = p->nodeTime;
				}
			if (p->isCalibrated == YES)
				{
				if (p->calibrationNum-1 >= nCalibrations)
					{
					printf ("\n   ERROR: Calibration out of bounds\n");
					return ERROR;
					}
				else
					calibratedNodes[p->calibrationNum-1] = p->nodeTime;
				}
			}
		for (i=0; i<nConstraints; i++)
			{
			fprintf (fp1, "%lf\t", constrainedNodes[i]);
			fprintf (fp2, ", %lf", constrainedNodes[i]);
			}
		for (i=0; i<nCalibrations; i++)
			{
			fprintf (fp1, "%lf\t", calibratedNodes[i]);
			fprintf (fp2, ", %lf", calibratedNodes[i]);
			}
		}
	fprintf (fp1, "\n");
	fprintf (fp2, ";\n");
	if (n == nGen)
		fprintf (fp2, "end;\n");
	fflush (fp1);
	fflush (fp2);
	
	fp2 = tFile;

	fprintf (fp2, "   tree rep.%d = ", n);
	WriteTreeToFile (root[coldId*2 + whichState]->left, fp2, saveBrlens);
	if (n == nGen)
		fprintf (fp2, "end;\n");
	fflush (fp2);
	
	return (NO_ERROR);
			
}





int ProposeNewState (long int *seed)

{

	int			i, proposedState;
	double		ran, sum, cumProposalProbs[NUM_PROPOSAL_TYPES];
						
	sum = 0.0;
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		sum += relProposalProbs[i];
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		relProposalProbs[i] /= sum;
	cumProposalProbs[0] = relProposalProbs[0];
	for (i=1; i<NUM_PROPOSAL_TYPES; i++)
		cumProposalProbs[i] = cumProposalProbs[i-1] + relProposalProbs[i];

	ran = RandomNumber(seed);
	
	proposedState = 100;
	if (ran >= 0.0 && ran <= cumProposalProbs[0])
		proposedState = CHANGE_QMAT;
	else if (ran >cumProposalProbs[0] && ran <= cumProposalProbs[1])
		proposedState = CHANGE_BASEFREQS;
	else if (ran >cumProposalProbs[1] && ran <= cumProposalProbs[2])
		proposedState = CHANGE_GAMMA_SHAPE;
	else if (ran >cumProposalProbs[2] && ran <= cumProposalProbs[3])
		proposedState = CHANGE_SITE_RATES;
	else if (ran >cumProposalProbs[3] && ran <= cumProposalProbs[4])
		proposedState = CHANGE_UNROOT_LOCAL;
	else if (ran >cumProposalProbs[4] && ran <= cumProposalProbs[5])
		proposedState = CHANGE_CLOCK_LOCAL;
	else if (ran >cumProposalProbs[5] && ran <= cumProposalProbs[6])
		proposedState = CHANGE_CLOCK_TIME_LOCAL;
	else if (ran >cumProposalProbs[6] && ran <= cumProposalProbs[7])
		proposedState = CHANGE_TREE_HEIGHT;
	else if (ran >cumProposalProbs[7] && ran <= cumProposalProbs[8])
		proposedState = CHANGE_WORM;
	else if (ran >cumProposalProbs[8] && ran <= cumProposalProbs[9])
		proposedState = CHANGE_NODE_TIME;
	else if (ran >cumProposalProbs[9] && ran <= cumProposalProbs[10])
		proposedState = CHANGE_BD_PARAMS;
	else if (ran >cumProposalProbs[10] && ran <= cumProposalProbs[11])
		proposedState = CHANGE_OMEGA;
	else if (ran >cumProposalProbs[11] && ran <= cumProposalProbs[12])
		proposedState = CHANGE_OMEGA_PROBS;
	else if (ran >cumProposalProbs[12] && ran <= cumProposalProbs[13])
		proposedState = CHANGE_AUTO_CORR;
	else if (ran >cumProposalProbs[13] && ran <= cumProposalProbs[14])
		proposedState = CHANGE_LAG;
	else if (ran >cumProposalProbs[14] && ran <= cumProposalProbs[15])
		proposedState = CHANGE_TREE_SPR;
	else if (ran >cumProposalProbs[15] && ran <= cumProposalProbs[16])
		proposedState = CHANGE_INV_P;
	else if (ran >cumProposalProbs[16] && ran <= cumProposalProbs[17])
		proposedState = CHANGE_SWITCH_RATE;
	else if (ran >cumProposalProbs[17] && ran <= cumProposalProbs[18])
		proposedState = CHANGE_UNROOT_TBR;
	else if (ran >cumProposalProbs[18] && ran <= cumProposalProbs[19])
		proposedState = CHANGE_GCSWITCH;
	else if (ran >cumProposalProbs[19] && ran <= cumProposalProbs[20])
		proposedState = CHANGE_TREE_FTBR;
	else if (ran >cumProposalProbs[20] && ran <= cumProposalProbs[21])
		proposedState = CHANGE_BRLEN;
	else if (ran >cumProposalProbs[21] && ran <= cumProposalProbs[22])
		proposedState = CHANGE_ERASER;
#if defined (MORPH)
	else if (ran >cumProposalProbs[22] && ran <= cumProposalProbs[23])
		proposedState = CHANGE_BETA_SHAPE;
#endif
	return (proposedState);

}





/*-------| RandomNumber |------------------------------------------------
|   This pseudorandom number generator is described in:
|   Park, S. K. and K. W. Miller.  1988.  Random number generators: good
|      ones are hard to find.  Communications of the ACM, 31(10):1192-1201.
*/
double RandomNumber (long int *seed)

{

	long int	lo, hi, test;
	
	hi = (*seed) / 127773;
	lo = (*seed) % 127773;
	test = 16807 * lo - 2836 * hi;
	if (test > 0)
		*seed = test;
	else
		*seed = test + 2147483647;
	return (double)(*seed) / (double)2147483647;

}





double RndGamma (double s, long int *seed)

{

	double  r=0.0;
	
	if (s <= 0.0)      
		puts ("jgl gamma..");
	else if (s < 1.0)  
		r = RndGamma1 (s, seed);
	else if (s > 1.0)  
		r = RndGamma2 (s, seed);
	else           
		r =- log(RandomNumber(seed));
	return (r);
   
}





double RndGamma1 (double s, long int *seed)

{

	double			r, x=0.0, small=1e-37, w;
	static double   a, p, uf, ss=10.0, d;
	
	if (s!=ss) 
		{
		a  = 1.0-s;
		p  = a/(a+s*exp(-a));
		uf = p*pow(small/a,s);
		d  = a*log(a);
		ss = s;
		}
	for (;;) 
		{
		r = RandomNumber(seed);
		if (r > p)        
			x = a-log((1.0-r)/(1.0-p)), w=a*log(x)-d;
		else if (r>uf)  
			x = a*pow(r/p,1/s), w=x;
		else            
			return (0.0);
		r = RandomNumber(seed);
		if (1.0-r <= w && r > 0.0)
		if (r*(w+1.0) >= 1.0 || -log(r) <= w)  
			continue;
		break;
		}
	return (x);
   
}





double RndGamma2 (double s, long int *seed)

{

	double			r ,d, f, g, x;
	static double	b, h, ss=0;
	
	if (s!=ss) 
		{
		b  = s-1.0;
		h  = sqrt(3.0*s-0.75);
		ss = s;
		}
	for (;;) 
		{
		r = RandomNumber(seed);
		g = r-r*r;
		f = (r-0.5)*h/sqrt(g);
		x = b+f;
		if (x <= 0.0) 
			continue;
		r = RandomNumber(seed);
		d = 64*r*r*g*g*g;
		if (d*x < x-2.0*f*f || log(d) < 2*(b*log(x/b)-f))  
			break;
		}
	return (x);
   
}





int RunChain (void)

{

	int			i, n, numTaxa, numChars, numRateCats;
	long int	seed;

	printf ("   Running Markov chain\n");
	
	seed = randomSeed;
	
	/* set all of the indicators for allocated memory to "NO" */
	for (i=0; i<NUM_ALLOCS; i++)
		allocatedMemory[i] = NO;
		
	/* check and set all of the model and chain parameters */
	if (useParsCriterion == NO)
		{
		if (SetModel (&numRateCats) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}
	else
		treeModel = UNROOTED;


	/* compress character matrix */
	if (useParsCriterion == NO)
		{
		if (CompressMatrix (&numTaxa, &numChars) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}
	else
		{
		if (CompressMatrixPars (&numTaxa, &numChars) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}
		
	/* build starting tree(s) */
	if (BuildStartingTree (numTaxa, numChars, &seed, NO) == ERROR)
		{
		FreeMemory ();
		return (ERROR);
		}
	
	/* set up trees */
	if (SetUpTrees (numTaxa) == ERROR)
		{
		FreeMemory ();
		return (ERROR);
		}
	
	/* initialize conditional likelihoods */
	if (useParsCriterion == NO)
		{
		if (InitializeConditionalLikes (numTaxa, numChars, numRateCats) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}
	else
		{
		if (InitializeTipStates (numTaxa, numChars) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}

	/* set up transition probabilities */
#	if defined (SMART_TI_PROBS)
	if (useParsCriterion == NO)
		{
		printf ("      Setting up transition probabilities\n");
		if (SetUpTransitionProbs (numRateCats) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}
#	endif

	/* copy trees and conditional likelihoods from memory space 0 -> 1 */
	if (useParsCriterion == NO)
		{
		printf ("      Copying states in memory\n");
		for (n=0; n<numChains; n++)
			{
			for (i=0; i<numNodes; i++)
				clUpdateFlag[i] = YES;
			CopyTree (0, 1, n);
			CopyConditionalLikelihoods (0, 1, n, numTaxa, numChars, numRateCats);
			}
		}
	else
		{
		printf ("      Copying trees in memory\n");
		for (n=0; n<numChains; n++)
			CopyTree (0, 1, n);
		}
		
	/* add some number of random perturbations to the starting trees */
	if (!strcmp(startingTreeModel, "user") && nPerturbations > 0)
		{
		printf ("      Perturbing starting trees\n");
		if (PerturnStartingTree (numTaxa, &seed) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}
		
	/* run Markov chain */
	printf ("      Running Markov chain\n");
	if (useParsCriterion == NO)
		{
		if (MarkovChain (numTaxa, numChars, numRateCats, &seed) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}
	else
		{
		if (MarkovChainPars (numTaxa, numChars, &seed) == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		}
		
	/* free memory */
	FreeMemory ();
		
	printf ("   Chain successfully run\n");

	randomSeed = seed;
	
	return (NO_ERROR);

}





void SetCode (void)

{

	int			i, s, s1, s2, s3;

	printf ("      Setting genetic code\n");
	
	codon[ 0] = 12; /* AAA Lys */
	codon[ 1] =  3; /* AAC Asn */
	codon[ 2] = 12; /* AAG Lys */
	codon[ 3] =  3; /* AAT Asn */
	codon[ 4] = 17; /* ACA Thr */
	codon[ 5] = 17; /* ACC Thr */
	codon[ 6] = 17; /* ACG Thr */
	codon[ 7] = 17; /* ACT Thr */
	codon[ 8] =  2; /* AGA Arg */
	codon[ 9] = 16; /* AGC Ser */
	codon[10] =  2; /* AGG Arg */
	codon[11] = 16; /* AGT Ser */
	codon[12] = 10; /* ATA Ile */
	codon[13] = 10; /* ATC Ile */
	codon[14] = 13; /* ATG Met */
	codon[15] = 10; /* ATT Ile */
	codon[16] =  6; /* CAA Gln */
	codon[17] =  9; /* CAC His */
	codon[18] =  6; /* CAG Gln */
	codon[19] =  9; /* CAT His */
	codon[20] = 15; /* CCA Pro */
	codon[21] = 15; /* CCC Pro */
	codon[22] = 15; /* CCG Pro */
	codon[23] = 15; /* CCT Pro */
	codon[24] =  2; /* CGA Arg */
	codon[25] =  2; /* CGC Arg */
	codon[26] =  2; /* CGG Arg */
	codon[27] =  2; /* CGT Arg */
	codon[28] = 11; /* CTA Leu */
	codon[29] = 11; /* CTC Leu */
	codon[30] = 11; /* CTG Leu */
	codon[31] = 11; /* CTT Leu */
	codon[32] =  7; /* GAA Glu */
	codon[33] =  4; /* GAC Asp */
	codon[34] =  7; /* GAG Glu */
	codon[35] =  4; /* GAT Asp */
	codon[36] =  1; /* GCA Ala */
	codon[37] =  1; /* GCC Ala */
	codon[38] =  1; /* GCG Ala */
	codon[39] =  1; /* GCT Ala */
	codon[40] =  8; /* GGA Gly */
	codon[41] =  8; /* GGC Gly */
	codon[42] =  8; /* GGG Gly */
	codon[43] =  8; /* GGT Gly */
	codon[44] = 20; /* GTA Val */
	codon[45] = 20; /* GTC Val */
	codon[46] = 20; /* GTG Val */
	codon[47] = 20; /* GTT Val */
	codon[48] = 21; /* TAA Stop*/
	codon[49] = 19; /* TAC Tyr */
	codon[50] = 21; /* TAG Stop*/
	codon[51] = 19; /* TAT Tyr */
	codon[52] = 16; /* TCA Ser */
	codon[53] = 16; /* TCC Ser */
	codon[54] = 16; /* TCG Ser */
	codon[55] = 16; /* TCT Ser */
	codon[56] = 21; /* TGA Stop*/
	codon[57] =  5; /* TGC Cys */
	codon[58] = 18; /* TGG Trp */
	codon[59] =  5; /* TGT Cys */
	codon[60] = 11; /* TTA Leu */
	codon[61] = 14; /* TTC Phe */
	codon[62] = 11; /* TTG Leu */
	codon[63] = 14; /* TTT Phe */
	
	if (aaCode == VERTMT)
		{
		printf ("         Vertebrate mitochondrial code\n");
		printf ("            UGA: Ter -> Trp\n");
		printf ("            AUA: Ile -> Met\n");
		printf ("            AGA: Arg -> Ter\n");
		printf ("            AGG: Arg -> Ter\n");
		codon[ 8] = 21; /* AGA Stop */ 
		codon[10] = 21; /* AGG Stop */
		codon[12] = 13; /* ATA Met */
		codon[56] = 18; /* TGA Trp */
		}
	else if (aaCode == MYCO)
		{
		printf ("         Mycoplasma nuclear code\n");
		printf ("            UGA: Ter -> Trp\n");
		codon[56] = 18; /* TGA Trp */
		}
	else if (aaCode == YEAST)
		{
		printf ("         Yeast mitochondrial code\n");
		printf ("            UGA: Ter -> Trp\n");
		printf ("            AUA: Ile -> Met\n");
		printf ("            CUA: Leu -> Thr\n");
		printf ("            CUC: Leu -> Thr\n");
		printf ("            CUG: Leu -> Thr\n");
		printf ("            CUU: Leu -> Thr\n");
		codon[12] = 13; /* ATA Met */
		codon[28] = 17; /* CTA Thr */
		codon[29] = 17; /* CTC Thr */
		codon[30] = 17; /* CTG Thr */
		codon[31] = 17; /* CTT Thr */
		codon[56] = 18; /* TGA Trp */
		}
	else if (aaCode == CILIATES)
		{
		printf ("         Ciliate nuclear code\n");
		printf ("            UAA: Ter -> Gln\n");
		printf ("            UAG: Ter -> Gln\n");
		codon[48] =  6; /* TAA Gln */
		codon[50] =  6; /* TAG Gln */
		}
	else if (aaCode == METMT)
		{
		printf ("         Metazoan (except vertebrates) mitochondrial code\n");
		printf ("            UGA: Ter -> Trp\n");
		printf ("            AUA: Ile -> Met\n");
		printf ("            AGA: Arg -> Ser\n");
		printf ("            AGG: Arg -> Ser\n");
		codon[ 8] = 16; /* AGA Ser */ 
		codon[10] = 16; /* AGG Ser */
		codon[12] = 13; /* ATA Met */
		codon[56] = 18; /* TGA Trp */
		}
	else
		{
		printf ("         Universal code\n");
		}
	
	nStates = 0;
	for (i=0; i<64; i++)
		{
		if (codon[i] != 21)
			nStates++;
		}
	printf ("         There are a total of %d coding triplets\n", nStates);
	
	s = 0;
	for (s1=0; s1<4; s1++)
		{
		for (s2=0; s2<4; s2++)
			{
			for (s3=0; s3<4; s3++)
				{
				if (codon[s1*16 + s2*4 + s3] != 21)
					{
					transCodon[s] = codon[s1*16 + s2*4 + s3];
					codonNucs[s][0] = s1;
					codonNucs[s][1] = s2;
					codonNucs[s][2] = s3;
					s++;
					}
				}
			}
		}

}





int SetModel (int *numRateCats)

{

	int			i, j, chain, nIncludedTaxa, nIncludedChars, x, y, isDiff;
	double		scaler, sum;
	
	
	/* set all proposal mechanisms to zero */
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		{
		relProposalProbs[i] = 0.0;
		chainMins[i] = 0.0;
		chainMaxs[i] = 0.0;
		}


	/* check to see what type of data was input ***************************************************/
	if (dataType == DNA || dataType == RNA)
		{
		nStates = 4;
		if (dataType == DNA)
			printf ("      Data type = DNA\n");
		else if (dataType == RNA)
			printf ("      Data type = RNA\n");
#if defined (TRANSLATE_TO_AA)
		if (treatAsAA == YES)
			printf ("      Translated to amino acids and analyzed as such\n");

		if (enforceCodonModel == YES || treatAsAA == YES)
#else
		if (enforceCodonModel == YES)
#endif
			{
			/* set genetic code */
			SetCode ();
#if defined (TRANSLATE_TO_AA)
			if (treatAsAA == YES)
				{
				TranslateToAA();
				nStates = 20;
				dataType = PROTEIN;
				}
#endif
			}
		}
	else if (dataType == PROTEIN)
		{
		nStates = 20;
		printf ("      Data type = protein\n");
		}
	else if (dataType == RESTRICTION)
		{
		nStates = 2;
		printf ("      Data type = restriction site\n");
		}
	else if (dataType == STANDARD)
		{
		nStates = 2;
		printf ("      Data type = standard\n");
		}
	else
		{
		printf ("\n   ERROR: Unknown data type.\n");
		FreeMemory ();
		return (ERROR);
		}
	numBetaCats = 1; /* this is the number of categories for the beta distribution for morphological data */

	/* check coding of data ***********************************************************************/
	if (dataType == DNA || dataType == RNA)
		{
		if (!strcmp(codingType, "variable") || !strcmp(codingType, "informative") || !strcmp(codingType, "noabsence") || !strcmp(codingType, "nopresence"))
			{
			printf ("\n   ERROR: Only coding=all is allowed for DNA/RNA data.\n");
			FreeMemory ();
			return (ERROR);
			}
		}
	else if (dataType == PROTEIN)
		{
		if (!strcmp(codingType, "variable") || !strcmp(codingType, "informative") || !strcmp(codingType, "noabsence") || !strcmp(codingType, "nopresence"))
			{
			printf ("\n   ERROR: Only coding=all is allowed for AA data.\n");
			FreeMemory ();
			return (ERROR);
			}
		}
	else if (dataType == RESTRICTION)
		{
		if (!strcmp(codingType, "informative"))
			{
			printf ("\n   ERROR: coding=informative is not allowed for restriction site data.\n");
			FreeMemory ();
			return (ERROR);
			}
		}
	else if (dataType == STANDARD)
		{
		if (!strcmp(codingType, "noabsence") || !strcmp(codingType, "nopresence"))
			{
			printf ("\n   ERROR: coding=noabsence/nopresence is not allowed for standard data.\n");
			FreeMemory ();
			return (ERROR);
			}
		}

	/* check to see if the data matrix is of a reasonable size ************************************/
	nIncludedTaxa = 0;
	for (i=0; i<nTaxa; i++)
		{
		if (excludedTaxa[i] == NO)
			{
			nIncludedTaxa++;
			}
		}
	nIncludedChars = 0;
	for (i=0; i<nChar; i++)
		{
		if (excludedSites[i] == NO)
			{
			nIncludedChars++;
			}
		}
	if (nIncludedTaxa < 4)
		{
		printf ("\n   ERROR: The data matrix is too small. Must have at least four taxa.\n");
		FreeMemory ();
		return (ERROR);
		}
	if (nIncludedChars < 1)
		{
		printf ("\n   ERROR: Too few characters.\n");
		FreeMemory ();
		return (ERROR);
		}
	printf ("      Data matrix included %d taxa and %d sites\n", nIncludedTaxa, nIncludedChars);
	if (excludedTaxa[outgroupNum] == YES)
		{
		printf ("      WARNING: The old outgroup taxon was excluded. The new\n");
		printf ("               outgroup is species ");
		for (j=0; j<nTaxa; j++)
			{
			if (excludedTaxa[j] == NO)
				break;
			}
		i = 0;
		while (taxonLabels[j*100+i] != '|')
			{
			printf ("%c", taxonLabels[j*100+i]);
			i++;
			}
		printf ("\n");
		localOutgroup = 0;
		}
	else
		{
		i = 0;
		for (j=0; j<nTaxa; j++)
			{
			if (j == outgroupNum)
				break;
			if (excludedTaxa[j] == NO)
				i++;
			}
		localOutgroup = i;
		}
		
	printf ("         Outgroup is species ");
	j = 0;
	for (i=0; i<nTaxa; i++)
		{
		if (excludedTaxa[i] == NO)
			{
			if (j == localOutgroup)
				break;
			j++;
			}
		}
	j = 0;
	while (taxonLabels[i*100+j] != '|')
		{
		printf ("%c", taxonLabels[i*100+j]);
		j++;
		}
	printf ("\n");

	
	
	/* check tree priors ***************************************************************************/
	printf ("      Branch length constraints\n");
	if (!strcmp(clockModel, "unconstrained"))
		{
		printf ("         Branch lengths are unconstrained\n");
		treeModel = UNROOTED;
		if (isUserTreeDefined == YES && isTreeRooted == YES)
			{
			if (DerootTree (userTreeRoot) == ERROR)
				{
				FreeMemory ();
				return (ERROR);
				}
			isTreeRooted = NO;
			}
		}
	else if (!strcmp(clockModel, "relaxed"))
		{
		printf ("\n   ERROR: Sorry, but the relaxed clock is not yet implemented.\n");
		FreeMemory ();
		return (ERROR);
		treeModel = ROOTED;
		if (isUserTreeDefined == YES && isTreeRooted == NO)
			{
			if (RootTree (userTreeRoot) == ERROR)
				{
				FreeMemory ();
				return (ERROR);
				}
			isTreeRooted = YES;
			}
		}
	else if (!strcmp(clockModel, "strict"))
		{
		printf ("         Branch lengths are constrained to satisfy the clock requirement\n");
		if (!strcmp(startingTreeModel, "user"))
			{
			isStartingTreeRandom = NO;
			if (isUserTreeDefined == NO)
				{
				printf ("\n   ERROR: You requested that the chain start with a user-\n");
				printf ("          specified tree, but never entered a tree using\n");
				printf ("          \"usertree\".\n");
				FreeMemory ();
				return (ERROR);
				}
			}
		else
			isStartingTreeRandom = YES;
		if (isStartingTreeRandom == NO && isUserTreeDefined == YES && isTreeRooted == NO)
			{
			printf ("\n   WARNING: You requested that the chain start with a user-\n");
			printf ("            specified tree. Such a tree was provided, but the\n");
			printf ("            tree is unrooted. The strict clock model requires\n");
			printf ("            rooted trees. The tree is being rooted at the outgroup\n");
			printf ("            species\n\n");
			if (RootTree (userTreeRoot) == ERROR)
				{
				FreeMemory ();
				return (ERROR);
				}
			}
		treeModel = ROOTED;
		if (isUserTreeDefined == YES && isTreeRooted == NO)
			{
			if (RootTree (userTreeRoot) == ERROR)
				{
				FreeMemory ();
				return (ERROR);
				}
			isTreeRooted = YES;
			}
		}
	else
		{
		printf ("\n   ERROR: Unknown branch constraint model\n");
		FreeMemory ();
		return (ERROR);
		}
	if (!strcmp(brlenprModel, "uniform"))
		{
		printf ("         Branch lengths have a uniform(%1.4lf, %1.4lf) prior\n", brlenprUni[0], brlenprUni[1]);
		}
	else if (!strcmp(brlenprModel, "exponential"))
		{
		printf ("         Branch lengths have an exponential(%1.4lf) prior\n", brlenprExp);
		}
	else if (!strcmp(brlenprModel, "birth-death"))
		{
		if (treeModel == UNROOTED)
			{
			printf ("\n   ERROR: The birth-death prior requires rooted trees.\n");
			FreeMemory ();
			return (ERROR);
			}
		if (!(!strcmp(clockModel, "strict")))
			{
			printf ("\n   ERROR: The birth-death prior requires the clock constraint.\n");
			FreeMemory ();
			return (ERROR);
			}
			
		spRate = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
		if (!spRate)
			{
			printf ("ERROR: Problem allocating spRate\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_SP_RATE] = YES;
		exRate = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
		if (!exRate)
			{
			printf ("ERROR: Problem allocating exRate\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_EX_RATE] = YES;
			
		if (speciationRate == extinctionRate)
			{
			printf ("\n         Warning: Speciation and extinction rates cannot\n");
			printf ("                  be equal. Setting extinction rate to be\n");
			printf ("                  90 percent of the speciation rate.\n\n");
			extinctionRate = speciationRate * 0.9;
			}
		for (i=0; i<numChains*2; i++)
			{
			spRate[i] = speciationRate;
			exRate[i] = extinctionRate;
			}

		relProposalProbs[CHANGE_BD_PARAMS] = moveRates[CHANGE_BD_PARAMS];
		chainMins[CHANGE_BD_PARAMS] = BRLEN_EPSILON;
		chainMaxs[CHANGE_BD_PARAMS] = 100.0;
		
		printf ("         Branch lengths and topology have a birth-death process prior\n");
		}
	else
		{
		printf ("\n   ERROR: Unknown prior model on branch lengths\n");
		FreeMemory ();
		return (ERROR);
		}
	
	
	/* check constraints and calibrations **********************************************************/
	if (enforceConstraints == YES)
		{
		if (nConstraints <= 0)
			{
			printf ("\n   ERROR: You requested that constraits be enforced without ever\n");
			printf ("          defining constraints.\n");
			FreeMemory ();
			return (ERROR);
			}
		/* TO DO: check to see if constraints have been defined */
		printf ("         Enforcing constraints\n");
		}
	if (enforceCalibrations == YES)
		{
		printf ("\n   NOTICE: You requested that calibrations be used so that \n");
		printf ("           speciation times can be estimated. This part of the \n");
		printf ("           program is temporarily deactivated as the MCMC \n");
		printf ("           routines that I originally implemented are unstable. \n");
		printf ("           Please wait until a later version to perform speciation\n");
		printf ("           time estimation.\n");
		FreeMemory ();
		return (ERROR);
		
		if (nCalibrations <= 0)
			{
			printf ("\n   ERROR: You requested that calibrations be used without ever\n");
			printf ("          defining calibrations.\n");
			FreeMemory ();
			return (ERROR);
			}
		if (!strcmp(clockModel, "unconstrained"))
			{
			printf ("\n   ERROR: Calibrations only work when the strict or relaxed molecular\n");
			printf ("          clocks have been specified. You specified that the branch lengths\n");
			printf ("          are unconstrained. You need to change this using \"lset clock=strict\" or\n");
			printf ("          \"lset clock=relaxed\".\n");
			FreeMemory ();
			return (ERROR);
			}
		if (!strcmp(startingTreeModel, "user"))
			{
			printf ("\n   WARNING: You requested that the chain start with a user-\n");
			printf ("            specified tree. Such a tree was provided, but the\n");
			printf ("            tree is unrooted. Tree calibrations require rooted\n");
			printf ("            input trees. Hence, the tree is being rooted at the outgroup\n");
			printf ("            species\n\n");
			if (RootTree (userTreeRoot) == ERROR)
				{
				FreeMemory ();
				return (ERROR);
				}
			}
		printf ("         Enforcing calibrations\n");
		
		treeHeight = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
		if (!treeHeight)
			{
			printf ("ERROR: Problem allocating treeHeight\n");
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_TREE_HEIGHT] = YES;
		}
	if (inferAncStates == YES)
		{
		if (nConstraints <= 0)
			{
			printf ("\n   ERROR: You requested that ancestral states be estimated. This option\n");
			printf ("          requires that you specify constraints. The constraints\n");
			printf ("          correspond to the node(s) that will have the ancestral\n");
			printf ("          states estimated.\n");
			FreeMemory ();
			return (ERROR);
			}
		printf ("         Estimating ancestral states at constrained nodes\n");
		}
	
		
	/* figure out starting tree for chain **********************************************************/
	if (!strcmp(startingTreeModel, "random"))
		{
		isStartingTreeRandom = YES;
		}
	else if (!strcmp(startingTreeModel, "user"))
		{
		isStartingTreeRandom = NO;
		if (isUserTreeDefined == NO)
			{
			printf ("\n   ERROR: You requested that the chain start with a user-\n");
			printf ("          specified tree, but never entered a tree using\n");
			printf ("          \"usertree\".\n");
			FreeMemory ();
			return (ERROR);
			}
		}
	else
		{
		printf ("\n   ERROR: Unknown starting tree (should be \"random\" or \"user\"\n");
		FreeMemory ();
		return (ERROR);
		}
		

	/* how many chains *****************************************************************************/
	if (numChains <= 0)
		{
		printf ("\n   ERROR: Invalid number of chains\n");
		}
	else
		{
		printf ("      Number of chains = %d\n", numChains);
		if (numChains > 1)
			{
			printf ("         Chains (i: {1, ..., %d}) are incrementally heated, with the heat\n", numChains);
			printf ("         being 1 / (1 + (i - 1) T), where T = %lf\n", chainTemp);
			}
		}
	
	
	/* how many substitution parameters ************************************************************/
	chainMins[CHANGE_QMAT] = 0.000001;
	chainMaxs[CHANGE_QMAT] = 1000.0;
	printf ("      Substitution model\n");
	if (dataType == DNA || dataType == RNA)
		{
		if (enforceCodonModel == NO)
			{
			/* 4 X 4 model of DNA substitution */
			if (!strcmp(subModel, "1"))
				{
				printf ("         All substitution types have equal rates.\n");
				printf ("         This corresponds to the JC69 or F81 models.\n");
				nst = 1;
				}
			else if (!strcmp(subModel, "2"))
				{
				printf ("         Two substitution types. Transitions have one\n");
				printf ("         rate whereas tranversions have another.\n");
				printf ("         This corresponds to the K80 or HKY85 models.\n");
				nst = 2;
				kappa = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
				if (!kappa)
					{
					printf ("\n   ERROR: Problem allocating kappa.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_KAPPA] = YES;
				for (i=0; i<2*numChains; i++)
					kappa[i] = tRatio;
				printf ("         Starting kappa = %lf\n", kappa[0]);
				}
			else if (!strcmp(subModel, "6"))
				{
				printf ("         There are six substitution types: A <-> C, A <-> G, A <-> T\n");
				printf ("         C <-> G, C <-> T, and G <-> T, each with a potentially\n");
				printf ("         different rate. This corresponds to the GTR model.\n");
				nst = 6;
				subParams = (double *)malloc((size_t) (numChains * 2 * 6 * sizeof(double)));
				if (!subParams)
					{
					printf ("\n   ERROR: Problem allocating subParams.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_SUBPARAMS] = YES;
				for (chain=0; chain<numChains; chain++)
					{
					for (i=0; i<6; i++)
						{
						subParams[chain*2*nst + 0*6 + i] = revRates[i];
						subParams[chain*2*nst + 1*6 + i] = revRates[i];
						}
					}
					
				printf ("         Starting rates = ");
				for (i=0; i<6; i++)
					printf ("%1.3lf ", subParams[i]);
				printf ("\n");
				}
			else if (!strcmp(subModel, "12"))
				{
				printf ("         There are 12 substitution types: A -> C, A -> G, A -> T\n");
				printf ("         C -> A, C -> G, C -> T, G -> A, G -> C, G -> T, T -> A\n");
				printf ("         T -> C and T -> G. This corresponds to the general\n");
				printf ("         nonreversible model.\n");
				nst = 12;
				if (isStartingTreeRandom == NO && isUserTreeDefined == YES && isTreeRooted == NO)
					{
					printf ("\n   WARNING: You requested that the chain start with a user-\n");
					printf ("            specified tree. Such a tree was provided, but the\n");
					printf ("            tree is unrooted. The nonreversible model requires\n");
					printf ("            rooted trees. The tree is being rooted at the outgroup\n");
					printf ("            species\n\n");
					if (RootTree (userTreeRoot) == ERROR)
						{
						FreeMemory ();
						return (ERROR);
						}
					}
				subParams = (double *)malloc((size_t) (numChains * 2 * 12 * sizeof(double)));
				if (!subParams)
					{
					printf ("\n   ERROR: Problem allocating subParams.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_SUBPARAMS] = YES;
				for (chain=0; chain<numChains; chain++)
					{
					for (i=0; i<12; i++)
						{
						subParams[chain*2*12 + 0*12 + i] = nonRevRates[i];
						subParams[chain*2*12 + 1*12 + i] = nonRevRates[i];
						}
					}
				printf ("         Starting rates = ");
				for (i=0; i<6; i++)
					printf ("%1.3lf ", subParams[i]);
				printf ("\n                          ");
				for (i=6; i<12; i++)
					printf ("%1.3lf ", subParams[i]);
				printf ("\n");
				treeModel = ROOTED;
				if (isUserTreeDefined == YES && isTreeRooted == NO)
					{
					if (RootTree (userTreeRoot) == ERROR)
						{
						FreeMemory ();
						return (ERROR);
						}
					isTreeRooted = YES;
					}
				}
			else
				{
				printf ("\n   ERROR: Unknown substitution model\n");
				FreeMemory ();
				return (ERROR);
				}
			}
		else
			{
			/* 61 X 61 (codon) model of DNA substitution */
			nst = 61;
			kappa = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!kappa)
				{
				printf ("\n   ERROR: Problem allocating kappa.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_KAPPA] = YES;
			for (i=0; i<2*numChains; i++)
				kappa[i] = tRatio;
			omega = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!omega)
				{
				printf ("\n   ERROR: Problem allocating omega.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_OMEGA] = YES;
			for (i=0; i<2*numChains; i++)
				omega[i] = omegaRatio;
			}
		}
	else if (dataType == PROTEIN)
		{
		if (SetAARates () == ERROR)
			{
			FreeMemory ();
			return (ERROR);
			}
		if (aaModelType == POISSON)
			{
			printf ("         All substitution types have equal rates.\n");
			}
		else if (aaModelType == EQUALIN)
			{
			printf ("         Equal input model of amino acid substitution.\n");
			}
		else if (aaModelType == JONES)
			{
			printf ("         Empirical model (Jones et al., 1990).\n");
			}
		else if (aaModelType == DAYHOFF)
			{
			printf ("         Empirical model (Dayhoff et al., 1978).\n");
			}
		else if (aaModelType == GTR)
			{
			printf ("         General time reversible model (very parameter rich).\n");
			nst = 190;
			subParams = (double *)malloc((size_t) (numChains * 2 * nst * sizeof(double)));
			if (!subParams)
				{
				printf ("\n   ERROR: Problem allocating subParams.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_SUBPARAMS] = YES;
			for (chain=0; chain<numChains; chain++)
				{
				for (i=0; i<nst; i++)
					{
					subParams[chain*2*nst + 0*nst + i] = 1.0;
					subParams[chain*2*nst + 1*nst + i] = 1.0;
					}
				}
			}
		else
			{
			printf ("\n   ERROR: Unknown substitution model\n");
			FreeMemory ();
			return (ERROR);
			}
		}
	else if (dataType == RESTRICTION)
		{
		nst = 1;
		printf ("         General two state model for gain and loss of site.\n");
		kappa = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
		if (!kappa)
			{
			printf ("\n   ERROR: Problem allocating kappa.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_KAPPA] = YES;
		for (i=0; i<2*numChains; i++)
			kappa[i] = tRatio;
		}
	else if (dataType == STANDARD)
		{
		nst = 1;
		printf ("         General two state model for gain and loss of character.\n");
		}
				
	if (dataType == DNA || dataType == RNA)
		{
		if (enforceCodonModel == NO)
			{
			/* 4 X 4 model of DNA substitution */
			if (nst > 1)
				{
				if (!strcmp(qmatprModel, "fixed"))
					{
					printf ("         Instantaneous rate matrix is fixed\n");
					}
				else if (!strcmp(qmatprModel, "exponential"))
					{
					printf ("         Instantaneous rate matrix has exponential(%1.4lf) prior\n", qmatprExp);
					relProposalProbs[CHANGE_QMAT] = moveRates[CHANGE_QMAT];
					}
				else if (!strcmp(qmatprModel, "uniform"))
					{
					printf ("         Instantaneous rate matrix has uniform(%1.4lf, %1.4lf) prior\n", qmatprUni[0], qmatprUni[1]);
					relProposalProbs[CHANGE_QMAT] = moveRates[CHANGE_QMAT];
					chainMins[CHANGE_QMAT] = qmatprUni[0];
					chainMaxs[CHANGE_QMAT] = qmatprUni[1];
					}
				else
					{
					printf ("\n   ERROR: Unknown prior model on instantaneous rates\n");
					FreeMemory ();
					return (ERROR);
					}
				}
			}
		else
			{
			/* 61 X 61 (codon) model of DNA substitution */
			if (!strcmp(qmatprModel, "fixed"))
				{
				printf ("         Kappa is fixed\n");
				}
			else if (!strcmp(qmatprModel, "exponential"))
				{
				printf ("         Kappa has an exponential(%1.4lf) prior\n", qmatprExp);
				relProposalProbs[CHANGE_QMAT] = moveRates[CHANGE_QMAT];
				}
			else if (!strcmp(qmatprModel, "uniform"))
				{
				printf ("         Kappa has a uniform(%1.4lf, %1.4lf) prior\n", qmatprUni[0], qmatprUni[1]);
				relProposalProbs[CHANGE_QMAT] = moveRates[CHANGE_QMAT];
				chainMins[CHANGE_QMAT] = qmatprUni[0];
				chainMaxs[CHANGE_QMAT] = qmatprUni[1];
				}
			else
				{
				printf ("\n   ERROR: Unknown prior model on instantaneous rates\n");
				FreeMemory ();
				return (ERROR);
				}
			if (!strcmp(omegaprModel, "fixed"))
				{
				printf ("         Omega is fixed\n");
				}
			else if (!strcmp(omegaprModel, "exponential"))
				{
				printf ("         Omega has an exponential(%1.4lf) prior\n", omegaprExp);
				relProposalProbs[CHANGE_OMEGA] = moveRates[CHANGE_OMEGA];
				}
			else if (!strcmp(qmatprModel, "uniform"))
				{
				printf ("         Omega has a uniform(%1.4lf, %1.4lf) prior\n", omegaprUni[0], omegaprUni[1]);
				relProposalProbs[CHANGE_OMEGA] = moveRates[CHANGE_OMEGA];
				chainMins[CHANGE_OMEGA] = omegaprUni[0];
				chainMaxs[CHANGE_OMEGA] = omegaprUni[1];
				}
			else
				{
				printf ("\n   ERROR: Unknown prior model on instantaneous rates\n");
				FreeMemory ();
				return (ERROR);
				}
			}
		}
	else if (dataType == PROTEIN)
		{
		if (aaModelType == GTR)
			{
			if (!strcmp(qmatprModel, "fixed"))
				{
				printf ("         Instantaneous rate matrix is fixed\n");
				}
			else if (!strcmp(qmatprModel, "exponential"))
				{
				printf ("         Instantaneous rate matrix has exponential(%1.4lf) prior\n", qmatprExp);
				relProposalProbs[CHANGE_QMAT] = moveRates[CHANGE_QMAT]; 
				}
			else if (!strcmp(qmatprModel, "uniform"))
				{
				printf ("         Instantaneous rate matrix has uniform(%1.4lf, %1.4lf) prior\n", qmatprUni[0], qmatprUni[1]);
				relProposalProbs[CHANGE_QMAT] = moveRates[CHANGE_QMAT]; 
				chainMins[CHANGE_QMAT] = qmatprUni[0];
				chainMaxs[CHANGE_QMAT] = qmatprUni[1];
				}
			else
				{
				printf ("\n   ERROR: Unknown prior model on instantaneous rates\n");
				FreeMemory ();
				return (ERROR);
				}
			}
		}
	else if (dataType == RESTRICTION)
		{
		if (!strcmp(qmatprModel, "fixed"))
			{
			printf ("         Instantaneous rate matrix is fixed\n");
			}
		else if (!strcmp(qmatprModel, "exponential"))
			{
			printf ("         Instantaneous rate matrix has exponential(%1.4lf) prior\n", qmatprExp);
			relProposalProbs[CHANGE_QMAT] = moveRates[CHANGE_QMAT];
			}
		else if (!strcmp(qmatprModel, "uniform"))
			{
			printf ("         Instantaneous rate matrix has uniform(%1.4lf, %1.4lf) prior\n", qmatprUni[0], qmatprUni[1]);
			relProposalProbs[CHANGE_QMAT] = moveRates[CHANGE_QMAT];
			chainMins[CHANGE_QMAT] = qmatprUni[0];
			chainMaxs[CHANGE_QMAT] = qmatprUni[1];
			}
		else
			{
			printf ("\n   ERROR: Unknown prior model on instantaneous rates\n");
			FreeMemory ();
			return (ERROR);
			}
		}
	else if (dataType == STANDARD)
		{
		if (!strcmp(stateFreqPrModel, "fixed"))
			{
			printf ("         State frequencies are fixed to 0.5\n");
			}
#if defined (MORPH)
		else if (!strcmp(stateFreqPrModel, "dirichlet"))
			{
			numBetaCats = 5; /* this should be set to some arbitrary (but odd) number by user */
			printf ("         Stationary frequencies follow a symmetric dirichlet/beta distribution\n");
			printf ("         The shape of this distribution is estimated\n");
			printf ("         Starting shape parameter: %1.4lf\n", statefreqprDir);
			printf ("         Shape parameter has a  uniform(%1.4lf, %1.4lf) prior\n", 0.0, 100.0);
			printf ("         The distribution is divided into %d discrete categories\n", numBetaCats);

			statefreqP = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!statefreqP)
				{
				printf ("\n   ERROR: Problem allocating statefreqP.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_BETA] = YES;
			for (i=0; i<2*numChains; i++)
				statefreqP[i] = statefreqprDir;
			
			relProposalProbs[CHANGE_BETA_SHAPE] = moveRates[CHANGE_BETA_SHAPE];
			chainMins[CHANGE_BETA_SHAPE] = 0.0;
			chainMaxs[CHANGE_BETA_SHAPE] = 100.0;
			}
#endif
		else
			{
			printf ("\n   ERROR: Unknown prior model on state frequencies\n");
			FreeMemory ();
			return (ERROR);
			}
		}
		
	/* set base frequencies ************************************************************************/
	chainMins[CHANGE_BASEFREQS] = 0.0;
	chainMaxs[CHANGE_BASEFREQS] = 1.0;
	printf ("      Base frequencies\n");
	if (((dataType == DNA || dataType == RNA) && enforceCodonModel == NO) && useCovarion == YES && !strcmp(covarionModelType, "gcswitch"))
		{
		gc1 = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
		if (!gc1)
			{
			printf ("\n   ERROR: Problem allocating gc1.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_GC1] = YES;
		gc2 = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
		if (!gc2)
			{
			printf ("\n   ERROR: Problem allocating gc2.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_GC2] = YES;
		fracA = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
		if (!fracA)
			{
			printf ("\n   ERROR: Problem allocating fracA.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_FRAC_A] = YES;
		fracG = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
		if (!fracG)
			{
			printf ("\n   ERROR: Problem allocating fracA.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_FRAC_G] = YES;
		for (i=0; i<2*numChains; i++)
			{
			gc1[i] = 0.25;
			gc2[i] = 0.75;
			fracA[i] = 0.50;
			fracG[i] = 0.50;
			}
		printf ("         Two classes of base frequencies, with switching between\n");
		printf ("         the classes. The first class has GC content constrained\n");
		printf ("         to be less than 1/2 and the other has GC content con-\n");
		printf ("         strained to be greater than 1/2.\n");
		relProposalProbs[CHANGE_GCSWITCH] = moveRates[CHANGE_GCSWITCH];
		}
	else if (dataType == DNA || dataType == RNA || dataType == PROTEIN)
		{
		baseFreq = (double *)malloc((size_t) (numChains * 2 * nStates * sizeof(double)));
		if (!baseFreq)
			{
			printf ("\n   ERROR: Problem allocating baseFreq.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_BASEFREQS] = YES;
		if (dataType == DNA || dataType == RNA)
			{
			if (enforceCodonModel == NO)
				{
				/* 4 X 4 model of DNA substitution */
				if (nst == 12)
					{
					printf ("         Base frequencies are determined by the Q matrix (model of\n");
					printf ("         DNA substitution is non-reversible).\n");
					for (i=0; i<numChains*2*nStates; i++)
						baseFreq[i] = 0.25;
					}
				else
					{
					if (!strcmp(baseFreqModel, "equal"))
						{
						printf ("         Equal base frequencies\n");
						for (i=0; i<numChains*2*nStates; i++)
							baseFreq[i] = 0.25;
						}
					else if (!strcmp(baseFreqModel, "empirical"))
						{
						printf ("         Empirical base frequencies\n");
						GetEmpiricalBaseFreqs ();
						}
					else if (!strcmp(baseFreqModel, "estimate"))
						{
						printf ("         Base frequencies to be estimated\n");
						for (i=0; i<numChains*2*nStates; i++)
							baseFreq[i] = 0.25;
						}
					else
						{
						printf ("\n   ERROR: Unknown base frequency model\n");
						FreeMemory ();
						return (ERROR);
						}
					printf ("         Starting base frequencies = %1.3lf %1.3lf %1.3lf %1.3lf\n", 
						baseFreq[0], baseFreq[1], baseFreq[2], baseFreq[3]);
					}
				if (nst < 12)
					{
					if (!strcmp(basefreqprModel, "fixed"))
						{
						printf ("         Base frequencies are fixed\n");
						}
					else if (!strcmp(basefreqprModel, "dirichlet"))
						{
						printf ("         Base frequencies have a dirichlet(%1.4lf) prior\n", basefreqprDir);
						relProposalProbs[CHANGE_BASEFREQS] = moveRates[CHANGE_BASEFREQS];
						}
					else
						{
						printf ("\n   ERROR: Unknown prior model on base frequencies\n");
						FreeMemory ();
						return (ERROR);
						}
					}
				}
			else
				{
				/* 61 X 61 (codon) model of DNA substitution */
				if (!strcmp(baseFreqModel, "equal"))
					{
					printf ("         Equal codon frequencies\n");
					for (i=0; i<numChains*2*nStates; i++)
						baseFreq[i] = (1.0 / (double)nStates);
					}
				else if (!strcmp(baseFreqModel, "empirical"))
					{
					printf ("         Empirical codon frequencies are not implemented with codon\n");
					printf ("         models. Initial codon frequencies set to 1/61.\n");
					for (i=0; i<numChains*2*nStates; i++)
						baseFreq[i] = (1.0 / (double)nStates);
					}
				else if (!strcmp(baseFreqModel, "estimate"))
					{
					printf ("         Codon frequencies to be estimated\n");
					for (i=0; i<numChains*2*nStates; i++)
						baseFreq[i] = (1.0 / (double)nStates);
					}
				else
					{
					printf ("\n   ERROR: Unknown codon frequency model\n");
					FreeMemory ();
					return (ERROR);
					}
				if (!strcmp(basefreqprModel, "fixed"))
					{
					printf ("         Codon frequencies are fixed\n");
					}
				else if (!strcmp(basefreqprModel, "dirichlet"))
					{
					printf ("         Codon frequencies have a dirichlet(%1.4lf) prior\n", basefreqprDir);
					relProposalProbs[CHANGE_BASEFREQS] = moveRates[CHANGE_BASEFREQS];
					}
				else
					{
					printf ("\n   ERROR: Unknown prior model on base frequencies\n");
					FreeMemory ();
					return (ERROR);
					}
				}
			}
		else if (dataType == PROTEIN)
			{
			if (aaModelType == JONES)
				{
				for (j=0; j<numChains; j++)
					{
					for (i=0; i<20; i++)
						{
						baseFreq[j*2*20 + 0*20 + i] = jonesPi[i];
						baseFreq[j*2*20 + 1*20 + i] = jonesPi[i];
						}
					}
				}
			else if (aaModelType == DAYHOFF)
				{
				for (j=0; j<numChains; j++)
					{
					for (i=0; i<20; i++)
						{
						baseFreq[j*2*20 + 0*20 + i] = dayhoffPi[i];
						baseFreq[j*2*20 + 1*20 + i] = dayhoffPi[i];
						}
					}
				}
			else
				{
				if (!strcmp(baseFreqModel, "equal"))
					{
					printf ("         Equal amino acid frequencies\n");
					for (i=0; i<numChains*2*nStates; i++)
						baseFreq[i] = 0.05;
					}
				else if (!strcmp(baseFreqModel, "empirical"))
					{
					printf ("         Empirical amino acid frequencies\n");
					GetEmpiricalAAFreqs ();
					}
				else if (!strcmp(baseFreqModel, "estimate"))
					{
					printf ("         Amino acid frequencies to be estimated\n");
					for (i=0; i<numChains*2*nStates; i++)
						baseFreq[i] = 0.05;
					}
				else
					{
					printf ("\n   ERROR: Unknown base frequency model\n");
					FreeMemory ();
					return (ERROR);
					}
				}

			printf ("         Starting aa frequencies = %1.3lf %1.3lf %1.3lf %1.3lf %1.3lf \n", baseFreq[0], baseFreq[1], baseFreq[2], baseFreq[3], baseFreq[4]);
			printf ("                                   %1.3lf %1.3lf %1.3lf %1.3lf %1.3lf \n", baseFreq[5], baseFreq[6], baseFreq[7], baseFreq[8], baseFreq[9]);
			printf ("                                   %1.3lf %1.3lf %1.3lf %1.3lf %1.3lf \n", baseFreq[10], baseFreq[11], baseFreq[12], baseFreq[13], baseFreq[14]);
			printf ("                                   %1.3lf %1.3lf %1.3lf %1.3lf %1.3lf \n", baseFreq[15], baseFreq[16], baseFreq[17], baseFreq[18], baseFreq[19]);

			if (!strcmp(basefreqprModel, "fixed"))
				{
				printf ("         Amino acid frequencies are fixed\n");
				}
			else if (!strcmp(basefreqprModel, "dirichlet"))
				{
				if (aaModelType == EQUALIN || aaModelType == GTR)
					{
					printf ("         Amino acid frequencies have a dirichlet(%1.4lf) prior\n", basefreqprDir);
					relProposalProbs[CHANGE_BASEFREQS] = moveRates[CHANGE_BASEFREQS];
					}
				}
			else
				{
				printf ("\n   ERROR: Unknown prior model on amino acid frequencies\n");
				FreeMemory ();
				return (ERROR);
				}
			}
		}
	else if (dataType == RESTRICTION)
		{
		printf ("         State frequencies are determined by the Q matrix.\n");
		}
	else if (dataType == STANDARD)
		{
		printf ("         State frequencies are determined by the Q matrix.\n");
		}
		
		
	/* rate variation across sites *****************************************************************/
	(*numRateCats) = 1;
	if (dataType == RESTRICTION)
		{
		if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
			{
			/* I believe that these are the only models that work for restriction sites */
			}
		else
			{
			printf ("\n   ERROR: This rate across sites model is not supported\n");
			printf ("          for restriction site data\n");
			FreeMemory ();
			return (ERROR);
			}
		}
	else if (dataType == STANDARD)
		{
#if !defined (MORPH)
		if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant") || !strcmp(ratesModel, "invgamma"))
#else
		if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "invariant")
			|| !strcmp(ratesModel, "invgamma") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "sitespec"))
#endif
			{
			// These models are supported!
			}
		else
			{
			printf ("\n   ERROR: This rate across sites model is not supported\n");
			printf ("          for standard data\n");
			FreeMemory ();
			return (ERROR);
			}
		}
#if !defined (MORPH)
		if (enforceCodonModel == NO || (enforceCodonModel == YES && dataType == PROTEIN) || (enforceCodonModel == YES && dataType == RESTRICTION) || (enforceCodonModel == YES && dataType == STANDARD))
#else
		if (enforceCodonModel == NO || dataType == PROTEIN || dataType == RESTRICTION || dataType == STANDARD)
#endif
		{
		printf ("      Among-site rate variation\n");
		/* codon model is not being used */
		(*numRateCats) = 1;
		if (!strcmp(ratesModel, "equal"))
			{
			printf ("         Equal rates across sites\n");
			}
		else if (!strcmp(ratesModel, "gamma") || !strcmp(ratesModel, "adgamma"))
			{
			chainMins[CHANGE_GAMMA_SHAPE] = 0.000001;
			chainMaxs[CHANGE_GAMMA_SHAPE] = 100.0;
			printf ("         Gamma-distributed rates across sites\n");
			if (nRateCats <= 1)
				{
				printf ("\n   ERROR: Too few rate categories. ncat must be at least 2\n");
				FreeMemory ();
				return (ERROR);
				}
			(*numRateCats) = nRateCats;
			printf ("         Gamma distribution approximated with %d categories\n", (*numRateCats));
			alpha = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!alpha)
				{
				printf ("\n   ERROR: Problem allocating alpha.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_GAMMA_SHAPE] = YES;
			for (i=0; i<2*numChains; i++)
				alpha[i] = shape;
			printf ("         Starting gamma shape parameter: %1.4lf\n", shape);
			
			if (!strcmp(shapeprModel, "fixed"))
				{
				printf ("         Gamma shape parameter is fixed\n");
				}
			else if (!strcmp(shapeprModel, "uniform"))
				{
				printf ("         Gamma shape parameter has a uniform(%1.4lf, %1.4lf) prior\n", shapeprUni[0], shapeprUni[1]);
				relProposalProbs[CHANGE_GAMMA_SHAPE] = moveRates[CHANGE_GAMMA_SHAPE];
				chainMins[CHANGE_GAMMA_SHAPE] = shapeprUni[0];
				chainMaxs[CHANGE_GAMMA_SHAPE] = shapeprUni[1];
				}
			else if (!strcmp(shapeprModel, "exponential"))
				{
				printf ("         Gamma shape parameter has an exponential(%1.4lf) prior\n", shapeprExp);
				
				relProposalProbs[CHANGE_GAMMA_SHAPE] = moveRates[CHANGE_GAMMA_SHAPE];
				}
			else
				{
				printf ("\n   ERROR: Unknown prior model for gamma shape parameter\n");
				FreeMemory ();
				return (ERROR);
				}
			if (!strcmp(ratesModel, "adgamma"))
				{
				printf ("         Auto-discrete-gamma model implemented (correlated rates across sites)\n");
				rateCorrelation = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
				if (!rateCorrelation)
					{
					printf ("\n   ERROR: Problem allocating rateCorrelation.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_AUTO_GAMMA] = YES;
				for (i=0; i<2*numChains; i++)
					rateCorrelation[i] = 0.0;
				relProposalProbs[CHANGE_AUTO_CORR] = moveRates[CHANGE_AUTO_CORR];
				chainMins[CHANGE_AUTO_CORR] = -1.0;
				chainMaxs[CHANGE_AUTO_CORR] = 1.0;
				lag = (int *)malloc((size_t) (numChains * 2 * sizeof(int)));
				if (!lag)
					{
					printf ("\n   ERROR: Problem allocating lag.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_LAG] = YES;
				for (i=0; i<2*numChains; i++)
					lag[i] = lagNumber;
				if (!strcmp(lagprModel, "uniform") || !strcmp(lagprModel, "exponential"))
					{
					relProposalProbs[CHANGE_LAG] = moveRates[CHANGE_LAG];
					chainMins[CHANGE_LAG] = 1;
					chainMaxs[CHANGE_LAG] = 50;
					}
				}
			}
		else if (!strcmp(ratesModel, "invariant"))
			{
			relProposalProbs[CHANGE_INV_P] = moveRates[CHANGE_INV_P];
			chainMins[CHANGE_INV_P] = 0.0;
			chainMaxs[CHANGE_INV_P] = 1.0;
			printf ("         Proportion of invariant sites among-site rate variation\n");
			(*numRateCats) = 2;
			invP = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!invP)
				{
				printf ("\n   ERROR: Problem allocating invP.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_INV_P] = YES;
			for (i=0; i<2*numChains; i++)
				invP[i] = 0.1;
			printf ("         Starting proportion invariant: %1.4lf\n", 0.1);
			printf ("         Proportion sites invariant has a uniform (0,1) prior\n");
			}
		else if (!strcmp(ratesModel, "invgamma"))
			{
			chainMins[CHANGE_GAMMA_SHAPE] = 0.000001;
			chainMaxs[CHANGE_GAMMA_SHAPE] = 100.0;
			printf ("         Gamma-distributed rates across sites\n");
			if (nRateCats <= 1)
				{
				printf ("\n   ERROR: Too few rate categories. ncat must be at least 2\n");
				FreeMemory ();
				return (ERROR);
				}
			(*numRateCats) = nRateCats + 1;
			printf ("         Gamma distribution approximated with %d categories\n", (*numRateCats));
			alpha = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!alpha)
				{
				printf ("\n   ERROR: Problem allocating alpha.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_GAMMA_SHAPE] = YES;
			for (i=0; i<2*numChains; i++)
				alpha[i] = shape;
			printf ("         Starting gamma shape parameter: %1.4lf\n", shape);
			
			if (!strcmp(shapeprModel, "fixed"))
				{
				printf ("         Gamma shape parameter is fixed\n");
				}
			else if (!strcmp(shapeprModel, "uniform"))
				{
				printf ("         Gamma shape parameter has a uniform(%1.4lf, %1.4lf) prior\n", shapeprUni[0], shapeprUni[1]);
				relProposalProbs[CHANGE_GAMMA_SHAPE] = moveRates[CHANGE_GAMMA_SHAPE];
				chainMins[CHANGE_GAMMA_SHAPE] = shapeprUni[0];
				chainMaxs[CHANGE_GAMMA_SHAPE] = shapeprUni[1];
				}
			else if (!strcmp(shapeprModel, "exponential"))
				{
				printf ("         Gamma shape parameter has an exponential(%1.4lf) prior\n", shapeprExp);
				
				relProposalProbs[CHANGE_GAMMA_SHAPE] = moveRates[CHANGE_GAMMA_SHAPE];
				}
			else
				{
				printf ("\n   ERROR: Unknown prior model for gamma shape parameter\n");
				FreeMemory ();
				return (ERROR);
				}

			relProposalProbs[CHANGE_INV_P] = moveRates[CHANGE_INV_P];
			chainMins[CHANGE_INV_P] = 0.0;
			chainMaxs[CHANGE_INV_P] = 1.0;
			printf ("         Proportion of invariant sites among-site rate variation\n");
			invP = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!invP)
				{
				printf ("\n   ERROR: Problem allocating invP.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_INV_P] = YES;
			for (i=0; i<2*numChains; i++)
				invP[i] = 0.1;
			printf ("         Starting proportion invariant: %1.4lf\n", 0.1);
			printf ("         Proportion sites invariant has a uniform (0,1) prior\n");
			}
		else if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
			{
			chainMins[CHANGE_SITE_RATES] = 0.000001;
			chainMaxs[CHANGE_SITE_RATES] = 100.0;
			printf ("         Site specific rates across sites\n");
			if (!strcmp(partitionName, "none defined"))
				{
				printf ("\n   ERROR: You must specify the partition name in \"lset sitepartition=<name>\"\n");
				FreeMemory ();
				return (ERROR);
				}
			if (isPartitionDefined == NO)
				{
				printf ("\n   ERROR: You must define a partition\n");
				FreeMemory ();
				return (ERROR);
				}
			x = strlen(partitionName);
			y = strlen(defPartitionName);
			if (x != y)
				{
				printf ("\n   ERROR: The partition you defined (using \"partition\") \n");
				printf ("          and the partition you specified (using \"lset\") do\n");
				printf ("          not match.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				{
				isDiff = NO;
				i = 0;
				while (partitionName[i] != '\0')
					{
					if (partitionName[i] != defPartitionName[i])
						isDiff = YES;
					i++;
					}
				if (isDiff == YES)
					{
					printf ("\n   ERROR: The partition you defined (using \"partition\") \n");
					printf ("          and the partition you specified (using \"lset\") do\n");
					printf ("          not match.\n");
					FreeMemory ();
					return (ERROR);
					}
				}
			printf ("         Partition name: \"%s\"\n", partitionName);
			printf ("         Data is partitioned into %d parts\n", nPartitions);
			if (nPartitions <= 1)
				{
				printf ("\n   ERROR: There are too few partitions of the data. You must\n");
				printf ("          have at least two partitions.\n");
				FreeMemory ();
				return (ERROR);
				}
			else if (nPartitions > 49)
				{
				printf ("\n   ERROR: There are too many partitions of the data. You must\n");
				printf ("          have fewer than 49 partitions.\n");
				FreeMemory ();
				return (ERROR);
				}
			scaledRates = (double *)malloc((size_t) (numChains * 2 * nPartitions * sizeof(double)));
			if (!scaledRates)
				{
				printf ("\n   ERROR: Problem allocating scaledRates.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_SITE_RATES] = YES;
			unscaledRates = (double *)malloc((size_t) (numChains * 2 * nPartitions * sizeof(double)));
			if (!unscaledRates)
				{
				printf ("\n   ERROR: Problem allocating unscaledRates.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_UNSCALED_SITE_RATES] = YES;
			for (chain=0; chain<numChains; chain++)
				{
				for (i=0; i<nPartitions; i++)
					{
					unscaledRates[chain*2*nPartitions + 0*nPartitions + i] = siteRates[i];
					unscaledRates[chain*2*nPartitions + 1*nPartitions + i] = siteRates[i];
					}
				}
			nSitesInPartition = (int *)malloc((size_t) (nPartitions * sizeof(int)));
			if (!nSitesInPartition)
				{
				printf ("\n   ERROR: Problem allocating nSitesInPartition.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_NSITES_IN_PART] = YES;
			for (i=0; i<nPartitions; i++)
				nSitesInPartition[i] = 0;
			for (i=0; i<nChar; i++)
				{
				if (excludedSites[i] == NO)
					{
					if (sitePartitions[i] == 0)
						{
						printf ("\n   ERROR: Site %d is not assigned to a partition\n", i+1);
						FreeMemory ();
						return (ERROR);
						}
					nSitesInPartition[ sitePartitions[i] - 1 ]++;
					}
				}
			scaler = 0.0;
			for (i=0; i<nPartitions; i++)
				scaler += unscaledRates[i] * nSitesInPartition[i];
			scaler = (double)nIncludedChars / scaler;
			for (chain=0; chain<numChains; chain++)
				{
				for (i=0; i<nPartitions; i++)
					{
					scaledRates[chain*2*nPartitions + 0*nPartitions + i] = unscaledRates[chain*2*nPartitions + 0*nPartitions + i] * scaler;
					scaledRates[chain*2*nPartitions + 0*nPartitions + i] = unscaledRates[chain*2*nPartitions + 1*nPartitions + i] * scaler;
					}
				}
			for (i=0; i<nPartitions; i++)
				{
				printf ("         Partition %d contains %d sites and has an initial rate of %1.4lf\n", 
					i+1, nSitesInPartition[i], scaledRates[0*2*nPartitions + 0*nPartitions + i]);
				}
			
			if (!strcmp(siterateprModel, "fixed"))
				{
				printf ("         Site rates are fixed\n");
				}
			else if (!strcmp(siterateprModel, "uniform"))
				{
				printf ("         Site rates have a uniform(%1.4lf, %1.4lf) prior\n", siterateprUni[0], siterateprUni[1]);
				relProposalProbs[CHANGE_SITE_RATES] = moveRates[CHANGE_SITE_RATES];
				chainMins[CHANGE_SITE_RATES] = siterateprUni[0];
				chainMaxs[CHANGE_SITE_RATES] = siterateprUni[1];
				}
			else if (!strcmp(siterateprModel, "exponential"))
				{
				printf ("         Site rates have an exponential(%1.4lf) prior\n", siterateprExp);
				relProposalProbs[CHANGE_SITE_RATES] = moveRates[CHANGE_SITE_RATES];
				}
			else
				{
				printf ("\n   ERROR: Unknown prior model for site rates\n");
				FreeMemory ();
				return (ERROR);
				}
			if (!strcmp(ratesModel, "ssgamma"))
				{
				chainMins[CHANGE_GAMMA_SHAPE] = 0.000001;
				chainMaxs[CHANGE_GAMMA_SHAPE] = 100.0;
				printf ("         Gamma-distributed rates across sites for each codon\n");
				if (nRateCats <= 1)
					{
					printf ("\n   ERROR: Too few rate categories. ncat must be at least 2\n");
					FreeMemory ();
					return (ERROR);
					}
				(*numRateCats) = nRateCats;
				printf ("         Gamma distribution approximated with %d categories\n", (*numRateCats));
				alpha = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
				if (!alpha)
					{
					printf ("\n   ERROR: Problem allocating alpha.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_GAMMA_SHAPE] = YES;
				for (i=0; i<2*numChains; i++)
					alpha[i] = shape;
				printf ("         Starting gamma shape parameter: %1.4lf\n", shape);
				
				if (!strcmp(shapeprModel, "fixed"))
					{
					printf ("         Gamma shape parameter is fixed\n");
					}
				else if (!strcmp(shapeprModel, "uniform"))
					{
					printf ("         Gamma shape parameter has a uniform(%1.4lf, %1.4lf) prior\n", shapeprUni[0], shapeprUni[1]);
					relProposalProbs[CHANGE_GAMMA_SHAPE] = moveRates[CHANGE_GAMMA_SHAPE];
					chainMins[CHANGE_GAMMA_SHAPE] = shapeprUni[0];
					chainMaxs[CHANGE_GAMMA_SHAPE] = shapeprUni[1];
					}
				else if (!strcmp(shapeprModel, "exponential"))
					{
					printf ("         Gamma shape parameter has an exponential(%1.4lf) prior\n", shapeprExp);
					
					relProposalProbs[CHANGE_GAMMA_SHAPE] = moveRates[CHANGE_GAMMA_SHAPE];
					}
				else
					{
					printf ("\n   ERROR: Unknown prior model for gamma shape parameter\n");
					FreeMemory ();
					return (ERROR);
					}
				}
			if (!strcmp(ratesModel, "ssadgamma"))
				{
				chainMins[CHANGE_GAMMA_SHAPE] = 0.000001;
				chainMaxs[CHANGE_GAMMA_SHAPE] = 100.0;
				printf ("         Gamma-distributed rates across sites for each codon\n");
				if (nRateCats <= 1)
					{
					printf ("\n   ERROR: Too few rate categories. ncat must be at least 2\n");
					FreeMemory ();
					return (ERROR);
					}
				(*numRateCats) = nRateCats;
				printf ("         Gamma distribution approximated with %d categories\n", (*numRateCats));
				alpha = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
				if (!alpha)
					{
					printf ("\n   ERROR: Problem allocating alpha.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_GAMMA_SHAPE] = YES;
				for (i=0; i<2*numChains; i++)
					alpha[i] = shape;
				printf ("         Starting gamma shape parameter: %1.4lf\n", shape);
				
				if (!strcmp(shapeprModel, "fixed"))
					{
					printf ("         Gamma shape parameter is fixed\n");
					}
				else if (!strcmp(shapeprModel, "uniform"))
					{
					printf ("         Gamma shape parameter has a uniform(%1.4lf, %1.4lf) prior\n", shapeprUni[0], shapeprUni[1]);
					relProposalProbs[CHANGE_GAMMA_SHAPE] = moveRates[CHANGE_GAMMA_SHAPE];
					chainMins[CHANGE_GAMMA_SHAPE] = shapeprUni[0];
					chainMaxs[CHANGE_GAMMA_SHAPE] = shapeprUni[1];
					}
				else if (!strcmp(shapeprModel, "exponential"))
					{
					printf ("         Gamma shape parameter has an exponential(%1.4lf) prior\n", shapeprExp);
					
					relProposalProbs[CHANGE_GAMMA_SHAPE] = moveRates[CHANGE_GAMMA_SHAPE];
					}
				else
					{
					printf ("\n   ERROR: Unknown prior model for gamma shape parameter\n");
					FreeMemory ();
					return (ERROR);
					}
				
				printf ("         Auto-discrete-gamma model implemented (correlated rates across sites)\n");
				rateCorrelation = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
				if (!rateCorrelation)
					{
					printf ("\n   ERROR: Problem allocating rateCorrelation.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_AUTO_GAMMA] = YES;
				for (i=0; i<2*numChains; i++)
					rateCorrelation[i] = 0.0;
				relProposalProbs[CHANGE_AUTO_CORR] = moveRates[CHANGE_AUTO_CORR];
				chainMins[CHANGE_AUTO_CORR] = -1.0;
				chainMaxs[CHANGE_AUTO_CORR] = 1.0;
				lag = (int *)malloc((size_t) (numChains * 2 * sizeof(int)));
				if (!lag)
					{
					printf ("\n   ERROR: Problem allocating lag.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_LAG] = YES;
				for (i=0; i<2*numChains; i++)
					lag[i] = lagNumber;
				if (!strcmp(lagprModel, "uniform") || !strcmp(lagprModel, "exponential"))
					{
					relProposalProbs[CHANGE_LAG] = moveRates[CHANGE_LAG];
					chainMins[CHANGE_LAG] = 1;
					chainMaxs[CHANGE_LAG] = 50;
					}
				}
			}
		else
			{
			printf ("\n   ERROR: Unknown rate variation model\n");
			FreeMemory ();
			return (ERROR);
			}
		}
	else
		{
		printf ("      Among-site omega variation\n");
		/* enforcing 61 X 61 codon model */
		if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98") || !strcmp(codonModelType, "covny98"))
			{
			printf ("         Omega varies across sites according to Nielsen and Yang (1998) model\n");
			if (!strcmp(codonModelType, "covny98"))
				(*numRateCats) = 1;
			else
				(*numRateCats) = 3;
			
			for (i=0; i<2*numChains; i++)
				omega[i] = 2.0;

			probPur = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!probPur)
				{
				printf ("\n   ERROR: Problem allocating probPur.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_PUR] = YES;
			for (i=0; i<2*numChains; i++)
				probPur[i] = 0.3333333;
			probNeu = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!probNeu)
				{
				printf ("\n   ERROR: Problem allocating probNeu.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_NEU] = YES;
			for (i=0; i<2*numChains; i++)
				probNeu[i] = 0.3333333;
			probPos = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
			if (!probPos)
				{
				printf ("\n   ERROR: Problem allocating probPos.\n");
				FreeMemory ();
				return (ERROR);
				}
			else
				allocatedMemory[ALLOC_POS] = YES;
			for (i=0; i<2*numChains; i++)
				probPos[i] = 0.3333333;
			chainMins[CHANGE_OMEGA_PROBS] = 0.0;
			chainMaxs[CHANGE_OMEGA_PROBS] = 1.0;
			relProposalProbs[CHANGE_OMEGA_PROBS] = moveRates[CHANGE_OMEGA_PROBS];

			relProposalProbs[CHANGE_OMEGA] = moveRates[CHANGE_OMEGA];
			chainMins[CHANGE_OMEGA] = 1.0;
			chainMaxs[CHANGE_OMEGA] = 50.0;
			
			if (!strcmp(codonModelType, "ac1ny98"))
				{
				printf ("         Auto-correlated codon model implemented (correlated omega across sites)\n");
				rateCorrelation = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
				if (!rateCorrelation)
					{
					printf ("\n   ERROR: Problem allocating rateCorrelation.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_AUTO_GAMMA] = YES;
				for (i=0; i<2*numChains; i++)
					rateCorrelation[i] = 0.0;
				relProposalProbs[CHANGE_AUTO_CORR] = moveRates[CHANGE_AUTO_CORR];
				chainMins[CHANGE_AUTO_CORR] = 0.0;
				chainMaxs[CHANGE_AUTO_CORR] = 1.0;
				}
			else if (!strcmp(codonModelType, "ac2ny98"))
				{
				printf ("         Auto-correlated codon model implemented (correlated omega across sites)\n");
				rateCorrelation = (double *)malloc((size_t) (numChains * 2 * sizeof(double)));
				if (!rateCorrelation)
					{
					printf ("\n   ERROR: Problem allocating rateCorrelation.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_AUTO_GAMMA] = YES;
				for (i=0; i<2*numChains; i++)
					rateCorrelation[i] = 0.0;
				rateCorrelation2 = (double *)malloc((size_t) (2 * numChains * 2 * sizeof(double)));
				if (!rateCorrelation2)
					{
					printf ("\n   ERROR: Problem allocating rateCorrelation2.\n");
					FreeMemory ();
					return (ERROR);
					}
				else
					allocatedMemory[ALLOC_AUTO_GAMMA2] = YES;
				for (i=0; i<4*numChains; i++)
					rateCorrelation2[i] = 0.0;
				relProposalProbs[CHANGE_AUTO_CORR] = moveRates[CHANGE_AUTO_CORR];
				chainMins[CHANGE_AUTO_CORR] = 0.0;
				chainMaxs[CHANGE_AUTO_CORR] = 1.0;
				}
			
			}
		else
			{
			(*numRateCats) = 1;
			printf ("         Equal omega across sites\n");
			chainMins[CHANGE_OMEGA_PROBS] = 0.0;
			chainMaxs[CHANGE_OMEGA_PROBS] = 1.0;
			relProposalProbs[CHANGE_OMEGA_PROBS] = 0.0;
			}
		}
		
	/* set up covarion model */
	if (useCovarion == YES)
		{
		if (((dataType == DNA || dataType == RNA) && enforceCodonModel == NO) || dataType == PROTEIN)
			{
			if (!strcmp(covarionModelType, "ts98"))
				{
				printf ("      Rates vary along tree according to covarion/covariotide\n");
				printf ("      model of Tuffley and Steel (1998).\n");
				}
			}
		else
			{
			printf ("\n   ERROR: Covarion/covariotide model is only implemented for DNA sequences\n");
			printf ("          without enforcing the codon model.\n");
			FreeMemory ();
			return (ERROR);
			}
		if (dataType == PROTEIN && !strcmp(covarionModelType, "gcswitch"))
			{
			printf ("\n   ERROR: This model is only implemented for DNA/RNA sequence information.\n");
			FreeMemory ();
			return (ERROR);
			}
		if (nst == 12)
			{
			printf ("\n   ERROR: Sorry, but only time-reversible models are allowed with \n");
			printf ("          the covarion model.\n");
			FreeMemory ();
			return (ERROR);
			}
		switchRate = (double *)malloc((size_t) (4 * numChains * sizeof(double)));
		if (!switchRate)
			{
			printf ("\n   ERROR: Problem allocating switchRate.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_SWITCH_RATE] = YES;
		for (i=0; i<4*numChains; i++)
			switchRate[i] = 0.05;		
		switchPi = (double *)malloc((size_t) (4 * numChains * sizeof(double)));
		if (!switchPi)
			{
			printf ("\n   ERROR: Problem allocating switchPi.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_SWITCH_PI] = YES;
		for (i=0; i<4*numChains; i++)
			switchPi[i] = 0.5;	
		relProposalProbs[CHANGE_SWITCH_RATE] = moveRates[CHANGE_SWITCH_RATE];
		chainMins[CHANGE_SWITCH_RATE] = 0.0001;
		chainMaxs[CHANGE_SWITCH_RATE] = 100.0;
		}
		
	/* set up switch model for codons */
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES && !strcmp(codonModelType, "covny98"))
		{
		printf ("      Codons change categories along the tree.\n");
		switchRate = (double *)malloc((size_t) (4 * numChains * sizeof(double)));
		if (!switchRate)
			{
			printf ("\n   ERROR: Problem allocating switchRate.\n");
			FreeMemory ();
			return (ERROR);
			}
		else
			allocatedMemory[ALLOC_SWITCH_RATE] = YES;
		for (i=0; i<4*numChains; i++)
			switchRate[i] = 0.05;		
		relProposalProbs[CHANGE_SWITCH_RATE] = moveRates[CHANGE_SWITCH_RATE];
		chainMins[CHANGE_SWITCH_RATE] = 0.0001;
		chainMaxs[CHANGE_SWITCH_RATE] = 100.0;
		}
	
	/* set up moves for topology */
	if (!strcmp(clockModel, "unconstrained") && treeModel == UNROOTED)
		{
		relProposalProbs[CHANGE_UNROOT_LOCAL] = moveRates[CHANGE_UNROOT_LOCAL];
		chainMins[CHANGE_UNROOT_LOCAL] = BRLEN_EPSILON;
		chainMaxs[CHANGE_UNROOT_LOCAL] = 100.0;
		relProposalProbs[CHANGE_TREE_FTBR] = moveRates[CHANGE_TREE_FTBR];
		chainMins[CHANGE_TREE_FTBR] = BRLEN_EPSILON;
		chainMaxs[CHANGE_TREE_FTBR] = 100.0;
		relProposalProbs[CHANGE_BRLEN] = moveRates[CHANGE_BRLEN];
		chainMins[CHANGE_BRLEN] = BRLEN_EPSILON;
		chainMaxs[CHANGE_BRLEN] = 100.0;
		relProposalProbs[CHANGE_ERASER] = moveRates[CHANGE_ERASER];
		chainMins[CHANGE_ERASER] = BRLEN_EPSILON;
		chainMaxs[CHANGE_ERASER] = 100.0;
		if (!strcmp(brlenprModel, "uniform"))
			{
			chainMins[CHANGE_UNROOT_LOCAL] = brlenprUni[0];
			if (chainMins[CHANGE_UNROOT_LOCAL] < BRLEN_EPSILON)
				chainMins[CHANGE_UNROOT_LOCAL] = BRLEN_EPSILON;
			chainMaxs[CHANGE_UNROOT_LOCAL] = brlenprUni[1];
			}
		if (enforceCalibrations == NO && enforceConstraints == NO)
			{
			relProposalProbs[CHANGE_WORM] = moveRates[CHANGE_WORM];
			chainMins[CHANGE_WORM] = BRLEN_EPSILON;
			chainMaxs[CHANGE_WORM] = 10.0;
			
			relProposalProbs[CHANGE_TREE_SPR] = moveRates[CHANGE_TREE_SPR];
			chainMins[CHANGE_TREE_SPR] = BRLEN_EPSILON;
			chainMaxs[CHANGE_TREE_SPR] = 10.0;

			relProposalProbs[CHANGE_UNROOT_TBR] = moveRates[CHANGE_UNROOT_TBR];
			chainMins[CHANGE_UNROOT_TBR] = BRLEN_EPSILON;
			chainMaxs[CHANGE_UNROOT_TBR] = 10.0;
			}
		}
	else if (!strcmp(clockModel, "unconstrained") && treeModel == ROOTED)
		{
		relProposalProbs[CHANGE_UNROOT_LOCAL] = moveRates[CHANGE_UNROOT_LOCAL];
		chainMins[CHANGE_UNROOT_LOCAL] = BRLEN_EPSILON;
		chainMaxs[CHANGE_UNROOT_LOCAL] = 10.0;
		relProposalProbs[CHANGE_TREE_FTBR] = moveRates[CHANGE_TREE_FTBR];
		chainMins[CHANGE_TREE_FTBR] = BRLEN_EPSILON;
		chainMaxs[CHANGE_TREE_FTBR] = 100.0;
		relProposalProbs[CHANGE_BRLEN] = moveRates[CHANGE_BRLEN];
		chainMins[CHANGE_BRLEN] = BRLEN_EPSILON;
		chainMaxs[CHANGE_BRLEN] = 100.0;
		if (!strcmp(brlenprModel, "uniform"))
			{
			chainMins[CHANGE_UNROOT_LOCAL] = brlenprUni[0];
			if (chainMins[CHANGE_UNROOT_LOCAL] < BRLEN_EPSILON)
				chainMins[CHANGE_UNROOT_LOCAL] = BRLEN_EPSILON;
			chainMaxs[CHANGE_UNROOT_LOCAL] = brlenprUni[1];
			}
		}
	else if (!strcmp(clockModel, "strict") && treeModel == ROOTED)
		{
		if (enforceCalibrations == NO)
			{
			relProposalProbs[CHANGE_CLOCK_LOCAL] = moveRates[CHANGE_CLOCK_LOCAL];
			chainMins[CHANGE_CLOCK_LOCAL] = BRLEN_EPSILON;
			chainMaxs[CHANGE_CLOCK_LOCAL] = 10.0;
			}
		else
			{
			relProposalProbs[CHANGE_CLOCK_TIME_LOCAL] = moveRates[CHANGE_CLOCK_TIME_LOCAL];
			chainMins[CHANGE_CLOCK_TIME_LOCAL] = BRLEN_EPSILON;
			chainMaxs[CHANGE_CLOCK_TIME_LOCAL] = 10.0;
			
			relProposalProbs[CHANGE_TREE_HEIGHT] = moveRates[CHANGE_TREE_HEIGHT];
			chainMins[CHANGE_TREE_HEIGHT] = BRLEN_EPSILON;
			chainMaxs[CHANGE_TREE_HEIGHT] = 100.0;
			
			relProposalProbs[CHANGE_NODE_TIME] = moveRates[CHANGE_NODE_TIME];
			chainMins[CHANGE_NODE_TIME] = BRLEN_EPSILON;
			chainMaxs[CHANGE_NODE_TIME] = 100.0;
			}
		}

	/* show proposal mechanisms that are turned on */
	printf ("      Proposal mechanisms\n");
	sum = 0.0;
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		sum += relProposalProbs[i];
	for (i=0; i<NUM_PROPOSAL_TYPES; i++)
		{
		if (relProposalProbs[i] > 0.0)
			printf ("         %1.2lf percent of the time attempts %s\n", (relProposalProbs[i]/sum)*100.0, proposalName[i]);
		}

	return (NO_ERROR);
	
}


#if defined (TRANSLATE_TO_AA)
/*-------------------------------------------------------------------
TranslateToAA: Translate data matrix from DNA or RNA to AA
-------------------------------------------------------------------*/
void TranslateToAA (void)
{
}
#endif


int SetAARates (void)

{


	aaJones[ 0][ 0] =   0; aaJones[ 0][ 1] =  58; aaJones[ 0][ 2] =  54; aaJones[ 0][ 3] =  81; aaJones[ 0][ 4] =  56; 
	aaJones[ 0][ 5] =  57; aaJones[ 0][ 6] = 105; aaJones[ 0][ 7] = 179; aaJones[ 0][ 8] =  27; aaJones[ 0][ 9] =  36; 
	aaJones[ 0][10] =  30; aaJones[ 0][11] =  35; aaJones[ 0][12] =  54; aaJones[ 0][13] =  15; aaJones[ 0][14] = 194; 
	aaJones[ 0][15] = 378; aaJones[ 0][16] = 475; aaJones[ 0][17] =   9; aaJones[ 0][18] =  11; aaJones[ 0][19] = 298; 
	aaJones[ 1][ 0] =  58; aaJones[ 1][ 1] =   0; aaJones[ 1][ 2] =  45; aaJones[ 1][ 3] =  16; aaJones[ 1][ 4] = 113; 
	aaJones[ 1][ 5] = 310; aaJones[ 1][ 6] =  29; aaJones[ 1][ 7] = 137; aaJones[ 1][ 8] = 328; aaJones[ 1][ 9] =  22; 
	aaJones[ 1][10] =  38; aaJones[ 1][11] = 646; aaJones[ 1][12] =  44; aaJones[ 1][13] =   5; aaJones[ 1][14] =  74; 
	aaJones[ 1][15] = 101; aaJones[ 1][16] =  64; aaJones[ 1][17] = 126; aaJones[ 1][18] =  20; aaJones[ 1][19] =  17; 
	aaJones[ 2][ 0] =  54; aaJones[ 2][ 1] =  45; aaJones[ 2][ 2] =   0; aaJones[ 2][ 3] = 528; aaJones[ 2][ 4] =  34; 
	aaJones[ 2][ 5] =  86; aaJones[ 2][ 6] =  58; aaJones[ 2][ 7] =  81; aaJones[ 2][ 8] = 391; aaJones[ 2][ 9] =  47; 
	aaJones[ 2][10] =  12; aaJones[ 2][11] = 263; aaJones[ 2][12] =  30; aaJones[ 2][13] =  10; aaJones[ 2][14] =  15; 
	aaJones[ 2][15] = 503; aaJones[ 2][16] = 232; aaJones[ 2][17] =   8; aaJones[ 2][18] =  70; aaJones[ 2][19] =  16; 
	aaJones[ 3][ 0] =  81; aaJones[ 3][ 1] =  16; aaJones[ 3][ 2] = 528; aaJones[ 3][ 3] =   0; aaJones[ 3][ 4] =  10; 
	aaJones[ 3][ 5] =  49; aaJones[ 3][ 6] = 767; aaJones[ 3][ 7] = 130; aaJones[ 3][ 8] = 112; aaJones[ 3][ 9] =  11; 
	aaJones[ 3][10] =   7; aaJones[ 3][11] =  26; aaJones[ 3][12] =  15; aaJones[ 3][13] =   4; aaJones[ 3][14] =  15; 
	aaJones[ 3][15] =  59; aaJones[ 3][16] =  38; aaJones[ 3][17] =   4; aaJones[ 3][18] =  46; aaJones[ 3][19] =  31; 
	aaJones[ 4][ 0] =  56; aaJones[ 4][ 1] = 113; aaJones[ 4][ 2] =  34; aaJones[ 4][ 3] =  10; aaJones[ 4][ 4] =   0; 
	aaJones[ 4][ 5] =   9; aaJones[ 4][ 6] =   5; aaJones[ 4][ 7] =  59; aaJones[ 4][ 8] =  69; aaJones[ 4][ 9] =  17; 
	aaJones[ 4][10] =  23; aaJones[ 4][11] =   7; aaJones[ 4][12] =  31; aaJones[ 4][13] =  78; aaJones[ 4][14] =  14; 
	aaJones[ 4][15] = 223; aaJones[ 4][16] =  42; aaJones[ 4][17] = 115; aaJones[ 4][18] = 209; aaJones[ 4][19] =  62; 
	aaJones[ 5][ 0] =  57; aaJones[ 5][ 1] = 310; aaJones[ 5][ 2] =  86; aaJones[ 5][ 3] =  49; aaJones[ 5][ 4] =   9; 
	aaJones[ 5][ 5] =   0; aaJones[ 5][ 6] = 323; aaJones[ 5][ 7] =  26; aaJones[ 5][ 8] = 597; aaJones[ 5][ 9] =   9; 
	aaJones[ 5][10] =  72; aaJones[ 5][11] = 292; aaJones[ 5][12] =  43; aaJones[ 5][13] =   4; aaJones[ 5][14] = 164; 
	aaJones[ 5][15] =  53; aaJones[ 5][16] =  51; aaJones[ 5][17] =  18; aaJones[ 5][18] =  24; aaJones[ 5][19] =  20; 
	aaJones[ 6][ 0] = 105; aaJones[ 6][ 1] =  29; aaJones[ 6][ 2] =  58; aaJones[ 6][ 3] = 767; aaJones[ 6][ 4] =   5; 
	aaJones[ 6][ 5] = 323; aaJones[ 6][ 6] =   0; aaJones[ 6][ 7] = 119; aaJones[ 6][ 8] =  26; aaJones[ 6][ 9] =  12; 
	aaJones[ 6][10] =   9; aaJones[ 6][11] = 181; aaJones[ 6][12] =  18; aaJones[ 6][13] =   5; aaJones[ 6][14] =  18; 
	aaJones[ 6][15] =  30; aaJones[ 6][16] =  32; aaJones[ 6][17] =  10; aaJones[ 6][18] =   7; aaJones[ 6][19] =  45; 
	aaJones[ 7][ 0] = 179; aaJones[ 7][ 1] = 137; aaJones[ 7][ 2] =  81; aaJones[ 7][ 3] = 130; aaJones[ 7][ 4] =  59; 
	aaJones[ 7][ 5] =  26; aaJones[ 7][ 6] = 119; aaJones[ 7][ 7] =   0; aaJones[ 7][ 8] =  23; aaJones[ 7][ 9] =   6; 
	aaJones[ 7][10] =   6; aaJones[ 7][11] =  27; aaJones[ 7][12] =  14; aaJones[ 7][13] =   5; aaJones[ 7][14] =  24; 
	aaJones[ 7][15] = 201; aaJones[ 7][16] =  33; aaJones[ 7][17] =  55; aaJones[ 7][18] =   8; aaJones[ 7][19] =  47; 
	aaJones[ 8][ 0] =  27; aaJones[ 8][ 1] = 328; aaJones[ 8][ 2] = 391; aaJones[ 8][ 3] = 112; aaJones[ 8][ 4] =  69; 
	aaJones[ 8][ 5] = 597; aaJones[ 8][ 6] =  26; aaJones[ 8][ 7] =  23; aaJones[ 8][ 8] =   0; aaJones[ 8][ 9] =  16; 
	aaJones[ 8][10] =  56; aaJones[ 8][11] =  45; aaJones[ 8][12] =  33; aaJones[ 8][13] =  40; aaJones[ 8][14] = 115; 
	aaJones[ 8][15] =  73; aaJones[ 8][16] =  46; aaJones[ 8][17] =   8; aaJones[ 8][18] = 573; aaJones[ 8][19] =  11; 
	aaJones[ 9][ 0] =  36; aaJones[ 9][ 1] =  22; aaJones[ 9][ 2] =  47; aaJones[ 9][ 3] =  11; aaJones[ 9][ 4] =  17; 
	aaJones[ 9][ 5] =   9; aaJones[ 9][ 6] =  12; aaJones[ 9][ 7] =   6; aaJones[ 9][ 8] =  16; aaJones[ 9][ 9] =   0; 
	aaJones[ 9][10] = 229; aaJones[ 9][11] =  21; aaJones[ 9][12] = 479; aaJones[ 9][13] =  89; aaJones[ 9][14] =  10; 
	aaJones[ 9][15] =  40; aaJones[ 9][16] = 245; aaJones[ 9][17] =   9; aaJones[ 9][18] =  32; aaJones[ 9][19] = 961; 
	aaJones[10][ 0] =  30; aaJones[10][ 1] =  38; aaJones[10][ 2] =  12; aaJones[10][ 3] =   7; aaJones[10][ 4] =  23; 
	aaJones[10][ 5] =  72; aaJones[10][ 6] =   9; aaJones[10][ 7] =   6; aaJones[10][ 8] =  56; aaJones[10][ 9] = 229; 
	aaJones[10][10] =   0; aaJones[10][11] =  14; aaJones[10][12] = 388; aaJones[10][13] = 248; aaJones[10][14] = 102; 
	aaJones[10][15] =  59; aaJones[10][16] =  25; aaJones[10][17] =  52; aaJones[10][18] =  24; aaJones[10][19] = 180; 
	aaJones[11][ 0] =  35; aaJones[11][ 1] = 646; aaJones[11][ 2] = 263; aaJones[11][ 3] =  26; aaJones[11][ 4] =   7; 
	aaJones[11][ 5] = 292; aaJones[11][ 6] = 181; aaJones[11][ 7] =  27; aaJones[11][ 8] =  45; aaJones[11][ 9] =  21; 
	aaJones[11][10] =  14; aaJones[11][11] =   0; aaJones[11][12] =  65; aaJones[11][13] =   4; aaJones[11][14] =  21; 
	aaJones[11][15] =  47; aaJones[11][16] = 103; aaJones[11][17] =  10; aaJones[11][18] =   8; aaJones[11][19] =  14; 
	aaJones[12][ 0] =  54; aaJones[12][ 1] =  44; aaJones[12][ 2] =  30; aaJones[12][ 3] =  15; aaJones[12][ 4] =  31; 
	aaJones[12][ 5] =  43; aaJones[12][ 6] =  18; aaJones[12][ 7] =  14; aaJones[12][ 8] =  33; aaJones[12][ 9] = 479; 
	aaJones[12][10] = 388; aaJones[12][11] =  65; aaJones[12][12] =   0; aaJones[12][13] =  43; aaJones[12][14] =  16; 
	aaJones[12][15] =  29; aaJones[12][16] = 226; aaJones[12][17] =  24; aaJones[12][18] =  18; aaJones[12][19] = 323; 
	aaJones[13][ 0] =  15; aaJones[13][ 1] =   5; aaJones[13][ 2] =  10; aaJones[13][ 3] =   4; aaJones[13][ 4] =  78; 
	aaJones[13][ 5] =   4; aaJones[13][ 6] =   5; aaJones[13][ 7] =   5; aaJones[13][ 8] =  40; aaJones[13][ 9] =  89; 
	aaJones[13][10] = 248; aaJones[13][11] =   4; aaJones[13][12] =  43; aaJones[13][13] =   0; aaJones[13][14] =  17; 
	aaJones[13][15] =  92; aaJones[13][16] =  12; aaJones[13][17] =  53; aaJones[13][18] = 536; aaJones[13][19] =  62; 
	aaJones[14][ 0] = 194; aaJones[14][ 1] =  74; aaJones[14][ 2] =  15; aaJones[14][ 3] =  15; aaJones[14][ 4] =  14; 
	aaJones[14][ 5] = 164; aaJones[14][ 6] =  18; aaJones[14][ 7] =  24; aaJones[14][ 8] = 115; aaJones[14][ 9] =  10; 
	aaJones[14][10] = 102; aaJones[14][11] =  21; aaJones[14][12] =  16; aaJones[14][13] =  17; aaJones[14][14] =   0; 
	aaJones[14][15] = 285; aaJones[14][16] = 118; aaJones[14][17] =   6; aaJones[14][18] =  10; aaJones[14][19] =  23; 
	aaJones[15][ 0] = 378; aaJones[15][ 1] = 101; aaJones[15][ 2] = 503; aaJones[15][ 3] =  59; aaJones[15][ 4] = 223; 
	aaJones[15][ 5] =  53; aaJones[15][ 6] =  30; aaJones[15][ 7] = 201; aaJones[15][ 8] =  73; aaJones[15][ 9] =  40; 
	aaJones[15][10] =  59; aaJones[15][11] =  47; aaJones[15][12] =  29; aaJones[15][13] =  92; aaJones[15][14] = 285; 
	aaJones[15][15] =   0; aaJones[15][16] = 477; aaJones[15][17] =  35; aaJones[15][18] =  63; aaJones[15][19] =  38; 
	aaJones[16][ 0] = 475; aaJones[16][ 1] =  64; aaJones[16][ 2] = 232; aaJones[16][ 3] =  38; aaJones[16][ 4] =  42; 
	aaJones[16][ 5] =  51; aaJones[16][ 6] =  32; aaJones[16][ 7] =  33; aaJones[16][ 8] =  46; aaJones[16][ 9] = 245; 
	aaJones[16][10] =  25; aaJones[16][11] = 103; aaJones[16][12] = 226; aaJones[16][13] =  12; aaJones[16][14] = 118; 
	aaJones[16][15] = 477; aaJones[16][16] =   0; aaJones[16][17] =  12; aaJones[16][18] =  21; aaJones[16][19] = 112; 
	aaJones[17][ 0] =   9; aaJones[17][ 1] = 126; aaJones[17][ 2] =   8; aaJones[17][ 3] =   4; aaJones[17][ 4] = 115; 
	aaJones[17][ 5] =  18; aaJones[17][ 6] =  10; aaJones[17][ 7] =  55; aaJones[17][ 8] =   8; aaJones[17][ 9] =   9; 
	aaJones[17][10] =  52; aaJones[17][11] =  10; aaJones[17][12] =  24; aaJones[17][13] =  53; aaJones[17][14] =   6; 
	aaJones[17][15] =  35; aaJones[17][16] =  12; aaJones[17][17] =   0; aaJones[17][18] =  71; aaJones[17][19] =  25; 
	aaJones[18][ 0] =  11; aaJones[18][ 1] =  20; aaJones[18][ 2] =  70; aaJones[18][ 3] =  46; aaJones[18][ 4] = 209; 
	aaJones[18][ 5] =  24; aaJones[18][ 6] =   7; aaJones[18][ 7] =   8; aaJones[18][ 8] = 573; aaJones[18][ 9] =  32; 
	aaJones[18][10] =  24; aaJones[18][11] =   8; aaJones[18][12] =  18; aaJones[18][13] = 536; aaJones[18][14] =  10; 
	aaJones[18][15] =  63; aaJones[18][16] =  21; aaJones[18][17] =  71; aaJones[18][18] =   0; aaJones[18][19] =  16; 
	aaJones[19][ 0] = 298; aaJones[19][ 1] =  17; aaJones[19][ 2] =  16; aaJones[19][ 3] =  31; aaJones[19][ 4] =  62; 
	aaJones[19][ 5] =  20; aaJones[19][ 6] =  45; aaJones[19][ 7] =  47; aaJones[19][ 8] =  11; aaJones[19][ 9] = 961; 
	aaJones[19][10] = 180; aaJones[19][11] =  14; aaJones[19][12] = 323; aaJones[19][13] =  62; aaJones[19][14] =  23; 
	aaJones[19][15] =  38; aaJones[19][16] = 112; aaJones[19][17] =  25; aaJones[19][18] =  16; aaJones[19][19] =   0; 

	jonesPi[ 0] = 0.076748;
	jonesPi[ 1] = 0.051691;
	jonesPi[ 2] = 0.042645;
	jonesPi[ 3] = 0.051544;
	jonesPi[ 4] = 0.019803;
	jonesPi[ 5] = 0.040752;
	jonesPi[ 6] = 0.061830;
	jonesPi[ 7] = 0.073152;
	jonesPi[ 8] = 0.022944;
	jonesPi[ 9] = 0.053761;
	jonesPi[10] = 0.091904;
	jonesPi[11] = 0.058676;
	jonesPi[12] = 0.023826;
	jonesPi[13] = 0.040126;
	jonesPi[14] = 0.050901;
	jonesPi[15] = 0.068765;
	jonesPi[16] = 0.058565;
	jonesPi[17] = 0.014261;
	jonesPi[18] = 0.032102;
	jonesPi[19] = 0.066005;

	aaDayhoff[ 0][ 0] =   0; aaDayhoff[ 0][ 1] =  27; aaDayhoff[ 0][ 2] =  98; aaDayhoff[ 0][ 3] = 120; aaDayhoff[ 0][ 4] =  36; 
	aaDayhoff[ 0][ 5] =  89; aaDayhoff[ 0][ 6] = 198; aaDayhoff[ 0][ 7] = 240; aaDayhoff[ 0][ 8] =  23; aaDayhoff[ 0][ 9] =  65; 
	aaDayhoff[ 0][10] =  41; aaDayhoff[ 0][11] =  26; aaDayhoff[ 0][12] =  72; aaDayhoff[ 0][13] =  18; aaDayhoff[ 0][14] = 250; 
	aaDayhoff[ 0][15] = 409; aaDayhoff[ 0][16] = 371; aaDayhoff[ 0][17] =   0; aaDayhoff[ 0][18] =  24; aaDayhoff[ 0][19] = 208; 
	aaDayhoff[ 1][ 0] =  27; aaDayhoff[ 1][ 1] =   0; aaDayhoff[ 1][ 2] =  32; aaDayhoff[ 1][ 3] =   0; aaDayhoff[ 1][ 4] =  23; 
	aaDayhoff[ 1][ 5] = 246; aaDayhoff[ 1][ 6] =   1; aaDayhoff[ 1][ 7] =   9; aaDayhoff[ 1][ 8] = 240; aaDayhoff[ 1][ 9] =  64; 
	aaDayhoff[ 1][10] =  15; aaDayhoff[ 1][11] = 464; aaDayhoff[ 1][12] =  90; aaDayhoff[ 1][13] =  14; aaDayhoff[ 1][14] = 103; 
	aaDayhoff[ 1][15] = 154; aaDayhoff[ 1][16] =  26; aaDayhoff[ 1][17] = 201; aaDayhoff[ 1][18] =   8; aaDayhoff[ 1][19] =  24; 
	aaDayhoff[ 2][ 0] =  98; aaDayhoff[ 2][ 1] =  32; aaDayhoff[ 2][ 2] =   0; aaDayhoff[ 2][ 3] = 905; aaDayhoff[ 2][ 4] =   0; 
	aaDayhoff[ 2][ 5] = 103; aaDayhoff[ 2][ 6] = 148; aaDayhoff[ 2][ 7] = 139; aaDayhoff[ 2][ 8] = 535; aaDayhoff[ 2][ 9] =  77; 
	aaDayhoff[ 2][10] =  34; aaDayhoff[ 2][11] = 318; aaDayhoff[ 2][12] =   1; aaDayhoff[ 2][13] =  14; aaDayhoff[ 2][14] =  42; 
	aaDayhoff[ 2][15] = 495; aaDayhoff[ 2][16] = 229; aaDayhoff[ 2][17] =  23; aaDayhoff[ 2][18] =  95; aaDayhoff[ 2][19] =  15; 
	aaDayhoff[ 3][ 0] = 120; aaDayhoff[ 3][ 1] =   0; aaDayhoff[ 3][ 2] = 905; aaDayhoff[ 3][ 3] =   0; aaDayhoff[ 3][ 4] =   0; 
	aaDayhoff[ 3][ 5] = 134; aaDayhoff[ 3][ 6] = 1153; aaDayhoff[ 3][ 7] = 125; aaDayhoff[ 3][ 8] =  86; aaDayhoff[ 3][ 9] =  24; 
	aaDayhoff[ 3][10] =   0; aaDayhoff[ 3][11] =  71; aaDayhoff[ 3][12] =   0; aaDayhoff[ 3][13] =   0; aaDayhoff[ 3][14] =  13; 
	aaDayhoff[ 3][15] =  95; aaDayhoff[ 3][16] =  66; aaDayhoff[ 3][17] =   0; aaDayhoff[ 3][18] =   0; aaDayhoff[ 3][19] =  18; 
	aaDayhoff[ 4][ 0] =  36; aaDayhoff[ 4][ 1] =  23; aaDayhoff[ 4][ 2] =   0; aaDayhoff[ 4][ 3] =   0; aaDayhoff[ 4][ 4] =   0; 
	aaDayhoff[ 4][ 5] =   0; aaDayhoff[ 4][ 6] =   0; aaDayhoff[ 4][ 7] =  11; aaDayhoff[ 4][ 8] =  28; aaDayhoff[ 4][ 9] =  44; 
	aaDayhoff[ 4][10] =   0; aaDayhoff[ 4][11] =   0; aaDayhoff[ 4][12] =   0; aaDayhoff[ 4][13] =   0; aaDayhoff[ 4][14] =  19; 
	aaDayhoff[ 4][15] = 161; aaDayhoff[ 4][16] =  16; aaDayhoff[ 4][17] =   0; aaDayhoff[ 4][18] =  96; aaDayhoff[ 4][19] =  49; 
	aaDayhoff[ 5][ 0] =  89; aaDayhoff[ 5][ 1] = 246; aaDayhoff[ 5][ 2] = 103; aaDayhoff[ 5][ 3] = 134; aaDayhoff[ 5][ 4] =   0; 
	aaDayhoff[ 5][ 5] =   0; aaDayhoff[ 5][ 6] = 716; aaDayhoff[ 5][ 7] =  28; aaDayhoff[ 5][ 8] = 606; aaDayhoff[ 5][ 9] =  18; 
	aaDayhoff[ 5][10] =  73; aaDayhoff[ 5][11] = 153; aaDayhoff[ 5][12] = 114; aaDayhoff[ 5][13] =   0; aaDayhoff[ 5][14] = 153; 
	aaDayhoff[ 5][15] =  56; aaDayhoff[ 5][16] =  53; aaDayhoff[ 5][17] =   0; aaDayhoff[ 5][18] =   0; aaDayhoff[ 5][19] =  35; 
	aaDayhoff[ 6][ 0] = 198; aaDayhoff[ 6][ 1] =   1; aaDayhoff[ 6][ 2] = 148; aaDayhoff[ 6][ 3] = 1153; aaDayhoff[ 6][ 4] =   0; 
	aaDayhoff[ 6][ 5] = 716; aaDayhoff[ 6][ 6] =   0; aaDayhoff[ 6][ 7] =  81; aaDayhoff[ 6][ 8] =  43; aaDayhoff[ 6][ 9] =  61; 
	aaDayhoff[ 6][10] =  11; aaDayhoff[ 6][11] =  83; aaDayhoff[ 6][12] =  30; aaDayhoff[ 6][13] =   0; aaDayhoff[ 6][14] =  51; 
	aaDayhoff[ 6][15] =  79; aaDayhoff[ 6][16] =  34; aaDayhoff[ 6][17] =   0; aaDayhoff[ 6][18] =  22; aaDayhoff[ 6][19] =  37; 
	aaDayhoff[ 7][ 0] = 240; aaDayhoff[ 7][ 1] =   9; aaDayhoff[ 7][ 2] = 139; aaDayhoff[ 7][ 3] = 125; aaDayhoff[ 7][ 4] =  11; 
	aaDayhoff[ 7][ 5] =  28; aaDayhoff[ 7][ 6] =  81; aaDayhoff[ 7][ 7] =   0; aaDayhoff[ 7][ 8] =  10; aaDayhoff[ 7][ 9] =   0; 
	aaDayhoff[ 7][10] =   7; aaDayhoff[ 7][11] =  27; aaDayhoff[ 7][12] =  17; aaDayhoff[ 7][13] =  15; aaDayhoff[ 7][14] =  34; 
	aaDayhoff[ 7][15] = 234; aaDayhoff[ 7][16] =  30; aaDayhoff[ 7][17] =   0; aaDayhoff[ 7][18] =   0; aaDayhoff[ 7][19] =  54; 
	aaDayhoff[ 8][ 0] =  23; aaDayhoff[ 8][ 1] = 240; aaDayhoff[ 8][ 2] = 535; aaDayhoff[ 8][ 3] =  86; aaDayhoff[ 8][ 4] =  28; 
	aaDayhoff[ 8][ 5] = 606; aaDayhoff[ 8][ 6] =  43; aaDayhoff[ 8][ 7] =  10; aaDayhoff[ 8][ 8] =   0; aaDayhoff[ 8][ 9] =   7; 
	aaDayhoff[ 8][10] =  44; aaDayhoff[ 8][11] =  26; aaDayhoff[ 8][12] =   0; aaDayhoff[ 8][13] =  48; aaDayhoff[ 8][14] =  94; 
	aaDayhoff[ 8][15] =  35; aaDayhoff[ 8][16] =  22; aaDayhoff[ 8][17] =  27; aaDayhoff[ 8][18] = 127; aaDayhoff[ 8][19] =  44; 
	aaDayhoff[ 9][ 0] =  65; aaDayhoff[ 9][ 1] =  64; aaDayhoff[ 9][ 2] =  77; aaDayhoff[ 9][ 3] =  24; aaDayhoff[ 9][ 4] =  44; 
	aaDayhoff[ 9][ 5] =  18; aaDayhoff[ 9][ 6] =  61; aaDayhoff[ 9][ 7] =   0; aaDayhoff[ 9][ 8] =   7; aaDayhoff[ 9][ 9] =   0; 
	aaDayhoff[ 9][10] = 257; aaDayhoff[ 9][11] =  46; aaDayhoff[ 9][12] = 336; aaDayhoff[ 9][13] = 196; aaDayhoff[ 9][14] =  12; 
	aaDayhoff[ 9][15] =  24; aaDayhoff[ 9][16] = 192; aaDayhoff[ 9][17] =   0; aaDayhoff[ 9][18] =  37; aaDayhoff[ 9][19] = 889; 
	aaDayhoff[10][ 0] =  41; aaDayhoff[10][ 1] =  15; aaDayhoff[10][ 2] =  34; aaDayhoff[10][ 3] =   0; aaDayhoff[10][ 4] =   0; 
	aaDayhoff[10][ 5] =  73; aaDayhoff[10][ 6] =  11; aaDayhoff[10][ 7] =   7; aaDayhoff[10][ 8] =  44; aaDayhoff[10][ 9] = 257; 
	aaDayhoff[10][10] =   0; aaDayhoff[10][11] =  18; aaDayhoff[10][12] = 527; aaDayhoff[10][13] = 157; aaDayhoff[10][14] =  32; 
	aaDayhoff[10][15] =  17; aaDayhoff[10][16] =  33; aaDayhoff[10][17] =  46; aaDayhoff[10][18] =  28; aaDayhoff[10][19] = 175; 
	aaDayhoff[11][ 0] =  26; aaDayhoff[11][ 1] = 464; aaDayhoff[11][ 2] = 318; aaDayhoff[11][ 3] =  71; aaDayhoff[11][ 4] =   0; 
	aaDayhoff[11][ 5] = 153; aaDayhoff[11][ 6] =  83; aaDayhoff[11][ 7] =  27; aaDayhoff[11][ 8] =  26; aaDayhoff[11][ 9] =  46; 
	aaDayhoff[11][10] =  18; aaDayhoff[11][11] =   0; aaDayhoff[11][12] = 243; aaDayhoff[11][13] =   0; aaDayhoff[11][14] =  33; 
	aaDayhoff[11][15] =  96; aaDayhoff[11][16] = 136; aaDayhoff[11][17] =   0; aaDayhoff[11][18] =  13; aaDayhoff[11][19] =  10; 
	aaDayhoff[12][ 0] =  72; aaDayhoff[12][ 1] =  90; aaDayhoff[12][ 2] =   1; aaDayhoff[12][ 3] =   0; aaDayhoff[12][ 4] =   0; 
	aaDayhoff[12][ 5] = 114; aaDayhoff[12][ 6] =  30; aaDayhoff[12][ 7] =  17; aaDayhoff[12][ 8] =   0; aaDayhoff[12][ 9] = 336; 
	aaDayhoff[12][10] = 527; aaDayhoff[12][11] = 243; aaDayhoff[12][12] =   0; aaDayhoff[12][13] =  92; aaDayhoff[12][14] =  17; 
	aaDayhoff[12][15] =  62; aaDayhoff[12][16] = 104; aaDayhoff[12][17] =   0; aaDayhoff[12][18] =   0; aaDayhoff[12][19] = 258; 
	aaDayhoff[13][ 0] =  18; aaDayhoff[13][ 1] =  14; aaDayhoff[13][ 2] =  14; aaDayhoff[13][ 3] =   0; aaDayhoff[13][ 4] =   0; 
	aaDayhoff[13][ 5] =   0; aaDayhoff[13][ 6] =   0; aaDayhoff[13][ 7] =  15; aaDayhoff[13][ 8] =  48; aaDayhoff[13][ 9] = 196; 
	aaDayhoff[13][10] = 157; aaDayhoff[13][11] =   0; aaDayhoff[13][12] =  92; aaDayhoff[13][13] =   0; aaDayhoff[13][14] =  11; 
	aaDayhoff[13][15] =  46; aaDayhoff[13][16] =  13; aaDayhoff[13][17] =  76; aaDayhoff[13][18] = 698; aaDayhoff[13][19] =  12; 
	aaDayhoff[14][ 0] = 250; aaDayhoff[14][ 1] = 103; aaDayhoff[14][ 2] =  42; aaDayhoff[14][ 3] =  13; aaDayhoff[14][ 4] =  19; 
	aaDayhoff[14][ 5] = 153; aaDayhoff[14][ 6] =  51; aaDayhoff[14][ 7] =  34; aaDayhoff[14][ 8] =  94; aaDayhoff[14][ 9] =  12; 
	aaDayhoff[14][10] =  32; aaDayhoff[14][11] =  33; aaDayhoff[14][12] =  17; aaDayhoff[14][13] =  11; aaDayhoff[14][14] =   0; 
	aaDayhoff[14][15] = 245; aaDayhoff[14][16] =  78; aaDayhoff[14][17] =   0; aaDayhoff[14][18] =   0; aaDayhoff[14][19] =  48; 
	aaDayhoff[15][ 0] = 409; aaDayhoff[15][ 1] = 154; aaDayhoff[15][ 2] = 495; aaDayhoff[15][ 3] =  95; aaDayhoff[15][ 4] = 161; 
	aaDayhoff[15][ 5] =  56; aaDayhoff[15][ 6] =  79; aaDayhoff[15][ 7] = 234; aaDayhoff[15][ 8] =  35; aaDayhoff[15][ 9] =  24; 
	aaDayhoff[15][10] =  17; aaDayhoff[15][11] =  96; aaDayhoff[15][12] =  62; aaDayhoff[15][13] =  46; aaDayhoff[15][14] = 245; 
	aaDayhoff[15][15] =   0; aaDayhoff[15][16] = 550; aaDayhoff[15][17] =  75; aaDayhoff[15][18] =  34; aaDayhoff[15][19] =  30; 
	aaDayhoff[16][ 0] = 371; aaDayhoff[16][ 1] =  26; aaDayhoff[16][ 2] = 229; aaDayhoff[16][ 3] =  66; aaDayhoff[16][ 4] =  16; 
	aaDayhoff[16][ 5] =  53; aaDayhoff[16][ 6] =  34; aaDayhoff[16][ 7] =  30; aaDayhoff[16][ 8] =  22; aaDayhoff[16][ 9] = 192; 
	aaDayhoff[16][10] =  33; aaDayhoff[16][11] = 136; aaDayhoff[16][12] = 104; aaDayhoff[16][13] =  13; aaDayhoff[16][14] =  78; 
	aaDayhoff[16][15] = 550; aaDayhoff[16][16] =   0; aaDayhoff[16][17] =   0; aaDayhoff[16][18] =  42; aaDayhoff[16][19] = 157; 
	aaDayhoff[17][ 0] =   0; aaDayhoff[17][ 1] = 201; aaDayhoff[17][ 2] =  23; aaDayhoff[17][ 3] =   0; aaDayhoff[17][ 4] =   0; 
	aaDayhoff[17][ 5] =   0; aaDayhoff[17][ 6] =   0; aaDayhoff[17][ 7] =   0; aaDayhoff[17][ 8] =  27; aaDayhoff[17][ 9] =   0; 
	aaDayhoff[17][10] =  46; aaDayhoff[17][11] =   0; aaDayhoff[17][12] =   0; aaDayhoff[17][13] =  76; aaDayhoff[17][14] =   0; 
	aaDayhoff[17][15] =  75; aaDayhoff[17][16] =   0; aaDayhoff[17][17] =   0; aaDayhoff[17][18] =  61; aaDayhoff[17][19] =   0; 
	aaDayhoff[18][ 0] =  24; aaDayhoff[18][ 1] =   8; aaDayhoff[18][ 2] =  95; aaDayhoff[18][ 3] =   0; aaDayhoff[18][ 4] =  96; 
	aaDayhoff[18][ 5] =   0; aaDayhoff[18][ 6] =  22; aaDayhoff[18][ 7] =   0; aaDayhoff[18][ 8] = 127; aaDayhoff[18][ 9] =  37; 
	aaDayhoff[18][10] =  28; aaDayhoff[18][11] =  13; aaDayhoff[18][12] =   0; aaDayhoff[18][13] = 698; aaDayhoff[18][14] =   0; 
	aaDayhoff[18][15] =  34; aaDayhoff[18][16] =  42; aaDayhoff[18][17] =  61; aaDayhoff[18][18] =   0; aaDayhoff[18][19] =  28; 
	aaDayhoff[19][ 0] = 208; aaDayhoff[19][ 1] =  24; aaDayhoff[19][ 2] =  15; aaDayhoff[19][ 3] =  18; aaDayhoff[19][ 4] =  49; 
	aaDayhoff[19][ 5] =  35; aaDayhoff[19][ 6] =  37; aaDayhoff[19][ 7] =  54; aaDayhoff[19][ 8] =  44; aaDayhoff[19][ 9] = 889; 
	aaDayhoff[19][10] = 175; aaDayhoff[19][11] =  10; aaDayhoff[19][12] = 258; aaDayhoff[19][13] =  12; aaDayhoff[19][14] =  48; 
	aaDayhoff[19][15] =  30; aaDayhoff[19][16] = 157; aaDayhoff[19][17] =   0; aaDayhoff[19][18] =  28; aaDayhoff[19][19] =   0;

	dayhoffPi[ 0] = 0.087127;
	dayhoffPi[ 1] = 0.040904;
	dayhoffPi[ 2] = 0.040432;
	dayhoffPi[ 3] = 0.046872;
	dayhoffPi[ 4] = 0.033474;
	dayhoffPi[ 5] = 0.038255;
	dayhoffPi[ 6] = 0.049530;
	dayhoffPi[ 7] = 0.088612;
	dayhoffPi[ 8] = 0.033618;
	dayhoffPi[ 9] = 0.036886;
	dayhoffPi[10] = 0.085357;
	dayhoffPi[11] = 0.080482;
	dayhoffPi[12] = 0.014753;
	dayhoffPi[13] = 0.039772;
	dayhoffPi[14] = 0.050680;
	dayhoffPi[15] = 0.069577;
	dayhoffPi[16] = 0.058542;
	dayhoffPi[17] = 0.010494;
	dayhoffPi[18] = 0.029916;
	dayhoffPi[19] = 0.064718;
	 
	return (NO_ERROR);
	
}





int SetAAQMatrix (double **a, int whichTree, int whichChain)

{

	register int	i, j, count, temp;
	double			scaler, mult;

	
	/* set diagonal of Q matrix to 0 */
	for (i=0; i<nStates; i++)
		a[i][i] = 0.0;
	
	if (aaModelType == POISSON)
		{
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				a[i][i] -= (a[i][j] = 0.05);
				a[j][j] -= (a[j][i] = 0.05);
				scaler += 0.05 * a[i][j];
				scaler += 0.05 * a[j][i];
				}
			}
		}
	else if (aaModelType == EQUALIN)
		{
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				a[i][i] -= (a[i][j] = baseFreq[whichChain*2*nStates + whichTree*nStates + j]);
				a[j][j] -= (a[j][i] = baseFreq[whichChain*2*nStates + whichTree*nStates + i]);
				scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + i] * a[i][j];
				scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + j] * a[j][i];
				}
			}
		}
	else if (aaModelType == JONES)
		{
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				a[i][i] -= (a[i][j] = jonesPi[j] * aaJones[i][j]);
				a[j][j] -= (a[j][i] = jonesPi[i] * aaJones[j][i]);
				scaler += jonesPi[i] * a[i][j];
				scaler += jonesPi[j] * a[j][i];
				}
			}
		}
	else if (aaModelType == DAYHOFF)
		{
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				a[i][i] -= (a[i][j] = dayhoffPi[j] * aaDayhoff[i][j]);
				a[j][j] -= (a[j][i] = dayhoffPi[i] * aaDayhoff[j][i]);
				scaler += dayhoffPi[i] * a[i][j];
				scaler += dayhoffPi[j] * a[j][i];
				}
			}
		}
	else if (aaModelType == GTR)
		{
		temp = whichChain*2*190 + whichTree*190;
		count = 0;
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				if (count >= 190)
					{
					printf ("   ERROR: AA model went out of bounds\n");
					return (ERROR);
					}
				mult = subParams[temp + count];
				a[i][i] -= (a[i][j] = baseFreq[whichChain*2*nStates + whichTree*nStates + j] * mult);
				a[j][j] -= (a[j][i] = baseFreq[whichChain*2*nStates + whichTree*nStates + i] * mult);
				scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + i] * a[i][j];
				scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + j] * a[j][i];
				count++;
				}
			}
		}
		
	/* rescale Q matrix */
	scaler = 1.0 / scaler;
	for (i=0; i<nStates; i++)
		for (j=0; j<nStates; j++)
			a[i][j] *= scaler;

#	if 0
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			printf ("%0.5lf ", a[i][j]);
		printf ("\n");
		}
#	endif

	return (NO_ERROR);
	
}





int SetCodonQMatrix (double **a, int whichTree, int whichChain, double nonsyn, double kap)

{

	register int	i, j, k, nDiff, isTransition;
	double			scaler, mult;

	/* set diagonal of Q matrix to 0 */
	for (i=0; i<nStates; i++)
		a[i][i] = 0.0;
	
	scaler = 0.0;
	for (i=0; i<nStates; i++)
		{
		for (j=i+1; j<nStates; j++)
			{
			nDiff = 0;
			for (k=0; k<3; k++)
				{
				if (codonNucs[i][k] != codonNucs[j][k])
					{
					nDiff++;
					if ((codonNucs[i][k] == 0 && codonNucs[j][k] == 2) || (codonNucs[i][k] == 2 && codonNucs[j][k] == 0) ||
					    (codonNucs[i][k] == 1 && codonNucs[j][k] == 3) || (codonNucs[i][k] == 3 && codonNucs[j][k] == 1))
						isTransition = YES;
					else
						isTransition = NO;
					}
				}
			if (nDiff > 1)
				{
				mult = 0.0;
				}
			else
				{
				if (transCodon[i] == transCodon[j])
					mult = 1.0;
				else
					mult = nonsyn;
				if (isTransition == YES)
					mult *= kap;
				}
			
			a[i][i] -= (a[i][j] = baseFreq[whichChain*2*nStates + whichTree*nStates + j] * mult);
			a[j][j] -= (a[j][i] = baseFreq[whichChain*2*nStates + whichTree*nStates + i] * mult);
			scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + i] * a[i][j];
			scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + j] * a[j][i];
			}
		}
		
	/* rescale Q matrix */
	scaler = 1.0 / scaler;
	for (i=0; i<nStates; i++)
		for (j=0; j<nStates; j++)
			a[i][j] *= scaler;

#	if 0
	printf ("k = %lf w = %lf\n", kap, nonsyn);
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			printf ("%0.4lf ", a[i][j]);
		printf ("\n");
		}
#	endif

	return (NO_ERROR);
	
}






int SetCodonSwitchQMatrix (double **a, int whichTree, int whichChain, double nonsyn, double kap, double sr)

{

	register int	i, j, k, nDiff, isTransition, temp, nLocalStates, twoTimesS;
	double			scaler, piPur, piNeu, piPos, multPur, multNeu, multPos, **sPur, **sNeu, **sPos, codonFreq;

	sPur = psdmatrix (nStates);
	sNeu = psdmatrix (nStates);
	sPos = psdmatrix (nStates);
	
	temp = whichChain*2*nStates + whichTree*nStates;
	piPur = probPur[whichChain*2 + whichTree];
	piNeu = probNeu[whichChain*2 + whichTree];
	piPos = probPos[whichChain*2 + whichTree];
	nLocalStates = 3 * nStates;
	twoTimesS = 2 * nStates;

	/* set diagonal of Q matrix to 0 */
	for (i=0; i<nStates; i++)
		{
		sPur[i][i] = sNeu[i][i] = sPos[i][i] = 0.0;
		}
	
	/* set three q matrices */
	for (i=0; i<nStates; i++)
		{
		for (j=i+1; j<nStates; j++)
			{
			nDiff = 0;
			for (k=0; k<3; k++)
				{
				if (codonNucs[i][k] != codonNucs[j][k])
					{
					nDiff++;
					if ((codonNucs[i][k] == 0 && codonNucs[j][k] == 2) || (codonNucs[i][k] == 2 && codonNucs[j][k] == 0) ||
					    (codonNucs[i][k] == 1 && codonNucs[j][k] == 3) || (codonNucs[i][k] == 3 && codonNucs[j][k] == 1))
						isTransition = YES;
					else
						isTransition = NO;
					}
				}
			if (nDiff > 1)
				{
				multPur = multNeu = multPos = 0.0;
				}
			else
				{
				if (transCodon[i] == transCodon[j])
					{
					multPur = 1.0;
					multNeu = 1.0;
					multPos = 1.0;
					}
				else
					{
					multPur = 0.0;
					multNeu = 1.0;
					multPos = nonsyn;
					}
				if (isTransition == YES)
					{
					multPur *= kap;
					multNeu *= kap;
					multPos *= kap;
					}
				}
			sPur[i][j] = baseFreq[temp + j] * multPur;
			sPur[j][i] = baseFreq[temp + i] * multPur;
			sNeu[i][j] = baseFreq[temp + j] * multNeu;
			sNeu[j][i] = baseFreq[temp + i] * multNeu;
			sPos[i][j] = baseFreq[temp + j] * multPos;
			sPos[j][i] = baseFreq[temp + i] * multPos;
			}
		}
	
	/* get scalers for q matrices */
	scaler = 0.0;
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			{
			if (i != j)
				{
				codonFreq = baseFreq[temp + i];
				scaler += codonFreq * piPur * sPur[i][j];
				scaler += codonFreq * piNeu * sNeu[i][j];
				scaler += codonFreq * piPos * sPos[i][j];
				}
			}
		}
		
	/* rescale Q matrices (off diagonals) */
	scaler = 1.0 / scaler;
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			{
			if (i != j)
				{
				sPur[i][j] *= scaler;
				sNeu[i][j] *= scaler;
				sPos[i][j] *= scaler;
				}
			}
		}
	/* rescale Q matrices (diagonals) */
	for (i=0; i<nStates; i++)
		{
		multPur = multNeu = multPos = 0.0;
		for (j=0; j<nStates; j++)
			{
			if (i != j)
				{
				multPur += sPur[i][j];
				multNeu += sNeu[i][j];
				multPos += sPos[i][j];
				}
			}
		multPur += (piNeu + piPos) * sr;
		multNeu += (piPur + piPos) * sr;
		multPos += (piNeu + piNeu) * sr;
		sPur[i][i] = -multPur;
		sNeu[i][i] = -multNeu;
		sPos[i][i] = -multPos;
		}
		
	/* fill in a matrix */
	for (i=0; i<nLocalStates; i++)
		for (j=0; j<nLocalStates; j++)
			a[i][j] = 0.0;
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			{
			a[i][j] = sPur[i][j];
			a[nStates+i][nStates+j] = sNeu[i][j];
			a[twoTimesS+i][twoTimesS+j] = sPos[i][j];
			if (i == j)
				{
				a[i][nStates + j]             = piNeu * sr;
				a[i][twoTimesS + j]           = piPos * sr;
				a[nStates + i][j]             = piPur * sr;
				a[nStates + i][twoTimesS + j] = piPos * sr;
				a[twoTimesS + i][j]           = piPur * sr;
				a[twoTimesS + i][nStates + j] = piNeu * sr;
				}
			}
		}
					
	free_psdmatrix (sPur);
	free_psdmatrix (sNeu);
	free_psdmatrix (sPos);

#	if 0
	printf ("k = %lf w = %lf\n", kap, nonsyn);
	for (i=0; i<nLocalStates; i++)
		{
		for (j=0; j<nLocalStates; j++)
			printf ("%0.4lf ", a[i][j]);
		printf ("\n");
		}
	printf ("%lf %lf %lf %lf\n", piPur, piNeu, piPos, sr);
#	endif

	return (NO_ERROR);
	
}





int SetAACovQMatrix (double **a, int whichTree, int whichChain, double r)

{

	register int	i, j, count, temp;
	double			scaler, mult, s[20][20], probOn, sum, s1, s2;

	
	probOn = switchPi[whichChain*4 + whichTree*2 + 0];
	s1 = switchRate[whichChain*4 + whichTree*2 + 0];
	s2 = switchRate[whichChain*4 + whichTree*2 + 1];

	/* set matrix a to 0 */
	for (i=0; i<40; i++)
		for (j=0; j<40; j++)
			a[i][j] = 0.0;
	
	if (aaModelType == POISSON)
		{
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				s[i][j] = 0.05;
				s[j][i] = 0.05;
				scaler += 0.05 * s[i][j] * probOn;
				scaler += 0.05 * s[j][i] * probOn;
				}
			}
		}
	else if (aaModelType == EQUALIN)
		{
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				s[i][j] = baseFreq[whichChain*2*nStates + whichTree*nStates + j];
				s[j][i] = baseFreq[whichChain*2*nStates + whichTree*nStates + i];
				scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + i] * s[i][j] * probOn;
				scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + j] * s[j][i] * probOn;
				}
			}
		}
	else if (aaModelType == JONES)
		{
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				s[i][j] = jonesPi[j] * aaJones[i][j];
				s[j][i] = jonesPi[i] * aaJones[j][i];
				scaler += jonesPi[i] * s[i][j] * probOn;
				scaler += jonesPi[j] * s[j][i] * probOn;
				}
			}
		}
	else if (aaModelType == DAYHOFF)
		{
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				s[i][j] = dayhoffPi[j] * aaDayhoff[i][j];
				s[j][i] = dayhoffPi[i] * aaDayhoff[j][i];
				scaler += dayhoffPi[i] * s[i][j] * probOn;
				scaler += dayhoffPi[j] * s[j][i] * probOn;
				}
			}
		}
	else if (aaModelType == GTR)
		{
		temp = whichChain*2*190 + whichTree*190;
		count = 0;
		scaler = 0.0;
		for (i=0; i<nStates; i++)
			{
			for (j=i+1; j<nStates; j++)
				{
				if (count >= 190)
					{
					printf ("   ERROR: AA model went out of bounds\n");
					return (ERROR);
					}
				mult = subParams[temp + count];
				s[i][j] = baseFreq[whichChain*2*nStates + whichTree*nStates + j] * mult;
				s[j][i] = baseFreq[whichChain*2*nStates + whichTree*nStates + i] * mult;
				scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + i] * s[i][j] * probOn;
				scaler += baseFreq[whichChain*2*nStates + whichTree*nStates + j] * s[j][i] * probOn;
				count++;
				}
			}
		}
		
	/* rescale off diagonal elements of Q matrix */
	scaler = 1.0 / scaler;
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			{
			if (i != j)
				s[i][j] *= scaler;
			}
		}
		
	/* now, scale by rate factor */
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			{
			if (i != j)
				s[i][j] *= r;
			}
		}
		
	/* put in diagonal elements */
	for (i=0; i<nStates; i++)
		{
		sum = 0.0;
		for (j=0; j<nStates; j++)
			{
			if (i != j)
				sum += s[i][j];
			s[i][i] = -(sum + s1);
			}
		}
			
	/* now, put s into top left portion of a matrix and other parts of the matrix */
	for (i=0; i<nStates; i++)
		for (j=0; j<nStates; j++)
			a[i][j] = s[i][j];
	for (i=nStates; i<2*nStates; i++)
		a[i][i] = -s2;
		
	for (i=0; i<nStates; i++)
		{
		a[i][nStates+i] = s1;
		a[nStates+i][i] = s2;
		}

#	if 0
	for (i=0; i<nStates; i++)
		{
		for (j=0; j<nStates; j++)
			printf ("%0.5lf ", a[i][j]);
		printf ("\n");
		}
#	endif

	return (NO_ERROR);
	
}





int SetDNACovQMatrix (double **a, int whichTree, int whichChain, double r)

{

	register int	i, j;
	double			scaler, mult, s[4][4], probOn, sum, s1, s2;

	probOn = switchPi[whichChain*4 + whichTree*2 + 0];
	s1 = switchRate[whichChain*4 + whichTree*2 + 0];
	s2 = switchRate[whichChain*4 + whichTree*2 + 1];
	
	/* set matrix a to 0 */
	for (i=0; i<8; i++)
		for (j=0; j<8; j++)
			a[i][j] = 0.0;

	if (nst == 1)
		{
		scaler = 0.0;
		for (i=0; i<4; i++)
			{
			for (j=i+1; j<4; j++)
				{
				s[i][j] = baseFreq[whichChain*8 + whichTree*4 + j];
				s[j][i] = baseFreq[whichChain*8 + whichTree*4 + i];
				scaler += baseFreq[whichChain*8 + whichTree*4 + i] * s[i][j] * probOn;
				scaler += baseFreq[whichChain*8 + whichTree*4 + j] * s[j][i] * probOn;
				}
			}
		}
	else if (nst == 2)
		{
		scaler = 0.0;
		for (i=0; i<4; i++)
			{
			for (j=i+1; j<4; j++)
				{
				if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 3) || (i == 3 && j == 1))
					mult = kappa[whichChain*2 + whichTree];
				else if (i == 0 && j == 2)
					mult = 1.0;
				s[i][j] = baseFreq[whichChain*8 + whichTree*4 + j] * mult;
				s[j][i] = baseFreq[whichChain*8 + whichTree*4 + i] * mult;
				scaler += baseFreq[whichChain*8 + whichTree*4 + i] * s[i][j] * probOn;
				scaler += baseFreq[whichChain*8 + whichTree*4 + j] * s[j][i] * probOn;
				}
			}
		}
	else if (nst == 6)
		{
		scaler = 0.0;
		for (i=0; i<4; i++)
			{
			for (j=i+1; j<4; j++)
				{
				if (i == 0 && j == 1)
					mult = subParams[whichChain*12 + whichTree*6 + 5];
				else if (i == 0 && j == 2)
					mult = subParams[whichChain*12 + whichTree*6 + 4];
				else if (i == 0 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 3];
				else if (i == 1 && j == 2)
					mult = subParams[whichChain*12 + whichTree*6 + 2];
				else if (i == 1 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 1];
				else if (i == 2 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 0];

				s[i][j] = baseFreq[whichChain*8 + whichTree*4 + j] * mult;
				s[j][i] = baseFreq[whichChain*8 + whichTree*4 + i] * mult;
				scaler += baseFreq[whichChain*8 + whichTree*4 + i] * s[i][j] * probOn;
				scaler += baseFreq[whichChain*8 + whichTree*4 + j] * s[j][i] * probOn;
				}
			}
		}

	/* rescale off diagonal elements of Q matrix */
	scaler = 1.0 / scaler;
	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			if (i != j)
				s[i][j] *= scaler;
			}
		}
		
	/* now, scale by rate factor */
	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			if (i != j)
				s[i][j] *= r;
			}
		}
		
	/* put in diagonal elements */
	for (i=0; i<4; i++)
		{
		sum = 0.0;
		for (j=0; j<4; j++)
			{
			if (i != j)
				sum += s[i][j];
			s[i][i] = -(sum + s1);
			}
		}
			
	/* now, put s into top left portion of a matrix and other parts of the matrix */
	for (i=0; i<4; i++)
		for (j=0; j<4; j++)
			a[i][j] = s[i][j];
	for (i=4; i<8; i++)
		a[i][i] = -s2;
	a[0][4] = s1;
	a[1][5] = s1;
	a[2][6] = s1;
	a[3][7] = s1;
	a[4][0] = s2;
	a[5][1] = s2;
	a[6][2] = s2;
	a[7][3] = s2;


#	if 0
	for (i=0; i<8; i++)
		{
		for (j=0; j<8; j++)
			printf ("%0.5lf ", a[i][j]);
		printf ("\n");
		}
#	endif

	return (NO_ERROR);
	
}






int SetGCSwitchQMatrix (double **a, int whichTree, int whichChain, double r)

{

	register int	i, j;
	double			scaler, mult, q0[4][4], q1[4][4], bs0[4], bs1[4], prob0, prob1, sum, s01, s10;

	s01 = switchRate[whichChain*4 + whichTree*2 + 0];
	s10 = switchRate[whichChain*4 + whichTree*2 + 1];
	prob0 = s10 / (s01+s10);
	prob1 = s01 / (s01+s10);
	bs0[A] = (1.0 - gc1[whichChain*2 + whichTree]) * (fracA[whichChain*2 + whichTree]);
	bs0[C] = (gc1[whichChain*2 + whichTree])       * (1.0 - fracG[whichChain*2 + whichTree]);
	bs0[G] = (gc1[whichChain*2 + whichTree])       * (fracG[whichChain*2 + whichTree]);
	bs0[T] = (1.0 - gc1[whichChain*2 + whichTree]) * (1.0 - fracA[whichChain*2 + whichTree]);
	bs1[A] = (1.0 - gc2[whichChain*2 + whichTree]) * (fracA[whichChain*2 + whichTree]);
	bs1[C] = (gc2[whichChain*2 + whichTree])       * (1.0 - fracG[whichChain*2 + whichTree]);
	bs1[G] = (gc2[whichChain*2 + whichTree])       * (fracG[whichChain*2 + whichTree]);
	bs1[T] = (1.0 - gc2[whichChain*2 + whichTree]) * (1.0 - fracA[whichChain*2 + whichTree]);

	/* set matrix a to 0 */
	for (i=0; i<8; i++)
		for (j=0; j<8; j++)
			a[i][j] = 0.0;

	if (nst == 1)
		{
		scaler = 0.0;
		for (i=0; i<4; i++)
			{
			for (j=i+1; j<4; j++)
				{
				q0[i][j] = bs0[j];
				q0[j][i] = bs0[i];
				scaler += bs0[i] * q0[i][j] * prob0;
				scaler += bs0[j] * q0[j][i] * prob0;

				q1[i][j] = bs1[j];
				q1[j][i] = bs1[i];
				scaler += bs1[i] * q1[i][j] * prob1;
				scaler += bs1[j] * q1[j][i] * prob1;
				}
			}
		}
	else if (nst == 2)
		{
		scaler = 0.0;
		for (i=0; i<4; i++)
			{
			for (j=i+1; j<4; j++)
				{
				if ((i == 0 && j == 2) || (i == 2 && j == 0) || (i == 1 && j == 3) || (i == 3 && j == 1))
					mult = kappa[whichChain*2 + whichTree];
				else if (i == 0 && j == 2)
					mult = 1.0;
				q0[i][j] = bs0[j] * mult;
				q0[j][i] = bs0[i] * mult;
				scaler += bs0[i] * q0[i][j] * prob0;
				scaler += bs0[j] * q0[j][i] * prob0;

				q1[i][j] = bs1[j] * mult;
				q1[j][i] = bs1[i] * mult;
				scaler += bs1[i] * q1[i][j] * prob1;
				scaler += bs1[j] * q1[j][i] * prob1;
				}
			}
		}
	else if (nst == 6)
		{
		scaler = 0.0;
		for (i=0; i<4; i++)
			{
			for (j=i+1; j<4; j++)
				{
				if (i == 0 && j == 1)
					mult = subParams[whichChain*12 + whichTree*6 + 5];
				else if (i == 0 && j == 2)
					mult = subParams[whichChain*12 + whichTree*6 + 4];
				else if (i == 0 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 3];
				else if (i == 1 && j == 2)
					mult = subParams[whichChain*12 + whichTree*6 + 2];
				else if (i == 1 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 1];
				else if (i == 2 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 0];

				q0[i][j] = bs0[j] * mult;
				q0[j][i] = bs0[i] * mult;
				scaler += bs0[i] * q0[i][j] * prob0;
				scaler += bs0[j] * q0[j][i] * prob0;

				q1[i][j] = bs1[j] * mult;
				q1[j][i] = bs1[i] * mult;
				scaler += bs1[i] * q1[i][j] * prob1;
				scaler += bs1[j] * q1[j][i] * prob1;
				}
			}
		}

	/* rescale off diagonal elements of Q matrix */
	scaler = 1.0 / scaler;
	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			if (i != j)
				{
				q0[i][j] *= scaler;
				q1[i][j] *= scaler;
				}
			}
		}
		
	/* now, scale by rate factor */
	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			{
			if (i != j)
				{
				q0[i][j] *= r;
				q1[i][j] *= r;
				}
			}
		}
		
	/* put in diagonal elements */
	for (i=0; i<4; i++)
		{
		sum = 0.0;
		for (j=0; j<4; j++)
			{
			if (i != j)
				sum += q0[i][j];
			q0[i][i] = -(sum + s01);
			}

		sum = 0.0;
		for (j=0; j<4; j++)
			{
			if (i != j)
				sum += q1[i][j];
			q1[i][i] = -(sum + s10);
			}
		}
			
	/* now, put q0 into top left portion of matrix and q1 in bottom right portion*/
	for (i=0; i<4; i++)
		for (j=0; j<4; j++)
			a[i][j] = q0[i][j];
	for (i=4; i<8; i++)
		for (j=4; j<8; j++)
			a[i][j] = q1[i-4][j-4];
	a[0][4] = s01;
	a[1][5] = s01;
	a[2][6] = s01;
	a[3][7] = s01;
	a[4][0] = s10;
	a[5][1] = s10;
	a[6][2] = s10;
	a[7][3] = s10;


#	if 0
	for (i=0; i<8; i++)
		{
		for (j=0; j<8; j++)
			printf ("%0.5lf ", a[i][j]);
		printf ("\n");
		}
#	endif

	return (NO_ERROR);
	
}





int SetQMatrix (double **a, int whichTree, int whichChain)

{

	register int	i, j, k;
	int				isComplex, stopLoop;
	double			scaler, mult, **q, *eigenValues, *eigvalsImag, 
					**eigvecs, **inverseEigvecs, *c_ijk, **probs, v, max;
	complex 		**Ceigvecs, **CinverseEigvecs;

	
	/* set diagonal of Q matrix to 0 */
	for (i=0; i<4; i++)
		a[i][i] = 0.0;

	if (nst == 6)
		{
		scaler = 0.0;
		for (i=0; i<4; i++)
			{
			for (j=i+1; j<4; j++)
				{
				if (i == 0 && j == 1)
					mult = subParams[whichChain*12 + whichTree*6 + 5];
				else if (i == 0 && j == 2)
					mult = subParams[whichChain*12 + whichTree*6 + 4];
				else if (i == 0 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 3];
				else if (i == 1 && j == 2)
					mult = subParams[whichChain*12 + whichTree*6 + 2];
				else if (i == 1 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 1];
				else if (i == 2 && j == 3)
					mult = subParams[whichChain*12 + whichTree*6 + 0];

				a[i][i] -= (a[i][j] = baseFreq[whichChain*8 + whichTree*4 + j] * mult);
				a[j][j] -= (a[j][i] = baseFreq[whichChain*8 + whichTree*4 + i] * mult);
				scaler += baseFreq[whichChain*8 + whichTree*4 + i] * a[i][j];
				scaler += baseFreq[whichChain*8 + whichTree*4 + j] * a[j][i];
				}
			}
			
		/* rescale Q matrix */
		scaler = 1.0 / scaler;
		for (i=0; i<4; i++)
			for (j=0; j<4; j++)
				a[i][j] *= scaler;

		}
	else if (nst == 12)
		{
		for (i=0; i<4; i++)
			{
			for (j=0; j<4; j++)
				{
				if (i != j)
					{
					if (i == 0 && j == 1)
						mult = subParams[whichChain*24 + whichTree*12 + 0];
					else if (i == 0 && j == 2)
						mult = subParams[whichChain*24 + whichTree*12 + 1];
					else if (i == 0 && j == 3)
						mult = subParams[whichChain*24 + whichTree*12 + 2];
					else if (i == 1 && j == 2)
						mult = subParams[whichChain*24 + whichTree*12 + 3];
					else if (i == 1 && j == 3)
						mult = subParams[whichChain*24 + whichTree*12 + 4];
					else if (i == 2 && j == 3)
						mult = subParams[whichChain*24 + whichTree*12 + 5];

					else if (i == 1 && j == 0)
						mult = subParams[whichChain*24 + whichTree*12 + 6];
					else if (i == 2 && j == 0)
						mult = subParams[whichChain*24 + whichTree*12 + 7];
					else if (i == 3 && j == 0)
						mult = subParams[whichChain*24 + whichTree*12 + 8];
					else if (i == 2 && j == 1)
						mult = subParams[whichChain*24 + whichTree*12 + 9];
					else if (i == 3 && j == 1)
						mult = subParams[whichChain*24 + whichTree*12 + 10];
					else if (i == 3 && j == 2)
						mult = subParams[whichChain*24 + whichTree*12 + 11];
					a[i][i] -= (a[i][j] = mult);
					}
				}
			}
			
		/* now, figure out base frequencies (if v -> infty) */
		probs = psdmatrix (4);
		q = psdmatrix (4);
		eigenValues = (double *)malloc((size_t) (4 * sizeof(double)));
		if (!eigenValues)
			{
			printf ("\n   ERROR: Cannot allocate eigenValues.\n");
			return (ERROR);
			}
		eigvalsImag = (double *)malloc((size_t) (4 * sizeof(double)));
		if (!eigvalsImag)
			{
			printf ("\n   ERROR: Cannot allocate eigvalsImag.\n");
			free (eigenValues);
			return (ERROR);
			}
		eigvecs = psdmatrix (4);
		inverseEigvecs  = psdmatrix (4);
		Ceigvecs = pscmatrix (4);
		CinverseEigvecs = pscmatrix (4);
		for (i=0; i<4; i++)
			for (j=0; j<4; j++)
				q[i][j] = a[i][j];
		isComplex = GetEigens (4, q, eigenValues, eigvalsImag, eigvecs, inverseEigvecs, Ceigvecs, CinverseEigvecs);
		if (isComplex == NO)
			{
			c_ijk = (double *)malloc((size_t) (4 * 4 * 4 * sizeof(double)));
			if (!c_ijk)
				{
				printf ("\n   ERROR: Cannot allocate c_ijk.\n");
				free (eigenValues);
				free (eigvalsImag);
				return (ERROR);
				}
			CalcCijk (c_ijk, 4, eigvecs, inverseEigvecs);
			}
		stopLoop = NO;
		v = 0.1;
		do
			{
			if (isComplex == NO)
				{
				CalcPij (c_ijk, 4, eigenValues, v,  1.0, probs);
				}
			else
				{
				if (ComplexChangeMatrix (eigenValues, eigvalsImag, Ceigvecs, CinverseEigvecs, 4, probs, v,  1.0) == ERROR)
					printf ("Problem calculating transition probabilities for complex eigen values.\n");
				}
			stopLoop = YES;
			for (i=0; i<4; i++)
				{
				max = 0.0;
				for (j=0; j<3; j++)
					{
					for (k=j+1; k<4; k++)
						{
						if (fabs(probs[j][i] - probs[k][i]) > max)
							max = fabs(probs[j][i] - probs[k][i]);
						}
					}
					if (max > 0.00000001)
						stopLoop = NO;
				}
			/*printf ("v = %lf\n", v);
			for (i=0; i<4; i++)
				{
				for (j=0; j<4; j++)
					printf ("%lf ", probsL[i][j]);
				printf ("\n");
				}*/
			v *= 2.0;
			if (v > 10000.0)
				{
				printf ("\n   ERROR: Q matrix does not have a stationary distribution\n");
				for (i=0; i<4; i++)
					{
					for (j=0; j<4; j++)
						printf ("%lf ", a[i][j]);
					printf ("\n");
					}
				free_psdmatrix (probs);
				free_psdmatrix (q);
				free (eigenValues);
				free (eigvalsImag);
				free_psdmatrix (eigvecs);
				free_psdmatrix (inverseEigvecs);
				free_pscmatrix (Ceigvecs);
				free_pscmatrix (CinverseEigvecs);
				if (isComplex == NO)
					free (c_ijk);
				return (ERROR);
				}
			} while (stopLoop == NO);

		baseFreq[whichChain*8 + whichTree*4 + A] = probs[whichTree][0];
		baseFreq[whichChain*8 + whichTree*4 + C] = probs[whichTree][1];
		baseFreq[whichChain*8 + whichTree*4 + G] = probs[whichTree][2];
		baseFreq[whichChain*8 + whichTree*4 + T] = probs[whichTree][3];
		
		free_psdmatrix (probs);
		free_psdmatrix (q);
		free (eigenValues);
		free (eigvalsImag);
		free_psdmatrix (eigvecs);
		free_psdmatrix (inverseEigvecs);
		free_pscmatrix (Ceigvecs);
		free_pscmatrix (CinverseEigvecs);
		if (isComplex == NO)
			free (c_ijk);

		/* get scaler */
		scaler = 0.0;
		for (i=0; i<4; i++)
			scaler += baseFreq[whichChain*8 + whichTree*4 + i] * (-a[i][i]);

		/* rescale Q matrix */
		scaler = 1.0 / scaler;
		for (i=0; i<4; i++)
			for (j=0; j<4; j++)
				a[i][j] *= scaler;
			
		/*printf ("%lf %lf %lf %lf\n", baseFreq[whichChain*8 + whichTree*4 + A], baseFreq[whichChain*8 + whichTree*4 + C],
			baseFreq[whichChain*8 + whichTree*4 + G], baseFreq[whichChain*8 + whichTree*4 + T]);*/
		}
	else
		{
		printf ("\n   ERROR: Unknown model type in Q matrix\n");
		return (ERROR);
		}

#	if 0
	for (i=0; i<4; i++)
		{
		for (j=0; j<4; j++)
			printf ("%0.5lf ", a[i][j]);
		printf ("\n");
		}
#	endif

	return (NO_ERROR);
	
}





#	if defined (SMART_TI_PROBS)
int SetUpTransitionProbs (int numRateCats)

{
	
	int			i, lnStates, nRates, lnPartitions, lnumRateCats;
	
	/* how many states and rates are there? */
	if ((dataType == DNA || dataType == RNA) && enforceCodonModel == NO)
		{
		if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
			lnPartitions = nPartitions;
		else
			lnPartitions = 1;
		if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
			lnumRateCats = 1;
		else
			lnumRateCats = numRateCats;
		nRates = lnPartitions * lnumRateCats;
		if (useCovarion == NO)
			{
			lnStates = 4;
			}
		else
			{
			lnStates = 2 * nStates;
			}
		}
	else if ((dataType == DNA || dataType == RNA) && enforceCodonModel == YES)
		{
		if (useCovarion == NO)
			{
			if (!strcmp(codonModelType, "covny98"))
				lnStates = 3 * nStates;
			else
				lnStates = nStates;
			if (!strcmp(codonModelType, "ny98") || !strcmp(codonModelType, "ac1ny98") || !strcmp(codonModelType, "ac2ny98"))
				nRates = 3;
			else
				nRates = 1;
			}
		else
			{
			return (ERROR);
			}
		}
	else if (dataType == PROTEIN)
		{
		if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
			lnPartitions = nPartitions;
		else
			lnPartitions = 1;
		if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
			lnumRateCats = 1;
		else
			lnumRateCats = numRateCats;
		nRates = lnPartitions * lnumRateCats;
		if (useCovarion == NO)
			{
			lnStates = 20;
			}
		else
			{
			lnStates = 2 * nStates;
			}
		}
	else if (dataType == RESTRICTION)
		{
		if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
			lnPartitions = nPartitions;
		else
			lnPartitions = 1;
		if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
			lnumRateCats = 1;
		else
			lnumRateCats = numRateCats;
		nRates = lnPartitions * lnumRateCats;
		if (useCovarion == NO)
			{
			lnStates = 2;
			}
		else
			{
			return (ERROR);
			}
		}
	else if (dataType == STANDARD)
		{
		if (!strcmp(ratesModel, "sitespec") || !strcmp(ratesModel, "ssgamma") || !strcmp(ratesModel, "ssadgamma"))
			lnPartitions = nPartitions;
		else
			lnPartitions = 1;
		if (!strcmp(ratesModel, "equal") || !strcmp(ratesModel, "sitespec"))
			lnumRateCats = 1;
		else
			lnumRateCats = numRateCats;
		nRates = lnPartitions * lnumRateCats;
		if (useCovarion == NO)
			{
			lnStates = 2;
			}
		else
			{
			return (ERROR);
			}
		}
	else
		return (ERROR);
			
	/* how big is the information at one node */
	nodeTiSize = nRates * lnStates * lnStates;
	
	/* allocate enough memory for all of the transition probabilities on the tree */
	transitionProbs = (double *)malloc((size_t) (numChains * 2 * numNodes * nodeTiSize * sizeof(double)));
	if (!transitionProbs)
		{
		printf ("ERROR: Problem allocating transitionProbs\n");
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_TI_PROBS] = YES;
		
	updateTiFlag = (int *)malloc((size_t) (numNodes * sizeof(int)));
	if (!updateTiFlag)
		{
		printf ("ERROR: Problem allocating updateTiFlag\n");
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_TI_FLAGS] = YES;
	for (i=0; i<numNodes; i++)
		updateTiFlag[i] = NO;

	return (NO_ERROR);
	
}
#	endif





int SetUpTrees (int numTaxa)

{

	int			i, j, n;
	TreeNode	*p;

	if (treeModel == ROOTED)
		{
		numNodes = 2*numTaxa;
		numIntNodes = numTaxa-1;
		}
	else
		{
		numNodes = 2*numTaxa-2;
		numIntNodes = numTaxa - 2;
		}
	printf ("         Allocating traversal memory\n");
	intNodeDownPassSeq = (TreeNode **)malloc((size_t) (numChains*2*numIntNodes) * sizeof(TreeNode *));
	if (!intNodeDownPassSeq)
		{
		printf ("\n   ERROR: Problem allocating intNodeDownPassSeq\n");
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_INTDOWNPASS] = YES;
	allNodesDownPassSeq = (TreeNode **)malloc((size_t) (numChains*2*numNodes) * sizeof(TreeNode *));
	if (!allNodesDownPassSeq)
		{
		printf ("\n   ERROR: Problem allocating allNodesDownPassSeq\n");
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_ALLDOWNPASS] = YES;
	printf ("         Getting downpass information\n");
	for (n=0; n<numChains; n++)
		{
		i = j = 0;
		GetDownPassSeq (root[n*2+0], 0, n, numTaxa, &i, &j);
		
		for (i=0; i<numNodes; i++)
			{
			p = allNodesDownPassSeq[n*2*numNodes+i];
			p->scaler = 0.0;
			p->scalerNode = NO;
			if (p->length < BRLEN_EPSILON)
				p->length = 2 * BRLEN_EPSILON;
			}
		//printf ("Starting tree %d:\n", n);
		//ShowTree (spTreeRoot[n*2+0], 2);
		}
		
	clUpdateFlag = (int *)malloc((size_t) numNodes * sizeof(int));
	if (!clUpdateFlag)
		{
		printf ("\n   ERROR: Problem allocating clUpdateFlag\n");
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_CLUPDATE_FLAG] = YES;
	for (i=0; i<numNodes; i++)
		clUpdateFlag[i] = NO;
		
	scalerUpdateFlag = (int *)malloc((size_t) numNodes * sizeof(int));
	if (!scalerUpdateFlag)
		{
		printf ("\n   ERROR: Problem allocating scalerUpdateFlag\n");
		FreeMemory ();
		return (ERROR);
		}
	else
		allocatedMemory[ALLOC_SCALER_UPDATE_FLAG] = YES;
	for (i=0; i<numNodes; i++)
		scalerUpdateFlag[i] = NO;

	return (NO_ERROR);

}





#define	EDDIE_NODES
int ShowStartTree (TreeNode *r, int nt, int isThisTreeRooted)

{

	int 			i, j, k, nNodes, x, nLines, nLevels, levelDepth, from, to;
	char			treeLine[SCREENWIDTH2], labelLine[100];
	TreeNode		**downPass, *p;

	/* get down pass sequence */
	if (isThisTreeRooted == YES)
		nNodes = 2 * nt;
	else
		nNodes = 2 * nt - 2;
	downPass = (TreeNode **)malloc((size_t) (2 * nTaxa * sizeof(TreeNode *)));
	if (!downPass)
		{
		printf ("   ERROR: Could not allocate downPass\n");
		return (ERROR);
		}
	i = 0;
	GetTempDownPassSeq (r, &i, downPass);
	
	/* get coordinates */
	x = 0;
	nLines = 0;
	for (i=0; i<nNodes; i++)
		{
		p = downPass[i];
		if (p->left == NULL && p->right == NULL)
			{
			p->x = x;
			x += 2;
			p->y = 0;
			nLines += 2;
			}
		else if (p->left != NULL && p->right != NULL && p->anc != NULL)
			{
			p->x = p->left->x + (p->right->x - p->left->x) / 2;
			if (p->left->y > p->right->y)
				p->y = p->left->y + 1;
			else
				p->y = p->right->y + 1;
			}
		else
			{
			p->x = x;
			x += 2;
			p->y = 0;
			}
		} 
				
	/* print tree out, line-by-line */
	levelDepth = SCREENWIDTH / r->left->y;
	nLevels = r->left->y;
	for (j=0; j<=nLines-2; j++)
		{
		if (j % 2 == 0)
			{
			for (i=0; i<nNodes; i++)
				{
				p = downPass[i];
				if (p->left == NULL && p->x == j)
					{
					strcpy (labelLine, p->label);
					}
				}
			}
			
		for (i=0; i<SCREENWIDTH; i++)
			treeLine[i] = ' ';
		treeLine[SCREENWIDTH-1] = '\0';
		for (i=0; i<nNodes; i++)
			{
			p = downPass[i];
			if (p->anc != NULL)
				{
				if (p->anc->anc != NULL)
					{
					if (p->x == j)
						{
						from = (nLevels - p->anc->y) * levelDepth;
						to   = (nLevels - p->y) * levelDepth;
						if (p->y == 0)
							to = SCREENWIDTH-1;
						if (to >= SCREENWIDTH)
							to = SCREENWIDTH-1;
						for (k=from; k<to; k++)
							treeLine[k] = '-';
						if (p->anc->left == p)
							treeLine[from] = '/';
						else
							treeLine[from] = '\\';
						if (p->left != NULL)
							{
#							if defined (EDDIE_NODES)
							treeLine[to] = '|';
#							else
							treeLine[to] = '+';
#							endif
							}
						if (p->anc->anc == r && p->anc->right == p)
							{
							if (isThisTreeRooted == NO)
								{
								if (p->left != NULL)
#									if defined (EDDIE_NODES)
									treeLine[to] = '|';
#									else
									treeLine[to] = '+';
#									endif
								}
							else
								treeLine[from] = '\\';
							}
						}
					else if (p->left != NULL && p->right != NULL)
						{
						if (j < p->x && j > p->left->x)
							{
							from = (nLevels - p->y) * levelDepth;
							treeLine[from] = '|';
							}
						else if (j > p->x && j < p->right->x)
							{
							from = (nLevels - p->y) * levelDepth;
							treeLine[from] = '|';
							}
						}
					}
				else
					{
					if (p->x == j)
						{
						treeLine[0] = '|'; /* temp */
						}
					else if (j < p->x && j > p->left->x)
						{
						treeLine[0] = '|';
						}
					else if (j > p->x && j < p->right->x)
						{
						treeLine[0] = '|';
						}
					if (isThisTreeRooted == NO)
						{
						if (j > p->x && j <= nLines-2)
							treeLine[0] = '|';
						if (j == p->right->x)
#							if defined (EDDIE_NODES)
							treeLine[0] = '|';
#							else
							treeLine[0] = '+';
#							endif
						}
					else
						{
						if (j == p->x)
#							if defined (EDDIE_NODES)
							treeLine[0] = '|';
#							else
							treeLine[0] = '+';
#							endif
						}
					}
				}
			}
		if (j % 2 == 0)
			printf ("         %s %s\n", treeLine, labelLine);
		else
			printf ("         %s \n", treeLine);
		}

	if (isThisTreeRooted == NO)
		{
		for (i=0; i<SCREENWIDTH; i++)
			treeLine[i] = ' ';
		treeLine[SCREENWIDTH-1] = '\0';
		printf ("         |\n");
		for (k=0; k<SCREENWIDTH; k++)
			treeLine[k] = '-';
		treeLine[SCREENWIDTH-1] = '\0';
		treeLine[0] = '\\';
		strcpy (labelLine, r->label);
		labelLine[19] = '\0';
		printf ("         %s %s\n", treeLine, labelLine);
		}
	
	free (downPass);
	
	return (NO_ERROR);
	   
}





void UpDateAllCls (int whichState, int whichChain)

{

	int			i;
	TreeNode	*p;

	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + whichState*numNodes + i];
		p->upDateCl = YES;
		}

}





#if defined (SMART_TI_PROBS)
void UpDateAllTIs (int whichState, int whichChain)

{

	int			i;
	TreeNode	*p;

	for (i=0; i<numNodes; i++)
		{
		p = allNodesDownPassSeq[whichChain*2*numNodes + whichState*numNodes + i];
		p->upDateTi = YES;
		}

}
#endif





char WhichAA (int x)

{

	if (x == 0)
		return ('A');
	else if (x == 1)
		return ('R');
	else if (x == 2)
		return ('N');
	else if (x == 3)
		return ('D');
	else if (x == 4)
		return ('C');
	else if (x == 5)
		return ('Q');
	else if (x == 6)
		return ('E');
	else if (x == 7)
		return ('G');
	else if (x == 8)
		return ('H');
	else if (x == 9)
		return ('I');
	else if (x == 10)
		return ('L');
	else if (x == 11)
		return ('K');
	else if (x == 12)
		return ('M');
	else if (x == 13)
		return ('F');
	else if (x == 14)
		return ('P');
	else if (x == 15)
		return ('S');
	else if (x == 16)
		return ('T');
	else if (x == 17)
		return ('W');
	else if (x == 18)
		return ('Y');
	else if (x == 19)
		return ('V');
	else 
		return ('?');
		
}





void WriteTreeToFile (TreeNode *p, FILE *fp, int showBrlens)

{

	if (p != NULL)
		{
		if (p->left == NULL && p->right == NULL)
			{
			if (showBrlens == YES)
				fprintf (fp, "%d:%1.6lf", p->index + 1, p->length);
			else
				fprintf (fp, "%d", p->index + 1);
			}
		else
			{
			if (p->anc != NULL)
				fprintf (fp, "(");
			WriteTreeToFile (p->left,  fp, showBrlens);
			if (p->anc != NULL)
				fprintf (fp, ",");
			WriteTreeToFile (p->right, fp, showBrlens);	
			if (p->anc != NULL)
				{
				if (p->anc->anc == NULL)
					{
					if (treeModel == UNROOTED)
						{
						if (showBrlens == YES)
							fprintf (fp, ",%d:%1.6lf);\n", p->anc->index + 1, p->length);
						else
							fprintf (fp, ",%d);\n", p->anc->index + 1);
						}
					else
						fprintf (fp, ");\n");
					}
				else
					{
					if (showBrlens == YES)
						fprintf (fp, "):%1.6lf", p->length);
					else
						fprintf (fp, ")");
					}
				}
			}
		}
	
}





void WriteTreeToScreen (TreeNode *p, int showBrlens)

{

	if (p != NULL)
		{
		if (p->left == NULL && p->right == NULL)
			{
			if (showBrlens == YES)
				printf ("%s:%1.6lf", p->label, p->length);
			else
				printf ("%s", p->label);
			}
		else
			{
			if (p->anc != NULL)
				printf ("(");
			WriteTreeToScreen (p->left,  showBrlens);
			if (p->anc != NULL)
				printf (",");
			WriteTreeToScreen (p->right, showBrlens);	
			if (p->anc != NULL)
				{
				if (p->anc->anc == NULL)
					{
					if (showBrlens == YES)
						printf (",%s:%1.6lf);\n", p->anc->label, p->length);
					else
						printf (",%s);\n", p->anc->label);
					}
				else
					{
					if (showBrlens == YES)
						printf ("):%1.6lf", p->length);
					else
						printf (")");
					}
				}
			}
		}
	
}





int YesNo (void)

{

	char			tempString[20], *s;
	unsigned int	i;
	
	for (;;)
		{
		fgets (tempString,20,stdin);
		s = strtok(tempString," ;\n");
		for (i=0; i<strlen(tempString); i++)
			s[i] = tolower(s[i]);
				
		if (!strcmp(tempString,"yes") || !strcmp(tempString,"y"))
			return YES;
		else if (!strcmp(tempString,"no") || !strcmp(tempString,"n"))
			return NO;

		printf ("      Enter Yes or No: ");
		}

}




Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.