package edu.stanford.nlp.sempre.tables.alter;
import java.io.*;
import java.util.*;
import edu.stanford.nlp.sempre.*;
import edu.stanford.nlp.sempre.tables.TableKnowledgeGraph;
import edu.stanford.nlp.sempre.tables.serialize.SerializedDataset;
import edu.stanford.nlp.sempre.tables.test.CustomExample;
import fig.basic.IOUtils;
import fig.basic.LogInfo;
import fig.basic.StrUtils;
import fig.exec.Execution;
/**
* Execute the formulas on the altered tables.
*
* Summarized turk data can be provided in
* BatchTableAlterer.opts.turkedDataPath,
* in which case only turked tables will be executed on.
* A "check" file, indicating whether the denotation matches
* the turked answers, will also be dumped.
*
* Annotated formulas can be provided in
* BatchTableAlterer.opts.annotatedFormulasPath,
* in which case the annotated formula will be executed
* (to a separate file).
*
* @author ppasupat
*/
public class AlteredTablesExecutor implements Runnable {
public static void main(String[] args) {
Execution.run(args, "AlteredTablesExecutorMain", new AlteredTablesExecutor(), Master.getOptionsParser());
}
private Builder builder;
private TableAltererCache tableAltererCache = null;
private boolean hasAnnotated = false;
private Map<String, CustomExample> idToAnnotated = new HashMap<>();
private boolean hasTurk = false;
private AggregatedTurkData turkedData = null;
@Override
public void run() {
builder = new Builder();
builder.build();
// Read dataset
Dataset dataset;
if (Dataset.opts.inPaths.isEmpty() || Dataset.opts.inPaths.get(0).getSecond().endsWith(".gz")) {
LogInfo.logs("Loading SERIALIZED dataset");
dataset = new SerializedDataset();
} else {
LogInfo.logs("Loading USUAL dataset");
dataset = new Dataset();
}
dataset.read();
List<Example> examples = dataset.examples("train");
// Alterer cache
tableAltererCache = new TableAltererCache();
// Read annotation file
if (!StrUtils.isEmpty(BatchTableAlterer.opts.annotatedFormulasPath)) {
hasAnnotated = true;
// Prevent verbose output
if (CustomExample.opts.verbose > 1)
CustomExample.opts.verbose = 1;
List<CustomExample> annotated = CustomExample.getDataset(BatchTableAlterer.opts.annotatedFormulasPath);
for (CustomExample ex : annotated) {
if (ex == null || ex.targetFormula == null) continue;
// Check annotation
Value rawValue = builder.executor.execute(ex.targetFormula, ex.context).value;
if (rawValue instanceof ListValue)
rawValue = ((TableKnowledgeGraph) ex.context.graph).getListValueWithOriginalStrings((ListValue) rawValue);
if (builder.valueEvaluator.getCompatibility(ex.targetValue, rawValue) == 1)
idToAnnotated.put(ex.id, ex);
else
LogInfo.warnings("Wrong annotation [%s] expected %s; got %s", ex.id, ex.targetValue, rawValue);
}
}
// Read Turked data
if (!StrUtils.isEmpty(BatchTableAlterer.opts.turkedDataPath)) {
hasTurk = true;
turkedData = new AggregatedTurkData(BatchTableAlterer.opts.turkedDataPath);
}
Execution.putOutput("group", "train");
int index = -1;
for (Example ex : examples) {
Execution.putOutput("example", ++index);
if (CustomExample.checkFilterExamples(index))
process(ex);
ex.predDerivations.clear(); // Save memory
}
}
// For each example, execute on the turked tables, then dump to file
private void process(Example ex) {
LogInfo.begin_track("Processing %s", ex.id);
ex.log();
if (ex.predDerivations == null)
ex.predDerivations = Collections.emptyList();
LogInfo.logs("Read %d derivations", ex.predDerivations.size());
DenotationData denotationData = new DenotationData(BatchTableAlterer.opts.numAlteredTables, ex.predDerivations.size());
DenotationData checkData = new DenotationData(BatchTableAlterer.opts.numAlteredTables, ex.predDerivations.size());
// Get the relevant indices
List<Integer> tableIndices;
if (hasTurk) {
tableIndices = turkedData.getAllTurkedTables(ex.id);
if (tableIndices == null)
tableIndices = new ArrayList<>();
} else {
tableIndices = new ArrayList<>(BatchTableAlterer.opts.numAlteredTables + 1);
for (int i = 0; i <= BatchTableAlterer.opts.numAlteredTables; i++)
tableIndices.add(i);
}
for (int tableIndex : tableIndices) {
LogInfo.begin_track("Executing on table %d", tableIndex);
TableKnowledgeGraph graph = tableAltererCache.load(ex.id, tableIndex);
Value target = hasTurk ? turkedData.get(ex.id, tableIndex) : null;
ContextValue context = new ContextValue(graph);
// Execute all formulas on the new graph
for (int k = 0; k < ex.predDerivations.size(); k++) {
Derivation deriv = ex.predDerivations.get(k);
Value value = builder.executor.execute(deriv.formula, context).value;
if (value instanceof ListValue)
value = graph.getListValueWithOriginalStrings((ListValue) value);
boolean correct = isCorrect(ex, target, value);
value = ValueCanonicalizer.canonicalize(value);
denotationData.addDenotation(k, tableIndex, value);
if (hasTurk)
checkData.addDenotation(k, tableIndex, getCheck(target, value, correct));
}
// Annotated formula
if (hasAnnotated) {
Value annotatedValue = null;
Example annotatedEx = idToAnnotated.get(ex.id);
boolean annotatedCorrect = false;
if (annotatedEx != null && annotatedEx.targetFormula != null) {
annotatedValue = builder.executor.execute(annotatedEx.targetFormula, context).value;
if (annotatedValue instanceof ListValue)
annotatedValue = graph.getListValueWithOriginalStrings((ListValue) annotatedValue);
annotatedCorrect = isCorrect(ex, target, annotatedValue);
annotatedValue = ValueCanonicalizer.canonicalize(annotatedValue);
}
denotationData.addAnnotatedDenotation(tableIndex, annotatedValue);
if (hasTurk)
checkData.addAnnotatedDenotation(tableIndex, getCheck(target, annotatedValue, annotatedCorrect));
}
LogInfo.end_track();
}
{
File dir = new File(Execution.getFile("actual-denotations"));
if (!dir.isDirectory()) dir.mkdir();
PrintWriter writer = IOUtils.openOutHard(dir.toString() + "/" + ex.id + ".gz");
denotationData.dump(writer);
writer.close();
}
if (hasAnnotated) {
File dir = new File(Execution.getFile("actual-annotated-denotations"));
if (!dir.isDirectory()) dir.mkdir();
PrintWriter writer = IOUtils.openOutHard(dir.toString() + "/" + ex.id + ".gz");
denotationData.dumpAnnotated(writer);
writer.close();
}
if (hasTurk) {
File dir = new File(Execution.getFile("check-denotations"));
if (!dir.isDirectory()) dir.mkdir();
PrintWriter writer = IOUtils.openOutHard(dir.toString() + "/" + ex.id + ".gz");
checkData.dump(writer);
writer.close();
}
if (hasTurk && hasAnnotated) {
File dir = new File(Execution.getFile("check-annotated-denotations"));
if (!dir.isDirectory()) dir.mkdir();
PrintWriter writer = IOUtils.openOutHard(dir.toString() + "/" + ex.id + ".gz");
checkData.dumpAnnotated(writer);
writer.close();
}
LogInfo.end_track();
}
// See if a value matches the targetValue
boolean isCorrect(Example ex, Value target, Value pred) {
if (target == null || target instanceof ErrorValue) return false;
double result = 0;
try {
result = builder.valueEvaluator.getCompatibility(target, pred);
} catch (Exception e) {
LogInfo.logs("%s", e);
e.printStackTrace();
}
return result == 1;
}
private static final Value TURK_A_MATCHED = new NameValue("Ao");
private static final Value TURK_A_MISMATCHED = new NameValue("Ax");
private static final Value TURK_B_MATCHED = new NameValue("Bo");
private static final Value TURK_B_MISMATCHED = new NameValue("Bx");
private static final Value TURK_X = new NameValue("X");
private Value getCheck(Value target, Value pred, boolean correct) {
if (target == null) return TURK_X;
if (target instanceof ErrorValue) {
return pred instanceof ErrorValue ? TURK_B_MATCHED : TURK_B_MISMATCHED;
} else {
return correct ? TURK_A_MATCHED : TURK_A_MISMATCHED;
}
}
}