Skip to content
Snippets Groups Projects
AUTGraph.java 57.96 KiB
/* Copyright or (C) or Copr. GET / ENST, Telecom-Paris, Ludovic Apvrille
 * 
 * ludovic.apvrille AT enst.fr
 * 
 * This software is a computer program whose purpose is to allow the
 * edition of TURTLE analysis, design and deployment diagrams, to
 * allow the generation of RT-LOTOS or Java code from this diagram,
 * and at last to allow the analysis of formal validation traces
 * obtained from external tools, e.g. RTL from LAAS-CNRS and CADP
 * from INRIA Rhone-Alpes.
 * 
 * This software is governed by the CeCILL  license under French law and
 * abiding by the rules of distribution of free software.  You can  use,
 * modify and/ or redistribute the software under the terms of the CeCILL
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".
 * 
 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability.
 * 
 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and,  more generally, to use and operate it in the
 * same conditions as regards security.
 * 
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL license and that you accept its terms.
 */


package graph;

import myutil.Conversion;
import myutil.DijkstraState;
import myutil.GraphAlgorithms;
import myutil.TraceManager;

import java.io.BufferedReader;
import java.io.StringReader;
import java.util.*;

import rationals.*;
import rationals.transformations.*;

/**
 * Class AUTGraph
 * Creation : 16/09/2004
 * * @version 1.0 16/09/2004
 *
 * @author Ludovic APVRILLE
 */
public class AUTGraph implements myutil.Graph {

    // Graph is defined with this only
    protected ArrayList<AUTTransition> transitions;
    protected int nbState;

    // Can be built with computeStates()
    protected ArrayList<AUTState> states;

    protected BufferedReader br;
    protected long nbTransition;
    protected int percentage;
    protected boolean[] hasExitTransition;
    protected boolean[] hasEntryTransition;
    protected boolean statesComputed;


    public AUTGraph() {
        transitions = new ArrayList<>();
        //buildGraph(dataAUT);
    }

    public AUTGraph(ArrayList<AUTState> _st, ArrayList<AUTTransition> _tr) {
        states = _st;
        transitions = _tr;
        nbState = states.size();
        statesComputed = true;
    }

    public void stopBuildGraph() {
        br = null;
    }

    public int getPercentage() {
        return percentage;
    }

    public void buildGraph(String data) {
        if (data == null) {
            return;
        }

        StringReader sr = new StringReader(data);
        br = new BufferedReader(sr);
        String s, s1, s2;
        int index1;
        //int origin, destination;
        AUTTransition at;

        percentage = 0;
        int cpt, mod;

        /* read header */
        //TraceManager.addDev("Building graph");
        try {
            while ((s = br.readLine()) != null) {
                index1 = s.indexOf("des");
                //TraceManager.addDev("Searching for des");
                if (index1 == 0) {
                    //TraceManager.addDev("des found");
                    s1 = s.substring(s.indexOf(',') + 1, s.length());
                    s1 = s1.substring(0, s1.indexOf(','));
                    s1 = Conversion.removeFirstSpaces(s1);
                    nbTransition = new Integer(s1).intValue();
                    s2 = s.substring(s.indexOf(",") + 1, s.indexOf(')'));
                    s2 = s2.substring(s2.indexOf(",") + 1, s2.length());
                    s2 = Conversion.removeFirstSpaces(s2);
                    nbState = new Integer(s2).intValue();
                    break;
                }
            }
        } catch (Exception e) {
            TraceManager.addDev("Exception when reading graph information: " + e.getMessage() + "\n");
            return;
        }

        String[] array;
        hasExitTransition = new boolean[nbState];
        hasEntryTransition = new boolean[nbState];
        TraceManager.addDev("NbState=" + nbState + "  NbTransition=" + nbTransition + "\n");

        /*for(cpt=0; cpt<nbState; cpt ++) {
          hasExitTransition[cpt] = false;
          hasEntryTransition[cpt] = false;
          }*/

        /* read transitions */
        try {
            cpt = 0;
            mod = Math.max(1, (int) (nbTransition / 100));


            while ((s = br.readLine()) != null) {
                //TraceManager.addDev("realine:" + s);
                array = AUTGraph.decodeLine(s);
                at = new AUTTransition(array[0], array[1], array[2]);
                transitions.add(at);
                hasExitTransition[at.origin] = true;
                hasEntryTransition[at.destination] = true;
                cpt++;
                if ((cpt % mod) == 0) {
                    percentage = (int) ((cpt * 100) / nbTransition);
                    //TraceManager.addDev("percentage=" + percentage + "cpt=" + cpt + "nbTransition=" + nbTransition);
                }
            }
        } catch (Exception e) {
            TraceManager.addDev("Cancelled: " + e.getMessage() + "\n");
            return;
        }
    }

    public static String[] decodeLine(String s) {
        int index1, index2;
        String s1, s2, s3;

        index1 = s.indexOf("(");
        index2 = s.indexOf(",");
        s1 = s.substring(index1 + 1, index2);
        s = s.substring(index2 + 1, s.length());
        s = Conversion.removeFirstSpaces(s);

        // for of the action
        // , action,
        // "i(action<1,2,4>)",
        // "action<1,2,4>",

        // guillemets ?
        index1 = s.indexOf("\"");
        if (index1 > -1) {
            //TraceManager.addDev("Guillemets on " + s);
            s2 = s.substring(index1 + 1, s.length());
            s2 = s2.substring(0, s2.indexOf("\""));
            //TraceManager.addDev("Guillemets on " + s2);
            /*index2 = s2.indexOf("(");
              if (index2 > -1) {
              s2 = s2.substring(index2+1, s2.indexOf(")"));
              }*/
            //TraceManager.addDev("Guillemets on " + s2);

        } else {
            //TraceManager.addDev("No Guillemets on " + s);
            index1 = s.indexOf(",");
            if ((index2 = s.indexOf("(")) >= 0) {
                s2 = s.substring(index2 + 1, index1 - 2);
            } else {
                if ((index2 = s.indexOf("\"t\"")) >= 0) {
                    s2 = "t";
                } else {
                    s2 = s.substring(0, index1);
                }
            }
        }

        s = s.substring(s.indexOf(s2) + s2.length(), s.length());
        //TraceManager.addDev("s=" + s);
        index1 = s.indexOf(",");
        //index2 = s.indexOf(")");
        //s2 = s.substring(0, index1-1);
        s3 = s.substring(index1 + 1, s.length() - 1);
        s3 = Conversion.removeFirstSpaces(s3);
        //TraceManager.addDev("s1=" + s1 + " s2=" + s2 + " s3=" + s3);

        String[] array = new String[3];
        array[0] = s1;
        array[1] = s2;
        array[2] = s3;
        return array;
    }

