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

/* riboprob.c
 * Functions to deal with the RIBOPROB matrices
 * ER,Tue Jan 28 17:48:54 CST 2003  [STL]
 */
#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"


static double  cal_RIBO_lambda(FILE *ofp, double *S, double *pmxl, double *pmxr, double *pmyl, double *pmyr, int L, int verbose);
static double  calfunc (double x, double *S, double *pmxl, double *pmxr, double *pmyl, double *pmyr, int L);
static double  caldfunc(double x, double *S, double *pmxl, double *pmxr, double *pmyl, double *pmyr, int L);
static int     compare_2_freqs(double *pml, double *pmr, double *targetfreq, int L);
static int     compare_freqs(double *pml, double *pmxl, double *pmxr, double *pmyl, double *targetfreq, int L);
static void    lone_MUT_cond  (int idx, int L, double *cond_mut_mtx,  double *mut5pxy);
static void    lone_PAIR_cond (int idx, int L, double *cond_pair_mtx, double *pair5prob);


/* Function: AllocFullMatrix()
 * Date:     ER, Wed Jan 22 14:20:31 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  allocate fullmat structure
 *
 * Args:     
 *
 * Returns:  void
 *           fullmat is allocated here
 */
fullmat_t *
AllocFullMatrix (int L) 
{
  fullmat_t *fullmat;
  
  fullmat = (fullmat_t *) MallocOrDie(sizeof(fullmat_t));

  fullmat->name = (char *) MallocOrDie(sizeof(char)*40);       /* More than enough */

  fullmat->unpaired = AllocMatrix (L);
  fullmat->paired   = AllocMatrix (L*L);

  return fullmat;
} 

fullcondmat_t *
AllocFullCondMatrix (int L) {

  fullcondmat_t *fullcondmat;

  fullcondmat = (fullcondmat_t *) MallocOrDie(sizeof(fullcondmat_t));
 
  fullcondmat->name = (char *) MallocOrDie(sizeof(char)*40);       /* More than enough */

  fullcondmat->marg = AllocCondMatrix (L);
  fullcondmat->cond = AllocCondMatrix (L*L);

  return fullcondmat;
} 

matrix_t *
AllocMatrix (int L) 
{
  matrix_t *mat;
  int c;

 mat = (matrix_t *) MallocOrDie(sizeof(matrix_t));

  mat->edge_size = L;
  mat->full_size = L*(L+1)/2;

  mat->matrix = (double *) MallocOrDie (sizeof(double) * mat->full_size);

  for (c = 0; c < mat->full_size; c++) 
    mat->matrix[c] = 0.0;

  mat->E = 0.0;
  mat->H = 0.0;

  return mat;
}

condmatrix_t *
AllocCondMatrix (int L) 
{
  condmatrix_t *condmat;
  int           x;

  condmat = (condmatrix_t *) MallocOrDie(sizeof(condmatrix_t));
  
  condmat->size = L;
  
  condmat->matrix = (double *) MallocOrDie (sizeof(double) * condmat->size * condmat->size);
  
  for (x = 0; x < condmat->size * condmat->size; x++) 
    condmat->matrix[x] = 0.0;
  
  return condmat;
}



/* Function: CalculatePPConditionalsAndMarginals()
 *
 *           ER,Wed Oct  8 10:37:05 CDT 2003 [St. Louis]
 *
 * Purpose:  Given       a LxLLxL matrix P(i,j)  of pair probabilities 
 *           calculate the LxL matrix Ql(i,j) of conditional probabilities.
 *           calculate the L   vector ml(i)   of marginal probabilities.
 *
 *           ml[i]     = \sum_k  P(i,k|t_o) 
 *
 *           Ql[i*L+j] = P(j|i, t_o) = P(i,j|t_o) / ml[i]
 *
 *           where P(i,j|t_o) are calculated according to 
 *           using a given pammodel t_o.
 *
 *           Notice that if P(i,j) are not real joint probs (ie non symmetric)
 *           this function calculates the LEFT conditionals and LEFT marginals.
 *
 * Args:     P  - LxL joint prob matrix (prealloc)
 *
 * Returns:  Ql(LxL), conditional probabilities.
 *           ml(L),   marginal probabilities.
 *           Q and ml are alocated here, freed by caller.
 */
void
CalculatePPConditionalsAndMarginals(FILE *ofp, double *pp, double **ret_Qx, double **ret_Qy, double **ret_Ql, double **ret_Qr, 
				    double **ret_pairx, double **ret_pairy, double **ret_pmutl, double **ret_pmutr, int L, int verbose)
{
  double *pairx;
  double *pairy;
  double *pmutl;
  double *pmutr;
  double *Qx;
  double *Qy;
  double *Ql;
  double *Qr;
  double  ppp;
  double  ppx, ppy;
  double  ppl, ppr;
  int     LSQ;
  int     xl, yl, xr, yr;
  int     xpair, ypair;
  int     lmut, lmutr;
  int     rmut, rmutr;
  int     idxm, idxmr;
  int     idxp, idxpr;
  int     i;
  int     no_Qx = FALSE;
  int     no_Qy = FALSE;
  int     no_Ql = FALSE;
  int     no_Qr = FALSE;
 
  LSQ = L * L;

  /* paranoia */
  CheckSingleProb(pp, LSQ * LSQ);

  if (verbose) {
    fprintf(ofp, "pair-to-pair Probs\n");
    PrintProbs(ofp, pp, LSQ);
  }
  
  /* allocate memory
   */
  Qx = (double *) MallocOrDie (sizeof(double) * LSQ * LSQ);
  Qy = (double *) MallocOrDie (sizeof(double) * LSQ * LSQ);
  Ql = (double *) MallocOrDie (sizeof(double) * LSQ * LSQ);
  Qr = (double *) MallocOrDie (sizeof(double) * LSQ * LSQ);

  for (i = 0; i < LSQ*LSQ; i++) {
    Qx[i] = -1.0;
    Qy[i] = -1.0;
    Ql[i] = -1.0;
    Qr[i] = -1.0;
  }
  
  CalculatePPMarginals(ofp, pp, &pairx, &pairy, &pmutl, &pmutr, L, verbose);

  /* calculate PAIR conditionals
   */
  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 = xl * L + xr;
	    ypair = yl * L + yr;
	    
	    lmut  = xl * L + yl;
	    rmut  = xr * L + yr;

	    lmutr = yl * L + xl;
	    rmutr = yr * L + xr;
	    
	    idxm  = lmut  * LSQ + rmut;
	    idxp  = xpair * LSQ + ypair;
	    idxmr = lmutr * LSQ + rmutr;

	    if      (pp[idxm] >   0.0 && pairx[xpair] > 0.0) Qx[idxp] = pp[idxm]  / pairx[xpair]; 
	    else if (pp[idxm] ==  0.0 && pairx[xpair] > 0.0) Qx[idxp] = 0.0;
	    else    no_Qx = TRUE;

	    if      (pp[idxmr] >  0.0 && pairy[xpair] > 0.0) Qy[idxp] = pp[idxmr] / pairy[xpair]; 
	    else if (pp[idxmr] == 0.0 && pairy[xpair] > 0.0) Qy[idxp] = 0.0;
	    else    no_Qy = TRUE;
	  }
  /* consistency check, rows should add up to one
   */
  if (!no_Qx)
    for (i = 0; i < LSQ; i++)
      CheckSingleProb(Qx+i*LSQ, LSQ);
  if (!no_Qy)
    for (i = 0; i < LSQ; i++)
      CheckSingleProb(Qy+i*LSQ, LSQ);
  
  /* calculate MUT conditionals
   */
  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 = xl * L + xr;
	    ypair = yl * L + yr;
	    
	    lmut  = xl * L + yl;
	    rmut  = xr * L + yr;
	    
	    idxm  = lmut * LSQ + rmut;
	    idxmr = rmut * LSQ + lmut;

	    if      (pp[idxm] >   0.0 && pmutl[lmut] > 0.0) Ql[idxm] = pp[idxm]  / pmutl[lmut]; 
	    else if (pp[idxm] ==  0.0 && pmutl[lmut] > 0.0) Ql[idxm] = 0.0;
	    else    no_Ql = TRUE;
	    if      (pp[idxmr] >  0.0 && pmutr[lmut] > 0.0) Qr[idxm] = pp[idxmr] / pmutr[lmut]; 
	    else if (pp[idxmr] == 0.0 && pmutr[lmut] > 0.0) Qr[idxm] = 0.0;
	    else    no_Qr = TRUE;
	  }

  /* consistency check, rows should add up to one
   */
  if (!no_Ql)
    for (i = 0; i < LSQ; i++)
      CheckSingleProb(Ql+i*LSQ, LSQ);
  if (!no_Qr)
    for (i = 0; i < LSQ; i++)
      CheckSingleProb(Qr+i*LSQ, LSQ);
  
  /* make sure that you calculated marginals and conditionals right
   */
  if (verbose) {
    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 = xl * L + xr;
	      ypair = yl * L + yr;
	      
	      lmut  = xl * L + yl;
	      rmut  = xr * L + yr;
	      
	      idxm  = lmut  * LSQ + rmut;
	      idxmr = rmut  * LSQ + lmut;
	      
	      idxp  = xpair * LSQ + ypair;
	      idxpr = ypair * LSQ + xpair;
	      
	      ppx = Qx[idxp]  * pairx[xpair];
	      ppy = Qy[idxpr] * pairy[ypair];
	      
	      ppl = Ql[idxm]  * pmutl[lmut];
	      ppr = Qr[idxmr] * pmutr[rmut];
	      
	      ppp = pp[idxm];
	      
	      if (fabs(ppx-ppp) > 1.0-accuracy1) Die ("CalculatePPConditionalsAndMarginals(); Bad Qx matrix\n"); 
	      if (fabs(ppy-ppp) > 1.0-accuracy1) Die ("CalculatePPConditionalsAndMarginals(); Bad Qy matrix\n"); 
	      if (fabs(ppl-ppp) > 1.0-accuracy1) Die ("CalculatePPConditionalsAndMarginals(); Bad Ql matrix\n"); 
	      if (fabs(ppr-ppp) > 1.0-accuracy1) Die ("CalculatePPConditionalsAndMarginals(); Bad Qr matrix\n"); 
	      
	    }
  }
  
  if (verbose) {
    printf("X-PAIR MARG probabilities\n");
    PrintProbs(ofp, pairx, L);
    printf("Y-PAIR MARG probabilities\n");
    PrintProbs(ofp, pairy, L);
    printf("L-MUT MARG probabilities\n");
    PrintProbs(ofp, pmutl, L);
    printf("R-MUT MARG probabilities\n");
    PrintProbs(ofp, pmutr, L);
    
    if (!no_Qx) {
      fprintf(ofp, "X-PAIR Conditionals\n");
      PrintProbs(ofp, Qx, LSQ);
    }
    if (!no_Qy) {
      fprintf(ofp, "Y-PAIR Conditionals\n");
      PrintProbs(ofp, Qy, LSQ);
    }
    if (!no_Ql) {
      fprintf(ofp, "L-MUT Conditionals\n");
      PrintProbs(ofp, Ql, LSQ);
    }
    if (!no_Qr) {
      fprintf(ofp, "R-MUT Conditionals\n");
      PrintProbs(ofp, Qr, LSQ);
    }
    
  }

  *ret_pairx = pairx;
  *ret_pairy = pairy;
  *ret_pmutl = pmutl;
  *ret_pmutr = pmutr;

  *ret_Qx = Qx;
  *ret_Qy = Qy;
  *ret_Ql = Ql;
  *ret_Qr = Qr;
  
}

void
CalculatePPMarginals(FILE *ofp, double *pp, double **ret_pairx, double **ret_pairy, double **ret_pmutl, double **ret_pmutr, int L, int verbose)
{
  double *pairx;
  double *pairy;
  double *pmutl;
  double *pmutr;
  int     LSQ;
  int     i;
  int     xl, yl, xr, yr;
  int     xpair, ypair;
  int     lmut, rmut;
  int     idxm;

  LSQ = L * L;

  /* paranoia */
  CheckSingleProb(pp, LSQ * LSQ);

  if (verbose) {
    fprintf(ofp, "pair-to-pair Probs\n");
    PrintProbs(ofp, pp, LSQ);
  }
  
  /* allocate memory
   */
  pairx = (double *) MallocOrDie (sizeof(double) * LSQ);
  pairy = (double *) MallocOrDie (sizeof(double) * LSQ);
  pmutl = (double *) MallocOrDie (sizeof(double) * LSQ);
  pmutr = (double *) MallocOrDie (sizeof(double) * LSQ);

  /* Initialize
   */
 for (i = 0; i < LSQ; i++) {
    pairx[i] = 0.0;
    pairy[i] = 0.0;
    pmutl[i] = 0.0;
    pmutr[i] = 0.0;
  }

  /* calculate PAIR and MUT marginals
   */
  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 = xl * L + xr;
	    ypair = yl * L + yr;
	    
	    lmut  = xl * L + yl;
	    rmut  = xr * L + yr;
	    
	    idxm  = lmut  * LSQ + rmut;
	    
	    pairx[xpair] += pp[idxm];
	    pairy[ypair] += pp[idxm];
	    
	    pmutl[lmut]  += pp[idxm];
	    pmutr[rmut]  += pp[idxm];
	  }
  
  CheckSingleProb(pairx, LSQ);
  CheckSingleProb(pairy, LSQ);
  CheckSingleProb(pmutl, LSQ);
  CheckSingleProb(pmutr, LSQ);

  if (verbose) {
    printf("X-PAIR MARG probabilities\n");
    PrintProbs(ofp, pairx, L);
    printf("Y-PAIR MARG probabilities\n");
    PrintProbs(ofp, pairy, L);
    printf("L-MUT MARG probabilities\n");
    PrintProbs(ofp, pmutl, L);
    printf("R-MUT MARG probabilities\n");
    PrintProbs(ofp, pmutr, L);
  }

  *ret_pairx = pairx;
  *ret_pairy = pairy;
  *ret_pmutl = pmutl;
  *ret_pmutr = pmutr;
  
}

void
ComputePPMarginals(FILE *ofp, double *pp, double *pairx, double *pairy, double *pmutl, double *pmutr, int L, int verbose)
{
  double *px;
  double *py;
  double *pl;
  double *pr;
 
  CalculatePPMarginals(ofp, pp, &px, &py, &pl, &pr, L, verbose);

   CopyMatrix (pairx, px, L, L);
   CopyMatrix (pairy, py, L, L);
   CopyVector (pmutl, pl, L);
   CopyVector (pmutr, pr, L);

   free (px);
   free (py);
   free (pl);
   free (pr);

}

