Package eas.simulation.spatial.sim2D.marbSimulation.endlAutomat

Source Code of eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.EndlicherAutomat

/*
* Datei:            EndlicherAutomat.java
* Autor(en):        Lukas König
* Java-Version:     6.0
* Erstellt (vor):   15.10.2008
*
* (c) This file and the EAS (Easy Agent Simulation) framework containing it
* is protected by Creative Commons by-nc-sa license. Any altered or
* further developed versions of this file have to meet the agreements
* stated by the license conditions.
*
* In a nutshell
* -------------
* You are free:
* - to Share -- to copy, distribute and transmit the work
* - to Remix -- to adapt the work
*
* Under the following conditions:
* - Attribution -- You must attribute the work in the manner specified by the
*   author or licensor (but not in any way that suggests that they endorse
*   you or your use of the work).
* - Noncommercial -- You may not use this work for commercial purposes.
* - Share Alike -- If you alter, transform, or build upon this work, you may
*   distribute the resulting work only under the same or a similar license to
*   this one.
*
* + Detailed license conditions (Germany):
*   http://creativecommons.org/licenses/by-nc-sa/3.0/de/
* + Detailed license conditions (unported):
*   http://creativecommons.org/licenses/by-nc-sa/3.0/deed.en
*
* This header must be placed in the beginning of any version of this file.
*/

package eas.simulation.spatial.sim2D.marbSimulation.endlAutomat;

import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Stack;

import eas.math.fundamentalAlgorithms.type2grammars.EarleyParser;
import eas.math.geometry.Geometry2D;
import eas.miscellaneous.StaticMethods;
import eas.miscellaneous.system.windowFrames.GeneralDialog;
import eas.simulation.agent.AbstractAgent;
import eas.simulation.spatial.sim2D.marbSimulation.Konstanten;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.conditions.Condition;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.conditions.ConstLeaf;
import eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.conditions.InnerNode;
import eas.simulation.spatial.sim2D.marbSimulation.translator.ConstantsTranslator;
import eas.simulation.spatial.sim2D.marbSimulation.translator.Translator;
import eas.simulation.spatial.sim2D.marbSimulation.translator.script.Script;
import eas.simulation.spatial.sim2D.marbSimulation.translator.script.ScriptInterpreter;
import eas.simulation.spatial.sim2D.marbSimulation.translator.versionOhneErgKante.ConstantsTranslatorWOC;
import eas.startSetup.ParCollection;
import eas.startSetup.marbBuilder.DargestellterGraph;
import eas.startSetup.marbBuilder.darstellungsModi.DarstModEA;
import eas.startSetup.marbBuilder.graph.Graph;
import eas.startSetup.marbBuilder.graph.Knoten;
import eas.startSetup.marbBuilder.zeichenModi.ArrowMaster;


/**
* Klasse zur Repräsentation eines endlichen Automaten.
*
* @author Lukas König
*/
public class EndlicherAutomat extends Graph {
   
    /**
     * Die Serial Version ID (generiert am 25. April 2007).
     */
    private static final long serialVersionUID = -3668557617529889755L;

    /**
     * Speichert den Namen des Startknotens.
     */
    private Integer startKnName = null;

    /**
     * Der Erkenner für die Sequenzgrammatik.
     */
    private EarleyParser seqErkenner;

    /**
     * The script interpreter.
     */
    private ScriptInterpreter scriptInterpreter;
   
    /**
     * Die Sequenz dieses Automaten. Wenn sie null ist, muss sie neu berechnet
     * werden.
     */
    private String sequenz;
   
    /**
     * Konstruktor.
     *
     * @param earl    Der Earley-Erkenner für die Sequenz-Grammatik.
     * @param scrInt  A script interpreter to generate automata from scripts.
     */
    public EndlicherAutomat(final EarleyParser    earl,
                            final ScriptInterpreter scrInt) {
        super();
        this.seqErkenner = earl;
        this.scriptInterpreter = scrInt;
        this.sequenz = null;
        this.currentState = this.holeStartzustand();
    }

    /**
     * Konstruktor, der den Automaten ohne Earley-Erkenner und
     * Script-Interpreter initialisiert.
     */
    public EndlicherAutomat() {
        this(null, null);
    }
   
    /**
     * Entfernt einen Knoten mit sämtlichen inzidenten Kanten.
     *
     * @param knotenName  Der Name des zu entfernenden Knotens.
     *
     * @return  True, falls der Knoten entfernt wurde, false, falls er nicht
     *          vorhanden war.
     */
    @Override
    public boolean entferneKnoten(final Integer knotenName) {
        final ArrayList<Integer> knotenlisteV;
        final ArrayList<Integer> knotenlisteN;
        Iterator<Integer>  it;
        Knoten          knoten;
        HashMap<Integer, Knoten> nachfolger;
        HashMap<Integer, Knoten> vorgaenger;

        nachfolger = this.holeKnoten(knotenName).holeNachfolger();
        vorgaenger = this.holeKnoten(knotenName).holeVorgaenger();
        knotenlisteN = new ArrayList<Integer>(nachfolger.keySet());
        knotenlisteV = new ArrayList<Integer>(vorgaenger.keySet());

        if (this.startKnName != null
            && this.startKnName.equals(knotenName)) {
            this.entferneStartZ();
        }

        if (this.holAdj().containsKey(knotenName)) {
            it = knotenlisteV.iterator();
            while (it.hasNext()) {
                knoten = this.holeKnoten(it.next());
                this.entferneKante(knoten.holeName(), knotenName);
                knoten.entferneNachfolger(this.holeKnoten(knotenName));
                knoten.entferneVorgaenger(this.holeKnoten(knotenName));
            }
            it = knotenlisteN.iterator();
            while (it.hasNext()) {
                knoten = this.holeKnoten(it.next());
                knoten.entferneNachfolger(this.holeKnoten(knotenName));
                knoten.entferneVorgaenger(this.holeKnoten(knotenName));
            }
            this.holAdj().remove(knotenName);
           
            this.sequenz = null;
           
            return true;
        } else {
            return false;
        }
    }

    /**
     * Fügt einen Knoten in den Graph ein. Ist der Knoten bereits vorhanden,
     * werden die zu ihm inzidenten Kanten eingefügt, die angehängte
     * Zusatzinformation wird jedoch nur angehängt, falls diese beim bereits
     * vorhandenen Knoten null war. (Siehe auch Javadoc der Klasse Graph!)
     *
     * @param knotenName  Der Name des neuen Knoten.
     * @param nachfolger  Die Nachfolger des Knotens.
     * @param vorgaenger  Die Vorg�nger des Knotens.
     * @param aktion      Zusatzinformationen für den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param param       Zusatzinformationen für den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param beds        Zusatzinformationen für den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param alt         Das Rekombinationsalter des Knotens.
     *
     * @return  True, falls der Knoten eingefügt wurde, false, falls er bereits
     *          vorhanden war (ob Kanten eingefügt wurden, geht nicht aus dem
     *          Rückgabewert hervor).
     */
    private boolean einfuegenKnoten(final Integer                  knotenName,
                                   final HashMap<Integer, Knoten> nachfolger,
                                   final HashMap<Integer, Knoten> vorgaenger,
                                   final int                      aktion,
                                   final int                      param,
                                   final List<Transition>         beds,
                                   final int                      alt) {
        boolean eingefuegt;
        boolean start = false;

        if (start) {
            if (this.startKnName != null
                && !this.startKnName.equals(knotenName)) {
                throw new RuntimeException(
                           Messages.getString("EndlicherAutomat."
                               + "VersucheinerMehrfachbelegung"
                               + "desStartknotens"));
            }
            this.startKnName = knotenName;
        }

        ZInfo zusatz = new ZInfo(aktion, param, beds, start, alt);

        eingefuegt =  super.einfuegenKnoten(knotenName,
                                            nachfolger,
                                            vorgaenger,
                                            zusatz);
       
        if (eingefuegt) {
            this.sequenz = null;
            return true;
        } else {
            return false;
        }
    }

    /**
     * Erstellt einen neuen Knoten mit dem übergebenen Namen und fügt ihn in
     * den Graph ein.
     *
     * @param knotenName  Der Name des neuen Knotens.
     * @param aktion      Zusatzinformationen für den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param param       Zusatzinformationen für den endlichen Automaten;
     *                    das sind: Aktion, Param. und Achsenbeschriftungen.
     * @param alt         Das Rekombinationsalter des Knotens.
     *
     * @return  True, falls der Knoten eingefügt wurde, false, falls er bereits
     *          vorhanden war.
     */
    public boolean einfuegenKnoten(final Integer knotenName,
                                   final int     aktion,
                                   final int     param,
                                   final int     alt) {
        int realAktion = aktion;

//        if (aktion == 106) {
//            System.out.println();
//            System.out.println();
//            System.out.println(Arrays.deepToString(Thread.currentThread().getStackTrace()).replace(',', '\n'));
//        }
       
        return this.einfuegenKnoten(knotenName,
                                    new HashMap<Integer, Knoten>(),
                                    new HashMap<Integer, Knoten>(),
                                    realAktion,
                                    param,
                                    null,
                                    alt);
    }

