return extract(p.getFirstState(), p.getSecondState(), new HashSet<MLFAStatePair>());
}
private Automaton extract(MLFAState s, MLFAState f, final Set<MLFAStatePair> stack) {
MLFAStatePair p = new MLFAStatePair(s, f);
Automaton a = memo.get(p);
if (a != null) {
return a;
}
if (stack.contains(p)) {
throw new RuntimeException("MLFA is non-rankable");
}
stack.add(p);
Set<MLFAState> reachable = findReachable(s, f);
// handle special case with just one automaton/epsilon/identity transition from s to f
if (((s != f && reachable.size() == 2) || (s == f && reachable.size() == 1))
&& s.getEdges().size() == 1 && f.getEdges().size() == 0) {
MLFATransition t = s.getEdges().iterator().next().getTransition();
a = t.visitBy(new TransitionVisitor<Automaton>() {
public Automaton visitAutomatonTransition(AutomatonTransition t) {
return t.getAutomaton();
}
public Automaton visitEpsilonTransition(EpsilonTransition t) {
return Automaton.makeEmptyString();
}
public Automaton visitIdentityTransition(IdentityTransition t) {
return extract(t.getStartState(), t.getFinalState(), stack);
}
public Automaton visitUnaryTransition(UnaryTransition t) {
return null;
}
public Automaton visitBinaryTransition(BinaryTransition t) {
return null;
}
});
}
if (a == null) {
a = new Automaton();
// construct automaton states
Map<MLFAState, State> statemap = new HashMap<MLFAState, State>();
for (MLFAState q : reachable) {
State ss = new State();
statemap.put(q, ss);
if (q == s) {
a.setInitialState(ss);
}
if (q == f) {
ss.setAccept(true);
}
}
// add transitions
final Set<StatePair> epsilons = new HashSet<StatePair>();
for (MLFAState q : reachable) {
for (MLFAEdge e : q.getEdges()) {
if (reachable.contains(e.getDestination())) {
final State qq = statemap.get(q);
final State pp = statemap.get(e.getDestination());
Automaton b = e.getTransition().visitBy(new TransitionVisitor<Automaton>() {
public Automaton visitAutomatonTransition(AutomatonTransition t) {
return t.getAutomaton().clone();
}
public Automaton visitEpsilonTransition(EpsilonTransition t) {
epsilons.add(new StatePair(qq, pp));
return null;
}
public Automaton visitIdentityTransition(IdentityTransition t) {
return extract(t.getStartState(), t.getFinalState(), stack).clone();
}
public Automaton visitUnaryTransition(UnaryTransition t) {
return t.getOperation().op(extract(t.getStartState(), t.getFinalState(), stack));
}
public Automaton visitBinaryTransition(BinaryTransition t) {
return t.getOperation().op(
extract(t.getStartState1(), t.getFinalState1(), stack),
extract(t.getStartState2(), t.getFinalState2(), stack));
}
});
if (b != null) {
epsilons.add(new StatePair(qq, b.getInitialState()));
for (State rr : b.getAcceptStates()) {
rr.setAccept(false);
epsilons.add(new StatePair(rr, pp));
}
}
}