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

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

// method: pdf
//
// arguments:
//  VectorDouble& pdf: (output) pdf of histogram data
//
// return: boolean value indicating status
//
// this method computes the probability density function given counts from
// the histogram data
//
boolean Histogram::pdf(VectorDouble& pdf_a) const {

  // make sure the histogram has been initialized
  //
  if ((bins_d.length() == 0)) {
    return Error::handle(name(), L"pdf", ERR_BINS, __FILE__, __LINE__);
  }

  // copy the counts over
  //
  pdf_a.assign(counts_d);

  // divide by the sum of all counts
  //
  double sum = pdf_a.sum();
  if (sum != 0) {
    pdf_a.div(sum);
  }
  
  // exit gracefully
  //
  return true;
}

// method: pdf
//
// arguments:
//  MatrixDouble& pdf: (output) pdf of histogram data
//
// return: boolean value indicating status
//
// this method computes the 2D pdf given counts from
// the histogram data
//
boolean Histogram::pdf(MatrixDouble& pdf_a) {

  long i;
  VectorDouble tmp_pdf;
  Vector<VectorLong> bin_index;

  // make sure the histogram has been initialized
  //
  if (bins_d.length() == 0 || dim_d != (long)2) {
    return Error::handle(name(), L"pdf", ERR_BINS, __FILE__, __LINE__);
  }

  // compute the pdf
  //
  pdf(tmp_pdf);

  // convert the vectorized array pdf into a matrix pdf  
  //
  pdf_a.setDimensions(num_bins_d(1), num_bins_d(0));
  getBinIndexCoordinates(bin_index);

  for (i = 0; i < tmp_pdf.length(); i++) {
    pdf_a.setValue(bin_index(i)(1), bin_index(i)(0), tmp_pdf(i));
  }

  return true;
}

// method: cdf
//
// arguments:
//  VectorDouble& cdf: (output) cdf of histogram data
//
// return: boolean value indicating status
//
// this method computes the cumulative density function given counts from
// the histogram data
//
boolean Histogram::cdf(VectorDouble& cdf_a) {

  long i, j, k;
    
  // make sure the histogram has been initialized
  //
  if (bins_d.length() == 0) {
    return Error::handle(name(), L"cdf", ERR_BINS, __FILE__, __LINE__);
  }

  // get the pdf
  //
  pdf(cdf_a);

  // compute the cdf by summing pdfs
  //
  Vector<VectorLong> bin_index_coordinates;
  getBinIndexCoordinates(bin_index_coordinates);

  long num_neighbors = (1 << dim_d) - 1;
  Vector<VectorLong> neighbor_rel_index(num_neighbors);
  VectorLong sign_neighbor(num_neighbors);

  for (i = 0; i < num_neighbors; i++) {
    long tmp_sign = 0;
    neighbor_rel_index(i).setLength(dim_d);
    
    for (j = 0; j < dim_d; j++) {
      long tmp = ((i + 1) >> ((long)dim_d - 1 -j)) & 1;
      neighbor_rel_index(i)(j) = tmp;
      tmp_sign += tmp;
    }
    tmp_sign %= 2;

    if (tmp_sign == 0) {
      sign_neighbor(i) = (long)-1;
    }
    else {
      sign_neighbor(i) = (long)1;
    }
  }
    
  for (i = 1; i < cdf_a.length(); i++) {

    VectorLong bin_abs_index(bin_index_coordinates(i));
    VectorLong neighbor_abs_index;
    
    double tmp_cdf = (double)0;
    
    for (j = 0; j < num_neighbors; j++) {
      neighbor_abs_index.sub(bin_abs_index, neighbor_rel_index(j));
      
      if (neighbor_abs_index >= (long) 0) {
	k = convertLocalToGlobalIndex(neighbor_abs_index);
	tmp_cdf += (double)(sign_neighbor(j)) * cdf_a(k);
      }
    }
    cdf_a(i) += tmp_cdf;
  }    

  return true;
}

// method: cdf
//
// arguments:
//  MatrixDouble& cdf: (output) cdf of histogram data
//
// return: boolean value indicating status
//
// this method computes the cumulative density function given counts from
// the 2D histogram
//
boolean Histogram::cdf(MatrixDouble& cdf_a) {

  long i, j;
  // make sure the histogram has been initialized
  //
  if (bins_d.length() == 0 || dim_d != (long)2) {
    return Error::handle(name(), L"cdf", ERR_BINS, __FILE__, __LINE__);
  }
      
  // get the pdf
  //
  pdf(cdf_a);

  long num_y = cdf_a.getNumRows();
  long num_x = cdf_a.getNumColumns();

  // fill the 1st row and 1st column first
  //

  double prev_cdf = cdf_a.getValue(0, 0);
  for (j = 1; j < num_x; j++) {
    prev_cdf += cdf_a.getValue(0, j);
    cdf_a.setValue(0, j, prev_cdf);
  }

  prev_cdf = cdf_a.getValue(0, 0);
  for (i = 1; i < num_y; i++) {
    prev_cdf += cdf_a.getValue(i, 0);
    cdf_a.setValue(i, 0, prev_cdf);
  }

  // fill cdf for the rest of matrix entries
  //
  for (i = 1; i < num_y; i++) {
    for (j = 1; j < num_x; j++) {
      double tmp_cdf = cdf_a.getValue(j, i)
	+ (cdf_a.getValue(j, i - 1) + cdf_a.getValue(j - 1, i))
	- cdf_a.getValue(j - 1, i - 1);
      cdf_a.setValue(j, i, tmp_cdf);
    }
  }

  return true;
}
