/********************************************************************************************************
 * 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.
 ***********************************************************************************************************/


/* rnamodel.c
 *
 * E. Rivas [St. Louis]
 * 
 * 9 april 1999.
 * 
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <time.h>
#include <limits.h>
#include <float.h>

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

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

static double   cal_inv (double *pp, int L);
static void     calculatePPderivedprobs(FILE *ofp, double *pp, int L);
static void     compare_marginals (int L, double *pp, double *mut5pxy, double *pair5prob, double tfactor, int verbose);
static double  *pair_2_pair_prob (fullcondmat_t *ribocond_mut, fullcondmat_t *ribocond_pair, 
				  double *mut5pxy, double *pair5prob, double tfactor, int verbose);
static double  *pair_2_pair_addgap_prob (fullcondmat_t *ribocond_pair, double *mut5pxy, double *pair5prob, double tfactor, int verbose);
static void     RNAparam_fit_to_length(int len, struct scfg_param_s *ret_scfg_param, struct pi2model_s *pi2, int verbose);
static double **rna_transition_matrix(struct rnaparam_s rnaparam, int dim);
static double **rna_transition_matrix_at_infty(double **T, double **T_zero, int dim);
static double **rna_transition_matrix_Rdiag(int dim);
static double **rna_transition_matrix_rate(int dim);
static double  *V_transition_matrix(struct rna_v_param_s vt, int dim);
static double  *W_transition_matrix(struct rna_w_param_s wt, int dim);
static double  *V_transition_matrix_from_data(struct rna_v5 *v, int dim);
static double  *W_transition_matrix_from_data(struct rna_w5 *w, int dim);



/* Function: AllocNUSModel()
 * Date:     ER, Wed Jun  9 09:59:08 CDT 1999 [St. Louis]
 *
 * Purpose:  Allocates memory for the transition and emission probs of the nusmodel
 *
 * Args:     nusmodel - nusmodel structure
 *
 * Returns:  void
 *           allocates nus->t[], nus->ROB, nus->ROJ, nus->ROE, nus->wx 
 *           (which must be free'd by caller).
 */
struct nusmodel_s *
AllocNUSModel(void)
{
  struct nusmodel_s *nus;  /* nusmodel structure           */

  nus = (struct nusmodel_s *)  MallocOrDie (sizeof(struct nusmodel_s));
  
  return nus;
}

/* Function: AllocPI2Model()
 * Date:     ER,  Tue Jun  8 14:15:46 CDT 1999 [St. Louis]
 *
 * Purpose:  Allocates memory for the transition and emission probs of the rnamodel
 *
 * Args:     rnamodel - rnamodel structure
 *
 * Returns:  void
 *           allocates rna->t[], rna->ROB, rna->ROJ, rna->ROE, 
 *                     rna->vx, rna->wx, rna->wbx, rna->is1, rna->is2, 
 *           (which must be free'd by caller).
 */
struct pi2model_s *
AllocPI2Model(void)
{
  struct pi2model_s *pi2;   /* rnamodel structure           */

  pi2        = (struct pi2model_s *)  MallocOrDie (sizeof(struct pi2model_s));
  pi2->v     = (struct rna_v5     *)  MallocOrDie (sizeof(struct rna_v5));
  pi2->w     = (struct rna_w5     *)  MallocOrDie (sizeof(struct rna_w5));
  pi2->wb    = (struct rna_w5     *)  MallocOrDie (sizeof(struct rna_w5));
  pi2->is1   = (struct rna_loop5  *)  MallocOrDie (sizeof(struct rna_loop5));
  pi2->is2b  = (struct rna_loop5  *)  MallocOrDie (sizeof(struct rna_loop5));
  pi2->is2i  = (struct rna_loop5  *)  MallocOrDie (sizeof(struct rna_loop5));

  pi2->Rloop = AllocOTHModel();
  
  return pi2;
}

/* Function: AllocRNAModel()
 * Date:     ER,  Tue Jun  8 14:15:46 CDT 1999 [St. Louis]
 *
 * Purpose:  Allocates memory for the transition and emission probs of the rnamodel
 *
 * Args:     rnamodel - rnamodel structure
 *
 * Returns:  void
 *           allocates rna->t[], rna->ROB, rna->ROJ, rna->ROE, 
 *                     rna->vx, rna->wx, rna->wbx, rna->is1, rna->is2, 
 *           (which must be free'd by caller).
 */
struct rnamodel_s *
AllocRNAModel(void)
{
  struct rnamodel_s *rna;   /* rnamodel structure           */

  rna      = (struct rnamodel_s *)  MallocOrDie (sizeof(struct rnamodel_s));
  rna->t   = (double *)             MallocOrDie (sizeof(double) * RTRANS);

  rna->ROB = AllocOTHModel();
  rna->ROJ = AllocOTHModel();
  rna->ROE = AllocOTHModel();

  rna->nus = AllocNUSModel();
  rna->pi2 = AllocPI2Model();
  
  PatternRNAModel(rna);

  return rna;
}

/* Function: CheckRNAProbs()
 * Date:     ER, Thu Jun 10 11:59:42 CDT 1999 [St. Louis]
 *
 * Purpose:  Verify that transition prob's of a RNAmodel add up to one
 *
 * Args:     rna - the structure for an pi2model
 *
 * Returns:  void. 
 */
void
CheckRNAProbs(struct rnamodel_s *rna)
{
  int    idx;               /* index for transition prob's      +*/
  int    st;                /* state we are at                  +*/
  double sum;

  /* check transition prob's add up to one
   */
  for (st = 0; st < RSTATES; st++) {
    sum = 0.0; 
    for (idx = IdxTransRNA[st]; idx < IdxTransRNA[st]+TransPerRNAState[st]; idx++)
      sum += rna->t[idx];
    
    if (sum > 2.0-accuracy || sum < accuracy) 
      Die("CheckRNAProbs(); transition prob's sum for state %s is %f \n", rstNAME[st], sum);
  }
}


/* Function: ConstructRNAModel()
 * Date:     ER, Tue Jun  8 13:30:43 CDT 1999 [St. Louis]
 *
 * Modified: ER, JUL 24 2002 [St. Louis]
 *
 * Modified: ER, Thu Jan 16 16:59:19 CST 2003 [St. Louis]
 *
 *
 * Purpose:  Build the RNA model from the null model under
 *           certain simplifying assumptions; namely, that
 *           P(x1 y1 x2 y2) = P(x1 y1) P (x2 y2) P(x1 x2) / (P(x1) P(x2))
 *
 * Args:     pammodel[64][64]
 *           cfg      -- the file with the SCFG model
 *           rnamodel -- pointer to alloc'ed rnamodel
 *
 * Returns:  void
 *           fills in rnamodel
 */
