// file: $isip_ifc/class/numeric/Histogram/hist_06.cc
// version: $Id: hist_06.cc 10427 2006-02-13 19:33:54Z srinivas $
//

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

// method: setBins
//
// arguments:
//  const Vector<TVector>& bins: (input) input bins
//
// return: boolean value indicating status
//
// this method sets the bins defined by the user to be used for histograms.
// the counts are reset to zero
//
template <class TVector>
boolean Histogram::setBins(const Vector<TVector>& bins_a) {
  // assign the bins and dimension and reset the counts
  //
  if (dim_d != bins_a.length()) {
    return Error::handle(name(), L"setBins", Error::ARG, __FILE__, __LINE__);
  }
  else {
    bins_d.setLength(dim_d);
  }

  long i, tot_num_bins = 1;
  for (i = 0; i < dim_d; i++) {
    bins_d(i).assign(bins_a(i));
    num_bins_d(i) = bins_d(i).length();
    if (mode_d == EDGES) {
      num_bins_d(i) = num_bins_d(i) - (long)1;
    }
    tot_num_bins *= num_bins_d(i);
  }
  counts_d.setLength(tot_num_bins, false);
  counts_d.assign((long)0);
  
  // initialize the block boundaries for index generation
  //
  computeBlockBoundaryIndex();
  
  // exit gracefully
  //
  return true;
}

// explicit instantiations
//
template boolean
Histogram::setBins<VectorByte>(const Vector<VectorByte>&);
template boolean
Histogram::setBins<VectorDouble>(const Vector<VectorDouble>&);
template boolean
Histogram::setBins<VectorFloat>(const Vector<VectorFloat>&);
template boolean
Histogram::setBins<VectorLlong>(const Vector<VectorLlong>&);
template boolean
Histogram::setBins<VectorLong>(const Vector<VectorLong>&);
template boolean
Histogram::setBins<VectorShort>(const Vector<VectorShort>&);
template boolean
Histogram::setBins<VectorUllong>(const Vector<VectorUllong>&);
template boolean
Histogram::setBins<VectorUlong>(const Vector<VectorUlong>&);
template boolean
Histogram::setBins<VectorUshort>(const Vector<VectorUshort>&);

// method: setBins
//
// arguments:
//  const TVector& bins: (input) input bins
//
// return: boolean value indicating status
//
// this method sets the bins defined by the user to be used for histograms.
// uses same bins in all dimensions. the counts are reset to zero
// this method assumes that the dimension of the histogram is already set
//
template <class TVector>
boolean Histogram::setBins(const TVector& bins_a) {

  // assign the bins (assuming dimension is already set) and
  // reset the counts
  //
  long i, tot_num_bins;
  if (mode_d == EDGES) {
    tot_num_bins = (long)Integral::pow(bins_a.length() - 1, dim_d);
  }
  else {
    tot_num_bins = (long)Integral::pow(bins_a.length(), dim_d);
  }

  if (bins_d.length() != dim_d) {
    bins_d.setLength(dim_d);
  }

  for (i = 0; i < dim_d; i++) {
    bins_d(i).assign(bins_a);
    num_bins_d(i) = bins_d(i).length();
    if (mode_d == EDGES) {
      num_bins_d(i) = num_bins_d(i) - (long)1;
    }
  }
  counts_d.setLength(tot_num_bins, false);
  counts_d.assign((long)0);

  // initialize the block boundaries for index generation
  //
  computeBlockBoundaryIndex();

  // exit gracefully
  //
  return true;
}

// explicit instantiations
//
template boolean
Histogram::setBins<VectorByte>(const VectorByte&);
template boolean
Histogram::setBins<VectorDouble>(const VectorDouble&);
template boolean
Histogram::setBins<VectorFloat>(const VectorFloat&);
template boolean
Histogram::setBins<VectorLlong>(const VectorLlong&);
template boolean
Histogram::setBins<VectorLong>(const VectorLong&);
template boolean
Histogram::setBins<VectorShort>(const VectorShort&);
template boolean
Histogram::setBins<VectorUllong>(const VectorUllong&);
template boolean
Histogram::setBins<VectorUlong>(const VectorUlong&);
template boolean
Histogram::setBins<VectorUshort>(const VectorUshort&);

