package edu.stanford.nlp.ling.tokensregex.matcher;
import edu.stanford.nlp.util.BinaryHeapPriorityQueue;
import java.util.function.Function;
import edu.stanford.nlp.util.PriorityQueue;
import java.util.*;
/**
* Map that is sorted by cost - keep lowest scores
* When deciding what item to keep with the same cost, ties are arbitrarily broken
* @author Angel Chang
*/
public class BoundedCostOrderedMap<K,V> extends AbstractMap<K,V> {
/**
* Limit on the size of the map
*/
final int maxSize;
/**
* Limit on the maximum allowed cost
*/
final double maxCost;
/**
* Priority queue on the keys - note that the priority queue only orders on the cost,
* We can't control the ordering of keys with the same cost
*/
PriorityQueue<K> priorityQueue = new BinaryHeapPriorityQueue<>();
/** Map of keys to their values */
Map<K,V> valueMap = new HashMap<>();
/** Cost function on the values */
Function<V,Double> costFunction;
public BoundedCostOrderedMap(Function<V,Double> costFunction, int maxSize, double maxCost) {
this.costFunction = costFunction;
this.maxSize = maxSize;
this.maxCost = maxCost;
}
@Override
public int size() {
return valueMap.size();
}
@Override
public boolean isEmpty() {
return valueMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return valueMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return valueMap.containsValue(value);
}
@Override
public V get(Object key) {
return valueMap.get(key);
}
public double getCost(V value) {
return costFunction.apply(value);
}
@Override
public V put(K key, V value) {
double cost = getCost(value);
if (cost >= maxCost) return null;
V v = valueMap.get(key);
if (v != null && getCost(v) < cost) return null;
if (maxSize > 0 && priorityQueue.size() >= maxSize ) {
if (priorityQueue.getPriority() > cost) {
K k = priorityQueue.removeFirst();
valueMap.remove(k);
// keep maxSize lowest scores
priorityQueue.changePriority(key, cost);
return valueMap.put(key, value);
}
} else {
priorityQueue.changePriority(key, cost);
return valueMap.put(key, value);
}
return null;
}
@Override
public V remove(Object key) {
priorityQueue.remove(key);
return valueMap.remove(key);
}
@Override
public void putAll(Map<? extends K, ? extends V> m) {
for (K key:m.keySet()) {
put(key, m.get(key));
}
}
@Override
public void clear() {
valueMap.clear();
priorityQueue.clear();
}
@Override
public Set<K> keySet() {
return valueMap.keySet();
}
@Override
public Collection<V> values() {
return valueMap.values();
}
public List<V> valuesList() {
List<V> list = new ArrayList<>();
for (K k: priorityQueue.toSortedList()) {
list.add(valueMap.get(k));
}
Collections.reverse(list);
return list;
}
@Override
public Set<Entry<K, V>> entrySet() {
return valueMap.entrySet();
}
public double topCost() { return priorityQueue.getPriority(); }
public K topKey() { return priorityQueue.getFirst(); }
}