/* Function: CalculateRIBOConditionals()
 * Date:     ER, Thu Jan 23 17:29:56 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  Calculate conditional probabilities from a RIBOPROB matrix of joint probs
 *           
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
CalculateRIBOConditionals (FILE *fp, fullmat_t *fullmat, fullcondmat_t **ret_cond_mut, fullcondmat_t **ret_cond_pair, int verbose)
{
  fullcondmat_t *cond_mut1;
  fullcondmat_t *cond_mut2;
  fullcondmat_t *cond_pair;
  double     val, log2val;
  double     valm, log2valm;
  double     val1, val2;
  double     sum_mut1;
  double     sum_mut2;
  double     sum_pair;
  int        L;
  int        L2;
  int        xl, yl;
  int        xr, yr;
  int        xpair, ypair;
  int        xpairm, ypairm;
  int        lmut, rmut;
  int        idx;
  int        idxm;
  int        i, j;
  int        islog2;
  
  L = fullmat->unpaired->edge_size;
  L2 = L*L;
  
  cond_mut1 = AllocFullCondMatrix(L);
  cond_mut2 = AllocFullCondMatrix(L);
  cond_pair = AllocFullCondMatrix(L);

  snprintf (cond_mut1->name, 40, "%s%s", fullmat->name, "-CONDbyMUT");
  snprintf (cond_mut2->name, 40, "%s%s", fullmat->name, "-CONDbyMUT");
  snprintf (cond_pair->name, 40, "%s%s", fullmat->name, "-CONDbyPAIR");
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  xpairm = idx(xr,xl);
	  ypairm = idx(yr,yl);

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

	  log2val  = fullmat->paired->matrix[matrix_index(xpair,ypair)];
	  log2valm = fullmat->paired->matrix[matrix_index(xpairm,ypairm)];

	  val  = EXP2(log2val);
	  valm = EXP2(log2valm);
	 
	  cond_mut1->cond->matrix[idxm] = log2val;
	  cond_mut2->cond->matrix[idxm] = log2valm;
	  cond_pair->cond->matrix[idx]  = log2val;
  
	  cond_mut1->marg->matrix[lmut]  += val;
	  cond_mut2->marg->matrix[lmut]  += valm;
	  cond_pair->marg->matrix[xpair] += val;
	}

  /* normalize */
  sum_mut1 = 0.0;
  sum_mut2 = 0.0;
  sum_pair = 0.0;
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) {    
      idx = idx(xl,xr);
      
      sum_mut1 += cond_mut1->marg->matrix[idx];
      sum_mut2 += cond_mut2->marg->matrix[idx];
      sum_pair += cond_pair->marg->matrix[idx];
    }
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) {
      idx = idx(xl,xr);
      
      cond_mut1->marg->matrix[idx] /= sum_mut1;
      cond_mut2->marg->matrix[idx] /= sum_mut2;
      cond_pair->marg->matrix[idx] /= sum_pair;
    }
  
  
  /* check the marginal probabilities */
  CheckSingleProb(cond_mut1->marg->matrix, L2);
  CheckSingleProb(cond_mut2->marg->matrix, L2);
  CheckSingleProb(cond_pair->marg->matrix, L2);
  
  /* convert to log2 */
  DLog2(cond_mut1->marg->matrix, L2);
  DLog2(cond_mut2->marg->matrix, L2);
  DLog2(cond_pair->marg->matrix, L2);
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  lmut = idx(xl,yl);
	  rmut = idx(xr,yr);
	  
	  idx  = xpair * L2 + ypair;
	  idxm = lmut  * L2 + rmut;
	  
	  cond_mut1->cond->matrix[idxm] -= cond_mut1->marg->matrix[lmut]; 
	  cond_mut2->cond->matrix[idxm] -= cond_mut2->marg->matrix[lmut]; 
	  cond_pair->cond->matrix[idx]  -= cond_pair->marg->matrix[xpair];
	  
	}

 /* merge both conditional for the mutation case into cond_mut1
   */
  for (i = 0; i < L2; i++) {
    
    val1 = EXP2(cond_mut1->marg->matrix[i]);
    val2 = EXP2(cond_mut2->marg->matrix[i]);
    
    cond_mut1->marg->matrix[i] = LOG2(val1+val2) -1.0;
    
    for (j = 0; j < L2; j++) {
      idx = i * L2 + j;
      
      val1 = EXP2(cond_mut1->cond->matrix[idx]);
      val2 = EXP2(cond_mut2->cond->matrix[idx]);

      cond_mut1->cond->matrix[idx] = LOG2(val1+val2) -1.0;
    }
  }

  /* And renormalize conditionals
   */
   for (i = 0; i < L2; i++) {
    DLog2Norm (cond_mut1->cond->matrix + i*L2, L2);
    DLog2Norm (cond_mut2->cond->matrix + i*L2, L2);
    DLog2Norm (cond_pair->cond->matrix + i*L2, L2);
  }


    /* check the conditional probabilities */
  for (i = 0; i < L2; i++) 
    CheckSingleLog2Prob(cond_pair->cond->matrix + i*L2, L2);  
  for (i = 0; i < L2; i++) 
    CheckSingleLog2Prob(cond_mut1->cond->matrix + i*L2, L2);
  for (i = 0; i < L2; i++) 
    CheckSingleLog2Prob(cond_mut2->cond->matrix + i*L2, L2);

  islog2 = FALSE;
  if (verbose) {
    PrintFullRIBOCondMatrix(fp, cond_mut1, FALSE, islog2);
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE,  islog2);
  }
  

  *ret_cond_mut  = cond_mut1;
  *ret_cond_pair = cond_pair;
  
  FreeFullCondMatrix(cond_mut2);
}

/* Function: CalculateRIBO5Conditionals()
 * Date:     ER, Wed Jan 29 18:01:09 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  Calculate conditional probabilities from a RIBOPROB matrix of jont probs. add gaps
 *           
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
CalculateRIBO5Conditionals (FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond5_mut, fullcondmat_t **ret_ribocond5_pair, 
			    double *mut5pxy, double *pair5prob, int verbose)
{
  fullcondmat_t *cond_mut1;
  fullcondmat_t *cond_mut2;
  fullcondmat_t *cond_pair;
  double     val, log2val;
  double     valm, log2valm;
  double     val1, val2;
  int        L, L5;
  int        LSQ, L5SQ;
  int        xl, yl;
  int        xr, yr;
  int        xpair, ypair;
  int        xpairm, ypairm;
  int        xpair5, ypair5;
  int        xpairm5, ypairm5;
  int        lmut, rmut;
  int        lmut5, rmut5;
  int        idxm, idx5m;
  int        idxp, idx5p;
  int        i, j;
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  L5   = L + 1;
  L5SQ = L5 * L5;
  
  cond_mut1 = AllocFullCondMatrix(L5);
  cond_mut2 = AllocFullCondMatrix(L5);
  cond_pair = AllocFullCondMatrix(L5);

  snprintf (cond_mut1->name, 40, "%s%s", riboprob->name, "-CONDbyMUT");
  snprintf (cond_mut2->name, 40, "%s%s", riboprob->name, "-CONDbyMUT");
  snprintf (cond_pair->name, 40, "%s%s", riboprob->name, "-CONDbyPAIR");
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  xpairm = idx(xr,xl);
	  ypairm = idx(yr,yl);

	  lmut = idx(xl,yl);
	  rmut = idx(xr,yr);
	  
	  xpair5 = idx5(xl,xr);
	  ypair5 = idx5(yl,yr);

	  xpairm5 = idx5(xr,xl);
	  ypairm5 = idx5(yr,yl);

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

	  idx5p = xpair5 * L5SQ + ypair5;
	  idx5m = lmut5  * L5SQ + rmut5;

	  log2val  = riboprob->paired->matrix[matrix_index(xpair,ypair)];
	  log2valm = riboprob->paired->matrix[matrix_index(xpairm,ypairm)];

	  val  = EXP2(log2val);
	  valm = EXP2(log2valm);
	 
	  if (xl < 4 && xr < 4 && yl < 4 && yr < 4 ) {
	    cond_mut1->cond->matrix[idx5m] = log2val;
	    cond_mut2->cond->matrix[idx5m] = log2valm;
	    cond_pair->cond->matrix[idx5p] = log2val;
	    
	    cond_mut1->marg->matrix[lmut5]  += val;
	    cond_mut2->marg->matrix[lmut5]  += valm;
	    cond_pair->marg->matrix[xpair5] += val;
	  }
	}
  
  /* check the marginal probabilities before adding gaps*/
  CheckSingleProb(cond_mut1->marg->matrix, L5SQ);
  CheckSingleProb(cond_mut2->marg->matrix, L5SQ);
  CheckSingleProb(cond_pair->marg->matrix, L5SQ);
  
  /* convert marginals to log2 */
  DLog2(cond_mut1->marg->matrix, L5SQ);
  DLog2(cond_mut2->marg->matrix, L5SQ);
  DLog2(cond_pair->marg->matrix, L5SQ);
  
  /* Calculate conditionals in log2 space, before adding gaps */
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	    xpair5 = idx5(xl,xr);
	    ypair5 = idx5(yl,yr);
	    
	    lmut5 = idx5(xl,yl);
	    rmut5 = idx5(xr,yr);
	    
	    idx5p = xpair5 * L5SQ + ypair5;
	    idx5m = lmut5  * L5SQ + rmut5;
	    
	    if (xl < 4 && xr < 4 && yl < 4 && yr < 4 ) {
	      cond_mut1->cond->matrix[idx5m] -= cond_mut1->marg->matrix[lmut5]; 
	      cond_mut2->cond->matrix[idx5m] -= cond_mut2->marg->matrix[lmut5]; 
	      cond_pair->cond->matrix[idx5p] -= cond_pair->marg->matrix[xpair5];
	    }
	    else {
	      cond_mut1->cond->matrix[idx5m] = -DBL_MAX; 
	      cond_mut2->cond->matrix[idx5m] = -DBL_MAX;
	      cond_pair->cond->matrix[idx5p] = -DBL_MAX;
	    }
	}

 /* merge both conditional for the mutation case into cond_mut1
   */
  for (i = 0; i < L5SQ; i++) {
    
    if (i%L5SQ < L && i/L5SQ < L) 
      {
	val1 = EXP2(cond_mut1->marg->matrix[i]);
	val2 = EXP2(cond_mut2->marg->matrix[i]);
	
	cond_mut1->marg->matrix[i] = LOG2(val1+val2) -1.0;
	
	for (j = 0; j < L5SQ; j++) {
	  if (j%L5SQ < L && j/L5SQ < L) 
	    {
	      idx5m = i * L5SQ + j;
	      
	      val1 = EXP2(cond_mut1->cond->matrix[idx5m]);
	      val2 = EXP2(cond_mut2->cond->matrix[idx5m]);
	      
	      cond_mut1->cond->matrix[idx5m] = LOG2(val1+val2) -1.0;
	    }
	}
      }
  }
  
  /* check the conditional probabilities */
  for (i = 0; i < L5SQ; i++) 
    if (i%L5SQ < L && i/L5SQ < L) {
      CheckSingleLog2Prob(cond_mut1->cond->matrix + i*L5SQ, L5SQ);
      CheckSingleLog2Prob(cond_pair->cond->matrix + i*L5SQ, L5SQ);  
      CheckSingleLog2Prob(cond_mut2->cond->matrix + i*L5SQ, L5SQ);
    }
  
  /* Finally, add gaps (in log2 space)
   */

                                 /* GAPS to the marginals */ 
  for (xl = 0; xl < L5; xl++) 
    for (yl = 0; yl < L5; yl++) {
	lmut5 = idx5(xl,yl);
	cond_mut1->marg->matrix[lmut5] =  LOG2(mut5pxy[lmut5]);	    
    }
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) {
	xpair5 = idx5(xl,xr);
	cond_pair->marg->matrix[xpair5] = LOG2(pair5prob[xpair5]);	    
    }
  
  /* And renormalize marginals
   */
  DLog2Norm (cond_mut1->marg->matrix, L5SQ);
  DLog2Norm (cond_pair->marg->matrix, L5SQ);

                        /* GAPS to the conditionals */ 
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	  if (xl == L || xr == L || yl == L || yr == L) {
	    xpair5 = idx5(xl,xr);
	    ypair5 = idx5(yl,yr);
	    
	    lmut5 = idx5(xl,yl);
	    rmut5 = idx5(xr,yr);
	    
	    idx5p = xpair5 * L5SQ + ypair5;
	    idx5m = lmut5  * L5SQ + rmut5;

	    /* Mutational Conditionals */
	    lone_MUT_cond(idx5m, L5SQ, &cond_mut1->cond->matrix[idx5m], mut5pxy);
	    
	    /* Pair conditionals */
	    lone_PAIR_cond(idx5p, L5SQ, &cond_pair->cond->matrix[idx5p], pair5prob);
	  }
	  
	}

 
  /* And renormalize conditionals
   */
   for (i = 0; i < L5SQ; i++) {
    DLog2Norm (cond_mut1->cond->matrix + i*L5SQ, L5SQ);
    DLog2Norm (cond_pair->cond->matrix + i*L5SQ, L5SQ);
  }
  
  if (verbose) {
    PrintFullRIBOCondMatrix(fp, cond_mut1, FALSE, TRUE);
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE,  TRUE);
  }

  *ret_ribocond5_mut  = cond_mut1;
  *ret_ribocond5_pair = cond_pair;
  
  FreeFullCondMatrix(cond_mut2);
}

