/********************************************************************************************************
 * QRNA - Comparative analysis of biological sequences 
 *         with pair hidden Markov models, pair stochastic context-free
 *        grammars, and probabilistic evolutionary  models.
 *       
 * Version 2.0.0 (JUN 2003)
 *
 * Copyright (C) 2000-2003 Howard Hughes Medical Institute/Washington University School of Medicine
 * All Rights Reserved
 * 
 *     This source code is distributed under the terms of the
 *     GNU General Public License. See the files COPYING and LICENSE
 *     for details.
 ***********************************************************************************************************/


/* rnacreatealign.c
 *
 * ER, Wed Jun  2 09:43:57 CDT 1999 [St. Louis]
 * 
 * creates an alignment acoding to the rnamodel
 * 
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>

#include "funcs.h"
#include "globals.h"
#include "squid.h"
#include "structs.h"

#ifdef MEMDEBUG
#include "dbmalloc.h"
#endif

static void coemitIS1(FILE *ofp, SQINFO *sqinfoX, int *seqX, SQINFO *sqinfoY, int *seqY, struct pi2model_s *pi2, 
		      int j, int d, double *pnode_is1, 
		      struct tracekn_s *cur_tr, struct traceknstack_s *dolist, char *charX, char *charY,
		      int traceback, int *ct);
static void coemitIS1_from_posterior(FILE *ofp, int *seqX, int *seqY, struct rna_loop5 *is1, int L, int j, int d, double *pnode_is1,
				     struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
				     int traceback, int *ct);
static void  coemitIS2(FILE *ofp, int *seqX, int *seqY, struct rna_loop5 *is2, int j, int d, 
		      int d1, int d2, double *pnode_is2,
		      struct tracekn_s *cur_tr, struct traceknstack_s *dolist, char *charX, char *charY,
		      int traceback, int *ct);
static void coemitIS2_from_posterior(FILE *ofp, int *seqX, int *seqY, struct rna_loop5 *is2, int L, int j, int d, 
				     int d1, int d2, double *pnode_is2,
				     struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
				     int traceback, int *ct);
static void  coemitV(FILE *ofp, int **ret_seqX, int **ret_seqY, struct rna_v5 *v, int L, int *ret_len, int j, int d, double *pnode_v,
		     double *pnode_is1, double *pnode_is2b, double *pnode_is2i, 
		     struct tracekn_s *cur_tr, struct traceknstack_s *dolist, int traceback,  
		     char **ret_charX, char **ret_charY, int **ret_ct, 
		     int *pairs, int *comp_pairs, int *noncomp_pairs);
static void  coemitW(FILE *ofp, int **ret_seqX, int **ret_seqY, struct rna_w5 *w, int L, int *ret_len, int j, int d, double *pnode_w,
		     struct tracekn_s *cur_tr, struct traceknstack_s *dolist, int traceback, 
		     char **ret_charX, char **ret_charY, int **ret_ct, 
		     int *pairs, int *comp_pairs, int *noncomp_pairs);
static void coemitV_from_posterior(FILE *ofp, int *seqX, int *seqY, struct rna_v5 *v, int L, int j, int d, 
				   struct rnamtx_s *in,
				   double *pnode_pos_v, double *pnode_v, double *pnode_is1, double *pnode_is2b, double *pnode_is2i, 
				   struct tracekn_s *cur_tr, struct traceknstack_s *dolist, 
				   struct ali_s *ali, int traceback, int *ct, int* pairs, int *comp_pairs, int *noncomp_pairs);
static void coemitW_from_posterior(FILE *ofp, int *seqX, int *seqY, struct rna_w5 *w, int L, int j, int d, 
				   double **wx, double **vx,
				   double *pnode_pos_w, double *pnode_w,
				   struct tracekn_s *cur_tr, 
				   struct traceknstack_s *dolist, struct ali_s *ali, 
				   int traceback, int *ct, int *pairs, int *comp_pairs, int *noncomp_pairs);
static void emitIS1(FILE *ofp, int *seq, int *seqX, int *seqY, struct rna_loop5 *is1, int L, int j, int d, 
		    double *pnode_is1, struct tracekn_s *cur_tr, struct traceknstack_s *dolist, 
		    struct ali_s *ali, int traceback, int *ct);
static void emitIS2(FILE *ofp, int *seq, int *seqX, int *seqY, struct rna_loop5 *is2, int L, int j, int d, 
		    int d1, int d2, double *pnode_is2,
		    struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
		    int traceback, int *ct);
static void emitV(FILE *ofp, int *seq, int *seqX, int *seqY, struct rna_v5 *v, int L, int j, int d, double *pnode_v,
		  double *pnode_is1, double *pnode_is2b,  double *pnode_is2i, struct tracekn_s *cur_tr, struct traceknstack_s *dolist, 
		  struct ali_s *ali, int traceback, int *ct, int *pairs, int *comp_pairs, int *noncomp_pairs);
static void emitW(FILE *ofp, int *seq, int *seqX, int *seqY, struct rna_w5 *w, int L, int j, int d, double *pnode_w,
		  struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
		  int traceback, int *ct, int *pairs, int *comp_pairs, int *noncomp_pairs);

static void realloc_strings(int L, int *ret_len, int k, 
			    int **ret_seqX, int **ret_seqY, char **ret_charX, char **ret_charY, int **ret_ct);


/* Function: SimulateNUSSequences()
 * Date:     ER, Wed Jun  9 17:21:30 CDT 1999 [St. Louis]
 *
 * Purpose:  Simulated an ungapped alignment of two sequences
 *           generated by the RNA model. Not a complete generation:
 *           rather, is given a structure (implying a given parse tree)
 *           and just generates residues.
 *           
 * Args:     ct     : Zuker .ct notation for an RNA structure 
 *                      e.g. 0..L-1 values if paired -1 if not          
 *           L      : length of structure
 *           ret_sX : RETURN: string X
 *           ret_sY : RETURN: string Y
 *
 * Returns:  void
 */
void
SimulateNUSSequences(struct rnamodel_s *rna, int *ct, int L, char **ret_sX, char **ret_sY)
{
  char   *sX, *sY;
  double  pair[256];
  double  single[16];
  int     z;
  int     x1,x2,y1,y2;
  int     i,j;
  double  totsc;

  sX = MallocOrDie(sizeof(char) * (L+1));
  sY = MallocOrDie(sizeof(char) * (L+1));

  for (z = 0; z < 16; z++) 
    {
      x1 = z / 4;
      y1 = z % 4;
      single[z] = rna->nus->p[idx(x1,y1)];
    }
  for (z = 0; z < 256; z++)
    {
      x1 = z / 64;
      x2 = (z % 64) / 16;
      y1 = (z % 16) / 4;
      y2 = z % 4;
      pair[z] = rna->nus->pp[idx(x1,y1)][idx(x2,y2)];
    }

  totsc = 0.0;
  for (i = 0; i < L; i++)
    {
      if (ct[i] == -1)		/* singlet */
	{
	  z  = DChoose(single, 16);
	  x1 = z / 4;
	  y1 = z % 4;

	  sX[i] = DNAAlphabet[x1];
	  sY[i] = DNAAlphabet[y1];
	  
	  totsc += rna->nus->p[idx(x1,y1)];

	}
      else if (ct[i] > i)	/* doublet that we haven't done yet */
	{
	  j = ct[i];
	  z = DChoose(pair, 256);
	  x1 = z / 64;
	  x2 = (z % 64) / 16;
	  y1 = (z % 16) / 4;
	  y2 = z % 4;
	  
	  sX[i] = DNAAlphabet[x1];
	  sY[i] = DNAAlphabet[y1];
	  sX[j] = DNAAlphabet[x2];
	  sY[j] = DNAAlphabet[y2];

	  totsc += rna->nus->pp[idx(x1,y1)][idx(x2,y2)];
	}
    }    


  /* specific correction for tRNAPhe parse tree
   * (-82.23)
   */
  totsc += 34.0 * rna->nus->tl;
  totsc += 21.0 * rna->nus->tv;
  totsc += 2.0  * rna->nus->tw;
  totsc += 3.0  * rna->t[TRNAROE];

  /* printf("simulated RNAs should score at least %f\n", totsc); */
  sX[L] = '\0';
  sY[L] = '\0';
  *ret_sX = sX;
  *ret_sY = sY;
  return;
}


/* Function: SimulateRNAAlign()
 * 
 * Date:     ER, Thu Feb 10 10:18:06 CST 2000 [St. Louis]
 * 
 * Purpose:  Create an alignment of length L according to the RNA model.
 *           
 * Args:     ofp       - print to file
 *           sqinfoX   - info about sequence X
 *           seqX      - sequence X, in integer form (A=0, C=1, G=2, U=3)
 *           sqinfoY   - info about sequence Y
 *           seqY      - sequence Y, in integer form (A=0, C=1, G=2, U=3)
 *           start     - starting position in the arrays
 *           L         - length of alignment, which is 0..len-1
 *           rna       - the SCFG model
 *           null      - the Null model
 *           ali       - struture of arrays to store alingmend sequences
 *           traceback - if TRUE print walk through model
 *           alignment - if TRUE print  alignment
 *           ctX       - array to store structure
 *
 * Return:   void. seqX, seqY, ali, ct are filled here.
 */
