#  define QUIET
#if 0
#  define QUIET
#endif
/*
 * pstep-tripl.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$)
 *
 */


/******************************************************************************
 * Approach incorporating panalties and bonuses
 * --------------------------------------------
 * Penalty and bonus are collected on each internal edge 
 * using each quartet consisting of the new sequence and the  triplet centered 
 * by the internal node. 
 * values are than distributed through the subtrees like in the MRCA approach
 * (penaties) and in 1-2 tree-traversals (bonus). 
 * REMARK:
 * -------
 *  A combination of the recursive approach instead of MRCA (for penalties)
 *  with the 1-2 tree-traversals for the bonuses should be more efficient.
 *  (Dis)Advantages:
 *  + less memory requirement (no cluster penalty vectors per node, 
 *    penalty matrix instead)
 *  + no O(n) cluster penalty vector reset per node
 *  - longer update times for split instead of cluster update (additional 
 *    subtree. However needed for the triplets!!)
 *  + less memory needed by inner-node-base quartet scanning (no O(n^3) lookup
 *    matrix needed.
 *  - suboptimal non-memory-linear quartet scanning by inner-node-base quartet
 *    scanning (might cause more cache misses. Could maybe inproved by sorting
 *    split lists.)
 *****************************************************************************/

#ifndef QUIET
	uli stmax;
	uli ppmax;
#endif /* ! QUIET */

int pstep_voting_optn               = VOTING_DEFAULT;
int pstep_missing_random_optn       = QUARTET_MISSING_RANDOM_DEFAULT;
int pstep_unresolved_weighting_optn = QUARTET_WEIGHTED_VOTE_DEFAULT;
#define VOTING pstep_voting_optn

double compute_edgeval(
		ONEEDGE *curredge,      /* out: new array of edges          */
		int      voting)
{
	double edgevalue_ = -1;
	curredge->pmax = curredge->ppenalty + curredge->pbonus + curredge->pmissing;
	curredge->stmax = curredge->stpenalty + curredge->stbonus + curredge->stmissing;
	switch (voting) {
		case VOTING_SUBTREE_REL_BONUS_PENALTY:
			edgevalue_ = ((double)curredge->stbonus - (double)curredge->stpenalty) / (double)curredge->stmax; 
			break;
		case VOTING_SUBTREE_REL_BONUS:
			edgevalue_ = ((double)curredge->stbonus) / (double)curredge->stmax; 
			break;
		case VOTING_SUBTREE_REL_PENALTY:
			edgevalue_ = (-(double)curredge->stpenalty) / (double)curredge->stmax; 
			break;

		case VOTING_SUBTREE_ABS_BONUS_PENALTY:
			edgevalue_ = (double)curredge->stbonus - (double)curredge->stpenalty; 
			break;
		case VOTING_SUBTREE_ABS_BONUS:
			edgevalue_ = (double)curredge->stbonus; 
			break;
		case VOTING_SUBTREE_ABS_PENALTY:
			edgevalue_ = -(double)curredge->stpenalty; 
			break;

		case VOTING_PATH_REL_BONUS_PENALTY:
			edgevalue_ = ((double)curredge->pbonus - (double)curredge->ppenalty) / (double)curredge->pmax; 
			break;
		case VOTING_PATH_REL_BONUS:
			edgevalue_ = ((double)curredge->pbonus) / (double)curredge->pmax; 
			break;
		case VOTING_PATH_REL_PENALTY:
			edgevalue_ = (-(double)curredge->ppenalty) / (double)curredge->pmax; 
			break;

		case VOTING_PATH_ABS_BONUS_PENALTY:
			edgevalue_ = (double)curredge->pbonus - (double)curredge->ppenalty; 
			break;
		case VOTING_PATH_ABS_BONUS:
			edgevalue_ = (double)curredge->pbonus; 
			break;
		case VOTING_PATH_ABS_PENALTY:
			edgevalue_ = -(double)curredge->ppenalty; 
			break;
		default:
			/* unknown voting scheme */
			fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR VOT1 TO DEVELOPERS\n\n\n");
#			if PARALLEL
				PP_Finalize();
#			endif
			tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}
	return(edgevalue_);
}
char *voting_string(int voting)
{
	switch (voting) {
		case VOTING_PATH_ABS_PENALTY:
			return("absolute (path-penalty) = QP"); break;
		case VOTING_PATH_ABS_BONUS:
			return("absolute (path-bonus)"); break;
		case VOTING_PATH_ABS_BONUS_PENALTY:
			return("absolute (path-bonus - path-penalty)"); break;

		case VOTING_PATH_REL_PENALTY:
			return("normalized (path-penalty)"); break;
		case VOTING_PATH_REL_BONUS:
			return("normalized (path-bonus)"); break;
		case VOTING_PATH_REL_BONUS_PENALTY:
			return("normalized (path-bonus - path-penalty) = SQP"); break;

		case VOTING_SUBTREE_REL_PENALTY:
			return("normalized (subtree-penalty)"); break;
		case VOTING_SUBTREE_REL_BONUS:
			return("normalized (subtree-bonus)"); break;
		case VOTING_SUBTREE_REL_BONUS_PENALTY:
			return("normalized (subtree-bonus - subtree-penalty)"); break;

		case VOTING_SUBTREE_ABS_PENALTY:
			return("absolute (subtree-penalty)"); break;
		case VOTING_SUBTREE_ABS_BONUS:
			return("absolute (subtree-bonus)"); break;
		case VOTING_SUBTREE_ABS_BONUS_PENALTY:
			return("absolute (subtree-bonus - subtree-penalty)"); break;
		default:
			/* unknown voting scheme */
			fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR VOT1 TO DEVELOPERS\n\n\n");
#			if PARALLEL
				PP_Finalize();
#			endif
			tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}
	return("unknown voting scheme");
}

void fprintf_votings(
		FILE *ofp,
		ONEEDGE *curredge,      /* out: new array of edges          */
		double   edgevalue,
		int      numleaves,
		char    *status,
		char    *statusc,
		char    *filename,
		int      line)
{
	uli stmax;
	uli ppmax;
	stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
	ppmax = ((curredge->upsize * curredge->downsize) * (numleaves - 2))/2;
	fprintf(ofp, "VVV:%04d| %s |%4d %3d %4lu %4.2f", line, status,
		curredge->numedge, curredge->taxon, curredge->edgeinfo, (double)curredge->edgeinfo/ppmax); 
	fprintf(ofp, "| %4lu %4lu %4lu %4lu %4lu ",
		curredge->pbonus, curredge->ppenalty, curredge->pmissing,
		(curredge->pbonus + curredge->ppenalty + curredge->pmissing), ppmax);
	fprintf(ofp, "| %5.0f %6.3f  %5.3f %6.3f ",
		(double)curredge->pbonus - (double)curredge->ppenalty,
		((double)curredge->pbonus - (double)curredge->ppenalty)/ ppmax,
		(double)curredge->pbonus / ppmax,
		-(double)curredge->ppenalty / ppmax);
	fprintf(ofp, "| %5lu  %5lu  %5lu  %5lu ",
		curredge->stbonus, curredge->stpenalty, curredge->stmissing, stmax);
	fprintf(ofp, "| %6.0f  %6.3f  %5.3f  %6.3f ",
		(double)curredge->stbonus - (double)curredge->stpenalty,
		((double)curredge->stbonus - (double)curredge->stpenalty) / stmax,
		(double)curredge->stbonus / stmax, -(double)curredge->stpenalty / stmax);
	fprintf(ofp, "  %s  %5.2f\n", statusc, edgevalue);
}

