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


/* riboprob.c
 * Functions to deal with the RIBOPROB matrices
 * ER,Tue Jan 28 17:48:54 CST 2003  [STL]
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <time.h>
#include <limits.h>
#include <float.h>

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

static void lone_MUT_cond  (int idx, int L, double *cond_mut_mtx,  double *mut5pxy, double *pair5prob, double *px, double *py);
static void lone_PAIR_cond (int idx, int L, double *cond_pair_mtx, double *mut5pxy, double *pair5prob, double *px, double *py);


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

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

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

  return fullmat;
} 

fullcondmat_t *
AllocFullCondMatrix (int L) {

  fullcondmat_t *fullcondmat;

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

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

  return fullcondmat;
} 

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

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

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

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

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

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

  return mat;
}

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

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


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

  dep_mut  = AllocCondMatrix(L2);
  dep_pair = AllocCondMatrix(L2);

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

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

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

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

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

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

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

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

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

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

     

  /* Check of Independence */
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) 
      for (yl = 0; yl < L; yl++) 
	for (yr = 0; yr < L; yr++) { 

	  
	  xpair = idx(xl,xr);
	  ypair = idx(yl,yr);

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

	  dep_mut->matrix[idxm] = cond_mut1->cond->matrix[idxm] - cond_mut1->marg->matrix[rmut];
	  dep_pair->matrix[idx] = cond_pair->cond->matrix[idx]  - cond_pair->marg->matrix[ypair];
	}
	 
  islog2 = TRUE;
  if (verbose) {
    PrintFullRIBOCondMatrix(fp, cond_mut1, FALSE, islog2);
    PrintFullRIBOCondMatrix(fp, cond_pair, TRUE,  islog2);
  }

  if (verbose) {
    PrintRIBOCondMatrix    (fp, dep_mut,   FALSE, TRUE, cond_mut1->name);
    PrintRIBOCondMatrix    (fp, dep_pair,  TRUE,  TRUE, cond_pair->name);
  }
  
  *ret_cond_mut  = cond_mut1;
  *ret_cond_pair = cond_pair;
  
  FreeFullCondMatrix(cond_mut2);
  FreeCondMatrix(dep_mut);
  FreeCondMatrix(dep_pair);
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

/* Function: CalculateRIBO5Conditionals_at_zero()
 * Date:     ER, Wed Jan 29 18:40:16 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  Calculate conditional probabilities from a RIBOPROB matrix of jont probs. add gaps
 *           
 *
 * Args:     
 *
 * Returns:  void
 *           
 */
void
CalculateRIBO5Conditionals_at_zero (FILE *fp, fullcondmat_t **ret_ribocond5_mut_nought, fullcondmat_t **ret_ribocond5_pair_nought, 
				    double *mut5pxy_nought, double *pair5prob_nought, double *px_nought, double *py_nought, int verbose)
{  
  fullcondmat_t *cond_mut_nought;
  fullcondmat_t *cond_pair_nought;
  int            L;
  int            L2;
  int            xl, xr;
  int            yl, yr;
  int            xpair, ypair;
  int            lmut, rmut;
  int            idxm, idxp;
  int            i;

  L  = 5;
  L2 = L * L;

  cond_mut_nought  = AllocFullCondMatrix(L);
  cond_pair_nought = AllocFullCondMatrix(L);

  snprintf (cond_mut_nought->name,  40, "%s", "COND5byMUTatZero");
  snprintf (cond_pair_nought->name, 40, "%s", "COND5byPAIRatZero");

  cond_mut_nought->marg->size  = L;
  cond_pair_nought->marg->size = L;

  cond_mut_nought->cond->size  = L2;
  cond_pair_nought->cond->size = L2;

                                  /* marginals asigned as pair5probs and mut5pxy*/ 
  for (xl = 0; xl < L; xl++) 
    for (yl = 0; yl < L; yl++) {
      lmut = idx5(xl,yl);
      cond_mut_nought->marg->matrix[lmut] = LOG2(mut5pxy_nought[lmut]);	    
      
    }
  for (xl = 0; xl < L; xl++) 
    for (xr = 0; xr < L; xr++) {
      xpair = idx5(xl,xr);
      cond_pair_nought->marg->matrix[xpair] = LOG2(pair5prob_nought[xpair]);	    
    }
  
  /* check the marginal probabilities */
  CheckSingleLog2Prob(cond_pair_nought->marg->matrix, L2);  
  CheckSingleLog2Prob(cond_mut_nought->marg->matrix,  L2);

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

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

	    /* Mutational Conditionals */
	    lone_MUT_cond(idxm, L2, &cond_mut_nought->cond->matrix[idxm], mut5pxy_nought, pair5prob_nought, px_nought, py_nought);
	    
	    /* Pair conditionals */
	    lone_PAIR_cond(idxp, L2, &cond_pair_nought->cond->matrix[idxp], mut5pxy_nought, pair5prob_nought, px_nought, py_nought);
    
	  }

   for (i = 0; i < L2; i++) {
    DLog2Norm (cond_mut_nought->cond->matrix  + i*L2, L2);
    DLog2Norm (cond_pair_nought->cond->matrix + i*L2, L2);
  }

 /* check the conditional probabilities */
  for (i = 0; i < L2; i++) {
    CheckSingleLog2Prob(cond_mut_nought->cond->matrix  + i*L2, L2);
  }
  for (i = 0; i < L2; i++) {
    CheckSingleLog2Prob(cond_pair_nought->cond->matrix + i*L2, L2);
  }

  if (verbose) {
    PrintFullRIBOCondMatrix(fp, cond_mut_nought,  FALSE, TRUE);
    PrintFullRIBOCondMatrix(fp, cond_pair_nought, TRUE,  TRUE);
  }


  *ret_ribocond5_mut_nought  = cond_mut_nought;
  *ret_ribocond5_pair_nought = cond_pair_nought;

}  