void
SimulateRNAAlign(FILE *ofp, SQINFO *sqinfoX, int **seqX, SQINFO *sqinfoY, int **seqY, int L, int start, int *ret_len, 	
		 struct rnamodel_s *rna, int traceback, int alignment, char *string_name, 
		 int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  struct tracekn_s      *tr;                   /* the traceback tree under construction         */
  struct tracekn_s      *cur_tr;               /* ptr to node of tr we're working on            */
  struct traceknstack_s *dolist;               /* pushdown stack of active tr nodes             */
  double                 pnode[NDPS][NNODES];  /* stores the transition probabilies of the SCFG */

  int                   *mseqX;
  int                   *mseqY;
  char                  *mcharX;
  char                  *mcharY;
  int                   *mct;

  int                    len;                  /* length of the allocated strings               */
  int                    leg = 0;              /* length of the aligment generated              */
  int                    state, node;          /* state and node we are at                      */
  int                    i,j,k,l;              /* coords in mtx's                               */
  int                    d, d1, d2;            /* coords in mtx's                               */
  int                    size;                 /* size of loops                                 */
  int                    pairs = 0;
  int                    comp_pairs = 0;
  int                    noncomp_pairs = 0;

  len = L;

  AllocCharSeqs(len, &mcharX, &mcharY);
  AllocCt(len, &mct);

  mseqX = *seqX;
  mseqY = *seqY;

  for (state = 0; state < NDPS; state++)
    for (node = 0; node < NNODES; node++)
      pnode[state][node] = -BIGFLOAT;

  pnode[V][dpcS1]  = rna->pi2->v->t1;
  pnode[V][dpcS2S] = rna->pi2->v->t2s;
  pnode[V][dpcS2B] = rna->pi2->v->t2b;
  pnode[V][dpcS2I] = rna->pi2->v->t2i;
  pnode[V][dpcMV]  = rna->pi2->v->t3;
  CheckSingleLog2Prob (pnode[V]+DpNodeidx[V], NodesPerDp[V]);
  
  pnode[W][dpcL]   = rna->pi2->w->tl;
  pnode[W][dpcR]   = rna->pi2->w->tr;
  pnode[W][dpcP]   = rna->pi2->w->tv;
  pnode[W][dpcBW]  = rna->pi2->w->tw;
  CheckSingleLog2Prob (pnode[W]+DpNodeidx[W], NodesPerDp[W]);

  pnode[WB][dpcL]  = rna->pi2->wb->tl;
  pnode[WB][dpcR]  = rna->pi2->wb->tr;
  pnode[WB][dpcP]  = rna->pi2->wb->tv;
  pnode[WB][dpcBW] = rna->pi2->wb->tw;
  CheckSingleLog2Prob (pnode[WB]+DpNodeidx[WB], NodesPerDp[WB]);

  for (size = 0; size < MAXRNALOOP; size++) {
    pnode[IS1][dpcLEN(size)] = rna->pi2->is1->tn[size];
    pnode[IS2B][dpcLEN(size)] = rna->pi2->is2b->tn[size];
    pnode[IS2I][dpcLEN(size)] = rna->pi2->is2i->tn[size];
  }  
  CheckSingleLog2Prob (pnode[IS1]+DpNodeidx[IS1], NodesPerDp[IS1]);
  CheckSingleLog2Prob (pnode[IS2B]+DpNodeidx[IS2B], NodesPerDp[IS2B]);
  CheckSingleLog2Prob (pnode[IS2I]+DpNodeidx[IS2I], NodesPerDp[IS2I]);
 
  /* Initialize.
   * Start at j = L-1, d = L-1, d1 = (int)(d/2), d2 = d - (int)(d/2) - 1.
   */
  tr     = InitTracekn();       /* start a trace tree */
  dolist = InitTraceknstack();	/* start a stack for traversing the trace tree */

  if (len == 0) return;
  else d = len - 1;
  
  j = start + d;
  i = j - d;
  k = i + (int)(d/2);
  l = k + 1;
  
  if (traceback) fprintf(ofp,"---------------------------------------------------\n");

 /* assigned state to (i,j):  V 
   *                          W 
   *                          WB
   *                          IS1
   *                          IS2
   */

  cur_tr = AttachTracekn(tr, i, j, k, l, W, dpcEW); 
  PushTraceknstack(dolist, cur_tr);

  /* Recursion. While there's active nodes in the stack, trace from them.
   * 
  */
  while ((cur_tr = PopTraceknstack(dolist)) != NULL)
   {
     /* get some useful numbers, mostly for clarity */
      i = cur_tr->emiti;
      j = cur_tr->emitj;
      k = cur_tr->emitk;
      l = cur_tr->emitl;
      
      state = cur_tr->type;
      
      d  = j - i;
      
      d1 = k - i;
      d2 = j - l;
      
      if (len < L) Die ("SimulateRNAAlign(): bad sampling state %s (len = %d)\n", stNAME[cur_tr->type], len);

      if (traceback) fprintf(ofp,"---------------------------------------------------\n");
      if (traceback) fprintf(ofp,"%s %d %d %d %d  \n", stNAME[cur_tr->type], j, d, d1, d2); 
      
      switch (state){
      case IS1: 
	coemitIS1(ofp, sqinfoY, mseqX, sqinfoY, mseqY, rna->pi2, j, d, pnode[state], cur_tr, dolist, mcharX, mcharY,
		  traceback, mct);
	break;
	
      case IS2B: 
	coemitIS2(ofp, mseqX, mseqY, rna->pi2->is2b, j, d, d1, d2, pnode[state], cur_tr, dolist, mcharX, mcharY, 
		  traceback, mct);
	break;
	
      case IS2I: 
	coemitIS2(ofp, mseqX, mseqY, rna->pi2->is2i, j, d, d1, d2, pnode[state], cur_tr, dolist, mcharX, mcharY, 
		  traceback, mct);
	break;
	
      case V: 
	coemitV(ofp, &mseqX, &mseqY, rna->pi2->v, L, &len, j, d, pnode[state], pnode[IS1], pnode[IS2B], pnode[IS2I],  
		cur_tr, dolist, traceback, &mcharX, &mcharY, &mct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
	
      case W: 
	coemitW(ofp, &mseqX, &mseqY, rna->pi2->w, L, &len, j, d, pnode[state], cur_tr, dolist,  
		traceback, &mcharX, &mcharY, &mct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
	
      case WB: 
	coemitW(ofp, &mseqX, &mseqY, rna->pi2->wb, L, &len, j, d, pnode[state], cur_tr, dolist,  
		traceback, &mcharX, &mcharY, &mct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
	
      default:
	Die("invalid matrix assignement in SimulateRNAAlign()");  

      }

   } /* while something is in the trace stack */

  if (alignment) {
    leg = CleanUpCharSeqsCt(mcharX, mcharY, mct, len-1, len-1);
    PrintCtCharSeqs(ofp, sqinfoX, sqinfoY, 0, leg, mcharX, mcharY, mct, string_name);
  }
  
  *ret_len           = len;
  *ret_pairs         = pairs;
  *ret_comp_pairs    = comp_pairs;
  *ret_noncomp_pairs = noncomp_pairs;

  *seqX = mseqX;
  *seqY = mseqY;
  
  free(mcharX);
  free(mcharY);
  free(mct);

  FreeTracekn(tr);
  FreeTracekn(cur_tr);
  FreeTraceknstack(dolist);

}

/* Function: SimulateRNAAlignFromPosterior()
 * 
 * Date:     ER, Mon Mar 10 10:25:21 CST 2003 [St. Louis]
 * 
 * Purpose:  Create an alignment of length L according to the RNA model.
 *           
 * Args:     ofp       - print to file
 *           sqinfoX   - info about sequence X
 *           seqX      - sequence X, in integer form (A=0, C=1, G=2, U=3)
 *           sqinfoY   - info about sequence Y
 *           seqY      - sequence Y, in integer form (A=0, C=1, G=2, U=3)
 *           start     - starting position in the arrays
 *           L         - length of alignment, which is 0..len-1
 *           rna       - the SCFG model
 *           null      - the Null model
 *           ali       - struture of arrays to store alingmend sequences
 *           traceback - if TRUE print walk through model
 *           alignment - if TRUE print  alignment
 *           ctX       - array to store structure
 *
 * Return:   void. seqX, seqY, ali, ct are filled here.
 */
void
SimulateRNAAlignFromPosterior(FILE *ofp, SQINFO *sqinfoX, int *seqX, SQINFO *sqinfoY, int *seqY, int start, 
			      int L, struct rnamodel_s *rna, struct rnamtx_s *in, struct ali_s *ali, 
			      int *ct, int traceback, int alignment, char *string_name, 
			      int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  struct tracekn_s      *tr;                   /* the traceback tree under construction         */
  struct tracekn_s      *cur_tr;               /* ptr to node of tr we're working on            */
  struct traceknstack_s *dolist;                   /* pushdown stack of active tr nodes                       */
  double                 pnode[NDPS][NNODES];      /* stores the transition probabilies of the SCFG           */
  double                 pnode_pos[NDPS][NNODES];  /* stores the posterios transition probabilies of the SCFG */
  int                    state, node;              /* state and node we are at                                */
  int                    i,j,k,l;                  /* coords in mtx's                                         */
  int                    d, d1, d2;                /* coords in mtx's                                         */
  int                    size;                     /* size of loops                                           */
  int                    pairs = 0;
  int                    comp_pairs = 0;
  int                    noncomp_pairs = 0;

  for (state = 0; state < NDPS; state++)
    for (node = 0; node < NNODES; node++) {
      pnode[state][node]     = -BIGFLOAT;
      pnode_pos[state][node] = -BIGFLOAT;
    }

  pnode[V][dpcS1]  = rna->pi2->v->t1;
  pnode[V][dpcS2S] = rna->pi2->v->t2s;
  pnode[V][dpcS2B] = rna->pi2->v->t2b;
  pnode[V][dpcS2I] = rna->pi2->v->t2i;
  pnode[V][dpcMV]  = rna->pi2->v->t3;
  CheckSingleLog2Prob (pnode[V]+DpNodeidx[V], NodesPerDp[V]);
  
  pnode[W][dpcL]   = rna->pi2->w->tl;
  pnode[W][dpcR]   = rna->pi2->w->tr;
  pnode[W][dpcP]   = rna->pi2->w->tv;
  pnode[W][dpcBW]  = rna->pi2->w->tw;
  CheckSingleLog2Prob (pnode[W]+DpNodeidx[W], NodesPerDp[W]);
 
  pnode[WB][dpcL]  = rna->pi2->wb->tl;
  pnode[WB][dpcR]  = rna->pi2->wb->tr;
  pnode[WB][dpcP]  = rna->pi2->wb->tv;
  pnode[WB][dpcBW] = rna->pi2->wb->tw;
  CheckSingleLog2Prob (pnode[WB]+DpNodeidx[WB], NodesPerDp[WB]);
 
  for (size = 0; size < MAXRNALOOP; size++) {
    pnode[IS1][dpcLEN(size)] = rna->pi2->is1->tn[size];
    pnode[IS2B][dpcLEN(size)] = rna->pi2->is2b->tn[size];
    pnode[IS2I][dpcLEN(size)] = rna->pi2->is2i->tn[size];
  }  
  CheckSingleLog2Prob (pnode[IS1]+DpNodeidx[IS1], NodesPerDp[IS1]);
  CheckSingleLog2Prob (pnode[IS2B]+DpNodeidx[IS2B], NodesPerDp[IS2B]);
  CheckSingleLog2Prob (pnode[IS2I]+DpNodeidx[IS2I], NodesPerDp[IS2I]);
  
  /* Initialize.
   * Start at j = L-1, d = L-1, d1 = (int)(d/2), d2 = d - (int)(d/2) - 1.
   */
  tr     = InitTracekn();       /* start a trace tree */
  dolist = InitTraceknstack();	/* start a stack for traversing the trace tree */

  if (L == 0) return;
  else d = L - 1;
  
  j = start + d;
  i = j - d;
  k = i + (int)(d/2);
  l = k + 1;
  
  if (traceback) fprintf(ofp,"---------------------------------------------------\n");

 /* assigned state to (i,j):  V 
   *                          W 
   *                          WB
   *                          IS1
   *                          IS2
   */

  cur_tr = AttachTracekn(tr, i, j, k, l, W, dpcEW); 
  PushTraceknstack(dolist, cur_tr);

  /* Recursion. While there's active nodes in the stack, trace from them.
   * 
  */
  while ((cur_tr = PopTraceknstack(dolist)) != NULL)
   {
     /* get some useful numbers, mostly for clarity */
      i = cur_tr->emiti;
      j = cur_tr->emitj;
      k = cur_tr->emitk;
      l = cur_tr->emitl;
      
      state = cur_tr->type;

      d  = j - i;
      
      if (d == 0) continue;

      d1 = k - i;
      d2 = j - l;
      
      if (d < 5) 
	{
	  if(state == V) {
	    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, k+1, IS1, dpcEIS));
	    if (traceback) fprintf(ofp," emit IS1 (%d)  \n", d); 
	    continue;
	  }
	}
      
      if (traceback) fprintf(ofp,"---------------------------------------------------\n");
      if (traceback) fprintf(ofp,"%s %d %d %d %d  \n", stNAME[cur_tr->type], j, d, d1, d2); 
      
      switch (state){
      case IS1: 
	coemitIS1_from_posterior(ofp, seqX, seqY, rna->pi2->is1, L, j, d, pnode[state], cur_tr, dolist, ali, 
				 traceback, ct);
	break;
	
      case IS2B: 
	coemitIS2_from_posterior(ofp, seqX, seqY, rna->pi2->is2b, L, j, d, d1, d2, pnode[state], cur_tr, dolist, ali, 
				 traceback, ct);
	break;
	
      case IS2I: 
	coemitIS2_from_posterior(ofp, seqX, seqY, rna->pi2->is2i, L, j, d, d1, d2, pnode[state], cur_tr, dolist, ali, 
				 traceback, ct);
	break;
	
      case V: 
	coemitV_from_posterior(ofp, seqX, seqY, rna->pi2->v, L, j, d, in, pnode_pos[state], pnode[state], pnode[IS1], pnode[IS2B],  pnode[IS2I], 
			       cur_tr, dolist, ali, traceback, ct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
	
      case W: 
	coemitW_from_posterior(ofp, seqX, seqY, rna->pi2->w, L, j, d, in->wx, in->vx, pnode_pos[state], pnode[state], cur_tr, dolist, ali, 
			       traceback, ct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
	
      case WB: 
	coemitW_from_posterior(ofp, seqX, seqY, rna->pi2->wb, L, j, d, in->wbx, in->vx, pnode_pos[state], pnode[state], cur_tr, dolist, ali, 
			       traceback, ct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
	
     default:
	Die("invalid matrix assignement in SimulateRNAAlignFromPosterior()");
      }
   } /* while something is in the trace stack */

  if (alignment) PrintCtAlign(ofp, sqinfoX, sqinfoY, start, L, ali, ct, string_name);

  *ret_pairs         = pairs;
  *ret_comp_pairs    = comp_pairs;
  *ret_noncomp_pairs = noncomp_pairs;
 
  FreeTracekn(tr);
  FreeTracekn(cur_tr);
  FreeTraceknstack(dolist);

}

/* Function: SimulateRNASequence()
 * 
 * Date:     ER, Mon Mar 27 13:49:09 CST 2000 [St. Louis]
 * 
 * Purpose:  Given a sequence, simulate a second sequence
 *           related to it by the RNA model.
 *           
 * Args:     ofp       - print to file
 *           sqinfoX   - info about sequence X
 *           seqX      - sequence X, in integer form (A=0, C=1, G=2, U=3)
 *           sqinfoY   - info about sequence Y
 *           seqY      - sequence Y, in integer form (A=0, C=1, G=2, U=3)
 *           start     - starting position in the arrays
 *           L         - length of alignment, which is 0..len-1
 *           rna       - the SCFG model
 *           null      - the Null model
 *           ali       - struture of arrays to store alingmend sequences
 *           traceback - if TRUE print walk through model
 *           alignment - if TRUE print  alignment
 *           ctX       - array to store structure
 *
 * Return:   void. seqX, seqY, ali, ct are filled here.
 */
void
SimulateRNASequence(FILE *ofp, int *seq, SQINFO *sqinfoX, int *seqX, SQINFO *sqinfoY, int *seqY, int start, 
		    int L, struct rnamodel_s *rna, struct ali_s *ali, 
		    int *ct, int traceback, int alignment, char *string_name, 
		    int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  struct tracekn_s      *tr;                   /* the traceback tree under construction         */
  struct tracekn_s      *cur_tr;               /* ptr to node of tr we're working on            */
  struct traceknstack_s *dolist;               /* pushdown stack of active tr nodes             */
  double                 pnode[NDPS][NNODES];  /* stores the transition probabilies of the SCFG */
  int                    state, node;          /* state and node we are at                      */
  int                    i,j,k,l;              /* coords in mtx's                               */
  int                    d, d1, d2;            /* coords in mtx's                               */
  int                    size;                 /* size of loops                                 */
  int                    pairs = 0;
  int                    comp_pairs = 0;
  int                    noncomp_pairs = 0;

  for (state = 0; state < NDPS; state++)
    for (node = 0; node < NNODES; node++)
      pnode[state][node] = -BIGFLOAT;

  pnode[V][dpcS1]  = rna->pi2->v->t1;
  pnode[V][dpcS2S] = rna->pi2->v->t2s;
  pnode[V][dpcS2B] = rna->pi2->v->t2b;
  pnode[V][dpcS2I] = rna->pi2->v->t2i;
  pnode[V][dpcMV]  = rna->pi2->v->t3;
  CheckSingleLog2Prob (pnode[V]+DpNodeidx[V], NodesPerDp[V]);
 
  pnode[W][dpcL]   = rna->pi2->w->tl;
  pnode[W][dpcR]   = rna->pi2->w->tr;
  pnode[W][dpcP]   = rna->pi2->w->tv;
  pnode[W][dpcBW]  = rna->pi2->w->tw;
  CheckSingleLog2Prob (pnode[W]+DpNodeidx[W], NodesPerDp[W]);
 
  pnode[WB][dpcL]  = rna->pi2->wb->tl;
  pnode[WB][dpcR]  = rna->pi2->wb->tr;
  pnode[WB][dpcP]  = rna->pi2->wb->tv;
  pnode[WB][dpcBW] = rna->pi2->wb->tw;
  CheckSingleLog2Prob (pnode[WB]+DpNodeidx[WB], NodesPerDp[WB]);

  for (size = 0; size < MAXRNALOOP; size++) {
    pnode[IS1][dpcLEN(size)]  = rna->pi2->is1->tn[size];
    pnode[IS2B][dpcLEN(size)] = rna->pi2->is2b->tn[size];
    pnode[IS2I][dpcLEN(size)] = rna->pi2->is2i->tn[size];
  }  
  CheckSingleLog2Prob (pnode[IS1]+DpNodeidx[IS1],   NodesPerDp[IS1]);
  CheckSingleLog2Prob (pnode[IS2B]+DpNodeidx[IS2B], NodesPerDp[IS2B]);
  CheckSingleLog2Prob (pnode[IS2I]+DpNodeidx[IS2I], NodesPerDp[IS2I]);
  
 /* Initialize.
   * Start at j = L-1, d = L-1, d1 = (int)(d/2), d2 = d - (int)(d/2) - 1.
   */
  tr     = InitTracekn();       /* start a trace tree */
  dolist = InitTraceknstack();	/* start a stack for traversing the trace tree */

  if (L == 0) return;
  else d = L - 1;
  
  j = start + d;
  i = j - d;
  k = i + (int)(d/2);
  l = k + 1;
  
  if (traceback) fprintf(ofp,"---------------------------------------------------\n");

 /* assigned state to (i,j):  V 
   *                          W 
   *                          WB
   *                          IS1
   *                          IS2
   */

  cur_tr = AttachTracekn(tr, i, j, k, l, W, dpcEW); 
  PushTraceknstack(dolist, cur_tr);

  /* Recursion. While there's active nodes in the stack, trace from them.
   * 
  */
  while ((cur_tr = PopTraceknstack(dolist)) != NULL)
   {
     /* get some useful numbers, mostly for clarity */
      i = cur_tr->emiti;
      j = cur_tr->emitj;
      k = cur_tr->emitk;
      l = cur_tr->emitl;
      
      state = cur_tr->type;

      d  = j - i;
      
      if (d == 0) continue;

      d1 = k - i;
      d2 = j - l;
      
      if (d < 5) 
	{
	  if (state == V) {
	    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, k+1, IS1, dpcEIS));
	    if (traceback) fprintf(ofp," emit IS1 (%d)  \n", d); 
	    continue;
	  }
	}
      
      if (traceback) fprintf(ofp,"---------------------------------------------------\n");
      if (traceback) fprintf(ofp,"%s %d %d %d %d  \n", stNAME[cur_tr->type], j, d, d1, d2); 
      
      switch (state){
      case IS1: 
	emitIS1(ofp, seq, seqX, seqY, rna->pi2->is1, L, j, d, pnode[state], cur_tr, dolist, ali, 
		traceback, ct);
	break;
	
      case IS2B: 
	emitIS2(ofp, seq, seqX, seqY, rna->pi2->is2b, L, j, d, d1, d2, pnode[state], cur_tr, dolist, ali, 
		traceback, ct);
	break;

      case IS2I: 
	emitIS2(ofp, seq, seqX, seqY, rna->pi2->is2i, L, j, d, d1, d2, pnode[state], cur_tr, dolist, ali, 
		traceback, ct);
	break;

      case V: 
	emitV(ofp, seq, seqX, seqY, rna->pi2->v, L, j, d, pnode[state], pnode[IS1], pnode[IS2B], pnode[IS2I], 
	      cur_tr, dolist, ali, traceback, ct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
	
      case W: 
	emitW(ofp, seq, seqX, seqY, rna->pi2->w, L, j, d, pnode[state], cur_tr, dolist, ali, 
	      traceback, ct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
      
      case WB: 
	emitW(ofp, seq, seqX, seqY, rna->pi2->wb, L, j, d, pnode[state], cur_tr, dolist, ali, 
	      traceback, ct, &pairs, &comp_pairs, &noncomp_pairs);
	break;
      
     default:
	Die("invalid matrix assignement in SimulateRNAAlign()");
      }
   } /* while something is in the trace stack */

  if (alignment) PrintCtAlign(ofp, sqinfoX, sqinfoY, start, L, ali, ct, string_name);

  *ret_pairs         = pairs;
  *ret_comp_pairs    = comp_pairs;
  *ret_noncomp_pairs = noncomp_pairs;

  FreeTracekn(tr);
  FreeTracekn(cur_tr);
  FreeTraceknstack(dolist);
}


void
coemitIS1(FILE *ofp, SQINFO *sqinfoX, int *seqX, SQINFO *sqinfoY, int *seqY, struct pi2model_s *pi2, 
	  int j, int d, double *pnode_is1, 
	  struct tracekn_s *cur_tr, struct traceknstack_s *dolist, char *charX, char *charY,
	  int traceback, int *ct)
{
  int    leg_loop = 0;
  int    i, r;
  int    pos_r;
  int    cur_xr, cur_yr;

  i = j - d;

 if (traceback && d > 0) fprintf(ofp," loop: ");
  for (r = 0; r <= d; r++) {
    pos_r = DLog2Choose(pi2->is1->ps, 25);
    
    cur_xr = pos_r / 5;
    cur_yr = pos_r % 5;
    
    seqX[i+r] = cur_xr;
    seqY[i+r] = cur_yr;
    
    ct[i+r] = -1;
    
    charX[i+r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
    charY[i+r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';

  }
 
 for (r = 0; r <= d; r++)
   if (seqX[i+r] != -1 && seqY[i+r] != -1) leg_loop ++;

 if (traceback) {
   for (r = 0; r < leg_loop; r++) 
     fprintf(ofp,"[%d %d] ", seqX[i+r], seqY[i+r]);  
   
   fprintf(ofp,"\n");
 }
 
}

void
coemitIS1_from_posterior(FILE *ofp, int *seqX, int *seqY, struct rna_loop5 *is1, int L, int j, int d, double *pnode_is1,
	struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
	int traceback, int *ct)
{
  int    i, r;
  int    pos_r;
  int    cur_xr, cur_yr;

  i = j - d;

 if (traceback && d > 1) fprintf(ofp," loop: ");
   for (r = 1; r < d ; r++) {
    pos_r = DLog2Choose(is1->ps, 25);
    
    cur_xr = pos_r / 5;
    cur_yr = pos_r % 5;
    
    seqX[i+r] = cur_xr;
    seqY[i+r] = cur_yr;
    
    ct[i+r] = -1;
    
    ali->charX[i+r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
    ali->charY[i+r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';

    if (traceback) fprintf(ofp,"[%d %d] ", cur_xr, cur_yr); 
    }
  if (traceback) fprintf(ofp,"\n");
}

void
emitIS1(FILE *ofp, int *seq, int *seqX, int *seqY, struct rna_loop5 *is1, int L, int j, int d, double *pnode_is1,
	struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
	int traceback, int *ct)
{
  int    i, r;
  int    cur_xr, cur_yr;
  int    y;
  double pxy[5][5], py[5];

  i = j - d;

  /* calculate pxy[x][y]= P(y|x) = P(x,y) / P(x)
   */
  for (y = 0; y < 5; y++) 
    py[y] = 0.;

  for (y = 0; y < 25; y++)
    py[y/5] += EXP2(is1->ps[y]);

  for (y = 0; y < 5; y++)
    py[y] = LOG2(py[y]);
  
  for (y = 0; y < 25; y++) 
    pxy[y/5][y%5] = is1->ps[y] - py[y/5];

  if (traceback && d > 1) fprintf(ofp," loop: ");

   for (r = 1; r < d ; r++) {
     cur_xr = seq[i+r];
     
     cur_yr = DLog2Choose(pxy[cur_xr], 5);
     
     seqX[i+r] = cur_xr;
     seqY[i+r] = cur_yr;
     
     ct[i+r] = -1;
     
     ali->charX[i+r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
     ali->charY[i+r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';
     
     if (traceback) fprintf(ofp,"[%d %d] ", cur_xr, cur_yr); 
   }
   if (traceback) fprintf(ofp,"\n");
}

void
coemitIS2(FILE *ofp, int *seqX, int *seqY, struct rna_loop5 *is2, int j, int d, int d1, int d2, 
	  double *pnode_is2, struct tracekn_s *cur_tr, struct traceknstack_s *dolist, char *charX, char *charY,
	  int traceback, int *ct)
{
  int    i, r;
  int    pos_r;
  int    cur_xr, cur_yr;

  i = j - d;

  if (traceback && d1 > 1) fprintf(ofp," loop l: ");

  for (r = 1; r < d1 ; r++) {
    pos_r = DLog2Choose(is2->ps, 25);
    
    cur_xr = pos_r / 5;
    cur_yr = pos_r % 5;
    
    seqX[i+r] = cur_xr;
    seqY[i+r] = cur_yr;
    
    ct[i+r] = -1;
    
    charX[i+r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
    charY[i+r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';

    if (traceback) fprintf(ofp,"[%d %d] ", cur_xr, cur_yr); 
  }
  
  if (traceback && d2 > 1) fprintf(ofp,"\n loop r: ");
  for (r = 1; r < d2 ; r++) {
    pos_r = DLog2Choose(is2->ps, 25);
    
    cur_xr = pos_r / 5;
    cur_yr = pos_r % 5;
    
    seqX[j-r] = cur_xr;
    seqY[j-r] = cur_yr;
    
    ct[j-r] = -1;
    
    charX[j-r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
    charY[j-r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';

    if (traceback) fprintf(ofp,"[%d %d] ", cur_xr, cur_yr); 
  }
  if (traceback) fprintf(ofp,"\n");

}

void
coemitIS2_from_posterior(FILE *ofp, int *seqX, int *seqY, struct rna_loop5 *is2, int L, int j, int d, int d1, int d2, 
			 double *pnode_is2, struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
			 int traceback, int *ct)
{
  int    i, r;
  int    pos_r;
  int    cur_xr, cur_yr;

  i = j - d;

  if (traceback && d1 > 1) fprintf(ofp," loop l: ");
  for (r = 1; r < d1 ; r++) {
    pos_r = DLog2Choose(is2->ps, 25);
    
    cur_xr = pos_r / 5;
    cur_yr = pos_r % 5;
    
    seqX[i+r] = cur_xr;
    seqY[i+r] = cur_yr;
    
    ct[i+r] = -1;
    
    ali->charX[i+r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
    ali->charY[i+r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';

    if (traceback) fprintf(ofp,"[%d %d] ", cur_xr, cur_yr); 
  }
  
  if (traceback && d2 > 1) fprintf(ofp,"\n loop r: ");
  for (r = 1; r < d2 ; r++) {
    pos_r = DLog2Choose(is2->ps, 25);
    
    cur_xr = pos_r / 5;
    cur_yr = pos_r % 5;
    
    seqX[j-r] = cur_xr;
    seqY[j-r] = cur_yr;
    
    ct[j-r] = -1;
    
    ali->charX[j-r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
    ali->charY[j-r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';

    if (traceback) fprintf(ofp,"[%d %d] ", cur_xr, cur_yr); 
  }
  if (traceback) fprintf(ofp,"\n");
}

void
emitIS2(FILE *ofp, int *seq, int *seqX, int *seqY, struct rna_loop5 *is2, int L, int j, int d, int d1, int d2, 
	double *pnode_is2, struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
	int traceback, int *ct)
{
  int    i, r;
  int    cur_xr, cur_yr;
  int    y;
  double pxy[5][5], py[5];

  /* calculate pxy[x][y]= P(y|x) = P(x,y) / P(x)
   */
  for (y = 0; y < 5; y++) 
    py[y] = 0.;

  for (y = 0; y < 25; y++)
    py[y/5] += EXP2(is2->ps[y]);

  for (y = 0; y < 5; y++)
    py[y] = LOG2(py[y]);
  
  for (y = 0; y < 25; y++) 
    pxy[y/5][y%5] = is2->ps[y] - py[y/5];


  i = j - d;

  if (traceback && d1 > 1) fprintf(ofp," loop l: ");
  for (r = 1; r < d1 ; r++) {
    cur_xr = seq[i+r];
    cur_yr = DLog2Choose(pxy[cur_xr], 5);
    
    seqX[i+r] = cur_xr;
    seqY[i+r] = cur_yr;
    
    ct[i+r] = -1;
    
    ali->charX[i+r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
    ali->charY[i+r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';

    if (traceback) fprintf(ofp,"[%d %d] ", cur_xr, cur_yr); 
  }
  
  if (traceback && d2 > 1) fprintf(ofp,"\n loop r: ");
  for (r = 1; r < d2 ; r++) {
    cur_xr = seqX[i+r];
    cur_yr = DLog2Choose(pxy[cur_xr], 5);
    
    seqY[j-r] = cur_yr;
    
    ct[j-r] = -1;
    
    ali->charX[j-r] = (cur_xr < 4)? DNAAlphabet[cur_xr] : '.';
    ali->charY[j-r] = (cur_yr < 4)? DNAAlphabet[cur_yr] : '.';

    if (traceback) fprintf(ofp,"[%d %d] ", cur_xr, cur_yr); 
  }
  if (traceback) fprintf(ofp,"\n");
}

void
coemitV(FILE *ofp, int **ret_seqX, int **ret_seqY, struct rna_v5 *v, int L, int *ret_len, int j, int d, double *pnode_v, 
	double *pnode_is1, double *pnode_is2b, double *pnode_is2i, 
	struct tracekn_s *cur_tr, struct traceknstack_s *dolist, int traceback, 
	char **ret_charX, char **ret_charY, int **ret_ct, 
	int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  double        pp[625];
  double        pn[5];
  int          *mseqX;
  int          *mseqY;
  char         *mcharX;
  char         *mcharY;
  int          *mct;
  int           len;
  int           i, k, l, r;
  int           delta = 0;
  int           pos_k, pos_l, pos_kl;
  int           cur_xk, cur_yk;
  int           cur_xl, cur_yl;
  int           state;
  int           size, size_i, size_j;
  int           pairs = 0;
  int           comp_pairs = 0;
  int           noncomp_pairs = 0;
  int           verbose;

  verbose = FALSE;
  
  mseqX  = *ret_seqX;
  mseqY  = *ret_seqY;
  mcharX = *ret_charX;
  mcharY = *ret_charY;
  mct    = *ret_ct;
  
  len = *ret_len;

  i = j - d;
  k = i + (int) (d/2);
  l = k + 1;

  state = cur_tr->type;

  pn[0] = pnode_v[dpcS1];
  pn[1] = pnode_v[dpcS2S];
  pn[2] = pnode_v[dpcS2B];
  pn[3] = pnode_v[dpcS2I];
  pn[4] = pnode_v[dpcMV];
  CheckSingleLog2Prob (pn, 5);
  
  for (pos_kl = 0; pos_kl < 625; pos_kl++)
    pp[pos_kl] = v->pp[pos_kl/25][pos_kl%25];

  cur_tr->node = DpNodeidx[state] + DENChoose(pn, NodesPerDp[state]);

  switch (cur_tr->node) {
  case dpcS1:
    size = DENChoose(pnode_is1 + DpNodeidx[IS1], MAXRNALOOP);
     
   k = i + size;
   if (k > j) { 
     delta = size + L;
     j += delta;
     if (verbose) Warn ("coemitV() IS1: reallocation\n");
     realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
   }
    
   r = i + (int) (size/2);
   if (size > 2)  PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, k-1, r, r+1, IS1, dpcEIS));
   else Die ("coemitV() IS1: You should not be here\n");
   
   if (traceback) fprintf(ofp," emit IS1 (%d)  \n", size); 
   break;
   
  case dpcS2S:
    pos_kl = DLog2Choose(pp, 625);
    
    k = i+1;
    l = j-1;

    if (k >= l) { 
      delta = 2 + L;
      j += delta;
      l = j - 1;
      if (verbose) Warn ("coemitV() S2S: realocation \n"); 
      realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
   }
    
    pos_k = pos_kl / 25;
    pos_l = pos_kl % 25;

    cur_xk = pos_k / 5;
    cur_yk = pos_k % 5;
    cur_xl = pos_l / 5;
    cur_yl = pos_l % 5;
    
    if (cur_xk > 5 || cur_xk < 0) Die("coemitV(): wrong nucleotide in pp");
    if (cur_xl > 5 || cur_xl < 0) Die("coemitV(): wrong nucleotide in pp");
    if (cur_yk > 5 || cur_yk < 0) Die("coemitV(): wrong nucleotide in pp");
    if (cur_yl > 5 || cur_yl < 0) Die("coemitV(): wrong nucleotide in pp");
        
    mseqX[k] = cur_xk;
    mseqY[k] = cur_yk;
    mseqX[l] = cur_xl;
    mseqY[l] = cur_yl;

    mct[k] = l;
    mct[l] = k;

    mcharX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    mcharY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    mcharX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    mcharY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';
   
    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++; 
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;
    
    d = l - k;
    r = k + (int)(d/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    
    
    if (traceback) fprintf(ofp," emit IS2S [%d %d] [%d %d]  \n", cur_xk, cur_yk, cur_xl, cur_yl);
    break;
    
  case dpcS2B:
    size = DENChoose(pnode_is2b + DpNodeidx[IS2B], MAXRNALOOP);
 
    pos_kl = DLog2Choose(pp, 625);
   
    k = i + size - 1;
    l = j - 1;

    if (k >= l)  {
      delta = size + L;
      j += delta;
      l = j - 1;
      if (verbose) Warn("coemitV() S2B: reallocation \n");
      realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
    }
    
    pos_k = pos_kl / 25;
    pos_l = pos_kl % 25;
    
    cur_xk = pos_k / 5;
    cur_yk = pos_k % 5;
    cur_xl = pos_l / 5;
    cur_yl = pos_l % 5;
    
    mseqX[k] = cur_xk;
    mseqY[k] = cur_yk;
    mseqX[l] = cur_xl;
    mseqY[l] = cur_yl;

    mct[k] = l;
    mct[l] = k;

    mcharX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    mcharY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    mcharX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    mcharY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';

    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++;
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;

    d = l - k;
    r = k + (int)(d/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, l, IS2B, dpcEIS));
    
    if (traceback) fprintf(ofp," emit IS2B(%d %d) [%d %d] [%d %d]  \n", 
			   size, 1, cur_xk, cur_yk, cur_xl, cur_yl); 
    break;
    
  case dpcS2I:
    size = DENChoose(pnode_is2i + DpNodeidx[IS2I], MAXRNALOOP);
 
    if (size >= 4) {
      size_i = 2 + (int) ((size-4) * sre_random());
      size_j = size - size_i;
    }
    else Die ("Size of internal loop should be at least 4 (size = %d\n", size); 

    k = i + size_i;
    l = j - size_j;

    if (k >= l)  {
      delta = size + L;
      j += delta;
      l = j - size_j;
       if (verbose) Warn("coemitV() S2I: reallocate\n");
     realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
   }
    
    pos_kl = DLog2Choose(pp, 625);
    
    pos_k = pos_kl / 25;
    pos_l = pos_kl % 25;

    cur_xk = pos_k / 5;
    cur_yk = pos_k % 5;
    cur_xl = pos_l / 5;
    cur_yl = pos_l % 5;
    
    mseqX[k] = cur_xk;
    mseqY[k] = cur_yk;
    mseqX[l] = cur_xl;
    mseqY[l] = cur_yl;

    mct[k] = l;
    mct[l] = k;

    mcharX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    mcharY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    mcharX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    mcharY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';

    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++;
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;  
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;
    
    d = l - k;
    r = k + (int) (d/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, l, IS2I, dpcEIS));

    if (traceback) fprintf(ofp," emit IS2I(%d %d) [%d %d] [%d %d]  \n", 
			   size_i, size_j, cur_xk, cur_yk, cur_xl, cur_yl); 
    break;
    
  case dpcMV:
    if (d <= 3) {
      delta = 3 + L;
      j += delta;
       if (verbose) Warn("coemitV() WbWb: reallocate\n");
       realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
    }
   
    d = j - i;
    k = i + 1 + (d-2)/2;   /* split the remaining space in the vector between the two */
    
    l = i + 1 + (int)((k-i-1)/2);
    r = k + 1 + (int)((j-k-2)/2);

    /* The W to the right has to be picked up first so that a reallocation does not
     * affect the coordenates of the W to the left.
     */
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, k, l, l+1, WB, dpcEW));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k+1, j-1, r, r+1, WB, dpcEW));
    
    if (traceback) fprintf(ofp," emit W_b[%d] W_b[%d]\n", k, j-1); 
    break;
    
  default:
    Die("invalid matrix assignement in emitV()");
  }

  *ret_len            = len;
  *ret_pairs         += pairs;
  *ret_comp_pairs    += comp_pairs;
  *ret_noncomp_pairs += noncomp_pairs;

  *ret_seqX  = mseqX;
  *ret_seqY  = mseqY;
  *ret_charX = mcharX;
  *ret_charY = mcharY;
  *ret_ct    = mct;
  
} 

void 
coemitV_from_posterior(FILE *ofp, int *seqX, int *seqY, struct rna_v5 *v, int L, int j, int d, 
		       struct rnamtx_s *in,
		       double *pnode_pos_v, double *pnode_v, double *pnode_is1, double *pnode_is2b, double *pnode_is2i, 
		       struct tracekn_s *cur_tr, struct traceknstack_s *dolist, 
		       struct ali_s *ali, int traceback, int *ct, int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  double  pp[625];
  double *bif;
  double *bulges;
  double *inloop;
  double  hairpinloop;
  double  stemloop;
  int     i, k, l, r;
  int     mid, mid1, mid2;
  int     pos_k, pos_l, pos_kl;
  int     cur_xk, cur_yk;
  int     cur_xl, cur_yl;
  int     state;
  int     size, size_i, size_j;
  int     pairs = 0;
  int     comp_pairs = 0;
  int     noncomp_pairs = 0;

  i = j - d;
  k = i + (int) (d/2);
  l = k + 1;

  state = cur_tr->type;

  /* Calculate probabilities from the posteriors
   */
  bif    = (double *) MallocOrDie(sizeof(double) * (d));
  bulges = (double *) MallocOrDie(sizeof(double) * (2 * d));
  inloop = (double *) MallocOrDie(sizeof(double) * (d * d));

  hairpinloop =  (d < MAXRNALOOP) ? pnode_is1[dpcLEN(d)] : -BIGFLOAT;

  stemloop = (d > 1)? in->vx[j-1][d-2] : -BIGFLOAT;

  for (mid1 = 0; mid1 < d; mid1++)
    if (mid1 > 1 && (mid1+1) < MAXRNALOOP) bulges[mid1] =  in->vx[j-1][d-mid1-1] + pnode_is2b[dpcLEN(mid1+1)];
    else                                   bulges[mid1] = -BIGFLOAT;

  for (mid2 = 0; mid2 < d; mid2++) 
    if (mid2 > 1 && (mid2+1) < MAXRNALOOP) bulges[d+mid2] =  in->vx[j-mid2][d-mid2-1] + pnode_is2b[dpcLEN(mid2+1)];
    else                                   bulges[d+mid2] = -BIGFLOAT;

  for (mid1 = 0; mid1 < d; mid1++)  
    for (mid2 = 0; mid2 < d; mid2++) 
      if (mid1 > 1 && mid2 > 1 && mid1+mid2 <= d && (mid1+mid2) < MAXRNALOOP) 
	inloop[mid1*d+mid2] =  in->vx[j-mid2][d-mid1-mid2] + pnode_is2i[dpcLEN(mid1+mid2)] - LOG2(mid1+mid2-3);
      else                                        
	inloop[mid1*d+mid2] = -BIGFLOAT;
  
  for (mid = 0; mid < d; mid++) 
    if (mid < d-3) bif[mid] = in->wbx[j-1][d-mid-3] + in->wbx[j-d+1+mid][mid];
    else           bif[mid] = -BIGFLOAT;

  pnode_pos_v[dpcS1]  = pnode_v[dpcS1]  - in->vx[j][d] + hairpinloop;
  pnode_pos_v[dpcS2S] = pnode_v[dpcS2S] - in->vx[j][d] + stemloop;
  pnode_pos_v[dpcS2B] = pnode_v[dpcS2B] - in->vx[j][d] + DLog2Sum(bulges, 2*d) - 1.0;
  pnode_pos_v[dpcS2I] = pnode_v[dpcS2I] - in->vx[j][d] + DLog2Sum(inloop, d*d);
  pnode_pos_v[dpcMV]  = pnode_v[dpcMV]  - in->vx[j][d] + DLog2Sum(bif, d);
  CheckSingleLog2Prob (pnode_pos_v+DpNodeidx[V], NodesPerDp[state]);
  
  /* choose from these probabilities
   */
  cur_tr->node = DpNodeidx[state] + DENChoose(pnode_pos_v + DpNodeidx[state], NodesPerDp[state]);
  
  for (pos_kl = 0; pos_kl < 625; pos_kl++)
    pp[pos_kl] = v->pp[pos_kl/25][pos_kl%25];


  switch (cur_tr->node) {
  case dpcS1:
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, j-1, k-2, k-1, IS1, dpcEIS));
    if (traceback) fprintf(ofp," emit IS1 (%d)  \n", d); 
    break;
    
  case dpcS2S:
    pos_kl = DLog2Choose(pp, 625);
    
    k = i+1;
    l = j-1;

    pos_k = pos_kl / 25;
    pos_l = pos_kl % 25;

    cur_xk = pos_k / 5;
    cur_yk = pos_k % 5;
    cur_xl = pos_l / 5;
    cur_yl = pos_l % 5;
    
    seqX[k] = cur_xk;
    seqY[k] = cur_yk;
    seqX[l] = cur_xl;
    seqY[l] = cur_yl;

    ct[k] = l;
    ct[l] = k;

    ali->charX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    ali->charY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    ali->charX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    ali->charY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';
   
    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++; 
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;
   
    d = l - k;
    r = k + (int)(d/2);
    if (d > 0)  PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    if (traceback) fprintf(ofp," emit IS2S [%d %d] [%d %d]  \n", cur_xk, cur_yk, cur_xl, cur_yl);
    break;
    
  case dpcS2B:
    size = DENChoose(pnode_is2b + DpNodeidx[IS2B], d-2);

    pos_kl = DLog2Choose(pp, 625);
   
    k = i + size - 1;
    l = j - 1;

    pos_k = pos_kl / 25;
    pos_l = pos_kl % 25;

    cur_xk = pos_k / 5;
    cur_yk = pos_k % 5;
    cur_xl = pos_l / 5;
    cur_yl = pos_l % 5;
    
    seqX[k] = cur_xk;
    seqY[k] = cur_yk;
    seqX[l] = cur_xl;
    seqY[l] = cur_yl;

    ct[k] = l;
    ct[l] = k;

    ali->charX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    ali->charY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    ali->charX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    ali->charY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';

    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++; 
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;
   
    d = l - k;
    r = k + (int)(d/2);
   if (d > 0)  PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, l, IS2B, dpcEIS));
    if (traceback) fprintf(ofp," emit IS2B(%d %d) [%d %d] [%d %d]  \n", 
			   size, 1, cur_xk, cur_yk, cur_xl, cur_yl); 
    break;
    
  case dpcS2I:
    size = DENChoose(pnode_is2i + DpNodeidx[IS2I], d-3);

    if (size >= 4) {
      size_i = 2 + (int) ((size-2) * sre_random());
      size_j = size - size_i;
    }
    else Die ("Size of internal loop should be at least 4 (size = %d\n", size);
    
    k = i + size_i;
    l = j - size_j;

    pos_kl = DLog2Choose(pp, 625);
    
    pos_k = pos_kl / 25;
    pos_l = pos_kl % 25;

    cur_xk = pos_k / 5;
    cur_yk = pos_k % 5;
    cur_xl = pos_l / 5;
    cur_yl = pos_l % 5;
    
    seqX[k] = cur_xk;
    seqY[k] = cur_yk;
    seqX[l] = cur_xl;
    seqY[l] = cur_yl;

    ct[k] = l;
    ct[l] = k;

    ali->charX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    ali->charY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    ali->charX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    ali->charY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';

    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++; 
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;

    d = l - k;
    r = k + (int) (d/2);
    if (d > 0) PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, l, IS2I, dpcEIS));
    if (traceback) fprintf(ofp," emit IS2I(%d %d) [%d %d] [%d %d]  \n", 
			   size_i, size_j, cur_xk, cur_yk, cur_xl, cur_yl); 
    break;
    
  case dpcMV:
    k = i + 1 + (int)(sre_random()*(d-2));   /* choose the breaking point at randon */
    l = i + 1 + (int)((k-i-1)/2);
    r = k + 1 + (int)((j-k-2)/2);

    PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, k, l, l+1, WB, dpcEW));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k+1, j-1, r, r+1, WB, dpcEW));
    if (traceback) fprintf(ofp," emit W_b[%d] W_b[%d]\n", k, j-1); 
    break;
    
  default:
    Die("invalid matrix assignement in emitV()");
  }

  free(bif);
  free(bulges);
  free(inloop);

  *ret_pairs         += pairs;
  *ret_comp_pairs    += comp_pairs;
  *ret_noncomp_pairs += noncomp_pairs;

} 



void 
emitV(FILE *ofp, int *seq, int *seqX, int *seqY, struct rna_v5 *v, int L, int j, int d, double *pnode_v, 
      double *pnode_is1, double *pnode_is2b, double *pnode_is2i, struct tracekn_s *cur_tr, struct traceknstack_s *dolist, 
      struct ali_s *ali, int traceback, int *ct, int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  double pp[25][25];
  double pn[5];
  int    i, k, l, r;
  int    pos_k, pos_l, pos_kl;
  int    cur_xk, cur_yk;
  int    cur_xl, cur_yl;
  int    pos_x, pos_y;
  int    state;
  int    size, size_i, size_j;
  int    pairs = 0;
  int    comp_pairs = 0;
  int    noncomp_pairs = 0;

  i = j - d;
  k = i + (int) (d/2);
  l = k + 1;

  state = cur_tr->type;

  if (d < 5) {
    pn[0] = 0.;
    pn[1] = -BIGFLOAT;
    pn[2] = -BIGFLOAT;
    pn[3] = -BIGFLOAT;
    pn[4] = -BIGFLOAT;
  }

  else if (d < 10){
    pn[0] = pnode_v[dpcS1]  + pnode_is1[dpcLEN(d)];
    pn[1] = pnode_v[dpcS2S];
    pn[2] = pnode_v[dpcS2B] + DLog2Sum(pnode_is2b + DpNodeidx[IS2B], d-2);
    pn[3] = pnode_v[dpcS2I] + DLog2Sum(pnode_is2i + DpNodeidx[IS2I], d-3);
    pn[4] = -BIGFLOAT;
  }

  else {
    pn[0] = pnode_v[dpcS1]  + pnode_is1[dpcLEN(d)];
    pn[1] = pnode_v[dpcS2S];
    pn[2] = pnode_v[dpcS2B] + DLog2Sum(pnode_is2b + DpNodeidx[IS2B] + 3, d-2);
    pn[3] = pnode_v[dpcS2I] + DLog2Sum(pnode_is2i + DpNodeidx[IS2I] + 4, d-3);
    pn[4] = pnode_v[dpcMV];
  }
  CheckSingleLog2Prob (pn, 5);
  
  for (pos_kl = 0; pos_kl < 625; pos_kl++) {

    pos_k = pos_kl / 25;
    pos_l = pos_kl % 25;

    cur_xk = pos_k / 5;
    cur_yk = pos_k % 5;
    cur_xl = pos_l / 5;
    cur_yl = pos_l % 5;

    pos_x = cur_xk * 5 + cur_xl;
    pos_y = cur_yk * 5 + cur_yl;

    pp[pos_x][pos_y] = v->pp[pos_k][pos_l];
  }

  cur_tr->node = DpNodeidx[state] + DENChoose(pn, NodesPerDp[state]);

  switch (cur_tr->node) {
  case dpcS1:
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, j-1, k-2, k-1, IS1, dpcEIS));
    if (traceback) fprintf(ofp," emit IS1 (%d)  \n", d); 
    break;
    
  case dpcS2S:
    k = i+1;
    l = j-1;

    cur_xk = seq[k];
    cur_xl = seq[l];

    pos_x = cur_xk * 5 + cur_xl;
    pos_y = DLog2Choose(pp[pos_x], 25);
    
    cur_yk = pos_y % 5;
    cur_yl = pos_y % 5;
    
    seqX[k] = cur_xk;
    seqY[k] = cur_yk;
    seqX[l] = cur_xl;
    seqY[l] = cur_yl;

    ct[k] = l;
    ct[l] = k;

    ali->charX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    ali->charY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    ali->charX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    ali->charY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';
   
    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++; 
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;

    d = l - k;
    r = k + (int)(d/2);
    if (d > 0)  PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    if (traceback) fprintf(ofp," emit IS2S [%d %d] [%d %d]  \n", cur_xk, cur_yk, cur_xl, cur_yl);
    break;
    
  case dpcS2B:
    size = DENChoose(pnode_is2b + DpNodeidx[IS2B], d-2);

    k = i + size - 1;
    l = j - 1;

    cur_xk = seq[k];
    cur_xl = seq[l];

    pos_x = cur_xk * 5 + cur_xl;
    pos_y = DLog2Choose(pp[pos_x], 25);
    
    cur_yk = pos_y % 5;
    cur_yl = pos_y % 5;
    
    seqX[k] = cur_xk;
    seqY[k] = cur_yk;
    seqX[l] = cur_xl;
    seqY[l] = cur_yl;

    ct[k] = l;
    ct[l] = k;

    ali->charX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    ali->charY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    ali->charX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    ali->charY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';

    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++; 
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;

    d = l - k;
    r = k + (int)(d/2);
   if (d > 0)  PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, l, IS2B, dpcEIS));
    if (traceback) fprintf(ofp," emit IS2B(%d %d) [%d %d] [%d %d]  \n", 
			   size, 1, cur_xk, cur_yk, cur_xl, cur_yl); 
    break;
    
  case dpcS2I:
    size = DENChoose(pnode_is2i + DpNodeidx[IS2I], d-3);
    
    if (size >= 4) {
      size_i = 2 + (int) ((size-2) * sre_random());
      size_j = size - size_i;
    }
    else Die ("Size of internal loop should be at least 4 (size = %d\n", size);
    
    k = i + size_i;
    l = j - size_j;
    
    cur_xk = seq[k];
    cur_xl = seq[l];
    
    pos_x = cur_xk * 5 + cur_xl;
    pos_y = DLog2Choose(pp[pos_x], 25);
    
    cur_yk = pos_y % 5;
    cur_yl = pos_y % 5;
    
    seqX[k] = cur_xk;
    seqY[k] = cur_yk;
    seqX[l] = cur_xl;
    seqY[l] = cur_yl;

    ct[k] = l;
    ct[l] = k;

    ali->charX[k] = (cur_xk < 4)? DNAAlphabet[cur_xk] : '.';
    ali->charY[k] = (cur_yk < 4)? DNAAlphabet[cur_yk] : '.';
   
    ali->charX[l] = (cur_xl < 4)? DNAAlphabet[cur_xl] : '.';
    ali->charY[l] = (cur_yl < 4)? DNAAlphabet[cur_yl] : '.';

    if (IsWcPair(cur_xk, cur_yk, cur_xl, cur_yl)) pairs ++; 
    if (IsCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) comp_pairs ++;
    if (IsNonCompensatory(cur_xk, cur_yk, cur_xl, cur_yl)) noncomp_pairs ++;

    d = l - k;
    r = k + (int) (d/2);
    if (d > 0) PushTraceknstack(dolist, AttachTracekn(cur_tr, k, l, r, r+1, V, dpcEV));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, l, IS2I, dpcEIS));
    if (traceback) fprintf(ofp," emit IS2I(%d %d) [%d %d] [%d %d]  \n", 
			   size_i, size_j, cur_xk, cur_yk, cur_xl, cur_yl); 
    break;
    
  case dpcMV:
    k = i + 1 + (int)(sre_random()*(d-2));   /* choose the breaking point at randon */
    l = i + 1 + (int)((k-i-1)/2);
    r = k + 1 + (int)((j-k-2)/2);

    PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, k, l, l+1, WB, dpcEW));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k+1, j-1, r, r+1, WB, dpcEW));
    if (traceback) fprintf(ofp," emit W_b[%d] W_b[%d]\n", k, j-1); 
    break;
    
  default:
    Die("invalid matrix assignement in emitV()");
  }

  *ret_pairs         += pairs;
  *ret_comp_pairs    += comp_pairs;
  *ret_noncomp_pairs += noncomp_pairs;
}