/***XXX***/
/* initialize tree with the following starting configuration (see pstep.h) */
void inittree_tripl(
		ONEEDGE **edge,      /* out: new array of edges          */
		int     **edgeofleaf,/* out: array of external edge ptrs */
		int      *rootleaf,  /* out: rooting leaf (=permut[0])   */
		int       Maxspc,    /* in:  Number of species (n)       */
		int       Maxbrnch,  /* in:  Number of branches (2n-3)   */
		int      *nextedge,  /* out: next free edge index (=3)   */
		int      *nextleaf,  /* out: next free leaf index (=3)   */
		ivector   permut)    /* in: species permutation (trueID) */
{
	int i, j;
	ONEEDGE *tmpedge;
	int     *tmpedgeofleaf;

	/*** allocate the memory for the whole tree ***/

	/* allocate memory-vector with all the edges of the tree */
	tmpedge = (ONEEDGE *) calloc((size_t) Maxbrnch, sizeof(ONEEDGE) );
	if (tmpedge == NULL) maerror("edge in inittree");
	*edge = tmpedge;

	/* allocate memory for tmpvector with edge numbers of leaves */
	tmpedgeofleaf = (int *) calloc((size_t) Maxspc, sizeof(int) );
	if (tmpedgeofleaf == NULL) maerror("edgeofleaf in inittree");
	for (j = 0; j < Maxspc; j++) tmpedgeofleaf[j]=-1;
	*edgeofleaf = tmpedgeofleaf;

	/* allocate memory for the split map for each edge */
	for (i = 0; i < Maxbrnch; i++) {
		(tmpedge)[i].taxon = -1;

		(tmpedge)[i].split = (int *) calloc((size_t) Maxspc, sizeof(int) );
		if (tmpedge[i].split == NULL) maerror("split array in inittree");
		for (j = 0; j < Maxspc; j++) (tmpedge)[i].split[j]=-1;

		(tmpedge)[i].ppenaltyarr = (uli *) calloc((size_t) Maxspc, sizeof(uli) );
		if (tmpedge[i].ppenaltyarr == NULL) maerror("ppenalty array in inittree");
		(tmpedge)[i].pbonusarr   = (uli *) calloc((size_t) Maxspc, sizeof(uli) );
		if (tmpedge[i].pbonusarr   == NULL) maerror("pbonus array in inittree");
		(tmpedge)[i].pmissingarr = (uli *) calloc((size_t) Maxspc, sizeof(uli) );
		if (tmpedge[i].pmissingarr == NULL) maerror("pmissing array in inittree");

		/* number all edges */
		tmpedge[i].numedge = i;
	}

	/* initialize tree */

	*nextedge = 3;
	*nextleaf = 3;

	/* init split vectors: */
	/*   for edge 0 */
	(tmpedge[0].split)[0]        = permut[0]; /* leaf 0 above this edge */
	 tmpedge[0].upsize           = 1;
	(tmpedge[0].split)[Maxspc-1] = permut[1]; /* leaf 0 below this edge */
	(tmpedge[0].split)[Maxspc-2] = permut[2]; /* leaf 0 below this edge */
	 tmpedge[0].downsize         = 2;

	/*   for edge 1 */
	(tmpedge[1].split)[0]        = permut[0]; /* leaf 0 above this edge */
	(tmpedge[1].split)[1]        = permut[2]; /* leaf 0 above this edge */
	 tmpedge[1].upsize           = 2;
	(tmpedge[1].split)[Maxspc-1] = permut[1]; /* leaf 0 below this edge */
	 tmpedge[1].downsize         = 1;

	/*   for edge 2 */
	(tmpedge[2].split)[0]        = permut[0]; /* leaf 0 above this edge */
	(tmpedge[2].split)[1]        = permut[1]; /* leaf 0 above this edge */
	 tmpedge[2].upsize           = 2;
	(tmpedge[2].split)[Maxspc-1] = permut[2]; /* leaf 0 below this edge */
	 tmpedge[2].downsize         = 1;


	/* interconnection */
	tmpedge[0].up        = NULL;
	tmpedge[0].downleft  = &tmpedge[1];
	tmpedge[0].downright = &tmpedge[2];

	tmpedge[1].up        = &tmpedge[0];
	tmpedge[1].downleft  = NULL;
	tmpedge[1].downright = NULL;

	tmpedge[2].up = &tmpedge[0];
	tmpedge[2].downleft  = NULL;
	tmpedge[2].downright = NULL;

	/* taxon IDs of leaves */
	tmpedge[0].taxon = permut[0];
	tmpedge[1].taxon = permut[1];
	tmpedge[2].taxon = permut[2];

	/* edges of leaves */
	tmpedgeofleaf[permut[0]] = 0;
	tmpedgeofleaf[permut[1]] = 1;
	tmpedgeofleaf[permut[2]] = 2;

	/* uppest edge =: root edge*/
	*rootleaf = permut[0];

} /* inittree_tripl */

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


/***XXX***/
/* free memory (to be called after inittree) */
void freetree_tripl(ONEEDGE *edge,               /* edge array          */
                   int      *edgeofleaf,         /* ext. edge idx array */
                   int       Maxspc)             /* No. of species      */
{
	int i;

	/* free split vectors */
	for (i = 0; i < 2 * Maxspc - 3; i++) {
		free(edge[i].split);
		free(edge[i].ppenaltyarr);
		free(edge[i].pbonusarr);
		free(edge[i].pmissingarr);
	}

	/* free tree topology */
	free(edge);

	/* free external edge lookup vector */
	free(edgeofleaf);

} /* freetree_tripl */


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


/* check edge splits (debugging) */
void check_tripl(
                       ONEEDGE *edge,       /* edge array                   */
                       int     Maxspc,      /* No. of species               */
                       int    *edgeofleaf,  /* ext. edge idx array          */
                       int     nextedge, /* next free edge idx           */
                       int     nextleaf, /* next free leaf idx           */
                       int    *permut)
{
	int n,m;

	fprintf(stderr, "Permutation: ");
	for (m = 0; m<nextleaf; m++)
		fprintf(stderr, "%2d:%-2d ", m, permut[m]);
	fprintf(stderr, "+ %2d:%-2d\n", m, permut[m]);

	for (m = 0; m < (nextedge); m++) {
		if (edge[m].upsize + edge[m].downsize != nextleaf) {
			fprintf(stderr, "EEE[%2d]%c(%2d)    r<%d | %d>   %d != %d>\n", 
				m, (edge[m].taxon >= 0) ? 'e' : 'i', 
				edge[m].taxon, 
				edge[m].upsize, edge[m].downsize, 
				edge[m].upsize+edge[m].downsize, 
				nextleaf);
			fprintf(stderr, "        UP:");
			for (n = 0; n<edge[m].upsize; n++)
				fprintf(stderr, "%d, ", edge[m].split[n]);
			fprintf(stderr, " | DOWN:");
			for (n = Maxspc - edge[m].downsize; n<Maxspc; n++)
				fprintf(stderr, "%d, ", edge[m].split[n]);
			fprintf(stderr, "\n");
		} else {
			fprintf(stderr, "EEE[%2d]%c(%2d)    r<%d | %d>   %d == %d>     OK\n", 
				m, (edge[m].taxon >= 0) ? 'e' : 'i', 
				edge[m].taxon, 
				edge[m].upsize, edge[m].downsize, 
				edge[m].upsize+edge[m].downsize, 
				nextleaf);
		}
	}
} /* check_tripl */

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


/***XXX***/
/* update splits after insertion */
void updatesplit_tripl(ONEEDGE *curredge,    /* current edge                 */
                       int      wherefrom,   /* direction to last curr. edge */
                       int      newleaf,     /* leaf to add to splits        */
                       ONEEDGE *edge,       /* edge array                   */
                       int      Maxspc,      /* No. of species               */
                       int      Maxbrnch,    /* No. of branches              */
                       int     *edgeofleaf,  /* ext. edge idx array          */
                       int      in_nextedge, /* next free edge idx           */
                       int      in_nextleaf) /* next free leaf idx           */
{
	switch (wherefrom) {
		case UP:
			curredge->split[(curredge->upsize)++] = newleaf; /* leaf is up */
			if (curredge->downright != NULL) { /* not leaf */
				updatesplit_tripl(curredge->downright, UP, newleaf,
                       			edge, Maxspc, Maxbrnch, edgeofleaf, in_nextedge, in_nextleaf);
				updatesplit_tripl(curredge->downleft, UP, newleaf,
                       			edge, Maxspc, Maxbrnch, edgeofleaf, in_nextedge, in_nextleaf);
			} else { /* nothing to do */
				return;
			}
			break;
		case DOWNLEFT:
			curredge->split[Maxspc - ++(curredge->downsize)] = newleaf; /* leaf is down */
			if (curredge->downright != NULL) { /* not leaf */
				updatesplit_tripl(curredge->downright, UP, newleaf,
                       			edge, Maxspc, Maxbrnch, edgeofleaf, in_nextedge, in_nextleaf);
			}

			if (curredge->up != NULL) { /* not root */
				if ((curredge->up)->downright == curredge) {
					updatesplit_tripl(curredge->up, DOWNRIGHT, newleaf,
                       				edge, Maxspc, Maxbrnch, edgeofleaf, in_nextedge, in_nextleaf);
				} else {
					updatesplit_tripl(curredge->up, DOWNLEFT, newleaf,
                       				edge, Maxspc, Maxbrnch, edgeofleaf, in_nextedge, in_nextleaf);
				}
			}
			break;
		case DOWNRIGHT:
			curredge->split[Maxspc - ++(curredge->downsize)] = newleaf; /* leaf is down */
			if (curredge->downright != NULL) { /* not leaf */
				updatesplit_tripl(curredge->downleft, UP, newleaf,
                       			edge, Maxspc, Maxbrnch, edgeofleaf, in_nextedge, in_nextleaf);
			}

			if ((curredge->up) != NULL) { /* not root */
				if ((curredge->up)->downright == curredge) {
					updatesplit_tripl(curredge->up, DOWNRIGHT, newleaf,
                       				edge, Maxspc, Maxbrnch, edgeofleaf, in_nextedge, in_nextleaf);
				} else {
					updatesplit_tripl(curredge->up, DOWNLEFT, newleaf,
                       				edge, Maxspc, Maxbrnch, edgeofleaf, in_nextedge, in_nextleaf);
				}
			}
			break;
	}
} /* updatesplit_tripl */

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


