/*
 * ml.h
 *
 *
 * Part of TREE-PUZZLE 5.2 (February 2005)
 *
 * (c) 2003-2005 by Heiko A. Schmidt, Korbinian Strimmer, and Arndt von Haeseler
 * (c) 1999-2003 by Heiko A. Schmidt, Korbinian Strimmer,
 *                  M. Vingron, and Arndt von Haeseler
 * (c) 1995-1999 by Korbinian Strimmer and Arndt von Haeseler
 *
 * All parts of the source except where indicated are distributed under
 * the GNU public licence.  See http://www.opensource.org for details.
 *
 * ($Id$)
 *
 */


#ifndef _ML_
#define _ML_

/* values for mlmode */
#define ML_QUART 1
#define ML_TREE  2
#define NJ_TREE  3

#if 0
	/* values for rhettype */
	#define MLUNIFORMRATE 0
	#define MLGAMMARATE   1
	#define MLTWORATE     2
	#define MLMIXEDRATE   3
#endif

/* values for rhetmode */
#define UNIFORMRATE 0
#define GAMMARATE   1
#define TWORATE     2
#define MIXEDRATE   3

/* values for clockmode */
#define CLOCK_OFF 0
#define CLOCK_ON  1

/* definitions */

#define MINTS 0.20  /* Ts/Tv parameter */
#define MAXTS 30.0
#define MINYR 0.10  /* Y/R Ts parameter */
#define MAXYR 6.00
#define MINFI 0.00  /* fraction invariable sites */
#define MAXFI 0.99  /* only for input */
#define MINGE 0.01  /* rate heterogeneity parameter */
#define MAXGE 0.99
#define MINCAT 4    /* discrete Gamma categories */
#define MAXCAT 16

#define RMHROOT         5.0     /* upper relative bound for height of root   */    
#define MAXARC          900.0   /* upper limit on branch length (PAM) = 6.0  */
#define MINARC          0.001   /* lower limit on branch length (PAM) = 0.00001 */

#ifdef USE_ADJUSTABLE_EPS
    /* error in branch length (PAM) = 0.000001   */
#   define EPSILON_BRANCH_DEFAULT  0.0001  
#   define EPSILON_BRANCH epsilon_branch
    EXTERN double epsilon_branch;
#else
#   define EPSILON_BRANCH  0.0001  
#endif

#ifdef USE_ADJUSTABLE_EPS
/* error in node and root heights            */
#   define EPSILON_HEIGHTS_DEFAULT 0.0001
#   define EPSILON_HEIGHTS epsilon_heights
    EXTERN double epsilon_heights;
#else
#   define EPSILON_HEIGHTS 0.0001
#endif

#ifdef USE_ADJUSTABLE_EPS
#   if (EXTERN != extern)
	double epsilon_branch = EPSILON_BRANCH_DEFAULT;
	double epsilon_heights = EPSILON_HEIGHTS_DEFAULT;
#   endif
#endif

#define MAXIT           100     /* maximum number of iterates of smoothing   */
#define MINFDIFF        0.00002 /* lower limit on base frequency differences */
#define MINFREQ         0.0001  /* lower limit on base frequencies = 0.01%   */
#define NUMQBRNCH       5       /* number of branches in a quartet           */
#define NUMQIBRNCH      1       /* number of internal branches in a quartet  */
#define NUMQSPC         4       /* number of sequences in a quartet          */

/* 2D minimisation */

#ifdef USE_ADJUSTABLE_EPS
    /* epsilon substitution process estimation */
#   define EPSILON_SUBSTPARAM_DEFAULT 0.01
#   define EPSILON_SUBSTPARAM epsilon_substparam 
    EXTERN double epsilon_substparam;
#else
#   define EPSILON_SUBSTPARAM 0.01
#endif

#ifdef USE_ADJUSTABLE_EPS
    /* epsilon rate heterogeneity estimation  */