     /**
      * Überschreibung der Methode der Vaterklasse.
      *
      * @param knotenName   Ohne Funktion.
      * @param nachfolger   Ohne Funktion.
      * @param vorgaenger   Ohne Funktion.
      * @param information  Ohne Funktion.
      *
      * @return  Nichts.
      */
    @Override
    public boolean einfuegenKnoten(
            final Integer                  knotenName,
            final HashMap<Integer, Knoten> nachfolger,
            final HashMap<Integer, Knoten> vorgaenger,
            final ZInfo                    information) {
        throw new RuntimeException(
                Messages.getString("EndlicherAutomat."
                        + "BenutzungeinerunerlaubtenMethode"));
     }

    /**
     * Überschreibung der Methode der Vaterklasse.
     *
     * @param knotenName  Ohne Funktion.
     *
     * @return  Nichts.
     */
    @Override
    public boolean einfuegenKnoten(final Integer knotenName) {
        throw new RuntimeException(Messages.getString("EndlicherAutomat."
            + "BenutzungeinerunerlaubtenMethode"));
    }

    /**
     * Fügt eine Kante von Knoten1 nach Knoten2 ein, wobei die Bedingung bed
     * der Liste der Bedingungen von Knoten1 hinzugefügt wird.
     *
     * @param knotenName1  Erster zur Kante inzidenter Knoten.
     * @param knotenName2  Zweiter zur Kante inzidenter Knoten.
     * @param bedingung    Bedingung, unter der die Kante "durchlaufen werden"
     *                     soll.
     * @param alt          Das Alter der Transition, zu der die Bedingung
     *                     gehört.
     *
     * @return  Immer <code>true</code>.
     */
    public boolean einfuegKante(final Integer knotenName1,
                                final Integer knotenName2,
                                final String bedingung,
                                final int    alt) {

        return this.einfuegKante(knotenName1,
                                 knotenName2,
                                 StaticMethods.ausFormatBed(bedingung),
                                 alt);
    }

    /**
     * Fügt eine Kante von Knoten1 nach Knoten2 ein, wobei die Bedingung bed
     * der Liste der Bedingungen von Knoten1 hinzugefügt wird.
     *
     * @param knotenName1  Erster zur Kante inzidenter Knoten.
     * @param knotenName2  Zweiter zur Kante inzidenter Knoten.
     * @param cond         Bedingung, unter der die Kante "durchlaufen werden"
     *                     soll (in der <code>Condition</code> - Datenstruktur).
     * @param alt          Das Alter der Transition, zu der die Bedingung
     *                     gehört.
     *
     * @return  Immer <code>true</code>.
     */
    public boolean einfuegKante(final Integer    knotenName1,
                                final Integer    knotenName2,
                                final Condition  cond,
                                final int        alt) {

        final Knoten knoten1 = this.holeKnoten(knotenName1);
        final Knoten knoten2 = this.holeKnoten(knotenName2);
        ZInfo zusatz1;
        final Transition bed;

        if (!this.getAdjazenzliste().containsKey(knotenName1)
            || !this.getAdjazenzliste().containsKey(knotenName2)) {
            throw new RuntimeException(
                Messages.getString("EndlicherAutomat."
                    + "EinerderbeidenKnotenexistiertnicht"));
        }

        knoten1.neuerNachfolger(knoten2);
        knoten2.neuerVorgaenger(knoten1);

        zusatz1 = knoten1.getInfo();
        bed = new Transition(cond,
                             knotenName1.intValue(),
                             knotenName2.intValue(),
                             alt);

        zusatz1.addBedingung(bed);
       
        this.sequenz = null;

        return true;
    }

    /**
     * Überschreibung der Methode der Vaterklasse.
     *
     * @param knotenName1  Ohne Funktion.
     * @param knotenName2  Ohne Funktion.
     *
     * @return  Nichts.
     */
// TODO from UCDetector: Method "EndlicherAutomat.einfuegenKante(Object,Object)" has 0 references
    @Override
    public boolean einfuegenKante(final Integer knotenName1, // NO_UCD
                                  final Integer knotenName2) {
        throw new RuntimeException(
            Messages.getString("EndlicherAutomat."
                + "BenutzungeinerunerlaubtenMethode"));
    }

    /**
     * Entfernt eine Kante zwischen zwei benachbarten Knoten.
     *
     * @param knotenName1  Der erste der benachbarten Knoten (Vorg�nger).
     * @param knotenName2  Der zweite der benachbarten Knoten (Nachfolger).
     *
     * @return  True, falls eine Kante zwischen den Knoten
     *          existiert hat, die entfernt werden konnte, false in allen
     *          anderen Fällen.
     */
    @Override
    public boolean entferneKante(final Integer knotenName1,
                                 final Integer knotenName2) {
        boolean entfernt;
        ZInfo zusatz;

        entfernt = this.holeKnoten(knotenName1).entferneNachfolger(
                   this.holeKnoten(knotenName2));
        entfernt = entfernt
                   && this.holeKnoten(knotenName2).entferneVorgaenger(
                       this.holeKnoten(knotenName1));

        zusatz = this.holeKnoten(knotenName1).getInfo();
        zusatz.entferneTransZuZustand(knotenName2);

        if (entfernt) {
            this.sequenz = null;
        }
       
        return entfernt;
    }

    /**
     * Entfernt eine Kante zwischen zwei benachbarten Knoten, die mit einer
     * angegebenen Bedingung beschriftet ist. Insbesondere wird NUR die
     * Bedingung gelöscht, falls mehrere Kanten zwischen den Knoten existieren.
     *
     * @param knotenName1  Der erste der benachbarten Knoten (Vorg�nger).
     * @param knotenName2  Der zweite der benachbarten Knoten (Nachfolger).
     * @param bed          Die Bedingung, die zur Kante gehört.
     *
     * @return  True, falls eine Kante zwischen den Knoten
     *          existiert hat, die entfernt werden konnte, false in allen
     *          anderen Fällen.
     */
    public boolean entferneKante(final Integer    knotenName1,
                                 final Integer    knotenName2,
                                 final Transition bed) {
        boolean entfernt;
        ZInfo zusatz = this.holeKnoten(knotenName1).getInfo();
        int intName2 = knotenName2.intValue();
       
        entfernt = zusatz.entferneBed(bed);
       
        if (zusatz.getTransZuZustand(intName2).size() == 0) {
       
            entfernt = entfernt
                       && this.holeKnoten(knotenName1).entferneNachfolger(
                          this.holeKnoten(knotenName2));
            entfernt = entfernt
                       && this.holeKnoten(knotenName2).entferneVorgaenger(
                          this.holeKnoten(knotenName1));
   
            zusatz = this.holeKnoten(knotenName1).getInfo();
            zusatz.entferneTransZuZustand(knotenName2.intValue());
       
        }
       
        if (entfernt) {
            this.sequenz = null;
        }
       
        return entfernt;
    }

    /**
     * Gibt eine Sequenz als String zurück.
     *
     * @param l  Die auszugebende Sequenz.
     *
     * @return  String.
     */
    public String ausgabe(final List<Integer> l) {
        Iterator<Integer> it = l.iterator();
        int zahl;
        String seq = new String();

        while (it.hasNext()) {
            zahl = it.next().intValue();

            if (!seq.equals("")) {
                seq = seq + ", ";
            }
            if (zahl < 100) {
                seq = seq + "0";
            }
            if (zahl < 10) {
                seq = seq + "0";
            }
            seq = seq + zahl;
        }

        return seq;
    }

    /**
     * Gibt die Automatensequenz von <code>this</code> als fertige
     * String-Sequenz in der Standardkodierung zurück.
     *
     * @return  Die Stringsequenz des Endlichen Automaten.
     */
    public String erzeugeStringSeq() {
        // TODO
        this.sequenz = null;
       
        if (this.sequenz == null) {
            this.sequenz = this.ausgabe(this.generateSequence());
        }

        return this.sequenz;
    }
   