/***XXX***/
/* add next leaf on the specified edge */
void updatetreesplits_tripl(int      dockedge,    /* dockedge                */
                            int      newleaf,     /* leaf to add to splits   */
                            ONEEDGE *edge,        /* edge array              */
                            int      Maxspc,      /* No. of species          */
                            int     *edgeofleaf,  /* ext. edge idx array     */
                            int      in_nextedge, /* next free edge idx      */
                            int      in_nextleaf, /* next free leaf idx      */
                            ivector  permut)
{
	int      n;		/* counter */
        int      wherefrom;	/* direction to last edge  */
	ONEEDGE *curredge;	/* edge array              */

	/* copy clusters from dockedge to in_nextedge */
	/*   up-cluster: upsize-1 .. 0 */
	for (n=(edge[dockedge].upsize) - 1; n >= 0; n--) {
		(edge[in_nextedge]).split[n] = (edge[dockedge]).split[n];
	}
	(edge[in_nextedge]).upsize = (edge[dockedge]).upsize;

	/*   down-cluster: downsize .. Maxspc-1 */
	for (n=Maxspc - (edge[dockedge]).downsize; n < Maxspc; n++) {
		(edge[in_nextedge]).split[n] = (edge[dockedge]).split[n];
	}
	(edge[in_nextedge]).downsize = (edge[dockedge]).downsize;

	/* add the new taxon to in_nextedge */
	(edge[in_nextedge]).split[Maxspc - ++((edge[in_nextedge]).downsize)] 
		= permut[in_nextleaf];


	/* setup clusters for new external edge (in_nextedge+1) */
	/*   up-cluster: all taxa in tree */
	for (n=0; n < in_nextleaf; n++) {
		(edge[in_nextedge+1]).split[n] = permut[n];
	}
	(edge[in_nextedge+1]).upsize = in_nextleaf;

	/*   down-cluster: the new taxon itself */
	(edge[in_nextedge+1]).split[Maxspc-1] = permut[in_nextleaf];
	(edge[in_nextedge+1]).downsize = 1;

	curredge = &(edge[in_nextedge]);
	if (curredge->up != NULL) { /* not root */
		if (((curredge->up)->downright) == curredge) {
			wherefrom = DOWNRIGHT;
		} else {
			wherefrom = DOWNLEFT;
		}

		/* climbing up from insertion point */
		updatesplit_tripl(curredge->up, wherefrom, newleaf,
				edge, Maxspc, Maxbrnch, edgeofleaf, 
				in_nextedge, in_nextleaf);
	}

	/* climbing down to dockedge from insertion point */
	updatesplit_tripl(&(edge[dockedge]), UP, newleaf,
				edge, Maxspc, Maxbrnch, edgeofleaf, 
				in_nextedge, in_nextleaf);


} /* updatetreesplits_tripl */

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


/***XXX***/
/* add next leaf on the specified edge */
void addnextleaf_tripl(int      dockedge,        /* insert here         */
                       ONEEDGE *edge,            /* edge array          */
                       int     *edgeofleaf,      /* ext. edge idx array */
                       int      rootleaf,	 /* uppest leaf */
                       int      Maxspc,          /* No. of species      */
                       int      Maxbrnch,        /* No. of branches     */
                       int     *in_nextedge,        /* next free edge idx  */
                       int     *in_nextleaf,        /* next free leaf idx  */
                       ivector  permut)
{
	int nextedge;
	int nextleaf;

	nextedge=*in_nextedge;
	nextleaf=*in_nextleaf;

	if (dockedge >= nextedge) {
		/* Trying to add leaf nextleaf to nonexisting edge dockedge */
		fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR F TO DEVELOPERS\n\n\n");
#		if PARALLEL
			PP_Finalize();
#		endif
		tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}

	if (nextleaf >= Maxspc) {
		/* Trying to add leaf nextleaf to a tree with Maxspc leaves */
		fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR G TO DEVELOPERS\n\n\n");
#		if PARALLEL
			PP_Finalize();
#		endif
		tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}

	/* necessary change in edgeofleaf if dockedge == root edge */
	if (edgeofleaf[rootleaf] == dockedge) {
		edgeofleaf[rootleaf] = nextedge;
		edge[nextedge].taxon = edge[dockedge].taxon;
		edge[dockedge].taxon = -1;
	}

	/* adding nextedge to the tree */
	edge[nextedge].up = edge[dockedge].up;
	edge[nextedge].downleft = &edge[dockedge];
	edge[nextedge].downright = &edge[nextedge+1];
	edge[dockedge].up = &edge[nextedge];

	/* if not root edge: connect ancestor to internal edge (nextedge) */
	if (edge[nextedge].up != NULL) {
		if ( ((edge[nextedge].up)->downleft) == &edge[dockedge] )
			(edge[nextedge].up)->downleft  = &edge[nextedge];
		else
			(edge[nextedge].up)->downright = &edge[nextedge];
	}

	/* adding new external edge (nextedge+1) to the tree */
	edge[nextedge+1].up = &edge[nextedge];
	edge[nextedge+1].downleft = NULL;
	edge[nextedge+1].downright = NULL;
	edge[nextedge+1].taxon = permut[nextleaf];
	edgeofleaf[permut[nextleaf]] = nextedge+1;

	updatetreesplits_tripl(dockedge, permut[nextleaf], edge, Maxspc,
				edgeofleaf, nextedge, nextleaf, permut);

	(*in_nextedge) += 2;
	(*in_nextleaf) ++;

} /* addnextleaf_tripl */

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

