/*
 * consensus.c
 *
 *
 * 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$)
 *
 */


#define EXTERN extern
#include "consensus.h"
#ifdef PARALLEL
#	include "ppuzzle.h"
#endif

int ZZZ=0;
/* fprintf(stderr, "ZZZ: %d (%s:%d)\n", ZZZ++, __FILE__, __LINE__); */


/******************************************************************************/
/* functions for computing the consensus tree                                 */
/******************************************************************************/

/* prepare for consensus tree analysis */
void initconsensus()
{
#	if ! PARALLEL
		biparts = new_cmatrix(Maxspc-3, Maxspc);
#	endif /* PARALLEL */

	if (Maxspc % 32 == 0)
		splitlength = Maxspc/32;
	else splitlength = (Maxspc + 32 - (Maxspc % 32))/32;
	numbiparts = 0; /* no pattern stored so far */
	maxbiparts = 0; /* no memory reserved so far */
	splitfreqs = NULL;
	splitpatterns = NULL;
	splitsizes = NULL;
	splitcomptemp = (uli *) calloc((size_t) splitlength, sizeof(uli) );
	if (splitcomptemp == NULL) maerror("splitcomptemp in initconsensus");
} /* initconsensus */

/******************/


/* de-trueID-ed (HAS) */
/* recursive function to get bipartitions */
/* traversal should be optimazable (HAS) */
void makepart(int           i,          /*  */
              int           curribrnch, /* in: current branch in traversal */
              ONEEDGE      *edge,       /* in: tree topology    */
              int          *edgeofleaf, /* in: ext. edge list   */
              cmatrix       biparts,    /* out: split strings, edge by edge */
              int           Maxspc)	/* in: number of species in tree */
{	
	if ( edge[i].downright == NULL || edge[i].downleft == NULL) { 
		biparts[curribrnch][edge[i].taxon] = '*';
		return;
	} else { /* still on inner branch */
		makepart(edge[i].downleft->numedge, curribrnch, edge, edgeofleaf, biparts, Maxspc);
		makepart(edge[i].downright->numedge, curribrnch, edge, edgeofleaf, biparts, Maxspc);
	}
} /* makepart */

/******************/


/* de-trueID-ed (HAS) */
/* compute bipartitions of current puzzling step tree */
/* traversal should be optimazable (HAS) */
void computebiparts(ONEEDGE      *edge,       /* in: tree topology          */
                    int          *edgeofleaf, /* in: ext. edge list         */
                    int           psteprootleaf, /* virtual root from pstep */
                    cmatrix       biparts,    /* out: splits                */
                    int           outgroup,   /* in: outgroup of tree       */
                    int           Maxspc)     /* in: number of taxa in tree */
{
	int i, j, curribrnch;
	
	curribrnch = -1;
	
	for (i = 0; i < Maxspc - 3; i++)
		for (j = 0; j < Maxspc; j++)
			biparts[i][j] = '.';

	for (i = 0; i < Maxbrnch; i++) {   /* (HAS) */
		if (!(edgeofleaf[psteprootleaf] == i
		      || edge[i].downright == NULL
		      || edge[i].downleft == NULL) ) { /* check only inner branches */
			curribrnch++;
			makepart(i, curribrnch, edge, edgeofleaf, biparts, Maxspc);
			
			/* make sure that the root is always a '*' */
			if (biparts[curribrnch][outgroup] == '.') {
				for (j = 0; j < Maxspc; j++) {
					if (biparts[curribrnch][j] == '.')
						biparts[curribrnch][j] = '*';
					else
						biparts[curribrnch][j] = '.';
				}
			}
		}
	}
} /* computebiparts */

/******************/


/* print out the bipartition n of all different splitpatterns */
void fprintfsplit(FILE *fp,		/* outputfile stream */
                uli   n,		/* split number */
                uli  *splitpatterns,	/* splits */
                int   splitlength,	/* number of ulis per split */
                int   Maxspc,		/* number of taxa */
		int   printsep)		/* print separator ' ' every 10 columns */
{
	int i, j;	/* counter variables */
	int col;	/* current output column */
	uli z;		/* temporary variable for bit shifting */
	
	col = 0;
	for (i = 0; i < splitlength; i++) {
		z = splitpatterns[n*splitlength + i];
		for (j = 0; j < 32 && col < Maxspc; j++) {
			if (printsep && (col % 10 == 0) && (col != 0)) fprintf(fp, " ");
			if (z & 1) fprintf(fp, ".");
			else fprintf(fp, "*");
			z = (z >> 1);
			col++;
		}
	}
} /* printsplit */

/******************/


/* print out the bipartition n of all different splitpatterns */
void fprintfonesplitnexus(FILE    *nfp,			/* outputfile stream */
                          uli      numsplits,		/* number of split */
                          uli      numtrees,		/* number of trees */
                          uli      li,			/* split number */
                          uli     *splitfreqs,		/* bipartition frequencies (splitfreqs = 2 ulis = split freq, split number */
                          uli     *splitpatterns,	/* splits */
                          int      splitlength,		/* number of ulis per split */
                          cvector  pattern,		/* this split pattern */
                          int      Maxspc)		/* number of taxa */
{
	int i, j;	/* counter variables */
	int col;	/* current output column */
	int zeros = 0;
	int ones = 0;
	uli z;		/* temporary variable for bit shifting */
	
	col = 0;
	/* for (i = 0; i < Maxspc; i++) pattern[i] = 2; */
	for (i = 0; i < splitlength; i++) {
		z = splitpatterns[li*splitlength + i];
		for (j = 0; j < 32 && col < Maxspc; j++) {
			if (col % 10 == 0 && col != 0) fprintf(nfp, " ");
			if (z & 1) {
				/* fprintf(nfp, "."); */
				pattern[col] = 1;
				ones++;
			} else {
				/* fprintf(nfp, "*"); */
				pattern[col] = 0;
				zeros++;
			}
			z = (z >> 1);
			col++;
		}
	}
	if (zeros < ones) {
		fprintf(nfp, "\t[%ld, size=%d]\t", Maxspc+li+1, zeros);
		/* fprintf(nfp, "%.4f", (double) splitfreqs[2*li]); */
		fprintf(nfp, "%.4f", (double) splitfreqs[2*li] / numtrees);
		/* fprintf(nfp, "%lu", splitfreqs[2*li]); */
		for (col = 0; col < Maxspc; col++) {
			if (pattern[col]==0) fprintf(nfp, " %d", col+1);
		}
	} else {
		fprintf(nfp, "\t[%ld, size=%d]\t", Maxspc+li+1, ones);
		/* fprintf(nfp, "%.4f", (double) splitfreqs[2*li]); */
		fprintf(nfp, "%.4f", (double) splitfreqs[2*li] / numtrees);
		/* fprintf(nfp, "%lu", splitfreqs[2*li]); */
		for (col = 0; col < Maxspc; col++) {
			if (pattern[col]==1) fprintf(nfp, " %d", col+1);
		}
	}
} /* printsplitnexus */