/* Function: CopyFullMatrix()
 * Date:     ER, Mon Jan 27 12:34:27 CST 2003 [St. Louis]
 *           
 *
 * Purpose:  copy fullmat_t structure 
 *
 * Args:     
 *
 * Returns:  fullmat_t structure
 *           fullmatcopy is allocated here
 */
fullmat_t *
CopyFullMatrix (fullmat_t *fullmat) 
{
  fullmat_t *fullmatcopy;
  
  fullmatcopy = AllocFullMatrix (fullmat->unpaired->edge_size);

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

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


  return fullmatcopy;
} 

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

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

  for (x = 0; x < mat->full_size; x++) 
    matcopy->matrix[x] = mat->matrix[x];
}

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

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

  if (TRUE) {
    PrintRIBOCondMatrix(stdout, ribo5cond_nought->cond,  ispair, FALSE, "ZERO");
    PrintRIBOCondMatrix(stdout, ribo5cond->cond,         ispair, FALSE, "STAR");
  }

  DExp2(ribo5cond->marg->matrix, L2);
  for (i = 0; i < L2; i++)
    DExp2(ribo5cond->cond->matrix + i*L2, L2);

  ConditionalsEvolved(stdout, ribo5cond->cond->matrix, ribo5cond_nought->cond->matrix, L2, tfactor, pedantic, verbose);

  DLog2(ribo5cond->marg->matrix, L2);
  for (i = 0; i < L2; i++)
    DLog2(ribo5cond->cond->matrix + i*L2, L2);
  
  if (TRUE) 
    PrintFullRIBOCondMatrix(stdout, ribo5cond,  FALSE, TRUE);

}

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

  free (fullmat->name);

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

void
FreeFullCondMatrix (fullcondmat_t *fullcondmat) {

  free (fullcondmat->name);

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

void
FreeMatrix (matrix_t *mat) {

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

void
FreeCondMatrix (condmatrix_t *mat) {

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


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

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

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

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

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

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

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

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



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

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

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

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

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

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

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

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


  return (fullmat);
}

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

  LSQRT = sqrt(L);

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

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

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

  xpair = xl * LSQRT + xr;
  ypair = yl * LSQRT + yr;

  cond_mut_mtx = LOG2(mut5pxy[rmut]);
  
  if (mut5pxy[rmut] > 0.0) {
    
    if (px[xl] > 0.0 && 
	px[xr] > 0.0 && 
	py[yl] > 0.0 && 
	py[yr] > 0.0  ) 
      cond_mut_mtx += 
	- 1.0
	+ LOG2( (pair5prob[xpair] / (px[xl] * px[xr])) + (pair5prob[ypair] / (py[yl] * py[yr])) );
    
    else if (px[xl] > 0.0 && 
	     px[xr] > 0.0  )  
    cond_mut_mtx += 
      + LOG2( pair5prob[xpair] / (px[xl] * px[xr]) );
    
    else if (py[yl] > 0.0 && 
	     py[yr] > 0.0  ) 
      cond_mut_mtx += 
	+ LOG2( pair5prob[ypair] / (py[yl] * py[yr]) );
    
  }
  
  *ret_cond_mut_mtx = cond_mut_mtx;
}

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

  LSQRT = sqrt(L);

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

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

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

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

  cond_pair_mtx = LOG2(pair5prob[ypair]);
  
  if (pair5prob[ypair] > 0.0) {
    
    if (mut5pxy[lmut] > 0.0 &&
	mut5pxy[rmut] > 0.0 &&
	px[xl] > 0.0 && 
	px[xr] > 0.0 && 
	py[yl] > 0.0 && 
	py[yr] > 0.0  ) 
      cond_pair_mtx +=
	- 1.0
	+ LOG2( (mut5pxy[lmut] / (px[xl] * py[yl])) + (mut5pxy[rmut] / (px[xr] * py[yr])));
    
    else if (mut5pxy[lmut] > 0.0 &&
	     px[xl] > 0.0 && 
	     py[yl] > 0.0  )
      cond_pair_mtx +=
	+ LOG2( mut5pxy[lmut] / (px[xl] * py[yl]) );
    
    else if (mut5pxy[rmut] > 0.0 &&
	     px[xr] > 0.0 &&
	     py[yr] > 0.0  )
      cond_pair_mtx +=
	+ LOG2( mut5pxy[rmut] / (px[xr] * py[yr]) );
  }
  
  *ret_cond_pair_mtx = cond_pair_mtx;
  
}
