/********************************************************************************************************
 * QRNA - Comparative analysis of biological sequences 
 *         with pair hidden Markov models, pair stochastic context-free
 *        grammars, and probabilistic evolutionary  models.
 *       
 * Version 2.0.3 (MAY 2004)
 *
 * Copyright (C) 2000-2004 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.
 ***********************************************************************************************************/

/* evolemissions.c
 * 
 *
 * ER, Wed May 19 11:00:56 CDT 2004 [STL, at work with Coro]
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <time.h>

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

/* Function: EvolAddGapsRIBO5Probs()
 *
 * Date:     ER, Thu May 20 11:30:41 CDT 2004  [St. Louis at home with Coro]
 *           
 *
 * Purpose:  Given a set of  16x16 riboprob probabilities calculate the gapped 25x25 ribo5prob
 *
 * 
*`           x x'                                           
 *         p(    , t) = Q (y-y' | x-x', t) * p(x-x', t)   if x,x',y,y' non gaps
 *           y y'                                           
 *
 *           x x'                                           
 *         p(    , t) = p(x-x',t) * p(y-y',t) * 0.5 * [ p (x,y,t) /p(x,t)*p(y,t) + p(x',y',t) / p(x',t)*p(y',t) ]   if x,x',y,y' include gaps
 *           y y'                                           
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
EvolAddGapsRIBO5Probs(struct psubs_s *riboprob, struct psubs_s *mut5pxy, struct pnonsubs_s *pair5prob, 
		      struct psubs_s **ret_ribo5prob, double *targetfreq, int verbose)
{
  struct psubs_s    *ribo5prob;
  struct pnonsubs_s *ribo5mutcond;
  double          ppx;
  double          ppx_mut;
  double          ppx_pair_a;
  double          ppx_pair_b;
  double          ppx_mut_a;
  double          ppx_mut_b;
  double          ppx_pair;
  double          ppxadd_mut, ppxadd_pair;
  double          weight;
  double          weight_at_star;
  double          weight_at_zero;
  double          weight_at_infty;
  int             xl, xr, yl, yr;
  int             xpair, ypair;
  int             lmut, rmut;
  int             idxp, idxpr;
  int             idxm, idxmr;
  int             xpair5, ypair5;
  int             lmut5, rmut5;
  int             idxm5, idxmr5;
  int             idxp5, idxpr5;
  int             L, L5;
  int             LSQ, L5SQ;
  int             islog;

  LSQ = riboprob->L;
  L   =  sqrt(LSQ);

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

  if (verbose) {
    fprintf(stdout, "\nRIBOPairConditionals t=%f\n", riboprob->time);
    PrintProbs(stdout, riboprob->Q, LSQ);
    fprintf(stdout, "pair5probs t=%f\n", pair5prob->time);
    PrintProbs(stdout, pair5prob->P, L5);
    fprintf(stdout, "mut5pxy t=%f\n", mut5pxy->time);
    PrintProbs(stdout, mut5pxy->P, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pml, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pmr, L5);
    printf("mut5pxy marginals probabilities\n");
    PrintVectorProbs(stdout, mut5pxy->pm, L5);
  }
  
  /* allocate
   */
  AllocSubsProbs(L5SQ, &ribo5prob);
  
  ribo5prob->time = riboprob->time;
  
  /* the RIBOSUM pair-to-pair functions with gaps
   */
  for (xl = 0; xl < L5; xl++)
    for (yl = 0; yl < L5; yl++)
      for (xr = 0; xr < L5; xr++)
	for (yr = 0; yr < L5; yr++)
	  {
	    xpair5 = xl*L5 + xr;
	    ypair5 = yl*L5 + yr;
	    
	    lmut5  = xl*L5 + yl;
	    rmut5  = xr*L5 + yr;

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

	    idxp5  = xpair5 * L5SQ + ypair5;
	    idxpr5 = ypair5 * L5SQ + xpair5;
	    
	    if (pair5prob->P[xpair5] > 0.0 && pair5prob->P[ypair5] > 0.0 && 
		pair5prob->pml[xl]   > 0.0 && pair5prob->pmr[xr]   > 0.0 &&
		pair5prob->pml[yl]   > 0.0 && pair5prob->pmr[yr]   > 0.0   ) 
	      {
		ppxadd_mut  = - 1.0 
		  + LOG2( pair5prob->P[xpair5] / (pair5prob->pml[xl]*pair5prob->pmr[xr]) +
			  pair5prob->P[ypair5] / (pair5prob->pml[yl]*pair5prob->pmr[yr])   );
	      }
	    else 
	      {
		ppxadd_mut = -BIGFLOAT;
	      }
	    
	    if (mut5pxy->P[lmut5] > 0.0 && mut5pxy->P[rmut5] > 0.0 && 
		mut5pxy->pm[xl]   > 0.0 && mut5pxy->pm[yl]   > 0.0 &&
		mut5pxy->pm[xr]   > 0.0 && mut5pxy->pm[yr]   > 0.0   ) 
	      {
		ppxadd_pair = - 1.0
		  + LOG2( mut5pxy->P[lmut5] / (mut5pxy->pm[xl]*mut5pxy->pm[yl]) +     
			  mut5pxy->P[rmut5] / (mut5pxy->pm[xr]*mut5pxy->pm[yr])    );
	      }
	    else 
	      {
		ppxadd_pair = -BIGFLOAT;
	      }
	    
	    if (xl < L && yl < L && xr < L && yr < L) {
	      
	      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_pair_a = riboprob->P[idxm];
	      ppx_pair_b = riboprob->P[idxmr];
	      
	      ppx_mut_a  = (mut5pxy->P[lmut5] > 0.0)? LOG2(mut5pxy->P[lmut5]) : -BIGFLOAT;
	      ppx_mut_b  = (mut5pxy->P[rmut5] > 0.0)? LOG2(mut5pxy->P[rmut5]) : -BIGFLOAT;

	      ppx_pair = LOG2(EXP2(ppx_pair_a) + EXP2(ppx_pair_b)) - 1.0;
	      ppx_mut = ppx_mut_a + ppx_mut_b + ppxadd_mut;

	      ppx = ppx_pair;

	    }
	    else { /* assume independence */
	      
	      ppx_pair_a = (pair5prob->P[xpair5] > 0.0)? LOG2(pair5prob->P[xpair5]) : -BIGFLOAT;
	      ppx_pair_b = (pair5prob->P[ypair5] > 0.0)? LOG2(pair5prob->P[ypair5]) : -BIGFLOAT;
	      
	      ppx_mut_a  = (mut5pxy->P[lmut5] > 0.0)? LOG2(mut5pxy->P[lmut5]) : -BIGFLOAT;
	      ppx_mut_b  = (mut5pxy->P[rmut5] > 0.0)? LOG2(mut5pxy->P[rmut5]) : -BIGFLOAT;
	     	      
	      ppx_pair = ppx_pair_a + ppx_pair_b + ppxadd_pair;
	      
	      ppx_mut  = ppx_mut_a  + ppx_mut_b  + ppxadd_mut;

	      ppx = (ppx_mut < ppx_pair)? ppx_mut : ppx_pair;
	      
	    }
	    
	    if (pair5prob->pml[xl] > 0.0 || pair5prob->pmr[xr] > 0.0 ||
		pair5prob->pml[yl] > 0.0 || pair5prob->pmr[yr] > 0.0 ||
		mut5pxy->pm[xl]    > 0.0 || mut5pxy->pm[yl]    > 0.0 ||
		mut5pxy->pm[xr]    > 0.0 || mut5pxy->pm[yr]    > 0.0   )   
	      {
		ribo5prob->P[idxm5] = ppx;
	      }
	    else 
	      {		
		ribo5prob->P[idxm5] =  -BIGFLOAT;
	      }
	  }
  
  /* renormalize, renormalize, always renormalize! 
   *
   *   Thankfully, this is easier than applying the renormalization group :) 
   */
  DLog2Norm(ribo5prob->P, L5SQ*L5SQ);	
  CheckSingleLog2Prob(ribo5prob->P, L5SQ*L5SQ);

  /* Calculate conditionals and marginals */
  EvolCalculateRIBOPairConditionalsAndMarginals(stdout, ribo5prob, verbose);
  
  if (verbose) {
    fprintf(stdout, "\nRIBO5 (i,j, t=%f) Joint probabilities\n", ribo5prob->time);
    PrintProbs(stdout, ribo5prob->P, ribo5prob->L);
    fprintf(stdout, "Q(i|j, t=%f) conditional probabilities\n", ribo5prob->time);
    PrintProbs(stdout, ribo5prob->Q, ribo5prob->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, ribo5prob->Rate, ribo5prob->L);
    fprintf(stdout, "pm(i) marginal probabilities\n");
    PrintVectorProbs(stdout, ribo5prob->pm, ribo5prob->L);

    /* calculate Mutation Conditionals and Marginals */
    islog = TRUE;
    ribo5mutcond = EvolComputeRIBOMutConditionalsAndMarginals(stdout, ribo5prob, islog, verbose);
    FreeNonSubsProbs(ribo5mutcond);
   }

  /* this is it. ribo5prob->P are the evolved 25x25 Joint probabilities used by the RNA model
   *
   * BUT they are taken in exp2 form by EvolConstrucRNAModel() in evolrnamodel.c 
   */
  DExp2(ribo5prob->P, ribo5prob->L*ribo5prob->L);
  CheckSingleProb(ribo5prob->P, ribo5prob->L*ribo5prob->L); /* big dose of paranoia */

  if (verbose) {
    fprintf(stdout, "\nFINAL==RIBO5 (i,j, t=%f) Joint probabilities\n", ribo5prob->time);
    PrintProbs(stdout, ribo5prob->P, ribo5prob->L);
    EvolCalculateRIBOProbsCummulative(stdout, ribo5prob->L, ribo5prob->P, FALSE);

    DExp2(ribo5prob->pm, ribo5prob->L);
    EvolCalculateRIBOProbsSaturation(stdout, ribo5prob->L, ribo5prob->pm, FALSE);

    DExp2(ribo5prob->Q, ribo5prob->L*ribo5prob->L);
    fprintf(stdout, "Q(i|j, t=%f) conditional probabilities\n", ribo5prob->time);
    PrintProbs(stdout, ribo5prob->Q, ribo5prob->L);

    fprintf(stdout, "pm(i) marginal probabilities\n");
    PrintProbs(stdout, ribo5prob->pm, sqrt(ribo5prob->L));

    /* calculate Mutation Conditionals and Marginals */
    islog = FALSE;
    ribo5mutcond = EvolComputeRIBOMutConditionalsAndMarginals(stdout, ribo5prob, islog, TRUE);
    FreeNonSubsProbs(ribo5mutcond);
  }
  
  if (verbose) EvolCalculateRIBO5TargetError(targetfreq, ribo5prob, verbose);

  *ret_ribo5prob = ribo5prob;

}

