package edu.stanford.nlp.parser.shiftreduce;
import java.util.List;
import edu.stanford.nlp.ling.CoreLabel;
import edu.stanford.nlp.trees.Tree;
import edu.stanford.nlp.trees.TreeCoreAnnotations;
import edu.stanford.nlp.util.TreeShapedStack;
public class BasicFeatureFactory extends FeatureFactory {
public static void addUnaryStackFeatures(List<String> features, CoreLabel label, String conFeature, String wordTagFeature, String tagFeature, String wordConFeature, String tagConFeature) {
if (label == null) {
features.add(conFeature + NULL);
return;
}
String constituent = getFeatureFromCoreLabel(label, FeatureComponent.VALUE);
String tag = getFeatureFromCoreLabel(label, FeatureComponent.HEADTAG);
String word = getFeatureFromCoreLabel(label, FeatureComponent.HEADWORD);
features.add(conFeature + constituent);
features.add(wordTagFeature + word + "-" + tag);
features.add(tagFeature + tag);
features.add(wordConFeature + word + "-" + constituent);
features.add(tagConFeature + tag + "-" + constituent);
}
public static void addUnaryQueueFeatures(List<String> features, CoreLabel label, String wtFeature) {
if (label == null) {
features.add(wtFeature + NULL);
return;
}
String tag = label.get(TreeCoreAnnotations.HeadTagLabelAnnotation.class).value();
String word = label.get(TreeCoreAnnotations.HeadWordLabelAnnotation.class).value();
// TODO: check to see if this is slow because of the string concat
features.add(wtFeature + tag + "-" + word);
}
public static void addBinaryFeatures(List<String> features,
String name1, CoreLabel label1, FeatureComponent feature11, FeatureComponent feature12,
String name2, CoreLabel label2, FeatureComponent feature21, FeatureComponent feature22) {
if (label1 == null) {
if (label2 == null) {
features.add(name1 + "n" + name2 + "n");
} else {
addUnaryFeature(features, name1 + "n" + name2 + feature21.shortName() + "-", label2, feature21);
addUnaryFeature(features, name1 + "n" + name2 + feature22.shortName() + "-", label2, feature22);
}
} else if (label2 == null) {
addUnaryFeature(features, name1 + feature11.shortName() + name2 + "n-", label1, feature11);
addUnaryFeature(features, name1 + feature12.shortName() + name2 + "n-", label1, feature12);
} else {
addBinaryFeature(features, name1 + feature11.shortName() + name2 + feature21.shortName() + "-", label1, feature11, label2, feature21);
addBinaryFeature(features, name1 + feature11.shortName() + name2 + feature22.shortName() + "-", label1, feature11, label2, feature22);
addBinaryFeature(features, name1 + feature12.shortName() + name2 + feature21.shortName() + "-", label1, feature12, label2, feature21);
addBinaryFeature(features, name1 + feature12.shortName() + name2 + feature22.shortName() + "-", label1, feature12, label2, feature22);
}
}
public static void addUnaryFeature(List<String> features, String featureType, CoreLabel label, FeatureComponent feature) {
String value = getFeatureFromCoreLabel(label, feature);
features.add(featureType + value);
}
public static void addBinaryFeature(List<String> features, String featureType, CoreLabel label1, FeatureComponent feature1, CoreLabel label2, FeatureComponent feature2) {
String value1 = getFeatureFromCoreLabel(label1, feature1);
String value2 = getFeatureFromCoreLabel(label2, feature2);
features.add(featureType + value1 + "-" + value2);
}
public static void addTrigramFeature(List<String> features, String featureType, CoreLabel label1, FeatureComponent feature1, CoreLabel label2, FeatureComponent feature2, CoreLabel label3, FeatureComponent feature3) {
String value1 = getFeatureFromCoreLabel(label1, feature1);
String value2 = getFeatureFromCoreLabel(label2, feature2);
String value3 = getFeatureFromCoreLabel(label3, feature3);
features.add(featureType + value1 + "-" + value2 + "-" + value3);
}
public static void addPositionFeatures(List<String> features, State state) {
if (state.tokenPosition >= state.sentence.size()) {
features.add("QUEUE_FINISHED");
}
if (state.tokenPosition >= state.sentence.size() && state.stack.size() == 1) {
features.add("QUEUE_FINISHED_STACK_SINGLETON");
}
}
public static void addSeparatorFeature(List<String> features, String featureType, State.HeadPosition separator) {
if (separator == null) {
return;
}
features.add(featureType + separator);
}
public static void addSeparatorFeature(List<String> features, String featureType, CoreLabel label, FeatureComponent feature, State.HeadPosition separator) {
if (separator == null) {
return;
}
String value = getFeatureFromCoreLabel(label, feature);
features.add(featureType + value + "-" + separator);
}
public static void addSeparatorFeature(List<String> features, String featureType, CoreLabel label, FeatureComponent feature, boolean between) {
String value = getFeatureFromCoreLabel(label, feature);
features.add(featureType + value + "-" + between);
}
public static void addSeparatorFeature(List<String> features, String featureType, CoreLabel label1, FeatureComponent feature1, CoreLabel label2, FeatureComponent feature2, boolean between) {
String value1 = getFeatureFromCoreLabel(label1, feature1);
String value2 = getFeatureFromCoreLabel(label2, feature2);
features.add(featureType + value1 + "-" + value2 + "-" + between);
}
public static void addSeparatorFeatures(List<String> features, String name1, CoreLabel label1, String name2, CoreLabel label2, String separatorBetween, int countBetween) {
if (label1 == null || label2 == null) {
return;
}
// 0 separators is captured by the countBetween features
if (separatorBetween != null) {
String separatorBetweenName = "Sepb" + name1 + name2 + "-" + separatorBetween + "-";
addUnaryFeature(features, name1 + "w" + separatorBetweenName, label1, FeatureComponent.HEADWORD);
addBinaryFeature(features, name1 + "wc" + separatorBetweenName, label1, FeatureComponent.HEADWORD, label1, FeatureComponent.VALUE);
addUnaryFeature(features, name2 + "w" + separatorBetweenName, label2, FeatureComponent.HEADWORD);
addBinaryFeature(features, name2 + "wc" + separatorBetweenName, label2, FeatureComponent.HEADWORD, label2, FeatureComponent.VALUE);
addBinaryFeature(features, name1 + "c" + name2 + "c" + separatorBetweenName, label1, FeatureComponent.VALUE, label2, FeatureComponent.VALUE);
}
String countBetweenName = "Sepb" + name1 + name2 + "-" + countBetween + "-";
addUnaryFeature(features, name1 + "w" + countBetweenName, label1, FeatureComponent.HEADWORD);
addBinaryFeature(features, name1 + "wc" + countBetweenName, label1, FeatureComponent.HEADWORD, label1, FeatureComponent.VALUE);
addUnaryFeature(features, name2 + "w" + countBetweenName, label2, FeatureComponent.HEADWORD);
addBinaryFeature(features, name2 + "wc" + countBetweenName, label2, FeatureComponent.HEADWORD, label2, FeatureComponent.VALUE);
addBinaryFeature(features, name1 + "c" + name2 + "c" + countBetweenName, label1, FeatureComponent.VALUE, label2, FeatureComponent.VALUE);
}
public static void addSeparatorFeatures(List<String> features, CoreLabel s0Label, CoreLabel s1Label, State.HeadPosition s0Separator, State.HeadPosition s1Separator) {
boolean between = false;
if ((s0Separator != null && (s0Separator == State.HeadPosition.BOTH || s0Separator == State.HeadPosition.LEFT)) ||
(s1Separator != null && (s1Separator == State.HeadPosition.BOTH || s1Separator == State.HeadPosition.RIGHT))) {
between = true;
}
addSeparatorFeature(features, "s0sep-", s0Separator);
addSeparatorFeature(features, "s1sep-", s1Separator);
addSeparatorFeature(features, "s0ws0sep-", s0Label, FeatureComponent.HEADWORD, s0Separator);
addSeparatorFeature(features, "s0ws1sep-", s0Label, FeatureComponent.HEADWORD, s1Separator);
addSeparatorFeature(features, "s1ws0sep-", s1Label, FeatureComponent.HEADWORD, s0Separator);
addSeparatorFeature(features, "s1ws1sep-", s1Label, FeatureComponent.HEADWORD, s1Separator);
addSeparatorFeature(features, "s0cs0sep-", s0Label, FeatureComponent.VALUE, s0Separator);
addSeparatorFeature(features, "s0cs1sep-", s0Label, FeatureComponent.VALUE, s1Separator);
addSeparatorFeature(features, "s1cs0sep-", s1Label, FeatureComponent.VALUE, s0Separator);
addSeparatorFeature(features, "s1cs1sep-", s1Label, FeatureComponent.VALUE, s1Separator);
addSeparatorFeature(features, "s0ts0sep-", s0Label, FeatureComponent.HEADTAG, s0Separator);
addSeparatorFeature(features, "s0ts1sep-", s0Label, FeatureComponent.HEADTAG, s1Separator);
addSeparatorFeature(features, "s1ts0sep-", s1Label, FeatureComponent.HEADTAG, s0Separator);
addSeparatorFeature(features, "s1ts1sep-", s1Label, FeatureComponent.HEADTAG, s1Separator);
if (s0Label != null && s1Label != null) {
addSeparatorFeature(features, "s0wsb-", s0Label, FeatureComponent.HEADWORD, between);
addSeparatorFeature(features, "s1wsb-", s1Label, FeatureComponent.HEADWORD, between);
addSeparatorFeature(features, "s0csb-", s0Label, FeatureComponent.VALUE, between);
addSeparatorFeature(features, "s1csb-", s1Label, FeatureComponent.VALUE, between);
addSeparatorFeature(features, "s0tsb-", s0Label, FeatureComponent.HEADTAG, between);
addSeparatorFeature(features, "s1tsb-", s1Label, FeatureComponent.HEADTAG, between);
addSeparatorFeature(features, "s0cs1csb-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.VALUE, between);
}
}
/**
* Could potentially add the tags and words for the left and right
* ends of the tree. Also adds notes about the sizes of the given
* tree. However, it seems somewhat slow and doesn't help accuracy.
*/
public void addEdgeFeatures(List<String> features, State state, String nodeName, String neighborName, Tree node, Tree neighbor) {
if (node == null) {
return;
}
int left = ShiftReduceUtils.leftIndex(node);
int right = ShiftReduceUtils.rightIndex(node);
// Trees of size one are already featurized
if (right == left) {
features.add(nodeName + "SZ1");
return;
}
addUnaryQueueFeatures(features, getCoreLabel(state.sentence.get(left)), nodeName + "EL-");
addUnaryQueueFeatures(features, getCoreLabel(state.sentence.get(right)), nodeName + "ER-");
if (neighbor != null) {
addBinaryFeatures(features, nodeName, getCoreLabel(state.sentence.get(right)), FeatureComponent.HEADWORD, FeatureComponent.HEADTAG, neighborName, getCoreLabel(neighbor), FeatureComponent.HEADWORD, FeatureComponent.HEADTAG);
}
if (right - left == 1) {
features.add(nodeName + "SZ2");
return;
}
if (right - left == 2) {
features.add(nodeName + "SZ3");
addUnaryQueueFeatures(features, getCoreLabel(state.sentence.get(left + 1)), nodeName + "EM-");
return;
}
features.add(nodeName + "SZB");
addUnaryQueueFeatures(features, getCoreLabel(state.sentence.get(left + 1)), nodeName + "El-");
addUnaryQueueFeatures(features, getCoreLabel(state.sentence.get(right - 1)), nodeName + "Er-");
}
/** This option also does not seem to help */
public void addEdgeFeatures2(List<String> features, State state, String nodeName, Tree node) {
if (node == null) {
return;
}
int left = ShiftReduceUtils.leftIndex(node);
int right = ShiftReduceUtils.rightIndex(node);
CoreLabel nodeLabel = getCoreLabel(node);
String nodeValue = getFeatureFromCoreLabel(nodeLabel, FeatureComponent.VALUE) + "-";
CoreLabel leftLabel = getQueueLabel(state, left);
CoreLabel rightLabel = getQueueLabel(state, right);
addUnaryQueueFeatures(features, leftLabel, nodeName + "EL-" + nodeValue);
addUnaryQueueFeatures(features, rightLabel, nodeName + "ER-" + nodeValue);
CoreLabel previousLabel = getQueueLabel(state, left - 1);
addUnaryQueueFeatures(features, previousLabel, nodeName + "EP-" + nodeValue);
CoreLabel nextLabel = getQueueLabel(state, right + 1);
addUnaryQueueFeatures(features, nextLabel, nodeName + "EN-" + nodeValue);
}
/**
* Also did not seem to help
*/
public void addExtraTrigramFeatures(List<String> features, CoreLabel s0Label, CoreLabel s1Label, CoreLabel s2Label, CoreLabel q0Label, CoreLabel q1Label) {
addTrigramFeature(features, "S0wS1wS2c-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.HEADWORD, s2Label, FeatureComponent.VALUE);
addTrigramFeature(features, "S0wS1cS2w-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.VALUE, s2Label, FeatureComponent.HEADWORD);
addTrigramFeature(features, "S0cS1wS2w-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.HEADWORD, s2Label, FeatureComponent.HEADWORD);
addTrigramFeature(features, "S0wS1wQ0t-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.HEADWORD, q0Label, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0wS1cQ0w-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.VALUE, q0Label, FeatureComponent.HEADWORD);
addTrigramFeature(features, "S0cS1wQ0w-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.HEADWORD, q0Label, FeatureComponent.HEADWORD);
addTrigramFeature(features, "S0cQ0tQ1t-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.HEADTAG, q0Label, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0wQ0tQ1t-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.HEADTAG, q0Label, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0cQ0wQ1t-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.HEADWORD, q0Label, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0cQ0tQ1w-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.HEADTAG, q0Label, FeatureComponent.HEADWORD);
addTrigramFeature(features, "S0wQ0wQ1t-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.HEADWORD, q0Label, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0wQ0tQ1w-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.HEADTAG, q0Label, FeatureComponent.HEADWORD);
addTrigramFeature(features, "S0cQ0wQ1w-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.HEADWORD, q0Label, FeatureComponent.HEADWORD);
}
@Override
public List<String> featurize(State state, List<String> features) {
final TreeShapedStack<Tree> stack = state.stack;
final List<Tree> sentence = state.sentence;
final int tokenPosition = state.tokenPosition;
CoreLabel s0Label = getStackLabel(stack, 0); // current top of stack
CoreLabel s1Label = getStackLabel(stack, 1); // one previous
CoreLabel s2Label = getStackLabel(stack, 2); // two previous
CoreLabel s3Label = getStackLabel(stack, 3); // three previous
CoreLabel s0LLabel = getStackLabel(stack, 0, Transition.LEFT);
CoreLabel s0RLabel = getStackLabel(stack, 0, Transition.RIGHT);
CoreLabel s0ULabel = getStackLabel(stack, 0, Transition.UNARY);
CoreLabel s0LLLabel = getStackLabel(stack, 0, Transition.LEFT, Transition.LEFT);
CoreLabel s0LRLabel = getStackLabel(stack, 0, Transition.LEFT, Transition.RIGHT);
CoreLabel s0LULabel = getStackLabel(stack, 0, Transition.LEFT, Transition.UNARY);
CoreLabel s0RLLabel = getStackLabel(stack, 0, Transition.RIGHT, Transition.LEFT);
CoreLabel s0RRLabel = getStackLabel(stack, 0, Transition.RIGHT, Transition.RIGHT);
CoreLabel s0RULabel = getStackLabel(stack, 0, Transition.RIGHT, Transition.UNARY);
CoreLabel s0ULLabel = getStackLabel(stack, 0, Transition.UNARY, Transition.LEFT);
CoreLabel s0URLabel = getStackLabel(stack, 0, Transition.UNARY, Transition.RIGHT);
CoreLabel s0UULabel = getStackLabel(stack, 0, Transition.UNARY, Transition.UNARY);
CoreLabel s1LLabel = getStackLabel(stack, 1, Transition.LEFT);
CoreLabel s1RLabel = getStackLabel(stack, 1, Transition.RIGHT);
CoreLabel s1ULabel = getStackLabel(stack, 1, Transition.UNARY);
CoreLabel q0Label = getQueueLabel(sentence, tokenPosition, 0); // current location in queue
CoreLabel q1Label = getQueueLabel(sentence, tokenPosition, 1); // next location in queue
CoreLabel q2Label = getQueueLabel(sentence, tokenPosition, 2); // two locations later in queue
CoreLabel q3Label = getQueueLabel(sentence, tokenPosition, 3); // three locations later in queue
CoreLabel qP1Label = getQueueLabel(sentence, tokenPosition, -1); // previous location in queue
CoreLabel qP2Label = getQueueLabel(sentence, tokenPosition, -2); // two locations prior in queue
// It's kind of unpleasant having this magic order of feature names.
// On the other hand, it does save some time with string concatenation.
addUnaryStackFeatures(features, s0Label, "S0C-", "S0WT-", "S0T-", "S0WC-", "S0TC-");
addUnaryStackFeatures(features, s1Label, "S1C-", "S1WT-", "S1T-", "S1WC-", "S1TC-");
addUnaryStackFeatures(features, s2Label, "S2C-", "S2WT-", "S2T-", "S2WC-", "S2TC-");
addUnaryStackFeatures(features, s3Label, "S3C-", "S3WT-", "S3T-", "S3WC-", "S3TC-");
addUnaryStackFeatures(features, s0LLabel, "S0LC-", "S0LWT-", "S0LT-", "S0LWC-", "S0LTC-");
addUnaryStackFeatures(features, s0RLabel, "S0RC-", "S0RWT-", "S0RT-", "S0RWC-", "S0RTC-");
addUnaryStackFeatures(features, s0ULabel, "S0UC-", "S0UWT-", "S0UT-", "S0UWC-", "S0UTC-");
addUnaryStackFeatures(features, s0LLLabel, "S0LLC-", "S0LLWT-", "S0LLT-", "S0LLWC-", "S0LLTC-");
addUnaryStackFeatures(features, s0LRLabel, "S0LRC-", "S0LRWT-", "S0LRT-", "S0LRWC-", "S0LRTC-");
addUnaryStackFeatures(features, s0LULabel, "S0LUC-", "S0LUWT-", "S0LUT-", "S0LUWC-", "S0LUTC-");
addUnaryStackFeatures(features, s0RLLabel, "S0RLC-", "S0RLWT-", "S0RLT-", "S0RLWC-", "S0RLTC-");
addUnaryStackFeatures(features, s0RRLabel, "S0RRC-", "S0RRWT-", "S0RRT-", "S0RRWC-", "S0RRTC-");
addUnaryStackFeatures(features, s0RULabel, "S0RUC-", "S0RUWT-", "S0RUT-", "S0RUWC-", "S0RUTC-");
addUnaryStackFeatures(features, s0ULLabel, "S0ULC-", "S0ULWT-", "S0ULT-", "S0ULWC-", "S0ULTC-");
addUnaryStackFeatures(features, s0URLabel, "S0URC-", "S0URWT-", "S0URT-", "S0URWC-", "S0URTC-");
addUnaryStackFeatures(features, s0UULabel, "S0UUC-", "S0UUWT-", "S0UUT-", "S0UUWC-", "S0UUTC-");
addUnaryStackFeatures(features, s1LLabel, "S1LC-", "S1LWT-", "S1LT-", "S1LWC-", "S1LTC-");
addUnaryStackFeatures(features, s1RLabel, "S1RC-", "S1RWT-", "S1RT-", "S1RWC-", "S1RTC-");
addUnaryStackFeatures(features, s1ULabel, "S1UC-", "S1UWT-", "S1UT-", "S1UWC-", "S1UTC-");
addUnaryQueueFeatures(features, q0Label, "Q0WT-");
addUnaryQueueFeatures(features, q1Label, "Q1WT-");
addUnaryQueueFeatures(features, q2Label, "Q2WT-");
addUnaryQueueFeatures(features, q3Label, "Q3WT-");
addUnaryQueueFeatures(features, qP1Label, "QP1WT-");
addUnaryQueueFeatures(features, qP2Label, "QP2WT-");
// Figure out which are the most recent left and right node
// attachments to the heads of the given nodes. It seems like it
// should be more efficient to keep track of this in the state, as
// that would have a constant cost per transformation, but it is
// actually faster to find it by walking down the tree each time
CoreLabel recentL0Label = getRecentDependent(stack, Transition.LEFT, 0);
CoreLabel recentR0Label = getRecentDependent(stack, Transition.RIGHT, 0);
CoreLabel recentL1Label = getRecentDependent(stack, Transition.LEFT, 1);
CoreLabel recentR1Label = getRecentDependent(stack, Transition.RIGHT, 1);
addUnaryStackFeatures(features, recentL0Label, "recL0C-", "recL0WT-", "recL0T-", "recL0WC-", "recL0TC-");
addUnaryStackFeatures(features, recentR0Label, "recR0C-", "recR0WT-", "recR0T-", "recR0WC-", "recR0TC-");
addUnaryStackFeatures(features, recentL1Label, "recL1C-", "recL1WT-", "recL1T-", "recL1WC-", "recL1TC-");
addUnaryStackFeatures(features, recentR1Label, "recR1C-", "recR1WT-", "recR1T-", "recR1WC-", "recR1TC-");
addBinaryFeatures(features, "S0", s0Label, FeatureComponent.HEADWORD, FeatureComponent.VALUE, "S1", s1Label, FeatureComponent.HEADWORD, FeatureComponent.VALUE);
addBinaryFeatures(features, "S0", s0Label, FeatureComponent.HEADWORD, FeatureComponent.VALUE, "Q0", q0Label, FeatureComponent.HEADWORD, FeatureComponent.HEADTAG);
addBinaryFeatures(features, "S1", s1Label, FeatureComponent.HEADWORD, FeatureComponent.VALUE, "Q0", q0Label, FeatureComponent.HEADWORD, FeatureComponent.HEADTAG);
addBinaryFeatures(features, "Q0", q0Label, FeatureComponent.HEADWORD, FeatureComponent.HEADTAG, "Q1", q1Label, FeatureComponent.HEADWORD, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0cS1cS2c-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.VALUE, s2Label, FeatureComponent.VALUE);
addTrigramFeature(features, "S0wS1cS2c-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.VALUE, s2Label, FeatureComponent.VALUE);
addTrigramFeature(features, "S0cS1wS2c-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.HEADWORD, s2Label, FeatureComponent.VALUE);
addTrigramFeature(features, "S0cS1cS2w-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.VALUE, s2Label, FeatureComponent.HEADWORD);
addTrigramFeature(features, "S0cS1cQ0t-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.VALUE, q0Label, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0wS1cQ0t-", s0Label, FeatureComponent.HEADWORD, s1Label, FeatureComponent.VALUE, q0Label, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0cS1wQ0t-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.HEADWORD, q0Label, FeatureComponent.HEADTAG);
addTrigramFeature(features, "S0cS1cQ0w-", s0Label, FeatureComponent.VALUE, s1Label, FeatureComponent.VALUE, q0Label, FeatureComponent.HEADWORD);
addPositionFeatures(features, state);
// State.HeadPosition s0Separator = state.getSeparator(0);
// State.HeadPosition s1Separator = state.getSeparator(1);
// addSeparatorFeatures(features, s0Label, s1Label, s0Separator, s1Separator);
Tree s0Node = state.getStackNode(0);
Tree s1Node = state.getStackNode(1);
Tree q0Node = state.getQueueNode(0);
addSeparatorFeatures(features, "S0", s0Label, "S1", s1Label, state.getSeparatorBetween(s0Node, s1Node), state.getSeparatorCount(s0Node, s1Node));
addSeparatorFeatures(features, "S0", s0Label, "Q0", q0Label, state.getSeparatorBetween(q0Node, s0Node), state.getSeparatorCount(q0Node, s0Node));
return features;
}
private static final long serialVersionUID = 1;
}