package edu.stanford.nlp.sempre.tables.lambdadcs;
import java.util.*;
import fig.basic.*;
import edu.stanford.nlp.sempre.*;
import edu.stanford.nlp.sempre.corenlp.CoreNLPAnalyzer;
import edu.stanford.nlp.sempre.tables.TableKnowledgeGraph;
import org.testng.annotations.Test;
/**
* Test LambdaDCSExecutor: Execute a Formula on a given context graph.
*
* @author ppasupat
*/
public class LambdaDCSExecutorTest {
// ============================================================
// Value Checker (copied from SparqlExectutorTest)
// ============================================================
public static abstract class ValuesChecker {
void checkValue(Value value) {
if (value instanceof ListValue)
checkList(new HashSet<>(((ListValue) value).values));
else if (value instanceof PairListValue)
checkPairList(new HashSet<>(((PairListValue) value).pairs));
else
throw new RuntimeException("The answer is not a ListValue or a PairListValue.");
}
void checkList(Collection<Value> values) {
// Override this
throw new RuntimeException("Got a ListValue; expected something else: " + values);
}
void checkPairList(Collection<Pair<Value, Value>> pairs) {
// Override this
throw new RuntimeException("Got a PairListValue; expected something else: " + pairs);
}
}
public static ValuesChecker size(final int expectedNumResults) {
return new ValuesChecker() {
public void checkList(Collection<Value> values) {
if (values.size() != expectedNumResults)
throw new RuntimeException("Expected " + expectedNumResults + " results, but got " + values.size() + ": " + values);
}
public void checkPairList(Collection<Pair<Value, Value>> pairs) {
if (pairs.size() != expectedNumResults)
throw new RuntimeException("Expected " + expectedNumResults + " results, but got " + pairs.size() + ": " + pairs);
}
};
}
public static ValuesChecker sizeAtLeast(final int expectedNumResults) {
return new ValuesChecker() {
public void checkList(Collection<Value> values) {
if (values.size() < expectedNumResults)
throw new RuntimeException("Expected at least " + expectedNumResults + " results, but got " + values.size() + ": " + values);
}
public void checkPairList(Collection<Pair<Value, Value>> pairs) {
if (pairs.size() < expectedNumResults)
throw new RuntimeException("Expected at least " + expectedNumResults + " results, but got " + pairs.size() + ": " + pairs);
}
};
}
public static ValuesChecker matches(String expected) {
final Value expectedValue = Value.fromString(expected);
return new ValuesChecker() {
public void checkList(Collection<Value> values) {
if (values.size() != 1 || !(new ArrayList<>(values)).get(0).equals(expectedValue))
throw new RuntimeException("Expected " + expectedValue + ", but got " + values);
}
};
}
public static ValuesChecker matchesAll(String... expected) {
final List<Value> expectedValues = new ArrayList<>();
for (String x : expected) expectedValues.add(Value.fromString(x));
return new ValuesChecker() {
public void checkList(Collection<Value> values) {
if (values.size() != expectedValues.size() || !expectedValues.containsAll(values))
throw new RuntimeException("Expected " + new ListValue(expectedValues) + ", but got " + values);
}
};
}
public static ValuesChecker regexMatches(final String expectedPattern) {
return new ValuesChecker() {
public void checkList(Collection<Value> values) {
if (values.size() != 1 || !(new ArrayList<>(values)).get(0).toString().matches(expectedPattern))
throw new RuntimeException("Expected " + expectedPattern + ", but got " + values);
}
};
}
// ============================================================
// Processing
// ============================================================
LambdaDCSExecutor executor = new LambdaDCSExecutor();
protected static void runFormula(LambdaDCSExecutor executor, String formula, KnowledgeGraph graph) {
runFormula(executor, formula, graph, sizeAtLeast(0));
}
protected static void runFormula(LambdaDCSExecutor executor, String formula, KnowledgeGraph graph, ValuesChecker checker) {
ContextValue context = new ContextValue(graph);
LambdaDCSExecutor.opts.verbose = 5;
LambdaDCSExecutor.opts.executeBinary = true;
LogInfo.begin_track("formula: %s", formula);
Executor.Response response = executor.execute(Formulas.fromLispTree(LispTree.proto.parseFromString(formula)), context);
LogInfo.logs("RESULT: %s", response.value);
LogInfo.end_track();
if (checker != null)
checker.checkValue(response.value);
}
protected static KnowledgeGraph getKnowledgeGraph(String name) {
if ("simple".equals(name)) {
return KnowledgeGraph.fromLispTree(LispTree.proto.parseFromString(
"(graph NaiveKnowledgeGraph ((number 1) (number 2) (number 3)))"));
} else if ("prez".equals(name)) {
return KnowledgeGraph.fromLispTree(LispTree.proto.parseFromString(
"(graph NaiveKnowledgeGraph " +
"(fb:en.barack_obama fb:people.person.place_of_birth fb:en.honolulu)" +
"(fb:en.barack_obama fb:people.person.profession fb:en.politician)" +
"(fb:en.barack_obama fb:people.person.weight_kg (number 82))" +
"(fb:en.george_w_bush fb:people.person.place_of_birth fb:en.new_haven)" +
"(fb:en.george_w_bush fb:people.person.profession fb:en.politician)" +
"(fb:en.george_w_bush fb:people.person.weight_kg (number 86))" +
"(fb:en.bill_clinton fb:people.person.place_of_birth fb:en.hope_arkansas)" +
"(fb:en.bill_clinton fb:people.person.profession fb:en.lawyer)" +
"(fb:en.bill_clinton fb:people.person.profession fb:en.politician)" +
"(fb:en.bill_clinton fb:people.person.weight_kg (number 100))" +
"(fb:en.nicole_kidman fb:people.person.place_of_birth fb:en.honolulu)" +
"(fb:en.nicole_kidman fb:people.person.profession fb:en.actor)" +
"(fb:en.nicole_kidman fb:people.person.weight_kg (number 58))" +
"(fb:en.morgan_freeman fb:people.person.place_of_birth fb:en.memphis)" +
"(fb:en.morgan_freeman fb:people.person.profession fb:en.actor)" +
"(fb:en.morgan_freeman fb:people.person.weight_kg (number 91))" +
"(fb:en.ronald_reagan fb:people.person.place_of_birth fb:en.tampico)" +
"(fb:en.ronald_reagan fb:people.person.profession fb:en.politician)" +
"(fb:en.ronald_reagan fb:people.person.weight_kg (number 82))" +
"(fb:en.honolulu fb:location.location.containedby fb:en.hawaii)" +
"(fb:en.memphis fb:location.location.containedby fb:en.tennessee)" +
"(fb:en.new_haven fb:location.location.containedby fb:en.connecticut)" +
"(fb:en.hope_arkansas fb:location.location.containedby fb:en.arkansas)" +
"(fb:en.tampico fb:location.location.containedby fb:en.illinois)" +
")"));
} else if ("csv".equals(name)) {
return TableKnowledgeGraph.fromFilename("tables/toy-examples/random/nikos_machlas.csv");
} else if ("csv2".equals(name)) {
return TableKnowledgeGraph.fromFilename("lib/data/tables/csv/204-csv/495.tsv");
} else if ("csv3".equals(name)) {
return TableKnowledgeGraph.fromFilename("lib/data/tables/csv/203-csv/839.tsv");
}
throw new RuntimeException("Unknown graph name: " + name);
}
// ============================================================
// Actual Tests
// ============================================================
@Test(groups = "lambdaSimple") public void lambdaOnGraphDummyTest() {
KnowledgeGraph graph = getKnowledgeGraph("simple");
runFormula(executor, "(number 3)", graph, matches("(number 3)"));
}
@Test(groups = "lambdaPrez") public void lambdaOnGraphBasicTest() {
KnowledgeGraph graph = getKnowledgeGraph("prez");
runFormula(executor, "(fb:people.person.place_of_birth fb:en.honolulu)",
graph, matchesAll("(name fb:en.barack_obama)", "(name fb:en.nicole_kidman)"));
runFormula(executor, "(!fb:people.person.place_of_birth (fb:people.person.place_of_birth fb:en.honolulu))",
graph, matches("(name fb:en.honolulu)"));
runFormula(executor, "(!fb:people.person.place_of_birth fb:en.barack_obama)",
graph, matches("(name fb:en.honolulu)"));
runFormula(executor, "(and (fb:people.person.place_of_birth fb:en.honolulu) (fb:people.person.profession fb:en.actor))",
graph, matches("(name fb:en.nicole_kidman)"));
runFormula(executor, "(or (fb:people.person.place_of_birth fb:en.honolulu) (fb:people.person.profession fb:en.actor))",
graph, matchesAll("(name fb:en.barack_obama)", "(name fb:en.nicole_kidman)", "(name fb:en.morgan_freeman)"));
runFormula(executor, "(count (or (fb:people.person.place_of_birth fb:en.honolulu) (fb:people.person.profession fb:en.actor)))",
graph, matches("(number 3)"));
}
@Test(groups = "lambdaPrez") public void lambdaOnGraphInfiniteTest() {
KnowledgeGraph graph = getKnowledgeGraph("prez");
runFormula(executor, "(!fb:people.person.place_of_birth *)",
graph, size(5));
runFormula(executor, "(and * (fb:people.person.place_of_birth fb:en.honolulu))",
graph, matchesAll("(name fb:en.barack_obama)", "(name fb:en.nicole_kidman)"));
runFormula(executor, "(max (!fb:people.person.weight_kg *))",
graph, matches("(number 100)"));
runFormula(executor, "(sum (!fb:people.person.weight_kg *))",
graph, matches("(number 499)"));
runFormula(executor, "(argmax 1 1 * fb:people.person.weight_kg)",
graph, matches("(name fb:en.bill_clinton)"));
runFormula(executor, "(fb:people.person.weight_kg (> (number 95)))",
graph, matches("(name fb:en.bill_clinton)"));
runFormula(executor, "(fb:people.person.weight_kg (!= (!fb:people.person.weight_kg fb:en.barack_obama)))",
graph, size(4));
runFormula(executor, "(fb:people.person.weight_kg ((reverse >) (number 82)))",
graph, matchesAll("(name fb:en.barack_obama)", "(name fb:en.ronald_reagan)", "(name fb:en.nicole_kidman)"));
runFormula(executor, "(fb:people.person.weight_kg (and (< (number 100)) (> (number 90))))",
graph, matches("(name fb:en.morgan_freeman)"));
}
@Test(groups = "lambdaPrez") public void lambdaOnGraphLambdaTest() {
KnowledgeGraph graph = getKnowledgeGraph("prez");
runFormula(executor, "((lambda x (fb:people.person.place_of_birth (var x))) fb:en.honolulu)",
graph, matchesAll("(name fb:en.barack_obama)", "(name fb:en.nicole_kidman)"));
runFormula(executor, "(argmax 1 1 (fb:location.location.containedby *) (reverse (lambda x (count (fb:people.person.place_of_birth (var x))))))",
graph, matches("(name fb:en.honolulu)"));
runFormula(executor, "(and (!fb:people.person.place_of_birth *) ((reverse (lambda x (fb:people.person.place_of_birth (var x)))) fb:en.barack_obama))",
graph, matches("(name fb:en.honolulu)"));
runFormula(executor, "(and ((reverse (lambda x (fb:people.person.place_of_birth (var x)))) fb:en.barack_obama) (!fb:people.person.place_of_birth *))",
graph, matches("(name fb:en.honolulu)"));
runFormula(executor, "((reverse (lambda x (fb:people.person.place_of_birth (var x)))) fb:en.barack_obama)",
graph, matches("(name fb:en.honolulu)"));
}
@Test(groups = "floating") public void lambdaOnGraphFloatingLambdaTest() {
KnowledgeGraph graph = getKnowledgeGraph("prez");
runFormula(executor, "(lambda x (fb:people.person.place_of_birth (var x)))", graph);
runFormula(executor, "(lambda x ((reverse fb:people.person.place_of_birth) (var x)))", graph);
runFormula(executor, "(lambda x (count ((reverse fb:people.person.place_of_birth) (var x))))", graph);
}
@Test(groups = "lambdaCSV") public void lambdaOnGraphCSVTest() {
KnowledgeGraph graph = getKnowledgeGraph("csv");
runFormula(executor, "(number 3)", graph, matches("(number 3)"));
runFormula(executor, "(!fb:row.row.score (fb:row.row.opponent fb:cell.austria))",
graph, matches("(name fb:cell.1_2)"));
runFormula(executor, "(count (fb:row.row.result fb:cell.win))",
graph, matches("(number 16)"));
// Depending on tie-breaking, one of these will be correct
try {
// Return all top ties
runFormula(executor, "(argmax 1 1 (!fb:row.row.opponent (fb:type.object.type fb:type.row)) "
+ "(reverse (lambda x (count (fb:row.row.opponent (var x))))))",
graph, size(5));
} catch (Exception e) {
// Return only one item
runFormula(executor, "(count (fb:row.row.opponent (argmax 1 1 (!fb:row.row.opponent (fb:type.object.type fb:type.row)) "
+ "(reverse (lambda x (count (fb:row.row.opponent (var x))))))))",
graph, matches("(number 2)"));
}
}
@Test(groups = "lambdaCSV2") public void lambdaOnGraphCSV2Test() {
KnowledgeGraph graph = getKnowledgeGraph("csv2");
runFormula(executor,
"(and (!= (and (!= fb:cell.away) fb:cell.home)) ((reverse fb:row.row.opponent) (fb:row.row.index (- (number 1) (number 1)))))",
graph, matches("(name fb:cell.derby_county)"));
}
@Test(groups = "lambdaCSV3") public void lambdaOnGraphCSV3Test() {
LanguageAnalyzer.setSingleton(new CoreNLPAnalyzer());
KnowledgeGraph graph = getKnowledgeGraph("csv3");
runFormula(executor,
"(count (fb:type.object.type fb:type.row))",
graph, matches("(number 21)"));
runFormula(executor,
"(count (fb:row.row.opened (fb:cell.cell.date (< (date 1926 -1 -1)))))",
graph, matches("(number 6)"));
runFormula(executor,
"(sum (- (count ((reverse fb:row.row.index) (fb:type.object.type fb:type.row))) " +
"((reverse fb:row.row.index) (fb:row.row.latitude ((reverse fb:row.row.longitude) (fb:type.object.type fb:type.row))))))",
graph, matches("(number 6)"));
runFormula(executor,
"(- (number 1926) (argmax (number 1) (number 1) ((reverse fb:cell.cell.number) (or (or (or fb:cell.1920 fb:cell.1925) fb:cell.1926) fb:cell.1946)) (reverse (lambda x (sum ((reverse fb:cell.cell.number) (fb:cell.cell.number (var x))))))))",
graph, matches("(number 6)"));
}
}