    /**
     * Setzt die String-Sequenz auf null, als Zeichen, dass der Automat
     * von außen verändert wurde.
     */
    public void setSeqVeraendert() {
        this.sequenz = null;
    }
   
    /**
     * Gibt die zu <code>this</code> gehörende Automatensequenz in der
     * Standardkodierung zurück.
     *
     * @return  Die Automatensequenz.
     */
    public synchronized LinkedList<Integer> generateSequence() {
        LinkedList<Integer> seq = new LinkedList<Integer>();
        ArrayList<Knoten> alleKnot
            = new ArrayList<Knoten>(this.holAdj().values());
        Iterator<Knoten> it1;
        Iterator<Transition> it2;
        Knoten aktKnot;
        ZInfo aktZusatz;
        Integer aktName;
        Integer aktBefehl;
        Integer aktParam;
        Integer aktAlter;
        Transition aktBed;
        String bed;
        Integer folgeZu;
        String token;
        Stack<Character> stk;
        char tokC;
        Character c;
        Integer transAlter;

        // Sorgt dafür, dass der Startzustand am Beginn der Sequenz steht.
        Collections.sort(alleKnot, new StartZustKomp());

        it1 = alleKnot.iterator();
        while (it1.hasNext()) {
            aktKnot = it1.next();
            aktZusatz = aktKnot.getInfo();

            aktName = aktKnot.holeName();
            aktBefehl = new Integer(aktZusatz.getAktion());
            aktParam = new Integer(aktZusatz.getParam());
            aktAlter = new Integer(aktZusatz.getAlter());

            seq.add(aktName);
            seq.add(aktBefehl);
            seq.add(aktParam);
            seq.add(aktAlter);

            it2 = aktZusatz.getBeds().iterator();
            while (it2.hasNext()) {
                aktBed = it2.next();
                bed = aktBed.getCond().formatted();
                folgeZu = new Integer(aktBed.getFolgezustand());
                transAlter = new Integer(aktBed.getAlter());

                stk = new Stack<Character>();

                // " (  h 002 <  h 004 &  h 002 > 100 ) "
                for (int i = 0; i + 2 < bed.length(); i = i + 3) {
                    token = bed.substring(i, i + 3);
                    tokC = token.charAt(1);

                    if (tokC == Konstanten.KA) {
                        stk.push(new Character(Konstanten.KA));
                    } else if (tokC == Konstanten.KZ) {
                        while (!stk.empty()) {
                            c = stk.pop();
                            if (c.charValue() == Konstanten.KA) {
                                break;
                            } else {
                                seq.add(new Integer(Konstanten.TRENNZEICHEN));
                                seq.add(new Integer(
                                        this.sonderz2Code(c.charValue())));
                            }
                        }
                    } else if (StaticMethods.istOper(tokC)) {
                        if (stk.empty()) {
                            stk.push(new Character(tokC));
                        } else {
                            while (!stk.empty()) {
                                c = stk.pop();
                                if (c.charValue() == Konstanten.KA) {
                                    stk.push(c);
                                    break;
                                } else if (StaticMethods.istOper(c.charValue())) {
                                    if (this.schwaecher(c.charValue(), tokC)) {
                                        stk.push(c);
                                        break;
                                    } else {
                                        seq.add(new Integer(0));
                                        seq.add(new Integer(
                                            this.sonderz2Code(c.charValue())));
                                    }
                                }
//                              if (this.kleiner(c.charValue(), tokC)
//                                      || c.charValue() == Konstanten.KA) {
//                                      break;
//                                  }
                            }
                            stk.push(new Character(tokC));
                        }
                    } else {
                        if (StaticMethods.istSonderzeichen(tokC)) {
                            seq.add(new Integer(0));
                            seq.add(new Integer(this.sonderz2Code(tokC)));
                        } else {
                            seq.add(new Integer(Integer.parseInt(token)));
                        }
                    }
                }
                while (!stk.empty()) {
                    c = stk.pop();
                    seq.add(new Integer(0));
                    seq.add(new Integer(this.sonderz2Code(c.charValue())));
                }

                seq.add(new Integer(Konstanten.TRENNZEICHEN));
                seq.add(new Integer(Konstanten.TRENNZEICHEN));
                seq.add(folgeZu);
                seq.add(transAlter);
            }

            seq.add(new Integer(Konstanten.TRENNZEICHEN));
            seq.add(new Integer(Konstanten.TRENNZEICHEN));
            seq.add(new Integer(Konstanten.TRENNZEICHEN));
        }

        return seq;
    }

    /**
     * Gibt zurück, ob der erste der übergebenen Operatoren schw�cher bindet
     * als der zweite. Als Operatoren sind alle Character erlaubt, bei denen
     * die Methode <code>istOperator</code> <code>true</code> zurückgeben
     * würde.
     *
     * @param c1  Der erste Operator.
     * @param c2  Der zweite Operator.
     *
     * @return  Ob der erste Operator als der zweite Operator ist.
     */
    private boolean schwaecher(final char c1,
                               final char c2) {
        if (!StaticMethods.istOper(c1) || !StaticMethods.istOper(c2)) {
            throw new RuntimeException("Vergleichselement ist kein Operator.");
        }

        int i1;
        int i2;
        if (c1 == Konstanten.UND || c1 == Konstanten.ODER) {
            i1 = 1;
        } else {
            i1 = 2;
        }

        if (c2 == Konstanten.UND || c2 == Konstanten.ODER) {
            i2 = 1;
        } else {
            i2 = 2;
        }

        return i1 < i2;
    }

    /**
     * Erzeugt den Kode aus dem Buchstaben eines  Sonderzeichens. Sonderzeichen
     * sind alle Character, bei denen die Methode <code>istSonderzeichen</code>
     * <code>true</code> zurückgeben w�rde.
     *
     * @param c  Der zu kodierende Buchstabe.
     *
     * @return  Der Kode des Buchstabens.
     */
    private int sonderz2Code(final char c) {
        if (c == Konstanten.EING) {
            return Konstanten.EING_CODE;
        } else if (c == Konstanten.FALSE) {
            return Konstanten.FALSE_CODE;
        } else if (c == Konstanten.GL) {
            return Konstanten.GL_CODE;
        } else if (c == Konstanten.GR) {
            return Konstanten.GR_CODE;
        } else if (c == Konstanten.GRGL) {
            return Konstanten.GRGL_CODE;
        } else if (c == Konstanten.KA) {
            return Konstanten.KA_CODE;
        } else if (c == Konstanten.KL) {
            return Konstanten.KL_CODE;
        } else if (c == Konstanten.KLGL) {
            return Konstanten.KLGL_CODE;
        } else if (c == Konstanten.KZ) {
            return Konstanten.KZ_CODE;
        } else if (c == Konstanten.ODER) {
            return Konstanten.ODER_CODE;
        } else if (c == Konstanten.TRUE) {
            return Konstanten.TRUE_CODE;
        } else if (c == Konstanten.UGL) {
            return Konstanten.UGL_CODE;
        } else if (c == Konstanten.UND) {
            return Konstanten.UND_CODE;
        } else if (c == Konstanten.UNGF) {
            return Konstanten.UNGF_CODE;
        } else if (c == Konstanten.NUNGF) {
            return Konstanten.NUNGF_CODE;
        } else {
            throw new RuntimeException("Undefiniertes Sonderzeichen.");
        }
    }

    /**
     * Entfernt ungültige Zeichen aus dem String und fügt bei Zahlen, die aus
     * weniger als drei Ziffern bestehen entsprechend viele Nullen an.
     *
     * @param seqOrig  Die zu bereinigende Sequenz.
     *
     * @return  Die bereinigte Sequenz.
     */
    public static String bereinigeStatic(final String seqOrig) {
        return new EndlicherAutomat().bereinige(seqOrig);
    }
   
