// file: $isip/class/stat/GaussianModel/gaus_07.cc
// version: $Id: gaus_07.cc 7556 2001-12-26 22:32:53Z alphonso $
//

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

// method: setMode
//
// arguments:
//  MODE arg: (input) mode to set
//
// return: a boolean value indicating status
//
// this method sets the computation mode and sets the initialization flag.
//
boolean GaussianModel::setMode(MODE arg_a) {

  // mode: PRECOMPUTE and prior mode is NONE
  //  we must initialize
  //
  if ((arg_a == PRECOMPUTE) && (mode_d == NONE)) {
    mode_d = PRECOMPUTE;
    is_valid_d = false;
  }

  // mode: PRECOMPUTE and prior mode is PRECOMPUTE
  //  or NONE and prior mode is NONE
  //  leave the state unchanged. we still might need to initialize
  //  if is_valid_d was false.
  //

  // mode: NONE and prior mode is PRECOMPUTE
  //  we need to re-inverse the covariance matrix
  // 
  else if ((arg_a == NONE) && (mode_d == PRECOMPUTE)) {
    mode_d = arg_a;
    if (is_valid_d) {
      covariance_d.inverse();
    }
  }

  // exit gracefully
  //
  return true;
}

// method: init
//
// arguments: none
//
// return: a boolean value indicating status
//
// this precomputes the scale factor and the inverse of the covariance matrix
// so that these computations need not be done for every gaussian evaluation.
// after a call to this function:
//    scale_d = N/2 * log(2 * pi) + 1/2 * log(det(Cov))
//    covariance_d   = inverse(Cov)
//
boolean GaussianModel::init() {

  // if we are not in the precompute mode, we don't need to do anything.
  //
  if (mode_d != PRECOMPUTE) {
    is_valid_d = true;
    return true;
  }

  // if the data are valid, we also don't need to do anything.
  //
  else if (is_valid_d) {
    return true;
  }

  // check the arguments
  //
  long len_mean = mean_d.length();
  long len_cov = covariance_d.getNumRows();

  if ((len_mean != len_cov) || (len_mean <= 0) || (len_cov <= 0)) {
    is_valid_d = false;
    return false;
  }
       
  // compute the scale factor from its components.
  //
  double det = Integral::log(covariance_d.determinant());
  double tmp = Integral::log(Integral::TWO_PI);
  
  scale_d = (double)0.5 * ((double)len_mean * tmp + det);
  
  // pre-compute the inverse of the covariance matrix
  //
  covariance_d.inverse();

  // exit gracefully
  //
  return (is_valid_d = true);
}
