package edu.stanford.nlp.sempre.freebase.utils;
import edu.stanford.nlp.stats.ClassicCounter;
import edu.stanford.nlp.stats.Counter;
import edu.stanford.nlp.stats.Counters;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class MathUtils {
private MathUtils() { }
public static double jaccard(double intersection, double size1, double size2, double smoothing) {
return intersection / (size1 + size2 + smoothing - intersection);
}
public static <E> double generalizedJensenShannonDivergence(Counter<E> c1, Counter<E> c2) {
double sum = 0.0;
Set<E> nonZeroEntries = new HashSet<E>();
for (E entry : nonZeroEntries) {
double u = c1.getCount(entry);
double v = c2.getCount(entry);
sum += coordinateJsDivergence(u, v);
}
return sum / 2.0;
}
private static double coordinateJsDivergence(double u, double v) {
return u * Math.log(2 * u / (u + v)) + v * Math.log(2 * v / (u + v));
}
public static double coordinateJsDiverDeriv(double x, double y) {
if (x == 0.0)
return 0.0;
if (y == 0.0)
return Math.log(2) / 2.0;
double xPlusY = x + y;
double res = -1 * Math.log(xPlusY) - (y / xPlusY) + x * (1 / x - 1 / xPlusY) + Math.log(x) + Math.log(2);
return res / 2.0;
}
public static Counter<String> prefixCounterKeys(Counter<String> counter, String prefix) {
Counter<String> res = new ClassicCounter<String>();
for (String key : counter.keySet()) {
res.setCount(prefix + "_" + key, counter.getCount(key));
}
return res;
}
public static double vectorCosine(List<Double> array1, List<Double> array2) {
if (array1.size() != array2.size())
throw new RuntimeException("Cannot compute cosine of arrays of differnt sizes: " + array1.size() + " " + array2.size());
double dotProd = 0.0;
double lsq1 = 0.0;
double lsq2 = 0.0;
for (int i = 0; i < array1.size(); ++i) {
dotProd += array1.get(i) * array2.get(i);
lsq1 += array1.get(i) * array1.get(i);
lsq2 += array2.get(i) * array2.get(i);
}
return dotProd / (Math.sqrt(lsq1) * Math.sqrt(lsq2));
}
public static double euclidDistance(List<Double> array1, List<Double> array2) {
if (array1.size() != array2.size())
throw new RuntimeException("Cannot compute cosine of arrays of differnt sizes: " + array1.size() + " " + array2.size());
double sqDistance = 0.0;
for (int i = 0; i < array1.size(); ++i) {
sqDistance += Math.pow(array1.get(i) - array2.get(i), 2);
}
return Math.sqrt(sqDistance);
}
public static <T> double sumDoubleMap(Map<T, DoubleContainer> map) {
double sum = 0.0;
for (DoubleContainer d : map.values())
sum += d.value();
return sum;
}
public static <T> void normalizeDoubleMap(Map<T, DoubleContainer> map) {
double sum = 0.0;
for (DoubleContainer d : map.values())
sum += d.value();
for (T key : map.keySet()) {
double normalizedValue = map.get(key).value() / sum;
map.get(key).set(normalizedValue);
}
}
/**
* Computes jaccard between sets of objects
* @param x
* @param y
* @return
*/
public static <T> double jaccard(Set<T> x, Set<T> y) {
Set<T> intersection = new HashSet<T>(x);
intersection.retainAll(y);
Set<T> union = new HashSet<T>(x);
union.addAll(y);
double res = union.size() == 0 ? 1.0 : (double) intersection.size() / union.size();
return res;
}
/**
* Computes jaccard between sets of objects
* @param x
* @param y
* @return
*/
public static <T> double jaccard(List<T> x, List<T> y) {
Set<T> intersection = new HashSet<T>(x);
intersection.retainAll(y);
Set<T> union = new HashSet<T>(x);
union.addAll(y);
double res = union.size() == 0 ? 1.0 : (double) intersection.size() / union.size();
return res;
}
/**
* how many of the tokens in x are covered by y
* @param x
* @param y
* @return
*/
public static <T> double coverage(List<T> x, List<T> y) {
Set<T> yTokens = new HashSet<T>(y);
int covered = 0;
for (T xItem : x) {
if (yTokens.contains(xItem))
covered++;
}
return (double) covered / x.size();
}
/**
* Geometric average of unigram bigram and trigram precision
* @param test
* @param ref
* @return
*/
public static double bleu(List<String> test, List<String> ref) {
Set<String> refUnigrams = new HashSet<String>();
Set<String> refBigrams = new HashSet<String>();
Set<String> refTrigrams = new HashSet<String>();
for (int i = 0; i < ref.size(); ++i) {
refUnigrams.add(ref.get(i));
if (i < ref.size() - 1)
refBigrams.add(ref.get(i) + " " + ref.get(i + 1));
if (i < ref.size() - 2)
refTrigrams.add(ref.get(i) + " " + ref.get(i + 1) + " " + ref.get(i + 2));
}
int unigramCov = 0;
int bigramCov = 0;
int trigramCov = 0;
for (int i = 0; i < test.size(); ++i) {
if (refUnigrams.contains(test.get(i)))
unigramCov++;
if (i < test.size() - 1) {
String bigram = test.get(i) + " " + test.get(i + 1);
if (refBigrams.contains(bigram))
bigramCov++;
}
if (i < test.size() - 2) {
String trigram = test.get(i) + " " + test.get(i + 1) + " " + test.get(i + 2);
if (refTrigrams.contains(trigram))
trigramCov++;
}
}
double unigramPrec = (double) unigramCov / test.size();
double bigramPrec = (double) bigramCov / (test.size() - 1);
double trigramPrec = (double) trigramCov / (test.size() - 2);
double exponent = (double) 1 / 3;
return Math.pow(unigramPrec * bigramPrec * trigramPrec, exponent);
}
public static double tokensCosine(List<String> x, List<String> y) {
Counter<String> xCounter = new ClassicCounter<String>();
for (String str : x)
xCounter.incrementCount(str);
Counter<String> yCounter = new ClassicCounter<String>();
for (String str : y)
yCounter.incrementCount(str);
return Counters.cosine(xCounter, yCounter);
}
}