Georg Hofferek Logik und Berechenbarkeit Handout Logik und Berechenbarkeit 22.11.2011 Binary Decision Diagrams (BDDs)1 Übersicht Es gibt viele verschiedene Möglichkeiten um Boole’sche Funktionen zu repräsentieren (Boole’sche Formeln, Minterme, Wahrheitstabellen,…). Manche davon sind kanonisch, das bedeutet, dass die Repräsentation einer gegebenen Funktion eindeutig ist, bzw. das zwei Funktionen dann und nur dann identisch sind, wenn ihre Repräsentationen identisch sind (wobei Dinge wie die Reihenfolge es Anschreibens von Termen meist vernachlässigt werden). Wahrheitstabellen sind beispielsweise eine kanonische Repräsentation von Boole’schen Funktionen, Boole’sche Formeln hingegen sind nicht kanonisch (zu einer gegebenen Funktion existieren viele Boole’sche Formeln, die sie beschreiben). Sogenannte Binäre Entscheidungsdiagramme (engl.: Binary Decision Diagrams; BDDs) sind eine weitere Möglichkeit Boole’sche Funktionen zu repräsentieren. Unter bestimmten Voraussetzungen, die nachfolgend noch näher beschrieben werden, sind BDDs kanonisch. BDDs bieten für viele Funktionen eine sehr kompakte Repräsentation, und es existieren effiziente Algorithmen zur Manipulation von BDDs. Abb. 1: Beispiel für ein BDD. Dargestellt ist die Funktion π = (π ∧ π ∧ π) ∨ (¬π ∧ π) ∨ (¬π ∧ π) 1 Grafiken übernommen aus Gary D. Hachtel, Fabio Somenzi: “Logic Synthesis and Verification Algorithms”, Springer, 1996 1 Georg Hofferek Logik und Berechenbarkeit BDDs sind gerichtete, azyklische Graphen (engl.: Directed Acyclic Graphs; DAGs). Ein Beispiel für ein BDD ist in Abb. 1 dargestellt. Das BDD besteht aus einem Wurzelknoten (f), Knoten für die Variablen (a, b, c, d) und Endknoten (1, 0). Die Kanten sind jeweils mit T (für „Then“) oder E (für „Else“) beschriftet. Um den Funktionswert zu einer gegebenen Variablenbelegung zu finden geht man wie folgt vor: Ausgehend vom Wurzelknoten folgt man an jedem Variablenknoten der „Then“-Kante, wenn die entsprechende Variable den Wert 1 hat, ansonsten folgt man der „Else“-Kante. Der Endknoten den man auf diese Art und Weise erreicht gibt den Funktionswert an. Wie wir bereits wissen lassen sich Formeln in CNF oder DNF direkt und unmittelbar in 2-Level Schaltungen, bestehend aus UND und ODER Gattern umsetzen. BDDs hingegen lassen sich unmittelbar durch ein Multiplexer-Netzwerk realisieren. Übung: Entwirf eine Multiplexer-Schaltung für das BDD in Abb. 1. Komplementierende Kanten (engl.: Complement Edges) Um in einigen Fällen noch effizientere Implementierungen erreichen zu können, gibt es neben den bereits gezeigten BDDs auch welche mit „komplementierenden Kanten“. Geht man entlang einer komplementierenden Kante, so ist der abschließend erhaltene Funktionswert zu komplementieren. Komplementierende Kanten werden in der graphischen Repräsentation durch einen ausgefüllten Kreis markiert. Um später Kanonizität sicherstellen zu können wird vereinbart, dass nur „Else“-Kanten komplementierend sein können. Des Weiteren ist es üblich, nicht komplementierende „Else“-Kanten mit einem leeren Kreis zu markieren. Dadurch kann dann die Markierung „T“ oder „E“ entfallen, weil alle nicht markierten Kanten „Then“-Kanten sind. Außerdem kann man durch die Einführung komplementierender Kanten auf einen der beiden Endknoten (0,1) verzichten, im Normalfall auf 0. Aus Gründen der Einfachheit sei darüber hinaus vereinbart, dass Kanten „ohne Ziel“ zum Endknoten 1 zeigen. (siehe Abb. 2) Abb. 2: BDDs mit komplementierenden Kanten Übung: Finde eine Formel für die dargestellten Funktionen 2 Georg Hofferek Logik und Berechenbarkeit Formale Definition Ein BDD ist ein gerichteter, azyklischer Graph (π ∪ Φ ∪ {π}, πΈ), der eine Funktion π: {0,1}π → {0,1}π repräsentiert. Seine Knoten sind in drei Untermengen unterteilt. π ist die Menge aller internen Knoten. Diese Knoten haben je zwei ausgehende Kanten. Jeder Knoten π£ ∈ π besitzt eine Bezeichnung π(π£) ∈ ππΉ , wobei ππΉ = {π₯1 , … , π₯π } die Menge der Variablen ist, von denen π abhängt. π ist der Endknoten. Er besitzt keine ausgehenden Kanten. Φ ist die Menge der Funktionsknoten. Die Funktionsknoten stehen in einer eineindeutigen Beziehung zu den Komponenten von π. Diese Knoten haben keine eingehenden Kanten und je nur eine ausgehende Kante. Die von Funktionsknoten ausgehenden Kanten können das Attribut „komplementierend“ besitzen. Die beiden von einem internen Knoten ausgehenden Kanten werden mit T und E beschriftet, wobei die mit E beschrifteten Kanten das Attribut „komplementierend“ besitzen können. Mit (π(π£), π, πΈ) wird ein interner Knoten und seine beiden ausgehenden Kanten bezeichnet. Die Variablen in ππΉ sind geordnet. Wenn der Knoten π£π ein Nachfahre des Knotens π£π ist, dann gilt π(π£π ) < π(π£π ). Die durch das BDD repräsentierte Funktion ist wie folgt definiert: 1. Die Funktion des Endknotens ist die konstante Funktion 1. 2. Die Funktion einer Kante ist die Funktion des Knotens, auf den sie zeigt, außer, die Kante besitzt, das „komplementierend“-Attribut. Falls die Kante das „komplementierend“Attribut besitzt, ist die Funktion der Kante das Komplement der Funktion des ZielKnotens. 3. Die Funktion eines internen Knotens π£ ∈ π ist gegeben durch (π(π£) ∧ ππ ) ∨ (¬π(π£) ∧ ππΈ ), wobei ππ bzw. ππΈ die Funktionen der T- bzw. E-Kante von π£ sind. 4. Die Funktion eines Funktionsknotens π ∈ Φ ist die Funktion der davon ausgehenden Kante. Variablenordnung und Reduzierte BDDs Die Ordnung der Variablen hat einen signifikanten Einfluss auf das resultierende BDD. So repräsentiert zum Beispiel das BDD in Abb. 3 dieselbe Funktion wie das BDD in Abb. 1, allerdings Abb. 3: BDD mit Variablenordnung π ≤ π ≤ π ≤ π 3 Georg Hofferek Logik und Berechenbarkeit mit wesentlich weniger Knoten. Übung: Betrachte die Funktion π = (π1 ∧ π1 ∧ π1 ) ∨ (π2 ∧ π2 ∧ π2 ) ∨ (π3 ∧ π3 ∧ π3 ) und überlege, welche der beiden Variablenordnungen „besser“ ist: π1 ≤ π2 ≤ π3 ≤ π1 ≤ π2 ≤ π3 ≤ π1 ≤ π2 ≤ π3 oder π1 ≤ π1 ≤ π1 ≤ π2 ≤ π2 ≤ π2 ≤ π3 ≤ π3 ≤ π3 Übung: Konstruiere ein BDD für die Funktion π = (π ∧ π ∧ π) ∨ (¬π ∧ π) ∨ (¬π ∧ π) mit der Variablenordnung π ≤ π ≤ π ≤ π. Hinweis: Berechne dafür (rekursiv) die Kofaktoren 2 von π in Bezug auf die jeweils erste Variable der Ordnung. Übung: Überlege eine gute Variablenordnung für die Funktion π = οΏ½π ∨ (π ∧ π)οΏ½ ∧ (π ∨ π) und konstruiere das BDD. Begründe deine Entscheidung. Wie man aus der Übung erkennt kann es vorkommen, dass sich beim Erstellen eines BDDs identische Kofaktoren bzw. isomorphe Subgraphen ergeben. Das bedeutet, es gibt zwei interne Knoten, die dieselbe Funktion repräsentieren. Ebenso kann es vorkommen, dass redundante Knoten auftreten. Ein Knoten ist dann redundant, wenn er „keine Entscheidung trifft“, also wenn seine T- und E-Kante zum selben nächsten Knoten zeigen. Durch das wiederholte Verschmelzen von isomorphen Subgraphen und Entfernen redundanter Knoten kommt man zu einem reduzierten BDD. Ein reduziertes BDD ist (für eine gegebene Variablenordnung) eine kanonische Darstellung für eine Funktion. Wenn nicht anders angegeben soll im Folgenden mit „BDD“ immer „reduziertes BDD“ gemeint sein. Vorteile • • • Die Größe eines BDDs (Anzahl der Knoten) ist im schlimmsten Fall exponentiell in der Anzahl der Variablen. Dieser schlimmste Fall wird z.B. für Multiplizierer (unabhängig von der Variablenordnung) erreicht. Für viele Fälle (z.B. XOR) liefern BDDs jedoch eine kompakte Repräsentation, selbst wenn für diese Fälle CNF oder DNF Formeln keine kompakte Repräsentation bieten können. Die logische UND-Verknüpfung bzw. die logische ODER-Verknüpfung von zwei BDDs kann effizient (in polynomieller Zeit) berechnet werden. Es kann in konstanter Zeit geprüft werden ob eine durch ein BDD repräsentierte Funktion erfüllbar (engl.: satisfiable) oder eine Tautologie ist. 2 Die Kofaktoren einer Funktion π bezüglich einer Variablen π£ sind die beiden Funktionen ππ£ bzw. π¬π£ , die man erhält in dem man in π für π£ einmal 1 und einmal 0 einsetzt. 4 Georg Hofferek Logik und Berechenbarkeit Nachteile • • • Die Größe eines BDDs hängt von der Variablenordnung ab. Eine gute Ordnung zu finden ist nicht immer einfach. Es gibt Funktionen für die CNF- oder DNF-Repräsentationen kompakter sind als BDDs. CNF- oder DNF-Repräsentationen sind für manche Anwendungen „näher“ an der endgültigen Implementierung der Funktion. Wenn die Funktion z.B. durch eine 2-Level Schaltung implementiert werden soll, so muss irgendwann eine CNF- oder DNFRepräsentation erzeugt werden. BDD Softwarepakete Es existieren mehrere Software-Pakete für die (effiziente) Verwaltung und Manipulation von (großen) BDDs. Einige für (alle) Implementierungen wichtige Grundkonzepte sollen kurz erwähnt werden: Shared BDDs: Wenn man mehrere Funktionen (mit denselben Variablen) repräsentieren will ist es sehr wahrscheinlich, dass es gemeinsame Subausdrücke gibt. Daher ist es üblich, dass mehrere Funktionen von demselben BDD (nicht nur zwei identischen BDDs) repräsentiert werden. Dieses shared BDD hat dann einfach mehrere Wurzelknoten, die die einzelnen Funktionen repräsentieren. Dadurch wird einerseits Speicher gespart, andererseits kann ein Identitätsvergleich dadurch in konstanter Zeit durchgeführt werden, weil es genügt die beiden Pointer auf den jeweiligen Funktionsknoten zu vergleichen. Unique Table: In der Unique Table, die meist als Hash-Table realisiert ist, werden die (Sub-) Funktionen abgespeichert, die bereits vom BDD repräsentiert werden. Dadurch ist es möglich beim Hinzufügen oder Berechnen neuer Funktionen ohne großen Suchaufwand bereits vorhandene Knoten einzusetzen. Computed Table: Die Computed Table speichert Funktionen ab, die kürzlich berechnet worden sind, und dient so als Cache zur Effizienzsteigerung. Im Gegensatz zur Unique Table, die Fragen der Art „Gibt es bereits einen Knoten v mit Kanten zu g und h?“ beantworten kann, dient die Computed Table dazu Fragen der Art „Wurde kürzlich ein Knoten berechnet, der die UNDVerknüpfung von x und y repräsentiert?“ zu beantworten. Diese Frage kann gestellt werden, bevor bekannt ist, dass die UND-Verknüpfung von x und y ein Knoten v mit Kindern g und h ist. Dadurch kann die erneute Berechnung vermieden werden. Dynamic Reordering: In vielen Fällen kann es von Vorteil sein, BDDs von Zeit zu Zeit neu zu ordnen, um die Größe zu reduzieren. Dafür existieren viele verschiedene Algorithmen und Ansätze, auf die hier nicht näher eingegangen wird. 5 Georg Hofferek Logik und Berechenbarkeit Algorithmen BDDs werden in der Regel erzeugt indem bestehende BDDs miteinander kombiniert werden (z.B. UND- oder ODER-verknüpft). Zu Beginn legt man primitive BDDs an, die die Funktionen π = π₯π für alle π₯π die als Variablen vorkommen darstellen. Diese können dann entsprechend kombiniert und verknüpft werden. Ein Operator der in diesem Zusammenhang große Bedeutung hat ist der ITE Operator (ITE für „If-Then-Else“), der wie folgt definiert ist: πΌππΈ(πΉ, πΊ, π») = (πΉ ∧ πΊ) ∨ (¬πΉ ∧ π») Der ITE-Operator ist deshalb so bedeutsam, weil er im Stande ist, alle binären Operatoren auszudrücken. (siehe Abb. 4) Abb. 4: Binäre Operatoren durch ITE ausgedrückt Der Operator ITE wird durch den folgenden Algorithmus implementiert: πΌππΈ(πΉ,πΊ,π») = (πΉ ∧ πΊ) ∨ (¬πΉ ∧ π») = (π£ ∧ ((πΉ ∧ πΊ) ∨ (¬πΉ ∧ π»))π£) ∨ (¬π£ ∧ ((πΉ ∧ πΊ) ∨ (¬πΉ ∧ π»))¬π£) = (π£, πΌππΈ(πΉπ£,πΊπ£, π»π£ ), πΌππΈ(πΉ¬π£,πΊ¬π£,π»¬π£)) Basisfälle: πΌππΈ(1,πΉ,πΊ) = πΌππΈ(0,πΊ,πΉ) = πΌππΈ(πΉ,1,0) = πΌππΈ(πΊ,πΉ,πΉ) = πΉ Übung: Berechne ITE(f,g,h) für die Funktionen π = π ∨ (¬π ∧ π) π = (¬π ∧ π) ∨ π β = π ∨ ¬π ∨ π Zu jedem Tripel (F,G,H) existieren weitere Tripel (F1, G1, H1), so dass ITE(F,G,H) = ITE(F1, G1, H1), obwohl mindestens einer der Operanden verschieden ist. Z.B. gilt ITE(F,1,G) = ITE(G,1,F). 6 Georg Hofferek Logik und Berechenbarkeit Indem man diese verschiedenen Paare mit dem gleichen Ergebnis auf einen eindeutigen Repräsentanten abbildet, kann man mit Hilfe der Computed Table zusätzliche ITE-Aufrufe sparen. In vielen Fällen ist es ausreichend zu berechnen, ob das Ergebnis eines ITE-Aufrufs eine konstante Funktion liefert oder nicht. Will man beispielsweise überprüfen ob πΉ → πΊ dann genügt es zu zeigen, dass ¬πΉ ∨ πΊ eine Tautologie ist. Dies kann durchgeführt werden, indem ¬πΉ ∨ πΊ mit Hilfe von ITE berechnet wird. Dabei ist das eigentliche Ergebnis jedoch uninteressant, falls es nicht konstant ist. Für solche Beispiele gibt es eine speziell in diesem Fall effizientere Lösung: Den ITE_CONSTANT Algorithmus: Abb. 5: Pseudo-Code für den ITE_CONSTANT Algorithmus ITE_CONSTANT liefert einen der drei Werte 0, 1 oder non_constant zurück. Der Algorithmus basiert auf der Beobachtung, dass eine Funktion nur dann konstant ist, wenn beide Kofaktoren konstant und gleich sind. Sobald eine Verletzung dieser Bedingung erkannt wird, wird abgebrochen. Dadurch können im Fall, dass das Ergebnis non_constant ist, rekursive Aufrufe eingespart werden. Übung: Betrachte die Funktionen π = (π ∧ π) ∨ (π ∧ π ∧ ¬π) und π = (π ∧ π) ∨ (π ∧ ¬π ∧ π). Berechne mit Hilfe von ITE_CONSTANT ob π → π. Hinweis: Berechne ITE_CONSTANT(f,g,1). 7