JADE



Java® Decision Diagram Package


Jochen Römmler
roemmler@informatik.uni-freiburg.de

Rolf Drechsler
drechsle@informatik.uni-bremen.de

 

Inhaltsverzeichnis

1. Einleitung * 1.1. Warum gerade BDDs? *
1.2. Die Vorteile von Java *
1.3. Themen dieses Dokuments *
2. Theoretische Grundlagen * 2.1. Notation *
2.2. Reduktionstypen im BDD *
2.3. Anwendungsmöglichkeiten von BDDs *
2.4. Implementation *
2.4.1. Notationen *
2.4.2. Der ITE-Operator *
2.4.3. Die "Unique-Table" *
2.4.4. Der ITE-Algorithmus und ein Beispiel dazu *
2.4.5. Mögliche Erweiterungen *  

2.4.5.1. "Memory-Funktion" für ITE *
2.4.5.2. Komplementäre Kanten *
2.4.5.3. Standard-Tripel für ITE *

3. Installation und Benutzung des Programms * 3.1. Installation *
3.1.1. Systemvoraussetzungen *
3.1.2. Installation / Starten unter UNIX / Linux *
3.1.3. Installation / Starten unter Win32 Betriebssystemen *
3.2. Die Benutzeroberfläche - Gesamtüberblick *
3.2.1. Markierung von Knoten *
3.2.2. Interaktive Variablensortierung *
3.2.3. Zoom *
3.3. Die Benutzeroberfläche im Einzelnen *
3.3.1. Die Formeleingabezeile *
3.3.2. Die Kontrollbuttons *
3.3.3. Variablensortierung einstellen… *
3.3.4. Die Menüpunkte im Einzelnen *  

3.3.4.1. Das File-Menü *
3.3.4.2. Das View-Menü *
3.3.4.3. Das I-T-E-Menü *
3.3.4.4. Verbose-Level-Menü *
3.3.4.5. ?-Menü *