/* Function: CalculateRIBO5ConditionalsUncorr()
 * Date:     ER, Wed Feb  5 09:56:51 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  Calculate conditional probabilities from a RIBOPROB matrix of jont probs. add gaps
 *           These are conditionals calculated from "modified" RIBO matrices trying to 
 *           get rid of the unwanted correlations.
 *
 *                                                                               xl - xr
 *                                                                         RIBO(  |    | )
 *                                                                               yl - yr
 *            to calculate ribo5Paircond P(xl-xr|yl-yr), I will use -------------------------------- as Joint Probs
 *                                                                         xl                xr
 *                                                                       P( | )            P( | )
 *                                                                         yl                yr
 *                                                                  1/2 ----------  + 1/2 ----------
 *                                                                     P(xl)P(yl)         P(xr)P(yr) 
 *
 *
 *                                                                               xl - xr
 *                                                                         RIBO(  |   |  )
 *                                         xl | xr                               yl - yr
 *            to calculate ribo5Mutcond P(  | | |  ),  I will use  --------------------------------  as Joint Probs
 *                                         yl | yr
 *                                                                     P(xl-xr)          P (yl-yr)
 *                                                                 1/2 ----------  + 1/2 ---------
 *                                                                     P(xl)P(xr)        P(yl)P(yr)
 *
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
CalculateRIBO5ConditionalsUncorr_201(FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond5_mut, fullcondmat_t **ret_ribocond5_pair, 
				     double *mut5pxy, double *pair5prob, double *targetfreq, int verbose)
{
  fullmat_t     *riboprob_mut_uncorr;
  fullmat_t     *riboprob_pair_uncorr;
  fullcondmat_t *cond_mut;
  fullcondmat_t *cond_pair;
  double        *pmut;
  double        *ppair;
  double        *psingle_pair;
  double        *psingle_mut;
  double        cum_prob_wc = 0.0;
  double        cum_prob_comp = 0.0;
  double        cum_prob_else = 0.0;
  double        sum_mut  = 0.0;
  double        sum_pair = 0.0;
  int           L, L5;
  int           LSQ, L5SQ;
  int           xl, yl;
  int           xr, yr;
  int           xpair, ypair;
  int           lmut, rmut;
  int           idxp;
  int           i, j;
  int           x;
  
  /* paranoia. Also to test that I have a function that can check that probs add up to one in the halh-matrix robbie style */
  CheckSYMLog2Prob(riboprob->paired->matrix, riboprob->paired->edge_size);    

  if (verbose) {
    PrintFullMatrix (fp, riboprob);
  }
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  L5   = L + 1;
  L5SQ = L5 * L5;
  
  riboprob_mut_uncorr  = CopyFullMatrix(riboprob);
  riboprob_pair_uncorr = CopyFullMatrix(riboprob);

  snprintf (riboprob_mut_uncorr->name,  40, "%s%s", riboprob->name, "-MUT_UNCORR");
  snprintf (riboprob_pair_uncorr->name, 40, "%s%s", riboprob->name, "-PAIR_UNCORR");

  if (verbose) {
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) {
	
	xl = i/L;
	xr = i%L;
	
	yl = j/L;
	yr = j%L;
	
	if (IsWcPair(xl, yl, xr, yr)) cum_prob_wc +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
	if (IsCompensatory(xl, yl, xr, yr)) cum_prob_comp +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
	if (IsNonCompensatory(xl, yl, xr, yr)) cum_prob_else +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
      }
    printf("RIBOSUM: cum_prob_wc = %f cum_prob_comp = %f cum_prob_else = %f \n", cum_prob_wc, cum_prob_comp, cum_prob_else);
  }
  
  /* marginals
   */
  pmut  = (double *) MallocOrDie(sizeof(double) * LSQ);  
  ppair = (double *) MallocOrDie(sizeof(double) * LSQ);  
  for (i = 0; i < LSQ; i++) {
    pmut[i]  = 0.0;
    ppair[i] = 0.0;
  }
  for (i = 0; i < LSQ; i++) 
    for (j = 0; j < LSQ; j++) {
      xl = i/L;
      xr = i%L;
      
      yl = j/L;
      yr = j%L;
      
      lmut = idx(xl,yl);
      
      pmut[lmut] += EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
      ppair[i]   += EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
    }
  
  for (j = 0; j < LSQ; j++) {
    sum_mut  +=  pmut[j];
    sum_pair +=  ppair[j];
  }
  
  for (j = 0; j < LSQ; j++) {
    pmut[j]  /= sum_mut;
    ppair[j] /= sum_pair;
  }
  
  if (verbose) {
    PrintProbs (fp, pmut, L);
    PrintProbs (fp, ppair, L);
  }
  
  CheckSingleProb(pmut,  LSQ);
  CheckSingleProb(ppair, LSQ);
  DLog2(pmut,  LSQ);
  DLog2(ppair, LSQ);
  
  /* single nts probs from the marginals
   */
  psingle_mut  = (double *) MallocOrDie(sizeof(double) * L);  
  psingle_pair = (double *) MallocOrDie(sizeof(double) * L); 
 
  for (x = 0; x < L; x++) { psingle_mut[x] = 0.0; psingle_pair[x] = 0.0; }
  
  for (i = 0; i < LSQ; i++) {
    psingle_mut[i/L]  += 0.5 * EXP2(pmut[i]);
    psingle_mut[i/L]  += 0.5 * EXP2(pmut[i]);
    psingle_pair[i%L] += 0.5 * EXP2(ppair[i]);
    psingle_pair[i%L] += 0.5 * EXP2(ppair[i]);
  }

  if (verbose) {
    PrintVectorProbs (fp, psingle_mut,  L);
    PrintVectorProbs (fp, psingle_pair, L);
  }
  CheckSingleProb(psingle_mut, L);
  CheckSingleProb(psingle_pair, L);
  DLog2(psingle_mut,  L);
  DLog2(psingle_pair, L);
  
  /* modify the Uncorr RIBOPROBs 
   */
    for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
 
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);
	  
	  lmut = idx(xl,yl);
	  rmut = idx(xr,yr);
	  
	  idxp = matrix_index(ypair,xpair);
	  
	  if (ypair <= xpair) {
	    riboprob_mut_uncorr->paired->matrix[idxp]  += 1.0 - LOG2(EXP2(pmut[lmut] - psingle_mut[xl] - psingle_mut[yl]) + 
								     EXP2(pmut[rmut] - psingle_mut[xr] - psingle_mut[yr]));
	    
	    riboprob_pair_uncorr->paired->matrix[idxp] += 1.0 - LOG2(EXP2(ppair[xpair] - psingle_pair[xl] - psingle_pair[xr]) + 
								     EXP2(ppair[ypair] - psingle_pair[yl] - psingle_pair[yr]));
	  }
	}
   

  DLog2SYMNorm(riboprob_mut_uncorr->paired->matrix,  riboprob_mut_uncorr->paired->edge_size);  
  DLog2SYMNorm(riboprob_pair_uncorr->paired->matrix, riboprob_pair_uncorr->paired->edge_size);  

  CheckSYMLog2Prob(riboprob_mut_uncorr->paired->matrix,  riboprob_mut_uncorr->paired->edge_size);  
  CheckSYMLog2Prob(riboprob_pair_uncorr->paired->matrix, riboprob_pair_uncorr->paired->edge_size);    

  if (verbose) {
    PrintFullMatrix (fp, riboprob_mut_uncorr);
    PrintFullMatrix (fp, riboprob_pair_uncorr);
  }

  /* use pair_uncorr RIBOPROBs to calculate cond_mut    -- adding gaps
   * use mut_uncorr  RIBOPROBs to calculate cond_pair   -- adding gaps
   */
  CalculateRIBO5PairConditionals_201(fp, riboprob_mut_uncorr,  &cond_pair, pair5prob, mut5pxy,   verbose);
  CalculateRIBO5MutConditionals_201 (fp, riboprob_pair_uncorr, &cond_mut,  mut5pxy,   pair5prob, verbose);


  if (verbose) {
    PrintFullRIBOCondMatrix(fp, cond_mut,  FALSE, TRUE);
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE,  TRUE);
  }
  
  *ret_ribocond5_mut  = cond_mut;
  *ret_ribocond5_pair = cond_pair;
  
  free(psingle_mut);
  free(psingle_pair);
  free(pmut);
  free(ppair);
  FreeFullMatrix(riboprob_mut_uncorr);
  FreeFullMatrix(riboprob_pair_uncorr);
}

void
CalculateRIBO5ConditionalsUncorr (FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond5_mut, fullcondmat_t **ret_ribocond5_pair, 
				  double *mut5pxy, double *pair5prob, double *targetfreq, int verbose)
{
  fullmat_t     *riboprob_mut_uncorr;
  fullmat_t     *riboprob_pair_uncorr;
  fullcondmat_t *cond_mut;
  fullcondmat_t *cond_pair;
  double        *pmut;
  double        *ppair;
  double        *psingle_pair;
  double        *psingle_mut;
  double        cum_prob_wc = 0.0;
  double        cum_prob_comp = 0.0;
  double        cum_prob_else = 0.0;
  double        sum_mut  = 0.0;
  double        sum_pair = 0.0;
  int           L, L5;
  int           LSQ, L5SQ;
  int           xl, yl;
  int           xr, yr;
  int           xpair, ypair;
  int           lmut, rmut;
  int           idxp;
  int           i, j;
  int           x;
  
  /* paranoia. Also to test that I have a function that can check that probs add up to one in the halh-matrix robbie style */
  CheckSYMLog2Prob(riboprob->paired->matrix, riboprob->paired->edge_size);    

  if (verbose) {
    PrintFullMatrix (fp, riboprob);
  }
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  L5   = L + 1;
  L5SQ = L5 * L5;
  
  riboprob_mut_uncorr  = CopyFullMatrix(riboprob);
  riboprob_pair_uncorr = CopyFullMatrix(riboprob);

  snprintf (riboprob_mut_uncorr->name,  40, "%s%s", riboprob->name, "-MUT_UNCORR");
  snprintf (riboprob_pair_uncorr->name, 40, "%s%s", riboprob->name, "-PAIR_UNCORR");

  if (verbose) {
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) {
	
	xl = i/L;
	xr = i%L;
	
	yl = j/L;
	yr = j%L;
	
	if (IsWcPair(xl, yl, xr, yr)) cum_prob_wc +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
	if (IsCompensatory(xl, yl, xr, yr)) cum_prob_comp +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
	if (IsNonCompensatory(xl, yl, xr, yr)) cum_prob_else +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
      }
    printf("RIBOSUM: cum_prob_wc = %f cum_prob_comp = %f cum_prob_else = %f \n", cum_prob_wc, cum_prob_comp, cum_prob_else);
  }
  
  /* marginals
   */
  pmut  = (double *) MallocOrDie(sizeof(double) * LSQ);  
  ppair = (double *) MallocOrDie(sizeof(double) * LSQ);  
  for (i = 0; i < LSQ; i++) {
    pmut[i]  = 0.0;
    ppair[i] = 0.0;
  }
  for (i = 0; i < LSQ; i++) 
    for (j = 0; j < LSQ; j++) {
      xl = i/L;
      xr = i%L;
      
      yl = j/L;
      yr = j%L;
      
      lmut = idx(xl,yl);
      
      pmut[lmut] += EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
      ppair[i]   += EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
    }
  
  for (j = 0; j < LSQ; j++) {
    sum_mut  +=  pmut[j];
    sum_pair +=  ppair[j];
  }
  
  for (j = 0; j < LSQ; j++) {
    pmut[j]  /= sum_mut;
    ppair[j] /= sum_pair;
  }
  
  if (verbose) {
    PrintProbs (fp, pmut, L);
    PrintProbs (fp, ppair, L);
  }
  
  CheckSingleProb(pmut,  LSQ);
  CheckSingleProb(ppair, LSQ);
  DLog2(pmut,  LSQ);
  DLog2(ppair, LSQ);
  
  /* single nts probs from the marginals
   */
  psingle_mut  = (double *) MallocOrDie(sizeof(double) * L);  
  psingle_pair = (double *) MallocOrDie(sizeof(double) * L); 
 
  for (x = 0; x < L; x++) { psingle_mut[x] = 0.0; psingle_pair[x] = 0.0; }
  
  for (i = 0; i < LSQ; i++) {
    psingle_mut[i/L]  += 0.5 * EXP2(pmut[i]);
    psingle_mut[i/L]  += 0.5 * EXP2(pmut[i]);
    psingle_pair[i%L] += 0.5 * EXP2(ppair[i]);
    psingle_pair[i%L] += 0.5 * EXP2(ppair[i]);
  }

  if (verbose) {
    PrintVectorProbs (fp, psingle_mut,  L);
    PrintVectorProbs (fp, psingle_pair, L);
  }
  CheckSingleProb(psingle_mut, L);
  CheckSingleProb(psingle_pair, L);
  DLog2(psingle_mut,  L);
  DLog2(psingle_pair, L);
  
  /* modify the Uncorr RIBOPROBs 
   */
    for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
 
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);
	  
	  lmut = idx(xl,yl);
	  rmut = idx(xr,yr);
	  
	  idxp = matrix_index(ypair,xpair);
	  
	  if (ypair <= xpair) {
	    riboprob_mut_uncorr->paired->matrix[idxp]  += 1.0 - LOG2(EXP2(pmut[lmut] - psingle_mut[xl] - psingle_mut[yl]) + 
								     EXP2(pmut[rmut] - psingle_mut[xr] - psingle_mut[yr]));
	    
	    riboprob_pair_uncorr->paired->matrix[idxp] += 1.0 - LOG2(EXP2(ppair[xpair] - psingle_pair[xl] - psingle_pair[xr]) + 
								     EXP2(ppair[ypair] - psingle_pair[yl] - psingle_pair[yr]));
	  }
	}
   

  DLog2SYMNorm(riboprob_mut_uncorr->paired->matrix,  riboprob_mut_uncorr->paired->edge_size);  
  DLog2SYMNorm(riboprob_pair_uncorr->paired->matrix, riboprob_pair_uncorr->paired->edge_size);  

  CheckSYMLog2Prob(riboprob_mut_uncorr->paired->matrix,  riboprob_mut_uncorr->paired->edge_size);  
  CheckSYMLog2Prob(riboprob_pair_uncorr->paired->matrix, riboprob_pair_uncorr->paired->edge_size);    

  if (verbose) {
    PrintFullMatrix (fp, riboprob_mut_uncorr);
    PrintFullMatrix (fp, riboprob_pair_uncorr);
  }

  /* use pair_uncorr RIBOPROBs to calculate cond_mut    -- adding gaps
   * use mut_uncorr  RIBOPROBs to calculate cond_pair   -- adding gaps
   */
  CalculateRIBO5MutConditionals  (fp, riboprob_pair_uncorr, &cond_mut,  mut5pxy,   pair5prob, verbose);
  CalculateRIBO5PairConditionals (fp, riboprob_mut_uncorr,  &cond_pair, pair5prob, mut5pxy,   verbose);
  
  if (verbose) {
    PrintFullRIBOCondMatrix(fp, cond_mut,  FALSE, TRUE);
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE,  TRUE);
  }
  
  *ret_ribocond5_mut  = cond_mut;
  *ret_ribocond5_pair = cond_pair;
  
  free(psingle_mut);
  free(psingle_pair);
  free(pmut);
  free(ppair);
  FreeFullMatrix(riboprob_mut_uncorr);
  FreeFullMatrix(riboprob_pair_uncorr);
}

