package edu.stanford.nlp.sempre.tables.match;
import java.util.*;
import edu.stanford.nlp.sempre.*;
import edu.stanford.nlp.sempre.tables.*;
import fig.basic.LispTree;
import fig.basic.LogInfo;
import fig.basic.Option;
/**
* Generate the closed class entities from the table, including:
* - [generic] Generic common entities (e.g., null = empty cell)
* - [column] If the number of unique entities in a column is <= the limit,
* and there is at least one repeated entity, generate all entities in the column.
*
* @author ppasupat
*/
public class ClosedClassFn extends SemanticFn {
public static class Options {
@Option(gloss = "verbosity") public int verbose = 0;
@Option(gloss = "maximum number of unique entities in a column to be considered a closed class")
public int maxNumClosedClassEntities = 3;
}
public static Options opts = new Options();
public enum ClosedClassFnMode {
GENERIC, COLUMN,
}
protected ClosedClassFnMode mode;
public void init(LispTree tree) {
super.init(tree);
String value = tree.child(1).value;
if ("generic".equals(value)) this.mode = ClosedClassFnMode.GENERIC;
else if ("column".equals(value)) this.mode = ClosedClassFnMode.COLUMN;
else throw new RuntimeException("Invalid argument: " + value);
}
@Override
public DerivationStream call(Example ex, Callable c) {
return new LazyClosedClassFnDerivs(ex, c, mode);
}
// ============================================================
// Derivation
// ============================================================
public static class LazyClosedClassFnDerivs extends MultipleDerivationStream {
final Example ex;
final TableKnowledgeGraph graph;
final Callable c;
final ClosedClassFnMode mode;
int index = 0;
List<Formula> formulas;
public LazyClosedClassFnDerivs(Example ex, Callable c, ClosedClassFnMode mode) {
this.ex = ex;
this.graph = (TableKnowledgeGraph) ex.context.graph;
this.c = c;
this.mode = mode;
}
@Override
public Derivation createDerivation() {
// Compute the formulas if not computed yet
if (formulas == null) {
switch (mode) {
case GENERIC:
formulas = new ArrayList<>(createGenericFormulas());
break;
case COLUMN:
formulas = new ArrayList<>(createColumnFormulas());
break;
default:
throw new RuntimeException("Invalid mode: " + mode);
}
}
// Use the next formula to create a derivation
if (index >= formulas.size()) return null;
Formula formula = formulas.get(index++);
SemType type = TypeInference.inferType(formula);
return new Derivation.Builder().withCallable(c)
.formula(formula).type(type).createDerivation();
}
protected final String NULL = TableTypeSystem.getCellName("null");
protected Collection<Formula> createGenericFormulas() {
List<Formula> formulas = new ArrayList<>();
// Find out if the table has a null cell
for (TableCellProperties properties : graph.cellProperties) {
if (NULL.equals(properties.id)) {
formulas.add(new ValueFormula<>(properties.nameValue));
break;
}
}
if (ClosedClassFn.opts.verbose >= 2) {
LogInfo.begin_track("ClosedClassFn(generic):");
for (Formula formula : formulas)
LogInfo.logs("%s", formula);
LogInfo.end_track();
}
return formulas;
}
protected Collection<Formula> createColumnFormulas() {
Set<Formula> formulas = new HashSet<>();
// Process the columns separately
for (TableColumn column : graph.columns) {
boolean hasRepeats = false;
Set<Value> values = new HashSet<>();
for (TableCell cell : column.children) {
if (NULL.equals(cell.properties.id)) continue;
if (values.contains(cell.properties.nameValue))
hasRepeats = true;
else
values.add(cell.properties.nameValue);
}
if (values.size() <= ClosedClassFn.opts.maxNumClosedClassEntities && hasRepeats) {
for (Value value : values) {
formulas.add(new ValueFormula<>(value));
}
}
}
if (ClosedClassFn.opts.verbose >= 2) {
LogInfo.begin_track("ClosedClassFn(column):");
for (Formula formula : formulas)
LogInfo.logs("%s", formula);
LogInfo.end_track();
}
return formulas;
}
}
}