void
coemitW(FILE *ofp, int **ret_seqX, int **ret_seqY, struct rna_w5 *w, int L, int *ret_len, int j, int d, double *pnode_w,
	struct tracekn_s *cur_tr, struct traceknstack_s *dolist, int traceback, 	
	char **ret_charX, char **ret_charY, int **ret_ct, 
	int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  double        pp[625];
  int           len;
  int          *mseqX;
  int          *mseqY;
  char         *mcharX;
  char         *mcharY;
  int          *mct;
  int           i, k, l, r;
  int           delta = 0;
  int           pos_i, pos_j, pos_ij;
  int           cur_xi, cur_yi;
  int           cur_xj, cur_yj;
  int           state;
  int           pairs = 0;
  int           comp_pairs = 0;
  int           noncomp_pairs = 0;
  int           verbose;

  verbose = FALSE;

  len = *ret_len;

  mseqX  = *ret_seqX;
  mseqY  = *ret_seqY;
  mcharX = *ret_charX;
  mcharY = *ret_charY;
  mct    = *ret_ct;
  
  i = j - d;
  k = i + (int) (d/2);
  l = k + 1;

  state = cur_tr->type;

 for (pos_ij = 0; pos_ij < 625; pos_ij++)
    pp[pos_ij] = w->pp[pos_ij/25][pos_ij%25];

  cur_tr->node = DpNodeidx[state] + DLog2Choose(pnode_w + DpNodeidx[state], NodesPerDp[state]);

  switch (cur_tr->node) {
  case dpcL:
    pos_i = DLog2Choose(w->pl, 25);

    if (d == 0) {
      delta = 1 + L;
      j += delta;
      if (verbose) Warn("coemitW() L: reallocate\n"); 
      realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
    }
   
    cur_xi = pos_i / 5;
    cur_yi = pos_i % 5;

    mseqX[i] = cur_xi;
    mseqY[i] = cur_yi;

    mct[i] = -1;

    mcharX[i] = (cur_xi < 4)? DNAAlphabet[cur_xi] : '.';
    mcharY[i] = (cur_yi < 4)? DNAAlphabet[cur_yi] : '.';
    
     k = i + 1 + (int) ((d-1)/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, j, k, k+1, state, dpcEW));
    if (traceback) fprintf(ofp," emit L [%d %d] \n", cur_xi, cur_yi); 
    break;
    
  case dpcR:
    pos_j = DLog2Choose(w->pr, 25);

    if (d == 0) {
      delta = 1 + L;
      j += delta;
       if (verbose) Warn("coemitW() R: reallocate\n"); 
       realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
    }
    
    cur_xj = pos_j / 5;
    cur_yj = pos_j % 5;
    
    mseqX[j] = cur_xj;
    mseqY[j] = cur_yj;

    mct[j] = -1;

    mcharX[j] = (cur_xj < 4)? DNAAlphabet[cur_xj] : '.';
    mcharY[j] = (cur_yj < 4)? DNAAlphabet[cur_yj] : '.';
   
    k = i + (int) ((d-1)/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j-1, k, k+1, state, dpcEW));
    if (traceback) fprintf(ofp," emit R [%d %d] \n", cur_xj, cur_yj); 
    break;
    
  case dpcP:
    pos_ij = DLog2Choose(pp, 625);
    
    pos_i = pos_ij / 25;
    pos_j = pos_ij % 25;

    cur_xi = pos_i / 5;
    cur_yi = pos_i % 5;
    cur_xj = pos_j / 5;
    cur_yj = pos_j % 5;

    if (cur_xi > 5 || cur_xi < 0) Die("coemitW(): wrong nucleotide in pp");
    if (cur_xj > 5 || cur_xj < 0) Die("coemitW(): wrong nucleotide in pp");
    if (cur_yi > 5 || cur_yi < 0) Die("coemitW(): wrong nucleotide in pp");
    if (cur_yj > 5 || cur_yj < 0) Die("coemitW(): wrong nucleotide in pp");
    
    if (d == 0) {
      delta = 2 + L;
      j += delta;
       if (verbose) Warn("coemitW() P: reallocate\n"); 
       realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
    }
   
    mseqX[i] = cur_xi;
    mseqY[i] = cur_yi;
    mseqX[j] = cur_xj;
    mseqY[j] = cur_yj;

    mct[i] = j;
    mct[j] = i;

    mcharX[i] = (cur_xi < 4)? DNAAlphabet[cur_xi] : '.';
    mcharY[i] = (cur_yi < 4)? DNAAlphabet[cur_yi] : '.';
   
    mcharX[j] = (cur_xj < 4)? DNAAlphabet[cur_xj] : '.';
    mcharY[j] = (cur_yj < 4)? DNAAlphabet[cur_yj] : '.';
   
    if (IsWcPair(cur_xi, cur_yi, cur_xj, cur_yj)) pairs ++; 
    if (IsCompensatory(cur_xi, cur_yi, cur_xj, cur_yj)) comp_pairs ++;
    if (IsNonCompensatory(cur_xi, cur_yi, cur_xj, cur_yj)) noncomp_pairs ++;

    d = j - i;
    k = i + 1 + (int) ((d-2)/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, k+1, V, dpcEV));
    if (traceback) fprintf(ofp," emit P [%d %d] [%d %d] \n", cur_xi, cur_yi, cur_xj, cur_yj); 
    break;
    
  case dpcBW:
    if (d <= 1) {
      delta = 1 + L;
      j += delta;
       if (verbose) Warn("coemitW() WW: reallocate\n"); 
       realloc_strings(delta, &len, i, &mseqX, &mseqY, &mcharX, &mcharY, &mct); 
    }

    d = j - i;
    k = i + d/2;   /* split the remaining space in the vector between the two */
    l = i + (int)((k-i)/2);
    r = k + 1 + (int)((j-k-1)/2);

    /* The W to the right has to be picked up first so that a reallocation does not
     * affect the coordenates of the W to the left.
     */
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, k, l, l+1, state, dpcEW));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k+1, j, r, r+1, state, dpcEW));

    if (traceback) fprintf(ofp," emit W[%d] W[%d]\n", k, j); 
    break;
    
  default:
    Die("invalid matrix assignement in emitW()");
  }

  *ret_len            = len;
  *ret_pairs         += pairs;
  *ret_comp_pairs    += comp_pairs;
  *ret_noncomp_pairs += noncomp_pairs;

  *ret_seqX  = mseqX;
  *ret_seqY  = mseqY;
  *ret_charX = mcharX;
  *ret_charY = mcharY;
  *ret_ct    = mct;
  
}