void
CalculateRIBOConditionalsUncorr (FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond_mut, fullcondmat_t **ret_ribocond_pair, 
				 double *targetfreq, int verbose)
{
  fullmat_t     *riboprob_mut_uncorr;
  fullmat_t     *riboprob_pair_uncorr;
  fullcondmat_t *cond_mut;
  fullcondmat_t *cond_pair;
  double        *pmutl;
  double        *pmutr;
  double        *ppairx;
  double        *ppairy;
  double        *pxl, *pxr, *pyl, *pyr;
  double        cum_prob_wc = 0.0;
  double        cum_prob_comp = 0.0;
  double        cum_prob_else = 0.0;
  double        sum_mutl  = 0.0;
  double        sum_mutr  = 0.0;
  double        sum_pairx = 0.0;
  double        sum_pairy = 0.0;
  int           L;
  int           LSQ;
  int           xl, yl;
  int           xr, yr;
  int           xpair, ypair;
  int           lmut, rmut;
  int           idxp;
  int           i, j;
  
  /* paranoia. Also to test that I have a function that can check that probs add up to one in the halh-matrix robbie style */
  CheckSYMLog2Prob(riboprob->paired->matrix, riboprob->paired->edge_size);    
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  riboprob_mut_uncorr  = CopyFullMatrix(riboprob);
  riboprob_pair_uncorr = CopyFullMatrix(riboprob);

  snprintf (riboprob_mut_uncorr->name,  40, "%s%s", riboprob->name, "-MUT_UNCORR");
  snprintf (riboprob_pair_uncorr->name, 40, "%s%s", riboprob->name, "-PAIR_UNCORR");

  if (verbose) {
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) {
	
	xl = i/L;
	xr = i%L;
	
	yl = j/L;
	yr = j%L;
	
	if (IsWcPair(xl, yl, xr, yr)) cum_prob_wc +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
	if (IsCompensatory(xl, yl, xr, yr)) cum_prob_comp +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
	if (IsNonCompensatory(xl, yl, xr, yr)) cum_prob_else +=  EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
      }
    printf("RIBOSUM: cum_prob_wc = %f cum_prob_comp = %f cum_prob_else = %f \n", cum_prob_wc, cum_prob_comp, cum_prob_else);
  }
  
  /* marginals
   */
  pmutl  = (double *) MallocOrDie(sizeof(double) * LSQ);  
  pmutr  = (double *) MallocOrDie(sizeof(double) * LSQ);  
  ppairx = (double *) MallocOrDie(sizeof(double) * LSQ);  
  ppairy = (double *) MallocOrDie(sizeof(double) * LSQ);  
  for (i = 0; i < LSQ; i++) {
    pmutl[i]  = 0.0;
    pmutr[i]  = 0.0;
    ppairx[i] = 0.0;
    ppairy[i] = 0.0;
  }
  for (i = 0; i < LSQ; i++) 
    for (j = 0; j < LSQ; j++) {
      xl = i/L;
      xr = i%L;
      
      yl = j/L;
      yr = j%L;
      
      lmut = idx(xl,yl);
      rmut = idx(xr,yr);
      
      pmutl[lmut] += EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
      pmutr[rmut] += EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
      ppairx[i]   += EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
      ppairy[j]   += EXP2(riboprob->paired->matrix[matrix_index(i,j)]);
    }
  
  for (j = 0; j < LSQ; j++) {
    sum_mutl  +=  pmutl[j];
    sum_mutr  +=  pmutr[j];
    sum_pairx +=  ppairx[j];
    sum_pairy +=  ppairy[j];
  }
  
  for (j = 0; j < LSQ; j++) {
    pmutl[j]  /= sum_mutl;
    pmutr[j]  /= sum_mutr;
    ppairx[j] /= sum_pairx;
    ppairy[j] /= sum_pairy;
  }
  
  if (verbose) {
    PrintProbs (fp, pmutl, L);
    PrintProbs (fp, pmutr, L);
    PrintProbs (fp, ppairx, L);
    PrintProbs (fp, ppairy, L);
  }
  
  CheckSingleProb(pmutl,  LSQ);
  CheckSingleProb(pmutr,  LSQ);
  CheckSingleProb(ppairx, LSQ);
  CheckSingleProb(ppairy, LSQ);

  CalculateRIBOMarginals(fp, riboprob, &pxl, &pxr, &pyl, &pyr, verbose);

  if (verbose) {
    fprintf(fp, "PMUTl  probabilities\n");
    PrintProbs(fp, pmutl, L);
    fprintf(fp, "PMUTr  probabilities\n");
    PrintProbs(fp, pmutr, L);
    fprintf(fp, "PPAIRx  probabilities\n");
    PrintProbs(fp, ppairx, L);
    fprintf(fp, "PPARIr  probabilities\n");
    PrintProbs(fp, ppairy, L);
    fprintf(fp, "pxl  probabilities\n");
    PrintVectorProbs(fp, pxl, L);
    fprintf(fp, "pxr  probabilities\n");
    PrintVectorProbs(fp, pxr, L);
    fprintf(fp, "pyl  probabilities\n");
    PrintVectorProbs(fp, pyl, L);
    fprintf(fp, "pyr  probabilities\n");
    PrintVectorProbs(fp, pyr, L);

  }

  DLog2(pmutl,  LSQ);
  DLog2(pmutr,  LSQ);
  DLog2(ppairx, LSQ);
  DLog2(ppairy, LSQ);

  DLog2(pxl, L);
  DLog2(pxr, L);
  DLog2(pyl, L);
  DLog2(pyr, L);
  
  /* modify the Uncorr RIBOPROBs  
   */ 
    for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
 
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);
	  
	  lmut = idx(xl,yl);
	  rmut = idx(xr,yr);
	  
	  idxp = matrix_index(ypair,xpair);
	  
	  if (ypair <= xpair) {
	    riboprob_mut_uncorr->paired->matrix[idxp]  += 1.0 - LOG2(EXP2(pmutl[lmut] - pxl[xl] - pyl[yl]) + 
								     EXP2(pmutr[rmut] - pxr[xr] - pyr[yr]));
	    
	    riboprob_pair_uncorr->paired->matrix[idxp] += 1.0 - LOG2(EXP2(ppairx[xpair] - pxl[xl] - pxr[xr]) + 
								     EXP2(ppairy[ypair] - pyl[yl] - pyr[yr]));
	  }
	}  

  DLog2SYMNorm(riboprob_mut_uncorr->paired->matrix,  riboprob_mut_uncorr->paired->edge_size);  
  DLog2SYMNorm(riboprob_pair_uncorr->paired->matrix, riboprob_pair_uncorr->paired->edge_size);  

  CheckSYMLog2Prob(riboprob_mut_uncorr->paired->matrix,  riboprob_mut_uncorr->paired->edge_size);  
  CheckSYMLog2Prob(riboprob_pair_uncorr->paired->matrix, riboprob_pair_uncorr->paired->edge_size);    

  if (verbose) {
    PrintFullMatrix (fp, riboprob);
    PrintFullMatrix (fp, riboprob_mut_uncorr);
    PrintFullMatrix (fp, riboprob_pair_uncorr);
  }

  /* use pair_uncorr RIBOPROBs to calculate cond_mut    -- adding gaps
   * use mut_uncorr  RIBOPROBs to calculate cond_pair   -- adding gaps
   */
  CalculateRIBOPairConditionals (fp, riboprob_mut_uncorr,  &cond_pair, verbose);
  CalculateRIBOMutConditionals  (fp, riboprob_pair_uncorr, &cond_mut,  verbose);
  
  if (verbose) {
    PrintFullRIBOCondMatrix(fp, cond_mut,  FALSE, FALSE);
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE,  FALSE);
  }
  
  *ret_ribocond_mut  = cond_mut;
  *ret_ribocond_pair = cond_pair;
  
  free(pmutl);
  free(pmutr);
  free(ppairx);
  free(ppairy);
  free(pxl);
  free(pxr);
  free(pyl);
  free(pyr);
  FreeFullMatrix(riboprob_mut_uncorr);
  FreeFullMatrix(riboprob_pair_uncorr);
}

/* Function: CalculateRIBO5MutConditionals()
 * Date:     ER, Fri Jan 31 14:36:02 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  Calculate conditional probabilities from a RIBOPROB matrix of jont probs. add gaps
 *           
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
CalculateRIBO5MutConditionals_201(FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond5_mut, 
				  double *mut5pxy, double *pair5prob, int verbose)
{
  fullcondmat_t *cond_mut;
  double        *pmarg;
  double     val, log2val;
  double     valm, log2valm;
  int        L, L5;
  int        LSQ, L5SQ;
  int        xl, yl;
  int        xr, yr;
  int        xpair, ypair;
  int        xpairm, ypairm;
  int        xpair5, ypair5;
  int        xpairm5, ypairm5;
  int        lmut, rmut;
  int        lmut5, rmut5;
  int        idxm, idx5m;
  int        i;
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  L5   = L + 1;
  L5SQ = L5 * L5;
  
  cond_mut = AllocFullCondMatrix(L5);

  snprintf (cond_mut->name, 40, "%s%s", riboprob->name, "-CONDbyMUT");
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  xpairm = idx(xr,xl);
	  ypairm = idx(yr,yl);

	  lmut = idx(xl,yl);
	  rmut = idx(xr,yr);
	  
	  xpair5 = idx5(xl,xr);
	  ypair5 = idx5(yl,yr);

	  xpairm5 = idx5(xr,xl);
	  ypairm5 = idx5(yr,yl);

	  lmut5 = idx5(xl,yl);
	  rmut5 = idx5(xr,yr);
	  
	  idxm  = lmut  * LSQ  + rmut;
	  idx5m = lmut5 * L5SQ + rmut5;

	  log2val  = riboprob->paired->matrix[matrix_index(xpair,ypair)];
	  log2valm = riboprob->paired->matrix[matrix_index(xpairm,ypairm)];

	  val  = EXP2(log2val);
	  valm = EXP2(log2valm);
	 
	  cond_mut->cond->matrix[idx5m] = LOG2(val+valm) - 1.0;
	  
	  cond_mut->marg->matrix[lmut5] += 0.5 * (val+valm);
	}
  
  /* check the marginal probabilities before adding gaps*/
  CheckSingleProb(cond_mut->marg->matrix, L5SQ);
  /* convert marginals to log2 */
  DLog2(cond_mut->marg->matrix, L5SQ);
  
  /* Calculate conditionals in log2 space, before adding gaps */
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	    xpair5 = idx5(xl,xr);
	    ypair5 = idx5(yl,yr);
	    
	    lmut5 = idx5(xl,yl);
	    rmut5 = idx5(xr,yr);
	    
	    idx5m = lmut5 * L5SQ + rmut5;
	    
	    if (xl < L && xr < L && yl < L && yr < L) 
	      cond_mut->cond->matrix[idx5m] -= cond_mut->marg->matrix[lmut5]; 
	    else 
	      cond_mut->cond->matrix[idx5m] = -DBL_MAX;   
	}
 
  /* check the conditional probabilities */
  for (i = 0; i < L5SQ; i++) 
    if (i%L5SQ < L && i/L5SQ < L) 
      CheckSingleLog2Prob(cond_mut->cond->matrix + i*L5SQ, L5SQ);
 
  /* Finally, add gaps (in log2 space)
   */

                                 /* GAPS to the marginals */ 
  for (xl = 0; xl < L5; xl++) 
    for (yl = 0; yl < L5; yl++) {
	lmut5 = idx5(xl,yl);
	cond_mut->marg->matrix[lmut5] =  LOG2(mut5pxy[lmut5]);	    
      }
  
  /* And renormalize marginals
   */
  DLog2Norm (cond_mut->marg->matrix, L5SQ);

  /* GAPS to the conditionals */
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	  if (xl == L || xr == L || yl == L || yr == L) {

	    lmut5 = idx5(xl,yl);
	    rmut5 = idx5(xr,yr);
	    
	    idx5m = lmut5  * L5SQ + rmut5;

	    /* Mutational Conditionals  */ 
	    lone_MUT_cond(idx5m, L5SQ, &cond_mut->cond->matrix[idx5m], mut5pxy);
	  
	  }
	  
	}

 
  /* And renormalize conditionals
   */
   for (i = 0; i < L5SQ; i++) 
    DLog2Norm (cond_mut->cond->matrix + i*L5SQ, L5SQ); 

   /* Now change the single nt marginals for each conditiona
    */
   pmarg = (double *) MallocOrDie (sizeof(double) * L5);
   DExp2(cond_mut->marg->matrix,  L5SQ);
   MarginalizeJointProbs(cond_mut->marg->matrix, pmarg, L5, 2);
   for (i = 0; i < L5SQ; i++) {
     DExp2(cond_mut->cond->matrix + i*L5SQ, L5SQ);
     ChangePairProbs(L5, cond_mut->cond->matrix + i*L5SQ, pmarg, TRUE, verbose);
     DLog2(cond_mut->cond->matrix + i*L5SQ, L5SQ);
   }
   DLog2(cond_mut->marg->matrix,  L5SQ);
  free (pmarg);
  
  if (verbose) 
    PrintFullRIBOCondMatrix(fp, cond_mut, FALSE, FALSE);

  *ret_ribocond5_mut  = cond_mut;
  
}

void
CalculateRIBO5MutConditionals (FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond5_mut, 
			       double *mut5pxy, double *pair5prob, int verbose)
{
  fullcondmat_t *cond_mut;
  double        *pmarg;
  double     val, log2val;
  double     valm, log2valm;
  int        L, L5;
  int        LSQ, L5SQ;
  int        xl, yl;
  int        xr, yr;
  int        xpair, ypair;
  int        xpairm, ypairm;
  int        xpair5, ypair5;
  int        xpairm5, ypairm5;
  int        lmut, rmut;
  int        lmut5, rmut5;
  int        idxm, idx5m;
  int        i;
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  L5   = L + 1;
  L5SQ = L5 * L5;
  
  cond_mut = AllocFullCondMatrix(L5);

  snprintf (cond_mut->name, 40, "%s%s", riboprob->name, "-CONDbyMUT");
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  xpairm = idx(xr,xl);
	  ypairm = idx(yr,yl);

	  lmut = idx(xl,yl);
	  rmut = idx(xr,yr);
	  
	  xpair5 = idx5(xl,xr);
	  ypair5 = idx5(yl,yr);

	  xpairm5 = idx5(xr,xl);
	  ypairm5 = idx5(yr,yl);

	  lmut5 = idx5(xl,yl);
	  rmut5 = idx5(xr,yr);
	  
	  idxm  = lmut  * LSQ  + rmut;
	  idx5m = lmut5 * L5SQ + rmut5;

	  log2val  = riboprob->paired->matrix[matrix_index(xpair,ypair)];
	  log2valm = riboprob->paired->matrix[matrix_index(xpairm,ypairm)];

	  val  = EXP2(log2val);
	  valm = EXP2(log2valm);
	 
	  cond_mut->cond->matrix[idx5m] = LOG2(val+valm) - 1.0;
	  
	  cond_mut->marg->matrix[lmut5] += 0.5 * (val+valm);
	}
  
  /* check the marginal probabilities before adding gaps*/
  CheckSingleProb(cond_mut->marg->matrix, L5SQ);
  /* convert marginals to log2 */
  DLog2(cond_mut->marg->matrix, L5SQ);
  
  /* Calculate conditionals in log2 space, before adding gaps */
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	    xpair5 = idx5(xl,xr);
	    ypair5 = idx5(yl,yr);
	    
	    lmut5 = idx5(xl,yl);
	    rmut5 = idx5(xr,yr);
	    
	    idx5m = lmut5 * L5SQ + rmut5;
	    
	    if (xl < L && xr < L && yl < L && yr < L) 
	      cond_mut->cond->matrix[idx5m] -= cond_mut->marg->matrix[lmut5]; 
	    else 
	      cond_mut->cond->matrix[idx5m] = -DBL_MAX;   
	}
 
  /* check the conditional probabilities */
  for (i = 0; i < L5SQ; i++) 
    if (i%L5SQ < L && i/L5SQ < L) 
      CheckSingleLog2Prob(cond_mut->cond->matrix + i*L5SQ, L5SQ);
 
  /* Finally, add gaps (in log2 space)
   */

                                 /* GAPS to the marginals */ 
  for (xl = 0; xl < L5; xl++) 
    for (yl = 0; yl < L5; yl++) {
	lmut5 = idx5(xl,yl);
	cond_mut->marg->matrix[lmut5] =  LOG2(mut5pxy[lmut5]);	    
      }
  
  /* And renormalize marginals
   */
  DLog2Norm (cond_mut->marg->matrix, L5SQ);

  /* GAPS to the conditionals */
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	  if (xl == L || xr == L || yl == L || yr == L) {

	    lmut5 = idx5(xl,yl);
	    rmut5 = idx5(xr,yr);
	    
	    idx5m = lmut5  * L5SQ + rmut5;

	    /* Mutational Conditionals  */ 
	    lone_MUT_cond(idx5m, L5SQ, &cond_mut->cond->matrix[idx5m], mut5pxy);
	  
	  }
	  
	}

 
  /* And renormalize conditionals
   */
   for (i = 0; i < L5SQ; i++) 
     DLog2Norm (cond_mut->cond->matrix + i*L5SQ, L5SQ); 
   if (verbose) 
     PrintFullRIBOCondMatrix(fp, cond_mut, FALSE, FALSE);
   
   /* Now change the single nt marginals for each conditional
    */
   pmarg = (double *) MallocOrDie (sizeof(double) * L5);
   DExp2(cond_mut->marg->matrix,  L5SQ);
   MarginalizeJointProbs(cond_mut->marg->matrix, pmarg, L5, 2);

  if (verbose) 
    fprintf(stdout, "RIBO5Mut Target Marginal probabilities \n");
    PrintVectorProbs(stdout, pmarg, L5);

   for (i = 0; i < L5SQ; i++) {
     DExp2(cond_mut->cond->matrix + i*L5SQ, L5SQ);
     /* ChangePairProbs(L5, cond_mut->cond->matrix + i*L5SQ, pmarg, TRUE, verbose);*/
     ChangePairProbsIterate(fp, cond_mut->cond->matrix + i*L5SQ, L5, pmarg, TRUE, verbose);
     DLog2(cond_mut->cond->matrix + i*L5SQ, L5SQ);
   }
   DLog2(cond_mut->marg->matrix,  L5SQ);
  free (pmarg);
  
  if (verbose) 
    PrintFullRIBOCondMatrix(fp, cond_mut, FALSE, FALSE);

  *ret_ribocond5_mut  = cond_mut;
  
}

