package edu.stanford.nlp.sempre.freebase.lexicons;
import edu.stanford.nlp.sempre.freebase.utils.FileUtils;
import edu.stanford.nlp.stats.ClassicCounter;
import edu.stanford.nlp.stats.Counter;
import fig.basic.LogInfo;
import fig.basic.Option;
import java.util.Arrays;
import java.util.List;
public final class TokenLevelMatchFeatures {
private TokenLevelMatchFeatures() { }
public static class Options {
@Option(gloss = "Verbose") public int verbose = 0;
}
public static Options opts = new Options();
public static boolean usePrefix = false;
public static boolean useSuffix = false;
public static boolean useQueryIsPrefix = true;
public static boolean useAnswerIsPrefix = true;
public static boolean useQueryIsSuffix = true;
public static boolean useAnswerIsSuffix = true;
public static boolean useQueryEqualAnswer = true;
public static boolean useDiffSet = false;
public static boolean useEqualSet = false;
public static boolean useDiffFirstName = false;
public static Counter<String> extractFeatures(String query, String answer) {
Counter<String> res = new ClassicCounter<String>();
query = FileUtils.omitPunct(query).toLowerCase();
answer = FileUtils.omitPunct(answer).toLowerCase();
String[] queryTokens = query.split("\\s+");
String[] answerTokens = answer.split("\\s+");
if (usePrefix) {
boolean prefix = isPrefix(queryTokens, answerTokens);
res.incrementCount("prefix", prefix ? 1 : 0);
}
if (useSuffix) {
boolean suffix = isSuffix(queryTokens, answerTokens);
res.incrementCount("suffix", suffix ? 1 : 0);
}
if (useDiffSet) {
boolean diffSet = isDiffSet(queryTokens, answerTokens);
res.incrementCount("diffset", diffSet ? 1 : 0);
}
if (useEqualSet) {
boolean equalSet = isEqualSet(queryTokens, answerTokens);
res.incrementCount("equalset", equalSet ? 1 : 0);
}
if (useDiffFirstName) {
boolean diffFirstName = isDiffFirstName(queryTokens, answerTokens);
res.incrementCount("diff_firstname", diffFirstName ? 1 : 0);
}
if (useQueryIsPrefix) {
boolean queryIsPrefix = isFirstPrefixOfSecond(queryTokens, answerTokens);
res.incrementCount("queryIsPrefix", queryIsPrefix ? 1 : 0);
}
if (useAnswerIsPrefix) {
boolean answerIsPrefix = isFirstPrefixOfSecond(answerTokens, queryTokens);
res.incrementCount("answerIsPrefix", answerIsPrefix ? 1 : 0);
}
if (useQueryIsSuffix) {
boolean queryIsSuffix = isFirstSuffixOfSecond(queryTokens, answerTokens);
res.incrementCount("queryIsSuffix", queryIsSuffix ? 1 : 0);
}
if (useAnswerIsSuffix) {
boolean answerIsSuffix = isFirstSuffixOfSecond(answerTokens, queryTokens);
res.incrementCount("answerIsSuffix", answerIsSuffix ? 1 : 0);
}
if (useQueryEqualAnswer) {
res.incrementCount("equal", isEqual(queryTokens, answerTokens) ? 1 : 0);
}
return res;
}
private static boolean isPrefix(String[] queryTokens, String[] answerTokens) {
int min = Math.min(queryTokens.length, answerTokens.length);
for (int i = 0; i < min; ++i) {
if (!queryTokens[i].equals(answerTokens[i]))
return false;
}
return true;
}
private static boolean isEqual(String[] queryTokens, String[] answerTokens) {
if (queryTokens.length != answerTokens.length)
return false;
for (int i = 0; i < queryTokens.length; ++i) {
if (!queryTokens[i].equals(answerTokens[i]))
return false;
}
return true;
}
private static boolean isFirstPrefixOfSecond(String[] tokens1, String[] tokens2) {
if (tokens1.length >= tokens2.length)
return false;
for (int i = 0; i < tokens1.length; ++i) {
if (!tokens1[i].equals(tokens2[i]))
return false;
}
return true;
}
private static boolean isSuffix(String[] queryTokens, String[] answerTokens) {
int min = Math.min(queryTokens.length, answerTokens.length);
for (int i = 0; i < min; ++i) {
if (!queryTokens[queryTokens.length - 1 - i].equals(answerTokens[answerTokens.length - 1 - i]))
return false;
}
return true;
}
private static boolean isFirstSuffixOfSecond(String[] tokens1, String[] tokens2) {
if (tokens1.length >= tokens2.length)
return false;
for (int i = 0; i < tokens1.length; ++i) {
if (!tokens1[tokens1.length - 1 - i].equals(tokens2[tokens2.length - 1 - i]))
return false;
}
return true;
}
private static boolean isDiffFirstName(String[] queryTokens, String[] answerTokens) {
return (queryTokens.length == 2 && answerTokens.length == 2 && queryTokens[1].equals(answerTokens[1])
&& !queryTokens[1].equals(answerTokens[0]));
}
private static boolean isDiffSet(String[] queryTokens, String[] answerTokens) {
List<String> queryList = Arrays.asList(queryTokens);
List<String> answerList = Arrays.asList(answerTokens);
return queryList.containsAll(answerList) || answerList.containsAll(queryList);
}
public static int diffSetSize(String query, String answer) {
query = FileUtils.omitPunct(query);
answer = FileUtils.omitPunct(answer);
String[] queryTokens = query.toLowerCase().split("\\s+");
String[] answerTokens = answer.toLowerCase().split("\\s+");
List<String> queryList = Arrays.asList(queryTokens);
List<String> answerList = Arrays.asList(answerTokens);
boolean queryContains = queryList.containsAll(answerList);
boolean answerContains = answerList.containsAll(queryList);
if (!queryContains && !answerContains)
return Integer.MAX_VALUE;
if (queryContains) {
return queryTokens.length - answerTokens.length;
}
return answerTokens.length - queryTokens.length;
}
private static boolean isEqualSet(String[] queryTokens, String[] answerTokens) {
List<String> queryList = Arrays.asList(queryTokens);
List<String> answerList = Arrays.asList(answerTokens);
return queryList.containsAll(answerList) && answerList.containsAll(queryList);
}
public static Counter<String> extractTokenMatchFeatures(List<String> source, List<String> target, boolean strict) {
if (opts.verbose >= 1) {
LogInfo.log("SOURCE: " + source);
LogInfo.log("TARGET: " + target);
}
Counter<String> res = new ClassicCounter<String>();
for (int i = 0; i < source.size(); ++i) {
for (int j = 0; j < target.size(); ++j) {
if (target.get(j).length() <= 2) // do not match very short words
continue;
int matchLength = findLongestMatch(source, target, i, j, strict);
double cover = (double) matchLength / target.size();
if (opts.verbose >= 1) {
if (cover > 0) {
LogInfo.logs("Source index %s, target index %s, cover %s", i, j, cover);
}
}
if (cover > 0) {
if (cover > 0.9999) {
res.setCount("equal", 1);
} else if (j == 0 && res.getCount("prefix") < cover) {
res.setCount("prefix", cover);
} else if (j + matchLength == target.size() && res.getCount("suffix") < cover) {
res.incrementCount("suffix", cover);
} else if (j > 0 && j + matchLength < target.size() && res.getCount("overlap") < cover) {
res.incrementCount("overlap", cover);
}
}
}
}
return res;
}
private static int findLongestMatch(List<String> source, List<String> target,
int i, int j, boolean strict) {
int match = 0;
for (int offset = 0; i + offset < source.size() && j + offset < target.size(); ++offset) {
if (strict) {
if (source.get(i + offset).equals(target.get(j + offset)))
match++;
else
break;
} else {
if (source.get(i + offset).startsWith(target.get(j + offset)) || target.get(j + offset).startsWith(source.get(i + offset)))
match++;
else
break;
}
}
return match;
}
}