    public int getNbOfStates() {
        return nbState;
    }

    public void setNbOfStates(int _nb) {
        nbState = _nb;
    }

    public int getNbOfTransitions() {
        //return nbTransition;
        return transitions.size();
    }

    public AUTTransition getAUTTransition(int index) {
        return transitions.get(index);
    }

    public ArrayList<AUTState> getStates() {
        return states;
    }

    public ArrayList<AUTTransition> getTransitions() {
        return transitions;
    }

    public void addTransition(AUTTransition _tr) {
        transitions.add(_tr);
        statesComputed = false;
    }

    public void addState(AUTState _st) {
        states.add(_st);
    }


    public int getNbPotentialDeadlocks() {
        int nb = 0;

        for (int i = 0; i < nbState; i++) {
            if (hasEntryTransition(i)) {
                if (!hasExitTransition(i)) {
                    nb++;
                }
            }
        }

        return nb;
    }

    public String getActionTransition(int origin, int destination) {

        for (AUTTransition aut1 : transitions) {
            if ((aut1.origin == origin) && (aut1.destination == destination)) {
                return aut1.transition;
            }
        }
        return "";
    }

    public boolean hasEntryTransition(int state) {
        if (hasEntryTransition == null) {
            computeEntryExitTransitions();
        }
        return hasEntryTransition[state];
    }

    public boolean hasExitTransition(int state) {
        if (hasExitTransition == null) {
            computeEntryExitTransitions();
        }
        return hasExitTransition[state];
    }

    public boolean hasExitTransitionTo(int state, int destination) {
        if (!hasExitTransition(state)) {
            return false;
        }


        for (AUTTransition aut1 : transitions) {
            if ((aut1.origin == state) && (aut1.destination == destination)) {
                return true;
            }
        }
        return false;

    }

    /* State numbers are return under the form of int */
    /* Should be rewritten: not of high performance at all */

    public int[] getVectorPotentialDeadlocks() {
        int nbPotentialDeadlock = getNbPotentialDeadlocks();
        //TraceManager.addDev("nb of deadlocks: " + nbPotentialDeadlock);
        int[] states = new int[nbPotentialDeadlock];
        int index = 0;

        for (int i = 0; i < nbState; i++) {
            if (hasEntryTransition(i)) {
                if (!hasExitTransition(i)) {
                    states[index] = i;
                    index++;
                }
            }
        }

        return states;
    }

    public int[] shortestPathTo(int fromState, int targetState) {
        return GraphAlgorithms.ShortestPathFrom(this, fromState)[targetState].path;
    }


    public boolean hasTransitionWithAction(String action) {

        for (AUTTransition aut1 : transitions) {
            if (aut1.transition.compareTo(action) == 0) {
                return true;
            }
        }
        return false;
    }

    // For Graph interface

    public int getWeightOfTransition(int originState, int destinationState) {
        if (statesComputed) {
            if (states.get(originState).hasTransitionTo(destinationState)) {
                return 1;
            }
        } else {
            if (hasExitTransitionTo(originState, destinationState)) {
                return 1;
            }
        }
        return 0;
    }

    public String toAUTStringFormat() {
        StringBuffer graph = new StringBuffer("");
        graph.append("des(0," + nbTransition + "," + nbState + ")\n");
        for (AUTTransition aut1 : transitions) {
            graph.append("(" + aut1.origin + ",\"" + aut1.transition + "\"," + aut1.destination + ")\n");
        }
        return graph.toString();
    }


    public String toFullString() {
        StringBuffer graph = new StringBuffer("Transitions:");
        for (AUTTransition aut1 : transitions) {
            graph.append(aut1.toString());
        }
        graph.append("\nstates:\n");
        for (AUTState str : states) {
            graph.append(str.toString());
        }
        return graph.toString();

    }

    public void computeStates() {
        if (!statesComputed) {
            states = new ArrayList<AUTState>(nbState);
            AUTState state;
            for (int i = 0; i < nbState; i++) {
                state = new AUTState(i);
                states.add(state);
            }

            for (AUTTransition aut1 : transitions) {
                states.get(aut1.origin).addOutTransition(aut1);
                states.get(aut1.destination).addInTransition(aut1);
            }
            statesComputed = true;
            setNbOfStates(states.size());
        }
    }

    public AUTState getState(int _id) {
        return states.get(_id);
    }

    public boolean areStateComputed() {
        return statesComputed;
    }

    public void setStates(ArrayList<AUTState> _states) {
        states = _states;
        nbState = states.size();
        statesComputed = true;
    }

    public HashSet<String> getAllActions() {
        HashSet<String> hs = new HashSet<String>();
        for (AUTTransition tr : transitions) {
            hs.add(tr.transition);
        }
        return hs;
    }


    public void reinitMet() {
        for (AUTState state : states) {
            state.met = false;
        }
    }

    public AUTState findFirstOriginState() {
        AUTState state;

        for (int i = 0; i < states.size(); i++) {
            state = states.get(i);
            //TraceManager.addDev("id=" + state.id + " transitions to me = " +state.inTransitions.size());
            if (state.inTransitions.size() == 0) {
                return state;
            }
        }

        return null;
    }

    public void putTransitionsFromInitFirst() {
        ArrayList<AUTTransition> tmp = new ArrayList<AUTTransition>();

        for (AUTTransition aut1 : transitions) {
            if (aut1.origin == 0) {
                tmp.add(aut1);
            }
        }

        for (AUTTransition aut2 : tmp) {
            transitions.remove(aut2);
            transitions.add(0, aut2);
        }
    }

    public void display() {
        display(false);
    }

    public void display(boolean exitOnClose) {
        AUTGraphDisplay display = new AUTGraphDisplay(this, exitOnClose);
        display.display();
    }


    public AUTGraph cloneMe() {
        AUTGraph newGraph = new AUTGraph();
        newGraph.setNbOfStates(getNbOfStates());
        for (AUTTransition tr : transitions) {
            AUTTransition newTr = new AUTTransition(tr.origin, tr.transition, tr.destination);
            newGraph.addTransition(newTr);
        }
        newGraph.computeStates();
        return newGraph;
    }