/******************/


/* print out the bipartition n of all different splitpatterns */
void fprintfsplitblocknexus(FILE    *nfp,		/* outputfile stream */
                            uli      numsplits,		/* number of split */
                            uli      numtrees,		/* number of trees */
                            double   cutoff,		/* number of split */
                            uli     *splitfreqs,	/* bipartition frequencies (splitfreqs = 2 ulis = split freq, split number */
                            uli     *splitpatterns,	/* splits */
                            int      splitlength,	/* number of ulis per split */
                            int      consfifty,		/* number of splits for M_50 */
                            int      conscongruent,	/* number of splits congruent = M_rel */
                            int      consincluded,	/* number of splits included in TP tree */
                            int      Maxspc)		/* number of taxa */
{
	uli      li;			/* list item = split number */
	uli      numoutputsplits;	/* number of splits to be output */
	int      t;
	int      notfound = TRUE;	/* cutoff met? */
	cvector  pattern;		/* split pattern */
	uli      splitfreqcutoff = (uli) floor(0.5 + (cutoff * numtrees));	/* list item = split number */

	/* allocate mamory */
	pattern = new_cvector(Maxspc + 1);

	/* find number of splits above cutoff */
	for (li=0; li<numsplits && notfound; li++) {
		if (splitfreqs[2*li] < splitfreqcutoff) notfound = FALSE;
	}
	numoutputsplits = li;

	/* print split block header */
	fprintf(nfp, "BEGIN Splits;\n");
	fprintf(nfp, "   DIMENSIONS ntax=%d nsplits=%ld;\n", Maxspc, numoutputsplits+Maxspc);
	fprintf(nfp, "   FORMAT no labels weights no confidences;\n");
	fprintf(nfp, "   MATRIX\n");

	/* print trivial splits of split block */
	for (t = 0; t < Maxspc; t++)
		fprintf(nfp, "\t[size=1]\t1.0\t%d,\n", t+1);

	/* print splits of split block */
	for (li = 0; li < numoutputsplits; li++) {
		if (li>0) fprintf(nfp, ",\n");
		if (li == (uli)consfifty) 
			fprintf(nfp, "\t[end of M_50 splits]\n");	/* number of splits for M_50 */
		if (li == (uli)conscongruent) 
			fprintf(nfp, "\t[end of congruent splits]\n");	/* number of splits congruent = M_rel */
		if (li == (uli)consincluded) 
			fprintf(nfp, "\t[end of splits included in puzzle tree]\n");	/* number of splits included in TP tree */
		fprintfonesplitnexus(nfp, numsplits, numtrees, li, splitfreqs, splitpatterns, splitlength, pattern, Maxspc);
	}

	/* print split block end */
	fprintf(nfp, ",\n;\n"); 			/* comma needed for current SplitTree version 4.0b6 (HAS) */
	fprintf(nfp, "END; [Splits]\n");

	free_cvector(pattern);
} /* fprintfsplitblocknexus */

/******************/

/* general remarks:

   - every entry in consbiparts is one node of the consensus tree
   - for each node one has to know which taxa and which other nodes
     are *directly* descending from it
   - for every taxon/node number there is a flag that shows
     whether it descends from the node or not
   - '0' means that neither a taxon nor another node with the
         corresponding number decends from the node
     '1' means that the corresponding taxon descends from the node
     '2' means that the corresponding node descends from the node
     '3' means that the corresponding taxon and node descends from the node
*/