3.4. Parameter der Applikation *
4. Programmtechnische Realisierung * 4.1. Der Parser *
4.2. Speicherung der Knoten *
4.3. Bekannte Einschränkungen und Fehler *
5. Inhalt der CD * 5.1. Für Entwickler *
5.2. Für Anwender *
6. Literatur *
 
 
  1. Einleitung

  2. Die Grundidee dieser Arbeit ist, eine grafische Veranschaulichung beliebiger Boolscher Funktionen in Form spezieller sog. Entscheidungsdiagramme (engl. decision diagrams) zu realisieren.

    Der Benutzer soll in einer einfachen grafischen Oberfläche eine Boolsche Funktion mit allen wichtigen logischen Operatoren (inkl. NOT, AND, OR, NOR, XOR, NAND, …) über einer (fast) beliebigen Variablenmenge eingeben können. Das Programm soll die eingegebene Formel interpretieren (engl. Fachbegriff parsen) und gleichzeitig eine spezielle Datenstruktur (BDD, engl. binary decision diagram) erstellen, welche die eingegebene Funktion eindeutig repräsentiert. Die Eindeutigkeit (Kanonizität) dieser Repräsentation wird dabei eine zentrale Rolle spielen. Das "Synthetisieren" dieser Datenstruktur übernimmt ein spezieller Synthesealgorithmus, genannt "ITE", der sich gerade bei solchen Funktionen anbietet, die durch BDDs repräsentiert werden, wie in dieser Arbeit.

    Um die eben geforderte Kanonizität der Repräsentation zu gewährleisten, müssen wir fordern, daß zu jeder fest gewählten Boolschen Funktion genau ein BDD existiert. Dafür brauchen wir zuerst eine feste Ordnung der Variablen in der Funktion, die sogenannte Variablensortierung, damit wir die Reihenfolge der Zerlegung der Funktion festhalten. Wir erhalten ein geordneten BDD, oder kurz OBDD (engl. ordered binary decision diagram). Zusätzlich wird mittels Reduktion aus der verbleibenden Menge äquivalenter OBDDs genau einer zur Repräsentation einer bestimmten Funktion ausgewählt. Daraus ergibt sich dann die geforderte Kanonizität (Beweis siehe [1], Seite 14). Ein derart vollständig reduzierter, geordneter BDD heißt also kurz ROBDD (engl. reduced ordered binary decision diagram). BDDs sind also eine echte Obermenge von ROBDDs.

       
    1. Warum gerade BDDs?

    2. BDDs sind heute sehr beliebt und können Ansätze für viele verschiedene Problemstellungen sein. Sie haben sich zu einer Art "Standarddatenstruktur" entwickelt, sind gut erforscht und lassen sich einfach handhaben – auch wenn es Anwendungen gibt, für die BDDs zu eingeschränkt / aufwendig sind.

    3. Die Vorteile von Java

    4. Die Programmiersprache Java der Firma SUN® zeichnet sich im Umgang mit speicherintensiven Funktionen als sehr flexibel und einfach zu bedienen aus (Stichwort "garbage collection"…). Außerdem ist Java durch seine Ähnlichkeit zu vorhandenen Standard-Programmiersprachen (wie C++) einfach zu erlernen, und es gibt es eine ganze Reihe vorgefertigter Grafik- und Hilfsroutinen. Nicht zuletzt verspricht der Einsatz von Java Plattformunabhängigkeit.

    5. Themen dieses Dokuments

    6. Kapitel 2 wird sich näher mit der theoretischen Grundlage der Arbeit befassen, sowie wichtige Begriffe klären, die immer wieder auftauchen werden.

      Technischer wird es dann in Kapitel 3. Hier wird auf die Installation und Benutzung des Programms selber eingegangen. Im einzelnen werden die Menüpunkte erklärt und mit Bildschirmfotos erläutert.

      Einiges zur programmtechnischen Realisierung (Implementierung) dieser Arbeit in Java wird in Kapitel 4 gegeben.

      Auf der CD zur Arbeit befindet sich auch eine Entwickler-Dokumentation, die in allen Einzelheiten die Klassen, Methoden und Variablen der Applikation und seiner Module für den interessierten Programmierer/Weiterentwickler dieser Software erklärt. Diese Dokumentation wurde automatisch generiert mit dem Java-Tool javadoc. Es extrahiert Klasseninformationen und Autorenkommentare und -verweise aus dem Quelltext und erstellt eine komplette HTML-Hilfestruktur. Eine geeignete Übersicht erhält man in der Datei index.html. Voraussetzung zur fehlerfreien Anzeige ist lediglich ein "frame"-fähiger Browser.

      Näheres zum Inhalt der CD befindet sich in Kapitel 5.

  3. Theoretische Grundlagen

  4. Theoretische Grundlage der Realisierung ist ein BDD-Package dreier Amerikaner: Karl S. Brace, Richard L. Rudell und Randal E. Bryant – vorgestellt 1990 auf der 27th ACM/IEEE Design Automation Conference (vgl. dazu [3]). In ihrem Package entstehen ROBDDs durch rekursive Aufrufe des sogenannten ITE-Operators. Als Operanden werden dafür drei fertige ROBDDs (im Weiteren mit F, G und H bezeichnet) benötigt, welche dann zu einem neuen, größeren ROBDD verschmelzen. Wichtig bei dieser Art der Synthese ist es, die Kanonizität der so erzeugten ROBDDs zu gewährleisten.

       
    1. Notation

    2. Ein binary decision diagram (BDD) ist ein gerichteter azyklischer Graph mit genau zwei Senken (=Blätter), die mit 0 und 1 bezeichnet werden und welche die Boolschen Funktionen 0 und 1 repräsentieren. Alle (anderen) Knoten im Graph werden mit einer Boolschen Variable xi (i ³ 0) bezeichnet; sie bilden die inneren Knoten. Diese inneren Knoten haben jeweils genau zwei ausgehende Kanten, die einmal mit 0 ("low"-Kante oder "low"-Sohn) und einmal mit 1 ("high"-Kante oder "high"-Sohn) bezeichnet werden. Dabei verweist die ausgehende "low"-Kante auf einen Knoten, der die entsprechende Boolsche Funktion für xi = 0 repräsentiert, und die ausgehende "high"-Kante auf einen Knoten, der die entsprechende Boolsche Funktion für xi = 1 repräsentiert. An jedem Knoten wird also entschieden, ob die Variable nun 0 oder 1 ist. Die so gewonnenen Funktionen nennt man auch die Kofaktoren bezüglich der Variablen xi.

      Ein BDD heißt geordnet (OBDD), wenn die Variablen irgendeiner (für dieses BDD festen) Sortierung gehorchen, d.h. auf jedem Weg im gerichteten Graphen ist die Reihenfolge der Variablen der besuchten Knoten identisch mit der Reihenfolge in der vorgegebenen Ordnung (was nicht ausschließt, daß verschiedene Variablensortierungen zum selben OBDD führen können; in der Regel ist dies jedoch nicht der Fall). Die Variablensortierung im Graphen entscheidet über dessen Größe. Das Auffinden der optimalen Variablensortierung ist sehr schwierig. Man kann zeigen, daß das Problem herauszufinden, ob es noch eine bessere Variablensortierung gibt, NP-vollständig ist, d.h. bisher existieren nur Verfahren mit exponentiellem Aufwand. Es gibt aber Heuristiken, die eine effiziente Approximierung liefern. Eine solche Heuristik, das sogenannte Sifting, benutzt auch dieses Package (s. 3.3.3). Der Benutzer des Programms kann die Variablensortierung auch von Hand ändern und so die Auswirkung auf den BDD sofort erfahren.

      Ein OBDD heißt reduziert (ROBDD), wenn jeder Knoten im OBDD eine unterschiedliche Boolsche Funktion repräsentiert. Das gilt in erster Linie natürlich auch für den Wurzelknoten des ROBDD, der die komplette Funktion repräsentiert.

      Bryant [3] hat als erster gezeigt, daß ein ROBDD wohldefiniert ist. Außerdem wies er nach, daß ein ROBDD eine kanonische Repräsentation einer logischen Funktion darstellt, d.h. zwei Funktionen sind genau dann äquivalent, wenn deren Darstellungen als ROBDD isomorph (also gestaltgleich) sind.

      Die Funktion F, die ein Knoten mit Variable xi repräsentiert, kann man also schreiben als, wobei die Funktion mit xi = 1 (also den "high"-Sohn) und die Funktion mit xi = 0 (also den "low"-Sohn) repräsentiert. Diese Art der "Zerlegung" einer Funktion nach einer Variable nennt man "Shannon"-Zerlegung oder -Dekomposition. Im BDD ist jeder Knoten nach Shannon zerlegt.

    3. Reduktionstypen im BDD

    4. Um den OBDD in einen ROBDD zu überführen und anschließend eine kanonische Repräsentation der Ausgangsfunktion zu erhalten, muß man verschiedene Reduzierungen am Graphen durchführen. Es hat sich gezeigt, daß zwei Reduktionstypen ausreichen, um die gewünschte Form zu erhalten. Ein OBDD heißt reduziert (ROBDD), wenn keine der unten angegebenen Reduktionstypen mehr angewendet werden können (erst dann ist gewährleistet, daß jeder Knoten eine unterschiedliche Funktion repräsentiert):

      Typ I: "Isomorphie"

      Lösche einen Knoten  und seine ausgehenden Kanten, wenn gilt: Es gibt einen anderen Knoten  mit , der nach derselben Variable zerlegt ist und hat denselben low- und high-Sohn wie .  Die eingehenden Kanten von  werden auf  umgelenkt. Ein grafische Veranschaulichung gibt es in Abb 2:

      Abb 2: Reduktionstyp I (Isomorphie)

      Typ S: "Shannon"

      Lösche einen Knoten , falls low- und high-Sohn des Knotens auf denselben Knoten zeigen. Die eingehenden Kanten von  werden auf  umgelenkt. Ein grafische Veranschaulichung gibt es in Abb 3:

      Abb 3: Reduktionstyp S (Shannon)


    5. Anwendungsmöglichkeiten von BDDs

    6. BDDs kommen heute im besonderen Maße beim computergestützten Schaltkreisentwurf (engl. computer-aided design, kurz CAD) zum Einsatz. Viele hier auftauchende Probleme lassen sich als Sequenz von Operationen (z.B. AND, OR, NOT, …) beschreiben, welche auf Boolschen Funktionen ausgeführt werden. Was man benötigt ist also eine effiziente Möglichkeit, diese Operationen zu verwirklichen. Genau das ist die Aufgabe eines BDD-Packages. Auf Effizienz wurde allerdings hier nicht der Schwerpunkt gelegt, denn vielmehr steht in diesem Projekt die Visualisierung im Vordergrund.

      Durch die Kanonizität von ROBDDs kann man auch "leicht" die Äquivalenz zweier Boolscher Funktionen testen. Dazu muß man lediglich die dazugehörigen ROBDDs auf Isomorphie prüfen. ROBDDs können zwar im schlechtesten Fall (engl. worst-case) auch exponentielle Größe in der Anzahl der Variablen haben, doch sie sind für die meisten interessanten Funktionen eher klein.

      Ebenfalls ein häufig auftauchendes Problem ist der Test auf Tautologie. Hier möchte man wissen, ob eine Boolsche Funktion für alle Variablenbelegungen immer zu 1 (oder zu 0) evaluiert. Das ROBDD der konstanten Funktion 1 (bzw. 0) ist einfach nur ein Blatt mit "1" (bzw. "0") markiert. Bleibt also nur noch, das ROBDD der zu untersuchenden Funktion zu erstellen und mit "1" (bzw. "0") zu vergleichen.
       
       

    7. Implementation

    8.  

       

         
      1. Notationen
      1. Der ITE-Operator

      2. Der ITE-Operator (engl. If-Then-Else) bildet das Kernstück des BDD-Packages. ITE benötigt drei Operanden und berechnet die Boolsche Funktion

        Wenn F eine Entscheidungsvariable ist, entspricht diese Form genau der Shannon-Dekomposition. Wie man leicht nachvollzieht, kann man mit ITE mindestens alle zweistelligen Boolschen Funktionen berechnen. Eine vollständige Liste gibt es in Abb 4:

        Abb 4: Mit dem ITE-Operator kann man alle
        zweistelligen Boolschen Funktionen darstellen

        Beispielhaft soll hier der "Beweis" für  (Nr. 0001) geführt werden:

          þ

        Die Tatsache, daß man alle zweistelligen Boolschen Funktionen durch verschiedene Aufrufe des ITE-Operators schreiben kann, vereinfacht die Implementation enorm, wie folgender Auszug aus dem Quelltext zeigt (Abb 5: AND-, OR- und NOT-Synthese von Knoten):

        […]

        /** Realisierung der AND Funktion mittels einem ITE-Aufruf
        * @param a,b Funktionen, welche verschmolzen werden sollen
        * @return Den so gewonnenen neuen Knoten (=a*b) */

        public node AND(node a, node b) { return ITE(a, b, ZERO); }

        /** Realisierung der OR Funktion mittels einem ITE-Aufruf
        * @param a,b Funktionen, welche verschmolzen werden sollen
        * @return Den so gewonnenen neuen Knoten (=a+b) */

        public node OR(node a, node b) { return ITE(a,ONE,b); }

        /** Realisierung der NOT Funktion mittels einem ITE-Aufruf
        * @param a Funktion, welche negiert werden soll
        * @return Den so gewonnenen neuen Knoten (=~a) */

        public node NOT(node a) { return ITE(a,ZERO,ONE); }

        Abb 5: Auszug aus der Synthese-Klasse. Mit diesen einfachen Methoden werden die wichtigsten Knotensynthesen bewältigt.
         
         

        Wir wissen also jetzt, wie man einzelne Funktionen mittels eines Aufrufs des ITE-Operators schreiben kann – gegeben dessen Argumente sind schon in der passenden "ROBDD" Datenstruktur. Doch wie bekommt man die?

        Dieses Problem löst eine rekursive Formulierung des ITE-Algorithmus:

        Sei Z = ITE(F, G, H) und v die Topvariable von {F, G, H}.

        Dann läßt sich Z schreiben als:

        Die Terminalfälle des Algorithmus sind: 

        Jeder Knoten Z speichert also ein Tripel mit einer Variablen v, nach der er zerlegt ist und zwei Söhnen, die sich rekursiv aus einem ITE-Aufruf der Kofaktoren ergeben.

        Es bleibt also nur noch die Bestimmung der Kofaktoren von F, G und H nach v. Das ist aber hier denkbar einfach, denn es gilt:

        Sei F ein Knoten mit F = (w,T,E) und v eine Variable mit v £ w.

        Dann gilt:


         
         

        Wobei v < w bedeutet, daß die Variable v gar nicht in F vorkommt, denn v ist schließlich die Topvariable von F.
         
         

      3. Die "Unique-Table"

      4. Mit einer Hashtabelle, genannt unique-table, gelingt es, eine streng kanonische Form im ROBDD aufrecht zu erhalten. Dabei wird jedem Tripel (v,G,H) ein Knoten im ROBDD zugeordnet. Jeder Knoten im ROBDD hat also einen entsprechenden Eintrag in der Hashtabelle. Bevor man nun einen neuen Knoten F = (v,G,H) in das ROBDD einfügt, prüft man zuerst, ob nicht schon ein entsprechender Eintrag in der Hashtabelle vorhanden ist. Falls dem so ist, wird der bereits vorhandene Knoten benutzt, falls nicht wird er eingefügt und ein Eintrag in der Hashtabelle unique-table wird vorgenommen. Wenn wir induktiv davon ausgehen, daß G und H schon in der gewünschten kanonischen Form sind, existiert die Funktion F im ROBDD genau dann, wenn es schon einen Eintrag für das Tripel (v,G,H) in der unique-table gibt. Nach Definition erhalten wir somit einen kanonische Repräsentation.

        Die Hashtabelle unique-table sorgt also dafür, daß Isomorphien in unserem Graphen gar nicht erst auftreten können. Um die zweite und letzte Reduzierungsart (Typ Shannon) zu bewältigen, bauen wir einen Kofaktor-Test in den ITE-Algorithmus mit ein, welche die Söhne des neu entstehenden Knotens vergleicht. Im Quelltext sieht das (auszugsweise) dann so aus (Abb 6) :

        […]

        node fv0 = cofactor0(v,F); // Kofaktoren berechnen
        node fv1 = cofactor1(v,F);
        node gv0 = cofactor0(v,G);
        node gv1 = cofactor1(v,G);
        node hv0 = cofactor0(v,H);
        node hv1 = cofactor1(v,H);
        node C0 = ITE(fv0, gv0, hv0);
        node C1 = ITE(fv1, gv1, hv1);
        // Shannon-Reduktion testen mit Kofaktorvergleich
        if (C0.equals(C1)) {
        System.out.println("ITE: Shannon-Reduzierung!");
        return C1;
        }
        Abb 6: Auszug aus der Implementation des ITE-Algorithmus. Mit dem Kofaktortest bewältige ich die Shannon-Reduzierung.

      5. Der ITE-Algorithmus und ein Beispiel dazu

      6. Der komplette ITE-Algorithmus sieht in Kurzform im Pseudocode folgendermaßen aus (Abb 7):

        ite(F,G,H) {
          if (Terminalfall) {
            return result;
          } else {
            v = Topvariable(F,G,H);
            T = ite(Fv,Gv,Hv);
            E = ite(Fv,Gv,Hv);
            if (T == E) return T; // Shannon-Test
            R = find_or_add_unique_table(v,T,E); // Isomorphie
            insert_computed_table({F,G,H},R);
            return R;
          }
        }
        Abb 7: Der ITE-Algorithmus im Pseudocode.
        Die Erweiterung mit computed-table ist optional; sie wird in Abschnitt 2.4.5.1 näher erklärt.

        Hier ein Beispiel, um die Funktionsweise des ITE-Algorithmus zu verdeutlichen (vgl. Abb 8).

        Abb 8: Beispiel zum ITE-Algorithmus: I wird synthetisiert durch iterierten Aufruf von ITE.
         
         

      7. Mögliche Erweiterungen
