Binary Decision Diagrams (BDDs) - IAIK

Werbung
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
Herunterladen