#   define EPSILON_RATEPARAM_DEFAULT  0.01
#   define EPSILON_RATEPARAM  epsilon_rateparam
    EXTERN double epsilon_rateparam;
#else
#   define EPSILON_RATEPARAM 0.01
#endif

#ifdef USE_ADJUSTABLE_EPS
#   if (EXTERN != extern)
	double epsilon_substparam = EPSILON_SUBSTPARAM_DEFAULT;
	double epsilon_rateparam = EPSILON_RATEPARAM_DEFAULT;
#   endif
#endif

/* quartet series */
#define MINPERTAXUM 2
#define MAXPERTAXUM 6
#define TSDIFF 0.20
#define YRDIFF 0.10

/* type definitions */

typedef struct node
{
	struct node *isop;	/* pointers within node (nodes) */
	struct node *kinp;	/* pointers between nodes (branches) */
	int descen;
	int number;
	double length;		/* branch length inferred (no clock) */
	double lengthc;		/* branch length inferred (clock) */
	double lengthext;	/* external length from usertree */
	int    lengthset;	/* length set by usertree */
	double varlen;
	double height;
	double varheight;
	ivector paths;		/* path directions for Korbi's p-step */
	cvector eprob;
	dcube partials;		/* partial likelihoods */
	char *label;		/* internal labels */
} Node;

typedef struct tree
{
	Node    *rootp;
	Node   **ebrnchp;	/* list of pointers to external branches     */
	Node   **ibrnchp;       /* list of pointers to internal branches     */
	double   lklhd;	        /* total log-likelihood                      */
	double   lklhdc;        /* total log-likelihood clock                */
	dmatrix  condlkl;	/* lhs for each pattern and non-zero rate    */
	double   rssleast;
} Tree;


/* global variables */

