package edu.stanford.nlp.sempre;
import com.google.common.collect.Sets;
import fig.basic.LogInfo;
import fig.basic.MapUtils;
import fig.basic.StopWatchSet;
import java.util.*;
/**
* Contains methods for putting derivations on the chart and combining them
* to add new derivations to the agenda
* @author joberant
*/
abstract class AbstractReinforcementParserState extends ChartParserState {
protected final ReinforcementParser parser;
protected final CoarseParser coarseParser;
protected CoarseParser.CoarseParserState coarseParserState;
protected static final double EPSILON = 10e-20; // used to break ties between agenda items
public AbstractReinforcementParserState(ReinforcementParser parser, Params params, Example ex, boolean computeExpectedCounts) {
super(parser, params, ex, computeExpectedCounts);
this.parser = parser;
coarseParser = parser.coarseParser;
}
protected abstract void addToAgenda(DerivationStream derivationStream);
protected boolean coarseAllows(String cat, int start, int end) {
return coarseParserState == null || coarseParserState.coarseAllows(cat, start, end);
}
//don't add to a cell in the chart that is fill
protected boolean addToBoundedChart(Derivation deriv) {
List<Derivation> derivations = chart[deriv.start][deriv.end].get(deriv.cat);
totalGeneratedDerivs++;
if (Parser.opts.visualizeChartFilling) {
chartFillingList.add(new CatSpan(deriv.start, deriv.end, deriv.cat));
}
if (derivations == null) {
chart[deriv.start][deriv.end].put(deriv.cat,
derivations = new ArrayList<>());
}
if (derivations.size() < getBeamSize()) {
derivations.add(deriv);
Collections.sort(derivations, Derivation.derivScoreComparator); // todo - perhaps can be removed
return true;
} else return false;
}
// for [start, end) we try to create [start, end + i) or [start - i, end) and add unary rules
protected void combineWithChartDerivations(Derivation deriv) {
expandDerivRightwards(deriv);
expandDerivLeftwards(deriv);
applyCatUnaryRules(deriv);
}
private void expandDerivRightwards(Derivation leftChild) {
if (parser.verbose(6))
LogInfo.begin_track("Expanding rightward");
Map<String, List<Rule>> rhsCategoriesToRules = parser.leftToRightSiblingMap.get(leftChild.cat);
if (rhsCategoriesToRules != null) {
for (int i = 1; leftChild.end + i <= numTokens; ++i) {
Set<String> intersection = Sets.intersection(rhsCategoriesToRules.keySet(), chart[leftChild.end][leftChild.end + i].keySet());
for (String rhsCategory : intersection) {
List<Rule> compatibleRules = rhsCategoriesToRules.get(rhsCategory);
List<Derivation> rightChildren = chart[leftChild.end][leftChild.end + i].get(rhsCategory);
generateParentDerivations(leftChild, rightChildren, true, compatibleRules);
}
}
// handle terminals
if (leftChild.end < numTokens)
handleTerminalExpansion(leftChild, false, rhsCategoriesToRules);
}
if (parser.verbose(6))
LogInfo.end_track();
}
private void expandDerivLeftwards(Derivation rightChild) {
if (parser.verbose(5))
LogInfo.begin_track("Expanding leftward");
Map<String, List<Rule>> lhsCategorisToRules = parser.rightToLeftSiblingMap.get(rightChild.cat);
if (lhsCategorisToRules != null) {
for (int i = 1; rightChild.start - i >= 0; ++i) {
Set<String> intersection = Sets.intersection(lhsCategorisToRules.keySet(), chart[rightChild.start - i][rightChild.start].keySet());
for (String lhsCategory : intersection) {
List<Rule> compatibleRules = lhsCategorisToRules.get(lhsCategory);
List<Derivation> leftChildren = chart[rightChild.start - i][rightChild.start].get(lhsCategory);
generateParentDerivations(rightChild, leftChildren, false, compatibleRules);
}
}
// handle terminals
if (rightChild.start > 0)
handleTerminalExpansion(rightChild, true, lhsCategorisToRules);
}
if (parser.verbose(5))
LogInfo.end_track();
}
private void generateParentDerivations(Derivation expandedDeriv, List<Derivation> otherDerivs,
boolean expandedLeftChild, List<Rule> compatibleRules) {
for (Derivation otherDeriv : otherDerivs) {
Derivation leftChild, rightChild;
if (expandedLeftChild) {
leftChild = expandedDeriv;
rightChild = otherDeriv;
} else {
leftChild = otherDeriv;
rightChild = expandedDeriv;
}
List<Derivation> children = new ArrayList<>();
children.add(leftChild);
children.add(rightChild);
for (Rule rule : compatibleRules) {
if (coarseAllows(rule.lhs, leftChild.start, rightChild.end)) {
DerivationStream resDerivations = applyRule(leftChild.start, rightChild.end, rule, children);
if (!resDerivations.hasNext())
continue;
addToAgenda(resDerivations);
}
}
}
}
// returns the score of derivation computed
private DerivationStream applyRule(int start, int end, Rule rule, List<Derivation> children) {
try {
if (Parser.opts.verbose >= 5)
LogInfo.logs("applyRule %s %s %s %s", start, end, rule, children);
StopWatchSet.begin(rule.getSemRepn()); // measuring time
StopWatchSet.begin(rule.toString());
DerivationStream results = rule.sem.call(ex,
new SemanticFn.CallInfo(rule.lhs, start, end, rule, com.google.common.collect.ImmutableList.copyOf(children)));
StopWatchSet.end();
StopWatchSet.end();
return results;
} catch (Exception e) {
LogInfo.errors("Composition failed: rule = %s, children = %s", rule, children);
e.printStackTrace();
throw new RuntimeException(e);
}
}
private void applyCatUnaryRules(Derivation deriv) {
if (parser.verbose(4))
LogInfo.begin_track("Category unary rules");
for (Rule rule : parser.catUnaryRules) {
if (!coarseAllows(rule.lhs, deriv.start, deriv.end))
continue;
if (deriv.cat.equals(rule.rhs.get(0))) {
DerivationStream resDerivations = applyRule(deriv.start, deriv.end, rule, Collections.singletonList(deriv));
addToAgenda(resDerivations);
}
}
if (parser.verbose(4))
LogInfo.end_track();
}
public List<DerivationStream> gatherRhsTerminalsDerivations() {
List<DerivationStream> derivs = new ArrayList<>();
final List<Derivation> empty = Collections.emptyList();
for (int i = 0; i < numTokens; i++) {
for (int j = i + 1; j <= numTokens; j++) {
for (Rule rule : MapUtils.get(parser.terminalsToRulesList, phrases[i][j], Collections.<Rule>emptyList())) {
if (!coarseAllows(rule.lhs, i, j))
continue;
derivs.add(applyRule(i, j, rule, empty));
}
}
}
return derivs;
}
// rules where one word is a terminal and the other is a non-terminal
private void handleTerminalExpansion(Derivation child, boolean before, Map<String, List<Rule>> categoriesToRules) {
String phrase = before ? phrases[child.start - 1][child.start] : phrases[child.end][child.end + 1];
int start = before ? child.start - 1 : child.start;
int end = before ? child.end : child.end + 1;
if (categoriesToRules.containsKey(phrase)) {
List<Derivation> children = new ArrayList<>();
children.add(child);
for (Rule rule : categoriesToRules.get(phrase)) {
if (coarseAllows(rule.lhs, start, end)) {
DerivationStream resDerivations = applyRule(start, end, rule, children);
if (!resDerivations.hasNext())
continue;
addToAgenda(resDerivations);
}
}
}
}
}