/*
* (C) Copyright 2001 Arnaud Bailly (arnaud.oqube@gmail.com),
* Yves Roos (yroos@lifl.fr) and others.
*
* Licensed under the Apache License, Version 2.0 (the License);
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rationals.transformations;
import rationals.Automaton;
import rationals.Builder;
import rationals.NoSuchStateException;
import rationals.State;
import rationals.Transition;
import java.util.*;
/**
* Computes the minimal automaton from a deterministic automaton.
* <p />
* This class first determinizes the transformed automaton, then compute
* states equivalence classes to create new states and transitions.
*
* @author nono
* @version $Id: Reducer.java 2 2006-08-24 14:41:48Z oqube $
*/
public class Reducer<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> {
/*
* equivalence on DFA
*/
private boolean same(State e1, State e2, Automaton<L, Tr, T> a, Map<State, Set<State>> m) {
if (!m.get(e1).equals(m.get(e2)))
return false;
/* iterate over all transitions */
Set<Transition<L>> tas = a.delta(e1);
Set<Transition<L>> tbs = a.delta(e2);
Iterator<Transition<L>> it = tas.iterator();
while (it.hasNext()) {
Transition<L> tr = it.next();
State ep1 = tr.end();
/* check transition exists in b */
Set<Transition<L>> tbsl = a.delta(e2, tr.label());
if (tbsl.isEmpty())
return false;
Iterator<Transition<L>> trb = tbsl.iterator();
while (trb.hasNext()) {
Transition<?> tb = trb.next();
/* mark transition as visited */
tbs.remove(tb);
State ep2 = tb.end();
if (!m.get(ep1).equals(m.get(ep2)))
return false;
}
}
if (!tbs.isEmpty()) {
return false;
}
return true;
}
public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) {
Automaton<L, Tr, T> b = new ToDFA<L, Tr, T>().transform(a);
Map<State, Set<State>> current = new HashMap<State, Set<State>>();
Set<State> s1 = b.getStateFactory().stateSet();
Set<State> s2 = b.getStateFactory().stateSet();
Iterator<State> i = b.states().iterator();
while (i.hasNext()) {
State e = i.next();
if (e.isTerminal()) {
s1.add(e);
current.put(e, s1);
} else {
s2.add(e);
current.put(e, s2);
}
}
Map<State, Set<State>> old;
do {
old = current;
current = new HashMap<State, Set<State>>();
i = old.keySet().iterator();
while (i.hasNext()) {
State e1 = i.next();
Set<State> s = b.getStateFactory().stateSet();
Iterator<State> j = current.keySet().iterator();
while (j.hasNext()) {
State e2 = j.next();
if (same(e1, e2, b, old)) {
s = current.get(e2);
break;
}
}
s.add(e1);
current.put(e1, s);
}
} while (!new HashSet<Set<State>>(current.values())
.equals(new HashSet<Set<State>>(old.values())));
Automaton<L, Tr, T> c = new Automaton<L, Tr, T>();
Set<Set<State>> setSet = new HashSet<Set<State>>(current.values());
Iterator<Set<State>> sets = setSet.iterator();
Map<Set<State>, State> newStates = new HashMap<>();
while (sets.hasNext()) {
Set<State> set = sets.next();
boolean term = TransformationsToolBox.containsATerminalState(set);
boolean init = TransformationsToolBox.containsAnInitialState(set);
newStates.put(set, c.addState(init, term));
}
sets = setSet.iterator();
while (sets.hasNext()) {
Set<State> set = sets.next();
State r = set.iterator().next();
State rp = newStates.get(set);
Iterator<L> k = b.alphabet().iterator();
while (k.hasNext()) {
L l = k.next();
Set<Transition<L>> ds = b.delta(r, l);
if(ds.isEmpty())
continue;
State f = ds.iterator().next().end();
State fp = newStates.get(current.get(f));
try {
c.addTransition(new Transition<>(rp, l, fp));
} catch (NoSuchStateException x) {
}
}
}
return c;
}
}