    /**
     * Entfernt ungültige Zeichen aus dem String und fügt bei Zahlen, die aus
     * weniger als drei Ziffern bestehen entsprechend viele Nullen an.
     *
     * @param seqOrig  Die zu bereinigende Sequenz.
     *
     * @return  Die bereinigte Sequenz.
     */
    public synchronized String bereinige(final String seqOrig) {
        String seq = " " + seqOrig;
        String seq1 = "";
        String seq2 = "";
        boolean trennSymb = false;
        String zwisch;

        for (int i = 0; i < seq.length(); i++) {
            if (StaticMethods.istZiff(seq.charAt(i))) {
                seq1 = seq1 + seq.charAt(i);
                trennSymb = false;
            } else {
                if (!trennSymb) {
                    seq1 = seq1 + " ";
                }
                trennSymb = true;
            }
        }

        if (!StaticMethods.istZiff(seq1.charAt(seq1.length() - 1))) {
            seq1 = seq1.substring(0, seq1.length() - 1);
        }

        zwisch = "";
        for (int i = 0; i < seq1.length(); i++) {
            if (StaticMethods.istZiff(seq1.charAt(i))) {
                zwisch = zwisch + seq1.charAt(i);
            } else {
                if (zwisch.length() == 3) {
                    seq2 = seq2 + zwisch;
                } else if (zwisch.length() == 2) {
                    seq2 = seq2 + "0" + zwisch;
                } else if (zwisch.length() == 1) {
                    seq2 = seq2 + "00" + zwisch;
//                } else if (zwisch.length() > 3) {
//                    throw new RuntimeException(
//                        Messages.getString("EndlicherAutomat."
//                            + "FehlerhafteSequenz"));
                }

                seq2 = seq2 + seq1.charAt(i);
                zwisch = "";
            }
        }
        if (zwisch.length() == 3) {
            seq2 = seq2 + zwisch;
        } else if (zwisch.length() == 2) {
            seq2 = seq2 + "0" + zwisch;
        } else if (zwisch.length() == 1) {
            seq2 = seq2 + "00" + zwisch;
//        } else if (zwisch.length() > 3) {
//            throw new RuntimeException(
//                Messages.getString("EndlicherAutomat."
//                    + "FehlerhafteSequenz"));
        }

        return seq2;
    }

    /**
     * Erzeugt eine Infix-Repräsentation einer Bedingung aus einer Postfix-
     * repräsentation.
     *
     * @param seq  Die Postfix-Repräsentation einer Bedingung.
     *
     * @return  Die Infix-Repräsentation der Bedingung.
     */
    private synchronized LinkedList<Integer> bedPost2in(
                      final LinkedList<Integer> seq) {
        Stack<LinkedList<Integer>> stk = new Stack<LinkedList<Integer>>();
        LinkedList<Integer> s1;
        LinkedList<Integer> s2;
        LinkedList<Integer> s3;
        int token;
        int i = 0;

        while (i < seq.size()) {
            token = seq.get(i).intValue();
            if (token == Konstanten.TRENNZEICHEN) {
                i++;
                token = seq.get(i).intValue();

                if (StaticMethods.istOperator(token)) {
                    s2 = stk.pop();
                    s1 = stk.pop();
                    if (token == Konstanten.ODER_CODE
                        || token == Konstanten.UND_CODE) {
                        s1.addFirst(new Integer(Konstanten.KA_CODE));
                        s1.addFirst(new Integer(0));
                        s1.add(new Integer(0));
                        s1.add(new Integer(token));
                        s1.addAll(s2);
                        s1.add(new Integer(0));
                        s1.add(new Integer(Konstanten.KZ_CODE));
                        stk.push(s1);
                    } else {
                        s1.add(new Integer(0));
                        s1.add(new Integer(token));
                        s1.addAll(s2);
                        stk.push(s1);
                    }
                } else {
                    s3 = new LinkedList<Integer>();
                    s3.add(new Integer(0));
                    s3.add(new Integer(token));
                    if (token == Konstanten.EING_CODE) {
                        i++;
                        token = seq.get(i).intValue();
                        s3.add(new Integer(token));
                    }
                    stk.push(s3);
                }
            } else {
                s3 = new LinkedList<Integer>();
                s3.add(new Integer(token));
                stk.push(s3);
            }

            i++;
        }

        return stk.pop();
    }

    /**
     * Fragt den Benutzer, ob seq auf Korrektheit überprüft werden soll und
     * überprüft diese im positiven Fall. Dabei ist die Korrektheit im Sinn
     * einer syntaktischen Richtigkeit bezogen auf die Standardkodierung
     * gemeint.
     *
     * @param seq  Die zu prüfende Sequenz.
     * @return  Ob die Sequenz korrekt ist oder der Benutzer keine Überprüfung
     *          angefordert hat.
     */
    private boolean seqKorrPruef(final String seq) {
        final GeneralDialog confirm;
        final GeneralDialog dia;
        final ArrayList<String> buttonsConf = new ArrayList<String>();
        buttonsConf.add(eas.startSetup.marbBuilder.Messages.getString("Vis.Yes"));
        buttonsConf.add(eas.startSetup.marbBuilder.Messages.getString("Vis.No"));
        buttonsConf.add(eas.startSetup.marbBuilder.Messages.getString("Vis.Cancel"));
        final ArrayList<String> buttons = new ArrayList<String>();
        buttons.add(eas.startSetup.marbBuilder.Messages.getString("SteuerFenster.OK"));


        confirm = new GeneralDialog(null,
        eas.startSetup.marbBuilder.Messages.getString(
                "SteuerFenster.ObSeqParsen"),
        eas.startSetup.marbBuilder.Messages.getString(
                "SteuerFenster.ObSeqParsenTitel"),
        buttonsConf,
        null);
        confirm.setVisible(true);
      
        if (confirm.getResult().equals(
                eas.startSetup.marbBuilder.Messages.getString(
                       "Vis.Yes"))) {
            if (!this.seqErkenner.erkenne(seq)) {
                dia = new GeneralDialog(null,
                        null,
                        eas.startSetup.marbBuilder.Messages.getString(
                            "SteuerFenster.Earley"),
                            buttons,
                        "<"
                        + seq
                        + ">\n\n\n"
                        + this.seqErkenner.toString());
                dia.setVisible(true);
                return false;
            }
        } else if (confirm.getResult().equals(
                eas.startSetup.marbBuilder.Messages.getString("Vis.Cancel"))) {
            return false;
        }
       
        return true;
    }

    /**
     * Erzeugt einen endlichen Automaten aus einer Sequenz mit einem
     * Translator und überschreibt <code>this</code> damit.
     *
     * @param seq      Die Sequenz des neuen Automaten.
     * @param trans    Der Translator, mit dem die Sequenz übersetzt werden
     *                 soll. Wenn hier <code>null</code> übergeben wird, wird
     *                 der Standardtranslator für Verhalten aus der Klasse
     *                 <code>Konstanten</code> des Pakets
     *                 <code>eas.endlAutomat.translator</code> verwendet.
     * @param pruefen  Gibt an, ob die Sequenz geprüft werden soll, bevor
     *                 der alte Automat überschrieben und ein neuer erzeugt
     *                 wird. Die überprüfung bezieht sich auf die Standard-
     *                 kodierung, ist also nicht sinnvoll, wenn ein anderer
     *                 Translator als der Standardtranslator übergeben wurde.
     */
    public synchronized void generateFromSequence(
            final String seq,
            final Translator trans,
            final boolean pruefen,
            final ParCollection params) {
        String seq2 = this.bereinige(seq);
        Translator trans2, konstTrBE;
       
        if (params.getParValueBoolean("UseTranslatorWITHCompletingTransitions")) {
            konstTrBE = ConstantsTranslator.getStdTranslatorBE(params);
        } else {
            konstTrBE = ConstantsTranslatorWOC.getStdTranslatorBE(params);
        }
       
        if (trans == null) {
            trans2 = konstTrBE;
        } else {
            trans2 = trans;
        }

        if (Konstanten.SEQUENZ_KORREKTHEIT_PRUEFEN) {
            if (pruefen) {
                if (!this.seqKorrPruef(seq2)) {
                    return;
                }
            }
        }
       
        /**
         * Anmerkung (Sabrina): if Teil der Bedingung war auskommentiert und wurde
         * wieder einkommentiert um das Aging nutzen zu können
         */
        // Falls nur Standardkodierung verwendet werden soll: (TODO!)
        if (params.getParValueBoolean("UseOnlyStandardDecoding")) {
            this.erzeugeAusStdSequenz(seq2, pruefen);
        } else {
            Script neuScript = trans2.translate(seq2);
            trans2.getScriptInterpreter().generateAutomaton(this, neuScript);
        }
    }
   
    /**
     * Erzeugt einen Endlichen Automaten aus einer Sequenz per fester
     * "Standardkodierung". Die Standardkodierung ist somit durch diese
     * Methode definiert.<BR>
     * <BR>
     * Diese Methode kann, wenn ein Translator zur Verfügung steht, immer
     * durch einen Aufruf von
     * <code>public synchronized void erzeugeAusSequenz(
     *      final String seq,
     *      final Translator trans,
     *      final boolean pruefen)</code>
     * ersetzt werden.
     *
     * @param seq      Die Sequenz, aus der der Automat erzeugt werden soll.
     */
    public synchronized void erzeugeAusStdSequenz(final String seq) {
        this.erzeugeAusStdSequenz(seq, false);
    }
   
