package edu.stanford.nlp.fsm;
import edu.stanford.nlp.util.Generics;
import edu.stanford.nlp.util.Scored;
import java.util.*;
/**
* DFSAState represents the state of a deterministic finite state
* automaton without epsilon transitions.
*
* @author Dan Klein
* @version 12/14/2000
* @author Sarah Spikes (sdspikes@cs.stanford.edu) - cleanup and filling in types
* @param <S> stateID type
* @param <T> transition type
*/
public final class DFSAState<T,S> implements Scored {
private S stateID;
private Map<T,DFSATransition<T,S>> inputToTransition;
public boolean accepting;
private DFSA<T,S> dfsa;
public double score;
public double score() {
return score;
}
public void setScore(double score) {
this.score = score;
}
public DFSA<T, S> dfsa() {
return dfsa;
}
public void setStateID(S stateID) {
this.stateID = stateID;
}
public S stateID() {
return stateID;
}
public void addTransition(DFSATransition<T,S> transition) {
inputToTransition.put(transition.input(), transition);
}
public DFSATransition<T,S> transition(T input) {
return inputToTransition.get(input);
}
public Collection<DFSATransition<T,S>> transitions() {
return inputToTransition.values();
}
public Set<T> continuingInputs() {
return inputToTransition.keySet();
}
public Set<DFSAState<T,S>> successorStates() {
Set<DFSAState<T,S>> successors = Generics.newHashSet();
Collection<DFSATransition<T, S>> transitions = inputToTransition.values();
for (DFSATransition<T,S> transition : transitions) {
successors.add(transition.getTarget());
}
return successors;
}
public void setAccepting(boolean accepting) {
this.accepting = accepting;
}
public boolean isAccepting() {
return accepting;
}
public boolean isContinuable() {
return !inputToTransition.isEmpty();
}
@Override
public String toString() {
return stateID.toString();
}
private int hashCodeCache; // = 0;
@Override
public int hashCode() {
if (hashCodeCache == 0) {
hashCodeCache = stateID.hashCode() ^ dfsa.hashCode();
}
return hashCodeCache;
}
// equals
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof DFSAState)) {
return false;
}
DFSAState s = (DFSAState) o;
// historically also checked: accepting == s.accepting &&
//inputToTransition.equals(s.inputToTransition))
return dfsa.equals(s.dfsa) && stateID.equals(s.stateID);
}
public Set<DFSAState<T, S>> statesReachable() {
Set<DFSAState<T, S>> visited = Generics.newHashSet();
List<DFSAState<T, S>> toVisit = new ArrayList<>();
toVisit.add(this);
exploreStates(toVisit, visited);
return visited;
}
private 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 DFSAState(S id, DFSA<T,S> dfsa) {
this.dfsa = dfsa;
this.stateID = id;
this.accepting = false;
this.inputToTransition = Generics.newHashMap();
this.score = Double.NEGATIVE_INFINITY;
}
public DFSAState(S id, DFSA<T,S> dfsa, double score) {
this(id,dfsa);
setScore(score);
}
}