// file: $isip/class/stat/UniformModel/uni_08.cc
// version: $Id: uni_08.cc 8296 2002-07-05 21:16:28Z parihar $
//

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

// method: getLikelihood
//
// arguments:
//  const VectorFloat& input: (input) test vector
//
// return: float value giving the log-likelihood of the data given the model
//
// this method computes the distance between the test vector and a
// probability distribution that is a uniform distribution:
//
//                1 
//  p(x) = -----------------  ,  min < x < max
//          Area(max - min)
//
//                0           ,  otherwise 
//
// the area is computed as a product of rectangular regions in
// N-dimensional space.
//
float UniformModel::getLikelihood(const VectorFloat& input_a) {

  // check if the input is within the region of support
  //
  long len = min_d.length();

  for (long i = 0; i < len; i++) {
    if ((input_a(i) < min_d(i)) || (input_a(i) > max_d(i))) {
      return (float)0;
    }
  }      

  // mode: PRECOMPUTE
  //
  if (mode_d == PRECOMPUTE) {

    // initialize
    //
    if (!init()) {
      Error::handle(name(), L"getLikelihood", ERR, __FILE__, __LINE__);
      return 0;
    }

    // calculate the uniform distribution weight
    //
    return scale_d;
  }

  // mode: other
  //  do a normal computation
  //
  return initScale();
}

// method: getLogLikelihood
//
// arguments:
//  const VectorFloat& input: (input) test vector
//
// return: float value giving the log likelihood of the data given the model
//
// this method needs to check for a zero value before applying the log.
//
float UniformModel::getLogLikelihood(const VectorFloat& input_a) {

  // compute the likelihood
  //
  float value = getLikelihood(input_a);

  // check for zero
  //
  if (value <= 0.0) {
    Error::handle(name(), L"getLogLikelihood", Error::ARG, __FILE__, __LINE__);
    return 0;
  }

  // exit gracefully
  //
  return Integral::log(value);
}

// method: getMean
//
// arguments:
//  VectorFloat& mean: (output) mean of the uniform distribution
//
// return: a boolean value indicating status
//
// this method computes the mean of the uniform distribution:
//
//          min + max
//  mean  = ----------  ,  min < x < max
//              2
//
boolean UniformModel::getMean(VectorFloat& mean_a) {

  // check if the max is greater than min
  //
  long len = min_d.length();

  for (long i = 0; i < len; i++) {
    if (min_d(i) > max_d(i)) {
      Error::handle(name(), L"getMean", ERR, __FILE__, __LINE__);
      return 0;
    }
  }

  // temporary variable
  //
  VectorFloat mean;
  mean.setLength(len);
  
  // compute the mean for each dimension of the distribution
  //
  for (long i = 0; i < len; i++) {
    mean(i) = (min_d(i) + max_d(i)) / (float)2;
  }      
  mean_a = mean;
  
  // exit gracefully
  //
  return true;
}

// method: getCovariance
//
// arguments:
//  MatrixFloat& cov: (output) covariance of the uniform distribution
//
// return: a boolean value indicating status
//
// presently, this method computes the covariance of the uniform
// distribution for one-dimension only
//
// for one-dimensional distribution:
//         square(max - min) 
//  var = ------------------  ,  min < x < max
//               12
//
boolean UniformModel::getCovariance(MatrixFloat& cov_a) {

  // check if the max is greater than min
  //
  long len = min_d.length();

  for (long i = 0; i < len; i++) {
    if (min_d(i) > max_d(i)) {
      Error::handle(name(), L"getCovariance", ERR, __FILE__, __LINE__);
      return 0;
    }
  }

  // compute the variance if the distribution is one dimensional
  //
  if (len == 1) {

    // temporary variable
    //
    MatrixFloat cov((long)1, (long)1);
    VectorFloat temp;
    
    // compute the variance for one dimensional distribution
    //
    temp.sub(max_d, min_d);
    temp.square();
    temp.div((float)12);
    cov.assign(temp(0));
    cov_a = cov;      
  }

  // else error
  //
  else {
    Error::handle(name(), L"getCovariance", ERR, __FILE__, __LINE__);
  }
  
  // exit gracefully
  //
  return true;
}