void
ConstructRNAModel_201(double **pammodel_star, double ***cfg_node, double *pair5, fullmat_t *riboprob,
		      int win, double tfactor, struct rnamodel_s *rna, struct nullmodel_s *null,
		      double *targetfreq, int changefreq, int pedantic, int verbose)
{
  fullcondmat_t     *ribocond_mut;
  fullcondmat_t     *ribocond_pair;
  fullcondmat_t     *ribo5cond_mut;
  fullcondmat_t     *ribo5cond_pair;
  condmatrix_t      *ribocond_pair_nought;
  double            *mutpxy_rna;
  double            *mut5pxy_rna;
  double            *mut;
  double            *pair;
  double            *pair5prob;                /* [5x5] base-pair joint probabilities +*/
  double            *pair5prob_cond_nought;    /* [5x5] base-pair conditional probabilities at time zero +*/
  double            *pmarX;                    /* [5] marginalization of the pair5probs +*/
  double            *pmarY;                    /* [5] marginalization of the pair5probs +*/
  double            *mut5pxy_rna_cond_nought;      /* [5x5] mutation joint probabilities at time zero +*/
  double            *psingle;                  /* [5] single nt vector probabilities +*/
  double            *psingle_nought;           /* [5] single nt vector probabilities at time zero +*/
  double            *psingle_Rdiag;            /* [5] single nt vector probabilities evol matrix +*/
  double            *p_infty;                  /* [5] single nt vector probabilities at time infty +*/
  double            *pp;                       /* [625] pair-to-pair vector probabilities +*/
  double             sum;                      /* For normalization purposes +*/
  int                idx;                      /* Index for transition prob's              +*/
  int                i,j;                      /* Symbols for emission prob's              +*/
  int                len;                      /* Length of a loop (< MAXRNALOOP)          +*/
  double             ave_len_ROB;             /* expected length of the other models */
  double             ave_len_ROE;
  double             ave_len_ROJ;
  double             ave_len_ROB_zero;             /* expected length of the other models */
  double             ave_len_ROE_zero;
  double             ave_len_ROJ_zero;
  double             ave_len_ROB_infty;             /* expected length of the other models */
  double             ave_len_ROE_infty;
  double             ave_len_ROJ_infty;
  double             ave_len_Rloop;
  double             is1_ave,  is1_sd;
  double             is2b_ave, is2b_sd;
  double             is2i_ave, is2i_sd;
  double             corr;
  double             gap = GAPP;
  double             gap2gap;

  if (verbose) printf("Construct RNA model at time = %.4f\n\n", tfactor);

  /* Calculate delta^prime = delta^2/(1-delta^2)
   */
  gap2gap = DeltaPrimeFromDelta (gap);

  /* calculate the mutpxy and mut5pxy from the pammodel_star at the corresponding time
   */

  ConstructTiedProbs(pammodel_star, tfactor, &mutpxy_rna, &mut5pxy_rna, targetfreq, changefreq, pedantic, verbose);

  ave_len_ROB_zero = EXP2(0.70*LOG2((double)win));
  ave_len_ROE_zero = EXP2(0.70*LOG2((double)win));
  ave_len_ROJ_zero = EXP2(0.70*LOG2((double)win));

  ave_len_ROB       = EXP2(0.99*LOG2(ave_len_ROB_zero));
  ave_len_ROE       = EXP2(0.99*LOG2(ave_len_ROE_zero));
  ave_len_ROJ       = EXP2(0.99*LOG2(ave_len_ROJ_zero));

  ave_len_ROB_infty = EXP2(0.50*LOG2(ave_len_ROB_zero));
  ave_len_ROE_infty = EXP2(0.50*LOG2(ave_len_ROE_zero));
  ave_len_ROJ_infty = EXP2(0.50*LOG2(ave_len_ROJ_zero));

  ConstructOTHModel(pammodel_star, ROBparam, ROBparam_zero, ROBparam_infty, ave_len_ROB, ave_len_ROB_zero, ave_len_ROB_infty, tfactor, 
		    targetfreq, changefreq, rna->ROB, pedantic, FALSE);
  ConstructOTHModel(pammodel_star, ROJparam, ROJparam_zero, ROJparam_infty, ave_len_ROJ, ave_len_ROJ_zero, ave_len_ROJ_infty, tfactor, 
		    targetfreq, changefreq, rna->ROJ, pedantic, FALSE);
  ConstructOTHModel(pammodel_star, ROEparam, ROEparam_zero, ROEparam_infty, ave_len_ROE, ave_len_ROE_zero, ave_len_ROE_infty, tfactor, 
		    targetfreq, changefreq, rna->ROE, pedantic, FALSE);
  
  ave_len_Rloop = 15.0;
  ConstructOTHModel(pammodel_star, Rloopparam, Rloopparam_zero, Rloopparam_infty, ave_len_Rloop, ave_len_Rloop, ave_len_Rloop, tfactor, 
		    targetfreq, changefreq, rna->pi2->Rloop, pedantic, FALSE);

 /* 24 JUL 02
  *
  * For the HHM-part of the RNA model,
  * the evolutionary RNA model is as follows:
  *
  *       - A 2x2 matrix for transitions T                RNA     ROE
  *                                               ROB  |  psi    1-psi |
  *                                       T =          |               |
  *                                               RNA  | 1-eta    eta  |
  *
  *
  *               at t=0                               |  1        0   |
  *                                       T_0 =        |               |
  *                                                    |  0        1   |
  *
  *              parametric family:      T = exp [tA]
  *
  */
  RNAmodelTransitionProbabilities(tfactor, rna, pedantic, verbose);

  mut = (double *) MallocOrDie(sizeof(double) * 4 * 4);
  for (i = 0; i < 4; i++)
    for (j = 0; j < 4; j++) {
      mut[i*4+j] = mut5pxy_rna[i*5+j];
      sum += mut[i*4+j];
    }
  for (i = 0; i < 4; i++)
    for (j = 0; j < 4; j++) 
      mut[i*4+j] /= sum;
   if (verbose) {
    fprintf(stdout, "mut 4x4 probabilities\n");
    PrintProbs(stdout, mut, 4);
  }
  
  pair = (double *) MallocOrDie(sizeof(double) * 4 * 4);
  for (i = 0; i < 4; i++)
    for (j = 0; j < 4; j++)
      pair[i*4+j] = pair5[i*5+j];
   if (verbose) {
    fprintf(stdout, "pair 4x4 probabilities\n");
    PrintProbs(stdout, pair, 4);
   }

   /* ******************
   * [1] TIME: t*
   * *******************/
  psingle = (double *) MallocOrDie (sizeof(double)*5);
  MarginalizeJointProbs(mut5pxy_rna, psingle, 5, 2);
  CheckSingleProb(psingle, 5);

  /* mut5pxy_rna at t* are given
   */
   if (verbose) {
    fprintf(stdout, "mut5pxy_rna(i|j, t*) Joint probabilities\n");
    PrintProbs(stdout, mut5pxy_rna, 5);
  }

  /* Pair5Probs at t*
   */
  pair5prob = (double *) MallocOrDie (sizeof(double) * 25);
  for (i = 0; i < 5; i++)
    for (j = 0; j < 5; j++)
      pair5prob[idx5(i,j)] = pair5[idx5(i,j)];

  /* OK, NT-2-GAP AND GAP-2-GAP Watson-Crick-Pair-Probabilities cannot be justified
   *
   * This is how I deal with them:
   */
  /* add pair-to-gap */
  pmarX       = (double *) MallocOrDie (sizeof(double) * 5);
  pmarY       = (double *) MallocOrDie (sizeof(double) * 5);
  MarginalizeJointProbs(pair5prob, pmarX, 5, 1);
  MarginalizeJointProbs(pair5prob, pmarY, 5, 0);
  for (i = 0; i < 4; i++) {
    pair5prob[idx5(i,4)] = gap*pmarX[i];
    pair5prob[idx5(4,i)] = gap*pmarY[i];
  }
  pair5prob[idx5(4,4)] = gap2gap;
  free(pmarX);
  free(pmarY);

   /* normalize */
  DNorm(pair5prob, 25);

 /* To change the overall base composition
   *
   * calculate:         P(i|j) = P(i,j) / P(j)
   *
   * then use:         ^P(j) = f(j)
   *
   * to recalculate:   ^P(i,j) = P(i|j) * ^P(j)
   *
   *
   *  Wed Mar  5 09:01:22 CST 2003:
   *  we change pair5prob so it has similar marginals as mut5px
   *
   */
  ChangePairProbs(5, pair5prob, psingle, FALSE, verbose);
  CheckSingleProb(pair5prob, 25);
  if (verbose) {
    fprintf(stdout, "Ppair5(i, j |  t=*) probabilities\n");
    PrintProbs(stdout, pair5prob, 5);
  }

  /* Calculate RIBOconditional matrices.
   *
   */
  CalculateRIBOMutConditionals (stdout, riboprob, &ribocond_mut,  verbose);
  CalculateRIBOPairConditionals(stdout, riboprob, &ribocond_pair, verbose);
  
  /* ******************
   * [2] TIME: zero
   * *******************/
  /* Infer single probs at time zero by impossing that p(gap) = 0
   */
  psingle_nought = (double *) MallocOrDie (sizeof(double) * 5);
  for (i = 0; i < 4; i++)
    psingle_nought[i] = psingle[i] / ( 1.0 - psingle[4]);

  psingle_nought[4] = 0.0;

  CheckSingleProb(psingle_nought, 5);
  if (verbose) {
    fprintf(stdout, "Psingle(i| t=zero) single nt probabilities\n");
    PrintVectorProbs(stdout, psingle_nought, 5);
  }

  /* Conditional mut5pxy_rna at time zero is the identity
   */
  mut5pxy_rna_cond_nought = Cal_Id(5);

  /* Conditional pair5prob at time zero are infered from pair5probs at t* marginalizing the gaps
   *
   */
  pair5prob_cond_nought = Condi_From_Joint(stdout, pair5prob, 5, verbose);

  if (verbose) {
    fprintf(stdout, "Ppair5(i|j, t=0) Cond probabilities\n");
    PrintProbs(stdout, pair5prob_cond_nought, 5);
  }
   /* marginalize the gaps in the first 4 rows
   */
  for (i = 0; i < 4; i++)
    {
      for (j = 0; j < 4; j++)
        pair5prob_cond_nought[idx5(i,j)] /= (1.0 - pair5prob_cond_nought[idx5(i,4)]);

      pair5prob_cond_nought[idx5(i,4)] = 0.0;
    }

  /* lasts row is free to choose
   */
   pair5prob_cond_nought[idx5(4,4)] = 1.0;  /* this is a hack that works -- meaning the models extrapolate and interpolate in a [0,6] time range */
  for (j = 0; j < 4; j++)
    pair5prob_cond_nought[idx5(4,j)] = (1.0-pair5prob_cond_nought[idx5(4,4)]) / 4.0;

  for (i = 0; i < 5; i++) CheckSingleProb(pair5prob_cond_nought+i*5, 5);

  if (verbose) {
    fprintf(stdout, "Ppair5(i|j, t=0) Cond probabilities\n");
    PrintProbs(stdout, pair5prob_cond_nought, 5);
  }

  /* the 16x16 pair conditionals at t=0 
   */
  ribocond_pair_nought = AllocCondMatrix (16);
  Comp_Id (ribocond_pair_nought->matrix, 16);
  if (verbose) {
    fprintf(stdout, "PAIR-COND-nought probabilities\n");
    PrintProbs(stdout, ribocond_pair_nought->matrix, 16);
  }  

  /* ******************
   * [3] TIME: infty
   * *******************/
  /* Infer single probs from mut5pxy_rna at time infty
   */
  p_infty = (double *) MallocOrDie (sizeof(double) * 5);
  p_infty[4] = INDL_INFTY; /* this is another hack */

  for (i = 0; i < 4; i++)
    if (p_infty[4]-psingle[4] > 0.0)
      p_infty[i] = psingle[i] - (p_infty[4]-psingle[4]) / 4.0;
    else
      Die ("rnamodel: you need to put more gaps at infty");

  CheckSingleProb(p_infty, 5);
  if (verbose) {
    fprintf(stdout, "Psingle(i| t=infty) single nt probabilities\n");
    PrintVectorProbs(stdout, p_infty, 5);
  }

 /* ******************
   * [4] EVOLVE
   * *******************/
  /* evolve the sigle probs -- it's the same function than to evolve transition probs.
   */
  psingle_Rdiag = (double *) MallocOrDie (sizeof(double) * 5);
  psingle_Rdiag = TransitionsExpVector(psingle, psingle_nought, p_infty, 5);
  TransitionsEvolved(stdout, psingle, psingle_nought, p_infty, psingle_Rdiag, 5, tfactor, pedantic, verbose);
  if (verbose) {
    fprintf(stdout, "Psingle(i| t=%f) single nt probabilities\n", tfactor);
    PrintVectorProbs(stdout, psingle, 5);
  }

  /* evolve mut5pxy_rna
   */
  Joint2JointGap(mut5pxy_rna, mut5pxy_rna_cond_nought, psingle, 5, tfactor, targetfreq, FALSE, pedantic, FALSE);
  if (verbose) {
    fprintf(stdout, "mut5pxy_rna(i|j, t=%f) Joint probabilities\n", tfactor);
    PrintProbs(stdout, mut5pxy_rna, 5);
  }

  /* evolve pair5probs
   */
  Joint2JointGap(pair5prob, pair5prob_cond_nought, psingle, 5, tfactor, targetfreq, FALSE, pedantic, FALSE);

  MarginalizeJointProbs(mut5pxy_rna, psingle, 5, 2);
  ChangePairProbs(5, pair5prob, psingle, TRUE, verbose);
  if (verbose) {
    fprintf(stdout, "pair5prob(i|j, t=%f) Joint probabilities\n", tfactor);
    PrintProbs(stdout, pair5prob, 5);
  }

 /* Calculate Uncorrelated RIBOPROB Joint matrices.
   *
   * Use the RIBO_MUT_UNCORR to calculate the RIBO5PairCond    set gaps as pair5probs
   *                                                           set the RIBO5PairMarg to the already evolved pair5probs
   *
   * Use the RIBO_PAIR_UNCORR to calculate the RIBO5MUTCond    set gaps as mut5pxy_rna
   *                                                           set the RIBO5MutMarg to the already evolved mut5pxy_rna
   *
   */
  CalculateRIBO5ConditionalsUncorr_201(stdout, riboprob, &ribo5cond_mut, &ribo5cond_pair, mut5pxy_rna, pair5prob, targetfreq, verbose);

  /*
   * Pair-to-Pair at t --- Here we  put everything together
   */
  pp = pair_2_pair_prob (ribo5cond_mut, ribo5cond_pair, mut5pxy_rna, pair5prob, tfactor, verbose);
  
  /* PI2 model
   */
  /* Trnasition probabilities from the training set
   */
  rna->pi2->v->t1  = 0.;
  rna->pi2->v->t2s = 0.;
  rna->pi2->v->t2b = 0.;
  rna->pi2->v->t2i = 0.;
  rna->pi2->v->t3  = 0.;

  for (idx = 0; idx < Idx[V]; idx++) {
    rna->pi2->v->t1  += EXP2(cfg_node[V][idx][dpcS1  - DpNodeidx[V]]);

    rna->pi2->v->t2s += EXP2(cfg_node[V][idx][dpcS2S - DpNodeidx[V]]);
    rna->pi2->v->t2b += EXP2(cfg_node[V][idx][dpcS2B - DpNodeidx[V]]);
    rna->pi2->v->t2i += EXP2(cfg_node[V][idx][dpcS2I - DpNodeidx[V]]);
    rna->pi2->v->t3  += EXP2(cfg_node[V][idx][dpcMV  - DpNodeidx[V]]);
  }
  rna->pi2->v->t1  /= Idx[V];
  rna->pi2->v->t2s /= Idx[V];
  rna->pi2->v->t2b /= Idx[V];
  rna->pi2->v->t2i /= Idx[V];
  rna->pi2->v->t3  /= Idx[V];

  sum = rna->pi2->v->t1+rna->pi2->v->t2s+rna->pi2->v->t2b+rna->pi2->v->t2i+rna->pi2->v->t3;
  if (sum > 2.0-accuracy || sum < accuracy)
    Die ("pi2->v transtitions don't add up to one (sum_v = %f)\n", sum);
  if (verbose) printf("V: %f %f %f %f %f\n", rna->pi2->v->t1, rna->pi2->v->t2s, rna->pi2->v->t2b, rna->pi2->v->t2i, rna->pi2->v->t3);

  /* tie L and R emission
   */
  rna->pi2->w->tl = EXP2(cfg_node[W][0][dpcL   - DpNodeidx[W]]);
  rna->pi2->w->tr = EXP2(cfg_node[W][0][dpcR   - DpNodeidx[W]]);
  rna->pi2->w->tl = 0.5 * (rna->pi2->w->tl + rna->pi2->w->tr);
  rna->pi2->w->tr = rna->pi2->w->tl;
  rna->pi2->w->tv = EXP2(cfg_node[W][0][dpcP   - DpNodeidx[W]]);
  rna->pi2->w->tw = EXP2(cfg_node[W][0][dpcBW  - DpNodeidx[W]]);

  sum = rna->pi2->w->tl + rna->pi2->w->tr + rna->pi2->w->tv + rna->pi2->w->tw;
  if (sum > 2.0-accuracy || sum < accuracy)
    Die ("pi2->w transtitions don't add up to one (sum_w = %f)\n", sum);
  if (verbose) printf("W: %f %f %f %f\n", rna->pi2->w->tl, rna->pi2->w->tr, rna->pi2->w->tv, rna->pi2->w->tw);

  rna->pi2->wb->tl = EXP2(cfg_node[WB][0][dpcL  - DpNodeidx[WB]]);
  rna->pi2->wb->tr = EXP2(cfg_node[WB][0][dpcR  - DpNodeidx[WB]]);
  rna->pi2->wb->tl = 0.5 * (rna->pi2->wb->tl+rna->pi2->wb->tr);
  rna->pi2->wb->tr = rna->pi2->wb->tl;
  rna->pi2->wb->tv = EXP2(cfg_node[WB][0][dpcP  - DpNodeidx[WB]]);
  rna->pi2->wb->tw = EXP2(cfg_node[WB][0][dpcBW - DpNodeidx[WB]]);

  sum = rna->pi2->wb->tl + rna->pi2->wb->tr + rna->pi2->wb->tv + rna->pi2->wb->tw;
  if (sum > 2.0-accuracy || sum < accuracy)
    Die ("pi2->wb transtitions don't add up to one (sum_wb = %f)\n", sum);
  if (verbose) printf("WB: %f %f %f %f\n", rna->pi2->wb->tl, rna->pi2->wb->tr, rna->pi2->wb->tv, rna->pi2->wb->tw);

   /* this is a hack.
   * The contribution of  IS1, IS2 seems to work better if I substitute
   *
   *   tn[l] --> tn[l]*(1-\eta)^l / sum_{l'}(tn[l']*(1-\eta)^l')
   *
   * in this way, larger lengths get a lower probability
   */
  corr = LOG2(0.15);
  for (len = 0; len < MAXRNALOOP; len++)
    if (len > 3) rna->pi2->is1->tn[len] = EXP2(cfg_node[IS1][0][dpcLEN(len)-DpNodeidx[IS1]] + ((double)len-1.)*corr);
    else         rna->pi2->is1->tn[len] = 0.0;
  DNorm( rna->pi2->is1->tn, MAXRNALOOP);
  
  for (len = 0; len < MAXRNALOOP; len++)
    if (len > 2) rna->pi2->is2b->tn[len] = EXP2(cfg_node[IS2B][0][dpcLEN(len)-DpNodeidx[IS2B]] + ((double)len-2.)*corr);
    else         rna->pi2->is2b->tn[len] = 0.0;
  DNorm(rna->pi2->is2b->tn, MAXRNALOOP);

  for (len = 0; len < MAXRNALOOP; len++)
    if (len > 3) rna->pi2->is2i->tn[len] = EXP2(cfg_node[IS2I][0][dpcLEN(len)-DpNodeidx[IS2I]] + ((double)len-2.)*corr);
    else         rna->pi2->is2i->tn[len] = 0.0;
  DNorm(rna->pi2->is2i->tn, MAXRNALOOP);

 /* 24 SEP 02
  *
  * The evolutionary SCFG model is as follows:
  *
  */
  SCFGTransitionProbabilities(win, tfactor, rna->pi2, pedantic, verbose);


                                /* copy singlets */
  for (i = 0; i < 25; i++) {
    rna->pi2->w->pl[i]    = mut5pxy_rna[i];
    rna->pi2->w->pr[i]    = mut5pxy_rna[i];
    rna->pi2->wb->pl[i]   = mut5pxy_rna[i];
    rna->pi2->wb->pr[i]   = mut5pxy_rna[i];
    rna->pi2->is1->ps[i]  = mut5pxy_rna[i];
    rna->pi2->is2b->ps[i] = mut5pxy_rna[i];
    rna->pi2->is2i->ps[i] = mut5pxy_rna[i];
  }

                                   /* assign the pair probabilities */
  for (i = 0; i < 25; i++)
    for (j = 0; j < 25; j++) {
          rna->pi2->v->pp [i][j] = pp[i*25+j];
          rna->pi2->w->pp [i][j] = pp[i*25+j];
          rna->pi2->wb->pp[i][j] = pp[i*25+j];
    }

  /* NUS model
   */
  rna->nus->tl = 0.1;
  rna->nus->tr = 0.1;
  rna->nus->tv = 0.7;
  rna->nus->tw = 0.095;
  rna->nus->te = 0.005;

  sum = rna->nus->tl + rna->nus->tr + rna->nus->tv + rna->nus->tw + rna->nus->te;
  if (sum > 1.02 || sum < 0.998)
    Die ("nus->w transtitions don't add up to one (sum_w = %f)\n", sum);

  for (i = 0; i < 25; i++) {
    rna->nus->p[i] = rna->pi2->wb->pl[i];

    for (j = 0; j < 25; j++)
      rna->nus->pp[i][j] = rna->pi2->v->pp[i][j];
  }

  /* check prob's add up to one
   */
  CheckRNAProbs(rna);

  /* convert to Log2 form
   */
  RNAToLog2(rna, null);

  /* Print Transition Probabilities if asked for it
   */
  if (FALSE) PrintRNATrProbs(rna);
  if (FALSE) PrintRNAModel(rna);

  /* Calculate loop statistics if asked for it
   */
  if (FALSE) {
    fprintf(stdout, "IS1 loops\n");
    DistributionLogMeanVar(rna->pi2->is1->tn, MAXRNALOOP, &is1_ave, &is1_sd);
    fprintf(stdout, "av = %f sd = %f\n", is1_ave, is1_sd);
    PrintVectorProbs(stdout, rna->pi2->is1->tn, MAXRNALOOP);

    fprintf(stdout, "IS2B loops\n");
    DistributionLogMeanVar(rna->pi2->is2b->tn, MAXRNALOOP, &is2b_ave, &is2b_sd);
    fprintf(stdout, "av = %f sd = %f\n", is2b_ave, is2b_sd);
    PrintVectorProbs(stdout, rna->pi2->is2b->tn, MAXRNALOOP);

    fprintf(stdout, "IS2I loops\n");
    DistributionLogMeanVar(rna->pi2->is2i->tn, MAXRNALOOP, &is2i_ave, &is2i_sd);
    fprintf(stdout, "av = %f sd = %f\n", is2i_ave, is2i_sd);
    PrintVectorProbs(stdout, rna->pi2->is2i->tn, MAXRNALOOP);
  }

  FreeFullCondMatrix(ribocond_mut);
  FreeFullCondMatrix(ribocond_pair);
  FreeFullCondMatrix(ribo5cond_mut);
  FreeFullCondMatrix(ribo5cond_pair);
  FreeCondMatrix(ribocond_pair_nought);
  free(mut);
  free(pair);
  free(pair5prob);
  free(pair5prob_cond_nought);
  free(mut5pxy_rna_cond_nought);
  free(psingle);
  free(psingle_nought);
  free(psingle_Rdiag);
  free(p_infty);
  free(pp);

  if (verbose) printf("DONE, RNA model at time = %.4f\n", tfactor);
}

/* Function: ConstructRNAModel()
 * Date:     ER, Tue Jun  8 13:30:43 CDT 1999 [St. Louis]
 *
 * Modified: ER, JUL 24 2002 [St. Louis]
 *
 * Modified: ER, Thu Jan 16 16:59:19 CST 2003 [St. Louis]
 *
 *
 * Purpose:  Build the RNA model from the null model under
 *           certain simplifying assumptions; namely, that
 *           P(x1 y1 x2 y2) = P(x1 y1) P (x2 y2) P(x1 x2) / (P(x1) P(x2))
 *
 * Args:     pammodel[64][64]
 *           cfg      -- the file with the SCFG model
 *           rnamodel -- pointer to alloc'ed rnamodel
 *
 * Returns:  void
 *           fills in rnamodel
 */
