// file: $isip/class/system/Integral/itgl_06.cc
// version: $Id: itgl_06.cc 9809 2004-10-03 16:55:34Z parihar $
//

// isip include files
//
#include "Integral.h"
#include <SysString.h>

// method: logAddLog
//
// arguments:
//  const double x: (input) first log value to add.
//  const double y: (input) second log value to add
//
// return: double value returning the log addition of the two numbers
//
// this method computes the log addition of two numbers which are
// themselves log values.
// 
// the below derivation is due to a private correspondence with Aravind
// Ganapathiraju, September 14, 2000.
//
//   We have in hand log(x) and log(y) . We want Log(x+y).
//   
//   Consider, log(1+exp(log(x) - log(y))):
//   
//   log(1+exp(log(x) - log(y)))= log(1+ exp(log(x/y)))
//                              = log(1+ x/y)
//                              = log((x+y)/y)
//                              = log(x+y) - log(y)
//   
//   If we take score as log(y) and tmp_score as log(x), then
//   
//      log(x+y) = log(y) + log(1 + exp(log(x) - log(y)))
//   
//   In the below code this is done using: return (log(1.0 + exp(tmp)));
//
//   If an underflow occurs, the input values whose absolute value is
//   lesser will be returned.
// 
double Integral::logAddLog(const double x_a, const double y_a) {

  // define the variables to hold the gaussian score
  //
  double tmp = 0;
  double tmp_value = y_a;
  double output_value = x_a;
  
  // find the minimum component so that the sign of tmp is negative below
  //
  if (output_value < tmp_value) {
    tmp = output_value;
    output_value = tmp_value;
    tmp_value = tmp;
  }

  // find the difference between the two values. the output of this will
  // always be negative since output_value >= tmp_value
  //
  tmp = tmp_value - output_value;

  // do not allow the score to underflow.
  //
  if (tmp >= MIN_LOG_VALUE) {
    output_value += Integral::log1p(Integral::exp(tmp));
  }

  // exit gracefully
  //
  return output_value;
}

// method: hash
//
// arguments:
//  ulong* vec: (input) values to hash
//  long num_elem: (input) size of vector
//  long capacity: (input) upper bound on hash output
//
// return: a hash of the input vector
//
// this is a generic hash function, as defined by Knuth's "The Art of
// Computer Programming", volume 3, "Sorting and Searching", chapter
// 6.4.
//
long Integral::hash(ulong* vec_a, long num_elem_a, long capacity_a) {

  // local variable
  //
  ulong hash = 0;

  for (long i = 0; i < num_elem_a; i++) {
    hash = (hash << 5) ^ (hash >> 27) ^ (ulong)vec_a[i];
  }

  // set the modulus to be the capacity - 1, so that the hash will
  // most likely not be a multiple of 2 or 10
  //
  return (hash % (capacity_a - 1));
}

// method: cTime  
// arguments:
//  SysString& time: (output) string indicating calendar time
//
// return: a boolean value indicating status
//
//  method that returns the calendar time as a string of the form
//  "Sun Oct  3 09:50:40 2004\n", expressed relative to the local
//  standard time  
//
boolean Integral::cTime(SysString& time_a) {
  
  // call system ctime function to get calendar time
  //
  time_t t;
  ::time(&t);
  byte* val = (byte*)::ctime(&t);
  
  // if it is not null then assign assign calendar time to output
  // string
  //
  if (val != (byte*)NULL) {
    time_a.assign((byte*)val);
  }
  
  // if calendar time is NULL then clear the output string
  // 
  else {
    time_a.clear();
    return false;
  }
  
  // exit gracefully
  //
  return true;
}

// method: utcTime
// arguments:
//  SysString& time: (output) string indicating calendar time
//
//  method that returns the calendar time as a string of the form
//  "Sun Oct  3 14:50:40 2004\n", expressed in Coordinated Universal
//  Time (UTC)
//
boolean Integral::utcTime(SysString& time_a) {
  
  // call system ctime function to get calendar time
  //
  time_t t;
  ::time(&t);
  byte* val = (byte*)::asctime(gmtime(&t));
  // if it is not null then assign assign calendar time to output
  // string
  //
  if (val != (byte*)NULL) {
    time_a.assign((byte*)val);
  }
  
  // if calendar time is NULL then clear the output string
  // 
  else {
    time_a.clear();
    return false;
  }
  
  // exit gracefully
  //
  return true;
}