Es gibt eine Reihe von Erweiterungen, die zu diesem Thema noch denkbar wären. Als Beispiel seihen hier die drei wichtigsten Ideen genannt:
  1. Eine "Memory-Funktion" für ITE
  2. Benutzung "komplementärer Kanten"
  3. Verwendung von "Standard-Tripel" für ITE
        1. "Memory-Funktion" für ITE

        2. Um den Rechen- und damit den Zeitaufwand des ITE-Algorithmus zu senken, wird – nach einer Idee von R.E. Bryant – eine zweite Hashtabelle eingeführt, genannt computed-table. Einmal berechnete Ergebnisse von ITE werden einfach in die Hashtabelle geschrieben, um bei erneutem Berechnen der Funktion sofort das Ergebnis liefern zu können. Also eine Art "Cache".

        3. Komplementäre Kanten

        4. Betrachtet man beispielsweise die ROBDD Knoten G und , so fällt auf, daß sie einander ähneln, bis auf die Tatsache, daß ihre Senken 0 und 1 gerade vertauscht sind! Das kann man sich zu Nutze machen, indem man nicht speichert, sondern vielmehr eine Kante auf G, welche ein zusätzliches Bit, das sog. complement-bit, gesetzt hat. Dieses Bit gibt also an, daß die Funktion, in der diese Kante endet, als komplementär interpretiert werden muß. Insbesondere entfällt dadurch eine Senke im Graph, also die 0 oder die 1.

          Doch jetzt ist wieder Vorsicht geboten, um nicht die Kanonizität zu verletzen. Wenn man sich alle möglichen Fälle genau anschaut, sieht man, daß es vier verschiede Paare gibt, die jeweils äquivalent zueinander sind (vgl. Abb 9)

          Abb 9: Komplementäre Kanten. Diese vier Paare sind funktionell äquivalent.

          Um nun wieder für Eindeutigkeit zu sorgen muß man sich eine Eigenschaft aussuchen, die jeweils von den 4 Paaren immer genau ein bestimmtes nur erlaubt; z.B. einigt man sich auf folgende Eigenschaft: Die high-Kante (hier mit 1 beschriftet) muß immer regulär (also nicht-komplementär) sein. Das schafft wieder Eindeutigkeit (Kanonizität).

          Der Overhead, der bei der Verwaltung von komplementären Kanten bei ITE entsteht, ist vernachlässigbar klein. Außerdem kommt man ohne zusätzlichen Speicher aus, wenn man einen kleinen Trick anwendet und das low-Bit eines jeden Zeigers zur Kodierung des complement-Bits verwendet.

        5. Standard-Tripel für ITE

        6. Es gibt Funktionsparameter F1,F2,F3 und G1,G2,G3 von ITE, für die gilt

          ITE(F1,F2,F3) = ITE(G1,G2,G3)

          …und es gibt mindestens ein i mit Fi ¹ Gi.

          Also definiert man sich auf der Menge von drei Funktionen F1,F2,F3 eine Äquivalenzrelation auf Basis der Boolschen Funktion ITE(F1,F2,F3 ). Wir hätten jetzt gerne aus jeder Äquivalenzklasse einen eindeutigen Repräsentanten, um evtl. die Berechnung zu beschleunigen bzw. die Größe der computed-table zu reduzieren und wiederholte Berechnungen zu vermeiden. Dazu wird zunächst eine Substitution der Parameter gemäß folgendem Schema gemacht:

          ITE(F,F,G) ð ITE(F,1,G)

          ITE(F,G,F) ð ITE(F,G,0)

          ITE(F,G,F) ð ITE(F,G,1)

          ITE(F,F,G) ð ITE(F,0,G)

          wobei F eine Komplement-Kante meint. Also nächstes werden folgende Standard-Tripel als Repräsentanten aus den Äquivalenzklassen genommen:

          ITE(F,1,G) ð ITE(G,1,F)

          ITE(F,G,0) ð ITE(G,F,0)

          ITE(F,G,1) ð ITE(G,F,1)

          ITE(F,0,G) ð ITE(G,0,F)

          ITE(F,G,G) ð ITE(G,F,F)

          Mit diesen Vereinfachungen läßt sich Zeit und Kosten sparen.


 
 
  1. Installation und Benutzung des Programms

  2. Dieses Kapitel beschäftigt sich mit der Installation / Einrichtung der Anwendung und deren Benutzung. Bei der Installation wird unterschieden, ob sie in einer UNIX- oder einer Windowsumgebung durchgeführt wird.

       
    1. Installation
      1. Systemvoraussetzungen
