package edu.stanford.nlp.parser.lexparser;
import java.util.*;
import edu.stanford.nlp.util.Index;
/** This class is currently unused.
* @author Dan Klein
*/
public class OutsideRuleFilter {
private final Index<String> tagIndex;
private int numTags;
private int numFAs;
private FA[] leftFA;
private FA[] rightFA;
protected static <A> List<A> reverse(List<A> list) {
int sz = list.size();
List<A> reverse = new ArrayList<>(sz);
for (int i = sz - 1; i >= 0; i--) {
reverse.add(list.get(i));
}
return reverse;
}
private FA buildFA(List<String> tags) {
FA fa = new FA(tags.size() + 1, numTags);
fa.setLoopState(0, true);
for (int state = 1; state <= tags.size(); state++) {
String tagO = tags.get(state - 1);
if (tagO == null) {
fa.setLoopState(state, true);
for (int symbol = 0; symbol < numTags; symbol++) {
fa.setTransition(state - 1, symbol, state);
}
} else {
int tag = tagIndex.indexOf(tagO);
fa.setTransition(state - 1, tag, state);
}
}
return fa;
}
private void registerRule(List<String> leftTags, List<String> rightTags, int state) {
leftFA[state] = buildFA(leftTags);
rightFA[state] = buildFA(reverse(rightTags));
}
public void init() {
for (int rule = 0; rule < numFAs; rule++) {
leftFA[rule].init();
rightFA[rule].init();
}
}
public void advanceRight(boolean[] tags) {
for (int tag = 0; tag < numTags; tag++) {
if (!tags[tag]) {
continue;
}
for (int rule = 0; rule < numFAs; rule++) {
leftFA[rule].input(tag);
}
}
for (int rule = 0; rule < numFAs; rule++) {
leftFA[rule].advance();
}
}
public void leftAccepting(boolean[] result) {
for (int rule = 0; rule < numFAs; rule++) {
result[rule] = leftFA[rule].isAccepting();
}
}
public void advanceLeft(boolean[] tags) {
for (int tag = 0; tag < numTags; tag++) {
if (!tags[tag]) {
continue;
}
for (int rule = 0; rule < numFAs; rule++) {
rightFA[rule].input(tag);
}
}
for (int rule = 0; rule < numFAs; rule++) {
rightFA[rule].advance();
}
}
public void rightAccepting(boolean[] result) {
for (int rule = 0; rule < numFAs; rule++) {
result[rule] = rightFA[rule].isAccepting();
}
}
private void allocate(int numFAs) {
this.numFAs = numFAs;
leftFA = new FA[numFAs];
rightFA = new FA[numFAs];
}
public OutsideRuleFilter(BinaryGrammar bg, Index<String> stateIndex, Index<String> tagIndex) {
this.tagIndex = tagIndex;
int numStates = stateIndex.size();
numTags = tagIndex.size();
allocate(numStates);
for (int state = 0; state < numStates; state++) {
String stateStr = stateIndex.get(state);
List<String> left = new ArrayList<>();
List<String> right = new ArrayList<>();
if (!bg.isSynthetic(state)) {
registerRule(left, right, state);
continue;
}
boolean foundSemi = false;
boolean foundDots = false;
List<String> array = left;
StringBuilder sb = new StringBuilder();
for (int c = 0; c < stateStr.length(); c++) {
if (stateStr.charAt(c) == ':') {
foundSemi = true;
continue;
}
if (!foundSemi) {
continue;
}
if (stateStr.charAt(c) == ' ') {
if (sb.length() > 0) {
String str = sb.toString();
if (!tagIndex.contains(str)) {
str = null;
}
array.add(str);
sb = new StringBuilder();
}
continue;
}
if (!foundDots && stateStr.charAt(c) == '.') {
c += 3;
foundDots = true;
array = right;
continue;
}
sb.append(stateStr.charAt(c));
}
registerRule(left, right, state);
}
}
/** This is a simple Finite Automaton implementation. */
static class FA {
private boolean[] inStatePrev;
private boolean[] inStateNext;
private final boolean[] loopState;
private final int acceptingState;
private static final int initialState = 0;
private final int numStates;
private final int numSymbols;
private final int[][] transition; // state x tag
public void init() {
Arrays.fill(inStatePrev, false);
Arrays.fill(inStateNext, false);
inStatePrev[initialState] = true;
}
public void input(int symbol) {
for (int prevState = 0; prevState < numStates; prevState++) {
if (inStatePrev[prevState]) {
inStateNext[transition[prevState][symbol]] = true;
}
}
}
public void advance() {
boolean[] temp = inStatePrev;
inStatePrev = inStateNext;
inStateNext = temp;
Arrays.fill(inStateNext, false);
for (int state = 0; state < numStates; state++) {
if (inStatePrev[state] && loopState[state]) {
inStateNext[state] = true;
}
}
}
public boolean isAccepting() {
return inStatePrev[acceptingState];
}
public void setTransition(int state, int symbol, int result) {
transition[state][symbol] = result;
}
public void setLoopState(int state, boolean loops) {
loopState[state] = loops;
}
public FA(int numStates, int numSymbols) {
this.numStates = numStates;
this.numSymbols = numSymbols;
acceptingState = numStates - 1;
inStatePrev = new boolean[numStates];
inStateNext = new boolean[numStates];
loopState = new boolean[numStates];
transition = new int[numStates][numSymbols];
}
} // end class FA
} // end class OutsideRuleFilter