void
ConstructRNAModel(double **pammodel_star, double ***cfg_node, double *pair5, fullmat_t *riboprob, 
		  int win, double tfactor, struct rnamodel_s *rna, struct nullmodel_s *null, 
		  double *targetfreq, int changefreq, int pedantic, int verbose)
{
  fullcondmat_t     *ribocond_mut;
  fullcondmat_t     *ribocond_pair;
  fullcondmat_t     *ribocondapprox_pair;
  double            *riboprobapprox;
  fullcondmat_t     *ribo5cond_mut;
  fullcondmat_t     *ribo5cond_pair;
  condmatrix_t      *ribocond_pair_nought;
  double            *mutpxy_rna;
  double            *mut5pxy_rna;
  double            *ps;
  double            *mut;
  double            *pair;
  double            *pair5prob;                /* [5x5] base-pair joint probabilities +*/
  double            *pair5prob_nought;         /* [5x5] base-pair joint probabilities +*/
  double            *pair5prob_condl_nought;   /* [5x5] base-pair conditional probabilities at time zero +*/
  double            *pair5prob_condr_nought;   /* [5x5] base-pair conditional probabilities at time zero +*/
  double            *pmarX;                    /* [5] marginalization of the pair5probs +*/
  double            *pmarY;                    /* [5] marginalization of the pair5probs +*/
  double            *mut5pxy_rna_cond_nought;  /* [5x5] mutation joint probabilities at time zero +*/ 
  double            *psingle;                  /* [5] single nt vector probabilities +*/
  double            *psingle_nought;           /* [5] single nt vector probabilities at time zero +*/  
  double            *pp;                       /* [625] pair-to-pair vector probabilities +*/
  double             sum;                      /* For normalization purposes +*/
  int                idx;                      /* Index for transition prob's              +*/
  int                i,j;                      /* Symbols for emission prob's              +*/
  int                len;                      /* Length of a loop (< MAXRNALOOP)          +*/
  double             ave_len_ROB;             /* expected length of the other models */
  double             ave_len_ROE;
  double             ave_len_ROJ;
  double             ave_len_ROB_zero;             /* expected length of the other models */
  double             ave_len_ROE_zero;
  double             ave_len_ROJ_zero;
  double             ave_len_ROB_infty;             /* expected length of the other models */
  double             ave_len_ROE_infty;
  double             ave_len_ROJ_infty;
  double             ave_len_Rloop;
  double             is1_ave,  is1_sd;
  double             is2b_ave, is2b_sd;
  double             is2i_ave, is2i_sd;
  double             corr;
  double             gap = GAPP;
  double             gap2gap;
  
  if (verbose) printf("Construct RNA model at time = %.4f\n", tfactor);

  /* Calculate delta^prime = delta^2/(1-delta^2)
   */
  gap2gap = DeltaPrimeFromDelta (gap);

  /* calculate the mutpxy(t) and mut5pxy(t^*) from the pammodel_star
   */
  ConstructTiedProbs(pammodel_star, tfactor, &mutpxy_rna, &mut5pxy_rna, targetfreq, changefreq, pedantic, verbose);
   if (verbose) {
    fprintf(stdout, "mutpxy_rna (t=%f) 4x4 probabilities\n", tfactor);
    PrintProbs(stdout, mutpxy_rna, 4);
    fprintf(stdout, "mut5pxy_rna (t=t^*) 5x5 probabilities\n");
    PrintProbs(stdout, mut5pxy_rna, 5);
  }

  /* the oth model has a paramente tau that set the invers of the average length generated by those models
   * This is how I set them as a few percentages of the length under analysis.
   */
  ave_len_ROB_zero = EXP2(0.40*LOG2((double)win));
  ave_len_ROE_zero = EXP2(0.40*LOG2((double)win));
  ave_len_ROJ_zero = EXP2(0.40*LOG2((double)win));

  ave_len_ROB       = EXP2(1.00*LOG2(ave_len_ROB_zero));
  ave_len_ROE       = EXP2(1.00*LOG2(ave_len_ROE_zero));
  ave_len_ROJ       = EXP2(1.00*LOG2(ave_len_ROJ_zero));

  ave_len_ROB_infty = EXP2(1.00*LOG2(ave_len_ROB_zero));
  ave_len_ROE_infty = EXP2(1.00*LOG2(ave_len_ROE_zero));
  ave_len_ROJ_infty = EXP2(1.00*LOG2(ave_len_ROJ_zero));

  ConstructOTHModel(pammodel_star, ROBparam, ROBparam_zero, ROBparam_infty, ave_len_ROB, ave_len_ROB_zero, ave_len_ROB_infty, tfactor, 
		    targetfreq, changefreq, rna->ROB, pedantic, FALSE);
  ConstructOTHModel(pammodel_star, ROJparam, ROJparam_zero, ROJparam_infty, ave_len_ROJ, ave_len_ROJ_zero, ave_len_ROJ_infty, tfactor, 
		    targetfreq, changefreq, rna->ROJ, pedantic, FALSE);
  ConstructOTHModel(pammodel_star, ROEparam, ROEparam_zero, ROEparam_infty, ave_len_ROE, ave_len_ROE_zero, ave_len_ROE_infty, tfactor, 
		    targetfreq, changefreq, rna->ROE, pedantic, FALSE);
  
  ave_len_Rloop = 15.0;
  ConstructOTHModel(pammodel_star, Rloopparam, Rloopparam_zero, Rloopparam_infty, ave_len_Rloop, ave_len_Rloop, ave_len_Rloop, tfactor, 
		    targetfreq, changefreq, rna->pi2->Rloop, pedantic, FALSE);

 /* 24 JUL 02
  *
  * For the HHM-part of the RNA model,
  * the evolutionary RNA model is as follows:
  *
  *       - A 2x2 matrix for transitions T                RNA     ROE                          
  *                                               ROB  |  psi    1-psi |
  *                                       T =          |               |
  *                                               RNA  | 1-eta    eta  |
  * 
  *
  *               at t=0                               |  1        0   |
  *                                       T_0 =        |               |
  *                                                    |  0        1   |
  *
  *              parametric family:      T = exp [tA]
  *
  */
  RNAmodelTransitionProbabilities(tfactor, rna, pedantic, verbose);

  
  mut = (double *) MallocOrDie(sizeof(double) * 4 * 4);
  for (i = 0; i < 4; i++)
    for (j = 0; j < 4; j++) {
      mut[i*4+j] = mut5pxy_rna[i*5+j];
      sum += mut[i*4+j];
    }
  for (i = 0; i < 4; i++)
    for (j = 0; j < 4; j++) 
      mut[i*4+j] /= sum;
   if (verbose) {
    fprintf(stdout, "mut(t^*) 4x4 probabilities\n");
    PrintProbs(stdout, mut, 4);
  }
  
  pair = (double *) MallocOrDie(sizeof(double) * 4 * 4);
  for (i = 0; i < 4; i++)
    for (j = 0; j < 4; j++)
      pair[i*4+j] = pair5[i*5+j];
   if (verbose) { 
    fprintf(stdout, "pair 4x4 probabilities\n");
    PrintProbs(stdout, pair, 4);
  }

 /* ******************
   * [1] TIME: t*
   * *******************/
  psingle = (double *) MallocOrDie (sizeof(double)*5);
  MarginalizeJointProbs(mut5pxy_rna, psingle, 5, 2);
  CheckSingleProb(psingle, 5);
   if (verbose) {
    fprintf(stdout, "sum_j mut5pxy_rna(ij| t*) marginal probabilities\n");
    PrintVectorProbs(stdout, psingle, 5);
  }
  
  /* mut5pxy_rna at t* are given
   */
   if (verbose) {
    fprintf(stdout, "mut5pxy_rna(i|j, t*) Joint probabilities\n");
    PrintProbs(stdout, mut5pxy_rna, 5);
  }
  
  /* Pair5Probs at t*
   */
  ps = (double *) MallocOrDie (sizeof(double) * 4);
  for (i = 0; i < 4; i++)
    ps[i] = psingle[i] / ( 1.0 - psingle[4]);

  if (!changefreq) targetfreq = ps;
  ChangePairProbsIterate(stdout, pair, 4, targetfreq, FALSE, verbose);

  for (i = 0; i < 4; i++)
    for (j = 0; j < 4; j++)
      pair5[i*5+j] = pair[i*4+j];

  CheckSingleProb(pair5, 5*5);
   
  pair5prob = (double *) MallocOrDie (sizeof(double) * 25);
  for (i = 0; i < 5; i++) 
    for (j = 0; j < 5; j++) 
      pair5prob[idx5(i,j)] = pair5[idx5(i,j)];

  /* OK, NT-2-GAP AND GAP-2-GAP Watson-Crick-Pair-Probabilities cannot be justified
   *
   * This is how I deal with them:
   */
  /* add pair-to-gap */
  pmarX       = (double *) MallocOrDie (sizeof(double) * 5);
  pmarY       = (double *) MallocOrDie (sizeof(double) * 5);
  MarginalizeJointProbs(pair5prob, pmarX, 5, 0);
  MarginalizeJointProbs(pair5prob, pmarY, 5, 1);
  for (i = 0; i < 4; i++) {
    pair5prob[idx5(i,4)] = gap*pmarX[i];
    pair5prob[idx5(4,i)] = gap*pmarY[i];
  }
  pair5prob[idx5(4,4)] = gap2gap;
  free(pmarX);
  free(pmarY);
  
  /* normalize */
  DNorm(pair5prob, 25);
  if (verbose) {
    fprintf(stdout, "pair5prob(i|j, t*) probabilities\n");
    PrintProbs(stdout, pair5prob, 5);
  }
  
  /* Calculate RIBOconditional matrices from the aproximated riboprobapprox
   *
   */
  CalculateRIBOProbsApprox(stdout, 4, mut, pair, &riboprobapprox, verbose);
  CalculateRIBOPairConditionalsApprox(stdout, 4, riboprobapprox, &ribocondapprox_pair, verbose);

  /* Calculate RIBOconditional matrices from RIBOSUM.mat
   *
   */
  CalculateRIBOMutConditionals (stdout, riboprob, &ribocond_mut,  verbose);
  CalculateRIBOPairConditionals(stdout, riboprob, &ribocond_pair, verbose);
 
 /* ******************
   * [2] TIME: zero
   * *******************/
  /* Infer single probs at time zero by impossing that p(gap) = 0
   */
  psingle_nought = (double *) MallocOrDie (sizeof(double) * 5);
  for (i = 0; i < 4; i++) 
    psingle_nought[i] = psingle[i] / ( 1.0 - psingle[4]);

  psingle_nought[4] = 0.0;

  CheckSingleProb(psingle_nought, 5);
  if (verbose) {
    fprintf(stdout, "Psingle(i| t=zero) single nt probabilities\n");
    PrintVectorProbs(stdout, psingle_nought, 5);
  }
  
  /* Conditional mut5pxy_rna at time zero is the identity, 
   * except for the last row. We need a Q_0 neq I so that the
   * fixation probabilities are not the psingle at t*.
   */
  mut5pxy_rna_cond_nought = Cal_Id(5);
  mut5pxy_rna_cond_nought[idx5(4,4)] = 0.980;
  for (i = 0; i < 4; i++)   
    mut5pxy_rna_cond_nought[idx5(4,i)] = (1.0-mut5pxy_rna_cond_nought[idx5(4,4)]) * psingle_nought[i];

  if (verbose) {
    fprintf(stdout, "mut5pxy(i|j, t=0) L-Cond probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_cond_nought, 5);
    fprintf(stdout, "pm(i, t=0) marginal probabilities\n");
    PrintVectorProbs(stdout, psingle_nought, 5);
  }

  /* Conditional pair5prob at time zero are infered from pair5probs at t* marginalizing the gaps
   *
   */
  pair5prob_nought = (double *) MallocOrDie (sizeof(double) * 5 * 5);
  for (i = 0; i < 5; i++) 
    for (j = 0; j < 5; j++) 
      pair5prob_nought[idx5(i,j)] = pair5[idx5(i,j)];

  pair5prob_condl_nought = Condi_From_Joint (stdout, pair5prob_nought, 5, verbose);
  pair5prob_condr_nought = CondiR_From_Joint(stdout, pair5prob_nought, 5, verbose);

  /* lasts row is free to choose
   */
  pair5prob_condl_nought[idx5(4,4)] = 0.980;  
  pair5prob_condr_nought[idx5(4,4)] = 0.980;  
  for (j = 0; j < 4; j++) {
    pair5prob_condl_nought[idx5(4,j)] = (1.0-pair5prob_condl_nought[idx5(4,4)]) * psingle_nought[j];
    pair5prob_condr_nought[idx5(4,j)] = (1.0-pair5prob_condr_nought[idx5(4,4)]) * psingle_nought[j];
  }
  for (i = 0; i < 5; i++) CheckSingleProb(pair5prob_condl_nought+i*5, 5);
  for (i = 0; i < 5; i++) CheckSingleProb(pair5prob_condr_nought+i*5, 5);

  if (verbose) {
    fprintf(stdout, "Ppair5(i|j, t=0) L-Cond probabilities\n");
    PrintProbs(stdout, pair5prob_condl_nought, 5);
    fprintf(stdout, "Ppair5(i|j, t=0) R-Cond probabilities\n");
    PrintProbs(stdout, pair5prob_condr_nought, 5);
  }

  /* the 16x16 pair conditionals at t=0 
   */
  ribocond_pair_nought = AllocCondMatrix (16);
  Comp_Id (ribocond_pair_nought->matrix, 16);
  if (verbose) {
    fprintf(stdout, "PAIR-COND-nought probabilities\n");
    PrintProbs(stdout, ribocond_pair_nought->matrix, 16);
  }  

  /* ******************
   * [3] EVOLVE
   * *******************/
  /* evolve mut5pxy_rna
   */
  Joint2Joint(mut5pxy_rna, mut5pxy_rna_cond_nought, mut5pxy_rna_cond_nought, 5, tfactor, targetfreq, changefreq, TRUE, FALSE, pedantic, FALSE);
  if (verbose) {
    fprintf(stdout, "mut5pxy_rna(i|j, t=%f) Joint probabilities\n", tfactor);
    PrintProbs(stdout, mut5pxy_rna, 5);
  }
 
  /* evolve pair5probs  
   */  
  /* the method to change the background frequencies does not work for non-joint probabilities like
   * the base-pair probabilities (basically because the reversibility condition for the diagonal element
   * is non trivial, and it cannot be let free. What we do is if we need to change the background frequencies
   * of the pair probs, we do so at the 4x4 t=t* level with the approximate method of lambda, so at this stage
   * they do not need to be changed again
   */
  Joint2Joint(pair5prob, pair5prob_condl_nought, pair5prob_condr_nought, 5, tfactor, targetfreq, FALSE, TRUE, TRUE, pedantic, FALSE); 
  if (verbose) { 
    fprintf(stdout, "pair5prob(i|j, t=%f) Joint probabilities\n", tfactor);  
    PrintProbs(stdout, pair5prob, 5);   
  }    
  
  /* Calculate Uncorrelated RIBOPROB Joint matrices.
   *
   * Use the RIBO_MUT_UNCORR to calculate the RIBO5PairCond    set gaps as pair5probs
   *                                                           set the RIBO5PairMarg to the already evolved pair5probs
   *
   * Use the RIBO_PAIR_UNCORR to calculate the RIBO5MUTCond    set gaps as mut5pxy_rna
   *                                                           set the RIBO5MutMarg to the already evolved mut5pxy_rna
   *
   */
  if (1) {
    /* Evolve the RIBO5PairCond    
     */
    EvolveRIBOPairConditionals(ribocondapprox_pair, ribocond_pair_nought, tfactor, pair, TRUE, FALSE, verbose);
    /* 
     * Pair-to-Pair at t --- Here we  put everything together: we add the gaps
     */
    pp = pair_2_pair_addgap_prob (ribocondapprox_pair, mut5pxy_rna, pair5prob, tfactor, verbose);
  }
  else {
    /*
     * This is the old method used in ConstructRNAModel_201()
     */
    CalculateRIBO5ConditionalsUncorr (stdout, riboprob, &ribo5cond_mut, &ribo5cond_pair, mut5pxy_rna, pair5prob, targetfreq, verbose);
    pp = pair_2_pair_prob (ribo5cond_mut, ribo5cond_pair, mut5pxy_rna, pair5prob, tfactor, verbose);
    FreeFullCondMatrix(ribo5cond_mut);
    FreeFullCondMatrix(ribo5cond_pair);
  }
  

  /* PI2 model
   */
  /* Trnasition probabilities from the training set
   */
  rna->pi2->v->t1  = 0.;
  rna->pi2->v->t2s = 0.;
  rna->pi2->v->t2b = 0.;
  rna->pi2->v->t2i = 0.;
  rna->pi2->v->t3  = 0.;

  for (idx = 0; idx < Idx[V]; idx++) {
    rna->pi2->v->t1  += EXP2(cfg_node[V][idx][dpcS1  - DpNodeidx[V]]);

    rna->pi2->v->t2s += EXP2(cfg_node[V][idx][dpcS2S - DpNodeidx[V]]);
    rna->pi2->v->t2b += EXP2(cfg_node[V][idx][dpcS2B - DpNodeidx[V]]);
    rna->pi2->v->t2i += EXP2(cfg_node[V][idx][dpcS2I - DpNodeidx[V]]);
    rna->pi2->v->t3  += EXP2(cfg_node[V][idx][dpcMV  - DpNodeidx[V]]);
  }
  rna->pi2->v->t1  /= Idx[V];
  rna->pi2->v->t2s /= Idx[V];
  rna->pi2->v->t2b /= Idx[V];
  rna->pi2->v->t2i /= Idx[V];
  rna->pi2->v->t3  /= Idx[V];

  sum = rna->pi2->v->t1+rna->pi2->v->t2s+rna->pi2->v->t2b+rna->pi2->v->t2i+rna->pi2->v->t3;
  if (sum > 2.0-accuracy || sum < accuracy)
    Die ("pi2->v transtitions don't add up to one (sum_v = %f)\n", sum);
  if (verbose) printf("V: %f %f %f %f %f\n", rna->pi2->v->t1, rna->pi2->v->t2s, rna->pi2->v->t2b, rna->pi2->v->t2i, rna->pi2->v->t3);
  
  /* tie L and R emission
   */
  rna->pi2->w->tl = EXP2(cfg_node[W][0][dpcL   - DpNodeidx[W]]);
  rna->pi2->w->tr = EXP2(cfg_node[W][0][dpcR   - DpNodeidx[W]]);
  rna->pi2->w->tl = 0.5 * (rna->pi2->w->tl + rna->pi2->w->tr);
  rna->pi2->w->tr = rna->pi2->w->tl;
  rna->pi2->w->tv = EXP2(cfg_node[W][0][dpcP   - DpNodeidx[W]]);
  rna->pi2->w->tw = EXP2(cfg_node[W][0][dpcBW  - DpNodeidx[W]]);

  sum = rna->pi2->w->tl + rna->pi2->w->tr + rna->pi2->w->tv + rna->pi2->w->tw;
  if (sum > 2.0-accuracy || sum < accuracy)
    Die ("pi2->w transtitions don't add up to one (sum_w = %f)\n", sum);
  if (verbose) printf("W: %f %f %f %f\n", rna->pi2->w->tl, rna->pi2->w->tr, rna->pi2->w->tv, rna->pi2->w->tw);
  
  rna->pi2->wb->tl = EXP2(cfg_node[WB][0][dpcL  - DpNodeidx[WB]]);
  rna->pi2->wb->tr = EXP2(cfg_node[WB][0][dpcR  - DpNodeidx[WB]]);
  rna->pi2->wb->tl = 0.5 * (rna->pi2->wb->tl+rna->pi2->wb->tr);
  rna->pi2->wb->tr = rna->pi2->wb->tl;
  rna->pi2->wb->tv = EXP2(cfg_node[WB][0][dpcP  - DpNodeidx[WB]]);
  rna->pi2->wb->tw = EXP2(cfg_node[WB][0][dpcBW - DpNodeidx[WB]]);

  sum = rna->pi2->wb->tl + rna->pi2->wb->tr + rna->pi2->wb->tv + rna->pi2->wb->tw;
  if (sum > 2.0-accuracy || sum < accuracy)
    Die ("pi2->wb transtitions don't add up to one (sum_wb = %f)\n", sum);
  if (verbose) printf("WB: %f %f %f %f\n", rna->pi2->wb->tl, rna->pi2->wb->tr, rna->pi2->wb->tv, rna->pi2->wb->tw);

   /* this is a hack. 
   * The contribution of  IS1, IS2 seems to work better if I substitute
   * 
   *   tn[l] --> tn[l]*(1-\eta)^l / sum_{l'}(tn[l']*(1-\eta)^l')
   *
   * in this way, larger lengths get a lower probability
   */
  corr = LOG2(0.15); 
  for (len = 0; len < MAXRNALOOP; len++) 
    if (len > 3) rna->pi2->is1->tn[len] = EXP2(cfg_node[IS1][0][dpcLEN(len)-DpNodeidx[IS1]] + ((double)len-1.)*corr);
    else         rna->pi2->is1->tn[len] = 0.0;
  DNorm( rna->pi2->is1->tn, MAXRNALOOP);
  
  for (len = 0; len < MAXRNALOOP; len++) 
    if (len > 2) rna->pi2->is2b->tn[len] = EXP2(cfg_node[IS2B][0][dpcLEN(len)-DpNodeidx[IS2B]] + ((double)len-2.)*corr);
    else         rna->pi2->is2b->tn[len] = 0.0;
  DNorm(rna->pi2->is2b->tn, MAXRNALOOP);

  for (len = 0; len < MAXRNALOOP; len++) 
    if (len > 3) rna->pi2->is2i->tn[len] = EXP2(cfg_node[IS2I][0][dpcLEN(len)-DpNodeidx[IS2I]] + ((double)len-2.)*corr);
    else         rna->pi2->is2i->tn[len] = 0.0;
  DNorm(rna->pi2->is2i->tn, MAXRNALOOP);

 /* 24 SEP 02
  *
  * The evolutionary SCFG model is as follows:
  *
  */
  SCFGTransitionProbabilities(win, tfactor, rna->pi2, pedantic, verbose);


				/* copy singlets */
  for (i = 0; i < 25; i++) {
    rna->pi2->w->pl[i]    = mut5pxy_rna[i];
    rna->pi2->w->pr[i]    = mut5pxy_rna[i];
    rna->pi2->wb->pl[i]   = mut5pxy_rna[i];
    rna->pi2->wb->pr[i]   = mut5pxy_rna[i];
    rna->pi2->is1->ps[i]  = mut5pxy_rna[i];
    rna->pi2->is2b->ps[i] = mut5pxy_rna[i];
    rna->pi2->is2i->ps[i] = mut5pxy_rna[i];
  }
  
                                   /* assign the pair probabilities */
  for (i = 0; i < 25; i++)
    for (j = 0; j < 25; j++) {
	  rna->pi2->v->pp [i][j] = pp[i*25+j];  
	  rna->pi2->w->pp [i][j] = pp[i*25+j];  
	  rna->pi2->wb->pp[i][j] = pp[i*25+j];
    }  
 
  /* NUS model
   */
  rna->nus->tl = 0.1; 
  rna->nus->tr = 0.1; 
  rna->nus->tv = 0.7;
  rna->nus->tw = 0.095;
  rna->nus->te = 0.005;

  sum = rna->nus->tl + rna->nus->tr + rna->nus->tv + rna->nus->tw + rna->nus->te;
  if (sum > 1.02 || sum < 0.998) 
    Die ("nus->w transtitions don't add up to one (sum_w = %f)\n", sum);

  for (i = 0; i < 25; i++) {
    rna->nus->p[i] = rna->pi2->wb->pl[i];

    for (j = 0; j < 25; j++)
      rna->nus->pp[i][j] = rna->pi2->v->pp[i][j];
  }

  /* check prob's add up to one
   */
  CheckRNAProbs(rna);

  /* convert to Log2 form
   */
  RNAToLog2(rna, null);

  /* Print Transition Probabilities if asked for it
   */
  if (FALSE) PrintRNATrProbs(rna);
  if (FALSE) PrintRNAModel(rna);

  /* Calculate loop statistics if asked for it
   */
  if (FALSE) {
    fprintf(stdout, "IS1 loops\n");
    DistributionLogMeanVar(rna->pi2->is1->tn, MAXRNALOOP, &is1_ave, &is1_sd);
    fprintf(stdout, "av = %f sd = %f\n", is1_ave, is1_sd);
    PrintVectorProbs(stdout, rna->pi2->is1->tn, MAXRNALOOP);
 
    fprintf(stdout, "IS2B loops\n");
    DistributionLogMeanVar(rna->pi2->is2b->tn, MAXRNALOOP, &is2b_ave, &is2b_sd);
    fprintf(stdout, "av = %f sd = %f\n", is2b_ave, is2b_sd);
    PrintVectorProbs(stdout, rna->pi2->is2b->tn, MAXRNALOOP);

    fprintf(stdout, "IS2I loops\n");
    DistributionLogMeanVar(rna->pi2->is2i->tn, MAXRNALOOP, &is2i_ave, &is2i_sd);
    fprintf(stdout, "av = %f sd = %f\n", is2i_ave, is2i_sd);
    PrintVectorProbs(stdout, rna->pi2->is2i->tn, MAXRNALOOP);
  }

  FreeFullCondMatrix(ribocond_mut);
  FreeFullCondMatrix(ribocond_pair);
  FreeFullCondMatrix(ribocondapprox_pair);
  free(riboprobapprox);
  FreeCondMatrix(ribocond_pair_nought);
  free(mutpxy_rna);
  free(mut5pxy_rna);
  free(ps);
  free(mut);
  free(pair);
  free(pair5prob);
  free(pair5prob_nought);
  free(pair5prob_condl_nought);
  free(pair5prob_condr_nought);
  free(mut5pxy_rna_cond_nought);
  free(psingle);
  free(psingle_nought);
  free(pp);

  if (verbose) printf("DONE, RNA model at time = %.4f\n", tfactor);

}

struct pi2model_s *
CopyPI2Model(struct pi2model_s *pi2)
{
  struct pi2model_s *pi2_copy;
  int               i, j;
  int               n;

  pi2_copy = AllocPI2Model();

  /* V state */
  pi2_copy->v->t1  = pi2->v->t1;
  pi2_copy->v->t2s = pi2->v->t2s;
  pi2_copy->v->t2b = pi2->v->t2b;
  pi2_copy->v->t2i = pi2->v->t2i;
  pi2_copy->v->t3  = pi2->v->t3;

  for (i = 0; i < 25; i++)
    for (j = 0; j  < 25; j++)
      pi2_copy->v->pp[i][j] = pi2->v->pp[i][j];
  
  /* W state */
  pi2_copy->w->tl = pi2->w->tl;
  pi2_copy->w->tr = pi2->w->tr;
  pi2_copy->w->tv = pi2->w->tv;
  pi2_copy->w->tw = pi2->w->tw;

  for (i = 0; i < 25; i++)
    pi2_copy->w->pl[i] = pi2->w->pl[i];
  for (i = 0; i < 25; i++)
    pi2_copy->w->pr[i] = pi2->w->pr[i];
  for (i = 0; i < 25; i++)
    for (j = 0; j  < 25; j++)
      pi2_copy->w->pp[i][j] = pi2->w->pp[i][j];
  
  /* WB state */
  pi2_copy->wb->tl = pi2->wb->tl;
  pi2_copy->wb->tr = pi2->wb->tr;
  pi2_copy->wb->tv = pi2->wb->tv;
  pi2_copy->wb->tw = pi2->wb->tw;
  
  for (i = 0; i < 25; i++)
    pi2_copy->wb->pl[i] =  pi2->wb->pl[i] ;
  for (i = 0; i < 25; i++)
    pi2_copy->wb->pr[i] = pi2->wb->pr[i];
  for (i = 0; i < 25; i++)
    for (j = 0; j  < 25; j++)
      pi2_copy->wb->pp[i][j] = pi2->wb->pp[i][j];
  
  /* IS1 state */
  for (n = 0; n < MAXRNALOOP; n ++)
    pi2_copy->is1->tn[n] = pi2->is1->tn[n];
  for (i = 0; i < 25; i++)
    pi2_copy->is1->ps[i] = pi2->is1->ps[i];
  
  /* IS2B state */
  for (n = 0; n < MAXRNALOOP; n ++)
    pi2_copy->is2b->tn[n] = pi2->is2b->tn[n];
  for (i = 0; i < 25; i++)
    pi2_copy->is2b->ps[i] = pi2->is2b->ps[i];
  
  /* IS2I state */
  for (n = 0; n < MAXRNALOOP; n ++)
    pi2_copy->is2i->tn[n] = pi2->is2i->tn[n] ;
  for (i = 0; i < 25; i++)
    pi2_copy->is2i->ps[i] = pi2->is2i->ps[i];

  return pi2_copy;
}

void
FreeNUSModel(struct nusmodel_s *nus)
{
  free(nus);
}

void
FreePI2Model(struct pi2model_s *pi2)
{
  FreeOTHModel(pi2->Rloop);

  free(pi2->v);
  free(pi2->w);
  free(pi2->wb);

  free(pi2->is1);
  free(pi2->is2b);
  free(pi2->is2i);

  free(pi2);
}

void
FreeRNAModel(struct rnamodel_s *rna)
{
  FreeOTHModel(rna->ROB);
  FreeOTHModel(rna->ROJ);
  FreeOTHModel(rna->ROE);

  FreeNUSModel(rna->nus);
  FreePI2Model(rna->pi2);

  free(rna->t);
  free(rna);
}

/* Function: NUSToLog2()
 * Date:     ER, Wed Jun  9 17:48:13 CDT 1999 [St. Louis]
 *
 * Purpose:  Converts transition and emission prob's of a nusmodel to log2 form
 *
 * Args:     nus - the structure for an nusmodel
 *
 * Returns:  void. 
 */
void
NUSToLog2(struct nusmodel_s *nus)
{
  int x1,x2;       /* symbols for emission prob's      +*/

  /* transition prob's 
   */
  nus->tl = LOG2(nus->tl);		
  nus->tr = LOG2(nus->tr);
  nus->tv = LOG2(nus->tv);
  nus->tw = LOG2(nus->tw);
  nus->te = LOG2(nus->te);

  /* emission prob's 
   */
  for (x1 = 0; x1 < 25; x1++) {
    nus->p[x1] = LOG2(nus->p[x1]);
    
    for (x2 = 0; x2 < 25; x2++)
      nus->pp[x1][x2] = LOG2(nus->pp[x1][x2]);
  }
}


/* Function: NUSLog2ToOdds()
 * Date:     ER, Wed Jun  9 17:46:37 CDT 1999 [St. Louis]
 *
 * Purpose:  Converts transition and emission prob's of a nusmodel
 *           from log2 to log2odds form
 *
 * Args:     rna - the structure for an rnamodel
 *
 * Returns:  void. 
 */
void
NUSLog2ToOdds(struct nusmodel_s *nus, struct nullmodel_s *null)
{
  int x1,x2;
  double nullx1, nullx2;

  /* transition prob's 
   */
  nus->tl -= 2.0 * null->meta;
  nus->tr -= 2.0 * null->meta;
  nus->tv -= 4.0 * null->meta;

  /* emission prob's 
   */
  for (x1 = 0; x1 < 25; x1++) {
    nullx1  = (x1/5<4)? null->xem[x1/5] : -null->meta;
    nullx1 += (x1%5<4)? null->yem[x1%5] : -null->meta;

    nus->p[x1] -= nullx1;

   for (x2 = 0; x2 < 25; x2++) {
      nullx2  = (x2/5<4)? null->xem[x2/5] : -null->meta;
      nullx2 += (x2%5<4)? null->yem[x2%5] : -null->meta;

      nus->pp[x1][x2] -= nullx1 + nullx2; 
    }
  }
}

void     
PatternRNAModel(struct rnamodel_s *rna)
{
  int st;

  for (st = 0; st < RSTATES; st++) rna->t[st] = 0.0;

  PatternOTHModel(rna->ROB);
  PatternOTHModel(rna->ROJ);
  PatternOTHModel(rna->ROE);

  PatternOTHModel(rna->pi2->Rloop);

}
/* Function: PI2ToLog2()
 * Date:     ER, Tue Jun  8 12:46:08 CDT 1999 [St. Louis]
 *
 * Purpose:  Converts transition and emission prob's of a pi2model to log2 form
 *
 * Args:     rna - the structure for an rnamodel
 *
 * Returns:  void. 
 */
void
PI2ToLog2(struct pi2model_s *pi2, struct nullmodel_s *null)
{
  int len;               /* length of a loop (< MAXRNALOOP)  +*/
  int i,j;               /* symbols for emission prob's      +*/

  /* transition prob's 
   */
  pi2->v->t1  = LOG2(pi2->v->t1);		
  pi2->v->t2s = LOG2(pi2->v->t2s);		
  pi2->v->t2b = LOG2(pi2->v->t2b);		
  pi2->v->t2i = LOG2(pi2->v->t2i);		
  pi2->v->t3  = LOG2(pi2->v->t3);
		
  pi2->w->tl = LOG2(pi2->w->tl);		
  pi2->w->tr = LOG2(pi2->w->tr);
  pi2->w->tv = LOG2(pi2->w->tv);
  pi2->w->tw = LOG2(pi2->w->tw);

  pi2->wb->tl = LOG2(pi2->wb->tl);		
  pi2->wb->tr = LOG2(pi2->wb->tr);
  pi2->wb->tv = LOG2(pi2->wb->tv);
  pi2->wb->tw = LOG2(pi2->wb->tw);
  
 for (len = 0; len < MAXRNALOOP; len++) 
    if (len > 3) pi2->is1->tn[len] = LOG2(pi2->is1->tn[len]); 
    else         pi2->is1->tn[len] = -BIGFLOAT;

   DLog2Norm(pi2->is1->tn, MAXRNALOOP);
  if (FALSE) {
    fprintf(stdout, "IS1 loops\n");
    PrintVectorProbs(stdout, pi2->is1->tn, MAXRNALOOP);
  }
  
  for (len = 0; len < MAXRNALOOP; len++) 
    if (len > 2) pi2->is2b->tn[len] = LOG2(pi2->is2b->tn[len]);
    else         pi2->is2b->tn[len] = -BIGFLOAT;
 
  DLog2Norm(pi2->is2b->tn, MAXRNALOOP);
  if (FALSE) {
    fprintf(stdout, "IS2b loops\n");
    PrintVectorProbs(stdout, pi2->is2b->tn, MAXRNALOOP);
  }

  for (len = 0; len < MAXRNALOOP; len++) 
    if (len > 3) pi2->is2i->tn[len] = LOG2(pi2->is2i->tn[len]);
    else         pi2->is2i->tn[len] = -BIGFLOAT;
 
  DLog2Norm(pi2->is2i->tn, MAXRNALOOP);
  if (FALSE) {
    fprintf(stdout, "IS2I loops\n");
    PrintVectorProbs(stdout, pi2->is2i->tn, MAXRNALOOP);
  }

  /* emission prob's 
   */
  for (i = 0; i < 25; i++) {
    pi2->w->pl  [i]  = LOG2(pi2->w->pl  [i]);
    pi2->w->pr  [i]  = LOG2(pi2->w->pr  [i]);
    pi2->wb->pl [i]  = LOG2(pi2->wb->pl [i]);
    pi2->wb->pr [i]  = LOG2(pi2->wb->pr [i]);
    pi2->is1->ps[i]  = LOG2(pi2->is1->ps[i]);
    pi2->is2b->ps[i] = LOG2(pi2->is2b->ps[i]);
    pi2->is2i->ps[i] = LOG2(pi2->is2i->ps[i]);
    
    for (j = 0; j < 25; j++) {
      pi2->v->pp [i][j] = LOG2(pi2->v->pp [i][j]);
      pi2->w->pp [i][j] = LOG2(pi2->w->pp [i][j]);
      pi2->wb->pp[i][j] = LOG2(pi2->wb->pp[i][j]);
    }
  }
}

/* Function: PI2Log2ToOdds()
 * Date:     ER, Tue Jun  8 12:49:42 CDT 1999 [St. Louis]
 *
 * Purpose:  Converts transition and emission prob's of a pi2model
 *           from log2 to log2odds form
 *
 * Args:     rna - the structure for an pi2model
 *
 * Returns:  void. 
 */
void
PI2Log2ToOdds(struct pi2model_s *pi2, struct nullmodel_s *null)
{
  int    len;               /* length of a loop (< MAXRNALOOP)  +*/
  int    x1,x2;
  double nullx1, nullx2;

  OTHLog2ToOdds(pi2->Rloop, null);
  
  /* transition prob's 
   */
  pi2->v->t2s -= 4.0 * null->meta;
  pi2->v->t2b -= 4.0 * null->meta;
  pi2->v->t2i -= 4.0 * null->meta;

  pi2->w->tl  -= 2.0 * null->meta;
  pi2->w->tr  -= 2.0 * null->meta;
  pi2->w->tv  -= 4.0 * null->meta;

  pi2->wb->tl -= 2.0 * null->meta;
  pi2->wb->tr -= 2.0 * null->meta;
  pi2->wb->tv -= 4.0 * null->meta;
  
  for (len = 0; len < MAXRNALOOP; len++) { 
    pi2->is1->tn[len]  -= (len-1)>0? (len-1.)*2.*null->meta : .0; /* pi2->is1->tn[len] emits len-1 nts */
    pi2->is2b->tn[len] -= (len-2)>0? (len-2.)*2.*null->meta : .0; /* pi2->is2->tn[len] emits len-2 nts */
    pi2->is2i->tn[len] -= (len-2)>0? (len-2.)*2.*null->meta : .0; /* pi2->is2->tn[len] emits len-2 nts */
  }  
  
  /* emission prob's 
   */
  for (x1 = 0; x1 < 25; x1++) {
    nullx1  = (x1/5<4)? null->xem[x1/5] : -null->meta;
    nullx1 += (x1%5<4)? null->yem[x1%5] : -null->meta;
    
    pi2->w->pl  [x1]  -= nullx1;
    pi2->w->pr  [x1]  -= nullx1;
    pi2->wb->pl [x1]  -= nullx1;
    pi2->wb->pr [x1]  -= nullx1;
    pi2->is1->ps[x1]  -= nullx1;
    pi2->is2b->ps[x1] -= nullx1;
    pi2->is2i->ps[x1] -= nullx1;
    
    for (x2 = 0; x2 < 25; x2++) {
      nullx2  = (x2/5<4)? null->xem[x2/5] : -null->meta;
      nullx2 += (x2%5<4)? null->yem[x2%5] : -null->meta;
      
      pi2->v->pp [x1][x2] -= nullx1 + nullx2; 
      pi2->w->pp [x1][x2] -= nullx1 + nullx2; 
      pi2->wb->pp[x1][x2] -= nullx1 + nullx2; 
    }
  }
}

/* Function: PrintNUSModel()
 * Date:     ER, Wed Jun  9 17:43:05 CDT 1999 [St. Louis]
 *
 * Purpose:  print base pair alignment stuff for NUS model (given in log2 form)
 *
 * Args:     nusmodel, nullmodel
 *
 * Returns:  void, prints stuff.
 */
void
PrintNUSModel(struct nusmodel_s *nus)
{
  int    x1,x2,y1,y2;
  double mutp;
  double info   = 0.0;
  double expect = 0.0;

  printf("\nNUS MODEL -- Transition probabilities\n");
  printf("t[M->aM]  = %f\n", EXP2(nus->tl));		
  printf("t[M-> Ma] = %f\n", EXP2(nus->tr));
  printf("t[M->aMb] = %f\n", EXP2(nus->tv));
  printf("t[M->M M] = %f\n", EXP2(nus->tw));
  printf("t[M-> e]  = %f\n", EXP2(nus->te));

  printf("\nNUS MODEL -- Emission probabilities\n");
  for (x1 = 0; x1 < 5; x1++)
    for (y1 = 0; y1 < 5; y1++) {
      printf("%c*%c wl = %12f\n ", 
	     (x1<4)?DNAAlphabet[x1]:'-',    (y1<4)?DNAAlphabet[y1]:'-', 
	     EXP2(nus->p[idx5(x1,y1)]));
      
      for (x2 = 0; x2 < 5; x2++)
	for (y2 = 0; y2 < 5; y2++) {
	  mutp = nus->p[idx5(x1,y1)];
	  printf("%c*%c %c*%c w = %12f \n",
		 (x1<4)?DNAAlphabet[x1]:'-', (y1<4)?DNAAlphabet[y1]:'-',
		 (x2<4)?DNAAlphabet[x2]:'-', (y2<4)?DNAAlphabet[y2]:'-',
		 EXP2(nus->pp[idx5(x1,y1)][idx5(x2,y2)]));
	  info += EXP2(nus->pp[idx5(x1,y1)][idx5(x2,y2)]) * 
	    (nus->pp[idx5(x1,y1)][idx5(x2,y2)] - mutp);
	  expect += EXP2(mutp) * 
	    (nus->pp[idx5(x1,y1)][idx5(x2,y2)] - mutp);
	}
    }
  
  printf("NUS model info   = %f bits\n", info);
  printf("NUS model expect = %f bits\n", expect);
}

/* Function: PrintPI2Model()
 * Date:     ER, Tue Jun  8 13:32:19 CDT 1999 [St. Louis]
 *
 * Purpose:  print base pair alignment stuff for PI2 model (given in log2 form)
 *
 * Args:     rnamodel, nullmodel
 *
 * Returns:  void, prints stuff.
 */
void
PrintPI2Model(struct pi2model_s *pi2)
{
  int    x1,x2,y1,y2;
  int    len;               /* length of a loop (< MAXRNALOOP)  +*/
  double mutp;
  double info   = 0.0;
  double expect = 0.0;

  printf("\nRloop MODEL \n");
  PrintOTHModel(pi2->Rloop);

  printf("\nPI2 MODEL -- Transition probabilities\n");
  printf("t[V->IS1]  \t = %f\n", EXP2(pi2->v->t1));		
  printf("t[V->IS2S] \t = %f\n", EXP2(pi2->v->t2s));		
  printf("t[V->IS2B] \t = %f\n", EXP2(pi2->v->t2b));		
  printf("t[V->IS2I] \t = %f\n", EXP2(pi2->v->t2i));		
  printf("t[V->WB WB]\t = %f\n\n", EXP2(pi2->v->t3));
		
  printf("t[W->aW] \t = %f\n", EXP2(pi2->w->tl));		
  printf("t[W-> Wa]\t = %f\n", EXP2(pi2->w->tr));
  printf("t[W->aVb]\t = %f\n", EXP2(pi2->w->tv));
  printf("t[W->W W]\t = %f\n\n", EXP2(pi2->w->tw));

  printf("t[WB->aWB]  \t = %f\n", EXP2(pi2->wb->tl));		
  printf("t[WB-> WBa] \t = %f\n", EXP2(pi2->wb->tr));
  printf("t[WB->aVb]  \t = %f\n", EXP2(pi2->wb->tv));
  printf("t[WB->WB WB]\t = %f\n\n", EXP2(pi2->wb->tw));
  
  for (len = 1; len < MAXRNALOOP; len++) 
     printf("t[IS1->%d]\t = %f\n", len, EXP2(pi2->is1->tn[len]));
  printf("\n");
  for (len = 2; len < MAXRNALOOP; len++) 
     printf("t[IS2->%d]\t = %f\n", len ,EXP2(pi2->is2b->tn[len]));
  for (len = 2; len < MAXRNALOOP; len++) 
     printf("t[IS2->%d]\t = %f\n", len ,EXP2(pi2->is2i->tn[len]));

  printf("\nPI2 MODEL -- Emission probabilities\n");
  for (x1 = 0; x1 < 5; x1++)
    for (y1 = 0; y1 < 5; y1++) {
      printf("%c*%c    wl = %12f wr  = %12f\n      wbl = %12f wbr = %12f\n      is1 = %12f is2b = %12f  is2i = %12f \n", 
	     (x1<4)?DNAAlphabet[x1]:'-',     (y1<4)?DNAAlphabet[y1]:'-', 
	     EXP2(pi2->w->pl  [idx5(x1,y1)]), EXP2(pi2->w->pr  [idx5(x1,y1)]),
	     EXP2(pi2->wb->pl [idx5(x1,y1)]), EXP2(pi2->wb->pr [idx5(x1,y1)]),
	     EXP2(pi2->is1->ps[idx5(x1,y1)]), EXP2(pi2->is2b->ps[idx5(x1,y1)]), EXP2(pi2->is2i->ps[idx5(x1,y1)]));
      
      for (x2 = 0; x2 < 5; x2++)
	for (y2 = 0; y2 < 5; y2++) {
	  mutp = pi2->w->pl[idx5(x1,y1)] + pi2->w->pl[idx5(x2,y2)];
	  printf("%c*%c %c*%c v = %12f \n",
		 (x1<4)?DNAAlphabet[x1]:'-', (y1<4)?DNAAlphabet[y1]:'-',
		 (x2<4)?DNAAlphabet[x2]:'-', (y2<4)?DNAAlphabet[y2]:'-',
		 EXP2(pi2->v->pp [idx5(x1,y1)][idx5(x2,y2)]));

	  info += EXP2(pi2->v->pp[idx5(x1,y1)][idx5(x2,y2)]) * 
	    (pi2->v->pp[idx5(x1,y1)][idx5(x2,y2)] - mutp);
	  expect += EXP2(mutp) * 
	    (pi2->v->pp[idx5(x1,y1)][idx5(x2,y2)] - mutp);
	}
    }
  
  printf("PI2 model info   = %f bits\n", info);
  printf("PI2 model expect = %f bits\n", expect);
}

/* Function: PrintRNAModel()
 * Date:     ER, Tue Jun  8 13:32:19 CDT 1999 [St. Louis]
 *
 * Purpose:  print base pair alignment stuff for RNA model (given in log2 form)
 *
 * Args:     rnamodel, nullmodel
 *
 * Returns:  void, prints stuff.
 */
void
PrintRNAModel(struct rnamodel_s *rna)
{
  int idx;

  printf("\nROB MODEL \n");
  PrintOTHModel(rna->ROB);

  printf("\nROJ MODEL \n");
  PrintOTHModel(rna->ROJ);

  printf("\nROE MODEL \n");
  PrintOTHModel(rna->ROE);

  printf("\nRNA MODEL -- Transition probabilities\n");
  for (idx = 0; idx < RTRANS; idx++)
    printf("t[%s]\t = %f\n", rtrNAME[idx], EXP2(rna->t[idx])); 

  printf("\nNUS MODEL -- Probabilities\n");
  PrintNUSModel(rna->nus);

  printf("\nPI2 MODEL -- Probabilities\n");
  PrintPI2Model(rna->pi2);

}

/* Function: PrintRNATrProbs()
 * Date:     ER, Tue Aug  6 16:53:02 CDT 2002 [St. Louis]
 *
 * Purpose:  Print a RNA model transition probabilities
 *
 * Args:     rnamodel -- the rnamodel prob's, in log2 form
 *
 * Returns:  void. prints transition and emission probs for rna model, in [0,1] form.
 */
void
PrintRNATrProbs(struct rnamodel_s *rna) 
{
  int    idx;               /* index for transition prob's      +*/
  double tr;

  printf("\n***RNA MODEL*** -- Transition probabilities\n");
  for (idx = 0; idx < RTRANS; idx++) {
    tr = EXP2(rna->t[idx]);
    if (tr <= 1.0)
      printf("t[%s]\t = %f\n", rtrNAME[idx], tr); 
    else if (tr > 1.0) 
      Die ("tr prob larger than 1.0 at %s (tr = %f) \n", rtrNAME[idx], tr);
  }

}

/* Function: RNAToLog2()
 * Date:     ER, Tue Jun  8 12:46:08 CDT 1999 [St. Louis]
 *
 * Purpose:  Converts transition and emission prob's of a rnamodel to log2 form
 *
 * Args:     rna - the structure for an rnamodel
 *
 * Returns:  void. 
 */
void
RNAToLog2(struct rnamodel_s *rna, struct nullmodel_s *null)
{
  int idx;               /* index for transition prob's      +*/

  NUSToLog2(rna->nus);
  PI2ToLog2(rna->pi2, null);

  /* transition prob's 
   */
  for (idx = 0; idx < RTRANS; idx++) 
    rna->t[idx] = LOG2(rna->t[idx]);
  
}

/* Function: RNALog2ToOdds()
 * Date:     ER, Tue Jun  8 12:49:42 CDT 1999 [St. Louis]
 *
 * Purpose:  Converts transition and emission prob's of a rnamodel
 *           from log2 to log2odds form
 *
 * Args:     rna - the structure for an pi2model
 *
 * Returns:  void. 
 */
void
RNALog2ToOdds(struct rnamodel_s *rna, struct nullmodel_s *null)
{

  OTHLog2ToOdds(rna->ROB, null);
  OTHLog2ToOdds(rna->ROJ, null);
  OTHLog2ToOdds(rna->ROE, null);
  
  NUSLog2ToOdds(rna->nus, null);
  PI2Log2ToOdds(rna->pi2, null);
}



double
cal_inv (double *pp, int L)
{
  double inv = 0.;
  int    i;

  for (i = 0; i < L; i ++) {
    inv += pp[i*L+i];
  }

  return inv;
}


void
calculatePPderivedprobs(FILE *ofp, double *pp, int L)
{
  double *ppxl;
  double *ppxr;
  double *ppyl;
  double *ppyr;
  double *pmxl;
  double *pmxr;
  double *pmyl;
  double *pmyr;
  double *pairx;
  double *pairy;
  double *pmutl;
  double *pmutr;
  double *Qx;
  double *Qy;
  double *Ql;
  double *Qr;
  int     i;

  /* allocate memory
   */
  ppxl  = (double *) MallocOrDie (sizeof(double) * L);
  ppxr  = (double *) MallocOrDie (sizeof(double) * L);
  ppyl  = (double *) MallocOrDie (sizeof(double) * L);
  ppyr  = (double *) MallocOrDie (sizeof(double) * L);
  pmxl  = (double *) MallocOrDie (sizeof(double) * L);
  pmxr  = (double *) MallocOrDie (sizeof(double) * L);
  pmyl  = (double *) MallocOrDie (sizeof(double) * L);
  pmyr  = (double *) MallocOrDie (sizeof(double) * L);

  /* Initialize
   */
  for (i = 0; i < L; i++) {
    ppxl[i] = 0.0;
    ppxr[i] = 0.0;
    ppyl[i] = 0.0;
    ppyr[i] = 0.0;

    pmxl[i] = 0.0;
    pmxr[i] = 0.0;
    pmyl[i] = 0.0;
    pmyr[i] = 0.0;
  }

  CalculatePPConditionalsAndMarginals(ofp, pp, &Qx, &Qy, &Ql, &Qr, &pairx, &pairy, &pmutl, &pmutr, L, TRUE);
  
  MarginalizeJointProbs(pairx, ppxl, L, 0);
  MarginalizeJointProbs(pairx, ppxr, L, 1);
  MarginalizeJointProbs(pairy, ppyl, L, 0);
  MarginalizeJointProbs(pairy, ppyr, L, 1);
  
  MarginalizeJointProbs(pmutl, pmxl, L, 0);
  MarginalizeJointProbs(pmutl, pmyl, L, 1);
  MarginalizeJointProbs(pmutr, pmxr, L, 0);
  MarginalizeJointProbs(pmutr, pmyr, L, 1);
  
  printf("X-PAIR marginals probabilities\n");
  PrintVectorProbs(ofp, ppxl, L);
  printf("X-PAIR marginals probabilities\n");
  PrintVectorProbs(ofp, ppxr, L);
  printf("Y-PAIR marginals probabilities\n");
  PrintVectorProbs(ofp, ppyl, L);
  printf("Y-PAIR marginals probabilities\n");
  PrintVectorProbs(ofp, ppyr, L);
  
  printf("L-MUT marginals probabilities\n");
  PrintVectorProbs(ofp, pmxl, L);
  printf("L-MUT marginals probabilities\n");
  PrintVectorProbs(ofp, pmyl, L);
  printf("R-MUT marginals probabilities\n");
  PrintVectorProbs(ofp, pmxr, L);
  printf("R-MUT marginals probabilities\n");
  PrintVectorProbs(ofp, pmyr, L);
  
  free(ppxl);
  free(ppxr);
  free(ppyl);
  free(ppyr);

  free(pmxl);
  free(pmxr);
  free(pmyl);
  free(pmyr);
  
  free(pairx);
  free(pairy);
  free(pmutl);
  free(pmutr);
  
  free(Qx);
  free(Qy);
  free(Ql);
  free(Qr);

}


/* Function: compare_marginals
 *
 * Date:     ER, Tue Mar  4 18:13:11 CST 2003  [STL]
 *
 * Purpose: compares the marginals generated by the pair-to-pair probs to the
 *          "canonical ones" coming from the OTH model
 *
 *
 * Args:     
 *
 * Returns:  void
 */
void
compare_marginals (int L, double *pp, double *pair5prob, double *mut5pxy, double tfactor, int verbose)
{
  char          *title;
  double        *pp_old;
  double        *pp_rev;
  double        *pp_old_rev;
  double        *pp_marg_mut;
  double        *pp_marg_pair;
  double        *pp_single_marg_mut;
  double        *pp_single_marg_pair;
  double        *pp_old_marg_mut;
  double        *pp_old_marg_pair;
  double        *pp_old_single_marg_mut;
  double        *pp_old_single_marg_pair;
  double        *pp_single_mut;
  double        *pp_single_pair;
  int            xl, xr, yl, yr;
  int            xpair, ypair;
  int            lmut, rmut;
  int            idxm;
  int            idxp;
  int            L2;

  L2 = L*L;

  pp_old                  = (double *) MallocOrDie (sizeof(double) * L2 * L2);
  pp_rev                  = (double *) MallocOrDie (sizeof(double) * L2 * L2);
  pp_old_rev              = (double *) MallocOrDie (sizeof(double) * L2 * L2);
  pp_marg_mut             = (double *) MallocOrDie (sizeof(double) * L2);
  pp_marg_pair            = (double *) MallocOrDie (sizeof(double) * L2);
  pp_old_marg_mut         = (double *) MallocOrDie (sizeof(double) * L2);
  pp_old_marg_pair        = (double *) MallocOrDie (sizeof(double) * L2);
  pp_single_marg_mut      = (double *) MallocOrDie (sizeof(double) * L);
  pp_single_marg_pair     = (double *) MallocOrDie (sizeof(double) * L);
  pp_old_single_marg_mut  = (double *) MallocOrDie (sizeof(double) * L);
  pp_old_single_marg_pair = (double *) MallocOrDie (sizeof(double) * L);
  pp_single_mut           = (double *) MallocOrDie (sizeof(double) * L);
  pp_single_pair          = (double *) MallocOrDie (sizeof(double) * L);

  MarginalizeJointProbs(mut5pxy,   pp_single_mut,  L, 2);
  MarginalizeJointProbs(pair5prob, pp_single_pair, L, 2);

  for (xl = 0; xl < L; xl++)
    for (yl = 0; yl < L; yl++)
      for (xr = 0; xr < L; xr++)
	for (yr = 0; yr < L; yr++)
	  {
	    xpair = idx5(xl,xr);
	    ypair = idx5(yl,yr);

	    lmut = idx5(xl,yl);
	    rmut = idx5(xr,yr);
	  
	    idxm = lmut  * L2 + rmut;
	    idxp = xpair * L2 + ypair;


	    if (mut5pxy[lmut]    == 0.0 || mut5pxy[rmut]    == 0.0 ||
		pair5prob[xpair] == 0.0 || pair5prob[ypair] == 0.0   ) 
	      
		pp_old[idxm] = 0.0;
	    else 
	      pp_old[idxm]  = 0.5 
		* pair5prob[xpair] * pair5prob[ypair] 
		* ( (mut5pxy[lmut] / (pp_single_pair[xl] * pp_single_pair[yl])) + (mut5pxy[rmut] / (pp_single_pair[xr] * pp_single_pair[yr])) );
	    

	    pp_rev[idxp]     = pp[idxm];
	    pp_old_rev[idxp] = pp_old[idxm];


	  }
  DNorm(pp_old,     L2*L2);	
  DNorm(pp_old_rev, L2*L2);	
 
  MarginalizeJointProbs(pp,     pp_marg_mut,  L2, 2); 
  MarginalizeJointProbs(pp_rev, pp_marg_pair, L2, 2); 
  
  MarginalizeJointProbs(pp_old,     pp_old_marg_mut,  L2, 2); 
  MarginalizeJointProbs(pp_old_rev, pp_old_marg_pair, L2, 2); 

  MarginalizeJointProbs(pp_marg_mut,     pp_single_marg_mut,     L, 2);
  MarginalizeJointProbs(pp_old_marg_mut, pp_old_single_marg_mut, L, 2);

  MarginalizeJointProbs(pp_marg_pair,     pp_single_marg_pair,     L, 2);
  MarginalizeJointProbs(pp_old_marg_pair, pp_old_single_marg_pair, L, 2);

   printf ("\nMutation marginals from pair-to-pair probs >>> inv=%f\n", cal_inv(pp_marg_mut, L)); PrintProbs(stdout, pp_marg_mut,     L);
  printf ("OTHmut probs >>> inv=%f\n", cal_inv(mut5pxy, L));                                      PrintProbs(stdout, mut5pxy,         L);
  if (verbose) { printf ("Old >>> inv=%f\n", cal_inv(pp_old_marg_mut, L));                           PrintProbs(stdout, pp_old_marg_mut, L); }

  printf ("\nPair marginals from pair-to-pair probs \n"); PrintProbs(stdout, pp_marg_pair,     L);
  printf ("Pair5Probs \n");                               PrintProbs(stdout, pair5prob,        L);
  if (verbose) { printf ("Old \n");                          PrintProbs(stdout, pp_old_marg_pair, L); }
  
  printf ("\nSingle nt probs from Mutation marginals from pair-to-pair probs\n");
  PrintVectorProbs(stdout, pp_single_marg_mut, L);
  if (verbose) { 
    printf ("Old\n");
    PrintVectorProbs(stdout, pp_old_single_marg_mut, L);
  }
  printf ("Single nt probs from OTHmut probs\n");
  PrintVectorProbs(stdout, pp_single_mut,     L);

  printf ("\nSingle nt probs from Pair marginals from pair-to-pair probs\n");
  PrintVectorProbs(stdout, pp_single_marg_pair, L);
  if (verbose) { 
    printf ("Old\n");
    PrintVectorProbs(stdout, pp_old_single_marg_pair, L);
  }
  printf ("Single nt probs from Pair5Probs\n");
  PrintVectorProbs(stdout, pp_single_pair,     L);

  if (FALSE) {
    title = (char *) MallocOrDie(sizeof(char)*40);
    snprintf (title,  40, "%s--t=%.4f", "Pair-to-Pair--OLD", tfactor);
    PrintRIBOMatrix (stdout, pp_old, L2, FALSE, FALSE, FALSE, title);
    
    snprintf (title,  40, "%s--t=%.4f", "Pair-to-Pair", tfactor);
    PrintRIBOMatrix (stdout, pp, L2, FALSE, FALSE, FALSE, title);
    free(title);
  }
  
  free (pp_old);
  free (pp_rev);
  free (pp_old_rev);
  free (pp_marg_mut);
  free (pp_marg_pair);
  free (pp_single_marg_mut);
  free (pp_single_marg_pair);
  free (pp_old_marg_mut);
  free (pp_old_marg_pair);
  free (pp_old_single_marg_mut);
  free (pp_old_single_marg_pair);
  free (pp_single_mut);
  free (pp_single_pair);

}

/* Function: pair_2_pair_prob
 *
 * Date:     ER, Thu Jan 16 16:14:43 CST 2003  [STL]
 *
 * Purpose:  given the [5x5] mutation probs, the [5x5] pair probs,  and the [5] sigle nucleotide probs,
 *           calculate the [25x25] joint probabilities
 *
 *                  X_l    X_r
 *              P(             )
 *                  Y_l    Y_r
 *
 *
 * Args:     
 *
 * Returns:  pp. pp is allocated and filled here. pp freed by caller.
 */
double *
pair_2_pair_prob (fullcondmat_t *ribo5cond_mut, fullcondmat_t *ribo5cond_pair, double *mut5pxy, double *pair5prob, 
		  double tfactor, int verbose)
{
  char          *title;
  double        *pp;
  double        *psingle_mut;
  double        *psingle_pair;
  double         pp_pair, pp_mut;
  double         pp_pair_old, pp_mut_old;
  double         pp_pair_a, pp_mut_a;
  double         pp_pair_b, pp_mut_b;
  double         ppx;
  double         weight;
  double         weight_at_star;
  double         weight_at_zero;
  double         weight_at_infty;
  int            xl, xr, yl, yr;
  int            xpair, ypair;
  int            lmut, rmut;
  int            idxm, idxmr;
  int            idxp, idxpr;
  int            L = 5;
  int            L2;

  L2 = L * L;
 
  weight_at_zero  = 1.0;
  weight_at_star  = 0.1;
  weight_at_infty = 0.001;
  
  weight = weight_at_infty + 
    (weight_at_zero - weight_at_infty) *  EXP2(tfactor * LOG2( (weight_at_star-weight_at_infty)/(weight_at_zero-weight_at_infty) ));
  if (weight < 0.0 || weight > 1.0) Die ("imposible weigth factor (%f)\n", weight);

  /* Marginals */
  psingle_mut  = (double *) MallocOrDie (sizeof(double) * L);
  psingle_pair = (double *) MallocOrDie (sizeof(double) * L);

 
  if (verbose) {
    PrintFullRIBOCondMatrix(stdout, ribo5cond_mut,  FALSE, FALSE);
    PrintFullRIBOCondMatrix(stdout, ribo5cond_pair, TRUE,  FALSE);
  }

  /* Exponentiate */
  DExp2(ribo5cond_mut->marg->matrix,  L2);
  DExp2(ribo5cond_pair->marg->matrix, L2);

  DExp2(ribo5cond_mut->cond->matrix,  L2*L2);
  DExp2(ribo5cond_pair->cond->matrix, L2*L2);

  MarginalizeJointProbs(ribo5cond_mut->marg->matrix,  psingle_mut,  L, 2);
  MarginalizeJointProbs(ribo5cond_pair->marg->matrix, psingle_pair, L, 2);

 if (verbose) {
    PrintFullRIBOCondMatrix(stdout, ribo5cond_pair, TRUE, TRUE);
    fprintf(stdout, "pair5probs t=%f\n", tfactor);
    PrintProbs(stdout, pair5prob, L);
    fprintf(stdout, "mut5pxy t=%f\n", tfactor);
    PrintProbs(stdout, mut5pxy, L);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, psingle_pair, L);
    printf("mut5pxy marginals probabilities\n");
    PrintVectorProbs(stdout, psingle_mut, L);
  }

  /* allocate
   */
  pp = (double *) MallocOrDie (sizeof(double) * L2 * L2);

  for (xl = 0; xl < L; xl++)
    for (yl = 0; yl < L; yl++)
      for (xr = 0; xr < L; xr++)
	for (yr = 0; yr < L; yr++)
	  {
	    xpair = idx5(xl,xr);
	    ypair = idx5(yl,yr);

	    lmut = idx5(xl,yl);
	    rmut = idx5(xr,yr);
	  
	    idxm  = lmut  * L2 + rmut;
	    idxmr = rmut  * L2 + lmut;
	    idxp  = xpair * L2 + ypair;
	    idxpr = ypair * L2 + xpair;

	    /* the simple pair-to-pair functions
	     */
	    pp_pair_old  = 0.5 
	      * pair5prob[xpair] * pair5prob[ypair] 
	      * ( (mut5pxy[lmut] / (psingle_pair[xl] * psingle_pair[yl])) + (mut5pxy[rmut] / (psingle_pair[xr] * psingle_pair[yr]))     );
	    
	    pp_mut_old  = 0.5 
	      * mut5pxy[lmut] * mut5pxy[rmut]
	      * ( (pair5prob[xpair] / (psingle_mut[xl] * psingle_mut[xr])) + (pair5prob[ypair] / (psingle_mut[yl] * psingle_mut[yr])) );
	    
	    /* the RIBOSUM pair-to-pair functions
	     */
	    pp_pair_a  = 0.5 
	      * ribo5cond_pair->cond->matrix[idxp] * ribo5cond_pair->marg->matrix[xpair] 
	      * (   (ribo5cond_mut->marg->matrix[lmut] / (psingle_pair[xl] * psingle_pair[yl])) 
		    + (ribo5cond_mut->marg->matrix[rmut] / (psingle_pair[xr] * psingle_pair[yr])) );
	    
	    pp_pair_b  = 0.5 
	      * ribo5cond_pair->cond->matrix[idxpr] * ribo5cond_pair->marg->matrix[ypair]
	      * (   (ribo5cond_mut->marg->matrix[lmut] / (psingle_pair[xl] * psingle_pair[yl])) 
		    + (ribo5cond_mut->marg->matrix[rmut] / (psingle_pair[xr] * psingle_pair[yr])) );
	    
	    pp_mut_a  = 0.5 
	      * ribo5cond_mut->cond->matrix[idxm] * ribo5cond_mut->marg->matrix[lmut]
	      * (   (ribo5cond_pair->marg->matrix[xpair] / (psingle_mut[xl] * psingle_mut[xr])) 
		    + (ribo5cond_pair->marg->matrix[ypair] / (psingle_mut[yl] * psingle_mut[yr])) );
	    
	    pp_mut_b  = 0.5 
	      * ribo5cond_mut->cond->matrix[idxmr] * ribo5cond_mut->marg->matrix[rmut] 
	      * (   (ribo5cond_pair->marg->matrix[xpair] / (psingle_mut[xl] * psingle_mut[xr])) 
		    + (ribo5cond_pair->marg->matrix[ypair] / (psingle_mut[yl] * psingle_mut[yr])) );
	    
	    
	    /* Now make the actual assignations to the pair-to-pair probabilities pp
	     *
	     */
	    if ( ribo5cond_mut->marg->matrix[lmut]   == 0.0 || ribo5cond_mut->marg->matrix[rmut]   == 0.0 ||
		 ribo5cond_pair->marg->matrix[xpair] == 0.0 || ribo5cond_pair->marg->matrix[ypair] == 0.0   ) 
	      {
		pp[idxm] = 0.0;
	      }
	    
	    else 
	      {	      
		if ((xl == 4 && xr == 4) || (yl == 4 && yr == 4)) pp_mut = 0.0;
		else                                              pp_mut  = (pp_mut_a  < pp_mut_b)?  pp_mut_a  : pp_mut_b;
		
		if ((xl == 4 && xr == 4) || (yl == 4 && yr == 4)) pp_pair = 0.0;
		else                                              pp_pair = (pp_pair_a < pp_pair_b)? pp_pair_a : pp_pair_b;
		
		ppx = weight*pp_mut + (1.0-weight)*pp_pair;

		pp[idxm] = ppx;
		
	      }
	  }
  
  /* renormalize, renormalize, always renormalize! 
   *
   *           Thankfully, this is is easier than applying the renormalization group :) 
   */
  DNorm(pp, L2*L2);	
  CheckSingleProb(pp, L2*L2);
  
  if (verbose) {
    title = (char *) MallocOrDie(sizeof(char)*40);
    snprintf (title,  40, "%s--t=%.4f", "Pair-to-Pair", tfactor);
    PrintRIBOMatrix (stdout, pp, L2, FALSE, FALSE, TRUE, title);
    free(title);
  }

  if (verbose)
    compare_marginals(L, pp, mut5pxy, pair5prob, tfactor, verbose);
  
  free (psingle_mut);
  free (psingle_pair);

  return pp;
}