EXTERN Node    *chep;           /* pointer to current height node                 */
EXTERN Node    *rootbr;         /* pointer to root branch                         */
EXTERN Node   **heights;        /* pointer to height nodes in unrooted tree       */
EXTERN int      Numhts;         /* number of height nodes in unrooted tree        */
EXTERN double   hroot;          /* height of root                                 */
EXTERN double   varhroot;       /* variance of height of root                     */
EXTERN double   maxhroot;       /* maximal height of root                         */
EXTERN int      locroot;        /* location of root                               */
EXTERN int      numbestroot;    /* number of best locations for root            */
EXTERN int      clockmode;      /* clocklike vs. nonclocklike computation         */
EXTERN cmatrix  Identif;        /* sequence names                                 */
EXTERN cmatrix  Namestr;        /* sequence names (delimited by '\0')             */
EXTERN cmatrix  Seqchar;        /* ML sequence data                               */
EXTERN cmatrix  Seqpat;         /* ordered site patterns                          */
EXTERN ivector  constpat;       /* indicates constant site patterns               */
EXTERN cvector  seqchi;
EXTERN cvector  seqchj;
EXTERN dcube    partiali;
EXTERN dcube    partialj;
EXTERN dcube    ltprobr;        /* transition probabilites (for all non-zero rates*/
EXTERN dmatrix  Distanmat;      /* matrix with maximum likelihood distances     */
EXTERN dmatrix  Evec;           /* Eigenvectors                                 */
EXTERN dmatrix  Ievc;           /* Inverse eigenvectors                         */
EXTERN double   TSparam;        /* Ts/Tv parameter                              */
EXTERN double   GTR_ACrate;     /* A <-> G mutation rate for GTR                */
EXTERN double   GTR_AGrate;     /* A <-> C mutation rate for GTR                */
EXTERN double   GTR_ATrate;     /* A <-> T mutation rate for GTR                */
EXTERN double   GTR_CGrate;     /* C <-> G mutation rate for GTR                */
EXTERN double   GTR_CTrate;     /* C <-> T mutation rate for GTR                */
EXTERN double   GTR_GTrate;     /* G <-> T mutation rate for GTR                */
EXTERN double   tsmean, yrmean;
EXTERN double   YRparam;        /* Y/R Ts parameter                             */
EXTERN double   geerr;          /* estimated error of rate heterogeneity        */
EXTERN double   Geta;           /* rate heterogeneity parameter                 */
EXTERN double   fracconst;      /* fraction of constant sites                   */
EXTERN double   fracconstpat;   /* fraction of constant patterns                */
EXTERN double   Proportion;     /* for tree drawing                             */
EXTERN double   tserr;          /* estimated error of TSparam                   */
EXTERN double   yrerr;          /* estimated error of YRparam                   */
EXTERN double   fracinv;        /* fraction of invariable sites                 */
EXTERN double   fierr;          /* estimated error of fracinv                   */
EXTERN dvector  Brnlength;
EXTERN dvector  Distanvec;
EXTERN dvector  Eval;           /* Eigenvalues of 1 PAM rate matrix             */
EXTERN dvector  Freqtpm;        /* base frequencies                             */
EXTERN dvector  Rates;          /* rate of each of the categories               */
EXTERN dmatrix  iexp;
EXTERN imatrix  Basecomp;       /* base composition of each taxon               */
EXTERN ivector  usedtaxa;       /* list needed in the input treefile procedure  */
EXTERN int      numtc;          /* auxiliary variable for printing rooted tree  */
EXTERN int      qcalg_optn;     /* use quartet subsampling algorithm            */
EXTERN int      approxp_optn;   /* approximate parameter estimation             */
EXTERN int      chi2fail;       /* flag for chi2 test                           */
EXTERN int      Converg;        /* flag for ML convergence (no clock)           */
EXTERN int      Convergc;       /* flag for ML convergence (clock)              */
EXTERN int      data_optn;      /* type of sequence input data                  */  
EXTERN int      Dayhf_optn;     /* Dayhoff model                                */
EXTERN int      HKY_optn;       /* use HKY model                                */
EXTERN int      Jtt_optn;       /* JTT model                                    */
EXTERN int      print_GTR_optn; /* print (restricted) GTR matrix                */
EXTERN int      GTR_optn;       /* GTR model                                    */
EXTERN int      blosum62_optn;  /* BLOSUM 62 model                              */
EXTERN int      mtrev_optn;     /* mtREV model                                  */
EXTERN int      cprev_optn;     /* cpREV model                                  */
EXTERN int      vtmv_optn;      /* VT model                                     */
EXTERN int      wag_optn;       /* WAG model                                    */
EXTERN int      lg_optn;        /* LG model                                     */
/* EXTERN int      poisson_optn; */  /* Poisson model                                */
/* EXTERN int      equalin_optn; */  /* Equalin model                                */
/* EXTERN int      mtmam_optn;   */  /* mtMAM model                                  */
/* EXTERN int      rtrev_optn;   */  /* rtREV model                                  */

EXTERN int      Maxsite;     /* number of ML characters per taxum            */
EXTERN int      Maxspc;      /* number of sequences                          */
EXTERN int      mlmode;      /* quartet ML or user defined tree ML           */
EXTERN int      nuc_optn;    /* nucleotide (4x4) models                      */
EXTERN int      Numbrnch;    /* number of branches of current tree           */
EXTERN int      numcats;     /* number of rate categories                    */
EXTERN int      Numconst;    /* number of constant sites                     */
EXTERN int      Numconstpat; /* number of constant patterns                  */
EXTERN int      Numibrnch;   /* number of internal branches of current tree  */
EXTERN int      Numitc;      /* number of ML iterations assumning clock      */
EXTERN int      Numit;       /* number of ML iterations if convergence       */
EXTERN int      Numptrn;     /* number of site patterns                      */
EXTERN int      Numspc;      /* number of sequences of current tree          */
EXTERN int      optim_optn;  /* optimize model parameters                    */
EXTERN int      grate_optim; /* optimize Gamma rate heterogeneity parameter  */
EXTERN int      SH_optn;     /* SH nucleotide (16x16) model                  */
EXTERN int      TN_optn;     /* use TN model                                 */
EXTERN int      tpmradix;    /* number of different states                   */
EXTERN int      fracinv_optim;  /* optimize fraction of invariable sites     */
EXTERN int      typ_optn;    /* type of PUZZLE analysis                      */
EXTERN ivector  Weight;      /* weight of each site pattern                  */
EXTERN Tree    *Ctree;       /* pointer to current tree                      */
EXTERN int      qca, qcb, qcc, qcd; /* quartet currently optimized           */
EXTERN ivector  Alias;       /* link site -> corresponding site pattern      */
EXTERN ivector  bestrate;    /* optimal assignment of rates to sequence sites*/
/* EXTERN sitepostprob   posterior sitelhl */

