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

/* rnascorealign.c
 *
 * ER, Wed Jun  2 09:46:02 CDT 1999[St. Louis]
 * 
 * score of a given alignment with the rnamodel
 * 
 * calculates:
 *             log2[P(seqX, seqY, \pi^{given} | rnamodel) /  P(seqX, seqY, \pi^{given} | nullmodel)]
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>

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

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

static double scorewithRNA_onepass(FILE *ofp, SQINFO sqinfoX, int *sX, SQINFO sqinfoY, int *sY, char *gss, int start, int L, 
				   struct model_s *model, struct othdpd_s *othdp, 
				   struct rnamtx_s *mtx, double *sc, double *vp,
				   int *ret_scfg_status, int cyk, int fastintloop, int logodds, int do_nus, int parse, int traceback);

/* Function: ScoreWithNUS_ungapped()
 * Date:     ER, Wed Jun  9 17:11:22 CDT 1999 [St. Louis]
 *
 * Purpose:  Score an ungapped sequence alignment with NUS model.
 *           Sums over all possible structures. Nussinov-like algorithm
 *
 */
double
ScoreWithNUS_ungapped(int *sX, int *sY, int L, struct nusmodel_s *nus, int traceback)
{
  double **mx;
  double *sc;
  double  totsc;
  int     idx;
  int     xi,xj,yi,yj;
  int     i,j,d,mid;

  /* Allocate a 0..L-1 square matrix.
   */
  mx = MallocOrDie(sizeof(double *) * L);
  for (j = 0; j < L; j++)
    mx[j] = MallocOrDie(sizeof(double) * L);
  sc = MallocOrDie(sizeof(double) * (L+3));

  for (j = 0; j < L; j++)
    for (d = 0; d <= j; d++)
      {
	i = j - d;
	xi = sX[i];
	yi = sY[i];
	xj = sX[j];
	yj = sY[j];

	/* Initialize diagonal and short subseqs 
	 * Enforce a minimum loop length of 4
	 */
	if (d == 0)
	  mx[j][0] = nus->tl + nus->p[idx(xi,yi)];
	else if (d < 4) 
	  mx[j][d] = mx[j][d-1] + nus->tl + nus->p[idx(xi,yi)];
	else {
	  /* Main recursion
	   */
	  
	  /* i left; connect to i+1, j; emit xi,yi */
	  idx = 0;
	  sc[idx] = mx[j][d-1] + nus->tl + nus->p[idx(xi,yi)];
	  idx++;
				/* j right; connect to i, j-1; emit xj,yj */
	  sc[idx] = mx[j-1][d-1] + nus->tr + nus->p[idx(xj,yj)];
	  idx++;
				/* i,j pair; connect to i+1,j-1; emit xy */
	  sc[idx] = mx[j-1][d-2] + nus->tv + nus->pp[idx(xi,yi)][idx(xj,yj)];
	  idx++;
				/* bifurcations */
	  for (mid = 0; mid < d; mid++)
	    {
	      sc[idx] = mx[j][mid] + mx[j-mid-1][d-mid-1] + nus->tw;
	      idx++;
	    }
				/* summation */
	  mx[j][d] = DLog2Sum(sc, idx);
	}
      }
 
  totsc = mx[L-1][L-1];
  Free2DArray(mx, L);
  free(sc);
  return totsc;
}



/* Function: ScoreWithRNA()
 * Date:     ER, Mon Oct  1 11:37:57 CDT 2001 [St. Louis]
 *
 * Purpose:  Score an ungapped sequence alignment with RNA model.
 *           Sums over all possible structures. Zuker-like algorithm
 *
 */
void
ScoreWithRNA(FILE *ofp, SQINFO sqinfoX, int *seqX, SQINFO sqinfoY, int *seqY, char *gss, int start, int L, 
	     struct model_s *model, struct othdpd_s *othdp, struct rnascfg_s *mx, struct sc2_s *rnasc,
	     int *ret_scfg_status, int *ret_scfgrv_status, int cyk, int fastintloop, int logodds, int do_nus, int ones, int parse, int traceback)
{
  int *reqX, *reqY;                /* reverse complements */

  rnasc->pl = scorewithRNA_onepass(ofp, sqinfoX, seqX, sqinfoY, seqY, gss, start, L, model, othdp,
				   mx->in, mx->sc, mx->vp, 
				   ret_scfg_status, cyk, fastintloop, logodds, do_nus, parse, traceback);
  
 /* revcomp */
  reqX = (int *) MallocOrDie(sizeof(int) * L);
  reqY = (int *) MallocOrDie(sizeof(int) * L);
  RevComp(reqX, seqX+start, L);
  RevComp(reqY, seqY+start, L);

  if (!ones) {
    if (sqinfoX.flags & SQINFO_SS) gss = RevSS(gss+start, L);
    
    rnasc->mn = scorewithRNA_onepass(ofp, sqinfoX, reqX, sqinfoY, reqY, gss, start, L, model, othdp,
				     mx->inrv, mx->sc, mx->vp, 
				     ret_scfgrv_status, cyk, fastintloop, logodds, do_nus, parse, traceback);

    free(reqX);
    free(reqY);
  }
  else  rnasc->mn = 0.0;

}

/* Function: ScoreWithRNA()
 * Date:     ER, Wed Jun  9 17:11:22 CDT 1999 [St. Louis]
 *
 * Purpose:  Score an ungapped sequence alignment with RNA model.
 *           Sums over all possible structures. Zuker-like algorithm
 *
 */
double
scorewithRNA_onepass(FILE *ofp, SQINFO sqinfoX, int *sX, SQINFO sqinfoY, int *sY, char *gss, int start, int L, 
		     struct model_s *model, struct othdpd_s *othdp, 
		     struct rnamtx_s *mtx, double *sc, double *vp,
		     int *ret_scfg_status, int cyk, int fastintloop, int logodds, int do_nus, int parse, int traceback)
{
  int     scfg_status;
  int    *ct;
  double  score;

  scfg_status = *ret_scfg_status;

  if (parse) KHS2ct (gss+start, L, FALSE, &ct);

  if (!scfg_status) {
    if (!cyk) {
      if (!parse)
      scfg_status = InsideRNA(ofp, sqinfoX, sX, sqinfoY, sY, start, L, model->rna, model->null,
			      othdp, mtx, sc, vp, do_nus, fastintloop, logodds);
      else
	scfg_status = InsideParseRNA(ofp, sqinfoX, sX, sqinfoY, sY, ct, start, L, model->rna, model->null,
				     othdp, mtx, sc, vp, do_nus, logodds);
    }
    else 
      if (!parse)
	scfg_status = CYKRNA(ofp, sqinfoX, sX, sqinfoY, sY, start, L, model->rna, model->null,
			     othdp, mtx, vp, logodds, do_nus, traceback);
      else
	scfg_status = CYKParseRNA(ofp, sqinfoX, sX, sqinfoY, sY, ct, start, L, model->rna, model->null,
				  othdp, mtx, vp, logodds, do_nus, traceback);
  }
  
  score = ScoreWithOTH(ofp, sX, sY, start, 0, model->rna->ROB, FALSE) 
    + model->rna->t[TROBRNA]
    + mtx->wx[L-1][L-1]  
    + model->rna->t[TRNAROE] 
    + ScoreWithOTH(ofp, sX, sY, L-1, 0, model->rna->ROE, FALSE);

  *ret_scfg_status = scfg_status;

  if (parse) free (ct);

  return score;
}
















