package edu.berkeley.nlp.util; import java.util.Arrays; public class Scaler { final int MAX_LEN ; int[] scales ; double[] unscaled; int index ; final double SCALE ; double sumUnscaled ; int sumScale ; public Scaler(double scale, int maxLen) { this.SCALE = scale; this.MAX_LEN = maxLen; scales = new int[MAX_LEN]; unscaled = new double[MAX_LEN]; clear(); } public Scaler() { this(Math.exp(200), 400); clear(); } public void add(double score, int scale) { assert score >= 0.0 : "Invald score: " + score; unscaled[index] = score; scales[index] = scale; index++; } public void clear( ) { index = 0; Arrays.fill(unscaled, 0.0); Arrays.fill(scales, 0); } private double getScale(int logScale) { if (logScale == 0.0) return 1.0; if (logScale == 1.0) return SCALE; if (logScale == 2.0) return SCALE * SCALE; if (logScale == 3.0) return SCALE * SCALE * SCALE; if (logScale == -1.0) return 1.0 / SCALE; if (logScale == -2.0) return 1.0 / SCALE / SCALE; if (logScale == -3.0) return 1.0 / SCALE / SCALE / SCALE; return Math.pow(SCALE, logScale); } public void scale() { sumScale = Integer.MIN_VALUE; for (int scale: scales) sumScale = Math.max(sumScale, scale); assert sumScale > Integer.MIN_VALUE; sumUnscaled = 0.0; for (int i=0; i < index; ++i) { double scale = getScale(scales[i]-sumScale); sumUnscaled += scale * unscaled[i]; } while (true) { if (sumUnscaled == 0.0) { break; } if (sumUnscaled > SCALE) { sumUnscaled /= SCALE; sumScale++; continue; } if (sumUnscaled < 1.0/SCALE) { sumUnscaled *= SCALE; sumScale--; continue; } break; } } public double getScaleFactor() { return SCALE; } public int getLogScale() { return (int) Math.log(SCALE); } public double getSumUnscaled() { return sumUnscaled; } public int getSumScale() { return sumScale; } public double getSumScaled() { return getScale(getSumScale()) * getSumUnscaled(); } public double getScaled(double unscaled, int scale) { return unscaled * getScale(scale); } }