    /**
     * Erzeugt einen Endlichen Automaten aus einer Sequenz per fester
     * "Standardkodierung". Die Standardkodierung ist somit durch diese
     * Methode definiert.<BR>
     * <BR>
     * Diese Methode kann, wenn ein Translator zur Verfügung steht, immer
     * durch
     * <code>public synchronized void erzeugeAusSequenz(
     *      final String seq,
     *      final Translator trans,
     *      final boolean pruefen)</code>
     * ersetzt werden.
     *
     * @param seq      Die Sequenz, aus der der Automat erzeugt werden soll.
     * @param pruefen  Gibt an, ob die Sequenz geprüft werden soll, bevor
     *                 der alte Automat überschrieben und ein neuer erzeugt
     *                 wird.
     */
    public synchronized void erzeugeAusStdSequenz(
            final String  seq,
            final boolean pruefen) {
        final String seq2 = this.bereinige(seq);

        if (Konstanten.SEQUENZ_KORREKTHEIT_PRUEFEN) {
            if (pruefen) {
                if (!this.seqKorrPruef(seq2)) {
                    return;
                }
            }
        }

        LinkedList<LinkedList<Integer>> zustaende
            = new LinkedList<LinkedList<Integer>>();
        LinkedList<Integer> zustand;
        LinkedList<LinkedList<Integer>> bedingungen;
        LinkedList<Integer> bedingung;
        LinkedList<Integer> folgeZustaende;
        LinkedList<Integer> kantenAlter;
        int folgeZ;
        int kantAlt;
        int aktZustand = 1000;
        Iterator<LinkedList<Integer>> it;
        Iterator<LinkedList<Integer>> it1;
        Iterator<Integer> it2;
        Iterator<Integer> it3;
        Iterator<Integer> it4;
       
        Integer aktTok;
        int letzt;
        int vletzt;
        String token;
        int[] tokenInt = new int[seq2.length() / 4];
        int j = 0;

        this.leereGraph();

        // Einzelne Ziffer-Tokens parsen.
        for (int i = 0; i < seq2.length(); i = i + 4) {
            token = seq2.substring(i + 1, i + 4);
            tokenInt[j] = Integer.parseInt(token);
            j = j + 1;
        }

        // Tokenliste in Zustände aufteilen.
        zustand = new LinkedList<Integer>();
        int i = 0;
        while (i < tokenInt.length) {
            if (tokenInt[i] == Konstanten.TRENNZEICHEN
                && tokenInt[i + 1] == Konstanten.TRENNZEICHEN
                && tokenInt[i + 2] == Konstanten.TRENNZEICHEN) {

                zustaende.add(zustand);
                zustand = new LinkedList<Integer>();
                i = i + 3;
            } else {
                zustand.add(new Integer(tokenInt[i]));
                i++;
            }
        }

        // Knoten erzeugen.
        j = 0;
        it = zustaende.iterator();
        while (it.hasNext()) {
            zustand = it.next();
            this.einfuegenKnoten(zustand.get(0),
                                zustand.get(1).intValue(),
                                zustand.get(2).intValue(),
                                zustand.get(3).intValue());
            if (j == 0) {
                this.setStart(this.holeKnoten(zustand.get(0)));
            }
            j++;
        }

        // Kanten erzeugen.
        it = zustaende.iterator();
        bedingungen = new LinkedList<LinkedList<Integer>>();
        folgeZustaende = new LinkedList<Integer>();
        kantenAlter = new LinkedList<Integer>();
        while (it.hasNext()) {
            zustand = it.next();

            it4 = zustand.iterator();
            if (it4.hasNext()) {
                aktZustand = it4.next().intValue();
                it4.next();
                it4.next();
                it4.next();
            }

            bedingung = new LinkedList<Integer>();
            j = 0;
            letzt = 1000;
            vletzt = 1000;
            while (it4.hasNext()) {
                aktTok = it4.next();

                bedingung.add(j, aktTok);
                if (letzt == Konstanten.TRENNZEICHEN
                    && vletzt == Konstanten.TRENNZEICHEN) {
                    bedingung.remove(j);
                    bedingung.remove(j - 1);
                    bedingung.remove(j - 2);
                    bedingungen.add(bedingung);
                    bedingung = new LinkedList<Integer>();
                    folgeZustaende.add(aktTok);
                    aktTok = it4.next();
                    kantenAlter.add(aktTok);

                    j = 0;
                    letzt = 1000;
                    vletzt = 1000;
                } else {
                    vletzt = letzt;
                    letzt = aktTok.intValue();
                    j++;
                }
            }

            it1 = bedingungen.iterator();
            it2 = folgeZustaende.iterator();
            it3 = kantenAlter.iterator();
            while (it1.hasNext() && it2.hasNext() && it3.hasNext()) {
                bedingung = it1.next();
                bedingung = this.bedPost2in(bedingung); // Umwandeln in Infix.
                folgeZ = it2.next();
                kantAlt = it3.next();
                this.einfuegKante(new Integer(aktZustand),
                                    new Integer(folgeZ),
                                    this.stringAusListe(bedingung),
                                    kantAlt);
            }

            bedingungen = new LinkedList<LinkedList<Integer>>();
            folgeZustaende = new LinkedList<Integer>();
            kantenAlter = new LinkedList<Integer>();
        }
    }

    /**
     * Erzeugt einen String aus der Kodierung durch eine Liste von Integern.
     *
     * @param liste  Die kodierte Liste.
     *
     * @return  Dekodierter String.
     */
    private String stringAusListe(final LinkedList<Integer> liste) {
        String bed = "";
        Iterator<Integer> it;
        int akt;

        it = liste.iterator();
        while (it.hasNext()) {
            akt = it.next().intValue();
            if (akt == Konstanten.TRENNZEICHEN) {
                akt = it.next().intValue();
                bed = bed + " ";
                if (akt == Konstanten.EING_CODE) {
                    bed = bed + Konstanten.EING;
                }
                if (akt == Konstanten.FALSE_CODE) {
                    bed = bed + Konstanten.FALSE;
                }
                if (akt == Konstanten.GL_CODE) {
                    bed = bed + Konstanten.GL;
                }
                if (akt == Konstanten.GR_CODE) {
                    bed = bed + Konstanten.GR;
                }
                if (akt == Konstanten.GRGL_CODE) {
                    bed = bed + Konstanten.GRGL;
                }
                if (akt == Konstanten.KA_CODE) {
                    bed = bed + Konstanten.KA;
                }
                if (akt == Konstanten.KL_CODE) {
                    bed = bed + Konstanten.KL;
                }
                if (akt == Konstanten.KLGL_CODE) {
                    bed = bed + Konstanten.KLGL;
                }
                if (akt == Konstanten.KZ_CODE) {
                    bed = bed + Konstanten.KZ;
                }
                if (akt == Konstanten.ODER_CODE) {
                    bed = bed + Konstanten.ODER;
                }
                if (akt == Konstanten.TRUE_CODE) {
                    bed = bed + Konstanten.TRUE;
                }
                if (akt == Konstanten.UGL_CODE) {
                    bed = bed + Konstanten.UGL;
                }
                if (akt == Konstanten.UND_CODE) {
                    bed = bed + Konstanten.UND;
                }
                if (akt == Konstanten.UNGF_CODE) {
                    bed = bed + Konstanten.UNGF;
                }
                if (akt == Konstanten.NUNGF_CODE) {
                    bed = bed + Konstanten.NUNGF;
                }
                bed = bed + " ";
            } else {
                if (akt < 10) {
                    bed = bed + "0";
                }
                if (akt < 100) {
                    bed = bed + "0";
                }
                bed = bed + akt;
            }
        }

        return bed;
    }

    /**
     * Setzt den Knoten k als Startknoten ein und entfernt diese Eigenschaft
     * vom fr�heren Startknoten.
     *
     * @param k  Der als Startknoten einzusetzenden Knoten. Bei null wird
     *           der Startknoten NICHT VERänderT.
     */
    public void setStart(final Knoten k) {
        if (k == null) {
            return;
        }
       
        Knoten knot = this.holeKnoten(k.holeName());
       
        if (this.startKnName != null) {
            this.holeKnoten(this.startKnName).getInfo().setStartZu(false);
        }

        knot.getInfo().setStartZu(true);
        this.startKnName = knot.holeName();
       
        this.sequenz = null;
    }
   