/* make new entries for new different bipartitions and count frequencies */
/* internal use: splitcomptemp */
void makenewsplitentries(cmatrix  bip,             /* in: split string vector        */
                         int      numspl,          /* in: no. of new splits          */
                         uli    **in_splitpatterns,/* io: known compr splits         */
                         int    **in_splitsizes,   /* io: kn. split sizes: '.'       */
                         uli    **in_splitfreqs,   /* io: kn. split frequences       */
                         uli     *in_numbiparts,   /* io: no. of splits so far       */
                         uli     *in_maxbiparts,   /* io: reserved memory            */
                         uli      treenum,         /* in: tree-no for co-occur. list */
                         int      Maxspc,          /* in: no. of species             */
                         int      savesplitoccur)  /* print split occurrences to file */
{
        int  i, j;             /* count variables */
	int  bpc;              /* split count */
	int  identical;        /* split identical flag */
        int  idflag;           /* split size identical flag */
	int  bpsize;           /* split size: count the '.' */
        uli  nextentry;        /* temp vaiable for split amount numbiparts */
	uli  obpc;             /* split count - old splits */
	uli *splitpatternstmp; /* temp pointer, saves derefs. */
	uli  splitid;          /* id of the current split */
	int *splitsizestmp;    /* temp pointer, saves derefs. */
	uli *splitfreqstmp;    /* temp pointer, saves derefs. */
	uli  maxbipartstmp;    /* split memory reserved so far */
	FILE *splitoccurfp;    /* file pointer for split occurrences */

	splitpatternstmp = *in_splitpatterns;
	splitsizestmp    = *in_splitsizes;
	splitfreqstmp    = *in_splitfreqs;
	maxbipartstmp    = *in_maxbiparts;

        /* where the next entry would be in splitpatterns */
        nextentry = *in_numbiparts;
	splitid = 0;

        if(savesplitoccur){
		openfiletoappend(&splitoccurfp, SPLITOCCUR, "split occurrence file", stdinput_fp);
	}

        for (bpc = 0; bpc < numspl; bpc++) { /* for every new bipartition */
                /* convert bipartition into a more compact format */
                bpsize = 0;
                for (i = 0; i < splitlength; i++) {
                        splitcomptemp[i] = 0;
                        for (j = 0; j < 32; j++) {
                                splitcomptemp[i] = splitcomptemp[i] >> 1;
                                if (i*32 + j < Maxspc)
                                        if (bip[bpc][i*32 + j] == '.') {
                                                /* set highest bit */
                                                splitcomptemp[i] = (splitcomptemp[i] | 2147483648UL);
                                                bpsize++; /* count the '.' */
                                        }
                        }
                }
                /* compare to the *old* patterns */
                identical = FALSE;
                for (obpc = 0; (obpc < *in_numbiparts) && (!identical); obpc++) {
                        /* compare first partition size */
                        if (splitsizestmp[obpc] == bpsize) idflag = TRUE;
                        else idflag = FALSE;
                        /* if size is identical compare whole partition */
                        for (i = 0; (i < splitlength) && idflag; i++)
                                if (splitcomptemp[i] != splitpatternstmp[obpc*splitlength + i])
                                        idflag = FALSE;
                        if (idflag) identical = TRUE;
                }
                if (identical) { /* if identical increase frequency */
                        splitfreqstmp[2*(obpc-1)]++;
                        splitid=1+splitfreqstmp[2*(obpc-1)+1]; /* i.e. split-ID 1,... */
                        /* fprintf(splitoccurfp, "XXX1 %ld\n", splitid); ;^) HAS */
			/* XXX why was the following line here? There is no new entry, but only an identical one - now commented out. ;^) HAS */
                        /* splitfreqstmp[2*nextentry+1] = nextentry; */ /* index for sorting, to keep link to the split array */
                } else { /* create new entry */
                        if (nextentry == maxbipartstmp) { /* reserve more memory */
                                maxbipartstmp = maxbipartstmp + 2*Maxspc;
                                splitfreqstmp = (uli *) myrealloc(splitfreqstmp,
                                        2*maxbipartstmp * sizeof(uli) );
                                /* 2x: splitfreqstmp contains also an index (sorting!) */
                                if (splitfreqstmp == NULL) maerror("splitfreqstmp in makenewsplitentries");

                                splitpatternstmp = (uli *) myrealloc(splitpatternstmp,
                                        splitlength*maxbipartstmp * sizeof(uli) );
                                if (splitpatternstmp == NULL) maerror("splitpatternstmp in makenewsplitentries");

                                splitsizestmp = (int *) myrealloc(splitsizestmp,
                                        maxbipartstmp * sizeof(int) );
                                if (splitsizestmp == NULL) maerror("splitsizestmp in makenewsplitentries");
                        }
                        splitfreqstmp[2*nextentry] = 1; /* frequency */
                        splitfreqstmp[2*nextentry+1] = nextentry; /* index for sorting, to keep link to the split array */
                        for (i = 0; i < splitlength; i++)
                                splitpatternstmp[nextentry*splitlength + i] = splitcomptemp[i];
                        splitsizestmp[nextentry] = bpsize;
                        nextentry++;
                        splitid=nextentry; /* i.e. split-ID 1,... = (splitfreqstmp[2*nextentry+1]+1) before nextentry++ */
                        /* fprintf(splitoccurfp, "XXX2 %ld\n", splitid); ;^) HAS */
                }
        	if(savesplitoccur){
                        /* fprintf(splitoccurfp, "%d\t%ld\t%ld\n", bpc+1, treenum, splitid); */
                        fprintf(splitoccurfp, "%ld\t%ld\t%ld\n", splitid, treenum, splitfreqstmp[2*(splitid-1)]);
		}

        }

        if(savesplitoccur){
		fclose(splitoccurfp);
	}

	/* export new values */
        *in_numbiparts = nextentry;
	*in_splitpatterns = splitpatternstmp;
	*in_splitsizes = splitsizestmp;
	*in_splitfreqs = splitfreqstmp;
	*in_maxbiparts = maxbipartstmp;

} /* makenewsplitentries - new */


/***************************************************************************/

/* copy bipartition n of all different splitpatterns to consbiparts[k] */
void copysplit(uli n, uli *splitpatterns, int k, cmatrix consbipartsvec)
{
	int i, j, col;
	uli z;
	
	col = 0;
	for (i = 0; i < splitlength; i++) {
		z = splitpatterns[n*splitlength + i];
		for (j = 0; j < 32 && col < Maxspc; j++) {
			if (z & 1) consbipartsvec[k][col] = '1';
			else       consbipartsvec[k][col] = '0';
			z = (z >> 1);
			col++;
			consbipartsvec[k][Maxspc] = '\0';
		}
	}
} /* copysplit */

/******************/



/* <consbipartsvec> and the quartet topologies from the ML step. Values are  */
/* stored in <qsupparr[splitnum]>                                            */
/* missing parameter: quartetinfo */
void quartsupport(int splitnum, cmatrix consbipartsvec, qsupportarr_t *qsupparr)