EXTERN int      bestratefound;  /* best rate per site already reconstructed ? */

/* function prototypes of all ml function */

void convfreq(dvector);
void tp_radixsort(cmatrix, ivector, int, int, int *);
void condenceseq(cmatrix, ivector, cmatrix, ivector, int, int, int);
void countconstantsites(cmatrix, ivector, int, int, int *, int*);
void evaluateseqs(void);
void elmhes(dmatrix, ivector, int);
void eltran(dmatrix, dmatrix, ivector, int);
void mcdiv(double, double, double, double, double *, double *);
void hqr2(int, int, int, dmatrix, dmatrix, dvector, dvector);
void onepamratematrix(dmatrix);
void eigensystem(dvector, dmatrix);
void luinverse(dmatrix, dmatrix, int);
void checkevector(dmatrix, dmatrix, int);
void tranprobmat(void);
void tprobmtrx(double, dmatrix);
double comptotloglkl(dmatrix);
void allsitelkl(dmatrix, dvector);
void writesitelklmatrixphy(FILE *outf, int numut, int numsite, dmatrix allslkl, dmatrix allslklc, int clock);
void writesitelklvectorphy(FILE *outf, char *name, int numsite, dvector aslkl);
/* void writesitelklbin(FILE *, dvector); */ /* TODO */
double pairlkl(double);
double mldistance(int, int, double); /*epe*/
/* double mldistance(int, int); */
void initdistan(void);
void computedistan(void);

/* multiply partial likelihoods */
void productpartials(Node *op);

/* compute internal partial likelihoods */
void partialsinternal(Node *op, int clockmode);

/* compute external partial likelihoods */
void partialsexternal(Node *op, int clockmode);

/* compute all partial likelihoods */
void initpartials(Tree *tr, int clockmode);

double intlkl(double);
void optinternalbranch(Node *);
double extlkl(double);
void optexternalbranch(Node *);
void finishlkl(Node *);

/* optimize branch lengths to get maximum likelihood (nonclocklike branchs) */
double optlkl(Tree *tr, int clockmode);

/* compute likelihood of tree for given branch lengths */
double treelkl(Tree *tr, int clockmode);

void luequation(dmatrix, dvector, int);

/* least square estimation of branch lengths
   used for the approximate ML and as starting point
   in the calculation of the exact value of the ML */
void lslength(Tree *tr, dvector distanvec, int numspc, int numibrnch, dvector Brnlength, int clockmode);
#if PARALLEL
	/*epe*/
	void lslength_par(Tree *tr, dvector distanvec, int numspc, int numibrnch, dvector Brnlength, int clockmode);
#endif

/* set branch lengths to the externally given lengths  (-usebranchlen) */
void setextlength(Tree *tr, int numspc, int numibrnch, dvector Brnlength, int clockmode);

void getusertree(FILE *, cvector, int, int);
Node *internalnode(Tree *, char **, int *);
void constructtree(Tree *, cvector, int);
void removebasalbif(cvector);
void makeusertree(FILE *, int);
Tree *new_tree(int, int, cmatrix);
Tree *new_quartet(int, cmatrix);
void free_tree(Tree *, int);
void make_quartet(int, int, int, int);
void changedistan(dmatrix, dvector, int);

