/********************************************************************************************************
 * 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
 * UE
 *     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, Sun May 16 11:54:20 CDT 2004 [STL, at home with Coro and my Mother]
 */

#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"

/* #define YU_PAIR         if defined uses the Yu_Altchul method to calculate the modified pair probabilities. Naive method by defaul */
 #define YU_COD /*         if defined uses the Yu_Altchul method to calculate the modified p(xyz). Naive method by defaul  */ 
 #define YU_PAIR_COD /*     if defined uses the Yu_Altchul method to calculate the modified p(xyz1,xyz2). Naive method by defaul  */ 

static void estimate_rna_indels (struct psubs_s *mutpxy_rna_star, struct psubs_s *mut5pxy_star, 
				 double *ret_indel, double *ret_indel2indel, int verbose);
static void estimate_rna_loop_indels (struct psubs_s *mutpxy_rna_star, struct psubs_s *mut5pxy_star, 
				      double *ret_indel, double *ret_indel2indel, int verbose);
static void mut5pxy_conditionals_at_zero(struct psubs_s *mut5pxy_star, double indel, double indel2indel, double lambda_infty, int verbose);
static void pair5prob_conditionals_at_zero(struct pnonsubs_s *pairprob_star, struct pnonsubs_s *pair5prob_star, 
					   double gap, double gap2gap, double lambda_infty, int verbose);

void 
AllocSubsProbs(int L, struct psubs_s **ret_psubs)
{
  struct psubs_s *psubs;
  int             LSQ;
  int             i; 
  psubs = (struct psubs_s *) MallocOrDie (sizeof(struct psubs_s));
 
  psubs->L = L;
  LSQ = L*L;
  psubs->time = -1.0;

  psubs->P       = (double *) MallocOrDie (sizeof(double) * LSQ);
  psubs->Q       = (double *) MallocOrDie (sizeof(double) * LSQ);
  psubs->Qnought = (double *) MallocOrDie (sizeof(double) * LSQ);
  psubs->Rate    = (double *) MallocOrDie (sizeof(double) * LSQ);
  psubs->pm      = (double *) MallocOrDie (sizeof(double) * L);
 
  for (i = 0; i < LSQ; i++) {
    psubs->P[i]       = 0.0;
    psubs->Q[i]       = 0.0;
    psubs->Qnought[i] = 0.0;
    psubs->Rate[i]    = 0.0; 
  } 
  for (i = 0; i < L; i++) psubs->pm[i] = 0.0;
  
  *ret_psubs = psubs;

}

void 
AllocNonSubsProbs(int L, struct pnonsubs_s **ret_pnonsubs)
{
  struct pnonsubs_s *pnonsubs;
  int                LSQ;
  int                i;

  pnonsubs = (struct pnonsubs_s *) MallocOrDie (sizeof(struct pnonsubs_s));
 
  pnonsubs->L = L;
  LSQ = L*L;

  pnonsubs->time = -1.0;

  pnonsubs->P        = (double *) MallocOrDie (sizeof(double) * LSQ);
  pnonsubs->Ql       = (double *) MallocOrDie (sizeof(double) * LSQ);
  pnonsubs->Qr       = (double *) MallocOrDie (sizeof(double) * LSQ);
  pnonsubs->Qlnought = (double *) MallocOrDie (sizeof(double) * LSQ);
  pnonsubs->Qrnought = (double *) MallocOrDie (sizeof(double) * LSQ);
  pnonsubs->Ratel    = (double *) MallocOrDie (sizeof(double) * LSQ);
  pnonsubs->Rater    = (double *) MallocOrDie (sizeof(double) * LSQ);
  pnonsubs->pml      = (double *) MallocOrDie (sizeof(double) * L);
  pnonsubs->pmr      = (double *) MallocOrDie (sizeof(double) * L);
 

  for (i = 0; i < LSQ; i++) {
    pnonsubs->P[i]       = 0.0;
    pnonsubs->Ql[i]       = 0.0;
    pnonsubs->Qr[i]       = 0.0;
    pnonsubs->Qlnought[i] = 0.0;
    pnonsubs->Qrnought[i] = 0.0;
    pnonsubs->Ratel[i]    = 0.0;
    pnonsubs->Rater[i]    = 0.0;

  }

  for (i = 0; i < L; i++) {
    pnonsubs->pml[i] = 0.0;
    pnonsubs->pmr[i] = 0.0;
  }
  
  *ret_pnonsubs = pnonsubs;

}

double
DeltaPrimeFromDelta (double indel)
{
  double indel2indel;
  int verbose = FALSE;

  /* use the relationship sigma_indel2indel = sigma_indel*sigma_indel /(1-sigma_indel*sigma_indel)
   */
  if (indel < sqrt(0.5)) 
    indel2indel = indel*indel/(1.0-indel*indel);
  else Die ("bad gap parameters\n");

  if (verbose) 
    printf("GAP parameters: delta = %f delta^2 = %f delta^prime = %f\n", indel, indel*indel, indel2indel);

  return indel2indel;
}

/* Function: EvolCalCODRate()
 * Date:     ER, Mon Jan 17 14:49:38 CST 2005 [St. Louis]
 *
 * Purpose:  given the joint probs cod_star[64x64],
 *           calculate the rate matrix
 * Args:    
 *
 * Returns:  (void)
 *            
 */
void
EvolCalCODRate(struct psubs_s *cod_star, int verbose)
{

  /* Qnougt is the identity */
  Comp_Id(cod_star->Qnought, cod_star->L);

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, cod_star->Rate, cod_star->Q, cod_star->Qnought, cod_star->L, 1.0, FALSE, FALSE, verbose);

  if (verbose) { 

    printf("average subs per site %f\n", SubsPerSite(stdout, cod_star->L, cod_star->Rate, cod_star->pm, verbose));

    fprintf(stdout, "\nCOD_star %dx%d probabilities\n", cod_star->L, cod_star->L);
    PrintProbs(stdout, cod_star->P, cod_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, cod_star->Q, cod_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, cod_star->Rate, cod_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, cod_star->pm, cod_star->L);
  }

}

/* Function: EvolCalMutRateFromCOD()
 * Date:     ER, Mon May 17 18:33:41 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given joint probs pammodel_star[64][64] 
 *           calculate the joint probs mutpxy_star[4x4] as marginalizations
 *           and calculate the rate matrix
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mutpxy_star 
 */
void
EvolCalMutRateFromCOD(struct psubs_s *codprob_star, int L, struct psubs_s **ret_mutpxy_star, 
		      double *targetfreq, int changefreq, int pedantic, int verbose)
{ 
  struct psubs_s *mutpxy_star;
  int             LSQ;
  int             x1, x2, x3;
  int             y1, y2, y3;
  int             idx;

  LSQ = L*L;

  /* allocate memory */
  AllocSubsProbs(L, &mutpxy_star);

  mutpxy_star->time = 1.0;

  /* Marginalize and average the codprobs over the three positions
   */
  for (x1 = 0; x1 < L; x1++)
    for (x2 = 0; x2 < L; x2++)
      for (x3 = 0; x3 < L; x3++)
	for (y1 = 0; y1 < L; y1++)
	  for (y2 = 0; y2 < L; y2++)
	    for (y3 = 0; y3 < L; y3++)
	      {
		idx = CODON(x1,x2,x3)*codprob_star->L + CODON(y1,y2,y3);

		mutpxy_star->P[idx(x1,y1)] += codprob_star->P[idx] / 3.0;
		mutpxy_star->P[idx(x2,y2)] += codprob_star->P[idx] / 3.0;
		mutpxy_star->P[idx(x3,y3)] += codprob_star->P[idx] / 3.0;
	      }
  CheckSingleProb(mutpxy_star->P, LSQ);

  if (verbose) {
    fprintf(stdout, "codprob->P(i,j, t=%f) probabilities\n", codprob_star->time);
    PrintProbs(stdout, codprob_star->P, codprob_star->L);
   }

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mutpxy_star->P, mutpxy_star->Q, mutpxy_star->pm, mutpxy_star->L, FALSE, verbose);
  
  /* Qnougt is the identity */
  Comp_Id(mutpxy_star->Qnought, mutpxy_star->L);

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, mutpxy_star->Rate, mutpxy_star->Q, mutpxy_star->Qnought, mutpxy_star->L, 1.0, FALSE, FALSE, verbose);

  /* Change backgroung frequencies if we are asked to */

  if (changefreq) {

    if (verbose) {
      fprintf(stdout, "\nmutpxy(i,j, t*) Joint probabilities -- before changing\n"); 
      PrintProbs(stdout, mutpxy_star->P, mutpxy_star->L);
      fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
      PrintProbs(stdout, mutpxy_star->Q, mutpxy_star->L);
      fprintf(stdout, "Rate matrix\n");
      PrintProbs(stdout, mutpxy_star->Rate, mutpxy_star->L);
      printf("average subs per site %f\n", SubsPerSite(stdout, mutpxy_star->L, mutpxy_star->Rate, mutpxy_star->pm, verbose));
      fprintf(stdout, "pm(i, t*) marginal probabilities\n");
      PrintVectorProbs(stdout, mutpxy_star->pm, mutpxy_star->L);
    }
    
    EvolChangeFreqMutProbsModifRate(mutpxy_star, targetfreq, pedantic, verbose);
  }
  
  if (verbose) {
    fprintf(stdout, "\nmutpxy(i,j, t*) Joint probabilities\n"); 
    PrintProbs(stdout, mutpxy_star->P, mutpxy_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mutpxy_star->Q, mutpxy_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mutpxy_star->Rate, mutpxy_star->L);

    printf("average subs per site %f\n", SubsPerSite(stdout, mutpxy_star->L, mutpxy_star->Rate, mutpxy_star->pm, verbose));

    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mutpxy_star->pm, mutpxy_star->L);
   }

  *ret_mutpxy_star = mutpxy_star;
}

/* Function: EvolCalMutRateFromRIBOUnpaired()
 * Date:     ER, Tue Aug  3 11:48:04 CDT 2004 [St. Louis, Coro is with Maribel]
 *
 * Purpose:  given joint probs ribomat->unpaired->matrix[4][4] 
 *           calculate the joint probs mutpxy_rna_star[4x4] 
 *           and calculate the rate matrix
 *
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mutpxy_star 
 */
void
EvolCalMutRateFromRIBOUnpaired(fullmat_t *ribomat, int L, struct psubs_s *mutpxy_star, 
			       struct psubs_s **ret_mutpxy_rna_unpaired_star, 
			       double *targetfreq, int changefreq, int pedantic, int verbose)
{ 
  struct psubs_s *mutpxy_rna_unpaired_star;
  int             LSQ;
  int             x, y;
  int             mut;
  int             hasindel = FALSE;

  LSQ = L*L;
  
  if (verbose) {
    fprintf(stdout, "\nribomat->unpaired->P(i,j, t^*) probabilities\n");
    fprintf (stdout, "\n"); 
    for (x = 0; x < sizeof(RNA_ALPHABET)-1; x++) { 
      fprintf (stdout, "%c   ", RNA_ALPHABET[x]); 
      for (y = 0; y <= x; y++) { 
	fprintf (stdout, "%-9.2f ",
		 ribomat->unpaired->matrix[matrix_index(numbered_nucleotide(RNA_ALPHABET[x]), numbered_nucleotide(RNA_ALPHABET[y]))]); 
      } 
      fprintf (stdout, "\n"); 
    }
  }
  
  /* allocate memory */
  AllocSubsProbs(L, &mutpxy_rna_unpaired_star);

  /* time will be rescaled later to have similar substitution per site than mutpxy_star
   */
  mutpxy_rna_unpaired_star->time = 1.0;

  /* 
   */
  for (x = 0; x < L; x++) 
    for (y = 0; y < L; y++) {
      
      mut = idx(x,y);
      
      mutpxy_rna_unpaired_star->P[mut] = 
	EXP2(ribomat->unpaired->matrix[matrix_index(numbered_nucleotide(RNA_ALPHABET[x]), numbered_nucleotide(RNA_ALPHABET[y]))]);	 
      
    }
  DNorm(mutpxy_rna_unpaired_star->P, LSQ);
  CheckSingleProb(mutpxy_rna_unpaired_star->P, LSQ);

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mutpxy_rna_unpaired_star->P, mutpxy_rna_unpaired_star->Q, mutpxy_rna_unpaired_star->pm, 
				  mutpxy_rna_unpaired_star->L, FALSE, verbose);
  
  /* Qnougt is the identity */
  Comp_Id(mutpxy_rna_unpaired_star->Qnought, mutpxy_rna_unpaired_star->L);

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, mutpxy_rna_unpaired_star->Rate, mutpxy_rna_unpaired_star->Q, mutpxy_rna_unpaired_star->Qnought, 
		       mutpxy_rna_unpaired_star->L, mutpxy_rna_unpaired_star->time, FALSE, FALSE, verbose);

  /* time needs to be rescaled to have similar number of substitution per site that mutpxy_star->Rate
  mutpxy_rna_unpaired_star->time = 
    RescaleMutRate(stdout, mutpxy_rna_unpaired_star->L, mutpxy_rna_unpaired_star->Rate, mutpxy_star->Rate, hasindel, verbose);
  */
 
  if (verbose) {
    fprintf(stdout, "\nmutpxy_rna_unpaired(i,j, t*) Joint probabilities --BEFORE\n");
    PrintProbs(stdout, mutpxy_rna_unpaired_star->P, mutpxy_rna_unpaired_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mutpxy_rna_unpaired_star->Q, mutpxy_rna_unpaired_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mutpxy_rna_unpaired_star->Rate, mutpxy_rna_unpaired_star->L);
    printf("average subs per site %f\n", 
	   SubsPerSite(stdout, mutpxy_rna_unpaired_star->L, mutpxy_rna_unpaired_star->Rate, mutpxy_rna_unpaired_star->pm, verbose));

    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mutpxy_rna_unpaired_star->pm, mutpxy_rna_unpaired_star->L);
   }

  /* Change backgroung frequencies to to the target probs if we are asked to do so */
  if (changefreq)
    EvolChangeFreqMutProbsModifRate(mutpxy_rna_unpaired_star, targetfreq, pedantic, verbose);

  if (verbose) {
    fprintf(stdout, "\nmutpxy_rna_unpaired(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, mutpxy_rna_unpaired_star->P, mutpxy_rna_unpaired_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mutpxy_rna_unpaired_star->Q, mutpxy_rna_unpaired_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mutpxy_rna_unpaired_star->Rate, mutpxy_rna_unpaired_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mutpxy_rna_unpaired_star->pm, mutpxy_rna_unpaired_star->L);
   }

  *ret_mutpxy_rna_unpaired_star = mutpxy_rna_unpaired_star;
}

/* Function: EvolCalMutRateFromRIBOPaired()
 * Date:     ER, Tue Aug  3 15:52:09 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given joint probs ribomat->unpaired->matrix[4][4] 
 *           calculate the joint probs mutpxy_rna_star[4x4] 
 *           and calculate the rate matrix
 *
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mutpxy_star
 */
void
EvolCalMutRateFromRIBOPaired(struct psubs_s *riboprob_star, int L, struct psubs_s *mutpxy_star, 
			     struct psubs_s **ret_mutpxy_rna_paired_star, 
			     double *targetfreq, int changefreq, int pedantic, int verbose)
{ 
  struct pnonsubs_s *ribomutcond;
  struct psubs_s    *mutpxy_rna_paired_star;
  int                LSQ;
  int                x, y;
  int                mut;
  int                hasindel = FALSE;
  int                islog = TRUE;
  
  LSQ = L*L;
  
  if (verbose) {
    fprintf(stdout, "\nRIBO(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, riboprob_star->P, riboprob_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, riboprob_star->Q, riboprob_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, riboprob_star->Rate, riboprob_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintProbs(stdout, riboprob_star->pm, sqrt(riboprob_star->L));
  }
   
  /* allocate memory */
  AllocSubsProbs(L, &mutpxy_rna_paired_star);

  /* time will be rescaled later to have similar substitution per site than mutpxy_star
   */
  mutpxy_rna_paired_star->time = 1.0;

  /* calculate Mutation Conditionals and Marginals of the riboprob_star joints*/
  islog = TRUE;
  ribomutcond = EvolComputeRIBOMutConditionalsAndMarginals(stdout, riboprob_star, islog, verbose);

  for (x = 0; x < L; x++) 
    for (y = 0; y < L; y++) {
      
      mut = idx(x,y);
      
      mutpxy_rna_paired_star->P[mut] = 0.5 * (EXP2(ribomutcond->pml[mut]) + EXP2(ribomutcond->pmr[mut]));	  
    }
  CheckSingleProb(mutpxy_rna_paired_star->P, LSQ);
  

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mutpxy_rna_paired_star->P, mutpxy_rna_paired_star->Q, mutpxy_rna_paired_star->pm, 
				  mutpxy_rna_paired_star->L, FALSE, verbose);
  
  /* Qnougt is the identity */
  Comp_Id(mutpxy_rna_paired_star->Qnought, mutpxy_rna_paired_star->L);

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, mutpxy_rna_paired_star->Rate, mutpxy_rna_paired_star->Q, mutpxy_rna_paired_star->Qnought, 
		       mutpxy_rna_paired_star->L, mutpxy_rna_paired_star->time, FALSE, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "\nmutpxy_rna_paired(i,j, t*) Joint probabilities * As given\n");
    PrintProbs(stdout, mutpxy_rna_paired_star->P, mutpxy_rna_paired_star->L);    
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mutpxy_rna_paired_star->Q, mutpxy_rna_paired_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mutpxy_rna_paired_star->Rate, mutpxy_rna_paired_star->L);
    printf("average subs per site %f\n", 
	   SubsPerSite(stdout, mutpxy_rna_paired_star->L, mutpxy_rna_paired_star->Rate, mutpxy_rna_paired_star->pm, verbose));

    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mutpxy_rna_paired_star->pm, mutpxy_rna_paired_star->L);
  }
  /* time needs to be rescaled to have similar number of substitution per site that mutpxy_star->Rate
   
  mutpxy_rna_paired_star->time = 
    RescaleMutRate(stdout, mutpxy_rna_paired_star->L, mutpxy_rna_paired_star->Rate, mutpxy_star->Rate, hasindel, verbose);
  */

  if (verbose) {
    fprintf(stdout, "Rate matrix ** rescaled by %f\n", 1.0/mutpxy_rna_paired_star->time);
    PrintProbs(stdout, mutpxy_rna_paired_star->Rate, mutpxy_rna_paired_star->L);
    printf("average subs per site %f\n", 
	   SubsPerSite(stdout, mutpxy_rna_paired_star->L, mutpxy_rna_paired_star->Rate, mutpxy_rna_paired_star->pm, verbose));
  }

  /* Change backgroung frequencies if we are asked to */
  if (changefreq) 
    EvolChangeFreqMutProbsModifRate(mutpxy_rna_paired_star, targetfreq, pedantic, verbose);

  if (verbose) {
    fprintf(stdout, "\nmutpxy_rna_paired(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, mutpxy_rna_paired_star->P, mutpxy_rna_paired_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mutpxy_rna_paired_star->Q, mutpxy_rna_paired_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mutpxy_rna_paired_star->Rate, mutpxy_rna_paired_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mutpxy_rna_paired_star->pm, mutpxy_rna_paired_star->L);
   }
  
  FreeNonSubsProbs(ribomutcond);
  
  *ret_mutpxy_rna_paired_star = mutpxy_rna_paired_star;
}

/* Function: EvolCalMut5RateFromCOD()
 * Date:     ER, Mon May 17 18:33:41 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given joint probs pammodel_star[64][64] 
 *           calculate the joint probs mut5pxy_star[5x5] as marginalizations
 *           and calculate the rate matrix
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mut5pxy_star 
 */
