/** * */ package rationals.transformations; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import rationals.Automaton; import rationals.NoSuchStateException; import rationals.State; import rationals.Transition; /** * A (rational) substitution is a morphism that maps * letters to languages. * A rational substitution is constructed like a {@see rationals.transformations.Morphism} * with an instance of {@see java.util.Map} that has Object as * keys and either Object or Automaton instances as values. * If the value of a key is an object, then it is considered a letter * and this class acts like a morphism. If the value of the key is an * Automaton, then the complete transition is replaced by the language * denoted by the automaton. * * @author nono * @see J.Berstel, "Transductions and context-free languages" */ public class Substitution implements UnaryTransformation { private Map morph; public Substitution(Map m) { this.morph = m; } /* (non-Javadoc) * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) */ public Automaton transform(Automaton a) { Automaton b = new Automaton(); /* state map */ Map stm = new HashMap(); for (Iterator i = a.delta().iterator(); i.hasNext();) { Transition tr = (Transition) i.next(); State ns = tr.start(); State nss = (State) stm.get(ns); if (nss == null) { nss = b.addState(ns.isInitial(), ns.isTerminal()); stm.put(ns, nss); } State ne = tr.end(); State nse = (State) stm.get(ne); if (nse == null) { nse = b.addState(ne.isInitial(), ne.isTerminal()); stm.put(ne, nse); } Object lbl = tr.label(); if (!morph.containsKey(lbl)) try { b.addTransition(new Transition(nss, lbl, nse)); } catch (NoSuchStateException e) { } else try { /* is value an automaton ? */ Object o = morph.get(lbl); if (o instanceof Automaton) insert(nss, nse, b, (Automaton) o); else b .addTransition(new Transition(nss, morph .get(lbl), nse)); } catch (NoSuchStateException e1) { } } return b; } /** * Insert <code>automaton</code> between states <code>nss</code> and * <code>nse</code> in automaton <code>b</code>. * This method add epsilon transitions from <code>nss</code> to each starting * state of automaton and from each ending state to <code>nse</code>. * * @param nss * @param nse * @param b * @param automaton */ private void insert(State nss, State nse, Automaton b, Automaton automaton) { /* map states */ Map map = new HashMap(); for (Iterator i = automaton.states().iterator(); i.hasNext();) { State e = (State) i.next(); State n = b.addState(false, false); map.put(e, n); if (e.isInitial()) try { b.addTransition(new Transition(nss, null, n)); } catch (NoSuchStateException e1) { } if (e.isTerminal()) try { b.addTransition(new Transition(n, null, nse)); } catch (NoSuchStateException e1) { } } for (Iterator i = automaton.delta().iterator(); i.hasNext();) { Transition t = (Transition) i.next(); try { b.addTransition(new Transition((State) map.get(t.start()), t .label(), (State) map.get(t.end()))); } catch (NoSuchStateException x) { } } } }