Um die Java-Applikation selbst starten zu können, braucht man (idealerweise) nur das frei verfügbare Java von der Firma SUN® Microsystems installiert zu haben. SUN bietet Java in zwei Versionen an: Für Entwickler das j2sdk (Java 2 Software Developer Kit) und für Benutzer die Runtime-Version JRE. Jedes dieser Pakete ist natürlich für verschiedene Rechnerarchitekturen erhältlich: z.B.
  • für PCs (für Microsoft 32-Bit Windows Betriebssysteme, kurz Win32, oder Linux)
  • für UNIX Workstations (Solaris)
Dieses systemunabhängige Konzept macht es möglich, den einmal erzeugten Zwischen-Code (Java Byte-Code) auf einer Vielzahl von verschiedenen Rechnerarchitekturen ausführen zu können – jedoch sollten diese genügend Reserven mitbringen. Daher hier meine Empfehlungen:
  1. Rechner mit installiertem JDK 1.2 oder höher (das beinhaltet auch den korrekt gesetzten Klassenpfad und die swing-Bibliotheken). Fragen zur Installation beantwortet die mitgelieferte Onlinehilfe von Java oder das Internet J
  2. Grafische Benutzeroberfläche mit mind. 256 gleichzeitig darstellbaren Farben (je mehr desto besser, weil dann nicht gerastert werden muß)
  3. Eine hohe Bildschirmauflösung wird empfohlen, damit man mehrere Fenster der Applikation gleichzeitig und nebeneinander plazieren kann, ohne daß diese sich großflächig überdecken. Sinnvoll sind Auflösungen ab 1024*768 Pixel.
  4. Für die Applikation sollten nach dem Starten des Betriebssystems noch mind. 20MB Arbeitsspeicher zur Verfügung gestellt werden können, um ein Auslagern der Seiten zu vermeiden. Das garantiert einen flüssigen Programmablauf. Für PCs mit Win32/Linux bedeutet das idealerweise 64MB Arbeitsspeicher, für UNIX Maschinen etwa das Doppelte. Mit weniger sollte es aber auch akzeptabel laufen.
  5. Beim PC mit i386 kompatiblen Prozessoren der Pentium-Klasse sollten wir eine Mindesttaktrate von 200MHz ansetzen. Ähnliches sollte bei den versch. UNIX Maschinen gelten. [Die Applikation macht von keiner 2D/3D Beschleunigungshardware explizit Gebrauch und benötigt daher viel "CPU-Zeit"]
      1. Installation / Starten unter UNIX / Linux
  1. Starten Sie Ihre grafische Benutzeroberfläche X und öffnen Sie ein Terminalfenster.
  2. Wechseln Sie zuerst in das Verzeichnis, in welches Sie das Programmarchiv kopiert / downgeloaded haben.
  3. Entpacken Sie die Datei in einem Verzeichnis Ihrer Wahl. Die entpackten Dateien werden zur Laufzeit der Applikation benötigt werden (insbesondere die Hauptdatei OBDDApp.jar). Stellen Sie sicher, daß der Benutzer, der das Programm startet, Read- und Write-Rechte auf allen Unterverzeichnissen und Dateien der eben entpackten Applikation hat (es werden Konfigurationsdateien beim Beenden der Applikation gespeichert).
  4. Das Startskript JADE-Unix benötigt das das Execute-Recht, welches man explizit mit chmod +x JADE-Unix setzen muß.
  5. Es wurde automatisch ein Unterverzeichnis angelegt, in welches Sie mit cd <VZ—Name> wechseln. Stellen Sie sicher, daß Java korrekt installiert ist, alle Bibliotheken verfügbar sind, die JDK 1.2 Programme sich im aktuellen Suchpfad befinden und die Klassenpfad-Variable richtig gesetzt ist (mit dem Kommando setenv | grep CLASSPATH kann man sich auch den aktuellen Klassenpfad und mit setenv | grep path den aktuellen Suchpfad für Dateien anzeigen lassen).
  6. Starten Sie dann das Skript JADE-Unix, um das Programm zu laden, oder geben Sie von Hand java -cp OBDDApp.jar OBDDApp ein. Sollten nun Fehlermeldungen über falsche oder nicht vorhandene Zeichensätze / Schriftarten erscheinen können Sie diese normalerweise getrost ignorieren. Das System sollte dann die fehlende Schriftart durch eine passende ersetzen. Nun sollte sich das grafische Frontend der Anwendung aufbauen. Dem Terminalfenster können Sie zur Laufzeit nützliche Programmausgaben und -informationen entnehmen. Diese Ausgaben lassen sich auch durch den Programmstartparameter -o <file> in eine Datei umleiten. Beachten Sie die Lücke nach dem Schalter –o.
  7. Sie haben es geschafft! Lesen Sie weiter im Abschnitt über die Bedienung des Programms, um eine kurze Einführung zu erhalten.
      1. Installation / Starten unter Win32 Betriebssystemen
  1. Starten Sie Windows 95/98/2000/NT und öffnen Sie ein DOS-Fenster.
  2. Wechseln Sie in das Verzeichnis, in welches Sie das Programmarchiv kopiert / downgeloaded haben.
  3. Entpacken Sie das Archiv mit einem passenden Packer in ein beliebiges Verzeichnis (z.B. der Packer WinZip®). Jetzt entpacken sich eine paar Dateien, welche zur Laufzeit der Applikation benötigt werden (insbesondere die Hauptdatei OBDDApp.jar). Stellen Sie insbesondere unter WindowsNT/2000 sicher, daß der Benutzer, der das Programm startet, Lese-, Schreib- und Execute-Rechte in allen Unterverzeichnissen der eben entpackten Applikation hat (es werden Konfigurationsdateien beim Beenden der Applikation gespeichert).
  4. Es wurde automatisch ein Unterverzeichnis angelegt, in welches Sie mit cd <VZ-Name> wechseln. Stellen Sie sicher, daß Java korrekt installiert ist, alle Bibliotheken verfügbar sind, die Java executables (v.a. java und javac) sich im aktuellen Suchpfad befinden und die Klassenpfad-Variable richtig gesetzt ist (mit dem Kommando echo %CLASSPATH% kann man sich auch den aktuellen Klassenpfad bzw. mit echo %PATH% den aktuellen Suchpfad anzeigen lassen).
  5. Starten Sie dann die Batchdatei JADE-Win32, um das Programm zu starten, oder geben Sie von Hand java –cp OBDDApp.jar OBDDApp in der DOS-Box ein. Sollten nun Fehlermeldungen über falsche oder nicht vorhandene Zeichensätze / Schriftarten erscheinen können Sie diese normalerweise getrost ignorieren. Das System sollte dann die fehlende Schriftart durch eine passende ersetzen. Nun sollte sich das grafische Frontend der Anwendung aufbauen. Dem Terminalfenster können Sie zur Laufzeit nützliche Programmausgaben und -informationen entnehmen. Diese Ausgaben lassen sich auch durch den Programmstartparameter -o <file> in eine Datei umleiten. Beachten Sie die Lücke nach dem Schalter –o.
  6. Sie haben es geschafft! Lesen Sie weiter im Abschnitt über die Bedienung des Programms, um eine kurze Einführung zu erhalten.
    1. Die Benutzeroberfläche - Gesamtüberblick

    2. Das grafische Frontend von JADE ist schlicht und einfach gehalten, so daß eine intuitive Bedienung von Anfang an möglich ist. Trotzdem gehe ich kurz auf die einzelnen Elemente der Anwendung ein.

      Das Hauptfenster besteht aus einer Menüzeile, Statuszeile, Kontrollbuttons, dem Zeichenfenster und Kontrollen zum Strecken der Zeichnung.

      Über die Kontrollbuttons (vgl. 3.3.2) kann man zu der Formel in der Eingabezeile (vgl. 3.3.1) ein äquivalentes ROBDD erstellen lassen. Dieser wird dann im schwarzen Zeichenfenster angezeigt. Ist der Step-Mode (vgl. 3.3.4.6) eingeschaltet, kann man die schrittweise Entstehung des ROBDDs verfolgen.

         
      1. Markierung von Knoten

      2. Ist das ROBDD fertig aufgebaut (erkennbar an der Meldung "Waiting for Input" in der Statuszeile) kann man z.B. einen Knoten im Baum mit einem Klick auf die linke Maustaste markieren. Die ausgehenden Kanten zu den Söhnen dieses Knotens werden dann dicker dargestellt, um Mißverständnissen, die durch das Zeichnen bedingt sind, vorzubeugen.

      3. Interaktive Variablensortierung

      4. Ist der markierte Knoten nicht die Wurzel (oberster Knoten) des ROBDD-Graphen, dann kann man mit dem Pfeil nach oben (rechts neben "Lock X/Y") die Variablensortierung derart verändern, daß die markierte Variable mit ihrem Vorgänger in der globalen Variablensortierung getauscht wird. Daraufhin wird sofort ein neues ROBDD erstellt, welches die Veränderung visualisiert. Hat man einen Knoten markiert, von dessen beiden Söhnen höchstens einer ein Blatt (=Terminalknoten, ="0"- oder "1"-markierter Knoten) ist, dann kann man entsprechend durch Anklicken auf den Pfeil nach unten (links neben dem "Quit"-Knopf) ein Vertauschen mit dem Nachfolger in der globalen Variablensortierung erzielen. Dieser Effekt wird ebenfalls sofort sichtbar.

        Durch ein Klicken-und-Ziehen (engl. drag) auf den schwarzen Zeichenbereich kann man den Graphen verschieben.

      5. Zoom

      6. Mittels der Schieberegler für Zoom-X und Zoom-Y kann man einen horizontalen bzw. vertikalen Streckfaktor festlegen, der für alle schwarze Zeichenbereiche (also auch für die Fenster aus 3.3.4.6) gilt. Die Zeichnung wird dann sofort gestreckt/gestaucht. Ist zusätzlich noch das Optionsfeld Lock-X/Y aktiviert (Häkchen sichtbar) dann verändert sich der vertikale und horizontale Streckfaktor in gleichen Teilen, was zur Folge hat, daß die Zeichnung ge-"zoom"-t wird.

    3. Die Benutzeroberfläche im Einzelnen

    4.  

       

         
      1. Die Formeleingabezeile

