From c83abc16b3708e04164075f5e6f7585e34594e25 Mon Sep 17 00:00:00 2001 From: Ludovic Apvrille <ludovic.apvrille@telecom-paristech.fr> Date: Fri, 28 Sep 2018 11:32:27 +0200 Subject: [PATCH] Adding jautomata-core and new minimiztion algorithm in TTool --- .idea/libraries/libs.xml | 2 +- extra/jautomata-core/Makefile | 7 + extra/jautomata-core/rationals/Acceptor.java | 56 + extra/jautomata-core/rationals/Automaton.java | 1017 +++++++++++++++++ .../rationals/AutomatonRunListener.java | 51 + .../rationals/AutomatonRunner.java | 50 + extra/jautomata-core/rationals/Builder.java | 79 ++ extra/jautomata-core/rationals/Couple.java | 63 + .../rationals/DefaultStateFactory.java | 181 +++ .../rationals/DefaultSynchronization.java | 77 ++ extra/jautomata-core/rationals/MixPlay.java | 347 ++++++ .../rationals/NoSuchStateException.java | 56 + .../rationals/RandomAutomaton.java | 168 +++ extra/jautomata-core/rationals/Rational.java | 214 ++++ extra/jautomata-core/rationals/State.java | 56 + .../rationals/StateFactory.java | 86 ++ .../jautomata-core/rationals/StateLabels.java | 77 ++ .../rationals/StateMachine.java | 155 +++ .../jautomata-core/rationals/StatesTuple.java | 78 ++ .../rationals/Synchronization.java | 83 ++ .../jautomata-core/rationals/Transition.java | 170 +++ .../rationals/TransitionBuilder.java | 127 ++ .../rationals/algebra/Matrix.java | 226 ++++ .../rationals/algebra/RationalMatrix.java | 145 +++ .../rationals/algebra/SemiRing.java | 70 ++ .../converters/ConverterException.java | 24 + .../rationals/converters/Expression.java | 29 + .../rationals/converters/FromString.java | 26 + .../rationals/converters/ToRExpression.java | 144 +++ .../rationals/converters/ToString.java | 25 + .../converters/analyzers/DefaultLexer.class | Bin 0 -> 2567 bytes .../converters/analyzers/DefaultLexer.java | 178 +++ .../converters/analyzers/Lexer.class | Bin 0 -> 849 bytes .../rationals/converters/analyzers/Lexer.java | 102 ++ .../converters/analyzers/Parser.class | Bin 0 -> 4800 bytes .../converters/analyzers/Parser.java | 301 +++++ .../rationals/converters/toAscii.java | 45 + .../rationals/expr/BinaryExpr.java | 64 ++ .../rationals/expr/Iteration.java | 52 + .../jautomata-core/rationals/expr/Letter.java | 93 ++ extra/jautomata-core/rationals/expr/Plus.java | 41 + .../rationals/expr/Product.java | 43 + .../rationals/expr/RationalExpr.java | 86 ++ .../rationals/properties/AreEquivalent.java | 78 ++ .../rationals/properties/AreIsomorph.java | 46 + .../rationals/properties/BinaryTest.java | 54 + .../rationals/properties/Bisimilar.java | 34 + .../rationals/properties/Bisimulation.java | 139 +++ .../rationals/properties/ContainsEpsilon.java | 52 + .../rationals/properties/IsDeterministic.java | 64 ++ .../rationals/properties/ModelCheck.java | 76 ++ .../rationals/properties/Relation.java | 77 ++ .../rationals/properties/Similar.java | 34 + .../rationals/properties/Simulation.java | 144 +++ .../properties/TraceEquivalence.java | 161 +++ .../rationals/properties/TraceEquivalent.java | 34 + .../rationals/properties/UnaryTest.java | 25 + .../properties/WeakBisimulation.java | 70 ++ .../rationals/properties/WeaklyBisimilar.java | 35 + .../rationals/properties/isEmpty.java | 37 + .../rationals/properties/isNormalized.java | 45 + .../rationals/transformations/Accessible.java | 97 ++ .../transformations/BinaryTransformation.java | 30 + .../rationals/transformations/Complement.java | 93 ++ .../transformations/CompleteNop.java | 91 ++ .../transformations/Concatenation.java | 118 ++ .../EpsilonTransitionRemover.java | 110 ++ .../rationals/transformations/HashValue.java | 64 ++ .../rationals/transformations/Identity.java | 37 + .../transformations/InverseMorphism.java | 131 +++ .../rationals/transformations/Mix.java | 194 ++++ .../rationals/transformations/Morphism.java | 83 ++ .../rationals/transformations/Normalizer.java | 104 ++ .../transformations/PartialCommutation.java | 34 + .../transformations/PrefixClosure.java | 77 ++ .../rationals/transformations/Projection.java | 84 ++ .../rationals/transformations/Pruner.java | 57 + .../transformations/RandomWalk.java.old | 89 ++ .../rationals/transformations/Reducer.java | 140 +++ .../rationals/transformations/Reverser.java | 62 + .../rationals/transformations/Shuffle.java | 71 ++ .../transformations/SinkComplete.java | 89 ++ .../rationals/transformations/Star.java | 75 ++ .../transformations/StatesCouple.java | 66 ++ .../transformations/Substitution.java | 133 +++ .../rationals/transformations/ToC.java | 104 ++ .../transformations/ToCanonicalRFSA.java | 31 + .../rationals/transformations/ToDFA.java | 121 ++ .../transformations/Transformations.java | 39 + .../TransformationsToolBox.java | 124 ++ .../transformations/UnaryTransformation.java | 25 + .../rationals/transformations/Union.java | 61 + src/main/java/graph/AUTGraph.java | 35 +- src/main/java/ui/window/JFrameMinimize.java | 2 +- ttool/build.gradle | 1 + 95 files changed, 8756 insertions(+), 15 deletions(-) create mode 100644 extra/jautomata-core/Makefile create mode 100755 extra/jautomata-core/rationals/Acceptor.java create mode 100755 extra/jautomata-core/rationals/Automaton.java create mode 100755 extra/jautomata-core/rationals/AutomatonRunListener.java create mode 100755 extra/jautomata-core/rationals/AutomatonRunner.java create mode 100755 extra/jautomata-core/rationals/Builder.java create mode 100755 extra/jautomata-core/rationals/Couple.java create mode 100755 extra/jautomata-core/rationals/DefaultStateFactory.java create mode 100755 extra/jautomata-core/rationals/DefaultSynchronization.java create mode 100755 extra/jautomata-core/rationals/MixPlay.java create mode 100755 extra/jautomata-core/rationals/NoSuchStateException.java create mode 100755 extra/jautomata-core/rationals/RandomAutomaton.java create mode 100755 extra/jautomata-core/rationals/Rational.java create mode 100755 extra/jautomata-core/rationals/State.java create mode 100755 extra/jautomata-core/rationals/StateFactory.java create mode 100755 extra/jautomata-core/rationals/StateLabels.java create mode 100755 extra/jautomata-core/rationals/StateMachine.java create mode 100755 extra/jautomata-core/rationals/StatesTuple.java create mode 100755 extra/jautomata-core/rationals/Synchronization.java create mode 100755 extra/jautomata-core/rationals/Transition.java create mode 100755 extra/jautomata-core/rationals/TransitionBuilder.java create mode 100755 extra/jautomata-core/rationals/algebra/Matrix.java create mode 100755 extra/jautomata-core/rationals/algebra/RationalMatrix.java create mode 100755 extra/jautomata-core/rationals/algebra/SemiRing.java create mode 100755 extra/jautomata-core/rationals/converters/ConverterException.java create mode 100755 extra/jautomata-core/rationals/converters/Expression.java create mode 100755 extra/jautomata-core/rationals/converters/FromString.java create mode 100755 extra/jautomata-core/rationals/converters/ToRExpression.java create mode 100755 extra/jautomata-core/rationals/converters/ToString.java create mode 100644 extra/jautomata-core/rationals/converters/analyzers/DefaultLexer.class create mode 100755 extra/jautomata-core/rationals/converters/analyzers/DefaultLexer.java create mode 100644 extra/jautomata-core/rationals/converters/analyzers/Lexer.class create mode 100755 extra/jautomata-core/rationals/converters/analyzers/Lexer.java create mode 100644 extra/jautomata-core/rationals/converters/analyzers/Parser.class create mode 100755 extra/jautomata-core/rationals/converters/analyzers/Parser.java create mode 100755 extra/jautomata-core/rationals/converters/toAscii.java create mode 100755 extra/jautomata-core/rationals/expr/BinaryExpr.java create mode 100755 extra/jautomata-core/rationals/expr/Iteration.java create mode 100755 extra/jautomata-core/rationals/expr/Letter.java create mode 100755 extra/jautomata-core/rationals/expr/Plus.java create mode 100755 extra/jautomata-core/rationals/expr/Product.java create mode 100755 extra/jautomata-core/rationals/expr/RationalExpr.java create mode 100755 extra/jautomata-core/rationals/properties/AreEquivalent.java create mode 100755 extra/jautomata-core/rationals/properties/AreIsomorph.java create mode 100755 extra/jautomata-core/rationals/properties/BinaryTest.java create mode 100755 extra/jautomata-core/rationals/properties/Bisimilar.java create mode 100755 extra/jautomata-core/rationals/properties/Bisimulation.java create mode 100755 extra/jautomata-core/rationals/properties/ContainsEpsilon.java create mode 100755 extra/jautomata-core/rationals/properties/IsDeterministic.java create mode 100755 extra/jautomata-core/rationals/properties/ModelCheck.java create mode 100755 extra/jautomata-core/rationals/properties/Relation.java create mode 100755 extra/jautomata-core/rationals/properties/Similar.java create mode 100755 extra/jautomata-core/rationals/properties/Simulation.java create mode 100755 extra/jautomata-core/rationals/properties/TraceEquivalence.java create mode 100755 extra/jautomata-core/rationals/properties/TraceEquivalent.java create mode 100755 extra/jautomata-core/rationals/properties/UnaryTest.java create mode 100755 extra/jautomata-core/rationals/properties/WeakBisimulation.java create mode 100755 extra/jautomata-core/rationals/properties/WeaklyBisimilar.java create mode 100755 extra/jautomata-core/rationals/properties/isEmpty.java create mode 100755 extra/jautomata-core/rationals/properties/isNormalized.java create mode 100755 extra/jautomata-core/rationals/transformations/Accessible.java create mode 100755 extra/jautomata-core/rationals/transformations/BinaryTransformation.java create mode 100755 extra/jautomata-core/rationals/transformations/Complement.java create mode 100755 extra/jautomata-core/rationals/transformations/CompleteNop.java create mode 100755 extra/jautomata-core/rationals/transformations/Concatenation.java create mode 100755 extra/jautomata-core/rationals/transformations/EpsilonTransitionRemover.java create mode 100755 extra/jautomata-core/rationals/transformations/HashValue.java create mode 100755 extra/jautomata-core/rationals/transformations/Identity.java create mode 100755 extra/jautomata-core/rationals/transformations/InverseMorphism.java create mode 100755 extra/jautomata-core/rationals/transformations/Mix.java create mode 100755 extra/jautomata-core/rationals/transformations/Morphism.java create mode 100755 extra/jautomata-core/rationals/transformations/Normalizer.java create mode 100755 extra/jautomata-core/rationals/transformations/PartialCommutation.java create mode 100755 extra/jautomata-core/rationals/transformations/PrefixClosure.java create mode 100755 extra/jautomata-core/rationals/transformations/Projection.java create mode 100755 extra/jautomata-core/rationals/transformations/Pruner.java create mode 100755 extra/jautomata-core/rationals/transformations/RandomWalk.java.old create mode 100755 extra/jautomata-core/rationals/transformations/Reducer.java create mode 100755 extra/jautomata-core/rationals/transformations/Reverser.java create mode 100755 extra/jautomata-core/rationals/transformations/Shuffle.java create mode 100755 extra/jautomata-core/rationals/transformations/SinkComplete.java create mode 100755 extra/jautomata-core/rationals/transformations/Star.java create mode 100755 extra/jautomata-core/rationals/transformations/StatesCouple.java create mode 100755 extra/jautomata-core/rationals/transformations/Substitution.java create mode 100755 extra/jautomata-core/rationals/transformations/ToC.java create mode 100755 extra/jautomata-core/rationals/transformations/ToCanonicalRFSA.java create mode 100755 extra/jautomata-core/rationals/transformations/ToDFA.java create mode 100755 extra/jautomata-core/rationals/transformations/Transformations.java create mode 100755 extra/jautomata-core/rationals/transformations/TransformationsToolBox.java create mode 100755 extra/jautomata-core/rationals/transformations/UnaryTransformation.java create mode 100755 extra/jautomata-core/rationals/transformations/Union.java diff --git a/.idea/libraries/libs.xml b/.idea/libraries/libs.xml index f6f184a7f6..19404ec0f4 100644 --- a/.idea/libraries/libs.xml +++ b/.idea/libraries/libs.xml @@ -6,7 +6,6 @@ <root url="jar://$PROJECT_DIR$/libs/commons-io-2.5.jar!/" /> <root url="jar://$PROJECT_DIR$/libs/gs-core-1.3.jar!/" /> <root url="jar://$PROJECT_DIR$/libs/jaxen-1.1.6.jar!/" /> - <root url="jar://$PROJECT_DIR$/libs/commons-io-2.4-javadoc.jar!/" /> <root url="jar://$PROJECT_DIR$/libs/jsoup-1.8.1.jar!/" /> <root url="jar://$PROJECT_DIR$/libs/commons-io-2.5-javadoc.jar!/" /> <root url="jar://$PROJECT_DIR$/libs/gs-ui-1.3.jar!/" /> @@ -25,6 +24,7 @@ <root url="jar://$PROJECT_DIR$/libs/batik-svggen.jar!/" /> <root url="jar://$PROJECT_DIR$/libs/batik-util.jar!/" /> <root url="jar://$PROJECT_DIR$/libs/batik-xml.jar!/" /> + <root url="jar://$PROJECT_DIR$/libs/jautomata-core.jar!/" /> </CLASSES> <JAVADOC> <root url="jar://$PROJECT_DIR$/libs/commons-io-2.5-javadoc.jar!/" /> diff --git a/extra/jautomata-core/Makefile b/extra/jautomata-core/Makefile new file mode 100644 index 0000000000..769ac920bb --- /dev/null +++ b/extra/jautomata-core/Makefile @@ -0,0 +1,7 @@ +all: clean + mkdir build/ + javac -d build/ rationals/*.java rationals/*/*.java + cd build;jar -cf jautomata-core.jar rationals/*.class rationals/*/*.class + +clean: + rm -rf build/ diff --git a/extra/jautomata-core/rationals/Acceptor.java b/extra/jautomata-core/rationals/Acceptor.java new file mode 100755 index 0000000000..ee519c61d7 --- /dev/null +++ b/extra/jautomata-core/rationals/Acceptor.java @@ -0,0 +1,56 @@ +/* + * (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; + +import java.util.List; +import java.util.Set; + +/** + * @author nono + * @version $Id: Acceptor.java 10 2007-05-30 17:25:00Z oqube $ + */ +public interface Acceptor<L> { + /** + * Checks this automaton accepts the given "word". + * A word is a list of objects. This method checks that reading <code>word</code> + * starting from initials state leads to at least one terminal state. + * + * @param word + * @return + */ + boolean accept(List<L> word); + + /** + * Return a trace of states reading word from start state. + * If start state is null, assume reading from + * initials(). + * This method returns a List of Set objects showing all the states + * reached by this run while reading <code>word</code> starting from <code>start</code>. + * + * @param word a List of objects in this automaton's alphabet + * @param start a starting State. Maybe null + * @return a List of Set of State objects + */ + List<Set<State>> traceStates(List<L> word, State start); + + /* + * (non-Javadoc) + * @see rationals.Acceptor#steps(java.util.List) + */ + Set<State> steps(List<L> word); + +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/Automaton.java b/extra/jautomata-core/rationals/Automaton.java new file mode 100755 index 0000000000..02b6d2e8d8 --- /dev/null +++ b/extra/jautomata-core/rationals/Automaton.java @@ -0,0 +1,1017 @@ +/* + * (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; + +import rationals.transformations.TransformationsToolBox; + +import java.util.*; + +/** + * A class defining Automaton objects + * + * This class defines the notion of automaton. Following notations are used to + * describe this class. + * <p> + * An automaton is a 5-uple <em>A = (X , Q , I , T , D)</em> where + * <ul> + * <li><em>X</em> is a finite set of labels named alphabet , + * <li><em>Q</em> is a finite set of states, + * <li><em>I</em>, included in <em>Q</em>, is the set of initial states, + * <li><em>T</em>, included in <em>Q</em>, is the set of terminal states + * <li>and <em>D</em> is the set of transitions, which is included in + * <em>Q times X times Q</em> (transitions are triples <em>(q , l , q')</em> where <em>q, q'</em> + * are states and <em>l</em> a label). + * </ul> + * The empty word, usually denoted by <em>epsilon</em> will be denoted here by + * the symbol <em>@</em>. + * <p> + * In this implementation of automaton, any object may be a label, states are + * instance of class <tt>State</tt> and transitions are intances of class + * <tt>Transition</tt>. Only automata should create instances of states through + * <tt>Automaton</tt> method <tt>newState</tt>. + * + * @author yroos@lifl.fr + * @author bailly@lifl.fr + * @version $Id: Automaton.java 10 2007-05-30 17:25:00Z oqube $ + * @see Transition State + */ +public class Automaton<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> + implements Acceptor<L>, StateMachine<L>, Rational<L>, Cloneable { + /* the identification of this automaton */ + private Object id; + + protected Builder<L, Tr, T> builder; + + /** + * @return Returns the id. + */ + public Object getId() { + return id; + } + + /** + * @param id + * The id to set. + */ + public void setId(Object id) { + this.id = id; + } + + // The set of all objects which are labels of + // transitions of this automaton. + protected Set<L> alphabet; + + // The set of all states of this automaton. + private Set<State> states; + + // the set of initial states + private Set<State> initials; + + // the set of terminal states + private Set<State> terminals; + + // Allows access to transitions of this automaton + // starting from a given state and labelled by + // a given object. The keys of this map are instances + // of class Key and + // values are sets of transitions. + private Map<Key, Set<Transition<L>>> transitions; + + // Allows access to transitions of this automaton + // arriving to a given state and labelled by + // a given object. The keys of this map are instances + // of class Key and + // values are sets of transitions. + private Map<Key, Set<Transition<L>>> reverse; + + // bonte + private StateFactory stateFactory = new DefaultStateFactory(this); + + private StateLabels stateLabels = new StateLabels(); + + /** + * @return + */ + public StateFactory getStateFactory() { + return this.stateFactory; + } + + /** + * @param factory + */ + public void setStateFactory(StateFactory factory) { + this.stateFactory = factory; + factory.setAutomaton(this); + } + + /** + * Returns an automaton which recognizes the regular language associated + * with the regular expression <em>@</em>, where <em>@</em> denotes the + * empty word. + * + * @return an automaton which recognizes <em>@</em> + */ + public static <L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> Automaton<L, Tr, T> epsilonAutomaton() { + Automaton<L, Tr, T> v = new Automaton<>(); + v.addState(true, true); + return v; + } + + /** + * Returns an automaton which recognizes the regular language associated + * with the regular expression <em>l</em>, where <em>l</em> is a given + * label. + * + * @param label + * any object that will be used as a label. + * @return an automaton which recognizes <em>label</em> + */ + public static <L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> Automaton<L, Tr, T> labelAutomaton(L label) { + Automaton<L, Tr, T> v = new Automaton<>(); + State start = v.addState(true, false); + State end = v.addState(false, true); + try { + v.addTransition(new Transition<L>(start, label, end)); + } catch (NoSuchStateException x) { + } + return v; + } + + /** + * Returns an automaton which recognizes the regular language associated + * with the regular expression <em>u</em>, where <em>u</em> is a given word. + * + * @param word + * a List of Object interpreted as a word + * @return an automaton which recognizes <em>label</em> + */ + public static <L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> Automaton<L, Tr, T> labelAutomaton(List<L> word) { + Automaton<L, Tr, T> v = new Automaton<>(); + State start = null; + if (word.isEmpty()) { + v.addState(true, true); + return v; + } else + start = v.addState(true, false); + State end = null; + try { + for (Iterator<L> i = word.iterator(); i.hasNext();) { + L o = i.next(); + end = v.addState(false, !i.hasNext()); + v.addTransition(new Transition<L>(start, o, end)); + start = end; + } + } catch (NoSuchStateException x) { + } + return v; + } + + /** + * Creates a new empty automaton which contains no state and no transition. + * An empty automaton recognizes the empty language. + */ + public Automaton() { + this(null); + } + + /** + * Create a new empty automaton with given state factory. + * + * @param sf + * the StateFactory object to use for creating new states. May be + * null. + */ + public Automaton(StateFactory sf) { + this.stateFactory = sf == null ? new DefaultStateFactory(this) : sf; + alphabet = new HashSet<>(); + states = stateFactory.stateSet(); + initials = stateFactory.stateSet(); + terminals = stateFactory.stateSet(); + transitions = new HashMap<>(); + reverse = new HashMap<>(); + } + + /** + * Returns a new instance of state which will be initial and terminal or not + * depending of parameters. + * + * @param initial + * if true, the new state will be initial; otherwise this state + * will be non initial. + * @param terminal + * if true, the new state will be terminal; otherwise this state + * will be non terminal. + * @return a new state, associated with this automaton. This new state + * should be used only with this automaton in order to create a new + * transition for this automaton. + * @see Transition + */ + public State addState(boolean initial, boolean terminal) { + + State state = stateFactory.create(initial, terminal); + if (initial) + initials.add(state); + if (terminal) + terminals.add(state); + states.add(state); + return state; + } + + /** + * Returns the alphabet <em>X</em> associated with this automaton. + * + * @return the alphabet <em>X</em> associated with this automaton. + */ + @Override + public Set<L> alphabet() { + return alphabet; + } + + /** + * Returns the set of states <em>Q</em> associated with this automaton. + * + * @return the set of states <em>Q</em> associated with this automaton. + * Objects which are contained in this set are instances of class + * <tt>State</tt>. + * @see State + */ + public Set<State> states() { + return states; + } + + /** + * Returns the set of initial states <em>I</em> associated with this + * automaton. + * + * @return the set of initial states <em>I</em> associated with this + * automaton. Objects which are contained in this set are instances + * of class <tt>State</tt>. + * @see State + */ + public Set<State> initials() { + return initials; + } + + /** + * Returns the set of terminal states <em>T</em> associated with this + * automaton. + * + * @return set of terminal states <em>T</em> associated with this automaton. + * Objects which are contained in this set are instances of class + * <tt>State</tt>. + * @see State + */ + public Set<State> terminals() { + return terminals; + } + + // Computes and return the set of all accessible states, starting + // from a given set of states and using transitions + // contained in a given Map + protected Set<State> access(Set<State> start, Map<Key, Set<Transition<L>>> map) { + Set<State> current = start; + Set<State> old; + do { + old = current; + current = stateFactory.stateSet(); + Iterator<State> i = old.iterator(); + while (i.hasNext()) { + State e = i.next(); + current.add(e); + Iterator<L> j = alphabet.iterator(); + while (j.hasNext()) { + Iterator<Transition<L>> k = find(map, e, j.next()).iterator(); + while (k.hasNext()) { + current.add(k.next().end()); + } + } + } + } while (current.size() != old.size()); + return current; + } + + /** + * Returns the set of all accessible states in this automaton. + * + * @return the set of all accessible states in this automaton. A state + * <em>s</em> is accessible if there exists a path from an initial + * state to <em>s</em>. Objects which are contained in this set are + * instances of class <tt>State</tt>. + * @see State + */ + public Set<State> accessibleStates() { + return access(initials, transitions); + } + + /** + * Returns the set of states that can be accessed in this automaton starting + * from given set of states + * + * @param states + * a non null set of starting states + * @return a - possibly empty - set of accessible states + */ + public Set<State> accessibleStates(Set<State> states) { + return access(states, transitions); + } + + /* + * (non-Javadoc) + * + * @see rationals.Rational#accessibleStates(rationals.State) + */ + public Set<State> accessibleStates(State state) { + Set<State> s = stateFactory.stateSet(); + s.add(state); + return access(s, transitions); + } + + /** + * Returns the set of co-accesible states for a given set of states, that is + * the set of states from this automaton from which there exists a path to a + * state in <code>states</code>. + * + * @param states + * a non null set of ending states + * @return a - possibly empty - set of coaccessible states + */ + public Set<State> coAccessibleStates(Set<State> states) { + return access(states, reverse); + } + + /** + * Returns the set of all co-accessible states in this automaton. + * + * @return the set of all co-accessible states in this automaton. A state + * <em>s</em> is co-accessible if there exists a path from this + * state <em>s</em> to a terminal state. Objects which are contained + * in this set are instances of class <tt>State</tt>. + * @see State + */ + public Set<State> coAccessibleStates() { + return access(terminals, reverse); + } + + /** + * Returns the set of all states which are co-accessible and accessible in + * this automaton. + * + * @return the set of all states which are co-accessible and accessible in + * this automaton. A state <em>s</em> is accessible if there exists + * a path from an initial state to <em>s</em>. A state <em>s</em> is + * co-accessible if there exists a path from this state <em>s</em> + * to a terminal state. Objects which are contained in this set are + * instances of class <tt>State</tt>. + * @see State + */ + public Set<State> accessibleAndCoAccessibleStates() { + Set<State> ac = accessibleStates(); + ac.retainAll(coAccessibleStates()); + return ac; + } + + // Computes and return the set of all transitions, starting + // from a given state and labelled by a given label + // contained in a given Map + protected Set<Transition<L>> find(Map<Key, Set<Transition<L>>> m, State e, L l) { + Key n = new Key(e, l); + if (!m.containsKey(n)) + return new HashSet<Transition<L>>(); + return m.get(n); + } + + // add a given transition in a given Map + protected void add(Map<Key, Set<Transition<L>>> m, Transition<L> t) { + Key n = new Key(t.start(), t.label()); + Set<Transition<L>> s; + if (!m.containsKey(n)) { + s = new HashSet<>(); + m.put(n, s); + } else + s = m.get(n); + s.add(t); + } + + /** + * Returns the set of all transitions of this automaton + * + * @return the set of all transitions of this automaton Objects which are + * contained in this set are instances of class <tt>Transition</tt>. + * @see Transition + */ + public Set<Transition<L>> delta() { + Set<Transition<L>> s = new HashSet<>(); + for (Set<Transition<L>> tr : transitions.values()) + s.addAll(tr); + return s; + } + + /** + * Returns the set of all transitions of this automaton starting from a + * given state and labelled b a given label. + * + * @param state + * a state of this automaton. + * @param label + * a label used in this automaton. + * @return the set of all transitions of this automaton starting from state + * <tt>state</tt> and labelled by <tt>label</tt>. Objects which are + * contained in this set are instances of class <tt>Transition</tt>. + * @see Transition + */ + public Set<Transition<L>> delta(State state, L label) { + return find(transitions, state, label); + } + + /** + * Returns the set of all transitions from state <code>from</code> to state + * <code>to</code>. + * + * @param from + * starting state + * @param to + * ending state + * @return a Set of Transition objects + */ + @Override + public Set<Transition<L>> deltaFrom(State from, State to) { + Set<Transition<L>> t = delta(from); + for (Iterator<Transition<L>> i = t.iterator(); i.hasNext();) { + Transition<L> tr = i.next(); + if (!to.equals(tr.end())) + i.remove(); + } + return t; + } + + /** + * Return all transitions from a State + * + * @param state + * start state + * @return a new Set of transitions (maybe empty) + */ + public Set<Transition<L>> delta(State state) { + Set<Transition<L>> s = new HashSet<>(); + for (L lt : alphabet) + s.addAll(delta(state, lt)); + return s; + } + + /** + * Returns all transitions from a given set of states. + * + * @param s + * a Set of State objects + * @return a Set of Transition objects + */ + public Set<Transition<L>> delta(Set<State> s) { + Set<Transition<L>> ds = new HashSet<>(); + for (State st : s) + ds.addAll(delta(st)); + return ds; + } + + /** + * Return a mapping from couples (q,q') of states to all (q,l,q') + * transitions from q to q' + * + * @return a Map + */ + public Map<Couple, Set<Transition<L>>> couples() { + // loop on transition map keys + Iterator<Map.Entry<Key, Set<Transition<L>>>> it = transitions.entrySet().iterator(); + Map<Couple, Set<Transition<L>>> ret = new HashMap<>(); + while (it.hasNext()) { + Map.Entry<Key, Set<Transition<L>>> e = it.next(); + // get start and end state + State st = e.getKey().s; + Iterator<Transition<L>> trans = e.getValue().iterator(); + while (trans.hasNext()) { + Transition<L> tr = trans.next(); + State nd = tr.end(); + Couple cpl = new Couple(st, nd); + Set<Transition<L>> s = ret.get(cpl); + if (s == null) + s = new HashSet<>(); + s.add(tr); + ret.put(cpl, s); + } + } + return ret; + } + + /** + * Returns the set of all transitions of the reverse of this automaton + * + * @return the set of all transitions of the reverse of this automaton. A + * reverse of an automaton <em>A = (X , Q , I , T , D)</em> is the + * automaton <em>A' = (X , Q , T , I , D')</em> where <em>D'</em> is the set <em>{ (q , l , q') | (q' , l , q) in D}</em>. Objects + * which are contained in this set are instances of class + * <tt>Transition</tt>. + * @see Transition + */ + @Override + public Set<Transition<L>> deltaMinusOne(State state, L label) { + return find(reverse, state, label); + } + + /** + * Adds a new transition in this automaton if it is a new transition for + * this automaton. The parameter is considered as a new transition if there + * is no transition in this automaton which is equal to the parameter in the + * sense of method <tt>equals</tt> of class <tt>Transition</tt>. + * + * @param transition + * the transition to add. + * @throws NoSuchStateException + * if <tt>transition</tt> is <tt>null</<tt> + * or if <tt>transition</tt> = <em>(q , l , q')</em> and <em>q</em> or <em>q'</em> does + * not belong to <em>Q</em> the set of the states of this + * automaton. + */ + public void addTransition(Transition<L> transition) throws NoSuchStateException { + if (!states.contains(transition.start()) + || !states.contains(transition.end())) + throw new NoSuchStateException(); + if (!alphabet.contains(transition.label())) { + alphabet.add(transition.label()); + } + add(transitions, transition); + add(reverse, new Transition<>(transition.end(), transition.label(), transition.start())); + } + + /** + * the project method keeps from the Automaton only the transitions labelled + * with the letters contained in the set alph, effectively computing a + * projection on this alphabet. + * + * @param alph + * the alphabet to project on + */ + public void projectOn(Set<?> alph) { + // remove unwanted transitions from ret + Iterator<Map.Entry<Key, Set<Transition<L>>>> trans = transitions.entrySet().iterator(); + Set<Transition<L>> newtrans = new HashSet<>(); + while (trans.hasNext()) { + Map.Entry<Key, Set<Transition<L>>> entry = trans.next(); + Key k = entry.getKey(); + Iterator<Transition<L>> tit = entry.getValue().iterator(); + while (tit.hasNext()) { + Transition<?> tr = tit.next(); + if (!alph.contains(k.l)) { + // create epsilon transition + newtrans.add(new Transition<L>(k.s, null, tr.end())); + // remove transition + tit.remove(); + } + } + } + // add newly created transitions + if (!newtrans.isEmpty()) { + for (Transition<L> tr : newtrans) { + add(transitions, tr); + add(reverse, new Transition<>(tr.end(), tr.label(), tr.start())); + } + } + // remove alphabet + alphabet.retainAll(alph); + } + + /** + * returns a textual representation of this automaton. + * + * @return a textual representation of this automaton based on the converter + * <tt>toAscii</tt>. + * @see rationals.converters.toAscii + */ + public String toString() { + return new rationals.converters.toAscii().toString(this); + } + + /** + * returns a copy of this automaton. + * + * @return a copy of this automaton with new instances of states and + * transitions. + */ + @Override + public Automaton<L, Tr, T> clone() { + Automaton<L, Tr, T> b = new Automaton<L, Tr, T>(); + Map<State, State> map = new HashMap<>(); + for (State e : states) + map.put(e, b.addState(e.isInitial(), e.isTerminal())); + for (Transition<L> t : delta()) { + try { + b.addTransition(new Transition<>(map.get(t.start()), t.label(), map.get(t.end()))); + } catch (NoSuchStateException x) { + } + } + return b; + } + + /** + * + * @return the set of labels matching initial states. + */ + public Set<Object> labelledInitials() { + return stateLabels.labels(initials()); + } + + /** + * + * @return the set of labels for terminal states. + */ + public Set<Object> labelledTerminals() { + return stateLabels.labels(terminals()); + } + + /** + * + * @return labels for states of this automaton. + */ + public Set<Object> labelledStates() { + return stateLabels.labels(states); + } + + private class Key { + private State s; + + private L l; + + protected Key(State s, L l) { + this.s = s; + this.l = l; + } + + public boolean equals(Object o) { + if (o == null || !(o instanceof Automaton.Key)) + return false; + Key t = (Key) o; + boolean ret = (l == null ? t.l == null : l.equals(t.l)) && (s == null ? t.s == null : s.equals(t.s)); + return ret; + } + + public int hashCode() { + int x, y; + if (s == null) + x = 0; + else + x = s.hashCode(); + if (l == null) + y = 0; + else + y = l.hashCode(); + return y << 16 | x; + } + } + + /** + * Returns true if this automaton accepts given word -- ie. sequence of + * letters. Note that this method accepts words with letters not in this + * automaton's alphabet, effectively recognizing all words from any alphabet + * projected to this alphabet. + * <p> + * If you need standard recognition, use + * + * @see{accept(java.util.List) . + * @param word + * @return + */ + public boolean prefixProjection(List<L> word) { + Set<?> s = stepsProject(word); + return !s.isEmpty(); + } + + /** + * Return the set of steps this automaton will be in after reading word. + * Note this method skips letters not in alphabet instead of rejecting them. + * + * @param l + * @return + */ + public Set<State> stepsProject(List<L> word) { + Set<State> s = initials(); + Iterator<L> it = word.iterator(); + while (it.hasNext()) { + L o = it.next(); + if (!alphabet.contains(o)) + continue; + s = step(s, o); + if (s.isEmpty()) + return s; + } + return s; + } + + /* + * (non-Javadoc) + * + * @see rationals.Acceptor#accept(java.util.List) + */ + @Override + public boolean accept(List<L> word) { + Set<State> s = TransformationsToolBox.epsilonClosure(steps(word), this); + s.retainAll(terminals()); + return !s.isEmpty(); + } + + /** + * Return true if this automaton can accept the given word starting from + * given set. <em>Note</em> The ending state(s) need not be terminal for + * this method to return true. + * + * @param state + * a starting state + * @param word + * a List of objects in this automaton's alphabet + * @return true if there exists a path labelled by word from s to at least + * one other state in this automaton. + */ + public boolean accept(State state, List<L> word) { + Set<State> s = stateFactory.stateSet(); + s.add(state); + return !steps(s, word).isEmpty(); + } + + /* + * (non-Javadoc) + * + * @see rationals.Acceptor#steps(java.util.List) + */ + @Override + public Set<State> steps(List<L> word) { + Set<State> s = TransformationsToolBox.epsilonClosure(initials(), this); + return steps(s, word); + } + + /** + * Return the set of states this automaton will be in after reading the word + * from start states s. + * + * @param s + * the set of starting states + * @param word + * the word to read. + * @return the set of reached states. + */ + @Override + public Set<State> steps(Set<State> s, List<L> word) { + Iterator<L> it = word.iterator(); + while (it.hasNext()) { + L o = it.next(); + s = step(s, o); + if (s.isEmpty()) + return s; + } + return s; + } + + /** + * Return the set of states this automaton will be in after reading the word + * from single start state s. + * + * @param st + * the starting state + * @param word + * the word to read. + * @return the set of reached states. + */ + @Override + public Set<State> steps(State st, List<L> word) { + Set<State> s = stateFactory.stateSet(); + s.add(st); + Iterator<L> it = word.iterator(); + while (it.hasNext()) { + L o = it.next(); + s = step(s, o); + if (s.isEmpty()) + return s; + } + return s; + } + + /** + * Return the list of set of states this automaton will be in after reading + * word from start state. Is start state is null, assume reading from + * initials(). + * + * @param word + * @param start + */ + @Override + public List<Set<State>> traceStates(List<L> word, State start) { + List<Set<State>> ret = new ArrayList<Set<State>>(); + Set<State> s = null; + if (start != null) { + s = stateFactory.stateSet(); + s.add(start); + } else { + s = initials(); + } + Iterator<L> it = word.iterator(); + while (it.hasNext()) { + L o = it.next(); + if (!alphabet.contains(o)) + continue; + s = step(s, o); + ret.add(s); + if (s.isEmpty()) + return null; + } + return ret; + } + + /** + * Returns the size of the longest word recognized by this automaton where + * letters not belonging to its alphabet are ignored. + * + * + * @param word + * @return + */ + public int longestPrefixWithProjection(List<L> word) { + int lret = 0; + Set<State> s = initials(); + Iterator<L> it = word.iterator(); + while (it.hasNext()) { + L o = it.next(); + if ((o == null) || !alphabet.contains(o)) { + lret++; + continue; + } + s = step(s, o); + if (s.isEmpty()) + break; + lret++; + } + return lret; + } + + /** + * Return the set of states accessible in one transition from given set of + * states s and letter o. + * + * @param s + * @param o + * @return + */ + public Set<State> step(Set<State> s, L o) { + Set<State> ns = stateFactory.stateSet(); + Set<State> ec = TransformationsToolBox.epsilonClosure(s, this); + Iterator<State> it = ec.iterator(); + while (it.hasNext()) { + State st = it.next(); + Iterator<?> it2 = delta(st).iterator(); + while (it2.hasNext()) { + Transition<?> tr = (Transition<?>) it2.next(); + if (tr.label() != null && tr.label().equals(o)) + ns.add(tr.end()); + } + } + return ns; + } + + /** + * @param tr + * @param msg + */ + public void updateTransitionWith(Transition<L> tr, L msg) { + L lbl = tr.label(); + alphabet.remove(lbl); + alphabet.add(msg); + /* update transition map */ + Key k = new Key(tr.start(), lbl); + Set<Transition<L>> s = transitions.remove(k); + if (s != null) + transitions.put(new Key(tr.start(), msg), s); + /* update reverse map */ + k = new Key(tr.end(), lbl); + s = reverse.remove(k); + if (s != null) + reverse.put(new Key(tr.end(), msg), s); + tr.setLabel(msg); + } + + /** + * @param st + * @return + */ + @Override + public Set<Transition<L>> deltaMinusOne(State st) { + Set<Transition<L>> s = new HashSet<>(); + Iterator<L> alphit = alphabet().iterator(); + while (alphit.hasNext()) { + s.addAll(deltaMinusOne(st, alphit.next())); + } + return s; + } + + /** + * Enumerate all prefix of words of length lower or equal than i in this + * automaton. This method takes exponential time and space to execute: <em> + * use with care !</em> + * . + * + * @param i + * maximal length of words. + * @return a Set of List of Object + */ + public Set<List<L>> enumerate(int ln) { + Set<List<L>> ret = new HashSet<>(); + class EnumState { + /** + * @param s + * @param list + */ + public EnumState(State s, List<L> list) { + st = s; + word = new ArrayList<L>(list); + } + + State st; + + List<L> word; + } + ; + LinkedList<EnumState> ll = new LinkedList<EnumState>(); + List<L> cur = new ArrayList<>(); + for (Iterator<State> i = initials.iterator(); i.hasNext();) { + State s = i.next(); + if (s.isTerminal()) + ret.add(new ArrayList<L>()); + ll.add(new EnumState(s, cur)); + } + + do { + EnumState st = ll.removeFirst(); + Set<Transition<L>> trs = delta(st.st); + List<L> word = st.word; + for (Iterator<Transition<L>> k = trs.iterator(); k.hasNext();) { + Transition<L> tr = k.next(); + word.add(tr.label()); + if (word.size() <= ln) { + EnumState en = new EnumState(tr.end(), word); + ll.add(en); + ret.add(en.word); + } + word.remove(word.size() - 1); + } + } while (!ll.isEmpty()); + return ret; + } + + /** + * Create a new state with given label. The state is created with as neither + * initial nor terminal. + * + * @param label + * the state's label. May not be null. + * @return the newly created state. + */ + public State state(L label) { + State s = stateLabels.state(label); + if (s == null) { + s = stateFactory.create(false, false, label); + states.add(s); + stateLabels.bind(s, label); + } + return s; + } + + /** + * Starts creation of a new transition from the given state. Note that the + * state is created with given label if it does not exists. + * + * @param o + * the label of state to create transition from. may not be null. + * @return a TransitionBuilder that can be used to create a new transition. + */ + public T from(L o) { + return builder.build(state(o), this); + } + + public void setBuilder(Builder<L, Tr, T> t) { + this.builder = t; + this.builder.setAutomaton(this); + } + + public void build(State from, L l, State to) + throws NoSuchStateException { + addTransition(this.builder.build(from, l, to)); + } +} diff --git a/extra/jautomata-core/rationals/AutomatonRunListener.java b/extra/jautomata-core/rationals/AutomatonRunListener.java new file mode 100755 index 0000000000..7dd2643814 --- /dev/null +++ b/extra/jautomata-core/rationals/AutomatonRunListener.java @@ -0,0 +1,51 @@ +/* + * (C) Copyright 2003 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; + +import java.util.Set; + +/** + * An interface to communicate run events. + * <p> + * This interface should be implemented by objects interested in being notified + * of run events, that is the firing of transitions during a run of an automaton. + * + * @version $Id: AutomatonRunListener.java 2 2006-08-24 14:41:48Z oqube $ + */ +public interface AutomatonRunListener { + + /** + * Callback method for notification of fire events occuring during the + * run of an automaton. + * + * @param automatonutomaton where the event took place + * @param transitions the set of transitions which have been fired + * @param o the object effectively "read" for firing transitions + */ + public void fire(Automaton automaton,Set transitions,Object o); + +} + +/* + * $Log: AutomatonRunListener.java,v $ + * Revision 1.2 2004/07/23 14:36:34 bailly + * ajout setTag + * + * Revision 1.1 2004/07/23 11:59:17 bailly + * added listener interfaces + * +*/ \ No newline at end of file diff --git a/extra/jautomata-core/rationals/AutomatonRunner.java b/extra/jautomata-core/rationals/AutomatonRunner.java new file mode 100755 index 0000000000..53bd4202f0 --- /dev/null +++ b/extra/jautomata-core/rationals/AutomatonRunner.java @@ -0,0 +1,50 @@ +/* + * (C) Copyright 2003 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; + +/** + * An interface for objects running automatons + * <p> + * This interface essentially provide a way to communicate with {@link AutomatonRunListener} + * objects for notifying run events + * + * @author nono + * @version $Id: AutomatonRunner.java 2 2006-08-24 14:41:48Z oqube $ + */ +public interface AutomatonRunner { + + /** + * Adds a listener to this runner + * + * @param l the listener to add - may no be null + */ + public void addRunListener(AutomatonRunListener l); + + /** + * Remove a listener from this runner + * + * @param l the listener to remove + */ + public void removeRunListener(AutomatonRunListener l); +} + +/* + * $Log: AutomatonRunner.java,v $ + * Revision 1.1 2004/07/23 11:59:17 bailly + * added listener interfaces + * +*/ \ No newline at end of file diff --git a/extra/jautomata-core/rationals/Builder.java b/extra/jautomata-core/rationals/Builder.java new file mode 100755 index 0000000000..3c5d84d899 --- /dev/null +++ b/extra/jautomata-core/rationals/Builder.java @@ -0,0 +1,79 @@ +/* + * (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; + +/** + * An interface for easier creation of automata. + */ +public interface Builder<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + + /** + * Factory method. + * + * @param label + * @param auto + * @return + */ + T build(State label, Automaton<L, Tr, T> auto); + + /** + * Sets the label of the transition. + * + * @param label + * @return this transition builder. + */ + T on(L label); + + /** + * Sets the end state and terminates transition construction. This method + * effectively adds the transition to the automaton. + * + * @param o + * the label of the end state. + */ + T go(L o); + + /** + * Adds a new transition in the automaton that loops on current label and + * from state. + * + * @return + */ + T loop(); + + /** + * Resets this builder to another starting state. Note that the state is + * created if needed. + * + * @param label + * the state to start from. + * @return this builder. + */ + T from(L label); + + /** + * Build a transition according to the specific logic of this builder. + * + * @param from + * @param lable + * @param to + * @return + */ + Tr build(State from, L label, State to); + + void setAutomaton(Automaton<L, Tr, T> a); +} diff --git a/extra/jautomata-core/rationals/Couple.java b/extra/jautomata-core/rationals/Couple.java new file mode 100755 index 0000000000..f78c5c8b5d --- /dev/null +++ b/extra/jautomata-core/rationals/Couple.java @@ -0,0 +1,63 @@ +/* + * (C) Copyright 2004 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; + +public class Couple { + + private final int hash; + + public final State from; + + public final State to; + + public Couple(State from, State to) { + this.from = from; + this.to = to; + this.hash = (from.hashCode() << 16) ^ to.hashCode(); + } + + public State getFrom() { + return from; + } + + public State getTo() { + return to; + } + + public boolean equals(Object o) { + if ((o != null) && (o instanceof Couple)) { + Couple c = (Couple) o; + return from.equals(c.from) && to.equals(c.to); + } + return false; + } + + public int hashCode() { + return hash; + } +} + +/* + * $Log: Couple.java,v $ + * Revision 1.2 2004/09/21 11:50:28 bailly + * added interface BinaryTest + * added class for testing automaton equivalence (isomorphism of normalized automata) + * added computation of RE from Automaton + * Revision 1.1 2004/07/19 06:39:02 bailly made Automaton, + * State and Transition subclasses of Graph API modified StateFactory API + * + */ \ No newline at end of file diff --git a/extra/jautomata-core/rationals/DefaultStateFactory.java b/extra/jautomata-core/rationals/DefaultStateFactory.java new file mode 100755 index 0000000000..4247b24cda --- /dev/null +++ b/extra/jautomata-core/rationals/DefaultStateFactory.java @@ -0,0 +1,181 @@ +/* + * (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; + +import java.util.HashSet; +import java.util.Set; + +/** + * This class is used by Automaton objects to create new states on A user can + * implement its own version of StateFactory by providing an implementation for + * createState + * + * @author Arnaud.Bailly - bailly@lifl.fr + */ +public class DefaultStateFactory<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements StateFactory<L, Tr, T>, Cloneable { + + private int id = 0; + + private Automaton<L, Tr, T> automaton; + + public class DefaultState implements State { + + public final int i; + + boolean initial; + + boolean terminal; + + Automaton<L, Tr, T> a; + + private Object label = null; + + DefaultState(int i, boolean initial, boolean terminal) { + this.i = i; + this.a = automaton; + this.initial = initial; + this.terminal = terminal; + } + + /* + * (non-Javadoc) + * + * @see rationals.State#setInitial(boolean) + */ + public State setInitial(boolean initial) { + this.initial = initial; + if (initial) + a.initials().add(this); + else + a.initials().remove(this); + return this; + } + + /* + * (non-Javadoc) + * + * @see rationals.State#setTerminal(boolean) + */ + public State setTerminal(boolean terminal) { + this.terminal = terminal; + if (terminal) + a.terminals().add(this); + else + a.terminals().remove(this); + return this; + } + + /* + * (non-Javadoc) + * + * @see rationals.State#isInitial() + */ + public boolean isInitial() { + return this.initial; + } + + /* + * (non-Javadoc) + * + * @see rationals.State#isTerminal() + */ + public boolean isTerminal() { + return this.terminal; + } + + @Override + public String toString() { + return label == null ? Integer.toString(i) : label.toString(); + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof DefaultStateFactory.DefaultState)) return false; + @SuppressWarnings("unchecked") + DefaultState ds = (DefaultState) o; + return (ds.i == i) && (a == ds.a); + } + + @Override + public int hashCode() { + return i; + } + } + + DefaultStateFactory(Automaton<L, Tr, T> a) { + this.automaton = a; + } + + /** + * Creates a new state which is initial and terminal or not, depending on the + * value of parameters. + * + * @param initial if true, this state will be initial; otherwise this state will be non initial. + * @param terminal if true, this state will be terminal; otherwise this state will be non terminal. + */ + public State create(boolean initial, boolean terminal) { + return new DefaultState(id++, initial, terminal); + } + + /* + * (non-Javadoc) + * + * @see rationals.StateFactory#stateSet() + */ + public Set<State> stateSet() { + return new HashSet<State>(); + } + + /* + * (non-Javadoc) + * + * @see rationals.StateFactory#stateSet(java.util.Set) + */ + @Override + public Set<State> stateSet(Set<State> s) { + Set<State> result = new HashSet<>(); + result.addAll(s); + return s; + } + + public DefaultStateFactory<L, Tr, T> clone() { + try { + @SuppressWarnings("unchecked") + DefaultStateFactory<L, Tr, T> cl = (DefaultStateFactory<L, Tr, T>) super.clone(); + cl.id = 0; + return cl; + } catch (CloneNotSupportedException ex) { + throw new Error(ex); + } + } + + /* + * (non-Javadoc) + * + * @see rationals.StateFactory#setAutomaton(rationals.Automaton) + */ + public void setAutomaton(Automaton<L, Tr, T> automaton) { + this.automaton = automaton; + } + + @Override + public State create(boolean initial, boolean terminal, Object label) { + DefaultState defaultState = new DefaultState(id++, initial, terminal); + defaultState.label = label; + return defaultState; + } +} diff --git a/extra/jautomata-core/rationals/DefaultSynchronization.java b/extra/jautomata-core/rationals/DefaultSynchronization.java new file mode 100755 index 0000000000..376adb9f74 --- /dev/null +++ b/extra/jautomata-core/rationals/DefaultSynchronization.java @@ -0,0 +1,77 @@ +/* + * (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; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * Default synchronization scheme for standard automaton. This class + * synchronizes the labels of two transitions if they are equal as returned by + * {@see java.lang.Object#equals(java.lang.Object)}. + * + * @author nono + * @version $Id: DefaultSynchronization.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class DefaultSynchronization implements Synchronization { + + /* + * (non-Javadoc) + * + * @see rationals.Synchronization#synchronize(rationals.Transition, + * rationals.Transition) + */ + public Object synchronize(Object t1, Object t2) { + return t1 == null ? null : (t1.equals(t2) ? t1 : null); + } + + /* (non-Javadoc) + * @see rationals.Synchronization#synchronizing(java.util.Set, java.util.Set) + */ + public Set synchronizable(Set a, Set b) { + Set r = new HashSet(a); + r.retainAll(b); + return r; + } + + /* + * TO VERIFY (non-Javadoc) + * @see rationals.Synchronization#synchronizing(java.util.Collection) + */ + public Set synchronizing(Collection alphabets) { + Set niou = new HashSet(); + /* + * synchronization set is the union of pairwise + * intersection of the sets in alphl + */ + for(Iterator i = alphabets.iterator();i.hasNext();) { + Set s = (Set)i.next(); + for(Iterator j = alphabets.iterator();j.hasNext();) { + Set b = (Set)j.next(); + niou.addAll(synchronizable(s,b)); + } + } + return niou; + } + + public boolean synchronizeWith(Object object, Set alph) { + return alph.contains(object); + } + +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/MixPlay.java b/extra/jautomata-core/rationals/MixPlay.java new file mode 100755 index 0000000000..bd6eb1f271 --- /dev/null +++ b/extra/jautomata-core/rationals/MixPlay.java @@ -0,0 +1,347 @@ +/* + * (C) Copyright 2004 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; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Random; +import java.util.Set; + +/** + * This class implements an algorithm for finding a synchronizing + * word given a target letter. + * + * @author bailly + * @version $Id: MixPlay.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class MixPlay implements AutomatonRunner { + + class MixException extends Exception { + + List word; + + List states; + + MixException(List w, List st) { + this.word = w; + this.states = st; + } + } + + private Set explored; + + private final static Random random = new Random(); + + private final static Transition[] trmodel = new Transition[0]; + + private int upperBound = 1; + + private Object target; + + private List autos; + + private Synchronization sync; + + private Set syncAlphabet; + + private Set listeners = new HashSet(); + + /* + * current set of states + */ + private StatesTuple current; + + /** + * Construct a mix with the given list of automata. + * + * @param autos a List of automaton objects + */ + public MixPlay(List autos) { + this.autos = autos; + this.sync = new DefaultSynchronization(); + } + + /** + * Construct an empty mix. + * + */ + public MixPlay() { + this.autos = new ArrayList(); + this.sync = new DefaultSynchronization(); + } + + /** + * Adds a new automaton to this mix. + * + * @param a + */ + public void addAutomaton(Automaton a) { + this.autos.add(a); + } + + /** + * Reset the state of this mix. + * The current state is set to the start states of the + * mixed automata. + */ + public void reset() { + this.explored = new HashSet(); + this.target = null; + Set[] states = new Set[autos.size()]; + int i = 0; + Set synalph = new HashSet(); + List alphl = new ArrayList(); + for (Iterator it = autos.iterator(); it.hasNext();) { + Automaton a = (Automaton) it.next(); + upperBound *= a.states().size(); + states[i++] = a.initials(); + Set alph = a.alphabet(); + alphl.add(alph); + } + /* make synalph */ + this.syncAlphabet = sync.synchronizing(alphl); + this.current = new StatesTuple(states); + } + + /** + * Try to play for given target with given start states in each automaton. + * + * @param target + * the targeted letter + * @return a list of letters ending in <code>target</code> + */ + public List play(Object target) throws Exception { + this.target = target; + List word = new ArrayList(); + List tuples = new ArrayList(); + /* initial states */ + try { + doPlay(word, tuples, current); + } catch (MixException mex) { + /* notify listeners of synchronization */ + notify(mex.word, mex.states); + return mex.word; + } + return new ArrayList(); + } + + /** + * Notify each listener of the fired transitions when a word is found. + * + * @param word + * @param states + */ + private void notify(List word, List states) { + if (listeners.isEmpty() || word.isEmpty() || states.isEmpty()) + return; + Iterator wit = word.iterator(); + Iterator sit = states.iterator(); + for (; sit.hasNext();) { + StatesTuple tup = (StatesTuple) sit.next(); + Object lt = wit.next(); + int ln = tup.sets.length; + /* fire event */ + for (int i = 0; i < ln; i++) { + Automaton a = (Automaton) autos.get(i); + Set trans = new HashSet(); + for (Iterator stit = tup.sets[i].iterator(); stit.hasNext();) + trans.addAll(a.delta((State) stit.next(), lt)); + for (Iterator lit = listeners.iterator(); lit.hasNext();) + ((AutomatonRunListener) lit.next()).fire(a, trans, lt); + } + } + } + + /** + * Recursive play function + * + * @param word current accumulated word + * @param tuples current accumulated list of states tuples + * @param states current states tuple + */ + private void doPlay(List word, List tuples, StatesTuple states) + throws MixException { + /* set current states*/ + System.err.println("in states "+ states); + current = states; + if (!word.isEmpty() && word.get(word.size() - 1).equals(target)) + throw new MixException(word, tuples); + /* stop exploring on loop */ + if (explored.contains(states)) + return; + else + explored.add(states); + /* contains already tested transitions */ + Set s = new HashSet(); + /* list of transitions */ + for (int i = 0; i < states.sets.length; i++) { + Transition[] trs = (Transition[]) ((Automaton) autos.get(i)).delta( + states.sets[i]).toArray(trmodel); + int ln = trs.length; + int k = random.nextInt(ln); + for (int j = 0; j < ln; j++) { + Transition tr = trs[(k + j) % ln]; + System.err.println("trying random transition "+ tr); + if (s.contains(tr)) + continue; + s.add(tr); + /* check synchronization */ + if (!checkSynchronizableWith(tr.label(), states)) + continue; + /* check early rejection */ + if (!checkAccessibleWith(tr.label(), states)) + continue; + /* ok - try this transition */ + StatesTuple tup = advanceWith(tr.label(), states); + /* recurse - an exception is thrown if a match is found */ + word.add(tr.label()); + tuples.add(states); + System.err.println("Trying " + word); + doPlay(word, tuples, tup); + System.err.println("No way for " + word); + word.remove(word.size() - 1); + tuples.remove(tuples.size() - 1); + } + } + } + + /** + * Checks synchronization of automaton on this letter + * + * @param object + * @param states + * @return + */ + private boolean checkSynchronizableWith(Object object, StatesTuple states) { + if (!syncAlphabet.contains(object)) + return true; + for (int i = 0; i < states.sets.length; i++) { + Automaton auto = (Automaton) autos.get(i); + if (!sync.synchronizeWith(object, auto.alphabet())) + continue; + /* + * compute synchronizing transitions + */ + Set s = auto.delta(states.sets[i]); + Set adv = auto.getStateFactory().stateSet(); + for (Iterator j = s.iterator(); j.hasNext();) { + Transition tr = (Transition) j.next(); + Object lbl = tr.label(); + if (sync.synchronize(lbl, object) != null) + adv.add(tr.end()); + } + if (adv.isEmpty()) + return false; + } + return true; + } + + /** + * Checks that, if object is in the alphabet of an automaton, firing of + * transation does not preclude access of target + * + * @param object + * @param states + * @return + */ + private boolean checkAccessibleWith(Object object, StatesTuple states) { + return true; + } + + /** + * @param object + * @param states + * @return + */ + private StatesTuple advanceWith(Object object, StatesTuple states) { + Set[] nstates = new Set[autos.size()]; + for (int i = 0; i < states.sets.length; i++) { + Automaton auto = (Automaton) autos.get(i); + /* + * compute synchronizing transitions + */ + Set s = auto.delta(states.sets[i]); + Set adv = auto.getStateFactory().stateSet(); + for (Iterator j = s.iterator(); j.hasNext();) { + Transition tr = (Transition) j.next(); + Object lbl = tr.label(); + if (sync.synchronize(lbl, object) != null) + adv.add(tr.end()); + } + nstates[i] = adv.isEmpty() ? states.sets[i] : adv; + } + return new StatesTuple(nstates); + } + + /* + * (non-Javadoc) + * @see rationals.AutomatonRunner#addRunListener(rationals.AutomatonRunListener) + */ + public void addRunListener(AutomatonRunListener l) { + listeners.add(l); + } + + /* + * (non-Javadoc) + * @see rationals.AutomatonRunner#removeRunListener(rationals.AutomatonRunListener) + */ + public void removeRunListener(AutomatonRunListener l) { + listeners.remove(l); + } + + /** + * + * @return + */ + public Synchronization getSynchronization() { + return sync; + } + + /** + * + * @param sync + */ + public void setSynchronization(Synchronization sync) { + this.sync = sync; + } +} +/* + * Created on Apr 9, 2004 + * + * $Log: MixPlay.java,v $ Revision 1.7 2004/08/31 14:16:22 bailly *** empty log + * message *** + * + * Revision 1.6 2004/04/15 11:51:00 bailly added randomization of MixPlay TODO: + * check accessibility of synchronization letter + * + * Revision 1.5 2004/04/14 10:02:14 bailly *** empty log message *** + * + * Revision 1.4 2004/04/14 07:33:43 bailly correct version of synchronization on + * the fly + * + * Revision 1.3 2004/04/13 07:08:38 bailly *** empty log message *** + * + * Revision 1.2 2004/04/12 16:37:59 bailly worked on synchronization algorithm : + * begins to work but there are still problems with proper implementation of + * backtracking + * + * Revision 1.1 2004/04/09 15:51:50 bailly Added algorithm for computing a mixed + * word from several automata (to be verified) + * + */ diff --git a/extra/jautomata-core/rationals/NoSuchStateException.java b/extra/jautomata-core/rationals/NoSuchStateException.java new file mode 100755 index 0000000000..6a7acd36f2 --- /dev/null +++ b/extra/jautomata-core/rationals/NoSuchStateException.java @@ -0,0 +1,56 @@ +/* + * (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; + +/** Instances of this class are thrown by the method + * <tt>addTransition</tt> in class <tt>Automaton</tt> + * when an attempt is made to use a state which does + * not belong to the correct automaton. + * @author yroos@lifl.fr + * @version 1.0 + * @see Automaton + */ +public class NoSuchStateException extends Exception { + + private static final long serialVersionUID = 1L; + + public NoSuchStateException() { + super(); + } + + /** + * @param message + */ + public NoSuchStateException(String message) { + super(message); + } + + /** + * @param message + * @param cause + */ + public NoSuchStateException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param cause + */ + public NoSuchStateException(Throwable cause) { + super(cause); + } +} diff --git a/extra/jautomata-core/rationals/RandomAutomaton.java b/extra/jautomata-core/rationals/RandomAutomaton.java new file mode 100755 index 0000000000..02c42f279e --- /dev/null +++ b/extra/jautomata-core/rationals/RandomAutomaton.java @@ -0,0 +1,168 @@ +/* + * (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; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Random; + +/** + * Instances of this class are random automata. A RandomAutomaton is generated + * according to following parameters : + * <ul> + * <li>The number of states in the automaton</li> + * <li>The number of terminal states</li> + * <li>The alphabet : if the alphabet contains a <code>null</code> element, + * it will be used and the resulting automaton will contain epsilon-transitions + * </li> + * <li>The mean transition density which is the number of transitions in the + * automaton divided by the square of the number of states times the size of the + * alphabet</li> + * <li>The standard deviation of the transition density</li> + * <li>A flag indicating if the automaton should be deterministic or not. Note + * that if the alphabet contains epsilon, then the resulting automaton will most + * probably be non-deterministic even if this flag is set.</li> + * </ul> + * The result is an - non reduced - automaton with a single start state and + * random transitions following a normal distribution according to preceding + * parameters over the alphabet. + * + * @version $Id: RandomAutomaton.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class RandomAutomaton<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> extends Automaton<L, Tr, T> { + + private static final Random rand = new Random(); + + private int nstate; + + private int fstate; + + private L[] alph; + + private double density; + + private double deviation; + + /** + * Construct a RandomAutomaton according to the given parameters. + * + * @param nstate + * number of total states + * @param fstate + * number of final states + * @param alphabet + * alphabet + * @param density + * mean transition density + * @param deviation + * transition density standard deviation + * @param det + * is the result deterministic + */ + public RandomAutomaton(int nstate, int fstate, L[] alph, double density, double deviation, boolean det) { + this.nstate = nstate; + this.fstate = fstate; + this.alph = alph; + this.density = density; + this.deviation = deviation; + if (det) + makeDFA(); + else + makeNFA(); + } + + /** + * + */ + private void makeNFA() { + /* create initial state and other states */ + addState(true, false); + for (int i = 0; i < fstate; i++) + addState(false, true); + for (int i = fstate; i < nstate; i++) + addState(false, false); + State[] sts = states().toArray(new State[nstate + 1]); + /* create transitions */ + Iterator<State> it = states().iterator(); + while (it.hasNext()) { + State from = it.next(); + int c = alph.length * sts.length * sts.length; + /* number of transitions from this state to other state */ + int nt = (int) (c * (deviation * rand.nextGaussian() + density)); + for (int i = 0; i < nt; i++) { + State to = sts[rand.nextInt(sts.length)]; + L lbl = alph[rand.nextInt(alph.length)]; + try { + /* create transition */ + addTransition(new Transition<L>(from, lbl, to)); + } catch (NoSuchStateException e1) { + } + } + } + } + + /** + * + */ + private void makeDFA() { + /* create initial state and other states */ + State init = addState(true, false); + List<State> todo = new ArrayList<>(); + List<State> done = new ArrayList<>(); + int fs = fstate; + int ns = nstate; + todo.add(init); + while (ns > 0) { + /* pop state */ + State from = (State) todo.remove(0); + done.add(from); + /* list for alph */ + List<L> l = new ArrayList<>(Arrays.asList(alph)); + /* number of transitions from this state to other state */ + int nt = (int) (deviation * rand.nextGaussian() + density); + for (int i = 0; i < nt && !l.isEmpty(); i++) { + /* + * select a state : this an already visited state with + * probability (done.size() / nstate) + */ + State to = null; + double r = rand.nextDouble() * (nstate - 1); + if ((int) r < done.size()) { + to = done.get((int) r); + } else { + /* + * state is final with probability fs / ns + */ + r = rand.nextDouble() * ns; + to = addState(false, r < fs); + todo.add(to); + ns--; + if (r < fs) + fs--; + } + L lbl = l.remove(rand.nextInt(l.size())); + try { + /* create transition */ + addTransition(new Transition<>(from, lbl, to)); + } catch (NoSuchStateException e1) { + } + } + } + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/Rational.java b/extra/jautomata-core/rationals/Rational.java new file mode 100755 index 0000000000..8e0cbcd1e7 --- /dev/null +++ b/extra/jautomata-core/rationals/Rational.java @@ -0,0 +1,214 @@ +/* + * (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; + +import java.util.Set; + +/** + * @version $Id: Rational.java 10 2007-05-30 17:25:00Z oqube $ + */ +public interface Rational<L> { + /** + * Returns a new instance of state which will be initial and terminal or not + * depending of parameters. + * + * @param initial + * if true, the new state will be initial; otherwise this state will + * be non initial. + * @param terminal + * if true, the new state will be terminal; otherwise this state will + * be non terminal. + * @return a new state, associated with this automaton. This new state should + * be used only with this automaton in order to create a new + * transition for this automaton. + * @see Transition + */ + State addState(boolean initial, boolean terminal); + + /** + * Returns the alphabet <em>X</em> associated with this automaton. + * + * @return the alphabet <em>X</em> associated with this automaton. + */ + Set<L> alphabet(); + + /** + * Returns the set of states <em>Q</em> associated with this automaton. + * + * @return the set of states <em>Q</em> associated with this automaton. + * Objects which are contained in this set are instances of class + * <tt>State</tt>. + * @see State + */ + Set<State> states(); + + /** + * Returns the set of initial states <em>I</em> associated with this + * automaton. + * + * @return the set of initial states <em>I</em> associated with this + * automaton. Objects which are contained in this set are instances of + * class <tt>State</tt>. + * @see State + */ + Set<State> initials(); + + /** + * Returns the set of terminal states <em>T</em> associated with this + * automaton. + * + * @return set of terminal states <em>T</em> associated with this automaton. + * Objects which are contained in this set are instances of class + * <tt>State</tt>. + * @see State + */ + Set<State> terminals(); + + /** + * Returns the set of all accessible states in this automaton. + * + * @return the set of all accessible states in this automaton. A state + * <em>s</em> is accessible if there exists a path from an initial + * state to <em>s</em>. Objects which are contained in this set are + * instances of class <tt>State</tt>. + * @see State + */ + Set<State> accessibleStates(); + + /** + * Returns the set of states that can be accessed in this automaton starting + * from given set of states + * + * @param states + * a non null set of starting states + * @return a - possibly empty - set of accessible states + */ + Set<State> accessibleStates(Set<State> states); + + /** + * Returns the set of co-accesible states for a given set of states, that is + * the set of states from this automaton from which there exists a path to a + * state in <code>states</code>. + * + * @param states + * a non null set of ending states + * @return a - possibly empty - set of coaccessible states + */ + Set<State> coAccessibleStates(Set<State> states); + + /** + * Returns the set of all co-accessible states in this automaton. + * + * @return the set of all co-accessible states in this automaton. A state + * <em>s</em> is co-accessible if there exists a path from this + * state <em>s</em> to a terminal state. Objects which are contained + * in this set are instances of class <tt>State</tt>. + * @see State + */ + Set<State> coAccessibleStates(); + + /** + * Returns the set of all states which are co-accessible and accessible in + * this automaton. + * + * @return the set of all states which are co-accessible and accessible in + * this automaton. A state <em>s</em> is accessible if there exists + * a path from an initial state to <em>s</em>. A state <em>s</em> + * is co-accessible if there exists a path from this state <em>s</em> + * to a terminal state. Objects which are contained in this set are + * instances of class <tt>State</tt>. + * @see State + */ + Set<State> accessibleAndCoAccessibleStates(); + + /** + * Returns the set of all transitions of this automaton + * + * @return the set of all transitions of this automaton Objects which are + * contained in this set are instances of class <tt>Transition</tt>. + * @see Transition + */ + Set<Transition<L>> delta(); + + /** + * Returns the set of all transitions of this automaton starting from a given + * state and labelled b a given label. + * + * @param state + * a state of this automaton. + * @param label + * a label used in this automaton. + * @return the set of all transitions of this automaton starting from state + * <tt>state</tt> and labelled by <tt>label</tt>. Objects which + * are contained in this set are instances of class + * <tt>Transition</tt>. + * @see Transition + */ + Set<Transition<L>> delta(State state, L label); + + /** + * Return all transitions from a State + * + * @param state + * start state + * @return a new Set of transitions (maybe empty) + */ + Set<Transition<L>> delta(State state); + + Set<Transition<L>> deltaFrom(State from, State to); + + /** + * Returns the set of all transitions of the reverse of this automaton + * + * @return the set of all transitions of the reverse of this automaton. A + * reverse of an automaton <em>A = (X , Q , I , T , D)</em> is the + * automaton <em>A' = (X , Q , T , I , D')</em> where <em>D'</em> + * is the set <em>{ (q , l , q') | (q' , l , q) in D}</em>. Objects + * which are contained in this set are instances of class + * <tt>Transition</tt>. + * @see Transition + */ + Set<Transition<L>> deltaMinusOne(State state, L label); + + /** + * Adds a new transition in this automaton if it is a new transition for this + * automaton. The parameter is considered as a new transition if there is no + * transition in this automaton which is equal to the parameter in the sense + * of method <tt>equals</tt> of class <tt>Transition</tt>. + * + * @param transition + * the transition to add. + * @throws NoSuchStateException + * if <tt>transition</tt> is <tt>null</<tt> + * or if <tt>transition</tt> = <em>(q , l , q')</em> and <em>q</em> or + * <em>q'</em> does not belong to <em>Q</em> the set of the states + * of this automaton. + */ + void addTransition(Transition<L> transition) throws NoSuchStateException; + + /** + * @param st + * @return + */ + Set<Transition<L>> deltaMinusOne(State st); + + /** + * @param st + * @return + */ + Set<State> accessibleStates(State st); +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/State.java b/extra/jautomata-core/rationals/State.java new file mode 100755 index 0000000000..f83a98192f --- /dev/null +++ b/extra/jautomata-core/rationals/State.java @@ -0,0 +1,56 @@ +/* + * (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; + + +/** + * Interface for State objects + * + * This class defines the notion of state of an automaton. + * @author yroos@lifl.fr + * @version 1.0 + * @see Automaton + * @see StateFactory +*/ +public interface State { + + + /** Determines if this state is initial. + * @return true iff this state is initial. + */ + public boolean isInitial(); + + /** Determines if this state is terminal. + * @return true iff this state is terminal. + */ + public boolean isTerminal(); + + /** returns a textual representation of this state. + * @return a textual representation of this state. + */ + public String toString(); + + /** + * Sets the initial status of this state. + * + * @param initial + * @return + */ + public State setInitial(boolean initial); + + public State setTerminal(boolean terminal); +} diff --git a/extra/jautomata-core/rationals/StateFactory.java b/extra/jautomata-core/rationals/StateFactory.java new file mode 100755 index 0000000000..667b59c76d --- /dev/null +++ b/extra/jautomata-core/rationals/StateFactory.java @@ -0,0 +1,86 @@ +/* + * (C) Copyright 2004 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; + +import java.util.Set; + +/** + * This class is used by Automaton objects to create new states on A user can + * implement its own version of StateFactory by providing an implementation for + * createState + * + * @author Arnaud.Bailly - bailly@lifl.fr + * @version $Id: StateFactory.java 10 2007-05-30 17:25:00Z oqube $ + */ +public interface StateFactory<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + + /** + * @param initial + * @param terminal + * @return + */ + State create(boolean initial, boolean terminal); + + /** + * Return a new empty set that can contains State instances created by this + * factory. This method is provided for optimisation purposes so that more + * efficient implementations than plain sets can be used for handling sets of + * states. + * + * @return an - opaque - implementation of Set. + */ + Set<State> stateSet(); + + /** + * Returns a new Set which is a copy of <code>s</code>. The given set s + * must have been created through <strong>this</strong> StateFactory object + * to ensure consistent behavior. + * + * @param s a Set + * @return a shallow copy of <code>s</code> + */ + Set<State> stateSet(Set<State> s); + + /** + * Returns a new StateFactory object which is the same as this StateFactory. + * + * @return an initialized StateFactory. + */ + Object clone(); + + /** + * @param automaton + */ + void setAutomaton(Automaton<L, Tr, T> automaton); + + State create(boolean initial, boolean terminal, Object label); +} +// /* +// * $Log: StateFactory.java,v $ +// * Revision 1.3 2004/07/20 13:21:25 bonte +// * *** empty log message *** +// * +// */======= +// /* +// * $Log: StateFactory.java,v $ +// * Revision 1.3 2004/07/20 13:21:25 bonte +// * *** empty log message *** +// * +// * Revision 1.2 2004/07/19 06:39:02 bailly +// * made Automaton, State and Transition subclasses of Graph API +// * modified StateFactory API +// * diff --git a/extra/jautomata-core/rationals/StateLabels.java b/extra/jautomata-core/rationals/StateLabels.java new file mode 100755 index 0000000000..b60abcc1c8 --- /dev/null +++ b/extra/jautomata-core/rationals/StateLabels.java @@ -0,0 +1,77 @@ +/* + * (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; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Maintain mapping between labels and abstract {@link State} objects. + * <p> + * This is a disguised bi-directional {@link Map} between {@link State} instances + * and arbitrary {@link Object} instances as labels. + * </p> + */ +class StateLabels { + + private Map<State, Object> stateToLabels = new HashMap<State, Object>(); + private Map<Object, State> labelToStates = new HashMap<Object, State>(); + + + public State state(Object label) { + return labelToStates.get(label); + } + + public Set<Object> labels(Set<State> states) { + Set<Object> ret = new HashSet<Object>(); + for (State state : states) { + Object label = stateToLabels.get(state); + if(label != null) + ret.add(label); + else + ret.add(state); + } + return ret; + } + + /** + * Register a unique binding betwee a {@link State} object and an arbitrary label. + * <p> + * Both must be unique within their respective collection. + * </p> + * + * @param state a state. Must not exist in this set. + * @param label a lable. Must not exist in this set. + * @return this object for chaining purpose. + */ + public StateLabels bind(State state, Object label) { + if(state == null) { + throw new NullPointerException("cannot bind a null state"); + } + + if(label == null) { + label = state; + } + + stateToLabels.put(state,label); + labelToStates.put(label,state); + + return this; + } +} diff --git a/extra/jautomata-core/rationals/StateMachine.java b/extra/jautomata-core/rationals/StateMachine.java new file mode 100755 index 0000000000..e44433c788 --- /dev/null +++ b/extra/jautomata-core/rationals/StateMachine.java @@ -0,0 +1,155 @@ +/* + * (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; + +import java.util.List; +import java.util.Set; + +/** + * An interface for abstract state machines. + * <p> + * A state machine - or labelled transition system - is defined by + * a tuple <code>(Q,S,q0,d)</code> where: + * <ul> + * <li><code>Q</code> is a set of states ;</li> + * <li><code>S</code> is a finite set of labels ;</li> + * <li><code>q0</code> is the initial state of the machine ;</li> + * <li><code>d</code> is a transition relation in <code>Q x S x Q</code>. + * </ul> + * This definition is slightly modified for this interface as the initials + * is defined as a {@see java.util.Set} instead of a single state. <code>null</code> + * may be used to denote <em>silent transitions</em>, that is unobservable + * internal behaviour of the machine, which can lead to non determinism. + * <p> + * The {@see rationals.Automaton} is the main implementation for this interface. + * + * @version $Id: StateMachine.java 10 2007-05-30 17:25:00Z oqube $ + */ +public interface StateMachine<L> { + + /** + * Returns the alphabet - <code>S</code> - of this state machine. + * + * @return a Set of Object. + */ + Set<L> alphabet(); + + /** + * @return Returns the id. + */ + Object getId(); + + /** + * @param id + * The id to set. + */ + void setId(Object id); + + /** + * Retrieves the state factory associated to this SM. + * + * @return a StateFactory instance + */ + StateFactory getStateFactory(); + + /** + * Defines the state factory to use for this SM. + * + * @param factory a StateFactory instance. + */ + void setStateFactory(StateFactory factory); + + /** + * Returns the set of all transitions of this machine starting from a + * given state and labelled + * with a given label. + * + * @param state + * a state of this SM. + * @param label + * a label used in this SM. + * @return the set of all transitions of this automaton starting from state + * <tt>state</tt> and labelled by <tt>label</tt>. Objects which + * are contained in this set are instances of class + * <tt>Transition</tt>. + * @see Transition + */ + Set<Transition<L>> delta(State state, L label); + + /** + * Return all transitions from a State. + * + * @param state + * start state + * @return a new Set of transitions (maybe empty) + */ + Set<Transition<L>> delta(State state); + + /** + * Returns all transitions from a given set of states. + * + * @param s a Set of State objects + * @return a Set of Transition objects + */ + Set<Transition<L>> delta(Set<State> s); + + /** + * Return the set of states this SM will be in + * after reading the word from start states <code>s</code>. + * + * @param s the set of starting states + * @param word the word to read. + * @return the set of reached states. Maybe empty or <code>null</code>. + */ + Set<State> steps(Set<State> s, List<L> word); + + /** + * Return the set of states this SM will be in + * after reading the word from single start state s. + * + * @param st the starting state + * @param word the word to read. + * @return the set of reached states. Maybe empty or <code>null</code> + */ + Set<State> steps(State st, List<L> word); + + /** + * Return the set of states accessible in one transition from given set of + * states s and letter o. + * + * @param s the starting states + * @param o the letter + * @return a set of reachable states. Maybe empty or <code>null</code>. + */ + Set<State> step(Set<State> s, L o); + + /** + * Returns the set of initial states for this machine. + * + * @return a Set of State objects. + */ + Set<State> initials(); + + /** + * Returns the set of states that can access the given states' set <code>st</code>. + * This is the inverse relation of <code>d</code> + * + * @param st end states + * @return a set of states that can reach <code>st</code>. May be empty or null. + */ + Set<Transition<L>> deltaMinusOne(State st); +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/StatesTuple.java b/extra/jautomata-core/rationals/StatesTuple.java new file mode 100755 index 0000000000..6c18ad4119 --- /dev/null +++ b/extra/jautomata-core/rationals/StatesTuple.java @@ -0,0 +1,78 @@ +/* + * (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; + +import java.util.Set; + +public class StatesTuple { + public final Set<State>[] sets; + + final int hash; + + @SuppressWarnings("unchecked") + public StatesTuple(Set<State>[] sets) { + this.sets = new Set[sets.length]; + System.arraycopy(sets,0,this.sets,0,sets.length); + int h = 0; + for (int i = 0; i < sets.length; i++) + h ^= sets[i].hashCode() << i; + this.hash = h; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof StatesTuple)) return false; + StatesTuple sc = (StatesTuple) obj; + for (int i = 0; i < sc.sets.length; i++) + if (!sets[i].equals(sc.sets[i])) + return false; + return true; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return hash; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("( "); + for(int i = 0; i < sets.length; i++){ + sb.append(sets[i]); + if(i != sets.length - 1) + sb.append(","); + } + sb.append(")"); + return sb.toString(); + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/Synchronization.java b/extra/jautomata-core/rationals/Synchronization.java new file mode 100755 index 0000000000..4b995b9eea --- /dev/null +++ b/extra/jautomata-core/rationals/Synchronization.java @@ -0,0 +1,83 @@ +/* + * (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; + +import java.util.Collection; +import java.util.Set; + +/** + * An interface for defining various synchronization schemes. + * This interface is used in {@see rationals.transformations.Synchronize} for + * and allows various strategies of synchronization between transitions + * of two automata. + * + * @author nono + * @version $Id: Synchronization.java 2 2006-08-24 14:41:48Z oqube $ + */ +public interface Synchronization<L> { + + /** + * Synchronize two transitions. + * This method should return a letter denoting the result of synchronizing + * the two transitions' labels. If the result is <code>null</code>, then no synchronization + * occurs. + * + * @param t1 first label to synchronize + * @param t2 second label to synchronize + * @return a non null Object if the two transitions can be synchronized. + */ + L synchronize(L t1, L t2); + + /** + * Compute the synchronizing letters from two alphabets. + * This method returns the set of letters from a and b that can be synchronized. + * In the default case, this method simply computes the intersection of the two + * sets. More precisely, the resultant set will contain the result of all + * possible synchronizations between both input sets. + * + * @param a an alphabet + * @param b another alphabet + * @return a new Set of letters (may be empty) from a and b that can be synchronized. + */ + Set<L> synchronizable(Set<L> a, Set<L> b); + + /** + * Construct the synchronization alphabet from a collection of + * alphabets. + * + * <p>This is an extension to more than 2 alphabets of {@link #synchronizable(Set, Set)}.</p> + * + * @param alphabets a collection of alphabets (sets) on which to compute synchronizing letters. + * @return a Set implementation containing all letters of all alphabets + * in <code>alphabets</code> that could be synchronized. + */ + Set<L> synchronizing(Collection<Set<L>> alphabets); + + /** + * Checks whether or not the given letter is synchronizing in the + * given automaton's alphabet. + * This method checks in a synchronization dependant way that the + * given letter pertains to the synchronization set. + * + * @param object the letter to check + * @param alph the alphabet + * @return true if object is synchronizing with some letter in <code>alph</code>, + * false otherwise. + */ + boolean synchronizeWith(L object, Set<L> alph); + +} diff --git a/extra/jautomata-core/rationals/Transition.java b/extra/jautomata-core/rationals/Transition.java new file mode 100755 index 0000000000..bafe9aebe2 --- /dev/null +++ b/extra/jautomata-core/rationals/Transition.java @@ -0,0 +1,170 @@ +/* + * (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; + +/** + * Defines a Transition (an edge from a state to a state) in an Automaton + * + * This class defines the notion of transition of an automaton. a transition is + * a triple <em>(q , l , q')</em> where <em>q, q'</em> are states and + * <em>l</em> a label. States <em>q</em> and <em>q'</em> must belong to + * the same automaton <em>A</em> and the transition may only be used with this + * automaton <em>A</em>. + * + * @author yroos@lifl.fr + * @version 1.0 + * @see Automaton + */ +public class Transition<L> { + + private int hashCodeCache = Integer.MIN_VALUE; + + private State start; + + private L label; + + private State end; + + /** + * Creates a new transition <em>(q , l , q')</em>. + * + * @param start + * the state <em>q</em> for this transition <em>(q , l , q')</em>. + * @param label + * the label <em>l</em> + * @param end + * the state <em>q'</em> for this transition <em>(q , l , q')</em>. + */ + public Transition(State start, L label, State end) { + this.start = start; + this.label = label; + this.end = end; + } + + /** + * Creates a new (invalid) transition. This transition is meant to be updated + * internally by an automaton. + * + * @param start + * the starting state. + */ + Transition(State start) { + this.start = start; + } + + /** + * Returns the starting state of this transition. + * + * @return the starting state of this transition, that is the state <em>q</em> + * for this transition <em>(q , l , q')</em>. + */ + public State start() { + return start; + } + + /** + * Returns the label this transition. + * + * @return the label state of this transition, that is the object <em>l</em> + * for this transition <em>(q , l , q')</em>. + */ + public L label() { + return label; + } + + /** + * Returns the ending state of this transition. + * + * @return the ending state of this transition, that is the state <em>q'</em> + * for this transition <em>(q , l , q')</em>. + */ + public State end() { + return end; + } + + /** + * returns a textual representation of this transition. + * + * @return a textual representation of this transition based + */ + @Override + public String toString() { + if (label == null) { + return "(" + start + " , epsilon , " + end + ")"; + } else { + return "(" + start + " , " + label + " , " + end + ")"; + } + } + + /** + * Determines if this transition is equal to the parameter. + * + * @param o + * any object. + * @return true iff this transition is equal to the parameter. That is if + * <tt>o</tt> is a transition which is composed same states and + * label (in the sense of method <tt>equals</tt>). + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof Transition)) return false; + @SuppressWarnings("unchecked") + Transition<L> t = (Transition<L>) o; + if (label != t.label) { + if (label == null || t.label == null) + return false; + if (!t.label.equals(label)) + return false; + } + return (start == t.start()) && (end == t.end()); + } + + /** + * Returns a hashcode value for this transition. + * + * @return a hashcode value for this transition. + */ + @Override + public int hashCode() { + /* store computed value */ + if (hashCodeCache != Integer.MIN_VALUE) + return hashCodeCache; + int x = start == null ? 0 : start.hashCode(); + int y = end == null ? 0 : end.hashCode(); + int z = label == null ? 0 : label.hashCode(); + int hash = 17; + hash = hash * 31 + x; + hash = hash * 31 + y; + hash = hash * 31 + z; + hashCodeCache = hash; + return hash; + } + + /** + * Replaces the label for this transition + * <p> + * WARNING: this method is extremely dangerous as it does not update the + * alphabet of the automaton this transition is part of. Be sure you know what + * you are doing or else everything could break down + * + * @param msg + */ + void setLabel(L obj) { + this.label = obj; + } + +} diff --git a/extra/jautomata-core/rationals/TransitionBuilder.java b/extra/jautomata-core/rationals/TransitionBuilder.java new file mode 100755 index 0000000000..3cfe9b66f4 --- /dev/null +++ b/extra/jautomata-core/rationals/TransitionBuilder.java @@ -0,0 +1,127 @@ +/* + * (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; + +/** + * A class for step-by-step creation of transitions. A TransitionBuilder can be + * used to add expesiveness to transition creation withing automaton. + */ +public class TransitionBuilder<L> implements + Builder<L, Transition<L>, TransitionBuilder<L>> { + + private State start; + + private Automaton<L, Transition<L>, TransitionBuilder<L>> automaton; + + protected L label; + + /** + * Creates a transition builder for given automaton. + * + * @param state + * the starting state of transition. + * @param automaton + * the automaton where transition will be added. + */ + public TransitionBuilder(State state, Automaton<L, Transition<L>, TransitionBuilder<L>> automaton) { + this.start = state; + this.automaton = automaton; + } + + public TransitionBuilder() { + } + + /** + * Sets the label of the transition. + * + * @param label + * @return this transition builder. + */ + @Override + public TransitionBuilder<L> on(L label) { + this.label = label; + return this; + } + + /** + * Sets the end state and terminates transition construction. This method + * effectively adds the transition to the automaton. + * + * @param o + * the label of the end state. + */ + @Override + public TransitionBuilder<L> go(L o) { + State s = automaton.state(o); + try { + automaton.addTransition(new Transition<L>(start, label, s)); + } catch (NoSuchStateException e) { + assert false; + } + return this; + } + + /** + * Adds a new transition in the automaton that loops on current label and + * from state. + * + * @return + */ + public TransitionBuilder<L> loop() { + try { + automaton.addTransition(new Transition<L>(start, label, start)); + } catch (NoSuchStateException e) { + assert false; + } + return this; + } + + /** + * Resets this builder to another starting state. Note that the state is + * created if needed. + * + * @param label + * the state to start from. + * @return this builder. + */ + public TransitionBuilder<L> from(L label) { + this.start = automaton.state(label); + this.label = null; + return this; + } + + /* + * (non-Javadoc) + * + * @see rationals.Builder#build(java.lang.Object, rationals.Automaton) + */ + public TransitionBuilder<L> build(State state, Automaton<L, Transition<L>, TransitionBuilder<L>> auto) { + this.start = state; + this.label = null; + this.automaton = auto; + return this; + } + + public Transition<L> build(State from, L label, State to) { + return new Transition<L>(from, label, to); + } + + public void setAutomaton(Automaton<L, Transition<L>, TransitionBuilder<L>> a) { + this.automaton = a; + } + +} diff --git a/extra/jautomata-core/rationals/algebra/Matrix.java b/extra/jautomata-core/rationals/algebra/Matrix.java new file mode 100755 index 0000000000..8d7e05fd2b --- /dev/null +++ b/extra/jautomata-core/rationals/algebra/Matrix.java @@ -0,0 +1,226 @@ +/* + * (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.algebra; + +import java.util.Arrays; + +/** + * Matrix representation of an automaton. + * <p> + * The elements of a the matrix are {@see SemiRing}objects. + * + * @author nono + * @version $Id: Matrix.java 6 2006-08-30 08:56:44Z oqube $ + */ +public final class Matrix implements SemiRing { + + /* matrices for transitions, initial and terminal states */ + protected final SemiRing[][] matrix; + + private int line; + + private int col; + + + public Matrix(int ns) { + this.line = this.col = ns; + this.matrix = new SemiRing[ns][ns]; + } + + /** + * @param matrix + */ + public Matrix(Matrix matrix) { + this(matrix.line); + for (int i = 0; i < line; i++) + for (int j = 0; j < col; j++) + this.matrix[i][j] = matrix.matrix[i][j]; + + } + + /** + * @param l + * @param c + */ + public Matrix(int l, int c) { + this.line = l; + this.col = c; + matrix = new SemiRing[l][c]; + } + + /** + * Returns the n <sup>th </sup> power of this matrix. + * + * @param n + * the power. Must be positive or null. + * @param res + * matrix where the result should be stored. Must be same size as + * this matrix with all elements initialized with null. + * @return the result Matrix object with transition matrix equals the n + * <sup>th </sup> power of this matrix's transition. + */ + public Matrix power(int n, Matrix res) { + int l = line; + if(line != col) + throw new IllegalStateException("Cannot compute power of a non square matrix"); + SemiRing[][] tmp = new SemiRing[l][l]; + for (int i = 0; i < l; i++) + Arrays.fill(tmp[i], matrix[0][0].zero()); + for (int k = 0; k <n; k++) { + for (int i = 0; i < l; i++) { + for (int j = 0; j < l; j++) { + for (int m = 0; m < l; m++) { + if (k==0) + tmp[i][j] = tmp[i][j].plus(matrix[i][m] + .mult(matrix[m][j])); + else + tmp[i][j] = tmp[i][j].plus(res.matrix[i][m] + .mult(matrix[m][j])); + } + } + } + /* copy to res */ + for (int i = 0; i < l; i++) + System.arraycopy(tmp[i],0,res.matrix[i],0,l); + } + return res; + } + + + /** + * Returns the star of this matrix. + * + * @return + */ + public Matrix star() { + return null; + } + + public int getLine() { + return line; + } + + public String toString() { + final String ln = System.getProperty("line.separator"); + StringBuffer sb = new StringBuffer(); + int n = matrix.length; + for (int i = 0; i < line; i++) { + sb.append("[ "); + for (int j = 0; j < col; j++) { + String s = matrix[i][j].toString(); + sb.append(s).append(' '); + } + sb.append("]").append(ln); + } + return sb.toString(); + } + + /* (non-Javadoc) + * @see rationals.algebra.SemiRing#plus(rationals.algebra.SemiRing) + */ + public SemiRing plus(SemiRing s2) { + if(s2 == null) + throw new IllegalArgumentException("Null argument"); + Matrix o = (Matrix)s2; // maybe ClassCastException + if(col != o.col || line != o.line) + throw new IllegalArgumentException("Incompatible matrices dimensions : cannot add non square matrices"); + int l = line; + int c = col; + Matrix res = Matrix.zero(l,c,matrix[0][0]); + for(int i=0;i<l;i++) + for(int j=0;j<c;j++) + res.matrix[i][j] = matrix[i][j].plus(o.matrix[i][j]); + return res; + } + + /* (non-Javadoc) + * @see rationals.algebra.SemiRing#mult(rationals.algebra.SemiRing) + */ + public SemiRing mult(SemiRing s2) { + if(s2 == null) + throw new IllegalArgumentException("Null argument"); + Matrix o = (Matrix)s2; // maybe ClassCastException + if(col != o.line) + throw new IllegalArgumentException("Incompatible matrices dimensions"); + int l = line; // lines + int c = o.col; // cols + int m = col; + Matrix res = Matrix.zero(l,c,matrix[0][0]); + for(int i=0;i<l;i++) { + for(int j=0;j<c;j++) + for(int k=0;k<m;k++){ + if(k ==0) + res.matrix[i][j] = matrix[i][k].mult(o.matrix[k][j]); + else + res.matrix[i][j] = res.matrix[i][j].plus(matrix[i][k].mult(o.matrix[k][j])); + } + } + return res; + } + + /* (non-Javadoc) + * @see rationals.algebra.SemiRing#one() + */ + public SemiRing one() { + if(line != col) + throw new IllegalStateException("Cannot get unit matrix on non-square matrices"); + return one(line,matrix[0][0]); + } + + /* (non-Javadoc) + * @see rationals.algebra.SemiRing#zero() + */ + public SemiRing zero() { + return zero(line,col,matrix[0][0]); + } + + public int getCol() { + return col; + } + + /** + * Factory method for creating Matrix instances with coefficients + * in a certain SemiRing. + * + * @param sr a SemiRing instance. Used to get one and zero. + * @return a new zero matrix. + */ + public static Matrix zero(int line,int col,SemiRing sr) { + Matrix m = new Matrix(line,col); + for(int i=0;i<line;i++) + for(int j=0;j<col;j++) + m.matrix[i][j] = sr.zero(); + return m; + } + + /** + * Factory method for creating unit Matrix instances with coefficients + * in a certain SemiRing. + * + * @param sr a SemiRing instance. Used to get one and zero. + * @return a new unit square matrix. + */ + public static Matrix one(int dim,SemiRing sr) { + Matrix m = new Matrix(dim); + for(int i=0;i<dim;i++) + for(int j=0;j<dim;j++) + m.matrix[i][j] = (i == j) ? sr.one() : sr.zero(); + return m; + } + + +} diff --git a/extra/jautomata-core/rationals/algebra/RationalMatrix.java b/extra/jautomata-core/rationals/algebra/RationalMatrix.java new file mode 100755 index 0000000000..7a7ffbaf61 --- /dev/null +++ b/extra/jautomata-core/rationals/algebra/RationalMatrix.java @@ -0,0 +1,145 @@ +/* + * (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.algebra; + +import java.util.Iterator; +import java.util.Set; + +import rationals.Rational; +import rationals.State; +import rationals.Transition; +import rationals.expr.Letter; +import rationals.expr.Plus; +import rationals.expr.RationalExpr; + +/** + * A matrix for representing regular languages. + * <p> + * The cell of the matrix are rational expressions made from concatenation, + * epsilon, letters and union. + * + * @author nono + * @version $Id: RationalMatrix.java 2 2006-08-24 14:41:48Z oqube $ + * @see rationals.expr + */ +public class RationalMatrix { + + private Matrix init; + private Matrix fini; + private Matrix transitions; + + /** + * @return Returns the fini. + */ + public Matrix getFini() { + return fini; + } + + /** + * @param fini The fini to set. + */ + public void setFini(Matrix fini) { + this.fini = fini; + } + + /** + * @return Returns the init. + */ + public Matrix getInit() { + return init; + } + + /** + * @param init The init to set. + */ + public void setInit(Matrix init) { + this.init = init; + } + + /** + * @return Returns the transitions. + */ + public Matrix getTransitions() { + return transitions; + } + + /** + * @param transitions The transitions to set. + */ + public void setTransitions(Matrix transitions) { + this.transitions = transitions; + } + + /** + * Construct the matrix of a rational language. + * + * @param rat + * a Rational language. + */ + public RationalMatrix(Rational rat) { + Set st = rat.states(); + int n = st.size(); + init = Matrix.zero(1,n,RationalExpr.zero); + fini = Matrix.zero(n,1,RationalExpr.zero); + transitions = Matrix.zero(n,n,RationalExpr.zero); + State[] sta = (State[]) rat.states().toArray(new State[n]); + /* fill matrices */ + for (int i = 0; i < sta.length; i++) { + if (sta[i].isInitial()) + init.matrix[0][i] = Letter.epsilon; + else + init.matrix[0][i] = RationalExpr.zero; + if (sta[i].isTerminal()) + fini.matrix[i][0] = Letter.epsilon; + else + fini.matrix[i][0] = RationalExpr.zero; + /* transitions */ + for (int j = 0; j < n; j++) { + Set trs = rat.deltaFrom(sta[i], (State) sta[j]); + RationalExpr re = null; + for (Iterator it = trs.iterator(); it.hasNext();) { + Transition tr = (Transition) it.next(); + Object o = tr.label(); + Letter l = (o == null) ? Letter.epsilon : new Letter(o); + if (re == null) + re = l; + else + re = new Plus(re, l); + } + transitions.matrix[i][j] = re == null ? RationalExpr.zero : re; + } + } + } + + /** + * Compute words from this rational whose length is + * n. + * + * @param n + * @return + */ + public Matrix nwords(int n) { + Matrix res = transitions.power(n,Matrix.zero(transitions.getLine(),transitions.getLine(),RationalExpr.zero)); + /* compute product for init and fini */ + Matrix in = (Matrix)init.mult(res); + return (Matrix)in.mult(fini); + } + + public String toString() { + return init.toString() + '\n'+ transitions.toString() + '\n'+fini.toString(); + } +} diff --git a/extra/jautomata-core/rationals/algebra/SemiRing.java b/extra/jautomata-core/rationals/algebra/SemiRing.java new file mode 100755 index 0000000000..62c2229a79 --- /dev/null +++ b/extra/jautomata-core/rationals/algebra/SemiRing.java @@ -0,0 +1,70 @@ +/* + * (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.algebra; + +/** + * An interface implemented by objects that can be coefficients of a + * Matrix. + * <p> + * A semi-ring is a structure <code>(R,+,*,0,1)</code> such that: + * <ol> + * <li><code>(R,+,0)</code> is a commutative monoid </li> + * <li><code>(R,*,1)</code> is a monoid </li> + * <li><code>x*(y+z) = x*y + x*z</code> and <code>(y+z)*x = y*x + z*x</code> : multiplication + * is distributive with respect to addition </li> + * <li><code>x*0 = 0*x = 0</code>: 0 is an absorbing element for *</li> + * </ol> + * + * @author nono + * @version $Id: SemiRing.java 2 2006-08-24 14:41:48Z oqube $ + * @see Matrix + */ +public interface SemiRing { + + /** + * Addition of a Semi-ring element with another element. + * + * @param s1 + * @param s2 + * @return + */ + public SemiRing plus(SemiRing s2); + + /** + * Multiplication of semiring element with another element. + * + * @param s1 + * @param s2 + * @return + */ + public SemiRing mult(SemiRing s2); + + /** + * Neutral element for multiplication. + * + * @return + */ + public SemiRing one(); + + /** + * Neutral element for addition. + * + * @return + */ + public SemiRing zero(); + +} diff --git a/extra/jautomata-core/rationals/converters/ConverterException.java b/extra/jautomata-core/rationals/converters/ConverterException.java new file mode 100755 index 0000000000..046b833c71 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/ConverterException.java @@ -0,0 +1,24 @@ +/* + * (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.converters; + + +public class ConverterException extends Exception { + private static final long serialVersionUID = 1L; + + public ConverterException(String message) {super(message) ;} +} diff --git a/extra/jautomata-core/rationals/converters/Expression.java b/extra/jautomata-core/rationals/converters/Expression.java new file mode 100755 index 0000000000..e34ba3dee5 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/Expression.java @@ -0,0 +1,29 @@ +/* + * (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.converters; +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; +import rationals.converters.analyzers.Parser; + +public class Expression<Tr extends Transition<String>, T extends Builder<String, Tr, T>> implements FromString<Tr, T> { + public Automaton<String, Tr, T> fromString(String s) throws ConverterException { + return new Parser<String, Tr, T>(s).analyze() ; + } + +} + diff --git a/extra/jautomata-core/rationals/converters/FromString.java b/extra/jautomata-core/rationals/converters/FromString.java new file mode 100755 index 0000000000..e02ee06633 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/FromString.java @@ -0,0 +1,26 @@ +/* + * (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.converters; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; + + +public interface FromString<Tr extends Transition<String>, T extends Builder<String, Tr, T>> { + public Automaton<String, Tr, T> fromString(String s) throws ConverterException ; +} diff --git a/extra/jautomata-core/rationals/converters/ToRExpression.java b/extra/jautomata-core/rationals/converters/ToRExpression.java new file mode 100755 index 0000000000..0e5a5f3556 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/ToRExpression.java @@ -0,0 +1,144 @@ +/* + * (C) Copyright 2004 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.converters; + +import rationals.*; +import rationals.properties.isNormalized; +import rationals.transformations.Normalizer; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * This Converter takes an Automaton and generates an equivalent Regular + * expression. + * <p> + * This conversion applies classical conversion algorithm based on state + * removal. + * cf. Algorithm BMC (Brozowski et al.) from J.sakarovitch "Eléments de théorie + * des automates", sec. 2 + * + * @version $Id: ToRExpression.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class ToRExpression<Tr extends Transition<String>, T extends Builder<String, Tr, T>> implements ToString<String, Tr, T> { + + private Map<Couple, String> keys = new HashMap<>(); + + /* + * (non-Javadoc) + * + * @see rationals.converters.ToString#toString(rationals.Automaton) + */ + public String toString(Automaton<String, Tr, T> a) { + if(a == null) return "0"; + Automaton<String, Tr, T> ret = a.clone(); + if (!new isNormalized().test(a)) + ret = new Normalizer<String, Tr, T>().transform(a); + /* special case for empty automaton */ + if (ret.initials().isEmpty()) + return "0"; + /* add all transitions from start to end state */ + State init = ret.initials().iterator().next(); + State fini = ret.terminals().iterator().next(); + String re = ""; + for(Iterator<Transition<String>> i = ret.deltaFrom(init,fini).iterator();i.hasNext();) { + Transition<String> tr = i.next(); + if("".equals(re)) { + re = (tr.label() == null) ? "1" : tr.label().toString(); + }else + re += "+" + ((tr.label() == null) ? "1" : tr.label().toString()); + } + if(!"".equals(re)) + keys.put(new Couple(init,fini), re); + Iterator<State> it = ret.states().iterator(); + while (it.hasNext()) { + State st = it.next(); + if (st.isInitial() || st.isTerminal()) + continue; + + re = ""; + /* first handle self transitions */ + Iterator<Transition<String>> it2 = ret.delta(st).iterator(); + while (it2.hasNext()) { + Transition<String> t1 = it2.next(); + if (!t1.end().equals(st)) + continue; + re += "+" + t1.label(); + } + /* clean first '+' */ + if (!"".equals(re)) { + re = re.substring(1); + if (re.length() > 1) + re = "(" + re + ")*"; + else + re = re + "*"; + } + Set<Transition<String>> to = ret.delta(st); /* outgoing */ + Set<Transition<String>> from = ret.deltaMinusOne(st); /* incoming */ + it2 = from.iterator(); + while (it2.hasNext()) { + /* beware : this is reverse transition */ + Transition<String> t1 = it2.next(); + if (t1.end().equals(st)) /* skip self transitions */ + continue; + Iterator<Transition<String>> it3 = to.iterator(); + while (it3.hasNext()) { + Transition<String> t2 = it3.next(); + if (t2.end().equals(st)) + continue; + /* find completed expression from start to end */ + State s2 = t2.end(); + State s1 = t1.end(); + Couple k = new Couple(s1, s2); + String oldre = (String) keys.get(k); + String nre = t1.label() + "" + re + t2.label(); + if (oldre == null) { + oldre = nre; + } else { + oldre += "+" + nre; + } + try { + keys.put(k, oldre); + ret.addTransition(new Transition<String>(s1, oldre, s2)); + } catch (NoSuchStateException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + } + /* returns the transition from stat to end */ + re = (String) keys.get(new Couple(init,fini)); + return re; + } + +} + +/* + * $Log: ToRExpression.java,v $ Revision 1.3 2005/03/23 07:22:42 bailly created + * transductions package corrected EpsilonRemover added some tests removed + * DirectedGRaph Interface from Automaton + * + * Revision 1.2 2005/02/02 14:21:10 bailly corrected bad import + * + * Revision 1.1 2004/09/21 11:50:28 bailly added interface BinaryTest added + * class for testing automaton equivalence (isomorphism of normalized automata) + * added computation of RE from Automaton + * + */ diff --git a/extra/jautomata-core/rationals/converters/ToString.java b/extra/jautomata-core/rationals/converters/ToString.java new file mode 100755 index 0000000000..606a6daba4 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/ToString.java @@ -0,0 +1,25 @@ +/* + * (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.converters ; +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; + + +public interface ToString<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + public String toString(Automaton<L, Tr, T> a) ; +} diff --git a/extra/jautomata-core/rationals/converters/analyzers/DefaultLexer.class b/extra/jautomata-core/rationals/converters/analyzers/DefaultLexer.class new file mode 100644 index 0000000000000000000000000000000000000000..89d2dcd099c23a2f4d0417ca39cef7734ae05274 GIT binary patch literal 2567 zcmZ`)`%_a_5dID%xyj`M0a0GsVznAVdDyDeg3tI0f`}j%-<NQKKuF@v4G-Vdscol@ zojQH$)S-hNf6$qh8Av*1+RpUH{t5k8Y&-qVO@Kf#GrOC!XLrxHdv?$L^WR^71F#); z6$BI<Qjv$lDg=(G*n*=fw&IwF|AJE2D%o+#+9Ye2?1W?;lAV-xoeEA#*(EjI3QjBN zapR1NG8~rr_uc4~@~nsZ=Tw}>1r--@Nx@|Wx{B9uOtL-&Ar%|ZFBgVn12W*Cf*}QA z0gn|MF{0tChAB|lHmr~7jp0~hmt`9IX!pWavp~KP?H3Sd1)Skgeb5jn%~(hD=%BO@ zM+a%<9MdC7Zi=9Q5=xq;5w!$dE#YX`+AFZu_kX9_9sx%n)=#hEws6!qksR$a%x=9e zLd}}212LU4^nSx^mgei1v@4O?(FmSk^L=tr*k$RVk#;?9N3`pBSwKBJ5i;UdI2KKC z5m`Le_9Av?MDH^q0%gA19K;=c!$!zrnrc@pX@-m=VTrNikTIYqBUYO+VVDiFgaYNS zs3ari?678;tTb%H+mh{&Y^P+qH26@fVOahfK}5r-WKqdth-<h4Q$s>BKk5WFo4QO# zk0csHvFMm#T85cu)Tx-{<t7?!bQ+q_sKEm7V$A}OV8>!H1h%dkCa@4O$Fl5n)R>5~ z9!7snXh=78{v((MGzvh&Td3ENM7@GB4da+lFsb1xt}PsF_f1Z?OvQ4#>0mM(;e~6s zjvLFI0!xQ&!%ew=OT%q^py7_pt8Uc{mI{%3TLNCY3ih#?+Z8A<jf7!!O-3z!f(Aw` z5=?Z32czMEa7dT!?C_nnJ1Y_!H_U*ZFxu_zElou9#88)Hf!OFMJD<Jfxsr@ohJ-Br zg3`}39y9x;hTBeG(AE`?4}~ow5!XYut#o8{Eqem#nBZ6~!<rd5PL{0v0UJ}WHo#t7 zN+%e#j6pfp?l_M!xO~O@vE5yIJZ=wo{b~c6GXa@%vsc4GaQFf;rDbl}Dajq2m2Pe; zwvfT{3Cn01*d=E&8sp2gg)b*_hm#K~CxUNmp6qyAvdL`8rn4oxo6=2t&J+1NTs6T( z51`CH579f1yxzJr^3!mn;hdpf@XZF~a}C<B;Yxb%$a>epVeb^$-t=6}Z4di>ukE%o z>vkXcwp*J&4VS-e4vK#kN(yc%@>B3+r7EQ(g#szPZ=|5vf113zQz*1;yfrBl`Sa&c zyacuZ1q6GP(2l`_AdAzA3LHlb+E}7?!aso)bl?b1Qrk&P?_wA6upD`hS;%~5J;vz8 z-$M0!J##3Tk!Ph)+VTuV?ei$>EnS<&y5FnwrcmW~@NkKs++SKThsvx+wfCPXSbpg^ ziz=y~MI}?K_BMTw&c(&<X&hQG`Wfq&qRgWF5%YHO^k=A`eYs<bYp1<-%R@_M+WlVD zMrWT+MxYrCQc?Y!Rd_)1kT#J<NIsHDl8rJ+@{`VxWW#ilE@tT(<!#b+Qa|Yi=_9|} zKEf+O&G?nfq97x*jL0gphJ_hrku4-Xw#jR~X}n%qkwVQpHuhFOOoR8jDTU3f(F|{) z2<uSEMjOF2o?-(vvH}0XPV#Q>3xz`T(CQrRF4FQms&E0Dafvxy=KHGi9{aExA?zda z{TSdq4>GqQMjU3&Be;bK?(uu^fM1HQ5XTc%WSX!3Q$EN)U<}XsAiv;aJcDaUu>xt_ z#IN-F1GhyP?ubg<6;=39)Zm`jh>yh<d?L2uQ&Ermq5%)Yc6=sw;B(Q8hoS{vh=cf2 z1n{*8;v3P5N8%(Ni%xtedhkRfF-5HMe#(kk6}<O1R8jpB?ZuA$3Yr!5CC)otPM7^- z(}GRSk0fc2JyLRlYq;V!B{MuJy!nFvGgIrb_0#10ScuHLZ=jUcPT7J#tuTGYt%k+G bxu)eSqduo;)2gN=D@}i-=>eXUhlBqCs4FYP literal 0 HcmV?d00001 diff --git a/extra/jautomata-core/rationals/converters/analyzers/DefaultLexer.java b/extra/jautomata-core/rationals/converters/analyzers/DefaultLexer.java new file mode 100755 index 0000000000..e3d97a9111 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/analyzers/DefaultLexer.java @@ -0,0 +1,178 @@ +/* + * (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.converters.analyzers; + +import rationals.converters.ConverterException; + +import java.io.IOException; +import java.io.Reader; +import java.io.StreamTokenizer; +import java.io.StringReader; + +/** + * Default lexical analyser for regular expressions. + * This lexer parse a regular expression and treats each letter + * as a label. + * + * @author yroos + * @version $Id: DefaultLexer.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class DefaultLexer implements Lexer { + private StreamTokenizer tokenizer; + + private boolean end; + + private String image; + + private int value; + + private int current; + + /** + * Construct a lexical analyzer to parse given string. + * + * @param in the String to parse. + */ + public DefaultLexer(String in) { + this(new StreamTokenizer(new StringReader(in))); + } + + /** + * construct a lexical analyzer to parse the characters from given + * Reader object. + * + * @param rd the character stream to parse. + */ + public DefaultLexer(Reader rd) { + this(new StreamTokenizer(rd)); + } + + /** + * Construct a lexical analyzer that uses given StreamTokenizer object + * to get data from. + * Note that the tokenizer is reset and given new attributes. + * + * @param st + */ + public DefaultLexer(StreamTokenizer st) { + tokenizer = st; + tokenizer.resetSyntax(); + tokenizer.eolIsSignificant(false); + tokenizer.lowerCaseMode(false); + tokenizer.slashSlashComments(true); + tokenizer.quoteChar('\"'); + tokenizer.wordChars('0', '9'); + tokenizer.whitespaceChars(0, 32); + end = false; + } + + public void read() throws ConverterException { + if (end) { + current = END; + return; + } + ; + int tk; + try { + tk = tokenizer.nextToken(); + } catch (IOException e) { + throw new ConverterException("Unexpected character"); + } + if (tk == StreamTokenizer.TT_EOF) { + end = true; + value = 0; + image = ""; + current = END; + return; + } + if (tk == StreamTokenizer.TT_WORD) { + image = tokenizer.sval; + if (image.charAt(0) >= '0' && image.charAt(0) <= '9') { + try { + value = Integer.parseInt(tokenizer.sval); + image = ""; + if (value == 0) + current = EMPTY; + else { + if (value == 1) + current = EPSILON; + else + current = INT; + } + return; + } catch (Exception e) { + current = UNKNOWN; + return; + } + } + value = 0; + current = LABEL; + return; + } + image = ""; + value = 0; + switch (tk) { + case '+': + current = UNION; + return; + case '*': + current = STAR; + return; + case '^': + current = ITERATION; + return; + case '|': + current = SHUFFLE; + return; + case '#': + current = MIX; + return; + case '(': + current = OPEN; + return; + case ')': + current = CLOSE; + return; + case '{': + current = OBRACE; + return; + case '}': + current = CBRACE; + return; + default: + current = LABEL; + image = "" + new Character((char) tk); + } + } + + public int lineNumber() { + return tokenizer.lineno(); + } + + public Object label() { + return image; + } + + public int value() { + return value; + } + + public int current() { + return current; + } +} + diff --git a/extra/jautomata-core/rationals/converters/analyzers/Lexer.class b/extra/jautomata-core/rationals/converters/analyzers/Lexer.class new file mode 100644 index 0000000000000000000000000000000000000000..c175185f4eb1d3a357b62bb62980e9f1b82fd033 GIT binary patch literal 849 zcmZwF*>2N76b9fkNgOw6)0Va@WnT()SZbDX0|+S%j<A^8QS20YIdMl-D&wGu9Tgsp z3m$-nLj2=Y)rfMH`Of^aoN<2t`T2{8cImZEFKv3o$l{$nk27LEqgHp4O>>du2O=$G z6+vQD^@CUs86(^4M?Mb&%?g%!`~CP(qspk^$KIe5`}5fvW{1HUEJn2`?hJIYj&a!c z$}Mb!x;%_LJ+Xk3yx@Z#HgM7~_!NYn%UBbPJ`Q_5UIrHt-1ooe;1Z*HxHsr@%ZV1$ zJ=Zc0Qc@ft?X(XVHNDeBe#^(`(578D9cMBqzK*0SBWT}B#Ym=%Hk>v;5i{YYB0F}& z(TPm*x9Bh$A7>&jltk2N#~d|lre6vdObVrBmNRnR@i!M&zrR?*6{1O@64@K4*rCbg zsZ=}qTt-_;=$ndk>L!zHCRHxg)D<Xv|Di`^meK0Jw`8>a-<9~T^G(hl0pEd91#h@Q zn^dJ5WI+|G!?xiCxM8>nFB)EgTZWh66~n9WCBtj*y5SA@vf(T6Rm0cdO~cor8-{Pf zw+!Eg?-;%d-!pulEc`hi&=xv=h>msVk5Jhr2Vm5u$EZ9h-{L9!?5w_{fAK!^8JC`y Gdhr*(=7Qb; literal 0 HcmV?d00001 diff --git a/extra/jautomata-core/rationals/converters/analyzers/Lexer.java b/extra/jautomata-core/rationals/converters/analyzers/Lexer.java new file mode 100755 index 0000000000..d743ee76a7 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/analyzers/Lexer.java @@ -0,0 +1,102 @@ +/* + * (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.converters.analyzers; + +import rationals.converters.ConverterException; + +/** + * Interface lifting lexical analysis. + * This interface allows customization of parsing of RE, in particular to + * override the definition of what is a labeL. + * Instances of Lexer are used by instances of Parser to retrieve tokens. + * @author nono + * @version $Id: Lexer.java 2 2006-08-24 14:41:48Z oqube $ + * @see DefaultLexer + * @see Parser + */ +public interface Lexer<L> { + public static final int LABEL = 0; + + public static final int INT = 1; + + public static final int EPSILON = 2; + + public static final int EMPTY = 3; + + public static final int ITERATION = 4; + + public static final int UNION = 5; + + public static final int STAR = 6; + + public static final int OPEN = 7; + + public static final int CLOSE = 8; + + public static final int END = 9; + + public static final int UNKNOWN = 10; + + // AB + public static final int SHUFFLE = 11; + + public static final int MIX = 12; + + public static final int OBRACE = 13; + + public static final int CBRACE = 14; + + /** + * Read more data from the underying input. + * + * @throws ConverterException if some characters cannot be converted + */ + public abstract void read() throws ConverterException; + + /** + * Return the current line number in the underlying character + * stream. + * Line separation is platform dependent. + * + * @return number of current line, starting from 1 + */ + public abstract int lineNumber(); + + /** + * Return the image of current token. + * This method is used by Parser to create atomic Automaton objects + * so any Object can be used. + * + * @return an Object which is a label for a transition. + */ + public abstract L label(); + + /** + * Return the value of a number. + * + * @return value of a number. + */ + public abstract int value(); + + /** + * Returns the current token value. + * This value must be one of the constants defined in interface Lexer. + * + * @return a constant denoting the kind of token. + */ + public abstract int current(); +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/converters/analyzers/Parser.class b/extra/jautomata-core/rationals/converters/analyzers/Parser.class new file mode 100644 index 0000000000000000000000000000000000000000..03676571000bffa59bc33c11a0550350912164ce GIT binary patch literal 4800 zcmcInZE#dq8Gg=Yvv;#xLf96N2s9*+Cc8i={Sfn|1cK5oDJ2Vtt(BY2O|r1rP4Die z3--fmtF~4utw>uxDCqc6W*lH@QjMeIA9b9OAC9Ac?2P~X<ES(0jHOKL^WKl$&F04N zr#ExYJ?Gu?zUO`3=RNN^`R%(u{W*ZU@ZAXdaZG~|K>#BS=tD}ws0K5F5RQd0Cg1U8 zScM7crNcNbgA+2ygfS`KYy|Zf5pga;15?s_M1vJZUd9D!iqcGLcr=1$S+5kqIvkVc zq)1MM@tH6l)9`o%ts?Kk6Vg1X;j<C6i=-VV!+1)5{+x!-M-UfbT-5vUv^39X_(BBR zMZDb+e^JC=3gg)@o)g6{Yj{3_oibx5PKlde3FEYe7c_iTA(Syo=~PakJz*JzbS`UT z@?EK1cG|QGrj_q9C^&gadI_^+T0II4!|Cy?Q7BrbLj0zbdXtHserkq#)7f;PUtv{8 z;<zzwbY+a}c-L^jN@vG=Iu9!ZcjrcFbwwhbHHV6mBc_!!MlzIicHGoLwvlZ&H`j4W zR;@QJD`(k@EcB{s-Ce~(Zqg{^vV;;DETzmTiC13XZa+AFin3-hY4Nq=p}E0TSkuwz zH=heFA1)ZF6Z?%RI}%J4g*N}mHOAGTLSXQKf=aTJ9A<}aASsf)d<Qrf;9yI2xGE4A z^JkCm^m%Lhs?M9CFwvXnuF8S?M~<7RLQm4_t_nlaGP3!!#8{O3dy?JNzYY}BnNic4 zXSaW$Nm4bOD_SXYZ(0&**#X1Ko7OfVTE}jjVGb{m_j}ASqnIh!=`SjKbbJIKRk+<( zZ@0H~$_YYtYtzd0ovD{$rnl&L5ijZZ8qP}Z>k4%(TPQq-mu38ljJr9072nYDO`Oqj z5JNh?g|iBqe4VJ-v<l5;cC;lo)?${XEHj^HNTth=o1;4R;a(j{F*%GOg^d-H1z}(; zXEEy~)4L9uqs5fTt#aGqa}H%WRmZn+UYZ9LZt+=Ep|L3Q%3g3<#bh}PbsQGA4lUu< z@I-NJOxRt`!j&=#Cd*T`aUHLTh4qycYJu%fmvnqW);c0HtEjD=Nq#FU=r}4mpA?uY z#*9=UXH_AJbd(1=F5sfVhQ&SLHn((qM>xIpP}U=-B{gAKv@0>+Tv7I|&rW75G*z<A z*;dS-4ykh?V`_?dps>}qURBhbitHw-6g$aMrykq3_9?9E*w<OL*=jZFGscLSArzLX zid}b?*Erxxt0&f)3m0;ZsMew*rHet!G>A+~6)nrm7I;dPiBs6+TeEtqN=-TAdVGr) z7ico4^65-2Tb{`jwn0`2cuFk*yO_QDX(LlKv5{wWKkp<g#!^-I-NjJ=16a;Jiw)aB zO71|AQeb6l7AiJ}z|r_D>VAyi6<c{P+eXx}-NA`>qKTIrQU4f~L_Nl@s7Gw|xQ|{B z^?D&!A;*D_b3O|LZHoROclo|K)E}Kg=;$o8Xm|z<u{RL>2_gzJSQgdGg5@G;jIN*{ z&UXe)vsn2H8d4BfL;Qkh?_(QezusLm!Tx>>xr-igo!;y$5>=r0w<Mg=t)!&kJOM>l z&tlDy_+^?3*v6wY2?nl#o;Om`#wgrRNf_z|+B6(ku<QfWWJz_G{Q>nQl7;d@uX6;9 z+AW~-yW1Vh*Xzsg^45-RIX(YCg3a3fb7*GtJ~)SU{H%{}nZbq`+;%w@Z6S^diq#AX z=xKufKES`j^l%an*+@bNyn{rGFAkP)7soXh$MZEf9;01(JRCCia7h0kUr%-~`|`@z zeq+&%;^rJ$>3!SfYG#(gXDiZ<!%{2x01V<YdF+hiL8KYI<7`hLiwvGY-eoOFtRbz_ z7cEb%_nEa#!rJBvYwg5+yRg==IBO-MdYqg+LDrrmYtJsp8c#R}hpKm3yIRBAMMg^= zk2M*4tVv&3@?;)sG9KbvibXqxwKox)$Ji3s?5*wWy4sm>Mq!IYVXG4b+dNltxZPoU zd74ppk=&l;nR*V#@G_Zxg$%!nr+6`V4(IU#UgM?b0xscuc7z&GFI?Ak`jgGO!23-0 zHX*yKLiTpTyhC8_Se)!jgn5}{Um@97N%qf{B%4<Z7snNs>{1Qc6AYz19@#SX$d<m8 z6i?=r9Zx<=2>&04od!-u(2he{Gix&NOJeyIvHY4?enTwR@Cbfy<IzwjC8y4J7xLod z0y<4|0UCO^29RW-JRTq!dw`_xy(07a<!_9L?wrM4i8!m|-SeuXQ|tdkxBtvD>Mds4 zU#r3&@%5HhHpg4l?s_{{<LxDSA&+?b5?>jMXHprZ@4aSK-;-TpbloG0TPN;S%4(6b z+QQ>3Y#(R$2*C0bLbkUd57amDp?OwnLNUNYANU(X@pm2>|KQE^pDe2XLJI$8IsFfd z>VNSl-ewuUjx%_N+wcbenRpLB<WYQ8DZHVU*`ZsB5Sea_-asqQ%Ik=%@r@$yylxZ+ zc~Z$)^;S(3e@B@-9_Odo_g?Ru9Hh+41Nn-MJ@#-jO63D{CwJqAd7bFCH=|db%0D}s zbq-b2oNa5*<Q1;39942ORCiBsRdC%!w9GfKl?#a4(9=Qn{rCQ|l_}RdFXg&<seo!i zLapJy3TtshHDgk($F$mjbE*{=R2yDboA4vG8M92WYyAE}b>NRGX2*9mG{#qL=zJGz h6(g*!qxEgxd+sCj>buZGOit%2_9;Bf-vapb{{WD~E3N<l literal 0 HcmV?d00001 diff --git a/extra/jautomata-core/rationals/converters/analyzers/Parser.java b/extra/jautomata-core/rationals/converters/analyzers/Parser.java new file mode 100755 index 0000000000..51f42d2bc9 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/analyzers/Parser.java @@ -0,0 +1,301 @@ +/* + * (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.converters.analyzers; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; +import rationals.converters.ConverterException; +import rationals.transformations.Concatenation; +import rationals.transformations.Mix; +import rationals.transformations.Reducer; +import rationals.transformations.Shuffle; +import rationals.transformations.Star; +import rationals.transformations.Union; +// Grammar : +// E -> T E' +// E' -> + T E' | '/' '{' L '}' | eps +// T -> S T" +// T" -> '|' S T" | '#' S T" | eps +// S -> F T' +// T' -> F T' | eps +// F -> B B' +// B' -> * | int | ^ | eps +// B -> letter | 1 | 0 | ( E ) +public class Parser<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + + private Lexer<L> lexico ; + + /** + * Parse given string using standard grammar and lexical analyzer. + * + * @param expression the expression to parse + * @see Lexer + * @see DefaultLexer + */ + public Parser(String expression) { + lexico = new DefaultLexer(expression) ; + } + + /** + * Parse using the given lexer. + * + * @param lexer the lexer to use for parsing. + */ + public Parser(Lexer<L> lexer) { + this.lexico = lexer; + } + + private Automaton<L, Tr, T> error(String message) throws ConverterException { + throw new ConverterException("line " + lexico.lineNumber() + " , " + lexico.label() + " : " + message); + } + + public Automaton<L, Tr, T> analyze() throws ConverterException { + lexico.read() ; + Automaton<L, Tr, T> r = E() ; + if (lexico.current() != Lexer.END) error("end of expression expected") ; + return r ; + } + + private Automaton<L, Tr, T> E() throws ConverterException { + switch(lexico.current()) { + case Lexer.EPSILON : + case Lexer.EMPTY : + case Lexer.OPEN : + case Lexer.LABEL : { + Automaton<L, Tr, T> a = T() ; + Automaton<L, Tr, T> b = EP() ; + return new Reducer<L, Tr, T>().transform(new Union<L, Tr, T>().transform(a , b)) ; + } + case Lexer.CLOSE : + case Lexer.END : + case Lexer.UNION : + case Lexer.SHUFFLE : + case Lexer.MIX : + case Lexer.STAR : + case Lexer.ITERATION : + case Lexer.INT : + default : return error("expression expected") ; + } + } + + private Automaton<L, Tr, T> EP() throws ConverterException { + switch(lexico.current()) { + case Lexer.EPSILON : + case Lexer.EMPTY : + case Lexer.OPEN : + case Lexer.LABEL : return error("union expected") ; + case Lexer.CLOSE : + case Lexer.END : return new Automaton<L, Tr, T>() ; + case Lexer.UNION : { + lexico.read() ; + Automaton<L, Tr, T> a = T() ; + Automaton<L, Tr, T> b = EP() ; + return new Reducer<L, Tr, T>().transform(new Union().transform(a , b)) ; + } + case Lexer.SHUFFLE : + case Lexer.MIX : + case Lexer.STAR : + case Lexer.ITERATION : + case Lexer.INT : + default : return error("union expected") ; + } + } + + private Automaton<L, Tr, T> T() throws ConverterException { + switch(lexico.current()) { + case Lexer.EPSILON : + case Lexer.EMPTY : + case Lexer.OPEN : + case Lexer.LABEL : { + Automaton<L, Tr, T> a = S() ; + Automaton<L, Tr, T> b = TS() ; + return new Reducer<L, Tr, T>().transform(new Shuffle().transform(a , b)) ; + } + case Lexer.CLOSE : + case Lexer.END : + case Lexer.UNION : + case Lexer.SHUFFLE : + case Lexer.MIX : + case Lexer.STAR : + case Lexer.ITERATION : + case Lexer.INT : + default : return error("expression expected") ; + } + } + + private Automaton<L, Tr, T> TS() throws ConverterException { + switch(lexico.current()) { + case Lexer.EPSILON : + case Lexer.EMPTY : + case Lexer.OPEN : + case Lexer.LABEL :return error("concatenation expected") ; + case Lexer.CLOSE : + case Lexer.END : + case Lexer.UNION : return Automaton.epsilonAutomaton() ; + case Lexer.SHUFFLE : { + lexico.read() ; + Automaton<L, Tr, T> a = S() ; + Automaton<L, Tr, T> b = TS() ; + return new Reducer<L, Tr, T>().transform(new Shuffle<L, Tr, T>().transform(a , b)) ; + } + case Lexer.MIX : + { + lexico.read() ; + Automaton<L, Tr, T> a = S() ; + Automaton<L, Tr, T> b = TS() ; + return new Reducer<L, Tr, T>().transform(new Mix().transform(a , b)) ; + } + case Lexer.STAR : + case Lexer.ITERATION : + case Lexer.INT : + default : return error("concatenation expected") ; + } + } + + private Automaton<L, Tr, T> S() throws ConverterException { + switch(lexico.current()) { + case Lexer.EPSILON : + case Lexer.EMPTY : + case Lexer.OPEN : + case Lexer.LABEL : { + Automaton<L, Tr, T> a = F() ; + Automaton<L, Tr, T> b = TP() ; + return new Reducer<L, Tr, T>().transform(new Concatenation<L, Tr, T>().transform(a , b)) ; + } + case Lexer.CLOSE : + case Lexer.END : + case Lexer.UNION : + case Lexer.SHUFFLE : + case Lexer.MIX : + case Lexer.STAR : + case Lexer.ITERATION : + case Lexer.INT : + default : return error("expression expected") ; + } + } + + private Automaton<L, Tr, T> TP() throws ConverterException { + switch(lexico.current()) { + case Lexer.EPSILON : + case Lexer.EMPTY : + case Lexer.OPEN : + case Lexer.LABEL :{ + Automaton<L, Tr, T> a = F() ; + Automaton<L, Tr, T> b = TP() ; + return new Reducer<L, Tr, T>().transform(new Concatenation<L, Tr, T>().transform(a , b)) ; + } + case Lexer.CLOSE : + case Lexer.END : + case Lexer.UNION : + case Lexer.MIX : + case Lexer.SHUFFLE :return Automaton.epsilonAutomaton() ; + case Lexer.STAR : + case Lexer.ITERATION : + case Lexer.INT : + default : return error("concatenation expected") ; + } + } + + private Automaton<L, Tr, T> F() throws ConverterException { + switch(lexico.current()) { + case Lexer.EPSILON : + case Lexer.EMPTY : + case Lexer.OPEN : + case Lexer.LABEL : { + Automaton<L, Tr, T> a = BP(B()) ; + return a ; + } + case Lexer.CLOSE : + case Lexer.END : + case Lexer.UNION : + case Lexer.MIX : + case Lexer.SHUFFLE : + case Lexer.STAR : + case Lexer.ITERATION : + case Lexer.INT : + default : return error("factor expected") ; + } + } + + private Automaton<L, Tr, T> B() throws ConverterException { + switch(lexico.current()) { + case Lexer.EPSILON : { + Automaton<L, Tr, T> a = Automaton.epsilonAutomaton() ; + lexico.read() ; + return a ; + } + case Lexer.EMPTY : { + Automaton<L, Tr, T> a = new Automaton<>() ; + lexico.read() ; + return a ; + } + case Lexer.OPEN : { + lexico.read() ; + Automaton<L, Tr, T> a = E() ; + if (lexico.current() != Lexer.CLOSE) return error("( expected") ; + lexico.read() ; + return a ; + } + case Lexer.LABEL : { + Automaton<L, Tr, T> a = Automaton.labelAutomaton(lexico.label()) ; + lexico.read() ; + return a ; + } + case Lexer.CLOSE : + case Lexer.END : + case Lexer.SHUFFLE : + case Lexer.MIX : + case Lexer.UNION : + case Lexer.STAR : + case Lexer.ITERATION : + case Lexer.INT : + default : return error("factor expected") ; + } + } + + private Automaton<L, Tr, T> BP(Automaton<L, Tr, T> a) throws ConverterException { + switch(lexico.current()) { + case Lexer.OPEN : + case Lexer.LABEL : + case Lexer.CLOSE : + case Lexer.END : + case Lexer.UNION : + case Lexer.MIX : + case Lexer.SHUFFLE :return a ; + case Lexer.STAR : { + lexico.read() ; + return new Reducer<L, Tr, T>().transform(new Star().transform(a)) ; + } + case Lexer.ITERATION : + lexico.read() ; + return new Reducer<L, Tr, T>().transform(new Concatenation<L, Tr, T>().transform(a, new Star().transform(a))) ; + case Lexer.EPSILON : + case Lexer.EMPTY : + case Lexer.INT : { + int value = lexico.value() ; + lexico.read() ; + Automaton<L, Tr, T> b = Automaton.epsilonAutomaton(); + for (int i = 0 ; i < value ; i++) { + b = new Reducer<L, Tr, T>().transform(new Concatenation<L, Tr, T>().transform(b , a)) ; + } + return b ; + } + default : return error("Unexpected character") ; + } + } +} diff --git a/extra/jautomata-core/rationals/converters/toAscii.java b/extra/jautomata-core/rationals/converters/toAscii.java new file mode 100755 index 0000000000..db3088b711 --- /dev/null +++ b/extra/jautomata-core/rationals/converters/toAscii.java @@ -0,0 +1,45 @@ +/* + * (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.converters; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class toAscii<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements ToString<L, Tr, T> { + public String toString(Automaton<L, Tr, T> a) { + StringBuilder sb = new StringBuilder(); + sb.append("A = ").append(a.alphabet().toString()).append("\n"); + sb.append("Q = ").append(a.states().toString()).append("\n"); + sb.append("I = ").append(a.initials().toString()).append("\n"); + sb.append("T = ").append(a.terminals().toString()).append("\n"); + sb.append("delta = [\n"); + List<String> list = new ArrayList<>(); + Iterator<Transition<L>> i = a.delta().iterator(); + while (i.hasNext()) + list.add(i.next().toString()); + java.util.Collections.sort(list); + for (String s : list) + sb.append(s).append("\n"); + sb.append("]\n"); + return sb.toString(); + } +} diff --git a/extra/jautomata-core/rationals/expr/BinaryExpr.java b/extra/jautomata-core/rationals/expr/BinaryExpr.java new file mode 100755 index 0000000000..a9b2cbec55 --- /dev/null +++ b/extra/jautomata-core/rationals/expr/BinaryExpr.java @@ -0,0 +1,64 @@ +/* + * (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.expr; + +/** + * @author nono + * @version $Id: BinaryExpr.java 2 2006-08-24 14:41:48Z oqube $ + */ +public abstract class BinaryExpr extends RationalExpr { + + private RationalExpr left; + private RationalExpr right; + + /** + * Construct a binary expression from two sub-expressions. + * + * @param e + * @param f + */ + public BinaryExpr(RationalExpr e,RationalExpr f) { + this.left = e ; + this.right = f; + } + + /** + * @return Returns the left. + */ + public RationalExpr getLeft() { + return left; + } + /** + * @param left The left to set. + */ + public void setLeft(RationalExpr left) { + this.left = left; + } + /** + * @return Returns the right. + */ + public RationalExpr getRight() { + return right; + } + /** + * @param right The right to set. + */ + public void setRight(RationalExpr right) { + this.right = right; + } + +} diff --git a/extra/jautomata-core/rationals/expr/Iteration.java b/extra/jautomata-core/rationals/expr/Iteration.java new file mode 100755 index 0000000000..61b2b0f82c --- /dev/null +++ b/extra/jautomata-core/rationals/expr/Iteration.java @@ -0,0 +1,52 @@ +/* + * (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.expr; + +/** + * @author nono + * @version $Id: Iteration.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Iteration extends RationalExpr{ + + + private RationalExpr expr; + + public Iteration(RationalExpr expr) { + this.expr = expr; + } + + /** + * @return Returns the expr. + */ + public RationalExpr getExpr() { + return expr; + } + + /** + * @param expr The expr to set. + */ + public void setExpr(RationalExpr expr) { + this.expr = expr; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return expr.toString() + "*"; + } +} diff --git a/extra/jautomata-core/rationals/expr/Letter.java b/extra/jautomata-core/rationals/expr/Letter.java new file mode 100755 index 0000000000..415a00df14 --- /dev/null +++ b/extra/jautomata-core/rationals/expr/Letter.java @@ -0,0 +1,93 @@ +/* + * (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.expr; + +import rationals.algebra.SemiRing; + +/** + * A letter expression is simply a wrapper over any object. + * Note that the semantics of equals and hashcode must be properly + * implemented by the wrapped object as this may be used in + * Collections, for example as keys in hashtables. + * + * @author nono + * @version $Id: Letter.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Letter extends RationalExpr { + + private Object label; + + public static final Letter epsilon = new Letter(null) { + + public boolean equals(Object o) { + return o == epsilon; + } + + + public SemiRing mult(SemiRing s2) { + return s2; + } + + public String toString() { + return "1"; + } + + public int hashCode() { + return 0; + } + }; + + /** + * Construct a new letter expression. + * + * @param o + * label of the letter. May not be null. (use epsilon constant). + */ + public Letter(Object o) { + this.label = o; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + Letter lt = (Letter) obj; + if (lt == null) + return false; + return lt.label == null ? this.label == null : lt.label.equals(label); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return label.hashCode(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + public String toString() { + return label.toString(); + } +} diff --git a/extra/jautomata-core/rationals/expr/Plus.java b/extra/jautomata-core/rationals/expr/Plus.java new file mode 100755 index 0000000000..95999114c0 --- /dev/null +++ b/extra/jautomata-core/rationals/expr/Plus.java @@ -0,0 +1,41 @@ +/* + * (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.expr; + +/** + * A plus expression. + * + * @author nono + * @version $Id: Plus.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Plus extends BinaryExpr { + + /** + * @param e + * @param f + */ + public Plus(RationalExpr e, RationalExpr f) { + super(e, f); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return getLeft() + "+"+getRight(); + } +} diff --git a/extra/jautomata-core/rationals/expr/Product.java b/extra/jautomata-core/rationals/expr/Product.java new file mode 100755 index 0000000000..8e1cc98bb5 --- /dev/null +++ b/extra/jautomata-core/rationals/expr/Product.java @@ -0,0 +1,43 @@ +/* + * (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.expr; + + +/** + * A product expression. + * + * @author nono + * @version $Id: Product.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Product extends BinaryExpr { + + /** + * @param e + * @param f + */ + public Product(RationalExpr e, RationalExpr f) { + super(e, f); + } + + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return getLeft() + "" +getRight(); + } +} diff --git a/extra/jautomata-core/rationals/expr/RationalExpr.java b/extra/jautomata-core/rationals/expr/RationalExpr.java new file mode 100755 index 0000000000..18584c59f6 --- /dev/null +++ b/extra/jautomata-core/rationals/expr/RationalExpr.java @@ -0,0 +1,86 @@ +/* + * (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.expr; + +import rationals.algebra.SemiRing; + +/** + * @author nono + * @version $Id: RationalExpr.java 2 2006-08-24 14:41:48Z oqube $ + */ +public abstract class RationalExpr implements SemiRing { + + + public static final RationalExpr zero = new RationalExpr() { + + public SemiRing mult(SemiRing s1) { + return zero; + } + + public SemiRing plus(SemiRing s1) { + return s1; + } + + @Override + public boolean equals(Object o) { + return this == o; + } + + @Override + public int hashCode() { + return -1; + } + + @Override + public String toString() { + return "0"; + } + }; + + public static final RationalExpr one = Letter.epsilon; + + /* (non-Javadoc) + * @see rationals.SemiRing#one() + */ + public final SemiRing one() { + return one; + } + + /* (non-Javadoc) + * @see rationals.SemiRing#zero() + */ + public final SemiRing zero() { + return zero; + } + + + public SemiRing mult(SemiRing s2) { + if(s2 == zero) + return zero; + if(s2 == Letter.epsilon) + return this; + RationalExpr re = (RationalExpr)s2; + return new Product(this,re); + } + + public SemiRing plus(SemiRing s2) { + if(s2 == zero) + return this; + return new Plus(this,(RationalExpr)s2); + } + +} diff --git a/extra/jautomata-core/rationals/properties/AreEquivalent.java b/extra/jautomata-core/rationals/properties/AreEquivalent.java new file mode 100755 index 0000000000..681b3e5eb7 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/AreEquivalent.java @@ -0,0 +1,78 @@ +/* + * (C) Copyright 2004 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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; + +/** + * Tests that two automata are equivalent according to some equivalence relation + * between states. + * <p> + * Instances of this class are parameterized by an instance of {@link TransducerRelation}. + * Given any such instance R, and two automata A1=(Q1,q01,T1,S1,d1) and + * A2=(Q2,q02,T2,S2,d2), we say that <code>A1 R A2</code> iff + * <code>q01 R q02</code>. + * + * @version $Id: AreEquivalent.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class AreEquivalent<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements BinaryTest<L, Tr, T> { + + private Relation<L, Tr, T> relation; + + public AreEquivalent(Relation<L, Tr, T> r) { + this.setRelation(r); + } + + /** + * Defines the relation to be used for computing equivalence. + * + * @param r + */ + public void setRelation(Relation<L, Tr, T> r) { + this.relation = r; + } + + /* + * (non-Javadoc) + * + * @see rationals.tests.BinaryTest#test(rationals.Automaton, + * rationals.Automaton) + */ + public boolean test(Automaton<L, Tr, T> a, Automaton<L, Tr, T> b) { + relation.setAutomata(a, b); + return relation.equivalence(a.initials(), b.initials()); + } + +} + +/* + * $Log: AreEquivalent.java,v $ Revision 1.1 2005/03/23 07:22:42 bailly created + * transductions package corrected EpsilonRemover added some tests removed + * DirectedGRaph Interface from Automaton + * + * Revision 1.3 2005/02/20 21:14:19 bailly added API for computing equivalence + * relations on automata + * + * Revision 1.2 2004/11/15 12:45:33 bailly changed equivalence algorithm + * + * Revision 1.1 2004/09/21 11:50:28 bailly added interface BinaryTest added + * class for testing automaton equivalence (isomorphism of normalized automata) + * added computation of RE from Automaton + * + */ \ No newline at end of file diff --git a/extra/jautomata-core/rationals/properties/AreIsomorph.java b/extra/jautomata-core/rationals/properties/AreIsomorph.java new file mode 100755 index 0000000000..08f43e3417 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/AreIsomorph.java @@ -0,0 +1,46 @@ +/* + * (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.properties; + +//import rationals.Automaton; +//import java.util.HashMap; +//import java.util.Map; + +/** + * Test if two automaton are isomorphic. + * Two automata are isomorphic iff there exists a bijection + * between states of each automata that preserve the initial states, the + * terminal states and the transition relation. + * + * @author nono + * @version $Id: AreIsomorph.java 2 2006-08-24 14:41:48Z oqube $ + */ +//public class AreIsomorph implements BinaryTest { +// +// /* (non-Javadoc) +// * @see rationals.properties.BinaryTest#test(rationals.Automaton, rationals.Automaton) +// */ +// public boolean test(Automaton a, Automaton b) { +// /* basic test */ +// if(a.states().size() != b.states().size() || a.initials().size() != b.initials().size() || a.terminals().size() != b.terminals().size()) +// return false; +// Map /* < State , State > */ atob = new HashMap(); +// // TODO +// return false; +// } +// +//} diff --git a/extra/jautomata-core/rationals/properties/BinaryTest.java b/extra/jautomata-core/rationals/properties/BinaryTest.java new file mode 100755 index 0000000000..c75db1c069 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/BinaryTest.java @@ -0,0 +1,54 @@ +/* + * (C) Copyright 2004 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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; + +/** + * Interface describing binary tests (ie. tests between two automata). + * + * @version $Id: BinaryTest.java 2 2006-08-24 14:41:48Z oqube $ + */ +public interface BinaryTest<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + + /** + * Tests that some predicate is true for two given automata. + * + * @param a + * @param b + * @return + */ + public boolean test(Automaton<L, Tr, T> a, Automaton<L, Tr, T> b); + +} + +/* + * $Log: BinaryTest.java,v $ + * Revision 1.1 2005/03/23 07:22:42 bailly + * created transductions package + * corrected EpsilonRemover + * added some tests + * removed DirectedGRaph Interface from Automaton + * + * Revision 1.1 2004/09/21 11:50:28 bailly + * added interface BinaryTest + * added class for testing automaton equivalence (isomorphism of normalized automata) + * added computation of RE from Automaton + * +*/ \ No newline at end of file diff --git a/extra/jautomata-core/rationals/properties/Bisimilar.java b/extra/jautomata-core/rationals/properties/Bisimilar.java new file mode 100755 index 0000000000..6c2bcb0a3a --- /dev/null +++ b/extra/jautomata-core/rationals/properties/Bisimilar.java @@ -0,0 +1,34 @@ +/* + * (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.properties; + +import rationals.Builder; +import rationals.Transition; + +/** + * @version $Id: Bisimilar.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Bisimilar<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> extends AreEquivalent<L, Tr, T> { + + /** + * @param r + */ + public Bisimilar() { + super(new Bisimulation<L, Tr, T>()); + } + +} diff --git a/extra/jautomata-core/rationals/properties/Bisimulation.java b/extra/jautomata-core/rationals/properties/Bisimulation.java new file mode 100755 index 0000000000..53081ee767 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/Bisimulation.java @@ -0,0 +1,139 @@ +/* + * (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.properties; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Couple; +import rationals.State; +import rationals.Transition; + +/** + * This method computes the (strong) bisimulation relation between two states. + * + * @version $Id: Bisimulation.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Bisimulation<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements Relation<L, Tr, T> { + + private Automaton<L, Tr, T> a1; + + private Automaton<L, Tr, T> a2; + + private Set<Couple> exp; + + /** + * Constructor with two automaton. + * This constructor effectively calls {@link setAutomata(Automaton,Automaton)}. + * + * @param automaton + * @param automaton2 + */ + public Bisimulation(Automaton<L, Tr, T> automaton, Automaton<L, Tr, T> automaton2) { + setAutomata(automaton,automaton2); + } + + /** + * Argument-less constructor. + * Note that this implies the method {@link setAutomata(Automaton,Automaton)} + * <strong>must</strong> be called before using this relation. + */ + public Bisimulation() { + } + + /* + * (non-Javadoc) + * + * @see rationals.tests.Relation#setAutomata(rationals.Automaton, + * rationals.Automaton) + */ + public void setAutomata(Automaton<L, Tr, T> a1, Automaton<L, Tr, T> a2) { + this.a1 = a1; + this.a2 = a2; + this.exp = new HashSet<>(); + } + + /* + * (non-Javadoc) + * + * @see rationals.tests.Relation#equivalence(rationals.State, + * rationals.State) + */ + public boolean equivalence(State q0a, State q0b) { + Couple cpl = new Couple(q0a, q0b); + /* check states are unknown */ + if (exp.contains(cpl)) + return true; + exp.add(cpl); + /* iterate over all transitions */ + Set<Transition<L>> tas = a1.delta(q0a); + Set<Transition<L>> tbs = a2.delta(q0b); + Iterator<Transition<L>> it = tas.iterator(); + while (it.hasNext()) { + Transition<L> tr = it.next(); + State ea = tr.end(); + /* check transition exists in b */ + Set<Transition<L>> tbsl = a2.delta(q0b, tr.label()); + if (tbsl.isEmpty()) + return false; + Iterator<Transition<L>> trb = tbsl.iterator(); + while (trb.hasNext()) { + Transition<L> tb = trb.next(); + /* mark transition as visited */ + tbs.remove(tb); + State eb = tb.end(); + if (!equivalence(ea, eb) && !trb.hasNext()) + return false; + } + } + /* checks all transitions from b has been visited */ + if (!tbs.isEmpty()) { + exp.remove(cpl); + return false; + } + /* OK */ + return true; + } + + /** + * Checks that all combination of states from nsa and nsb + * are bisimilar. + * + */ + public boolean equivalence(Set<State> nsa, Set<State> nsb) { + for(Iterator<State> i = nsa.iterator();i.hasNext();) { + State sa = i.next(); + for(Iterator<State> j = nsb.iterator();j.hasNext();) { + State sb = j.next(); + if(!equivalence(sa,sb)) + return false; + } + } + return true; + } + + /* (non-Javadoc) + * @see rationals.properties.Relation#getErrorTrace() + */ + public List<L> getErrorTrace() { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/properties/ContainsEpsilon.java b/extra/jautomata-core/rationals/properties/ContainsEpsilon.java new file mode 100755 index 0000000000..b15e1cf044 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/ContainsEpsilon.java @@ -0,0 +1,52 @@ +/* + * (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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.State; +import rationals.Transition; +import rationals.transformations.TransformationsToolBox; + +import java.util.Iterator; +import java.util.Set; + +/** + * Checks whether an automaton recognizes the empty word. This test assumes that + * the tested automaton does not contain epsilon (ie. <code>null</code>) + * transitions. + * + * @version $Id: ContainsEpsilon.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class ContainsEpsilon<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTest<L, Tr, T> { + + public boolean test(Automaton<L, Tr, T> a) { + Iterator<State> i = a.initials().iterator(); + Set<State> s = a.getStateFactory().stateSet(); + while (i.hasNext()) { + State st = i.next(); + if (st.isTerminal()) + return true; + s.add(st); + /* compute epsilon closure */ + Set<State> cl = TransformationsToolBox.epsilonClosure(s,a); + if(TransformationsToolBox.containsATerminalState(cl)) + return true; + } + return false; + } +} diff --git a/extra/jautomata-core/rationals/properties/IsDeterministic.java b/extra/jautomata-core/rationals/properties/IsDeterministic.java new file mode 100755 index 0000000000..785d3ffc0f --- /dev/null +++ b/extra/jautomata-core/rationals/properties/IsDeterministic.java @@ -0,0 +1,64 @@ +/* + * (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.properties; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import rationals.Automaton; +import rationals.Builder; +import rationals.State; +import rationals.Transition; + +/** + * A property that checks a given automaton is deterministic. + * <p> + * An automaton <code>(X,Q,I,T,D)</code> is deterministic iff : + * <ul> + * <li><code>|I| = 1</code></li> + * <li><code>D is a function from (Q x X) -> Q</code> + * <li><code>X</code> does not contains the symbol <code>epsilon</code></li> + * </ul> + * + * @version $Id: IsDeterministic.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class IsDeterministic<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTest<L, Tr, T> { + + /* (non-Javadoc) + * @see rationals.properties.UnaryTest#test(rationals.Automaton) + */ + public boolean test(Automaton<L, Tr, T> a) { + if(a.alphabet().contains(null)) + return false; + if(a.initials().size() > 1) + return false; + for(Iterator<State> it = a.states().iterator();it.hasNext();) { + State s = it.next(); + Set<L> tra = new HashSet<>(); + for(Iterator<Transition<L>> it2 = a.delta(s).iterator();it2.hasNext();) { + Transition<L> tr = it2.next(); + if(tra.contains(tr.label())) + return false; + else + tra.add(tr.label()); + } + } + return true; + } + +} diff --git a/extra/jautomata-core/rationals/properties/ModelCheck.java b/extra/jautomata-core/rationals/properties/ModelCheck.java new file mode 100755 index 0000000000..ddb4e82286 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/ModelCheck.java @@ -0,0 +1,76 @@ +/* + * (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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; +import rationals.transformations.Complement; +import rationals.transformations.Mix; +import rationals.transformations.Pruner; +import rationals.transformations.ToDFA; + +/** + * This class implements a basic model-checking algorithm. + * <p> + * The first automata is first complemented on its alphabet using the operation + * {@see rationals.transformations.Complement}. It is then synchronized with + * the second automaton using the {@see rationals.transformations.Mix} + * operation. + * <p> + * If the language produced is empty, then the test returns true which means that + * automaton <code>b</code> contains the language of <code>a</code>. Else, + * the language produced represents counterexamples of the property modelled by + * <code>a</code> in <code>b</code>: the test returns false. + * <p> + * The resulting automaton can be retrieved using the method + * {@see #counterExamples()}. + * + * @version $Id: ModelCheck.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class ModelCheck<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements BinaryTest<L, Tr, T> { + + private Automaton<L, Tr, T> cex; + + /* + * (non-Javadoc) + * + * @see rationals.properties.BinaryTest#test(rationals.Automaton, + * rationals.Automaton) + */ + public boolean test(Automaton<L, Tr, T> a, Automaton<L, Tr, T> b) { + Automaton<L, Tr, T> aDFA = new ToDFA<L, Tr, T>().transform(a); + Automaton<L, Tr, T> bDFA = new ToDFA<L, Tr, T>().transform(b); + Automaton<L, Tr, T> caDFA = new Complement<L, Tr, T>().transform(aDFA); + cex = new Pruner<L, Tr, T>().transform(new Mix<L, Tr, T>().transform(caDFA, bDFA)); + if (new isEmpty<L, Tr, T>().test(cex)) + return true; + else + return false; + } + + /** + * Return the automaton resulting from this test. + * + * @return an Automaton or null if + * {@see #test(rationals.Automaton,rationals.Automaton)}has not + * been called yet. + */ + public Automaton<L, Tr, T> counterExamples() { + return cex; + } +} diff --git a/extra/jautomata-core/rationals/properties/Relation.java b/extra/jautomata-core/rationals/properties/Relation.java new file mode 100755 index 0000000000..e657e6674e --- /dev/null +++ b/extra/jautomata-core/rationals/properties/Relation.java @@ -0,0 +1,77 @@ +/* + * (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.properties; + +import java.util.List; +import java.util.Set; + +import rationals.Automaton; +import rationals.Builder; +import rationals.State; +import rationals.Transition; + +/** + * An interface for computing equivalences between automata. + * + * This interface allows definition of various relation between + * states. + * + * @version $Id: Relation.java 2 2006-08-24 14:41:48Z oqube $ + */ +public interface Relation<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + + /** + * Sets the context for computing the relation. + * This method must be called before {@link equivalent(State,State)}. + * + * @param a1 + * @param a2 + */ + void setAutomata(Automaton<L, Tr, T> a1, Automaton<L, Tr, T> a2); + + /** + * Assert the equivalence between two states. + * This method returns true if and only if the two states + * are in relation. + * + * @param s1 + * @param s2 + * @return true is s1 ~ s2, false otherwise + */ + boolean equivalence(State s1, State s2); + + /** + * Asset the equivalence between two set of states. + * This method returns true if and only if the two states set + * are equivalent. + * + * @param nsa a Set of State objects from a + * @param nsb a Set of State objects from b + * @return true if nsa is equivalent to nsb + */ + public boolean equivalence(Set<State> nsa, Set<State> nsb); + + /** + * Returns the trace of labels that lead to an error. + * + * This is an optional operation, and subclasses may throw {@link UnsupportedOperationException}/ + * + * @return a List of objects or null. + */ + public List<L> getErrorTrace() throws UnsupportedOperationException; + +} diff --git a/extra/jautomata-core/rationals/properties/Similar.java b/extra/jautomata-core/rationals/properties/Similar.java new file mode 100755 index 0000000000..e36756de34 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/Similar.java @@ -0,0 +1,34 @@ +/* + * (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.properties; + +import rationals.Builder; +import rationals.Transition; + +/** + * @version $Id: Similar.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Similar<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> extends AreEquivalent<L, Tr, T> { + + /** + * @param r + */ + public Similar() { + super(new Simulation<L, Tr, T>()); + } + +} diff --git a/extra/jautomata-core/rationals/properties/Simulation.java b/extra/jautomata-core/rationals/properties/Simulation.java new file mode 100755 index 0000000000..567141fcfd --- /dev/null +++ b/extra/jautomata-core/rationals/properties/Simulation.java @@ -0,0 +1,144 @@ +/* + * (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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Couple; +import rationals.State; +import rationals.Transition; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +/** + * This class implements (strong) simulation equivalence between + * two automata. + * <p /> + * Given two automata <code>A=(Qa,q0a,Ta,Sa,deltaA)</code> and <code>B=(Qb,q0b,Tb,Sb,deltaB)</code>, + * a simulation S of A by B is a relation in <code>Qa x Qb</code> + * s.t., whenever <code>(qa,qb) \in S</code>, + * <ul> + * <li>for each <code>(qa,a,qa') \in deltaA</code>, exists <code>(qb,a,qb')\in deltaB</code> + * and <code>(qa',qb') \in S</code>,</li> + * </ul> + * B is a simulation of A iff <code>q0b ~ q0a</code>. + * <p /> + * Note that in general, a simulation is not symetric. A symmetric + * simulation is of course a bisimulation. + * + * @version $Id: Simulation.java 2 2006-08-24 14:41:48Z oqube $ + * @see rationals.properties.Bisimulation + */ +public class Simulation<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements Relation<L, Tr, T> { + + private Automaton<L, Tr, T> a1; + + private Automaton<L, Tr, T> a2; + + private Set<Couple> exp; + + /** + * Constructor with two automataon. + * This constructor effectively calls {@link #setAutomata(Automaton,Automaton)}. + * + * @param automaton + * @param automaton2 + */ + public Simulation(Automaton<L, Tr, T> automaton, Automaton<L, Tr, T> automaton2) { + setAutomata(automaton,automaton2); + } + + + /* + * (non-Javadoc) + * + * @see rationals.tests.Relation#setAutomata(rationals.Automaton, + * rationals.Automaton) + */ + public void setAutomata(Automaton<L, Tr, T> a1, Automaton<L, Tr, T> a2) { + this.a1 = a1; + this.a2 = a2; + this.exp = new HashSet<>(); + } + + public Simulation() {} + + /** + * Checks that all combination of states from nsa and nsb + * are bisimilar. + * + */ + public boolean equivalence(Set<State> nsa, Set<State> nsb) { + for(Iterator<State> i = nsa.iterator();i.hasNext();) { + State sa = i.next(); + for(Iterator<State> j = nsb.iterator();j.hasNext();) { + State sb = j.next(); + if(!equivalence(sa,sb)) + return false; + } + } + return true; + } + + /* + * (non-Javadoc) + * + * @see rationals.tests.Relation#equivalence(rationals.State, + * rationals.State) + */ + public boolean equivalence(State q0a, State q0b) { + Couple cpl = new Couple(q0a, q0b); + /* check states are unknown */ + if (exp.contains(cpl)) + return true; + exp.add(cpl); + /* iterate over all transitions */ + Set<Transition<L>> tas = a1.delta(q0a); + Set<Transition<L>> tbs = a2.delta(q0b); + Iterator<Transition<L>> it = tas.iterator(); + while (it.hasNext()) { + Transition<L> tr = it.next(); + State ea = tr.end(); + /* check transition exists in b */ + Set<Transition<L>> tbsl = a2.delta(q0b, tr.label()); + if (tbsl.isEmpty()) + return false; + Iterator<Transition<L>> trb = tbsl.iterator(); + while (trb.hasNext()) { + Transition<L> tb = trb.next(); + /* mark transition as visited */ + tbs.remove(tb); + State eb = tb.end(); + if (!equivalence(ea, eb) && !trb.hasNext()) + return false; + } + } + /* OK */ + return true; + } + + /* (non-Javadoc) + * @see rationals.properties.Relation#getErrorTrace() + */ + public List<L> getErrorTrace() { + throw new UnsupportedOperationException(); + } + +} diff --git a/extra/jautomata-core/rationals/properties/TraceEquivalence.java b/extra/jautomata-core/rationals/properties/TraceEquivalence.java new file mode 100755 index 0000000000..65b3e4ee3e --- /dev/null +++ b/extra/jautomata-core/rationals/properties/TraceEquivalence.java @@ -0,0 +1,161 @@ +/* + * (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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.State; +import rationals.Transition; +import rationals.transformations.StatesCouple; +import rationals.transformations.TransformationsToolBox; + +import java.util.*; + +/** + * A class that compute trace equivalence relation between two states. This + * class checks whether two states from two automata are trace equivalent, which + * simply means they recognize the same prefix of languages. + * <p> + * This class effectively computes the deterministic form of the two given + * automata. + * + * @version $Id: TraceEquivalence.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class TraceEquivalence<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements Relation<L, Tr, T> { + + private Automaton<L, Tr, T> a1; + + private Automaton<L, Tr, T> a2; + + private List<L> errorTrace; + + /* + * (non-Javadoc) + * + * @see rationals.tests.Relation#setAutomata(rationals.Automaton, + * rationals.Automaton) + */ + public void setAutomata(Automaton<L, Tr, T> a1, Automaton<L, Tr, T> a2) { + this.a1 = a1; + this.a2 = a2; + } + + /* + * (non-Javadoc) + * + * @see rationals.tests.Relation#equivalence(rationals.State, + * rationals.State) + */ + public boolean equivalence(State q0a, State q0b) { + /* compute epsilon closures on states */ + Set<State> nsa = a1.getStateFactory().stateSet(); + Set<State> nsb = a2.getStateFactory().stateSet(); + nsa.add(q0a); + nsb.add(q0b); + /* check equivalence on sets */ + return equivalence(nsa, nsb); + } + + /* + * (non-Javadoc) + * + * @see rationals.properties.Relation#equivalence(java.util.Set, + * java.util.Set) + */ + public boolean equivalence(Set<State> nsa, Set<State> nsb) { + /* sets of explored states */ + Stack<StatesCouple> todo = new Stack<>(); + /* current traces for failure */ + Stack<L> labels = new Stack<>(); + Stack<L> trace = new Stack<>(); + Set<StatesCouple> done = new HashSet<>(); + todo.push(new StatesCouple(nsa, nsb)); + labels.push(null); // Needed to avoid empty stack + do { + StatesCouple cpl = todo.pop(); + L lbl = labels.pop(); + Set<State> sa = TransformationsToolBox.epsilonClosure(cpl.sa, a1); + Set<State> sb = TransformationsToolBox.epsilonClosure(cpl.sb, a2); + if (done.contains(cpl)) { + L top = trace.peek(); + // Bug fix: two different transitions to the same state can cause the trace to become empty + if (top == null ? lbl == null : top.equals(lbl)) trace.pop(); + continue; + } else { + trace.push(lbl); + } + done.add(cpl); + /* compute set of transitions */ + List<Transition<L>> tas = new ArrayList<>(a1.delta(sa)); + List<Transition<L>> tbs = new ArrayList<>(a2.delta(sb)); + /* map from letters to set of states */ + Map<L, Set<State>> am = new HashMap<>(); + Map<L, Set<State>> bm = new HashMap<>(); + /* compute set of states reached for each letter */ + mapAlphabet(tas, am, a1); + mapAlphabet(tbs, bm, a2); + Iterator<Map.Entry<L, Set<State>>> it2 = am.entrySet().iterator(); + while (it2.hasNext()) { + Map.Entry<L, Set<State>> me = it2.next(); + L l = me.getKey(); + Set<State> as = me.getValue(); + Set<State> bs = bm.remove(l); + if (bs == null) { + this.errorTrace = trace; + this.errorTrace.add(l); + return false; + } + StatesCouple sc = new StatesCouple(as, bs); + todo.push(sc); + labels.push(l); + } + if (!bm.isEmpty()) { + this.errorTrace = trace; + this.errorTrace.addAll(bm.keySet()); + return false; + } + } while (!todo.isEmpty()); + return true; + } + + /** + * @param tas + * @param am + */ + public void mapAlphabet(List<Transition<L>> tas, Map<L, Set<State>> am, Automaton<L, Tr, T> a) { + /* compute set of states for each letter */ + while (!tas.isEmpty()) { + Transition<L> tr = tas.remove(0); + L l = tr.label(); + if (l == null) + continue; + Set<State> as = am.get(l); + if (as == null) { + as = a.getStateFactory().stateSet(); + am.put(l, as); + } + as.add(tr.end()); + } + } + + /** + * @return Returns the errorTrace. + */ + public List<L> getErrorTrace() { + return errorTrace; + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/properties/TraceEquivalent.java b/extra/jautomata-core/rationals/properties/TraceEquivalent.java new file mode 100755 index 0000000000..f4bbc10eb8 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/TraceEquivalent.java @@ -0,0 +1,34 @@ +/* + * (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.properties; + +import rationals.Builder; +import rationals.Transition; + +/** + * @version $Id: TraceEquivalent.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class TraceEquivalent<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> extends AreEquivalent<L, Tr, T> { + + /** + * @param r + */ + public TraceEquivalent() { + super(new TraceEquivalence<L, Tr, T>()); + } + +} diff --git a/extra/jautomata-core/rationals/properties/UnaryTest.java b/extra/jautomata-core/rationals/properties/UnaryTest.java new file mode 100755 index 0000000000..0c4083bf04 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/UnaryTest.java @@ -0,0 +1,25 @@ +/* + * (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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; + +public interface UnaryTest<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + public boolean test(Automaton<L, Tr, T> a) ; +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/properties/WeakBisimulation.java b/extra/jautomata-core/rationals/properties/WeakBisimulation.java new file mode 100755 index 0000000000..9e4837b021 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/WeakBisimulation.java @@ -0,0 +1,70 @@ +/* + * (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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.State; +import rationals.Transition; +import rationals.transformations.EpsilonTransitionRemover; + +import java.util.List; +import java.util.Set; + +/** + * This method computes the weak bisimulation relation between two states. + * The weak bisimulation is computed as (strong) bisimulation between the two + * given automata where all epsilon transitions have been removed. + * + * @version $Id: WeakBisimulation.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class WeakBisimulation<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements Relation<L, Tr, T> { + + private Bisimulation<L, Tr, T> bisim; + + /* + * (non-Javadoc) + * + * @see rationals.tests.Relation#setAutomata(rationals.Automaton, + * rationals.Automaton) + */ + public void setAutomata(Automaton<L, Tr, T> a1, Automaton<L, Tr, T> a2) { + EpsilonTransitionRemover<L, Tr, T> er = new EpsilonTransitionRemover<>(); + this.bisim = new Bisimulation<>(er.transform(a1), er.transform(a2)); + } + + /* + * (non-Javadoc) + * + * @see rationals.tests.Relation#equivalence(rationals.State, + * rationals.State) + */ + public boolean equivalence(State q0a, State q0b) { + return bisim.equivalence(q0a, q0b); + } + + public boolean equivalence(Set<State> nsa, Set<State> nsb) { + return bisim.equivalence(nsa, nsb); + } + + /* (non-Javadoc) + * @see rationals.properties.Relation#getErrorTrace() + */ + public List<L> getErrorTrace() { + throw new UnsupportedOperationException(); + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/properties/WeaklyBisimilar.java b/extra/jautomata-core/rationals/properties/WeaklyBisimilar.java new file mode 100755 index 0000000000..abdbbaa428 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/WeaklyBisimilar.java @@ -0,0 +1,35 @@ +/* + * (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.properties; + +import rationals.Builder; +import rationals.Transition; + +/** + * @author nono + * @version $Id: WeaklyBisimilar.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class WeaklyBisimilar<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> extends AreEquivalent<L, Tr, T> { + + /** + * @param r + */ + public WeaklyBisimilar() { + super(new WeakBisimulation<L, Tr, T>()); + } + +} diff --git a/extra/jautomata-core/rationals/properties/isEmpty.java b/extra/jautomata-core/rationals/properties/isEmpty.java new file mode 100755 index 0000000000..772ed06797 --- /dev/null +++ b/extra/jautomata-core/rationals/properties/isEmpty.java @@ -0,0 +1,37 @@ +/* + * (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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.State; +import rationals.Transition; + +import java.util.Iterator; + + +public class isEmpty<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTest<L, Tr, T> { + + public boolean test(Automaton<L, Tr, T> a) { + Iterator<State> i = a.accessibleStates().iterator() ; + while (i.hasNext()) { + if (i.next().isTerminal()) return false ; + } + return true ; + } + +} diff --git a/extra/jautomata-core/rationals/properties/isNormalized.java b/extra/jautomata-core/rationals/properties/isNormalized.java new file mode 100755 index 0000000000..4eff572f0d --- /dev/null +++ b/extra/jautomata-core/rationals/properties/isNormalized.java @@ -0,0 +1,45 @@ +/* + * (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.properties; + +import rationals.Automaton; +import rationals.Builder; +import rationals.State; +import rationals.Transition; + +/** + * Tests if an automaton is normalized. + * + * @see rationals.transformations.Normalizer + * @author nono + * @version $Id: isNormalized.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class isNormalized<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTest<L, Tr, T> { + public boolean test(Automaton<L, Tr, T> a) { + if (a.initials().size() != 1) + return false; + if (a.terminals().size() != 1) + return false; + State e = a.initials().iterator().next(); + if (a.deltaMinusOne(e).size() > 0) + return false; + e = a.terminals().iterator().next(); + if (a.delta(e).size() > 0) + return false; + return true; + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/Accessible.java b/extra/jautomata-core/rationals/transformations/Accessible.java new file mode 100755 index 0000000000..2f32a626f5 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Accessible.java @@ -0,0 +1,97 @@ +/* + * (C) Copyright 2004 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 java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import rationals.Automaton; +import rationals.Builder; +import rationals.NoSuchStateException; +import rationals.State; +import rationals.Transition; + +/** + * Compute the automaton accessible from a given state + * @author bailly + * @version $Id: Accessible.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Accessible<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + private State state; + + /** + * The state we must start exploration from + * + */ + public Accessible(State s) { + this.state = s; + } + + /* (non-Javadoc) + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Set<Transition<L>> trs = a.delta(); + Automaton<L, Tr, T> b = new Automaton<>(); + Map<State, State> stmap = new HashMap<>(); + /* initial state = state */ + State ns = b.addState(true, state.isTerminal()); + stmap.put(state, ns); + explore(state, stmap, a, b); + /* explore a and remove transitions from trs */ + Iterator<Transition<L>> it = trs.iterator(); + while(it.hasNext()) { + Transition<L> tr = it.next(); + State nstart = stmap.get(tr.start()); + State nend = stmap.get(tr.end()); + if(nstart != null && nend != null) + try { + b.addTransition(new Transition<>(nstart,tr.label(),nend)); + } catch (NoSuchStateException e) { + System.err.println(e.getMessage()); + return null; + } + } + return b; + } + + /** + * Recursive function to explore transitions from a state + * @param state + * @param stmap + * @param b + */ + private void explore(State curstate, Map<State, State> stmap, Automaton<L, Tr, T> a, Automaton<L, Tr, T> b) { + Iterator<Transition<L>> it = a.delta(curstate).iterator(); + while(it.hasNext()) { + Transition<L> tr = it.next(); + State e = tr.end(); + State ne = stmap.get(e); + if(ne != null) + continue; + else { + ne = b.addState(e.isInitial(),e.isTerminal()); + stmap.put(e,ne); + explore(e,stmap,a,b); + } + } + } + +} diff --git a/extra/jautomata-core/rationals/transformations/BinaryTransformation.java b/extra/jautomata-core/rationals/transformations/BinaryTransformation.java new file mode 100755 index 0000000000..a7439d3750 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/BinaryTransformation.java @@ -0,0 +1,30 @@ +/* + * (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.Transition; + +/** + * A generic interface for binary operations between two automata. + * + * @version $Id: BinaryTransformation.java 2 2006-08-24 14:41:48Z oqube $ + */ +public interface BinaryTransformation<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a , Automaton<L, Tr, T> b) ; +} diff --git a/extra/jautomata-core/rationals/transformations/Complement.java b/extra/jautomata-core/rationals/transformations/Complement.java new file mode 100755 index 0000000000..67c6c4945c --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Complement.java @@ -0,0 +1,93 @@ +/* + * (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.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.Builder; +import rationals.NoSuchStateException; +import rationals.State; +import rationals.Transition; + +/** + * A transformation that computes the complement of an automaton. + * <p> + * This transformation computes the complement of an automaton: Terminal states + * are inverted and missing transitions are added. + * + * @author nono + * @version $Id: Complement.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Complement<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + /* + * (non-Javadoc) + * + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Automaton<L, Tr, T> ret = new Automaton<>(); + List<State> todo = new ArrayList<>(); + Map<State, State> sm = new HashMap<>(); + Set<State> done = new HashSet<>(); + Set<State> s = a.initials(); + todo.addAll(s); + while (!todo.isEmpty()) { + State st = todo.remove(0); + State ns = sm.get(st); + if (ns == null) { + ns = ret.addState(st.isInitial(), !st.isTerminal()); + sm.put(st, ns); + } + done.add(st); + for (Iterator<L> it = a.alphabet().iterator(); it.hasNext();) { + L l = it.next(); + Set<Transition<L>> ends = a.delta(st, l); + if (ends.isEmpty()) + try { + ret.addTransition(new Transition<>(ns, l, ns)); + } catch (NoSuchStateException e) { + } + else { + for (Iterator<Transition<L>> i = ends.iterator(); i.hasNext();) { + State end = i.next().end(); + State ne = sm.get(end); + if (ne == null) { + ne = ret.addState(end.isInitial(), !end.isTerminal()); + sm.put(end, ne); + todo.add(end); + } + try { + ret.addTransition(new Transition<>(ns, l, ne)); + } catch (NoSuchStateException e) { + } + } + } + + } + } + return ret; + } + +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/CompleteNop.java b/extra/jautomata-core/rationals/transformations/CompleteNop.java new file mode 100755 index 0000000000..4105186a6a --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/CompleteNop.java @@ -0,0 +1,91 @@ +/* + * (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.transformations; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import rationals.Automaton; +import rationals.Builder; +import rationals.NoSuchStateException; +import rationals.State; +import rationals.Transition; + +/** + * This methods completes the transitions in an Automaton w.r.t. to an + * arbitrary alphabet. + * <p> + * That is, for each state <code>q</code> and for each letter <code>l</code> + * in <code>ioa</code>'s alphabet, if there is no transition labelled with + * <code>l</code> starting from <code>q</code>, it adds a transition + * <code>(q,l,q)</code> to this automaton. + * <p> + * The semantic of this completion scheme should be compared with + * {@link rationals.transformations.CompleteSink}which completes an automaton + * by adding a sink state. + * <p> + * + * @version $Id: CompleteNop.java 6 2006-08-30 08:56:44Z oqube $ + */ +public class CompleteNop<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + private Set<L> alphabet; + + public CompleteNop(Set<L> alphabet) { + this.alphabet = alphabet; + } + + /* + * (non-Javadoc) + * + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Automaton<L, Tr, T> b = new Automaton<>(); + Map<State, State> qm = new HashMap<>(); + for (Iterator<State> i = a.states().iterator(); i.hasNext();) { + State q = i.next(); + State p = b.addState(q.isInitial(), q.isTerminal()); + qm.put(q, p); + } + Set<L> alph = new HashSet<>(); + for (Iterator<State> it = a.states().iterator(); it.hasNext();) { + State q = it.next(); + alph.addAll(alphabet); + for (Iterator<Transition<L>> i2 = a.delta(q).iterator(); i2.hasNext();) { + Transition<L> tr = i2.next(); + try { + b.addTransition(new Transition<>(qm.get(tr.start()), tr.label(), qm.get(tr.end()))); + } catch (NoSuchStateException e) { + } + alph.remove(tr.label()); + } + for (Iterator<L> i2 = alph.iterator(); i2.hasNext();) { + try { + b.addTransition(new Transition<L>(q, i2.next(), q)); + } catch (NoSuchStateException e) { + } + } + alph.clear(); + } + return b; + } + +} diff --git a/extra/jautomata-core/rationals/transformations/Concatenation.java b/extra/jautomata-core/rationals/transformations/Concatenation.java new file mode 100755 index 0000000000..86ef5cf5c3 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Concatenation.java @@ -0,0 +1,118 @@ +/* + * (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 rationals.properties.ContainsEpsilon; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Compute the concatenation of two automata. + * <ul> + * <li>C = A . B</li> + * <li>S(C) = S(A) U S(B)</li> + * <li>S0(C) = + * <ul> + * <li>S0(A), if not A contains epsilon,</li> + * <li>S0(A) U SO(B), otherwise</li> + * </ul> + * </li> + * <li>T(C) = + * <ul> + * <li>T(B), if not B contains epsilon,</li> + * <li>T(A) U T(B), otherwise</li> + * </ul> + * </li> + * <li>D(C) = D(A) U D(B) U { (s1,a,s2) | (s,a,s2) in D(B), s in S0(B),s1 in + * T(A) } - {(s,a,s2) in D(B), s in S0(B) }</li> + * </ul> + * + * @version $Id: Concatenation.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Concatenation<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements BinaryTransformation<L, Tr, T> { + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a, Automaton<L, Tr, T> b) { + Automaton<L, Tr, T> ap = new Normalizer<L, Tr, T>().transform(a); + Automaton<L, Tr, T> bp = new Normalizer<L, Tr, T>().transform(b); + ContainsEpsilon<L, Tr, T> ce = new ContainsEpsilon<L, Tr, T>(); + boolean ace = ce.test(a); + boolean bce = ce.test(b); + if (ap.states().size() == 0 && ace) + return b; + if (bp.states().size() == 0 && bce) + return a; + State junc = null; /* junction state */ + Automaton<L, Tr, T> c = new Automaton<>(); + Map<State, State> map = new HashMap<>(); + /* add all states from ap */ + Iterator<State> i1 = ap.states().iterator(); + while (i1.hasNext()) { + State e = i1.next(); + State n; + if (e.isInitial()) { + n = c.addState(true, ace && bce); + } else if(!e.isTerminal()) + n = c.addState(false, e.isTerminal() && bce); + else + continue; + map.put(e, n); + } + /* add states from bp */ + Iterator<State> i2 = bp.states().iterator(); + while (i2.hasNext()) { + State e = i2.next(); + State n; + if (!e.isInitial()) { + n = c.addState(false, e.isTerminal()); + map.put(e, n); + } + } + /* create junction state */ + junc = c.addState(ace,bce); + Iterator<Transition<L>> i3 = ap.delta().iterator(); + while (i3.hasNext()) { + Transition<L> t = i3.next(); + try { + if (t.end().isTerminal()) + c.addTransition(new Transition<>(map.get(t.start()), t.label(), junc)); + else + c.addTransition(new Transition<>(map.get(t.start()), t.label(), map.get(t.end()))); + } catch (NoSuchStateException x) { + } + + } + Iterator<Transition<L>> i4 = bp.delta().iterator(); + while (i4.hasNext()) { + Transition<L> t = i4.next(); + try { + if (t.start().isInitial()) + c.addTransition(new Transition<>(junc, t.label(), map.get(t.end()))); + else + c.addTransition(new Transition<>(map.get(t.start()), t.label(), map.get(t.end()))); + } catch (NoSuchStateException x) { + } + } + return c; + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/EpsilonTransitionRemover.java b/extra/jautomata-core/rationals/transformations/EpsilonTransitionRemover.java new file mode 100755 index 0000000000..1526fb319c --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/EpsilonTransitionRemover.java @@ -0,0 +1,110 @@ +/* + * (C) Copyright 2002 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.*; + +/** + * This class allows to remove epsilon transitions in an automaton. Epsilon + * transition are transitions (q , l , q') where l is null. + * + * @author Yves Roos + * @version 22032002 + */ +public class EpsilonTransitionRemover<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + /* + * (non-Javadoc) + * + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Automaton<L, Tr, T> ret = new Automaton<>(); /* resulting automaton */ + Map<HashValue<State>, State> sm = new HashMap<>(); + Set<HashValue<State>> done = new HashSet<>(); + List<HashValue<State>> todo = new ArrayList<>(); /* set of states to explore */ + Set<State> cur = TransformationsToolBox.epsilonClosure(a.initials(), a); + /* add cur as initial state of ret */ + State is = ret.addState(true,TransformationsToolBox.containsATerminalState(cur)); + HashValue<State> hv = new HashValue<>(cur); + sm.put(hv,is); + todo.add(hv); + do { + HashValue<State> s = todo.remove(0); + State ns = sm.get(s); + if(ns == null) { + ns = ret.addState(false,TransformationsToolBox.containsATerminalState(s.s)); + sm.put(s,ns); + } + /* set s as explored */ + done.add(s); + /* look for all transitions in s */ + Map<L, Set<State>> trm = instructions(a.delta(s.s),a); + Iterator<Map.Entry<L, Set<State>>> it = trm.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry<L, Set<State>> e = it.next(); + L o = e.getKey(); + Set<State> ar = e.getValue(); + /* compute closure of arrival set */ + ar = TransformationsToolBox.epsilonClosure(ar, a); + hv = new HashValue<>(ar); + /* retrieve state in new automaton from hashvalue */ + State ne = sm.get(hv); + if(ne == null) { + ne = ret.addState(false,TransformationsToolBox.containsATerminalState(ar)); + sm.put(hv,ne); + } + try { + /* create transition */ + ret.addTransition(new Transition<L>(ns,o,ne)); + } catch (NoSuchStateException e1) { + } + /* explore new state */ + if(!done.contains(hv)) + todo.add(hv); + } + } while (!todo.isEmpty()); + return ret; + } + + private Map<L, Set<State>> instructions(Set<Transition<L>> s, Automaton<L, Tr, T> a) { + Map<L, Set<State>> m = new HashMap<L, Set<State>>(); + Iterator<Transition<L>> it = s.iterator(); + while (it.hasNext()) { + Transition<L> tr = it.next(); + L l = tr.label(); + if (l != null) { + Set<State> st = m.get(l); + if (st == null) { + st = a.getStateFactory().stateSet(); + m.put(l,st); + } + /* add arrival state */ + st.add(tr.end()); + } + } + return m; + } + +} + diff --git a/extra/jautomata-core/rationals/transformations/HashValue.java b/extra/jautomata-core/rationals/transformations/HashValue.java new file mode 100755 index 0000000000..9fd2185449 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/HashValue.java @@ -0,0 +1,64 @@ +/* + * (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.transformations; + +import java.util.Set; + +/** + * A simple class for encapsulating sets s.t. they can be used + * efficiently in Set or HashMap. + * + * @author nono + * @version $Id: HashValue.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class HashValue<T> { + + public final int hash; + + public final Set<T> s; + + public HashValue(Set<T> s) { + this.s = s; + this.hash = s.hashCode(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (!(obj instanceof HashValue)) return false; + return ((HashValue<?>) obj).hash == hash; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return hash; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return s.toString(); + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/Identity.java b/extra/jautomata-core/rationals/transformations/Identity.java new file mode 100755 index 0000000000..fe03048455 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Identity.java @@ -0,0 +1,37 @@ +/* + * (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.transformations; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; + +/** + * A transformation that simply returns a clone of its argument. + * + * @version $Id: Identity.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Identity<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + /* (non-Javadoc) + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + return a.clone(); + } + +} diff --git a/extra/jautomata-core/rationals/transformations/InverseMorphism.java b/extra/jautomata-core/rationals/transformations/InverseMorphism.java new file mode 100755 index 0000000000..e89364350a --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/InverseMorphism.java @@ -0,0 +1,131 @@ +/* + * (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.transformations; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import rationals.Automaton; +import rationals.NoSuchStateException; +import rationals.State; +import rationals.Transition; + +/** + * A general class for applying inverse morphism on rational sets. + * <p> + * A morphism is constructed from a {@see java.util.Map} from letters to + * letters (ie. from Object to Object). An inverse morphism is then computed + * by inversing the given map. A morphism is usually surjective, which is + * not the case of an inverse morphism, unless of course it is also + * injective. This means that the image of a single letter may be a + * set of letters. + * </p> + * <p> + * + * </p> + * + * @author nono + * @version $Id: InverseMorphism.java 2 2006-08-24 14:41:48Z oqube $ + * @see rationals.transformations.Morphism + */ +public class InverseMorphism implements UnaryTransformation { + + private Map morph; + + public InverseMorphism(Map m) { + this.morph = inverse(m); + } + + /* + * create inverse mapping from given map. + * The key are letters (Object) and the values + * are sets of letters (Set). + */ + private Map inverse(Map m) { + Map inv = new HashMap(); + for(Iterator i = m.entrySet().iterator();i.hasNext();) { + Map.Entry e = (Map.Entry)i.next(); + Object v = e.getValue(); + Object k = e.getKey(); + Set s = (Set)inv.get(v); + if(s == null) { + s = new HashSet(); + inv.put(v,s); + } + s.add(k); + } + return inv; + } + + /* (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(); + Set s = (Set)morph.get(lbl); + if(s == null) + try { + b.addTransition(new Transition(nss,lbl,nse)); + } catch (NoSuchStateException e) { + } + else + try { + for(Iterator j = s.iterator();j.hasNext();) + b.addTransition(new Transition(nss,j.next(),nse)); + } catch (NoSuchStateException e1) { + } + } + // handle epsilon's image + Set s = (Set)morph.get(null); + if(s != null) { + // append auto transition to each state + for(Iterator i = b.states().iterator();i.hasNext();){ + State st = (State)i.next(); + for(Iterator j = s.iterator();j.hasNext();) { + Object o = j.next(); + try { + if(o != null) + b.addTransition(new Transition(st,o,st)); + } catch (NoSuchStateException e) { + } + } + } + } + return b; + } + +} diff --git a/extra/jautomata-core/rationals/transformations/Mix.java b/extra/jautomata-core/rationals/transformations/Mix.java new file mode 100755 index 0000000000..a86fea3332 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Mix.java @@ -0,0 +1,194 @@ +/* + * (C) Copyright 2002 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.*; + +import java.util.*; + +/** + * 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<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements BinaryTransformation<L, Tr, T> { + + private Synchronization<L> 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<L, Tr, T> transform(Automaton<L, Tr, T> a, Automaton<L, Tr, T> b) { + Automaton<L, Tr, T> ret = (Automaton<L, Tr, T>) new Automaton(); + // FIXME: Potentially unsafe cast, but adding generics reveals an inconsistency in the APIs + ret.setBuilder((T) new TransitionBuilder<L>()); + return transformTo(a, b, ret); + } + + /** + * Compute transformation and stores the result in the given automaton. + * + * @param a + * @param b + * @param ret + * @return the automaton {@code ret} containing the result of the + * transformation. + */ + public Automaton<L, Tr, T> transformTo(Automaton<L, Tr, T> a, Automaton<L, Tr, T> b, Automaton<L, Tr, T> ret) { + Set alph = synchronization.synchronizable(a.alphabet(), b.alphabet()); + /* check alphabets */ + Map<StatesCouple, State> amap = (Map<StatesCouple, State> )(new HashMap()); + //Map<StatesCouple, State> bmap = (Map<StatesCouple, State>)new HashMap(); + List<StatesCouple> todo = (List<StatesCouple>)new ArrayList(); + Set<StatesCouple> done = (Set<StatesCouple>)(new HashSet()); + Set<State> as = TransformationsToolBox.epsilonClosure(a.initials(), a); + Set<State> 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 = todo.remove(0); + from = amap.get(couple); + if (done.contains(couple)) + continue; + done.add(couple); + /* get transition sets */ + Map<L, Set<State>> tam = TransformationsToolBox.mapAlphabet(a.delta(couple.sa), a); + Map<L, Set<State>> tbm = TransformationsToolBox.mapAlphabet(b.delta(couple.sb), b); + /* create label map for synchronized trans */ + Map<L, StatesCouple> tcm = new HashMap(); + /* unsynchronizable transitions in A */ + for (Iterator<Map.Entry<L, Set<State>>> i = tam.entrySet().iterator(); i.hasNext();) { + Map.Entry<L, Set<State>> me = i.next(); + L l = me.getKey(); + as = me.getValue(); + if (!alph.contains(l)) { + Set<State> asc = TransformationsToolBox.epsilonClosure(as, a); + tcm.put(l, sc = new StatesCouple(asc, couple.sb)); + State to = amap.get(sc); + makeNewState(ret, amap, sc, to); + todo.add(sc); + i.remove(); + } + } + /* unsynchronizable transition(s) in B */ + for (Iterator<Map.Entry<L, Set<State>>> i = tbm.entrySet().iterator(); i.hasNext();) { + Map.Entry<L, Set<State>> me = i.next(); + L l = me.getKey(); + bs = me.getValue(); + if (!alph.contains(l)) { + Set<State> bsc = TransformationsToolBox.epsilonClosure(bs, b); + tcm.put(l, sc = new StatesCouple(couple.sa, bsc)); + State to = amap.get(sc); + makeNewState(ret, amap, sc, to); + todo.add(sc); + i.remove(); + } + } + /* + * there remains in tam and tbm only possibly synchronizing + * transitions + */ + for (Iterator<Map.Entry<L, Set<State>>> i = tam.entrySet().iterator(); i.hasNext();) { + Map.Entry<L, Set<State>> me = i.next(); + L l = me.getKey(); + as = me.getValue(); + for (Iterator<Map.Entry<L, Set<State>>> j = tbm.entrySet().iterator(); j.hasNext();) { + Map.Entry<L, Set<State>> mbe = j.next(); + L k = mbe.getKey(); + bs = mbe.getValue(); + L sy = synchronization.synchronize(l, k); + if (sy != null) { + Set<State> asc = TransformationsToolBox.epsilonClosure(as, a); + Set<State> bsc = TransformationsToolBox.epsilonClosure(bs, b); + tcm.put(sy, sc = new StatesCouple(asc, bsc)); + State to = amap.get(sc); + makeNewState(ret, amap, sc, to); + todo.add(sc); + } + } + } + /* + * + * create new transitions in return automaton, update maps + */ + for (Iterator<Map.Entry<L, StatesCouple>> i = tcm.entrySet().iterator(); i.hasNext();) { + Map.Entry<L, StatesCouple> me = i.next(); + L l = me.getKey(); + sc = me.getValue(); + State to = amap.get(sc); + makeNewState(ret, amap, sc, to); + try { + ret.build(from, l, to); + } catch (NoSuchStateException e) { + } + // ret.from(from).on(l).go(to); + } + } while (!todo.isEmpty()); + return ret; + } + + private void makeNewState(Automaton ret, Map amap, StatesCouple sc, State to) { + if (to == null) { + to = ret.addState(false, TransformationsToolBox + .containsATerminalState(sc.sa) + && TransformationsToolBox.containsATerminalState(sc.sb)); + amap.put(sc, to); + } + } + +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/Morphism.java b/extra/jautomata-core/rationals/transformations/Morphism.java new file mode 100755 index 0000000000..35da2eb14f --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Morphism.java @@ -0,0 +1,83 @@ +/* + * (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.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 general class for alphabetic morphism over automaton. + * <p> + * A morphism is constructed from a {@see java.util.Map} from letters to + * letters (ie. from Object to Object). To distinguish between explicit + * mapping to <code>null</code> and implicit identity, if a letter is mapped + * as is, then it should not be included as a key. + * + * @author nono + * @version $Id: Morphism.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Morphism implements UnaryTransformation { + + private Map morph; + + public Morphism(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 { + b.addTransition(new Transition(nss,morph.get(lbl),nse)); + } catch (NoSuchStateException e1) { + } + } + return b; + } + +} diff --git a/extra/jautomata-core/rationals/transformations/Normalizer.java b/extra/jautomata-core/rationals/transformations/Normalizer.java new file mode 100755 index 0000000000..392a41cadf --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Normalizer.java @@ -0,0 +1,104 @@ +/* + * (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 rationals.properties.ContainsEpsilon; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * A transformation that normalizes a given Automaton. + * <p> + * This transformation produces a new Automaton with the following features : + * <ol> + * <li>it has <em>one</em> start state and <em>one</em> end state,</li> + * <li>there is no incoming (resp. outgoing) transitions to (resp. from) the + * start (resp. end) state,</li> + * <li>the resultant automaton is then pruned ({@link Pruner}) to remove + * inaccessible states.</li> + * </ol> + * + * @author yroos + * @version $Id: Normalizer.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Normalizer<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Automaton<L, Tr, T> b = new Automaton<>(); + State ni = b.addState(true, false); + State nt = b.addState(false, true); + Map<State, State> map = new HashMap<State, State>(); + Iterator<State> i1 = a.states().iterator(); + while (i1.hasNext()) { + State st = i1.next(); + map.put(st, b.addState(false, false)); + } + /* add epsilon transition if contains epsilon */ + if (new ContainsEpsilon<L, Tr, T>().test(a)) + try { + b.addTransition(new Transition<L>(ni, null, nt)); + } catch (NoSuchStateException e) { + } + Iterator<Transition<L>> i2 = a.delta().iterator(); + while (i2.hasNext()) { + Transition<L> t = i2.next(); + if (t.start().isInitial() && t.end().isTerminal()) { + try { + b.addTransition(new Transition<L>(ni, t.label(), nt)); + } catch (NoSuchStateException x) { + } + } + if (t.start().isInitial()) { + try { + b.addTransition(new Transition<L>(ni, t.label(), map.get(t.end()))); + } catch (NoSuchStateException x) { + } + } + + if (t.end().isTerminal()) + try { + b.addTransition(new Transition<L>(map.get(t.start()), t.label(), nt)); + } catch (NoSuchStateException x) { + } + + try { + b.addTransition(new Transition<L>(map.get(t.start()), t.label(), map.get(t.end()))); + } catch (NoSuchStateException x) { + } + + } + b = new Pruner<L, Tr, T>().transform(b); + return b; + } +} + +/* + * $Log: Normalizer.java,v $ Revision 1.4 2005/02/20 21:14:19 bailly added API + * for computing equivalence relations on automata + * + * Revision 1.3 2004/09/21 11:50:28 bailly added interface BinaryTest added + * class for testing automaton equivalence (isomorphism of normalized automata) + * added computation of RE from Automaton + * + */ \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/PartialCommutation.java b/extra/jautomata-core/rationals/transformations/PartialCommutation.java new file mode 100755 index 0000000000..4311b009f3 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/PartialCommutation.java @@ -0,0 +1,34 @@ +/* + * (C) Copyright 2013 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 java.util.Set; + +public class PartialCommutation implements UnaryTransformation{ + private final Set commutingLetters; + + public PartialCommutation(Set commutingLetters) { + this.commutingLetters = commutingLetters; + } + + public Automaton transform(Automaton a) { + Automaton b = new Automaton(); + return a; + }; +} diff --git a/extra/jautomata-core/rationals/transformations/PrefixClosure.java b/extra/jautomata-core/rationals/transformations/PrefixClosure.java new file mode 100755 index 0000000000..2becec3923 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/PrefixClosure.java @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2004 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 java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import rationals.Automaton; +import rationals.NoSuchStateException; +import rationals.State; +import rationals.Transition; + +/** + * Computes the prefix closure of given automaton. + * <p> + * The resulting automaton is simply the starting automaton with all states made + * terminal. + * <ul> + * <li>C = Pref(A)</li> + * <li>S(C) = S(A)</li> + * <li>S0(C) = S0(A)</li> + * <li>T(C) = S(A)</li> + * <li>D(C) = D(A)</li> + * </ul> + * + * @author nono + * @version $Id: PrefixClosure.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class PrefixClosure implements UnaryTransformation { + + /* + * (non-Javadoc) + * + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton transform(Automaton a) { + Automaton ret = new Automaton(); + Map sm = new HashMap(); + for (Iterator it = a.states().iterator(); it.hasNext();) { + State st = (State) it.next(); + State sr = ret.addState(st.isInitial(), true); + sm.put(st, sr); + } + /* add all transitions */ + for (Iterator it = a.delta().iterator(); it.hasNext();) { + Transition tr = (Transition) it.next(); + try { + ret.addTransition(new Transition((State) sm.get(tr.start()), tr + .label(), (State) sm.get(tr.end()))); + } catch (NoSuchStateException e) { + } + } + return ret; + } + +} + +/* + * $Log: PrefixClosure.java,v $ Revision 1.1 2004/11/15 12:39:14 bailly added + * PrefixClosure transformation + * + */ \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/Projection.java b/extra/jautomata-core/rationals/transformations/Projection.java new file mode 100755 index 0000000000..3af2bac34d --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Projection.java @@ -0,0 +1,84 @@ +/* + * (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.transformations; + +import rationals.Automaton; +import rationals.NoSuchStateException; +import rationals.State; +import rationals.Transition; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * This class computes the projection of an Automaton on given alphabet. The + * projection alphabet is set by the class's constructor. + * <p /> + * The algorithm is verys simple: All transitions which are not labelled + * with letters from the projection alphabet are transformed into + * <code>null</code> transitions. The resulting automaton is obviously no + * more deterministic if the automaton <code>a</code> was. + * + * @author nono + * @version $Id: Projection.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Projection implements UnaryTransformation { + + private Set alphabet; + + public Projection(Set alphabet) { + this.alphabet = alphabet; + } + + /* + * (non-Javadoc) + * + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton transform(Automaton a) { + Automaton b = new Automaton(); + Map smap = new HashMap(); + Iterator it = a.delta().iterator(); + while (it.hasNext()) { + Transition tr = (Transition) it.next(); + State os = tr.start(); + State oe = tr.end(); + Object l = tr.label(); + /* check states exist */ + State ns = (State) smap.get(os); + State ne = (State) smap.get(oe); + if (ns == null) + smap.put(os, ns = b.addState(os.isInitial(), os.isTerminal())); + if (ne == null) + smap.put(oe, ne = b.addState(oe.isInitial(), oe.isTerminal())); + /* check label is in alphabet */ + if (alphabet.contains(l)) + try { + b.addTransition(new Transition(ns, l, ne)); + } catch (NoSuchStateException e) { + } + else + try { + b.addTransition(new Transition(ns, null, ne)); + } catch (NoSuchStateException e1) { + } + } + return b; + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/Pruner.java b/extra/jautomata-core/rationals/transformations/Pruner.java new file mode 100755 index 0000000000..182263dab7 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Pruner.java @@ -0,0 +1,57 @@ +/* + * (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.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Removes states that neither accessible nor coaccessible. + * + * @version $Id: Pruner.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Pruner<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Map<State, State> conversion = new HashMap<>() ; + Iterator<State> i1 = a.accessibleAndCoAccessibleStates().iterator(); + Automaton<L, Tr, T> b = new Automaton<>() ; + while(i1.hasNext()) { + State e = i1.next() ; + conversion.put(e , b.addState(e.isInitial() , e.isTerminal())) ; + } + Iterator<Transition<L>> i2 = a.delta().iterator(); + while(i2.hasNext()) { + Transition<L> t = i2.next() ; + State bs = conversion.get(t.start()) ; + State be = conversion.get(t.end()) ; + if(bs == null || be == null) continue; + try { + b.addTransition(new Transition<>(bs, t.label(), be)); + } catch (NoSuchStateException x) {} + } + return b ; + } +} + diff --git a/extra/jautomata-core/rationals/transformations/RandomWalk.java.old b/extra/jautomata-core/rationals/transformations/RandomWalk.java.old new file mode 100755 index 0000000000..da6707b885 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/RandomWalk.java.old @@ -0,0 +1,89 @@ +/* + * (C) Copyright 2013 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 org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; +import rationals.Automaton; +import rationals.Transition; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; +import java.util.Set; + + +/** +Randomly walk an {@link rationals.Automaton} until some condition is met. + +<p>A random walk start from the initial(s) state of the given automaton and repeatedly builds a word that, firing a +transition, moving to given state, until the accumulated word matches some predicate. The condition is given as a +parameter of the random walk.</p> + */ +public class RandomWalk { + + private final Random random = new Random(); + + public List<Object> walk(Automaton a, Matcher<List<Object>> condition) { + Set states = a.initials(); + List<Object> word = new ArrayList<Object>(); + + while (true) { + Object l = selectALetter(a, states); + word.add(l); + states = a.step(states, l); + if (condition.matches(word)) { + break; + } + } + + return word; + } + + private Object selectALetter(Automaton a, Set states) { + Set<Transition> delta = a.delta(states); + + if (delta.isEmpty()) { + throw new IllegalStateException("cannot find a transition"); + } + + Object selected = null; + int ln = random.nextInt(delta.size()); + for (Transition transition : delta) { + if (ln-- == 0) { + selected = transition.label(); + break; + } + } + return selected; + } + + public static Matcher<List<Object>> hasLength(final int length) { + return new TypeSafeMatcher<List<Object>>() { + @Override + protected boolean matchesSafely(List<Object> objects) { + return objects.size() == length; + } + + @Override + public void describeTo(Description description) { + description.appendText("a word of length " + length); + } + }; + } +} diff --git a/extra/jautomata-core/rationals/transformations/Reducer.java b/extra/jautomata-core/rationals/transformations/Reducer.java new file mode 100755 index 0000000000..ba207bcfbf --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Reducer.java @@ -0,0 +1,140 @@ +/* + * (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; + } + +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/Reverser.java b/extra/jautomata-core/rationals/transformations/Reverser.java new file mode 100755 index 0000000000..a9c9bb1a0c --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Reverser.java @@ -0,0 +1,62 @@ +/* + * (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.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Computes the reversal of an Automaton. + * <p /> + * <ul> + * <li>C = A-</li> + * <li>S(C) = S(A)</li> + * <li>S0(C) = T(A)</li> + * <li>T(C) = S0(A)</li> + * <li>D(C) = { (s1,a,s2) | exists (s2,a,s1) in D(A) }</li> + * </ul> + * + * @version $Id: Reverser.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Reverser<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Automaton<L, Tr, T> b = new Automaton<>() ; + Map<State, State> map = new HashMap<>() ; + Iterator<State> i1 = a.states().iterator() ; + while(i1.hasNext()) { + State e = i1.next() ; + map.put(e , b.addState(e.isTerminal() , e.isInitial())) ; + } + Iterator<Transition<L>> i2 = a.delta().iterator() ; + while(i2.hasNext()) { + Transition<L> t = i2.next() ; + try { + b.addTransition(new Transition<L>(map.get(t.end()), t.label(), map.get(t.start()))); + } catch(NoSuchStateException x) {} + } + return b; + } +} diff --git a/extra/jautomata-core/rationals/transformations/Shuffle.java b/extra/jautomata-core/rationals/transformations/Shuffle.java new file mode 100755 index 0000000000..52fe8dff6d --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Shuffle.java @@ -0,0 +1,71 @@ +/* + * (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.transformations; + +import rationals.Automaton; +import rationals.Builder; +import rationals.Synchronization; +import rationals.Transition; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * This class implements the shuffle operator between two automatas. + * <ul> + * <li>C = A shuffle 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) or exists + * (s1b,a,s2b) in D(b) }</li> + * </ul> + * This class uses the Mix operator with an empty alphabet to compute the + * Shuffle. + * + * @author Arnaud Bailly + * @version $Id: Shuffle.java 2 2006-08-24 14:41:48Z oqube $ + * @see Mix + */ +public class Shuffle<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements BinaryTransformation<L, Tr, T> { + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a, Automaton<L, Tr, T> b) { + + Mix mix = new Mix(new Synchronization() { + public Object synchronize(Object t1, Object t2) { + return null; + } + + public Set synchronizable(Set a, Set b) { + return Collections.unmodifiableSet(new HashSet()); + } + + public Set synchronizing(Collection alphabets) { + // TODO Auto-generated method stub + return null; + } + + public boolean synchronizeWith(Object object, Set alph) { + // TODO Auto-generated method stub + return false; + } + }); + return mix.transform(a, b); + } +} diff --git a/extra/jautomata-core/rationals/transformations/SinkComplete.java b/extra/jautomata-core/rationals/transformations/SinkComplete.java new file mode 100755 index 0000000000..46239247e1 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/SinkComplete.java @@ -0,0 +1,89 @@ +/* + * (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.transformations; + +import rationals.Automaton; +import rationals.NoSuchStateException; +import rationals.State; +import rationals.Transition; + +import java.util.Iterator; +import java.util.Set; + +/** + * Complete an Automaton by adding a sink state and needed transitions. + * <p /> + * <ul> + * <li>C = complete(A)</li> + * <li>S(C) = S(A) U {sink}</li> + * <li>S0(C) = S0(A)</li> + * <li>T(C) = T(A)</li> + * <li>D(C) = D(A) U { (s1,a,sink)) | not exists (s1,a,s2) in D(A) }</li> + * </ul> + * + * @author nono + * @version $Id: SinkComplete.java 6 2006-08-30 08:56:44Z oqube $ + */ +public class SinkComplete implements UnaryTransformation { + + private Set alphabet; + + public SinkComplete(Set alphabet) { + this.alphabet = alphabet; + } + + public SinkComplete() { + } + + /* + * (non-Javadoc) + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton transform(Automaton a) { + Automaton b = (Automaton) a.clone(); + Set alph = (alphabet == null) ? b.alphabet() : alphabet; + State hole = null; + Set states = b.getStateFactory().stateSet(); + states.addAll(b.states()); + Iterator i = states.iterator(); + while (i.hasNext()) { + State e = (State) i.next(); + Iterator j = alph.iterator(); + while (j.hasNext()) { + Object label = j.next(); + if (b.delta(e, label).isEmpty()) { + if (hole == null) + hole = b.addState(false, false); + try { + b.addTransition(new Transition(e, label, hole)); + } catch (NoSuchStateException x) { + } + } + } + } + if (!(hole == null)) { + Iterator j = alph.iterator(); + while (j.hasNext()) { + try { + b.addTransition(new Transition(hole, j.next(), hole)); + } catch (NoSuchStateException x) { + } + } + } + return b; + } +} diff --git a/extra/jautomata-core/rationals/transformations/Star.java b/extra/jautomata-core/rationals/transformations/Star.java new file mode 100755 index 0000000000..743a0679b1 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Star.java @@ -0,0 +1,75 @@ +/* + * (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.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Compute the kleene-star closure of an automaton. + * + * @version $Id: Star.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Star<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + if (a.delta().size() == 0) + return Automaton.epsilonAutomaton(); + Automaton<L, Tr, T> b = new Automaton<>(); + State ni = b.addState(true, true); + State nt = b.addState(true, true); + Map<State, State> map = new HashMap<>(); + Iterator<State> i1 = a.states().iterator(); + while (i1.hasNext()) { + map.put(i1.next(), b.addState(false, false)); + } + Iterator<Transition<L>> i2 = a.delta().iterator(); + while (i2.hasNext()) { + Transition<L> t = i2.next(); + try { + b.addTransition(new Transition<>(map.get(t.start()), t.label(), map.get(t.end()))); + } catch (NoSuchStateException x) { + } + if (t.start().isInitial() && t.end().isTerminal()) { + try { + b.addTransition(new Transition<>(ni, t.label(), nt)); + b.addTransition(new Transition<>(nt, t.label(), ni)); + } catch (NoSuchStateException x) { + } + } else if (t.start().isInitial()) { + try { + b.addTransition(new Transition<>(ni, t.label(), map.get(t.end()))); + b.addTransition(new Transition<>(nt, t.label(), map.get(t.end()))); + } catch (NoSuchStateException x) { + } + } else if (t.end().isTerminal()) { + try { + b.addTransition(new Transition<>(map.get(t.start()), t.label(), nt)); + b.addTransition(new Transition<>(map.get(t.start()), t.label(), ni)); + } catch (NoSuchStateException x) { + } + } + } + return b; + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/StatesCouple.java b/extra/jautomata-core/rationals/transformations/StatesCouple.java new file mode 100755 index 0000000000..ee8c3a1f1d --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/StatesCouple.java @@ -0,0 +1,66 @@ +/* + * (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.transformations; + +import java.util.Set; + +import rationals.State; + + +public final class StatesCouple { + public final Set<State> sa; + public final Set<State> sb; + private final int hash; + + public StatesCouple(Set<State> sa, Set<State> sb) { + this.sa = sa; + this.sb = sb; + this.hash = sa.hashCode() + sb.hashCode(); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof StatesCouple)) return false; + StatesCouple sc = (StatesCouple) obj; + return sc.sa.equals(sa) && sc.sb.equals(sb); + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return hash; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + return " < " + sa.toString() + "," + sb.toString() + " >"; + } +} \ No newline at end of file diff --git a/extra/jautomata-core/rationals/transformations/Substitution.java b/extra/jautomata-core/rationals/transformations/Substitution.java new file mode 100755 index 0000000000..23ec063494 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Substitution.java @@ -0,0 +1,133 @@ +/* + * (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.transformations; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import rationals.Automaton; +import rationals.Builder; +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<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + private Map<?, ?> morph; + + public Substitution(Map<?, ?> m) { + this.morph = m; + } + + /* (non-Javadoc) + * @see rationals.transformations.UnaryTransformation#transform(rationals.Automaton) + */ + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Automaton<L, Tr, T> b = new Automaton<>(); + /* state map */ + Map<State, State> stm = new HashMap<>(); + for (Iterator<Transition<L>> i = a.delta().iterator(); i.hasNext();) { + Transition<L> tr = i.next(); + State ns = tr.start(); + State nss = stm.get(ns); + if (nss == null) { + nss = b.addState(ns.isInitial(), ns.isTerminal()); + stm.put(ns, nss); + } + State ne = tr.end(); + State nse = stm.get(ne); + if (nse == null) { + nse = b.addState(ne.isInitial(), ne.isTerminal()); + stm.put(ne, nse); + } + L lbl = tr.label(); + if (!morph.containsKey(lbl)) + try { + b.addTransition(new Transition<L>(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<L, Tr, T>) o); + else + b.addTransition(new Transition<L>(nss, (L) 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<L, Tr, T> b, Automaton<L, Tr, T> automaton) { + /* map states */ + Map<State, State> map = new HashMap<State, State>(); + for (Iterator<State> i = automaton.states().iterator(); i.hasNext();) { + State e = i.next(); + State n = b.addState(false, false); + map.put(e, n); + if (e.isInitial()) + try { + b.addTransition(new Transition<L>(nss, null, n)); + } catch (NoSuchStateException e1) { + } + if (e.isTerminal()) + try { + b.addTransition(new Transition<L>(n, null, nse)); + } catch (NoSuchStateException e1) { + } + + } + for (Iterator<Transition<L>> i = automaton.delta().iterator(); i.hasNext();) { + Transition<L> t = i.next(); + try { + b.addTransition(new Transition<L>(map.get(t.start()), t.label(), map.get(t.end()))); + } catch (NoSuchStateException x) { + } + } + + } + +} diff --git a/extra/jautomata-core/rationals/transformations/ToC.java b/extra/jautomata-core/rationals/transformations/ToC.java new file mode 100755 index 0000000000..cf530f47ba --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/ToC.java @@ -0,0 +1,104 @@ +/* + * (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.*; + +public class ToC<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Automaton b = new EpsilonTransitionRemover().transform(a); + Set Ib = b.initials(); + Set Tb = b.terminals(); + Map /* < Set <State>, Set < State > > */ subsets = new HashMap(); + Map /* < Set < State > , Map < Object, Set < State > > > */delta = new HashMap(); + LinkedList l = new LinkedList(); + Set /* < Set < State > > */ done = new HashSet(); + l.add(Ib); + while (!l.isEmpty()) { + Set e1 = (Set) l.removeFirst(); + Set sub = b.getStateFactory().stateSet(); + subsets.put(e1, sub); + Iterator j = done.iterator(); + while (j.hasNext()) { + Set x = (Set) j.next(); + if (x.containsAll(e1) && !x.equals(e1)) + ((Set) subsets.get(x)).addAll(e1); + if (e1.containsAll(x) && !x.equals(e1)) + sub.addAll(x); + } + done.add(e1); + delta.put(e1, new HashMap()); + j = b.alphabet().iterator(); + while (j.hasNext()) { + Object label = j.next(); + Iterator i = e1.iterator(); + Set e2 = b.getStateFactory().stateSet(); + while (i.hasNext()) { + Iterator k = b.delta((State) i.next(), label).iterator(); + while (k.hasNext()) { + e2.add(((Transition) k.next()).end()); + } + } + ((Map) delta.get(e1)).put(label, e2); + if (!done.contains(e2)) + l.add(e2); + } + } + Automaton c = new Automaton(); + Map corr = new HashMap(); + Iterator i = done.iterator(); + while (i.hasNext()) { + Set x = (Set) i.next(); + if (!x.isEmpty()) { + if (!((Set) subsets.get(x)).containsAll(x)) { + boolean ini = Ib.containsAll(x); + boolean term = TransformationsToolBox + .containsATerminalState(x); + corr.put(x, c.addState(ini, term)); + } + } + } + i = corr.keySet().iterator(); + while (i.hasNext()) { + Set e = (Set) i.next(); + Iterator j = b.alphabet().iterator(); + while (j.hasNext()) { + Object lab = j.next(); + Set f = (Set) ((Map) delta.get(e)).get(lab); + Iterator k = corr.keySet().iterator(); + while (k.hasNext()) { + Set x = (Set) k.next(); + if (f.containsAll(x)) { + try { + c.addTransition(new Transition((State) corr.get(e), + lab, (State) corr.get(x))); + } catch (NoSuchStateException z) { + } + } + } + } + } + return c; + } +} diff --git a/extra/jautomata-core/rationals/transformations/ToCanonicalRFSA.java b/extra/jautomata-core/rationals/transformations/ToCanonicalRFSA.java new file mode 100755 index 0000000000..df4b01e6c3 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/ToCanonicalRFSA.java @@ -0,0 +1,31 @@ +/* + * (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.transformations; + + +import rationals.Automaton; +import rationals.Builder; +import rationals.Transition; + +public class ToCanonicalRFSA<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Reverser<L, Tr, T> r = new Reverser<>(); + ToC<L, Tr, T> c = new ToC<>() ; + return c.transform(r.transform(c.transform(r.transform(a)))) ; + } +} diff --git a/extra/jautomata-core/rationals/transformations/ToDFA.java b/extra/jautomata-core/rationals/transformations/ToDFA.java new file mode 100755 index 0000000000..2d906b11d5 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/ToDFA.java @@ -0,0 +1,121 @@ +/* + * (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.*; + +/** + * Determinization of an automaton. + * + * @author yroos + * @version $Id: ToDFA.java 7 2006-08-31 23:01:30Z oqube $ + */ +public class ToDFA<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements UnaryTransformation<L, Tr, T> { + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) { + Automaton<L, Tr, T> ret = new Automaton<>(); + Map<Set<State>, State> bmap = new HashMap<>(); + List<Set<State>>todo = new ArrayList<>(); + Set<Set<State>>done = new HashSet<>(); + Set<State> as = TransformationsToolBox.epsilonClosure(a.initials(), a); + State from = ret.addState(true, TransformationsToolBox.containsATerminalState(as)); + bmap.put(as, from); + todo.add(as); + do { + Set<State> sts = todo.remove(0); + from = bmap.get(sts); + if (done.contains(sts)) + continue; + done.add(sts); + /* get transition sets */ + Map<L, Set<State>> tam = TransformationsToolBox.mapAlphabet(a.delta(sts), a); + /* unsynchronizable transitions in A */ + for (Iterator<Map.Entry<L, Set<State>>> i = tam.entrySet().iterator(); i.hasNext();) { + Map.Entry<L, Set<State>> me = i.next(); + L l = me.getKey(); + as = (Set<State>) me.getValue(); + Set<State> asc = TransformationsToolBox.epsilonClosure(as, a); + State to = (State) bmap.get(asc); + if (to == null) { + to = ret.addState(false, TransformationsToolBox + .containsATerminalState(asc)); + bmap.put(asc, to); + } + todo.add(asc); + try { + ret.addTransition(new Transition<L>(from, l, to)); + } catch (NoSuchStateException e) { + assert false; + } + } + } while (!todo.isEmpty()); + return ret; + } + + /* + public Automaton transform(Automaton a) { + a = new EpsilonTransitionRemover().transform(a); + Automaton b = new Automaton(); + Map map = new HashMap(); + LinkedList l = new LinkedList(); + Set done = new HashSet(); + Set e = a.initials(); + boolean t = TransformationsToolBox.containsATerminalState(e); + map.put(e, b.addState(true, t)); + l.add(e); + while (!l.isEmpty()) { + Set e1 = (Set) l.removeFirst(); + done.add(e1); + State ep1 = (State) map.get(e1); + Iterator j = a.alphabet().iterator(); + Object label = null; + while (j.hasNext()) { + label = j.next(); + Iterator i = e1.iterator(); + Set e2 = a.getStateFactory().stateSet(); + while (i.hasNext()) { + Iterator k = a.delta((State) i.next(), label).iterator(); + while (k.hasNext()) { + e2.add(((Transition) k.next()).end()); + } + } + State ep2; + if (!e2.isEmpty()) { + if (!map.containsKey(e2)) { + t = TransformationsToolBox.containsATerminalState(e2); + map.put(e2, b.addState(false, t)); + } + ep2 = (State) map.get(e2); + try { + b.addTransition(new Transition(ep1, label, ep2)); + } catch (NoSuchStateException x) { + } + if (!done.contains(e2)) + l.add(e2); + } + } + } + return b; + } + */ +} diff --git a/extra/jautomata-core/rationals/transformations/Transformations.java b/extra/jautomata-core/rationals/transformations/Transformations.java new file mode 100755 index 0000000000..420ec5be7c --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Transformations.java @@ -0,0 +1,39 @@ +/* + * (C) Copyright 2013 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.Synchronization; + + +/** Provides useful transformations as static methods for convenience. */ +public class Transformations { + + /** + * Compute the <em>reduced synchronization product</em> of two automata under given {@link Synchronization} relation. + * + * @param a first automaton. Must not be null. + * @param b second automaton. Must not be null. + * @param synchronization relation to synchronize letters on. may be null in which case it defaults to {@link + * rationals.DefaultSynchronization}. + * + * @return a new {@link Automaton} instance. + */ + public static Automaton miniMix(Automaton a, Automaton b, Synchronization synchronization) { + return new Reducer().transform(new Mix(synchronization).transform(a, b)); + } +} diff --git a/extra/jautomata-core/rationals/transformations/TransformationsToolBox.java b/extra/jautomata-core/rationals/transformations/TransformationsToolBox.java new file mode 100755 index 0000000000..abb4b51e1c --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/TransformationsToolBox.java @@ -0,0 +1,124 @@ +/* + * (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.State; +import rationals.Transition; + +import java.util.*; + +/** + * A set of utility methods used in transformations of automaton. + * + * @author nono + * @version $Id: TransformationsToolBox.java 10 2007-05-30 17:25:00Z oqube $ + */ +public class TransformationsToolBox { + + public static boolean containsATerminalState(Set<?> s) { + Iterator<?> i = s.iterator() ; + while(i.hasNext()) { + try { + State e = (State) i.next() ; + if (e.isTerminal()) return true ; + } catch(ClassCastException x) {} + } + return false ; + } + + public static boolean containsAnInitialState(Set<?> s) { + Iterator<?> i = s.iterator() ; + while(i.hasNext()) { + try { + State e = (State) i.next() ; + if (e.isInitial()) return true ; + } catch(ClassCastException x) {} + } + return false ; + } + + /** + * Compute the set of states that are reachable ina given automanton + * from a set of states using epsilon moves. + * An epsilon transition is a transition which is labelled <code>null</code>. + * + * @param s the set of starting states + * @param a the automaton + * @return a - possibly empty - set of states reachable from <code>s</code> through + * epsilon transitions. + */ + public static Set<State> epsilonClosure(Set<State> s, Automaton<?, ?, ?> a) { + Set<State> exp = a.getStateFactory().stateSet(); + exp.addAll(s); /* set of states to visit */ + Set<State> view = a.getStateFactory().stateSet(); /* set of states visited */ + Set<State> arr = a.getStateFactory().stateSet(); /* the set of arrival states */ + arr.addAll(s); + do { + Set<State> ns = a.getStateFactory().stateSet(); + ns.addAll(exp); /* arrival states */ + Iterator<State> it = ns.iterator(); + while (it.hasNext()) { + State st = (State) it.next(); + Iterator<?> it2 = a.delta(st).iterator(); + while (it2.hasNext()) { + Transition<?> tr = (Transition<?>) it2.next(); + if (tr.label() == null && !view.contains(tr.end()) + && !tr.end().equals(st)) { + /* compute closure of epsilon transitions */ + exp.add(tr.end()); + arr.add(tr.end()); + } + } + exp.remove(st); + view.add(st); + } + } while (!exp.isEmpty()); + return arr; + } + + + /** + * Compute a map from letters to set of states given + * a set of transitions. + * This method computes the arrival set of states for each letter + * occuring in a given set of transitions. epsilon transitions + * are not taken into account. + * + * @param ts a Set of Transition objects. + * @return a Map from Object - transition labels - to Set of State objects. + */ + public static <L> Map<L, Set<State>> mapAlphabet(Set<Transition<L>> ts, Automaton<L, ?, ?> a) { + Map<L, Set<State>> am = new HashMap<>(); + List<Transition<L>> tas = new ArrayList<>(ts); + /* compute set of states for each letter */ + while (!tas.isEmpty()) { + Transition<L> tr = tas.remove(0); + L l = tr.label(); + if (l == null) + continue; + Set<State> as = (Set<State>) am.get(l); + if (as == null) { + as = a.getStateFactory().stateSet(); + am.put(l, as); + } + as.add(tr.end()); + } + return am; + } + +} diff --git a/extra/jautomata-core/rationals/transformations/UnaryTransformation.java b/extra/jautomata-core/rationals/transformations/UnaryTransformation.java new file mode 100755 index 0000000000..7d229f54a0 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/UnaryTransformation.java @@ -0,0 +1,25 @@ +/* + * (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.Transition; + +public interface UnaryTransformation<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> { + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a) ; +} diff --git a/extra/jautomata-core/rationals/transformations/Union.java b/extra/jautomata-core/rationals/transformations/Union.java new file mode 100755 index 0000000000..462a2c0523 --- /dev/null +++ b/extra/jautomata-core/rationals/transformations/Union.java @@ -0,0 +1,61 @@ +/* + * (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.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * Compute the union of two automaton. + * <ul> + * <li>C = A + B</li> + * <li>S(C) = S(A) U S(B)</li> + * <li>S0(C) = S0(A) U SO(B)</li> + * <li>T(C) = T(A) U T(B)</li> + * <li>D(C) = D(A) U D(B)</li> + * </ul> + + * @author nono + * @version $Id: Union.java 2 2006-08-24 14:41:48Z oqube $ + */ +public class Union<L, Tr extends Transition<L>, T extends Builder<L, Tr, T>> implements BinaryTransformation<L, Tr, T> { + + + public Automaton<L, Tr, T> transform(Automaton<L, Tr, T> a , Automaton<L, Tr, T> b) { + Automaton<L, Tr, T> ap = a.clone() ; + Map<State, State> map = new HashMap<State, State>() ; + Iterator<State> i1 = b.states().iterator() ; + while(i1.hasNext()) { + State e = i1.next() ; + map.put(e , ap.addState(e.isInitial() , e.isTerminal())) ; + } + Iterator<Transition<L>> i2 = b.delta().iterator() ; + while(i2.hasNext()) { + Transition<L> t = i2.next(); + try { + ap.addTransition(new Transition<>(map.get(t.start()), t.label(), map.get(t.end()))) ; + } catch(NoSuchStateException x) {} + } + return ap ; + } +} diff --git a/src/main/java/graph/AUTGraph.java b/src/main/java/graph/AUTGraph.java index bab26ef529..e85ae7c51f 100755 --- a/src/main/java/graph/AUTGraph.java +++ b/src/main/java/graph/AUTGraph.java @@ -522,7 +522,7 @@ public class AUTGraph implements myutil.Graph { } - public void minimize(String[] tauTransitions, boolean tauOnly) { + public AUTGraph minimize(String[] tauTransitions, boolean tauOnly) { String s = "tau"; // mark all transitions as non tau @@ -540,8 +540,10 @@ public class AUTGraph implements myutil.Graph { } } - minimizeTau(tauOnly); + //minimizeTau(tauOnly); + //return this; + return reduceGraph(); } public void minimizeTau(boolean tauOnly) { @@ -1033,10 +1035,11 @@ public class AUTGraph implements myutil.Graph { public AUTGraph fromAutomaton(Automaton a) { AUTGraph graph = new AUTGraph(); - Set<Transition<String>> trs = a.delta(); - Set<State> sts = a.states(); + Set<Transition<String>> trs = (Set<Transition<String>>)(a.delta()); + //Set<?> trs = a.delta(); + Set<State> sts = (Set<State>)(a.states()); - HashMap<State, Integer> mapOfStates = new HashMap<>(); + Map<State, Integer> mapOfStates = new HashMap<>(); int cpt = 1; for(State st: sts) { if (st.isInitial()) { @@ -1047,10 +1050,12 @@ public class AUTGraph implements myutil.Graph { } } - for(Transition tr: trs) { + graph.setNbOfStates(mapOfStates.size()); + + for(Transition<String> tr: trs) { State s1 = tr.start(); State s2 = tr.end(); - String label = (String)(tr.label()); + String label = tr.label(); Integer i1 = mapOfStates.get(s1); Integer i2 = mapOfStates.get(s2); @@ -1060,7 +1065,7 @@ public class AUTGraph implements myutil.Graph { } } - computeStates(); + graph.computeStates(); return graph; } @@ -1090,14 +1095,18 @@ public class AUTGraph implements myutil.Graph { return a; } - public void reduceGraph() { + public AUTGraph reduceGraph() { Automaton a = toAutomaton(); - Automaton<String, Transition<String>, TransitionBuilder<String>> b = + //TraceManager.addDev("Initial AUT:" + a.toString()); + Automaton<String, Transition<String>, TransitionBuilder<String>> newA = (Automaton<String, Transition<String>, TransitionBuilder<String>>)( new EpsilonTransitionRemover<String, Transition<String>, - TransitionBuilder<String>>().transform(a); + TransitionBuilder<String>>().transform(a)); + //TraceManager.addDev("Aut with no tau / epsilon:" + newA.toString()); - b = new Reducer<String, Transition<String>, TransitionBuilder<String>>().transform(b); - TraceManager.addDev("Error in reduce graph:" + b); + newA = new Reducer<String, Transition<String>, TransitionBuilder<String>>().transform(newA); + //TraceManager.addDev("Error in reduce graph:" + newA); + //TraceManager.addDev("New Aut:" + newA.toString()); + return fromAutomaton(newA); } diff --git a/src/main/java/ui/window/JFrameMinimize.java b/src/main/java/ui/window/JFrameMinimize.java index a2f07000a7..fd1af9bdbe 100644 --- a/src/main/java/ui/window/JFrameMinimize.java +++ b/src/main/java/ui/window/JFrameMinimize.java @@ -581,7 +581,7 @@ public class JFrameMinimize extends javax.swing.JFrame implements ActionListener } } - newRG.graph.minimize(strarray, tauOnly.isSelected()); + newRG.graph = newRG.graph.minimize(strarray, tauOnly.isSelected()); newRG.nbOfStates = newRG.graph.getNbOfStates(); newRG.nbOfTransitions = newRG.graph.getTransitions().size(); mgui.addRG(newRG); diff --git a/ttool/build.gradle b/ttool/build.gradle index 8543ce1b9b..aeceeb9ea5 100644 --- a/ttool/build.gradle +++ b/ttool/build.gradle @@ -32,6 +32,7 @@ dependencies { compile name: 'batik-svggen' compile name: 'batik-dom' compile name: 'batik-awt-util' + compile name: 'jautomata-core' // Use JUnit test framework testCompile 'junit:junit:4.12' -- GitLab