/**
* 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());
}