package jclassifier;
import static java.lang.Math.abs;
import static java.util.Arrays.binarySearch;
import static net.sourceforge.aprog.tools.Tools.getOrCreate;
import java.util.Map;
import java.util.TreeMap;
import net.sourceforge.aprog.tools.Factory;
import net.sourceforge.aprog.tools.Factory.ConstantFactory;
import net.sourceforge.aprog.tools.MathTools.Statistics;
/**
* @author codistmonk (creation 2013-07-02)
*/
public final class EqualizingAdaptiveQuantizer implements Quantizer {
private final int bitCount;
private final Map<Double, Double> data;
private final Statistics statistics;
private Double[] keys;
public EqualizingAdaptiveQuantizer(final int bitCount) {
this.bitCount = bitCount;
this.data = new TreeMap<Double, Double>();
this.statistics = new Statistics();
}
@Override
public final void add(final double key, final double value) {
if (this.bitCount <= 0) {
return;
}
if (this.keys != null) {
throw new IllegalStateException();
}
this.statistics.addValue(key);
this.data.put(key, getOrCreate(this.data, key, (Factory<Double>) ConstantFactory.forInstance(0.0)) + value);
}
@Override
public final double quantize(final double value) {
if (this.bitCount <= 0) {
return value;
}
this.finish();
final int i0 = binarySearch(this.keys, value);
final int i2 = 0 <= i0 ? i0 : -(i0 + 1);
final int i1 = i2 - 1;
final double d1 = 0 <= i1 ? abs(value - this.keys[i1]) : Double.POSITIVE_INFINITY;
final double d2 = i2 < this.keys.length ? abs(value - this.keys[i2]) : Double.POSITIVE_INFINITY;
return this.data.get(d1 <= d2 ? this.keys[i1] : this.keys[i2]);
}
private final void finish() {
if (this.keys == null) {
Double total = 0.0;
for (final Map.Entry<Double, Double> entry : this.data.entrySet()) {
total += entry.getValue() - this.statistics.getMinimum();
entry.setValue(total);
}
final long quanta = 1L << this.bitCount;
for (final Map.Entry<Double, Double> entry : this.data.entrySet()) {
entry.setValue(this.statistics.getMinimum() +
this.statistics.getAmplitude() * (long) (quanta * entry.getValue() / total) / quanta);
}
this.keys = this.data.keySet().toArray(new Double[this.data.size()]);
}
}
}