/* Function: pair_2_pair_addgap_prob
 *
 * Date:     ER, Tue Oct  7 17:21:14 CDT 2003 [STL]
 *
 * Purpose:  given the [5x5] evolved mutation probs, the [5x5] evolved pair probs,  and the [16x16] evolved conditional probs
 *           calculate the [25x25] joint probabilities
 *
 *                  X_l    X_r
 *              P(             )
 *                  Y_l    Y_r
 *
 *
 * Args:     
 *
 * Returns:  pp. pp is allocated and filled here. pp freed by caller.
 */
double *
pair_2_pair_addgap_prob (fullcondmat_t *ribocond_pair, double *mut5pxy, double *pair5prob, double tfactor, int verbose)
{
  char          *title;
  double        *pp5;
  double        *pmx, *pmy;
  double        *ppl, *ppr;
  double         ppx;
  double         ppx_mut;
  double         ppx_pair_a;
  double         ppx_pair_b;
  double         ppx_pair;
  double         ppxadd_mut, ppxadd_pair;
  double         weight;
  double         weight_at_star;
  double         weight_at_zero;
  double         weight_at_infty;
  int            xl, xr, yl, yr;
  int            xpair, ypair;
  int            lmut, rmut;
  int            idxp, idxpr;
  int            idxm, idxmr;
  int            xpair5, ypair5;
  int            lmut5, rmut5;
  int            idxm5, idxmr5;
  int            idxp5, idxpr5;
  int            L, L5;
  int            LSQ, L5SQ;

  L = ribocond_pair->marg->size;

  L5 = L + 1;

  LSQ =  L  * L;
  L5SQ = L5 * L5;
 
  weight_at_zero  = 1.0;
  weight_at_star  = 0.1;
  weight_at_infty = 0.001;
  
  weight = weight_at_infty + 
    (weight_at_zero - weight_at_infty) *  EXP2(tfactor * LOG2( (weight_at_star-weight_at_infty)/(weight_at_zero-weight_at_infty) ));
  if (weight < 0.0 || weight > 1.0) Die ("imposible weigth factor (%f)\n", weight);

  pmx = (double *) MallocOrDie (sizeof(double) * L5);
  pmy = (double *) MallocOrDie (sizeof(double) * L5);
  ppl = (double *) MallocOrDie (sizeof(double) * L5);
  ppr = (double *) MallocOrDie (sizeof(double) * L5);

  MarginalizeJointProbs(mut5pxy,   pmx, L5, 0);
  MarginalizeJointProbs(mut5pxy,   pmy, L5, 1);
  MarginalizeJointProbs(pair5prob, ppl, L5, 0);
  MarginalizeJointProbs(pair5prob, ppr, L5, 1);

 if (verbose) {
    PrintFullRIBOCondMatrix(stdout, ribocond_pair, TRUE,  FALSE);
    fprintf(stdout, "pair5probs t=%f\n", tfactor);
    PrintProbs(stdout, pair5prob, L5);
    fprintf(stdout, "mut5pxy t=%f\n", tfactor);
    PrintProbs(stdout, mut5pxy, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, ppl, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, ppr, L5);
    printf("mut5pxy marginals probabilities\n");
    PrintVectorProbs(stdout, pmx, L5);
    printf("mut5pxy marginals probabilities\n");
    PrintVectorProbs(stdout, pmy, L5);
  }

  /* allocate
   */
  pp5 = (double *) MallocOrDie (sizeof(double) * L5SQ * L5SQ);

  /* the RIBOSUM pair-to-pair functions with gaps
   */
  for (xl = 0; xl < L5; xl++)
    for (yl = 0; yl < L5; yl++)
      for (xr = 0; xr < L5; xr++)
	for (yr = 0; yr < L5; yr++)
	  {
	    xpair5 = xl*L5 + xr;
	    ypair5 = yl*L5 + yr;
	    
	    lmut5  = xl*L5 + yl;
	    rmut5  = xr*L5 + yr;

	    idxm5  = lmut5  * L5SQ + rmut5;
	    idxmr5 = rmut5  * L5SQ + lmut5;

	    idxp5  = xpair5 * L5SQ + ypair5;
	    idxpr5 = ypair5 * L5SQ + xpair5;

	    ppxadd_mut  = LOG2( pair5prob[xpair5]/(ppl[xl]*ppr[xr]) + pair5prob[ypair5]/(ppl[yl]*ppr[yr]) ) - 1.0;
	    ppxadd_pair = LOG2( mut5pxy[lmut5]   /(pmx[xl]*pmy[yl]) + mut5pxy[rmut5]   /(pmx[xr]*pmy[yr]) ) - 1.0;

	    if (xl < L && yl < L && xr < L && yr < L) {
	      
	      xpair = xl*L + xr;
	      ypair = yl*L + yr;

	      idxm  = lmut  * LSQ + rmut;
	      idxmr = rmut  * LSQ + lmut;

	      idxp  = xpair * LSQ + ypair;
	      idxpr = ypair * LSQ + xpair;
	      
	      ppx_pair_a = EXP2(ribocond_pair->cond->matrix[idxp])*pair5prob[xpair5]; 
	      ppx_pair_b = EXP2(ribocond_pair->cond->matrix[idxpr])*pair5prob[ypair5];
	      
	      ppx_pair = LOG2(ppx_pair_a + ppx_pair_b) - 1.0;

	      ppx = ppx_pair + ppxadd_mut;
	      
	    }
	    else { /* assume independence */
	      ppx_pair = LOG2(pair5prob[xpair5]) + LOG2(pair5prob[ypair5]) + ppxadd_pair;
	      ppx_mut  = LOG2(mut5pxy[lmut5])    + LOG2(mut5pxy[rmut5])    + ppxadd_mut;

	      ppx = weight*ppx_mut + (1.0-weight)*ppx_pair;
	      ppx = ppx_pair;
	    }

	    pp5[idxm5] = ppx;

	  }
  
  /* renormalize, renormalize, always renormalize! 
   *
   *   Thankfully, this is easier than applying the renormalization group :) 
   */
  DLog2Norm(pp5, L5SQ*L5SQ);	
  CheckSingleLog2Prob(pp5, L5SQ*L5SQ);

  DExp2(pp5, L5SQ*L5SQ);
  
  if (verbose) {
    title = (char *) MallocOrDie(sizeof(char)*40);
    snprintf (title,  40, "%s--t=%.4f", "Pair-to-Pair", tfactor);
    PrintRIBOMatrix (stdout, pp5, L5SQ, FALSE, FALSE, TRUE, title);
    free(title);
  }

  if (verbose)
    calculatePPderivedprobs(stdout, pp5, L5);
  
  free(pmx);
  free(pmy);
  free(ppl);
  free(ppr);

  return pp5;
}