    public String getCompoundString(AUTTransition t, HashSet<AUTTransition> set) {
        String ret = "";
        int cpt = 0;
        for(AUTTransition tr: transitions) {
            if ((tr.origin == t.origin) && (tr.destination == t.destination)) {
                set.add(tr);
                if (cpt > 0) {
                    ret += " OR ";
                } else {
                    cpt ++;
                }
                ret += tr.transition;
            }
        }
        return ret;
    }



    public void minimizeRemoveInternal(boolean tauOnly) {
        String s = "tau";

        // mark all transitions as non tau
        for (AUTTransition tr : transitions) {
            tr.isTau = false;
        }

        // Mark all tau transitions as tau
        for (AUTTransition tr : transitions) {

            if (tr.transition.startsWith("i(")) {
                tr.isTau = true;
                tr.transition = s;
            }

        }

        minimizeTau(tauOnly);
    }


    public AUTGraph minimize(String[] tauTransitions, boolean tauOnly) {
        String s = "tau";

        // mark all transitions as non tau
        for (AUTTransition tr : transitions) {
            tr.isTau = false;
        }

        // Mark all tau transitions as tau
        for (AUTTransition tr : transitions) {
            for (int i = 0; i < tauTransitions.length; i++) {
                if (tr.transition.compareTo(tauTransitions[i]) == 0) {
                    tr.isTau = true;
                    tr.transition = s;
                }
            }
        }



        //minimizeTau(tauOnly);
        //return this;

        return reduceGraph();
    }

    public void minimizeTau(boolean tauOnly) {
        boolean modif = true;
        //TraceManager.addDev(toFullString());

        factorizeNonTauTransitions();

        if (tauOnly) {
            return;
        }

        TraceManager.addDev("RG before partition: " + toFullString());

        partitionGraph();

    }

    // Remove transition going from one state with only one tau transition as output
    private boolean removeOnlyOneTauTr() {
        AUTTransition tr;
        ArrayList<AUTState> toRemoveStates = new ArrayList<AUTState>();
        // Remove in case state with one outgoing and outgoing is tau -> remove tr
        for (AUTState st : states) {
            if (st.outTransitions.size() == 1) {
                tr = st.outTransitions.get(0);
                if (tr.isTau) {
                    transitions.remove(tr);
                    st.outTransitions.clear();


                    AUTState st1 = states.get(tr.destination);
                    if (st1 != st) {
                        toRemoveStates.add(st1);
                        //TraceManager.addDev("Removing state " + st1.id);

                        // Must put all incoming transition to the first state
                        st1.inTransitions.remove(tr);
                        for (AUTTransition trM : st1.inTransitions) {
                            trM.destination = st.id;
                            st.inTransitions.add(trM);
                            //TraceManager.addDev("New in transitions " + trM);
                        }
                        st1.inTransitions.clear();

                        // Out transitions
                        st.outTransitions.clear();
                        for (AUTTransition trM : st1.outTransitions) {
                            st.outTransitions.add(trM);
                            trM.origin = st.id;
                           // TraceManager.addDev("New out transitions " + trM);
                        }
                        st1.outTransitions.clear();
                        break;
                    }
                }
            }
        }

        // Remove all states and adapt the id in the graph
        if (toRemoveStates.size() > 0) {
            removeStates(toRemoveStates);
            return true;
        }

        return false;
    }


    // Rework states with at least 2 tau transitions
    private boolean removeMultipleTauOutputTr() {
        AUTTransition tr1, tr2, trtmp;
        AUTState st1, st2, sttmp;
        ArrayList<AUTState> toRemoveStates = new ArrayList<AUTState>();
        AUTTransition[] ret;
        boolean modif = false;

        // Remove in case state with one outgoing and outgoing is tau -> remove transition
        for (AUTState st : states) {
            ret = st.getAtLeastTwoOutTauTransitions();
            if (ret != null) {
                tr1 = ret[0];
                tr2 = ret[1];
                tr2 = st.outTransitions.get(1);
                st1 = states.get(tr1.destination);
                st2 = states.get(tr2.destination);

                // Same states
                if (st1 == st2) {
                    //We can simply remove the transition
                    transitions.remove(tr2);
                    st.outTransitions.remove(tr2);
                    modif = true;
                }

                // We can merge st1 or st2 because one has no other incoming transition than
                // the tau transition
                else if ((st1.inTransitions.size() == 1) && (st2.inTransitions.size() == 1)) {
                    //We can remove st2 and the tau transition
                    toRemoveStates.add(st2);
                    transitions.remove(tr2);
                    st.outTransitions.remove(tr2);

                    // All transitions leaving st2 must now leave from st1 as well
                    for (AUTTransition trf : st2.outTransitions) {
                        trf.origin = st1.id;
                        st1.outTransitions.add(trf);
                    }
                }

            }
        }

        // Remove all states and adapt the id in the graph
        if (toRemoveStates.size() > 0) {
            removeStates(toRemoveStates);
            modif = true;
        }


        return modif;
    }

    // Rework states with only one tau before, and only one action after
    private boolean removeTauWithOneFollower() {
        AUTTransition tr1, tr2;
        AUTState st1, st2;
        ArrayList<AUTState> toRemoveStates = new ArrayList<AUTState>();
        boolean modif = false;

        // Remove stgate in case state with one outgoing and outgoing is tau
        for (AUTState st : states) {
            if (st.hasOneIncomingTauAndOneFollower()) {
                //We can remove the previous tau transaction, and the current state
                tr1 = st.inTransitions.get(0);
                st1 = states.get(tr1.origin);
                if (st1 != st) {
                    tr2 = st.outTransitions.get(0);
                    tr2.origin = st1.id;
                    st1.outTransitions.remove(tr1);
                    st1.outTransitions.add(tr2);
                    transitions.remove(tr1);
                    toRemoveStates.add(st);
                    break;
                }
            }

        }

        // Remove all states and adapt the id in the graph
        if (toRemoveStates.size() > 0) {
            removeStates(toRemoveStates);
            modif = true;
        }


        return modif;
    }