void
coemitW_from_posterior(FILE *ofp, int *seqX, int *seqY, struct rna_w5 *w, int L, int j, int d, 
		       double **wx, double **vx,
		       double *pnode_pos_w, double *pnode_w, struct tracekn_s *cur_tr, 
		       struct traceknstack_s *dolist, struct ali_s *ali, 
		       int traceback, int *ct, int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  double pp[625];
  double *bif;
  int    i, k, l, r;
  int    mid;
  int    pos_i, pos_j, pos_ij;
  int    cur_xi, cur_yi;
  int    cur_xj, cur_yj;
  int    state;
  int    pairs = 0;
  int    comp_pairs = 0;
  int    noncomp_pairs = 0;

  i = j - d;
  k = i + (int) (d/2);
  l = k + 1;

  state = cur_tr->type;

  for (pos_ij = 0; pos_ij < 625; pos_ij++)
    pp[pos_ij] = w->pp[pos_ij/25][pos_ij%25];

  /* Calculate from posteriors
   */
  bif = (double *) MallocOrDie(sizeof(double)*d);
  for (mid = 0; mid < d; mid++)
    bif[mid] = wx[j][mid] + wx[j-mid-1][d-mid-1];
  
  if (d > 0) {
    pnode_pos_w[dpcL]  = pnode_w[dpcL]  - wx[j][d] + wx[j][d-1];
    pnode_pos_w[dpcR]  = pnode_w[dpcR]  - wx[j][d] + wx[j-1][d-1];
    pnode_pos_w[dpcP]  = pnode_w[dpcP]  - wx[j][d] + vx[j][d];
    pnode_pos_w[dpcBW] = pnode_w[dpcBW] - wx[j][d] + DLog2Sum(bif, d);
  }
  else {
    if (state == W) {
      pnode_pos_w[dpcL]  = pnode_w[dpcL];
      pnode_pos_w[dpcR]  = pnode_w[dpcR];
      pnode_pos_w[dpcP]  = -BIGFLOAT;
      pnode_pos_w[dpcBW] = -BIGFLOAT;
    }
    else if (state == WB) {
      pnode_pos_w[dpcL]  = -BIGFLOAT;
      pnode_pos_w[dpcR]  = -BIGFLOAT;
      pnode_pos_w[dpcP]  = -BIGFLOAT;
      pnode_pos_w[dpcBW] = -BIGFLOAT;
    }
    else Die ("coemitW_from_posterior() state is wrong %d", state);
  }

  CheckSingleLog2Prob (pnode_pos_w + DpNodeidx[state], NodesPerDp[state]);

  cur_tr->node = DpNodeidx[state] + DLog2Choose(pnode_pos_w + DpNodeidx[state], NodesPerDp[state]);

  switch (cur_tr->node) {
  case dpcL:
    pos_i = DLog2Choose(w->pl, 25);

    cur_xi = pos_i / 5;
    cur_yi = pos_i % 5;

    seqX[i] = cur_xi;
    seqY[i] = cur_yi;

    ct[i] = -1;

    ali->charX[i] = (cur_xi < 4)? DNAAlphabet[cur_xi] : '.';
    ali->charY[i] = (cur_yi < 4)? DNAAlphabet[cur_yi] : '.';
    
    k = i + 1 + (int) ((d-1)/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, j, k, k+1, state, dpcEW));
    if (traceback) fprintf(ofp," emit L [%d %d] \n", cur_xi, cur_yi); 
    break;
    
  case dpcR:
    pos_j = DLog2Choose(w->pr, 25);
    
    cur_xj = pos_j / 5;
    cur_yj = pos_j % 5;
    
    seqX[j] = cur_xj;
    seqY[j] = cur_yj;

    ct[j] = -1;

    ali->charX[j] = (cur_xj < 4)? DNAAlphabet[cur_xj] : '.';
    ali->charY[j] = (cur_yj < 4)? DNAAlphabet[cur_yj] : '.';
   
    k = i + (int) ((d-1)/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j-1, k, k+1, state, dpcEW));
    if (traceback) fprintf(ofp," emit R [%d %d] \n", cur_xj, cur_yj); 
    break;
    
  case dpcP:
    pos_ij = DLog2Choose(pp, 625);
    
    pos_i = pos_ij / 25;
    pos_j = pos_ij % 25;

    cur_xi = pos_i / 5;
    cur_yi = pos_i % 5;
    cur_xj = pos_j / 5;
    cur_yj = pos_j % 5;
    
    seqX[i] = cur_xi;
    seqY[i] = cur_yi;
    seqX[j] = cur_xj;
    seqY[j] = cur_yj;

    ct[i] = j;
    ct[j] = i;

    ali->charX[i] = (cur_xi < 4)? DNAAlphabet[cur_xi] : '.';
    ali->charY[i] = (cur_yi < 4)? DNAAlphabet[cur_yi] : '.';
   
    ali->charX[j] = (cur_xj < 4)? DNAAlphabet[cur_xj] : '.';
    ali->charY[j] = (cur_yj < 4)? DNAAlphabet[cur_yj] : '.';
   
    if (IsWcPair(cur_xi, cur_yi, cur_xj, cur_yj)) pairs ++; 
    if (IsCompensatory(cur_xi, cur_yi, cur_xj, cur_yj)) comp_pairs ++;
    if (IsNonCompensatory(cur_xi, cur_yi, cur_xj, cur_yj)) noncomp_pairs ++;

    if (d > 1) PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, k+1, V, dpcEV));
    if (traceback) fprintf(ofp," emit P [%d %d] [%d %d] \n", cur_xi, cur_yi, cur_xj, cur_yj); 
    break;
    
  case dpcBW:
    k = i + (int)(sre_random()*d);   /* choose the breaking point at randon */
    l = i + (int)((k-i)/2);
    r = k + 1 + (int)((j-k-1)/2);

    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, k, l, l+1, state, dpcEW));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k+1, j, r, r+1, state, dpcEW));
    if (traceback) fprintf(ofp," emit W[%d] W[%d]\n", k, j); 
    break;
    
  default:
    Die("invalid matrix assignement in emitW()");
  }

  *ret_pairs         += pairs;
  *ret_comp_pairs    += comp_pairs;
  *ret_noncomp_pairs += noncomp_pairs;

  free(bif);

}