/* Function: RNAmodelTransitionProbabilities()
 * Date:     ER, Tue Aug 13 19:19:55 CDT 2002  [St. Louis]
 *
 * Purpose:  Constructs a rnamodel_s
 *
 * Args:     RNAparam - the list of parameters that define a RNAmodel           
 *
 * Returns:  (void)
 *           fills all prob's for rnamodel, log2 form 
 *           (allc'ed here, freed by caller)
 */
void     
RNAmodelTransitionProbabilities(double tfactor, struct rnamodel_s *rna, int pedantic, int verbose)
{
  double           **T;                        /* 2x2 matrix of transition probs.          +*/
  double           **R_diag;                   /* 2x2 matrix of transition probs.          +*/
  double           **T_zero;                   /* 2x2 matrix of transition probs.          +*/
  double           **T_infty;                  /* 2x2 matrix of transition probs.          +*/
  int                dim;
  int                i;

  dim = 2;
  /* Convert 
   *         conditional probabilities T(ab, t_o) 
   *   to 
   *         conditional probabilities T(ab, tfactor*t_o)
   */

  /* allocate Rate matrices
   */
  R_diag = (double **) MallocOrDie (sizeof(double *) * dim);

   /* 24 JUL 02
   *
   * The evolutionary RNA model is as follows: T 
   *
   *       - A 2x2 matrix for transitions T               RNA      ROE                          
   *                                               ROB  |  psi    1-psi |
   *                                     T =            |               |   *                                               RNA  | 1-eta    eta  |
   * 
   *
   *               at t=0                               |  1        0   |
   *                                   T_0 =            |               |
   *                                                    |  0        1   |
   *
   */
  T       = rna_transition_matrix(RNAparam,       dim);
  T_zero  = rna_transition_matrix(RNAparam_zero,  dim);
  T_infty = rna_transition_matrix(RNAparam_infty, dim);

  for (i = 0; i < dim; i++) {
    R_diag[i] = TransitionsExpVector(T[i], T_zero[i], T_infty[i], dim);
    TransitionsEvolved(stdout, T[i], T_zero[i], T_infty[i], R_diag[i], dim, tfactor, FALSE, FALSE); 
  }  
  
  /* recalculate RNA model transitions */
  rna->t[TROBRNA] = T[0][0];   
  rna->t[TROBROE] = T[0][1];   
  rna->t[TRNAROJ] = T[1][0];   
  rna->t[TRNAROE] = T[1][1];   
  rna->t[TROJRNA] = 1.0;   
  rna->t[TROEROE] = 1.0;   

  free(T[0]);
  free(T_zero[0]);
  free(T_infty[0]);
  for (i = 0; i < dim; i++) free(R_diag[i]);

  free(T);
  free(T_zero);
  free(T_infty);
  free(R_diag);

}

