package edu.stanford.nlp.sempre;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import fig.basic.LispTree;
import java.util.*;
/**
* Represents the discourse context (time, place, history of exchanges).
* This is part of an Example and used by ContextFn.
*
* @author Percy Liang
*/
public class ContextValue extends Value {
// A single exchange between the user and the system
// Note: we are not storing the entire derivation right now.
public static class Exchange {
public final String utterance;
public final Formula formula;
public final Value value;
public Exchange(String utterance, Formula formula, Value value) {
this.utterance = utterance;
this.formula = formula;
this.value = value;
}
public Exchange(LispTree tree) {
utterance = tree.child(1).value;
formula = Formulas.fromLispTree(tree.child(2));
value = Values.fromLispTree(tree.child(3));
}
public LispTree toLispTree() {
LispTree tree = LispTree.proto.newList();
tree.addChild("exchange");
tree.addChild(utterance);
tree.addChild(formula.toLispTree());
tree.addChild(value.toLispTree());
return tree;
}
@Override public String toString() { return toLispTree().toString(); }
}
public final String user;
public final DateValue date;
public final List<Exchange> exchanges; // List of recent exchanges with the user
public final KnowledgeGraph graph; // Mini-knowledge graph that captures the context
public ContextValue withDate(DateValue newDate) {
return new ContextValue(user, newDate, exchanges, graph);
}
public ContextValue withNewExchange(List<Exchange> newExchanges) {
return new ContextValue(user, date, newExchanges, graph);
}
public ContextValue withGraph(KnowledgeGraph newGraph) {
return new ContextValue(user, date, exchanges, newGraph);
}
public ContextValue(String user, DateValue date, List<Exchange> exchanges, KnowledgeGraph graph) {
this.user = user;
this.date = date;
this.exchanges = exchanges;
this.graph = graph;
}
public ContextValue(String user, DateValue date, List<Exchange> exchanges) {
this(user, date, exchanges, null);
}
public ContextValue(KnowledgeGraph graph) {
this(null, null, new ArrayList(), graph);
}
// Example:
// (context (user pliang)
// (date 2014 4 20)
// (exchange "when was chopin born" (!fb:people.person.date_of_birth fb:en.frederic_chopin) (date 1810 2 22))
// (graph NaiveKnowledgeGraph ((string Obama) (string "born in") (string Hawaii)) ...))
public ContextValue(LispTree tree) {
String user = null;
DateValue date = null;
KnowledgeGraph graph = null;
exchanges = new ArrayList<Exchange>();
for (int i = 1; i < tree.children.size(); i++) {
String key = tree.child(i).child(0).value;
if (key.equals("user")) {
user = tree.child(i).child(1).value;
} else if (key.equals("date")) {
date = new DateValue(tree.child(i));
} else if (key.equals("graph")) {
graph = KnowledgeGraph.fromLispTree(tree.child(i));
} else if (key.equals("exchange")) {
exchanges.add(new Exchange(tree.child(i)));
} else {
throw new RuntimeException("Invalid: " + tree.child(i));
}
}
this.user = user;
this.date = date;
this.graph = graph;
}
public LispTree toLispTree() {
LispTree tree = LispTree.proto.newList();
tree.addChild("context");
if (user != null)
tree.addChild(LispTree.proto.newList("user", user));
if (date != null)
tree.addChild(date.toLispTree());
// When logging examples, logging the entire graph takes too much screen space.
// I don't think that we ever deserialize a graph from a serialized context,
// so this should be fine.
if (graph != null)
tree.addChild(graph.toShortLispTree());
for (Exchange e : exchanges)
tree.addChild(LispTree.proto.newList("exchange", e.toLispTree()));
return tree;
}
@Override public int hashCode() {
int hash = 0x7ed55d16;
hash = hash * 0xd3a2646c + user.hashCode();
hash = hash * 0xd3a2646c + date.hashCode();
hash = hash * 0xd3a2646c + exchanges.hashCode();
hash = hash * 0xd3a2646c + graph.hashCode();
return hash;
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ContextValue that = (ContextValue) o;
if (!this.user.equals(that.user)) return false;
if (!this.date.equals(that.date)) return false;
if (!this.exchanges.equals(that.exchanges)) return false;
if (!this.graph.equals(that.graph)) return false;
return true;
}
@JsonValue
public String toString() { return toLispTree().toString(); }
@JsonCreator
public static ContextValue fromString(String str) {
return new ContextValue(LispTree.proto.parseFromString(str));
}
}