/** * Finds the set of states among s that can reach an accept state. */ private Set findLiveStates(Set s) { Map> back = new HashMap>(); // back(q) contains p iff delta(p,c)=q for some c for (State p : s) back.put(p, new HashSet()); for (State p : s) for (char c : alphabet.symbols) { State q = delta(p, c); if (s.contains(q)) back.get(q).add(p); } Set live = new HashSet(accept); Set pending = new HashSet(accept); while (!pending.isEmpty()) { State q = pending.iterator().next(); pending.remove(q); for (State p : back.get(q)) if (!live.contains(p)) { live.add(p); pending.add(p); } } return live; } /** * Checks whether there is a loop among s reachable from p * through the states in path. */ private boolean containsLoop(State p, Set s, Set path) { path.add(p); for (char c : alphabet.symbols) { // find the states that are reachable from p in one step and are in s State q = delta(p, c); if (s.contains(q) && (path.contains(q) || containsLoop(q, s, path))) return true; } path.remove(p); return false; } /** * Checks whether the language of this automaton is finite. [Martin, Example 2.34] */ public boolean isFinite() { // We use an alternative algorithm exploiting the fact that the language is infinite iff // there is a reachable loop with a path to an accept state. Set live = findLiveStates(findReachableStates()); return !containsLoop(initial, live, new HashSet()); }