// file: ht_nbest_0.cc
//

// isip include files
//
#include "hmm_train.h"
#include "hmm_train_constants.h"

// method: para_estimate_cc
//
// arguments:
//  int_4 num_hyps : (input) number of hypotheses
//  Train_Trace** array : (input) array of nbest hypotheses
//  float_8** data : (input) the all feature vectors in one mfcc file
//  Train_State** states : (input) the states array
//  Train_Model** models : (input) the models array
//  float_8*** mean : (output) the sum of the data of each state
//  float_8*** covar : (output) the sum of the var. of each state
//  int_4** count : (output) the appearing number of each state
//  int_4 num_feat : (input) the number of features
//  int_4 num_st : (input) the number of states
//  int_4 num_mix : (input) the number of mixtures
//  int_4*** trans : (output) the count of the arcs of the transition metrix
//  int_4* mod_map : (input) the map from the phone to the model
//  int_4** st_map : (input) the map from the model and temp state to the
//                           final state
//  int_4* trans_map : (input) the map from the model to the transition
//  int_4 sp_phn_ind : (input) the phone index of sp
//
// return: a logical_1 flag indicating success
//
// this method trace back the n-best hypotheses and keep track of the mean
// and variance of each state
//
logical_1 para_estimate_cc(int_4 num_hyps_a, Train_Trace** array_a, float_8** data_a,
			   Train_State** states_a, Train_Model** models_a,
			   float_8*** mean_a,
			   float_8*** covar_a, int_4** count_a,
			   int_4 num_feat_a, int_4 num_st_a, int_4 num_mix_a,
			   int_4*** trans_a, int_4* mod_map_a,
			   int_4** st_map_a, int_4* trans_map_a,
			   int_4 sp_phn_ind_a) {
 
  // dummy variables
  //
  Train_Trace* tr = (Train_Trace*)NULL; 
  Train_Trace* btr = (Train_Trace*)NULL;
  Train_Trace* pre_tr = (Train_Trace*)NULL;
  Train_Trace** back = (Train_Trace**)NULL;
  Train_Link_list* trlist = (Train_Link_list*)NULL;

  int_4 frm = (int_4)0;
  int_4 pre_frm = (int_4)0;
  int_4 level = (int_4)0;
  int_4 pre_level = (int_4)0;
  float_8 score = (float_8)0;
  float_8 presc = (float_8)0;
  
  int_4 ph_ind = (int_4)0;
  int_4 pre_ph_ind = (int_4)0;
  int_4 pre_st_ind = (int_4)0;
  int_4 trans_ind = (int_4)0;
  int_4 pre_trans_ind = (int_4)0;
  int_4 mod_ind = (int_4)0;
  int_4 num_states = (int_4)0;
    
  // trace back the n-best hypotheses
  //
  for (int_4 tt = 0; tt < num_hyps_a; tt++) {

    // local variables
    //
    trlist = new Train_Link_list();

    // put the traces in the right order
    //
    for (tr = array_a[tt]; tr != (Train_Trace*)NULL; tr = btr) {
      trlist->insert_cc(tr);
      back = tr->get_back_ptr_cc();
      if (back != (Train_Trace**)NULL) {
	btr = back[0];
      }
      else {
	break;
      }
    }

    // now loop again and output data
    //
    Train_Link_node* nd = trlist->get_curr_cc();
    while (nd != (Train_Link_node*)NULL) {

      // get the trace
      //
      tr = (Train_Trace*)(nd->get_item_cc());

      // get the trace params
      //
      frm = tr->get_frame_ind_cc();
      level = tr->get_level_cc();

      // make sure this is not start trace
      //
      if (frm > (int_4)0) {

	if (level == HT_STATE_LEVEL) {
	    
	  // re_estimate the params
	  //
	  count_state_cc(tr, data_a, mean_a, covar_a, count_a, num_feat_a,
			 num_st_a, num_mix_a, states_a, mod_map_a, st_map_a);

   	  if (pre_tr != (Train_Trace*)NULL) {
	    pre_frm = pre_tr->get_frame_ind_cc();
	    if (pre_frm > (int_4)0) {
	      pre_level = pre_tr->get_level_cc();
	      
	      // if model internal transition
	      //
	      if (pre_level == HT_STATE_LEVEL) {
		count_arc_cc(tr, pre_tr, trans_a, trans_map_a, mod_map_a,
			     models_a);
	      }
	      
	      // if entering a new model
	      //
	      else if (pre_tr->get_level_cc() == HT_WORD_LEVEL ||
		       pre_tr->get_level_cc() == HT_PHONE_LEVEL) {
		ph_ind = tr->get_phone_ind_cc();
		trans_ind = trans_map_a[mod_map_a[pre_ph_ind]];
		trans_a[trans_ind][0][1] += (int_4)1;
	      }
	    }
	  }
	}
	
	// if current trace belongs to model level, increment transition
	// to exit state, since we exit this model now
	//
	else if (tr->get_level_cc() == HT_PHONE_LEVEL &&
		 pre_tr->get_level_cc() == HT_STATE_LEVEL) {
	  pre_ph_ind = pre_tr->get_phone_ind_cc();
	  pre_trans_ind = trans_map_a[mod_map_a[pre_ph_ind]];
	  pre_st_ind = (int_4)pre_tr->get_state_ind_cc();
	  mod_ind = mod_map_a[pre_ph_ind];
	  num_states = models_a[mod_ind]->get_num_states_cc();
	  trans_a[pre_trans_ind][pre_st_ind][num_states-1] += (int_4)1;
	}

	// if current trace is word level and the current word ends with
	// skip sp, add count for skip sp
	//
	else if (tr->get_level_cc() == HT_WORD_LEVEL &&
		 pre_tr->get_level_cc() == HT_PHONE_LEVEL) {

	  // check the word ending phone
	  //
	  score = tr->get_score_cc();
	  presc = pre_tr->get_score_cc();
	  if (score < presc) {
	    trans_ind = trans_map_a[mod_map_a[sp_phn_ind_a]];
	    trans_a[trans_ind][0][2]++;
	  }
	}
      }
      
      // get the previous trace
      //
      nd = nd->get_prev_cc();
      
      // set the current trace
      //
      pre_tr = tr;
    }
    
    // free memory
    //
    delete trlist;
    trlist = (Train_Link_list*)NULL;
  }

  // exit gracefully
  //
  return ISIP_TRUE;
}
