package edu.stanford.nlp.sempre; import fig.basic.MapUtils; import fig.basic.NumUtils; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; /** * Utils for <code>ReinforcementParser</code> */ public final class ReinforcementUtils { private static double logMaxValue = Math.log(Double.MAX_VALUE); private ReinforcementUtils() { } // add to double map after adding prefix to all keys public static void addToDoubleMap(Map<String, Double> mutatedMap, Map<String, Double> addedMap, String prefix) { for (String key : addedMap.keySet()) MapUtils.incr(mutatedMap, prefix + key, addedMap.get(key)); } public static void subtractFromDoubleMap(Map<String, Double> mutatedMap, Map<String, Double> subtractedMap) { for (String key : subtractedMap.keySet()) MapUtils.incr(mutatedMap, key, -1 * subtractedMap.get(key)); } // subtract from double map after adding prefix to all keys public static void subtractFromDoubleMap(Map<String, Double> mutatedMap, Map<String, Double> subtractedMap, String prefix) { for (String key : subtractedMap.keySet()) MapUtils.incr(mutatedMap, prefix + key, -1 * subtractedMap.get(key)); } public static Map<String, Double> multiplyDoubleMap(Map<String, Double> map, double factor) { Map<String, Double> res = new HashMap<>(); for (Map.Entry<String, Double> entry: map.entrySet()) res.put(entry.getKey(), entry.getValue() * factor); return res; } public static int sampleIndex(Random rand, List<? extends HasScore> scorables, double denominator) { double randD = rand.nextDouble(); double sum = 0; for (int i = 0; i < scorables.size(); ++i) { HasScore pds = scorables.get(i); double prob = computeProb(pds, denominator); sum += prob; if (randD < sum) { return i; } } throw new RuntimeException(sum + " < " + randD); } public static int sampleIndex(Random rand, double[] scores, double denominator) { double randD = rand.nextDouble(); double sum = 0; for (int i = 0; i < scores.length; ++i) { double pds = scores[i]; double prob = computeProb(pds, denominator); sum += prob; if (randD < sum) { return i; } } throw new RuntimeException(sum + " < " + randD); } public static int sampleIndex(Random rand, double[] probs) { double randD = rand.nextDouble(); double sum = 0; for (int i = 0; i < probs.length; ++i) { sum += probs[i]; if (randD < sum) return i; } throw new RuntimeException(sum + " < " + randD); } public static double computeProb(HasScore deriv, double denominator) { double prob = Math.exp(deriv.getScore() - denominator); if (prob < -0.0001 || prob > 1.0001) throw new RuntimeException("Probability is out of range, prob=" + prob + ",score=" + deriv.getScore() + ", denom=" + denominator); return prob; } public static double computeProb(double score, double denominator) { double prob = Math.exp(score - denominator); if (prob < -0.0001 || prob > 1.0001) throw new RuntimeException("Probability is out of range, prob=" + prob + ",score=" + score + ", denom=" + denominator); return prob; } public static double computeLogExpSum(List<? extends HasScore> scorables) { double sum = Double.NEGATIVE_INFINITY; for (HasScore scorable : scorables) { sum = NumUtils.logAdd(sum, scorable.getScore()); } return sum; } public static double[] expNormalize(List<? extends HasScore> scorables) { // Input: log probabilities (unnormalized too) // Output: normalized probabilities // probs actually contains log probabilities; so we can add an arbitrary constant to make // the largest log prob 0 to prevent overflow problems double[] res = new double[scorables.size()]; double max = Double.NEGATIVE_INFINITY; for (int i = 0; i < scorables.size(); i++) max = Math.max(max, scorables.get(i).getScore()); if (Double.isInfinite(max)) throw new RuntimeException("Scoreables is probably empty"); for (int i = 0; i < scorables.size(); i++) res[i] = Math.exp(scorables.get(i).getScore() - max); NumUtils.normalize(res); return res; } public static double[] expNormalize(ParserAgenda<? extends HasScore> scorables) { // Input: log probabilities (unnormalized too) // Output: normalized probabilities // probs actually contains log probabilities; so we can add an arbitrary constant to make // the largest log prob 0 to prevent overflow problems double[] res = new double[scorables.size()]; double max = Double.NEGATIVE_INFINITY; for (HasScore scorable : scorables) max = Math.max(max, scorable.getScore()); if (Double.isInfinite(max)) throw new RuntimeException("Scoreables is probably empty"); int i = 0; for (HasScore scorable : scorables) res[i++] = Math.exp(scorable.getScore() - max); NumUtils.normalize(res); return res; } // Return log(exp(a)-exp(b)) public static double logSub(double a, double b) { if(a <= b) throw new RuntimeException("First argument must be strictly greater than second argument"); if(Double.isInfinite(b) || a-b > logMaxValue || b-a < 30) return a; return a + Math.log(1d - Math.exp(b-a)); } }