/**
* Copyright 2013 BigML
* Licensed under the Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*/
package org.streaminer.stream.histogram.spdt;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/**
* This class implements bin operations (insertions, merges, etc) for a histogram.
* This implementation is best for histograms with a small (<=256) number of bins.
* It uses an ArrayList to give O(N) insert performance with regard to the number
* of bins in the histogram. For histograms with more bins, the TreeBinReservoir
* class offers faster insert performance.
*/
public class ArrayBinReservoir <T extends Target> extends BinReservoir<T> {
public ArrayBinReservoir(int maxBins, boolean weightGaps, Long freezeThreshold) {
super(maxBins, weightGaps, freezeThreshold);
_bins = new ArrayList<Bin<T>>();
}
@Override
public void insert(Bin<T> bin) {
addTotalCount(bin);
int index = Collections.binarySearch(_bins, bin);
if (index >= 0) {
_bins.get(index).sumUpdate(bin);
} else {
if (isFrozen()) {
int prevIndex = Math.abs(index) - 2;
int nextIndex = prevIndex + 1;
double prevDist = (prevIndex >= 0) ?
bin.getMean() - _bins.get(prevIndex).getMean() : Double.MAX_VALUE;
double nextDist = (nextIndex < _bins.size()) ?
_bins.get(nextIndex).getMean() - bin.getMean() : Double.MAX_VALUE;
if (prevDist < nextDist) {
_bins.get(prevIndex).sumUpdate(bin);
} else {
_bins.get(nextIndex).sumUpdate(bin);
}
} else {
_bins.add(Math.abs(index) - 1, bin);
}
}
}
@Override
public Bin<T> first() {
return _bins.get(0);
}
@Override
public Bin<T> last() {
return _bins.get(_bins.size() - 1);
}
@Override
public Bin<T> get(double p) {
int index = Collections.binarySearch(_bins, new Bin(p, 0, null));
return (index >= 0) ? _bins.get(index) : null;
}
@Override
public Bin<T> floor(double p) {
int index = Collections.binarySearch(_bins, new Bin(p, 0, null));
if (index >= 0) {
return _bins.get(index);
} else {
index = Math.abs(index) - 2;
return (index >= 0) ? _bins.get(index) : null;
}
}
@Override
public Bin<T> ceiling(double p) {
int index = Collections.binarySearch(_bins, new Bin(p, 0, null));
if (index >= 0) {
return _bins.get(index);
} else {
index = Math.abs(index) - 1;
return (index < _bins.size()) ? _bins.get(index) : null;
}
}
@Override
public Bin<T> lower(double p) {
int index = Collections.binarySearch(_bins, new Bin(p, 0, null));
if (index >= 0) {
index--;
} else {
index = Math.abs(index) - 2;
}
return (index >= 0) ? _bins.get(index) : null;
}
@Override
public Bin<T> higher(double p) {
int index = Collections.binarySearch(_bins, new Bin(p, 0, null));
if (index >= 0) {
index++;
} else {
index = Math.abs(index) - 1;
}
return (index < _bins.size()) ? _bins.get(index) : null;
}
@Override
public Collection<Bin<T>> getBins() {
return _bins;
}
@Override
public void merge() {
while (_bins.size() > getMaxBins()) {
int minGapIndex = -1;
double minGap = Double.MAX_VALUE;
for (int i = 0; i < _bins.size() - 1; i++) {
double gap = gapWeight(_bins.get(i), _bins.get(i + 1));
if (minGap > gap) {
minGap = gap;
minGapIndex = i;
}
}
Bin<T> prev = _bins.get(minGapIndex);
Bin<T> next = _bins.remove(minGapIndex + 1);
_bins.set(minGapIndex, prev.combine(next));
}
}
private ArrayList<Bin<T>> _bins;
}