In dieser Eingabezeile kann man eine Boolsche Funktion eingeben.
Bei der Formeleingabe muß folgendes beachtet werden:
      1. Die Kontrollbuttons

      2. Hinter den Kontrollbuttons verstecken sich folgende Funktionen (s. Abb 12):

        Abb 12: Kontrollbuttons

      3. Variablensortierung einstellen…

      4. Um die Variablensortierung im Programm zu ändern, muß ein kleines Hilfsfenster aufgerufen werden. Es befindet sich im "View"-Menü unter dem Punkt "Modify variable order…". Hier hat man die Kontrolle über die Variablensortierung des BDDs (s. Abb 13):
         
         

        Abb 13: Hilfsfenster zum Einstellen der Variablensortierung im BDD

        Bei "partial order:" kann man (wie in der Abbildung zu erkennen) Teilordnungen definieren, die für die globale Variablensortierung im BDD gelten sollen. Das ermöglicht ein schnelles und effizientes Eingeben der gewünschten Sortierung. Wichtig dabei ist nur, daß man das "<"-Zeichen benutzt. Eine Benutzung von ">" ist nicht vorgesehen, um Mißverständnisse zu vermeiden. Leerstellen werden bei der Eingabe nicht berücksichtigt.
         

        Diese partielle Ordnung wird dann über den Schaltknopf "Apply" in die globale Variablensortierung (in Abb 13: "current order") integriert, und der BDD (sofern schon angezeigt) wird ggf. sofort entsprechend angepaßt bzw. neu erstellt.

        Die "current order" gibt einen Gesamtüberblick über die momentan vorherrschende globale Variablensortierung im Programm. Dabei werden auch Variablenindizes angezeigt, die evtl. im aktuellen BDD gar nicht verwendet werden.

        Ein Häkchen vor "mark current level while sifting" legt fest, ob bei der Durchführung des Sifting-Algorithmus der momentan betrachtete Variablen-Level optisch hervorgehoben werden soll (zur Veranschaulichung der Funktionsweise), oder nicht.
        Falls ja, entscheidet der Regler "Sifting-Delay/Level" darüber, wie lange zwischen zwei Schritten gewartet werden soll (~ Geschwindigkeit der Animation).

        Der Knopf "Defaults" sorgt dafür, daß die Standardvariablensortierung (aufsteigend) wiederhergestellt wird.
        Der Knopf "Ok" schließt das Fenster einfach wieder, ohne zusätzliche Veränderungen an der Variablensortierung vorzunehmen.

        Der Knopf "Sifting" führt am aktuell angezeigten BDD den Sifting-Algorithmus durch. Dabei wird die Variablensortierung des BDDs nach einer bestimmten Heuristik so verändert, daß sich die Anzahl der Knoten im BDD reduziert. Die so gefundene Variablensortierung wird nach Abschluß des Algorithmus in die globale Variablensortierung übernommen und der BDD entsprechend angepaßt / neu erstellt. Beachten Sie, daß während dem Sifting der "Step-Modus" nicht verfügbar ist, selbst wenn er aktiviert wurde. Das kommt daher, daß beim Sifting der komplette BDD exponentiell-in-der-Anzahl-der-Variablen oft neu erstellt werden muß. Normalerweise ist das beim "echten" Sifting nicht notwendig (dort genügt pro Variablentausch ein "Umhängen" der betroffenen Söhne in O(1) ).

      5. Die Menüpunkte im Einzelnen

      6. In diesem Abschnitt gibt es einen kleinen Überblick, was sich alles hinter den einzelnen Menüs und deren Unterpunkten verbirgt.

           
        1. Das File-Menü
  • Save configuration on exit: Beim Verlassen des Programms, werden alle Benutzereinstellungen in einer Datei gespeichert, um eine erneute Eingabe beim nächsten Programmstart zu ersparen. Diese Einstellungen sind z.B.:

  • > Alle Einstellungen aus den Menüs (sichtbare Fenster und an-/abgewählte Optionen),
    > Fensterpositionen,
    > Variablensortierung,
    > letzte Formel in der Eingabezeile, …
    Befindet sich ein Häkchen vor dem Menüpunkt, dann werden diese Einstellungen beim ordnungsgemäßen Beenden (s. nächsten Menüpunkt) des Programms gespeichert. Der Dateiname, der zum Speichern benutzt wird, ist - sofern nicht anders angegeben - entweder der Defaultdateiname (OBDDApp.conf) oder der Dateiname, der als Parameter beim Programmstart mit der Option –c <filename> angegeben worden ist (für eine Übersicht über die versch. Programmparameter vgl. 3.4). Beachten Sie, daß beim Programmstart das ROBDD aus der Formeln in der Eingabezeile nicht automatisch wieder aufgebaut wird.
  • Exit: Führt zum sofortigen Beenden des Programms ohne erneute Nachfrage.

  • Die aktuellen Einstellungen werden für den nächsten Programmstart gespeichert, falls gewünscht (vgl. dazu obigen Menüpunkt).
        1. Das View-Menü