void
EvolCalRIBOMutRate (double *R, int L)
{
  double *rate;
  double  mutsite = 0.0;
  int     Lh;
  int     i, j;
  int     xl, xr, yl, yr;

  Lh =sqrt(L);

  rate = (double *) MallocOrDie (sizeof(double) * L);
  for (i = 0; i < L; i++) rate[i] = 0.0;
  
  for (i = 0; i < L; i++) {

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

      rate[xl*Lh+yl] += R[i*L+j] * 0.25;

    }
  }

  for (i = 0; i < L; i ++) {
    xl = i/Lh;
    yl = i%Lh;

      if (xl == yl) mutsite -= rate[i] * 0.25;
  }

  if (FALSE) {
    printf("cum mutations per site %f\n", mutsite);
    fprintf(stdout, "RIBO cumrate\n");
    PrintProbs(stdout, rate, Lh);
  }

  free(rate);
}

/* Function: EvolCalculateRIBO5MutUncorrelated()
 *
 * Date:     ER, Mon Jul  5 13:14:02 CDT 2004  [St. Louis at work, Coro with Maribel]
 *           
 *
 * Purpose:  
 *
 * Args:   all probabilities in log2 form
 *
 * Returns:  void
 *           
 */
void
EvolCalculateRIBO5MutUncorrelated(FILE *ofp, struct psubs_s *riboprob_star, 
				  struct psubs_s *mut5pxy, struct pnonsubs_s *pair5prob, 
				  struct psubs_s **ret_ribo5prob_MU, int verbose)
{
  struct psubs_s *ribo5prob_MU;
  double          ppxsubs_mut;
  int             xl, xr, yl, yr;
  int             xpair, ypair;
  int             lmut, rmut;
  int             idxp, idxpr;
  int             idxm, idxmr;
  int             xpair5, ypair5;
  int             lmut5, rmut5;
  int             idxm5, idxmr5;
  int             idxp5, idxpr5;
  int             L, L5;
  int             LSQ, L5SQ;
  int             islog;

  islog = TRUE;

  LSQ = riboprob_star->L;
  L   =  sqrt(LSQ);

  L5   = mut5pxy->L;
  L5SQ = L5 * L5;
 
  if (verbose) {
    fprintf(stdout, "\nRIBOPairJoint t=%f\n", riboprob_star->time);
    PrintProbs(stdout, riboprob_star->P, LSQ);
    EvolCalculateRIBOProbsCummulative(ofp, riboprob_star->L, riboprob_star->P, islog);

    fprintf(stdout, "\nRIBOPairConditionals t=%f\n", riboprob_star->time);
    PrintProbs(stdout, riboprob_star->Q, LSQ);
    fprintf(stdout, "pair5probs t=%f\n", pair5prob->time);
    PrintProbs(stdout, pair5prob->P, L5);
    fprintf(stdout, "mut5pxy t=%f\n", mut5pxy->time);
    PrintProbs(stdout, mut5pxy->P, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pml, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pmr, L5);
    printf("mut5pxy marginals probabilities\n");
    PrintVectorProbs(stdout, mut5pxy->pm, L5);
  }
  
  /* allocate
   */
  AllocSubsProbs(L5SQ, &ribo5prob_MU);
  ribo5prob_MU->time = mut5pxy->time;

  /* the Joint probabilities
   */
  for (xl = 0; xl < L5; xl++)
    for (yl = 0; yl < L5; yl++)
      for (xr = 0; xr < L5; xr++)
	for (yr = 0; yr < L5; yr++)
	  {

	    xpair5 = xl*L5 + xr;
	    ypair5 = yl*L5 + yr;
	    
	    lmut5  = xl*L5 + yl;
	    rmut5  = xr*L5 + yr;

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

	    idxp5  = xpair5 * L5SQ + ypair5;
	    idxpr5 = ypair5 * L5SQ + xpair5;
	    
	    if (xl < L && yl < L && xr < L && yr < L) {

	      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;

	    
	      if (mut5pxy->pm[xl] == 0.0 || mut5pxy->pm[yl] == 0.0 ||
		  mut5pxy->pm[xr] == 0.0 || mut5pxy->pm[yr] == 0.0   ) 
		{
		  ppxsubs_mut = BIGFLOAT;
		}
	      else if (mut5pxy->P[lmut5] == 0.0 || mut5pxy->P[rmut5] == 0.0) 
		{
		  ppxsubs_mut = BIGFLOAT;
		}
	      else 
		{
		  ppxsubs_mut = - 1.0
		    + LOG2( mut5pxy->P[lmut5] / (mut5pxy->pm[xl]*mut5pxy->pm[yl]) +     
			    mut5pxy->P[rmut5] / (mut5pxy->pm[xr]*mut5pxy->pm[yr])    );
	      }
	      
	      ribo5prob_MU->P[idxm5] = riboprob_star->P[idxm] - ppxsubs_mut;
	      
	    }
	    else { /* assume independence */
	      ribo5prob_MU->P[idxm5] = LOG2(pair5prob->P[xpair5]) + LOG2(pair5prob->P[ypair5]);
	    }

	  }
  /* normalize */
  DLog2Norm(ribo5prob_MU->P, L5SQ*L5SQ);	
  CheckSingleLog2Prob(ribo5prob_MU->P, L5SQ*L5SQ);
  
  /* the Conditionals and Marginals probabilities
   */
  EvolCalculateRIBOPairConditionalsAndMarginals(stdout, ribo5prob_MU, verbose);

  if (verbose) {
    fprintf(stdout, "\nRIBO5 (i,j, t=%f) MU Joint probabilities\n", ribo5prob_MU->time);
    PrintProbs(stdout, ribo5prob_MU->P, ribo5prob_MU->L);
    EvolCalculateRIBOProbsCummulative(ofp, ribo5prob_MU->L, ribo5prob_MU->P, islog);

    fprintf(stdout, "\nRIBO5 (i,j, t=%f) MU Conditional probabilities\n", ribo5prob_MU->time);
    PrintProbs(stdout, ribo5prob_MU->Q, ribo5prob_MU->L);
  }
  
  *ret_ribo5prob_MU = ribo5prob_MU;

}

/* Function: EvolCalculateRIBO5PairUncorrelated()
 *
 * Date:     ER, Mon Jul  5 13:14:02 CDT 2004  [St. Louis at work, Coro with Maribel]
 *           
 *
 * Purpose:  
 *
 * Args:   all probabilities in log2 form
 *
 * Returns:  void
 *           
 */
void
EvolCalculateRIBO5PairUncorrelated(FILE *ofp, struct psubs_s *riboprob_star, 
				   struct psubs_s *mut5pxy, struct pnonsubs_s *pair5prob, 
				   struct pnonsubs_s **ret_ribo5prob_PU, int verbose)
{
  struct pnonsubs_s *ribo5prob_PU;
  double             ppxsubs_pair;
  int                xl, xr, yl, yr;
  int                xpair, ypair;
  int                lmut, rmut;
  int                idxp, idxpr;
  int                idxm, idxmr;
  int                xpair5, ypair5;
  int                lmut5, rmut5;
  int                idxm5, idxmr5;
  int                idxp5, idxpr5;
  int                L, L5;
  int                LSQ, L5SQ;
  int                islog;

  islog = TRUE;

  LSQ = riboprob_star->L;
  L   =  sqrt(LSQ);

  L5   = mut5pxy->L;
  L5SQ = L5 * L5;
 
  if (verbose) {
    fprintf(stdout, "\nRIBOPairJoint t=%f\n", riboprob_star->time);
    PrintProbs(stdout, riboprob_star->P, LSQ);
    EvolCalculateRIBOProbsCummulative(ofp, riboprob_star->L, riboprob_star->P, islog);

    fprintf(stdout, "\nRIBOPairConditionals t=%f\n", riboprob_star->time);
    PrintProbs(stdout, riboprob_star->Q, LSQ);
    fprintf(stdout, "pair5probs t=%f\n", pair5prob->time);
    PrintProbs(stdout, pair5prob->P, L5);
    fprintf(stdout, "mut5pxy t=%f\n", mut5pxy->time);
    PrintProbs(stdout, mut5pxy->P, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pml, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pmr, L5);
    printf("mut5pxy marginals probabilities\n");
    PrintVectorProbs(stdout, mut5pxy->pm, L5);
  }
  