void
EvolCalMut5RateFromCOD(struct psubs_s *codprob_star, int L5, struct psubs_s **ret_mut5pxy_star, 
		       double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct psubs_s *mut5pxy_star;
  double         *psat;
  double         *target;
  double         *Q_0R;
  double          indel = INDL;
  double          indel2indel;
  double          lambda_infty = INDL_INFTY;
  int             L;
  int             LSQ;
  int             L5SQ;
  int             i;
  int             x1, x2, x3;
  int             y1, y2, y3;
  int             idx;

  /* Calculate delta^prime = delta^2/(1-delta^2)
   */
  indel2indel = DeltaPrimeFromDelta (indel);

  /* allocate memory */
  AllocSubsProbs(L5, &mut5pxy_star);

  mut5pxy_star->time = 1.0;

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

  if (verbose) {
    fprintf(stdout, "PAM(i,j, t) probabilities\n");
    PrintProbs(stdout, codprob_star->P, codprob_star->L);
   }

  /* Marginalize and average the codprobs over the three positions
   */
  for (x1 = 0; x1 < L; x1++)
    for (x2 = 0; x2 < L; x2++)
      for (x3 = 0; x3 < L; x3++)
	for (y1 = 0; y1 < L; y1++)
	  for (y2 = 0; y2 < L; y2++)
	    for (y3 = 0; y3 < L; y3++)
	      {
		idx = CODON(x1,x2,x3)*codprob_star->L + CODON(y1,y2,y3);

		mut5pxy_star->P[idx5(x1,y1)] += codprob_star->P[idx] / 3.0;
		mut5pxy_star->P[idx5(x2,y2)] += codprob_star->P[idx] / 3.0;
		mut5pxy_star->P[idx5(x3,y3)] += codprob_star->P[idx] / 3.0;
	      }
  CheckSingleProb(mut5pxy_star->P, L5SQ);
  MarginalizeJointProbs(mut5pxy_star->P, mut5pxy_star->pm, L5, 0);

  if (verbose) {
    fprintf(stdout, "marginal probabilities\n");
    PrintProbs(stdout, mut5pxy_star->pm, mut5pxy_star->L);
   }
  
  /* Add GAPS to mut5pxy_star->P[5x5] */
  for (x1 = 0; x1 < L; x1++) {
    mut5pxy_star->P[idx5(x1,L)] = indel * mut5pxy_star->pm[x1];
    mut5pxy_star->P[idx5(L,x1)] = indel * mut5pxy_star->pm[x1];
  }
  mut5pxy_star->P[idx5(L,L)] = indel2indel;
  
  /* normalize */
  DNorm(mut5pxy_star->P, L5SQ);
  CheckSingleProb(mut5pxy_star->P, L5SQ);
  
  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_star->P, mut5pxy_star->Q, 
				  mut5pxy_star->pm, mut5pxy_star->L, FALSE, verbose);
  
  /* Qnougt is the identity, except from the last row*/
  mut5pxy_conditionals_at_zero (mut5pxy_star, indel, indel2indel, lambda_infty, verbose);

  if (verbose) {
    fprintf(stdout, "Q(i|j, t=0.0) mut5pxy conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_star->Qnought, mut5pxy_star->L);
  }

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, mut5pxy_star->Rate, mut5pxy_star->Q, mut5pxy_star->Qnought, mut5pxy_star->L, 1.0, FALSE, FALSE, verbose);
 
  if (verbose) {
    fprintf(stdout, "\nmut5pxy(i,j, t*) Joint probabilities -- BEFORE\n");
    PrintProbs(stdout, mut5pxy_star->P, mut5pxy_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_star->Q, mut5pxy_star->L);
    fprintf(stdout, "Qnought(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_star->Qnought, mut5pxy_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy_star->Rate, mut5pxy_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mut5pxy_star->pm, mut5pxy_star->L);
   }

  /* Change backgroung frequencies if we are asked to */ 
  if (changefreq) 
    EvolChangeFreqMut5ProbsModifRate(mut5pxy_star, targetfreq, pedantic, verbose);

  if (verbose) {
    fprintf(stdout, "\nmut5pxy(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, mut5pxy_star->P, mut5pxy_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_star->Q, mut5pxy_star->L);
    fprintf(stdout, "Qnought(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_star->Qnought, mut5pxy_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy_star->Rate, mut5pxy_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mut5pxy_star->pm, mut5pxy_star->L);
   }

  if (verbose) {
    Q_0R = Cal_M_N_Prod(stdout, mut5pxy_star->Qnought, mut5pxy_star->Rate, mut5pxy_star->L, mut5pxy_star->L, mut5pxy_star->L, FALSE);
    fprintf(stdout, "Q_0R Instant Rate\n");
    PrintProbs(stdout, Q_0R, mut5pxy_star->L);

    free(Q_0R);
  }

  if (verbose) {
    psat = SaturationProbs(mut5pxy_star->Rate, mut5pxy_star->Qnought, mut5pxy_star->L, FALSE, verbose);

    fprintf(stdout, "pml(i, infty) saturation marginal probabilities\n");
    PrintVectorProbs(stdout, psat, mut5pxy_star->L);

    target = (double *) MallocOrDie (sizeof(double) * L);

    for (i = 0; i < L; i++) 
      target[i] = psat[i] / (1.0 - psat[L]);
    
    fprintf(stdout, "pl(i) target probabilities\n");
    PrintVectorProbs(stdout, target, L);
    
    free(target);
    free(psat);
  }


  *ret_mut5pxy_star = mut5pxy_star;
}

/* Function: EvolCalMut5RateFromRIBOUnpaired()
 * Date:     ER, Tue Aug  3 11:49:32 CDT 2004 [St. Louis, Coro is with Maribel]
 *
 * Purpose:  given joint probs ribomat->unpaired->matrix[4][4] 
 *           calculate the joint probs mut5pxy_rna_unpaired_star[5x5] 
 *           and calculate the rate matrix
 *
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mut5pxy_rna_unpaired_star 
 */
void
EvolCalMut5RateFromRIBOUnpaired(fullmat_t *ribomat, int L5, struct psubs_s *mutpxy_star, struct psubs_s *mut5pxy_star, 
				struct psubs_s *mutpxy_rna_unpaired_star, struct psubs_s **ret_mut5pxy_rna_unpaired_star, 
				double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct psubs_s *mut5pxy_rna_unpaired_star;
  double         *psat;
  double         *target;
  double         *Q_0R;
  double          indel;
  double          indel2indel;
  double          lambda_infty = INDL_INFTY;
  int             L;
  int             LSQ;
  int             L5SQ;
  int             i;
  int             x, y;
  int             mut5;
  int             hasindel = TRUE;

  if (verbose) {
    fprintf(stdout, "\nribomat->unpaired->P(i,j, t^*) probabilities\n");
    fprintf (stdout, "\n"); 
    for (x = 0; x < sizeof(RNA_ALPHABET)-1; x++) { 
      fprintf (stdout, "%c   ", RNA_ALPHABET[x]); 
      for (y = 0; y <= x; y++) { 
	fprintf (stdout, "%-9.2f ", 
		 ribomat->unpaired->matrix[matrix_index(numbered_nucleotide(RNA_ALPHABET[x]), numbered_nucleotide(RNA_ALPHABET[y]))]); 
      } 
      fprintf (stdout, "\n"); 
    }
  }

  /* allocate memory */
  AllocSubsProbs(L5, &mut5pxy_rna_unpaired_star);

  /* time will be rescaled later to have similar substitution per site than mutpxy_star
   */
  mut5pxy_rna_unpaired_star->time = 1.0;

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

  /* Estimate gap values based on mut5pxy so that they are similar after reescaling of the rate matrix*/
  estimate_rna_indels (mutpxy_rna_unpaired_star, mut5pxy_star, &indel, &indel2indel, verbose);

  /* 
   */
  for (x = 0; x < L; x++) 
    for (y = 0; y < L; y++) {
      
      mut5 = idx5(x,y);
      
      mut5pxy_rna_unpaired_star->P[mut5] = 
	EXP2(ribomat->unpaired->matrix[matrix_index(numbered_nucleotide(RNA_ALPHABET[x]), numbered_nucleotide(RNA_ALPHABET[y]))]);	 
      
    }
  DNorm(mut5pxy_rna_unpaired_star->P, L5SQ);
  CheckSingleProb(mut5pxy_rna_unpaired_star->P, L5SQ);
  MarginalizeJointProbs(mut5pxy_rna_unpaired_star->P, mut5pxy_rna_unpaired_star->pm, L5, 0);

  if (verbose) {
    fprintf(stdout, "marginal probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->pm, mut5pxy_rna_unpaired_star->L);
   }
  
  /* Add GAPS to mut5pxy_unpaired_star->P[5x5] */
  for (x = 0; x < L; x++) {
    mut5pxy_rna_unpaired_star->P[idx5(x,L)] = indel * mut5pxy_rna_unpaired_star->pm[x];
    mut5pxy_rna_unpaired_star->P[idx5(L,x)] = indel * mut5pxy_rna_unpaired_star->pm[x];
  }
  mut5pxy_rna_unpaired_star->P[idx5(L,L)] = indel2indel; 
  
  /* normalize */
  DNorm(mut5pxy_rna_unpaired_star->P, L5SQ);
  CheckSingleProb(mut5pxy_rna_unpaired_star->P, L5SQ);
  
  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_rna_unpaired_star->P, mut5pxy_rna_unpaired_star->Q,
				    mut5pxy_rna_unpaired_star->pm, mut5pxy_rna_unpaired_star->L, FALSE, verbose);
  
  /* Qnougt is the identity, except from the last row*/
  mut5pxy_conditionals_at_zero (mut5pxy_rna_unpaired_star, indel, indel2indel, lambda_infty, verbose);

  if (verbose) {
    fprintf(stdout, "Q(i|j, t=0.0) conditional probabilities indel=%f indel2indel=%f\n", indel, indel2indel);
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->Qnought, mut5pxy_rna_unpaired_star->L);
  }

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, mut5pxy_rna_unpaired_star->Rate, mut5pxy_rna_unpaired_star->Q, mut5pxy_rna_unpaired_star->Qnought,
		       mut5pxy_rna_unpaired_star->L, mut5pxy_rna_unpaired_star->time, FALSE, FALSE, verbose);
  
  /* Rate and Q_0 matrices  need to be rescaled to have similar number of substitution per site that mutpxy_star->Rate
   */
  mut5pxy_rna_unpaired_star->time = 
    RescaleMutRate(stdout, mut5pxy_rna_unpaired_star->L, mut5pxy_rna_unpaired_star->Rate, mut5pxy_star->Rate, hasindel, verbose);

 /* Qnougt needs to be recalculated again*/
  indel /= mut5pxy_rna_unpaired_star->time;
  indel2indel = DeltaPrimeFromDelta(indel);
  mut5pxy_conditionals_at_zero (mut5pxy_rna_unpaired_star, indel, indel2indel, lambda_infty, verbose);

  if (verbose) {
    fprintf(stdout, "scaled-Q(i|j, t=0.0) conditional probabilitiesindel=%f indel2indel=%f\n", indel, indel2indel);
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->Qnought, mut5pxy_rna_unpaired_star->L);
  }

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_rna_unpaired_star->P, mut5pxy_rna_unpaired_star->Q,
				    mut5pxy_rna_unpaired_star->pm, mut5pxy_rna_unpaired_star->L, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "\nmut5pxy_rna_unpaired(i,j, t*) Joint probabilities -- BEFORE\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->P, mut5pxy_rna_unpaired_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->Q, mut5pxy_rna_unpaired_star->L);
    fprintf(stdout, "Qnought(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->Qnought, mut5pxy_rna_unpaired_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->Rate, mut5pxy_rna_unpaired_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mut5pxy_rna_unpaired_star->pm, mut5pxy_rna_unpaired_star->L);
   }

  /* Change backgroung frequencies to the target probs if we are asked to do so */
  if (changefreq) 
    EvolChangeFreqMut5ProbsModifRate(mut5pxy_rna_unpaired_star, targetfreq, pedantic, verbose);
  
  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_rna_unpaired_star->P, mut5pxy_rna_unpaired_star->Q, 
				  mut5pxy_rna_unpaired_star->pm, mut5pxy_rna_unpaired_star->L, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "\nmut5pxy_rna_unpaired(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->P, mut5pxy_rna_unpaired_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->Q, mut5pxy_rna_unpaired_star->L);
    fprintf(stdout, "Qnought(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->Qnought, mut5pxy_rna_unpaired_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy_rna_unpaired_star->Rate, mut5pxy_rna_unpaired_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mut5pxy_rna_unpaired_star->pm, mut5pxy_rna_unpaired_star->L);
   }

  if (verbose) {
    Q_0R = Cal_M_N_Prod(stdout, mut5pxy_rna_unpaired_star->Qnought, mut5pxy_rna_unpaired_star->Rate, 
			mut5pxy_rna_unpaired_star->L, mut5pxy_rna_unpaired_star->L, mut5pxy_rna_unpaired_star->L, FALSE);
    fprintf(stdout, "Q_0R Instant Rate\n");
    PrintProbs(stdout, Q_0R, mut5pxy_rna_unpaired_star->L);

    free(Q_0R);
  }

  if (verbose) {
    psat = SaturationProbs(mut5pxy_rna_unpaired_star->Rate, mut5pxy_rna_unpaired_star->Qnought, 
			    mut5pxy_rna_unpaired_star->L, FALSE, verbose);

    fprintf(stdout, "pm(i, infty) saturation marginal probabilities\n");
    PrintVectorProbs(stdout, psat, mut5pxy_rna_unpaired_star->L);

    target = (double *) MallocOrDie (sizeof(double) * L);

    for (i = 0; i < L; i++) 
      target[i] = psat[i] / (1.0 - psat[L]);
    
    fprintf(stdout, "p(i) target probabilities\n");
    PrintVectorProbs(stdout, target, L);

    free(target);
    free(psat);
  }

  *ret_mut5pxy_rna_unpaired_star = mut5pxy_rna_unpaired_star;
}

/* Function: EvolCalMut5RateLoopFromRIBOUnpaired()
 * Date:     ER, Tue Aug  3 11:49:32 CDT 2004 [St. Louis]
 *
 * Purpose:  given joint probs ribomat->unpaired->matrix[4][4] 
 *           calculate the joint probs mut5pxy_rna_loop_star[5x5] 
 *           and calculate the rate matrix
 *
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mut5pxy_rna_loop_star 
 */
void
EvolCalMut5RateLoopFromRIBOUnpaired(fullmat_t *ribomat, int L5, struct psubs_s *mutpxy_star, struct psubs_s *mut5pxy_star, 
				    struct psubs_s *mutpxy_rna_loop_star, struct psubs_s **ret_mut5pxy_rna_loop_star, 
				    double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct psubs_s *mut5pxy_rna_loop_star;
  double         *psat;
  double         *target;
  double         *Q_0R;
  double          indel;
  double          indel2indel;
  double          lambda_infty = INDL_INFTY;
  int             L;
  int             LSQ;
  int             L5SQ;
  int             i;
  int             x, y;
  int             mut5;
  int             hasindel = TRUE;

  if (verbose) {
    fprintf(stdout, "\nribomat->loop->P(i,j, t^*) probabilities\n");
    fprintf (stdout, "\n"); 
    for (x = 0; x < sizeof(RNA_ALPHABET)-1; x++) { 
      fprintf (stdout, "%c   ", RNA_ALPHABET[x]); 
      for (y = 0; y <= x; y++) { 
	fprintf (stdout, "%-9.2f ", 
		 ribomat->unpaired->matrix[matrix_index(numbered_nucleotide(RNA_ALPHABET[x]), numbered_nucleotide(RNA_ALPHABET[y]))]); 
      } 
      fprintf (stdout, "\n"); 
    }
  }

  /* allocate memory */
  AllocSubsProbs(L5, &mut5pxy_rna_loop_star);

  /* time will be rescaled later to have similar substitution per site than mutpxy_star
   */
  mut5pxy_rna_loop_star->time = 1.0;

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

  /* Estimate gap values based on mut5pxy so that they are similar after reescaling of the rate matrix*/
  estimate_rna_loop_indels (mutpxy_rna_loop_star, mut5pxy_star, &indel, &indel2indel, verbose);

  /* 
   */
  for (x = 0; x < L; x++) 
    for (y = 0; y < L; y++) {
      
      mut5 = idx5(x,y);
      
      mut5pxy_rna_loop_star->P[mut5] = 
	EXP2(ribomat->unpaired->matrix[matrix_index(numbered_nucleotide(RNA_ALPHABET[x]), numbered_nucleotide(RNA_ALPHABET[y]))]);	 
      
    }
  DNorm(mut5pxy_rna_loop_star->P, L5SQ);
  CheckSingleProb(mut5pxy_rna_loop_star->P, L5SQ);
  MarginalizeJointProbs(mut5pxy_rna_loop_star->P, mut5pxy_rna_loop_star->pm, L5, 0);

  if (verbose) {
    fprintf(stdout, "marginal probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->pm, mut5pxy_rna_loop_star->L);
   }
  
  /* Add GAPS to mut5pxy_loop_star->P[5x5] */
  for (x = 0; x < L; x++) {
    mut5pxy_rna_loop_star->P[idx5(x,L)] = indel * mut5pxy_rna_loop_star->pm[x];
    mut5pxy_rna_loop_star->P[idx5(L,x)] = indel * mut5pxy_rna_loop_star->pm[x];
  }
  mut5pxy_rna_loop_star->P[idx5(L,L)] = indel2indel; 
  
  /* normalize */
  DNorm(mut5pxy_rna_loop_star->P, L5SQ);
  CheckSingleProb(mut5pxy_rna_loop_star->P, L5SQ);
  
  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_rna_loop_star->P, mut5pxy_rna_loop_star->Q,
				    mut5pxy_rna_loop_star->pm, mut5pxy_rna_loop_star->L, FALSE, verbose);
  
  /* Qnougt is the identity, except from the last row*/
  mut5pxy_conditionals_at_zero (mut5pxy_rna_loop_star, indel, indel2indel, lambda_infty, verbose);

  if (verbose) {
    fprintf(stdout, "Q(i|j, t=0.0) conditional probabilities indel=%f indel2indel=%f\n", indel, indel2indel);
    PrintProbs(stdout, mut5pxy_rna_loop_star->Qnought, mut5pxy_rna_loop_star->L);
  }

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, mut5pxy_rna_loop_star->Rate, mut5pxy_rna_loop_star->Q, mut5pxy_rna_loop_star->Qnought,
		       mut5pxy_rna_loop_star->L, mut5pxy_rna_loop_star->time, FALSE, FALSE, verbose);
  
  /* Rate and Q_0 matrices  need to be rescaled to have similar number of substitution per site that mutpxy_star->Rate
   */
  mut5pxy_rna_loop_star->time = 
    RescaleMutRate(stdout, mut5pxy_rna_loop_star->L, mut5pxy_rna_loop_star->Rate, mut5pxy_star->Rate, hasindel, verbose);

 /* Qnougt needs to be recalculated again*/
  indel /= mut5pxy_rna_loop_star->time;
  indel2indel = DeltaPrimeFromDelta(indel);
  mut5pxy_conditionals_at_zero (mut5pxy_rna_loop_star, indel, indel2indel, lambda_infty, verbose);

  if (verbose) {
    fprintf(stdout, "scaled-Q(i|j, t=0.0) conditional probabilitiesindel=%f indel2indel=%f\n", indel, indel2indel);
    PrintProbs(stdout, mut5pxy_rna_loop_star->Qnought, mut5pxy_rna_loop_star->L);
  }

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_rna_loop_star->P, mut5pxy_rna_loop_star->Q,
				    mut5pxy_rna_loop_star->pm, mut5pxy_rna_loop_star->L, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "\nmut5pxy_rna_loop(i,j, t*) Joint probabilities -- BEFORE\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->P, mut5pxy_rna_loop_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->Q, mut5pxy_rna_loop_star->L);
    fprintf(stdout, "Qnought(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->Qnought, mut5pxy_rna_loop_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->Rate, mut5pxy_rna_loop_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mut5pxy_rna_loop_star->pm, mut5pxy_rna_loop_star->L);
   }

  /* Change backgroung frequencies to the target probs if we are asked to do so */
  if (changefreq) 
    EvolChangeFreqMut5ProbsModifRate(mut5pxy_rna_loop_star, targetfreq, pedantic, verbose);
  
  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_rna_loop_star->P, mut5pxy_rna_loop_star->Q, 
				  mut5pxy_rna_loop_star->pm, mut5pxy_rna_loop_star->L, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "\nmut5pxy_rna_loop(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->P, mut5pxy_rna_loop_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->Q, mut5pxy_rna_loop_star->L);
    fprintf(stdout, "Qnought(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->Qnought, mut5pxy_rna_loop_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy_rna_loop_star->Rate, mut5pxy_rna_loop_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mut5pxy_rna_loop_star->pm, mut5pxy_rna_loop_star->L);
   }

  if (verbose) {
    Q_0R = Cal_M_N_Prod(stdout, mut5pxy_rna_loop_star->Qnought, mut5pxy_rna_loop_star->Rate, 
			mut5pxy_rna_loop_star->L, mut5pxy_rna_loop_star->L, mut5pxy_rna_loop_star->L, FALSE);
    fprintf(stdout, "Q_0R Instant Rate\n");
    PrintProbs(stdout, Q_0R, mut5pxy_rna_loop_star->L);

    free(Q_0R);
  }

  if (verbose) {
    psat = SaturationProbs(mut5pxy_rna_loop_star->Rate, mut5pxy_rna_loop_star->Qnought, 
			    mut5pxy_rna_loop_star->L, FALSE, verbose);

    fprintf(stdout, "pm(i, infty) saturation marginal probabilities\n");
    PrintVectorProbs(stdout, psat, mut5pxy_rna_loop_star->L);

    target = (double *) MallocOrDie (sizeof(double) * L);

    for (i = 0; i < L; i++) 
      target[i] = psat[i] / (1.0 - psat[L]);
    
    fprintf(stdout, "p(i) target probabilities\n");
    PrintVectorProbs(stdout, target, L);

    free(target);
    free(psat);
  }

  *ret_mut5pxy_rna_loop_star = mut5pxy_rna_loop_star;
}

/* Function: EvolCalMut5RateFromRIBOPaired()
 * Date:     ER, Tue Aug  3 11:49:32 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given joint probs ribomat->paired->matrix[4][4] 
 *           calculate the joint probs mut5pxy_rna_paired_star[5x5] 
 *           and calculate the rate matrix
 *
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mut5pxy_rna_paired_star 
 */
void
EvolCalMut5RateFromRIBOPaired(struct psubs_s *riboprob_star, int L5, struct psubs_s *mut5pxy_star, 
			      struct psubs_s *mutpxy_rna_paired_star, struct psubs_s **ret_mut5pxy_rna_paired_star, 
			      double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct pnonsubs_s *ribomutcond;
  struct psubs_s    *mut5pxy_rna_paired_star;
  double            *psat;
  double            *target;
  double            *Q_0R;
  double             indel;
  double             indel2indel;
  double             lambda_infty = INDL_INFTY;
  int                L;
  int                LSQ;
  int                L5SQ;
  int                x, y;
  int                mut, mut5;
  int                hasindel = TRUE;
  int                islog = TRUE;

  if (verbose) {
    fprintf(stdout, "\nRIBO(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, riboprob_star->P, riboprob_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, riboprob_star->Q, riboprob_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, riboprob_star->Rate, riboprob_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintProbs(stdout, riboprob_star->pm, sqrt(riboprob_star->L));
  }
   
  /* allocate memory */
  AllocSubsProbs(L5, &mut5pxy_rna_paired_star);

  /* time will be rescaled later to have similar substitution per site than mutpxy_star
   */
  mut5pxy_rna_paired_star->time = 1.0;

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

  /* Estimate gap values based on mut5pxy so that they are similar after reescaling of the rate matrix*/
  estimate_rna_indels (mutpxy_rna_paired_star, mut5pxy_star, &indel, &indel2indel, verbose);

  /* calculate Mutation Conditionals and Marginals of the riboprob_star joints*/
  islog = TRUE;
  ribomutcond = EvolComputeRIBOMutConditionalsAndMarginals(stdout, riboprob_star, islog, verbose);

  /* 
   */
  for (x = 0; x < L; x++) 
    for (y = 0; y < L; y++) {
      mut  = idx(x,y);
      mut5 = idx5(x,y);
      
      mut5pxy_rna_paired_star->P[mut5] = 0.5 * (EXP2(ribomutcond->pml[mut]) + EXP2(ribomutcond->pmr[mut]));	  
    }
  DNorm(mut5pxy_rna_paired_star->P, L5SQ);
  CheckSingleProb(mut5pxy_rna_paired_star->P, L5SQ);
  MarginalizeJointProbs(mut5pxy_rna_paired_star->P, mut5pxy_rna_paired_star->pm, L5, 2);

  if (verbose) {
    fprintf(stdout, "marginal probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_paired_star->pm, mut5pxy_rna_paired_star->L);
   }
  
  /* Add GAPS to mut5pxy_star->P[5x5] */
  for (x = 0; x < L; x++) {
    mut5pxy_rna_paired_star->P[idx5(x,L)] = indel * mut5pxy_rna_paired_star->pm[x];
    mut5pxy_rna_paired_star->P[idx5(L,x)] = indel * mut5pxy_rna_paired_star->pm[x];
  }
  mut5pxy_rna_paired_star->P[idx5(L,L)] = indel2indel;
  
  /* normalize */
  DNorm(mut5pxy_rna_paired_star->P, L5SQ);
  CheckSingleProb(mut5pxy_rna_paired_star->P, L5SQ);
  
  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_rna_paired_star->P, mut5pxy_rna_paired_star->Q,
				  mut5pxy_rna_paired_star->pm, mut5pxy_rna_paired_star->L, FALSE, verbose);
  
  /* Qnougt is the identity, except from the last row*/
  mut5pxy_conditionals_at_zero (mut5pxy_rna_paired_star, indel, indel2indel, lambda_infty, verbose);

  if (verbose) {
    fprintf(stdout, "Q(i|j, t=0.0) conditional probabilitiesindel=%f indel2indel=%f\n", indel, indel2indel);
    PrintProbs(stdout, mut5pxy_rna_paired_star->Qnought, mut5pxy_rna_paired_star->L);
  }

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, mut5pxy_rna_paired_star->Rate, mut5pxy_rna_paired_star->Q, mut5pxy_rna_paired_star->Qnought, 
		       mut5pxy_rna_paired_star->L, mut5pxy_rna_paired_star->time, FALSE, FALSE, verbose);
  
  /* Rate and Q_0 matrices need to be rescaled to have similar number of substitution per site that mutpxy_star->Rate
   */
  mut5pxy_rna_paired_star->time = 
    RescaleMutRate(stdout, mut5pxy_rna_paired_star->L, mut5pxy_rna_paired_star->Rate, mut5pxy_star->Rate, hasindel, verbose);

 /* Qnougt needs to be recalculated again*/
  indel /= mut5pxy_rna_paired_star->time;
  indel2indel = DeltaPrimeFromDelta(indel);
  mut5pxy_conditionals_at_zero (mut5pxy_rna_paired_star, indel, indel2indel, lambda_infty, verbose);

  if (verbose) {
    fprintf(stdout, "scaled-Q(i|j, t=0.0) conditional probabilitiesindel=%f indel2indel=%f\n", indel, indel2indel);
    PrintProbs(stdout, mut5pxy_rna_paired_star->Qnought, mut5pxy_rna_paired_star->L);
  }

  /* Change backgroung frequencies if we are asked to */
  if (changefreq) 
    EvolChangeFreqMut5ProbsModifRate(mut5pxy_rna_paired_star, targetfreq, pedantic, verbose);

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy_rna_paired_star->P, mut5pxy_rna_paired_star->Q, 
				  mut5pxy_rna_paired_star->pm, mut5pxy_rna_paired_star->L, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "\nmut5pxy_rna_paired(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_paired_star->P, mut5pxy_rna_paired_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_paired_star->Q, mut5pxy_rna_paired_star->L);
   fprintf(stdout, "Qnought(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_rna_paired_star->Qnought, mut5pxy_rna_paired_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy_rna_paired_star->Rate, mut5pxy_rna_paired_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, mut5pxy_rna_paired_star->pm, mut5pxy_rna_paired_star->L);
   }

  if (verbose) {
    Q_0R = Cal_M_N_Prod(stdout, mut5pxy_rna_paired_star->Qnought, mut5pxy_rna_paired_star->Rate, 
			mut5pxy_rna_paired_star->L, mut5pxy_rna_paired_star->L, mut5pxy_rna_paired_star->L, FALSE);
    fprintf(stdout, "Q_0R Instant Rate\n");
    PrintProbs(stdout, Q_0R, mut5pxy_rna_paired_star->L);

    free(Q_0R);
  }

  if (verbose) {
    psat = SaturationProbs(mut5pxy_rna_paired_star->Rate, mut5pxy_rna_paired_star->Qnought, 
			   mut5pxy_rna_paired_star->L, FALSE, verbose);
    
    fprintf(stdout, "pm(i, infty) saturation marginal probabilities\n");
    PrintVectorProbs(stdout, psat, mut5pxy_rna_paired_star->L);

    target = (double *) MallocOrDie (sizeof(double) * L);

    for (x = 0; x < L; x++) 
      target[x] = psat[x] / (1.0 - psat[L]);
    
    fprintf(stdout, "p(i) target probabilities\n");
    PrintVectorProbs(stdout, target,L);
    
    free(target);
    free(psat);
  }

  *ret_mut5pxy_rna_paired_star = mut5pxy_rna_paired_star;

  FreeNonSubsProbs(ribomutcond);
  
}

