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

// this file contains utility methods for compute, pdf and cdf methods, and
// also index conversion methods
//

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

// method: findBinIndex
//
// arguments:
//  double value: (input) values to histogram
//  long dim_num: (input) the dimension number to search in
//
// return: index of 1-D bin to which x belongs
//
// this method finds the bin (1-D) to which a scalar point belongs
// using binary tree search
//
long Histogram::findBinIndex(double value_a, long dim_num_a) {
  
  // define local variables
  //
  double value = -1;
  double diffi = 0;
  double diffip1 = 0;
  boolean counted = false;

  if (scale_d == USER_DEFINED) {
    // the counting algorithm varies with the bin mode
    //
    if (mode_d == CENTERS) {
      long last_bin = num_bins_d(dim_num_a) - (long)1;

      diffi = Integral::abs(bins_d(dim_num_a)(0) - value_a);
      diffip1 = 0;
      counted = false;

      for (long i = 0; i < last_bin; i++) {
	// count for bin(i) if  abs(bin(i) - value) < abs(bin(i+1) - value)
	//
	diffip1 = Integral::abs(bins_d(dim_num_a)(i + 1) - value_a);
	if (diffi <= diffip1) {
	  return i;
	}
	diffi = diffip1;
      }

      // value is to the right of last bin, put it in last bin
      //
      return last_bin;
    }
    else if (mode_d == EDGES) {
      long last_bin = num_bins_d(dim_num_a) - (long)1;

      // if value is to the left of first bin, put it in first bin
      //
      if (value_a <= bins_d(dim_num_a)(0)) {
	return 0;
      }

      for (long i = 0; i < last_bin; i++) {
	// count for bin(i) if  bin(i) <= value < bin(i+1)
	//
	if ((value_a >= bins_d(dim_num_a)(i)) && (value_a < bins_d(dim_num_a)(i+1))) {
	  return i;
	}
      }
      
      // value is to the right of last bin, put it in last bin
      //
      return last_bin;
    }
  }

  else if (scale_d == LINEAR) {
    long index = (long)( (value_a - min_d(dim_num_a)) /  delta_d(dim_num_a) );
    long last_bin_index = num_bins_d(dim_num_a) - (long)1;
    if (index > last_bin_index) {
      index = last_bin_index;
    }
    else if (index < 0) {
      index = 0;
    }
    return index;
  }

  else if (scale_d == LOG) {
    value = log10(value_a);

    long index = (long)( (value - min_d(dim_num_a)) /  delta_d(dim_num_a) );
    long last_bin_index = num_bins_d(dim_num_a) - (long)1;

    if (index > last_bin_index) {
      index = last_bin_index;
    }
    else if (index < 0) {
      index = 0;
    }
    return index;
  }

  // should never reach here
  //
  return -1;
}  


// method: computeBlockBoundaryIndex
//
// this method fills up the block_boundary_index_d array to be usable for
// conversion from global index to array of local indices
//
boolean Histogram::computeBlockBoundaryIndex() {
  block_boundary_index_d.setLength(dim_d + (long)1);
  block_boundary_index_d(0) = (long)1;

  for (long i = 1; i < dim_d + (long)1; i++) {
    block_boundary_index_d(i) = block_boundary_index_d(i - 1) * num_bins_d(i - 1);
  }

  return true;
}


// method: convertGlobalToLocalIndex
//
// arguments:
//  VectorLong& loc_ind: (output) vector of local indices
//  long glob_ind: (input) global index
//
// return: boolean status
//
// converts global index to local index vector
//
boolean Histogram::convertGlobalToLocalIndex(VectorLong& loc_ind_a, long glob_ind_a) {
  long i;
  
  if (block_boundary_index_d.length() == 0) {
    computeBlockBoundaryIndex();
  }
  loc_ind_a.setLength(dim_d);
  
  for (i = (long)dim_d - 1; i >= 0; i--) {
    loc_ind_a((long)dim_d - 1 - i) = glob_ind_a / block_boundary_index_d(i);
    glob_ind_a %= block_boundary_index_d(i);
  }

  return true;
}

// method: convertLocalToGlobalIndex
//
// arguments:
//  const VectorLong& loc_ind: (input) vector of local indices
//
// return: global index
//
// convert local index vector to global index
//
long Histogram::convertLocalToGlobalIndex(const VectorLong& loc_ind_a) {
  long i;
  long glob_index = 0;

  if (block_boundary_index_d.length() == 0) {
    computeBlockBoundaryIndex();
  }
  
  for (i = 0; i < dim_d; i++) {
    glob_index += loc_ind_a((dim_d - (long)1)- i) * block_boundary_index_d(i);
  }

  return glob_index;
}


// method: getBinIndexCoordinates
//
// arguments:
//  Vector<VectorLong>& multidim_bin_index: (output) array of multidimensional index vectors.
//
// return: boolean status
// 
// get the vector coordinates of all bins in the multidimensional space.
//  each bin is specified with a  vector index, each element of which
//  gives the bin number in one dimension. the bins are ordered according to
//  its global index from 0 to total number of bins. this is useful to
//  identify the bin index for each entry in the vector from  pdf or cdf
//  methods.
//
boolean Histogram::getBinIndexCoordinates(Vector<VectorLong>& multidim_bin_index_a) {
  if (bins_d.length() == 0) {
  }

  long i, length = counts_d.length();
  VectorLong index_vector;

  multidim_bin_index_a.setLength(length);
  
  for (i = 0; i < length; i++) {
    convertGlobalToLocalIndex(multidim_bin_index_a(i), i);
  }
  
  return true;
}   
    
    
    
