/*
* Datei: EndlicherAutomat.java
* Autor(en): Lukas K�nig
* Java-Version: 6.0
* Erstellt (vor): 15.10.2008
*
* (c) Lukas K�nig, die Datei unterliegt der LGPL
* -> http://www.gnu.de/lgpl-ger.html
*/
package fmg.fmg8.endlAutomat;
import fmg.fmg8.earleyErkenner.EarleyErkenner;
import fmg.fmg8.endlAutomat.conditions.Condition;
import fmg.fmg8.endlAutomat.conditions.ConstLeaf;
import fmg.fmg8.endlAutomat.script.Script;
import fmg.fmg8.endlAutomat.script.ScriptInterpreter;
import fmg.fmg8.endlAutomat.translator.Translator;
import fmg.fmg8.graphVis.fensterDialoge.AllgemeinerDialog;
import fmg.fmg8.graphVis.graph.Graph;
import fmg.fmg8.graphVis.graph.Knoten;
import fmg.fmg8.sonstiges.SonstMeth;
import java.io.Serializable;
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;
/**
* Klasse zur Repr�sentation eines endlichen Automaten.
*
* @author Lukas K�nig
*/
public class EndlicherAutomat extends Graph implements Serializable {
/**
* 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 EarleyErkenner 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 EarleyErkenner earl,
final ScriptInterpreter scrInt) {
super();
this.seqErkenner = earl;
this.scriptInterpreter = scrInt;
this.sequenz = null;
}
/**
* 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.
*/
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).
*/
public 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 = (Integer) 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) {
return this.einfuegenKnoten(knotenName,
new HashMap<Integer, Knoten>(),
new HashMap<Integer, Knoten>(),
aktion,
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.
*/
public boolean einfuegenKnoten(final Object knotenName,
final HashMap<Object, Knoten> nachfolger,
final HashMap<Object, Knoten> vorgaenger,
final Object information) {
throw new RuntimeException(
Messages.getString("EndlicherAutomat."
+ "BenutzungeinerunerlaubtenMethode"));
}
/**
* �berschreibung der Methode der Vaterklasse.
*
* @param knotenName Ohne Funktion.
*
* @return Nichts.
*/
public boolean einfuegenKnoten(final Object 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,
SonstMeth.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.
*/
public boolean einfuegenKante(final Object knotenName1,
final Object 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.
*/
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 = (ZInfo) this.holeKnoten(knotenName1).getInfo();
zusatz.entferneTransZuZustand(((Integer) knotenName2).intValue());
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 = (ZInfo)
this.holeKnoten(knotenName1).getInfo();
int intName2 = ((Integer) 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 = (ZInfo)
this.holeKnoten(knotenName1).getInfo();
zusatz.entferneTransZuZustand(((Integer) 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 LinkedList<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 zur�ck.
*
* @return Die Stringsequenz des Endlichen Automaten.
*/
public String erzeugeStringSeq() {
// TODO
this.sequenz = null;
if (this.sequenz == null) {
this.sequenz = this.ausgabe(this.erzeugeSequenz());
}
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 zur�ck.
*
* @return Die Automatensequenz.
*/
public synchronized LinkedList<Integer> erzeugeSequenz() {
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 = (ZInfo) aktKnot.getInfo();
aktName = (Integer) 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 = (Character) 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 (SonstMeth.istOper(tokC)) {
if (stk.empty()) {
stk.push(new Character(tokC));
} else {
while (!stk.empty()) {
c = (Character) stk.pop();
if (c.charValue() == Konstanten.KA) {
stk.push(c);
break;
} else if (SonstMeth.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 (SonstMeth.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 = (Character) 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 (!SonstMeth.istOper(c1) || !SonstMeth.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 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 (SonstMeth.istZiff(seq.charAt(i))) {
seq1 = seq1 + seq.charAt(i);
trennSymb = false;
} else {
if (!trennSymb) {
seq1 = seq1 + " ";
}
trennSymb = true;
}
}
if (!SonstMeth.istZiff(seq1.charAt(seq1.length() - 1))) {
seq1 = seq1.substring(0, seq1.length() - 1);
}
zwisch = "";
for (int i = 0; i < seq1.length(); i++) {
if (SonstMeth.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 = ((Integer) seq.get(i)).intValue();
if (token == Konstanten.TRENNZEICHEN) {
i++;
token = ((Integer) seq.get(i)).intValue();
if (SonstMeth.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 = ((Integer) 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 AllgemeinerDialog confirm;
final AllgemeinerDialog dia;
final ArrayList<String> buttonsConf = new ArrayList<String>();
buttonsConf.add(fmg.fmg8.graphVis.Messages.getString("Vis.Yes"));
buttonsConf.add(fmg.fmg8.graphVis.Messages.getString("Vis.No"));
buttonsConf.add(fmg.fmg8.graphVis.Messages.getString("Vis.Cancel"));
final ArrayList<String> buttons = new ArrayList<String>();
buttons.add(fmg.fmg8.graphVis.Messages.getString("SteuerFenster.OK"));
confirm = new AllgemeinerDialog(null,
fmg.fmg8.graphVis.Messages.getString(
"SteuerFenster.ObSeqParsen"),
fmg.fmg8.graphVis.Messages.getString(
"SteuerFenster.ObSeqParsenTitel"),
buttonsConf,
null);
confirm.setVisible(true);
if (confirm.getResult().equals(
fmg.fmg8.graphVis.Messages.getString(
"Vis.Yes"))) {
if (!this.seqErkenner.erkenne(seq)) {
dia = new AllgemeinerDialog(null,
null,
fmg.fmg8.graphVis.Messages.getString(
"SteuerFenster.Earley"),
buttons,
"<"
+ seq
+ ">\n\n\n"
+ this.seqErkenner.toString());
dia.setVisible(true);
return false;
}
} else if (confirm.getResult().equals(
fmg.fmg8.graphVis.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>fmg.fmg7.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 erzeugeAusSequenz(
final String seq,
final Translator trans,
final boolean pruefen) {
String seq2 = this.bereinige(seq);
Translator trans2, konstTrBE;
konstTrBE = fmg.fmg8.endlAutomat.translator.Konstanten.STD_TRANSL_BE;
if (trans == null) {
trans2 = konstTrBE;
} else {
trans2 = trans;
}
if (Konstanten.SEQUENZ_KORREKTHEIT_PRUEFEN) {
if (pruefen) {
if (!this.seqKorrPruef(seq2)) {
return;
}
}
}
Script neuScript = trans2.translate(seq2);
trans2.getScriptInterpreter().generateAutomaton(this, neuScript);
/* TODO: Langfristig weglassen, dient nur Testzwecken:
Translator konstTrTR
= fmg.fmg8.endlAutomat.translator.Konstanten.STD_TRANSL_TR;
if (trans2.equals(konstTrBE) || trans2.equals(konstTrTR)) {
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"Teste Sequenz...",
trans2.getPars());
if (this.getClass().equals(EndlicherAutomat.class)) {
EndlicherAutomat aut = new EndlicherAutomat();
try {
aut.erzeugeAusSequenz(seq, pruefen);
} catch (final Exception e) {
SonstMeth.log(
SonstMeth.LOG_DEBUG,
" Test nicht durchgef�hrt - Kein Standardcode.",
trans2.getPars(),
"plain",
null);
return true;
}
if (aut.equals(this)) {
return true;
} else {
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"Test nicht erfolgreich.",
trans2.getPars(),
"plain",
null);
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"\nSequenz: " + seq,
trans2.getPars(),
"plain",
null);
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"\nErw�nscht: " + aut.erzeugeStringSeq(),
trans2.getPars(),
"plain",
null);
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"\nThis: " + this.erzeugeStringSeq(),
trans2.getPars(),
"plain",
null);
return false;
}
} else {
Translator aut = new Translator(
"",
new ScriptInterpreter(
null,
ScriptInterpreter.MODUS_VERHALTEN),
((Translator) this).getPars());
try {
aut.erzeugeAusSequenz(seq, pruefen);
} catch (final Exception e) {
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"Test nicht durchgef�hrt - ung�ltiger Code.",
trans2.getPars(),
"plain",
null);
}
if (aut.equals(this)) {
return true;
} else {
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"Test nicht erfolgreich.",
trans2.getPars(),
"plain",
null);
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"\nSequenz: " + seq,
trans2.getPars(),
"plain",
null);
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"\nErw�nscht: " + aut.erzeugeStringSeq(),
trans2.getPars(),
"plain",
null);
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"\nThis: " + this.erzeugeStringSeq(),
trans2.getPars(),
"plain",
null);
return false;
}
}
} else {
SonstMeth.log(
SonstMeth.LOG_DEBUG,
"Teste nicht.",
trans2.getPars());
return true;
}
*/
}
/**
* Erzeugt einen Endlichen Automaten aus einer Sequenz per fester
* "Standardkodierung". Die Standardkodierung ist 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 erzeugeAusSequenz(
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 = (LinkedList<Integer>) it.next();
it4 = zustand.iterator();
if (it4.hasNext()) {
aktZustand = ((Integer) it4.next()).intValue();
it4.next();
it4.next();
it4.next();
}
bedingung = new LinkedList<Integer>();
j = 0;
letzt = 1000;
vletzt = 1000;
while (it4.hasNext()) {
aktTok = (Integer) 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 = (Integer) 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 = ((Integer) it2.next()).intValue();
kantAlt = ((Integer) it3.next()).intValue();
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 = ((Integer) it.next()).intValue();
if (akt == Konstanten.TRENNZEICHEN) {
akt = ((Integer) 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) {
((ZInfo)
this.holeKnoten(this.startKnName).getInfo()).setStartZu(false);
}
((ZInfo) knot.getInfo()).setStartZu(true);
this.startKnName = (Integer) 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 ((ZInfo) k.getInfo()).istStartZ();
}
/**
* Entfernt den Startzustand.
*/
public void entferneStartZ() {
if (this.startKnName != null) {
((ZInfo)
this.holeKnoten(this.startKnName).getInfo()).setStartZu(
false);
this.startKnName = null;
this.sequenz = null;
}
}
/**
* Erzeugt einen leeren Graphen ohne Knoten und Kanten.
*/
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.
*/
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 (SonstMeth.istZiff(zwischBed.charAt(i))) {
if (i + 1 >= zwischBed.length()
|| !SonstMeth.istZiff(zwischBed.charAt(i + 1))) {
neueBed = neueBed + "00";
neueBed = neueBed + zwischBed.charAt(i);
} else if (i + 2 >= zwischBed.length()
|| !SonstMeth.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 (SonstMeth.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(((ZInfo) 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 von k aus erreichbar ist. Falls k == null, wird der
* Startknoten gew�hlt. Dabei werden nur topologische Eigenschaften
* betrachtet, ob Kantenbedingungen erf�llbar sind, wird nicht gepr�ft.
*
* @param k Ein Startknotenname (kann null sein).
* @param l Ein Zielknotenname.
*
* @return Ob l von k aus erreichbar ist.
*/
public boolean erreichbar(final Integer k, final Integer l) {
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>());
}
/**
* 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.
*
* @return Ob l von k aus erreichbar ist.
*/
private boolean erreichbar(final Knoten k,
final Knoten l,
final LinkedList<Knoten> besucht) {
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 = (Knoten) it.next();
LinkedList<Transition> transs
= ((ZInfo) k.getInfo()).getTransZuZustand(
((Integer) aktNachf.holeName()).intValue());
Iterator<Transition> it2 = transs.iterator();
while (it2.hasNext()) {
Transition trans = (Transition) it2.next();
// Pr�fen, ob Bedingung potentiell erf�llbar (nicht false).
if (!trans.getCond().getClass().equals(ConstLeaf.class)
|| trans.evaluiere(null)) {
if (erreichbar(aktNachf, l, besucht)) {
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 = (ZInfo) k1.getInfo();
List<Transition> l = z.getTransZuZustand(((Integer) kName2).intValue());
if (l.size() > 0) {
return ((Transition) 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() {
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(null, 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) {
this.scriptInterpreter.generateAutomaton(this, new Script(script));
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;
}
/**
* @param scriInt Der neue Scriptinterpreter.
*/
public void setScriptInterpreter(final ScriptInterpreter scriInt) {
this.scriptInterpreter = scriInt;
}
}