package edu.stanford.nlp.sempre.interactive;
import java.util.ArrayList;
import java.util.List;
import edu.stanford.nlp.sempre.Derivation;
import edu.stanford.nlp.sempre.Example;
import edu.stanford.nlp.sempre.FeatureComputer;
import edu.stanford.nlp.sempre.FeatureExtractor;
import edu.stanford.nlp.sempre.Rule;
import fig.basic.Option;
/**
* Feature computer for the the dependency-based action language TODOs: -
* control what categories to abstract out - efficiency improvement, right now
* use all members of the cross product
*
* @author sidaw
*/
public class DALFeatureComputer implements FeatureComputer {
public static class Options {
@Option(gloss = "Verbosity")
public int verbose = 0;
@Option(gloss = "the N in N-gram")
public int ngramN = 3;
@Option(gloss = "size of the context window to consider")
public int windowSize = 2;
}
public static Options opts = new Options();
@Override
public void extractLocal(Example ex, Derivation deriv) {
addStatsFeatures(ex, deriv);
addWindowFeatures(ex, deriv);
addSocialFeatures(ex, deriv);
extractRuleFeatures(ex, deriv);
extractSpanFeatures(ex, deriv);
}
// function to abstract out ALL anchored stuff in the utterance.
private List<String> abstractAnchors(Derivation deriv, List<String> tokens, int window) {
if (deriv.start == -1)
return tokens;
List<String> newTokens = new ArrayList<>();
int startInd = Math.max(0, deriv.start - window);
int endInd = Math.min(tokens.size(), deriv.end + window);
newTokens.addAll(tokens.subList(startInd, deriv.start));
newTokens.add(deriv.cat);
newTokens.addAll(tokens.subList(deriv.end, endInd));
return newTokens;
}
private List<String> getAllNgrams(List<String> tokens, int n, Derivation deriv) {
List<String> ngrams = new ArrayList<>();
List<String> paddedTokens = new ArrayList<>();
if (deriv.start == -1) // floating, just add everything
paddedTokens.addAll(tokens);
else {
paddedTokens.addAll(tokens.subList(Math.max(0, deriv.start - n + 1), Math.min(tokens.size(), deriv.end + n - 1)));
}
for (int i = 0; i < paddedTokens.size() - n + 1; i++) {
List<String> current = new ArrayList<>(paddedTokens.subList(i, i + n));
ngrams.add(current.toString());
}
return ngrams;
}
private List<String> getAllSkipGrams(List<String> tokens, Derivation deriv) {
List<String> ngrams = new ArrayList<>();
List<String> paddedTokens = new ArrayList<>();
if (tokens.size() < 3)
return ngrams;
if (deriv.start == -1) // floating, just add everything
paddedTokens.addAll(tokens);
else
paddedTokens.addAll(tokens.subList(Math.max(0, deriv.start - 2), Math.min(tokens.size(), deriv.end + 2)));
for (int i = 0; i < tokens.size() - 2; i++) {
ngrams.add("[" + tokens.get(i).toString() + ", *, " + tokens.get(i + 2) + "]");
}
return ngrams;
}
private void addWindowFeatures(Example ex, Derivation deriv) {
if (!FeatureExtractor.containsDomain(":window"))
return;
if (deriv.rule != Rule.nullRule) {
deriv.addFeature(":window", abstractAnchors(deriv, ex.getTokens(), 1).toString());
deriv.addFeature(":window", abstractAnchors(deriv, ex.getTokens(), 2).toString());
}
}
private void addStatsFeatures(Example ex, Derivation deriv) {
if (!FeatureExtractor.containsDomain(":stats"))
return;
if (deriv.rule != Rule.nullRule) {
if (deriv.rule.isInduced())
deriv.addFeature(":stats", "induced");
else
deriv.addFeature(":stats", "core");
if (deriv.rule.source != null) {
deriv.addFeature(":stats", "cite", deriv.rule.source.cite);
if (deriv.rule.source.cite > 0)
deriv.addFeature(":stats", "has_cite");
else
deriv.addFeature(":stats", "no_cite");
if (deriv.rule.source.self > 0)
deriv.addFeature(":stats", "has_selfcite");
else
deriv.addFeature(":stats", "no_selfcite");
if (deriv.rule.source.align)
deriv.addFeature(":stats", "align");
else
deriv.addFeature(":stats", "no_align");
if (deriv.rule.getInfoTag("simple_packing") != -1.0)
deriv.addFeature(":stats", "simple_packing");
else
deriv.addFeature(":stats", "no_simple_packing");
}
}
}
private void addSocialFeatures(Example ex, Derivation deriv) {
if (!FeatureExtractor.containsDomain(":social"))
return;
if (deriv.rule != Rule.nullRule && deriv.rule.source != null) {
// everyone like a particular author
deriv.addFeature(":social", deriv.rule.source.uid);
// a particular user likes a particular author, perhaps himself
deriv.addFeature(":social", deriv.rule.source.uid + "::" + ex.id);
// the degree everyone likes to use their own rules
deriv.addFeature(":social", "isself::" + deriv.rule.source.uid.equals(ex.id));
}
}
// Add an indicator for each applied rule.
private void extractRuleFeatures(Example ex, Derivation deriv) {
if (!FeatureExtractor.containsDomain(":rule"))
return;
if (deriv.rule != Rule.nullRule) {
deriv.addFeature(":rule", "fire");
deriv.addFeature(":rule", deriv.rule.toString());
}
}
// Extract features on the linguistic information of the spanned (anchored)
// tokens.
// (Not applicable for floating rules)
private void extractSpanFeatures(Example ex, Derivation deriv) {
if (!FeatureExtractor.containsDomain(":span") || deriv.start == -1)
return;
deriv.addFeature(":span", "cat=" + deriv.cat + ":: len=" + (deriv.end - deriv.start));
deriv.addFeature(":span", "cat=" + deriv.cat + ":: " + ex.token(deriv.start) + "..." + ex.token(deriv.end - 1));
}
}