// method: setBins
//
// arguments:
//  long num_bins: (input) number of bins to use
//  TIntegral min: (input) minimum of the histogram range
//  TIntegral max: (input) maximum of the histogram range
//
// return: boolean value indicating status
//
// this method computes the bin locations from the min, max, num_bins
// and binning mode, and assigns the same binning to all dimensions
// it is assumed that the dimension of the histogram is already set
//
template <class TIntegral>
boolean Histogram::setBins(long num_bins_a, TIntegral min_a, TIntegral max_a) {

  long i, j;
  double log_min_thr = (double)(1.0 - 0.0001);
  
  // error checking
  //
  if ((num_bins_a <= 0) || (max_a < min_a)) {
    return Error::handle(name(), L"setBins", ERR_BINS, __FILE__, __LINE__);
  }

  if (bins_d.length() == 0) {
    setDim((long)dim_d);
  }
  
  // set same bins for all dimensions
  //
  for (i = 0; i < dim_d; i++) {

    if (scale_d == LINEAR || scale_d == USER_DEFINED) {
      min_d(i) = (double)min_a;
      max_d(i) = (double)max_a;
    }

    else if (scale_d == LOG) {
      if ((double)min_a < log_min_thr ) {
	return Error::handle(name(), L"setBins", ERR_BINS, __FILE__, __LINE__);
      }
      min_d(i) = (double)Integral::log10(min_a);
      max_d(i) = (double)Integral::log10(max_a);
    }

    else {
      return Error::handle(name(), L"setBins", ERR_BINS, __FILE__, __LINE__);
    }
    
    num_bins_d(i) = num_bins_a;
    delta_d(i) = (max_d(i) - min_d(i)) / num_bins_d(i);

    bins_d(i).setLength(num_bins_d(i) + (long)1);
    for (j = 0; j <= num_bins_d(i); j++) {
      bins_d(i)(j) = min_d(i) + delta_d(i) * (double)j;
    }

    if (scale_d == LOG) {
      bins_d(i).exp10();
    }
  }

  if (mode_d == CENTERS) {
    
    if (scale_d == LINEAR || scale_d == USER_DEFINED) {
      for (i = 0; i < dim_d; i++) {
	bins_d(i).add(delta_d(i) / 2.0);
	bins_d(i).setLength(bins_d(i).length() - (long)1);
      }
    }
    
    else {
      for (i = 0; i < dim_d; i++) {
	for (j = 0; j < bins_d(i).length() - 1; j++) {
	  bins_d(i)(j) = (bins_d(i)(j) + bins_d(i)(j + 1)) / 2.0;
	}
	bins_d(i).setLength(bins_d(i).length() - (long)1);
      }
    }
  }
  
  // initialize the count vector
  //
  long tot_num_bins = (long)Integral::pow(num_bins_a, dim_d);
  counts_d.setLength(tot_num_bins, false);
  counts_d.assign((long)0);

  // initialize the block boundaries for index generation
  //
  computeBlockBoundaryIndex();

  // exit gracefully
  //
  return true;
}

// explicit instantiations
//
template boolean
Histogram::setBins<byte>(long, byte, byte);
template boolean
Histogram::setBins<double>(long, double, double);
template boolean
Histogram::setBins<float>(long, float, float);
template boolean
Histogram::setBins<llong>(long, llong, llong);
template boolean
Histogram::setBins<long>(long, long, long);
template boolean
Histogram::setBins<short>(long, short, short);
template boolean
Histogram::setBins<ullong>(long, ullong, ullong);
template boolean
Histogram::setBins<ulong>(long, ulong, ulong);
template boolean
Histogram::setBins<ushort>(long, ushort, ushort);