  /* allocate
   */
  AllocNonSubsProbs(L5SQ, &ribo5prob_PU);
  ribo5prob_PU->time = mut5pxy->time;
  
  /* the Joint probabilities
   */
  for (xl = 0; xl < L5; xl++)
    for (yl = 0; yl < L5; yl++)
      for (xr = 0; xr < L5; xr++)
	for (yr = 0; yr < L5; yr++)
	  {
	    xpair5 = xl*L5 + xr;
	    ypair5 = yl*L5 + yr;
	    
	    lmut5  = xl*L5 + yl;
	    rmut5  = xr*L5 + yr;

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

	    idxp5  = xpair5 * L5SQ + ypair5;
	    idxpr5 = ypair5 * L5SQ + xpair5;
	    
	    if (xl < L && yl < L && xr < L && yr < L) {

	      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;
	      
	      if (pair5prob->pml[xl] == 0.0 || pair5prob->pmr[xr] == 0.0 ||
		  pair5prob->pml[yl] == 0.0 || pair5prob->pmr[yr] == 0.0   ) 
		{
		  ppxsubs_pair = BIGFLOAT;
		}
	      else if (pair5prob->P[xpair5] == 0.0 || pair5prob->P[ypair5] == 0.0) 
		{
		  ppxsubs_pair = BIGFLOAT;
		}
	      else 
		{
		  ppxsubs_pair = - 1.0 
		    + LOG2( pair5prob->P[xpair5] / (pair5prob->pml[xl]*pair5prob->pmr[xr]) +
			    pair5prob->P[ypair5] / (pair5prob->pml[yl]*pair5prob->pmr[yr]) );
		}
	      
	      ribo5prob_PU->P[idxm5] = riboprob_star->P[idxm] - ppxsubs_pair;
	      
	    }
	    else { /* assume independence */
	      ribo5prob_PU->P[idxm5] = LOG2(mut5pxy->P[lmut5]) + LOG2(mut5pxy->P[rmut5]);
	    }

	  }
  /* normalize */
  DLog2Norm(ribo5prob_PU->P, L5SQ*L5SQ);	
  CheckSingleLog2Prob(ribo5prob_PU->P, L5SQ*L5SQ);

  /* the Conditionals and Marginals probabilities
   */
  EvolCalculateRIBOMutConditionalsAndMarginals(stdout, ribo5prob_PU, islog, verbose);

  if (verbose) {
    fprintf(stdout, "\nRIBO5 (i,j, t=%f) PU Joint probabilities\n", ribo5prob_PU->time);
    PrintProbs(stdout, ribo5prob_PU->P, ribo5prob_PU->L);
    EvolCalculateRIBOProbsCummulative(ofp, ribo5prob_PU->L, ribo5prob_PU->P, islog);

    fprintf(stdout, "\nRIBO5 (i,j, t=%f) PU L-Conditional probabilities\n", ribo5prob_PU->time);
    PrintProbs(stdout, ribo5prob_PU->Ql, ribo5prob_PU->L);
    fprintf(stdout, "\nRIBO5 (i,j, t=%f) PU R-Conditional probabilities\n", ribo5prob_PU->time);
    PrintProbs(stdout, ribo5prob_PU->Qr, ribo5prob_PU->L);
  }

  *ret_ribo5prob_PU = ribo5prob_PU;

}


/* Function: EvolCalculateRIBOMutConditionalsApprox()
 *
 * Date:     ER, Tue Jun  1 12:22:04 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:   all probabilities in log2 form
 *
 * Returns:  void
 *           
 */
struct pnonsubs_s *
EvolComputeRIBOMutConditionalsAndMarginals(FILE *ofp, struct psubs_s *riboprob, int islog, int verbose)
{
  struct pnonsubs_s *ribomutcond;
  int                LSQ;

  LSQ = riboprob->L;

  if (verbose) {
    fprintf (ofp, "RIBO Probabilities\n");
    PrintProbs(ofp, riboprob->P, LSQ);
  }

  /* Allocate */
  AllocNonSubsProbs(LSQ, &ribomutcond);
  ribomutcond->time = riboprob->time;

  CopyMatrix(ribomutcond->P, riboprob->P, LSQ, LSQ);

  EvolCalculateRIBOMutConditionalsAndMarginals(ofp, ribomutcond, islog, verbose);
  
  return ribomutcond;

 }

void
EvolCalculateRIBOMutConditionalsAndMarginals(FILE *ofp, struct pnonsubs_s *ribomutcond, int islog, int verbose)
{
  double            val, log2val;
  int               xl, yl;
  int               xr, yr;
  int               lmut, rmut;
  int               idxm, idxmr;
  int               i;
  int               L;
  int               LSQ;

  LSQ = ribomutcond->L;
  L   = sqrt(LSQ);

  if (verbose) {
    fprintf (ofp, "RIBO Probabilities\n");
    PrintProbs(ofp, ribomutcond->P, ribomutcond->L);
  }

  /* put in log2 form if not given that way */
  if (!islog) DLog2(ribomutcond->P, LSQ*LSQ);

  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) {
	  
	  lmut = xl*L + yl;
	  rmut = xr*L + yr;

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

	  log2val = ribomutcond->P[idxm];

	  val = EXP2(log2val);
	 
	  ribomutcond->Ql[idxm]  = log2val;
	  ribomutcond->Qr[idxmr] = log2val;
	  
	  ribomutcond->pml[lmut] += val;
	  ribomutcond->pmr[rmut] += val;
	  
	}
  
  /* convert marginals to log2 and normalize*/
  DLog2(ribomutcond->pml, LSQ);
  DLog2(ribomutcond->pmr, LSQ);
  DLog2Norm(ribomutcond->pml, LSQ);
  DLog2Norm(ribomutcond->pmr, LSQ);
  
  /* check the marginal probabilities */
  CheckSingleLog2Prob(ribomutcond->pml, LSQ);
  CheckSingleLog2Prob(ribomutcond->pmr, 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++) {
	  
	    lmut = xl*L + yl;
	    rmut = xr*L + yr;
	    
	    idxm = lmut * LSQ + rmut;
	    
	    ribomutcond->Ql[idxm] -= ribomutcond->pml[lmut];
	    ribomutcond->Qr[idxm] -= ribomutcond->pmr[lmut];
	}
  
  /* And renormalize conditionals
   */
  for (i = 0; i < LSQ; i++) {
    DLog2Norm (ribomutcond->Ql + i*LSQ, LSQ);
    DLog2Norm (ribomutcond->Qr + i*LSQ, LSQ);
  }

  /* check the conditional and marginal probabilities */
  CheckSingleLog2Prob(ribomutcond->pml, LSQ);  
  CheckSingleLog2Prob(ribomutcond->pmr, LSQ);  
  for (i = 0; i < LSQ; i++) {
    CheckSingleLog2Prob(ribomutcond->Ql + i*LSQ, LSQ);  
    CheckSingleLog2Prob(ribomutcond->Qr + i*LSQ, LSQ);  
  }

  if (verbose) {
    fprintf (ofp, "RIBO MUT-L-conditionals\n");
    PrintProbs(ofp, ribomutcond->Ql, ribomutcond->L);
    fprintf (ofp, "RIBO MUT-R-conditionals\n");
    PrintProbs(ofp, ribomutcond->Qr, ribomutcond->L);

    DExp2(ribomutcond->pml, LSQ);
    DExp2(ribomutcond->pmr, LSQ);
    fprintf (ofp, "RIBO MUT-L-marginals\n");
    PrintProbs(ofp, ribomutcond->pml, L);
    fprintf (ofp, "RIBO MUT-R-marginals\n");
    PrintProbs(ofp, ribomutcond->pmr, L);
    DLog2(ribomutcond->pml, LSQ);
    DLog2(ribomutcond->pmr, LSQ);
  }
}

/* Function: EvolCalculateRIBOPairConditionalsAndMarginals()
 *
 * Date:     ER, Wed May 19 11:20:24 CDT 2004   [St. Louis at work with Coro]
 *           
 *
 * Purpose:  Given a set of  16x16 pair probabilities calculate the PAIR 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:   all probabilities in log2 form
 *
 * Returns:  void
 *           
 */
void  
EvolCalculateRIBOPairConditionalsAndMarginals(FILE *ofp, struct psubs_s *riboprob, int verbose)
{
  double   val, log2val;
  int      xl, yl;
  int      xr, yr;
  int      xpair, ypair;
  int      lmut, rmut;
  int      idxp;
  int      idxm;
  int      i;
  int      L;
  int      LSQ;

  LSQ = riboprob->L;
  L   = sqrt(LSQ);

  if (verbose) {
    fprintf (ofp, "RIBO Probabilities\n");
    PrintProbs(ofp, riboprob->P, riboprob->L);
  }

  /*initialize marginals to zero */
  for (i = 0; i < LSQ; i++) riboprob->pm[i] = 0.0;

  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 = riboprob->P[idxm];

	  val = EXP2(log2val);
	 
	  riboprob->Q[idxp] = log2val;
	  
	  riboprob->pm[xpair] += val;
	  
	}
  
  /* convert marginals to log2 and normalize*/
  DLog2(riboprob->pm, LSQ);
  DLog2Norm(riboprob->pm, LSQ);
  
  /* check the marginal probabilities */
  CheckSingleLog2Prob(riboprob->pm, 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;
	    
	    riboprob->Q[idxp] -= riboprob->pm[xpair];
	}
  
  /* And renormalize conditionals
   */
  for (i = 0; i < LSQ; i++) 
    DLog2Norm (riboprob->Q + i*LSQ, LSQ);

  if (verbose) {
    fprintf (ofp, "RIBO Pair-conditionals\n");
    PrintProbs(ofp, riboprob->Q, riboprob->L);
    fprintf (ofp, "RIBO marginals\n");
    PrintProbs(ofp, riboprob->pm, L);
  }

  /* check the conditional and marginal probabilities */
  CheckSingleLog2Prob(riboprob->pm, LSQ);  
  for (i = 0; i < LSQ; i++) 
    CheckSingleLog2Prob(riboprob->Q + i*LSQ, LSQ);  

}

