package edu.stanford.nlp.sempre.tables.features; import java.util.*; import edu.stanford.nlp.sempre.*; import edu.stanford.nlp.sempre.tables.TableTypeSystem; import fig.basic.*; /** * Extract features based on (phrase, denotation) pairs. * Intuition: "when" usually matches a date, which "how many" usually matches a number. * * @author ppasupat */ public class PhraseDenotationFeatureComputer implements FeatureComputer { public static class Options { @Option(gloss = "Verbosity") public int verbose = 0; @Option(gloss = "Look for the type under the first cell property") public boolean lookUnderCellProperty = false; @Option(gloss = "Define features for generic cell types too") public boolean useGenericCellType = false; } public static Options opts = new Options(); @Override public void extractLocal(Example ex, Derivation deriv) { if (!(FeatureExtractor.containsDomain("custom-denotation") || FeatureExtractor.containsDomain("phrase-denotation") || FeatureExtractor.containsDomain("headword-denotation"))) return; // Only compute features at the root. if (!deriv.isRoot(ex.numTokens())) return; Collection<String> denotationTypes = tableTypes(deriv); extractCustomDenotationFeatures(ex, deriv, denotationTypes); extractPhraseDenotationFeatures(ex, deriv, denotationTypes); extractHeadwordDenotationFeatures(ex, deriv, denotationTypes); } public static Collection<String> tableTypes(Derivation deriv) { Set<String> denotationTypes = new HashSet<>(); // Type based on SemType populateSemType("", deriv.type, denotationTypes); // Look for the type under the first cell property if (opts.lookUnderCellProperty) { Formula formula = deriv.formula; if (formula instanceof JoinFormula) { JoinFormula join = (JoinFormula) formula; String property = getCellProperty(join.relation); if (property != null) { populateSemType(property + "/", TypeInference.inferType(join.child), denotationTypes); } } } if (denotationTypes.isEmpty()) denotationTypes.add("OTHER"); return denotationTypes; } private static void populateSemType(String prefix, SemType type, Collection<String> denotationTypes) { LispTree tree = type.toLispTree(); if (tree.isLeaf()) { denotationTypes.add(prefix + tree.value); } else { for (LispTree subtree : tree.children) { if (!subtree.isLeaf()) continue; // TODO: not sure if this is correct if (subtree.value.startsWith(TableTypeSystem.CELL_TYPE)) { denotationTypes.add(prefix + subtree.value); if (opts.useGenericCellType) denotationTypes.add(prefix + TableTypeSystem.CELL_TYPE); } } } } private static String getCellProperty(Formula formula) { LispTree tree = formula.toLispTree(); if (tree.isLeaf()) { String value = tree.value; if (value.charAt(0) == '!' && value.substring(1).startsWith(TableTypeSystem.CELL_PROPERTY_NAME_PREFIX)) return value; } else { if ("reverse".equals(tree.child(0).value) && tree.child(1).value.startsWith(TableTypeSystem.CELL_PROPERTY_NAME_PREFIX)) return "!" + tree.child(1).value; } return null; } // ============================================================ // Custom Denotation Features // ============================================================ private void extractCustomDenotationFeatures(Example ex, Derivation deriv, Collection<String> denotationTypes) { if (!FeatureExtractor.containsDomain("custom-denotation")) return; if (deriv.value instanceof ErrorValue) { deriv.addFeature("custom-denotation", "error"); return; } else if (deriv.value instanceof ListValue) { ListValue list = (ListValue) deriv.value; int size = list.values.size(); deriv.addFeature("custom-denotation", "size" + (size < 3 ? "=" + size : ">=" + 3)); if (size == 1) { Value value = list.values.get(0); if (value instanceof NumberValue) { double number = ((NumberValue) value).value; deriv.addFeature("custom-denotation", "number" + (number > 0 ? ">0" : number == 0 ? "=0" : "<0")); deriv.addFeature("custom-denotation", "number" + ((int) number == number ? "-int" : "-frac")); } } } } // ============================================================ // Phrase - Denotation // ============================================================ private void extractPhraseDenotationFeatures(Example ex, Derivation deriv, Collection<String> denotationTypes) { if (!FeatureExtractor.containsDomain("phrase-denotation")) return; List<PhraseInfo> phraseInfos = PhraseInfo.getPhraseInfos(ex); if (opts.verbose >= 2) LogInfo.logs("%s %s %s", deriv.value, deriv.type, denotationTypes); for (String denotationType : denotationTypes) { for (PhraseInfo phraseInfo : phraseInfos) { deriv.addFeature("p-d", phraseInfo.lemmaText + ";" + denotationType); } // Check original column text String[] tokens = denotationType.split("/"); String actualType = tokens[tokens.length - 1], suffix = (tokens.length == 1) ? "" : "(" + tokens[0] + ")"; String originalColumn; if ((originalColumn = PredicateInfo.getOriginalString(actualType, ex)) != null) { originalColumn = PredicateInfo.getLemma(originalColumn); for (PhraseInfo phraseInfo : phraseInfos) { if (phraseInfo.lemmaText.equals(originalColumn)) { if (opts.verbose >= 2) LogInfo.logs("%s %s %s %s", phraseInfo, actualType, originalColumn, Arrays.asList(tokens)); deriv.addFeature("p-d", "=" + suffix); } } } } } // ============================================================ // Headword - Denotation // ============================================================ private void extractHeadwordDenotationFeatures(Example ex, Derivation deriv, Collection<String> denotationTypes) { if (!FeatureExtractor.containsDomain("headword-denotation")) return; HeadwordInfo headwordInfo = HeadwordInfo.analyze(ex.languageInfo); if (headwordInfo == null) return; if (opts.verbose >= 2) LogInfo.logs("%s [%s] | %s %s %s", ex.utterance, headwordInfo, deriv.value, deriv.type, denotationTypes); for (String denotationType : denotationTypes) { deriv.addFeature("h-d", headwordInfo + ";" + denotationType); deriv.addFeature("h-d", headwordInfo.questionWordTuple() + ";" + denotationType); deriv.addFeature("h-d", headwordInfo.headwordTuple() + ";" + denotationType); // Check original column text String[] tokens = denotationType.split("/"); String actualType = tokens[tokens.length - 1], suffix = (tokens.length == 1) ? "" : "(" + tokens[0] + ")"; String originalColumn; if ((originalColumn = PredicateInfo.getOriginalString(actualType, ex)) != null) { originalColumn = PredicateInfo.getLemma(originalColumn); if (headwordInfo.headword.equals(originalColumn)) { if (opts.verbose >= 2) LogInfo.logs("%s %s %s %s", headwordInfo, actualType, originalColumn, Arrays.asList(tokens)); deriv.addFeature("h-d", "=" + suffix); deriv.addFeature("h-d", headwordInfo.questionWordTuple() + "=" + suffix); } } } } }