Integration des JEFIS Projekts in die Drools - Lab4Inf
Transcrição
Integration des JEFIS Projekts in die Drools - Lab4Inf
Fuzzylogik und Regelbasierte Systeme Ausarbeitung für das Masterprojekt: Thomas Beermann Dennis Huning Dennis Löhr Inhaltsverzeichnis I. Übersicht 2 Autor: Dennis Löhr, B.Sc. 1. Übersicht 1.1. Einleitung . . . . . . . . . . . . . . . . . 1.2. Fuzzy-Logik . . . . . . . . . . . . . . . . 1.2.1. Klassische Logik vs. Fuzzy-Logik 1.2.2. Fuzzysets . . . . . . . . . . . . . 1.2.3. Fuzzifizierung . . . . . . . . . . . 1.2.4. Defuzzifizierung . . . . . . . . . . 1.2.5. Fuzzy Operatoren . . . . . . . . 1.2.6. Fuzzy-Controlling . . . . . . . . 1.2.6.1. Einleitung . . . . . . . 1.2.6.2. Implikation . . . . . . . 1.2.6.3. Anwendungen . . . . . 1.3. Regelbasierte Systeme . . . . . . . . . . 1.3.1. Einleitung . . . . . . . . . . . . . 1.3.2. Die Regelbasis . . . . . . . . . . 1.3.3. Die Faktenbasis . . . . . . . . . . 1.3.4. Inferenzmaschine . . . . . . . . . 1.3.4.1. Vorwärtsverkettung . . 1.3.4.2. Rückwärtsverkettung . 1.3.5. Zusammenfassung . . . . . . . . 1.3.6. Herkunft . . . . . . . . . . . . . 1.4. Jefis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 3 4 4 4 5 6 6 7 7 9 9 10 11 11 11 12 12 12 13 II. Jefis Drools Adapter 14 Autor: Dennis Huning, B.Sc. 2. Jefis Drools Adapter 2.1. Einleitung . . . . . . . . . . . . . . . . . . . . . . 2.2. Der Rete-OO Algorithmus . . . . . . . . . . . . . 2.2.1. Überblick . . . . . . . . . . . . . . . . . . 2.2.2. Erzeugen eines deterministischen Baumes ii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 15 15 15 15 Inhaltsverzeichnis 2.2.3. Laufzeit Ausführung . . . . . . 2.2.4. Beispiel eines Baumes . . . . . 2.3. Erweiterung des Rete-OO Algorithmus 2.4. Drools Chance . . . . . . . . . . . . . 2.5. Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . um Fuzzy . . . . . . . . . . . . . . . . . . . . Logik . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 17 18 19 19 III. Jefis Ruleengine 22 Autor: Dennis Löhr, B.Sc. 3. Jefis Ruleengine 3.1. Einleitung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2. Beispiel in Lab4Jefis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3. Die Lab4Jefis Rule-Engine . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 23 23 24 IV. FCL und ANTLR 27 Autor: Thomas Beermann, B.Sc. 4. FCL und ANTLR 4.1. FCL . . . . . . . . . . . . . . . . . . . . . . . . . 4.1.1. Einleitung . . . . . . . . . . . . . . . . . . 4.1.2. Beispiel . . . . . . . . . . . . . . . . . . . 4.1.3. Beschreibung . . . . . . . . . . . . . . . . 4.1.3.1. VAR INPUT / VAR OUTPUT 4.1.3.2. FUZZIFY / DEFUZZIFY . . . . 4.1.3.3. RULEBLOCK . . . . . . . . . . 4.2. ANTLR . . . . . . . . . . . . . . . . . . . . . . . 4.2.1. Einleitung . . . . . . . . . . . . . . . . . . 4.2.2. Lexer/Parser . . . . . . . . . . . . . . . . 4.2.3. Beispiel . . . . . . . . . . . . . . . . . . . 4.2.4. Benutzung in Java . . . . . . . . . . . . . 4.2.5. Treewalker . . . . . . . . . . . . . . . . . 4.2.6. Beispiel . . . . . . . . . . . . . . . . . . . V. Anhang . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 28 28 28 30 30 30 31 32 32 32 33 36 36 37 38 5. ANTLR 39 A. Fcl.g . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 B. FCLTreeWalker.g . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 6. Jefis Ruleengine 45 Abbildungsverzeichnis 46 iii Inhaltsverzeichnis Literaturverzeichnis 47 iv Einleitung Diese Ausarbeitung dokumentiert das Masterprojekt 2009/2010 im Labor für Informatik an der Fachhochschule Münster - Fachbereich Elektrotechnik und Informatik. Thema des Masterprojektes war es Fuzzy-Logik und klassische Regelbasierte Systeme zu verbinden. Das Kapitel 1 beschreibt dafür die Grundlagen im Bereich Fuzzy-Logik und Regelbasierte Systeme, die für das Verständnis der Ausarbeitung erforderlich sind. Nachfolgend stellt das Kapitel 2 den ersten Teil bzw. das erste Semester des Masterprojektes dar. Hierbei geht es hauptsächlich um die Fuzzy-Erweiterung von drools:chance, das ein Unterprojekt von Drools 1 ist. Im Weiteren wird das zweite Semester geschildert. Nach dem Abschluss des drools:chance Projektes wurde das Projekt Jefis um Ruleengine Funktionalitäten erweitert. Das Kapitel 3 beschreibt, wie die Ruleengine für Jefis implementiert wurde und gibt zum Schluss noch ein ausführliches Beispiel für die Benutzung. Ein wichtiger Bestandteil der Ruleengine ist es Regeln und Fuzzysets aus einer Datei auslesen zu lassen. Dafür war es notwendig eine einheitliche Form zu bestimmen, die in der Fuzzy Control Language (FCL) gefunden wurde, beschrieben in Kapitel 4.1. Zuletzt bestand dann noch das Problem diese FCL-Dateien mit Java auszulesen und in JefisObjekte umzuwandeln. Aus verschiedenen Gründen, erläutert in Kapitel 4.2, wurde dafür ANTLR genommen. 1 http://www.jboss.org/drools 1 Teil I. Übersicht Autor: Dennis Löhr, B.Sc. 2 1. Übersicht 1.1. Einleitung Dieses Kapitel gibt eine Übersicht über die notwendigen Grundlagen um den weiteren Teil der Ausarbeitung nachzuvollziehen. Es werden grundlegende Aspekte von Fuzzy erklärt, wie beispielsweise Fuzzysets, Fuzzifizierung oder Fuzzy-Operatoren. Im Abschnitt Regelbasierte Systeme werden Themen wie Faktenbasis, Inferenzmaschinen und Vorwärtsverkettung erläutert. Abschließend gibt der Abschnitt Jefis einen Überblick über das im Labor für Informatik der FH-Münster entstandene gleichnamige Projekt. 1.2. Fuzzy-Logik 1.2.1. Klassische Logik vs. Fuzzy-Logik In der klassischen Logik kann ein Element x ∈ X entweder einer bestimmten Menge A zugeordnet werden oder nicht. Schnell ist ersichtlich, dass es in vielen Fällen einer weicheren Betrachtung bedarf. Als Beispiel sei hier eine Regel zur Lüftersteuerung genannt, die Regel besagt, dass die Kühlung ab einer Temperatur größer 80◦ C angeschaltet wird. Eine minimale Abweichung um -0,0001◦ von der kritischen Temperatur würde in der klassischen Logik nicht zum Einschalten der Kühlung führen. Wodurch es in diesem Beispiel zu einer unnötig langen thermischen Überstrapazierung der CPU und daraus resultierend zu einer schnelleren Alterung kommt. Ein anderes Systemverhalten ist in der klassischen Logik nicht möglich, da für die Indikatorfunktion oder Charakteristische Funktion χA der Menge A gilt: χA : X → {0, 1} 1:x∈A χA (x) = 0:x∈ /A Um eine solche Einschränkung zu umgehen, erweitert die Fuzzy-Logik die zweielementige Menge {0, 1} auf das abgeschlossene Intervall I:= [0, 1]. Die so entstehende Lösungsmenge à wird als Fuzzy-Menge bezeichnet und besteht aus geordneten Paaren der Form: à = {(x, µ (x)) ∧ x ∈ X} à Durch µ ist auf dieser Menge eine Funktion definiert, die den Grad angibt, zu dem ein Element x ∈ X in der Menge à enthalten ist. Die Funktion µ wird als Zugehörigkeitsfunktion bezeichnet. 3 KAPITEL 1. ÜBERSICHT Abbildung 1.1.: Beispiel Fuzzy Partition für einen Wertebereich von 0 bis 80 1.2.2. Fuzzysets Damit die Zugehörigkeitsfunktion überhaupt den Wert der Zugehörigkeit ermitteln kann, muss über der Menge à eine beliebige Funktion beschrieben werden. Eine solche Funktion wird als Fuzzyset bezeichnet. Mehrere Fuzzysets werden zu einer Fuzzy Partition zusammengefasst. In der Abbildung 1.1 wird eine Beispiel Partition mit drei Fuzzysets gezeigt. Wie das Beispiel zeigt können beliebige Funktionen genutzt werden um ein Fuzzyset zu beschreiben. Zusätzlich sieht man, dass ein Wert mehrere Zugehörigkeitswerte haben kann, z.B. für den Wert 45 liefert µ(45) = {0, 0.7, 0.5}. Das bedeutet, dass der Eingabewert von 45 zu 0% im ersten Fuzzyset, zu 70% im Fuzzyset zwei und zu 50% im dritten Fuzzyset liegt. 1.2.3. Fuzzifizierung Bei der Fuzzifizierung wird für einen scharfen Wert in einem dazugehörigen Fuzzyset die Zugehörigkeit ermittelt, dafür wird aber erstmal ein Eingabe-Fuzzyset benötigt. In diesem Fuzzyset wird der Zugehörigkeitsgrad wie in Abbildung 1.1 bestimmt. Hierbei wird von der X-Achse bei dem scharfen Wert senkrecht bis zu dem Fuzzyset gegangen und dann die Zugehörigkeit auf der Y-Achse abgelesen. Hierbei können verschiedene Verfahren benutzt werden um dies dann in ein Eingabe-Fuzzyset umzuwandeln. Eines dieser Verfahren funktioniert so: Das betreffende Eingabe Fuzzyset dadurch gebildet wird, dass das zugehörige Fuzzyset bis zur Zugehörigkeit gefüllt wird. Bei einem weiterem Verfahren wird das zugehörige Fuzzyset mit der Zugehörigkeit Multipliziert. Es gibt noch andere Verfahren die hier allerdings nicht weiter beschrieben werden. 1.2.4. Defuzzifizierung Für die Defuzzifizierung gibt es auch mehrere Methoden dies zu machen die wohl am weitesten verbreitete Methode ist die Schwerpunktmethode (center of gravity). Die Defuzzifizierung eines Sets sehen wir in Abbildung 1.2. In diesem Beispiel wurde die Schwerpunktmethode verwendet, durch die Verteilung und den Füllstand der Sets ergibt sich der Schwerpunkt bei 28,57%. Zusätzlich zu dieser gibt es auch noch die Maximum Methode, hierbei wird das Maximum innerhalb des Fuzzysets gesucht und als defuzzifizierter Wert zurückgegeben. Dabei gibt es drei Methoden: 4 KAPITEL 1. ÜBERSICHT Abbildung 1.2.: Beispiel Defuzzifizierung über die Schwerpunktmethode x 0 0 1 1 y 0 1 0 1 x∧y 0 0 0 1 x∨y 0 1 1 1 1 ¬x 1 1 0 0 Tabelle 1.1.: Wahrheitstabelle der klassischen Logik 1. Linkes Maximum - hier wird von links das Maximum gesucht. 2. Rechtes Maximum - hier wird von rechts das Maximum gesucht. 3. Mittleres Maximum - hier wird erst das linke und das rechte Maximum gesucht und anschließend der Mittelwert gebildet. 1.2.5. Fuzzy Operatoren In der klassischen Logik ist es möglich mehrere Elemente verschiedener Mengen über die Operatoren ∨, ∧ und ¬“, zu verknüpfen (Tabelle 1.1). Da die Fuzzy-Logik nicht ” aus einer endlichen Mengen von Möglichkeiten besteht wird schnell ersichtlich, dass man die Operatoren nicht eins zu eins auf die Fuzzy-Logik überführen kann. Daher müssen spezielle Operatoren eingeführt werden, die die gleichen Ergebnisse wie in Tabelle 1.1 liefern. Eine Lösung dieses Problems ist es die Operatoren durch die in Tabelle 1.2 gezeigten Funktionen zu ersetzen. Die sich dadurch ergebene Wahrheitstabelle wird in Tabelle 1.3 gezeigte. Wie man leicht erkennen kann, liefern die Funktionen für die Grenzwerte 0 und 1 die gleichen Ergebnisse. Diese Norm wird auch MINMAX-Norm genannt. 1 Quelle der Graphik ist das Labor für Prozessinformatik und Prozesslenkung, FH-Münster - Fachbereich Elektrotechnik und Informatik 5 KAPITEL 1. ÜBERSICHT x∧y x∨y ¬x min(x,y) max(x,y) 1-x t-Norm s-Norm c-Norm Tabelle 1.2.: Abbilden der Operationen auf Funktionen x 0 0 1 1 0.2 0.7 0.6 y 0 1 0 1 0.5 0.2 0.6 min(x,y) 0 0 0 1 0.2 0.2 0.6 max(x,y) 0 1 1 1 0.5 0.7 0.6 1-x 1 1 0 0 0.8 0.3 0.4 Tabelle 1.3.: Wahrheitstabelle der Fuzzy-Logik 1.2.6. Fuzzy-Controlling 1.2.6.1. Einleitung Fuzzy-Controlling wird in der Elektrotechnik seit den 1970er Jahren eingesetzt. Zu Beginn aber fast ausschließlich im asiatischen Raum. In der Elektrotechnik werden FuzzyController als Regler eingesetzt, wobei diese genauso wie andere Regler auch mit scharfen Eingabewerten versorgt werden. Abbildung 1.3.: Beispiel Fuzzy-Regler in einem Schaltbild Aber anders als bei anderen Reglern fuzzifiziert der Fuzzy-Regler die Eingabewerte bevor er mit den Daten arbeitet. Wenn die Eingabedaten dann für den Fuzzy-Regler aufbereitet wurden, verarbeitet der Regler die Eingaben mit seinen Regeln. Nachdem die internen Regeln des Fuzzy-Reglers dann abgearbeitet sind, werden die Ausgabewerte defuzzifiziert. Das Defuzzifizieren wird gemacht um wieder scharfe Werte für z.B. eine Motorsteuerung zu erhalten. Auch beim Fuzzy-Controlling ist es möglich FuzzyRegler zu verketten, um so eine Hintereinanderausführung von verschiedenen Regeln zu ermöglichen. Das wird allerdings in der Praxis nicht gemacht da dies nur die Komplexität des Systems unnötig steigern würde. 6 KAPITEL 1. ÜBERSICHT 1.2.6.2. Implikation Die Implikation ist der Kernbestandteil des Systems, hier gibt es eine Vielzahl an verschiedenen Verfahren. Einige dieser Verfahren sind Goedel,Lucasiewicz oder Zadeh, in technischen Systemen wird aber meist nur Larsen oder Mamdani eingesetzt. Wobei die Mamdani Implikation die am meisten genutzte in der Elektrotechnik ist. Allgemein beschrieben wird bei der Implikation bestimmt, zu welchem Anteil die einzelnen Werte innerhalb eines Fuzzysets erfüllt sind. Bei der Mamdani Implikation µA⇒B (x, y) := min{µA (x), µB (x)} wird beispielsweise ein Wert innerhalb eines Fuzzysets bis zum Maximum der Schnittmenge gefüllt. 1.2.6.3. Anwendungen In der Elektrotechnik werden Fuzzy-Systeme mit den folgenden Vor- bzw. Nachteilen beschrieben. Vorteile sind, dass Lösungen auch möglich sind, wenn • Kein in sich geschlossenes mathematisches Modell des Prozesses, z.B. in Form von Differentialgleichungen, existiert oder gefunden werden kann, oder wenn die Komplexität des Problems für eine solche Modellierung zu groß ist. • Unscharfe und vage Aussagen oder intuitive Einschätzungen zur Modellierung des Sachverhalts herangezogen werden müssen. • Viele Eingangsparameter und hohe Nichtlinearität vorliegen. Nachteile sind: • Die Beliebigkeit bzw. die Freiheit, die der Entwickler bei der Wahl und Implementierung des Fuzzy-Modells hat. Es existieren keine standardisierten Vorgehensweisen, um Erfahrungswissen in die Daten- und Regelbasis eines Fuzzy-Systems umzusetzen. • Die Beliebigkeit bzw. die Freiheit, die der Entwickler bei der Modifizierung eines Fuzzy-Modells zur Feinabstimmung oder Ergebnisverbesserung hat. Hierzu existieren ebenfalls keine standardisierten Methoden. Die Anpassung eines Fuzzy-Modells an veränderte Parameter kann daher schwierig und zeitaufwendig werden oder auch scheitern. • Fuzzy-Systeme besitzen keine Lernfähigkeit, die Regeln und Zugehörigkeitsfunktionen müssen vom Entwickler entworfen und optimiert werden. [Nel05] Auch bei Systemen bei denen man annehmen würde, dass dort besonders auf eine mathematische Beweisbarkeit geachtet wird gibt es Gegenbeispiele. Eines dieser Gegenbeispiele ist ein Raketen Zielsystem. In der Diplomarbeit von Alfons Möllers2 wurde ein 2 Quelle für das Beispiel ist die Diplomarbeit von Alfons Möllers an der FH Münster aus dem Jahr 1995 7 KAPITEL 1. ÜBERSICHT Abbildung 1.4.: Flugbahn und Geschwindigkeitskorrektur über Fuzzy Abbildung 1.5.: Schaltplan der Flugbahn und Geschwindigkeitskorrektur Problem beschrieben bei dem Es die Aufgabe war ein System zu entwerfen, dass die Geschwindigkeit eines Flugobjekts so anpasst das dieses zum richtigen Zeitpunkt am Ziel ankommt. Hierbei muss man jedoch erwähnen das durch einen Fuzzy-Regler nur Korrekturwerte an die eigentliche Flugkontrolle geliefert werden und nicht das ganze System auf Fuzzy-Controlling basiert. Ein weiteres Beispiel ist das inverse Pendel3 . In einem Versuchsaufbau an der Fachhochschule Münster ist es sogar möglich, ein gefülltes Bierglas auf das inverse Pendel zu stellen, wie in Abbildung 1.6 zu sehen ist. Beim Versuchsaufbau wird an einem beweglichen Schlitten über ein Kugellager eine Stange befestigt. Ziel des Systems ist es die Stange in eine aufrechte Position zu bekommen. Dies gilt als schönes Beispiel, denn über eine normale Regelung ist es nicht möglich den gesamten Vorgang in einen Regler abzubilden. Da es sich bei Normalen Regler meist um lineare Systeme handelt. Wenn dieses Problem versucht wird über normale Regler 3 Quelle für das Beispiel ist die Diplomarbeit von Stefan Tombrock an der FH Münster aus dem Jahr 1996 8 KAPITEL 1. ÜBERSICHT zu lösen, ist hierfür notwendig das die zugehörigen Differentialgleichungen für viele Positionen linearisiert wird. Durch den Einsatz von einem Fuzzy-Regler ist es möglich, das Ganze in einem Regler zu implementieren. Eine Lösung hierfür ist das Aufstellen der Regeln die in Abbildung 1.7 zu sehen sind, zusammen mit den Fuzzysets aus Abbildung 1.6. Abbildung 1.6.: Bierglas auf Inversen Pendel; Fuzzysets des Beispiels Abbildung 1.7.: Regeln des Inversen Pendels 1.3. Regelbasierte Systeme 1.3.1. Einleitung Ein Regelbasiertes System besteht aus einer Faktenbasis, einer Regelbasis und einer Inferenzmaschine. Hierbei stellt die Inferenzmaschine den Kern des Systems dar, da 9 KAPITEL 1. ÜBERSICHT die Inferenzmaschine aus den in der Regelbasis enthaltenen Regeln zusammen mit den gegebenen Fakten Schlussfolgerungen bildet. Hierbei wird beispielsweise aus dem Fakt, dass es gerade regnet gefolgert, dass die Straßen nass sind. Was im weiteren Verlauf noch genauer erklärt wird. Abbildung 1.8.: Komponenten eines Regelbasierten Systems [Bec] 1.3.2. Die Regelbasis ist eine Sammlung von Wissen. Diese Regeln sind folgendermaßen aufgebaut: WENN (Prämisse / Voraussetzung) DANN (Konklusion durch eine Aktion). Sollte das Wissen nicht in dieser Form vorliegen so muss es umgeformt werden, dies wird beispielsweise aus dem Wissen Alle Vögel können fliegen“ =⇒ Wenn ein Tier ein ” ” Vogel ist, dann kann es fliegen“. Diese Regeln werden aber nicht einfach fest integriert, sondern dynamisch hinzugefügt. Dadurch ist es möglich das System auf viele spezielle Anwendungsgebiete anzupassen oder das System an sich ändernde Anforderungen anzupassen. Dies ist auch notwendig, denn einer IDC-Studie zufolge ändern sich ca. 45% aller Regeln in einem Release-Zyklus [DWM08]. Aktuelle Beispiele für Systeme bzw. Notationen, mit denen Regeln erstellt werden können sind: JBOSS-Rules, Ross-Notation, AORML - Agent Object Relationship Modeling Language , ORM - Objekt Role Modeling Language und URML - UML-Based Rule Modeling Language. [Dre]. 10 KAPITEL 1. ÜBERSICHT 1.3.3. Die Faktenbasis setzt sich aus allen bekannten Fakten zusammen. Hierbei kann es sich sowohl um Messwerte, Symptome oder auch um Ergebnisse aus vorherigen Berechnungen handeln. Zu dem gibt es auch Regelsysteme die gezielt Fragen stellen, um beispielsweise medizinische Diagnosen zu stellen. Ein Beispiel ist hierfür das medizinische Diagnosesystem MYCIN. MYCIN ist in den 70er Jahren als ein Konsultationssystem zur Diagnose und Therapie von Infektionskrankheiten durch Antibiotika entwickelt worden. [Bei06] Durch die Trennung des Wissens, was in den Regeln definiert ist und dem Verarbeiten des Wissens in der Inferenzmaschine werden einige Eigenschaften von Regelbasierten Systemen begründet. Folgende Eigenschaften von Regelsystemen stammen von Torben Pullmann [Pul00] • Transparenz: Aufgrund der transparenten Wissensrepräsentation kann das Verhalten von wissensbasierten Systemen in einfacher Weise erklärt und vorhergesagt werden. • Flexibilität: Wissen kann in einfacher Weise hinzugefügt und entfernt werden. • Benutzerfreundlichkeit: Der Umgang mit wissensbasierten Systemen erfordert kein programmiertechnisches Vorwissen. • Kompetenz: Wissensbasierte Systeme verfügen in ihrem Anwendungsbereich über eine hohe Problemlösungsfähigkeit. 1.3.4. Inferenzmaschine Für die Inferenzmaschine selbst gibt es zwei grundsätzliche Vorgehensweisen, die Vorwärtsverkettung und die Rückwärtsverkettung. Bei der Vorwärtsverkettung wird versucht aus den vorhandenen Informationen, durch die Auswertung neue Informationen zu generieren. Das Verfahren wird auch in Abbildung 1.8 verwendet. Ein Beispiel für dieses Verfahren ist. Aus den Regeln: 1. Wenn man viel Schokolade isst, dann nimmt man viele Kalorien auf. 2. Wenn man viele Kalorien aufnimmt, dann wird man dick. Wenn jetzt bekannt ist, dass jemand viele Kalorien zu sich nimmt, folgern wir aus der zweiten Regel, dass diese Person dick ist. Dies ist die einfache Inferenz, da hier noch nicht das Ergebnis einer anderen Regel ausgewertet wird. 1.3.4.1. Vorwärtsverkettung Wenn aber die Inferenzmaschine die Vorwärtsverkettung verwendet, brauch nur bekannt sein, dass eine Person viel Schokolade isst. So können wir daraus folgern, dass diese Person viele Kalorien zu sich nimmt und daraus wieder das diese Person dick ist. Dieses Verfahren hat aber einen Nachteil, um beispielsweise einen bestimmten angestrebten Zustand zu erreichen, müssten bei der Vorwärtsverkettung alle Möglichkeiten der Faktenbasis durchgegangen werden. 11 KAPITEL 1. ÜBERSICHT 1.3.4.2. Rückwärtsverkettung Dies wird von der Rückwärtsverkettung besser behandelt. Haben wir wieder die vorherige Regel gegeben und der Zustand den wir anstreben ist es herauszufinden, warum eine bestimmte Person übergewichtig ist, so können wir unsere Regeln auswerten, die das gewünschte Ergebnis haben. In diesem Fall wäre das die zweite Regel, die besagt Wenn ” eine Person viele Kalorien zu sich nimmt, dann wird sie dick“. Aber das ist nicht die einzige Möglichkeit, sondern wir haben noch die Regeln, die die Prämisse der zweiten Regel als Konklusion haben, was bei der ersten Regel gegeben ist. Daraus ergibt sich das Ergebnis mit dieser Regelbasis, dass eine Person dick ist, wenn sie viele Kalorien zu sich nimmt oder viel Schokolade isst. 1.3.5. Zusammenfassung Zusammengefasst bezeichnet der Begriff der Inferenz das Gewinnen von neuen Fakten aus alten Fakten. Um die Faktenbasis zu erweitern und noch mehr Fakten zu erzeugen. Um eine Schleifenbildung zu verhindern, die im Normalfall auftreten würde, wird ein Beispiel gegeben. Als Regeln gelten wieder die beiden bekannten: 1. Wenn man viel Schokolade isst, dann nimmt man viele Kalorien auf. 2. Wenn man viele Kalorien aufnimmt, dann wird man dick. Wenn in diesem Fall die Faktenbasis den Input bekommt, dass jemand viel Schokolade isst, generiert die erste Regel daraus, dass diese Person viele Kalorien zu sich nimmt. Für die nächste Iteration haben wir also in der Faktenbasis das Wissen, dass eine Person viel Schokolade isst und viele Kalorien zu sich nimmt, damit können wir jetzt beide Regeln wieder ausführen. Damit würde also eine Endlosschleife laufen, da kein Wissen aus der Faktenbasis entfernt wird. Aus diesem Grund wird bei einer Inferenzmaschine noch eine Konfliktmenge gebildet. Die Konfliktmenge stellt die aktiven Regeln dar, an dem Beispiel erklärt heißt das für die Faktenbasis und die Konfliktmenge, dass sie leer sind. Geben wir nun zur Faktenbasis die Information hinzu, dass jemand viel Schokolade isst, so werden der Konfliktmenge auch alle Regeln hinzugefügt, die von der aktuellen Faktenbasis bedient werden können. Nachdem dann die Regeln aus der Konfliktmenge gefeuert wurden, werden die neu gewonnenen Informationen der Faktenbasis hinzugefügt. Dabei werden alle vorherigen aktiven Regeln aus der Konfliktmenge entfernt und im Anschluss die Regeln hinzugefügt die durch die neuen Informationen gefeuert werden können. Damit würde also nach der ersten Iteration bzw. dem Ausführen der ersten Regel nur die zweite Regel in der Konfliktmenge enthalten sein, wodurch wir das Problem der Endlosschleife für dieses einfache Beispiel gelöst haben. 1.3.6. Herkunft Als Geburtsstunde der künstlichen Intelligenz wird ein Workshop in Dartmouth im Sommer des Jahres 1956 angesehen, der von John McCarthy, Marvin Minsky, Nathan Rochester und Claude Shannon organisiert wurde. Durch diesen Workshop hat sich auch 12 KAPITEL 1. ÜBERSICHT der englische Name artificial intelligence” durchgesetzt. Vor diesem Workshop wurden ” Computer nur als arithmetische Rechenmaschinen angesehen. Nach diesem Workshop aber haben die Teilnehmer, an verschiedenen Einrichtungen, versucht dem Computer mit Wissen über einzelne Fachgebiete zu versehen, woraus auch die Regelbasierten Systeme entstanden. Das erste System, das erfolgreich intensiv Wissen in der Form einer großen Anzahl von Regeln aus einem spezifischen Anwendungsbereich einsetze, war DENDRAL. Das DENDRAL Projekt wurde in den 1960er Jahren gestartet und interpretiert Auswertungen von Massenspektrometern. [Bei06] 1.4. Jefis Jefis (Java Expert Fuzzy Inference System) ist ein Projekt der FH-Münster 4 . Das Projekt beschäftigt sich mit Fuzzylogic. Wie in Abbildung 1.9 zu sehen ist, ist das Fuzzyset einer der zentralen Bestandteile des Systems. Es unterstützt eine Vielzahl von verschiedenen Implikationen wie beispielsweise Goedel, Lucasiewicz, Larsen, Mamdani und noch einige mehr. Diese Vielfalt setzt sich bei den Normen fort, hier gibt es die Normen Algebraic, Bounded oder MinMax um nur einige zu nennen. Des Weiteren sind Elemente zur Visualisierung enthalten mit denen sich Beispiel Applets in kurzer Zeit erstellen lassen. Ein Beispiel für die Visualisierung lässt sich in Abbildung 3.1 finden. Abbildung 1.9.: UML Diagramm der wichtigsten Jefis Klassen [NW09] 4 Jefis ist ein Projekt des Labor für Informatik das zu finden ist unter http://www.lab4inf.fh-muenster.de 13 Teil II. Jefis Drools Adapter Autor: Dennis Huning, B.Sc. 14 2. Jefis Drools Adapter 2.1. Einleitung Das erste Kapitel hat einen Überblick über die grundlegenden Themen des folgendem Kapitels gegeben. In diesem Kapitel wird kurz der Rete-OO Algorithmus angeschnitten, da dieser in JBoss Drools verwendet wird und alle folgenden Abschnitte in diesem Kapitel auf diesem Projekt basieren. Anschließend wird auf die Kombination von Regelbasierten Systemen und Fuzzy eingegangen, im Speziellen auf die Arbeit von Davide Sottara 2.3 und den im Masterprojekt 2009/10 entstandenen Adapter des Jefis-Projektes 2.5. 2.2. Der Rete-OO Algorithmus 2.2.1. Überblick Der Rete-OO ist eine für objektorientierte Systeme optimierte Version des Rete Pattern Matching Algorithmus und wird in der Business-Rule-Engine JBoss Drools eingesetzt. Erfunden wurde der Rete Algorithmus von Dr. Charles Forgy. Der eigentliche Algorithmus kann in zwei Aufgaben aufgeteilt werden: • Erzeugen eines deterministischen Baumes • Laufzeit Ausführung 2.2.2. Erzeugen eines deterministischen Baumes Während der ersten Ausführungsphase wird aus den Bedingungen der LHS aller Regeln eine Baumstruktur erzeugt, dabei entspricht jeder Knoten einer Teilbedingung (Prämisse). Die LHS einer speziellen Regel ergibt sich aus der Verknüpfung einzelner Pfade. Zusätzlich werden gleiche Bedingungsteile von unterschiedlichen Knoten geteilt. In der Literatur wird vom Nodesharing gesprochen. Rete-OO kennt insgesamt die acht in der Abbildung 2.1 gezeigten Knoten. In jedem Baum ist der erste Knoten der ReteNode. Dieser Knoten errechnet für jedes Objekt, das zum WorkingMemory hinzugefügt wird, den zugehörigen Hashwert und speichert diesen. Durch diese Maßnahme wird sichergestellt, dass kein gleiches Faktum zweimal den Baum durchläuft. In der zweiten Ebene befinden sich die ObjectTypeNodes die eine instanceof -Prüfung durchführen. Somit kann jeder Pfad nur von dem Faktum durchlaufen werden an dem eine objektspezifische Prüfung erfolgreich durchgeführt werden kann. AlphaNodes führen eine atomare Überprüfung an einer Membervariable durch. Trifft 15 KAPITEL 2. JEFIS DROOLS ADAPTER Abbildung 2.1.: Auflistung der unterschiedlichen Rete-OO Knoten die abgefragte Bedingung zu, wird das Faktum im sogenannten AlphaMemory abgespeichert. Zusätzlich propagiert ein AlphaNode, falls das Faktum die Bedingung erfüllt hat, dieses zu seinem Nachfolger. BetaNodes (JoinNodes) stellen eine Verbindung zwischen Gruppen aus einem oder mehreren Tupeln und eindeutigen Fakten her. Tupel werden an dem linken und Fakten am rechten Eingang angelegt. Auch BetaNodes verfügen über einen Speicher. Für die Daten vom linken Eingang heißt dieser Speicher BetaMemory. Die Daten vom rechten Eingang werden im AlphaMemory gespeichert. Daher enthält der BetaMemory alle eingehenden Tupel und der AlphaMemory alle eingehenden Objekte. LeftInputAdapterNodes bekommen ein Objekt übergeben und propagieren nur ein einzelnes Objekttupel weiter an den darunter liegenden Knoten. Jeder Pfad endet mit dem TerminalNode. Dieser Knoten ist mit einer bestimmten Regel verknüpft. Sobald der Knoten aktiviert wird, fügt der Algorithmus die mit der TerminalNode verknüpften Regel zur Konfliktmenge hinzu. 2.2.3. Laufzeit Ausführung Während der Laufzeit Ausführung durchläuft der Rete-Algorithmus drei Phasen: Match: Inhalt des WorkingMemories (WM) wird auf alle LHS angewendet. Als Resultat wird eine Menge (Conflict-Set), bestehend aus den Regeln deren LHS Wahrheitswert gleich wahr“ ist, geliefert. ” Conflict-Resolution: Es wird eine Regel aus der Konfliktmenge zum Ausführen ausgewählt. Act: Es wird die ausgewählte Regel ausgeführt. Dies hat zur Folge, dass sich der Status des WM ändert, wodurch ein Rematching getriggert wird. Zu beachten ist hierbei, dass 90% der Rechenzeit für die Matching-Phase benötigt wird. 16 KAPITEL 2. JEFIS DROOLS ADAPTER 2.2.4. Beispiel eines Baumes In der Software Drools [dro10] werden die Regeln in der Drools Rule Language (DRL) verfasst. Dabei werden die Regeln standardmäßig im MVEL-Dialekt[mve10] angegeben. Eine in MVEL verfasste Regel zeigt das nachfolgende Beispiel: Listing 2.1: Beispiel Regel in MVEL 1 3 5 7 rule " rule1 " when $cpu : CPU ( temp > 80 && voltage > 1.55 ) $cpucooler : Cooler ( cpu == $cpu && fanspeed <= 120 ) then $cpucooler . setFanspeed (200); end Die Regel hängt von den zwei Objekten CPU und Cooler ab. Der deterministische Baum, der für diese Regel erzeugt wird, besteht aus zwei Pfaden (Abbildung 2.2). Einer behandelt alle Abfragen am Objekt CPU und der Andere Abfragen am Objekt Cooler. Die ersten Knoten jedes Zweiges sind vom Typ ObjektTypNode und überprüfen die im WorkingMermory enthaltenden Fakten auf ihr Instanzart. Das bedeutet: Für unser Beispiel werden alle Objekte kontrolliert, ob sie vom Typ CPU oder vom Typ Cooler sind. Wenn die Fakten vom Typ des entsprechenden Zweiges sind, werden diese an den darauf folgenden Knoten propagiert. Jeder Zweig enthält für jede atomare Abfrage, aus einer Regel, einen Knoten vom Typ AlphaNode. Der Pfad für die Fakten vom Typ CPU beinhaltet zwei AlphaNodes. Der erste Knoten überprüft ob die Temperatur größer als 80◦ C ist. Falls dies zutrifft, wird ein neuer Eintrag in dem AlphaMemory für das Objekt erzeugt. Anschließend wird das Objekt an den nächsten Knoten propagiert. Der nächste Knoten vom Typ AlphaNode überprüft, ob die Spannung der CPU größer als 1,55V ist. Im Pfad des Coolers wird abgefragt, ob die Cooler-Instanz zu einer im AlphaMemory Abbildung 2.2.: Baum für die im Listing gezeigte Regel gespeicherten CPU-Instanz gehört. Daher propagiert der LeftInputAdapterNode, aus 17 KAPITEL 2. JEFIS DROOLS ADAPTER dem Pfad der CPU das Tupel, bestehend aus Objekt Hashwert und Instanz-ID, an den linken Eingang des BetaNodes. Wurden alle Bedingungen erfüllt, fügt der TerminalNode die Regel zur Konfliktmenge hinzu. 2.3. Erweiterung des Rete-OO Algorithmus um Fuzzy Logik Davide Sottara hat in [DS08] eine Möglichkeit vorgestellt den Rete-OO Algorithmus um Fuzzy Logik zu erweitern. Seine Erweiterungen sind in dem Drools-Branch Drools Chance [Sot10b] zu finden. In den nächsten Zeilen wird auf die grundlegende Idee seiner Erweiterung eingegangen. Bei der Implementierung von Fuzzy Logik gibt es mehrere gravierende Unterschiede. Bei der von Davide Sottara vorgestellten Möglichkeit wird die Unschärfe als ungefähr aufgefasst. Bei dieser Implementierung kann man sich die Fuzzy-Sets, je nach Abfrage, als ansteigende oder abfallende Flanke vorstellen, wobei der zu prüfende Wert als Schwellwert dient. Bei diesem Verfahren wird die Standard MVEL-Syntax um die Operatoren ˜“, is und seems ergänzt. Auf den beiden Operatoren is und seems wird in den nächsten ” Abschnitten noch eingegangen. Eine Abfrage, die mit dem ˜“-Operator anfängt, wird ” als unscharfer Wert aufgefasst. Dies bedeutet für die Temperatur-Regel aus 2.1: Listing 2.2: Beispiel Regel mit ˜“-Operator ” 1 3 5 7 rule " rule1 " degree r when cpu : CPU ( temp ~ > 80 && voltage ~ > 1.55 ) cpucooler : Cooler ( cpu == cpu && fanspeed ~ > 120 ) then cpucooler . setFanspeed (200); end Wie durch die vorangegangenen Abschnitte zu erkennen ist, muss bei der Erweiterung des Rete-OO-Algorithmus bedacht werden, dass es keine scharfen Werte mehr gibt. Hierdurch können Auswertungen der Knoten bei falsch“ nicht einfach verworfen wer” den. Dies führt zu einem weiteren Problem: Was passiert mit nicht erfüllten Regeln?“. ” Um dieses Problem zu lösen, gibt es mehrere Strategien: Niemals verwerfen: Regeln deren Bedingungen nicht erfüllt sind, werden trotzdem gefeuert. Dieses Verhalten generiert allerdings ein Performance Problem. Künstliche Schwellwerte: Über ein Regelargument (degree) kann man einen Schwellwert setzen, der den Zugehörigkeitswert angibt, der erfüllt sein muss, damit eine Regel feuert. Heuristiken und weiteres: Über Interfaces ist es möglich eigene Evaluatoren zu implementieren. 18 KAPITEL 2. JEFIS DROOLS ADAPTER 2.4. Drools Chance Wie bereits erwähnt ist es möglich eigene Evaluatoren zu erstellen. Diese Evaluatoren müssen sich von der abstrakten Klasse BaseImperfectEvaluator ableiten. Die abstrakte Klasse enthält eine Vielzahl von unterschiedlichen eval()-Methoden. Das nächste Listing zeigt eine solche Methode. Wie man erkennen kann, gibt diese Methode eine Variable des Typs IDegree zurück. Listing 2.3: Beispiel einer eval()-Methode der abstrakten Klasse BaseImperfectEvaluator protected abstract IDegree eval ( Object left , Object right , IDegreeFactory factory ); Das Interface IDegree repräsentiert den Zugehörigkeitswert einer Variable, also einen Wert im Intervall I:= [0, 1]. Zusätzlich zu der Repräsentation des Intervalls ist es laut [Sot10a] eine Anforderung an IDegree, die Werte True und False annehmen zu können. Daher bietet es eine Möglichkeit den Zugehörigkeitswert auf boolean zu casten. Damit die Ruleengine bei der Auswertung einer Regel mit Fuzzylogik auch den angepassten Evaluator wählt, muss dieser registriert werden. Das Registrieren eines solchen Evaluators geschieht in zwei Schritten. Zum einem muss eine Definition, die sich von ImperfectEvaluatorDefinition ableitet, erstellt werden. Diese Definition enthält eine ID (z.B. seems“), die angibt auf welche Regeln der Evaluatoroperator angewendet werden ” soll. Außerdem enthält die Definition eine getEvaluator()-Methode, die den Evaluator zurückgibt. Zusätzlich muss der Operator an der Klasse Operator registriert werden. Im zweiten Schritt wird der Classname des Standards Operators durch den eigenen Classname ersetzt. Dazu wird beim Erstellen der RuleEngine eine modifizierte PackageBuilderConfiguration übergeben. Durch diesen Mechanismus war es uns möglich einen Adapter für das Jefis Projekt zu schreiben. Dieser Adapter erlaubt es die Regeln mit Hilfe der FuzzySets und FuzzyNormen aus Jefis auszuwerten. Im nächsten Abschnitt wird die Implementierung des Adapters beschrieben, wodurch noch einmal verdeutlicht wird, wie man eigene Evaluatoren erstellt und registriert. 2.5. Adapter Die Abbildung 2.3 gibt einen Überblick über die Klassen die genutzt werden um Jefis zu adaptieren. Das zentrale Objekt des Jefis Projektes ist das FuzzySet. FuzzySets verfügen über das Wissen wie sie miteinander verknüpft werden sollen. Das heißt: Welche Operatoren beim And oder Or angewendet werden sollen. Außerdem liefern FuzzySets die Zugehörigkeit zu einer Variable. Hinter jeder linguistischen Variable aus einer Regel steht ein solches Set. Auf dieses FuzzySet muss der Evaluator zugreifen können um die Zugehörigkeit zurückgeben. Für das folgende Listing 2.4 bedeutet dies, dass der Evaluator auf die beiden FuzzySets mit cold“ und low“ zugreifen muss. Über die toString()-Methode des right“-Objektes aus ” ” ” der eval()-Methode bekommt man den Namen des Sets geliefert. 19 KAPITEL 2. JEFIS DROOLS ADAPTER Abbildung 2.3.: Klassendiagramm des Jefis-Drools-Adapters Listing 2.4: Beispiel Regel mit Fuzzy-Evaluatoren 1 3 5 rule " R11 " when $cooler : Cooler ( $t : temperature is " cold " && $c : fanCurrent is " low " ) then $cooler . setStatus (" green " , drools . g e t C o n s e q u e n c e D e g r e e ()); end Mit diesen Namen kann man sich an der Klasse FuzzySetRegistry das entsprechende FuzzySet geben lassen. Die Registry ist als Singelton realisiert worden. Registriert werden die FuzzySets automatisch beim Erzeugen eines FuzzySetDecorators. Dieses Vorgehen schließt ein, dass der Name cold“, da er zu Identifizierung genutzt wird, eindeutig sein ” muss. Damit die Ruleengine den FuzzyEvaluator auch benutzt, wird in der Klasse JefisDroolsBuilder der Property Eintrag des entsprechenden Evaluators in der Klasse PackageBuilderConfiguration angepasst, siehe nachfolgendes Listing 2.5. Listing 2.5: Ersetzen der Standard Evaluatoren 2 protected void c o n f i g u r e P a c k a g e B u i l d e r () { packageBuilder = new PackageBuilder (); p ac k ag eB u il d er Co n f = packageBuilder . g e t P a c k a g e B u i l d e r C o n f i g u r a t i o n (); 4 // r e g i s t e r some EvaluatorDefinitions . . . p ac k ag eB u il d er Co n f . setProperty ( " drools . evaluator . seems " , F u z z y S e e m s E v a l u a t o r D e f i n i t i o n . class . getName ()); p ac k ag eB u il d er Co n f . setProperty ( " drools . evaluator . is " , I s E v a l u a t o r D e f i n i t i o n . class . getName ()); 6 8 10 } Die Regel R11 aus dem vorausgegangenen Beispiel besteht aus zwei Prämissen, die durch den &&-Operator verknüpft sind. Für die Berechnung ruft die Ruleengine ein Implemen- 20 KAPITEL 2. JEFIS DROOLS ADAPTER tierung von IDegreeFactory auf. Welche Factory gewählt wird, kann beim Erzeugen einer RuleBase angegeben werden, siehe nachfolgendes Listing: Listing 2.6: Übergabe der DegreeFactory 2 4 ruleBaseConf = new R u l e B a s e C o n f i g u r a t i o n (); ruleBaseConf . setProperty ( DEGREE_FACTORY_TAG , J e fi s De gr e eF a ct or y . class . getName ()); ... RuleBase ruleBase = RuleBaseFactory . newRuleBase ( ruleBaseConf ); Welche Algorithmen die Factory JefisDegreeFactory für die Operatoren zurückgibt, wird in einer Properties-Datei parametrisiert [NW09]. Durch einen Eintrag bestimmt man welcher Operator mit welcher Klasse verknüpft ist. Im folgendem Beispiel 2.7 wird die Factory so parametrisiert, dass diese als Standardnormoperator eine Instanz der Klasse de.lab4inf.fuzzy.norms.FuzzyMinMax“ und als Standardimplikationsoperator eine In” stanz der Klasse de.lab4inf.fuzzy.logic.Mamdani“ zurückgibt. ” Listing 2.7: Beispiel der Properties-Datei 1 3 5 7 9 11 norm . operator . DEFAULT norm . operator . MinMax . . . = de . lab4inf . fuzzy . norms . FuzzyMinMax = de . lab4inf . fuzzy . norms . FuzzyMinMax implication . operator . DEFAULT implication . operator . Zadeh implication . operator . Goedel . . . = de . lab4inf . fuzzy . logic . Mamdani = de . lab4inf . fuzzy . logic . Zadeh = de . lab4inf . fuzzy . logic . Goedel 21 Teil III. Jefis Ruleengine Autor: Dennis Löhr, B.Sc. 22 3. Jefis Ruleengine 3.1. Einleitung Nach einem erfolgreichen Abschluss der ersten Hälfte des Masterprojektes, wurde entschieden das wir uns in der zweiten Hälfte des Masterprojektes das an der Fachhochschule Münster entwickelte Jefis erweitern. Damit es mit Jefis nicht nur möglich ist Fuzzy-Controlling zu betreiben, sondern auch möglich ist Fuzzy-Logic abzubilden. Dabei sollte man berücksichtigen das Jefis von sich aus keine Ruleengine, sondern einen Fuzzy-Controller abbildet. Dieser ist zwar so entwickelt, dass Jefis aus einer XML-Datei die Regeln dynamisch neu einliest aber dadurch, dass der Controller nur scharfe Werte verarbeiten kann, war er nicht geeignet für das eigentliche Ziel unseres Masterprojektes. Eines der wichtigsten Eigenschaften einer Ruleengine ist, dass es die Ergebnisse aus einer vorherigen Regel, als Eingabe für eine neue benutzen kann (siehe Vorwärtsverkettung 1.3.4.1 bzw. Rückwärtsverkettung 1.3.4.2). Dies wurde bei Jefis darüber gelöst, das die Ergebnisse erst defuzzifiziert und anschließend wieder fuzzifiziert werden. Durch dieses Defuzzifizieren und anschließendem Fuzzifizieren entstehen Ungenauigkeiten die spätestens nach der Hintereinanderausführung von mehreren Regeln ein erhebliches Ausmaß annehmen. 3.2. Beispiel in Lab4Jefis Da Jefis eine gute Möglichkeit liefert die Fuzzysets zu visualisieren wurde eine Beispielanwendung im Applet FuzzyRuleEngineApplet demonstriert. Bei diesem Applet gibt es vier Fuzzysets in der Regelbasis (Food, Service, Tip und Waiter), damit wir eine Hintereinanderausführung von mehreren Regeln haben gibt es dazu die Regeln: 1. IF service IS good AND food IS delicious THEN tip IS generous 2. IF tip IS generous THEN waiter IS happy In Abbildung 3.1 ist unter den Fuzzysets Premise: food und Premise: service zu sehen, mit welchen Eingabesets wir in die Regeln hineingegangen sind. Die Eingabe Sets sind auch in den Fuzzysets Service und Food zu sehen, bei service ist dies das gelbe Dreieck wobei die Schnittmenge mit dem Set service:good hier als weiße Fläche eingefärbt ist. Beim set food ist das Eingabeset durch das lila Dreieck und die Schnittmenge durch eine türkise Fläche gekennzeichnet. Aus diesen beiden Fuzzyset-Schnittmengen ergibt sich jetzt das Fuzzyset Premise: tip das im Ausgabe Set Tip bis zum Minimum der beiden 23 KAPITEL 3. JEFIS RULEENGINE Abbildung 3.1.: Applet zur Visualisierung der Implikation Eingabe Sets gefüllt ist. Zum Schluss bildet sich aus dem neuen Eingabeset Premise:tip das neue Ausgabeset Result:waiter. In dem Applet 3.2 wurde die Regelbasis noch fest in den Javacode eingegeben. Für eine produktive Umgebung kann man dies allerdings nur schwer durchsetzen da, wie im Kapitel 1.3.2 schon beschrieben ist, sich viele Regeln ändern. Deshalb haben wir vor der Auswahl einer geeigneten Repräsentation der Regeln gestanden, zur Auswahl kamen dabei die XML-Basierte Sprache von Jefis, die standardisierte FCL 4.1 oder eine vollkommen eigene Entwicklung. Aufgrund dessen, dass es sich im Gegensatz zu beiden Alternativen bei FCL um eine standardisierte Sprache für Fuzzy handelt wurde diese dann auch genommen. Genaueres kann aus dem Kapitel 4.1 entnommen werden. 3.3. Die Lab4Jefis Rule-Engine Um das Beispiel des Applet 3.1 mit FCL Unterstützung zu benutzen, benötigen wir eine FCL-Datei. Diese FCL-Datei muss wie im nachfolgenden Kapitel 4.1 beschrieben wird aufgebaut sein. Für das Beispiel stellt die FCL-Dateien die Wissensbasis des Systems dar. Damit die beiden Eingabesets aus dem obigen Beispiel also zur Verfügung stehen, benötigen wir innerhalb des FUNCTION BLOCKs die Elemente aus dem Listing 3.1. 24 KAPITEL 3. JEFIS RULEENGINE Listing 3.1: FCL beschreibung der Fuzzysets service und food 2 4 6 8 10 12 14 VAR_INPUT service : REAL ; food : REAL ; END_VAR FUZZIFY service TERM poor := (0 , 1) (4 , 0); TERM good := (1 , 0) (4 ,1) (6 ,1) (9 ,0); TERM excellent := (6 , 0) (9 , 1); END_FUZZIFY FUZZIFY food TERM rancid := (0 , 1) (1 , 1) (3 ,0); TERM delicious := (7 ,0) (9 ,1); END_FUZZIFY Wobei es für die Rule-Engine nicht erheblich ist, ob ein Fuzzyify oder Defuzzify Block benutzt wird, da wir in der Rule-Engine mit den Ausgabesets der vorherigen Regel weiter arbeiten. Deshalb sollten wir auch für tip“ einen Fuzzyify Block, wie im folgenden ” Listing 3.2 benutzen. Listing 3.2: FCL beschreibung der Fuzzysets tip und waiter 1 3 VAR_OUTPUT tip : REAL ; waiter : REAL ; END_VAR 5 7 9 FUZZIFY tip TERM cheap := (0 ,0) (5 ,1) (10 ,0); TERM average := (10 ,0) (15 ,1) (20 ,0); TERM generous := (20 ,0) (25 ,1) (30 ,0); END_FUZZIFY 11 13 15 DEFUZZIFY waiter TERM sad := ( -1.1 ,0) ( -1 ,1) (0 ,1) (3 ,0); TERM normal := (2 ,0) (4 ,1) (5 ,1) (7 ,0); TERM happy := (6 ,0) (9 ,1) (9.5 ,1) (9.6 ,0); END_DEFUZZIFY Wie beim Fuzzyset waiter bzw. food zu sehen ist, können nicht nur Dreiecke benutzt werden, sondern es ist auch möglich Senken, Trapeze oder Polygone zu benutzen. Dadurch ist der Freiheitsgrad beim Erstellen der Fuzzysets groß, was allerdings bei den Polygonen, wenn sehr viele Regeln benutzt werden zu Performance Einbußen führt. Damit die Wissensbasis für das Beispiel aus dem Applet aber komplett ist, wird zusätzlich zu den Fuzzysets auch der RULEBLOCK mit den Regeln benötigt. Die beiden Regeln aus dem Beispiel können hierfür einfach wie in Listing 3.3 eingegeben werden oder zusätzlich mit der Norm und der Implikation versehen werden wie in Listing 3.4. Listing 3.3: FCL beschreibung der Regeln ohne Norm und Implikation 2 4 RULEBLOCK No1 RULE 1 : IF service IS good AND food IS delicious THEN tip IS generous ; RULE 2 : IF tip IS generous THEN waiter IS happy ; END_RULEBLOCK Listing 3.4: FCL beschreibung der Regeln mit Norm und Implikation 2 4 6 RULEBLOCK No1 AND : MIN ; ACCU : MAX ; RULE 1 : IF service IS good AND food IS delicious THEN tip IS generous ; RULE 2 : IF tip IS generous THEN waiter IS happy ; END_RULEBLOCK Damit sind alle Teile der FCL-Datei komplett. Diese kann auch im Anhang zusammengefasst unter Listing 6.1 betrachtet werden. Damit das Wissen, das in der FCL-Datei 25 KAPITEL 3. JEFIS RULEENGINE enthalten ist, in der Rule-Engine benutzten werden kann, wird ein FCLRuleEngineBuilder benötigt. Über diesen kann mit der Methode buildRuleEngine dann die Rule-Engine mit der FCL-Datei erzeugt werden. Damit die Rule-Engine jetzt aber auch eine Regel ausführen kann, benötigt sie eine Faktenbasis. Als Input für die Faktenbasis hatte das Beispiel aus dem Applet für beide Fuzzysets, service und food, ein normales Dreieck. Dieses erzeugen wir über den Konstruktor des FuzzyTriangle und setzten den Namen des Fuzzysets, auf den es angewendet werden soll. Danach werden die einzelnen Sets zu der Premise hinzugefügt. Das Listing 3.5 enthält alle dafür notwendigen Elemente. Listing 3.5: Java Code zum erstellen der Beispiel Premise 2 4 6 HashMap < String , FuzzySet > premises ; FuzzySet set ; premises = new HashMap < String , FuzzySet >(); // Service set = new FuzzyTriangle (3 , 2); set . setName ( " service " ); premises . put ( set . getName () , set ); 8 10 12 // Food set = new FuzzyTriangle (7 , 3); set . setName ( " food " ); premises . put ( set . getName () , set ); Wenn in der FCL-Datei nicht die Implikation und die Norm gewählt wurden, müssen diese jetzt gesetzt werden. Die dafür notwendigen Funktionen sind im Listing 3.6 enthalten. Für diese stellt Jefis eine Vielzahl von verschiedenen Normen und Implikationen zur Verfügung. Listing 3.6: Java Code zum setzen der Implikation und der Norm 2 ruleEngine . s e tI mp l ic a ti on T yp e ( " Mamdani " ); ruleEngine . setNorm (new FuzzyMinMax ()); Nachdem der Rule-Engine nun alle Details bekannt sind, die notwendig sind, um das Beispiel aus dem Applet darzustellen, können die Faktenbasis und die Wissensbasis über die Methode conclusion zusammengeführt werden. Dabei wird eine Liste mit Fuzzysets zurückgegeben, bei der beachtet werden muss das diese keine bestimmte Reihenfolge besitzen, sondern über ihren Namen identifiziert werden können. 26 Teil IV. FCL und ANTLR Autor: Thomas Beermann, B.Sc. 27 4. FCL und ANTLR 4.1. FCL 4.1.1. Einleitung Die Fuzzy Control Language oder auch FCL ist eine von der International Electrotechnical Commission (IEC 61131-7) standardisierte, domänenspezifische Sprache. Es hat nur Sprachelemente die direkt mit Fuzzy Logik zusammenhängen, wie die Deklaration von Fuzzy Sets und Regeln, aber nicht einmal so grundlegende Konstrukte wie Schleifen. Aus dem Grund ist es auch nicht möglich ganze Programme in FCL zu schreiben sondern nur die Teile davon, die die Fuzzy Regelmaschine beschreiben. Der Standard ist nicht frei und muss erworben werden. Allerdings gibt es einen Entwurf von 1997 der sich nicht entscheidend von dem finalen Standard unterscheidet und frei verfügbar ist unter [iec10]. Dieser Entwurf wurde in diesem Projekt verwendet. 4.1.2. Beispiel Im Folgenden wird die Syntax von FCL genauer erklärt. Am Besten kann man dies an einem einfachen Beispiel erklären. Die in diesem FCL Codebeispiel beschriebene Regel Maschine berechnet die Glücklichkeit eines Kellers anhand des Trinkgelds, welches er wiederum bekommt abhängig von der Qualität des Essens und des Services. FUNCTION_BLOCK tipper // Anfang eines neuen Block . Es k ö nnen mehrere in einer Datei definiert sein . 2 4 6 VAR_INPUT service : REAL ; food : REAL ; tip : REAL ; END_VAR // Definition der E ing angs var iab len VAR_OUTPUT waiter : REAL ; END_VAR // Definition der Au sga ngsv ari abl en 8 10 12 14 16 FUZZIFY service // Festlegung der Sets f ü r den Eingang ’ service ’ TERM poor := (0 , 1) (4 , 0) ; TERM good := (1 , 0) (4 ,1) (6 ,1) (9 ,0); TERM excellent := (6 , 0) (9 , 1); END_FUZZIFY 18 20 22 24 26 28 30 32 FUZZIFY food // Festlegung der Sets f ü r den Eingang ’ food ’ TERM rancid := (0 , 1) (1 , 1) (3 ,0) ; TERM delicious := (7 ,0) (9 ,1); END_FUZZIFY FUZZIFY tip // Festlegung der Sets f ü r den Eingang / Ausgang ’tip ’ TERM cheap := (0 ,0) (5 ,1) (10 ,0); TERM average := (10 ,0) (15 ,1) (20 ,0); TERM generous := (20 ,0) (25 ,1) (30 ,0); END_FUZZIFY DEFUZZIFY waiter // Festlegung der Sets f ü r den Ausgang waiter TERM sad := (0 ,0) (5 ,1) (10 ,0) TERM normal := (10 ,0) (15 ,1) (20 ,0) TERM happy := (20 ,0) (25 ,1) (30 ,0) 28 KAPITEL 4. FCL UND ANTLR 34 END_DEFUZZIFY 36 RULEBLOCK service_food_tip AND : MIN ; ACCU : MAX ; ACT : MIN ; 38 // Angabe der Norm . ’MIN ’ f ü r ’AND ’ impliziert auch ’MAX ’ f ü r ’OR ’ // Angabe der Norm f ü r die Zusammenfassung der Ergebnisse . // Angabe der Norm f ü r die Aktivierung der Regeln . 40 42 RULE 1 : IF service IS poor OR food is rancid THEN tip IS cheap ; RULE 2 : IF service IS good THEN tip IS average ; RULE 3 : IF service IS excellent AND food IS delicious THEN tip is generous ; 44 46 48 50 52 RULEBLOCK tip_waiter AND : BOUNDED ; ACCU : MAX ; ACT : PROD ; RULE 4 : IF tip IS cheap THEN waiter IS sad ; RULE 5 : IF tip IS average THEN waiter IS normal ; RULE 6 : IF tip IS generous THEN waiter IS happy ; END_RULEBLOCK 54 E ND _ FU NC T IO N_ B LO C K FCL wurde als Sprache für Fuzzy Control entwickelt, was man auch direkt bemerkt. Eine FCL-Datei kann aus mehreren FUNCTION BLOCKs aufgebaut sein. Diese haben wie reale Bausteine einen oder mehrere Ein-und Ausgänge. Dieses Beispiel besteht nur aus dem FUNCTION BLOCK tipper. Die Eingaben und Ausgaben werden am Anfang deklariert in den Blöcken beginnend mit VAR INPUT bzw. VAR OUTPUT. Bei einem normalen Fuzzy Control Block werden die Eingänge immer fuzzifiziert und die Ausgänge immer defuzzifiert, so dass man die Variablen immer als Input oder Output deklarieren muss. Bei der Rule Engine aus diesem Projekt müssen die Eingänge und Ausgänge aber nicht unbedingt fuzzifiert und defuzzifiziert werden. Zu einen kann man auch mit unscharfen Werten als Eingang reingehen, zum anderen können auch unscharfe Werte als Ausgabe herauskommen. Aus diesem Grund können Regeln auch verkettet werden ohne jeweils die Eingänge oder Ausgänge fuzzifizieren bzw. defuzzifieren zu müssen. Daraus folgt, dass man die Variablen nicht immer unbedingt als Input oder Output deklarieren kann. Bei service und food ist es offensichtlich, da diese nur als Eingabe verwendet werden im Regelblock service food tip benutzt werden. Ebenso verhält es sich mit waiter nur eben als Ausgabe im zweiten Regelblock. Bei tip ist das nicht mehr so eindeutig. tip wird sowohl im 1. als auch im 2. Regelblock verwendet sowohl als Eingabe als auch als Ausgabe. Ist das der Fall wird eine Variable als Eingabe deklariert. Als nächstes folgt die Angabe der Partitionen und Sets für die einzelnen Variablen. Dies geschieht in dem FUZZIFY bzw. DEFUZZIFY Block. Für jede Variable wird ein eigener Block angelegt und in diesen Blöcken die Sets definiert. Jedes Set wird durch TERM gefolgt von dem Namen eingeleitet. Es gibt dann verschiedene Möglichkeiten ein Set zu definieren. In diesem Beispiel werden einfach verschiedene Referenzpunkte gewählt, die in den Klammern angegeben werden. Der erste Wert ist die Eingabe und der Zweite die Zugehörigkeit zum Set. Zwei Punkte müssen mindestens angegeben werden. Alle weiteren Werte werden dann daraus berechnet. Nachdem die Eingabe-und Ausgabewerte angegeben und die dazugehörigen Sets definiert wurden gibt man im RULEBLOCK die Regeln an. Bevor die eigentlichen Regeln beginnen, kann man die Rule Engine noch mit 3 verschiedenen Optionen parametrisieren. Zunächst ist da die Norm. Hier reicht es entweder die AND oder OR Norm anzugeben da die jeweils andere implizit darauf folgt. Dann gibt es noch die Akkumulationsnorm, 29 KAPITEL 4. FCL UND ANTLR die angibt, mit welcher Norm die Ergebnis verbunden werden. Als Drittes gibt es noch die Aktivierungsnorm, die angibt, welche Norm genutzt wird um herauszufinden welche Regeln gefeuert werden müssen. Alle drei Optionen sind optional und haben jeweils die MIN bzw. MAX Norm als Voreinstellung. Danach folgen die Regeln. Dies können beliebig viele sein eingeleitet jeweils durch RULE gefolgt von einer Nummer. Die Regel an sich wird durch einfache IF/THEN Konstrukte definiert. Die einzelnen Bedingungen können dabei beliebig mit AND oder OR verknüft werden. Mit diesen einführenden Beispiel kann der grundlegende Aufbau von FCL schon recht gut verstanden werden. Es folgt nun die genaue Beschreibung der einzelnen Blöcke. 4.1.3. Beschreibung 4.1.3.1. VAR INPUT / VAR OUTPUT • Beide Blöcke können beliebig viele müssen aber mindestens eine Variablendeklaration enthalten getrennt durch ein Semikolon. • Eine Variablendeklaration besteht dabei immer aus dem Namen und dem Datentypen getrennt durch einen Doppelpunkt abgeschlossen durch ein Semikolon. • Als Datentyp kann nur REAL gewählt werden. • Variablen die sowohl Eingabe als auch Ausgabe für unterschiedliche Regeln sind werden als Eingabe deklariert. 4.1.3.2. FUZZIFY / DEFUZZIFY • Für jede Eingabevariable wird ein FUZZIFY Block angegeben und für jede Ausgabevariable ein DEFUZZIFY Block. • Es können beliebig viele Sets getrennt durch ein Semikolon angeben werden. • Ein Set wird deklariert durch einen Namen gefolgt von := und der Angabe der Membershipfunktion. Es gibt: 1. Polygon: Hier werden einzelne Punkte angegeben. Alle weiteren Punkte dazwischen werden berechnet. 2. Trapez: Angegeben durch TRAPE gefolgt von 4 x-Werten, die von links nach rechts das linke Minimum, das linke Maximum, das rechte Maximum und das linke Minimum angeben. 3. Dreieck: Angegeben durch TRIAN gefolgt von 3 x-Werten, die von links nach rechts das linke Minimum, das Maximum und das rechte Minimum angeben. 4. Singleton: Angegeben durch einen einfachen x-Wert. • Der DEFUZZIFY Block hat zusätzlich noch die Option für die Defuzzifizierungsmethode (METHOD). Hier gibt es: 30 KAPITEL 4. FCL UND ANTLR 1. COG: Centre of Gravity. 2. LM: Left Most Maximum. 3. RM: Right Most Maximum. 4.1.3.3. RULEBLOCK • Ein FUNCTION BLOCK kann beliebig viele RULEBLOCKs haben. • Ein RULEBLOCK besteht immer aus drei optionalen Parametern und den Regeln selbst. • Der erste Parameter ist die Operatordefinition (AND / OR). Hier wird entweder die Norm für AND oder OR angegeben. Die jeweils dazugehörige andere Norm wird dadurch implizit mit angegeben. Für AND gibt es: 1. MIN: M in(µ1 (x), µ2 (x)) 2. PROD: µ1 (x) ∗ µ2 (x) 3. BDIF: M ax(0, µ1 (x) + µ2 (x) − 1) Für OR sind es: 1. MAX: M ax(µ1 (x), µ2 (x)) 2. ASUM: µ1 (x) + µ2 (x) − µ1 (x) ∗ µ2 (x) 3. BSUM: M in(1, µ1 (x) + µ2 (x)) Wenn keine Angabe für AND oder OR gemacht wird wird MIN bzw. MAX genommen. • Der zweite Parameter ist Aktivationsmethode (ACT). Sie gibt an welche Norm genommen wird um herauszufinden welche Regeln überhaupt gefeuert werden müssen. Hier gibt es: 1. PROD: µ1 (x) ∗ µ2 (x) 2. MIN: M in(µ1 (x), µ2 (x)) Wenn keine Angabe gemacht wird, wird MIN verwendet. • Der letzte Parameter ist der Akkumulationoperator (ACCU). Dieser gibt die Norm an die zum Zusammenfügen der Ergebnisse genutzt wird. Es gibt: 1. MAX: M ax(µ1 (x), µ2 (x)) 2. BSUM: M in(1, µ1 (x) + µ2 (x)) Wenn keine Angabe gemacht wird, wird MAX verwendet. • Danach folgen die Regeln. Davon kann es beliebig viele geben. Eine Regel beginnt immer mit dem Schlüsselwort RULE und einer ID, die eine beliebige Zeichenkette beginnen mit einem Buchstaben sein kann, und endet mit einem Semikolon. Dazwischen kommt dann die eigentliche Regel. Diese besteht aus einem IF...THEN...(WITH) Konstrukt. Dabei gibt es drei Abschnitte 31 KAPITEL 4. FCL UND ANTLR – IF: Besteht aus einer oder mehreren Bedingungen verknüpft durch AND oder OR. Eine Bedingung besteht dabei aus Input IS Set. Input ist der Name einer vorher definierten Eingabevariablen und Set ist der Name eines im FUZZIFY Teil für diese Variable definierten Sets. – THEN: Besteht aus einer Folgerung bestehend aus Output IS Set. – WITH: Der WITH Teil ist optional gibt einer Folgerung eine Gewichtung. Es sind Werte zwischen 0.0 und 1.0 erlaubt. Diese beeinflussen das Ausgabeset indem die Zugehörigkeit um den angegebenen Faktor verringert wird. Wenn kein Wert angeben ist wird 1.0 verwendet. 4.2. ANTLR 4.2.1. Einleitung Nachdem FCL als Sprache für die Angabe der Sets und Regeln bestimmt wurde musste entschieden werden, wie man diese in Java einliest und in Jefis-Objekte umwandelt. Ein Möglichkeit wäre es selbst die einzelnen Zeichen aus der Datei auszulesen und einen Automaten zu entwickeln, der die Zeichenfolge auf Korrektheit überprüft und dann die Objekte erstellt. Zum Einen ist dies aber sehr aufwendig zu machen zum Anderen wird es dadurch schwer wartbar und auch erweiterbar. Dieser Umstand führt zu ANother Tool for Language Recognition, kurz ANTLR. Ein großer Vorteil ist es, dass es schon eine Grammatikdatei von ANTLR für FCL gibt 1 . Lexer und Parser werden aus dieser Grammatikdatei automatisch erzeugt und Änderungen können einfach in der Grammatik vorgenommen. Der durch den Parser erzeugte Syntaxbaum kann dann mit einem auch von ANTLR erzeugten Tree Walker durchlaufen werden, so dass dann die Jefis-Objekte daraus erstellt werden können. Im Folgenden wird erklärt, wie eine solche Grammatik definiert wird und wie der Tree Walker den Syntaxbaum verarbeiten kann. 4.2.2. Lexer/Parser Die Hauptaufgabe des Lexer und des Parsers ist es eine eingegebene Datei auf ihre syntaktische Korrektheit zu überprüfen. Der Lexer zerlegt dabei den Strom an Zeichen in für den Parser verständliche Tokens. Wenn diese Tokens an den Parser übergeben worden sind überprüft der dieser, ob die Zeichenfolge einem gültigen Programm entspricht. Ist das der Fall wird ein Baum erstellt mithilfe dessen man später den Code erzeugen kann. Die Erstellung des Lexer und des Parsers wird komplett von ANTLR übernommen. Das einzige was ANTLR dafür braucht ist eine .g Datei (Grammatik Datei). In dieser Datei wird eine kontextfreie Grammatik in EBNF angegeben, die die gewünschte Sprache beschreibt. An einem kleinen Beispiel soll diese Grammatik jetzt beschrieben werden. Die komplette Grammatik für FCL kann im Anhang gefunden werden. 1 Entwickelt von Pablo Cingolani im Projekt JFuzzyLogic 32 KAPITEL 4. FCL UND ANTLR 4.2.3. Beispiel In diesem Beispiel wird der Teil von FCL.g erklärt, der die VAR INPUT/VAR OUTPUT Block bestimmt. 1 3 5 grammar FCL ; ...... FUNCTION_BLOCK : ( ’f ’| ’F ’)( ’ u ’| ’U ’)( ’ n ’| ’N ’)( ’ c ’| ’C ’)( ’ t ’| ’T ’)( ’ i ’| ’I ’)( ’ o ’| ’O ’)( ’ n ’| ’N ’) ’_ ’( ’b ’| ’B ’) ( ’l ’| ’L ’)( ’ o ’| ’O ’)( ’ c ’| ’C ’)( ’ k ’| ’K ’); E ND _ FU NC T IO N_ B LO C K : ( ’e ’| ’E ’)( ’ n ’| ’N ’)( ’ d ’| ’D ’) ’_ ’( ’f ’| ’F ’)( ’ u ’| ’U ’)( ’ n ’| ’N ’)( ’ c ’| ’C ’)( ’ t ’| ’T ’) ( ’i ’| ’I ’)( ’ o ’| ’O ’)( ’ n ’| ’N ’) ’_ ’( ’b ’| ’B ’)( ’ l ’| ’L ’)( ’ o ’| ’O ’)( ’ c ’| ’C ’)( ’ k ’| ’K ’); 7 9 11 TYPE_REAL VAR_INPUT VAR_OUTPUT END_VAR : : ( ’r ’| ’R ’)( ’ e ’| ’E ’)( ’ a ’| ’A ’)( ’ l ’| ’L ’); : ( ’v ’| ’V ’)( ’ a ’| ’A ’)( ’ r ’| ’R ’) ’_ ’( ’i ’| ’I ’)( ’ n ’| ’N ’)( ’ p ’| ’P ’)( ’ u ’| ’U ’)( ’ t ’| ’T ’); : ( ’v ’| ’V ’)( ’ a ’| ’A ’)( ’ r ’| ’R ’) ’_ ’( ’o ’| ’O ’)( ’ u ’| ’U ’)( ’ t ’| ’T ’)( ’ p ’| ’P ’)( ’ u ’| ’U ’)( ’ t ’| ’T ’); ( ’e ’| ’E ’)( ’ n ’| ’N ’)( ’ d ’| ’D ’) ’_ ’( ’v ’| ’V ’)( ’ a ’| ’A ’)( ’ r ’| ’R ’); 13 ...... 15 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Lexer // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ...... COLON : ’: ’; SEMICOLON : ’; ’ ; ...... // A DIGIT fragment DIGIT : ’0 ’.. ’9 ’ ; 17 19 21 23 25 27 // A letter fragment LETTER : LOWER | UPPER ; fragment LOWER : ’a ’.. ’ z ’; fragment UPPER : ’A ’.. ’ Z ’; 29 31 33 35 37 39 41 // Letter or digit fragment ALPHANUM : LETTER | DIGIT ; ...... // An identifier . ID : LETTER ( ALPHANUM | ’_ ’)*; ...... // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Parser // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - main : fcl : f = fcl -> ^( FCL $f ); ( function_block )+; 43 45 // Function block function_block : FUNCTION_BLOCK ^ ( ID )? ( declaration )* EN D_ F UN C TI ON _ BL OC K !; declaration : var_input | var_output | fuzzify_block | defuzzify_block | rule_block ; 47 51 // Variables input and output var_input : VAR_INPUT ^ ( var_def )+ END_VAR !; var_output : VAR_OUTPUT ^ ( var_def )+ END_VAR !; var_def : ID ^ COLON ! data_type SEMICOLON !; 53 ...... 55 data_type : TYPE_REAL ; 49 Zu Beginn einer .g Datei kommt die Deklaration der Schlüsselwörter. In diesem Ausschnitt ist es z.B. TYPE REAL, welches für die Zeichenkette REAL steht. Die Groß- und Kleinschreibung der einzelnen Buchstaben ist dabei egal. Weiter folgen dann die Angaben für den Lexer, d.h. wichtige Zeichen, wie z.B. der Doppelpunkt oder das Semikolon. Danach kommt dann der Teil für den Parser. Hier werden einfache Ersetzungsregeln aufgestellt in denen auch der Baum erstellt wird. Der oberste Knoten eines FCL Baumes ist immer die Zeichenfolge FCL. Die Kinder davon sind die Bäume für die einzelnen Funktionsblöcke. Um dies zu realisieren gibt es die beiden Regeln main und fcl. main wird einfach nur durch fcl ersetzt. Durch f=fcl wird eine Variable f erzeugt, die im zweiten Teil der Regeln benutzt werden kann. Der zweite Teil erzeugt den eigentlichen 33 KAPITEL 4. FCL UND ANTLR Baum. Durch das ^ gefolgt von den Klammern wird ein neuer Unterbaum erzeugt, wobei das erste Token, hier FCL, der Knoten ist und die darauf folgenden Token die Blätter, hier die vorher erzeugte Variable f. $f wird dann durch die von fcl erzeugten Unterbäume ersetzt. Die Regel fcl ist recht einfach. Durch das + gibt sie an, das es durch mehrere aber mindestens einen function block ersetzt werden muss. Hier wird kein neuer Unterbaum erzeugt. Das folgt in function block. Ein Funktionsblock muss immer mit FUNCTION BLOCK anfangen und mit END FUNCTION BLOCK enden. Dazwischen folgt eine optionale ID angegeben durch das ? und null oder mehrere declaration angegeben durch das *. Durch das ^ wird wieder der neue Unterbaum eingeleitet mit dem Knoten FUNCTION BLOCK. Das erste Blatt ist dann die ID. Die weitere Blätter sind die declaration, falls vorhanden. Das ! gibt an, dass END FUNCTION BLOCK verworfen und nicht mit in den Baum übernommen wird. Eine declaration wiederum wird durch eine der 5 Optionen ersetzt. Für das Beispiel sind nur var input und var output interessant. var input und var output sind recht ähnlich und unterscheiden sich nur durch die Namen. Auch hier wird wieder ein neuer Unterbaum für jeden Block angelegt. Der Knoten ist wieder VAR INPUT oder VAR OUTPUT und die Blätter sind eine oder mehrere var def. END VAR wird wieder verworfen. Eine der letzten Regeln für die Variablen Blöcke ist var def. Solch eine var def besteht immer aus einer ID gefolgt von einem Doppelpunkt, dem data type und abgeschlossen mit einem Semikolon. Der Unterbaum der daraus erzeugt wird besteht einfach nur aus der ID und dem Datentypen als Blatt. Zuletzt kommt noch data type. Hier ist nur TYPE REAL zugelassen. Zum verdeutlichen wird an dem folgenden kurzen Codebeispiel gezeigt, welcher Baum daraus erzeugt wird. 1 FUNCTION_BLOCK tipper 3 VAR_INPUT service : REAL ; food : REAL ; END_VAR 5 7 9 VAR_OUTPUT tip : REAL ; END_VAR 11 ...... 13 E ND _ FU NC T IO N_ B LO C K Aus der ersten Regel main wird zu Beginn der Knoten FCL erzeugt an dem später der restliche Baum hängt. Die ersten gefunden Token sind FUNCTION BLOCK und tipper. Zuerst wird dadurch die Regeln fcl behandelt, die dann wieder zu function block führt. In dieser Regeln wird ein neuer Baum angelegt mit dem Knoten FUNCTION BLOCK und zunächst tipper als einziges Kind. Dieser Baum wird als Kind an den Knoten FCL angehängt. Weiter geht es mit declaration. Davon kann es beliebig viele geben. In diesem Beispiel sind es genau zwei. Einmal ein var input und ein var output. Mit der Regel var input 34 KAPITEL 4. FCL UND ANTLR wird aus aus dem ersten Block zunächst ein Knoten VAR INPUT erzeugt, der an dem Knoten FUNCTION BLOCK dran gehangen wird. An den neuen Knoten werden wiederum mit der Regel var def zwei neue Knoten dran gehangen. Jeweils einer für service und einer für food. Jeder dieser Knoten bekommt noch den Datentypen, hier TYPE REAL angehängt. Das Gleiche passiert noch für var output. Hier wird der Knoten VAR OUTPUT erzeugt und der Knoten tip angehängt, der wiederum den Knoten TYPE REAL dranhängen hat. Auch VAR OUTPUT kommt an FUNCTION BLOCK und er Baum ist damit vollständig. Der gesamte Baum ist auch in Abbildung 4.1 abgebildet. Abbildung 4.1.: Der erzeugte Beispielbaum. 35 KAPITEL 4. FCL UND ANTLR 4.2.4. Benutzung in Java Wenn der Lexer und Parser in der .g Datei angegeben wurden muss dieser nur noch von ANTLR erzeugt werden, was komplett automatisch geschieht. Danach können beide in einem Java Programm benutzt werden. Es gibt verschiedene Möglichkeiten um mit ANTLR den Lexer/Parser zu erzeugen. Die erste wäre, das im ANTLR mitgelieferte Tool zu benutzen, dem man einfach die .g Datei übergibt und das dann die beiden Klassen für den Lexer und den Parser erzeugt und in .java Dateien ablegt. Die andere in dem Projekt benutzte Möglichkeit ist es das Maven Plugin zu verwenden. Man kann ein Goal erstellen, das automatisch die Klassen erzeugt. Dazu muss man nur in der pom.xml das Quellverzeichnis und das Ausgabeverzeichnis angeben und dann das Goal ausführen. 2 4 6 8 10 12 14 16 < plugin > < groupId > org . antlr </ groupId > < artifactId > antlr3 - maven - plugin </ artifactId > < version > 3.1.1 </ version > < configuration > < sourceDirectory > src / main / resources </ sourceDirectory > < outputDirectory > gen </ outputDirectory > </ configuration > < executions > < execution > < goals > < goal > antlr </ goal > </ goals > </ execution > </ executions > </ plugin > Die erzeugten Klassen kann man dann in dem Projekt folgendermaßen benutzen: 2 4 6 ...... String sourcefile = ‘‘ test . fcl ’ ’ FclLexer lexer = new FclLexer ( new ANT LRR eade rSt rea m ( new FileReader ( sourceFile ))); FclParser parser = new FclParser ( new Co mmo nTo ken Stre am ( lexer )); FclParser . main_return root = parser . main (); Tree parsingTree = (( Tree ) root . getTree ()); ...... Der Lexer bekommt einen ANTLRReaderStream der die Quelldatei geöffnet hat. Der Parser bekommt dann einen CommonTokenStream vom Lexer. Am dem Parser können dann die Regeln aufgerufen werden, die vorher in der .g Datei angelegt wurden. Da man hier die ganze Datei parsen will fängt man mit der ersten Regel main an. Von der Rückgabe des Aufrufs bekommt man den dann einen Tree geliefert den man weiter mit dem Treewalker verwenden kann. 4.2.5. Treewalker Mit dem erhaltenen Baum könnte man direkt in Java weiterarbeiten. Man kann jeweils die Kinder als eigene Bäume bekommen und so den kompletten Baum durchlaufen und auswerten. Allerdings gibt es bei ANTLR eine viel angenehmere Lösung, den Treewalker. Ein Treewalker wird wie der Lexer/Parser in einer .g Datei mit der selben Syntax angegeben. Die einzelnen Regeln sind fast identisch. Nur wird hier nicht die FCL Datei geparst sondern der Baum. In jeder Regel kann man Java Code angeben und die Werte aus den Knoten im Java Code verwenden, so dass man direkt an den gewünschten Stellen die passenden Aktionen vornehmen kann. 36 KAPITEL 4. FCL UND ANTLR 4.2.6. Beispiel In diesem Beispiel wird ein Treewalker vorgestellt der den Baum aus dem Beispiel zuvor parst und die Eingabe und Ausgabe Variablen und deren Datentyp einfach über System.out ausgibt. Der richtige Treewalker aus dem Projekt gibt die die einzelnen Werte natürlich nicht nur einfach aus sondern erzeugt damit die RuleEngine. Der Quellcode dafür befindet sich im Anhang. 1 3 5 7 @members { private String varType = null ; private String varName = null ; } main : fcl : ^( FCL fcl ); ( function_block )+; 9 11 // Function block function_block : ^( FUNCTION_BLOCK ( ID )? ( declaration )*); declaration : var_input | var_output | fuzzify_block | defuzzify_block | rule_block ; 13 15 17 19 21 // Variables input and output var_input : ^( VAR_INPUT ( var_def )*) { System . out . println ( ‘ ‘ Eingabevariablen : ’ ’); System . out . println (" Name : " + varName + " , Type : " + varType );}; var_output : ^( VAR_OUTPUT ( var_def )){ System . out . println ( ‘ ‘ Ausgabevariablen : ’ ’); System . out . println (" Name : " + varName + " , Type : " + var \ Ttype );}; var_def : ^( ID data_type ) { varName = $ID . text }; ...... data_type : TYPE_REAL { varType = ‘‘ REAL ’ ’}; Aus der .g Datei wird später eine Java Klasse erzeugt. Deshalb ist es auch möglich statische Java-Blöcke darin zu definieren, die 1 zu 1 in die Java Klasse übernommen werden. Zum einen gibt es den @header Block indem das Package und die Includes angegeben werden können und zum anderen den @members indem man sowohl Klassenvariablen als auch Funktionen deklarieren kann. In diesen Beispiel werden die beiden String varType und varName deklariert die später noch Verwendung finden. Danach fangen wieder die Regeln an. Um das Ganze übersichtlich zu gestalten werden hier wieder die gleichen Namen wie bei dem Parser gewählt. Die Regeln vom Parser können als Grundlage gewählt werden und müssen nur leicht angepasst werden um den Baum zu parsen. Das Zeichen ^ gibt auch hier wieder an, dass ein neuer Unterbaum beginnt. In den Klammern ist dann angegeben, wie dieser auszusehen hat um gematcht zu werden. In diesem Beispiel heißt das, dass der Baum mit dem Knoten FCL beginnen muss. Die Kinder werden aus der Regel fcl abgeleitet und die besteht wiederum aus einem oder mehreren function block. Das geht dann so weiter wie vorher. Ein function block besteht wieder aus dem Knoten FUNCTION BLOCK und den Kindern ID und declaration. Interessant wird es ab der Regel var input. Hier werden die Eingabevariablen mit Namen und Typ ausgegeben. Jetzt könnte man annehmen, dass die beiden Variablen varName und varType noch null sind, wenn man das erste Mal dort hinkommt und die Ausgabe würde nicht funktionieren. Das ist aber nicht der Fall. Der Baum wird von unten nach oben durchlaufen. D.h. es wird mit data type begonnen, wo die Variable varType gesetzt wird. Danach geht es in die Regel var def. Hier wird varName gesetzt. Dafür wird der Wert von ID ausgelesen. Dies kann man in Java Code einfach machen, indem man ein $ vor ID setzt und dann die Variable text ausliest. Erst dann kommt man in die Regel var input. Hier greift man dann einfach auf die vorher gesetzten Strings zu und gibt diese einfach über System.out aus. 37 Teil V. Anhang 38 5. ANTLR A. Fcl.g 1 grammar Fcl ; 3 options { // We ’ re going to output an AST . output = AST ; } 5 7 9 11 // Tokens ( reserved words ) tokens { POINT ; FCL ; } 13 15 @lexer :: header { package de . lab4inf . fcl ; } 17 19 @header { package de . lab4inf . fcl ; } 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54 56 58 60 62 64 66 68 ABS : ( ’a ’| ’A ’ )( ’b ’| ’B ’ )( ’s ’| ’S ’ ); ACCU : ( ’a ’| ’A ’ )( ’c ’| ’C ’ )( ’c ’| ’C ’ )( ’u ’| ’U ’ ); ACT : ( ’a ’| ’A ’ )( ’c ’| ’C ’ )( ’t ’| ’T ’ ); AND : ( ’a ’| ’A ’ )( ’n ’| ’N ’ )( ’d ’| ’D ’ ); ASUM : ( ’a ’| ’A ’ )( ’s ’| ’S ’ )( ’u ’| ’U ’ )( ’m ’| ’M ’ ); BDIF : ( ’b ’| ’B ’ )( ’d ’| ’D ’ )( ’i ’| ’I ’ )( ’f ’| ’F ’ ); BSUM : ( ’b ’| ’B ’ )( ’s ’| ’S ’ )( ’u ’| ’U ’ )( ’m ’| ’M ’ ); COA : ( ’c ’| ’C ’ )( ’o ’| ’O ’ )( ’a ’| ’A ’ ); COSINE : ( ’c ’| ’C ’ )( ’o ’| ’O ’ )( ’s ’| ’S ’ )( ’i ’| ’I ’ )( ’n ’| ’N ’ )( ’e ’| ’E ’ ); COG : ( ’c ’| ’C ’ )( ’o ’| ’O ’ )( ’g ’| ’G ’ ); COGS : ( ’c ’| ’C ’ )( ’o ’| ’O ’ )( ’g ’| ’G ’ )( ’s ’| ’S ’ ); COGF : ( ’c ’| ’C ’ )( ’o ’| ’O ’ )( ’g ’| ’G ’ )( ’f ’| ’F ’ ); COS : ( ’c ’| ’C ’ )( ’o ’| ’O ’ )( ’s ’| ’S ’ ); DEFAULT : ( ’d ’| ’D ’ )( ’e ’| ’E ’ )( ’f ’| ’F ’ )( ’a ’| ’A ’ )( ’u ’| ’U ’ )( ’l ’| ’L ’ )( ’t ’| ’T ’ ); DEFUZZIFY : ( ’d ’| ’D ’ )( ’e ’| ’E ’ )( ’f ’| ’F ’ )( ’u ’| ’U ’ )( ’z ’| ’Z ’ )( ’z ’| ’Z ’ )( ’i ’| ’I ’ )( ’f ’| ’F ’ )( ’y ’| ’Y ’ ); DSIGM : ( ’d ’| ’D ’ )( ’s ’| ’S ’ )( ’i ’| ’I ’ )( ’g ’| ’G ’ )( ’m ’| ’M ’ ); END_DEFUZZIFY : ( ’e ’| ’E ’ )( ’n ’| ’N ’ )( ’d ’| ’D ’) ’_ ’( ’d ’| ’D ’ )( ’e ’| ’E ’ )( ’f ’| ’F ’ )( ’u ’| ’U ’ )( ’z ’| ’Z ’) ( ’z ’| ’Z ’ )( ’i ’| ’I ’ )( ’f ’| ’F ’ )( ’y ’| ’Y ’ ); E ND _ FU NC T IO N_ B LO C K : ( ’e ’| ’E ’ )( ’n ’| ’N ’ )( ’d ’| ’D ’) ’_ ’( ’f ’| ’F ’ )( ’u ’| ’U ’ )( ’n ’| ’N ’ )( ’c ’| ’C ’) ( ’t ’| ’T ’ )( ’i ’| ’I ’ )( ’o ’| ’O ’ )( ’n ’| ’N ’) ’_ ’( ’b ’| ’B ’ )( ’l ’| ’L ’ )( ’o ’| ’O ’ )( ’c ’| ’C ’ )( ’k ’| ’K ’ ); END_FUZZIFY : ( ’e ’| ’E ’ )( ’n ’| ’N ’ )( ’d ’| ’D ’) ’_ ’( ’f ’| ’F ’ )( ’u ’| ’U ’ )( ’z ’| ’Z ’ )( ’z ’| ’Z ’ )( ’i ’| ’I ’) ( ’f ’| ’F ’ )( ’y ’| ’Y ’ ); END_RULEBLOCK : ( ’e ’| ’E ’ )( ’n ’| ’N ’ )( ’d ’| ’D ’) ’_ ’( ’r ’| ’R ’ )( ’u ’| ’U ’ )( ’l ’| ’L ’ )( ’e ’| ’E ’ )( ’b ’| ’B ’) ( ’l ’| ’L ’ )( ’o ’| ’O ’ )( ’c ’| ’C ’ )( ’k ’| ’K ’ ); END_VAR : ( ’e ’| ’E ’ )( ’n ’| ’N ’ )( ’d ’| ’D ’) ’_ ’( ’v ’| ’V ’ )( ’a ’| ’A ’ )( ’r ’| ’R ’ ); EXP : ( ’e ’| ’E ’ )( ’x ’| ’X ’ )( ’p ’| ’P ’ ); FUNCTION : ( ’f ’| ’F ’ )( ’u ’| ’U ’ )( ’n ’| ’N ’ )( ’c ’| ’C ’ )( ’t ’| ’T ’ )( ’i ’| ’I ’ )( ’o ’| ’O ’ )( ’n ’| ’N ’ ); GAUSS : ( ’g ’| ’G ’ )( ’a ’| ’A ’ )( ’u ’| ’U ’ )( ’s ’| ’S ’ )( ’s ’| ’S ’ ); GBELL : ( ’g ’| ’G ’ )( ’b ’| ’B ’ )( ’e ’| ’E ’ )( ’l ’| ’L ’ )( ’l ’| ’L ’ ); FUNCTION_BLOCK : ( ’f ’| ’F ’ )( ’u ’| ’U ’ )( ’n ’| ’N ’ )( ’c ’| ’C ’ )( ’t ’| ’T ’ )( ’i ’| ’I ’ )( ’o ’| ’O ’ )( ’n ’| ’N ’) ’_ ’( ’b ’| ’B ’ )( ’l ’| ’L ’ )( ’o ’| ’O ’ )( ’c ’| ’C ’ )( ’k ’| ’K ’ ); FUZZIFY : ( ’f ’| ’F ’ )( ’u ’| ’U ’ )( ’z ’| ’Z ’ )( ’z ’| ’Z ’ )( ’i ’| ’I ’ )( ’f ’| ’F ’ )( ’y ’| ’Y ’ ); IF : ( ’i ’| ’I ’ )( ’f ’| ’F ’ ); IS : ( ’i ’| ’I ’ )( ’s ’| ’S ’ ); LM : ( ’l ’| ’L ’ )( ’m ’| ’M ’ ); LN : ( ’l ’| ’L ’ )( ’n ’| ’N ’ ); LOG : ( ’l ’| ’L ’ )( ’o ’| ’O ’ )( ’g ’| ’G ’ ); MAX : ( ’m ’| ’M ’ )( ’a ’| ’A ’ )( ’x ’| ’X ’ ); METHOD : ( ’m ’| ’M ’ )( ’e ’| ’E ’ )( ’t ’| ’T ’ )( ’h ’| ’H ’ )( ’o ’| ’O ’ )( ’d ’| ’D ’ ); MIN : ( ’m ’| ’M ’ )( ’i ’| ’I ’ )( ’n ’| ’N ’ ); MM : ( ’m ’| ’M ’ )( ’m ’| ’M ’ ); NC : ( ’n ’| ’N ’ )( ’c ’| ’C ’ ); NOT : ( ’n ’| ’N ’ )( ’o ’| ’O ’ )( ’t ’| ’T ’ ); NSUM : ( ’n ’| ’N ’ )( ’s ’| ’S ’ )( ’u ’| ’U ’ )( ’m ’| ’M ’ ); OR : ( ’o ’| ’O ’ )( ’r ’| ’R ’ ); PROBOR : ( ’p ’| ’P ’ )( ’r ’| ’R ’ )( ’o ’| ’O ’ )( ’b ’| ’B ’ )( ’o ’| ’O ’ )( ’r ’| ’R ’ ); 39 KAPITEL 5. ANTLR 70 72 74 76 78 80 82 84 86 PROD : ( ’p ’| ’P ’ )( ’r ’| ’R ’ )( ’o ’| ’O ’ )( ’d ’| ’D ’ ); RANGE : ( ’r ’| ’R ’ )( ’a ’| ’A ’ )( ’n ’| ’N ’ )( ’g ’| ’G ’ )( ’e ’| ’E ’ ); RM : ( ’r ’| ’R ’ )( ’m ’| ’M ’ ); RULE : ( ’r ’| ’R ’ )( ’u ’| ’U ’ )( ’l ’| ’L ’ )( ’e ’| ’E ’ ); RULEBLOCK : ( ’r ’| ’R ’ )( ’u ’| ’U ’ )( ’l ’| ’L ’ )( ’e ’| ’E ’ )( ’b ’| ’B ’ )( ’l ’| ’L ’ )( ’o ’| ’O ’ )( ’c ’| ’C ’ )( ’k ’| ’K ’ ); SIGM : ( ’s ’| ’S ’ )( ’i ’| ’I ’ )( ’g ’| ’G ’ )( ’m ’| ’M ’ ); SIN : ( ’s ’| ’S ’ )( ’i ’| ’I ’ )( ’n ’| ’N ’ ); SINGLETONS : ( ’s ’| ’S ’ )( ’i ’| ’I ’ )( ’n ’| ’N ’ )( ’g ’| ’G ’ )( ’l ’| ’L ’ )( ’e ’| ’E ’ )( ’t ’| ’T ’ )( ’o ’| ’O ’) ( ’n ’| ’N ’ )( ’s ’| ’S ’ ); SUM : ( ’s ’| ’S ’ )( ’u ’| ’U ’ )( ’m ’| ’M ’ ); TAN : ( ’t ’| ’T ’ )( ’a ’| ’A ’ )( ’n ’| ’N ’ ); TERM : ( ’t ’| ’T ’ )( ’e ’| ’E ’ )( ’r ’| ’R ’ )( ’m ’| ’M ’ ); THEN : ( ’t ’| ’T ’ )( ’h ’| ’H ’ )( ’e ’| ’E ’ )( ’n ’| ’N ’ ); TRAPE : ( ’t ’| ’T ’ )( ’r ’| ’R ’ )( ’a ’| ’A ’ )( ’p ’| ’P ’ )( ’e ’| ’E ’ ); TRIAN : ( ’t ’| ’T ’ )( ’r ’| ’R ’ )( ’i ’| ’I ’ )( ’a ’| ’A ’ )( ’n ’| ’N ’ ); TYPE_REAL : ( ’r ’| ’R ’ )( ’e ’| ’E ’ )( ’a ’| ’A ’ )( ’l ’| ’L ’ ); VAR_INPUT : ( ’v ’| ’V ’ )( ’a ’| ’A ’ )( ’r ’| ’R ’) ’_ ’( ’i ’| ’I ’ )( ’n ’| ’N ’ )( ’p ’| ’P ’ )( ’u ’| ’U ’ )( ’t ’| ’T ’ ); VAR_OUTPUT : ( ’v ’| ’V ’ )( ’a ’| ’A ’ )( ’r ’| ’R ’) ’_ ’( ’o ’| ’O ’ )( ’u ’| ’U ’ )( ’t ’| ’T ’ )( ’p ’| ’P ’ )( ’u ’| ’U ’ )( ’t ’| ’T ’ ); WITH : ( ’w ’| ’W ’ )( ’i ’| ’I ’ )( ’t ’| ’T ’ )( ’h ’| ’H ’ ); 88 90 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Lexer // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 92 94 96 98 // Send runs of space and tab characters to the hidden channel . WS : ( ’ ’ | ’\ t ’ )+ { $channel = HIDDEN ; }; // Treat runs of newline characters as a single NEWLINE token . // On some platforms , newlines are represented by a \ n character . // On others they are represented by a \ r and a \ n character . NEWLINE : ( ’\ r ’? ’\ n ’ )+ { $channel = HIDDEN ; }; 100 102 104 106 108 110 112 114 116 // Common symbols ASSIGN_OPERATOR : ’: ’ ’= ’; COLON : ’: ’; COMMA : ’ , ’; DOT : ’. ’; DOTS : ’ .. ’; HAT : ’^ ’ ; LEFT_CURLY : ’{ ’; LEFT_PARENTHESIS : ’( ’; MINUS : ’ - ’ ; PERCENT : ’% ’ ; PLUS : ’+ ’ ; RIGHT_CURLY : ’} ’; RI GHT _PA RENT HES IS : ’) ’ ; SEMICOLON : ’; ’ ; SLASH : ’/ ’ ; STAR : ’* ’ ; 118 120 122 // A number is a set of digits fragment NUMBER : ( DIGIT )+; // A DIGIT fragment DIGIT : ’0 ’ .. ’9 ’ ; 124 126 128 130 // A letter fragment LETTER : LOWER | UPPER ; fragment LOWER : ’a ’ .. ’z ’; fragment UPPER : ’A ’ .. ’Z ’; // Letter or digit fragment ALPHANUM : LETTER | DIGIT ; 132 134 136 138 140 142 144 // Real number ( float / double ) without any sign REAL : ( PLUS | MINUS )? NUMBER ( ’. ’ NUMBER )? ( ’e ’ ( PLUS | MINUS )? NUMBER )? ; // FCL style comments COMMENT options { greedy = false ; } : ’ (* ’ .* ’ *) ’ NEWLINE ? { $channel = HIDDEN ; }; // ’C ’ style comments COMMENT_C options { greedy = false ; } : ’ /* ’ .* ’ */ ’ NEWLINE ? { $channel = HIDDEN ; }; // ’C ’ style single line comments COMMENT_SL : ’ // ’ ~( ’\ r ’ | ’\ n ’ )* NEWLINE { $channel = HIDDEN ; }; 146 148 150 152 // An identifier . ID : LETTER ( ALPHANUM | ’_ ’ )*; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // Parser // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 40 KAPITEL 5. ANTLR 154 156 158 160 162 164 // FCL file may contain several funcion blocks main : f = fcl -> ^( FCL $f ); fcl : ( function_block )+; // Function block function_block : FUNCTION_BLOCK ^ ( ID )? ( declaration )* EN D_ F UN C TI ON _ BL OC K !; declaration : var_input | var_output | fuzzify_block | defuzzify_block | rule_block ; // Variables input and output var_input : VAR_INPUT ^ ( var_def )* END_VAR !; var_output : VAR_OUTPUT ^ ( var_def )+ END_VAR !; var_def : ID ^ COLON ! data_type SEMICOLON ! ( range )? ; 166 168 170 172 174 176 178 180 182 // Fuzzify fuzzify_block : FUZZIFY ^ ID ( linguistic_term )* END_FUZZIFY !; linguistic_term : TERM ^ ID ASSIGN_OPERATOR ! m em b e r s h i p _ f un c t i o n SEMICOLON !; m e m b er s h i p _ f u n ct i o n : function | singleton | singletons | pi ece _wi se_ lin ear | gauss | trian | trape | sigm | gbell | cosine | dsigm ; cosine : COSINE ^ atom atom ; dsigm : DSIGM ^ atom atom atom atom ; gauss : GAUSS ^ atom atom ; gbell : GBELL ^ atom atom atom ; pi ece _wi se_l ine ar : ( points )+; sigm : SIGM ^ atom atom ; singleton : atom ; singletons : SINGLETONS ^ ( points )+ ; trape : TRAPE ^ atom atom atom atom ; trian : TRIAN ^ atom atom atom ; points : LEFT_PARENTHESIS x = atom COMMA y = atom RIG HT_ PAR ENT HES IS -> ^( POINT $x $y ); atom : ID | REAL ; 184 186 188 190 192 194 196 // Functions ( for singletons ) function : FUNCTION ^ fun_pm ; fun_pm : fun_md (( PLUS ^ | MINUS ^ ) fun_md )*; fun_md : fun_mp (( STAR ^ | SLASH ^) fun_mp )*; fun_mp : fun_atom (( HAT ^ | PERCENT ^) fun_atom )*; fun_atom : atom | ( EXP ^| LN ^| LOG ^| SIN ^| COS ^| TAN ^| ABS ^)? LEFT_PARENTHESIS ! fun_pm RI GHT _PA RENT HES IS !; // Defuzzify defuzzify_block : DEFUZZIFY ^ ID ( defuzzify_item )* END_DEFUZZIFY !; defuzzify_item : d e f u z z i f i c a t i o n _ m e t h o d | default_value | linguistic_term | range ; range : RANGE ^ ASSIGN_OPERATOR ! LEFT_PARENTHESIS ! REAL DOTS ! REAL R IGHT _PA REN THE SIS ! SEMICOLON !; d e f u z z i f i c a t i o n _ m e t h o d : METHOD ^ COLON ! ( COG | COGS | COGF | COA | LM | RM | MM ) SEMICOLON !; default_value : DEFAULT ^ ASSIGN_OPERATOR ! ( REAL | NC ) SEMICOLON !; 198 200 202 204 206 208 210 212 214 216 // Ruleblock rule_block : RULEBLOCK ^ ID ( rule_item )* END_RULEBLOCK !; rule_item : o p e r a t o r _ d ef i n i t i o n | a ctiv ati on_ met hod | a cc u m u l a t i o n _m e t h o d | rule ; o p e r at o r _ d e f i n it i o n : o p e r a t o r _ d e f i n i t i o n _ o r | o p e r a t o r _ d e f i n i t i o n _ a n d ; o p e r a t o r _ d e f i n i t i o n _ o r : OR ^ COLON ! ( MAX | ASUM | BSUM ) SEMICOLON !; o p e r a t o r _ d e f i n i t i o n _ a n d : AND ^ COLON ! ( MIN | PROD | BDIF ) SEMICOLON !; ac tiv ati on_m eth od : ACT ^ COLON ! ( PROD | MIN ) SEMICOLON !; a c c u mu l a t i o n _ m et h o d : ACCU ^ COLON ! ( MAX | BSUM | NSUM | PROBOR | SUM ) SEMICOLON !; rule : RULE ^ rule_name COLON ! if_clause then_clause ( with )? SEMICOLON ! ; rule_name : ID | REAL ; if_clause : IF ^ condition ; then_clause : THEN ^ conclusion ; condition : subcondition (( AND ^| OR ^) subcondition )*; subcondition : ( NOT ^)? ( s ubco ndi tio n_b are | s u bc o nd it i on _p a re n ); su bco ndi tion _ba re : ID ^ ( IS ! ( NOT )? ID )? ; s ub c on di t io n_ p ar e n : LEFT_PARENTHESIS ! condition R IGH T_P ARE NTHE SIS !; conclusion : sub_conclusion ( COMMA ! sub_conclusion )?; sub_conclusion : ID ^ IS ! ID ; with : WITH ^ REAL ; 218 220 // Data type data_type : TYPE_REAL ; B. FCLTreeWalker.g 1 3 5 7 9 tree grammar FCLTreeWalker ; options { tokenVocab = Fcl ; ASTLabelType = CommonTree ; output = AST ; } @header { package de . lab4inf . fcl ; 41 KAPITEL 5. ANTLR 11 13 15 17 19 21 23 25 27 29 31 import org . apache . log4j . Logger ; import java . util . Map ; import java . util . ArrayList ; import import import import } de . lab4inf . fcl . F C L T r e e W a l k e r P a r t i t i o n B u i l d e r ; de . lab4inf . fcl . F C L T r e e W a l k e r R u l e B u i l d e r ; de . lab4inf . fuzzy . FuzzyPartition ; de . lab4inf . fuzzy . controller . FuzzyRule ; @members { private F C L T r e e W a l k e r P a r t i t i o n B u i l d e r partitionBuilder = new F C L T r e e W a l k e r P a r t i t i o n B u i l d e r (); private F C L T r e e W a l k e r R u l e B u i l d e r ruleBuilder = new F C L T r e e W a l k e r R u l e B u i l d e r (); private String setType = null ; private String norm = null ; private String accu_method = null ; private String a ctiv ati on_ met hod = null ; private static Logger logger = Logger . getLogger ( " de . lab4inf . fuzzy " ); public Map < String , FuzzyPartition > getPartitions () { return partitionBuilder . getPartitions (); } 33 public ArrayList < FuzzyRule > getRules () { return ruleBuilder . getRules (); 35 } 37 public String getNormName () { return norm ; 39 } 41 public String get Acc uMe tho dNa me () { return accu_method ; 43 } 45 public String g e t A c t i v a t i o n M e t h o d N a m e () { return ac tiv ati on_ meth od ; 47 } } 49 51 53 55 57 59 main : fcl : ^( FCL fcl ); ( function_block )+ { logger . info ( " Walker Start " );}; // Function block function_block : ^( FUNCTION_BLOCK ( ID )? ( declaration )*); declaration : var_input | var_output | fuzzify_block | defuzzify_block | rule_block ; // Variables input and output var_input : ^( VAR_INPUT ( var_def )*); var_output : ^( VAR_OUTPUT ( var_def )); var_def : ^( ID data_type ) ; 61 63 65 67 69 71 73 75 77 79 81 83 85 87 89 91 93 // Fuzzify fuzzify_block : ^( FUZZIFY ID ( linguistic_term )*) { logger . info ( " Walker : fuzzify_block : " + $ID . text ); partitionBuilder . newPartition ( $ID . text ); }; linguistic_term : ^( TERM ID m e m b er s h i p _ f u n c ti o n ) { logger . info ( " Walker : Linguistic Term : " + $ID . text ); partitionBuilder . newSet ( $ID . text , setType ); }; m e m b er s h i p _ f u n ct i o n : function | singleton | singletons | pi ece _wi se_ lin ear | gauss | trian | trape | sigm | gbell | cosine | dsigm ; cosine : ^( COSINE atom atom ){ setType = " cosine " ; logger . info ( " POLYGON " ); }; dsigm : ^( DSIGM atom atom atom atom ){ setType = " dsigm " ; logger . info ( " POLYGON " ); }; gauss : ^( GAUSS center = atom delta = atom ){ double pCenter = Double . parseDouble ((( Tree )( center . getTree ())). toStringTree ()); double pDelta = Double . parseDouble ((( Tree )( delta . getTree ())). toStringTree ()); partitionBuilder . addPoint ( pCenter , 0); partitionBuilder . addPoint ( pDelta , 0); setType = " gauss " ; logger . info ( " POLYGON " ); }; gbell : ^( GBELL atom atom atom ){ setType = " gbell " ; logger . info ( " GBELL " ); }; pi ece _wi se_l ine ar : ( points )+ { setType = " polygon " ; logger . info ( " POLYGON " ); }; 42 KAPITEL 5. ANTLR 95 97 99 101 103 105 107 109 111 113 115 117 119 121 123 125 127 129 131 133 135 sigm : ^( SIGM atom atom ){ setType = " sigm " ; logger . info ( " SIGM " ); }; singleton : x0 = atom { double pX0 = Double . parseDouble ((( Tree )( x0 . getTree ())). toStringTree ()); partitionBuilder . addPoint ( pX0 , 0); setType = " singelton " ; logger . info ( " SINGLETON " ); }; singletons : ^( SINGLETONS ( points )+) { setType = " singeltons " ; logger . info ( " SINGLETONS " ); }; trape : ^( TRAPE l = atom ml = atom mr = atom r = atom ) { setType = " trapez " ; logger . info ( " TRAPE " ); double lp = Double . parseDouble ((( Tree )( l . getTree ())). toStringTree ()); double mlp = Double . parseDouble ((( Tree )( ml . getTree ())). toStringTree ()); double mrp = Double . parseDouble ((( Tree )( mr . getTree ())). toStringTree ()); double rp = Double . parseDouble ((( Tree )( r . getTree ())). toStringTree ()); partitionBuilder . addPoint ( lp , 0); partitionBuilder . addPoint ( mlp , 0); partitionBuilder . addPoint ( mrp , 0); partitionBuilder . addPoint ( rp , 0); }; trian : ^( TRIAN left = atom mean = atom right = atom ) { double leftp = Double . parseDouble ((( Tree )( left . getTree ())). toStringTree ()); double meanp = Double . parseDouble ((( Tree )( mean . getTree ())). toStringTree ()); double rightp = Double . parseDouble ((( Tree )( right . getTree ())). toStringTree ()); partitionBuilder . addPoint ( leftp , 0); partitionBuilder . addPoint ( meanp , 0); partitionBuilder . addPoint ( rightp , 0); setType = " triangle " ; logger . info ( " TRIAN " ); }; points : ^( POINT x = atom y = atom ) { double xp = Double . parseDouble ((( Tree )( x . getTree ())). toStringTree ()); double yp = Double . parseDouble ((( Tree )( y . getTree ())). toStringTree ()); partitionBuilder . addPoint ( xp , yp ); logger . info ( " POINT : " + (( Tree )( x . getTree ())). toStringTree () + " " + (( Tree )( y . getTree ())). toStringTree ());}; atom : ID | REAL ; 137 139 141 143 145 147 149 151 153 155 157 159 // Functions ( for singletons ) function : FUNCTION ^ fun_pm ; fun_pm : fun_md (( PLUS ^ | MINUS ^ ) fun_md )*; fun_md : fun_mp (( STAR ^ | SLASH ^) fun_mp )*; fun_mp : fun_atom (( HAT ^ | PERCENT ^) fun_atom )*; fun_atom : atom | ( EXP ^| LN ^| LOG ^| SIN ^| COS ^| TAN ^| ABS ^)? LEFT_PARENTHESIS ! fun_pm RI GHT _PA RENT HES IS !; // Defuzzify defuzzify_block : ^( DEFUZZIFY ID ( defuzzify_item )*) { logger . info ( " Walker : defuzzify_block : " + $ID . text ); partitionBuilder . newPartition ( $ID . text );}; defuzzify_item : d e f u z z i f i c a t i o n _ m e t h o d | default_value | linguistic_term | range ; range : ^( RANGE REAL ); defuzzification_method : ^( METHOD ( COG )) { logger . info ( " Defuzzifaction Method = COG " );} |^( METHOD ( COGS )) |^( METHOD ( COGF )) |^( METHOD ( COA )) |^( METHOD ( LM )) |^( METHOD ( RM )) |^( METHOD ( MM )); // d e f u z z i f i c a t i o n _ m e t h o d : ^( METHOD COG ); default_value : ^( DEFAULT ( REAL | NC )); 161 163 165 167 169 171 173 175 177 // Ruleblock rule_block : ^( RULEBLOCK ID ( rule_item )*) { logger . info ( " Walker : rule_block : " + $ID . text );}; rule_item : o p e r a t o r _ d ef i n i t i o n | a ctiv ati on_ met hod | a cc u m u l a t i o n _m e t h o d | rule ; o p e r at o r _ d e f i n it i o n : o p e r a t o r _ d e f i n i t i o n _ o r | o p e r a t o r _ d e f i n i t i o n _ a n d ; o p e r a t o r _ d e f i n i t i o n _ o r : ^( OR ( MAX { norm = " FuzzyMinMax " ;}| ASUM { norm = " FuzzyAlgebraic " ;}| BSUM { norm = " FuzzyBoundedNorm " ;})); o p e r a t o r _ d e f i n i t i o n _ a n d : ^( AND ( MIN { norm = " FuzzyMinMax " ;}| PROD { norm = " FuzzyAlgebraic " ;}| BDIF { norm = " FuzzyBoundedNorm " ;})); ac tiv ati on_m eth od : ^( ACT ( PROD { act iva tio n_m etho d = " FuzzyAlgebraic " ;}| MIN { ac tiv ati on_m eth od = " FuzzyMinMax " ;})); a c c u mu l a t i o n _ m et h o d : ^( ACCU ( MAX { accu_method = " FuzzyMinMax " ;}| BSUM { accu_method = " FuzzyBoundedNorm " ;})); rule : ^( RULE rule_name if_clause then_clause ( with )?); rule_name : ID { ruleBuilder . setPartitions ( partitionBuilder . getPartitions ()); ruleBuilder . setRuleName ( $ID . text ); logger . info ( " Walker : rule_name ( ID ): " + $ID . text );} | REAL { 43 KAPITEL 5. ANTLR 179 181 183 185 187 189 191 193 195 197 199 ruleBuilder . setPartitions ( partitionBuilder . getPartitions ()); ruleBuilder . setRuleName ( $REAL . text ); logger . info ( " Walker : rule_name ( REAL ): " + $REAL . text );}; if_clause : ^( IF condition ); then_clause : ^( THEN conclusion ) { logger . info ( " Walker : then_clause " );}; condition : ^( OR condition condition ) { ruleBuilder . addOrRelation (); logger . info ( " Walker : condition ( OR ) " );} | ^( AND condition condition ) { ruleBuilder . addAndRelation (); logger . info ( " Walker : condition ( AND ) " );} | subcondition { logger . info ( " Walker : condition " );}; // condition : subcondition (( AND ^| OR ^) subcondition )*; subcondition : ( NOT ^)? ( s ubco ndi tio n_b are ); su bco ndi tion _ba re : ^( x = ID ( ( NOT )? y = ID )?) { ruleBuilder . addVariable ( $x . text , $y . text ); logger . info ( " Walker : su bco ndi tion _ba re " + $x . text + " " + $y . text );}; // s ub c on d it io n _p a re n : condition ; conclusion : sub_conclusion ( sub_conclusion )* { ruleBuilder . c l e a r C on d i t i o n S t ac k ();}; sub_conclusion : ^( x = ID y = ID ) { ruleBuilder . addConclusion ( $x . text , $y . text ); ruleBuilder . newRule ();} ; with : ^( WITH REAL ); // Data type data_type : TYPE_REAL ; 201 203 atom1 atom2 : : atom ; atom ; 44 6. Jefis Ruleengine Listing 6.1: FCL-Datei Applet Beispiel FUNCTION_BLOCK applet 2 4 6 8 10 VAR_INPUT service : REAL ; food : REAL ; END_VAR VAR_OUTPUT tip : REAL ; waiter : REAL ; END_VAR 12 14 16 FUZZIFY service TERM poor := (0 , 1) (4 , 0); TERM good := (1 , 0) (4 ,1) (6 ,1) (9 ,0); TERM excellent := (6 , 0) (9 , 1); END_FUZZIFY 18 20 22 24 26 28 30 32 34 36 38 FUZZIFY food TERM rancid := (0 , 1) (1 , 1) (3 ,0); TERM delicious := (7 ,0) (9 ,1); END_FUZZIFY DEFUZZIFY tip TERM cheap := (0 ,0) (5 ,1) (10 ,0); TERM average := (10 ,0) (15 ,1) (20 ,0); TERM generous := (20 ,0) (25 ,1) (30 ,0); END_DEFUZZIFY DEFUZZIFY waiter TERM sad := ( -1.1 ,0) ( -1 ,1) (0 ,1) (3 ,0); TERM normal := (2 ,0) (4 ,1) (5 ,1) (7 ,0); TERM happy := (6 ,0) (9 ,1) (9.5 ,1) (9.6 ,0); END_DEFUZZIFY RULEBLOCK No1 RULE 1 : IF service IS good AND food IS delicious THEN tip IS generous ; RULE 2 : IF tip IS generous THEN waiter IS happy ; END_RULEBLOCK 40 E ND _ FU NC T IO N_ B LO C K 45 Abbildungsverzeichnis 1.1. 1.2. 1.3. 1.4. 1.5. 1.6. 1.7. 1.8. 1.9. Beispiel Fuzzy Partition für einen Wertebereich von 0 bis 80 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Beispiel Fuzzy-Regler in einem Schaltbild . . . . . . . . . . Flugbahn und Geschwindigkeitskorrektur über Fuzzy . . . . Schaltplan der Flugbahn und Geschwindigkeitskorrektur . . Bierglas auf Inversen Pendel; Fuzzysets des Beispiels . . . . Regeln des Inversen Pendels . . . . . . . . . . . . . . . . . . Komponenten eines Regelbasierten Systems [Bec] . . . . . . UML Diagramm der wichtigsten Jefis Klassen [NW09] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 . 5 . 6 . 8 . 8 . 9 . 9 . 10 . 13 2.1. Auflistung der unterschiedlichen Rete-OO Knoten . . . . . . . . . . . . . . 16 2.2. Baum für die im Listing gezeigte Regel . . . . . . . . . . . . . . . . . . . . 17 2.3. Klassendiagramm des Jefis-Drools-Adapters . . . . . . . . . . . . . . . . . 20 3.1. Applet zur Visualisierung der Implikation . . . . . . . . . . . . . . . . . . 24 4.1. Der erzeugte Beispielbaum. . . . . . . . . . . . . . . . . . . . . . . . . . . 35 46 Literaturverzeichnis [Bec] Becker, P.: Wissensbasierte Systeme II. Vorlesung an der FH Bonn Rhein Sieg. [Bei06] Beierle, C. und Kern-Isberner, G.: Methoden wissensbasierter Systeme: Grundlagen-Algorithmen-Anwendungen. Vieweg + Teubner Verlag, 2006. [Dre] Drexl, M.N. und Koch, M.: Modellierung von Gesch äftsregeln. Modellbasierte Softwareentwicklung, Seite 103. [dro10] JBoss Drools Documentation Drools Expert“. Website, Juni 2010. ” Verfügbar online unter http://downloads.jboss.com/drools/docs/5.0. 1.26597.FINAL/drools-expert/html_single/index.html; besucht am 18. Juni 2010. [DS08] Davide Sottara, Paola Mello und Mark Proctor: Rule Representation, Interchange and Reasoning on the Web, Kapitel Adding uncertainty to a Rete-OO inference engine, Seiten 104–118. Springer, 2008. [DWM08] Dr. Wolfgang Martin, Thomas Cotic und Lars Wunderlich: Das Ende des Software-Release-Zyklus? - Business Rules Management. Jaxenter, 2008. [iec10] FCL Entwurf der IEC. Website, Juni 2010. Verfügbar online unter http: //www.fuzzytech.com/binaries/ieccd1.pdf; besucht am 18. Juni 2010. [mve10] MVEL Codehaus Projektseite. Website, Juni 2010. Verfügbar online unter http://mvel.codehaus.org/; besucht am 18. Juni 2010. [Nel05] Nellessen, P.: Vortriebssynchrone Prognose der Setzungen bei Fl üssigkeitsschildvortrieben auf Basis der Auswertung der Betriebsdaten mit Hilfe eines Neuro-Fuzzy-Systems. Cuvillier Verlag, 2005. [NW09] Nikolaus Wulff, Davide Sottara: Rule Interchange and Applications, Kapitel Fuzzy Reasoning with a Rete-OO Rule Engine. Springer Berlin / Heidelberg, 2009. [Pul00] Pullmann, T.: Implementierung eines wissensbasierten Softwaresystems zum Entwurf und zur Bemessung von Stahlbeton-Tragwerken. TU Darmstadt, Vertieferarbeit, 2000. 47 Literaturverzeichnis [Sot10a] Sottora, D.: Blog Drools Chance. Website, Juni 2010. Verfügbar online unter http://blog.athico.com/search/label/Drools%20Chance; besucht am 18. Juni 2010. [Sot10b] Sottora, D.: Drools Chance Repisitory. Website, Juni 2010. Verfügbar online unter https://svn.jboss.org/repos/labs/labs/jbossrules/ branches/DroolsChance; besucht am 18. Juni 2010. 48