// file: bw_trans_1.cc
//

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

// method: acc_trans_cc
//
// arguments:
//  float_8*** new_trans : (output) the accumulation of numerator
//  float_8** for_probt : (input) the forward probabilities of current frame
//  float_8*** back_prob : (input) the backward probabilities
//  float_4*** transitions : (input) the old transitions
//  State** states : (input) the states for all models
//  Train_Model** models : (input) the models sequence
//  int_4 num_mod : (input) the number of models in current transcription
//  int_4* model_list : (input) the model index list
//  int_4* trans_map : (input) the mapping from model index to transition
//                             matrix index
//  int_4* st_map : (input) the mapping from model index and local state
//                          index to global state index
//  int_4 num_vect : (input) the number of frames in current data file
//  float_8** vectors : (input) the input feature vectors
//  float_8 utt_prob_a : (input) the utterance probability
//  float_8*** state_scores : (output/input) the state score array
//  int_4 frame : (input) the current frame index
//  int_2* upper : (input) upper bound
//  int_2* lower : (input) lower bound
//
//  return a logical_1 indicating status
//

// this method updates the transition accumulators for
// every utterance
//
logical_1 acc_trans_cc(float_8*** new_trans_a, float_8** for_probt_a,
		       float_8*** back_prob_a,
		       float_4*** transitions_a, Train_State** states_a,
		       Train_Model** models_a, int_4 num_mod_a, int_4* model_list_a,
		       int_4* trans_map_a, int_4** st_map_a, int_4 num_vect_a,
		       float_8** vectors_a, float_8 utt_prob_a,
		       float_8*** state_scores_a, int_4 frame_a,
		       int_2* upper_a, int_2* lower_a) {

  // local variables
  //
  int_4 loc_st = (int_4)0;
  int_4 trans_ind = (int_4)0;
  float_8 num_score = BW_LOG_ZERO;
  float_8 tmp_prob = BW_LOG_ZERO;
  float_8 tmp_trans = BW_LOG_ZERO;
  float_8 tmp_trans1 = BW_LOG_ZERO;
  int_4 tmp_mix = (int_4)0;

  // loop over all the input models
  //
  for (int_4 q = lower_a[frame_a]; q <= upper_a[frame_a]; q++) {
    
    // get the number of states in current model
    //
    loc_st = models_a[model_list_a[q-1]]->get_num_states_cc();
    trans_ind = trans_map_a[model_list_a[q-1]];

    // loop over all the states in the model
    //
    for (int_4 i = 1; i <= loc_st-1; i++) {

      // loop over the emitting states
      //
      for (int_4 j = 2; j <= loc_st; j++) {

	// get the transition between state i and state j
	//
	tmp_trans = transitions_a[trans_ind][i-1][j-1];

	// check if it is a valid transitions
	//
	if (tmp_trans <= BW_LOG_MIN) {
	  continue;
	}

	// if it is not a valid transition
	//
	else {
	  
	  // get the transition between first state and last state
	  //
	  tmp_trans1 = transitions_a[trans_ind][0][loc_st-1];
	  
	  // reset the score
	  //
	  num_score = BW_LOG_ZERO;
	  
	  // check if it is a within model transition
	  //
	  if ((i > 1) && (j < loc_st) && (frame_a != num_vect_a)) {
	    
	    // compute the output probability
	    //
	    if (state_scores_a[frame_a+1][q][j] != BW_LOG_ZERO) {
	      tmp_prob = state_scores_a[frame_a+1][q][j];
	    }
	    else {
	      tmp_prob = states_a[st_map_a[model_list_a[q-1]][j-1]]
		->eval_score_cc(vectors_a[frame_a], frame_a+1, tmp_mix);
	      state_scores_a[frame_a+1][q][j] = tmp_prob;
	    }
	    num_score = log_add_cc(num_score, (for_probt_a[q][i] +
					       tmp_trans + tmp_prob +
					       back_prob_a[frame_a+1]
					       [q][j]));
	  }
	  
	  // this is the case that transition is from a non-emitting state
	  // into HMM
	  //
	  else if ((i == 1) && (j < loc_st) && (frame_a != num_vect_a)) {
	    
	    // 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;
	    }
	    num_score = log_add_cc(num_score, (for_probt_a[q][1] +
					       tmp_trans + tmp_prob +
					       back_prob_a[frame_a][q][j]));
	  }
	  
	  // this is the transition out of HMM into non-emitting state
	  //
	  else if ((i > 1) && (j == loc_st)) {
	    
	    num_score = log_add_cc(num_score, (for_probt_a[q][i] +
					       tmp_trans + back_prob_a
					       [frame_a][q][loc_st]));
	  }
	  
	  // transition from non-emitting entry to exit
	  //
	  else if ((i == 1) && (j == loc_st)) {
	    
	    if (q < num_mod_a) {
	      num_score = log_add_cc(num_score, (for_probt_a[q][1] +
						 tmp_trans + back_prob_a
						 [frame_a][q+1][1]));
	    }
	  }
	}
	
	// divide by the utterance score
	//
	num_score -= utt_prob_a;
	
	// update the transition matrix
	//
	if (num_score > BW_MIN_EARG) {
	  new_trans_a[trans_ind][i-1][j-1] += exp(num_score);
	}
      } //end if the transitions is valid 
    } // end of loop all valid states
  } // end of loop all models
  
  // exit gracefully
  //
  return(ISIP_TRUE);
}
