4 Design und Implementierung werden in den Variablen result und paths gespeichert. result wird auf ” wahr“ gesetzt, falls die Kripke-Struktur kripke die Formel formula<strong>CTL</strong>pos im Zustand state erfüllt. In Abhängigkeit davon, ob es um eine Zustands- oder Pfad-Formel handelt, werden in paths Zustände bzw. Pfade verfasst, in denen die Erfüllbarkeit vorliegt. In Abschnitt 3.3.2 wurden die Implementierungsschwierigkeiten des Algorithmus 3 erwähnt. Hier liegt das Problem vor, dass man nichtdeterministisch mehrere Teilformeln oder Zustände abarbeiten ( ” nondet. choose“) oder aus mehreren einen Pfad oder einen Zustand aussuchen ( ” guess“) muss, in denen eine bestimmte Eigenschaft – d. h. eine Formel – erfüllt wird. Dieser Nichtdeterminismus wird durch die Überprüfung jeder Teilformel, jedes Zustandes und jedes Pfades der Reihe nach ersetzt, die in Frage kommen. Da es sich um die existentiellen Formeln handelt, kann man die Abarbeitung abbrechen, sobald eine Forderung (ein Zustand <strong>für</strong> die EX- oder ein Pfad <strong>für</strong> die EGbzw. EU-Formeln) erfüllt wurde. Im schlimmsten Fall müssen aber alle Kandidaten überprüft werden. Betrachten wir den Fall ϕ = EGα. Wenn man alle aus einem Zustand w0 ausgehenden Pfade betrachtet, hat man die exponentielle Anzahl von Möglichkeiten: ∣T ∣ ∣T ∣ , wobei ∣T ∣ die Anzahl aus einem Zustand ausgehender Übergänge ist. Die Laufzeit der Abarbeitung der Pfade ist entsprechend groß. Wenn die Pfade als ArrayList gespeichert sind, wird jeder Pfad vom ersten bis zum letzten Zustand auf die Erfüllbarkeit der Formel α geprüft. Die Situation ändert sich, wenn die Pfade in einem Baum gefasst sind. Abbildung 4.4 zeigt diese zwei Abarbeitunsmöglichkeiten. Oben ist eine Kripke-Struktur dargestellt. Die Zustände sind mit den atomaren Aussagen versehen. Sei ϕ = EGa. Unten links ist die Liste mit den Pfaden, rechts davon ist der entsprechende Berechnungsbaum. Die Pfade sowie der Berechnugsbaum sind unendlich, werden aber auf die Anzahl von Zuständen in der Kripke beschränkt, da die Pfade sonst einen Zyklus enthalten. Der gestrichelte Pfeil zeigt die Reihenfolge, in der die Zustände überprüft werden, ob die Formel α = a in diesen gilt. Bei der zweiten Implementierung wird nach einem ” falschen“ Zustand, in dem die Teilformel α nicht gilt, zu seinem rechten Geschwister übergegangen. Das wird solange durchgeführt, bis es noch solche vorhanden sind und noch kein Pfad gefunden wurde. Dies wird mittels des iterativen Tiefendurchlaufs (siehe [AUH82]) realisiert, bei dem zu jedem Knoten seine rechten Geschwister in einem Stack gespeichert werden. Im Gegensatz zu der ersten Implementierung wird somit die Überprüfung in allen vorherigen Zuständen gespart. Eine weitere Möglichkeit an der Laufzeit zu gewinnen, ist die Speicherung von Ergebnissen des <strong>Model</strong>-<strong>Checking</strong>s in den geprüften Zuständen. Das bedeutet, dass nachdem die Zustände ” a“, ” a,b“ und ” b“ geprüft wurden, wird <strong>für</strong> die Formel α = a gespeichert, dass sie in den Zuständen ” a“ und ” a,b“ erfüllt wird. Wenn der zweite Pfad im Baum analysiert wird, muss der <strong>Model</strong>- <strong>Checking</strong>-Algorithmus im nächsten potenziellen Zustand nicht mehr ausgeführt werden. Die schon ermittelten Ergebnisse müssen nur gelesen werden. Dieser Ansatz beansprucht einen zusätzlichen Speicher, vermindert aber die Laufzeit. Weiterhin setzt der Algorithmus einen Stack ein. Um den Nichtdeterminismus zu lösen, müssen alle möglichen Zustände bzw. Pfade sowie entsprechende Formeln im Stack gespeichert werden. Zusätzlich muss der Typ der Formeln bei der Speicherung ihrer Teilformeln mit angegeben werden, was jedoch <strong>für</strong> die Formeln ohne temporale Operatoren 27
a a a,b a,b a a b a,b Kripke-Struktur a b a a,b a b a a,b ArrayList) hat als Argument eine Menge von Zuständen, die mit der Teilformel markiert wurden und selektiert diejenigen Zustände der Kripke-Struktur, die nicht in der Menge sind. 28 a a