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

/* evolothmodel.c
 * 
 *
 * ER, Mon May 17 10:03:12 CDT 2004 [STL, at work with Coro]
 */

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

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

/* Function: EvolConstructOTHModel()
 * Date:     ER, Mon May 17 12:50:01 CDT 2004  [St. Louis, at work with Coro]
 *
 * Purpose:  Constructs a othmodel_s
 *
 * Args:     othparam - the list of parameters that define a othmodel           
 *
 * Returns:  (void)
 *           fills all prob's for othmodel, log2 form 
 *           (allc'ed here, freed by caller)
 */
void
EvolConstructOTHModel(struct psubs_s *mutpxy_star,  
		      struct othparam_s othparam, struct othparam_s othparam_zero, struct othparam_s othparam_infty, 
		      double win, double win_zero, double win_infty, double tfactor, double *targetfreq, int changefreq, 
		      struct othmodel_s *oth, int pedantic, int verbose)
{
  struct psubs_s *mutpxy_oth;
  double          factor_star  = 0.01;
  double          factor_infty = 0.02;

  if (verbose) printf("Construct OTH Model at time = %.4f\n", tfactor);

  /* the oth model has a paramente tau that set the invers of the average length generated by those models
   * This is how I set them as a few percentages of the length under analysis. This parameter does not evolve
   */
  othparam.tau       = (win       > 1.0)? 1.0 / win       : 1.0;
  othparam_zero.tau  = (win_zero  > 1.0)? 1.0 / win_zero  : 1.0;
  othparam_infty.tau = (win_infty > 1.0)? 1.0 / win_infty : 1.0;

  if (factor_star > 1.0/win_zero) { factor_star = 1.0/win_zero; factor_infty = factor_star; }

  othparam.FLN.eta = (factor_star*win > 1+MARGIN)? 1.0 / (factor_star*win) : 1.0;
  othparam.FRN.eta = (factor_star*win > 1+MARGIN)? 1.0 / (factor_star*win) : 1.0;
  othparam.FJN.eta = (factor_star*win > 1+MARGIN)? 1.0 / (factor_star*win) : 1.0;

  othparam_infty.FLN.eta = (factor_infty*win_infty > 1+MARGIN)? 1.0 / (factor_infty*win_infty) : 1.0;
  othparam_infty.FRN.eta = (factor_infty*win_infty > 1+MARGIN)? 1.0 / (factor_infty*win_infty) : 1.0; 
  othparam_infty.FJN.eta = (factor_infty*win_infty > 1+MARGIN)? 1.0 / (factor_infty*win_infty) : 1.0;
  
  if (othparam.FLN.eta >= 1.0) othparam_infty.FLN.eta = othparam.FLN.eta;
  if (othparam.FRN.eta >= 1.0) othparam_infty.FRN.eta = othparam.FRN.eta;
  if (othparam.FJN.eta >= 1.0) othparam_infty.FJN.eta = othparam.FJN.eta;
  
  /* Check probs are larger than zero
   */
  CheckOTHParam(othparam);
  CheckOTHParam(othparam_zero);
  CheckOTHParam(othparam_infty);

   /* 
   * Define the OTH Transfer matrices as:    
   *
   *                                     M    X    Y    E
   *                                B | TBM  TBX  TBY  TBE |
   *                                  |                    |
   *                                M | TMM  TMX  TMY  TME |
   *                           TA =   |                    |      
   *                                X | TXM  TXX  TXY  TXE |
   *                                  |                    |
   *                                Y | TYM  TYX  TYY  TYE |
   *
   *
   *                                      B      FR
   *                                FL |  xi    1-xi |
   *                          TB =     |             |
   *                                E  | 1-eta   eta |
   *
   *
   *                                
   * TA,TB are matrices of conditional probabilities (rows add up to one).
   *
   * TA,TB correspond to a given evolutionary time (be that blosum62, or any other)                   
   *
   */
  /*OTHmodel_transition_probabilities_linear (othparam, othparam_zero, tfactor, oth, pedantic, verbose);*/
  OTHmodelTransitionProbabilities (othparam, othparam_zero, othparam_infty, tfactor, oth, pedantic, verbose);

  /* Calculate emission prob's: OTH->mem[], OTH->xem[], OTH->yem[]
   */
  EvolMutProbs(mutpxy_star, tfactor, &mutpxy_oth, targetfreq, changefreq, pedantic, verbose);
  ConstructMemOTHProbs(mutpxy_oth->P, oth->mem);
  ConstructXemOTHProbs(oth->mem, oth->xem);
  ConstructYemOTHProbs(oth->mem, oth->yem);
  
  if (verbose) {
    fprintf(stdout, "OTH(i,j, t=%.6f) Joint probabilities\n", mutpxy_oth->time);
    PrintProbs(stdout, mutpxy_oth->P, mutpxy_oth->L);
    fprintf(stdout, "Q_OTH(i,j, t=%.6f) Conditional probabilities\n", mutpxy_oth->time);
    PrintProbs(stdout, mutpxy_oth->Q, mutpxy_oth->L);
    fprintf(stdout, "OTH_marg probabilities\n");
    PrintVectorProbs(stdout, mutpxy_oth->pm, mutpxy_oth->L);
  }

  /* Construct flanking null models (already in log2 form)
   *
   * 
   */
  EvolConstructNullModel(mutpxy_star, oth->FLN, othparam.FLN, othparam_zero.FLN, othparam_infty.FLN, tfactor, targetfreq, changefreq, verbose);
  EvolConstructNullModel(mutpxy_star, oth->FJN, othparam.FJN, othparam_zero.FJN, othparam_infty.FJN, tfactor, targetfreq, changefreq, verbose);
  EvolConstructNullModel(mutpxy_star, oth->FRN, othparam.FRN, othparam_zero.FRN, othparam_infty.FRN, tfactor, targetfreq, changefreq, verbose);

  /* check prob's add up to one
   */
  CheckOTHProbs(oth);
  
  /* convert to Log2 form
   */
  OTHToLog2(oth);

  if (verbose) PrintOTHTrProbs(oth);
  if (verbose) printf("OTH model completed at time = %.4f\n", tfactor);

  /* free memory */
  FreeSubsProbs(mutpxy_oth);

}