/***XXX***/
/* pre-compute edge penalties/bonus using triplets at each node before propagation */
void computepenaltiespernode_tripl(
		ONEEDGE  *tmpedge,        /* edge array            */
		int       nextedge,       /* idx to next free edge */
		int       Maxspc,         /* number of taxa        */
		ulimatrix neighbormatr,   /* neighborhood matrix   */
		int       next_taxon)     /* taxon to be inserted  */
{
	int  i;                /* counter */
	int  idxA, idxB, idxC;
	int chooseX, chooseY, neighb; /* end leaves of penalty path and 3rd leaf */
	int  maxUP;            /* index counter for right/left split cluster */
	int  maxDR;            /* index counter for right/left split cluster */
	int  maxDL;            /* index counter for right/left split cluster */
	unsigned char qinfo;   /* quartet topology information */
	int           qstatus; /* indicator whether quartet in missing/resolved/partly/unresolved */
	int *dr_split,     *dl_split,     *up_split;
	uli  dr_stbonus,      dl_stbonus,      up_stbonus;
	uli  dr_stpenalty,    dl_stpenalty,    up_stpenalty;
	uli  dr_stmissing,    dl_stmissing,    up_stmissing;
	uli *dr_pbonus,      *dl_pbonus,      *up_pbonus;
	uli *dr_ppenalty,    *dl_ppenalty,    *up_ppenalty;
	uli *dr_pmissing,    *dl_pmissing,    *up_pmissing;
	int up, dl, dr;
	

	/* TODO: reset should not be necessary (HAS ;-) */
	for (i = 0; i < nextedge; i++) {
		(tmpedge[i]).edgeinfo       = 0;	/* reset penalty/bonus */
		(tmpedge[i]).up_stpenalty   = 0;
		(tmpedge[i]).up_stbonus     = 0;
		(tmpedge[i]).up_stmissing   = 0;
		(tmpedge[i]).down_stpenalty = 0;
		(tmpedge[i]).down_stbonus   = 0;
		(tmpedge[i]).down_stmissing = 0;
		(tmpedge[i]).ppenalty       = 0;
		(tmpedge[i]).pbonus         = 0;
		(tmpedge[i]).pmissing       = 0;
	}

#ifndef QUIET
	fprintf(stderr, "MMM:nextedge = %d\n", nextedge);
#endif /* ! QUIET */
	/* TODO: how can root (up->NULL) can have taxon=-1 (HAS ;-) */
	for (i = 0; i < nextedge; i++) {
		if (((tmpedge)[i].taxon == -1) || (tmpedge[i].up == NULL)) { /* inner node = inner edge or root edge */
									    /* because only internal node (deg=3) can span a triplet */
			/* set shortcuts to split-array, its size, penalty-array -> faster memory access */
			/* and reset subtree-penalty/bonus */

			/* up-ward subtree */
			up_split     = (tmpedge[i]).split;
			maxUP        = (tmpedge[i]).upsize;
			up_pbonus    = (tmpedge[i]).pbonusarr;
			up_ppenalty  = (tmpedge[i]).ppenaltyarr;
			up_pmissing  = (tmpedge[i]).pmissingarr;
			up_stbonus   = 0;
			up_stpenalty = 0;
			up_stmissing = 0;
			/* down-right-ward subtree */
			dr_split     = (tmpedge[i]).downright->split;
			maxDR        = (tmpedge[i]).downright->downsize;
			dr_pbonus    = (tmpedge[i]).downright->pbonusarr;
			dr_ppenalty  = (tmpedge[i]).downright->ppenaltyarr;
			dr_pmissing  = (tmpedge[i]).downright->pmissingarr;
			dr_stbonus   = 0;
			dr_stpenalty = 0;
			dr_stmissing = 0;
			/* down-left-ward subtree */
			dl_split     = (tmpedge[i]).downleft->split;
			maxDL        = (tmpedge[i]).downleft->downsize;
			dl_pbonus    = (tmpedge[i]).downleft->pbonusarr;
			dl_ppenalty  = (tmpedge[i]).downleft->ppenaltyarr;
			dl_pmissing  = (tmpedge[i]).downleft->pmissingarr;
			dl_stbonus   = 0;
			dl_stpenalty = 0;
			dl_stmissing = 0;

#ifndef QUIET
			if ((tmpedge)[i].taxon == -1)
			fprintf(stderr, "MMM:internal node (edge %d/%d, taxon %d)  %d x %d x %d = %d quartets\n", i, nextedge, (tmpedge)[i].taxon, maxUP, maxDL, maxDR, maxUP*maxDL*maxDR);
			if (tmpedge[i].up == NULL)
			fprintf(stderr, "MMM:root     node (edge %d/%d, taxon %d)  %d x %d x %d = %d quartets\n", i, nextedge, (tmpedge)[i].taxon, maxUP, maxDL, maxDR, maxUP*maxDL*maxDR);
#endif /* ! QUIET */

			for (idxA = 0; idxA < maxUP; idxA++) {
				up = up_split[idxA];
				for (idxB = Maxspc - maxDL; idxB < Maxspc; idxB++) {
					dl = dl_split[idxB];
					for (idxC = Maxspc - maxDR; idxC < Maxspc; idxC++) {
						dr = dr_split[idxC];

						/* check which two leaves out of
						   up,dl,dr are closer related to each
						   other than to leaf ext_taxon according to a
						   least squares fit of the continous 
						   Bayesian weights to the seven
						   trivial "attractive regions". We 
						   add a penalty of 1 to all edges 
						   on the penalty path between these 
						   two leaves chooseX and chooseY */

						qinfo = checkquartet(up, dl, dr, next_taxon, &chooseX, &chooseY, &neighb, &qstatus, rootquartsonly_optn);
#ifndef QUIET
						fprintf(stderr, "QQQ:(edge %d taxon %2d) qinfo(%d,%d,%d,%d) = %d  (%d,%d|%d,x%d)\n", (tmpedge[i]).numedge, (tmpedge[i]).taxon, up, dl, dr, next_taxon, qinfo, chooseX, chooseY, neighb, next_taxon);
						/* qinfo=1; */ /* XXX: DON'T ignore unresolved (HAS ;-) */
#endif /* ! QUIET */
#if QUARTET_MISSING_RANDOM
 						qinfo=1; /* XXX: DON'T ignore unresolved (HAS ;-) */
#endif
						/* collect penalty-neighbors for the recursive path-penalty approach */
						(neighbormatr[chooseX][chooseY])++;

#if QUARTET_WEIGHTED_VOTE
						/* weighting partly resolved quartets 1, but resolved ones 2 */
						/* distribute penaties/bonus accordingly */
						if ((qstatus == QUARTET_UNRES) || (qstatus == QUARTET_MISSING)) { /* if qinfo==unresolved or missing */
							up_stmissing+=2;
							dl_stmissing+=2;
							dr_stmissing+=2;
							up_pmissing[up]+=2;
							dl_pmissing[dl]+=2;
							dr_pmissing[dr]+=2;
						} else { /* if ! qinfo==unresolved or missing */
							if (qstatus == QUARTET_PARTLY) {
								if (chooseX == up) { /* dl+dr neighbors */
									/* up_stbonus++; */
									dl_stbonus++;
									dr_stbonus++;
									up_stpenalty+=2;
									dl_stpenalty++;
									dr_stpenalty++;
									/* up_pbonus[up]++; */
									dl_pbonus[dl]++;
									dr_pbonus[dr]++;
									up_ppenalty[up]+=2;
									dl_ppenalty[dl]++;
									dr_ppenalty[dr]++;
								} else {
									if (chooseX == dl) { /* up+dr neighbors */
										up_stbonus++;
										/* dl_stbonus++; */
										dr_stbonus++;
										up_stpenalty++;
										dl_stpenalty+=2;
										dr_stpenalty++;
										up_pbonus[up]++;
										/* dl_pbonus[dl]++; */
										dr_pbonus[dr]++;
										up_ppenalty[up]++;
										dl_ppenalty[dl]+=2;
										dr_ppenalty[dr]++;
									} else { /* up+dl neighbors */
										up_stbonus++;
										dl_stbonus++;
										/* dr_stbonus++; */
										up_stpenalty++;
										dl_stpenalty++;
										dr_stpenalty+=2;
										up_pbonus[up]++;
										dl_pbonus[dl]++;
										/* dr_pbonus[dr]++; */
										up_ppenalty[up]++;
										dl_ppenalty[dl]++;
										dr_ppenalty[dr]+=2;
									}
								}
							} else { /* qstatus == QUARTET_FULLY */
								if (neighb == up) {
									up_stbonus+=2;
									dl_stpenalty+=2;
									dr_stpenalty+=2;
									up_pbonus[up]+=2;
									dl_ppenalty[dl]+=2;
									dr_ppenalty[dr]+=2;
								} else {
									if (neighb==dl) {
										dl_stbonus+=2;
										up_stpenalty+=2;
										dr_stpenalty+=2;
										dl_pbonus[dl]+=2;
										up_ppenalty[up]+=2;
										dr_ppenalty[dr]+=2;
									} else {
										dr_stbonus+=2;
										up_stpenalty+=2;
										dl_stpenalty+=2;
										dr_pbonus[dr]+=2;
										up_ppenalty[up]+=2;
										dl_ppenalty[dl]+=2;
									}
								}
							}
						} /* if ! qinfo==unresolved */

#else /* ! QUARTET_WEIGHTED_VOTE */

						/* distribute penaties/bonus accordingly */
						if ((qinfo>=7) || (qinfo==0)) { /* if qinfo==unresolved or missing */
							up_stmissing++;
							dl_stmissing++;
							dr_stmissing++;
							up_pmissing[up]++;
							dl_pmissing[dl]++;
							dr_pmissing[dr]++;
						} else { /* if ! qinfo==unresolved or missing */
							if (neighb == up) {
								up_stbonus++;
								dl_stpenalty++;
								dr_stpenalty++;
								up_pbonus[up]++;
								dl_ppenalty[dl]++;
								dr_ppenalty[dr]++;
							} else {
								if (neighb==dl) {
									dl_stbonus++;
									up_stpenalty++;
									dr_stpenalty++;
									dl_pbonus[dl]++;
									up_ppenalty[up]++;
									dr_ppenalty[dr]++;
								} else {
									dr_stbonus++;
									up_stpenalty++;
									dl_stpenalty++;
									dr_pbonus[dr]++;
									up_ppenalty[up]++;
									dl_ppenalty[dl]++;
								}
							}
						} /* if ! qinfo==unresolved */
#endif

					} /* end for downright split taxa */
				} /* end for downleft split taxa */
			} /* end for up split taxa */

			/* save bonus to edges for subtree propagation */
			/* subtree bonus: */
			(tmpedge[i]).up_stbonus                = up_stbonus;
			(tmpedge[i]).downleft->down_stbonus    = dl_stbonus;
			(tmpedge[i]).downright->down_stbonus   = dr_stbonus;

			/* subtree penalties: */
			(tmpedge[i]).up_stpenalty              = up_stpenalty;
			(tmpedge[i]).downleft->down_stpenalty  = dl_stpenalty;
			(tmpedge[i]).downright->down_stpenalty = dr_stpenalty;

			/* subtree missing quartets: */
			(tmpedge[i]).up_stmissing              = up_stmissing;
			(tmpedge[i]).downleft->down_stmissing  = dl_stmissing;
			(tmpedge[i]).downright->down_stmissing = dr_stmissing;
		} else { /* end if internal node */
#ifndef QUIET
			fprintf(stderr, "MMM:external node (edge %d/%d, taxon %d)\n", i, nextedge, (tmpedge)[i].taxon);
#endif /* ! QUIET */
			if (((tmpedge)[i].taxon < 0) || (tmpedge[i].taxon >= Maxspc)) { /* inner node = inner edge or root edge */
				fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR HSTBP3 TO DEVELOPERS\n");
			}
		} /* end if internal node */

	} /* for all edges */

} /* computepenaltiespernode_tripl */

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



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


/*
 * recur.c (obsolete)
 */

#define DESC_UP 0
#define DESC_DL 1
#define DESC_DR 2

#define RIGHT_MOST_PATH 0
#define SUBTREE_LEFT    1
#define RIGHT_MOST_LEAF 2

/* compute edge penalties using splits, if #minedges>1 choose one randomly */
/* re-propagate missing bonus/penalties from right parts into left subtrees */
void computepenalties_resubtree_tripl(
                            ONEEDGE  *curredge,/* edge array          */
                            int       numleaves,      /* number of leaves for voting     */
                            int       Maxspc,         /* number of taxa      */
#if 0
                            ulimatrix neighbormatr,   /* neighborhood matrix */
                            ulivector leafpenalty,    /* leaf edge penalties */
#endif
                            int      *minedges,   /* minimum edge vector     */
                            int      *howmany,    /* number minimum edge     */
                            double   *maxbonus,   /* minimum penalty         */
                            int       direction)   /* comming from direction  */
	