    private boolean removeSimilarTransitions() {
        boolean modif = false;

        // Remove tr if it is duplicated
        for (AUTState st : states) {

            // May modify the outTransitions list, and result in exception.
            // The try .. catch clause protects from this
            try {
                if (st.outTransitions.size() > 1) {
                    for (int i = 0; i < st.outTransitions.size(); i++) {
                        for (int j = i + 1; j < st.outTransitions.size(); j++) {
                            AUTTransition tri = st.outTransitions.get(i);
                            AUTTransition trj = st.outTransitions.get(j);
                            if (tri.destination == trj.destination) {
                                if (tri.transition.compareTo(trj.transition) == 0) {
                                    modif = true;
                                    //We remove trj
                                    st.outTransitions.remove(trj);
                                    transitions.remove(trj);
                                    i--;
                                    j--;
                                }
                            }
                        }
                    }


                }
            } catch (Exception e) {
            }
        }

        return modif;
    }


    private void removeStates(ArrayList<AUTState> toRemoveStates) {

        if (toRemoveStates.size() > 0) {
            hasExitTransition = null;
            hasEntryTransition = null;
        }

        // Remove all states and adapt the id in the graph
        //TraceManager.addDev("nbState=" + nbState + " states size = " + states.size());

        for (AUTState str : toRemoveStates) {
            // We need to remove all transitions of the removed state
            //TraceManager.addDev("Removing transitions of state:" + str.id + "\n" + toFullString());
            for (AUTTransition trin : str.inTransitions) {
                transitions.remove(trin);
            }
            for (AUTTransition trout : str.outTransitions) {
                transitions.remove(trout);
            }

            for (AUTState state : states) {
                state.removeAllTransitionsWithId(str.id);
            }

            //TraceManager.addDev("Done removing transitions of state:" + str.id + "\n" + toFullString());

            // Last state of the array?
            if (str.id == (nbState - 1)) {
                //TraceManager.addDev("Last state " + str.id);
                nbState--;
                states.remove(str.id);

                // str not at the end: we replace it with the last state
                // We need to accordingly update
            } else {

                AUTState moved = states.get(nbState - 1);
                //TraceManager.addDev("Moving state " + moved.id +  " to index " + str.id);
                states.set(str.id, moved);
                states.remove(nbState - 1);
                nbState--;
                //TraceManager.addDev("nbState=" + nbState + " states size = " + states.size());
                /*AUTTransition tt = findTransitionWithId(nbState);
                  if (tt != null) {
                  TraceManager.addDev("1) Transition with id not normal" + tt);
                  }*/
                //TraceManager.addDev("Update id\n" + toAUTStringFormat());
                moved.updateID(str.id);
                /*tt = findTransitionWithId(nbState);
                  if (tt != null) {
                  TraceManager.addDev("2) Transition with id not normal" + tt);
                  }*/
            }

        }
    }


    // Removes all tau transition of a state, replacing them with reachable non tau transitions
    // A tau transition reaching an end state cannot be removed but can be replaced with a unique transition
    private void factorizeNonTauTransitions() {
        boolean modif = false;
        boolean endState = false;
        // met is used to specify states that have a tau-path to a termination state
        for (AUTState st1 : states) {
            st1.met = false;
        }

        for (AUTState st : states) {
            if ((st.id == 0) || (st.getNbInTransitions() > 0)) {
                //TraceManager.addDev("  1. state " + st.id);
                if (st.hasOutputTauTransition()) {
                    //TraceManager.addDev("  2. state " + st.id);
                    LinkedList<AUTTransition> nonTauTransitions = new LinkedList<AUTTransition>();
                    boolean canReachAnEndStateWithTau = getAllNonTauTransitionsFrom(st, nonTauTransitions);

                    //TraceManager.addDev("State " + st.id + " has the following real transitions:");
                    /*for(AUTTransition tr: nonTauTransitions) {
                      TraceManager.addDev("\t" + tr);
                      }*/

                    //TraceManager.addDev("State " + st.id + " can reach an end state with tau tr only?" + canReachAnEndStateWithTau);
                    st.met = canReachAnEndStateWithTau;
                    endState = endState || canReachAnEndStateWithTau;
                }
            }
        }

        // Remove tr if it is duplicated
        for (AUTState st : states) {
            // We ignore states with no input tr apart from the start state (id 0)
            //TraceManager.addDev("0. state " + st.id);
            if ((st.id == 0) || (st.getNbInTransitions() > 0)) {
                //TraceManager.addDev("  1. state " + st.id);
                if (st.hasOutputTauTransition()) {
                    //TraceManager.addDev("  2. state " + st.id);
                    LinkedList<AUTTransition> nonTauTransitions = new LinkedList<AUTTransition>();
                    getAllNonTauTransitionsFrom(st, nonTauTransitions);

                    // Create these transitions in st if not yet existing
                    //TraceManager.addDev("Remove tau\n" + toFullString());
                    st.removeAllOutTauTransitions(transitions, states);
                    //TraceManager.addDev("Done remove tau. create trans\n" + toFullString());
                    st.createTransitionsButNotDuplicate(nonTauTransitions, states, transitions);
                    //TraceManager.addDev("Done create trans\n" + toFullString());
                }
            }
        }

        // Remove all non reachable state
        //removeAllNonReachableStates();

        // If end state: we must create a new end state, and all "met" states should have a tau transition
        // to this state
        if (endState) {
            // We must see if at least one met state has output transitions
            boolean hasEndState = false;
            for (AUTState st : states) {
                if (st.met) {
                    if (st.outTransitions.size() > 0) {
                        hasEndState = true;
                        break;
                    }

                }
            }
            if (hasEndState) {
                int newId = states.size();
                AUTState endSt = new AUTState(newId);
                states.add(endSt);
                nbState = states.size();
                for (AUTState st1 : states) {
                    if (st1.met) {
                        if (st1.outTransitions.size() > 0) {
                            //TraceManager.addDev("Adding an end tau to state " + st1.id);
                            AUTTransition tr = new AUTTransition(st1.id, "tau", endSt.id);
                            tr.isTau = true;
                            transitions.add(tr);
                            st1.addOutTransition(tr);
                            endSt.addInTransition(tr);
                        }
                    }
                    st1.met = false;
                }
            }
        }
        //TraceManager.addDev(toFullString());

        // Remove all non reachable state
        TraceManager.addDev("Remove all non reachable states");
        removeAllNonReachableStates();


        // Print graph in AUT
        //TraceManager.addDev(toAUTStringFormat());

    }

