package yi.stat.hist;

public class HistUtil {
  /**
   * Given a value and the histogram description, return the corresponding bin
   * index of that value.  This method is linear based.  The first bin
   * (bin_index = 0) corresponding to values fallen into
   * [base_value, base_value + bin_width) if left_inclusive is set to true;
   * or (base_value, base_value + bin_width] if right_inclusive is set to true.
   * The second bin corresponding to
   * [base_value + bin_width, base_value + 2 * bin_width) or
   * (base_value + bin_width, base_value + 2 * bin_width].
   * If the data <= based_value, it will be set to bin index 0.
   * @param data
   * @param base_value
   * @param bin_width
   * @param bin_num bin number.  if non positive number is given, then the
   *                returned could be infinite
   * @param left_inclusive
   * @return the corresponding bin index (0 based)
   */
  public static int linearBinIndex(double data, double base_value, double bin_width, int bin_num, boolean left_inclusive) {
    return (new LinearQuantizer(base_value, bin_width, bin_num, left_inclusive)).quantize(data);
  }

  /**
   * Generate the histogram of a double array.  The width of the bin, w, is
   * decided by (max-min)/bin_num.  The first bin is [0,w), second bin is
   * [w,2w), etc.
   * @param data
   * @param min
   * @param max
   * @param bin_num
   * @return
   */
  public static int[] histogram(double[] data, double min, double max, int bin_num) {
    int[] h = new int[bin_num];
    double w = (max-min)/bin_num;
    for (int i=0; i<data.length; i++) {
      int index = linearBinIndex(data[i], min, w, bin_num, true);
      if (index < 0) {
        index = 0;
      }
      if (index >= bin_num) {
        index = bin_num - 1;
      }
      h[index]++;
    }
    return h;
  }

  /**
   * Add one dimension of the bin value.  Useful for drawing the histogram.
   * eg. {2,5,3} -> {{0,2},{1,5},{3,3}}.  The width of the bin, w, is
   * decided by (max-min)/bin_num.  The first bin value w/2, second bin is
   * w+w/2, etc.
   * @param hist
   * @param min
   * @param max
   * @param bin_num
   * @return
   */
  public static double[][] histToXYPoints(double[] hist, double min, double max) {
    int bin_num = hist.length;
    double[][] xy = new double[bin_num][2];
    double w = (max-min)/bin_num;
    double value = w/2;
    for (int i=0; i<bin_num; i++, value += w) {
      xy[i][0] = value;
      xy[i][1] = hist[i];
    }
    return xy;
  }
}