package rationals.transformations;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import rationals.Automaton;
import rationals.DefaultSynchronization;
import rationals.NoSuchStateException;
import rationals.State;
import rationals.Synchronization;
import rationals.Transition;
/**
* This class implements the mix - ie: synchronization product - operator
* between two automatas.
* <ul>
* <li>C = A mix B</li>
* <li>S(C) = { (a,b) | a in S(A) and b in S(B) }</li>
* <li>S0(C) = (S0(A),SO(B))</li>
* <li>T(C) = { (a,b) | a in T(A) and b in T(B) }</li>
* <li>D(C) = { ((s1a,s1b),a,(s2a,s2b)) | exists (s1a,a,s2a) in D(A) and exists
* (s1b,a,s2b) in D(b) } U { ((s1a,s1b),a,(s1a,s2b)) | a not in S(A) and exists
* (s1b,a,s2b) in D(b) } U { ((s1a,s1b),a,(s2a,s1b)) | a not in S(B) and exists
* (s1a,a,s2a) in D(a) }</li>
* </ul>
*
* @author Arnaud Bailly
* @version 22032002
*/
public class Mix implements BinaryTransformation {
private Synchronization synchronization;
/**
* Compute mix of two automata using default synchronization scheme which is
* the equality of labels.
*
* @see rationals.DefaultSynchronization
* @see rationals.Synchronization
*/
public Mix() {
this.synchronization = new DefaultSynchronization();
}
/**
* Compute mix of two automata using given synchronization scheme.
*
* @param synch
* a Synchronization object. Must not be null.
*/
public Mix(Synchronization synch) {
this.synchronization = synch;
}
/*
* (non-Javadoc)
* @see rationals.transformations.BinaryTransformation#transform(rationals.Automaton, rationals.Automaton)
*/
public Automaton transform(Automaton a, Automaton b) {
Automaton ret = new Automaton();
Set alph = synchronization.synchronizable(a.alphabet(), b.alphabet());
/* check alphabets */
Map amap = new HashMap();
Map bmap = new HashMap();
List /* < StatesCouple > */todo = new ArrayList();
Set /* < StatesCouple > */done = new HashSet();
Set as = TransformationsToolBox.epsilonClosure(a.initials(), a);
Set bs = TransformationsToolBox.epsilonClosure(b.initials(), b);
State from = ret.addState(true, TransformationsToolBox
.containsATerminalState(as)
&& TransformationsToolBox.containsATerminalState(bs));
StatesCouple sc = new StatesCouple(as, bs);
amap.put(sc, from);
todo.add(sc);
do {
StatesCouple couple = (StatesCouple) todo.remove(0);
from = (State) amap.get(couple);
if (done.contains(couple))
continue;
done.add(couple);
/* get transition sets */
Map tam = TransformationsToolBox.mapAlphabet(a.delta(couple.sa), a);
Map tbm = TransformationsToolBox.mapAlphabet(b.delta(couple.sb), b);
/* create label map for synchronized trans */
Map /* < Object, StatesCouple > */tcm = new HashMap();
/* unsynchronizable transitions in A */
for (Iterator i = tam.entrySet().iterator(); i.hasNext();) {
Map.Entry me = (Map.Entry) i.next();
Object l = me.getKey();
as = (Set) me.getValue();
if (!alph.contains(l)) {
Set asc = TransformationsToolBox.epsilonClosure(as, a);
tcm.put(l, sc = new StatesCouple(asc, couple.sb));
State to = (State) amap.get(sc);
if (to == null) {
to = ret.addState(false, TransformationsToolBox
.containsATerminalState(sc.sa)
&& TransformationsToolBox
.containsATerminalState(sc.sb));
amap.put(sc, to);
}
todo.add(sc);
i.remove();
}
}
/* unsynchronizable transition(s) in B */
for (Iterator i = tbm.entrySet().iterator(); i.hasNext();) {
Map.Entry me = (Map.Entry) i.next();
Object l = me.getKey();
bs = (Set) me.getValue();
if (!alph.contains(l)) {
Set bsc = TransformationsToolBox.epsilonClosure(bs, b);
tcm.put(l, sc = new StatesCouple(couple.sa, bsc));
State to = (State) amap.get(sc);
if (to == null) {
to = ret.addState(false, TransformationsToolBox
.containsATerminalState(sc.sa)
&& TransformationsToolBox
.containsATerminalState(sc.sb));
amap.put(sc, to);
}
todo.add(sc);
i.remove();
}
}
/*
* there remains in tam and tbm only possibly synchronizable
* transitions
*/
for (Iterator i = tam.entrySet().iterator(); i.hasNext();) {
Map.Entry me = (Map.Entry) i.next();
Object l = me.getKey();
as = (Set) me.getValue();
for (Iterator j = tbm.entrySet().iterator(); j.hasNext();) {
Map.Entry mbe = (Map.Entry) j.next();
Object k = mbe.getKey();
bs = (Set) mbe.getValue();
Object sy = synchronization.synchronize(l, k);
if (sy != null) {
Set asc = TransformationsToolBox.epsilonClosure(as, a);
Set bsc = TransformationsToolBox.epsilonClosure(bs, b);
tcm.put(sy, sc = new StatesCouple(asc, bsc));
State to = (State) amap.get(sc);
if (to == null) {
to = ret.addState(false, TransformationsToolBox
.containsATerminalState(sc.sa)
&& TransformationsToolBox
.containsATerminalState(sc.sb));
amap.put(sc, to);
}
todo.add(sc);
}
}
}
/*
*
* create new transitions in return automaton, update maps
*/
for (Iterator i = tcm.entrySet().iterator(); i.hasNext();) {
Map.Entry me = (Map.Entry) i.next();
Object l = me.getKey();
sc = (StatesCouple) me.getValue();
State to = (State) amap.get(sc);
if (to == null) {
to = ret.addState(false, TransformationsToolBox
.containsATerminalState(sc.sa)
&& TransformationsToolBox
.containsATerminalState(sc.sb));
amap.put(sc, to);
}
try {
ret.addTransition(new Transition(from, l, to));
} catch (NoSuchStateException e) {
}
}
} while (!todo.isEmpty());
return ret;
}
}