// method: setBins
//
// arguments:
//  const VectorLong& num_bins: (input) number of bins to use
//  const TVector& min: (input) minimum of the histogram range
//  const TVector& max: (input) maximum of the histogram range
//
// return: boolean value indicating status
//
// this method computes the bin locations from the min, max, num_bins values
// specified for each dimension and the binning mode
//
template <class TVector>
boolean Histogram::setBins(const VectorLong& num_bins_a, const TVector& min_a, const TVector& max_a) {

  long i, j, tot_num_bins = (long)1;
  double log_min_thr = (double)(1.0 - 0.0001); 
  
  if (dim_d != num_bins_a.length()) {
    setDim(num_bins_a.length());
  }
    
  // error checking
  //
  if ((min_a.length() != dim_d) ||
      (max_a.length() != dim_d)) {
    return Error::handle(name(), L"setBins", ERR_BINS, __FILE__, __LINE__);
  }
      
  // set same bins for all dimensions
  //
  for (i = 0; i < dim_d; i++) {
    
    if (scale_d == LINEAR || scale_d == USER_DEFINED) {
      min_d(i) = (double)min_a(i);
      max_d(i) = (double)max_a(i);
    }
    
    else if (scale_d == LOG) {
      if ((double)min_a(i) < (double)log_min_thr) {
	return Error::handle(name(), L"setBins", ERR_BINS, __FILE__, __LINE__);
      }
      min_d(i) = (double)Integral::log10(min_a(i));
      max_d(i) = (double)Integral::log10(max_a(i));
    }
    
    else {
      return Error::handle(name(), L"setBins", ERR_BINS, __FILE__, __LINE__);
    }
    
    num_bins_d(i) = num_bins_a(i);
    delta_d(i) = (max_d(i) - min_d(i)) / num_bins_d(i);

    bins_d(i).setLength(num_bins_d(i) + (long)1);
    for (long j = 0; j <= num_bins_d(i); j++) {
      bins_d(i)(j) = min_d(i) + delta_d(i) * (double)j;
    }
    
    if (scale_d == LOG) {
      bins_d(i).exp10();
    }
    tot_num_bins *= num_bins_a(i);
  }
  
  if (mode_d == CENTERS) {

    if (scale_d == LINEAR || scale_d == USER_DEFINED) {
      for (i = 0; i < dim_d; i++) {
	bins_d(i).add(delta_d(i) / 2.0);
	bins_d(i).setLength(bins_d(i).length() - (long)1, true);
      }
    }
    
    else {
      for (i = 0; i < dim_d; i++) {
	for (j = 0; j < bins_d(i).length(); j++) {
	  bins_d(i)(j) = (bins_d(i)(j) + bins_d(i)(j + 1)) / 2.0;
	}
      bins_d(i).setLength(bins_d(i).length() - (long)1, true);
      }
    }
  }
  
  // initialize the count vector
  //
  counts_d.setLength(tot_num_bins, false);
  counts_d.assign((long)0);
  
  // initialize the block boundaries for index generation
  //
  computeBlockBoundaryIndex();

  // exit gracefully
  //
  return true;
}

// explicit instantiations
//
template boolean
Histogram::setBins<VectorByte>(const VectorLong&, const VectorByte&, const VectorByte&);
template boolean
Histogram::setBins<VectorDouble>(const VectorLong&, const VectorDouble&, const VectorDouble&);
template boolean
Histogram::setBins<VectorFloat>(const VectorLong&, const VectorFloat&, const VectorFloat&);
template boolean
Histogram::setBins<VectorLlong>(const VectorLong&, const VectorLlong&, const VectorLlong&);
template boolean
Histogram::setBins<VectorLong>(const VectorLong&, const VectorLong&, const VectorLong&);
template boolean
Histogram::setBins<VectorShort>(const VectorLong&, const VectorShort&, const VectorShort&);
template boolean
Histogram::setBins<VectorUllong>(const VectorLong&, const VectorUllong&, const VectorUllong&);
template boolean
Histogram::setBins<VectorUlong>(const VectorLong&, const VectorUlong&, const VectorUlong&);
template boolean
Histogram::setBins<VectorUshort>(const VectorLong&, const VectorUshort&, const VectorUshort&);


// method: setCounts
//
// arguments:
//  const VectorLong& counts: (input) counts to initialize histogram with
//
// return: boolean value indicating status
//
// this method sets the counts vector. the input vector must be the same
// length as the internal count vector
//
boolean Histogram::setCounts(const VectorLong& counts_a) {

  // verify the input vector length
  //
  if (counts_a.length() != counts_d.length()) {
    return Error::handle(name(), L"setCounts", ERR_BINS, __FILE__, __LINE__);
  }

  // assign the counts vector
  //
  return (counts_d.assign(counts_a));
}