{
	int  n;
	int *clusterA;
	int *clusterB;
	int  clustA = 0;
	int  clustB = 0;

	int a1, a2, b1, b2;
	int aa1, aa2, bb1, bb2;
	uli  fullres_pro = 0;
	uli  fullres_con = 0;
	uli  partres_pro = 0;
	uli  partres_con = 0;
	uli  unres = 0;
	uli  missing = 0;
	uli  qsum = 0;

	cvector splitstr;
	unsigned char tmpweight;

	clusterA = calloc((size_t) Maxspc, (sizeof(int)));
	if (clusterA == NULL) maerror("clusterA in quartsupport");
	clusterB = calloc((size_t) Maxspc, (sizeof(int)));
	if (clusterA == NULL) maerror("clusterB in quartsupport");

	splitstr = consbipartsvec[splitnum];

	for(n=0; n<Maxspc; n++) {
		if (splitstr[n] == '0') clusterA[clustA++] = n;
		else                    clusterB[clustB++] = n;
	}

	if ((clustA <= 1) ||  (clustB <= 1)) {
		/* split in outer edge */
		fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR HS1 TO DEVELOPERS\n\n\n");
#		if PARALLEL
			PP_Finalize();
#		endif
   		tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}

	for (aa1 = 0; aa1 < clustA-1; aa1++)
	  for (aa2 = aa1+1; aa2 < clustA; aa2++)
	     for (bb1 = 0; bb1 < clustB-1; bb1++)
		for (bb2 = bb1+1; bb2 < clustB; bb2++) {
		   a1 = clusterA[aa1];
		   a2 = clusterA[aa2];
		   b1 = clusterB[bb1];
		   b2 = clusterB[bb2];

		   if (a1 < b1) {
		      if (b1 < a2) {
		         if (a2 < b2) { /* a1<b1<a2<b2 */
		             tmpweight = readquartet(a1, b1, a2, b2);
			     qsum++;
			     switch (tmpweight) {
				case 1: fullres_con++; break;
				case 2: fullres_pro++; break;
				case 3: partres_pro++; break;
				case 4: fullres_con++; break;
				case 5: partres_con++; break;
				case 6: partres_pro++; break;
				case 7: unres++; break;
				case 0: missing++; break;
			     }
		         } else { /* a1<b1<b2<a2 */
		             tmpweight = readquartet(a1, b1, b2, a2);
			     qsum++;
			     switch (tmpweight) {
				case 1: fullres_con++; break;
				case 2: fullres_con++; break;
				case 3: partres_con++; break;
				case 4: fullres_pro++; break;
				case 5: partres_pro++; break;
				case 6: partres_pro++; break;
				case 7: unres++; break;
				case 0: missing++; break;
			     }
		         }
		      } else { /* a1<a2<b1<b2 */
		          tmpweight = readquartet(a1, a2, b1, b2);
			  qsum++;
			  switch (tmpweight) {
			     case 1: fullres_pro++; break;
			     case 2: fullres_con++; break;
			     case 3: partres_pro++; break;
			     case 4: fullres_con++; break;
			     case 5: partres_pro++; break;
			     case 6: partres_con++; break;
			     case 7: unres++; break;
			     case 0: missing++; break;
		          }
		      }
		   } else {
		      if (a1 < b2) {
		         if (b2 < a2) { /* b1<a1<b2<a2 */
		             tmpweight = readquartet(b1, a1, b2, a2);
			     qsum++;
			     switch (tmpweight) {
				case 1: fullres_con++; break;
				case 2: fullres_pro++; break;
				case 3: partres_pro++; break;
				case 4: fullres_con++; break;
				case 5: partres_con++; break;
				case 6: partres_pro++; break;
				case 7: unres++; break;
				case 0: missing++; break;
			     }
		         } else { /* b1<a1<a2<b2 */
		             tmpweight = readquartet(b1, a1, a2, b2);
			     qsum++;
			     switch (tmpweight) {
				case 1: fullres_con++; break;
				case 2: fullres_con++; break;
				case 3: partres_con++; break;
				case 4: fullres_pro++; break;
				case 5: partres_pro++; break;
				case 6: partres_pro++; break;
				case 7: unres++; break;
				case 0: missing++; break;
			     }
		         }
		      } else { /* b1<b2<a1<a2 */
		          tmpweight = readquartet(b1, b2, a1, a2);
			  qsum++;
			  switch (tmpweight) {
			     case 1: fullres_pro++; break;
			     case 2: fullres_con++; break;
			     case 3: partres_pro++; break;
			     case 4: fullres_con++; break;
			     case 5: partres_pro++; break;
			     case 6: partres_con++; break;
			     case 7: unres++; break;
			     case 0: missing++; break;
		          }
		      }
		   }
	}

	qsupparr[splitnum].fullres_pro = fullres_pro;
	qsupparr[splitnum].fullres_con = fullres_con;
	qsupparr[splitnum].partres_pro = partres_pro;
	qsupparr[splitnum].partres_con = partres_con;
	qsupparr[splitnum].unres= unres;
	qsupparr[splitnum].missing = missing;
	qsupparr[splitnum].qsum = qsum;

	free(clusterA);
	free(clusterB);
} /* quartsupport */

/******************/


/* general remarks: (Wdh.)

   - every entry in consbiparts is one node of the consensus tree
   - for each node one has to know which taxa and which other nodes
     are *directly* descending from it
   - for every taxon/node number there is a flag that shows
     whether it descends from the node or not
   - '0' means that neither a taxon nor another node with the
         corresponding number decends from the node
     '1' means that the corresponding taxon descends from the node
     '2' means that the corresponding node descends from the node
     '3' means that the corresponding taxon and node descends from the node
*/


