/**
* Copyright (C) 2011 Brian Ferris <bdferris@onebusaway.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.onebusaway.transit_data_federation.impl.realtime.history;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class CDFMap<T> {
private double _cumulativeProb = 0.0;
private double[] _cumulativeProbabilities = new double[2];
private List<T> _entries = new ArrayList<T>();
public void put(double prob, T object) {
if (_cumulativeProbabilities.length <= _entries.size()) {
int c = _cumulativeProbabilities.length << 1;
double[] cumulativeProbabilities = new double[c];
System.arraycopy(_cumulativeProbabilities, 0, cumulativeProbabilities, 0,
_cumulativeProbabilities.length);
_cumulativeProbabilities = cumulativeProbabilities;
}
_cumulativeProb += prob;
_cumulativeProbabilities[_entries.size()] = _cumulativeProb;
_entries.add(object);
}
public T sample() {
if (_entries.isEmpty())
throw new IllegalStateException("No entries in the CDF");
if (_cumulativeProb == 0.0)
throw new IllegalStateException("No cumulative probability in CDF");
double probability = Math.random() * _cumulativeProb;
int index = Arrays.binarySearch(_cumulativeProbabilities, 0,
_entries.size(), probability);
if (index < 0)
index = -(index + 1);
return _entries.get(index);
}
public List<T> sample(int samples) {
if (_entries.isEmpty())
throw new IllegalStateException("No entries in the CDF map");
if (_cumulativeProb == 0.0)
throw new IllegalStateException("No cumulative probability in CDF");
if (samples == 0)
return Collections.emptyList();
List<T> sampled = new ArrayList<T>(samples);
double step = _cumulativeProb / samples;
int index = 0;
for (double p = 0; p < _cumulativeProb && sampled.size() < samples; p += step) {
while (_cumulativeProbabilities[index] <= p)
index++;
sampled.add(_entries.get(index));
}
return sampled;
}
public boolean isEmpty() {
return _entries.isEmpty();
}
public boolean hasProbability() {
return _cumulativeProb > 0.0;
}
public boolean canSample() {
return !_entries.isEmpty() && _cumulativeProb > 0.0;
}
public int size() {
return _entries.size();
}
@Override
public String toString() {
StringBuilder b = new StringBuilder();
b.append("{");
for (int i = 0; i < _entries.size(); i++) {
if (i > 0)
b.append(", ");
b.append(_cumulativeProbabilities[i]);
b.append("=");
b.append(_entries.get(i));
}
b.append("}");
return b.toString();
}
}