/* Function: RNAparam_fit_to_length
 * Date:     ER, Thu Jul 17 10:05:58 CDT 2003  [St. Louis]
 *
 * Purpose:  
 *
 * Args:           
 *
 * Returns:  (void)
 *
 *
 */
void     
RNAparam_fit_to_length(int len, struct scfg_param_s *ret_scfg_param, struct pi2model_s *pi2, int verbose)
{
  struct scfg_param_s scfg_param;
  double              is2b_mean_len;
  double              is2i_mean_len;
  double              is2_mean_len;
  double              is1_mean_len;
  double              gamma;
  double              gammap;
  double              sigma;
  double              rho;
  double              top;
  double              bottom;
  double              a, p;

  
  scfg_param = *ret_scfg_param;

  /* calculate mean length of hairpin and bulges and internal loops
   */
  DistributionMean(pi2->is1->tn,  MAXRNALOOP, &is1_mean_len);
  DistributionMean(pi2->is2b->tn, MAXRNALOOP, &is2b_mean_len);
  DistributionMean(pi2->is2i->tn, MAXRNALOOP, &is2i_mean_len);

  is1_mean_len  -= 1.0;  /* number emitted nts = len - 2 */
  is2b_mean_len -= 2.0;  /* number emitted nts = len - 2 */
  is2i_mean_len -= 2.0;  /* number emitted nts = len - 2 */

  is2_mean_len = scfg_param.vt.v2b * is2b_mean_len +  scfg_param.vt.v2i * is2i_mean_len;
  
  gamma  = (1.0 - (scfg_param.wt.wv  + scfg_param.wt.www) ) / (scfg_param.wt.wv  - scfg_param.wt.www ); 
  gammap = (1.0 - (scfg_param.wbt.wv + scfg_param.wbt.www)) / (scfg_param.wbt.wv - scfg_param.wbt.www); 
  sigma  = (scfg_param.wbt.wv + scfg_param.wbt.www) / (scfg_param.wbt.wv - scfg_param.wbt.www);
  rho    = scfg_param.wt.wv                         / (scfg_param.wt.wv  - scfg_param.wt.www);

  if (gamma  < 0.0) Die ("RNAparam_fit_to_length(): gamma  has to be positive (%f)\n", gamma);
  if (gammap < 0.0) Die ("RNAparam_fit_to_length(): gammap has to be positive (%f)\n", gammap);
  if (sigma  < 0.0) Die ("RNAparam_fit_to_length(): sigma  has to be positive (%f)\n", sigma);
  if (rho    < 0.0) Die ("RNAparam_fit_to_length(): rho    has to be positive (%f)\n", rho);

  top    = rho*(2.0+is2_mean_len) + scfg_param.vt.v3 * ( rho*(2.0*gammap - is2_mean_len) + sigma*((double)len - gamma) ); 
  bottom = (double)len - gamma - rho*(is1_mean_len - is2_mean_len); 
  
  if ((top > 0.0 && bottom < 0.0) || (top < 0.0 && bottom > 0.0)) Die ("RNAparam_fit_to_length(): vt.t1 has to be positive (%f)", top/bottom);

  scfg_param.vt.v1 = top / bottom; 
  if (scfg_param.vt.v1 > 1.0) Die ("RNAparam_fit_to_length(): vt.t1 has to be a proability (%f)", scfg_param.vt.v1);

  scfg_param.vt.v1 /= (1.0 - SCFGparam.vt.v3); 

  a = scfg_param.vt.v1 * (1.0 - SCFGparam.vt.v3);
  p = (1.0 - scfg_param.vt.v1) * (1.0 - SCFGparam.vt.v3);

  if (FALSE) printf(" a = %f p = %f t3 = %f\n", a, p, scfg_param.vt.v3);

  *ret_scfg_param = scfg_param;
}