{
#if 0
	int l, r;
	int lmax, rmax;
	int taxon;
	uli temp;
#endif
	ONEEDGE *left;     /* temp edge ptr */
	ONEEDGE *right;    /* temp edge ptr */
	ONEEDGE *up;       /* temp edge ptr */
	double   edgevalue;
	int *split, max, i, idx;
	
#ifndef QUIET
	fprintf(stderr, "MMM:computepenalties_resubtree_tripl: descend to edge: %d %s\n", curredge->numedge, (direction==DESC_DL) ? "DL" : "DR");
#endif /* ! QUIET */

	if (curredge->downleft == NULL) {  /* leaf edge */

        	/******************************************/
		/*** collect bonus/penalty of leaf edge ***/
		/*** (only down-values possible)        ***/
        	/******************************************/

		curredge->stpenalty    += curredge->down_stpenalty;
		curredge->stbonus      += curredge->down_stbonus  ;
		curredge->stmissing    += curredge->down_stmissing  ;
		curredge->down_stpenalty = 0;
		curredge->up_stpenalty   = 0;
		curredge->down_stbonus   = 0;
		curredge->up_stbonus     = 0;
		curredge->down_stmissing = 0;
		curredge->up_stmissing   = 0;

		curredge->ppenalty        += curredge->ppenaltyarr[curredge->taxon];
		curredge->pbonus          += curredge->pbonusarr[curredge->taxon];
		curredge->pmissing        += curredge->pmissingarr[curredge->taxon];
#ifndef QUIET
{int idx = curredge->taxon, i=-2, max=-2;
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - leaf-coll-reprop split[%d/%d] = %d !!!\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[curredge->taxon]);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - leaf-coll-reprop split[%d/%d] = %d OK\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[curredge->taxon]);
}
#endif
		curredge->ppenaltyarr[curredge->taxon] = 0;
		curredge->pbonusarr[curredge->taxon]   = 0;
		curredge->pmissingarr[curredge->taxon] = 0;

	} else {   /* -> internal edge */
		up    = curredge->up;
		left  = curredge->downleft;
		right = curredge->downright;

        	/********************************************/
		/*** propagate to/from lower left subtree ***/
        	/********************************************/

		left->down_stpenalty += curredge->down_stpenalty;
		left->down_stbonus   += curredge->down_stbonus  ;
		left->down_stmissing += curredge->down_stmissing;

		split = left->split;
		max   = left->downsize;
		for (i = Maxspc-max; i < Maxspc; i++) {
			idx = split[i];
			left->ppenaltyarr[idx]    += curredge->ppenaltyarr[idx];
			left->pbonusarr[idx]      += curredge->pbonusarr[idx];
			left->pmissingarr[idx]    += curredge->pmissingarr[idx];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - dl-reprop split[%d/%d] = %d !!!\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - dl-reprop split[%d/%d] = %d OK\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
#endif
		}

		/* descend downleft */
		computepenalties_resubtree_tripl(left, numleaves, Maxspc,
		                       minedges, howmany,
                                       maxbonus,
		                       DESC_DL);

        	/*********************************************/
		/*** propagate to/from lower right subtree ***/
        	/*********************************************/

        	right->down_stpenalty += curredge->down_stpenalty;
        	right->down_stbonus   += curredge->down_stbonus  ;
        	right->down_stmissing += curredge->down_stmissing;

		split = right->split;
		max   = right->downsize;
		for (i = Maxspc-max; i < Maxspc; i++) {
			idx = split[i];
			right->ppenaltyarr[idx]    += curredge->ppenaltyarr[idx];
			right->pbonusarr[idx]      += curredge->pbonusarr[idx];
			right->pmissingarr[idx]    += curredge->pmissingarr[idx];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - dr-reprop split[%d/%d] = %d !!!\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - dr-reprop split[%d/%d] = %d OK\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
#endif
		}

		/* descend downright */
		computepenalties_resubtree_tripl(right, numleaves, Maxspc,
		                       minedges, howmany,
                                       maxbonus,
		                       DESC_DR);

        	/************************************************************/
		/*** collect redistributed bonus/penalty of internal edge ***/
		/*** (only down-values possible, due to redistribution)   ***/
        	/************************************************************/

		curredge->stpenalty += curredge->down_stpenalty;
		curredge->stbonus   += curredge->down_stbonus  ;
		curredge->stmissing += curredge->down_stmissing;
		curredge->stmax     += curredge->stpenalty + curredge->stbonus + curredge->stmissing;
		curredge->down_stpenalty = 0;
		curredge->down_stbonus   = 0;
		curredge->down_stmissing = 0;

		split = curredge->split;
		max   = curredge->downsize;
		for (i = Maxspc-max; i < Maxspc; i++) {
			idx = split[i];
			curredge->ppenalty        += curredge->ppenaltyarr[idx];
			curredge->pbonus          += curredge->pbonusarr[idx];
			curredge->pmissing        += curredge->pmissingarr[idx];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - down-coll-reprop split[%d/%d] = %d !!!\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[idx]);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - down-coll-reprop split[%d/%d] = %d OK\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[idx]);
#endif
			curredge->ppenaltyarr[idx] = 0;
			curredge->pbonusarr[idx]   = 0;
			curredge->pmissingarr[idx] = 0;
		}

	}

	/*** minimum check ***/
	curredge->pmax = curredge->ppenalty + curredge->pbonus + curredge->pmissing;
	edgevalue = compute_edgeval(curredge, pstep_voting_optn); 
#ifndef QUIET
fprintf(stderr, "PPP(%s:%04d)| ppenaly (edge %d taxon %d) - %lu %s %lu (recur)\n", __FILE__, __LINE__, curredge->numedge, curredge->taxon,
curredge->ppenalty, curredge->ppenalty==curredge->edgeinfo ? "==" : "!=", curredge->edgeinfo);
#endif
	if (*maxbonus == edgevalue) { 
		/* another min edge */
		minedges[(*howmany)++] = curredge->numedge;
#ifndef QUIET
		stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
		ppmax = ((curredge->upsize * curredge->downsize) * (numleaves - 2))/2;
		fprintf_votings(stderr, curredge, edgevalue, numleaves, "again","+", __FILE__, __LINE__); /* VVV: */
#endif /* ! QUIET */
	} else { /* -> not same minimum */
		if (*maxbonus < edgevalue) {
			/* new minimum penalty */
			*howmany = 1;
			minedges[0] = curredge->numedge;
			*maxbonus = edgevalue;
#ifndef QUIET
			stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
			ppmax = ((curredge->upsize * curredge->downsize) * (numleaves - 2))/2;
			fprintf_votings(stderr, curredge, edgevalue, numleaves, "best ","*", __FILE__, __LINE__); /* VVV: */
#endif /* ! QUIET */
		} /* if new minimum */
#ifndef QUIET
		else {
			stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
			ppmax = ((curredge->upsize * curredge->downsize) * (numleaves - 2))/2;
			fprintf_votings(stderr, curredge, edgevalue, numleaves, "worse","-", __FILE__, __LINE__); /* VVV: */
		}
#endif /* ! QUIET */
	} /* same minimum */
} /* computepenalties_resubtree_tripl */

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

/* compute edge penalties using splits, if #minedges>1 choose one randomly */
void computepenaltiessubtree_tripl(
                            ONEEDGE  *curredge,/* edge array          */
                            int       nextleaf,      /* number of leaves for voting     */
                            int       Maxspc,         /* number of taxa      */
                            ulimatrix neighbormatr,   /* neighborhood matrix */
                            ulivector leafpenalty,    /* leaf edge penalties */
                            int      *minedges,   /* minimum edge vector     */
                            int      *howmany,    /* number minimum edge     */
                            double   *maxbonus,   /* minimum penalty         */
                            int      direction,   /* comming from direction  */
                            int      status)      /* search best edge?       */
	
