// file: bw_comb_0.cc
//
// isip include files
//
#include "bw_train.h"
#include "bw_train_constants.h"

// method: combine_acc_cc
//
// arguments:
//  float_8*** new_trans : (output) numerator accumulators of transitions
//  float_8*** train_mean : (output) mean accumulators
//  float_8*** train_covar : (output) covariance accumulators
//  float_8** mix_weights : (output) mixture weights accumulators
//  float_8* state_occ : (output) state occupance accumulators
//  int_4* model_access_counts : (output) counts of model accesses
//  int_4 num_trans : (input) number of transition matrixes
//  int_4* trans_size : (input) sizes of transition matrixes
//  int_4 num_states : (input) number of states
//  int_4 num_mix : (input) number of mixtures
//  int_4 num_features : (input) number of features
//  int_4 num_models: (input) number of models
//  FILE* fp_acc_list : (input) accumulators file list
//
// return: a logical flag to indicate success
//

// this method reads all the accumulator files and updates means,
// covariances, model access counts. This method is called when the training
// is run in combined mode
//
logical_1 combine_acc_cc(float_8*** new_trans_a, float_8*** train_mean_a,
			 float_8*** train_covar_a,
			 float_8** mix_weights_a, float_8* state_occ_a,
			 int_4* model_access_counts, int_4 num_trans_a,
			 int_4* trans_size_a, int_4 num_states_a,
			 int_4 num_mix_a, int_4 num_features_a,
			 int_4 num_models_a, FILE* fp_acc_list_a) {

  // local variables
  //
  int_4 tmp = (int_4)0;
  char_1* acc_file = new char_1[ISIP_MAX_STRING_LENGTH];
  FILE* facc = (FILE*)NULL;
  
  // allocate memory for temporary variables
  //
  float_8*** temp_trans = new float_8**[num_trans_a];
    
  for (int_4 i = 0; i < num_trans_a; i++) {
    
    // get the size of current covariance matrix
    //
    tmp = trans_size_a[i];
    temp_trans[i] = new float_8*[tmp];
      
    for (int_4 j = 0; j < tmp; j++) {
      temp_trans[i][j] = new float_8[tmp];
      for (int_4 k = 0; k < tmp; k++) {
	temp_trans[i][j][k] = BW_LOG_ZERO;
      }
    }
  }
  
  // allocate memory for the new parameters for all states
  //
  float_8*** temp_mean = new float_8**[num_states_a];
  float_8*** temp_covar = new float_8**[num_states_a];
  float_8** temp_weights = new float_8*[num_states_a];
  float_8* temp_occ = new float_8[num_states_a];
  int_4* temp_model_counts = new int_4[num_models_a];
  
  for (int_4 i = 0; i < num_states_a; i++) {
    temp_mean[i] = new float_8*[num_mix_a];
    temp_covar[i] = new float_8*[num_mix_a];
    temp_weights[i] = new float_8[num_mix_a];
    temp_occ[i] = (float_8)0.0;
    for (int_4 j = 0; j < num_mix_a; j++) {
      temp_mean[i][j] = new float_8[num_features_a];
      temp_covar[i][j] = new float_8[num_features_a];
      temp_weights[i][j] = (float_8)0.0;
      for (int_4 k = 0; k < num_features_a; k++) {
	temp_mean[i][j][k] = (float_8)0.0;
	temp_covar[i][j][k] = (float_8)0.0;
      }
    }
  }
  
  // loop over all the accumulator files
  //
  while (fgets((char*)acc_file, ISIP_MAX_STRING_LENGTH, fp_acc_list_a) !=
	 (char*)NULL) {
    
    expand_filename_cc(acc_file);
    facc = fopen((char*)acc_file, "rb");

    // read the transition accumulators
    //
    for (int_4 i = 0; i < num_trans_a; i++) {
      tmp = trans_size_a[i];
      for (int_4 j = 0; j < tmp; j++) {
	fread((void_p)temp_trans[i][j], sizeof(float_8), tmp, facc);
	
	// update data arrays
	//
	for (int_4 k = 0; k < tmp; k++) {
	  new_trans_a[i][j][k] += temp_trans[i][j][k];
	}
      }
    }
    
    // read the states accumulators
    //
    for (int_4 i = 0; i < num_states_a; i++) {
      for (int_4 j = 0; j < num_mix_a; j++) {
	fread((void_p)temp_mean[i][j], sizeof(float_8), num_features_a,
	      facc);
	fread((void_p)temp_covar[i][j], sizeof(float_8), num_features_a,
	      facc);
	
	// update means and variances
	//
	for (int_4 k = 0; k < num_features_a; k++) {
	  train_mean_a[i][j][k] += temp_mean[i][j][k];
	  train_covar_a[i][j][k] += temp_covar[i][j][k];
	}
      }
      
      // read mixture weightes and update
      //
      fread((void_p)temp_weights[i], sizeof(float_8), num_mix_a, facc);
      for (int_4 j = 0; j < num_mix_a; j++) {
	mix_weights_a[i][j] += temp_weights[i][j];
      }
    }
    
    // read state occupancy accumulators and update
    //
    fread((void_p)temp_occ, sizeof(float_8), num_states_a, facc);
    for (int_4 i = 0; i < num_states_a; i++) {
      state_occ_a[i] += temp_occ[i];
    }

    // read the model access counts
    //
    fread((void_p)temp_model_counts, sizeof(int_4), num_models_a, facc);
    for (int_4 i = 0; i < num_models_a; i++) {
      model_access_counts[i] += temp_model_counts[i];
    }
    
    // close file
    //
    fclose(facc);
    facc = (FILE*)NULL;
  }
  
  // clean up
  //
  for (int_4 i = 0; i < num_trans_a; i++) {
    for (int_4 j = 0; j < trans_size_a[i]; j++) {
      delete [] temp_trans[i][j];
    }
    delete [] temp_trans[i];
  }
  delete [] temp_trans;
  
  for (int_4 i = 0; i < num_states_a; i++) {
    for (int_4 j =0; j < num_mix_a; j++) {
      delete [] temp_mean[i][j];
      delete [] temp_covar[i][j];
    }
    delete [] temp_mean[i];
    delete [] temp_covar[i];
    delete [] temp_weights[i];
  }
  delete [] temp_mean;
  delete [] temp_covar;
  delete [] temp_weights;
  delete [] temp_occ;
  delete [] temp_model_counts;
  delete [] acc_file;

  // exit gracefully
  //
  return ISIP_TRUE;
}