    /**
     * Setzt den Startknoten auf den ersten vorhandenen Knoten in der
     * Adjazenzliste oder löscht ihn, falls die Liste leer ist.
     */
    public void setStartBeliebig() {
        if (this.getAdjazenzliste().size() > 0) {
            this.setStart(this.getAdjazenzliste().values().iterator().next());
        } else {
            this.entferneStartZ();
        }
    }
   
    /**
     * Gibt den Startknoten des endlichen Automaten zurück.
     *
     * @return  Der Startknoten.
     */
    public Knoten holeStartzustand() {
        return this.holeKnoten(this.startKnName);
    }

    /**
     * Gibt zurück, ob der übergebene Knoten der Startknoten ist.
     *
     * @param k  Der zu überpf�fende Knoten.
     *
     * @return  Ob der Knoten der Startknoten ist.
     */
    public boolean istStartZ(final Knoten k) {
        return k.getInfo().istStartZ();
    }

    /**
     * Entfernt den Startzustand.
     */
    public void entferneStartZ() {
        if (this.startKnName != null) {
            this.holeKnoten(this.startKnName).getInfo().setStartZu(false);
            this.startKnName = null;
            this.sequenz = null;
        }
    }

    /**
     * Erzeugt einen leeren Graphen ohne Knoten und Kanten.
     */
    @Override
    public void leereGraph() {
        this.entferneStartZ();
        super.leereGraph();
        this.sequenz = "";
    }

    /**
     * fügt eine Clique, das heißt, einen vollst�ndig verbundenen Teilgraphen
     * aus den Knoten der Knotennamen, zum Graphen hinzu. Dabei werden keine
     * expliziten Selbstbez�ge (Schleifen) eingefügt; implizit können sich
     * aber Schleifen durch doppelte Vorkommen der Knotennamen oder durch
     * bereits im Graphen this vorhandene Knoten ergeben!
     *
     * ACHTUNG: Dabei werden die Knoten- und Kantenbeschriftungen mit
     *          Standardwerten belegt.
     *
     * @param knotenNamen  Die Namen der Knoten, die eingefügt werden sollen.
     */
    @Override
    public void einfClique(final ArrayList<Integer> knotenNamen) {
        for (int i = 0; i < knotenNamen.size(); i++) {
            this.einfuegenKnoten(knotenNamen.get(i), 1, 1, 1);
        }
        for (int i = 0; i < knotenNamen.size(); i++) {
            for (int j = 0; j < knotenNamen.size(); j++) {
                if (i != j) {
                    this.einfuegKante(knotenNamen.get(i),
                                        knotenNamen.get(j),
                                        " "
                                        + Konstanten.TRUE
                                        + " ",
                                        1);
                }
            }
        }
       
        this.sequenz = null;
    }

    /**
     * fügt einen Stern als Teilgraphen in den aktuellen Graph ein, also einen
     * Graphen, der einen ausgezeichneten mittleren Knoten hat, mit dem alle
     * anderen Knoten verbunden sind, und keine weiteren Kanten. Dabei
     * sind die KnotenNAMEN und die Information, die beim mittleren Knoten
     * zusätzlich gespeichert werden soll, als Parameter zu übergeben.
     * (Knotennamen können beliebige Objekte sein, also insbesondere auch die
     * gesamte Information tragen, die den Knoten ausmacht. Falls keine
     * strukturgleichen Knotennamen auftauchen sollen, müssen die zugehörigen
     * Klassen die Methoden equals und hashCode implementieren.)
     *
     * ACHTUNG: Dabei werden die Knoten- und Kantenbeschriftungen mit
     *          Standardwerten belegt.
     *
     * @param mittelKnoten  Der Name des Mittelknotens des Sterns.
     * @param andereKnoten  Die Namen der anderen, mit dem Mittelpunkt zu
     *                      verbindenden Knoten.
     */
    public void einfStern(final Integer       mittelKnoten,
                               final List<Integer> andereKnoten) {
        Integer           aktKnot;
        Iterator<Integer> it;

        this.einfuegenKnoten(mittelKnoten,
                             new HashMap<Integer, Knoten>(),
                             new HashMap<Integer, Knoten>(),
                             1,
                             1,
                             null,
                             1);

        it = andereKnoten.iterator();
        while (it.hasNext()) {
            aktKnot = it.next();
            this.einfuegenKnoten(aktKnot, 1, 1, 1);
            this.einfuegKante(mittelKnoten,
                                aktKnot,
                                " "
                                + Konstanten.TRUE
                                + " ",
                                1);
        }
       
        this.sequenz = null;
    }

    /**
     * Entfernt alle Leerzeichen aus dem String.
     *
     * @param str  Der String, aus dem die Leerzeichen entfernt werden sollen.
     *
     * @return  Der String ohne Leerzeichen.
     */
    private static String entferneLeerzeichen(final String str) {
        String neuerStr = "";

        for (int i = 0; i < str.length(); i++) {
            if (str.charAt(i) != ' ') {
                neuerStr = neuerStr + str.charAt(i);
            }
        }

        return neuerStr;
    }

    /**
     * Gibt die übergebene Bedingung formatiert zurück.
     *
     * @param bed  Die zu formatierende Bedingung.
     *
     * @return  Die formatierte Bedingung.
     */
    public static String formatBed(final String bed) {
        String zwischBed1 = entferneLeerzeichen(bed).toLowerCase();
        String zwischBed2 = zwischBed1.replaceAll("false", "f");
        String zwischBed3 = zwischBed2.replaceAll("true", "t");
        String zwischBed4 = zwischBed3.replaceAll("<=", "[");
        String zwischBed5 = zwischBed4.replaceAll(">=", "]");
        String zwischBed6 = zwischBed5.replaceAll("!=", "!");
        String zwischBed7 = zwischBed6.replaceAll("!~", "#");
        String zwischBed = zwischBed7;
           
        String neueBed = "";
        int i = 0;

        while (i < zwischBed.length()) {
            if (StaticMethods.istZiff(zwischBed.charAt(i))) {
                if (i + 1 >= zwischBed.length()
                    || !StaticMethods.istZiff(zwischBed.charAt(i + 1))) {
                    neueBed = neueBed + "00";
                    neueBed = neueBed + zwischBed.charAt(i);
                } else if (i + 2 >= zwischBed.length()
                           || !StaticMethods.istZiff(zwischBed.charAt(i + 2))) {
                        neueBed = neueBed
                                  + "0"
                                  + zwischBed.charAt(i)
                                  + zwischBed.charAt(i + 1);
                        i++;
                } else {
                    neueBed = neueBed
                              + zwischBed.charAt(i)
                              + zwischBed.charAt(i + 1)
                              + zwischBed.charAt(i + 2);
                    i = i + 2;
                }
            } else {
                if (StaticMethods.istSonderzeichen(zwischBed.charAt(i))) {
                    neueBed = neueBed
                              + " "
                              + zwischBed.charAt(i)
                              + " ";
                } else {
                    throw new RuntimeException(
                        "Ungültiges Zeichen in einer Bedingung: " + bed);
                }
            }
            i++;
        }

        return neueBed;
    }
   
    /**
     * Gibt eine HashMap mit allen Knotennamen und zugehörigen
     * Kantenbedingungen zurück (jeder Key ist ein Knotenname eines
     * Ursprungsknotens, der Value ist eine Liste der Bedingungen).
     * Insbesondere können daraus alle Kanten des Graphen abgeleitet werden.
     *
     * @return Eine HashMap mit allen Kantenbedingungen
     */
    public HashMap<Integer, LinkedList<Transition>> getAlleBedingungen() {
        HashMap<Integer, LinkedList<Transition>> alleBeds
            = new HashMap<Integer, LinkedList<Transition>>(
                    this.getAdjazenzliste().size());
        LinkedList<Transition> bedingungen;
        ArrayList<Integer> knotenNam
            = new ArrayList<Integer>(this.getAdjazenzliste().keySet());
        Iterator<Integer> it1 = knotenNam.iterator();
        Integer aktNam;
       
        while (it1.hasNext()) {
            aktNam = it1.next();
            bedingungen = this.holeKnoten(aktNam).getInfo().getBeds();
           
            alleBeds.put(aktNam, bedingungen);
        }
       
        return alleBeds;
    }
   
    /**
     * Gibt die unsortierte Liste aller vorhandenen Bedingungen zurück.
     *
     * @return  Die unsortierte Liste aller Bedingungen.
     */
    public ArrayList<Transition> getBedListe() {
        ArrayList<Transition> beds = new ArrayList<Transition>();
        ArrayList<Integer> knoten = this.getKnList();
        Iterator<Integer> it = knoten.iterator();
        Knoten aktKnoten;
       
        while (it.hasNext()) {
            aktKnoten = this.holeKnoten(it.next());
            beds.addAll(aktKnoten.getInfo().getBeds());
        }
       
        return beds;
    }
   