/* Function: rna_transfer_matrix()
 * Date:     ER, Wed Jul 24 17:18:18 CDT 2002 [STL]
 *
 * Purpose:  Fill the rna model transition matrix T
 *
 *
 *                           RNA       ROE
 *                    
 *                     ROB   psi      1-psi     
 *           T    =   
 *                     RNA  1-eta      eta  
 *              
 * Args:     
 *
 * Returns:  void. T is allocated and filled here. T freed by caller.
 */
double **
rna_transition_matrix(struct rnaparam_s rnaparam, int dim)
{
  double **T;
  int      row, col, idx;

  /* allocate T
   */
  T     = (double **) MallocOrDie (sizeof(double *) * dim      );
  T[0]  = (double  *) MallocOrDie (sizeof(double  ) * dim * dim);

  for (row = 1; row < dim; row++)
    T[row] = T[0] + row*dim;

  /* fill T
   * 
   */
  for (row = 0; row < dim; row++) 
    for (col = 0; col < dim; col++) {

      idx = row*dim + col;

	if      (idx == 0)  T[row][col] = rnaparam.psi;
	else if (idx == 1)  T[row][col] = 1.0 - rnaparam.psi;
	else if (idx == 2)  T[row][col] = 1.0 - rnaparam.eta;
	else if (idx == 3)  T[row][col] = rnaparam.eta;
    }
  
  if (FALSE) {
    printf("T - RNA transition matrix\n");
    for (row = 0; row < dim; row++) {
      for (col = 0; col < dim; col++) {
	printf("%.4f ", T[row][col]);
    }
      printf("\n");
    }
  }

  /* Check they are conditional probabilities
   */
  for (row = 0; row < dim; row++) 
    CheckSingleProb(T[row], dim);
     
  return T;
}