    private boolean getAllNonTauTransitionsFrom(AUTState st, LinkedList<AUTTransition> nonTauTransitions) {
        LinkedList<AUTState> metStates = new LinkedList<AUTState>();
        //metStates.add(st);

        return getAllNonTauTransitionsIterative(st, metStates, nonTauTransitions);
        //return getAllNonTauTransitionsRecursive(st, metStates, nonTauTransitions);
    }


    private boolean getAllNonTauTransitionsRecursive(AUTState st, LinkedList<AUTState> metStates, LinkedList<AUTTransition> nonTauTransitions) {
        if (metStates.contains(st)) {
            return false;
        }

        if (st.getNbOutTransitions() == 0) {
            return true;
        }

        boolean ret = false;
        for (AUTTransition at : st.outTransitions) {
            if (!(at.isTau)) {
                nonTauTransitions.add(at);
            } else {
                ret = ret || getAllNonTauTransitionsRecursive(states.get(at.destination), metStates, nonTauTransitions);
            }
        }

        return ret;
    }


    private boolean getAllNonTauTransitionsIterative(AUTState _st, LinkedList<AUTState> metStates, LinkedList<AUTTransition> nonTauTransitions) {

        boolean ret = false;

        LinkedList<AUTState> toExplore = new LinkedList<AUTState>();
        LinkedList<AUTState> toExploreTmp = new LinkedList<AUTState>();
        toExplore.add(_st);

        while (toExplore.size() > 0) {
            toExploreTmp.clear();
            for (AUTState st : toExplore) {
                if (!(metStates.contains(st))) {
                    metStates.add(st);
                    if (st.getNbOutTransitions() == 0) {
                        ret = true;
                    } else {
                        for (AUTTransition at : st.outTransitions) {
                            if (!(at.isTau)) {
                                nonTauTransitions.add(at);
                            } else {
                                toExploreTmp.add(states.get(at.destination));
                            }
                        }
                    }

                }
            } // for
            toExplore.clear();
            toExplore.addAll(toExploreTmp);

        }// While

        return ret;
    }

    private AUTTransition findTransitionWithId(int id) {
        for (AUTTransition tr : transitions) {
            if ((tr.origin == id) || (tr.destination == id)) {
                return tr;
            }
        }
        return null;
    }


    private void removeAllNonReachableStates() {
        // reset met of states
        for (AUTState st1 : states) {
            st1.met = false;
        }

        //int cpt = 0;

        long startTime = System.nanoTime();

                AUTState[] statesToConsider = new AUTState[1];
        LinkedList<AUTState> nextStatesToConsider = new LinkedList<AUTState>();
        statesToConsider[0] = states.get(0);
        states.get(0).met = true;

        for(int cpt=0; cpt<statesToConsider.length; cpt++){
            nextStatesToConsider.clear();
            for (AUTState st: statesToConsider) {
                //st.met = true;
                //cpt++;
                for (AUTTransition tr : st.outTransitions) {
                    AUTState s = states.get(tr.destination);
                    if (!(s.met)) {
                        s.met = true;
                        nextStatesToConsider.add(s);
                    }
                }
            }
            statesToConsider = nextStatesToConsider.toArray(new AUTState[nextStatesToConsider.size()]);
            cpt = -1;
            //TraceManager.addDev("Size of states to consider:" + statesToConsider.size());
        }

        //TraceManager.addDev("Found " + cpt + " reachable states");
        ArrayList<AUTState> toRemoveStates = new ArrayList<AUTState>();
        for (AUTState st2 : states) {
            if (!(st2.met)) {
                toRemoveStates.add(st2);
                //TraceManager.addDev("Removing state: " + st2.id);
            }
        }

        long time1 = System.nanoTime();

        //TraceManager.addDev(toFullString());

        removeStates(toRemoveStates);
        //TraceManager.addDev(toFullString());
        long endTime = System.nanoTime();


        TraceManager.addDev("First part: " + (time1-startTime)/1000000000 +
                "  Second part: " + (endTime - time1)/1000000000);


        //statesComputed = false;
        //states = null;
        //computeStates();

    }

    private void computeEntryExitTransitions() {
        hasExitTransition = new boolean[nbState];
        hasEntryTransition = new boolean[nbState];

        for (AUTTransition t : transitions) {
            hasExitTransition[t.origin] = true;
            hasEntryTransition[t.destination] = true;
        }
    }

    public void computeNbOfTransitions() {
        nbTransition = transitions.size();
    }

    public AUTGraph fromAutomaton(Automaton a) {
        AUTGraph graph = new AUTGraph();
        @SuppressWarnings("unchecked")
        Set<Transition<String>> trs = (Set<Transition<String>>) a.delta();
        //Set<?> trs = a.delta();
        @SuppressWarnings("unchecked")
        Set<State> sts = (Set<State>)(a.states());

        Map<State, Integer> mapOfStates = new HashMap<>();
        int cpt = 1;
        for(State st: sts) {
            if (st.isInitial()) {

                //@SuppressWarnings("unchecked")
                mapOfStates.put(st, new Integer(0));
            } else {

                //@SuppressWarnings("unchecked")
                mapOfStates.put(st, new Integer(cpt));
                cpt ++;
            }
        }

        graph.setNbOfStates(mapOfStates.size());

        for(Transition<String> tr: trs) {
            State s1 = tr.start();
            State s2 = tr.end();
            String label = tr.label();
            Integer i1 = mapOfStates.get(s1);
            Integer i2 = mapOfStates.get(s2);

            if ((i1 != null) && (i2 != null)) {
                AUTTransition trNew = new AUTTransition(i1.intValue(), label, i2.intValue());
                graph.addTransition(trNew);
            }
        }

        graph.computeNbOfTransitions();
        graph.computeStates();

        return graph;
    }

    public Automaton toAutomaton() {
        Automaton<String, Transition<String>, TransitionBuilder<String>> a = new Automaton<>();
        computeStates();

        boolean initial = true;
        for(AUTState s: states) {
            State as = a.addState(initial, s.isTerminationState());
            s.referenceObject = as;
            initial = false;
        }
        for(AUTTransition t: transitions) {
            try {
                String label = t.transition;
                if (t.isTau) {
                    label = null;
                }
                a.addTransition(new Transition<String>((State) (states.get(t.origin).referenceObject), label, (State) (states.get(t
                        .destination)
                        .referenceObject)));
            } catch (NoSuchStateException nsse) { }
        }

        return a;
    }