/* Function: EvolCalculateRIBOProbs()
 * Date:     ER,  Tue May 11 17:13:32 CDT 2004 [St. Louis at work with Coro]
 *           
 *
 * Purpose:  Calculate 16x16 pair probabilities at time t^* from 
 * Args:     
 *
 * Returns:  void
 *           
 */
void  
EvolCalculateRIBOProbs(FILE *ofp, fullmat_t *ribomat, struct psubs_s **ret_riboprob_star, int verbose)
{
  struct psubs_s *riboprob_star;
  int             L;
  int             LSQ;
  int             xl, xr, yl, yr;
  int             xpair, ypair;
  int             lmut, rmut;
  int             idxp, idxm;

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

  /* allocate */
  AllocSubsProbs(LSQ, &riboprob_star);
  
  /* this time will have to be rescaled after the rate matrix is calculated*/  
  riboprob_star->time = 1.0; 

  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 = xpair * LSQ + ypair;
	  idxm = lmut  * LSQ + rmut;

	  riboprob_star->P[idxm] = ribomat->paired->matrix[matrix_index(xpair,ypair)];	  
	}

  /* Now calculate PairConditionals, and PairMarginals */
  EvolCalculateRIBOPairConditionalsAndMarginals(stdout, riboprob_star, verbose);

 if (verbose) {
    fprintf (ofp, "RIBO Joint Probabilties from RIBOSUM.mat\n");
    PrintProbs(ofp, riboprob_star->P, LSQ);
    fprintf(stdout, "RIBOPairConditionals t=%f\n", riboprob_star->time);
    PrintProbs(stdout, riboprob_star->Q, LSQ);
    fprintf(stdout, "RIBOPair marginals\n");
    PrintProbs(stdout, riboprob_star->pm, L);
  }

  *ret_riboprob_star = riboprob_star;
}

/* Function: EvolCalculateRIBOProbsApprox()
 *
 * Date:     ER,  Tue May 11 17:13:32 CDT 2004 [St. Louis at work 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  
EvolCalculateRIBOProbsApprox(FILE *ofp, struct psubs_s *mutpxy_star, struct pnonsubs_s *pairprob_star, 
			     struct psubs_s **ret_riboprobapprox_star, int verbose)
{
  struct psubs_s *riboprobapprox_star;
  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             L;
  int             LSQ;

  if (mutpxy_star->L != pairprob_star->L) 
    Die ("EvolCalculateRIBOProbsApprox(): bad dimensions for mutpxy(%d) or pairprob (%d)\n", mutpxy_star->L, pairprob_star->L);
  
  L   = mutpxy_star->L; 
  LSQ = L*L;

  /* allocate */
  AllocSubsProbs(LSQ, &riboprobapprox_star);
 
  riboprobapprox_star->L    = LSQ;
  riboprobapprox_star->time = 1.0;
  
  if (verbose) { 
    fprintf(stdout, "pairprob 4x4 probabilities\n");
    PrintProbs(stdout, pairprob_star->P, L);
    fprintf(stdout, "mutpxy t=t^*\n");
    PrintProbs(stdout, mutpxy_star->P, L);
  }

  if (verbose) {
    /* make sure that mutpxy and pairprob have the same marginals
     */
    if (CompareFreqs(pairprob_star->pml, pairprob_star->pmr, mutpxy_star->pm, L)) {
      printf("pairprobs L-marginals probabilities\n");
      PrintVectorProbs(stdout, pairprob_star->pml, L);
      printf("pairprobs R-marginals probabilities\n");
      PrintVectorProbs(stdout, pairprob_star->pmr, L);
      printf("mutpxy marginals probabilities\n");
      PrintVectorProbs(stdout, mutpxy_star->pm, L);
      
      Warn("EvolCalculateRIBOProbsApprox(): mutpxy and pairprbo have substantially different marginals\n");
    }
  }
  
  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-functions pair  in log2 space
	     */
	    pp_pair  = -1.0 
	      + LOG2(pairprob_star->P[xpair]) + LOG2(pairprob_star->P[ypair])
	      + LOG2( (mutpxy_star->P[lmut] / (pairprob_star->pml[xl] * pairprob_star->pml[yl]))  
		      + (mutpxy_star->P[rmut] / (pairprob_star->pmr[xr] * pairprob_star->pmr[yr]))  );
	    
	    pp_mut  = -1.0 + 
	      + LOG2(mutpxy_star->P[lmut]) + LOG2(mutpxy_star->P[rmut])
	      + LOG2( (pairprob_star->P[xpair] / (mutpxy_star->pm[xl] * mutpxy_star->pm[xr])) 
		      + (pairprob_star->P[ypair] / (mutpxy_star->pm[yl] * mutpxy_star->pm[yr])) );

	    ppx = pp_pair;
	    
	    riboprobapprox_star->P[idxm] = ppx;
	  } 

  /* normalize */
  DLog2Norm(riboprobapprox_star->P, LSQ*LSQ);
  CheckSingleLog2Prob(riboprobapprox_star->P, LSQ*LSQ);

  /* Now calculate PairConditionals, and PairMarginals */
  EvolCalculateRIBOPairConditionalsAndMarginals(stdout, riboprobapprox_star, verbose);

 if (verbose) {
    fprintf (ofp, "\nRIBO Joint Probabilties from Approximation\n");
    PrintProbs(ofp, riboprobapprox_star->P, LSQ);
    fprintf(stdout, "RIBOPairConditionals t=%f\n", riboprobapprox_star->time);
    PrintProbs(stdout, riboprobapprox_star->Q, LSQ);
    fprintf(stdout, "RIBOPair marginals\n");
    PrintProbs(stdout, riboprobapprox_star->pm, L);
  }

  *ret_riboprobapprox_star = riboprobapprox_star;
}

/* Function: EvolCalculateRIBOProbsCumultive()
 * Date:     ER,  Tue May 11 17:13:32 CDT 2004 [St. Louis at work, Coro with Maribel]
 *           
 *
 * Purpose:  Calculate cumulative probabilities
 * Args:     
 *
 * Returns:  void
 *           
 */
void  
EvolCalculateRIBOProbsCummulative(FILE *ofp, int LSQ, double *ribojointprob, int islog)
{
  double cum_prob_wc   = 0.0;
  double cum_prob_comp = 0.0;
  double cum_prob_else = 0.0;
  int    i, j;
  int    xl, xr, yl, yr;
  int    L;

  L   = sqrt(LSQ);

    for (i = 0; i < LSQ; i++) 
      for (j = 0; j < LSQ; j++) {
	
	xl = i/L;
	yl = i%L;
	
	xr = j/L;
	yr = j%L;
       
	if (IsWcPair(xl, yl, xr, yr))          cum_prob_wc   +=  (islog)? EXP2(ribojointprob[i*LSQ+j]) : ribojointprob[i*LSQ+j];
	if (IsCompensatory(xl, yl, xr, yr))    cum_prob_comp +=  (islog)? EXP2(ribojointprob[i*LSQ+j]) : ribojointprob[i*LSQ+j];
	if (IsNonCompensatory(xl, yl, xr, yr)) cum_prob_else +=  (islog)? EXP2(ribojointprob[i*LSQ+j]) : ribojointprob[i*LSQ+j];
      }

    if (cum_prob_wc + cum_prob_comp + cum_prob_else > 1.0+MARGIN2) 
      Die ("EvolCalculateRIBOProbsCummulative(): sum is larger than one (sum = %f)\n", cum_prob_wc+cum_prob_comp+cum_prob_else);

    fprintf(ofp, "RIBOJOINT: cum_prob_wc = %f cum_prob_comp = %f cum_prob_else = %f \n\n",
	    cum_prob_wc, cum_prob_comp, cum_prob_else);
}
void  
EvolCalculateRIBOProbsSaturation(FILE *ofp, int LSQ, double *pairprob, int islog)
{
  double cum_prob_wc   = 0.0;
  double cum_prob_comp = 0.0;
  double cum_prob_else = 0.0;
  int    i, j;
  int    xl, xr, yl, yr;
  int    xpair, ypair;
  int    L;

  L   = sqrt(LSQ);

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

	if (IsWcPair(xl, yl, xr, yr))          cum_prob_wc   +=  (islog)? EXP2(pairprob[xpair])+EXP2(pairprob[ypair]) : pairprob[xpair]*pairprob[ypair];
	if (IsCompensatory(xl, yl, xr, yr))    cum_prob_comp +=  (islog)? EXP2(pairprob[xpair])+EXP2(pairprob[ypair]) : pairprob[xpair]*pairprob[ypair];
	if (IsNonCompensatory(xl, yl, xr, yr)) cum_prob_else +=  (islog)? EXP2(pairprob[xpair])+EXP2(pairprob[ypair]) : pairprob[xpair]*pairprob[ypair];
      }

    if (cum_prob_wc + cum_prob_comp + cum_prob_else > 1.0+MARGIN2) 
      Die ("EvolCalculateRIBOProbsSaturation(): sum is larger than one (sum = %f)\n", cum_prob_wc+cum_prob_comp+cum_prob_else);

    fprintf(ofp, "RIBO_SATURATION: cum_prob_wc = %f cum_prob_comp = %f cum_prob_else = %f \n\n",
	    cum_prob_wc, cum_prob_comp, cum_prob_else);
}