    /**
     * Gibt zurück, ob bereits eine Kante vom Knoten mit Namen knoten1 zum
     * Knoten mit Namen knoten2 existiert.
     *
     * @param knoten1  Der Name des Ausgangsknotens A.
     * @param knoten2  Der Name des Zielknotens Z.
     *
     * @return Ob eine Kante von A nach Z existiert.
     */
    public boolean kanteExistiert(
            final Integer knoten1,
            final Integer knoten2) {
        Knoten k1;

        if (knoten1 == null || knoten2 == null) {
            return false;
        }
       
        k1 = this.holeKnoten(knoten1);

        if (k1 == null) {
            return false;
        }
       
        return k1.holeNachfolger().containsKey(knoten2);
    }
   
    /**
     * Gibt eine Liste aller Knoten des Automaten zurück.
     * @return  Eine Liste aller Knoten des Automaten zurück.
     */
    public ArrayList<Integer> getKnList() {
        return new ArrayList<Integer>(this.getAdjazenzliste().keySet());
    }

    /**
     * Gibt zurück, ob l vom Startknoten aus erreichbar ist.
     *
     * @param l  Ein Zielknotenname.
     * @param wkeit  Die Mindest-Wahrscheinlichkeit, dass eine Kante wahr
     *               wird, um noch als erreichbar zu gelten.
     *
     * @return  Ob l vom Startknoten aus erreichbar ist.
     */
    public boolean erreichbarVonStart(
            final Integer l,
            final double wkeit) {
        return erreichbarVonAnderem(null, l, wkeit);
    }
   
    /**
     * Gibt zurück, ob l vom Startknoten aus erreichbar ist.
     * 
     * @param l  Der zu untersuchende Knoten.
     *
     * @return  Ob der Knoten l vom Startzustand mit beliebig kleiner Wkeit
     *          erreichbar ist.
     */
    public boolean erreichbar(final Integer l) {
        return this.erreichbarVonStart(l, -1);
    }
   
    /**
     * Gibt zurück, ob l von k aus erreichbar ist. Falls k == null, wird der
     * Startknoten gewählt.
     *
     * @param k  Ein Startknotenname (kann null sein).
     * @param l  Ein Zielknotenname.
     * @param wkeit  Die Mindest-Wahrscheinlichkeit, dass eine Kante wahr
     *               wird, um noch als erreichbar zu gelten.
     *
     * @return  Ob l von k aus erreichbar ist.
     */
    public boolean erreichbarVonAnderem(
            final Integer k,
            final Integer l,
            final double wkeit) {
        Knoten start;
        Knoten ziel;
       
        if (k == null) {
            start = this.holeStartzustand();
        } else {
            start = this.holeKnoten(k);
        }
       
        ziel = this.holeKnoten(l);
       
        if (start == null || ziel == null) {
            return false;
        }
           
        return erreichbar(start, ziel, new LinkedList<Knoten>(), wkeit);
    }
   
    /**
     * Gibt zurück, ob l von k aus erreichbar ist.
     *
     * @param k        Ein Knotenname (darf nicht null sein).
     * @param l        Ein Knotenname.
     * @param besucht  Liste bereits besuchter Knoten.
     * @param wkeit    Die Mindest-Wahrscheinlichkeit, dass eine Kante wahr
     *                 wird, um noch als erreichbar zu gelten.
     *
     * @return  Ob l von k aus erreichbar ist.
     */
    private boolean erreichbar(final Knoten k,
                               final Knoten l,
                               final LinkedList<Knoten> besucht,
                               final double wkeit) {
        ArrayList<Knoten> nachF;
        Iterator<Knoten> it;
       
        if (k == l) {
            return true;
        }
       
        if (besucht.contains(k)) {
            return false;
        }
       
        besucht.add(k);
        nachF = new ArrayList<Knoten>(k.holeNachfolger().values());

        it = nachF.iterator();
        while (it.hasNext()) {
            Knoten aktNachf = it.next();
           
            LinkedList<Transition> transs
                = k.getInfo().getTransZuZustand(
                        aktNachf.holeName().intValue());
            Iterator<Transition> it2 = transs.iterator();
           
            while (it2.hasNext()) {
                Transition trans = it2.next();
               
                if (wkeit <= 0 || StaticMethods.condStrength(
                   trans.getCond(),
                   eas.startSetup.marbBuilder.darstellungsModi.ConstantsDarstellung.STAERKE_ERST,
                   eas.startSetup.marbBuilder.darstellungsModi.ConstantsDarstellung.STAERKE_ZWEIT)
                   >= wkeit) {
                   
                    if (erreichbar(aktNachf, l, besucht, wkeit)) {
                        return true;
                    }
                } else {
                    break;
                }
            }
        }
       
        return false;
    }
   
    /**
     * Gibt die (erste) Bedingung zurück, mit der die Transition von k1 (mit
     * Namen kName1) nach k2 (mit Name kName2) beschriftet ist, falls eine
     * existiert, sonst null.
     *
     * @param kName1  Der Name von k1.
     * @param kName2  Der Name von k2.
     *
     * @return  Die Bedingung der Transition von k1 nach k2 oder null.
     */
    public Condition getCondZuTrans(final Integer kName1,
                                    final Integer kName2) {
        if (kName1 == null || kName2 == null) {
            return null;
        }

        Knoten k1 = this.holeKnoten(kName1);
        if (k1 == null) {
            return null;
        }
       
        ZInfo z = k1.getInfo();
        List<Transition> l = z.getTransZuZustand(kName2.intValue());
       
        if (l.size() > 0) {
            return l.get(0).getCond();
        } else {
            return null;
        }
    }
   
    /**
     * Vereinfacht den endlichen Automaten.<BR>
     * <BR>
     * Bisher implementiert: (1) Nichterreichbare Zustände löschen.
     *                       (2) true und false sowie andere Tautologien aus
     *                           nichttrivialen Transitionen entfernen.
     *                       (3) Inaktive Kanten entfernen.
     */
    public void vereinfache() {
        this.vereinfacheEinzeln();
        this.vereinfacheEinzeln();
    }
   
    /**
     * Vereinfacht den endlichen Automaten um eine Stufe - das bedeutet, dass
     * False-Kanten gelöscht werden, aber u.U. unverbundene Zustände
     * übrigbleiben können. Durch zweifachen Aufruf der Methode können diese
     * auch noch entfernt werden.<BR>
     * <BR>
     * Bisher implementiert: (1) Nichterreichbare Zustände löschen.
     *                       (2) true und false sowie andere Tautologien aus
     *                           nichttrivialen Transitionen entfernen.
     *                       (3) Inaktive Kanten entfernen.
     */
    private void vereinfacheEinzeln() {
        Integer knotenNam;
        LinkedList<Integer> zuEntf = new LinkedList<Integer>();
        ArrayList<Transition> beds;
        Iterator<Transition> it1;
        Iterator<Integer> it2;
        Transition trans;
       
        // Bedingungen vereinfachen.
        beds = this.getBedListe();       
        it1 = beds.iterator();
        while (it1.hasNext()) {
            trans = it1.next();
            Condition bedE = trans.getCond().simplify();
            trans.setBedingung(bedE.formatted());
        }
       
        // Unerreichbare Knoten löschen.
        it2 = this.getKnList().iterator();
        while (it2.hasNext()) {
            knotenNam = it2.next();
            if (!this.erreichbar(knotenNam)) {
                zuEntf.add(knotenNam);
            }
        }

        it2 = zuEntf.iterator();
        while (it2.hasNext()) {
            this.entferneKnoten(it2.next());
        }

        // Inaktive Kanten löschen.
        beds = this.getBedListe();
        it1 = beds.iterator();
        while (it1.hasNext()) {
            trans = it1.next();
            if (trans.getCond().getClass().equals(ConstLeaf.class)) {
                if (!trans.getCond().evaluiere(null)) {
                    this.entferneKante(
                        new Integer(trans.getUrsprungsZustand()),
                        new Integer(trans.getFolgezustand()),
                        trans);
                }
            }
           
        }
       
        this.sequenz = null;
    }
   
    /**
     * Erzeugt einen Automaten aus einem übergebenen Script.
     *
     * @param script  Das Script, aus dem der Automat erzeugt werden soll.
     */
    public void erzeugeAusScript(final String script, final ParCollection params) {
        this.scriptInterpreter.generateAutomaton(this, new Script(script, params));
        this.sequenz = null;
    }
   