Das View-Menü stellt mehrere Visualisierungsoptionen sowie eine Reihe von Möglichkeiten zur Manipulation der Variablensortierung im BDD zur Verfügung. Im einzelnen sind dies folgende Menüpunkte:
  • Swap high/low-edges: Ist diese Option eingeschaltet, dann wird in allen Fenstern bei der BDD-Anzeige die Lage von den ausgehenden low- und high-Kanten an jedem Knoten vertauscht.

  • Grafisch bedeutet das eine "Achsenspiegelung" am Wurzelknoten des jeweiligen BDDs.
  • Label edges: Eingeschaltet bewirkt diese Einstellmöglichkeit eine Bezeichnung aller Kanten im BDD mit "0" oder mit "1". "0" bedeutet hierbei, daß es sich um eine low-Kante im Graphen handelt, und bei "1" entsprechend um eine high-Kante.

  • Ist die Option deaktiviert, da werden die beiden Kantentypen zur Unterscheidung verschiedenfarbig dargestellt (vgl. dazu die Legende in der Grafikanzeige für die Bedeutung der unterschiedlichen Farben).
  • Label nodes: Geht es in der Darstellung des BDDs lediglich um dessen Gestalt, nicht aber um die Namen der einzelnen Knoten im Graph, dann macht diese Option Sinn. Ist sie aktiv, werden alle Knoten anonym (namenlos) und sind nicht mehr zu unterscheiden. Meistens ist möchte man aber wissen, wie die einzelnen Knoten heißen!
  • Invert variable order: Möchte man mal auf die Schnelle die Auswirkungen auf den BDD bei umgekehrter Variablensortierung erkunden, dann bietet sich diese Möglichkeit an. Die Auswirkungen werden grafisch sofort sichtbar, wenn bereits ein BDD im Hauptfenster dargestellt wird.
  • Modify variable order…: Hinter diesem Menüpunkt verbirgt sich ein kleines Fenster, in welchem man Kontrolle über die Variablensortierung des BDDs erlangt.

  • (Vergleiche dazu Abschnitt 3.3.3)
  • Grid-Layer 1: Mit Aktivierung dieses Menüpunkts werden horizontale Hilfslinien auf dem Graphenhintergrund gezeichnet, um die verschiedenen Level im BDD optisch besser trennen zu können. Zusätzlich zum Ebene-1-Grid gibt es noch das…
  • Grid-Layer 2: Dieser Punkt erlaubt eine noch feinere Hilfslinienauflösung. Normalerweise reicht aber das Einblenden der Grid-Ebene 1 bereits für eine gute Übersicht aus. Die Hilfslinien der Ebene 2 sind nur verfügbar, wenn die Ebene 1 bereits aktiviert wurde.
  • StartUp window: Ist diese Einstellung aktiv, dann wird beim nächsten Programmstart ein kleines Fenster mit Logo angezeigt. Das Fenster ist nur zur Information und hat sonst keine weitere Funktionalität im Programm.
        1. Das I-T-E-Menü