void
CalculateRIBOMutConditionals (FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond_mut, int verbose)
{
  fullcondmat_t *cond_mut;
  double     val, log2val;
  double     valm, log2valm;
  int        L;
  int        LSQ;
  int        xl, yl;
  int        xr, yr;
  int        xpair, ypair;
  int        xpairm, ypairm;
  int        lmut, rmut;
  int        idxm;
  int        i;
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  cond_mut = AllocFullCondMatrix(L);

  snprintf (cond_mut->name, 40, "%s%s", riboprob->name, "-CONDbyMUT");
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  xpairm = idx(xr,xl);
	  ypairm = idx(yr,yl);

	  lmut = idx(xl,yl);
	  rmut = idx(xr,yr);
	  
	  idxm  = lmut  * LSQ  + rmut;

	  log2val  = riboprob->paired->matrix[matrix_index(xpair,ypair)];
	  log2valm = riboprob->paired->matrix[matrix_index(xpairm,ypairm)];

	  val  = EXP2(log2val);
	  valm = EXP2(log2valm);
	 
	  cond_mut->cond->matrix[idxm] = LOG2(val+valm) - 1.0;
	  
	  cond_mut->marg->matrix[lmut] += 0.5 * (val+valm);
	}
  
  /* normalize marginals in log2 space */
  DLog2(cond_mut->marg->matrix, LSQ);
  DLog2Norm(cond_mut->marg->matrix, LSQ);
  
  /* check the marginal probabilities */
  CheckSingleLog2Prob(cond_mut->marg->matrix, LSQ);
  
  /* Calculate conditionals in log2 space*/
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	    xpair = idx(xl,xr);
	    ypair = idx(yl,yr);
	    
	    lmut = idx(xl,yl);
	    rmut = idx(xr,yr);
	    
	    idxm = lmut  * LSQ + rmut;
	    
	    cond_mut->cond->matrix[idxm] -= cond_mut->marg->matrix[lmut]; 
	}
 
  /* And renormalize conditionals
   */
  for (i = 0; i < LSQ; i++) 
    DLog2Norm (cond_mut->cond->matrix + i*LSQ, LSQ); 
  
  /* check the conditional probabilities */
  for (i = 0; i < LSQ; i++) 
    CheckSingleLog2Prob(cond_mut->cond->matrix + i*LSQ, LSQ);
 
  if (verbose)
    PrintFullRIBOCondMatrix(fp, cond_mut, FALSE, FALSE);

  *ret_ribocond_mut  = cond_mut;
  
}

/* Function: CalculateRIBOMutConditionalsApprox()
 * Date:     ER,  Tue May 11 17:23:39 CDT 2004  [St. Louis at home with Coro]
 *           
 *
 * Purpose:  Given a set of  16x16 pair probabilities calculate the mut conditionals.
 *
 *           This is NOT a substitution process, so we have TWO sets of Conditionals
 *
 *                             x x'                                           x x'
 *         Q_L (x',y'|x,y) = p(    ) / pl(x,y)   with pl(x,y) = sum_{x',y'} p(    )
 *                             y y'                                           y y'
 *
 *                             x' x                                           x' x
 *         Q_R (x',y'|x,y) = p(    ) / pr(x,y)   with pr(x,y) = sum_{x',y'} p(    )
 *                             y' y                                           y' y
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void  
CalculateRIBOMutConditionalsApprox(FILE *ofp, int L, double *riboprobs, fullcondmat_t **ret_ribocond_mut, int verbose)
{
  fullcondmat_t *ribocond_mut;
  int            LSQ;

  LSQ = L*L;

  ribocond_mut = AllocFullCondMatrix(L);

  *ret_ribocond_mut = ribocond_mut;
}

/* Function: CalculateRIBO5PairConditionals()
 * Date:     ER, Fri Jan 31 14:36:02 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  Calculate conditional probabilities from a RIBOPROB matrix of jont probs. add gaps
 *           
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
CalculateRIBO5PairConditionals_201(FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond5_pair, 
				   double *pair5prob, double *mut5pxy, int verbose)
{
  fullcondmat_t *cond_pair;
  fullcondmat_t *cond_pair_nought;
  double        *pmarg;
  double         val, log2val;
  int            L, L5;
  int            LSQ, L5SQ;
  int            xl, yl;
  int            xr, yr;
  int            xpair, ypair;
  int            xpair5, ypair5;
  int            idxp, idx5p;
  int            i;
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  L5   = L + 1;
  L5SQ = L5 * L5;
  
  cond_pair        = AllocFullCondMatrix(L5);
  cond_pair_nought = AllocFullCondMatrix(L5);

  cond_pair_nought->cond->matrix = Cal_Id(L5);

  snprintf (cond_pair->name, 40, "%s%s", riboprob->name, "-CONDbyPAIRatTstart");
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  xpair5 = idx5(xl,xr);
	  ypair5 = idx5(yl,yr);

	  idxp  = xpair  * LSQ  + ypair;
	  idx5p = xpair5 * L5SQ + ypair5;

	  log2val  = riboprob->paired->matrix[matrix_index(xpair,ypair)];

	  val  = EXP2(log2val);
	 
	  cond_pair->cond->matrix[idx5p] = log2val;
	  
	  cond_pair->marg->matrix[xpair5] += val;
	  
	}
  
  /* check the marginal probabilities before adding gaps*/
  CheckSingleProb(cond_pair->marg->matrix, L5SQ);
  
  /* convert marginals to log2 */
  DLog2(cond_pair->marg->matrix, L5SQ);
  
  /* Calculate conditionals in log2 space, before adding gaps */
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	    xpair5 = idx5(xl,xr);
	    ypair5 = idx5(yl,yr);
	    
	    idx5p = xpair5 * L5SQ + ypair5;
	    
	    if (xl < 4 && xr < 4 && yl < 4 && yr < 4 ) 
	      cond_pair->cond->matrix[idx5p] -= cond_pair->marg->matrix[xpair5];
	    else 
	      cond_pair->cond->matrix[idx5p] = -DBL_MAX;
	    
	}
  
 
  /* check the conditional probabilities */
  for (i = 0; i < L5SQ; i++) 
    if (i%L5SQ < L && i/L5SQ < L) 
      CheckSingleLog2Prob(cond_pair->cond->matrix + i*L5SQ, L5SQ);  
   
  /* Finally, add gaps (in log2 space)
   */

                                 /* GAPS to the marginals */ 
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) {
	xpair5 = idx5(xl,xr);
	cond_pair->marg->matrix[xpair5] = LOG2(pair5prob[xpair5]);	    
      }
  
  /* And renormalize marginals
   */
  DLog2Norm (cond_pair->marg->matrix, L5SQ);

                        /* GAPS to the conditionals */ 
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	  if (xl == L || xr == L || yl == L || yr == L) {
	    xpair5 = idx5(xl,xr);
	    ypair5 = idx5(yl,yr);
	    
	    idx5p = xpair5 * L5SQ + ypair5;

	    /* Pair conditionals */
	    lone_PAIR_cond(idx5p, L5SQ, &cond_pair->cond->matrix[idx5p], pair5prob);
	  }
       
	}
 
  /* And renormalize conditionals
   */
  for (i = 0; i < L5SQ; i++) 
    cond_pair->cond->matrix[i*L5SQ+i] = LOG2(pair5prob[i]);
  
  for (i = 0; i < L5SQ; i++) 
    DLog2Norm (cond_pair->cond->matrix + i*L5SQ, L5SQ);

  /* Now change the single nt marginals for each conditiona
   */
  pmarg = (double *) MallocOrDie (sizeof(double) * L5);
  DExp2(cond_pair->marg->matrix,  L5SQ);
  MarginalizeJointProbs(cond_pair->marg->matrix, pmarg, L5, 2);
  
  for (i = 0; i < L5SQ; i++) {
    DExp2(cond_pair->cond->matrix + i*L5SQ, L5SQ);
    ChangePairProbs(L5, cond_pair->cond->matrix + i*L5SQ, pmarg, TRUE, verbose);
    DLog2(cond_pair->cond->matrix + i*L5SQ, L5SQ);
  }
  DLog2(cond_pair->marg->matrix,  L5SQ);
  free (pmarg); 

  if (verbose) 
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE, FALSE);

  *ret_ribocond5_pair = cond_pair;
}

void
CalculateRIBO5PairConditionals (FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond5_pair, double *pair5prob, double *mut5pxy, int verbose)
{
  fullcondmat_t *cond_pair;
  fullcondmat_t *cond_pair_nought;
  double        *pmarg;
  double         val, log2val;
  int            L, L5;
  int            LSQ, L5SQ;
  int            xl, yl;
  int            xr, yr;
  int            xpair, ypair;
  int            xpair5, ypair5;
  int            idxp, idx5p;
  int            i;
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  L5   = L + 1;
  L5SQ = L5 * L5;
  
  cond_pair        = AllocFullCondMatrix(L5);
  cond_pair_nought = AllocFullCondMatrix(L5);

  cond_pair_nought->cond->matrix = Cal_Id(L5);

  snprintf (cond_pair->name, 40, "%s%s", riboprob->name, "-CONDbyPAIRatTstart");
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  xpair5 = idx5(xl,xr);
	  ypair5 = idx5(yl,yr);

	  idxp  = xpair  * LSQ  + ypair;
	  idx5p = xpair5 * L5SQ + ypair5;

	  log2val  = riboprob->paired->matrix[matrix_index(xpair,ypair)];

	  val  = EXP2(log2val);
	 
	  cond_pair->cond->matrix[idx5p] = log2val;
	  
	  cond_pair->marg->matrix[xpair5] += val;
	  
	}
  
  /* check the marginal probabilities before adding gaps*/
  CheckSingleProb(cond_pair->marg->matrix, L5SQ);
  
  /* convert marginals to log2 */
  DLog2(cond_pair->marg->matrix, L5SQ);
  
  /* Calculate conditionals in log2 space, before adding gaps */
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	    xpair5 = idx5(xl,xr);
	    ypair5 = idx5(yl,yr);
	    
	    idx5p = xpair5 * L5SQ + ypair5;
	    
	    if (xl < 4 && xr < 4 && yl < 4 && yr < 4 ) 
	      cond_pair->cond->matrix[idx5p] -= cond_pair->marg->matrix[xpair5];
	    else 
	      cond_pair->cond->matrix[idx5p] = -DBL_MAX;
	    
	}
  
 
  /* check the conditional probabilities */
  for (i = 0; i < L5SQ; i++) 
    if (i%L5SQ < L && i/L5SQ < L) 
      CheckSingleLog2Prob(cond_pair->cond->matrix + i*L5SQ, L5SQ);  
   
  /* Finally, add gaps (in log2 space)
   */

                                 /* GAPS to the marginals */ 
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) {
	xpair5 = idx5(xl,xr);
	cond_pair->marg->matrix[xpair5] = LOG2(pair5prob[xpair5]);	    
      }
  
  /* And renormalize marginals
   */
  DLog2Norm (cond_pair->marg->matrix, L5SQ);

                        /* GAPS to the conditionals */ 
  for (xl = 0; xl < L5; xl++) 
    for (xr = 0; xr < L5; xr++) 
      for (yl = 0; yl < L5; yl++) 
	for (yr = 0; yr < L5; yr++) {
	  
	  if (xl == L || xr == L || yl == L || yr == L) {
	    xpair5 = idx5(xl,xr);
	    ypair5 = idx5(yl,yr);
	    
	    idx5p = xpair5 * L5SQ + ypair5;

	    /* Pair conditionals */
	    lone_PAIR_cond(idx5p, L5SQ, &cond_pair->cond->matrix[idx5p], pair5prob);
	  }
       
	}
 
  /* And renormalize conditionals
   */
  for (i = 0; i < L5SQ; i++) 
    cond_pair->cond->matrix[i*L5SQ+i] = LOG2(pair5prob[i]);
  
  for (i = 0; i < L5SQ; i++) 
    DLog2Norm (cond_pair->cond->matrix + i*L5SQ, L5SQ);

  /* Now change the single nt marginals for each conditional
   */
  pmarg = (double *) MallocOrDie (sizeof(double) * L5);
  DExp2(cond_pair->marg->matrix,  L5SQ);
  MarginalizeJointProbs(cond_pair->marg->matrix, pmarg, L5, 2);
  
  for (i = 0; i < L5SQ; i++) {
    DExp2(cond_pair->cond->matrix + i*L5SQ, L5SQ);
    /*ChangePairProbs(L5, cond_pair->cond->matrix + i*L5SQ, pmarg, TRUE, verbose);*/
    ChangePairProbsIterate(fp, cond_pair->cond->matrix + i*L5SQ, L5, pmarg, TRUE, verbose);
    DLog2(cond_pair->cond->matrix + i*L5SQ, L5SQ);
  }
  DLog2(cond_pair->marg->matrix,  L5SQ);
  free (pmarg); 

  if (verbose) 
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE, FALSE);

  *ret_ribocond5_pair = cond_pair;
}

void
CalculateRIBOPairConditionals (FILE *fp, fullmat_t *riboprob, fullcondmat_t **ret_ribocond_pair, int verbose)
{
  fullcondmat_t *cond_pair;
  double         val, log2val;
  int            L;
  int            LSQ;
  int            xl, yl;
  int            xr, yr;
  int            xpair, ypair;
  int            idxp;
  int            i;
  
  L   = riboprob->unpaired->edge_size;
  LSQ = L * L;

  cond_pair = AllocFullCondMatrix(L);

  snprintf (cond_pair->name, 40, "%s%s", riboprob->name, "-CONDbyPAIRatTstart");
  
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

	  idxp  = xpair  * LSQ  + ypair;

	  log2val  = riboprob->paired->matrix[matrix_index(xpair,ypair)];

	  val  = EXP2(log2val);
	 
	  cond_pair->cond->matrix[idxp] = log2val;
	  
	  cond_pair->marg->matrix[xpair] += val;
	  
	}
  
  /* convert marginals to log2 and normalize*/
  DLog2(cond_pair->marg->matrix, LSQ);
  DLog2Norm(cond_pair->marg->matrix, LSQ);
  
  /* check the marginal probabilities */
  CheckSingleLog2Prob(cond_pair->marg->matrix, LSQ);
  
  /* Calculate conditionals in log2 space */
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	    xpair = idx(xl,xr);
	    ypair = idx(yl,yr);
	    
	    idxp = xpair * LSQ + ypair;
	    
	    cond_pair->cond->matrix[idxp] -= cond_pair->marg->matrix[xpair];
	}
  
  if (verbose) 
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE, FALSE);
  /* And renormalize conditionals
   */
  for (i = 0; i < LSQ; i++) 
    DLog2Norm (cond_pair->cond->matrix + i*LSQ, LSQ);

  /* check the conditional probabilities */
  for (i = 0; i < LSQ; i++) 
    CheckSingleLog2Prob(cond_pair->cond->matrix + i*LSQ, LSQ);  
   
  if (verbose) 
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE, FALSE);

  *ret_ribocond_pair = cond_pair;
}