/* compute majority rule consensus tree */
/* TODO: de-globalize: splitfreqs, numbiparts, consfifty, consincluded, conscongruent, ... */
void makeconsensus(uli maxnumtrees, int qsupp_optn)
{
	int k, n, size, subnode;
	int parent_count, test_count, taxa_count, split_count; /* , k, n, size, subnode; */
	int parent_idx, test_idx;
#if 0
	char chari, charj;
	int i, j;
#endif
	char char_parent, char_test;
	int done;
	int count01, count10, count00, count11, scount;

	/* sort bipartition frequencies (splitfreqs = 2 ulis = (split freq, split number) */
	qsort(splitfreqs, numbiparts, 2*sizeof(uli), ulicmp);

	/*** collect all splits for M_50 ***/
	/* how many bipartitions are included in the consensus tree yet */
	consincluded = 0;
	for (split_count = 0; (uli)split_count < numbiparts && split_count == consincluded; split_count++) {
		if (2*splitfreqs[2*split_count] > maxnumtrees) consincluded = split_count + 1;
	}

	/* collect all info about majority rule consensus tree */
	/* the +1 is due to the edge with the root */
	/* consincluded changed to (Maxspc-3) to collect sub-50%-splits */
	/* a maximum of (Maxspc-3) is possible in a Maxspc-tree (HAS) */
	/* extension for M_rel */
	consconfid  = new_ivector(  (Maxspc-3) + 1);			/* split confidence/occurrence */
	conssizes   = new_ivector(2*(Maxspc-3) + 2);			/* split size+index */
	consbiparts = new_cmatrix(  (Maxspc-3) + 1, Maxspc + 1);	/* necessary split strings for resolved tree */

	/* old routine (HAS) was for M_50 only
	consconfid = new_ivector(consincluded + 1);
	conssizes = new_ivector(2*consincluded + 2);
	consbiparts = new_cmatrix(consincluded + 1, Maxspc);
	*/
	
	/* initialize split strings (consbiparts) and sorting array (conssizes) */
	for (split_count = 0; split_count < consincluded; split_count++) {
		/* copy partition to consbiparts */
		copysplit(splitfreqs[2*split_count+1], splitpatterns, split_count, consbiparts);
		/* frequency in percent (rounded to integer) */
		consconfid[split_count] = (int) floor(100.0*splitfreqs[2*split_count]/maxnumtrees + 0.5);	/* TODO: why not double? (HAS ;-) */
		/* size of partition */
		conssizes[2*split_count] = splitsizes[splitfreqs[2*split_count+1]];	/* split size */
		conssizes[2*split_count+1] = split_count;				/* split index */
	}

	consfifty = consincluded;
	done = FALSE;
	split_count = consincluded;

	/* until maximum splits (Maxspc-3) incorporated or */
	/* first incongruence found */
	while ((split_count < (Maxspc-3)) && !done) { /* for Max-3 splits */

		/* copy partition to consbiparts */
		copysplit(splitfreqs[2*split_count+1], splitpatterns, split_count, consbiparts);
	
		for (scount = 0; (scount<split_count) && (!done); scount++) { /* for all previous splits */
			count01 = 0;
			count10 = 0;
			count00 = 0;
			count11 = 0;
			
			for (n = 0; (n<Maxspc) && (!done); n++) {
				if (consbiparts[split_count][n] != consbiparts[scount][n]) {
					if (consbiparts[split_count][n] == '0') count01++;
					else                          count10++;
				} else {
					if (consbiparts[split_count][n] == '0') count00++;
					else                          count11++;
				} /* end if different, else */

				/* intersection-rule: i.e., if all > 0, then incongruent */
				if ((count01 > 0) && (count10 > 0) && (count00 > 0) && (count11 > 0)) done = TRUE;
			} /* for all taxa */
		} /* end for all previous splits */

		/* set values + strings, if included in M_rel */
		if (!done) {
			/* frequency in percent (rounded to integer) */
			consconfid[split_count] = (int) floor(100.0*splitfreqs[2*split_count]/maxnumtrees+ 0.5);
			/* size of partition */
			conssizes[2*split_count] = splitsizes[splitfreqs[2*split_count+1]];
			conssizes[2*split_count+1] = split_count;
			split_count++;
		} /* end if !done */
	} /* end for Max-3 splits */
	
	/* if last split has same percentage as the first unincorporated, remove */
	if (((uli)(split_count + 1) < numbiparts) && (splitfreqs[2*split_count] == splitfreqs[2*(split_count+1)]))
		done = TRUE;

	/* remove all splits with same percentage as first incongruence */
	if (done) {
		while ((split_count > 0) && (splitfreqs[2*split_count] == splitfreqs[2*(split_count-1)])) 
			split_count--;
	}
	/*** M_rel splits finished ***/
	

	if (conssub50_optn) {
		/*** for M_rel include all congruent ***/
		consincluded = split_count;
		conscongruent = split_count;
	} else {
		/*** for M_50 include do not include all ***/
		conscongruent = split_count;
	}

	/* create a root split: root=0, rest=1 */
	for (taxa_count = 0; taxa_count < Maxspc; taxa_count++) 
		consbiparts[consincluded][taxa_count] = '1';
	consbiparts[consincluded][outgroup] = '0';
	consconfid[consincluded] = 100;			/* root split = trivial split -> 100% */
	conssizes[2*consincluded] = Maxspc - 1;		/* size = number of taxa except root ('0') */
	conssizes[2*consincluded + 1] = consincluded;	/* index correct, because it starts with 0, now last in list */

#ifdef VERBOSE_CONS
{int aaa,iii; 
	fprintf(stderr, "CCC splits (pre-size-sort): \n", aaa);
	for (aaa=0; aaa<consincluded+1; aaa++) {
  	fprintf(stderr, "CCC %3d: ", aaa);
  	for (iii=0; iii<Maxspc; iii++) {
    	fprintf(stderr, "%c", consbiparts[aaa][iii]);
    	if((iii+1) % 10 == 0) fprintf(stderr, " ");
  	}
  	fprintf(stderr, " [%d]", consconfid[aaa]);
  	fprintf(stderr, "\n");
	}}
#endif



	/* sort bipartitions according to cluster size */
	/* i.e. root split first, because one 0, rest 1 */
	/* conssizes-elements contains size (for sorting) and index of split */
	qsort(conssizes,   consincluded + 1, 2*sizeof(int),    intcmp);
	/*    ^sort array, ^# elements       ^size of element, ^cmp-function */

#ifdef VERBOSE_CONS
	{int aaa,iii; 
	fprintf(stderr, "CCC splits (post-size-sort): \n", aaa);
	for (aaa=0; aaa<consincluded+1; aaa++) {
  	fprintf(stderr, "CCC %3d: ", aaa);
  	for (iii=0; iii<Maxspc; iii++) {
    	fprintf(stderr, "%c", consbiparts[aaa][iii]);
    	if((iii+1) % 10 == 0) fprintf(stderr, " ");
  	}
  	fprintf(stderr, " [%d]", consconfid[aaa]);
  	fprintf(stderr, "\n");
	}}
#endif


		/* compute quartet support of all (icluded) splits, if requested */
	qsupportarr = malloc((size_t) (sizeof(qsupportarr_t) * consincluded)); /* TODO: inside the if clause ??? HAS ;-) */
	if (qsupp_optn) {
		for (split_count = 0; split_count < consincluded; split_count++) {
			quartsupport(split_count, consbiparts, qsupportarr);
		} /* for all splits */
	} /* if quartet support */

	/******************************/
	/* reconstruct consensus tree */
	/******************************/
	for (parent_count = 0; parent_count < consincluded; parent_count++) { /* try every node as "rooted" parent (1..n-1)*/
		size = conssizes[2*parent_count]; /* read size of current (parent) node */
		parent_idx = conssizes[2*parent_count+1];
		for (test_count = parent_count + 1; test_count < consincluded + 1; test_count++) { /* try every following node as descendant (i+1..n)*/
		
			/* compare only with nodes with more descendants */
			/* if sizes (# of 1s) equal -> must be sisters */
			if (size == conssizes[2*test_count]) continue;
			
			/* check whether node test_count is a subnode of parent_count */
			subnode = FALSE;
			test_idx   = conssizes[2*test_count+1];
			for (k = 0; k < Maxspc && !subnode; k++) {
				char_parent = consbiparts[ conssizes[2*parent_count+1] ][k];
				/* char_parent = consbiparts[ parent_idx ][k]; */
				if (char_parent != '0') { /* '0' -> k not in current cluster, ie, descendants */
					char_test = consbiparts[ conssizes[2*test_count+1] ][k];
					/* char_test = consbiparts[ test_idx ][k]; */
					if (char_parent == char_test || char_test == '3') subnode = TRUE;
				}
			}
			
			/* if test_count is a subnode of parent_count, change parent_count accordingly */
			if (subnode) {
				/* remove subnode test_count from parent_count */
				for (k = 0; k < Maxspc; k++) {
					char_parent = consbiparts[ conssizes[2*parent_count+1] ][k];
					/* char_parent = consbiparts[ parent_idx ][k]; */
					if (char_parent != '0') { /* ie, taxon k is cluster member = !'0' */
						char_test = consbiparts[ conssizes[2*test_count+1] ][k];
						/* char_test = consbiparts[ test_idx ][k]; */
						if (char_parent == char_test) { /* equal taxon status */
							consbiparts[ conssizes[2*test_count+1] ][k] = '0';
							/* consbiparts[ test_idx ][k] = '0'; */
						} else { /* unequal taxon status */
							if (char_test == '3') { /* if test[k] is '3', ie, taxon k descends + split k is parent */
								if (char_parent == '1') { /* if parent[k] is '1', ie, k descend from the parent */
									consbiparts[ conssizes[2*test_count+1] ][k] = '2';
     /* '2' means that the corresponding node descends from the node */
									/* consbiparts[ test_idx ][k] = '2'; */
								} else {
									if (char_parent == '2') { /* ie, the corresponding node descends from the node */
										consbiparts[ conssizes[2*test_count+1] ][k] = '1';
										/* consbiparts[ test_idx ][k] = '1'; */
									} else {
										/* Consensus tree [1] */
										fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR H TO DEVELOPERS\n\n\n");
#										if PARALLEL
											PP_Finalize();
#										endif
   										tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
									}
								}
							} else { /* if ! test[k] is '3' -> error */
								/* Consensus tree [2] */
								fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR I TO DEVELOPERS\n\n\n");
#								if PARALLEL
									PP_Finalize();
#								endif
   								tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
							} /* if test[k] is '3', else -> error */
						} /* end if equal taxon status, else */
					} /* if taxon k is cluster member */
				} /* for each taxon k */

				/* add link to subnode parent_count in node test_count */
				char_test = consbiparts[ conssizes[2*test_count+1] ][ conssizes[2*parent_count+1] ];
				/* char_test = consbiparts[ test_idx ][ parent_idx ]; */
				if (char_test == '0') {
					consbiparts[ conssizes[2*test_count+1] ][ conssizes[2*parent_count+1] ] = '2';
					/* consbiparts[ test_idx ][ parent_idx ] = '2'; */
				} else {
					if (char_test == '1') {
						consbiparts[ conssizes[2*test_count+1] ][ conssizes[2*parent_count+1] ] = '3';
						/* consbiparts[ test_idx ][ parent_idx ] = '3'; */
				     	} else {
						/* Consensus tree [3] */
						fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR J TO DEVELOPERS\n\n\n");
	#					if PARALLEL
							PP_Finalize();
	#					endif
   						tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
					} /* if test == 1, else */
				} /* if test == 0, else */
			} /* if test == subnode=descendant */
		} /* for all splits larger than (current) parent split */
#ifdef VERBOSE_CONS
		{int aaa,iii; 
		fprintf(stderr, "CCC splits (after split %d): \n", parent_count);
		for (aaa=0; aaa<consincluded+1; aaa++) {
  		fprintf(stderr, "CCC %3d: ", aaa);
  		for (iii=0; iii<Maxspc; iii++) {
    		fprintf(stderr, "%c", consbiparts[aaa][iii]);
    		if((iii+1) % 10 == 0) fprintf(stderr, " ");
  		}
  		fprintf(stderr, " [%d]", consconfid[aaa]);
  		fprintf(stderr, "\n");
		}}
#endif

	} /* for all (possible) parent splits */

#ifdef VERBOSE_CONS
	{int aaa,iii; int splitcount, taxcount;
	fprintf(stderr, "CCC check splits: \n", parent_count);
	for (iii=0; iii<Maxspc; iii++) {
  	taxcount=0;
  	splitcount=0;
  	for (aaa=0; aaa<consincluded+1; aaa++) {
     		switch (consbiparts[aaa][iii]) {
			case '0': break;
			case '1': taxcount++; break;
			case '2': splitcount++; break;
			case '3': taxcount++; splitcount++; break;
			default: fprintf(stderr, "ERROR in split markin!!!\n");
     		}
    		fprintf(stderr, "%c", consbiparts[aaa][iii]);
  	}
  	fprintf(stderr, " column %d:\tt:%d\ts:%d", iii, taxcount, splitcount);
  	if ((taxcount==1) && (splitcount==1)) {
  		fprintf(stderr, "\t- OK");
  	} else {
		if ((taxcount != 1)) {
			if ((iii == outgroup)) 
  				fprintf(stderr, "\t- taxon outgroup");
			else
  				fprintf(stderr, "\t- taxon wrong ");
		}
		if ((splitcount != 1) && (iii <= consincluded)) {
			if ((iii == consincluded)) 
  				fprintf(stderr, "\t- root split ");
			else
  				fprintf(stderr, "\t- split wrong ");
		}
		if ((taxcount == 1) && (iii > consincluded))
  			fprintf(stderr, "\t- OK");
  	}
  	fprintf(stderr, "\n");
	}}
#endif


} /* makeconsensus */