{
	int l, r;
	int lmax, rmax;
	int taxon;
	uli temp;
	ONEEDGE *left;     /* temp edge ptr */
	ONEEDGE *right;    /* temp edge ptr */
	ONEEDGE *up;       /* temp edge ptr */
	double   edgevalue;
	int *split, max, i, idx;

#ifndef QUIET
	fprintf(stderr, "MMM:computepenaltiessubtree_tripl: descend to edge: %d %s\n", curredge->numedge, (direction==DESC_DL) ? "DL" : "DR");
#endif /* ! QUIET */

	if (curredge->downleft == NULL) {  /* leaf edge */
		taxon                = curredge->taxon;
#if 0
		curredge->cluster[0] = taxon;
		curredge->clsize     = 1;
#endif
		if ((curredge->up_stpenalty != (uli)0) || ( curredge->up_stbonus != (uli)0) || ( curredge->up_stmissing != (uli)0)) {
			/* leaf edge should never get up_penalty/bonus */
			/* Hence, they cannot be propagated! */
			/*  NO up->down_stpenalty += curredge->down_stpenalty; */
			/*  NO up->down_stbonus   += curredge->down_stbonus  ; */
			/*  NO up->down_stmissing += curredge->down_stmissing; */
			fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR HSTBP1 TO DEVELOPERS\n");
			if ( curredge->up_stbonus   != (uli)0) 
				fprintf(STDOUT, "      leaf subtree up_bonus != 0 (%lu) taxon=%d (%d)\n", curredge->up_stbonus, curredge->taxon, curredge->numedge);
			if ( curredge->up_stpenalty != (uli)0) 
				fprintf(STDOUT, "      leaf subtree up_penalty != 0 (%lu) taxon=%d (%d)\n", curredge->up_stpenalty, curredge->taxon, curredge->numedge);
			if ( curredge->up_stmissing != (uli)0) 
				fprintf(STDOUT, "      leaf subtree up_missing != 0 (%lu) taxon=%d (%d)\n", curredge->up_stmissing, curredge->taxon, curredge->numedge);
			fprintf(STDOUT, "\n\n");
#			if PARALLEL
				PP_Finalize();
#			endif
			tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
		}

        	/******************************************/
		/*** collect bonus/penalty of leaf edge ***/
		/*** (only down-values possible)        ***/
        	/******************************************/

		curredge->stpenalty    += curredge->down_stpenalty;
		curredge->stbonus      += curredge->down_stbonus  ;
		curredge->stmissing    += curredge->down_stmissing;
		/* ... and reset buffer */
		curredge->down_stpenalty = 0;
		curredge->up_stpenalty   = 0;
		curredge->down_stbonus   = 0;
		curredge->up_stbonus     = 0;
		curredge->down_stmissing = 0;
		curredge->up_stmissing   = 0;

		curredge->ppenalty    += curredge->ppenaltyarr[curredge->taxon];
		curredge->pbonus      += curredge->pbonusarr[curredge->taxon];
		curredge->pmissing    += curredge->pmissingarr[curredge->taxon];
#ifndef QUIET
{int idx = curredge->taxon, i=-2, max=-2;
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - leaf-coll-prop split[%d/%d] = %d !!!\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[curredge->taxon]);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - leaf-coll-prop split[%d/%d] = %d OK\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[curredge->taxon]);
}
#endif
		curredge->ppenaltyarr[curredge->taxon] = 0;
		curredge->pbonusarr[curredge->taxon]   = 0;
		curredge->pmissingarr[curredge->taxon] = 0;

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

		curredge->edgeinfo   = leafpenalty[taxon];
		curredge->allsum     = leafpenalty[taxon];
		curredge->submatrsum    = 0;

		if ((direction == DESC_DR) && (status == RIGHT_MOST_PATH)) {
			/* right-most leaf reached -> search best edge from now */
#ifndef QUIET
			fprintf(stderr, "MMM:wenden bei taxon=%d (edge %d)\n", curredge->taxon, curredge->numedge);
#endif /* ! QUIET */

#ifndef QUIET
fprintf(stderr, "PPP(%s:%04d)| ppenaly (edge %d taxon %d) - %lu %s %lu (recur)\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon,
curredge->ppenalty, curredge->ppenalty==curredge->edgeinfo ? "==" : "!=", curredge->edgeinfo);
#endif
			/* use current as best edge */
			*howmany = 1;
			minedges[0] = curredge->numedge;
			/* compute voting score = (pro - contra)/(pro+contra+missing) */
			curredge->pmax = curredge->ppenalty + curredge->pbonus + curredge->pmissing;
			edgevalue = compute_edgeval(curredge, pstep_voting_optn); 
			*maxbonus = edgevalue; 
#ifndef QUIET
			stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
			ppmax = ((curredge->upsize * curredge->downsize) * (nextleaf - 2))/2;
			fprintf_votings(stderr, curredge, edgevalue, nextleaf, "start","*", __FILE__, __LINE__); /* VVV: */
#endif /* ! QUIET */
		}

	} else {   /* -> internal edge */
		up    = curredge->up;
		left  = curredge->downleft;
		right = curredge->downright;

        	/********************************************/
		/*** propagate to/from lower left subtree ***/
        	/********************************************/

		left->down_stpenalty += curredge->down_stpenalty;
		left->down_stbonus   += curredge->down_stbonus  ;
		left->down_stmissing += curredge->down_stmissing;
 
		split = left->split;
		max   = left->downsize;
		for (i = Maxspc-max; i < Maxspc; i++) {
			idx = split[i];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - dl-prop split[%d/%d] = %d !!!\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - dl-prop split[%d/%d] = %d OK\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
#endif
			left->ppenaltyarr[idx]    += curredge->ppenaltyarr[idx];
			left->pbonusarr[idx]      += curredge->pbonusarr[idx];
			left->pmissingarr[idx]    += curredge->pmissingarr[idx];
		}

		/* descend downleft */
		computepenaltiessubtree_tripl(left, nextleaf, Maxspc,
		                       neighbormatr, leafpenalty,
		                       minedges, howmany,
		                       maxbonus,   /* minimum penalty         */
		                       DESC_DL, SUBTREE_LEFT);

        	/*********************************************/
		/*** propagate to/from lower right subtree ***/
        	/*********************************************/

        	right->down_stpenalty += curredge->down_stpenalty;
        	right->down_stbonus   += curredge->down_stbonus  ;
        	right->down_stmissing += curredge->down_stmissing;

		split = right->split;
		max   = right->downsize;
		for (i = Maxspc-max; i < Maxspc; i++) {
			idx = split[i];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - dr-prop split[%d/%d] = %d !!!\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - dr-prop split[%d/%d] = %d OK\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
#endif
			right->ppenaltyarr[idx]    += curredge->ppenaltyarr[idx];
			right->pbonusarr[idx]      += curredge->pbonusarr[idx];
			right->pmissingarr[idx]    += curredge->pmissingarr[idx];
		}

		/* descend downright */
		computepenaltiessubtree_tripl(right, nextleaf, Maxspc,
		                       neighbormatr, leafpenalty,
		                       minedges, howmany,
		                       maxbonus,   /* minimum penalty         */
		                       DESC_DR, status);

        	/***********************************************/
		/*** re-propagate to/from lower left subtree ***/
        	/***********************************************/

		/* descend downleft */
		if (status == RIGHT_MOST_PATH) {
			computepenalties_resubtree_tripl(left, nextleaf, Maxspc,
		                       minedges, howmany,
		                       maxbonus,   /* minimum penalty         */
		                       DESC_DL);
		}

        	/*************************************************************/
		/*** propagate to/from subtree above and up-left or -right ***/
        	/*************************************************************/

        	up->up_stpenalty += curredge->up_stpenalty;
        	up->up_stbonus   += curredge->up_stbonus  ;
        	up->up_stmissing += curredge->up_stmissing;

		split = up->split;
		max   = up->upsize;
		for (i = 0; i < max; i++) {
			idx = split[i];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - upup-prop split[%d/%d] = %d !!!\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - upup-prop split[%d/%d] = %d OK\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
#endif
			up->ppenaltyarr[idx]    += curredge->ppenaltyarr[idx];
			up->pbonusarr[idx]      += curredge->pbonusarr[idx];
			up->pmissingarr[idx]    += curredge->pmissingarr[idx];
		}

		if (up->downright == curredge) {
        		up->downleft->down_stpenalty += curredge->up_stpenalty;
        		up->downleft->down_stbonus   += curredge->up_stbonus  ;
        		up->downleft->down_stmissing += curredge->up_stmissing;

			split = up->downleft->split;
			max   = up->downleft->downsize;
			for (i = Maxspc-max; i < Maxspc; i++) {
				idx = split[i];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - updl-prop split[%d/%d] = %d !!!\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - updl-prop split[%d/%d] = %d OK\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
#endif
				up->downleft->ppenaltyarr[idx]    += curredge->ppenaltyarr[idx];
				up->downleft->pbonusarr[idx]      += curredge->pbonusarr[idx];
				up->downleft->pmissingarr[idx]    += curredge->pmissingarr[idx];
			}
		} else {
        		up->downright->down_stpenalty += curredge->up_stpenalty;
        		up->downright->down_stbonus   += curredge->up_stbonus  ;
        		up->downright->down_stmissing += curredge->up_stmissing;

			split = up->downright->split;
			max   = up->downright->downsize;
			for (i = Maxspc-max; i < Maxspc; i++) {
				idx = split[i];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - updr-prop split[%d/%d] = %d !!!\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - updr-prop split[%d/%d] = %d OK\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx);
#endif
				up->downright->ppenaltyarr[idx]    += curredge->ppenaltyarr[idx];
				up->downright->pbonusarr[idx]      += curredge->pbonusarr[idx];
				up->downright->pmissingarr[idx]    += curredge->pmissingarr[idx];
			}
		}

        	/**********************************************/
		/*** collect bonus/penalty of internal edge ***/
        	/**********************************************/

		curredge->stpenalty += curredge->down_stpenalty + curredge->up_stpenalty;
		curredge->stbonus   += curredge->down_stbonus   + curredge->up_stbonus  ;
		curredge->stmissing += curredge->down_stmissing + curredge->up_stmissing;
		curredge->down_stpenalty = 0;
		curredge->up_stpenalty   = 0;
		curredge->down_stbonus   = 0;
		curredge->up_stbonus     = 0;
		curredge->down_stmissing = 0;
		curredge->up_stmissing   = 0;

		split = curredge->split;
		max   = curredge->upsize;
		for (i = 0; i < max; i++) {
			idx = split[i];
			curredge->ppenalty        += curredge->ppenaltyarr[idx];
			curredge->pbonus          += curredge->pbonusarr[idx];
			curredge->pmissing        += curredge->pmissingarr[idx];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - up-coll split[%d/%d] = %d !!!\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[idx]);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - up-coll split[%d/%d] = %d OK\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[idx]);