Das Programm bietet die Möglichkeit, bei der Synthese des fertigen ROBDD zuzuschauen. Genauer bedeutet das, daß sämtliche Aufrufe des ITE-Algorithmus zur Erzeugung des BDDs einzeln mitverfolgt werden können durch sogenannte Parameterfenster. In diesen Fenstern werden die Argumente sowie das Ergebnis des Algorithmus angezeigt. In diesem sogenannten "Step-Mode" kann man Schritt für Schritt die Entstehung des fertigen ROBDDs beobachten. Die einzelnen I-T-E-Menüpunkte werden hier kurz erklärt:
  • F-Parameter window: Bei Anwahl dieses Menüpunktes erscheint/verschwindet ein Fenster, in welchem der erste Parameter während des ITE-Synthesealgorithmus angezeigt werden kann. (vgl. 2.4.2)
  • G-Parameter window: Bei Anwahl dieses Menüpunktes erscheint/verschwindet ein Fenster, in welchem der zweite Parameter während des ITE-Synthesealgorithmus angezeigt werden kann. (vgl. 2.4.2)
  • H-Parameter window: Bei Anwahl dieses Menüpunktes erscheint/verschwindet ein Fenster, in welchem der dritte Parameter während des ITE-Synthesealgorithmus angezeigt werden kann. (vgl. 2.4.2)
  • I-Result window: Bei Anwahl dieses Menüpunktes erscheint/verschwindet ein Fenster, in welchem die Ergebnisse der einzelnen Aufrufe von ITE(F,G,H) während des ITE-Synthesealgorithmus angezeigt werden können. (vgl. 2.4.2)
  • Step-Mode: Der besagte "Step-Mode" kann mit dieser Menüoption eingeschaltet werden. Ist der Step-Modus aktiv, so wird nach allen Aufrufen von ITE(F,G,H) eine Pause eingelegt, so daß man die Ergebnisse des Aufrufs in Ruhe verfolgen kann. Auf Mausklick/Tastendruck geht es dann weiter. Vorsicht: die Anzahl der rekursiven ITE-Aufrufe steigt schnell an bei längeren Formeln! Beachten Sie, daß der Step-Mode während dem Sifting unabhängig von dieser Einstellung abgeschaltet bleibt.
        1. Verbose-Level-Menü

        2. Unter dieser Rubrik kann man die "Gesprächigkeit" des Programms einstellen. Das Programm produziert während seiner Ausführung ständig Meldungen, die (standardmäßig) auf der Konsole ausgegeben werden, sofern gewünscht. Eine Einstellung von "0: silent!" bedeutet, daß nur die notwendigsten Meldungen ausgegeben werden. Je höher der Level, desto "gesprächiger" und detaillierter werden die Meldungen. 

          Vorsicht: Bei Stufe "4: everything!" wird der Output recht unübersichtlich und groß, v.a. wenn ein komplizierter BDD (evtl. sogar mehrmals, wie beim Sifting!) aufgebaut werden muß!

          Hinweis: Statt die Meldungen auf der Konsole auszugeben, kann das Programm auch mit einem Parameter dazu überredet werden, die Ausgaben in eine bestimmte Datei zu speichern. Der Parameter lautet –o <filename>.
          Wichtig ist die Lücke zwischen –o und dem Dateinamen.

        3. ?-Menü
Unter diesem kleinen Menü verstecken sich eigentlich keine wichtige Funktionen.
Recht hilfreich ist vielleicht die

Abb 14: Das Hilfefenster für das Eingabe–
format der Boolschen Formel

  • Help: formula input: Durch Anwählen dieses Menüpunkts öffnet sich ein kleines Fenster, in dem das Eingabeformat für die Formeln erklärt wird. Unten im Fenster wird auch ein Beispiel angezeigt, das man auch in die Formel-Eingabezeile kopieren kann.
  • Last message…: Hier öffnet sich ebenfalls ein kleines Fenster, welches die letzte relevante Information / Fehlermeldung enthält.
  • About: Ein Fenster mit Informationen über den Autor,

  • Copyright und Programmversion/-datum.

Abb 15: Das Aboutfenster

    1. Parameter der Applikation
Die Applikation kann auch mit Parametern gestartet werden. Die Parameter und deren Funktionen sind:

-c <filename> Ändert das Konfigurationsfile auf <filename>.

Sofern Parameter –n nicht gesetzt ist, wird beim Programmstart
versucht, die Konfigurationsdaten aus der angegebenen Datei
zu lesen. Sofern gewünscht, wird beim Beenden des Programms
die Konfiguration in dieser Datei abgelegt.

-o <filename> Ändert das Outputfile auf <filename>.
Jetzt werden alle Meldungen, die normalerweise auf der Konsole
ausgegeben worden wären in eine Datei mit dem angegebenen
Namen gespeichert.

-n Verhindert ein Einlesen der Konfigurationsdatei
(dann werden die Programmdefaults benutzt!)