    @SuppressWarnings("unchecked")
    public AUTGraph reduceGraph() {
        //TraceManager.addDev("Factorize");
        //factorizeNonTauTransitions();

        Automaton a = toAutomaton();
        //TraceManager.addDev("Initial AUT:" +  a.toString());

        /*@SuppressWarnings("unchecked")
        Automaton<String, Transition<String>, TransitionBuilder<String>> newA =
                new EpsilonTransitionRemover<String, Transition<String>,
                        TransitionBuilder<String>>().transform((Automaton<String, Transition<String>, TransitionBuilder<String>>)a);
        TraceManager.addDev("Aut with no tau / epsilon:" +  newA.toString());*/
        Automaton newA = a;


        TraceManager.addDev("Reduce");
        newA = new Reducer<String, Transition<String>, TransitionBuilder<String>>().transform(newA);
        //TraceManager.addDev("Error in reduce graph:" +  newA);
        //TraceManager.addDev("New Aut:" +  newA.toString());
        TraceManager.addDev("Reduce done");
        return fromAutomaton(newA);
    }


    public void partitionGraph() {

        // Create the alphabet
        HashMap<String, AUTElement> alphabet = new HashMap<String, AUTElement>();
        for (AUTTransition tr : transitions) {
            AUTElement tmp = alphabet.get(tr.transition);
            if (tmp == null) {
                AUTElement elt = new AUTElement(tr.transition);
                alphabet.put(tr.transition, elt);
                tr.elt = elt;
            } else {
                tr.elt = tmp;
            }
            //TraceManager.addDev("Transition "+ tr + " has element " + tr.elt);
        }

        List<AUTElement> sortedAlphabet = new ArrayList<AUTElement>(alphabet.values());
        Collections.sort(sortedAlphabet);

        TraceManager.addDev("Alphabet size:" + sortedAlphabet.size());
        for (int i=0; i<alphabet.size(); i++) {
            TraceManager.addDev("Letter #" + i +  ": " + sortedAlphabet.get(i).toString());
        }


        Map<Integer, AUTBlock> allBlocks = Collections.synchronizedMap(new HashMap<Integer, AUTBlock>());

        // Create the first block that contains all states
        AUTBlock b0 = new AUTBlock();
        for (AUTState st : states) {
            b0.addState(st);
        }
        b0.computeHash();
        allBlocks.put(new Integer(b0.hashValue), b0);


        AUTBlock b0Test = new AUTBlock();
        for (AUTState st : states) {
            b0Test.addState(st);
        }
        b0Test.computeHash();

        AUTBlock B0Ret = allBlocks.get(new Integer(b0Test.hashValue));
        if (B0Ret == null) {
            //TraceManager.addDev("ERROR: hash not working for blocks");
        } else {
            //TraceManager.addDev("Hash working for blocks");
        }


        // Create the first partition containing only block B0
        AUTPartition partition = new AUTPartition();
        partition.addBlock(b0);

        // Create the splitter that contains partitions

        AUTPartition partitionForSplitter = new AUTPartition();
        partitionForSplitter.addBlock(b0);
        AUTSplitter w = new AUTSplitter();
        w.addPartition(partitionForSplitter);

        //printConfiguration(partition, w);

        int maxIte = 10; // With same nb of partitions
        int nbOfPartitions = w.size();
        int evolution = 20;
        int hashCode = -1;

        AUTPartition currentP;
        while ((w.size() > 0) && (maxIte > 0) && (evolution > 0)) {

            int newHash = w.getHashCode();
            if (newHash == hashCode) {
                break;
            }

            if (w.size() == nbOfPartitions) {
                evolution--;
            } else {
                evolution = 20;
            }
            nbOfPartitions = w.size();
            maxIte--;
            currentP = w.partitions.get(0);
            w.partitions.remove(0);


            // Simple splitter?
            if (currentP.blocks.size() == 1) {
                TraceManager.addDev("Simple splitter = " + currentP);
                AUTBlock currentBlock = currentP.blocks.get(0);
                //List<AUTElement> sortedAlphabet = new ArrayList<AUTElement>(alphabet.values());
                //Collections.sort(sortedAlphabet);
                for (AUTElement elt : sortedAlphabet) {
                    //TraceManager.addDev("\n*** Considering alphabet element = " + elt.value);
                    //printConfiguration(partition, w);
                    // Look for states of the leading to another state by a = T
                    // Construct I = all blocks of P that have at least an element in T
                    AUTBlock T_minus1_elt_B = currentBlock.getMinus1(elt, states);

                    //TraceManager.addDev("T_minus1_elt_B=" + T_minus1_elt_B);
                    LinkedList<AUTBlock> I = partition.getI(elt, T_minus1_elt_B);
                    //printI(I);
                    for (AUTBlock blockX : I) {
                        AUTBlock blockX1 = blockX.getStateIntersectWith(T_minus1_elt_B);
                        blockX1.computeHash();
                        AUTBlock blockX2 = blockX.getStateDifferenceWith(T_minus1_elt_B);
                        blockX2.computeHash();
                        //TraceManager.addDev("X1=" + blockX1);
                        //TraceManager.addDev("X2=" + blockX2);

                        if (blockX1.isEmpty() || blockX2.isEmpty()) {
                            //TraceManager.addDev("Nothing to do");
                            // Nothing to do!
                        } else {
                            boolean b = partition.removeBlock(blockX);
                            if (!b) {
                                //TraceManager.addDev("Block " + blockX + " could not be removed from partition");
                            }
                            partition.addBlock(blockX1);
                            partition.addBlock(blockX2);
                            AUTPartition X_X1_X2 = new AUTPartition();
                            X_X1_X2.addBlock(blockX);
                            X_X1_X2.addBlock(blockX1);
                            X_X1_X2.addBlock(blockX2);
                            //TraceManager.addDev("Test concat X1+X2=" + AUTBlock.concat(blockX1, blockX2));
                            w.addPartition(X_X1_X2);
                            TraceManager.addDev("Modifying P and W:");
                            printConfiguration(partition, w);
                            TraceManager.addDev("-----------------\n");
                        }

                    }
                    TraceManager.addDev("-----------------\n");

                }

            }

            // Compound splitter
            else if (currentP.blocks.size() == 3) {
                TraceManager.addDev("Complex splitter (b, bi, bii) =" + currentP);
                AUTBlock b = currentP.blocks.get(0);
                AUTBlock bi = currentP.blocks.get(1);
                AUTBlock bii = currentP.blocks.get(2);

                if (bi.size() > bii.size()) {
                    bi = currentP.blocks.get(2);
                    bii = currentP.blocks.get(1);
                }

                TraceManager.addDev("B= " + b +  " bi=" + bi + " bii=" + bii);

                for (AUTElement elt : sortedAlphabet) {
                    //TraceManager.addDev("\n*** Considering alphabet element = " + elt.value);
                    //printConfiguration(partition, w);
                    AUTBlock T_minus1_elt_B = b.getMinus1(elt, states);
                    //TraceManager.addDev("T_minus1_elt_B=" + T_minus1_elt_B);
                    LinkedList<AUTBlock> I = partition.getI(elt, T_minus1_elt_B);
                    //printI(I);
                    for (AUTBlock blockX : I) {
                        // Compute block X1 = set of states in blockX that goes to Bi, but not to Bii
                        // with current action
                        AUTBlock blockX1 = new AUTBlock();

                        // Compute block X2 = set of states in blockX that goes to Bii, but not to Bi
                        // with current action
                        AUTBlock blockX2 = new AUTBlock();

                        // Compute block X3 = set of states in blockX that goes to both Bi and Bii
                        // with current action
                        boolean b1, b2;
                        AUTBlock blockX3 = new AUTBlock();
                        for (AUTState st : blockX.states) {
                            b1 = blockX.leadsTo(bi, elt);
                            b2 = blockX.leadsTo(bii, elt);
                            if (b1 && !b2) {
                                blockX1.addState(st);
                            } else if (!b1 && b2) {
                                blockX2.addState(st);
                            } else {
                                blockX3.addState(st);
                            }
                        }
                        TraceManager.addDev("Block X = " + blockX + " Block1,2,3 computed\n\tX1 = " + blockX1 + "\n\tX2 = " + blockX2 + "\n\tX3 = " + blockX3);

                        if ((blockX.compareTo(blockX1) == 0) || (blockX.compareTo(blockX2) == 0) || (blockX.compareTo(blockX2) == 0)) {
                            // do nothing
                            TraceManager.addDev("Identical blocks! X");
                        } else {
                            TraceManager.addDev("Non Identical blocks! X");
                            // Modifying partition
                            partition.removeBlock(blockX);
                            partition.addIfNonEmpty(blockX1);
                            partition.addIfNonEmpty(blockX2);
                            partition.addIfNonEmpty(blockX3);


                            // Add two splitter to W if all are non null
                            if (!(blockX1.isEmpty()) && !(blockX2.isEmpty()) && !(blockX3.isEmpty())) {
                                // Add splitter (X, X1, X23) && (X23, X2, X3)
                                AUTPartition tmpP = new AUTPartition();
                                tmpP.addBlock(blockX);
                                tmpP.addBlock(blockX1);
                                tmpP.addBlock(AUTBlock.concat(blockX2, blockX3));
                                w.addPartition(tmpP);
                                tmpP = new AUTPartition();
                                tmpP.addBlock(AUTBlock.concat(blockX2, blockX3));
                                tmpP.addBlock(blockX2);
                                tmpP.addBlock(blockX3);
                                w.addPartition(tmpP);


                            } else {
                                // Add non empty individual block to W
                                AUTPartition tmpP;
                                if (!(blockX1.isEmpty())) {
                                    tmpP = new AUTPartition();
                                    tmpP.addBlock(blockX1);
                                    w.addPartition(tmpP);
                                }
                                if (!(blockX2.isEmpty())) {
                                    tmpP = new AUTPartition();
                                    tmpP.addBlock(blockX2);
                                    w.addPartition(tmpP);
                                }
                                if (!(blockX3.isEmpty())) {
                                    tmpP = new AUTPartition();
                                    tmpP.addBlock(blockX3);
                                    w.addPartition(tmpP);
                                }
                            }

                        }
                    }

                }

            }
        }
        TraceManager.addDev("\nAll done: it: " + maxIte + "\n---------");
        printConfiguration(partition, w);
        //TraceManager.addDev("------------------");

        // Generating new graph
        generateGraph(partition, alphabet);

    }