    /**
     * @param knotenName  Der Name des gesuchten Knotens.
     *
     * @return  Ob der Knoten existiert.
     */
    public boolean knotenExistiert(final Integer knotenName) {
        return this.getAdjazenzliste().containsKey(knotenName);
    }

    /**
     * @return Returns the scriptInterpreter.
     */
    public ScriptInterpreter getScriptInterpreter() {
        return this.scriptInterpreter;
    }
   
    /**
     * Setzt das Objekt auf "changed" als Nachricht für die Observer.
     */
    public void setzeChanged() {
        this.setChanged();
    }
   
    /**
     * @return  Der Hashcode.
     */
    @Override
    public int hashCode() {
        final int prime = 31;
        long result = 1;
        for (int i : this.getAdjazenzliste().keySet()) {
            result += prime * result + i;
            for (int j : this.holeKnoten(i).holeNachfolger().keySet()) {
                result += prime * result + j;
            }
        }
       
        return (int) (result % Integer.MAX_VALUE);
    }

    /**
     * Wie die equals-Methode, nur ohne Standardgebrauch mit hashCode().
     *
     * @param obj  Der zu vergleichende Automat.
     *
     * @return  Ob dieser und der zu vergleichende Automat aequivalent sind.
     */
    @Override
    public boolean equals(final Object obj) {
        if (this == obj) {
            return true;
        }
       
        if (obj == null) {
            return false;
        }
       
        if (this.getClass() != obj.getClass()) {
            return false;
        }
       
        final EndlicherAutomat anderer = (EndlicherAutomat) obj;
       
        HashSet<Integer> s1 = new HashSet<Integer>();
        HashSet<Integer> s2 = new HashSet<Integer>();
        Knoten k2;
       
        s1.addAll(this.getAdjazenzliste().keySet());
        s2.addAll(anderer.getAdjazenzliste().keySet());
       
        // überprüfe vorhandene Knotennamen in Automaten.
        if (!s1.equals(s2)) {
            return false;
        }
       
        // überprüfe für jeden Knoten: Info und Nachfolger der Knoten.
        for (Knoten k : this.getAdjazenzliste().values()) {
            k2 = anderer.holeKnoten(k.holeName());
            s1.clear();
            s2.clear();
            s1.addAll(k.holeNachfolger().keySet());
            s2.addAll(k2.holeNachfolger().keySet());
           
            if (!s1.equals(s2)
                    || !k.getInfo().equals(k2.getInfo())) {
                return false;
            }
        }
       
        return true;
    }

    /**
     * ergänzt Knoten kn1 um eine Kante nach kn2, die immer greift, wenn
     * alle anderen Kanten false sind.
     *
     * @param kn1  Quellknoten.
     * @param kn2  Zielknoten.
     */
    public void ergaenze(final Integer kn1, final Integer kn2) {
        Condition cond = new ConstLeaf(true);
        Condition zwisch;
       
        if (this.holeKnoten(kn1).getInfo().getBedingungen().size() > 0) {
            cond = StaticMethods.ausFormatBed(
                    this.holeKnoten(kn1).getInfo().
                        getBedingungen().get(0).getCond().formatted());
            cond.negiere();
        }
       
        for (int i = 1;
            i < this.holeKnoten(kn1).getInfo().getBedingungen().size();
            i++) {
            zwisch = StaticMethods.ausFormatBed(
                    this.holeKnoten(kn1).getInfo().
                        getBedingungen().get(i).getCond().formatted());
            zwisch.negiere();
            cond = new InnerNode(
                    cond,
                    zwisch,
                    eas.simulation.spatial.sim2D.marbSimulation.Konstanten.UND);
        }
       
        cond = cond.simplify();
       
        if (!cond.equals(new ConstLeaf(false))) {
            this.einfuegKante(kn1, kn2, cond, 1);
        }
    }
   
    /**
     * @param scriInt  Der neue Scriptinterpreter.
     */
    public void setScriptInterpreter(final ScriptInterpreter scriInt) {
        this.scriptInterpreter = scriInt;
    }

    /**
     * Erzeugt eine Kopie dieses Automaten auf Basis seines Codes.
     *
     * @return Die Kopie deses Automaten.
     *
     * @throws CloneNotSupportedException Die CloneNotSupportedException.
     */
    @Override
    public Object clone() throws CloneNotSupportedException {
        EndlicherAutomat kopie = new EndlicherAutomat();
       
        kopie.erzeugeAusStdSequenz(this.erzeugeStringSeq(), false);
       
        return kopie;
    }
   
    /**
     * Bennent einen vorhandenen Knoten um. Alle Kanten werden entsprechend
     * umgebogen.
     *
     * @param alt  Der alte Name des Knotens.
     * @param neu  Der neue Name des Knotens.
     */
    public void knUmbenennen(final int alt, final int neu) {
        Knoten altK = this.holeKnoten(alt);
        LinkedList<Transition>outgoingTrans = altK.getInfo().getBedingungen();
        HashMap<Integer, Knoten> vorgaenger;
        boolean isStart;
       
//        if (altK == null) {
//            throw new RuntimeException("Knoten " + alt + " nicht vorhanden."
//                    + " Umbennenen nicht möglich.");
//        }

        if (this.holeKnoten(neu) != null) {
            throw new RuntimeException("Knoten " + neu + " existiert bereits."
                    + " Umbennenen nicht möglich.");
        }       
        vorgaenger = altK.holeVorgaenger();
        isStart = this.istStartZ(altK);
        altK.setName(neu);
        HashMap<Integer, Knoten> adj = this.getAdjazenzliste();
        adj.remove(alt);
        adj.put(neu, altK);

        for (Knoten vorg : vorgaenger.values()) {
            for (Transition t : vorg.getInfo().getTransZuZustand(alt)) {
                t.setFolgezustand(neu);
            }
        }
       
        for (int i = 0; i < outgoingTrans.size(); i++) {
            outgoingTrans.get(i).setUrsprungszustan(neu);
        }
       
        if (isStart) {
            this.startKnName = null;
            this.setStart(this.holeKnoten(neu));
        }
    }
   
    private Knoten currentState;

    /**
     * @return Returns the currentState.
     */
    public Knoten getCurrentState() {
        if (this.currentState == null) {
            this.currentState = this.holeStartzustand();
        }
        return this.currentState;
    }

    private boolean[] activeSensors = new boolean[7];
   
    /**
     * @return  List of sensors that are possibly needed in the calculation
     *          of the next state.
     */
    public boolean[] requestActiveSensors() {
        HashSet<Integer> set = new HashSet<Integer>();
       
        for (int i = 0; i < activeSensors.length; i++) {
            activeSensors[i] = false;
        }

        if (this.currentState != null) {
            for (Transition t : this.currentState.getInfo().getBedingungen()) {
                set.addAll(t.getCond().aktSens());
            }
        }
       
        for (Integer i : set) {
            activeSensors[i] = true;
        }
       
        return activeSensors;
    }
   
    /**
     * Changes the state of the automaton to the next state.
     *
     * @return  The OLD state of the automaton, i.e., BEFORE the state change.
     */
    public Knoten step(final AbstractAgent<?> agent, int[] sens) {
        ZInfo nodeInformation;
        Knoten oldState = this.getCurrentState();
        LinkedList<Transition> transitions;
        Iterator<Transition> itTrans;
        int folgeZ = 0;
        Transition currentTrans;

        if (this.currentState == null) {
            this.currentState = this.holeStartzustand();
        }
       
        if (this.currentState != null) {
            nodeInformation = this.currentState.getInfo();
            transitions = nodeInformation.getBeds();
            itTrans = transitions.iterator();
           
            this.currentState = null;
            while (itTrans.hasNext() && folgeZ == 0) {
                currentTrans = itTrans.next();
                if (currentTrans.getCond().evaluiereAgent(agent, sens)) {
                    folgeZ = currentTrans.getFolgezustand();
                    this.currentState = this.holeKnoten(new Integer(folgeZ));
                }
            }
        }

        return oldState;
    }

    public BufferedImage erzeugeDarstellung(ParCollection params) {
        final int width = 500;
        final int height = 500;
        ArrowMaster master = new ArrowMaster(params);
       
        BufferedImage img;
        DarstModEA dar = new DarstModEA(0, 0, width, height);
        DargestellterGraph darGraph = dar.erzeuge(this, null);
        List<Object> drawList = master.graph(darGraph);
        img = Geometry2D.erzBuffImgAusObjekten(drawList);
       
        return img;
    }
}
TOP

Related Classes of eas.simulation.spatial.sim2D.marbSimulation.endlAutomat.EndlicherAutomat

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.