Die Parameter können beliebig kombiniert werden. Hier sind einige Anwendungsbeispiele zur Verdeutlichung und Erklärung (auf Win32-Systemen entsprechend JADE-Win32 statt JADE-Unix schreiben):

  1. Programmtechnische Realisierung

  2.  

     

       
    1. Der Parser

    2. Der frei erhältliche Parser namens CUP, der die Boolsche Formel auf die BDD-Datenstruktur abbildet, stammt von Scott E. Hudson, Graphics Visualization and Usability Center, Georgia Institute of Technology und ist im Internet unter http://www.cs.princeton.edu/~appel/modern/java/JLex/

      zu finden. CUP steht für "Constructor of Useful Parsers" . Die Version 0.10 ist in der Lage, LALR Grammatiken in Java-Code auf Basis einfacher Spezifikationsdateien zu erstellen, so daß der Benutzer lediglich die Grammatik in einer kleinen Datei angeben muß. Desweiteren sollte man noch eine Java-Datei namens scanner.java editieren, damit der Parser die Eingaben richtig verarbeiten und interpretieren kann. Hier ein Auszug aus der Spezifikationsdatei:

      // JavaCup Spezifikation zum Parsen von
      // "erweiterten Booleschen Ausdruecken" (EBEs)

      import java_cup.runtime.*;
      /* Anweisungen fuer den Parsergenerator, wie er den Scanner benutzen soll */
      init with {: scanner.init(OBDDApp.parseFormel); :};
      scan with {: return scanner.next_token(); :};
      /* Terminal-Symbole (Tokens, die der Scanner zurueckliefert) */
      terminal OR, AND, NAND, NOR, XOR, XNOR, NOT, ONE, ZERO, SEMI;
      terminal GREATER, GREATEREQUAL, LESS, LESSEQUAL;
      terminal LPAREN, RPAREN;
      terminal Integer VAR_IDX;
      /* Nicht-Terminal-Symbole -- fuer die Produktionsregeln */
      non terminal node expr;
      /* Bindungsstaerken: oben: wenig...unten:stark */
      precedence left OR, LESS, GREATER, LESSEQUAL, GREATEREQUAL;
      precedence left AND,NAND;
      precedence left XOR,XNOR,NOR;
      precedence left NOT, LPAREN;

      /* Die Grammatik-Regeln (kontextfreie Grammatik) */
      expr ::= expr:e1 OR expr:e2
      {: RESULT = OBDDApp.my_BDD.OR(e1,e2); :}
      |
      expr:e1 AND expr:e2
      {: RESULT = OBDDApp.my_BDD.AND(e1,e2); :}
      |
      expr:e1 NAND expr:e2
      {: RESULT = OBDDApp.my_BDD.NAND(e1,e2); :}
      |
      NOT expr:e
      {: RESULT = OBDDApp.my_BDD.NOT(e); :}
      |
      LPAREN expr:e RPAREN
      {: RESULT = e; :}
      |
      expr:e SEMI
      {: if (node.verboselevel>=3) System.out.println("PARSER: result: "+e);
      OBDDApp.my_BDD.setlast_node(e); :}
      ;

      Der Aufbau der Spezifikationsdatei parser.cup ist leicht durchschaubar. Interessant ist, daß man hier echten Java-Code einbauen kann, der während dem Parsen den ROBDD mittels ITE erstellen kann, was das ganze programmtechnisch wesentlich vereinfacht. Sind alle Einstellungen perfekt, dann muß man nur noch den Parsergenerator starten und bekommt als Ausgabe einen fertigen Java-Parser, welcher genau auf die jeweiligen Bedürfnisse zugeschnitten ist.
       
       

    3. Speicherung der Knoten
Die Knoten (engl. nodes) werden in einer Klasse namens node.java spezifiziert. Der Konstruktor kann einmal mit Söhnen ( => innerer Knoten mit Söhnen G und H) und einmal ohne Söhne (=> Blatt) aufgerufen werden.

// erstelle inneren Knoten

public node(int vi, node g, node h) {
G = g;
H = h;
v = vi;
last_x = 0;
last_y = 0;
version = 0;
selected=false;
counted=false;
}

// erstelle ein Blatt

public node(int vi) {
G = null;
H = null;
v = vi;
last_x = 0;
last_y = 0;
version = 0;
selected=false;
counted=false;
}

In dieser Klasse wird auch eine Zahl von Routinen bereitgestellt, die rekursiv auf der Datenstruktur operieren, z.B.

Außerdem verfügt die Klasse über eine Methode zeichnen(), welche rekursiv die grafische Ausgabe des Baumes veranlaßt. Dem geht eine gründliche, rekursive Strukturanalyse mit der Methode structure_analysis() voraus, welche die Koordinaten der einzelnen Knoten berechnet. Das ist alles andere als trivial, denn es gibt einige Einschränkungen, die beachtet werden müssen: z.B. der Graph sollte optisch ansprechend sein und alle Knoten mit derselben Beschriftung sollten sich auf einem Level befinden (vgl. dazu Problem bei 4.3).
 
 
    1. Bekannte Einschränkungen und Fehler
Bisher sind – trotz intensiver Fehlersuche – folgende Probleme und Einschränkungen bei der Benutzung dieser Applikation bekannt:
  1. Inhalt der CD

  2. Die Verzeichnisstruktur der CD mit Microsoft Joliet Filesystem wurde wie folgt gewählt:

    Image122.gif (3163 Byte)

    Der Inhalt der CD wurde in drei Bereiche aufgeteilt. Zum einen gibt es den Teil für den Anwender (Verzeichnis User), der das Programm lediglich starten möchte; zum anderen gibt es den Teil für den Entwickler (Verzeichnis Develop), der das Programm neu übersetzen oder weiterentwickeln will; schliesslich gibt es noch ein separates Verzeichnis Java in welchem J2SE v1.4.0 enthalten ist (für Windows und Linux).
     
     

       
    1. Für Entwickler
Alle Dateien/Verzeichnisse im Verzeichnis Develop sind für Entwickler gedacht. Die folgenden Pfadangaben beziehen sich alle auf dieses Verzeichnis.
    1. Für Anwender
Alle Dateien/Verzeichnisse im Verzeichnis User/JADE-1.5 sind für Endanwender gedacht. Die folgenden Pfadangaben beziehen sich alle auf dieses Verzeichnis. Um JADE benutzen zu können muss mindestens die Runtime Version von Java installiert sein.
  1. Literatur
[1] R. Drechsler. Ordered Kronecker Functional Decision Diagrams und ihre Anwendung. Modell Verlag, 1. Auflage, 1996

[2] K.S. Brace, R.L. Rudell und R.E. Bryant. Efficient Implementation of a BDD Package. In 27th ACM/IEEE Design Automation Conference, pages 40-45, 1990

[3] R.E. Bryant. Graph - based algorithms for Boolean function manipulation. IEEE Trans. on Comp., 8:677-691, 1986

[4] R. Drechsler und J. Römmler. Implementation and Visualization of a BDD Package in Java. GI/ITG/GMM Workshop "Methoden und Beschreibungssprachen zur Modellierung und Verifikation von Schaltungen und Systemen", Shaker Verlag, S. 219 ff, 2002


Warenzeichen