/******************/


/* prototype for recursion */
void writenode(FILE          *treefile,    /* in: output stream */
               int            node,        /* current node */
               int            qsupp_optn,  /* 'print quartet support' flag */
               qsupportarr_t *qsupparr,    /* quartet support values */
               int           *column);     /* current line position */

/* write node (writeconsensustree) */
/* missing: column */
void writenode(FILE          *treefile,    /* in: output stream */
               int            node,        /* current node */
               int            qsupp_optn,  /* 'print quartet support' flag */
               qsupportarr_t *qsupparr,    /* quartet support values */
               int           *column)      /* current line position */
{
	int i, first;
	
	fprintf(treefile, "(");
	(*column)++;
	/* write descending nodes */
	first = TRUE;
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[node][i] == '2' ||
		consbiparts[node][i] == '3') {
			if (first) first = FALSE;
			else {
				fprintf(treefile, ",");
				(*column)++;
			}
			if ((*column) > 60) {
				(*column) = 2;
				fprintf(treefile, "\n");
			}
			/* write node i */
			writenode(treefile, i, qsupp_optn, qsupparr, column);

			if (qsupp_optn) {
				/* reliability value as internal label */
				fprintf(treefile, "%d", consconfid[i]);
				(*column) += 3;
#if 0
				fprintf(treefile, "\"bs=%d|", consconfid[i]);
				(*column) += 7;

				fprintf(treefile, "f+=%.0f|", (100.0*qsupparr[i].fullres_pro/qsupparr[i].qsum));
				(*column) += 7;
				fprintf(treefile, "p+=%.0f|", (100.0*qsupparr[i].partres_pro/qsupparr[i].qsum));
				(*column) += 7;
				fprintf(treefile, "f-=%.0f|", (100.0*qsupparr[i].fullres_con/qsupparr[i].qsum));
				(*column) += 7;
				fprintf(treefile, "p-=%.0f|", (100.0*qsupparr[i].partres_con/qsupparr[i].qsum));
				(*column) += 7;
				fprintf(treefile, "ur=%.0f", (100.0*qsupparr[i].unres/qsupparr[i].qsum));
				(*column) += 6;
				if (qsupparr[i].missing > 0) {
					fprintf(treefile, "|md=%.0f", (100.0*qsupparr[i].missing/qsupparr[i].qsum));
					(*column) += 7;
				}
				fprintf(treefile, "/%ld\"", qsupparr[i].qsum);
				(*column) += 5;
#endif
			} else {
				/* reliability value as internal label */
				fprintf(treefile, "%d", consconfid[i]);
				(*column) += 3;
			}
		}
	}
	/* write descending taxa */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[node][i] == '1' ||
		consbiparts[node][i] == '3') {
			if (first) first = FALSE;
			else {
				fprintf(treefile, ",");
				(*column)++;
			}
			if ((*column) > 60) {
				(*column) = 2;
				fprintf(treefile, "\n");
			}
			(*column) += fputid(treefile, i);
		}
	}
	fprintf(treefile, ")");
	(*column)++;
} /* writenode */