/* Function: EvolCalPAMRate()
 * Date:     ER, Mon May 17 18:33:41 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given the joint probs pam_star[20x20],
 *           calculate the rate matrix
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s pam_star 
 */
void
EvolCalPAMRate(int **pam, double scale, int L, struct psubs_s **ret_pam_star, double *codon_joint, int add_codon, int pedantic, int verbose)
{
  struct psubs_s  *pam_star;
  double           sum;
  int              a, b;		/* 0..20 indices for amino acids */
  int              idxa, idxb;		/* 0..26 indices for amino acids */

  /* allocate memory */
  AllocSubsProbs(L, &pam_star);

  pam_star->time = 1.0;

 /* Convert integer pam matrix back to joint probabilities P(ab)
  */
  sum = 0.0;
  for (a = 0; a < L; a++)
    for (b = 0; b < L; b++)
      {
	idxa = Alphabet[a] - 'A';
	idxb = Alphabet[b] - 'A';
	pam_star->P[a*L+b] = aafq[a] * aafq[b] * exp((double) pam[idxa][idxb] * scale);
	sum += pam_star->P[a*L+b];
      }

  /* normalize */
  for (a = 0; a < L; a++)
    for (b = 0; b < L; b++) 
      pam_star->P[a*L+b] /= sum;		
  CheckSingleProb(pam_star->P, L*L);

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, pam_star->P, pam_star->Q, pam_star->pm, L, FALSE, verbose);
  
  /* Qnougt is the identity */
  Comp_Id(pam_star->Qnought, L);

  /* Calculate the rate matrix */
  RateFromConditionals(stdout, pam_star->Rate, pam_star->Q, pam_star->Qnought, L, 1.0, FALSE, FALSE, verbose);

  if (verbose) { 

    printf("average subs per site %f\n", SubsPerSite(stdout, pam_star->L, pam_star->Rate, pam_star->pm, verbose));

    fprintf(stdout, "\nPAM %dx%d probabilities\n", pam_star->L, pam_star->L);
    PrintProbs(stdout, pam_star->P, pam_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pam_star->Q, pam_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, pam_star->Rate, pam_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pam_star->pm, pam_star->L);
  }

  *ret_pam_star = pam_star;

}

/* Function: EvolCalPair5Rate()
 *
 * Date:     ER, Wed May 19 10:50:09 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given probs pair5prob_star[5x5] 
 *          calculate the rate matrix
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct pnonsubs_s pairprob_star and pair5prob_star 
 */
