/* * (C) Copyright 2005 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.transductions; 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 java.util.Stack; import rationals.Automaton; import rationals.NoSuchStateException; import rationals.State; import rationals.Transition; import rationals.transformations.Reducer; /** * An implementation of rational transductions using transducers. This * implementation expects each transition's label to be an instance of the class * {@link rationals.transductions.TransducerRelation} that contains input/output letters - * not words - and epsilon transitions. According to (Berstel, 1979), any * rational transduction can be encoded in such a transducer. * * @author nono * @version $Id: Transducer.java 2 2006-08-24 14:41:48Z oqube $ */ public class Transducer extends Automaton implements Transduction { /* input and output automata isomorphic ot this transducer */ private Automaton input = new Automaton(); private Automaton output = new Automaton(); /* maps from states */ /* map states of input automaton to this transducer states */ private Map ins = new HashMap(); /* map states of output automaton to this transudcer states */ private Map outs = new HashMap(); /* inverse maps */ private Map sin = new HashMap(); private Map sout = new HashMap(); /* * (non-Javadoc) * * @see rationals.transductions.Transduction#image(rationals.Automaton) */ public Automaton image(Automaton a) { /* * construct morphisms, inverse morphisms and rational * languages that are equivalent to transduciton */ return null; } /* * (non-Javadoc) * * @see rationals.Rational#newState(boolean, boolean) */ public State addState(boolean initial, boolean terminal) { State s = super.addState(initial, terminal); State is = input.addState(initial, terminal); State os = output.addState(initial, terminal); ins.put(is, s); outs.put(os, s); sin.put(s, is); sout.put(s, os); return s; } /** * The label of a transition in a transducer is a couple of letters, * possibliy null. * * @throws ClassCastException if transition is not a TransducerTransition * @see rationals.transductions.TransducerRelation * @see rationals.Rational#addTransition(rationals.Transition) */ public void addTransition(Transition transition) throws NoSuchStateException { // check transition's object is a couple of lists TransducerRelation rel = (TransducerRelation) transition.label(); /* update input and output automata */ input.addTransition(new Transition((State) sin.get(transition.start()), rel.getIn(), (State) sin.get(transition.end()))); output.addTransition(new Transition((State) sout .get(transition.start()), rel.getOut(), (State) sout .get(transition.end()))); super.addTransition(transition); } /* * (non-Javadoc) * * @see rationals.Transduction#image(java.util.List) */ public Automaton image(List word) { return image(word.toArray()); } /* * (non-Javadoc) * * @see rationals.Transduction#image(java.util.List) */ public Automaton image(Object[] word) { /* set of transitions fired */ Set s = initials(); List /* < Set < Transition > > */trs = new ArrayList(); /* * list of set * of * transitions */ List /* < Set < State > > */sts = new ArrayList(); /* * list of set of * states - does not * contain initials */ /* * first compute a the list of set of transition that the input word * crosses */ int ln = word.length; for (int i = 0; i < ln; i++) { Set tf = new HashSet(); s = step(s, word[i], tf); if (s.isEmpty()) return new Automaton(); /* language is empty */ trs.add(tf); sts.add(s); } s.retainAll(terminals()); Automaton ret = makeOutputAutomata(trs, sts); return new Reducer().transform(ret); } /** * Create the FSA representing the output language according to lists of * transitions and list of states reached while reading the word to * transduce. * * @param trs * a List of Set of transitions reached in one letter * @param sts * a List of set of states reached in one step. * @return an Automaton object on the output alphabet */ private Automaton makeOutputAutomata(List trs, List sts) { Set s; /* * construct the output automaton from tf This is the concatenation of * all the sub automata induced by the list of set of transitions */ Automaton ret = new Automaton(); Map sm = new HashMap(); /* nap old states to new states */ s = initials(); for (Iterator i = s.iterator(); i.hasNext();) { Set es = new HashSet(); es.add(ret.addState(true, false)); sm.put(i.next(), es); } Iterator tit = trs.iterator(); Iterator sit = sts.iterator(); while (tit.hasNext()) { /* * set of states and transitions resp. attained and crossed in one * step */ Set arr = (Set) sit.next(); Set trr = (Set) tit.next(); Map om = new HashMap(); Map /* < State, Set < State > > */ em = new HashMap(); /* construct a new automaton */ /* start states */ for (Iterator it2 = s.iterator(); it2.hasNext();) { State state = (State) it2.next(); State sst = ret.addState(false, false); om.put(state, sst); try { /* * connect start states in this step to end states in last * step */ Iterator it3 = ((Set)sm.get(state)).iterator(); while(it3.hasNext()) ret.addTransition(new Transition((State) it3.next(), null, sst)); } catch (NoSuchStateException e) { } } /* end states */ for (Iterator it2 = arr.iterator(); it2.hasNext();) { State state = (State) it2.next(); State sst = (State) om.get(state); if (sst == null) om.put(state, sst = ret.addState(false, false)); Set est = new HashSet(); est.add(sst); em.put(state,est); } /* transitions */ for (Iterator it2 = trr.iterator(); it2.hasNext();) { Transition trans = (Transition) it2.next(); TransducerRelation rel = (TransducerRelation)trans.label(); State ast, bst; State start = trans.start(); ast = (State) om.get(start); if (ast == null) { ast = ret.addState(false, false); om.put(trans.start(), ast); } /* handle differently null transitions from others */ State end = trans.end(); if(start == end && rel.getIn() != null) { Set est = (Set)em.get(end); bst = (State) om.get(end); ret.addState(false, false); om.put(trans.end(), bst); est.add(bst); } else { bst = (State) om.get(end); if (bst == null) { bst = ret.addState(false, false); om.put(trans.end(), bst); } } try { ret.addTransition(new Transition(ast, rel.getOut(), bst)); } catch (NoSuchStateException e1) { e1.printStackTrace(); } } /* connect sm to om */ sm = em; /* append to ret */ s = arr; } /* complete automaton with a start and end state */ State end = ret.addState(false, true); sit = s.iterator(); while (sit.hasNext()) { State old = (State) sit.next(); if (old.isTerminal()) try { Set niou = (Set) sm.get(old); for (Iterator iter = niou.iterator(); iter.hasNext();) { ret.addTransition(new Transition((State)iter.next(), null, end)); } } catch (NoSuchStateException e1) { } } return ret; } /* * */ protected Set step(Set s, Object o, Set trans) { Set arr = new HashSet(); Iterator it = s.iterator(); while (it.hasNext()) { State st = (State) it.next(); Iterator it2 = delta(st).iterator(); while (it2.hasNext()) { Transition tr = (Transition) it2.next(); TransducerRelation rel = (TransducerRelation)tr.label(); if (rel.getIn() != null && rel.getIn().equals(o)) { arr.add(tr.end()); trans.add(tr); } } } return epsilonClosure(arr, trans); } /* * Return the set of states that can be <em> reached </em> from s using * epsilon transitions only and update trans set. The reached states does * not contains the starting states. */ private Set epsilonClosure(Set s, Set trans) { Set exp = new HashSet(s); /* set of states to visit */ Set view = new HashSet(); /* set of states visited */ Set arr = new HashSet(); /* the set of arrival states */ do { Set ns = new HashSet(exp); /* arrival states */ Iterator it = ns.iterator(); while (it.hasNext()) { State st = (State) it.next(); exp.remove(st); Iterator it2 = delta(st).iterator(); while (it2.hasNext()) { Transition tr = (Transition) it2.next(); TransducerRelation rel = (TransducerRelation)tr.label(); if (rel.getIn() == null && !view.contains(tr.end())) { /* compute closure of epsilon transitions */ trans.add(tr); exp.add(tr.end()); } else { arr.add(tr.start()); } } view.add(st); } } while (!exp.isEmpty()); return arr; } /* * (non-Javadoc) * * @see rationals.Transduction#inverse(java.util.List) */ public Set inverse(List word) { // TODO Auto-generated method stub return null; } /** * @return the input alphabet of this transducer */ public Set inputAlphabet() { return input.alphabet(); } /** * * @return the output alphabet of this transducer */ public Set outputAlphabet() { return output.alphabet(); } /** * This method creates a set of input letters that covers all the * transitions occuring in this transducer. * * @return a Set of Object arrays */ public Set makeTransitionCover() { Set tr = new HashSet(); Stack /* < State > */todost = new Stack(); Stack /* < List < Object > > */todoword = new Stack(); Set /* < Set > */exp = new HashSet(); todost.addAll(initials()); int l = initials().size(); for (int i = 0; i < l; i++) todoword.push(new ArrayList()); do { /* build all sequences accessible from a state */ State s = (State) todost.pop(); List word = (List) todoword.pop(); /* state already viewed */ if (exp.contains(s)) { tr.add(word); continue; } exp.add(s); Iterator it = delta(s).iterator(); boolean first = true; while (it.hasNext()) { Transition t = (Transition) it.next(); TransducerRelation rel = (TransducerRelation)t.label(); List nw; if (!first) nw = new ArrayList(word); else nw = word; nw.add(rel.getIn()); /* push end state and new sequence */ todost.push(t.end()); todoword.push(nw); first = false; } } while (!todost.isEmpty()); return tr; } }