/* compute the likelihood for (a,b)-(c,d) quartet (+ inner length) */
double quartet_lklhd(int a, int b, int c, int d, double *iblen);

/* compute the approximate likelihood for (a,b)-(c,d) quartet (+ inner length) */
double quartet_alklhd(int a, int b, int c, int d, double *iblen);

void readusertree(FILE *, int);

/* compute the likelihood of a usertree */
double usertree_lklhd(int usebranch, int parallel);

/* compute the approximate likelihood of a usertree */
double usertree_alklhd(int usebranch, int parallel);

void mlstart(void);
void distupdate(int, int, int, int);
void mlfinish(void);

/* print branch to outfp recursively. current node=*up */
void prbranch(Node *up, int depth, int m, int maxm,
	ivector umbrella, ivector column, FILE *outfp, int clockmode);

void getproportion(double *, dvector, int);

/* print tree to outfp recursively. current node=*up */
void prtopology(FILE *outfp, int clockmode);

/* print unrooted tree file with branch lengths */
void fputphylogeny(FILE *fp, int clockmode, int dofoldlines);

/* print tree statistics: branch length, optimization */
void resulttree(FILE *outfp, int usebranch, int clockmode);

/* compute NJ tree and write to file */
void njtree(FILE *fp, int clockmode);

void njdistantree(Tree *);
void findbestratecombination(void);
void printbestratecombination(FILE *);
void printbestratecombinationtofile(FILE *, int);
int checkedge(int);
void fputsubstree(FILE *fp, Node *ip, int dofoldlines);
void fputrooted(FILE *fp, int e, int dofoldlines);

/* finds heights in subtree: recursively collect branches in a path from root to leaves */
void findheights(Node *ip);

/* initialise clocklike branch lengths (with root on edge e) */
void initclock(int e);

/* approximate likelihood under the constaining assumption of
   clocklike branch lengths (with root on edge e) */
double clock_alklhd(int e);

/* log-likelihood given height ht at node pointed to by chep (clock) */
/* global chep (= current height edge ptr) has to be set in advance (clock) */
double heightlkl(double ht);

/* optimize current height (chep = current height edge ptr) */
void optheight(Node *chep);

/* log-likelihood given height ht at root */
double rheightlkl(double ht);

/* optimize height of root */
void optrheight(void);

/* exact likelihood under the constaining assumption of
   clocklike branch lengths (with root on edge e) */
double clock_lklhd(int e);

int findrootedge(void);
void resultheights(FILE *);

/* mlparam.c */
double homogentest(int);
void YangDiscreteGamma(double, int, double *);
void updaterates(void);
void computestat(double *, int, double *, double *);
double quartetml(int, int, int, int);
double opttsq(double);
double optyrq(double);
void optimseqevolparamsquart(void);
double opttst(double);
double optyrt(double);
void optimseqevolparamstree(void);
double optfi(double);
double optge(double);
void optimrateparams(void);

/* estimate parameters of substitution process and rate heterogeneity - no tree
   n-taxon tree is not needed because of quartet method or NJ tree topology */
void estimateparametersnotree(int clockmode); /* moved from puzzle1.c */
void estimateparameterstree(void);   /* moved from puzzle1.c */
/* mlparam.c end */

int gettpmradix(void);
void rtfdata(dmatrix, double *);
int code2int(cvector, int *, int *);
char *int2code(int);

void jttdata(dmatrix, double *);
void dyhfdata(dmatrix, double *);
void mtrevdata(dmatrix, double *);
void cprev45data(dmatrix, double *);
void blosum62data(dmatrix, double *);
void vtmvdata(dmatrix, double *);
void wagdata(dmatrix, double *);
void lgdata(dmatrix, double *);

#endif