    // Assumes AUTElement have been added to transitions
    public void generateGraph(AUTPartition partition, HashMap<String, AUTElement> _alphabet) {
        ArrayList<AUTState> sts = new ArrayList<AUTState>();
        ArrayList<AUTTransition> trs = new ArrayList<AUTTransition>();
        HashMap<AUTBlock, AUTState> blockToNewStates = new HashMap<AUTBlock, AUTState>();

        int stID = 1;
        // We create one state per block
        // We look to the block that contains state 0 and we create the state id = 0
        for (AUTBlock bl : partition.blocks) {
            if (bl.hasState(0)) {
                AUTState st0 = new AUTState(0);
                blockToNewStates.put(bl, st0);
                sts.add(0, st0);
            } else {
                AUTState st = new AUTState(stID);
                stID++;
                blockToNewStates.put(bl, st);
                sts.add(st);
            }
        }

        // We now need to create the transitions
        // We parse all states in blocks, and consider their transition
        // We look for the destination and create a transition accordingly
        for (AUTBlock bl : partition.blocks) {
            AUTState newOrigin = blockToNewStates.get(bl);
            for (AUTState src : bl.states) {
                for (AUTTransition tr : src.outTransitions) {
                    AUTState newDestination = blockToNewStates.get(partition.getBlockWithState(tr.destination));

                    boolean foundSimilar = false;
                    AUTTransition newT = new AUTTransition(newOrigin.id, tr.transition, newDestination.id);
                    newT.elt = tr.elt;
                    for (AUTTransition testT : trs) {
                        if (testT.compareTo(newT) == 0) {
                            foundSimilar = true;
                            break;
                        }
                    }
                    if (!foundSimilar) {
                        trs.add(newT);
                        newOrigin.outTransitions.add(newT);
                        newDestination.inTransitions.add(newT);
                    }
                }
            }
        }

        states = sts;
        transitions = trs;
        nbState = sts.size();

        //TraceManager.addDev("New graph: " + toFullString());

    }