#endif
			curredge->ppenaltyarr[idx] = 0;
			curredge->pbonusarr[idx]   = 0;
			curredge->pmissingarr[idx] = 0;
		}

		max   = curredge->downsize;
		for (i = Maxspc-max; i < Maxspc; i++) {
			idx = split[i];
			curredge->ppenalty        += curredge->ppenaltyarr[idx];
			curredge->pbonus          += curredge->pbonusarr[idx];
			curredge->pmissing        += curredge->pmissingarr[idx];
#ifndef QUIET
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - down-coll split[%d/%d] = %d !!!\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[idx]);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - down-coll split[%d/%d] = %d OK\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[idx]);
#endif
			curredge->ppenaltyarr[idx] = 0;
			curredge->pbonusarr[idx]   = 0;
			curredge->pmissingarr[idx] = 0;
		}


		/* get split sizes beyond lower right/left descendant */
		lmax = left->downsize;
		rmax = right->downsize;

		temp = 0;

		for (r= Maxspc-rmax; r<Maxspc; r++) { /* was: for (r= 0; r<rmax; r++) */
			/* sum up sub neighborhood matrix */
			for (l= Maxspc-lmax; l<Maxspc; l++) { /* was: for (l= 0; l<lmax; l++) */
				temp += neighbormatr[left->split[l]][right->split[r]];
			}
		}

		/* compute edge penalty */
		curredge->submatrsum = 2*temp + 
		                       left->submatrsum + right->submatrsum;
		curredge->allsum = left->allsum + right->allsum;
		curredge->edgeinfo = curredge->allsum - curredge->submatrsum;

		if (status == RIGHT_MOST_PATH) {
			/* compute voting score = (pro - contra)/(pro+contra+missing) */
			curredge->pmax = curredge->ppenalty + curredge->pbonus + curredge->pmissing;
			edgevalue = compute_edgeval(curredge, pstep_voting_optn); 
#ifndef QUIET
fprintf(stderr, "PPP(%s:%04d)| ppenaly (edge %d taxon %d) - %lu %s %lu (recur)\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon,
curredge->ppenalty, curredge->ppenalty==curredge->edgeinfo ? "==" : "!=", curredge->edgeinfo);
#endif
			if (*maxbonus == edgevalue) { 
				/* another min edge */
				minedges[(*howmany)++] = curredge->numedge;
#ifndef QUIET
				stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
				ppmax = ((curredge->upsize * curredge->downsize) * (nextleaf - 2))/2;
				fprintf_votings(stderr, curredge, edgevalue, nextleaf, "again","+", __FILE__, __LINE__); /* VVV: */
#endif /* ! QUIET */

			} else { /* -> not same minimum */

				if (*maxbonus < edgevalue) {
					/* new minimum penalty */
					*howmany = 1;
					minedges[0] = curredge->numedge;
					*maxbonus = edgevalue;
#ifndef QUIET
					stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
					ppmax = ((curredge->upsize * curredge->downsize) * (nextleaf - 2))/2;
					fprintf_votings(stderr, curredge, edgevalue, nextleaf, "best ","*", __FILE__, __LINE__); /* VVV: */
#endif /* ! QUIET */
				} /* if new minimum */
#ifndef QUIET
				else {
					stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
					ppmax = ((curredge->upsize * curredge->downsize) * (nextleaf - 2))/2;
					fprintf_votings(stderr, curredge, edgevalue, nextleaf, "worse","-", __FILE__, __LINE__); /* VVV: */
				}
#endif /* ! QUIET */


			} /* same minimum */
		}
	}
} /* computepenaltiessubtree_tripl */

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

/***XXX***/
/* distribute penalties/bonus through the tree, if #minedges>1 choose one randomly */
void computepenaltiestree_tripl(
		ONEEDGE  *tmpedge,        /* edge array          */
		int      *edgeofleaf,     /* external edge ptrs  */
		int       rootleaf,       /* idx of uppest edge  */
		int       nextleaf,       /* next free leaf idx  */
		int       Maxspc,         /* number of taxa      */
		ulimatrix neighbormatr,   /* neighborhood matrix */
		ulivector leafpenalty,    /* leaf edge penalties */
		int      *minedges,       /* minimum edge vector */
		int      *out_howmany,    /* number minimum edge */
                double   *out_maxbonus,   /* minimum penalty         */
		int      *out_minedge)    /* minimum edge        */
{
	int      rootedge;
	int      lmax, rmax;
	int      l, r;
	int      howmany  = 0;
	uli      temp;
	ONEEDGE *left;     /* temp edge ptr */
	ONEEDGE *right;    /* temp edge ptr */
	double   edgevalue;
        double   maxbonus;   /* minimum penalty         */
	uli      submatrsum;
	uli      allsum;
	uli      edgeinfo;
	ONEEDGE *curredge;
	int      status;

	rootedge = edgeofleaf[rootleaf];
	curredge = &(tmpedge[rootedge]);
	curredge->edgeinfo = leafpenalty[rootleaf];

#ifndef QUIET
	fprintf(stderr, "MMM:computepenaltiestree_tripl: start at root edge: %d\n", curredge->numedge);
#endif /* ! QUIET */

	left  = curredge->downleft;
	right = curredge->downright;

        /********************************************/
	/*** propagate to/from lower left subtree ***/
        /********************************************/
	if ((curredge->down_stpenalty != (uli)0) || ( curredge->down_stbonus != (uli)0) || ( curredge->down_stmissing != (uli)0)) {
		/* root edge cluster should never get down_penalty/bonus */
		/* Hence, they cannot be propagated! */
		/*  NO left->down_stpenalty += curredge->down_stpenalty; */
		/*  NO left->down_stbonus   += curredge->down_stbonus  ; */
		/*  NO left->down_stmissing += curredge->down_stmissing; */
		fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR HSTBP2 TO DEVELOPERS\n");
		if ( curredge->down_stbonus   != (uli)0) 
			fprintf(STDOUT, "      root subtree down_bonus != 0 (%lu) taxon=%d (%d)\n",   curredge->down_stbonus, curredge->taxon, curredge->numedge);
		if ( curredge->down_stpenalty != (uli)0) 
			fprintf(STDOUT, "      root subtree down_penalty != 0 (%lu) taxon=%d (%d)\n", curredge->down_stpenalty, curredge->taxon, curredge->numedge);
		if ( curredge->down_stmissing != (uli)0) 
			fprintf(STDOUT, "      root subtree down_missing != 0 (%lu) taxon=%d (%d)\n",   curredge->down_stmissing, curredge->taxon, curredge->numedge);
		fprintf(STDOUT, "\n\n");
#		if PARALLEL
			PP_Finalize();
#		endif
		tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}

	/* descend downleft */
	computepenaltiessubtree_tripl(left, nextleaf, Maxspc,
	                       neighbormatr, leafpenalty,
	                       minedges, &howmany,
	                       &maxbonus, 
	                       DESC_DL, SUBTREE_LEFT);


        /*********************************************/
	/*** propagate to/from lower right subtree ***/
        /*********************************************/

	/* subtree bonus/penalties from lower left subtree are propagated */
	/* on last branch to curredge->up_st* and right->down_st* */
	/*  NO right->down_stpenalty += curredge->down_stpenalty; */
	/*  NO right->down_stbonus   += curredge->down_stbonus  ; */
	/*  NO right->down_stmissing += curredge->down_stmissing; */

	/* descend downright */
	computepenaltiessubtree_tripl(right, nextleaf, Maxspc,
	                       neighbormatr, leafpenalty,
	                       minedges, &howmany,
	                       &maxbonus, 
	                       DESC_DR, RIGHT_MOST_PATH);

        /******************************************/
	/*** re-propagate to lower left subtree ***/
        /******************************************/

	/* subtree bonus/penalties from lower left subtree are propagated */
	/* on last branch to curredge->up_st* and left->down_st* */
	/*  NO left->down_stpenalty += curredge->down_stpenalty; */
	/*  NO left->down_stbonus   += curredge->down_stbonus  ; */
	/*  NO left->down_stmissing += curredge->down_stmissing; */

	/* descend downleft */
	status = RIGHT_MOST_LEAF; /* search best edge */
	computepenalties_resubtree_tripl(left, nextleaf, Maxspc, 
	                       minedges, &howmany,
	                       &maxbonus, 
	                       DESC_DL);


        /******************************************/
	/*** collect bonus/penalty of root edge ***/
	/*** (only up-values possible)          ***/
        /******************************************/

	curredge->stpenalty += curredge->up_stpenalty;
	curredge->stbonus   += curredge->up_stbonus  ;
	curredge->stmissing += curredge->up_stmissing;

	curredge->down_stpenalty = 0;
	curredge->down_stbonus   = 0;
	curredge->down_stmissing = 0;

	curredge->ppenalty        += curredge->ppenaltyarr[curredge->taxon];
	curredge->pbonus          += curredge->pbonusarr[curredge->taxon];
	curredge->pmissing        += curredge->pmissingarr[curredge->taxon];
#ifndef QUIET
{int idx = curredge->taxon, i=-2, max=-2;
if (idx < 0 || idx > Maxspc) fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - root-coll-prop split[%d/%d] = %d !!!\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[curredge->taxon]);
else fprintf(stderr, "WWW:(%s:%d) edge %d tax %d - root-coll-prop split[%d/%d] = %d OK\t%lu <- %lu\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon, i, max, idx, curredge->ppenalty, curredge->ppenaltyarr[curredge->taxon]);
}
#endif
	curredge->ppenaltyarr[curredge->taxon] = 0;
	curredge->pbonusarr[curredge->taxon]   = 0;
	curredge->pmissingarr[curredge->taxon] = 0;


#ifdef PATHPENALTY
#else
	/* compute voting score = (pro - contra)/(pro+contra+missing) */
	curredge->pmax = curredge->ppenalty + curredge->pbonus + curredge->pmissing;
	edgevalue = compute_edgeval(curredge, pstep_voting_optn); 
#ifndef QUIET
fprintf(stderr, "PPP(%s:%04d)| ppenaly (edge %d taxon %d) - %lu %s %lu (recur)\n", __FILE__, __LINE__,  curredge->numedge, curredge->taxon,
curredge->ppenalty, curredge->ppenalty==curredge->edgeinfo ? "==" : "!=", curredge->edgeinfo);
#endif
	if (maxbonus == edgevalue) { 
		/* another min edge */
		minedges[howmany++] = curredge->numedge;
#ifndef QUIET
		stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
		ppmax = ((curredge->upsize * curredge->downsize) * (nextleaf - 2))/2;
		fprintf_votings(stderr, curredge, edgevalue, nextleaf, "again","+", __FILE__, __LINE__); /* VVV: */
#endif /* ! QUIET */

	} else { /* -> not same minimum */

		if (maxbonus < edgevalue) {
			/* new minimum penalty */
			howmany = 1;
			minedges[0] = curredge->numedge;
			maxbonus = edgevalue;
#ifndef QUIET
			stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
			ppmax = ((curredge->upsize * curredge->downsize) * (nextleaf - 2))/2;
			fprintf_votings(stderr, curredge, edgevalue, nextleaf, "best ","*", __FILE__, __LINE__); /* VVV: */
#endif /* ! QUIET */
		} /* if new minimum */
#ifndef QUIET
		else {
			stmax = curredge->stbonus + curredge->stpenalty + curredge->stmissing;
			ppmax = ((curredge->upsize * curredge->downsize) * (nextleaf - 2))/2;
			fprintf_votings(stderr, curredge, edgevalue, nextleaf, "worse","-", __FILE__, __LINE__); /* VVV: */
		}
#endif /* ! QUIET */

	} /* same minimum */
#endif

        /******************************************/
	/*** update splits and path penalties ***/
        /****************************************/

	/* get split sizes beyond lower right/left descendant */
	lmax = left->downsize;
	rmax = right->downsize;

	if ((lmax + rmax) != (nextleaf-1)) {
		/* root edge cluster should yield all other leaves */
		fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR HSCL1 TO DEVELOPERS\n\n\n");
#		if PARALLEL
			PP_Finalize();
#		endif
		tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}

	temp = 0;
	for (r= Maxspc-rmax; r<Maxspc; r++) { /* was: for (r= 0; r<rmax; r++) */
		/* sum up sub neighborhood matrix */
		for (l= Maxspc-lmax; l<Maxspc; l++) { /* was: for (l= 0; l<lmax; l++) */
			temp += neighbormatr[left->split[l]][right->split[r]];
		}
	}

	/* compute edge penalty */
	submatrsum = 2*temp + left->submatrsum + right->submatrsum;
	allsum = left->allsum + right->allsum;
	edgeinfo = allsum - submatrsum;


	if ((edgeinfo) != (curredge->edgeinfo)) {
		/* root edge cluster should yield same penalty as rest */
		fprintf(STDOUT, "\n\n\nHALT: PLEASE REPORT ERROR HSCL2 TO DEVELOPERS\n\n\n");
#		if PARALLEL
			PP_Finalize();
#		endif
		tp_exit(1, NULL, FALSE, __FILE__, __LINE__, exit_wait_optn);
	}



	if (howmany > 1) 
		*out_minedge = minedges[randominteger(howmany)];
	else
		*out_minedge = minedges[0];

#if 0 /* obsolete, due to optimization above (HAS) */
	if (howmany > 1) { /* draw random edge */
		int i, k, randomnum;
		randomnum = randominteger(howmany) + 1; /* 1 to howmany */
		i = -1;
		for (k = 0; k < randomnum; k++) {
			do {
				i++;
			} while (tmpedge[i].edgeinfo != minpenalty);
			*out_minedge = tmpedge[i].numedge;
		}
	} else {
		*out_minedge = minedges[0];
	}
#endif

	*out_howmany = howmany;
	*out_maxbonus = maxbonus;

} /* computepenaltiestree_tripl */

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