void
emitW(FILE *ofp, int *seq, int *seqX, int *seqY, struct rna_w5 *w, int L, int j, int d, double *pnode_w,
      struct tracekn_s *cur_tr, struct traceknstack_s *dolist, struct ali_s *ali, 
      int traceback, int *ct, int *ret_pairs, int *ret_comp_pairs, int *ret_noncomp_pairs)
{
  double pp[25][25];
  double pl[5][5], pr[5][5];
  int    i, k, l, r;
  int    pos_i, pos_j, pos_ij;
  int    cur_xi, cur_yi;
  int    cur_xj, cur_yj;
  int    pos_x, pos_y;
  int    state;
  int    pairs = 0;
  int    comp_pairs = 0;
  int    noncomp_pairs = 0;

  i = j - d;
  k = i + (int) (d/2);
  l = k + 1;

  state = cur_tr->type;

  if (d < 5) {
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, k+1, V, dpcEV));
    if (traceback) fprintf(ofp," emit P [%d %d] [%d %d] \n", seqX[i], seqY[i], seqX[j], seqY[j]); 
    return;
  }
  
  for (pos_i = 0; pos_i < 25; pos_i++) 
    pl[pos_i/5][pos_i%5] = w->pl[pos_i];
  
  for (pos_j = 0; pos_j < 25; pos_j++) 
    pr[pos_j/5][pos_j%5] = w->pr[pos_j];
  
  for (pos_ij = 0; pos_ij < 625; pos_ij++) {
    pos_i = pos_ij / 25;
    pos_j = pos_ij % 25;
    
    cur_xi = pos_i / 5;
    cur_yi = pos_i % 5;
    cur_xj = pos_j / 5;
    cur_yj = pos_j % 5;
    
    pos_x = cur_xi * 5 + cur_xj;
    pos_y = cur_yi * 5 + cur_yj;
    
    pp[pos_x][pos_y] = w->pp[pos_i][pos_j];
  }

  cur_tr->node = DpNodeidx[state] + DLog2Choose(pnode_w + DpNodeidx[state], NodesPerDp[state]);
  
  switch (cur_tr->node) {
  case dpcL:
    cur_xi = seq[i];
    cur_yi = DLog2Choose(pl[cur_xi], 5);

    seqX[i] = cur_xi;
    seqY[i] = cur_yi;

    ct[i] = -1;

    ali->charX[i] = (cur_xi < 4)? DNAAlphabet[cur_xi] : '.';
    ali->charY[i] = (cur_yi < 4)? DNAAlphabet[cur_yi] : '.';
    
    k = i + 1 + (int) ((d-1)/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i+1, j, k, k+1, state, dpcEW));
    if (traceback) fprintf(ofp," emit L [%d %d] \n", cur_xi, cur_yi); 
    break;
    
  case dpcR:
    cur_xj = seq[j];
    cur_yj = DLog2Choose(pr[cur_xj], 5);

    seqX[j] = cur_xj;
    seqY[j] = cur_yj;

    ct[j] = -1;

    ali->charX[j] = (cur_xj < 4)? DNAAlphabet[cur_xj] : '.';
    ali->charY[j] = (cur_yj < 4)? DNAAlphabet[cur_yj] : '.';
   
    k = i + (int) ((d-1)/2);
    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j-1, k, k+1, state, dpcEW));
    if (traceback) fprintf(ofp," emit R [%d %d] \n", cur_xj, cur_yj); 
    break;
    
  case dpcP:
    cur_xi = seq[i];
    cur_xj = seq[j];
    
    pos_x = cur_xi * 5 + cur_xj;
    pos_y = DLog2Choose(pp[pos_x], 25);

    cur_yi = pos_y / 5;
    cur_yj = pos_y % 5;
    
    seqX[i] = cur_xi;
    seqY[i] = cur_yi;
    seqX[j] = cur_xj;
    seqY[j] = cur_yj;

    ct[i] = j;
    ct[j] = i;

    ali->charX[i] = (cur_xi < 4)? DNAAlphabet[cur_xi] : '.';
    ali->charY[i] = (cur_yi < 4)? DNAAlphabet[cur_yi] : '.';
   
    ali->charX[j] = (cur_xj < 4)? DNAAlphabet[cur_xj] : '.';
    ali->charY[j] = (cur_yj < 4)? DNAAlphabet[cur_yj] : '.';
   
    if (IsWcPair(cur_xi, cur_yi, cur_xj, cur_yj)) pairs ++; 
    if (IsCompensatory(cur_xi, cur_yi, cur_xj, cur_yj)) comp_pairs ++;
    if (IsNonCompensatory(cur_xi, cur_yi, cur_xj, cur_yj)) noncomp_pairs ++;

    if (d > 1) PushTraceknstack(dolist, AttachTracekn(cur_tr, i, j, k, k+1, V, dpcEV));
    if (traceback) fprintf(ofp," emit P [%d %d] [%d %d] \n", cur_xi, cur_yi, cur_xj, cur_yj); 
    break;
    
  case dpcBW:
    k = i + (int)(sre_random()*d);   /* choose the breaking point at randon */
    l = i + (int)((k-i)/2);
    r = k + 1 + (int)((j-k-1)/2);

    PushTraceknstack(dolist, AttachTracekn(cur_tr, i, k, l, l+1, state, dpcEW));
    PushTraceknstack(dolist, AttachTracekn(cur_tr, k+1, j, r, r+1, state, dpcEW));
    if (traceback) fprintf(ofp," emit W[%d] W[%d]\n", k, j); 
    break;
    
  default: 
    Die("invalid matrix assignement in emitW()");
  } 

  *ret_pairs         += pairs;
  *ret_comp_pairs    += comp_pairs;
  *ret_noncomp_pairs += noncomp_pairs;
  
}