/******************/



/* write consensus tree */
/* missing: consbiparts, consincluded, consconfid,  */
void writeconsensustree(FILE          *treefile,   /* in: output stream */
                        int            qsupp_optn, /* 'print quartsupp' flag */
                        qsupportarr_t *qsupparr)   /* quartet support values */
{
	int i, first;
	int column;
	
#ifdef VERBOSE_CONS
	{int aaa,iii; 
	fprintf(stderr, "CCC consensus splits: \n", aaa);
	for (aaa=0; aaa<consincluded+1; aaa++) {
  	fprintf(stderr, "CCC %3d: ", aaa);
  	for (iii=0; iii<Maxspc; iii++) {
    	fprintf(stderr, "%c", consbiparts[aaa][iii]);
    	if((iii+1) % 10 == 0) fprintf(stderr, " ");
  	}
  	fprintf(stderr, " [%d]", consconfid[aaa]);
  	fprintf(stderr, "\n");
	}}
#endif

	column = 1;
	fprintf(treefile, "(");
	column += fputid(treefile, outgroup) + 2;
	fprintf(treefile, ",");
	/* write descending nodes */
	first = TRUE;
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[consincluded][i] == '2' || consbiparts[consincluded][i] == '3') {
			if (first) first = FALSE;
			else {
				fprintf(treefile, ",");  /* first (outgroup) has ',' already */
				column++;
			}
			if (column > 60) {
				column = 2;
				fprintf(treefile, "\n");
			}
			/* write node i */
			writenode(treefile, i, qsupp_optn, qsupparr, &column);

			if (qsupp_optn) {
				/* reliability value as internal label */
				fprintf(treefile, "%d", consconfid[i]);
				column += 3;
#if 0
				fprintf(treefile, "\"bs=%d|", consconfid[i]);
				column += 7;

				fprintf(treefile, "f+=%.0f|", (100.0*qsupparr[i].fullres_pro/qsupparr[i].qsum));
				column += 7;
				fprintf(treefile, "p+=%.0f|", (100.0*qsupparr[i].partres_pro/qsupparr[i].qsum));
				column += 7;
				fprintf(treefile, "f-=%.0f|", (100.0*qsupparr[i].fullres_con/qsupparr[i].qsum));
				column += 7;
				fprintf(treefile, "p-=%.0f|", (100.0*qsupparr[i].partres_con/qsupparr[i].qsum));
				column += 7;
				fprintf(treefile, "ur=%.0f", (100.0*qsupparr[i].unres/qsupparr[i].qsum));
				column += 6;
				if (qsupparr[i].missing > 0) {
					fprintf(treefile, "|md=%.0f", (100.0*qsupparr[i].missing/qsupparr[i].qsum));
					column += 7;
				}
				fprintf(treefile, "/%ld\"", qsupparr[i].qsum);
				column += 5;
#endif
			} else {
				/* reliability value as internal label */
				fprintf(treefile, "%d", consconfid[i]);
				column += 3;
			}
		}
	}
	/* write descending taxa */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[consincluded][i] == '1' ||
		consbiparts[consincluded][i] == '3') {
			if (first) first = FALSE;
			else {
				fprintf(treefile, ",");
				column++;
			}
			if (column > 60) {
				column = 2;
				fprintf(treefile, "\n");
			}
			column += fputid(treefile, i);
		}
	}
	fprintf(treefile, ");\n");
} /* writeconsensustree */

/******************/


/* prototype for recursion */
void nodecoordinates(int node);