/* Function: CalculateRIBOPairConditionalsApprox()
 *
 * Date:     ER,  Tue May 11 17:23:39 CDT 2004  [St. Louis at home with Coro]
 *           
 *
 * Purpose:  Given a set of  16x16 pair probabilities calculate the mut conditionals.
 *
 *           This is a substitution process, so we have ONE sets of Conditionals
 *
 *                           x x'                                           x x'
 *         Q (y-y'|x-x') = p(    ) / p(x-x')   with p(x-x') = sum_{y,y'} p(    )
 *                           y y'                                           y y'
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void  
CalculateRIBOPairConditionalsApprox(FILE *ofp, int L, double *riboprobs, fullcondmat_t **ret_ribocond_pair, int verbose)
{
  char          *title;
  fullcondmat_t *ribocond_pair;
  double          val, log2val;
  int             xl, yl;
  int             xr, yr;
  int             xpair, ypair;
  int             lmut, rmut;
  int             idxp;
  int             idxm;
  int             i;
  int             LSQ;

  LSQ = L*L;

  /* allocate */
  ribocond_pair = AllocFullCondMatrix(L);

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

	  lmut = xl*L + yl;
	  rmut = xr*L + yr;

	  idxp  = xpair * LSQ  + ypair;
	  idxm  = lmut  * LSQ  + rmut;

	  log2val  = riboprobs[idxm];

	  val  = EXP2(log2val);
	 
	  ribocond_pair->cond->matrix[idxp] = log2val;
	  
	  ribocond_pair->marg->matrix[xpair] += val;
	  
	}
  
  /* convert marginals to log2 and normalize*/
  DLog2(ribocond_pair->marg->matrix, LSQ);
  DLog2Norm(ribocond_pair->marg->matrix, LSQ);
  
  /* check the marginal probabilities */
  CheckSingleLog2Prob(ribocond_pair->marg->matrix, LSQ);
  
  /* Calculate conditionals in log2 space */
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	    xpair = xl*L + xr;
	    ypair = yl*L + yr;
	    
	    idxp = xpair * LSQ + ypair;
	    
	    ribocond_pair->cond->matrix[idxp] -= ribocond_pair->marg->matrix[xpair];
	}
  
  /* And renormalize conditionals
   */
  for (i = 0; i < LSQ; i++) 
    DLog2Norm (ribocond_pair->cond->matrix + i*LSQ, LSQ);

  if (verbose) {
    title = (char *) MallocOrDie(sizeof(char)*50);
    snprintf (title, 50, "%s--t=t^*", "PairConditionals from Approximation");
    fprintf (ofp, "\n%s\n", title);
    PrintFullRIBOCondMatrix(ofp, ribocond_pair, TRUE, FALSE);
    free(title);
  }

  /* check the conditional probabilities */
  for (i = 0; i < LSQ; i++) 
    CheckSingleLog2Prob(ribocond_pair->cond->matrix + i*LSQ, LSQ);  
   

  *ret_ribocond_pair = ribocond_pair;
}


void
CalculateRIBOMarginals(FILE *ofp, fullmat_t *riboprobs, double **ret_pmxl, double **ret_pmxr, double **ret_pmyl, double **ret_pmyr, int verbose)
{
  double *pmxl;
  double *pmxr;
  double *pmyl;
  double *pmyr;
  int     L;
  int     LSQ;
  int     i,j;
  int     x;

  L   = riboprobs->unpaired->edge_size;
  LSQ = L * L;

  /* allocate
   */
  pmxl  = (double *) MallocOrDie(sizeof(double) * L);  
  pmxr  = (double *) MallocOrDie(sizeof(double) * L);  
  pmyl  = (double *) MallocOrDie(sizeof(double) * L);  
  pmyr  = (double *) MallocOrDie(sizeof(double) * L);  
 
  for (x = 0; x < L; x++) { 
    pmxl[x] = 0.0; 
    pmxr[x] = 0.0; 
    pmyl[x] = 0.0; 
    pmyr[x] = 0.0; 
}
  
  for (i = 0; i < LSQ; i++) 
    for (j = 0; j < LSQ; j++) {
      pmxl[i/L] += EXP2(riboprobs->paired->matrix[matrix_index(i,j)]);
      pmxr[i%L] += EXP2(riboprobs->paired->matrix[matrix_index(i,j)]);
      pmyl[j/L] += EXP2(riboprobs->paired->matrix[matrix_index(i,j)]);
      pmyr[j%L] += EXP2(riboprobs->paired->matrix[matrix_index(i,j)]);
  }
  
  if (verbose) {
    fprintf(ofp, "RIBO marginals probabilities\n");
    PrintVectorProbs(ofp, pmxl, L);
    PrintVectorProbs(ofp, pmxr, L);  
    PrintVectorProbs(ofp, pmyl, L);
    PrintVectorProbs(ofp, pmyr, L);  
  }

  *ret_pmxl = pmxl;
  *ret_pmxr = pmxr;
  *ret_pmyl = pmyl;
  *ret_pmyr = pmyr;
}

void
ComputeRIBOMarginals(FILE *ofp, fullmat_t *riboprobs, double *pmxl, double *pmxr, double *pmyl, double *pmyr, int verbose)
{
  double *mxl;
  double *mxr;
  double *myl;
  double *myr;
  int     L;

  L = riboprobs->unpaired->edge_size;
 
  CalculateRIBOMarginals(ofp, riboprobs, &mxl, &mxr, &myl, &myr, verbose);

   CopyVector (pmxl, mxl, L);
   CopyVector (pmxr, mxr, L);
   CopyVector (pmyl, myl, L);
   CopyVector (pmyr, myr, L);

   free (mxl);
   free (mxr);
   free (myl);
   free (myr);

}


/* Function: CalculateRIBOProbsApprox()
 * Date:     ER,  Tue May 11 17:13:32 CDT 2004 [St. Louis at home with Coro]
 *           
 *
 * Purpose:  Calculate 16x16 pair probabilities at time t^* from 4x4 mutpxy and 4x4 pair
 *
 *           after they have been modified to have the same background probabilities
 *
 *             x x'
 *          p(     ) = pair(x-x') * pair(y-y') 0.5[ mutpxy(x,y)/p(x)p(y) + mutpxy(x',y')/p(x')p(y') ]
 *             y y'
 *
 *          p(x) are marginals, which should be the same for pair and mutpxy (check that).
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void  
CalculateRIBOProbsApprox(FILE *ofp, int L, double *mutpxy, double *pairprob, double **ret_riboprobs, int verbose)
{
  char   *title;
  double *riboprobs;
  double *psingle_mut;
  double *psingle_pair;
  double  pp_pair, pp_mut;
  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     LSQ;

  LSQ = L*L;

 if (verbose) {
    fprintf(stdout, "pairprobs t=t^*\n");
    PrintProbs(stdout, pairprob, L);
    fprintf(stdout, "mutpxy t=t^*\n");
    PrintProbs(stdout, mutpxy, L);
  }

  /* Allocate memory */
  riboprobs    = (double *) MallocOrDie (sizeof(double) * LSQ * LSQ); 
  psingle_mut  = (double *) MallocOrDie (sizeof(double) * L);
  psingle_pair = (double *) MallocOrDie (sizeof(double) * L);

  /* marginals */
  MarginalizeJointProbs(mutpxy,   psingle_mut,  L, 2);
  MarginalizeJointProbs(pairprob, psingle_pair, L, 2);

 if (verbose) {
   printf("pairprobs marginals probabilities\n");
    PrintVectorProbs(stdout, psingle_pair, L);
    printf("mutpxy marginals probabilities\n");
    PrintVectorProbs(stdout, psingle_mut, L);
  }

  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 = xl*L + xr;
	    ypair = yl*L + yr;

	    lmut = xl*L + yl;
	    rmut = xr*L + yr;
	  
	    idxm  = lmut  * LSQ + rmut;
	    idxmr = rmut  * LSQ + lmut;
	    idxp  = xpair * LSQ + ypair;
	    idxpr = ypair * LSQ + xpair;

	    /* the simple pair-to-pair functions  in log2 space
	     */
	    pp_pair  = -1.0 
	      + LOG2(pairprob[xpair]) + LOG2(pairprob[ypair])
	      + LOG2( (mutpxy[lmut] / (psingle_pair[xl] * psingle_pair[yl]))  + (mutpxy[rmut] / (psingle_pair[xr] * psingle_pair[yr]))  );
	    
	    pp_mut  = -1.0 + 
	      + LOG2(mutpxy[lmut]) + LOG2(mutpxy[rmut])
	      + LOG2( (pairprob[xpair] / (psingle_mut[xl] * psingle_mut[xr])) + (pairprob[ypair] / (psingle_mut[yl] * psingle_mut[yr])) );

	    ppx = pp_pair;
	    
	    riboprobs[idxm] = ppx;
	  } 

  /* normalize */
  DLog2Norm(riboprobs, LSQ*LSQ);
  CheckSingleLog2Prob(riboprobs, LSQ*LSQ);
  
  if (verbose) {
    title = (char *) MallocOrDie(sizeof(char)*40);
    snprintf (title,  40, "%s--t=t^*", "Pair-to-Pair from Approximation");
    PrintRIBOMatrix (stdout, riboprobs, LSQ, FALSE, TRUE, FALSE, title);
    free(title);
  }

  free (psingle_mut);
  free (psingle_pair);

  *ret_riboprobs = riboprobs;
}


void
ChangeRIBOProbsIterate(FILE *ofp, fullmat_t *riboprobs, double *targetfreq, int verbose)
{
  double           *S;
  double           *pmxl;
  double           *pmxr;
  double           *pmyl;
  double           *pmyr;
  double            lambda;
  int               L;
  int               LSQ;
  int               iterations = 0;
  int               xl, xr, yl, yr;
  int               i,j;

  L   = riboprobs->unpaired->edge_size;
  LSQ = L * L;

  CalculateRIBOMarginals(ofp, riboprobs, &pmxl, &pmxr, &pmyl, &pmyr, verbose);

  if (verbose) {
    fprintf(ofp, "Old RIBO Matrix\n");
    PrintFullMatrix (ofp, riboprobs);
    fprintf(ofp, "Old marginals probabilities\n");
    PrintVectorProbs(ofp, pmxl, L);
    PrintVectorProbs(ofp, pmxr, L);  
    PrintVectorProbs(ofp, pmyl, L);
    PrintVectorProbs(ofp, pmyr, L);  
  }
  
  S = (double *) MallocOrDie (sizeof(double) * LSQ * LSQ); 
  
  while (compare_freqs(pmxl, pmxr, pmyl, pmyr, targetfreq, L)) {
    iterations ++;
    
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) {
	xl = i/L;
	xr = i%L;
	
	yl = j/L;
	yr = j%L;
	
	S[i*LSQ+j] = riboprobs->paired->matrix[matrix_index(i,j)] 
	  - LOG2(pmxl[xl]) - LOG2(pmxr[xr]) - LOG2(pmyl[yl]) - LOG2(pmyr[yr]);
      }
    
    lambda = cal_RIBO_lambda(ofp, S, targetfreq, targetfreq, targetfreq, targetfreq, L, verbose);
    
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) {
	xl = i/L;
	xr = i%L;
	
	yl = j/L;
	yr = j%L;
	
	riboprobs->paired->matrix[matrix_index(i,j)] = lambda*S[i*LSQ+j]  
	  + LOG2(targetfreq[xl]) + LOG2(targetfreq[xr]) + LOG2(targetfreq[yl]) + LOG2(targetfreq[yr]);
      }

    /* normalize */
    DLog2SYMNorm(riboprobs->paired->matrix, riboprobs->paired->edge_size);  
    
    /* check they are probabilities */      
    CheckSYMLog2Prob(riboprobs->paired->matrix, riboprobs->paired->edge_size);    

    ComputeRIBOMarginals(ofp, riboprobs, pmxl, pmxr, pmyl, pmyr, verbose);
  }
  
  if (verbose) {
    fprintf(ofp, "new RIBO (%d it) Matrix\n", iterations);
    PrintFullMatrix (ofp, riboprobs);
    fprintf(ofp, "new marginals probabilities\n");
    PrintVectorProbs(ofp, pmxl, L);
    PrintVectorProbs(ofp, pmxr, L);  
    PrintVectorProbs(ofp, pmyl, L);
    PrintVectorProbs(ofp, pmyr, L);  
  }
  
  free(pmxl);
  free(pmxr);
  free(pmyl);
  free(pmyr);
  
  free(S);
}

void
ChangePPMutProbsIterate(FILE *ofp, double *pp, double *mut5pxy, int L, int verbose)
{
  double           *S;
  double           *pairx;
  double           *pairy;
  double           *pmutl;
  double           *pmutr;
  double            lambda;
  int               LSQ;
  int               iterations = 0;
  int               i,j;

  LSQ = L * L;

  CalculatePPMarginals(ofp, pp, &pairx, &pairy, &pmutl, &pmutr, L, verbose);

  if (verbose) {
    fprintf(ofp, "Old PP Matrix\n");
    PrintProbs(ofp, pp, LSQ);
    fprintf(ofp, "Old marginals probabilities\n");
    fprintf(ofp, "X-pair\n");
    PrintProbs(ofp, pairx, L);
    fprintf(ofp, "Y-pair\n");
    PrintProbs(ofp, pairy, L);  
    fprintf(ofp, "L-mut\n");
    PrintProbs(ofp, pmutl, L);
    fprintf(ofp, "R-mut\n");
    PrintProbs(ofp, pmutr, L);  
  }
  
  S = (double *) MallocOrDie (sizeof(double) * LSQ * LSQ); 
  
  while (compare_2_freqs(pmutl, pmutr, mut5pxy, L)) {
    iterations ++;
    
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) 	
	S[i*LSQ+j] = pp[i*LSQ+j] - LOG2(pmutl[i]) - LOG2(pmutr[j]);
    
    lambda = Cal_lambda(ofp, S, mut5pxy, mut5pxy, LSQ, verbose);
    
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) 
	pp[i*LSQ+j] = lambda*S[i*LSQ+j] + LOG2(mut5pxy[i]) + LOG2(mut5pxy[j]);

    /* normalize */
    DLog2Norm(pp, LSQ*LSQ);  
    
    /* check they are probabilities */      
    CheckSingleLog2Prob(pp, LSQ*LSQ);    

    ComputePPMarginals(ofp, pp, pairx, pairy, pmutl, pmutr, L, verbose);
  }
  
  if (fabs(lambda) < MARGIN) Die ("ChangePPMutProbsIterate(): lambda = %f. trivial", lambda);

  if (verbose) {
    fprintf(ofp, "new PP (%d it) Matrix\n", iterations);
    PrintProbs(ofp, pp, LSQ);
  }
  if (verbose) {
    fprintf(ofp, "new marginals probabilities\n");
    fprintf(ofp, "X-pair\n");
    PrintProbs(ofp, pairx, L);
    fprintf(ofp, "Y-pair\n");
    PrintProbs(ofp, pairy, L);  
    fprintf(ofp, "L-mut\n");
    PrintProbs(ofp, pmutl, L);
    fprintf(ofp, "R-mut\n");
    PrintProbs(ofp, pmutr, L);  
  }
  
  free(pairx);
  free(pairy);
  free(pmutl);
  free(pmutr);
  
  free(S);
}