/* Function: EvolCalculateRIBOTargetError()
 * Date:     ER, Thu Aug 19 19:45:17 CDT 2004  [St. Louis at home with Coro which is not very interested in coding ]
 *
 * Purpose:  Calculates the error commited when changing the background frequencies.
 *
 *
 * Args:    
 *
 * Returns:  (void)
 */
void
EvolCalculateRIBOTargetError(double *targetfreq, struct psubs_s *riboprob, int verbose)
{
  double *p;
  double  error = 0.0;
  int     LH;
  int     i;
  int     x;

  LH = sqrt(riboprob->L);
  
  if (verbose) {
    fprintf(stdout, "Target probabilities\n");
    PrintVectorProbs(stdout, targetfreq, LH);
  }
  CheckSingleProb(targetfreq, LH); /* paranoia */

  if (riboprob->time < 0.0) Die("EvolCalculateRIBO5TargetError(): negative time? %f\n", riboprob->time);

  if (verbose) {
    fprintf(stdout, "RIBO pair marginal probabilities\n");
    PrintProbs(stdout, riboprob->pm, LH);
  }

  p = (double *)  MallocOrDie (sizeof(double) * LH);
  for (x = 0; x < LH; x ++) p[x] = 0.0;
  
  for (i = 0; i < riboprob->L; i ++) {
    p[i/LH] += 0.5 * EXP2(riboprob->pm[i]);
    p[i%LH] += 0.5 * EXP2(riboprob->pm[i]);
  }
  if (verbose) {
    fprintf(stdout, "RIBO single nt marginal probabilities\n");
    PrintVectorProbs(stdout, p, LH);
  }
 CheckSingleProb(p, LH); /* paranoia */

  for (x = 0; x < LH; x ++) 
    error += fabs(targetfreq[x] - p[x]) * targetfreq[x];
 
  error *= 100.0;

  printf("average RIBO error[@t %.3f] = %.2f %\n\n", riboprob->time, error);
 
  free(p);
}

/* Function: EvolCalculateNaivePairTargetError()
 *
 * Date:     ER, Sat Aug 21 09:54:56 CDT 2004  [St. Louis at home with Coro ]
 *
 * Purpose:  Calculates the actual (time dependent) and max (at t infinity)
 *           error commited by using the naive method to change the background frequencies.
 *
 *           Naive method:  given  P(i,j) = pl_i Ql(i,j) = pr_j Qr(j,i)
 *   
 *                          for some target frequencies ~p
 *
 *                          define ~P(i,j) = 0.5 * [ ~pl_i Ql(i,j) + ~pr_j Qr(j,i) ] 
 *
 *                                       = ^pl_i ^Ql(i,j) = ^pr_j ^Qr(j,i)
 *   
 *                          the new marginals are ^p
 *                         
 *                          the difference between ~p (the target frequencies) and ^p (the obtained freqs) is
 *
 *                                        ^pl_i = 0.5 * [ ~p_i + \sum_j ~p_j Qr(j,i) ]
 *
 *                                        ^pr_i = 0.5 * [ ~p_i + \sum_j ~p_j Ql(j,i) ]
 *
 *                            predicted_ave_lerror = 1/2 * \sum_i |~p_i - \sum_j ~p_j Qr(j,i)| * ~pi 
 *                            predicted_ave_rerror = 1/2 * \sum_i |~p_i - \sum_j ~p_j Ql(j,i)| * ~pi 
 *
 *                            actual_ave_lerror    = \sum_i |^pl_i - ~p_i| * ~pi 
 *                            actual_ave_rerror    = \sum_i |^pr_i - ~p_i| * ~pi 
 *
 *
 *
 * Args:     tfactor
 *           L
 *           targetfreq   
 *           p_old 
 *           p_new 
 *           verbose 
 *
 * Returns:  (void)
 */
