package net.sf.orcc.frontend.schedule;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import net.sf.orcc.df.Tag;
/**
* This class performs e-closure and determinization in one step.
*
* @author Felix Abecassis
*
*/
public class eNFAtoDFA {
private ArrayList<Set<Integer>> closure;
private Automaton DFA;
private Automaton eNFA;
public eNFAtoDFA(Automaton a) {
eNFA = a;
DFA = new Automaton(SimpleEdge.class);
DFA.setAlphabet(eNFA.getAlphabet());
closure = new ArrayList<Set<Integer>>(eNFA.vertexSet().size());
for (Integer v : eNFA.vertexSet()) {
doClosure(v);
}
}
public Automaton convert() {
// Associate each set of states from eNFA to the index of the
// corresponding state in DFA.
Map<Set<Integer>, Integer> seen = new HashMap<Set<Integer>, Integer>();
Set<Integer> initial = new HashSet<Integer>();
Stack<Set<Integer>> todo = new Stack<Set<Integer>>();
Integer index = 0;
Integer initialState = eNFA.getInitialState();
initial.add(initialState);
todo.push(initial);
seen.put(initial, index);
++index;
DFA.addVertex(initialState);
DFA.setInitialState(initialState);
while (!todo.empty()) {
Set<Integer> src = todo.pop();
Integer srcIndex = seen.get(src);
Set<Integer> eClosure = getSuccsEpsilon(src);
for (Tag label : DFA.getAlphabet()) {
Set<Integer> dst = getSuccsLabel(eClosure, label);
if (dst.isEmpty()) {
continue;
}
Integer i = seen.get(dst);
Integer dstIndex;
if (i != null) {
dstIndex = i;
} else {
// Add this new set to seen, and add a new state to DFA.
dstIndex = index;
seen.put(dst, index);
todo.push(dst);
DFA.addVertex(index);
for (Integer v : dst) {
if (eNFA.getFinalStates().contains(v)) {
// The set contains a final state, the new state
// must be final.
DFA.addFinalState(index);
break;
}
}
++index;
}
// Add this transition
DFA.addEdge(srcIndex, dstIndex, new SimpleEdge(label));
}
}
return DFA;
}
/**
* From state src, computes the set of reachable states using epsilon
* transitions The resulting set is added to the closure attribute.
*
* @param src
* the source state
*/
private void doClosure(Integer src) {
Set<Integer> curClosure = new HashSet<Integer>();
Stack<Integer> todo = new Stack<Integer>();
// A state is in in its own closure.
curClosure.add(src);
todo.push(src);
while (!todo.empty()) {
Integer cur = todo.pop();
if (eNFA.getFinalStates().contains(cur)) {
// src can reach a final state, src is therefore a final state
eNFA.addFinalState(src);
}
Set<SimpleEdge> succs = eNFA.outgoingEdgesOf(cur);
for (SimpleEdge e : succs) {
Integer target = eNFA.getEdgeTarget(e);
Tag label = (Tag) e.getObject();
if (label == null) {
if (!curClosure.contains(target)) {
// A new state reachable through epsilon transitions
todo.push(target);
curClosure.add(target);
}
}
}
}
closure.add(curClosure);
}
/**
* Given a set of states, returns the set of reachable states through
* epsilon transitions.
*
* @param src
* a set of states
* @return the set of epsilon-reachable states
*/
private Set<Integer> getSuccsEpsilon(Set<Integer> src) {
Set<Integer> result = new HashSet<Integer>();
// Compute the union of all precomputed closure sets.
for (Integer v : src) {
result.addAll(closure.get(v));
}
return result;
}
/**
* Given a set of states and a letter from the alphabet, returns the set of
* reachable states using this letter.
*
* @param stateSet
* a set of states
* @param letter
* the letter from the alphabet
* @return the set of reachable states using the letter
*/
private Set<Integer> getSuccsLabel(Set<Integer> stateSet, Tag letter) {
Set<Integer> result = new HashSet<Integer>();
for (Integer v : stateSet) {
Set<SimpleEdge> succs = eNFA.outgoingEdgesOf(v);
for (SimpleEdge e : succs) {
Integer target = eNFA.getEdgeTarget(e);
if (letter.equals(e.getObject())) {
result.add(target);
}
}
}
return result;
}
}