// file: $isip/class/stat/SupportVectorModel/svm_09.cc
// version: $Id: svm_09.cc 8764 2002-10-26 19:45:56Z jelinek $
//

// isip include files
//
#include "SupportVectorModel.h"

// method: generateSvmFeatures
//
// arguments:
//  Vector<Vector<VectorFloat> >& output: (output) SVM segmental features
//  const Vector<VectorFloat>& input: (input) frame features
//  
// return: a boolean value indicating status
//
// this method gives the log likelihood of the test vector.
// log-likelihood will be computed as base 10 logarithm of distance.
//
boolean SupportVectorModel::generateSvmFeatures(
                              Vector<Vector<VectorFloat> >& output_a,
			      const Vector<VectorFloat>& input_a) {

  long inp_len = input_a.length();
  long feat_dim = input_a(0).length();
  output_a.setLength(inp_len);

  // loop over all starting frames
  //
  for (long i = 0; i < inp_len; i++) {

    output_a(i).setLength(inp_len - i);
    
    // loop over all ending frames
    //
    for (long j = i; j < inp_len; j++) {
      long jj = j - i;

      boolean duration_flag = true;
      long svm_feat_dim = 3 * feat_dim;
      if (duration_flag) {
	svm_feat_dim++;
      }
      output_a(i)(jj).setLength(svm_feat_dim);
      generateSvmSegment(output_a(i)(jj),
			 feat_dim, i, j + 1, duration_flag, input_a);
    }
  }

  // exit gracefully
  //
  return true;
}

// method: generateSvmSegment
//
// arguments:
//  VectorFloat& svm_features: (output) generated svm segmental features
//  long mfc_feat_dim: (output) feature dimension
//  long frame_start: (input) start frame of segment (inclusive)
//  long frame_end: (input) start frame of segment (inclusive)
//  boolean duration_flag: (input) whether or not to compute duration info
//  const Vector<VectorFloat>& mfc_features: (input) mfcc features
//
// return: a boolean value indicating status
//
// this method creates a 3-4-3 segment from the feature data and includes
// duration information. 
//
boolean SupportVectorModel::generateSvmSegment(
                              VectorFloat& svm_features_a,
			      long mfc_feat_dim_a,
			      long frame_start_a, long frame_end_a,
			      boolean duration_flag_a,
			      const Vector<VectorFloat>& mfc_features_a) {

  // generate the feature vector
  // we assume a 3 4 3 proportion and 3 segments here
  // with log duration information
  //
  static long seg_prop[3] = {
    3, 4, 3};
  static long num_seg = 3;
  static long total = 10;
  static long num_frame_per_seg[3];
  static long start_seg[3];
  static long end_seg[3];
  long end = frame_end_a;
  long start = frame_start_a;
  double duration = log(double(end - start));
  
  // get the start and end frame
  //
  long remaining_frames = end - start;
  long total_frames = remaining_frames;

  // compute the start and end frames for the various segments
  //  note: any additional frames left out because of integer arithmetic go
  //       to the central segment
  //
  for (long i = 0; i < num_seg; i++) {
    if (i != num_seg / 2) {
      num_frame_per_seg[i] = (long)floor((double)seg_prop[i]*
					  total_frames / (double)total);
      if (num_frame_per_seg[i] < 1 && total_frames >= 3) {
	num_frame_per_seg[i] = 1;
      }
      remaining_frames -= num_frame_per_seg[i];
    }
  }
  num_frame_per_seg[num_seg / 2] = remaining_frames;
    
  // compute the start and end frames for each segment
  //
  start_seg[0] = start;
  for (long i = 1; i < num_seg; i++) {
    start_seg[i] = start_seg[i - 1] + num_frame_per_seg[i - 1];
    end_seg[i - 1] =  start_seg[i];
  }
  end_seg[num_seg - 1] = end;

  // make sure that output space is allocated and initialized to zero
  //
  long svm_feat_dim = 3 * mfc_feat_dim_a;
  if (duration_flag_a) {
    svm_feat_dim++;
  }
  svm_features_a.setLength(svm_feat_dim);
  svm_features_a.setRange(0, svm_feat_dim, 0.0);

  // get means for the segments
  //
  for (long i = 0; i < num_seg; i++) {
    
    for (long j = start_seg[i]; j < end_seg[i]; j++) {
      
      // sum over the vectors in the segment
      //
      for (long k = 0; k < mfc_feat_dim_a; k++) {
	svm_features_a((i * mfc_feat_dim_a) + k) += mfc_features_a(j)(k);
      }
    }
    if (end_seg[i] - start_seg[i] > 1) {
      for (long k = 0; k < mfc_feat_dim_a; k++) {
	svm_features_a((i*mfc_feat_dim_a) + k) /= 
	  (double)(end_seg[i] - start_seg[i]);
      }
    }    
  }
  if (duration_flag_a) {
    svm_features_a(svm_feat_dim - 1) = duration / MAX_LOG_DURATION;
  }

  // exit gracefully
  //
  return true;
}