void
EvolCalculateNaivePairTargetError(double *targetfreq, struct pnonsubs_s *pairprob_old, struct pnonsubs_s *pairprob, int verbose)
{
  double *pl;
  double *pr;
  double  predic_lerror;
  double  predic_rerror;
  double  actual_lerror;
  double  actual_rerror;
  int     L;
  int     x, y;
  
  L = pairprob->L;

  if (verbose) {
    fprintf(stdout, "Target probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
    fprintf(stdout, "OLD probabilities\n");
    PrintVectorProbs(stdout, pairprob_old->pml, L);
    PrintVectorProbs(stdout, pairprob_old->pmr, L);
    fprintf(stdout, "NEW probabilities at time=%.3f\n", pairprob->time);
    PrintVectorProbs(stdout, pairprob->pml, L);
    PrintVectorProbs(stdout, pairprob->pmr, L);
  }

  if (pairprob->time < 0.0) Die("EvolCalculateTargetError(): negative time? %f\n", pairprob->time);

  CheckSingleProb(targetfreq,        L); /* paranoia */
  CheckSingleProb(pairprob_old->pml, L); /* paranoia */
  CheckSingleProb(pairprob_old->pmr, L); /* paranoia */
  CheckSingleProb(pairprob->pml,     L); /* paranoia */
  CheckSingleProb(pairprob->pmr,     L); /* paranoia */

  /* initialize */
  pl = (double *)  MallocOrDie (sizeof(double) * L);
  pr = (double *)  MallocOrDie (sizeof(double) * L);
  for (x = 0; x < L; x ++) {
    pl[x] = 0.0;
    pr[x] = 0.0;
  }
  predic_lerror = 0.0;
  predic_rerror = 0.0;
  actual_lerror = 0.0;
  actual_rerror = 0.0;
  
  for (x = 0; x < L; x ++) 
    for (y = 0; y < L; y ++) {
      pl[x] += targetfreq[y] * pairprob_old->Qr[y*L+x];
      pr[x] += targetfreq[y] * pairprob_old->Ql[y*L+x];
    }
  for (x = 0; x < L; x ++) {
      predic_lerror += 0.5 * fabs(targetfreq[x] - pl[x]) * targetfreq[x];
      predic_rerror += 0.5 * fabs(targetfreq[x] - pr[x]) * targetfreq[x];
    }

  for (x = 0; x < L; x ++) {
    actual_lerror += fabs(targetfreq[x] - pairprob->pml[x]) * targetfreq[x];
    actual_rerror += fabs(targetfreq[x] - pairprob->pmr[x]) * targetfreq[x];
  }

  predic_lerror *= 100.0;
  predic_rerror *= 100.0;
  actual_lerror *= 100.0;
  actual_rerror *= 100.0;

  printf("Predicted_average L-error[L=%d] = %.2f %\n", L, predic_lerror);
  printf("ACTUAL_average L-error[@t %.3f] = %.2f %\n\n", pairprob->time, actual_lerror);

  printf("Predicted_average R-error[L=%d] = %.2f %\n", L, predic_rerror);
  printf("ACTUAL_average R-error[@t %.3f] = %.2f %\n\n", pairprob->time, actual_rerror);
  
  free(pl);
  free(pr);
 
}

void
EvolCalculateRIBO5TargetError(double *targetfreq, struct psubs_s *ribo5prob, int verbose)
{
  double *p5;
  double  error = 0.0;
  double  sum   = 0.0;
  int     L5;
  int     L5SQ;
  int     L;
  int     LSQ;
  int     i;
  int     x;

  L5SQ = sqrt(ribo5prob->L);
  L5 = sqrt(ribo5prob->L);

  L = L5 - 1;
  LSQ = L*L;

  if (verbose) {
    fprintf(stdout, "Target probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
  }
  CheckSingleProb(targetfreq, L); /* paranoia */

  if (ribo5prob->time < 0.0) Die("EvolCalculateRIBO5TargetError(): negative time? %f\n", ribo5prob->time);

  if (verbose) {
    fprintf(stdout, "RIBO5 pair marginal probabilities\n");
    PrintProbs(stdout, ribo5prob->pm, L5);
  }

  p5 = (double *)  MallocOrDie (sizeof(double) * L5);
  for (x = 0; x < L5; x ++) p5[x] = 0.0;
  
  for (i = 0; i < ribo5prob->L; i ++) {
    p5[i/L5] += 0.5 * EXP2(ribo5prob->pm[i]);
    p5[i%L5] += 0.5 * EXP2(ribo5prob->pm[i]);
  }
  if (verbose) {
    fprintf(stdout, "RIBO single nt marginal probabilities\n");
    PrintVectorProbs(stdout, p5, L5);
  }
  CheckSingleProb(p5, L5); /* paranoia */
  
  for (x = 0; x < L; x ++) sum += p5[x];
  
  for (x = 0; x < L; x ++) 
    error += fabs(targetfreq[x] - p5[x]/sum) * targetfreq[x];
 
  error *= 100.0;

  printf("average RIBO5 error[@t %.3f] = %.2f %\n\n", ribo5prob->time, error);
 
  free(p5);
}


void
EvolChangePairProbsIterate(FILE *ofp, struct pnonsubs_s *pairprob, double *targetfreq, int hasindel, int verbose)
{
  double           *S;
  double            lambda;
  int               L;
  int               LSQ;
  int               iterations = 0;
  int               i,j;

  L = pairprob->L;
  LSQ = L * L;

  if (verbose) {
    fprintf(ofp, "\nTarget marginals probabilities\n");
    PrintVectorProbs(ofp, targetfreq, L);
    fprintf(ofp, "Old PAIR Matrix \n");
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "Old Ql(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Ql, L);
    fprintf(ofp, "Old Qr(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Qr, L);
    fprintf(ofp, "Old marginals probabilities\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);
  }
  
  S = (double *) MallocOrDie (sizeof(double) * LSQ); 
  for (i = 0; i < L; i++) 
    for (j = 0; j < L; j++) 
      S[i*L+j] = 0.0;
  
  while (CompareFreqs(pairprob->pml, pairprob->pmr, targetfreq, L)) {
    iterations ++;
    
    for (i = 0; i < L; i++) 
      for (j = 0; j < L; j++) 
	if (pairprob->pml[i] > 0.0 && pairprob->pmr[j] > 0.0 && pairprob->P[i*L+j] > 0.0)
	  S[i*L+j] = log(pairprob->P[i*L+j]) - log(pairprob->pml[i]) - log(pairprob->pmr[j]);
    
    if (verbose) {
      fprintf(ofp, "S coefficients\n");
      PrintProbs(ofp, S, L);
    }

    lambda = Cal_lambda(ofp, S, targetfreq, targetfreq, L, verbose);
    
    for (i = 0; i < L; i++)
      for (j = 0; j < L; j++)
        pairprob->P[i*L+j] = exp(lambda*S[i*L+j])*targetfreq[i]*targetfreq[j];

    /* check they are probabilities */  
    CheckSingleProb(pairprob->P, LSQ);
    
     /* Calculate Conditionals and Marginals */
    ComputeLRConditionalsAndMarginals(ofp, pairprob->P, pairprob->Ql, pairprob->Qr, 
				      pairprob->pml,  pairprob->pmr, pairprob->L, hasindel, verbose);

    if (verbose) {
      fprintf(ofp, "New P(;lambda=%f)\n", lambda);
      PrintProbs(ofp, pairprob->P, L);
      fprintf(ofp, "New marginals\n");
      PrintVectorProbs(ofp, pairprob->pml, L);
      PrintVectorProbs(ofp, pairprob->pmr, L);
    }
  }
  
  if (fabs(lambda) < MARGIN && iterations > 0) 
    Warn ("EvolChangePairProbsIterate(): lambda = 0 iterations = %d. trivial", iterations);
  
  if (verbose) {
    fprintf(ofp, "new PAIR (%d it) Matrix\n", iterations);
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "new Ql(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Ql, L);
    fprintf(ofp, "new Qr(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Qr, L);
    fprintf(ofp, "new marginals probabilities\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);  
  }
  
  free(S);
}

void
EvolChangePairProbsLambda(FILE *ofp, struct pnonsubs_s *pairprob, double *targetfreq, int hasindel, int verbose)
{
  double           *S;
  double            lambda;
  int               L;
  int               LSQ;
  int               i,j;

  L = pairprob->L;
  LSQ = L * L;

  if (verbose) {
    fprintf(ofp, "\nTarget marginals probabilities\n");
    PrintVectorProbs(ofp, targetfreq, L);
    fprintf(ofp, "Old PAIR Matrix \n");
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "Old Ql(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Ql, L);
    fprintf(ofp, "Old Qr(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Qr, L);
    fprintf(ofp, "Old marginals probabilities\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);
  }
  
  S = (double *) MallocOrDie (sizeof(double) * LSQ); 
  for (i = 0; i < L; i++) 
    for (j = 0; j < L; j++) 
      S[i*L+j] = 0.0;
  
  for (i = 0; i < L; i++) 
    for (j = 0; j < L; j++) 
      if (pairprob->pml[i] > 0.0 && pairprob->pmr[j] > 0.0 && pairprob->P[i*L+j] > 0.0)
	S[i*L+j] = log(pairprob->P[i*L+j]) - log(pairprob->pml[i]) - log(pairprob->pmr[j]);
  
  if (verbose) {
    fprintf(ofp, "S coefficients\n");
    PrintProbs(ofp, S, L);
  }
  
  lambda = Cal_lambda(ofp, S, targetfreq, targetfreq, L, verbose);
  
  for (i = 0; i < L; i++)
    for (j = 0; j < L; j++)
      pairprob->P[i*L+j] = exp(lambda*S[i*L+j])*targetfreq[i]*targetfreq[j];
  
  /* check they are probabilities */  
  CheckSingleProb(pairprob->P, LSQ);
  
  /* Calculate Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(ofp, pairprob->P, pairprob->Ql, pairprob->Qr, 
				    pairprob->pml,  pairprob->pmr, pairprob->L, hasindel, verbose);
  
  if (verbose) {
    fprintf(ofp, "New P(;lambda=%f)\n", lambda);
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "New marginals\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);
  }
  
  if (fabs(lambda) < MARGIN) 
    Warn ("EvolChangePairProbsLambda(): lambda = %f trivial!", lambda);
  
  if (verbose) {
    fprintf(ofp, "new PAIR (Lambda=%f it) Matrix\n", lambda);
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "new Ql(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Ql, L);
    fprintf(ofp, "new Qr(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Qr, L);
    fprintf(ofp, "new marginals probabilities\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);  
  }

  free(S);
}

/* Function: EvolChangePairProbsNaive()
 *
 * Date:     ER, Mon Jan 17 12:56:29 CST 2005  [St. Louis at work, Coro with Nikki]
 *           
 *
 * Purpose:  given  P(i,j) = pl_i Ql(i,j) = pr_j Qr(j,i)
 *   
 *                          for some target frequencies ~pl, ~pr
 *
 *                          define ~P(i,j) such that the new marginals are ~pl and ~pr
 *
 * 
 * Method:   Naive method:  given  P(i,j) = pl_i Ql(i,j) = pr_j Qr(j,i)
 *   
 *                          for some target frequencies ~p
 *
 *                          define ~P(i,j) = 0.5 * [ ~pl_i Ql(i,j) + ~pr_j Qr(j,i) ] 
 *
 *                                       = ^pl_i ^Ql(i,j) = ^pr_j ^Qr(j,i)
 *   
 *                          the new marginals are ^p
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
EvolChangePairProbsNaive(FILE *ofp, struct pnonsubs_s *pairprob, double *targetfreq, int hasindel, int verbose)
{
  struct pnonsubs_s *pairprob_old;
  int                L;
  int                LSQ;
  int                i,j;

  L = pairprob->L;
  LSQ = L * L;

  if (verbose) {
    fprintf(ofp, "\nTarget marginals probabilities\n");
    PrintVectorProbs(ofp, targetfreq, L);
    fprintf(ofp, "Old PAIR Matrix \n");
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "Old Ql(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Ql, L);
    fprintf(ofp, "Old Qr(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Qr, L);
    fprintf(ofp, "Old marginals probabilities\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);
  }
  
  /* allocate memory */
  AllocNonSubsProbs (pairprob->L, &pairprob_old);
  pairprob_old->time = pairprob->time;
  CopyVector(pairprob_old->P,        pairprob->P, L*L);
  CopyVector(pairprob_old->Ql,       pairprob->Ql, L*L);
  CopyVector(pairprob_old->Qr,       pairprob->Qr, L*L);
  CopyVector(pairprob_old->Qlnought, pairprob->Qlnought, L*L);
  CopyVector(pairprob_old->Qrnought, pairprob->Qrnought, L*L);
  CopyVector(pairprob_old->pml,      pairprob->pml, L);
  CopyVector(pairprob_old->pmr,      pairprob->pmr, L);

  for (i = 0; i < L; i++) 
    for (j = 0; j < L; j++) {
      pairprob->P[i*L+j] = 0.5 * (pairprob->Ql[i*L+j] * targetfreq[i] + pairprob->Qr[j*L+i] * targetfreq[j]);
     }

  DNorm(pairprob->P, LSQ);

  /* Calculate Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(ofp, pairprob->P, pairprob->Ql, pairprob->Qr, 
				    pairprob->pml,  pairprob->pmr, pairprob->L, hasindel, verbose);
  
  if (verbose) {
    fprintf(ofp, "new PAIR Matrix -- Naive\n");
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "new Ql(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Ql, L);
    fprintf(ofp, "new Qr(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Qr, L);
    fprintf(ofp, "new marginals probabilities\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);  
  }

  /* calculate the error between the target freq's and the obtained freqs
   * by using the Naive method
   */
  if (verbose) {
    printf("\nEvolChangePairProbsNaive()\n");
    EvolCalculateNaivePairTargetError(targetfreq, pairprob_old, pairprob, verbose);
  }

  FreeNonSubsProbs(pairprob_old);

}

/* Function: EvolChangePairProbsYuAltschul()
 *
 * Date:     ER, Mon Jan 17 12:56:29 CST 2005  [St. Louis at work, Coro with Nikki]
 *           
 *
 * Purpose:  given  P(i,j) = pl_i Ql(i,j) = pr_j Qr(j,i)
 *   
 *                          for some target frequencies ~pl, ~pr
 *
 *                          define ~P(i,j) such that the new marginals are ~pl and ~pr
 *
 * Method: Yu+Altchul PNAS 100 (2003) 15688-15693, 
 *
 *         see details in function Cal_YuAltschul_ModifProbs() in evolve.c
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
EvolChangePairProbsYuAltschul(FILE *ofp, struct pnonsubs_s *pairprob, double *targetfreq, int hasindel, int verbose)
{
  int               L;
  int               LSQ;
  int               i,j;

  L  = pairprob->L;
  LSQ = L * L;

  if (verbose) {
    fprintf(ofp, "\nTarget marginals probabilities\n");
    PrintVectorProbs(ofp, targetfreq, L);
    fprintf(ofp, "Old PAIR Matrix \n");
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "Old Ql(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Ql, L);
    fprintf(ofp, "Old Qr(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Qr, L);
    fprintf(ofp, "Old marginals probabilities\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);
  }
  
  
  Cal_YuAltschul_ModifProbs(ofp, pairprob->P, targetfreq, targetfreq, L, verbose);
  
  /* Calculate New Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(ofp, pairprob->P, pairprob->Ql, pairprob->Qr, 
				    pairprob->pml,  pairprob->pmr, pairprob->L, hasindel, verbose);
  
  if (CompareFreqs(pairprob->pml, pairprob->pmr, targetfreq, L)> 1.0-accuracy1) 
    Die("Error in EvolChangePairProbsYuAltschul(): this method should guarantee to get the target frequencies");

  if (verbose) {
    fprintf(ofp, "New P()\n");
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "New marginals\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);
  }
  
  /* check they are probabilities */  
  CheckSingleProb(pairprob->P, LSQ);
  
  /* Calculate Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(ofp, pairprob->P, pairprob->Ql, pairprob->Qr, 
				    pairprob->pml,  pairprob->pmr, pairprob->L, hasindel, verbose);
  
  if (verbose) {
    fprintf(ofp, "New P\n");
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "New marginals\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);
  }
  
  if (verbose) {
    fprintf(ofp, "new PAIR  Matrix\n");
    PrintProbs(ofp, pairprob->P, L);
    fprintf(ofp, "new Ql(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Ql, L);
    fprintf(ofp, "new Qr(i|j,t) probabilities\n");
    PrintProbs(ofp, pairprob->Qr, L);
    fprintf(ofp, "new marginals probabilities\n");
    PrintVectorProbs(ofp, pairprob->pml, L);
    PrintVectorProbs(ofp, pairprob->pmr, L);  
  }

}

/* Function: EvolCombineRIBO5Probs_OldMethod()
 *
 * Date:     ER, Mon Jul  5 12:42:46 CDT 2004  [St. Louis at work, Coro with Maribel]
 *           
 *
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
EvolCombineRIBO5Probs_OldMethod(struct psubs_s *ribo5prob_MU, struct pnonsubs_s *ribo5prob_PU, 
				struct psubs_s *mut5pxy, struct pnonsubs_s *pair5prob, 
				struct psubs_s **ret_ribo5prob, int verbose)
{
  struct psubs_s    *ribo5prob;
  struct pnonsubs_s *ribo5mutcond;
  double             ppx;
  double             ppx_mut_a;
  double             ppx_mut_b;
  double             ppx_mut;
  double             ppx_pair_a;
  double             ppx_pair_b;
  double             ppx_pair;
  double             ppxadd_mut, ppxadd_pair;
  double             weight;
  double             weight_at_star;
  double             weight_at_zero;
  double             weight_at_infty;
  double             tfactor;
  int                xl, xr, yl, yr;
  int                xpair, ypair;
  int                lmut, rmut;
  int                idxp, idxpr;
  int                idxm, idxmr;
  int                xpair5, ypair5;
  int                lmut5, rmut5;
  int                idxm5, idxmr5;
  int                idxp5, idxpr5;
  int                L5;
  int                L5SQ;
  int                islog;

  islog = TRUE;

  L5   = mut5pxy->L;
  L5SQ = L5 * L5;
 
  tfactor = ribo5prob_MU->time;

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

  if (verbose) {
    fprintf(stdout, "\nJoint-RIBO5prob_MU t=%f\n", ribo5prob_MU->time);
    PrintProbs(stdout, ribo5prob_MU->P, L5SQ);
    EvolCalculateRIBOProbsCummulative(stdout, ribo5prob_MU->L, ribo5prob_MU->P, islog);

    fprintf(stdout, "\nConditionals-RIBO5prob_MU t=%f\n", ribo5prob_MU->time);
    PrintProbs(stdout, ribo5prob_MU->Q, L5SQ);

    fprintf(stdout, "\nJoint-RIBO5prob_PU t=%f\n", ribo5prob_PU->time);
    PrintProbs(stdout, ribo5prob_PU->P, L5SQ);
    EvolCalculateRIBOProbsCummulative(stdout, ribo5prob_PU->L, ribo5prob_PU->P, islog);

    fprintf(stdout, "\nL-Conditionals-RIBO5prob_MU t=%f\n", ribo5prob_PU->time);
    PrintProbs(stdout, ribo5prob_PU->Ql, L5SQ);
    fprintf(stdout, "\nR-Conditionals-RIBO5prob_MU t=%f\n", ribo5prob_PU->time);
    PrintProbs(stdout, ribo5prob_PU->Qr, L5SQ);
    fprintf(stdout, "pair5probs t=%f\n", pair5prob->time);
    PrintProbs(stdout, pair5prob->P, L5);
    fprintf(stdout, "mut5pxy t=%f\n", mut5pxy->time);
    PrintProbs(stdout, mut5pxy->P, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pml, L5);
    printf("pair5probs marginals probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pmr, L5);
    printf("mut5pxy marginals probabilities\n");
    PrintVectorProbs(stdout, mut5pxy->pm, L5);
  }
  
  /* allocate
   */
  AllocSubsProbs(L5SQ, &ribo5prob);
  
  ribo5prob->time = tfactor;
  
  /* Putting everything together
   */
  for (xl = 0; xl < L5; xl++)
    for (yl = 0; yl < L5; yl++)
      for (xr = 0; xr < L5; xr++)
	for (yr = 0; yr < L5; yr++)
	  {
	    xpair5 = xl*L5 + xr;
	    ypair5 = yl*L5 + yr;
	    
	    lmut5  = xl*L5 + yl;
	    rmut5  = xr*L5 + yr;

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

	    idxp5  = xpair5 * L5SQ + ypair5;
	    idxpr5 = ypair5 * L5SQ + xpair5;
	    
	    if (pair5prob->pml[xl] == 0.0 || pair5prob->pmr[xr] == 0.0 ||
		pair5prob->pml[yl] == 0.0 || pair5prob->pmr[yr] == 0.0   ) 
	      {
		ppxadd_mut = -BIGFLOAT;
	      }
	    else 
	      {
		ppxadd_mut  = - 1.0 
		  + LOG2( pair5prob->P[xpair5] / (pair5prob->pml[xl]*pair5prob->pmr[xr]) +
			  pair5prob->P[ypair5] / (pair5prob->pml[yl]*pair5prob->pmr[yr]) );
	      }
	    
	    if (mut5pxy->pm[xl] == 0.0 || mut5pxy->pm[yl] == 0.0 ||
		mut5pxy->pm[xr] == 0.0 || mut5pxy->pm[yr] == 0.0   ) 
	      {
		ppxadd_pair = -BIGFLOAT;
	      }
	    else 
	      {
		ppxadd_pair = - 1.0
		  + LOG2( mut5pxy->P[lmut5] / (mut5pxy->pm[xl]*mut5pxy->pm[yl]) +     
			  mut5pxy->P[rmut5] / (mut5pxy->pm[xr]*mut5pxy->pm[yr])    );
	      }

	    ppx_pair_a = ribo5prob_MU->Q[idxp5]  + LOG2(pair5prob->P[xpair5]);
	    ppx_pair_b = ribo5prob_MU->Q[idxpr5] + LOG2(pair5prob->P[ypair5]);

	    ppx_mut_a  = ribo5prob_PU->Ql[idxm5]  + LOG2(mut5pxy->P[lmut5]);
	    ppx_mut_b  = ribo5prob_PU->Qr[idxmr5] + LOG2(mut5pxy->P[rmut5]);

	    if ((xl == 4 && xr == 4) || 
		(yl == 4 && yr == 4)   )   
	      ppx_mut = -BIGFLOAT;
	    else                                              
	      ppx_mut  = (EXP2(ppx_mut_a)  < EXP2(ppx_mut_b))?  ppx_mut_a  : ppx_mut_b;
	    
	    if ((xl == 4 && xr == 4) || 
		(yl == 4 && yr == 4)   ) 
	      ppx_pair = -BIGFLOAT;
	    else                                              
	      ppx_pair = (EXP2(ppx_pair_a) < EXP2(ppx_pair_b))? ppx_pair_a : ppx_pair_b;
	    
	    ppx_pair += ppxadd_pair;
	    ppx_mut  += ppxadd_mut;
	    
	    ppx = weight*EXP2(ppx_mut) + (1.0-weight)*EXP2(ppx_pair);

	    ribo5prob->P[idxm5] = (ppx > 0.0)? LOG2(ppx) : -BIGFLOAT;
	    
	  }  

  /* renormalize, renormalize, always renormalize!
   *
   *   Thankfully, this is easier than applying the renormalization group :) 
   */
  DLog2Norm(ribo5prob->P, L5SQ*L5SQ);	
  CheckSingleLog2Prob(ribo5prob->P, L5SQ*L5SQ);

  /* Calculate conditionals and marginals */
  EvolCalculateRIBOPairConditionalsAndMarginals(stdout, ribo5prob, verbose);
  
  if (verbose) {
    fprintf(stdout, "\nFINAL==RIBO5 (i,j, t=%f) Joint probabilities\n", ribo5prob->time);
    PrintProbs(stdout, ribo5prob->P, ribo5prob->L);
    EvolCalculateRIBOProbsCummulative(stdout, ribo5prob->L, ribo5prob->P, islog);

    fprintf(stdout, "Q(i|j, t=%f) conditional probabilities\n", ribo5prob->time);
    PrintProbs(stdout, ribo5prob->Q, ribo5prob->L);
    fprintf(stdout, "pm(i) marginal probabilities\n");
    PrintVectorProbs(stdout, ribo5prob->pm, ribo5prob->L);

    /* calculate Mutation Conditionals and Marginals */
    ribo5mutcond = EvolComputeRIBOMutConditionalsAndMarginals(stdout, ribo5prob, islog, verbose);
    FreeNonSubsProbs(ribo5mutcond);
   }

  printf("ribo 4\n");
  /* this is it. ribo5prob->P are the evolved 25x25 Joint probabilities used by the RNA model
   *
   * BUT they are taken in exp2 form by EvolConstrucRNAModel() in evolrnamodel.c 
   */
  DExp2(ribo5prob->P, ribo5prob->L*ribo5prob->L);
  CheckSingleProb(ribo5prob->P, ribo5prob->L*ribo5prob->L); /* big dose of paranoia */

  if (verbose) {
    fprintf(stdout, "\nFINAL==RIBO5 (i,j, t=%f) Joint probabilities\n", ribo5prob->time);
    PrintProbs(stdout, ribo5prob->P, ribo5prob->L);
    EvolCalculateRIBOProbsCummulative(stdout, ribo5prob->L, ribo5prob->P, FALSE);

    DExp2(ribo5prob->pm, ribo5prob->L);
    EvolCalculateRIBOProbsSaturation(stdout, ribo5prob->L, ribo5prob->pm, FALSE);

    DExp2(ribo5prob->Q, ribo5prob->L*ribo5prob->L);
    fprintf(stdout, "Q(i|j, t=%f) conditional probabilities\n", ribo5prob->time);
    PrintProbs(stdout, ribo5prob->Q, ribo5prob->L);

    fprintf(stdout, "pm(i) marginal probabilities\n");
    PrintProbs(stdout, ribo5prob->pm, sqrt(ribo5prob->L));
  }
  
  *ret_ribo5prob = ribo5prob;

}

/* Function: EvolRateFromRIBOPairConditionals()
 * Date:     ER, Wed May 19 11:39:30 CDT 2004 [St. Louis, at work with Coro]
 *
 * Purpose:  Given a set of conditionals probabilities Q(a|b, t) 
 *           at a given evolutionary time t, 
 *           and set of conditional probabilities at time zero Q_0
 *         
 *           calculate Q(a,b| r*t) using a Markov chain model for evolution
 *  
 * Method:   Q(a | b, r*t) = Q_0 * exp{r * log[Q_0^{-1} * Q}
 *
 *
 *
 *
 * Args:              
 *
 * Returns: Qr(LxL). 
 *          Qr is allocated here, freed by caller.
 *           
 */
void
EvolRateFromRIBOPairConditionals(FILE *ofp, struct psubs_s *riboprob, struct pnonsubs_s *pairprob, int changepair, int pedantic, int verbose)
{
  double  *Q_0_inv;
  double  *K;
  double  *S;
  double  *Qp;
  double  *pp;
  int      L;
  int      L2;
  int      i;
  int      xl, xr, yl, yr;
  int      xpair, ypair;
  int      lmut, rmut;
  int      idxm, idxp;

  L2 = riboprob->L;
  L  = sqrt(L2);

  if (verbose) {
    fprintf(ofp, "Q(j|i, t_*)  probabilities\n");
    PrintProbs(ofp, riboprob->Q, L2);
    fprintf(ofp, "Q_0(j|i)  probabilities\n");
    PrintProbs(ofp, riboprob->Qnought, L2);
    fprintf(ofp, "pair-Marginal  probabilities\n");
    PrintProbs(ofp, riboprob->pm, L);
    fprintf(ofp, "pair-target Marginal  probabilities\n");
    PrintProbs(ofp, pairprob->P, L);
  }
  
  /* consistency check, rows should add up to one
   */	
  for (i = 0; i < L2; i++) CheckSingleLog2Prob(riboprob->Q+i*L2, L2);
  
  /* exponentiate conditionals */
  DExp2(riboprob->Q, L2*L2);

  /* calculate Q_0_inv
   */
  Q_0_inv = Cal_M_Inv(ofp, riboprob->Qnought, L2, verbose);
  
  /* construct K = log [Q_0_inv * Q]
   */
  Comp_M_N_Prod(ofp, Q_0_inv, riboprob->Q, L2, verbose); /*  multiply Q_0_inv*Q, dump it in Q */
  
  S = Cal_Id(L2);
  Comp_M_N_Sum(ofp, riboprob->Q, S, L2, L2, FALSE, verbose);   /* S = Q - Id  */
  
  /* check that Q is consistent with a markovian stationary 
   * model of evolution. 
   * In plain words it checks whether logQ is going to exist.
   *
   * Basically, it checks whether  all eigenvalues of Q - I
   * are between -1 and 1. 
   *
   * remember log (1+x) = x - x^2/2 + ...   converges for -1 < x <= 1
   *
   */
  
  if (verbose) IsQConsistent(ofp, S, L2, pedantic, verbose);
  K = Cal_M_Taylor_Log(ofp, riboprob->Q, L2, verbose);
  MultiplyMatrix ((1.0/riboprob->time), L2, K);
  
  if (pedantic)
    IslogQConsistent(ofp, riboprob->Qnought, K, L2, L2, L2, verbose); /*  check that K is consistent with a 
						                       *  markovian stationary model of evolution. 
						                       *
						                       *  Basically, it checks whether all entries of  
						                       *  Q_0 + epsilon*Q_0*K are none negatives.
						                       */
  
  CopyMatrix(riboprob->Rate, K, L2, L2);
  
  /* If we are told to change the stationary frequencies we do it here.
   * This will also modify the rate matrix K, while keeping the exchangeability parameters S
   * defined as
   *            (Q_0 K)_ij  = S_ij (p_j/p_i)^{1/2}  i \neq j 
   *
   *   to  
   *            (Q_0 K')_ij = S_ij (p'_j/p'_i)^{1/2}
   *
   *    so       K' = Q_0_inv * (Q_0 K')
   *
   */
  if (verbose) {
    fprintf(ofp, "RIBO  rate matrix - before\n");
    PrintProbs(ofp, riboprob->Rate, L2);
  }
  if (changepair) EvolChangeRIBORate(ofp, riboprob, pairprob, verbose);
    
  if (verbose) {
    fprintf(ofp, "RIBO  rate matrix  - after\n");
    PrintProbs(ofp, riboprob->Rate, L2);
  }
 
  EvolCalRIBOMutRate (riboprob->Rate, L2);

  /* Recalculate the conditionals, joint and marginals for this modified rate matrix
   */
   /* calculate Qp = Q_0 * exp{tfactor*K}
   */
  Condi_From_Rate(&Qp, riboprob->Rate, riboprob->Qnought, 1.0, L2, pedantic, verbose);
  CopyMatrix(riboprob->Q, Qp, L2, L2);
  /* paranoia
   */
  for (i = 0; i < L2; i++)
    CheckSingleProb(riboprob->Q+i*L2, L2);

  /* Calculate the Joint probabilities from  the conditionals and marginals.
   *
   * Put them in a temporary array, because we need to change the coordinate
   * system, before they go into the riboprob structure.
   */
  pp = (double *) MallocOrDie(sizeof(double) * L2 * L2);
  DExp2(riboprob->pm, L2);
  Joint_From_Condi(stdout, pp, riboprob->Q, riboprob->pm, L2, verbose);

  /* change the coordinate system and put in log2 form */
  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  * L2 + rmut;
	    idxp  = xpair * L2 + ypair;
	    
	    riboprob->P[idxm] = LOG2(pp[idxp]);
	  }
  /* paranoia
   */
  CheckSingleLog2Prob(riboprob->P, L2*L2);
  
  /* Calculate PairConditionals, and PairMarginals
   */
  EvolCalculateRIBOPairConditionalsAndMarginals(stdout, riboprob, verbose);
  
  if (verbose) {
    fprintf(stdout, "pp(i,j, t^*) Joint probabilities\n");
    PrintProbs(stdout, pp, L2);
    fprintf(stdout, "PRIBO(i,j, t^*) Joint probabilities\n");
    PrintProbs(stdout, riboprob->P, L2);
    fprintf(stdout, "QPairRIBO(i,j, t^* Conditional probabilities\n");
    PrintProbs(stdout, riboprob->Q, L2);
    fprintf(stdout, "RIBOPairmarg probabilities\n");
    PrintProbs(stdout, riboprob->pm, L);
  }

  free(pp);
  free(Qp);
  free(S);
  free(K);
  free(Q_0_inv);
}

