// file: bw_comp_0.cc
//

// isip include files
//
#include "bw_train.h"
#include "bw_train_constants.h"

// method: comp_for_prob_cc
//
// arguments:
//  float_8** for_probt : (output) the forward probabilities
//  float_8** for_probt1 : (input) the forward prob. of previous frame
//  float_8*** back_prob : (input) the backward probabilities
//  int_2* upper : (input) the upper states bound
//  int_2* lower : (input) the lower states bound
//  int_4 frame : (input) the current index of frame
//  float_4*** transitions : (input) the old transition matrix
//  State** states : (input) the whole states sequence
//  int_4 num_mod : (input) the number of input models
//  int_4* model_list : (input) the index of each model
//  Model** models : (input) the whole models sequence
//  int_4* trans_map : (input) the mapping from model index to trans index
//  float_8** vectors : (input) the observations
//  int_4** st_map : (input) the mapping from model index and local state
//                             index to global state index
//  float_8* max_back : (input) the maximum back probability at each frame
//  float_8** max_mback : (input) the maximum back probability for each model
//                                at each frame
//  float_4 width : (input) the beam width
//  float_8 utt_prob : (input) the utterance probability
//  float_8*** state_scores : (input) the state scores array
//  float_4 min_mpd : (input) the minimum model probability
//
// return: a logical flag to indicate success
//
// this method computes forward probability by looping all the time frames,
// all the models and all the states within the model
//
logical_1 comp_for_prob_cc(float_8** for_probt_a, float_8** for_probt1_a,
			   float_8*** back_prob_a, int_2* upper_a,
			   int_2* lower_a, int_4 frame_a,
			   float_4*** transitions_a, Train_State** states_a,
			   int_4 num_mod_a, int_4* model_list_a,
			   Train_Model** models_a, int_4* trans_map_a,
			   float_8** vectors_a, int_4** st_map_a,
			   float_8* max_back_a, float_8** max_mback_a,
			   float_4 width_a, float_8 utt_prob_a,
			   float_8*** state_scores_a, float_4 min_mpd_a) {
  
  // local variables
  //
  int_4 loc_st = (int_4)0;
  int_4 pre_loc_st = (int_4)0;
  int_4 tmp_mix = (int_4)0;
  float_8 tmp_score = (float_8)0.0;
  float_8 tmp_trans = (float_8)0.0;
  float_8 tmp_trans1 = (float_8)0.0;
  float_8 tmp_prob = (float_8)0.0;

  // pruning
  //
  int_4 start_model = lower_a[frame_a];
  int_4 end_model = upper_a[frame_a];
  
  // loop over the models
  //
  for (int_2 q = start_model; q <= end_model; q++) {

    // if this is not the first model then get the number of states
    // of the previous model to calculate the forward
    // probabilities
    //
    if (q > 1) {
      pre_loc_st = models_a[model_list_a[q-2]]->get_num_states_cc();
    }

    // get the num states for the current model
    //
    loc_st = models_a[model_list_a[q-1]]->get_num_states_cc();

    // loop through all the states
    //
    for (int_4 j = 1; j <= loc_st; j++) {

      // check if beta pruning is done
      // if done do not consider the corresponding alpha values
      //
      if(max_mback_a[frame_a][q] <= BW_LOG_ZERO) {
	for_probt_a[q][j] = BW_LOG_ZERO;
      }

      // if the model has not been pruned then calculate the
      // forward probability
      //
      else {
	
	// set the initial conditions
	//

	// check if this is the first time frame
	//
	if (frame_a == 1) {
	  
	  // forward prob of first model's first state at the
	  // first time frame is 1.0
	  //
	  if ((q == 1) && (j == 1)) {
	    for_probt_a[q][j] = 0.0;
	  }

	  // if this is not the first model
	  //
	  else {

	    // check if this is the first state
	    //
	    if (j == 1) {
	      tmp_trans = transitions_a[trans_map_a[model_list_a[q-2]]]
		[j-1][pre_loc_st-1];
	      for_probt_a[q][j] = for_probt_a[q-1][j] + tmp_trans;
	    }

	    // check if this is the last state
	    //
	    else if (j == loc_st) {
	      tmp_score = BW_LOG_ZERO;
	      for(int_4 ii = 2; ii <= loc_st-1; ii++) {
		
		// find the transition score
		//
		tmp_trans = transitions_a[trans_map_a[model_list_a[q-1]]]
		  [ii-1][loc_st-1];
		tmp_score = log_add_cc(tmp_score, for_probt_a[q][ii] +
				       tmp_trans);
	      }
	      for_probt_a[q][j] = tmp_score;
	    }
	    else {
	      // calculate the forward probability of emitting states
	      // in the first time frame
	      //
	      
	      // compute the output probability
	      //
	      if (state_scores_a[frame_a][q][j] != BW_LOG_ZERO) {
		tmp_prob = state_scores_a[frame_a][q][j];
	      }
	      else {
		tmp_prob = states_a[st_map_a[model_list_a[q-1]][j-1]]
		  ->eval_score_cc(vectors_a[frame_a-1], frame_a, tmp_mix);
		state_scores_a[frame_a][q][j] = tmp_prob;
	      }
	      
	      // compute the transitions probability
	      //
	      tmp_trans = transitions_a[trans_map_a[model_list_a[q-1]]]
		[0][j-1];
	      for_probt_a[q][j] = tmp_trans + tmp_prob;
	    }
	  }	  
	}
      
	// compute the major part of forward probability
	// when it is not in the first time frame
	//
	else {

	  // forward probability of being in the first model's
	  // first state is zero
	  //
	  if ((q == 1) && (j == 1)) {
	    for_probt_a[q][j] = BW_LOG_ZERO;
	  }

	  // if this not the first model and first time frame
	  //
	  else {

	    // check if this is the first state
	    //
	    if (j == 1) {
	      tmp_trans = transitions_a[trans_map_a[model_list_a[q-2]]]
		[j-1][pre_loc_st-1];
	      tmp_score = for_probt1_a[q-1][pre_loc_st];
	      if ((q > lower_a[frame_a]) && (tmp_trans > BW_LOG_MIN)) {
		tmp_score = log_add_cc(tmp_score, (for_probt_a[q-1][j] +
						   tmp_trans));
	      }
	      for_probt_a[q][j] = tmp_score;
	    }

	    // check if this is the last state
	    //
	    else if (j == loc_st) {
	      tmp_score = BW_LOG_ZERO;
	      for (int_4 jj = 2; jj <= loc_st-1; jj++) {
		
		// find the transition score
		//
		tmp_trans = transitions_a[trans_map_a[model_list_a[q-1]]]
		  [jj-1][loc_st-1];
		if ((tmp_trans > BW_LOG_MIN) && (for_probt_a[q][jj] >
						 BW_LOG_MIN)) {
		  tmp_score = log_add_cc(tmp_score, (for_probt_a[q][jj] +
						     tmp_trans));
		}
	      }
	      for_probt_a[q][j] = tmp_score;
	    }

	    // if this is one of the emitting states
	    //
	    else {
	      
	      // compute the output probability
	      //
	      if (state_scores_a[frame_a][q][j] != BW_LOG_ZERO) {
		tmp_prob = state_scores_a[frame_a][q][j];
	      }
	      else {
		tmp_prob = states_a[st_map_a[model_list_a[q-1]][j-1]]
		  ->eval_score_cc(vectors_a[frame_a-1], frame_a, tmp_mix);
		state_scores_a[frame_a][q][j] = tmp_prob;
	      }
	      
	      // compute the first transition
	      //
	      tmp_trans = transitions_a[trans_map_a[model_list_a[q-1]]]
		[0][j-1];
	      
	      // compute the summation
	      //
	      tmp_score = BW_LOG_ZERO;
	      if (tmp_trans > BW_LOG_MIN) {
		tmp_score = for_probt_a[q][1] + tmp_trans;
	      }
	      for (int_4 kk = 2; kk <= loc_st-1; kk++) {
		tmp_trans1 = transitions_a[trans_map_a[model_list_a[q-1]]]
		  [kk-1][j-1];
		if ((tmp_trans1>BW_LOG_MIN) && (for_probt1_a[q][kk]>BW_LOG_MIN))
		  {
		    tmp_score = log_add_cc(tmp_score, (for_probt1_a[q][kk] +
						       tmp_trans1));
		  }
	      }
	      for_probt_a[q][j] = tmp_score + tmp_prob;
	    }
	  }
	} // end of computing major part of forward probability
	
	// floor
	//
	if (for_probt_a[q][j] < BW_LOG_ZERO) {
	  for_probt_a[q][j] = BW_LOG_ZERO;
	}
      }// end of beta pruning not done
    } // end of looping over each state
  } // end of looping over each model
  
  // exit gracefully
  //
  return(ISIP_TRUE);
}