/***XXX***/
/* perform one single puzzling step to produce one intermediate tree */
void onepstep_tripl(              /* PStep (intermediate) tree topol:   */
         ONEEDGE **edge,               /*   out: new array of edges          */
         int     **edgeofleaf,         /*   out: array of extern edge ptrs   */
         int      *rootleaf,           /*   out: root leaf in topol, starting perm[0]  */
         unsigned char *quartettopols, /* in: quartetblock with all topols   */
         int       Maxspc,             /* in: Number of species (n)          */
         ivector   permut,             /* in: species permutation (trueID)   */
         uli       iteration,          /* number of current iteration (Currtrial) */
         int       rootquartsonly_optn) /* use only root quartets */
{

	/* local variables: */
	int  Maxbrnch = (2*Maxspc)-3; /* Number of branches (2n-3)   */
	int  nextedge;                /* next free edge index (=3)   */
	int  nextleaf;                /* next free leaf index (=3)   */
	int  minedge;                 /* insertion edge of minimum penalty */
	double maxbonus;              /* minimum penalty         */
	int a, b, i;                  /* quartet leaves, i to be inserted */
	int idxA, idxB;
	int idxI;                     /* index counter for quartet leaves */
	ONEEDGE      *tmpedge;        /* new array of edges          */
	int          *tmpedgeofleaf;  /* array of extern edge ptrs   */
	int           tmprootleaf;    /* root edge                   */
	ulimatrix     neighbormatr;
	ulivector     leafpenalty;
	int          *minedges;
	int           howmany;

	minedges = (int *) calloc((size_t) (2*Maxspc - 3), sizeof(int));
	if (minedges == NULL) maerror("minimal edge set in onepstep_tripl");

	neighbormatr = new_ulimatrix(Maxspc,Maxspc);
	leafpenalty  = new_ulivector(Maxspc);

#if 0
	minedges = (int *) calloc((size_t) (2*Maxspc - 3), sizeof(int));
	if (minedges == NULL) maerror("minimal edge set in onepstep_recur");
#endif

	/* allocate and initialize new tree topology */
	inittree_tripl(&tmpedge, &tmpedgeofleaf, &tmprootleaf, Maxspc, Maxbrnch, &nextedge, &nextleaf, permut);

	for (idxI = 3; idxI < Maxspc; idxI++) { 

		i = permut[idxI];
#ifndef QUIET
		fprintf(stderr, "------ iteration %lu adding leaf %d = taxon %d ------------\n", iteration+1, idxI+1, i);
		fprintf(stderr, "VVV ------ iteration %lu adding leaf %d = taxon %d ------------ %s\n", iteration+1, idxI+1, i, voting_string(pstep_voting_optn));
		fprintf(stderr, "VVV:%04d|       |edge tax   EI  rEI|   PB   PP  PMs Psum Pmax |  B-P r(B-P)    rPB    -rPP |   STB    STP   STMs    Sum |    B-P  r(B-P)    rSB    -rSP  *+-\n", __LINE__);
#endif /* ! QUIET */

		/* initialize/reset penalty neighborhood matrix */
		for (idxA = 0; idxA < nextleaf - 1; idxA++) {
			a = permut[idxA];
			leafpenalty[a] = 0;
			for (idxB = idxA + 1; idxB < nextleaf; idxB++) {
				b = permut[idxB];

				neighbormatr[a][b] = 0;
				neighbormatr[b][a] = 0;
			} 
		} /* for all entries in the upper neighbormatr */

		/* fill neighborhood matrix & collect penalties/bonus node-wise */
		computepenaltiespernode_tripl(tmpedge, nextedge, Maxspc, neighbormatr, i);

		/*
		 * core of quartet puzzling algorithm
	 	 */

		/* from/for the recursive approach: (HAS ;-) */
		/* symmetrize penalty neighborhood matrix */
		for (idxA = 0; idxA < nextleaf - 1; idxA++) {
			a = permut[idxA];
			for (idxB = idxA + 1; idxB < nextleaf; idxB++) {
				b = permut[idxB];

				neighbormatr[a][b] += neighbormatr[b][a];
				neighbormatr[b][a] = neighbormatr[a][b];
				leafpenalty[a] += neighbormatr[a][b];
				leafpenalty[b] += neighbormatr[a][b];
			} 
		} /* for all entries in the upper neighbormatr */

		/* compute/propagate path/subtree bonus/penalties and find confidence set of minimum edges */
		computepenaltiestree_tripl(tmpedge, tmpedgeofleaf, tmprootleaf,
                            nextleaf, Maxspc, neighbormatr, leafpenalty,
                            minedges, &howmany, 
	                    &maxbonus,              /* minimum penalty         */
                            &minedge);

		/* add the next leaf on minedge */
		addnextleaf_tripl(minedge, tmpedge, tmpedgeofleaf, tmprootleaf, Maxspc, Maxbrnch, &nextedge, &nextleaf, permut);

	} /* adding all other leafs */

	*edge       = tmpedge;         /* export tree topology             */
	*edgeofleaf = tmpedgeofleaf;   /* export array of extern edge ptrs */
	*rootleaf   = tmprootleaf;     /* export root edge                 */

	free(minedges);
	free_ulivector(leafpenalty);
	free_ulimatrix(neighbormatr);
} /* onepstep_tripl */


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