/* establish node coordinates (plotconsensustree) */
void nodecoordinates(int node)
{
	int i, ymin, ymax, xcoordinate;

	/* first establish coordinates of descending nodes */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[node][i] == '2' ||
		    consbiparts[node][i] == '3') 
			nodecoordinates(i);
	}
	
	/* then establish coordinates of descending taxa */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[node][i] == '1' ||
		    consbiparts[node][i] == '3') {
			/* y-coordinate of taxon i */
			ycortax[i] = ytaxcounter;
			ytaxcounter = ytaxcounter - 2;
		}
	}
	
	/* then establish coordinates of this node */
	ymin = 2*Maxspc - 2;
	ymax = 0;
	xcoordinate = 0;
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[node][i] == '2' ||
		    consbiparts[node][i] == '3') {
			if (ycor[i] > ymax) ymax = ycor[i];
			if (ycor[i] < ymin) ymin = ycor[i];
			if (xcor[i] > xcoordinate) xcoordinate = xcor[i];
		}
	}
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[node][i] == '1' ||
		    consbiparts[node][i] == '3') {
			if (ycortax[i] > ymax) ymax = ycortax[i];
			if (ycortax[i] < ymin) ymin = ycortax[i];
		}
	}
	ycormax[node] = ymax;
	ycormin[node] = ymin;
	ycor[node] = (int) floor(0.5*(ymax + ymin) + 0.5);
	if (xcoordinate == 0) xcoordinate = 9;
	xcor[node] = xcoordinate + 4;
} /* nodecoordinates */

/******************/


/* prototype for recursion */
void drawnode(int node, int xold);

/* drawnode  (plotconsensustree) */
void drawnode(int node, int xold)
{
	int i, j;
	char buf[4];
	
	/* first draw vertical line */
	for (i = ycormin[node] + 1; i < ycormax[node]; i++)
		treepict[xcor[node]][i] = ':';
		
	/* then draw descending nodes */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[node][i] == '2' ||
		    consbiparts[node][i] == '3') 
			drawnode(i, xcor[node]);
	}
	
	/* then draw descending taxa */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[node][i] == '1' ||
		    consbiparts[node][i] == '3') {
			treepict[xcor[node]][ycortax[i]] = ':';
			for (j = xcor[node] + 1; j < xsize-10; j++)
				treepict[j][ycortax[i]] = '-';
			for (j = 0; j < 10; j++)
				treepict[xsize-10+j][ycortax[i]] = Identif[i][j];	
		}
	}
	
	/* then draw internal edge with consensus value */
	treepict[xold][ycor[node]] = ':';
	treepict[xcor[node]][ycor[node]] = ':';
	for (i = xold + 1; i < xcor[node]-3; i++)
		treepict[i][ycor[node]] = '-';
	sprintf(buf, "%d", consconfid[node]);
	if (consconfid[node] == 100) {
		treepict[xcor[node]-3][ycor[node]] = buf[0];
		treepict[xcor[node]-2][ycor[node]] = buf[1];
		treepict[xcor[node]-1][ycor[node]] = buf[2];	
	} else {
		treepict[xcor[node]-3][ycor[node]] = '-';
		treepict[xcor[node]-2][ycor[node]] = buf[0];
		treepict[xcor[node]-1][ycor[node]] = buf[1];
	}
} /* drawnode */

/******************/


/* plot consensus tree */
void plotconsensustree(FILE *plotfp)
{
	int i, j, yroot, startree;

	/* star tree or no star tree */
	if (consincluded == 0) {
		startree = TRUE;
		consincluded = 1; /* avoids problems with malloc */
	} else
		startree = FALSE;
	
	/* memory for x-y-coordinates of each bipartition */
	xcor = new_ivector(consincluded);
	ycor = new_ivector(consincluded);
	ycormax = new_ivector(consincluded);
	ycormin = new_ivector(consincluded);
	if (startree) consincluded = 0; /* avoids problems with malloc */

	/* y-coordinates of each taxon */
	ycortax = new_ivector(Maxspc);
	ycortax[outgroup] = 0;
	
	/* establish coordinates */
	ytaxcounter = 2*Maxspc - 2;
	
	/* first establish coordinates of descending nodes */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[consincluded][i] == '2' ||
		    consbiparts[consincluded][i] == '3') 
			nodecoordinates(i);
	}
	
	/* then establish coordinates of descending taxa */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[consincluded][i] == '1' ||
		    consbiparts[consincluded][i] == '3') {
			/* y-coordinate of taxon i */
			ycortax[i] = ytaxcounter;
			ytaxcounter = ytaxcounter - 2;
		}
	}

	/* then establish length of root edge and size of whole tree */
	yroot = 0;
	xsize = 0;
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[consincluded][i] == '2' ||
		    consbiparts[consincluded][i] == '3') {
			if (ycor[i] > yroot) yroot = ycor[i];
			if (xcor[i] > xsize) xsize = xcor[i];
		}
	}
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[consincluded][i] == '1' ||
		    consbiparts[consincluded][i] == '3') {
			if (ycortax[i] > yroot) yroot = ycortax[i];
		}
	}
	if (xsize == 0) xsize = 9;
	/* size in x direction inclusive one blank on the left */
	xsize = xsize + 6; 
	
	/* change all x-labels so that (0,0) is down-left */
	for (i = 0; i < consincluded; i++)
		xcor[i] = xsize-1-xcor[i];
	
	/* draw tree */
	treepict = new_cmatrix(xsize, 2*Maxspc-1);
	for (i = 0; i < xsize; i++)
		for (j = 0; j < 2*Maxspc-1; j++)
			treepict[i][j] = ' ';
	
	/* draw root */
	for (i = 1; i < yroot; i++)
		treepict[1][i] = ':';
	treepict[1][0] = ':';
	for (i = 2; i < xsize - 10; i++)
		treepict[i][0] = '-';
	for (i = 0; i < 10; i++)
		treepict[xsize-10+i][0] = Identif[outgroup][i];
	
	/* then draw descending nodes */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[consincluded][i] == '2' ||
		    consbiparts[consincluded][i] == '3') 
			drawnode(i, 1);
	}
	
	/* then draw descending taxa */
	for (i = 0; i < Maxspc; i++) {
		if (consbiparts[consincluded][i] == '1' ||
		    consbiparts[consincluded][i] == '3') {
			treepict[1][ycortax[i]] = ':';
			for (j = 2; j < xsize-10; j++)
				treepict[j][ycortax[i]] = '-';
			for (j = 0; j < 10; j++)
				treepict[xsize-10+j][ycortax[i]] = Identif[i][j];	
		}
	}
	
	/* plot tree */
	for (i = 2*Maxspc-2; i > -1; i--) {
		for (j = 0; j < xsize; j++)
			fputc(treepict[j][i], plotfp);
		fputc('\n', plotfp);
	}	
	
	free_ivector(xcor);
	free_ivector(ycor);
	free_ivector(ycormax);
	free_ivector(ycormin);
	free_ivector(ycortax);
	free_cmatrix(treepict);
} /* plotconsensustree */