void
ChangePPPairProbsIterate(FILE *ofp, double *pp, double *pair5prob, int L, int verbose)
{
  double           *S;
  double           *pairx;
  double           *pairy;
  double           *pmutl;
  double           *pmutr;
  double            lambda;
  int               LSQ;
  int               iterations = 0;
  int               xpair, ypair;
  int               i,j;

  LSQ = L * L;

  CalculatePPMarginals(ofp, pp, &pairx, &pairy, &pmutl, &pmutr, L, verbose);

  if (verbose) {
    fprintf(ofp, "Old PP Matrix\n");
    PrintProbs(ofp, pp, LSQ);
    fprintf(ofp, "Old marginals probabilities\n");
    fprintf(ofp, "X-pair\n");
    PrintProbs(ofp, pairx, L);
    fprintf(ofp, "Y-pair\n");
    PrintProbs(ofp, pairy, L);  
    fprintf(ofp, "L-mut\n");
    PrintProbs(ofp, pmutl, L);
    fprintf(ofp, "R-mut\n");
    PrintProbs(ofp, pmutr, L);  
  }
  
  S = (double *) MallocOrDie (sizeof(double) * LSQ * LSQ); 
  
  while (compare_2_freqs(pairx, pairy, pair5prob, L)) {
    iterations ++;
    
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) {	
	xpair = (i/L)*L + (j/L);
	ypair = (i%L)*L + (j%L);

	S[i*LSQ+j] = pp[i*LSQ+j] - LOG2(pair5prob[xpair]) - LOG2(pair5prob[ypair]);
      }
    
    lambda = Cal_lambda(ofp, S, pair5prob, pair5prob, LSQ, verbose);
    
    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) {
	xpair = (i/L)*L + (j/L);
	ypair = (i%L)*L + (j%L);

	pp[i*LSQ+j] = lambda*S[i*LSQ+j] + LOG2(pair5prob[xpair]) + LOG2(pair5prob[ypair]);
      }

    /* normalize */
    DLog2Norm(pp, LSQ*LSQ);  
    
    /* check they are probabilities */      
    CheckSingleLog2Prob(pp, LSQ*LSQ);    

    ComputePPMarginals(ofp, pp, pairx, pairy, pmutl, pmutr, L, verbose);

    fprintf(ofp, "TARGET\n");
    PrintProbs(ofp, pair5prob, L);  
  }
  
  if (fabs(lambda) < MARGIN) Die ("ChangePPPairProbsIterate(): lambda = %f. trivial", lambda);

  if (verbose) {
    fprintf(ofp, "new PP (%d it) Matrix\n", iterations);
    PrintProbs(ofp, pp, LSQ);
  }
  if (verbose) {
    fprintf(ofp, "new marginals probabilities\n");
    fprintf(ofp, "X-pair\n");
    PrintProbs(ofp, pairx, L);
    fprintf(ofp, "Y-pair\n");
    PrintProbs(ofp, pairy, L);  
    fprintf(ofp, "L-mut\n");
    PrintProbs(ofp, pmutl, L);
    fprintf(ofp, "R-mut\n");
    PrintProbs(ofp, pmutr, L);  
  }
  
  free(pairx);
  free(pairy);
  free(pmutl);
  free(pmutr);
  
  free(S);
}


/* Function: CopyFullMatrix()
 * Date:     ER, Mon Jan 27 12:34:27 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  copy fullmat_t structure 
 *
 * Args:     
 *
 * Returns:  fullmat_t structure
 *           fullmatcopy is allocated here
 */
fullcondmat_t *
CopyFullCondMatrix (fullcondmat_t *fullcondmat) 
{
  fullcondmat_t *fullcondmatcopy;
  
  fullcondmatcopy = AllocFullCondMatrix (fullcondmat->marg->size);

  snprintf (fullcondmatcopy->name, 40, "%s", fullcondmat->name);

  CopyRIBOCondMatrix(fullcondmatcopy->marg, fullcondmat->marg);
  CopyRIBOCondMatrix(fullcondmatcopy->cond, fullcondmat->cond);


  return fullcondmatcopy;
} 

fullmat_t *
CopyFullMatrix (fullmat_t *fullmat) 
{
  fullmat_t *fullmatcopy;
  
  fullmatcopy = AllocFullMatrix (fullmat->unpaired->edge_size);

  snprintf (fullmatcopy->name, 40, "%s", fullmat->name);

  CopyRIBOMatrix(fullmatcopy->unpaired, fullmat->unpaired);
  CopyRIBOMatrix(fullmatcopy->paired,   fullmat->paired);


  return fullmatcopy;
} 

/* Function: CopyMatrix()
 * Date:     ER, Mon Jan 27 12:24:42 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  copy matrix_t structure 
 *
 * Args:     
 *
 * Returns:  void
 *           fill matcopy.
 */
void
CopyRIBOMatrix (matrix_t *matcopy, matrix_t *mat)
{
  int x;

  matcopy->edge_size = mat->edge_size;
  matcopy->full_size = mat->full_size;

  for (x = 0; x < mat->full_size; x++) 
    matcopy->matrix[x] = mat->matrix[x];
}
void
CopyRIBOCondMatrix (condmatrix_t *condmatcopy, condmatrix_t *condmat)
{
  int x;

  condmatcopy->size = condmat->size;

  for (x = 0; x < condmat->size; x++) 
    condmatcopy->matrix[x] = condmat->matrix[x];
}

/* Function: EvolveRIBO5Conditionals()
 * Date:     ER, Wed Jan 29 18:46:12 CST 2003 [St. Louis]
 *           
 *
 * Purpose: Evolve the matrix of conditional probabilities using the model of evolution
 *
 *            Q(t) = Q_0 exp(tA), where A = 1/t^* log [ Q_0^{-1} Q^* ]        
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
EvolveRIBO5PairConditionals (fullcondmat_t *ribo5cond, condmatrix_t *ribo5cond_nought, double *pair5prob, 
			    double tfactor, int ispair, int pedantic, int verbose)
{
  fullcondmat_t *ribo5condr;
  condmatrix_t  *ribo5condr_nought;
  int            L;
  int            L2;
  int            i;

  L  = ribo5cond->marg->size;
  L2 = ribo5cond->cond->size;

  ribo5condr        = CopyFullCondMatrix(ribo5cond);
  ribo5condr_nought = AllocCondMatrix (ribo5cond_nought->size);
  CopyRIBOCondMatrix(ribo5condr_nought, ribo5cond_nought);

  if (verbose) {
    PrintRIBOCondMatrix    (stdout, ribo5cond_nought, ispair, TRUE, ribo5cond->name);
    PrintFullRIBOCondMatrix(stdout, ribo5cond,        ispair, FALSE);
  }

  /* Equate marginals to the already evolved pair5prbos*/
  for (i = 0; i < L2; i ++) 
    ribo5cond->marg->matrix[i] = LOG2(pair5prob[i]);

  /* evolve the conditionals */
  DExp2(ribo5cond->cond->matrix, L2*L2);

  ConditionalsEvolved(stdout, ribo5cond->cond->matrix,  ribo5condr->cond->matrix, ribo5cond_nought->matrix, ribo5condr_nought->matrix, 
		      ribo5cond->marg->matrix, ribo5condr->marg->matrix, 
		      L2, tfactor, ribo5cond->marg->matrix, FALSE, FALSE, pedantic, verbose);
 
  DLog2(ribo5cond->cond->matrix, L2*L2);
  
  snprintf (ribo5cond->name, 40, "%s-%.4f", "COND5byPAIR", tfactor);
  if (verbose) 
    PrintFullRIBOCondMatrix(stdout, ribo5cond, TRUE, FALSE);

  FreeFullCondMatrix(ribo5condr);
  FreeCondMatrix    (ribo5condr_nought);

}

void
EvolveRIBOPairConditionals (fullcondmat_t *ribocond, condmatrix_t *ribocond_nought,  
			    double tfactor, double *targetpair, int changepair, int pedantic, int verbose)
{
  int L;
  int L2;

  L  = ribocond->marg->size;
  L2 = ribocond->cond->size;

  if (verbose) {
    PrintRIBOCondMatrix    (stdout, ribocond_nought, TRUE, TRUE, ribocond->name);
    PrintFullRIBOCondMatrix(stdout, ribocond,        TRUE, FALSE);
    
    fprintf(stdout, "target pair probabilities\n");
    PrintProbs(stdout, targetpair, L);
  }

  /* evolve the conditionals */
  DLog2(targetpair, L2);
  DExp2(ribocond->cond->matrix, L2*L2);

  RIBOConditionalsEvolved(stdout, ribocond, ribocond_nought, tfactor, targetpair, changepair, pedantic, verbose);
  
  snprintf (ribocond->name, 40, "%s-%.4f", "CONDbyPAIR", tfactor);
  if (verbose) 
    PrintFullRIBOCondMatrix(stdout, ribocond, TRUE, FALSE);
}


/* Function: FreeFullMatrix()
 * Date:     ER, Wed Jan 22 14:07:26 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  free fullmat structure
 *
 * Args:     
 *
 * Returns:  void
 *           fullmat is freed
 */
void
FreeFullMatrix (fullmat_t *fullmat) {

  free (fullmat->name);

  FreeMatrix(fullmat->unpaired);
  FreeMatrix(fullmat->paired);
  
  free(fullmat);
}

void
FreeFullCondMatrix (fullcondmat_t *fullcondmat) {

  free (fullcondmat->name);

  FreeCondMatrix(fullcondmat->marg);
  FreeCondMatrix(fullcondmat->cond);
  
  free(fullcondmat);
}

void
FreeMatrix (matrix_t *mat) {

  free(mat->matrix);
  free(mat);
}

void
FreeCondMatrix (condmatrix_t *mat) {

  free(mat->matrix);
  free(mat);
}


/* Robbie's function 
 *
 * Maps c as follows:
 * A->0
 * C->1
 * G->2
 * T->3
 * U->3
 * else->-1
 */
int
numbered_nucleotide (char c) {
  switch (c) {
  case 'A':
  case 'a':
    return (0);
  case 'C':
  case 'c':
    return (1);
  case 'G':
  case 'g':
    return (2);
  case 'T':
  case 't':
  case 'U':
  case 'u':
    return (3);
  }
  return (-1);
}

/* Robbie's function 
 *
 * Maps base pair c,d as follows:
 *
 * AA -> 0
 * AC -> 1
 * ....
 * TG -> 15
 * TT -> 16 (T==U)
 * Anything else maps to -1
 */
int 
numbered_basepair (char c, char d) {
  int c_num, d_num;
  c_num = numbered_nucleotide (c);
  d_num = numbered_nucleotide (d);
  if (c_num < 0 || d_num < 0) {
    return (-1);
  } else {
    return ((c_num << 2) | d_num);
  }
}

/* Robbie's function -- it only works for ungapped and symetric matrices
 *
 * print_matrix
 *
 * Dumps the paired and unpaired matrices and gap penalties
 */
void 
PrintFullMatrix (FILE *fp, fullmat_t *fullmat) {
  
  int i, j;
  
  fprintf (fp, "%s\n\n", fullmat->name);
  
  fprintf (fp, "    ");
  for (i=0; i<sizeof(RNA_ALPHABET)-1; i++) { 
    fprintf (fp, "%c         ", RNA_ALPHABET[i]); 
  } 
  fprintf (fp, "\n"); 
  for (i=0; i<sizeof(RNA_ALPHABET)-1; i++) { 
    fprintf (fp, "%c   ", RNA_ALPHABET[i]); 
    for (j=0; j<=i; j++) { 
      fprintf (fp, "%-9.2f ", fullmat->unpaired->matrix[matrix_index(numbered_nucleotide(RNA_ALPHABET[i]), numbered_nucleotide(RNA_ALPHABET[j]))]); 
    } 
    fprintf (fp, "\n"); 
  } 
  
  if (strstr (fullmat->name, "RIBOPROB") == NULL)    /* Not probability mat */
    fprintf (fp, "H: %.4f\nE: %.4f\n", fullmat->unpaired->H, fullmat->unpaired->E);
  
  fprintf (fp, "\n    ");
  for (i=0; i<sizeof(RNAPAIR_ALPHABET)-1; i++) {
    fprintf (fp, "%c%c        ", RNAPAIR_ALPHABET[i], RNAPAIR_ALPHABET2[i]);
  }
  fprintf (fp, "\n");
  for (i=0; i<sizeof(RNAPAIR_ALPHABET)-1; i++) {
    fprintf (fp, "%c%c  ", RNAPAIR_ALPHABET[i], RNAPAIR_ALPHABET2[i]);
    for (j=0; j<=i; j++) {
      fprintf (fp, "%-9.2f ", fullmat->paired->matrix[matrix_index(numbered_basepair(RNAPAIR_ALPHABET[i], RNAPAIR_ALPHABET2[i]), numbered_basepair (RNAPAIR_ALPHABET[j], RNAPAIR_ALPHABET2[j]))]);
    }
    fprintf (fp, "\n");
  }
  
  if (strstr (fullmat->name, "RIBOPROB") == NULL)    /* Not probability mat */
    fprintf (fp, "H: %.4f\nE: %.4f\n", fullmat->paired->H, fullmat->paired->E);
  fprintf (fp, "\n");
}

/* Function: PrintFullRIBOCondMatrix()
 * Date:     ER, Thu Jan 30 11:13:09 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  prints a conditional fullcondmat_t structure. 
 *           Matrices can be  ungapped (4x4 / 16x16) or gapped (5x5 / 25x25)
 * Args:     
 *
 * Returns:  void
 *           
 */
void 
PrintFullRIBOCondMatrix (FILE *fp, fullcondmat_t *fullcondmat, int ispaircond, int islog2) 
{
  int L;
  int L2;
  int i, j;
  int k;

  L = fullcondmat->marg->size;
  L2 = L*L;
  
  fprintf (fp, "\n%s\n\n", fullcondmat->name);
  
  fprintf (fp, "    ");
  for (i = 0; i < L; i++) { 
    fprintf (fp, "%c         ", RNA_ALPHABET_GAP[i]); 
  } 
  fprintf (fp, "\n"); 
  for (i = 0; i < L; i++) { 
    fprintf (fp, "%c   ", RNA_ALPHABET_GAP[i]); 
    for (j = 0; j < L; j++) { 
      fprintf (fp, "%-9.4f ", (islog2)? fullcondmat->marg->matrix[i*L+j] : EXP2(fullcondmat->marg->matrix[i*L+j])); 
    } 
    fprintf (fp, "\n"); 
  } 
  
  fprintf (fp, "\n    ");
  if (ispaircond)
    {
      for (i = 0; i < L; i++) 
	for (j = 0; j < L; j++) 
	  fprintf (fp, "%c%c    ", RNA_ALPHABET_GAP[i], RNA_ALPHABET_GAP[j]);
    } 
  else 
    {  
      for (i = 0; i < L; i++) 
	for (j = 0; j < L; j++) 
	  fprintf (fp, "%c     ", RNA_ALPHABET_GAP[i]); 
      fprintf (fp, "\n    ");
      for (i = 0; i < L; i++) 
	for (j = 0; j < L; j++) 
	  fprintf (fp, "%c     ", RNA_ALPHABET_GAP[j]); 
      
    }
  fprintf (fp, "\n");
  
  for (i = 0; i < L; i++) 
    for (j = 0; j < L; j++) {
      if (ispaircond) { fprintf (fp, "%c%c  ", RNA_ALPHABET_GAP[i], RNA_ALPHABET_GAP[j]); }
      else            { fprintf (fp, "%c\n", RNA_ALPHABET_GAP[i]); fprintf (fp, "%c  ", RNA_ALPHABET_GAP[j]); }
      
      for (k = 0; k < L2; k++) 
	fprintf (fp, "%-5.4f, ", (islog2)? fullcondmat->cond->matrix[(i*L+j)*L2+k] : EXP2(fullcondmat->cond->matrix[(i*L+j)*L2+k]));
      fprintf (fp, "\n");
    }
  
}