void
EvolCalPair5Rate(double *cfg5prob, struct psubs_s *mutpxy_star, int L5, struct pnonsubs_s **ret_pairprob_star, 
		 struct pnonsubs_s **ret_pair5prob_star, double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct pnonsubs_s *pairprob_star;
  struct pnonsubs_s *pair5prob_star;
  double            *QL_0R;
  double            *QR_0R;
  double            *psatl;
  double            *psatr;
  double            *targetl;
  double            *targetr;
  double             gap = GAPP;
  double             gap2gap;
  double             lambda_infty = GAPP_INFTY;
  int                L;
  int                i, j;
  int                symmetrize;
  
  L = L5 - 1;

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

  /* allocate */
  AllocNonSubsProbs(L5, &pair5prob_star);
  AllocNonSubsProbs(L,  &pairprob_star);
  
  pair5prob_star->time = 1.0;
  pairprob_star->time  = 1.0;
  
  CopyMatrix(pair5prob_star->P, cfg5prob, L5, L5);
  
  for (i = 0; i < L; i++)
    for (j = 0; j < L; j++) 
      pairprob_star->P[i*L+j] = pair5prob_star->P[i*L5+j];

  /* normalize */
  DNorm(pairprob_star->P, L*L);

  /* Symmetrize */
  symmetrize = FALSE;
  if (symmetrize) {
    for (i = 0; i < L; i++)
      for (j = i+1; j < L; j++) {
	pairprob_star->P[i*L+j] = 0.5 * (pairprob_star->P[i*L+j] + pairprob_star->P[j*L+i]);
	pairprob_star->P[j*L+i] = pairprob_star->P[i*L+j];
      }
    CheckSingleProb(pairprob_star->P, L*L);
  }
  
  /* Calculate Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(stdout, pairprob_star->P, pairprob_star->Ql, pairprob_star->Qr, 
				    pairprob_star->pml,  pairprob_star->pmr, pairprob_star->L, FALSE, verbose);
  
  if (verbose) { 
    fprintf(stdout, "\npair %dx%d probabilities\n", pairprob_star->L, pairprob_star->L);
    PrintProbs(stdout, pairprob_star->P, pairprob_star->L);
    fprintf(stdout, "Ql(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pairprob_star->Ql, pairprob_star->L);
    fprintf(stdout, "Qr(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pairprob_star->Qr, pairprob_star->L);
    fprintf(stdout, "pml(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob_star->pml, pairprob_star->L);
    fprintf(stdout, "pmr(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob_star->pmr, pairprob_star->L);
  }
  
  /* make marginals identical to those of mutpxy_star by default, or to the target probs if we are asked to do so */
  if (!changefreq) targetfreq = mutpxy_star->pm;

#ifdef YU_PAIR
    EvolChangePairProbsYuAltschul(stdout, pairprob_star, targetfreq, FALSE, verbose);
#else
    EvolChangePairProbsNaive(stdout, pairprob_star, targetfreq, FALSE, verbose);
#endif

  if (verbose) { 
    fprintf(stdout, "\npair %dx%d probabilities - after changing backgroung frequencies with naive methods\n", 
	    pairprob_star->L, pairprob_star->L);
    PrintProbs(stdout, pairprob_star->P, pairprob_star->L);
    fprintf(stdout, "Ql(i|j, t=0) conditional probabilities\n");
    PrintProbs(stdout, pairprob_star->Qlnought, pairprob_star->L);
    fprintf(stdout, "Qr(i|j, t=0) conditional probabilities\n");
    PrintProbs(stdout, pairprob_star->Qrnought, pairprob_star->L);
    fprintf(stdout, "Ql(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pairprob_star->Ql, pairprob_star->L);
    fprintf(stdout, "Qr(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pairprob_star->Qr, pairprob_star->L);
    fprintf(stdout, "pml(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob_star->pml, pairprob_star->L);
    fprintf(stdout, "pmr(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob_star->pmr, pairprob_star->L);
  }
  
  for (i = 0; i < L5; i++)
    for (j = 0; j < L5; j++)
      if (i < L && j < L) pair5prob_star->P[i*L5+j] = pairprob_star->P[i*L+j];
      else                pair5prob_star->P[i*L5+j] = 0.0;
  CheckSingleProb(pair5prob_star->P, L5*L5);

  /* calculate Left/Right Marginals
   */
  MarginalizeJointProbs(pair5prob_star->P, pair5prob_star->pml, L5, 0);
  MarginalizeJointProbs(pair5prob_star->P, pair5prob_star->pmr, L5, 1);

  /* Conditional pair5prob at time zero are infered from pair5probs at t* before adding gaps
   *
   */
  pair5prob_conditionals_at_zero (pairprob_star, pair5prob_star, gap, gap2gap, lambda_infty, verbose);

  /* add gaps */
  /* OK, NT-2-GAP AND GAP-2-GAP Watson-Crick-Pair-Probabilities cannot be justified
   *
   * This is how I deal with them:
   */
  /* add pair-to-gap */
  for (i = 0; i < L; i++) {
    pair5prob_star->P[idx5(i,L)] = gap*pair5prob_star->pml[i];
    pair5prob_star->P[idx5(L,i)] = gap*pair5prob_star->pmr[i];
 }
  pair5prob_star->P[idx5(L,L)] = gap2gap;

  /* normalize */
  DNorm(pair5prob_star->P, L5*L5);

  /* Calculate Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(stdout, pair5prob_star->P, pair5prob_star->Ql, pair5prob_star->Qr, 
				    pair5prob_star->pml,  pair5prob_star->pmr, pair5prob_star->L, FALSE, verbose);
  
  /* Calculate the rate matrix */
  RateFromConditionals(stdout, pair5prob_star->Ratel, pair5prob_star->Ql, pair5prob_star->Qlnought, pair5prob_star->L, 1.0, 
		       FALSE, FALSE, verbose);  
  RateFromConditionals(stdout, pair5prob_star->Rater, pair5prob_star->Qr, pair5prob_star->Qrnought, pair5prob_star->L, 1.0, 
		       FALSE, FALSE, verbose);  

  if (verbose) {
    fprintf(stdout, "\nPair5prob(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, pair5prob_star->P, pair5prob_star->L);
    fprintf(stdout, "Ql(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pair5prob_star->Ql, pair5prob_star->L);
    fprintf(stdout, "Qr(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pair5prob_star->Qr, pair5prob_star->L);
    fprintf(stdout, "Ppair5(i|j, t=0) L-Cond probabilities\n");
    PrintProbs(stdout, pair5prob_star->Qlnought, L5);
    fprintf(stdout, "Ppair5(i|j, t=0) R-Cond probabilities\n");
    PrintProbs(stdout, pair5prob_star->Qrnought, L5);
    fprintf(stdout, "Ratel matrix\n");
    PrintProbs(stdout, pair5prob_star->Ratel, pair5prob_star->L);
    fprintf(stdout, "Rater matrix\n");
    PrintProbs(stdout, pair5prob_star->Rater, pair5prob_star->L);
    fprintf(stdout, "pml(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pair5prob_star->pml, pair5prob_star->L);
    fprintf(stdout, "pmr(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pair5prob_star->pmr, pair5prob_star->L);
   }

  if (verbose) {
    QL_0R = Cal_M_N_Prod(stdout, pair5prob_star->Qlnought, pair5prob_star->Ratel, 
			pair5prob_star->L, pair5prob_star->L, pair5prob_star->L, FALSE);
    QR_0R = Cal_M_N_Prod(stdout, pair5prob_star->Qrnought, pair5prob_star->Rater, 
			pair5prob_star->L, pair5prob_star->L, pair5prob_star->L, FALSE);

    fprintf(stdout, "QL_0R Instant Rate\n");
    PrintProbs(stdout, QL_0R, pair5prob_star->L);
    fprintf(stdout, "QR_0R Instant Rate\n");
    PrintProbs(stdout, QR_0R, pair5prob_star->L);

    free(QL_0R);
    free(QR_0R);
  }

  if (verbose) {

    psatl = SaturationProbs(pair5prob_star->Ratel, pair5prob_star->Qlnought, pair5prob_star->L, FALSE, verbose);
    psatr = SaturationProbs(pair5prob_star->Rater, pair5prob_star->Qrnought, pair5prob_star->L, FALSE, verbose);
    
    fprintf(stdout, "pml(i, infty) saturation  marginal probabilities\n");
    PrintVectorProbs(stdout, psatl, pair5prob_star->L);
    fprintf(stdout, "pmr(i, infty) saturation marginal probabilities\n");
    PrintVectorProbs(stdout, psatr, pair5prob_star->L);
    
    targetl = (double *) MallocOrDie (sizeof(double) * L);
    targetr = (double *) MallocOrDie (sizeof(double) * L);

    for (i = 0; i < L; i++) {
      targetl[i] = psatl[i] / (1.0 - psatl[L]);
      targetr[i] = psatr[i] / (1.0 - psatr[L]);
    }
    
    fprintf(stdout, "pl(i) target probabilities\n");
    PrintVectorProbs(stdout, targetl,L);
    fprintf(stdout, "pr(i) target probabilities\n");
    PrintVectorProbs(stdout, targetr, L);
    
    free(targetl);
    free(targetr);

    free(psatl);
    free(psatr);
  }
  
  *ret_pairprob_star  = pairprob_star;
  *ret_pair5prob_star = pair5prob_star;
  
}

/* Function: EvolCalRIBORate()
 * Date:     ER, Wed May 19 11:56:38 CDT 2004 [St. Louis, at work with Coro]
 *
 * Purpose:  given probs 
 *          calculate the rate matrix
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s riboprobapprox_star 
 */
void
EvolCalRIBORate(fullmat_t *ribomat, struct psubs_s *mutpxy_star, struct pnonsubs_s *pairprob_star, struct psubs_s **ret_riboprob_star, 
	        int changefreq, int pedantic, int verbose)
{
  struct psubs_s    *riboprob_star;
  struct pnonsubs_s *pairtarget;
  struct pnonsubs_s *ribomutcond;
  int                LH;
  int                islog;

  /* calculate the ribopro_star from ribomat (RIBOSUM85-60.mat by default). 
   * Calculate all three: Joint, PairConditionals and PairMarginals
   */
  EvolCalculateRIBOProbs(stdout, ribomat, &riboprob_star, verbose);
  
  LH = sqrt(riboprob_star->L);

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

  if (verbose) {
    fprintf(stdout, "\nRIBO(i,j, t*) Joint probabilities -- Before changing backgroundfreqs\n");
    PrintProbs(stdout, riboprob_star->P, riboprob_star->L);
    
    DExp2(riboprob_star->Q, riboprob_star->L*riboprob_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, riboprob_star->Q, riboprob_star->L);
    DLog2(riboprob_star->Q, riboprob_star->L*riboprob_star->L);
 
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    DExp2(riboprob_star->pm, riboprob_star->L);
    PrintProbs(stdout, riboprob_star->pm, LH);
    DLog2(riboprob_star->pm, riboprob_star->L);
  }

  /* Calculate the rate matrix */
  EvolRateFromRIBOPairConditionals(stdout, riboprob_star, pairprob_star, changefreq, pedantic, verbose);  
  
  if (verbose) {
    fprintf(stdout, "\nRIBO(i,j, t*) Joint probabilities -- After changing backgroundfreqs\n");
    PrintProbs(stdout, riboprob_star->P, riboprob_star->L);
    
    DExp2(riboprob_star->Q, riboprob_star->L*riboprob_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, riboprob_star->Q, riboprob_star->L);
    DLog2(riboprob_star->Q, riboprob_star->L*riboprob_star->L);
 
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    DExp2(riboprob_star->pm, riboprob_star->L);
    PrintProbs(stdout, riboprob_star->pm, LH);
    DLog2(riboprob_star->pm, riboprob_star->L);
  }

  if (verbose) {
    fprintf(stdout, "Rate matrix - BEFORE Rescaling\n");
    PrintProbs(stdout, riboprob_star->Rate, riboprob_star->L);
    DExp2(riboprob_star->pm, riboprob_star->L);
    printf("average subs per site %f\n", 
	   SubsPerSite(stdout, riboprob_star->L, riboprob_star->Rate, riboprob_star->pm, verbose));
    DLog2(riboprob_star->pm, riboprob_star->L);
  }
  
  /* have to scale time   
   */
  riboprob_star->time = RescaleRIBORate(stdout, riboprob_star, mutpxy_star, verbose); 
  
  if (verbose) {
    DExp2(riboprob_star->P, riboprob_star->L*riboprob_star->L); 
    fprintf(stdout, "\nRIBO(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, riboprob_star->P, riboprob_star->L);
    DLog2(riboprob_star->P, riboprob_star->L*riboprob_star->L);
    
    DExp2(riboprob_star->Q, riboprob_star->L*riboprob_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, riboprob_star->Q, riboprob_star->L);
    DLog2(riboprob_star->Q, riboprob_star->L*riboprob_star->L);
    
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, riboprob_star->Rate, riboprob_star->L);
    DExp2(riboprob_star->pm, riboprob_star->L);
    printf("average subs per site %f\n", 
	   SubsPerSite(stdout, riboprob_star->L, riboprob_star->Rate, riboprob_star->pm, verbose));
    DLog2(riboprob_star->pm, riboprob_star->L);
    
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    DExp2(riboprob_star->pm, riboprob_star->L);
    PrintProbs(stdout, riboprob_star->pm, LH);
    DLog2(riboprob_star->pm, riboprob_star->L);


    /* calculate Mutation Conditionals and Marginals */
    islog = TRUE;
    ribomutcond = EvolComputeRIBOMutConditionalsAndMarginals(stdout, riboprob_star, islog, verbose);
    FreeNonSubsProbs(ribomutcond);

    /* calculate the targetpair frequencies */
    AllocNonSubsProbs(LH, &pairtarget);
    pairtarget->time = riboprob_star->time;

    CopyMatrix(pairtarget->P, riboprob_star->pm, LH, LH);
    DExp2(pairtarget->P, riboprob_star->L);
    CheckSingleProb(pairtarget->P, riboprob_star->L); /* paranoia */
    
    fprintf(stdout, "PAIR marginals probabilities\n");
    PrintProbs(stdout, pairtarget->P, LH);
    
    ComputeLRConditionalsAndMarginals(stdout, pairtarget->P, pairtarget->Ql, pairtarget->Qr, 
				      pairtarget->pml,  pairtarget->pmr, pairtarget->L, FALSE, verbose);
    
    fprintf(stdout, "Pair  frequencies\n");
    PrintProbs(stdout, pairtarget->P, LH);
    fprintf(stdout, "Pair  marginals frequencies\n");
    PrintVectorProbs(stdout, pairtarget->pml, LH);
    PrintVectorProbs(stdout, pairtarget->pmr, LH);

    FreeNonSubsProbs(pairtarget);
  }


  *ret_riboprob_star = riboprob_star;
  
}

/* Function: EvolCalRIBOApproxRate()
 * Date:     ER, Tue May 18 13:54:24 CDT 2004 [St. Louis, at work with Coro]
 *
 * Purpose:  given probs mutpxy and pairprob, calculate the qrna approximation to 
 *           the 16x16 riboprob->P probabilities of the RNA model.
 *          
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s riboprobapprox_star 
 */
void
EvolCalRIBOApproxRate(struct psubs_s *mutpxy_star, struct pnonsubs_s *pairprob_star, struct psubs_s **ret_riboprobapprox_star, 
		      int changefreq, int pedantic, int verbose)
{
  struct psubs_s    *riboprobapprox_star;
  struct pnonsubs_s *ribomutcond;
  int                islog;
  
  /* calculate the riboproapprox_star from mutpxy_star->P and pair. 
   * Calculate all three: Joint, PairConditionals and PairMarginals
   */
  EvolCalculateRIBOProbsApprox(stdout, mutpxy_star, pairprob_star, &riboprobapprox_star, verbose);

  /* the 16x16 pair conditionals at t=0 
   */
  Comp_Id (riboprobapprox_star->Qnought, riboprobapprox_star->L);

  /* Calculate the rate matrix 
   */
  EvolRateFromRIBOPairConditionals(stdout, riboprobapprox_star, pairprob_star, changefreq, pedantic, verbose);  

  if (verbose) {
    fprintf(stdout, "\nRIBOapprox(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, riboprobapprox_star->P, riboprobapprox_star->L);
    fprintf(stdout, "Q(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, riboprobapprox_star->Q, riboprobapprox_star->L);
    fprintf(stdout, "PAIR-COND-nought probabilities\n");
    PrintProbs(stdout, riboprobapprox_star->Qnought, riboprobapprox_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, riboprobapprox_star->Rate, riboprobapprox_star->L);
    fprintf(stdout, "pm(i, t*) marginal probabilities\n");
    PrintProbs(stdout, riboprobapprox_star->pm, sqrt(riboprobapprox_star->L));

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

  *ret_riboprobapprox_star = riboprobapprox_star;
  
}

/* Function: EvolChangeFreqCODProbsGW()
 *
 * Date:     ER, Sun May 23 11:19:58 CDT 2004  [St. Louis, at home with Coro]
 *
 * Purpose: Obtain a new set of codon-codon probabilities changing the marginal probabilities
 * 
 * Method:  Change the rate matrix corresponding to the conditional probabilities.
 *
 *          The new Rate matrix is given by,
 *
 *         ~R(i,j) = R(i,j) * ~pm(j)/pm(j) * (~pm(j)*~pm(i) / pm(j)*pm(i) ) ^alpha(i,j)  
 *
 *                                      ,, alpha(i,j) = alpha(j,i) and in GW case they all take the value -1/2
 *
 *
 *         in this case, i = xyz and pm(i) is the codon marginal probabilities
 *
 *         for the new codon probabilities we assume independence, ie 
 *
 *         ~pm(i) = targetfreq(x) * targetfreq(y) * targetfreq(z)
 *
 * Args:      *
 * Returns:  (void)
 */
void
EvolChangeFreqCODProbsGW(struct psubs_s *codprob, double *targetfreq, int pedantic, int verbose)
{
  double *pnewmar;               /* [64] marginalization of the pjoint +*/
  int     L, LSQ, LC;
  int     i;

  LC  = codprob->L;
  L   = EXP2(1.0/3.0*LOG2(LC));
  LSQ = L*L;

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

  /* allocate memory */
  pnewmar = (double *) MallocOrDie (sizeof(double) * LC);
  
  /* For the new marginals we assume independence
   */
  for (i = 0; i < LC; i++)
    pnewmar[i] = targetfreq[i/LSQ] * targetfreq[(i%LSQ)/L] * targetfreq[i%L];

 /* Modify  Rate Matrix
   */
  if (verbose) {
    fprintf(stdout, "Old PAM Rate Matrix \n");
    PrintProbs(stdout, codprob->Rate, codprob->L);
  }
  ChangeRateMatrix(stdout, codprob->Rate, codprob->Qnought, codprob->Rate, codprob->pm, codprob->pm, codprob->L, 
		   pnewmar, FALSE, FALSE, verbose);
  if (verbose) {
    fprintf(stdout, "New PAM Rate Matrix \n");
    PrintProbs(stdout, codprob->Rate, codprob->L);
  }
 
  /*
   *          codprob->Q = codprob->Qnought * exp{ codprob->time * codprob->Rate }
   *
   *          codprob->P = codprob->Q * codprob->pm
   */
  ConditionalsFromRate(codprob->Q, codprob->Rate, codprob->Qnought, codprob->time, L, pedantic, verbose);
  Joint_From_Condi(stdout, codprob->P, codprob->Q, codprob->pm, L, verbose);

  if (verbose) {
    fprintf(stdout, "codprob->P(i,j, t=%f) COD Joint probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->P, LC);
    fprintf(stdout, "codprob->Q(i|j, t=%f) COD Conditional probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->Q, LC);
    fprintf(stdout, "codprob->pm(i) COD mariginal probabilities\n");
    PrintVectorProbs(stdout, codprob->pm, LC);
  }

  free(pnewmar);
}

/* Function: EvolChangeFreqCODProbsIterate()
 *
 * Date:     ER, Sun May 23 11:23:16 CDT 2004  [St. Louis, at home with Coro]
 *
 * Purpose:  Obtain a new set of codon-codon probabilities changing the marginal probabilities
 * 
 * 
 * Method: Change the Joint P(codon1, codon2) probabilities iteratively
 *
 *        P(i,j) = exp S_ij * pm(i) * pm(j)  --->  P'(i,j) = exp (lamda * S_ij) * ~pm(i) * ~pm(j) = exp S'_ij * pm'(i) * pm'(j)
 *         
 *                                           --->  P''(i,j) = exp (lamda' * S'_ij) * ~pm(i) * ~pm(j)
 *                                         
 *                                           --->  iterate eventually P^n converges to having ~pm as marginal probabilities
 *
 *
 *         in this case, i = xyz and pm(i) is the codon marginal probabilities
 *
 *         for the new codon probabilities we assume independence, ie 
 *
 *         ~pm(i) = targetfreq(x) * targetfreq(y) * targetfreq(z)
 *
 * Args:      *
 * Returns:  (void)
 */
void
EvolChangeFreqCODProbsIterate(struct psubs_s *codprob, double *targetfreq, int pedantic, int verbose)
{
  double *S;
  double *pnewmar;               /* [64] marginalization of the pjoint  +*/
  int     L, LSQ, LC;
  double  lambda;
  int     iterations = 0;
  int     i,j;

  LC  = codprob->L;
  L   = EXP2(1.0/3.0*LOG2(LC));
  LSQ = L*L;

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

  /* allocate memory */
  pnewmar = (double *) MallocOrDie (sizeof(double) * LC);
  S       = (double *) MallocOrDie (sizeof(double) * LC * LC); 

  /* For the new marginals we assume independence
   */
  for (i = 0; i < LC; i++)
    pnewmar[i] = targetfreq[i/LSQ] * targetfreq[(i%LSQ)/L] * targetfreq[i%L];

  for (i = 0; i < LC; i++) 
    for (j = 0; j < LC; j++) 
      S[i*LC+j] = 0.0;

  while (CompareFreqs(codprob->pm, codprob->pm, pnewmar, LC)) {
    iterations ++;
    
    for (i = 0; i < LC; i++) 
      for (j = 0; j < LC; j++) 
	if (codprob->pm[i] > 0.0 && codprob->pm[j] > 0.0 && codprob->P[i*LC+j] > 0.0)
	  S[i*L+j] = log(codprob->P[i*LC+j]) - log(codprob->pm[i]) - log(codprob->pm[j]);
    
    lambda = Cal_lambda(stdout, S, pnewmar, pnewmar, LC, verbose);
    
    for (i = 0; i < LC; i++)
      for (j = 0; j < LC; j++)
	codprob->P[i*LC+j] = exp(lambda*S[i*LC+j])*pnewmar[i]*pnewmar[j];
    
    /* check they are probabilities */  
    CheckSingleProb(codprob->P, LC*LC);
    
  }
  
  if (fabs(lambda) < MARGIN && iterations > 0) 
    Warn ("EvolChangeFreqCODProbsIterate(): lambda = 0 iterations = %d. trivial", iterations);  
  
  ComputeConditionalsAndMarginals(stdout, codprob->P, codprob->Q, codprob->pm, LC, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "codprob->P(i,j, t=%f) COD Joint probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->P, LC);
    fprintf(stdout, "codprob->Q(i|j, t=%f) COD Conditional probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->Q, LC);
    fprintf(stdout, "codprob->pm(i) COD mariginal probabilities\n");
    PrintVectorProbs(stdout, codprob->pm, LC);
  }
  
  free(pnewmar);
  free(S);

}

/* Function: EvolChangeFreqCODProbsNaive
 *
 * Date:     ER, Fri Aug 13 09:19:20 CDT 2004  [St. Louis at work, Coro with Maribel
 *
 * Purpose: Obtain a new set of codon-codon probabilities changing the marginal probabilities
 * 
 * Method: This is the simplest method because it does not need to calculate the
 *         rate matrix of the 64x64 codon-codon matrix which takes a considerable amount of time.
 *
 *
 *          calculate:         P(Cy|Cx) = P(Cx,Cy) / P(Cx)
 *
 *          then use:         ^p(C) = targetfreq(x1) * targetfreq(x2) * targetfreq(x3) //  C = x1 x2 x3
 *               
 *              this is a hack, I would like to know a better way of relating a given nucleotide frequencies, to
 *              a more realistic set of codon frequencies.
 *
 *          to recalculate:   ^P(Cx,Cj) = P(Cy|Cx) * ^p(Cx) and symmetrize
 *
 *             this does not warantee that the marginals of ^P(Cx,Cy) are the ^p's, but it is an approximation
 *             in that direction.
 *
 * Args:      
 *
 * Returns:  (void)
 */
void
EvolChangeFreqCODProbsNaive(struct psubs_s *codprob, double *targetfreq, int pedantic, int verbose)
{  
  double *pnewcod;               /* [64] marginalization of the pjoint     +*/
  double *newtargetfreq;         /*  [4] marginalizations of the pnewcond   */
  double *pmar_old;              /*  [4] marginalizations of the pjoint     */
  double *pmar_new;              /*  [4] marginalizations of the new pjoint */
  int     L, LSQ, LC;
  int     i, j;
  int     isindep;

  LC  = codprob->L;
  L   = EXP2(1.0/3.0*LOG2(LC));
  LSQ = L*L;

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

  /* allocate memory */
  newtargetfreq = (double *) MallocOrDie (sizeof(double) * L);
  pmar_old      = (double *) MallocOrDie (sizeof(double) * L);
  pmar_new      = (double *) MallocOrDie (sizeof(double) * L);
  
#ifdef YU_COD
  EvolChangeCODProbsYuAltchul(stdout, targetfreq, &pnewcod, codprob, verbose);
#else
  /* Using the naive methods, for the new marginals we have two choices:
   *
   *  isindep = TRUE  we assume independence
   *  isindep = FALSE we change the marginals p(x1) keeping the coditionals p(x2x3|x1)
   */
  isindep = FALSE;
  EvolChangeCODProbsNaive(stdout, targetfreq, &pnewcod, codprob, isindep, verbose);
#endif

  if (verbose) {
    fprintf(stdout, "Target Codon-marginals probabilities\n");
    PrintVectorProbs(stdout, pnewcod, LC);
  }

  MarginalizeCODProbs(pnewcod, newtargetfreq, verbose);
  
  if (verbose) {
    fprintf(stdout, "Target background probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
    fprintf(stdout, "Approx target probabilities\n");
    PrintVectorProbs(stdout, newtargetfreq, L);
  }

  if (verbose) {
    fprintf(stdout, "codprob->P(i,j, t=%f) COD Joint probabilities ** Before changing background frequencies\n", codprob->time);
    PrintProbs(stdout, codprob->P, LC);
    fprintf(stdout, "codprob->Q(i|j, t=%f) COD Conditional probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->Q, LC);
    fprintf(stdout, "codprob->pm(i) COD marginal probabilities\n");
    PrintVectorProbs(stdout, codprob->pm, LC);
    fprintf(stdout, "Target marginal probabilities\n");
    PrintVectorProbs(stdout, pnewcod, LC);
  }
  MarginalizeCODProbs(codprob->pm, pmar_old, verbose);

  /* this is the naive method
   */
  for (i = 0; i < LC; i++) 
    for (j = 0; j < LC; j++) 
      codprob->P[i*LC+j] = 0.5 * ( codprob->Q[i*LC+j] * pnewcod[i] + codprob->Q[j*LC+i] * pnewcod[j] );

  DNorm(codprob->P, LC*LC);

  ComputeConditionalsAndMarginals(stdout, codprob->P, codprob->Q, codprob->pm, LC, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "codprob->P(i,j, t=%f) COD Joint probabilities ** After changing background frequencies\n", codprob->time);
    PrintProbs(stdout, codprob->P, LC);
    fprintf(stdout, "codprob->Q(i|j, t=%f) COD Conditional probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->Q, LC);
    fprintf(stdout, "codprob->pm(i) COD mariginal probabilities\n");
    PrintVectorProbs(stdout, codprob->pm, LC);
    fprintf(stdout, "Target marginal probabilities\n");
    PrintVectorProbs(stdout, pnewcod, LC);
  }
  MarginalizeCODProbs(codprob->pm, pmar_new, verbose);
 
  /* calculate the error between the target freq's and the obtained freqs
   * by using the Naive method
   */
  if (verbose) {
    printf("\nEvolChangeFreqCODProbsNaive()\n");
    EvolCalculateNaiveTargetError(codprob->time, L, newtargetfreq, pmar_old, pmar_new, verbose);
  }

  free(pmar_old);
  free(pmar_new);
  free(pnewcod);
  free(newtargetfreq);
}

/* Function: EvolChangeFreqCODProbsYuAltchul()
 *
 * Date:     ER, Fri Jan 21 10:05:06 CST 2005  [St. Louis]
 *
 * Purpose: Obtain a new set of codon-codon probabilities changing the marginal probabilities
 * 
 * Method:  uses the Yu-ALtchul method PNAS 100 (2003) 15688-15693, 
 *
 *         see details in function Cal_YuAltschul_ModifProbs() in evolve.c
 *
 *
 *
 * Args:    
 *
 * Returns:  (void)
 */
void
EvolChangeFreqCODProbsYuAltchul(struct psubs_s *codprob, double *targetfreq, int pedantic, int verbose)
{
  double *pnewcod;               /* [64] marginalization of the pjoint     +*/
  double *newtargetfreq;         /*  [4] marginalizations of the pnewcond   */
  double *pmar_old;              /*  [4] marginalizations of the pjoint     */
  double *pmar_new;              /*  [4] marginalizations of the new pjoint */
  int     L, LSQ, LC;
  int     i, j;
  int     isindep;

  LC  = codprob->L;
  L   = EXP2(1.0/3.0*LOG2(LC));
  LSQ = L*L;

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

  /* allocate memory */
  newtargetfreq = (double *) MallocOrDie (sizeof(double) * L);
  pmar_old      = (double *) MallocOrDie (sizeof(double) * L);
  pmar_new      = (double *) MallocOrDie (sizeof(double) * L);
  
#ifdef YU_COD
  EvolChangeCODProbsYuAltchul(stdout, targetfreq, &pnewcod, codprob, verbose);
#else
  /* Using the naive methods, for the new marginals we have two choices:
   *
   *  isindep = TRUE  we assume independence
   *  isindep = FALSE we change the marginals p(x1) keeping the coditionals p(x2x3|x1)
   */
  isindep = FALSE;
  EvolChangeCODProbsNaive(stdout, targetfreq, &pnewcod, codprob, isindep, verbose);
#endif

  if (verbose) {
    fprintf(stdout, "Target Codon-marginals probabilities\n");
    PrintVectorProbs(stdout, pnewcod, LC);
  }

  MarginalizeCODProbs(pnewcod, newtargetfreq, verbose);
  
  if (verbose) {
    fprintf(stdout, "Target background probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
    fprintf(stdout, "Approx target probabilities\n");
    PrintVectorProbs(stdout, newtargetfreq, L);
  }

  if (verbose) {
    fprintf(stdout, "codprob->P(i,j, t=%f) COD Joint probabilities ** Before changing background frequencies\n", codprob->time);
    PrintProbs(stdout, codprob->P, LC);
    fprintf(stdout, "codprob->Q(i|j, t=%f) COD Conditional probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->Q, LC);
    fprintf(stdout, "codprob->pm(i) COD marginal probabilities\n");
    PrintVectorProbs(stdout, codprob->pm, LC);
    fprintf(stdout, "Target marginal probabilities\n");
    PrintVectorProbs(stdout, pnewcod, LC);
  }
  MarginalizeCODProbs(codprob->pm, pmar_old, verbose);

  /* this is the Yu-Altchul
   */
  Cal_YuAltschul_ModifProbs(stdout, codprob->P, pnewcod, pnewcod, LC, verbose);

  ComputeConditionalsAndMarginals(stdout, codprob->P, codprob->Q, codprob->pm, LC, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "codprob->P(i,j, t=%f) COD Joint probabilities ** After changing background frequencies\n", codprob->time);
    PrintProbs(stdout, codprob->P, LC);
    fprintf(stdout, "codprob->Q(i|j, t=%f) COD Conditional probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->Q, LC);
    fprintf(stdout, "codprob->pm(i) COD mariginal probabilities\n");
    PrintVectorProbs(stdout, codprob->pm, LC);
    fprintf(stdout, "Target marginal probabilities\n");
    PrintVectorProbs(stdout, pnewcod, LC);
  }
  MarginalizeCODProbs(codprob->pm, pmar_new, verbose);
 
  /* calculate the error between the target freq's and the obtained freqs
   * by using the Naive method
   */
  if (verbose) {
    printf("\nEvolChangeFreqCODProbsNaive()\n");
    EvolCalculateNaiveTargetError(codprob->time, L, newtargetfreq, pmar_old, pmar_new, verbose);
  }

  free(pmar_old);
  free(pmar_new);
  free(pnewcod);
  free(newtargetfreq);

}

/* Function: EvolChangeFreqMutProbsModifRate()
 * 
 * Date:     ER, Fri May 21 12:38:02 CDT 2004  [St. Louis, at work with Coro]
 *
 * Purpose: Obtain a new Rate matrix with a given set of marginal probabilities
 * 
 * Method: The new Rate matrix is given by,
 *
 *         R(i,j) = R(i,j) * ~pm(j)/pm(j) * (~pm(j)*~pm(i) / pm(j)*pm(i) ) ^alpha(i,j)  
 *
 *                                      ,, alpha(i,j) = alpha(j,i) and in GW case they all take the value -1/2 
 *
 *
 *          If Q_0 is different from the identity matrix, it has to be changed too.
 *
 *          Then it is easy to see that
 *
 *                 ~P(i,j) = ~pm(i) * ~Q(i,j) = ~pm(j) * ~Q(j,i)  for all times, including t=0
 *
 *         If there are indels the pmarginals have to be modified too.
 *
 *
 * Args:      *
 * Returns:  (void)
 */
void
EvolChangeFreqMutProbsModifRate(struct psubs_s *mutpxy, double *targetfreq, int pedantic, int verbose)
{
  double *Q_0_inv;
  double *Q_0R;
  double *old_psat;
  double *new_psat;
  int     L;
  int     i;
  int     hasindel = FALSE; /* 4x4 mutations; this is a substitution processs w/o indels */
  
  L = mutpxy->L;
  
  if (verbose) {
    fprintf(stdout, "Target marginals probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
  }
  CheckSingleProb(targetfreq, L); /* paranoia */

 if (verbose) {
    fprintf(stdout, "old P probs\n");
    PrintProbs(stdout, mutpxy->P, L);
    fprintf(stdout, "old Q probs\n");
    PrintProbs(stdout, mutpxy->Q, L);
    fprintf(stdout, "old Rate probs\n");
    PrintProbs(stdout, mutpxy->Rate, L);
  }

  old_psat = SaturationProbs(mutpxy->Rate, mutpxy->Qnought, L, FALSE, verbose);
  
  if (verbose) {
    fprintf(stdout, "Old Saturations probs\n");
    PrintVectorProbs(stdout, old_psat, L);
  }
  
  Q_0_inv = Cal_M_Inv(stdout, mutpxy->Qnought, L, verbose);
  
  /* Matrix Qnought*Rate is the one that changes using the GW method
   *
   * Matrix Qnought
   */
  Q_0R = Cal_M_N_Prod(stdout, mutpxy->Qnought, mutpxy->Rate, L, L, L, verbose);

  ChangeQ_0Matrix(stdout, mutpxy->Qnought, mutpxy->pm, mutpxy->pm, L, targetfreq, hasindel, TRUE, verbose);
  
  ChangeRateMatrix(stdout, Q_0R, Q_0_inv, mutpxy->Rate, mutpxy->pm, mutpxy->pm, L, targetfreq, hasindel, TRUE, verbose);
  
  /* calculate new marginals by saturation of the conditionals keepint the "last" component intact if the process involves indels
   *
  * p = (\pi_i(1-Lamba(t)), Lambda(t))
  *
  * new frquencies are
  *
  * ~p = (~\pi_i(1-Lamba(t)), Lambda(t))
  *
  *  where ~\pi_i are the saturation prob's of the new Conditonal probabilities
  */
  ChangeFrequencies(stdout, mutpxy->Qnought, mutpxy->Rate, mutpxy->pm, L, targetfreq, hasindel, verbose);
  
  /* With the new Rate matrices, recalculate the conditionals (a t = 1) joint and marginals
   */
  ConditionalsFromRate(mutpxy->Q, mutpxy->Rate, mutpxy->Qnought, 1.0, L, pedantic, verbose);
  Joint_From_Condi(stdout, mutpxy->P, mutpxy->Q, mutpxy->pm, L, verbose);

  /* new saturation probabilities
   */
  new_psat = SaturationProbs(mutpxy->Rate, mutpxy->Qnought, L, FALSE, verbose);
  
  if (verbose) {
    fprintf(stdout, "New Saturations probs\n");
    PrintVectorProbs(stdout, new_psat, L);
  }
  
  /* paranoia */
  for (i = 0; i < L; i++) 
    if (fabs(new_psat[i]-targetfreq[i]) > MARGIN) 
      Die ("ChangeRateMatrix():\nbad change of background frequencies -- indels, i=%d new_target=%f targetfreq=%f", 
	   i, new_psat[i], targetfreq[i]);

  if (verbose) {
    for (i = 0; i < L; i++) 
     printf("i=%d new_target=%f old_target=%f\n", i, new_psat[i], old_psat[i]);
  }
  
  if (verbose) {
    fprintf(stdout, "\nEvolChangeFreqMutProbsMOdifRate()\nNEW_JOINT probabilities\n");
    PrintProbs(stdout, mutpxy->P, L);
    fprintf(stdout, "Q\n");
    PrintProbs(stdout, mutpxy->Q, L);
    fprintf(stdout, "Rate\n");
    PrintProbs(stdout, mutpxy->Rate, L);
    fprintf(stdout, "Old Saturations probs\n");
    PrintVectorProbs(stdout, old_psat, L);
    fprintf(stdout, "New Saturations probs\n");
    PrintVectorProbs(stdout, new_psat, L);
    fprintf(stdout, "Target probs\n");
    PrintVectorProbs(stdout, targetfreq, L);
  }
  
  free(old_psat);
  free(new_psat);
  free(Q_0_inv);
  free(Q_0R);
}

/* Function: EvolChangeFreqMutProbsRecalRate()
 * 
 * Date:     ER, Tue Aug 31 12:14:55 CDT 2004  [St. Louis at work, Coro at daycar for her second day]
 *
 * Purpose: Obtain a new Rate matrix with a given set of marginal probabilities
 * 
 * Method: The new Conditional matrix is given by,
 *
 *         ~Q^*(i,j) = Q^*(i,j) * ~pm(j)/pm(j) * (~pm(j)*~pm(i) / pm(j)*pm(i) ) ^alpha(i,j)  
 *
 *                                      ,, alpha(i,j) = alpha(j,i) and in GW case they all take the value -1/2 
 *
 *
 *          If Q_0 is different from the identity matrix, it has to be changed too.
 *
 *          Then use ~Q^* and ~Q_0 to calculate the new Rate matrix
 *
 *          Then it is easy to see that
 *
 *                 ~P(i,j) = ~pm(i) * ~Q(i,j) = ~pm(j) * ~Q(j,i)  for all times, including t=0
 *
 *         If there are indels the pmarginals have to be modified too.
 *
 * Args:      
 *
 * Returns:  (void)
 */
void
EvolChangeFreqMutProbsRecalRate(struct psubs_s *mutpxy, double *targetfreq, int pedantic, int verbose)
{
  double *old_psat;
  double *new_psat;
  int     L;
  int     i;
  int     hasindel = FALSE; /* 4x4 mutations; this is a substitution processs w/o indels */
  
  L = mutpxy->L;
  
  if (verbose) {
    fprintf(stdout, "Target marginals probabilities\n");
    PrintVectorProbs(stdout, targetfreq, L);
  }
  CheckSingleProb(targetfreq, L); /* paranoia */

 if (verbose) {
    fprintf(stdout, "old P probs\n");
    PrintProbs(stdout, mutpxy->P, L);
    fprintf(stdout, "old Q probs\n");
    PrintProbs(stdout, mutpxy->Q, L);
    fprintf(stdout, "old Rate probs\n");
    PrintProbs(stdout, mutpxy->Rate, L);
  }

  old_psat = SaturationProbs(mutpxy->Rate, mutpxy->Qnought, L, FALSE, verbose);
  
  if (verbose) {
    fprintf(stdout, "Old Saturations probs\n");
    PrintVectorProbs(stdout, old_psat, L);
  }
  
  /* Matrices Qnought and Qstar change and then we recalculate the rate matrix
   *
   * 
   */
  ChangeConditionalMatrix(stdout, mutpxy->Qnought, mutpxy->pm, mutpxy->pm, L, targetfreq, hasindel, TRUE,  verbose);
  
  ChangeConditionalMatrix(stdout, mutpxy->Q, mutpxy->pm, mutpxy->pm, L, targetfreq, hasindel, TRUE,  verbose);
  
  RateFromConditionals(stdout, mutpxy->Rate, mutpxy->Q, mutpxy->Qnought, L, 1.0, hasindel, TRUE,  verbose);
  
  /* calculate new marginals by saturation of the conditionals keepint the "last" component intact if the process involves indels
   *
  * p = (\pi_i(1-Lamba(t)), Lambda(t))
  *
  * new frquencies are
  *
  * ~p = (~\pi_i(1-Lamba(t)), Lambda(t))
  *
  *  where ~\pi_i are the saturation prob's of the new Conditonal probabilities
  */
  ChangeFrequencies(stdout, mutpxy->Qnought, mutpxy->Rate, mutpxy->pm, mutpxy->L, targetfreq, hasindel, verbose);

  if (verbose) {
    fprintf(stdout, "New Q probs\n");
    PrintProbs(stdout, mutpxy->Q, L);
    fprintf(stdout, "New Rate probs\n");
    PrintProbs(stdout, mutpxy->Rate, L);
  }

  new_psat = SaturationProbs(mutpxy->Rate, mutpxy->Qnought, L, FALSE, verbose);
  
  if (verbose) {
    fprintf(stdout, "New Saturations probs\n");
    PrintVectorProbs(stdout, new_psat, L);
  }
  
  /* Finally recalculate the joint probabilities (at time = 1) 
   */
  Joint_From_Condi(stdout, mutpxy->P, mutpxy->Q, mutpxy->pm, L, verbose);
  
  /* paranoia */
  for (i = 0; i < L; i++) 
    if (fabs(new_psat[i]-targetfreq[i]) > MARGIN) 
      Die ("ChangeRateMatrix():\nbad change of background frequencies -- indels, i=%d new_target=%f targetfreq=%f", 
	   i, new_psat[i], targetfreq[i]);

  if (verbose) {
    for (i = 0; i < L; i++) 
      printf("i=%d new_target=%f old_target=%f\n", i, new_psat[i], old_psat[i]);
  }
  
  if (verbose) {
    fprintf(stdout, "\nEvolChangeFreqMutProbsRecalRate()\nNEW_JOINT probabilities\n");
    PrintProbs(stdout, mutpxy->P, L);
    fprintf(stdout, "Q\n");
    PrintProbs(stdout, mutpxy->Q, L);
    fprintf(stdout, "Rate\n");
    PrintProbs(stdout, mutpxy->Rate, L);
    fprintf(stdout, "Old Saturations probs\n");
    PrintVectorProbs(stdout, old_psat, L);
    fprintf(stdout, "New Saturations probs\n");
    PrintVectorProbs(stdout, new_psat, L);
    fprintf(stdout, "Target probs\n");
    PrintVectorProbs(stdout, targetfreq, L);
  }
  
  free(old_psat);
  free(new_psat);
}

/* Function: EvolChangeFreqMut5ProbsModifRate(/QR)
 * 
 * Date:     ER, Sun Aug 29 11:14:19 CDT 2004 [St. Louis at home, Coro asleep with her first cold ]
 *
 * Purpose: Obtain a new mut5pxy joint probabilities that have a given background frequencies "targetfreq"
 * 
 * Method:  model of evolution: Q(t) = Q_0 * e^{tR}
 *
 *          time-dependent reversability: pm(t)_i Q_ij(t) = pm(t)_j Q_ji(t) ,, pm_i(t) = [  p_i*(1-Lambda_t), Lambda_t ]
 *
 *          I change Q_0 and modify the Q_0Rate matrix 
 *
 *
 * Args:      
 *
 * Returns:  (void)
 */
void
EvolChangeFreqMut5ProbsModifRate(struct psubs_s *mut5pxy, double *targetfreq, int pedantic, int verbose)
{
  double *Q_0R;
  double *Q_0_inv;
  double *old_psat;
  double *new_psat;
  double *new_target;
  int     L;
  int     i;
  int     dim;
  int     hasindel = TRUE; /* 5x5 mutations; this is a substitution processs w indels */
  
  L = mut5pxy->L;
  
  dim = L-1;
  
  if (verbose) {
    fprintf(stdout, "target marginals probabilities %d\n", dim);
    PrintVectorProbs(stdout, targetfreq, dim);
  }
  CheckSingleProb(targetfreq, dim); /* paranoia */
  
  old_psat = SaturationProbs(mut5pxy->Rate, mut5pxy->Qnought, L, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "OLD_JOINT probabilities \n");
    PrintProbs(stdout, mut5pxy->P, L);
    fprintf(stdout, "Old Saturations probs\n");
    PrintVectorProbs(stdout, old_psat, L);
  }
  
  /* Matrices Qnought and Qstar change and then we recalculate the rate matrix
   *
   * 
   */
  
  /* before changing the Q_0 matrix, calculate Q_0 * R
   */
  Q_0R = Cal_M_N_Prod(stdout, mut5pxy->Qnought, mut5pxy->Rate, L, L, L, verbose);

  /* now change the Q_0 */
  ChangeQ_0Matrix(stdout, mut5pxy->Qnought, mut5pxy->pm, mut5pxy->pm, L, targetfreq, hasindel, TRUE,  verbose);

  /* calculate the inverse matrix of the new Q_0 */
  Q_0_inv = Cal_M_Inv(stdout, mut5pxy->Qnought, L, verbose);

  if (verbose) {
    fprintf(stdout, "Q_0 \n");
    PrintProbs(stdout, mut5pxy->Qnought, L);
    fprintf(stdout, "Q_0_inv\n");
    PrintProbs(stdout, Q_0_inv, L);
  }

  ChangeRateMatrix(stdout, Q_0R, Q_0_inv, mut5pxy->Rate, mut5pxy->pm, mut5pxy->pm, L, targetfreq, hasindel, TRUE, verbose);

  new_psat = SaturationProbs(mut5pxy->Rate, mut5pxy->Qnought, L, FALSE, verbose);
  
  /* calculate new marginals by saturation of the conditionals keeping the "last" component intact
   *
   * p = (\pi_i(1-Lamba(t)), Lambda(t))
   *
   * new frquencies are
   *
   * ~p = (~\pi_i(1-Lamba(t)), Lambda(t)
   *
   *  where ~\pi_i are the saturation prob's of the new Conditonal probabilities
   */
  ChangeFrequencies(stdout, mut5pxy->Qnought, mut5pxy->Rate, mut5pxy->pm, mut5pxy->L, targetfreq, hasindel, verbose);

  /* Recalculate the conditionals for this new rate matrix at t=1
   */
  ConditionalsFromRate(mut5pxy->Q, mut5pxy->Rate, mut5pxy->Qnought, 1.0, mut5pxy->L, pedantic, verbose);

  /* Finally recalculate the joint probabilities (at time = 1) 
   */
  Joint_From_Condi(stdout, mut5pxy->P, mut5pxy->Q, mut5pxy->pm,  mut5pxy->L, verbose);
  
  new_target = (double *) MallocOrDie (sizeof(double) * dim);
  for (i = 0; i < dim; i++) 
    if (fabs(1.0-new_psat[dim]) > 1.0-accuracy) new_target[i] = new_psat[i] / (1.0 - new_psat[dim]);
    else                                        new_target[i] = targetfreq[i];

  /* paranoia */
    if (fabs(new_psat[dim]-old_psat[dim]) > MARGIN) 
      Die ("EvolChangeFreqMut5ProbsModifRate():\nbad change of background frequencies -- indels, Lambda_infty=%f target)Lambda_infty=%f", 
	   new_psat[dim], old_psat[dim]);
  for (i = 0; i < dim; i++) 
    if (fabs(new_target[i]-targetfreq[i]) > MARGIN) 
      Die ("EvolChangeFreqMut5ProbsModifRate():\nbad change of background frequencies -- indels, i=%d new_target=%f targetfreq=%f", 
	   i, new_target[i], targetfreq[i]);

  if (verbose) {
    for (i = 0; i < L; i++) 
      if (i <  dim) printf("i=%d new_target=%f old_target=%f\n", i, new_target[i], targetfreq[i]);
      if (i == dim) printf("i=%d new_target=%f old_target=%f\n", i, new_psat[i],   old_psat[i]);
  }
  
  if (verbose) {
    fprintf(stdout, "\nEvolChangeFreqMut5ProbsModifRate()\nNEW_JOINT probabilities\n");
    PrintProbs(stdout, mut5pxy->P, L);
    fprintf(stdout, "Q\n");
    PrintProbs(stdout, mut5pxy->Q, L);
    fprintf(stdout, "Rate\n");
    PrintProbs(stdout, mut5pxy->Rate, L);
    fprintf(stdout, "Marginals \n");
    PrintVectorProbs(stdout, mut5pxy->pm, L);
    fprintf(stdout, "New Saturations probs\n");
    PrintVectorProbs(stdout, new_psat, L);
    fprintf(stdout, "New Target probs\n");
    PrintVectorProbs(stdout, new_target, dim);
    fprintf(stdout, "Target probs\n");
    PrintVectorProbs(stdout, targetfreq, dim);
  }
  
  free(new_target);
  free(old_psat);
  free(new_psat);
  free(Q_0_inv);
  free(Q_0R);
}

/* Function: EvolChangeFreqMut5ProbsRecalRate()
 * 
 * Date:     ER, Sun Aug 29 11:09:29 CDT 2004 [St. Louis at home, Coro asleep with her first cold ]
 *
 * Purpose: Obtain a new mut5pxy joint probabilities that have a given background frequencies "targetfreq"
 * 
 * Method:  model of evolution: Q(t) = Q_0 * e^{tR}
 *
 *          time-dependent reversability: pm(t)_i Q_ij(t) = pm(t)_j Q_ji(t) ,, pm_i(t) = [  p_i*(1-Lambda_t), Lambda_t ]
 *
 *          I change Q_0 and Q^*, then I redefine the rate, and finally calculate Lambda(t) so that the time
 *          dependent reversabilitiy holds for every t.
 *
 *
 * Args:      
 *
 * Returns:  (void)
 */
void
EvolChangeFreqMut5ProbsRecalRate(struct psubs_s *mut5pxy, double *targetfreq, int pedantic, int verbose)
{
  double *old_psat;
  double *new_psat;
  double *new_target;
  int     L;
  int     i;
  int     dim;
  int     hasindel = TRUE; /* 5x5 mutations; this is a substitution processs w indels */
  
  L = mut5pxy->L;
  
  dim = L-1;
  
  if (verbose) {
    fprintf(stdout, "\ntarget marginals probabilities %d\n", dim);
    PrintVectorProbs(stdout, targetfreq, dim);
  }
  CheckSingleProb(targetfreq, dim); /* paranoia */
  
  if (verbose) {
    fprintf(stdout, "old P probs\n");
    PrintProbs(stdout, mut5pxy->P, L);
    fprintf(stdout, "old Q probs\n");
    PrintProbs(stdout, mut5pxy->Q, L);
    fprintf(stdout, "old Rate probs\n");
    PrintProbs(stdout, mut5pxy->Rate, L);
  }

  old_psat = SaturationProbs(mut5pxy->Rate, mut5pxy->Qnought, L, FALSE, verbose);
  
  if (verbose) {
    fprintf(stdout, "Old Saturations probs\n");
    PrintVectorProbs(stdout, old_psat, L);
  }
  
  /* Matrices Qnought and Qstar change and then we recalculate the rate matrix
   *
   * 
   */
  /* calculate new marginals by saturation of the conditionals keeping the "last" component intact
   *
   * p = (\pi_i(1-Lamba(t)), Lambda(t))
   *
   * new frquencies are
   *
   * ~p = (~\pi_i(1-Lamba(t)), Lambda(t)
   *
   *  where ~\pi_i are the saturation prob's of the new Conditonal probabilities
   */
  ChangeConditionalMatrix(stdout, mut5pxy->Qnought, mut5pxy->pm, mut5pxy->pm, L, targetfreq, hasindel, TRUE,  verbose);
  
  ChangeConditionalMatrix(stdout, mut5pxy->Q, mut5pxy->pm, mut5pxy->pm, L, targetfreq, hasindel, TRUE,  verbose);
  
  RateFromConditionals(stdout, mut5pxy->Rate, mut5pxy->Q, mut5pxy->Qnought, L, 1.0, hasindel, TRUE,  verbose);
  
  ChangeFrequencies(stdout, mut5pxy->Qnought, mut5pxy->Rate, mut5pxy->pm, mut5pxy->L, targetfreq, hasindel, verbose);

  if (verbose) {
    fprintf(stdout, "New Q probs\n");
    PrintProbs(stdout, mut5pxy->Q, L);
    fprintf(stdout, "New Rate probs\n");
    PrintProbs(stdout, mut5pxy->Rate, L);
  }

  new_psat = SaturationProbs(mut5pxy->Rate, mut5pxy->Qnought, L, FALSE, verbose);
  
  if (verbose) {
    fprintf(stdout, "New Saturations probs\n");
    PrintVectorProbs(stdout, new_psat, L);
  }
  
 /* Finally recalculate the joint probabilities (at time = 1) 
   */
  Joint_From_Condi(stdout, mut5pxy->P, mut5pxy->Q, mut5pxy->pm, L, verbose);
  
  new_target = (double *) MallocOrDie (sizeof(double) * dim);
  for (i = 0; i < dim; i++) 
    if (new_psat[dim] < 1.0 ) new_target[i] = new_psat[i] / (1.0 - new_psat[dim]);
    else                      new_target[i] = 0.0;
  
  /* paranoia */
  if (fabs(new_psat[dim]-old_psat[dim]) > MARGIN) 
    Die ("ChangeRateMatrix():\nbad change of background frequencies -- indels, Lambda_infty=%f target)Lambda_infty=%f",
	 new_psat[dim], old_psat[dim]);
  for (i = 0; i < dim; i++) 
    if (fabs(new_target[i]-targetfreq[i]) > MARGIN) 
      Die ("ChangeRateMatrix():\nbad change of background frequencies -- indels, i=%d new_target=%f targetfreq=%f", 
	   i, new_target[i], targetfreq[i]);

  if (verbose) {
    for (i = 0; i < L; i++) 
      if (i < dim) printf("i=%d new_target=%f old_target=%f\n", i, new_target[i], targetfreq[i]);
      if (i == dim) printf("i=%d new_target=%f old_target=%f\n", i, new_psat[i], old_psat[i]);
  }
  
  if (verbose) {
    fprintf(stdout, "\nEvolChangeFreqMut5ProbsRecalRate()\nNEW_JOINT probabilities\n");
    PrintProbs(stdout, mut5pxy->P, L);
    fprintf(stdout, "Q\n");
    PrintProbs(stdout, mut5pxy->Q, L);
    fprintf(stdout, "Rate\n");
    PrintProbs(stdout, mut5pxy->Rate, L);
    fprintf(stdout, "New Saturations probs\n");
    PrintVectorProbs(stdout, new_psat, L);
    fprintf(stdout, "New Target probs\n");
    PrintVectorProbs(stdout, new_target, dim);
    fprintf(stdout, "Target probs\n");
    PrintVectorProbs(stdout, targetfreq, dim);
  }
  
  free(new_target);
  free(old_psat);
  free(new_psat);
}

/* Function: EvolChangeFreqPair5Probs()
 *
 * Date:     ER, Tue May 25 15:06:45 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given probs pair5prob_star[5x5] change the background probabilities
 *           THis function is very similar to EvolCalPair5Probs()
 *
 *           Because we change the frequencies using the iterative method
 *           The new rate matrix  has to be calculated again taking the log from the conditional probs
 *          
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct pnonsubs_s pair5prob 
 */
void
EvolChangeFreqPair5Probs(struct pnonsubs_s *pair5prob, double *targetfreq, int pedantic, int verbose)
{
  struct pnonsubs_s *pairprob;
  double             gap;
  double             gap2gap;
  double             lambda_infty;
  int                L5;
  int                L;
  int                i, j;
  
  L5 = pair5prob->L;

  L = L5 - 1;

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

  /* allocate */
  AllocNonSubsProbs(L, &pairprob);
  
  pairprob->time  = 1.0;
  
  for (i = 0; i < L; i++)
    for (j = 0; j < L; j++) 
      pairprob->P[i*L+j] = pair5prob->P[i*L5+j];

  /* normalize */
  DNorm(pairprob->P, L*L);
  
  if (verbose) { 
    fprintf(stdout, "\npair %dx%d probabilities\n", pairprob->L, pairprob->L);
    PrintProbs(stdout, pairprob->P, pairprob->L);
  }

 /* Calculate Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(stdout, pairprob->P, pairprob->Ql, pairprob->Qr, 
				    pairprob->pml, pairprob->pmr, pairprob->L, FALSE, verbose);
  
  if (verbose) { 
    fprintf(stdout, "\npair %dx%d probabilities\n", pairprob->L, pairprob->L);
    PrintProbs(stdout, pairprob->P, pairprob->L);
    fprintf(stdout, "Ql(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pairprob->Ql, pairprob->L);
    fprintf(stdout, "Qr(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pairprob->Qr, pairprob->L);
    fprintf(stdout, "pml(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob->pml, pairprob->L);
    fprintf(stdout, "pmr(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob->pmr, pairprob->L);
  }
  
  /* make marginals identical to those of targerfreq */
#ifdef YU_PAIR
    EvolChangePairProbsYuAltschul(stdout, pairprob, targetfreq, FALSE, verbose);
#else
    EvolChangePairProbsNaive(stdout, pairprob, targetfreq, FALSE, verbose);
#endif

  if (verbose) { 
    fprintf(stdout, "\npair %dx%d probabilities - after changing backgroung frequencies with iterative methods\n",
	    pairprob->L, pairprob->L);
    PrintProbs(stdout, pairprob->P, pairprob->L);
    fprintf(stdout, "Ql(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pairprob->Ql, pairprob->L);
    fprintf(stdout, "Qr(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pairprob->Qr, pairprob->L);
    fprintf(stdout, "pml(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob->pml, pairprob->L);
    fprintf(stdout, "pmr(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob->pmr, pairprob->L);
  }
  
  for (i = 0; i < L5; i++)
    for (j = 0; j < L5; j++)
      if (i < L && j < L) pair5prob->P[i*L5+j] = pairprob->P[i*L+j];
      else                pair5prob->P[i*L5+j] = 0.0;
  CheckSingleProb(pair5prob->P, L5*L5);

  /* Conditional pair5prob at time zero are infered from pair5probs at t* before adding gaps
   *
   */
  gap = GAPP;
  lambda_infty = GAPP_INFTY;

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

  pair5prob_conditionals_at_zero (pairprob, pair5prob, gap, gap2gap, lambda_infty, verbose);

  /* add gaps */
  /* OK, NT-2-GAP AND GAP-2-GAP Watson-Crick-Pair-Probabilities cannot be justified
   *
   * This is how I deal with them:
   */
  /* add pair-to-gap */
  MarginalizeJointProbs(pair5prob->P, pair5prob->pml, L5, 0);
  MarginalizeJointProbs(pair5prob->P, pair5prob->pmr, L5, 1);
  for (i = 0; i < L; i++) {
    pair5prob->P[idx5(i,L)] = gap*pair5prob->pml[i];
    pair5prob->P[idx5(L,i)] = gap*pair5prob->pmr[i];
  }
  pair5prob->P[idx5(L,L)] = gap2gap;

  /* normalize */
  DNorm(pair5prob->P, L5*L5);

  /* Calculate Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(stdout, pair5prob->P, pair5prob->Ql, pair5prob->Qr, 
				    pair5prob->pml,  pair5prob->pmr, pair5prob->L, FALSE, verbose);
  
  /* Calculate the rate matrix */
  RateFromConditionals(stdout, pair5prob->Ratel, pair5prob->Ql, pair5prob->Qlnought, pair5prob->L, 1.0, FALSE, FALSE, verbose);  
  RateFromConditionals(stdout, pair5prob->Rater, pair5prob->Qr, pair5prob->Qrnought, pair5prob->L, 1.0, FALSE, FALSE, verbose);  

  if (verbose) {
    fprintf(stdout, "\nPair5prob(i,j, t*) Joint probabilities\n");
    PrintProbs(stdout, pair5prob->P, pair5prob->L);
    fprintf(stdout, "Ql(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pair5prob->Ql, pair5prob->L);
    fprintf(stdout, "Qr(i|j, t*) conditional probabilities\n");
    PrintProbs(stdout, pair5prob->Qr, pair5prob->L);
    fprintf(stdout, "Ppair5(i|j, t=0) L-Cond probabilities\n");
    PrintProbs(stdout, pair5prob->Qlnought, L5);
    fprintf(stdout, "Ppair5(i|j, t=0) R-Cond probabilities\n");
    PrintProbs(stdout, pair5prob->Qrnought, L5);
    fprintf(stdout, "Ratel matrix\n");
    PrintProbs(stdout, pair5prob->Ratel, pair5prob->L);
    fprintf(stdout, "Rater matrix\n");
    PrintProbs(stdout, pair5prob->Rater, pair5prob->L);
    fprintf(stdout, "pml(i, t*) marginal probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pml, pair5prob->L);
    fprintf(stdout, "pmr(i, t*) marginal probabilities\n");
    PrintProbs(stdout, pair5prob->pmr, pair5prob->L);
   }

  FreeNonSubsProbs(pairprob);

}

/* Function: EvolChangeRIBORate()
 *
 * Date:     ER, TMon May 31 12:10:45 CDT 2004 [St. Louis, at work without Coro]
 *
 * Purpose:  
 *          
 * Args:    
 *
 * Returns:  (void)
 *           
 */
void
EvolChangeRIBORate(FILE *ofp, struct psubs_s *riboprob, struct pnonsubs_s *targetpair, int verbose)
{
  double *alpha;
  double *Q_0_inv;
  double *Rev1, *Rev2;
  double *epm;
  double  comesfrom;
  double  goesto;
  double  sum;
  int     L;
  int     L2;
  int     i,j;

  L  = targetpair->L;
  L2 = riboprob->L;
 
  DLog2(targetpair->P, L2);

  if (verbose) {
    fprintf(ofp, "Old Rate Matrix\n");
    PrintProbs(ofp, riboprob->Rate, L2);
    DExp2(riboprob->pm, L2);
    DExp2(targetpair->P, L2);
    fprintf(ofp, "old stat probabilities\n");
    PrintProbs(ofp, riboprob->pm, L);
    fprintf(ofp, "target stat probabilities\n");
    PrintProbs(ofp, targetpair->P, L);
    DLog2(riboprob->pm, L2);
    DLog2(targetpair->P, L2);
 }

  /* paranoia */
  CheckSingleLog2Prob(riboprob->pm,  L2);
  CheckSingleLog2Prob(targetpair->P, L2);
  
  alpha = (double *) MallocOrDie (sizeof(double) * L2 * L2);

  for (i = 0; i < L2; i++)
    for (j = 0; j < L2; j++) 
      alpha[i*L2+j] = 0.0;

  for (i = 0; i < L2; i++)
    for (j = i+1; j < L2; j++) {
      alpha[i*L2+j] = -0.5;      
      alpha[j*L2+i] = alpha[i*L2+j]; 
    }

  if (verbose) {
    fprintf(ofp, "alpha Matrix\n");
    PrintProbs(ofp, alpha, L2);
    fprintf(ofp, "stat marginals\n");
    PrintVectorProbs(ofp, riboprob->pm, L2);
    fprintf(ofp, "target marginals\n");
    PrintVectorProbs(ofp, targetpair->P, L2);
  }
 
 /* Non diagonal "reduced" components of (R) */
  for (i = 0; i < L2; i++) 
    for (j = 0; j < L2; j++) {

      comesfrom = targetpair->P[i] - riboprob->pm[i];
      goesto    = targetpair->P[j] - riboprob->pm[j];
      
      if (i != j ) riboprob->Rate[i*L2+j] *= EXP2(alpha[i*L2+j]*comesfrom) * EXP2((1.0+alpha[i*L2+j])*goesto);
    }

  /* Diagonal components of (Q_0*R) */
  for (i = 0; i < L2; i++) { 
    riboprob->Rate[i*L2+i] = 0.0;
    
    for (j = 0; j < L2; j++) 
      if (j != i) riboprob->Rate[i*L2+i] -= riboprob->Rate[i*L2+j];
  }
 
  if (verbose) {
    Rev1 = (double *) MallocOrDie (sizeof(double) * L2 * L2);
    Rev2 = (double *) MallocOrDie (sizeof(double) * L2 * L2);
    for (i = 0; i < L2; i++) 
      for (j = 0; j < L2; j++) {
	Rev1[i*L2+j] = riboprob->Rate[i*L2+j] * EXP2(targetpair->P[i]);
	Rev2[i*L2+j] = riboprob->Rate[j*L2+i] * EXP2(targetpair->P[j]);

	if (fabs(Rev1[i*L2+j]-Rev2[i*L2+j]) > MARGIN) 
	  Die ("ChangeRIBORateMatrix(): New rate matrix is not reversible respect to the new probabilities");
      }
	
    fprintf(ofp, "(R * pi) reversibility\n");
    PrintProbs(ofp, Rev1, L2);
    fprintf(ofp, "(R * pi) reversibility\n");
    PrintProbs(ofp, Rev2, L2);
    free(Rev1);
    free(Rev2);
  }

  Q_0_inv = Cal_Id(L2);
  Comp_M_N_Prod(ofp, Q_0_inv, riboprob->Rate, L2, verbose); /*  multiply Q_0_inv*M it in M */
  
  /* consistency check, rows should add up to zero
   */	
  for (i = 0; i < L2; i++) {
    sum = 0.0;
    for (j = 0; j < L2; j++)
      sum += riboprob->Rate[i*L2+j];
    if (sum > MARGIN || sum < -MARGIN) Warn("ChangeRIBORateMatrix(): column %d bad rate matrix (sum = %f)\n", i, sum);
  }

  for (i = 0; i < L2; i++) 
    riboprob->pm[i] = targetpair->P[i];
  
  if (verbose) {
    epm = (double *) MallocOrDie (sizeof(double) * L2);

    for (i = 0; i < L2; i++) 
      epm[i] = EXP2(targetpair->P[i]);
    
    fprintf(ofp, "New RIBO Rate Matrix\n");
    PrintProbs(ofp, riboprob->Rate, L2);
    fprintf(ofp, "New RIBO MARGINALS Matrix\n");
    PrintProbs(ofp, epm, L);
    
    free(epm);  
  }

  /* With the new Rate matrices, recalculate the conditionals (a t = 1) joint and marginals
   */
  ConditionalsFromRate(riboprob->Q, riboprob->Rate, riboprob->Qnought, 1.0, L2, FALSE, verbose);
  Joint_From_Condi(stdout, riboprob->P, riboprob->Q, riboprob->pm, L2, verbose);

  free(alpha);
  free(Q_0_inv);
}

/* Function: EvolCODProbsStar()
 * Date:     ER, Tue May 18 08:39:10 CDT 2004  [St. Louis, at home with Coro]
 *
 * Purpose: 
 *
 * Args:      *
 * Returns:  (void)
 *           fills in structure pammodel.
 */
void
EvolCODProbsStar(struct psubs_s *pam_star, struct psubs_s **ret_codprob_star, double *codon_joint, int add_codon, 
		 double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct psubs_s  *pam;
  struct psubs_s  *codprob_star;
  double         **estmodel;
  double          *pt2codon;
  double          *codonX;
  double          *codonY;
  double          *codfreq;
  double           tfactor = 1.0; /* by definition of t^* */
  int              L = 64;
  int              LSQ;
  int              i;
  int              a, b;
  int              x, y;
  int              xyz1, xyz2;
  
  LSQ = L*L;
  
  if (verbose) {
    fprintf(stdout, "PAM(i,j, t*) probabilities\n");
    PrintProbs(stdout, pam_star->P, pam_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, pam_star->Rate, pam_star->L);
  }
  
  /* allocate structure pam[20x20] and codprob_star[64x64]
   */
  AllocSubsProbs(pam_star->L, &pam);
  AllocSubsProbs(L,           &codprob_star);
  
  /* evoled pam Joint probabilities pam->P
   *
   *          pam->Q = pam->Qnought * exp{ pam->time * pam->Rate }
   *
   *          pam->P = pam->Q * pam->pm
   */
  pam->time = tfactor;

  /* The Rate and Qnought matrices are the same
   */
  CopyMatrix(pam->Rate,    pam_star->Rate,    pam->L, pam->L);
  CopyMatrix(pam->Qnought, pam_star->Qnought, pam->L, pam->L);
  
  /* The marginal probabilites are the same as well
   */
  CopyVector(pam->pm, pam_star->pm, pam->L);
  
  /* Conditionals are constructed from the rate matrix
   */
  if (pam->time == pam_star->time) {
    CopyMatrix(pam->Q, pam_star->Q, pam->L, pam->L);
    CopyMatrix(pam->P, pam_star->P, pam->L, pam->L);
  }
  else {
    ConditionalsFromRate(pam->Q, pam->Rate, pam->Qnought, pam->time, pam->L, pedantic, verbose);
    Joint_From_Condi(stdout, pam->P, pam->Q, pam->pm, pam->L, verbose);
  }
  
  /* paranoia
   */
  CheckSingleProb(pam->P, pam->L*pam->L);
  for (i = 0; i < pam->L; i++)
    CheckSingleProb(pam->Q+i*pam->L, pam->L);
  
  if (verbose) {
    fprintf(stdout, "PAM(i,j, t=%.6f) Joint probabilities\n", pam->time);
    PrintProbs(stdout, pam->P, pam->L);
    fprintf(stdout, "Q_PAM(i,j, t=%.6f) Conditional probabilities\n", pam->time);
    PrintProbs(stdout, pam->Q, pam->L);
    fprintf(stdout, "PAM_marg probabilities\n");
    PrintVectorProbs(stdout, pam->pm, pam->L);
  }
  
  /* fill structure codprob_star
   */
  codprob_star->L    = L;
  codprob_star->time = tfactor;
  
  /* allocate estmodel[20][64]
   */
  estmodel    = (double **) MallocOrDie (sizeof(double *) * pam->L);
  estmodel[0] = (double  *) MallocOrDie (sizeof(double  ) * pam->L * codprob_star->L);
  
  for (a = 1; a < pam->L; a++) estmodel[a] = estmodel[0] + a * codprob_star->L;
  
  ConstructESTModel(estmodel);
  
  /* calculate evolved Joint Codprob_Stars
   */
  /* There is an additional term that needs to be evolved:
   *
   *                  pt2cod(c2 c1 t) = pcodcod(c2, c1 | t) /  pcod(c1 | t) pcod(c2 | t)
   *
   *  The three "points" to make it evolve are:
   *
   *            t=0         pt2cod(c2 c1 t=0)     = delta(c1,c2)
   *
   *            t=t^*       pt2cod(c2 c1 t^*)     = 1    (we assume independence for now)
   */
  /* this is a hack 
   */
  pt2codon = (double *) MallocOrDie(sizeof(double) * codprob_star->L * codprob_star->L);
  codonX   = (double *) MallocOrDie(sizeof(double) * codprob_star->L);
  codonY   = (double *) MallocOrDie(sizeof(double) * codprob_star->L);
 
  if (add_codon) {
    MarginalizeJointProbs(codon_joint, codonX, codprob_star->L, 1);
    MarginalizeJointProbs(codon_joint, codonY, codprob_star->L, 0);
  }
  
  for (xyz1 = 0; xyz1 < codprob_star->L; xyz1++)
    for (xyz2 = 0; xyz2 < codprob_star->L; xyz2++)
      if (add_codon) pt2codon[xyz1*codprob_star->L+xyz2] = codon_joint[xyz1*codprob_star->L+xyz2] / ( codonX[xyz1] * codonY[xyz2] );
      else           pt2codon[xyz1*codprob_star->L+xyz2] = 1.0;
  
  /* Fill in codprob_star
   *   codprb->P(xyz1,xyz2) = \sum_ab P(xyz1,xyz2 | ab) P(ab)
   *
   *     independence assumption for converting aa to codon gives:
   *
   *   codprob_star->P(xyz1,xyz2) =  pcodcod(c1,c2|t) / [ pcod(c1) * pcod(c2) ]  \sum_ab P(xyz1 | a) P(xyz2 | b) pam->P(ab |t)
   *                                                                               ^ estmodel  ^estmodel   ^aajoint  
   */
  for (xyz1 = 0; xyz1 < L; xyz1++)
    for (xyz2 = 0; xyz2 < L; xyz2++)
      {
	codprob_star->P[xyz1*L+xyz2] = 0.0;
	
	for (a = 0; a < pam->L; a++)
	  for (b = 0; b < pam->L; b++) 
	    codprob_star->P[xyz1*L+xyz2] += pt2codon[xyz1*L+xyz2] *
	      estmodel[a][xyz1] * estmodel[b][xyz2] * pam->P[a*pam->L+b];
      }
  
  /* Normalize it
   */
  DNorm(codprob_star->P, LSQ);

  /* Check it
   */
  CheckSingleProb(codprob_star->P, LSQ); 

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, codprob_star->P, codprob_star->Q, codprob_star->pm, codprob_star->L, FALSE, verbose);
 
  /* it takes too long to calculate the 64x64 rate matrix
   *
   * EvolCalCODRate(codprob_star, verbose);
   */

  if (verbose) {
    fprintf(stdout, "\nBEFORE change background frequencies\n");
    fprintf(stdout, "COD(i,j, t=%.6f) Joint probabilities\n", codprob_star->time);
    PrintProbs(stdout, codprob_star->P, codprob_star->L);
    fprintf(stdout, "Q_COD(i,j, t=%.6f) Conditional probabilities\n", codprob_star->time);
    PrintProbs(stdout, codprob_star->Q, codprob_star->L);
    fprintf(stdout, "COD_marg probabilities\n");
    PrintVectorProbs(stdout, codprob_star->pm, codprob_star->L);
  }

  if (changefreq) {
#ifdef YU_PAIR_COD
    EvolChangeFreqCODProbsYuAltchul(codprob_star, targetfreq, pedantic, verbose);
#else
    EvolChangeFreqCODProbsNaive(codprob_star, targetfreq, pedantic, verbose);
#endif
  }

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, codprob_star->P, codprob_star->Q, codprob_star->pm, codprob_star->L, FALSE, verbose);
 
  if (verbose) {
    fprintf(stdout, "\nAFTER change background frequencies\n");
    fprintf(stdout, "COD(i,j, t=%.6f) Joint probabilities\n", codprob_star->time);
    PrintProbs(stdout, codprob_star->P, codprob_star->L);
    fprintf(stdout, "Q_COD(i,j, t=%.6f) Conditional probabilities\n", codprob_star->time);
    PrintProbs(stdout, codprob_star->Q, codprob_star->L);
    fprintf(stdout, "COD_marg probabilities\n");
    PrintVectorProbs(stdout, codprob_star->pm, codprob_star->L);
  }
  if (verbose) {
    codfreq = (double *) MallocOrDie (sizeof(double) * L);
    MarginalizeCODProbs(codprob_star->pm, codfreq, TRUE);
    
    free(codfreq);
  }

  *ret_codprob_star = codprob_star;

  /* free memory */
  FreeSubsProbs(pam);
  free(estmodel[0]);
  free(estmodel);
  free(pt2codon);
  free(codonX); 
  free(codonY);

}

/* Function: EvolCODProbs()
 * Date:     ER, Tue May 18 08:39:10 CDT 2004  [St. Louis at work, Coro with Maribel]
 *
 * Purpose: 
 *
 * Args:      *
 * Returns:  (void)
 *           fills in structure codprobs.
 */
void
EvolCODProbs(struct psubs_s *pam_star, struct psubs_s *codprob_star, double tfactor, 
	     struct psubs_s **ret_codprob, double *codon_joint, int add_codon, 
	     double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct psubs_s  *pam;
  struct psubs_s  *codprob;
  double         **estmodel;
  double          *pt2codon;
  double          *codonX;
  double          *codonY;
  double          *p4;
  double          *p4_zero;
  double          *pmarg;
  double          *codfreq;
  int              L;
  int              LSQ;
  int              L4;
  int              L4SQ;
  int              i;
  int              a, b;
  int              x;
  int              xyz1, xyz2;
  
  L = codprob_star->L;

  LSQ = L*L;

  L4   = EXP2(LOG2(L)/3.0);
  L4SQ = L4 * L4;

  if (verbose) {
    fprintf(stdout, "PAM(i,j, t*) probabilities\n");
    PrintProbs(stdout, pam_star->P, pam_star->L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, pam_star->Rate, pam_star->L);
  }
  if (verbose) {
    fprintf(stdout, "\nCOD(i,j, t=%.6f) Joint probabilities\n", codprob_star->time);
    PrintProbs(stdout, codprob_star->P, codprob_star->L);
    fprintf(stdout, "\nQ_COD(i,j, t=%.6f) Conditional probabilities\n", codprob_star->time);
    PrintProbs(stdout, codprob_star->Q, codprob_star->L);
  }
  
  /* allocate structure pam[20x20] and codprob[64x64]
   */
  AllocSubsProbs(pam_star->L, &pam);
  AllocSubsProbs(L,           &codprob);
  
  /* evoled pam Joint probabilities pam->P
   *
   *          pam->Q = pam->Qnought * exp{ pam->time * pam->Rate }
   *
   *          pam->P = pam->Q * pam->pm
   */
  pam->time = tfactor;

  /* The Rate and Qnought matrices are the same
   */
  CopyMatrix(pam->Rate,    pam_star->Rate,    pam->L, pam->L);
  CopyMatrix(pam->Qnought, pam_star->Qnought, pam->L, pam->L);
  
  /* The marginal probabilites are the same as well
   */
  CopyVector(pam->pm, pam_star->pm, pam->L);
  
  /* Conditionals are constructed from the rate matrix
   */
  if (pam->time == pam_star->time) {
    CopyMatrix(pam->Q, pam_star->Q, pam->L, pam->L);
    CopyMatrix(pam->P, pam_star->P, pam->L, pam->L);
  }
  else {
    ConditionalsFromRate(pam->Q, pam->Rate, pam->Qnought, pam->time, pam->L, pedantic, verbose);
    Joint_From_Condi(stdout, pam->P, pam->Q, pam->pm, pam->L, verbose);
  }
  
  /* paranoia
   */
  CheckSingleProb(pam->P, pam->L*pam->L);
  for (i = 0; i < pam->L; i++)
    CheckSingleProb(pam->Q+i*pam->L, pam->L);
  
  if (verbose) {
    fprintf(stdout, "PAM(i,j, t=%.6f) Joint probabilities\n", pam->time);
    PrintProbs(stdout, pam->P, pam->L);
    fprintf(stdout, "Q_PAM(i,j, t=%.6f) Conditional probabilities\n", pam->time);
    PrintProbs(stdout, pam->Q, pam->L);
    fprintf(stdout, "PAM_marg probabilities\n");
    PrintVectorProbs(stdout, pam->pm, pam->L);
  }
  
  /* fill structure codprob
   */
  codprob->L    = L;
  codprob->time = tfactor;
  
  /* allocate estmodel[20][64]
   */
  estmodel    = (double **) MallocOrDie (sizeof(double *) * pam->L);
  estmodel[0] = (double  *) MallocOrDie (sizeof(double  ) * pam->L * codprob->L);
  
  for (a = 1; a < pam->L; a++) estmodel[a] = estmodel[0] + a * codprob->L;
  
  ConstructESTModel(estmodel);
  
  /* calculate evolved Joint Codprobs
   */
  /* There is an additional term that needs to be evolved:
   *
   *                  pt2cod(c2 c1 t) = pcodcod(c2, c1 | t) /  pcod(c1 | t) pcod(c2 | t)
   *
   *  The three "points" to make it evolve are:
   *
   *            t=0         pt2cod(c2 c1 t=0)     = delta(c1,c2)
   *
   *            t=t^*       pt2cod(c2 c1 t^*)     = 1    (we assume independence for now)
   */
  /* this is a hack 
   */
  pt2codon      = (double *) MallocOrDie(sizeof(double) * codprob->L * codprob->L);
  codonX        = (double *) MallocOrDie(sizeof(double) * codprob->L);
  codonY        = (double *) MallocOrDie(sizeof(double) * codprob->L);
  p4            = (double *) MallocOrDie(sizeof(double) * L4SQ);
  pmarg         = (double *) MallocOrDie(sizeof(double) * L4);
  p4_zero       = Cal_Id (L4);
  
  /* intermediate state of calculating the codond marginals at t^* in order
   * to calculate the single nucleotide marginal probabilities
   */
  for (x = 0; x < L4SQ; x++) p4[x] = 0.0;
  for (xyz1 = 0; xyz1 < codprob->L; xyz1++) 
    for (xyz2 = 0; xyz2 < codprob->L; xyz2++) {
      p4[(xyz1/L4SQ)*L4+(xyz2/L4SQ)]         += codprob_star->P[xyz1*codprob->L+xyz2] / 3.0;
      p4[((xyz1%L4SQ)/L4)*L4+(xyz2%L4SQ)/L4] += codprob_star->P[xyz1*codprob->L+xyz2] / 3.0;
      p4[(xyz1%L4)*L4+xyz2%L4]               += codprob_star->P[xyz1*codprob->L+xyz2] / 3.0;
    }
  
  MarginalizeJointProbs(p4, pmarg, L4, 2);

  /* now the assumption of independence at t* for p4
   */
  for (x = 0; x < L4SQ; x++) p4[x] = pmarg[x/L4] * pmarg[x%L4];
  
  if (verbose) {
    fprintf(stdout, "p4(t=1.0)[%dx%d]\n", L4, L4);
    PrintProbs(stdout, p4, L4);
    fprintf(stdout, "pmarg\n");
    PrintVectorProbs(stdout, pmarg, L4);
  }
  CheckSingleProb(p4, L4SQ); 

  if (tfactor == 1.0) {
    for (xyz1 = 0; xyz1 < codprob_star->L; xyz1++)
      for (xyz2 = 0; xyz2 < codprob_star->L; xyz2++)
	if (add_codon) pt2codon[xyz1*codprob_star->L+xyz2] = codon_joint[xyz1*codprob_star->L+xyz2] / ( codonX[xyz1] * codonY[xyz2] );
	else           pt2codon[xyz1*codprob_star->L+xyz2] = 1.0;
  }
  else 
    Joint2Joint(p4, p4_zero, p4_zero, L4, (tfactor<1.0)?tfactor:1.0, codfreq, FALSE, FALSE, FALSE, pedantic, verbose);
  
  if (verbose) {
    fprintf(stdout, "p4(t=%f)\n", codprob->time);
    PrintProbs(stdout, p4, L4);
  }
  
  for (xyz1 = 0; xyz1 < codprob->L; xyz1++)
    for (xyz2 = 0; xyz2 < codprob->L; xyz2++) {
      
      pt2codon[xyz1*codprob->L+xyz2]  = p4[(xyz1/L4SQ)*L4+(xyz2/L4SQ)] * p4[((xyz1%L4SQ)/L4)*L4+(xyz2%L4SQ)/L4] * p4[(xyz1%L4)*L4+xyz2%L4];
      pt2codon[xyz1*codprob->L+xyz2] /= pmarg[xyz1/L4SQ] * pmarg[(xyz1%L4SQ)/L4] *pmarg[xyz1%L4];
      pt2codon[xyz1*codprob->L+xyz2] /= pmarg[xyz2/L4SQ] * pmarg[(xyz2%L4SQ)/L4] *pmarg[xyz2%L4];
  
    }
  
  if (verbose) {
    fprintf(stdout, "Pcodcod(c1,c2|t=%f)/[P(c1)*P(c2)]\n", codprob->time);
    PrintProbs(stdout, pt2codon, codprob->L);
  }

  /* Fill in codprob
   *   codprb->P(xyz1,xyz2) = \sum_ab P(xyz1,xyz2 | ab) P(ab)
   *
   *     independence assumption for converting aa to codon gives:
   *
   *   codprob->P(xyz1,xyz2) =  pcodcod(c1,c2|t) / [ pcod(c1) * pcod(c2) ]  \sum_ab P(xyz1 | a) P(xyz2 | b) pam->P(ab |t)
   *                                                                               ^ estmodel  ^estmodel   ^aajoint  
   */
  for (xyz1 = 0; xyz1 < L; xyz1++)
    for (xyz2 = 0; xyz2 < L; xyz2++)
      {
	codprob->P[xyz1*L+xyz2] = 0.0;
	
	for (a = 0; a < pam->L; a++)
	  for (b = 0; b < pam->L; b++) 
	    codprob->P[xyz1*L+xyz2] += pt2codon[xyz1*L+xyz2] *
	      estmodel[a][xyz1] * estmodel[b][xyz2] * pam->P[a*pam->L+b];
      }
  
  /* Normalize it
   */
  DNorm(codprob->P, LSQ);

  /* Check it
   */
  CheckSingleProb(codprob->P, LSQ); 

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, codprob->P, codprob->Q, codprob->pm, codprob->L, FALSE, verbose);

  if (changefreq && !NullProbs(targetfreq, L4)) {
#ifdef YU_PAIR_COD
   EvolChangeFreqCODProbsYuAltchul(codprob_star, targetfreq, pedantic, verbose);
#else
    EvolChangeFreqCODProbsNaive(codprob, targetfreq, pedantic, verbose);
#endif
  }

  if (verbose) {
    fprintf(stdout, "COD(i,j, t=%.6f) Joint probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->P, codprob->L);
    fprintf(stdout, "Q_COD(i,j, t=%.6f) Conditional probabilities\n", codprob->time);
    PrintProbs(stdout, codprob->Q, codprob->L);
    fprintf(stdout, "COD_marg probabilities\n");
    PrintVectorProbs(stdout, codprob->pm, codprob->L);
  }
  
  codfreq = (double *) MallocOrDie (sizeof(double) * L4);
  /* Instead of adjusting to the backgroud freqs of codprob->p, as in,
   *
   *    MarginalizeCODProbs(codprob->pm, codfreq, verbose);
   *
   * We do it to those of codprob_star->pm. At t ~ 0 the codprob->pm backgrounds
   * have an A-ridh behaviour that I do not want to propagate to the other
   * two models.
   */
  MarginalizeCODProbs(codprob_star->pm, codfreq, verbose);
  
  /* Here we select the background freq of the rest of the models 
   * according to those of the cod model
  */
  if (changefreq && NullProbs(targetfreq, L4)) CopyVector (targetfreq, codfreq, L4);
  if (verbose) {
    fprintf(stdout, "target-COD\n");
    PrintVectorProbs(stdout, targetfreq, L4);
  }
   
  *ret_codprob = codprob;

  /* free memory */
  free(codfreq);
  FreeSubsProbs(pam);
  free(estmodel[0]);
  free(estmodel);
  free(p4);
  free(p4_zero);
  free(pmarg);
  free(pt2codon);
  free(codonX); 
  free(codonY);

}

/* Function: EvolveIndelMarginalsByReversability()
 *
 * Date:     ER,  Mon Aug 30 10:34:33 CDT 2004 [St. Louis at work, Coro is at the daycare for the first time! ]
 *
 * Purpose:  Given      a LxL matrix Q(i,j) of conditional probabilities at a given time
 *
 *                      a L vector of marginal probs of the form   pmar = [p_i(1-lambda*), lamda*]
 *
 *           Use Q to calculate the marginals at time = [p_i(1-lambda_t), lamda_t] 
 *
 *           evolve lambda_t to mantain reversability
 *
 *              Lambda_t = \sum_i p_i Q(i,5) / [ \sum_i p_i Q(i,5) + (1-Q_55) ]
 *
 *           construct the evolved marginals as pmar(t) = [p_i(1-lambda_t), lamda_t]
 *
 *
 * Returns:  void.
 */
void
EvolveIndelMarginalsByReversability(FILE *ofp, double *Q, double *pm, int L, int pedantic, int verbose)
{
  double *P;
  double *ptarget;
  double  sum = 0.0;
  double  denom;
  double  Lambda;
  int     dim;
  int     i, j;

  dim = L-1;

   if (verbose) {
    fprintf(ofp, "\nEvolveIndelMarginalsByReversability(): Q\n");
    PrintProbs(ofp, Q, L);
    fprintf(ofp, "t^* marginals\n");
    PrintVectorProbs(ofp, pm, L);
   }

  ptarget = (double *) MallocOrDie (sizeof(double) * dim); 

  for (i = 0; i < dim; i++) 
     if (pm[dim] > 0.0)  ptarget[i] = pm[i] / (1.0-pm[dim]);
     else                ptarget[i] = pm[i];

   if (verbose) {
   fprintf(ofp, "target frequencies\n");
    PrintVectorProbs(ofp, ptarget, dim);
  }
  CheckSingleProb(ptarget, dim);
   
  /* Calculate Lambda_t so that reversability holds for arbitraty t
   */
  for (i = 0; i < dim; i++) 
    sum += ptarget[i] * Q[i*L+dim];
  denom = sum + 1.0 - Q[dim*L+dim];
  
  Lambda = (fabs(denom) > 0.0)? sum / denom : 0.0;
  
  if (Lambda < accuracy1-1.0) Die("EvolveIndelMarginalsByReversability(): Oh! negative probabilities! Lambda = %.10f\n", Lambda);
  
  /* use target and Lambda_t to recalculate the marginals
   */
  pm[dim] = Lambda;
  for (i = 0; i < dim; i++) 
    pm[i] = ptarget[i] * (1.0-Lambda);
  
  if (verbose) {
    fprintf(ofp, "marginals evolved\n");
    PrintVectorProbs(ofp, pm, L);
  }
  CheckSingleProb(pm, L);
  
  
  /* check of reversability */
  if (verbose) {
    P = (double *) MallocOrDie (sizeof(double) * L * L); 
    
    for (i = 0; i < L; i++) 
      for (j = 0; j < L; j++) 
	P[i*L+j] = pm[i] * Q[i*L+j];
    
    fprintf(ofp, "Is this matrix symmetric?\n");
    PrintProbs(ofp, P, L);
    
    free(P);
  }
  
  free(ptarget);
}

/* Function: EvolMutProbs()
 * Date:     ER, Tue May 18 08:39:10 CDT 2004  [St. Louis, at home with Coro]
 *
 * Purpose: 
 *
 * Args:      *
 * Returns:  (void)
 *           fills in structure pammodel.
 */
void
EvolMutProbs(struct psubs_s *mutpxy_star, double tfactor, struct psubs_s **ret_mutpxy, 
	     double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct psubs_s *mutpxy;
  int             L;
  int             LSQ;
  int             i;
   
  L   = mutpxy_star->L;
  LSQ = L*L;

  if (verbose) {
    printf("Target freqs in EvolMutProbs() changefreq=%d \n", changefreq);
    PrintVectorProbs(stdout, targetfreq, 4);    
  }
  
  if (verbose) {
    fprintf(stdout, "P(i,j, t*) probabilities\n");
    PrintProbs(stdout, mutpxy_star->P, L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mutpxy_star->Rate, L);
  }

  if (verbose) {
    fprintf(stdout, "Q(i,j, t*) Conditional probabilities - after changefreq\n");
    PrintProbs(stdout, mutpxy_star->Q, L);
    fprintf(stdout, "Rate matrix - after changefreq\n");
    PrintProbs(stdout, mutpxy_star->Rate, L);
  }

  /* allocate structure mutpxy[4x4]
   */
  AllocSubsProbs(L, &mutpxy);

  /* fill structure mutpxy
   */
  mutpxy->L    = L;
  mutpxy->time = tfactor;

  /* To start, copy everything over
   */
  CopyMatrix(mutpxy->P,       mutpxy_star->P,       L, L);
  CopyMatrix(mutpxy->Q,       mutpxy_star->Q,       L, L);
  CopyMatrix(mutpxy->Rate,    mutpxy_star->Rate,    L, L);
  CopyMatrix(mutpxy->Qnought, mutpxy_star->Qnought, L, L);

  /* The marginal probabilites are also the same, 
   */
  CopyVector(mutpxy->pm, mutpxy_star->pm, L);

  /* Change backgroung frequencies if we are asked to */
  if (changefreq) {
    if (verbose) {
      fprintf(stdout, "\nP(i,j, t=%.6f) Joint probabilities -- BEFORE changing background frequencies\n", mutpxy->time);
      PrintProbs(stdout, mutpxy->P, L);
      fprintf(stdout, "Q(i,j, t=%.6f) Conditional probabilities\n", mutpxy->time);
      PrintProbs(stdout, mutpxy->Q, L);
      fprintf(stdout, "Rate matrix\n");
      PrintProbs(stdout, mutpxy->Rate, L);
      fprintf(stdout, "marg probabilities\n");
      PrintVectorProbs(stdout, mutpxy->pm, L);
    }
    
    EvolChangeFreqMutProbsModifRate(mutpxy, targetfreq, pedantic, verbose);
  }

  if (verbose) {
    fprintf(stdout, "P(i,j, t*) probabilities - after\n");
    PrintProbs(stdout, mutpxy->P, L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mutpxy->Rate, L);
  }
  /* Evolve Joint probs mutpxy->P
   *
   *          mutpxy->Q = mutpxy->Qnought * exp{ mutpxy->time * mutpxy->Rate }
   *
   *          mutpxy->P = mutpxy->Q * mutpxy->pm
   */
  ConditionalsFromRate(mutpxy->Q, mutpxy->Rate, mutpxy->Qnought, tfactor, L, pedantic, verbose);
  Joint_From_Condi(stdout, mutpxy->P, mutpxy->Q, mutpxy->pm, L, verbose);

  /* paranoia
   */
  CheckSingleProb(mutpxy->P, LSQ);
  for (i = 0; i < L; i++)
    CheckSingleProb(mutpxy->Q+i*L, L);

  if (verbose) EvolCalculateMutProbsTargetError(stdout, targetfreq, mutpxy, verbose);
  
  if (verbose) {
    fprintf(stdout, "\nP(i,j, t=%.6f) Joint probabilities\n", mutpxy->time);
    PrintProbs(stdout, mutpxy->P, L);
    fprintf(stdout, "Q(i,j, t=%.6f) Conditional probabilities\n", mutpxy->time);
    PrintProbs(stdout, mutpxy->Q, L);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mutpxy->Rate, L);
    fprintf(stdout, "marg probabilities\n");
    PrintVectorProbs(stdout, mutpxy->pm, L);
 }

  *ret_mutpxy  = mutpxy;
}

/* Function: EvolMut5Probs()
 * Date:     ER, Mon May 17 12:21:38 CDT 2004 [St. Louis, at work with Coro]
 *
 * Purpose:  given a rate matrix for mut5pxy[5x5],
 *           calculate the probabilities at time "time".
 *
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mutpxy 
 */
void
EvolMut5Probs(struct psubs_s *mut5pxy_star, double tfactor, struct psubs_s **ret_mut5pxy, 
	      double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct psubs_s *mut5pxy;
  int             L5;
  int             L5SQ;
 
  L5   = mut5pxy_star->L;
  L5SQ = L5*L5;
  
  if (verbose) {
    fprintf(stdout, "\nP5(i,j, t*) probabilities\n");
    PrintProbs(stdout, mut5pxy_star->P, L5);
    fprintf(stdout, "Q5(i,j, t*) probabilities\n");
    PrintProbs(stdout, mut5pxy_star->Q, L5);
    fprintf(stdout, "Q5(i,j, t=0.0) probabilities\n");
    PrintProbs(stdout, mut5pxy_star->Qnought, L5);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy_star->Rate, L5);
    fprintf(stdout, "marginals\n");
    PrintVectorProbs(stdout, mut5pxy_star->pm, L5);
  }

  /* allocate structure mut5pxy[5x5]
   */
  AllocSubsProbs(L5, &mut5pxy);

  /* fill structure mutpxy
   */
  mut5pxy->L    = L5;
  mut5pxy->time = tfactor;

  /* Copy everything over to start
   */
  CopyMatrix(mut5pxy->P,       mut5pxy_star->P,       L5, L5);
  CopyMatrix(mut5pxy->Q,       mut5pxy_star->Q,       L5, L5);
  CopyMatrix(mut5pxy->Rate,    mut5pxy_star->Rate,    L5, L5);
  CopyMatrix(mut5pxy->Qnought, mut5pxy_star->Qnought, L5, L5);

 /* The marginal probabilites change because of the indelds, unless we are required
   * to change the background frequencies, then we need to change the Rate
   * matrix  and the Qnought  as well
   */
  CopyVector(mut5pxy->pm, mut5pxy_star->pm, L5);

     /* Change backgroung frequencies if we are asked to */
  if (changefreq) 
    EvolChangeFreqMut5ProbsModifRate(mut5pxy, targetfreq, pedantic, verbose);

  if (verbose) {
    fprintf(stdout, "\nP5(i,j, t*) probabilities -- after changefreq \n");
    PrintProbs(stdout, mut5pxy->P, L5);
    fprintf(stdout, "Q5(i|j, t*) probabilities -- after changefreq \n");
    PrintProbs(stdout, mut5pxy->Q, L5);
    fprintf(stdout, "Q(i|j, t=0) probabilities -- after changefreq \n");
    PrintProbs(stdout, mut5pxy->Qnought, L5);
    fprintf(stdout, "Rate matrix -- after changefreq \n");
    PrintProbs(stdout, mut5pxy->Rate, L5);
    fprintf(stdout, "marginals\n");
    PrintVectorProbs(stdout, mut5pxy->pm, L5);
  }

  /* Evolve Joint probs mut5pxy->P
   *
   *          mut5pxy->Q = mut5pxy->Qnought * exp{ mut5pxy->time * mut5pxy->Rate }
   *
   *          mut5pxy->P = mut5pxy->Q * mut5pxy->pm
   */
  ConditionalsFromRate(mut5pxy->Q, mut5pxy->Rate, mut5pxy->Qnought, tfactor, L5, pedantic, verbose);

  /* because the process involves indels, we have to evolve the marginal probabilities too
   * in the "quasi-reversible" manner
   *
   *          pm(t) = [ \pi(i)(1-\Lambda(t)), \Lambda(t) ] i = 1,...,4
   *
   *          where 
   *               pm^*     = [ \pi(i)(1-\Lambda^*    ), \Lambda^*     ] i = 1,...,4
   *
   *               pm^infty = [ \pi(i)(1-\Lambda^infty), \Lambda^infty ] i = 1,...,4 // calculated from R and Qnought
   *
   *          \Lambda(t) is set by the reversability condition
   */ 
  if (verbose) {
    fprintf(stdout, "mut marginals - before evolved\n");
    PrintVectorProbs(stdout, mut5pxy->pm, L5);
  }
  
  EvolveIndelMarginalsByReversability(stdout, mut5pxy->Q, mut5pxy->pm, L5, FALSE, verbose);

  if (verbose) {
    fprintf(stdout, "mut marginals - after evolved\n");
    PrintVectorProbs(stdout, mut5pxy->pm, L5);
  }

  /* FINALLY, Evolve Joint probs mut5pxy->P
   *
   *          mut5pxy->P = mut5pxy->Q * mut5pxy->pm
   */
  Joint_From_Condi(stdout, mut5pxy->P, mut5pxy->Q, mut5pxy->pm, L5, verbose);

  /* Calculate Conditionals and Marginals */
  ComputeConditionalsAndMarginals(stdout, mut5pxy->P, mut5pxy->Q, mut5pxy->pm, mut5pxy->L, TRUE, verbose);

  if (verbose) EvolCalculateMut5ProbsTargetError(stdout, targetfreq, mut5pxy, verbose);

  if (verbose) {
    fprintf(stdout, "\nP5(i,j, t=%.6f) Joint probabilities\n", mut5pxy->time);
    PrintProbs(stdout, mut5pxy->P, L5);
    fprintf(stdout, "Q5(i,j, t=%.6f) Conditional probabilities\n", mut5pxy->time);
    PrintProbs(stdout, mut5pxy->Q, L5);
    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, mut5pxy->Rate, L5);
    fprintf(stdout, "marg probabilities\n");
    PrintVectorProbs(stdout, mut5pxy->pm, L5);
 }

  *ret_mut5pxy = mut5pxy;
}


/* Function: EvolPair5Probs()
 * Date:     ER, Tue May 18 15:49:21 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given a rate matrix for pair5prob[5x5],
 *           calculate the probabilities at time "time".
 *
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s mutpxy 
 */
void
EvolPair5Probs(struct pnonsubs_s *pair5prob_star, double tfactor, struct pnonsubs_s **ret_pair5prob, 
	       double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct pnonsubs_s *pair5prob;
  int                L;
  int                L5;
  int                L5SQ;
 
  L5   = pair5prob_star->L;
  L5SQ = L5*L5;
  
  L = L5 - 1;

  if (verbose) {
    fprintf(stdout, "Pair5(i,j, t*) probabilities\n");
    PrintProbs(stdout, pair5prob_star->P, L5);
    fprintf(stdout, "Pair5 Ql(i|j, t*) probabilities\n");
    PrintProbs(stdout, pair5prob_star->Ql, L5);
    fprintf(stdout, "Pair5 Qr(i|j, t*) probabilities\n");
    PrintProbs(stdout, pair5prob_star->Qr, L5);
    fprintf(stdout, "Pair5 Ratel(i|j, t*) matrix\n");
    PrintProbs(stdout, pair5prob_star->Ratel, L5);
    fprintf(stdout, "Pair5 Rater(i|j, t*) matrix\n");
    PrintProbs(stdout, pair5prob_star->Rater, L5);
    fprintf(stdout, "Pair5 pml(i|j, t*) probabilities\n");
    PrintVectorProbs(stdout, pair5prob_star->pml, L5);
    fprintf(stdout, "Pair5 pmr(i|j, t*) probabilities\n");
    PrintVectorProbs(stdout, pair5prob_star->pmr, L5);
  }

  /* allocate structure pair5prob[5x5]
   */
  AllocNonSubsProbs(L5, &pair5prob);

  /* fill structure mutpxy
   */
  pair5prob->time = tfactor;

  /* Initialize by copyint everything over the pair5prob structure
   */
  CopyMatrix(pair5prob->P,        pair5prob_star->P,        L5, L5);
  CopyMatrix(pair5prob->Ql,       pair5prob_star->Ql,       L5, L5);
  CopyMatrix(pair5prob->Qr,       pair5prob_star->Qr,       L5, L5);
  CopyMatrix(pair5prob->Ratel,    pair5prob_star->Ratel,    L5, L5);
  CopyMatrix(pair5prob->Rater,    pair5prob_star->Rater,    L5, L5);
  CopyMatrix(pair5prob->Qlnought, pair5prob_star->Qlnought, L5, L5);
  CopyMatrix(pair5prob->Qrnought, pair5prob_star->Qrnought, L5, L5);

  CopyVector(pair5prob->pml, pair5prob_star->pml, L5);
  CopyVector(pair5prob->pmr, pair5prob_star->pmr, L5);

  /* Change Background freqs if we are asked to 
   */
  if (changefreq) EvolChangeFreqPair5Probs(pair5prob, targetfreq, pedantic, verbose);

  /* Calculate conditional Probs
   *
   *          pair5prob->Q = pair5prob->Qnought * exp{ pair5prob->time * pair5prob->Rate }
   *
   */
  ConditionalsFromRate(pair5prob->Ql, pair5prob->Ratel, pair5prob->Qlnought, tfactor, L5, pedantic, verbose);
  ConditionalsFromRate(pair5prob->Qr, pair5prob->Rater, pair5prob->Qrnought, tfactor, L5, pedantic, verbose);

  /* because the process involves indels, we have to evolve the marginal probabilities too
   * in the "quasi-reversible" manner
   *
   *          pm(t) = [ \pi(i)(1-\Lambda(t)), \Lambda(t) ] i = 1,...,4
   *
   *          where 
   *               pm^*     = [ \pi(i)(1-\Lambda^*    ), \Lambda^*     ] i = 1,...,4
   *
   *               pm^infty = [ \pi(i)(1-\Lambda^infty), \Lambda^infty ] i = 1,...,4 // calculated from R and Qnought
   *
   *          \Lambda(t) evolved by conserving reversability
   */ 
  EvolveIndelMarginalsByReversability(stdout, pair5prob->Ql, pair5prob->pml, L5, FALSE, verbose);
  EvolveIndelMarginalsByReversability(stdout, pair5prob->Qr, pair5prob->pmr, L5, FALSE, verbose);

  /* FINALLY, Evolve Joint probs pair5prob->P
   *
   *          pair5prob->P = pair5prob->Q * pair5prob->pm
   */
  Joint_From_Condi(stdout, pair5prob->P, pair5prob->Ql, pair5prob->pml, L5, verbose);

  /* Calculate Conditionals and Marginals */
  ComputeLRConditionalsAndMarginals(stdout, pair5prob->P, pair5prob->Ql, pair5prob->Qr, 
				    pair5prob->pml,  pair5prob->pmr, pair5prob->L, TRUE, verbose);

  if (verbose) {
    fprintf(stdout, "\nPair5(i,j, t=%.6f) Joint probabilities\n", pair5prob->time);
    PrintProbs(stdout, pair5prob->P, L5);
    fprintf(stdout, "Ql5(i,j, t=%.6f) Conditional probabilities\n", pair5prob->time);
    PrintProbs(stdout, pair5prob->Ql, L5);
    fprintf(stdout, "Qr5(i,j, t=%.6f) Conditional probabilities\n", pair5prob->time);
    PrintProbs(stdout, pair5prob->Qr, L5);
    fprintf(stdout, "L-marg probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pml, L5);
    fprintf(stdout, "R-marg probabilities\n");
    PrintVectorProbs(stdout, pair5prob->pmr, L5);
 }

  *ret_pair5prob = pair5prob;

}

/* Function: EvolRIBOProbs()
 * Date:     ER, Thu May 20 10:00:11 CDT 2004 [St. Louis, at home with Coro]
 *
 * Purpose:  given a rate matrix for riboprob[16x16],
 *           calculate the probabilities riboprob[16x16] at time "time".
 *
 * Args:    
 *
 * Returns:  (void)
 *           Fills in struct psubs_s riboprob
 */
void
EvolRIBOProbs(struct psubs_s *riboprob_star, double tfactor, struct psubs_s **ret_riboprob, 
	      double *targetfreq, int changefreq, int pedantic, int verbose)
{
  struct psubs_s    *riboprob;
  struct pnonsubs_s *ribomutcond;
  struct pnonsubs_s *pairtarget;
  double            *pp;
  int                L;
  int                LH;
  int                i;
  int                xl, xr, yl, yr;
  int                idxm, idxp;
  int                lmut, rmut;
  int                xpair, ypair;
  int                islog;
 
  L  = riboprob_star->L;
  LH = sqrt(L);

  if (verbose) {
    fprintf(stdout, "RIBO(i,j, t*) probabilities\n");
    PrintProbs(stdout, riboprob_star->P, L);
    EvolCalculateRIBOProbsCummulative(stdout, riboprob_star->L, riboprob_star->P, FALSE);
    fprintf(stdout, "RIBO(i,j, t*) Conditional probabilities\n");
    PrintProbs(stdout, riboprob_star->Q, L);
    fprintf(stdout, "RIBO(i,j, t*) marginal probabilities\n");
    PrintProbs(stdout, riboprob_star->pm, LH);

    fprintf(stdout, "Rate matrix\n");
    PrintProbs(stdout, riboprob_star->Rate, L);
  }
  
  /* allocate structure riboprob[16x16]
   */
  AllocSubsProbs(L, &riboprob);

  /* fill structure ribprob
   */
  riboprob->time = tfactor;

  /* The Rate and Qnought matrices are the same
   */
  CopyMatrix(riboprob->Rate,    riboprob_star->Rate,    L, L);
  CopyMatrix(riboprob->Qnought, riboprob_star->Qnought, L, L);

  /* The marginal probabilites are also the same, 
   */
  CopyVector(riboprob->pm, riboprob_star->pm, L);

  if (changefreq) {

    if (verbose) {
      fprintf(stdout, "Target marginals probabilities\n");
      PrintVectorProbs(stdout, targetfreq, LH);
    }
    CheckSingleProb(targetfreq, LH); /* paranoia */
    
    /* calculate the targetpair frequencies */
    AllocNonSubsProbs(LH, &pairtarget);
    pairtarget->time = riboprob_star->time;

    CopyMatrix(pairtarget->P, riboprob_star->pm, LH, LH);
    DExp2(pairtarget->P, L);
    CheckSingleProb(pairtarget->P, L); /* paranoia */
    if (verbose) {
      fprintf(stdout, "PAIR marginals probabilities\n");
      PrintProbs(stdout, pairtarget->P, LH);
    }
    ComputeLRConditionalsAndMarginals(stdout, pairtarget->P, pairtarget->Ql, pairtarget->Qr, 
				      pairtarget->pml,  pairtarget->pmr, pairtarget->L, FALSE, verbose);

    EvolChangePairProbsNaive(stdout, pairtarget, targetfreq, FALSE, verbose);

    if (verbose) {
      fprintf(stdout, "Target frequencies\n");
      PrintVectorProbs(stdout, targetfreq, LH);
      fprintf(stdout, "Target Pair  frequencies\n");
      PrintProbs(stdout, pairtarget->P, LH);
      fprintf(stdout, "Target Pair  marginals frequencies\n");
      PrintVectorProbs(stdout, pairtarget->pml, LH);
      PrintVectorProbs(stdout, pairtarget->pmr, LH);
    }

    /* modify the rate matrix accordingly */
    EvolChangeRIBORate(stdout, riboprob, pairtarget, verbose);

    FreeNonSubsProbs(pairtarget);
  }

  /* Evolve Joint probs mutpxy->P
   *
   *          riboprob->Q = riboprob->Qnought * exp{ riboprob->time * riboprob->Rate }
   *
   *          riboprob->P = riboprob->Q * riboprob->pm
   */
  
   /* calculate Qp = Q_0 * exp{tfactor*K}
   */
  ConditionalsFromRate(riboprob->Q, riboprob->Rate, riboprob->Qnought, tfactor, L, pedantic, verbose);

  /* paranoia
   */
  for (i = 0; i < L; i++)
    CheckSingleProb(riboprob->Q+i*L, L);

  /* 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) * L * L);
  DExp2(riboprob->pm, L);
  Joint_From_Condi(stdout, pp, riboprob->Q, riboprob->pm, L, verbose);

  /* change the coordinate system and put in log2 form */
  for (xl = 0; xl < LH; xl++)
    for (yl = 0; yl < LH; yl++)
      for (xr = 0; xr < LH; xr++)
	for (yr = 0; yr < LH; yr++)
	  {
	    xpair = xl*LH + xr;
	    ypair = yl*LH + yr;

	    lmut = xl*LH + yl;
	    rmut = xr*LH + yr;
	  
	    idxm  = lmut  * L + rmut;
	    idxp  = xpair * L + ypair;
	    
	    riboprob->P[idxm] = LOG2(pp[idxp]);
	  }
  /* paranoia
   */
  CheckSingleLog2Prob(riboprob->P, L*L);
  
  /* Calculate PairConditionals, and PairMarginals
   */
  EvolCalculateRIBOPairConditionalsAndMarginals(stdout, riboprob, verbose);
  
  if (verbose) EvolCalculateRIBOTargetError(targetfreq, riboprob, verbose);

  if (verbose) {
    fprintf(stdout, "pp(i,j, t=%.6f) Joint probabilities\n", tfactor);
    PrintProbs(stdout, pp, L);
    fprintf(stdout, "PRIBO(i,j, t=%.6f) Joint probabilities\n", tfactor);
    PrintProbs(stdout, riboprob->P, L);
    fprintf(stdout, "QPairRIBO(i,j, t=%.6f) Conditional probabilities\n", tfactor);
    DExp2(riboprob->Q, L*L);
    PrintProbs(stdout, riboprob->Q, L);
    DLog2(riboprob->Q, L*L);
    fprintf(stdout, "RIBOPairmarg probabilities\n");
    PrintProbs(stdout, riboprob->pm, LH);

    /* calculate Mutation Conditionals and Marginals */
    islog = TRUE;
    ribomutcond = EvolComputeRIBOMutConditionalsAndMarginals(stdout, riboprob, islog, verbose);
    FreeNonSubsProbs(ribomutcond);
  }
  
  *ret_riboprob = riboprob;
 
 free(pp);
}

/* Function: EvolRIBO5Probs_OldMethod()
 *
 * Date:     ER, Mon Jul  5 12:05:51 CDT 2004  [St. Louis at work, Coro with  Maribel]
 *           
 *
 * Purpose:  Given a set of  16x16 riboprob probabilities calculate the gapped 25x25 ribo5prob
 #
 *           Calculate conditional probabilities from a RIBOPROB matrix of joint 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
 *                                                                   qq  P(xl-xr)          P (yl-yr)
 *                                                                 1/2 ----------  + 1/2 ---------
 *                                                                     P(xl)P(xr)        P(yl)P(yr)
 *
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
EvolRIBO5Probs_OldMethod(struct psubs_s *riboprob_star, struct psubs_s *mut5pxy, struct pnonsubs_s *pair5prob, 
			 struct psubs_s **ret_ribo5prob, int verbose)
{
  struct psubs_s    *ribo5prob_MU;
  struct pnonsubs_s *ribo5prob_PU;
  struct psubs_s    *ribo5prob;
  struct pnonsubs_s *ribo5mutcond;
  double          ppx;
  double          ppx_mut;
  double          ppx_pair_a;
  double          ppx_pair_b;
  double          ppx_pair;
  double          ppxadd_mut, ppxadd_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;

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

  L5   = mut5pxy->L;
  L5SQ = L5 * L5;
 
  if (verbose) {
    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);
  }

  /* Calculate the "evolved" 
   *                PU (pair uncorrelated) and MU (Mutational uncorrelated) Joint and conditionals
   *
   */
  EvolCalculateRIBO5MutUncorrelated (stdout, riboprob_star, mut5pxy, pair5prob, &ribo5prob_MU, verbose);
  EvolCalculateRIBO5PairUncorrelated(stdout, riboprob_star, mut5pxy, pair5prob, &ribo5prob_PU, verbose);

  /* Use the PU and MU to generate the P(25x25) evolved probabilities
   */
  EvolCombineRIBO5Probs_OldMethod(ribo5prob_MU, ribo5prob_PU, mut5pxy, pair5prob, &ribo5prob, verbose);


  *ret_ribo5prob = ribo5prob;

  FreeSubsProbs(ribo5prob_MU);
  FreeNonSubsProbs(ribo5prob_PU);

}

void 
FreeSubsProbs(struct psubs_s *psubs)
{
  free(psubs->P);
  free(psubs->Q);
  free(psubs->pm);
  free(psubs->Qnought);
  free(psubs->Rate);

  free(psubs); 
}

void 
FreeNonSubsProbs(struct pnonsubs_s *pnonsubs)
{
  free(pnonsubs->P);
  free(pnonsubs->Ql);
  free(pnonsubs->Qr);
  free(pnonsubs->pml);
  free(pnonsubs->pmr);
  free(pnonsubs->Qlnought);
  free(pnonsubs->Qrnought);
  free(pnonsubs->Ratel);
  free(pnonsubs->Rater);

  free(pnonsubs); 
}

/* Function: RescaleMutRate()
 * Date:     ER, Tue Aug  3 13:31:25 CDT 2004 [St. Louis, Coro with Maribel]
 *
 * Purpose:  given a rate matrix  rescale so it has in average the same
 *           number of substitution per site than a given rate matrix
 *
 * Args:    
 *
 * Returns:  (void)
 *           
 */
double 
RescaleMutRate(FILE *ofp, int L, double *scaleRate, double *Rate, int hasindel, int verbose)
{
  double scale;
  double time;
  double target_subs = 0.0;
  double subs = 0.0;
  double sum = 0.0;
  int    dim;
  int    i, j;

  if (hasindel) dim = L-1;
  else          dim = L;

  for (i = 0; i < dim; i ++) {
    target_subs -= Rate[i*L+i];
    subs        -= scaleRate[i*L+i];
  }

  if (verbose) {
    fprintf(stdout, "\nTarget Rate matrix, average subs persite = %f \n", target_subs/dim);
    PrintProbs(stdout, Rate, L);
    fprintf(stdout, "Rate matrix to scale, current subs persite = %f \n", subs/dim);
    PrintProbs(stdout, scaleRate, L);
  }

  if (subs > 0.0) scale = target_subs / subs;
  else Die("RescaleMutRate(): cannot rescale this rate matrix. Scaling factor = %f\n", scale);
  
  /* Rescale 
   */
  for (i = 0; i < L; i ++) 
    for (j = 0; j < L; j ++) 
      scaleRate[i*L+j] *= scale;
  
  subs = 0.0;
  for (i = 0; i < dim; i ++) subs -= scaleRate[i*L+i];

  if (scale > 0.0) time = 1.0/scale;
  else Die("RescaleMutRate(): cannot rescale this rate matrix\n");

  /* Chech that each row adds up to one
   */
   for (i = 0; i < L; i++) {
    sum = 0.0;
    for (j = 0; j < L; j++)
      sum += scaleRate[i*L+j];
    if (sum > MARGIN || sum < -MARGIN) Die("RescaleMutRate(): column %d bad Rate matrix (sum = %f)\n", i, sum);
  }
 
  if (verbose) {
    fprintf(stdout, "Rescaled Rate matrix, current subs persite = %f ; scaling factor = %f; time = %f\n", subs/dim, scale, time);
    PrintProbs(stdout, scaleRate, L);
  }

  return time;
}


/* Function: RescaleCalculateRIBOScale()
 * Date:     ER, TThu Jan 13 15:26:36 CST 2005 [St. Louis, Coro with Nikki ant Tom]
 *
 * Purpose:    we know how to rescale the 4x4 rate, but not the 16X16, the scale
 *             has been determined nuemrically so that 
 *             the rate of the mutational marginals has "target_subs" subs per site.
 *
 *
 * Args:    
 *
 * Returns:  double scale
 *           
 */
double
RescaleCalculateRIBOScale(FILE *ofp, double target_subs, struct psubs_s *riboprob, int verbose)
{
  struct psubs_s *scaled_riboprob;
  double          scale;
  double          ribo_subs;
  double          ribo_subs_new;
  double          ribo_marg_subs;
  double          ribo_marg_subs_new;
  double          factor = 0.88;
  double          diff;
  int             L;

  L = riboprob->L;

  AllocSubsProbs(L, &scaled_riboprob);
  CopyMatrix(scaled_riboprob->Rate, riboprob->Rate, L, L);
  CopyVector(scaled_riboprob->pm,   riboprob->pm,   L);

  if ( (ribo_subs = SubsPerSite(ofp, L, scaled_riboprob->Rate, scaled_riboprob->pm, verbose)) > 0.0);
  else Die("RescaleCalculateRIBOScale(): cannot rescale this rate matrix. ribo_subs = %f\n", ribo_subs);
  if ((ribo_marg_subs = RIBOMutSubsperSite (ofp, scaled_riboprob, verbose)) > 0.0);
  else Die("RescaleCalculateRIBOScale(): cannot rescale this rate matrix. ribo_marg_subs = %f\n", ribo_marg_subs);

  if (verbose) {
    fprintf(ofp, "\nTarget Mut Rate matrix, average subs persite = %f \n", target_subs);
    fprintf(ofp, "RIBO Rate matrix, average subs persite = %f \n", ribo_subs);
    fprintf(ofp, "RIBO MARG Rate matrix, average subs persite = %f \n", ribo_marg_subs);
  }
 
  while (fabs(ribo_marg_subs_new - target_subs) > MARGIN) {
    scale = target_subs * (factor*ribo_subs / ribo_marg_subs) / ribo_marg_subs;

    MultiplyMatrix(scale, L, scaled_riboprob->Rate);
    if ( (ribo_subs_new = SubsPerSite(ofp, L, scaled_riboprob->Rate, scaled_riboprob->pm, verbose)) > 0.0);
    else Die("RescaleCalculateRIBOScale(): cannot rescale this rate matrix. ribo_subs = %f\n", ribo_subs_new);
    if ((ribo_marg_subs_new = RIBOMutSubsperSite (ofp, scaled_riboprob, verbose)) > 0.0);
    else Die("RescaleCalculateRIBOScale(): cannot rescale this rate matrix. ribo_marg_subs = %f\n", ribo_marg_subs_new);

    diff = ribo_marg_subs_new - target_subs;

    if (verbose) {
      fprintf(ofp, "\nfactor = %f \n", factor);
      fprintf(ofp, "scale = %f \n", scale);
      fprintf(ofp, "RIBO Rate matrix, average subs persite = %f \n", ribo_subs_new);
      fprintf(ofp, "RIBO MARG Rate matrix, average subs persite = %f diff = %f\n", ribo_marg_subs_new, diff);
    }
    
    CopyMatrix(scaled_riboprob->Rate, riboprob->Rate, L, L);
    CopyVector(scaled_riboprob->pm,   riboprob->pm,   L);

    factor -= diff;
  }

  FreeSubsProbs(scaled_riboprob);

  return scale;
}

/* Function: RescaleRIBORate()
 * Date:     ER, Tue Aug  3 13:31:25 CDT 2004 [St. Louis, Coro with Maribel]
 *
 * Purpose:  given a rate matrix  rescale so it has in average the same
 *           number of substitution per site than a given rate matrix
 *
 * Args:    
 *
 * Returns:  (void)
 *           
 */
double 
RescaleRIBORate(FILE *ofp, struct psubs_s *riboprob, struct psubs_s *mutpxy, int verbose)
{
  double             scale;
  double             time;
  double             target_subs;
  double             ribo_subs;
  double             ribo_marg_subs;
  double             ribo_ave_subs;
  int                L;
  int                Lh;
  int                i, j;
  int                xl, xr, yl, yr;
  int                islog;

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

  target_subs =  SubsPerSite(ofp, Lh, mutpxy->Rate, mutpxy->pm, verbose);
  if (verbose) {
    fprintf(stdout, "\nTarget Mut Rate matrix, average subs persite = %f \n", target_subs);
    PrintProbs(stdout, mutpxy->Rate, Lh);
  }

  DExp2(riboprob->pm, riboprob->L);
  ribo_subs = SubsPerSite(ofp, L, riboprob->Rate, riboprob->pm, verbose);
  if (verbose) fprintf(stdout, "\nRIBO Rate matrix, average subs persite = %f \n", ribo_subs);
  if (verbose) {
    fprintf(stdout, "\nRIBO Rate matrix, average subs persite = %f \n", ribo_subs);
    PrintProbs(stdout, riboprob->Rate, L);
  }

  /* Here I average the RIBO rate into a 4x4 rate. This is not the correct
   * way of rescaling the RIBO rate matrix
   */
  ribo_ave_subs = RIBOAverageSubsperSite (ofp, riboprob, verbose);
  if (verbose) fprintf(stdout, "\nRIBO AVE Rate matrix, average subs persite = %f \n", ribo_ave_subs);

  /* The rate matrix that has to match the substitutions per site of the MutRate
   * is the mut marginal of the RIBO rate
   */
  ribo_marg_subs = RIBOMutSubsperSite (ofp, riboprob, verbose);
  if (verbose) fprintf(stdout, "\nRIBO MARG Rate matrix, average subs persite = %f \n", ribo_marg_subs);

  /* We rescale 
   * 
   * we know how to rescale the 4x4 rate, but not the 16X16, the scale
   * has been determined nuemrically so that the rate of the mutational marginals has 1.1213 subs per site.
   * 
   */
  scale = RescaleCalculateRIBOScale(ofp, target_subs, riboprob, verbose);

  MultiplyMatrix(scale, L, riboprob->Rate);

  if (scale > 0.0) 
    {
      time = 1.0/scale;
      
      if (verbose)  fprintf(stdout, "\ntime = %f scaling factor = 1/time=%f\n", time, scale);
    }
  else 
    Die("RescaleRIBORate(): cannot rescale this rate matrix\n");
  
  if (verbose) {
    fprintf(stdout, "\nRescaled Rate matrix, time = %f scaleRate = 1/time=%f\n", time, scale);
    PrintProbs(stdout, riboprob->Rate, L);
  }

  /* check the average number of substitutions per site, after rescaling of the rate
   */
  if (verbose) {
    ribo_subs = SubsPerSite(ofp, L, riboprob->Rate, riboprob->pm, verbose);
    if (verbose) fprintf(stdout, "\nNEW*RIBO Rate matrix, average subs persite = %f \n", ribo_subs);
  } 
  if (verbose) {
    ribo_ave_subs = RIBOAverageSubsperSite (ofp, riboprob, verbose);
    if (verbose) fprintf(stdout, "\nNEW*RIBO AVE Rate matrix, average subs persite = %f \n", ribo_ave_subs);
  }   
  
  ribo_marg_subs = RIBOMutSubsperSite (ofp, riboprob, verbose);
  
  if (fabs(ribo_marg_subs - target_subs) > MARGIN) 
    Die ("RescaleRIBORate(): You may be using a different RIBO joint. bad rescaling of the RIBO rate matrix target=%f real=%f", 
	 target_subs, ribo_marg_subs);

  if (verbose) fprintf(stdout, "\nNEW*RIBO MARG Rate matrix, average subs persite = %f \n", ribo_marg_subs);
  

  DLog2(riboprob->pm, riboprob->L);

  return time;
}

double
RIBOAverageSubsperSite (FILE *ofp, struct psubs_s *riboprob, int verbose)
{
  double *rate;
  double *pm;
  double  subspersite = 0.0;
  int     L;
  int     Lh;
  int     i, j;
  int     xl, xr, yl, yr;

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

  /*allocate memory */
  rate = (double *) MallocOrDie(sizeof(double) * L);
  pm   = (double *) MallocOrDie(sizeof(double) * Lh);
  for (i = 0; i < L; i++)  rate[i] = 0.0;
  for (i = 0; i < Lh; i++) pm[i]   = 0.0;
  
  for (i = 0; i < L; i++) {
    xl = i/Lh;
    pm[xl] += riboprob->pm[i];
  }

  for (i = 0; i < L; i++) 
    for (j = 0; j < L; j++) {
      xl = i/Lh;
      xr = i%Lh;
      yl = j/Lh;
      yr = j%Lh;
    
    rate[xl*Lh+yl] += riboprob->pm[xr*L+yr] * riboprob->Rate[i*L+j];
    rate[xr*Lh+yr] += riboprob->pm[xl*L+yl] * riboprob->Rate[i*L+j];
  }
  subspersite = SubsPerSite(ofp, Lh, rate, pm, verbose);

  if (verbose) {
    fprintf(stdout, "AVE Rate matrix, ave subs per site = %f\n", subspersite);
    PrintProbs(stdout, rate, Lh);
  }
  
  free(pm);
  free(rate);

  return subspersite;
}

double
RIBOMutSubsperSite (FILE *ofp, struct psubs_s *ribo, int verbose)
{
  struct pnonsubs_s *ribomutcond;
  struct psubs_s    *riboprob;
  struct psubs_s    *ribomut;
  double             subspersite = 0.0;
  int                L;
  int                Lh;
  int                islog;
  int                i;

  L = ribo->L;
  Lh = sqrt(L);

  /* allocate memory */
  AllocNonSubsProbs(L, &ribomutcond);
  AllocSubsProbs(L,    &riboprob);
  AllocSubsProbs(Lh,   &ribomut);

  /* fill structure ribprob
   */
  riboprob->time = 1.0;

  /* Copy the Rate matrices 
   */
  CopyMatrix(riboprob->Rate, ribo->Rate, L, L);

  /* Qnought is the identity */
  Comp_Id(riboprob->Qnought, riboprob->L);

  ConditionalsFromRate(riboprob->Q, riboprob->Rate, riboprob->Qnought, riboprob->time, riboprob->L, FALSE, verbose);
  if (verbose) {
    fprintf(stdout, "\nConditionals From Rate \n");
    PrintProbs(ofp, riboprob->Q, L);
  }
 
  ComputeSaturationProbs(riboprob->Rate, riboprob->Qnought, riboprob->pm, L, FALSE, verbose);
  if (verbose) {
    fprintf(stdout, "\nMarginals From Rate \n");
    PrintProbs(ofp, riboprob->pm, Lh);
  }

  RIBOJoint_From_Condi(ofp, riboprob->P, riboprob->Q, riboprob->pm, L, verbose);
  DLog2(riboprob->P, riboprob->L*riboprob->L);
  if (verbose) {
    fprintf(stdout, "\nJoint From Rate \n");
    PrintProbs(ofp, riboprob->P, L);
  }

  /* calculate Mutation Conditionals and Marginals */
  islog = TRUE;
  ribomutcond = EvolComputeRIBOMutConditionalsAndMarginals(stdout, riboprob, islog, verbose);
 
  /* symmtrize the mutational marginals */
  if (verbose) {
    fprintf(stdout, "\nribomut MARG\n");
    PrintProbs(stdout, ribomutcond->pml, Lh);
    PrintProbs(stdout, ribomutcond->pmr, Lh);
  }
  for (i = 0; i < L; i ++)
    ribomut->P[i] = 0.5 * (EXP2(ribomutcond->pml[i]) + EXP2(ribomutcond->pmr[i]));
  CheckSingleProb(ribomut->P, L);
  if (verbose) {
    fprintf(stdout, "\nribomut MARG  symm\n");
    PrintProbs(stdout, ribomut->P, Lh);
  }

  ComputeConditionalsAndMarginals(ofp, ribomut->P, ribomut->Q, ribomut->pm, Lh, FALSE, verbose);

  Comp_Id(ribomut->Qnought, ribomut->L);

  /* calculate the mut rate matrix */
  RateFromConditionals(stdout, ribomut->Rate, ribomut->Q, ribomut->Qnought, Lh, 1.0, FALSE, TRUE, verbose);

  subspersite = SubsPerSite(ofp, Lh, ribomut->Rate, ribomut->pm, verbose);
  if (verbose) {
    fprintf(stdout, "\nRIBO MARG Mut Rate matrix, average subs persite = %f \n", subspersite);
    PrintProbs(stdout, ribomut->Rate, ribomut->L);
  }

  FreeNonSubsProbs(ribomutcond);
  FreeSubsProbs(riboprob);
  FreeSubsProbs(ribomut);

  return subspersite;
}

double 
SubsPerSite(FILE *ofp, int L, double *Rate, double *pm, int verbose)
{
  double subs = 0.0;
  int    i;
  
  for (i = 0; i < L; i ++) subs -= pm[i]*Rate[i*L+i];
  
  return subs;
}


void
estimate_rna_indels (struct psubs_s *mutpxy_rna_star, struct psubs_s *mut5pxy_star, 
		     double *ret_indel, double *ret_indel2indel, int verbose)
{
  double indel;
  double indel2indel;
  double scale;
  double target_subs;
  double subs;
  int    L;
  int    dim;

  L   = mut5pxy_star->L;
  dim = mutpxy_rna_star->L;
  
  /* Estimate the indel and indel2indel parameters 
   * so that once rescaled they put about the same number of gaps
   */
  target_subs =  SubsPerSite(stdout, L,   mut5pxy_star->Rate,    mut5pxy_star->pm,    verbose);
  subs        =  SubsPerSite(stdout, dim, mutpxy_rna_star->Rate, mutpxy_rna_star->pm, verbose);
  
  if (verbose) {
    fprintf(stdout, "\nmutpxy_rna Rate matrix, average subs persite = %f \n", subs);
    PrintProbs(stdout, mutpxy_rna_star->Rate, dim);
    fprintf(stdout, "\nmut5pxy Rate matrix, average subs persite = %f \n", target_subs);
    PrintProbs(stdout, mut5pxy_star->Rate, L);
  }

  if (subs > 0.0) scale = target_subs / subs;
  else Die("mut5pxy_rna_conditionals_at_zero(): Wrong Scaling factor = %f\n", scale);
  
  indel = INDL;
  if (scale > 0.0) indel /= scale;
  else Die ("mut5pxy_rna_conditionals_at_zero(): Bad scaling");

  /* Calculate delta^prime = delta^2/(1-delta^2)
   */
  indel2indel = DeltaPrimeFromDelta (indel);

  if (verbose) 
    printf("scaling = %f \nindel = %f indel2indel = %f\n", scale, indel, indel2indel);

  *ret_indel       = indel;
  *ret_indel2indel = indel2indel;
  
}

void
estimate_rna_loop_indels (struct psubs_s *mutpxy_rna_star, struct psubs_s *mut5pxy_star, 
			  double *ret_indel, double *ret_indel2indel, int verbose)
{
  double indel;
  double indel2indel;
  double scale;
  double target_subs;
  double subs;
  int    L;
  int    dim;

  L   = mut5pxy_star->L;
  dim = mutpxy_rna_star->L;
  
  /* Estimate the indel and indel2indel parameters 
   * so that once rescaled they put about the same number of gaps
   */
  target_subs =  SubsPerSite(stdout, L,   mut5pxy_star->Rate,    mut5pxy_star->pm,    verbose);
  subs        =  SubsPerSite(stdout, dim, mutpxy_rna_star->Rate, mutpxy_rna_star->pm, verbose);
  
  if (verbose) {
    fprintf(stdout, "\nmutpxy_rna Rate matrix, average subs persite = %f \n", subs);
    PrintProbs(stdout, mutpxy_rna_star->Rate, dim);
    fprintf(stdout, "\nmut5pxy Rate matrix, average subs persite = %f \n", target_subs);
    PrintProbs(stdout, mut5pxy_star->Rate, L);
  }

  if (subs > 0.0) scale = target_subs / subs;
  else Die("mut5pxy_rna_conditionals_at_zero(): Wrong Scaling factor = %f\n", scale);
  
  indel = INDL_LOOP;
  if (scale > 0.0) indel /= scale;
  else Die ("mut5pxy_rna_conditionals_at_zero(): Bad scaling");

  /* Calculate delta^prime = delta^2/(1-delta^2)
   */
  indel2indel = DeltaPrimeFromDelta (indel);

  if (verbose) 
    printf("scaling = %f \nindel = %f indel2indel = %f\n", scale, indel, indel2indel);

  *ret_indel       = indel;
  *ret_indel2indel = indel2indel;
  
}

void
mut5pxy_conditionals_at_zero (struct psubs_s *mut5pxy_star, double indel, double indel2indel, double lambda_infty, int verbose)
{
  double *psingle_zero;
  double *psingle_infty;
  double  q_0;
  int     L;
  int     L5;
  int     LSQ;
  int     L5SQ;
  int     i;

  L5 = mut5pxy_star->L;

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

  /* the relationship between lambda_infty and q_0 is: */
  if (lambda_infty == 0.0) q_0 = 1.0; /* no evolution of gaps */
  else {
    if (fabs(lambda_infty) > 0.0) q_0 = (1.0/lambda_infty - 1.0) * indel - 1.0;
    if (fabs(q_0) > 0.0) q_0 = 1.0 / q_0;
    
    q_0 *= indel*(1.0+indel)/(indel+indel2indel) - 1.0;

    if (q_0 > 1.0) 
      Die("mut5pxy_conditionals_at_zero(): q_o is larger than one (indel=%f indel^2=%f indel2indel=%f q_0=%f)", 
	  indel, indel*indel, indel2indel, q_0);
    if (q_0 < 0.0) 
      Die("mut5pxy_conditionals_at_zero(): q_o is negative (indel=%f indel^2=%f indel2indel=%f q_0=%f)", 
	  indel, indel*indel, indel2indel, q_0);
  }
  if (verbose) printf("MUT5: Lambda_infty = %f indel = %f indel2indel = %f q_0 = %f\n", lambda_infty, indel, indel2indel, q_0);

  /*initialize */
  psingle_zero  = (double *) MallocOrDie (sizeof(double) * L);
  psingle_infty = (double *) MallocOrDie (sizeof(double) * L5);

  /* marginals at zero */
  for (i = 0; i < L; i++) 
    if (mut5pxy_star->pm[L] < 1.0) psingle_zero[i] = mut5pxy_star->pm[i] / (1.0-mut5pxy_star->pm[L]);
    else                           psingle_zero[i] = 0.0;
  if (verbose) {
    fprintf(stdout, "psingle(i, t=0.0) marginal probabilities\n");
    PrintVectorProbs(stdout, psingle_zero, L);
  }
  CheckSingleProb(psingle_zero, L);

  /* marginals at infty */
  psingle_infty[L] = lambda_infty;
  for (i = 0; i < L; i++) 
    psingle_infty[i] = psingle_zero[i] * (1.0-psingle_infty[L]);
  CheckSingleProb(psingle_infty, L5);
   

 /* Conditional at time zero are the identity except for the last row
   *
   */
  Comp_Id(mut5pxy_star->Qnought, mut5pxy_star->L);

  /* last row
   *
   *
   */
  /* the diagonal  */
  mut5pxy_star->Qnought[L*L5+L] = q_0;

  /* the off-diagonal  
   *
   */
  for (i = 0; i < L; i++) 
    mut5pxy_star->Qnought[L*L5+i] = psingle_zero[i] * (1.0 - mut5pxy_star->Qnought[L*L5+L]);
  
  /* check of consistency */
  for (i = 0; i < L5; i++) 
    CheckSingleProb(mut5pxy_star->Qnought + i*L5, L5);

  if (verbose) {
    fprintf(stdout, "Q(i|j, t=0.0) mut5pxy conditional probabilities\n");
    PrintProbs(stdout, mut5pxy_star->Qnought, mut5pxy_star->L);
    fprintf(stdout, "psingle(i, t=0.0) marginal probabilities\n");
    PrintVectorProbs(stdout, psingle_zero, L);
    fprintf(stdout, "psingle(i, t=infty marginal probabilities\n");
    PrintVectorProbs(stdout, psingle_infty, L5);
  }

  free(psingle_zero);
  free(psingle_infty);
}

void
pair5prob_conditionals_at_zero (struct pnonsubs_s *pairprob_star, struct pnonsubs_s *pair5prob_star, 
				double gap, double gap2gap, double lambda_infty, int verbose)
{
  double  q_0;
  int     L;
  int     L5;
  int     LSQ;
  int     L5SQ;
  int     i;

  L5 = pair5prob_star->L;

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

  /* the relationship between lambda_infty and q_0 is: */
  if (lambda_infty == 0.0) q_0 = 1.0; /* no evolution of gaps */
  else {
    if (fabs(lambda_infty) > 0.0) q_0 = (1.0/lambda_infty - 1.0) * gap - 1.0;

    if (fabs(q_0) > 0.0) q_0 = 1.0 / q_0;
    else                 Die ("q_o is singular");
    
    q_0 *= gap*(1.0+gap)/(gap+gap2gap) - 1.0;

    if (q_0 > 1.0) Die("pair5prob_conditionals_at_zero(): q_o is larger than one");
    if (q_0 < 0.0) Die("pair5prob_conditionals_at_zero(): q_o is negative");
  }
  if (verbose) printf("PAIR5: Lambda_infty = %f q_0 = %f\n", lambda_infty, q_0);

  /* Conditional pair5prob at time zero are infered from pair5probs at t* before adding gaps
   *
   */
  pair5prob_star->Qlnought = Condi_From_Joint (stdout, pair5prob_star->P, L5, verbose);
  pair5prob_star->Qrnought = CondiR_From_Joint(stdout, pair5prob_star->P, L5, verbose);

  /* the last row
   *
  /* the diagonal  */
  pair5prob_star->Qlnought[L*L5+L] = q_0;
  pair5prob_star->Qrnought[L*L5+L] = q_0;
  
  /* the off-diagonal 
   *
   * YES! this is right -- not a typo:
   *
   *    use the pr marginals for the Ql_0 matrix and the other way arround
   */
  for (i = 0; i < L; i++) {
    pair5prob_star->Qlnought[L*L5+i] = pairprob_star->pmr[i] * (1.0 - pair5prob_star->Qlnought[L*L5+L]);
    pair5prob_star->Qrnought[L*L5+i] = pairprob_star->pml[i] * (1.0 - pair5prob_star->Qrnought[L*L5+L]);
  }

  /* check of consistency */
  for (i = 0; i < L5; i++) CheckSingleProb(pair5prob_star->Qlnought+i*L5, L5);
  for (i = 0; i < L5; i++) CheckSingleProb(pair5prob_star->Qrnought+i*L5, L5);

 if (verbose) {
    fprintf(stdout, "Q(i|j, t=0.0) pair5probs L-conditional probabilities\n");
    PrintProbs(stdout, pair5prob_star->Qlnought, pair5prob_star->L);
    fprintf(stdout, "Q(i|j, t=0.0) R-conditional probabilities\n");
    PrintProbs(stdout, pair5prob_star->Qrnought, pair5prob_star->L);
    fprintf(stdout, "psingle(i, t=0.0) L-marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob_star->pml, L);
    fprintf(stdout, "psingle(i, t=0.0) R-marginal probabilities\n");
    PrintVectorProbs(stdout, pairprob_star->pmr, L);
  }
}
