package edu.stanford.nlp.fsm;
import edu.stanford.nlp.util.logging.Redwood;
import edu.stanford.nlp.util.Generics;
import edu.stanford.nlp.util.Scored;
import java.io.IOException;
import java.io.Writer;
import java.util.*;
/**
* DFSA: A class for representing a deterministic finite state automaton
* without epsilon transitions.
*
* @author Dan Klein
* @author Michel Galley (AT&T FSM library format printing)
* @author Sarah Spikes (sdspikes@cs.stanford.edu) - cleanup and filling in types
*/
public final class DFSA<T,S> implements Scored {
/** A logger for this class */
private static Redwood.RedwoodChannels log = Redwood.channels(DFSA.class);
Object dfsaID;
DFSAState<T,S> initialState;
public DFSA(DFSAState<T,S> initialState, double score) {
this.initialState = initialState;
this.score = score;
}
public DFSA(DFSAState<T,S> initialState) {
this.initialState = initialState;
this.score = Double.NaN;
}
private double score;
@Override
public double score() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public DFSAState<T,S> initialState() {
return initialState;
}
public void setInitialState(DFSAState<T,S> initialState) {
this.initialState = initialState;
}
public Set<DFSAState<T, S>> states() {
Set<DFSAState<T, S>> visited = Generics.newHashSet();
List<DFSAState<T,S>> toVisit = new ArrayList<>();
toVisit.add(initialState());
exploreStates(toVisit, visited);
return visited;
}
private static <T, S> void exploreStates(List<DFSAState<T, S>> toVisit, Set<DFSAState<T, S>> visited) {
while (!toVisit.isEmpty()) {
DFSAState<T, S> state = toVisit.get(toVisit.size() - 1);
toVisit.remove(toVisit.size() - 1);
if (!visited.contains(state)) {
toVisit.addAll(state.successorStates());
visited.add(state);
}
}
}
public DFSA(Object dfsaID) {
this.dfsaID = dfsaID;
this.score = 0;
}
private static <T, S> void printTrieDFSAHelper(DFSAState<T, S> state, int level) {
if (state.isAccepting()) {
return;
}
Set<T> inputs = state.continuingInputs();
for (T input : inputs) {
DFSATransition<T, S> transition = state.transition(input);
System.out.print(level);
System.out.print(input);
for (int i = 0; i < level; i++) {
System.out.print(" ");
}
System.out.print(transition.score());
System.out.print(" ");
System.out.println(input);
printTrieDFSAHelper(transition.target(), level + 1);
}
}
public static <T, S> void printTrieDFSA(DFSA<T, S> dfsa) {
log.info("DFSA: " + dfsa.dfsaID);
printTrieDFSAHelper(dfsa.initialState(), 2);
}
public void printAttFsmFormat(Writer w) throws IOException {
Queue<DFSAState<T,S>> q = new LinkedList<>();
Set<DFSAState<T,S>> visited = Generics.newHashSet();
q.offer(initialState);
while(q.peek() != null) {
DFSAState<T, S> state = q.poll();
if(state == null || visited.contains(state))
continue;
visited.add(state);
if (state.isAccepting()) {
w.write(state.toString()+"\t"+state.score()+"\n");
continue;
}
TreeSet<T> inputs = new TreeSet<>(state.continuingInputs());
for (T input : inputs) {
DFSATransition<T, S> transition = state.transition(input);
DFSAState<T,S> target = transition.target();
if(!visited.contains(target))
q.add(target);
w.write(state.toString()+"\t"+target.toString()+"\t"+transition.getInput()+"\t"+transition.score()+"\n");
}
}
}
private static <T, S> void printTrieAsRulesHelper(DFSAState<T, S> state, String prefix, Writer w) throws IOException {
if (state.isAccepting()) {
return;
}
Set<T> inputs = state.continuingInputs();
for (T input : inputs) {
DFSATransition<T, S> transition = state.transition(input);
DFSAState<T, S> target = transition.target();
Set<T> inputs2 = target.continuingInputs();
boolean allTerminate = true;
for (T input2 : inputs2) {
DFSATransition<T, S> transition2 = target.transition(input2);
DFSAState<T, S> target2 = transition2.target();
if (target2.isAccepting()) {
// it's a binary end rule. Print it.
w.write(prefix + " --> " + input + " " + input2 + "\n");
} else {
allTerminate = false;
}
}
if (!allTerminate) {
// there are some longer continuations. Print continuation rule
String newPrefix = prefix + "_" + input;
w.write(prefix + " --> " + input + " " + newPrefix + "\n");
printTrieAsRulesHelper(transition.target(), newPrefix, w);
}
}
}
public static <T, S> void printTrieAsRules(DFSA<T, S> dfsa, Writer w) throws IOException {
printTrieAsRulesHelper(dfsa.initialState(), dfsa.dfsaID.toString(), w);
}
}