/* Function: PrintRIBOCondMatrix()
 * Date:     ER, Thu Jan 30 11:15:16 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  prints a conditional matrix
 *
 *           Matrices can be  ungapped (4x4 / 16x16) or gapped (5x5 / 25x25)
 *
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void 
PrintRIBOCondMatrix (FILE *fp, condmatrix_t *condmat, int ispaircond, int islog2, char *title) 
{
  int L;
  int LSQRT;
  int i, j;
  int k;

  L     = condmat->size;
  LSQRT = (int)sqrt(L);
  
  fprintf (fp, "\n%s\n\n", title);
  
  fprintf (fp, "\n    ");
  if (ispaircond)
    {
       for (i = 0; i < LSQRT; i++) 
	for (j = 0; j < LSQRT; j++) 
	  fprintf (fp, "%c%c    ", RNA_ALPHABET_GAP[i], RNA_ALPHABET_GAP[j]);
    } 
  else 
    {  
      for (i = 0; i < LSQRT; i++) 
	for (j = 0; j < LSQRT; j++) 
	  fprintf (fp, "%c     ", RNA_ALPHABET_GAP[i]); 
      fprintf (fp, "\n    ");
      for (i = 0; i < LSQRT; i++) 
	for (j = 0; j < LSQRT; j++) 
	  fprintf (fp, "%c     ", RNA_ALPHABET_GAP[j]); 
      
    }
  fprintf (fp, "\n");
  
  for (i = 0; i < LSQRT; i++) 
	for (j = 0; j < LSQRT; j++) {
    if (ispaircond) { fprintf (fp, "%c%c  ", RNA_ALPHABET_GAP[i], RNA_ALPHABET_GAP[j]); }
    else            { fprintf (fp, "%c\n", RNA_ALPHABET_GAP[i]); fprintf (fp, "%c  ", RNA_ALPHABET_GAP[j]); }

    for (k = 0; k < L; k++) 
      fprintf (fp, "%-5.3f ", (islog2)? condmat->matrix[(i*LSQRT+j)*L+k] : EXP2(condmat->matrix[(i*LSQRT+j)*L+k]));
    fprintf (fp, "\n");
  }
  
}

void 
PrintRIBOMatrix (FILE *fp, double *mat, int L, int ispaircond, int change, int takelog2, char *title) 
{
  int LSQRT;
  int i, j;
  int k;
  
  LSQRT = (int)sqrt(L);

  fprintf (fp, "\n%s\n\n", title);
  
  fprintf (fp, "\n    ");
  if (ispaircond)
    {
       for (i = 0; i < LSQRT; i++) 
	for (j = 0; j < LSQRT; j++) 
	  fprintf (fp, "%c%c    ", RNA_ALPHABET_GAP[i], RNA_ALPHABET_GAP[j]);
    } 
  else 
    {  
      for (i = 0; i < LSQRT; i++) 
	for (j = 0; j < LSQRT; j++) 
	  fprintf (fp, "%c      ", RNA_ALPHABET_GAP[i]); 
      fprintf (fp, "\n    ");
      for (i = 0; i < LSQRT; i++) 
	for (j = 0; j < LSQRT; j++) 
	  fprintf (fp, "%c      ", RNA_ALPHABET_GAP[j]); 
      
    }
  fprintf (fp, "\n");
  
  for (i = 0; i < LSQRT; i++) 
    for (j = 0; j < LSQRT; j++) {
      if (ispaircond) { fprintf (fp, "%c%c  ", RNA_ALPHABET_GAP[i], RNA_ALPHABET_GAP[j]); }
      else            { fprintf (fp, "%c\n", RNA_ALPHABET_GAP[i]); fprintf (fp, "%c  ", RNA_ALPHABET_GAP[j]); }
      
      for (k = 0; k < L; k++) {
	if (change) {
	  if (takelog2)
	    fprintf (fp, "%-5.4f ", LOG2(mat[(i*LSQRT+j)*L+k]));
	  else 
	    fprintf (fp, "%-5.4f ", EXP2(mat[(i*LSQRT+j)*L+k]));
	}
	else
	  fprintf (fp, "%-5.4f ", mat[(i*LSQRT+j)*L+k]);
      }
      
      fprintf (fp, "\n");
    }
  
}

/* Function: RIBOMutCondFromRIBOPairCond()
 * Date:     ER, Fri Jan 31 15:17:25 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  Calculate mut_conditionals from the pair_conditionals and the mutation and pair probs at a given time
 *           
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
RIBOMutCondFromRIBOPairCond (fullcondmat_t **ret_ribo5cond_mut, fullcondmat_t *ribo5cond_pair, double *mut5pxy, double tfactor, int pedantic, int verbose)
{
  fullcondmat_t *ribo5cond_mut;
  int            xl, yl;
  int            xr, yr;
  int            xpair, ypair;
  int            lmut, rmut;
  int            idxp, idxm;
  int            L;
  int            L2;
  int            i;

  L  = ribo5cond_pair->marg->size;
  L2 = L * L;

  if (verbose) 
    PrintFullRIBOCondMatrix(stdout, ribo5cond_pair, TRUE, FALSE); 

  ribo5cond_mut = AllocFullCondMatrix(L);

  snprintf (ribo5cond_mut->name, 40, "%s-%.4f", "COND5byMUT", tfactor);

  ribo5cond_mut->marg->size = L;
  ribo5cond_mut->cond->size = L2;

  /* Assing the marginals */
  for (i = 0; i < L2; i++) 
    ribo5cond_mut->marg->matrix[i] = LOG2(mut5pxy[i]);
  

  /* Assing the conditionals */
  for (idxp = 0; idxp < L2*L2; idxp++) {

    xpair = idxp / L2;
    ypair = idxp % L2;

    xl = xpair / L;
    xr = xpair % L;

    yl = ypair / L;
    yr = ypair % L;
    
    lmut = xl * L + yl;
    rmut = xr * L + yr;

    idxm = lmut * L2 + rmut;
    
    if (mut5pxy[lmut] > 0.0)
      ribo5cond_mut->cond->matrix[idxm] = ribo5cond_pair->cond->matrix[idxp] + 
	ribo5cond_pair->marg->matrix[xpair] - ribo5cond_mut->marg->matrix[lmut];
    else 
      ribo5cond_mut->cond->matrix[idxm] = -BIGFLOAT;
  }

 /* renormalize */
  for (i = 0; i < L2; i++) 
    DLog2Norm(ribo5cond_mut->cond->matrix + i*L2, L2);

  if (verbose) 
    PrintFullRIBOCondMatrix(stdout, ribo5cond_mut, FALSE, FALSE); 

 
 *ret_ribo5cond_mut = ribo5cond_mut;

}


/* Function: ReadRIOPROBMatrix()
 * Date:     ER, Thu Dec  5 11:17:23 CST 2002 [St. Louis]
 *
 * Purpose:  Read the RIBOPROB matrix from a file
 * 
 *           Modified from RJ Klein ReadMatrix() in rseach rnamat.c
 *
 *
 * Args:    
 *
 * Returns:  void.
 */
fullmat_t *
ReadRIBOPROBMatrix(FILE *matfp) {
  char linebuf[256];
  char fullbuf[16384];
  int fullbuf_used = 0;
  fullmat_t *fullmat;
  int i;
  char *cp, *end_mat_pos;

  fullmat = AllocFullMatrix (RNA_ALPHABET_SIZE);
 
  while (fgets (linebuf, 255, matfp)) {
    strncpy (fullbuf+fullbuf_used, linebuf, 16384-fullbuf_used-1);
    fullbuf_used += strlen(linebuf);
    if (fullbuf_used >= 16384) {
      Die ("ERROR: Matrix file bigger than 16kb\n");
    }
  }

  /* First, find RIBO, and copy matrix name to fullmat->name */
  cp = strstr (fullbuf, "RIBO");
  for (i = 0; cp[i] && !isspace(cp[i]); i++);   /* Find space after RIBO */
  fullmat->name = MallocOrDie(sizeof(char)*(i+1));
  strncpy (fullmat->name, cp, i);
  fullmat->name[i] = '\0';
  cp = cp + i;

  /* Now, find the first A */
  cp = strchr (cp, 'A');
  fullmat->unpaired->edge_size = 0;
  /* And count how edge size of the matrix */
  while (*cp != '\n' && cp-fullbuf < fullbuf_used) {
    if (!isspace (cp[0]) && isspace (cp[1])) {
      fullmat->unpaired->edge_size++;
    }
    cp++;
  }

  /* Find next A */
  while (*cp != 'A' && (cp-fullbuf) < fullbuf_used) cp++;
 
  /* Take numbers until we hit the first pair AA */
  end_mat_pos = strstr (cp, "AA");
  for (i=0; cp - fullbuf < end_mat_pos-fullbuf; i++) {
    while (!isdigit(*cp) && *cp != '-' && *cp != '.' && \
	   cp-fullbuf < fullbuf_used && cp != end_mat_pos) { 
	cp++;
    }
    if (cp == end_mat_pos)
      break;
    if (cp-fullbuf < fullbuf_used) {
      fullmat->unpaired->matrix[i] = atof(cp);
      while ((isdigit (*cp) || *cp == '-' || *cp == '.') &&\
	     (cp-fullbuf <fullbuf_used)) {
	cp++;
      }
    }
  }
  fullmat->unpaired->full_size = i;

  /********* PAIRED MATRIX ************/
  /* Now, find the first A */
  cp = strchr (cp, 'A');
  fullmat->paired->edge_size = 0;
  /* And count how edge size of the matrix */
  while (*cp != '\n') {
    if (!isspace (cp[0]) && isspace (cp[1])) {
      fullmat->paired->edge_size++;
    }
    cp++;
  }

  /* Find next A */
  while (*cp != 'A' && (cp-fullbuf) < fullbuf_used) cp++;

  /* Take numbers until we hit conditionlas (which we do need) */
  end_mat_pos = strstr (cp, "RIBO");
  for (i=0; cp - fullbuf < end_mat_pos-fullbuf; i++) {
    while (!isdigit(*cp) && *cp != '-' && *cp != '.' && \
	   cp-fullbuf < fullbuf_used && cp != end_mat_pos) { 
	cp++;
    }
    if (cp == end_mat_pos)
      break;
    if (cp-fullbuf < fullbuf_used) {
      fullmat->paired->matrix[i] = atof(cp);
      while ((isdigit (*cp) || *cp == '-' || *cp == '.') &&\
	     (cp-fullbuf <fullbuf_used)) {
	cp++;
      }
    }
  }
  fullmat->paired->full_size = i;


  return (fullmat);
}

double
cal_RIBO_lambda(FILE *ofp, double *S, double *pmxl, double *pmxr, double *pmyl, double *pmyr, int L, int verbose)
{
  double lambda;
  double func;
  double dfunc;
  double x = 0;
  double xnew = 1.0;
  
  while (fabs(xnew-x) > 1.0-accuracy1) {
    
    x = xnew;

    func  = calfunc (x, S, pmxl, pmxr, pmyl, pmyr, L);
    dfunc = caldfunc(x, S, pmxl, pmxr, pmyl, pmyr, L);
    
    if (dfunc != 0.0) xnew = x - func/dfunc;
    
  }

  lambda = xnew;
  
  return lambda;
}

double
calfunc(double x, double *S, double *pmxl, double *pmxr, double *pmyl, double *pmyr, int L)
{
  double y = 0.0;
  int    LSQ;
  int    xl, xr, yl, yr;
  int    i,j;

  LSQ = L * L;

  for (i = 0; i < LSQ; i++)
    for (j = 0; j < LSQ; j++) {
	xl = i/L;
	xr = i%L;
	
	yl = j/L;
	yr = j%L;
     
      y += exp(x*S[i*LSQ+j]) * pmxl[xl] * pmxr[xr] * pmyl[yl] * pmyr[yr];
    }

  y -= 1.0;

  return y;
}
double
caldfunc(double x, double *S, double *pmxl, double *pmxr, double *pmyl, double *pmyr, int L)
{
  double y = 0.0;
  int    LSQ;
  int    xl, xr, yl, yr;
  int    i,j;

  LSQ = L * L;

  for (i = 0; i < LSQ; i++)
    for (j = 0; j < LSQ; j++) {	
      xl = i/L;
	xr = i%L;
	
	yl = j/L;
	yr = j%L;

      y += S[i*L+j] * exp(x*S[i*LSQ+j]) * pmxl[xl] * pmxr[xr] * pmyl[yl] * pmyr[yr];
    }

  return y;
}

int
compare_2_freqs(double *pml, double *pmr, double *targetfreq, int L)
{
  int flag = FALSE;
  int i;
  
  for (i = 0; i < L; i ++) 
    if (fabs(pml[i]-targetfreq[i]) > 1.0-accuracy1 || fabs(pmr[i]-targetfreq[i]) > 1.0-accuracy1) 
      flag = TRUE;
  
  return flag;
}

int
compare_freqs(double *pmxl, double *pmxr, double *pmyl, double *pmyr, double *targetfreq, int L)
{
  int flag = FALSE;
  int i;
  
  for (i = 0; i < L; i ++) 
    if (fabs(pmxl[i]-targetfreq[i]) > 1.0-accuracy1 || fabs(pmxr[i]-targetfreq[i]) > 1.0-accuracy1 ||
	fabs(pmyl[i]-targetfreq[i]) > 1.0-accuracy1 || fabs(pmyr[i]-targetfreq[i]) > 1.0-accuracy1) 
      flag = TRUE;
  
  return flag;
}


void
lone_MUT_cond (int idx, int L, double *ret_cond_mut_mtx, double *mut5pxy)
{
  double  cond_mut_mtx;
  int     LSQRT;
  int     xl, xr;
  int     yl, yr;
  int     xpair, ypair;
  int     lmut, rmut;

  LSQRT = sqrt(L);

  lmut = idx / L;
  rmut = idx % L;

  xl = lmut / LSQRT;
  yl = lmut % LSQRT;

  xr = rmut / LSQRT;
  yr = rmut % LSQRT;

  xpair = xl * LSQRT + xr;
  ypair = yl * LSQRT + yr;
  
  cond_mut_mtx = LOG2(mut5pxy[rmut]);
    
  *ret_cond_mut_mtx = cond_mut_mtx;

}


void
lone_PAIR_cond (int idx, int L, double *ret_cond_pair_mtx, double *pair5prob)
{
  double  cond_pair_mtx;
  int     LSQRT;
  int     xl, xr;
  int     yl, yr;
  int     xpair, ypair;
  int     lmut, rmut;

  LSQRT = sqrt(L);

  xpair = idx / L;
  ypair = idx % L;

  xl = xpair / LSQRT;
  xr = xpair % LSQRT;

  yl = ypair / LSQRT;
  yr = ypair % LSQRT;

  lmut = xl * LSQRT + yl;
  rmut = xr * LSQRT + yr;

  cond_pair_mtx = LOG2(pair5prob[ypair]);
  
  *ret_cond_pair_mtx = cond_pair_mtx;

}