/* Function: rna_transfermatrix_at_infty()
 * Date:     ER, Fri Aug  2 10:30:52 CDT 2002 [St. Louis]
 *
 * Purpose:  Fill T_infty the transfer matrix for the RNA model at fixation
 *
 * Args:     T_infty -- transfer matrix for the RNA model at fixaion
 *
 *
 *                           RNA       ROE
 *                    
 *                     ROB   1/2       1/2     
 *           T_zero  =   
 *                     RNA   1/2       1/2  
 *              
 *
 *
 * Returns:  T_zero is allocated and filled here. T_zero freed by caller.
 */
double **
rna_transition_matrix_at_infty(double **T, double **T_zero, int dim)
{
  double **T_infty;
  int      row, col;

  /* allocate T_zero
   */
  T_infty     = (double **) MallocOrDie (sizeof(double *) * dim      );
  T_infty[0]  = (double  *) MallocOrDie (sizeof(double  ) * dim * dim);

  for (row = 1; row < dim; row++)
    T_infty[row] = T_infty[0] + row*dim;

  /* fill T_zero.
   * this is done totally ad hoc, just assuming no gaps at zero evolutionary distance,
   * 
   */
  for (row = 0; row < dim; row++)
    for (col = 0; col < dim; col++)
      T_infty[row][col] = 1.0/(float)dim;

  if (FALSE) {
    printf("T_infty - RNA transfer matrix\n");
    for (row = 0; row < dim; row++) {
      for (col = 0; col < dim; col++) {
	printf("%.4f ", T_infty[row][col]);
      }
      printf("\n");
    }
  }

  /* Check they are conditional probabilities
   */
  for (row = 0; row < dim; row++) 
    CheckSingleProb(T_infty[row], dim);
   
  return T_infty;
}


double **
rna_transition_matrix_Rdiag(int dim)
{
  double **R_diag;
  int      row, col;

  /* allocate R_diag
   */
  R_diag    = (double **) MallocOrDie (sizeof(double *) * dim      );
  R_diag[0] = (double  *) MallocOrDie (sizeof(double  ) * dim * dim);

  for (row = 1; row < dim; row++)
    R_diag[row] = R_diag[0] + row*dim;

  /* fill R_diag.
   */
  for (row = 0; row < dim; row++) 
    for (col = 0; col < dim; col++)  
      R_diag[row][col] = 0.0;
  
  if (FALSE) {
    printf("RB_diag - RNA transfer matrix\n");
    for (row = 0; row < dim; row++) {
      for (col = 0; col < dim; col++) {
	printf("%.4f ", R_diag[row][col]);
      }
      printf("\n");
    }
  }
  
  return R_diag;
}

double **
rna_transition_matrix_rate(int dim)
{
  double **R;
  int      row, col;

  /* allocate T_rate
   */
  R    = (double **) MallocOrDie (sizeof(double *) * dim      );
  R[0] = (double  *) MallocOrDie (sizeof(double  ) * dim * dim);

  for (row = 1; row < dim; row++)
    R[row] = R[0] + row*dim;

  /* fill T_rate.
   * 
   */
    for (row = 0; row < dim; row++) 
      for (col = 0; col < dim; col++)  
	R[row][col] = 0.5;
      
  if (FALSE) {
    printf("TB_rate - RNA transfer matrix\n");
    for (row = 0; row < dim; row++) {
      for (col = 0; col < dim; col++) {
	printf("%.4f ", R[row][col]);
      }
      printf("\n");
    }
  }
  
  return R;
}


/* Function: SCFGTransitionProbabilities()
 * Date:     ER, Wed Sep 25 13:03:29 CDT 2002  [St. Louis]
 *
 * Purpose:  Constructs a rnamodel_s
 *
 * Args:     SCFGparam - the list of parameters that define the SCFG           
 *
 * Returns:  (void)
 *           fills all prob's for rnamodel, log2 form 
 *           (allc'ed here, freed by caller)
 */
void     
SCFGTransitionProbabilities(int len, double tfactor, struct pi2model_s *pi2, int pedantic, int verbose)
{
  double           *VT;                        /* 1x5 matrix of transition probs.          +*/
  double           *VTR_diag;                  /* 1x5 matrix of transition probs.          +*/
  double           *VT_zero;                   /* 1x5 matrix of transition probs.          +*/
  double           *VT_infty;                  /* 1x5 matrix of transition probs.          +*/
  double           *WT;                        /* 1x4 matrix of transition probs.          +*/
  double           *WTR_diag;                  /* 1x4 matrix of transition probs.          +*/
  double           *WT_zero;                   /* 1x4 matrix of transition probs.          +*/
  double           *WT_infty;                  /* 1x4 matrix of transition probs.          +*/
  double           *WBT;                       /* 1x4 matrix of transition probs.          +*/  
  double           *WBTR_diag;                 /* 1x4 matrix of transition probs.          +*/
  double           *WBT_zero;                  /* 1x4 matrix of transition probs.          +*/
  double           *WBT_infty;                 /* 1x4 matrix of transition probs.          +*/
  int               dimV, dimW;
  int               t;

  dimV = 5;
  dimW = 4;
  /* Convert 
   *         conditional probabilities T(ab, t_o) 
   *   to 
   *         conditional probabilities T(ab, tfactor*t_o)
   */

  /* 
   *
   * The evolutionary RNA model is as follows: T 
   *
   *       - A 2x2 matrix for transitions T               RNA      ROE                          
   *                                               ROB  |  psi    1-psi |
   *                                     T =            |               |
   *                                               RNA  | 1-eta    eta  |
   * 
   *
   *               at t=0                               |  1        0   |
   *                                   T_0 =            |               |
   *                                                    |  0        1   |
   *
   */
  /* Modify SCFGparam.vt.v1 according to the expected length of the motif
   */
  RNAparam_fit_to_length(len, &SCFGparam,       pi2, verbose);
  RNAparam_fit_to_length(len, &SCFGparam_zero,  pi2, verbose);
  RNAparam_fit_to_length(len, &SCFGparam_infty, pi2, verbose);
  
  /* VT */
  VT       = V_transition_matrix(SCFGparam.vt,       dimV);
  VT_zero  = V_transition_matrix(SCFGparam_zero.vt,  dimV);
  VT_infty = V_transition_matrix(SCFGparam_infty.vt, dimV);

  /* WT */
  WT       = W_transition_matrix(SCFGparam.wt,       dimW);
  WT_zero  = W_transition_matrix(SCFGparam_zero.wt,  dimW);
  WT_infty = W_transition_matrix(SCFGparam_infty.wt, dimW);
 
  /* WBT */
  WBT       = W_transition_matrix(SCFGparam.wbt,  dimW);
  WBT_zero  = W_transition_matrix(SCFGparam_zero.wbt,  dimW);
  WBT_infty = W_transition_matrix(SCFGparam_infty.wbt, dimW);
 
  VTR_diag  = TransitionsExpVector(VT,  VT_zero,  VT_infty,  dimV);
  WTR_diag  = TransitionsExpVector(WT,  WT_zero,  WT_infty,  dimW);
  WBTR_diag = TransitionsExpVector(WBT, WBT_zero, WBT_infty, dimW);
 
  TransitionsEvolved(stdout, VT,  VT_zero,  VT_infty,  VTR_diag,  dimV, tfactor, FALSE, FALSE); 
  TransitionsEvolved(stdout, WT,  WT_zero,  WT_infty,  WTR_diag,  dimW, tfactor, FALSE, FALSE); 
  TransitionsEvolved(stdout, WBT, WBT_zero, WBT_infty, WBTR_diag, dimW, tfactor, FALSE, FALSE); 

  DNorm(VT,  dimV);
  DNorm(WT,  dimW);
  DNorm(WBT, dimW);

  if (verbose) {
    fprintf(stdout, "\nT(i->j | t)  Transition probabilities at time %.3f\n", tfactor);
    fprintf(stdout, "V\n");
    for (t = 0; t < dimV; t++) 
      fprintf(stdout, "%.4f ", VT[t]);
    fprintf(stdout, "\nW\n");
    for (t = 0; t < dimW; t++) 
      fprintf(stdout, "%.4f ", WT[t]);
    fprintf(stdout, "\nWB\n");
    for (t = 0; t < dimW; t++) 
      fprintf(stdout, "%.4f ", WBT[t]);
    fprintf(stdout, "\n");
  }
   

  /* recalculate SCFG model transitions */
  pi2->v->t1  = VT[0];
  pi2->v->t2s = VT[1];
  pi2->v->t2b = VT[2];
  pi2->v->t2i = VT[3];
  pi2->v->t3  = VT[4];

  pi2->w->tl = WT[0];
  pi2->w->tr = WT[1];
  pi2->w->tv = WT[2];
  pi2->w->tw = WT[3];

  pi2->wb->tl = WBT[0];
  pi2->wb->tr = WBT[1];
  pi2->wb->tv = WBT[2];
  pi2->wb->tw = WBT[3];

  free(VT);
  free(WT);
  free(WBT);
  free(VT_zero);
  free(WT_zero);
  free(WBT_zero);
  free(VT_infty);
  free(WT_infty);
  free(WBT_infty);
  free(VTR_diag);
  free(WTR_diag);
  free(WBTR_diag);

}

/* Function: V_transition_matrix()
 * Date:     ER, Wed Sep 25 16:55:00 CDT 2002 [STL]
 *
 * Purpose:  Fill the scfg-rna model transition matrix VT
 *
 *
 * Args:     
 *
 * Returns:  void. VT is allocated and filled here. VT freed by caller.
 */
double *
V_transition_matrix(struct rna_v_param_s vt, int dim)
{
  double *VT;
  int     idx;

  /* allocate VT
   */
  VT = (double *) MallocOrDie (sizeof(double) * dim);

  /* fill VT
   * 
   */
    for (idx = 0; idx < dim; idx++) {
      if      (idx == 0)  VT[idx] = vt.v1  * (1.0 - vt.v3);
      else if (idx == 1)  VT[idx] = vt.v2s * (1.0 - vt.v3) * (1.0 - vt.v1);
      else if (idx == 2)  VT[idx] = vt.v2b * (1.0 - vt.v3) * (1.0 - vt.v1);
      else if (idx == 3)  VT[idx] = vt.v2i * (1.0 - vt.v3) * (1.0 - vt.v1);
      else if (idx == 4)  VT[idx] = vt.v3;
    }
    
    if (FALSE) {
    printf("VT - SCFG transition matrix\n");

    for (idx = 0; idx < dim; idx++) 
	printf("%.4f ", VT[idx]);
      printf("\n");
    }
    
    /* Check they are conditional probabilities
     */
    CheckSingleProb(VT, dim);
    
    return VT;
}
double *
V_transition_matrix_from_data(struct rna_v5 *v, int dim)
{
  double *VT;
  int     idx;

  /* allocate VT
   */
  VT = (double *) MallocOrDie (sizeof(double) * dim);

  /* fill VT
   * 
   */
    for (idx = 0; idx < dim; idx++) {
      if      (idx == 0)  VT[idx] = v->t1;
      else if (idx == 1)  VT[idx] = v->t2s;
      else if (idx == 2)  VT[idx] = v->t2b;
      else if (idx == 3)  VT[idx] = v->t2i;
      else if (idx == 4)  VT[idx] = v->t3;
    }
    
    if (FALSE) {
    printf("VT - SCFG transition matrix\n");

    for (idx = 0; idx < dim; idx++) 
	printf("%.4f ", VT[idx]);
      printf("\n");
    }
    
    /* Check they are conditional probabilities
     */
    CheckSingleProb(VT, dim);
    
    return VT;
}


/* Function: W_transition_matrix()
 * Date:     ER, Wed Sep 25 16:55:00 CDT 2002 [STL]
 *
 * Purpose:  Fill the scfg-rna model transition matrix W
 *
 *
 * Args:     
 *
 * Returns:  void. WT is allocated and filled here. WT freed by caller.
 */
double *
W_transition_matrix(struct rna_w_param_s wt, int dim)
{
  double *WT;
  int     idx;

  /* allocate WT
   */
  WT = (double *) MallocOrDie (sizeof(double) * dim);

  /* fill WT
   * 
   */
    for (idx = 0; idx < dim; idx++) {
      if      (idx == 0)  WT[idx] = wt.wl * (1.0 - wt.www);
      else if (idx == 1)  WT[idx] = wt.wr * (1.0 - wt.www);
      else if (idx == 2)  WT[idx] = wt.wv * (1.0 - wt.www);
      else if (idx == 3)  WT[idx] = wt.www;
    }
    
    if (FALSE) {
    printf("WT - SCFG transition matrix\n");

    for (idx = 0; idx < dim; idx++) 
	printf("%.4f ", WT[idx]);
      printf("\n");
    }
    
    /* Check they are conditional probabilities
     */
    CheckSingleProb(WT, dim);
    
    return WT;
}
double *
W_transition_matrix_from_data(struct rna_w5 *w, int dim)
{
  double *WT;
  int     idx;

  /* allocate WT
   */
  WT = (double *) MallocOrDie (sizeof(double) * dim);

  /* fill WT
   * 
   */
    for (idx = 0; idx < dim; idx++) {
      if      (idx == 0)  WT[idx] = w->tl;
      else if (idx == 1)  WT[idx] = w->tr;
      else if (idx == 2)  WT[idx] = w->tv;
      else if (idx == 3)  WT[idx] = w->tw;
    }
    
    if (FALSE) {
    printf("WT - SCFG transition matrix\n");

    for (idx = 0; idx < dim; idx++) 
	printf("%.4f ", WT[idx]);
      printf("\n");
    }
    
    /* Check they are conditional probabilities
     */
    CheckSingleProb(WT, dim);
    
    return WT;
}