    public AUTGraph generateRefusalGraph() {
        computeStates();
        AUTState currentState = new AUTState(0);
        ArrayList<AUTState> newStates = new ArrayList<AUTState>();
        ArrayList<AUTTransition> newTransitions = new ArrayList<AUTTransition>();
        newStates.add(currentState);

        // We go thru the graph, starting at state1. Each time we meet an already handled state, we stop.
        HashSet<AUTState> metStates = new HashSet<AUTState>(); // in origin Graph
        HashMap<AUTState, AUTState> toRefusalState = new HashMap<AUTState, AUTState>();
        LinkedList<AUTState> toHandle = new LinkedList<AUTState>();
        toHandle.add(states.get(0));
        toRefusalState.put(states.get(0), currentState);

        while (toHandle.size() > 0) {
            AUTState current = toHandle.get(0);
            toHandle.remove(0);
            metStates.add(current);
            AUTState currentRefusal = toRefusalState.get(current);
            if (currentRefusal == null) {
                //TraceManager.addDev("NULL current Refusal");
            } else {
                // For each possible transition, we create a new transition to a new destination state
                for (AUTTransition tr : current.outTransitions) {
                    // Create new transition. Is a new state necessary?
                    AUTState destState = states.get(tr.destination);
                    AUTState stRefusal;
                    stRefusal = new AUTState(newStates.size());
                    newStates.add(stRefusal);
                    toRefusalState.put(destState, stRefusal);
                    AUTTransition trRefusal = new AUTTransition(current.id, tr.transition, stRefusal.id);
                    newTransitions.add(trRefusal);
                    stRefusal.addInTransition(trRefusal);
                    currentRefusal.addOutTransition(trRefusal);

                    if (!metStates.contains(destState)) {
                        if (!(toHandle.contains(destState))) {
                            toHandle.add(destState);
                        }
                    }

                }
            }
        }
        AUTGraph refusalGraph = new AUTGraph(newStates, newTransitions);

        return refusalGraph;
    }


    public AUTGraph makeTestSequencesFromRefusalGraph() {
        ArrayList<AUTState> newStates = new ArrayList<AUTState>();
        ArrayList<AUTTransition> newTransitions = new ArrayList<AUTTransition>();
        AUTState firstState = new AUTState(0);
        newStates.add(firstState);

        // Take all termination states of the refusal graph and get the shortest path
        // from the first state to this termination state
        // Add this path as a new path of the new graph

        computeStates();

        DijkstraState[] allPaths = GraphAlgorithms.LongestPathFrom(this, 0);

        for (AUTState state : states) {
            if (state.isTerminationState()) {
                int[] path = allPaths[state.id].path;
                if (path != null) {
                    AUTState currentStateN = firstState;
                    // We create a corresponding path in the new graph.
                    String s = "";
                    for (int j = 0; j < path.length; j++) {
                        s += path[j] + " ";
                    }
                    //TraceManager.addDev("path=" + s);
                    for (int i = 1; i < path.length; i++) {
                        AUTState currentState = states.get(path[i - 1]);
                        AUTState nextState = states.get(path[i]);

                        AUTTransition tr = currentState.getTransitionTo(nextState.id);
                        //TraceManager.addDev("Looking for transition");
                        if (tr != null) {
                            // We need to create the destination state
                            AUTState newDest = new AUTState(newStates.size());
                            newStates.add(newDest);
                            AUTTransition newTr = new AUTTransition(currentStateN.id, tr.transition, newDest.id);
                            newTransitions.add(newTr);
                            //TraceManager.addDev("Adding transition:" + newTr);
                            currentStateN = newDest;
                        } else {
                            //TraceManager.addDev(" -> null transitions");
                        }
                    }
                }
            }
        }


        // Making the graph
        AUTGraph testGraph = new AUTGraph(newStates, newTransitions);

        return testGraph;

    }


    private void printConfiguration(AUTPartition _part, AUTSplitter _w) {
        TraceManager.addDev("P={" + _part.toString() + "}");
        TraceManager.addDev("W={" + _w.toString() + "}");
    }

    private void printI(LinkedList<AUTBlock> I) {
        StringBuffer sb = new StringBuffer("I:");
        for (AUTBlock b : I) {
            sb.append(" " + b);
        }
        TraceManager.addDev(sb.toString());

    }


    public int getMinValue(String nameOfTransition) {
        int minValue = Integer.MAX_VALUE;
        //System.out.println("executing. min value");
        for (AUTTransition tr: transitions) {
            //System.out.println("executing. Dealing with " + tr.transition);
            if (tr.transition.length() > 3) {
                String trans = tr.transition.substring(2, tr.transition.length()-1);
                //System.out.println("executing. trans " + trans);
                int index = trans.indexOf("<");
                if (index > 0) {
                    String trName = trans.substring(0, index);
                    //System.out.println("executing. trName " + trName);
                    if (trName.equals(nameOfTransition)) {
                        String valS = trans.substring(index + 1);
                        //System.out.println("executing. valS " + valS);
                        int indexE = valS.indexOf(">");
                        if (indexE > 0) {
                            valS = valS.substring(0, indexE);
                            System.out.println("executing. max valS " + valS);
                            int val = Integer.decode(valS);
                            if (val < minValue) {
                                minValue = val;
                            }
                        }
                    }
                }
            }
        }
        return minValue;
    }

    public int getMaxValue(String nameOfTransition) {
        int maxValue = -1;
        //System.out.println("executing. min value");
        for (AUTTransition tr: transitions) {
            //System.out.println("executing. Dealing with " + tr.transition);
            if (tr.transition.length() > 3) {
                String trans = tr.transition.substring(2, tr.transition.length()-1);
                //System.out.println("executing. trans " + trans);
                int index = trans.indexOf("<");
                if (index > 0) {
                    String trName = trans.substring(0, index);
                    //System.out.println("executing. trName " + trName);
                    if (trName.equals(nameOfTransition)) {
                        String valS = trans.substring(index + 1);
                        //System.out.println("executing. valS " + valS);
                        int indexE = valS.indexOf(">");
                        if (indexE > 0) {
                            valS = valS.substring(0, indexE);
                            System.out.println("executing. min valS " + valS);
                            int val = Integer.decode(valS);
                            if (val > maxValue) {
                                maxValue = val;
                            }
                        }
                    }
                }
            }
        }
        return maxValue;
    }


}