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); } }