void
realloc_strings(int L, int *ret_len, int k, int **ret_seqX, int **ret_seqY, char **ret_charX, char **ret_charY, int **ret_ct)
{    
  int  *mseqX;
  int  *mseqY;
  char *mcharX;
  char *mcharY;
  int  *mct;
  int len;
  int new_len;
  int x;

  len = *ret_len;

  mseqX  = *ret_seqX;
  mseqY  = *ret_seqY;
  mcharX = *ret_charX;
  mcharY = *ret_charY;
  mct    = *ret_ct;
  
  if (L == 0) {  
    *ret_seqX  = mseqX;
    *ret_seqY  = mseqY; 
    *ret_charX = mcharX;
    *ret_charY = mcharY;
    *ret_ct    = mct;
    
    *ret_len = len;
    
    return;
  }

  new_len = len + L;

  mseqX  = (int  *) ReallocOrDie(mseqX,  sizeof(int ) * new_len);
  mseqY  = (int  *) ReallocOrDie(mseqY,  sizeof(int ) * new_len);
  mcharX = (char *) ReallocOrDie(mcharX, sizeof(char) * new_len);
  mcharY = (char *) ReallocOrDie(mcharY, sizeof(char) * new_len);
  mct    = (int  *) ReallocOrDie(mct,    sizeof(int ) * new_len);
  
  for (x = len-1; x >= k+1; x--) 
    {
      mseqX[x+L] = mseqX[x]; 
      mseqY[x+L] = mseqY[x]; 
      
      if (mct[x] <= k) { mct[x+L] = mct[x];     if (mct[x+L] != -1) mct[mct[x+L]] = x + L; }
      else             { mct[x+L] = mct[x] + L;                                            }

      mcharX[x+L] = mcharX[x];
      mcharY[x+L] = mcharY[x];
    }

  for (x = k+1; x <= k+L; x++) 
    {
      mseqX[x] = -1;
      mseqY[x] = -1;
      
      mct[x] = -1;
      
      mcharX[x] = '.';
      mcharY[x] = '.';
    }
  
  *ret_seqX  = mseqX;
  *ret_seqY  = mseqY; 
  *ret_charX = mcharX;
  *ret_charY = mcharY;
  *ret_ct    = mct;
  
  *ret_len = new_len;
}
