80 3. Grundlagen der Logik Definition 3.1: Syntax einer aussagenlogischen Formel (in EBNF) F ::= A | F ∨ F | F ∧ F | ¬F • wobei A: atomare Formel • Schreibabkürzungen: ? F1 ⇒ F2 für ¬F1 ∨ F2 ? F1 ⇔ F2 für (F1 ⇒ F2) ∧ (F2 ⇒ F1) • Beispiel: “Regen” ∧ “Kälte” ⇒ “Glätte” 2 81 Semantik der Aussagenlogik Definition 3.2: • sei AF die Menge aller (verwendeten) atomaren Formeln • sei F die Menge aller aussagenlogischen Formeln • eine Belegung ist eine Funktion β : AF → {0, 1} • β̂ : F → {0, 1} gibt zu jeder Formel F ∈ F ihre Semantik β̂(F ) an: ? β̂(A) := β(A) für alle A ∈ AF 1, falls β̂(F1) = 1 oder β̂(F2) = 1 ? β̂(F1 ∨ F2) := 0, sonst 1, falls β̂(F1) = 1 und β̂(F2) = 1 ? β̂(F1 ∧ F2) := 0, sonst 1, falls β̂(F ) = 0 ? β̂(¬F ) := 0, sonst 2 82 Erfüllbarkeit und Gültigkeit einer aussagenlogischen Formel Definition 3.3: • sei F ∈ F eine Formel • F heißt erfüllbar, wenn es eine Belegung β gibt mit β̂(F ) = 1 (in Zeichen: β |= F ) • F heißt gültig, wenn für jede Belegung β β̂(F ) = 1 2 • die Erfüllbarkeit und Gültigkeit sind z.B. durch Aufstellung der Wahrheitstabelle (mit exponentiellem Aufwand) entscheidbar 83 Wahrheitstabelle im Beispiel Regen 0 0 0 0 1 1 1 1 K älte 0 0 1 1 0 0 1 1 Glätte 0 1 0 1 0 1 0 1 R∧K ⇒G 1 1 1 1 1 1 0 1 • R ∧ K ⇒ G ist also erfüllbar, aber nicht gültig 84 Prädikatenlogik Definition 3.4: Syntax einer prädikatenlogischen Formel • sei sig = (S, Σ) eine Signatur mit Bool ∈ S und ∨, ∧, ¬ ∈ Σ • sei X eine Variablenmenge und Tsig (X) die zugehörige Termmenge • die Menge Fsig,X aller prädikatenlogischen Formeln über sig und X ist die kleinste Menge mit: ? p(t1, . . . , tn) ∈ F, falls das Prädikatssysmbol p ∈ Σ(s1...sn,Bool), si ti ∈ Tsig (X), si 6= Bool für i = 1, 2, . . . , n ? F1 ∨ F2 ∈ F, F1 ∧ F2 ∈ F, ¬F1 ∈ F ? ∃x F ∈ F, ∀x F ∈ F für F1, F2 ∈ F für F ∈ F, x ∈ X • Schreibabkürzungen wie bei der Aussagenlogik 2 85 Beispiel: Prädikatenlogische Formel ∀x1∀x2∀x3 M utter(x1, x2) ∧ V ater(x2, x3) ⇒ Oma(x1, x3) wobei: sig = ({P erson, Bool}, {true(ε,Bool), f alse(ε,Bool), M utter(P erson P erson,Bool) , V ater(P erson Oma(P erson X = X P erson = {x1, x2, x3} P erson,Bool) P erson,Bool) , , . . .}), 86 Semantik der Prädikatenlogik Definition 3.5: • seien sig = (S, Σ) eine Signatur und A = (A, Φ) eine sig-Algebra mit fA(t1, . . . , tn) = f (t1, . . . , tn) für alle f ∈ Σ(s1...sn,s) mit s 6= Bool und seien ∨A, ∧A und ¬A die üblichen booleschen Operationen oder, und, nicht • sei X eine Variablenmenge und β : X → A eine Variablenbelegung • β̂ : Fsig,X → {0, 1} gibt zu jeder Formel F ihre Semantik β̂(F ) an: ? β̂(p(t1, . . . , tn)) := 1, ? β̂(∃x F ) := 0, 1, ? β̂(∀x F ) := 0, pA(t1, . . . , tn) für alle p ∈ Σ(s1...sn,Bool) (inkl. ∨, ∧, ¬) falls es ein d ∈ As gibt mit β̂[x/d](F ) = 1, (f ür x ∈ X s) sonst wenn f ür alle d ∈ As gilt β̂[x/d](F ) = 1, (f ürx ∈ X s) sonst β(y), falls x 6= y wobei β[x/d](y) := 2 d, sonst 87 Erfüllbarkeit und Gültigkeit • Erfüllbarkeit und Gültigkeit einer prädikatenlogischen Formel werden analog zur Aussagenlogik definiert • die Erfüllbarkeit einer prädikatenlogischen Formel ist i.A. unentscheidbar • d.h. es gibt keinen stets terminierenden Algorithmus, der sicher feststellt, ob eine Formel erfüllbar ist oder nicht (→ Halteproblem) • für viele praxisrelevante Formeln wird sich die Erfüllbarkeit dennoch ermitteln lassen (→ Prolog) 88 Beispiel: Erfüllbarkeit M utter(Eva, Hans) = true M utter(Eva, Karl) = true M utter(Eva, U we) = true ... V ater(U do, Inge) = true V ater(Hans, Anna) = true ... M utter(x1, x2) ∧ V ater(x2, x3) wird erfüllt von β mit: β(x1) = Eva β(x2) = Hans β(x3) = Anna also: β |= M utter(x1, x2) ∧ V ater(x2, x3) 89 4. Die formale Spezifikationssprache Z • formale Syntax und Semantik • erzeugt Modell basierend auf Mengenlehre, Prädikatenlogik, . . . • Spezifikation besteht aus System überschaubarer Komponenten (Schemata) ? Behandlung von Sonderfällen und Fehlern getrennt von Normalfall ? Struktur von Beweisen orientiert an Struktur der Spezifikation Schema: • Name • Signatur: Deklaration und Typisierung von Bezeichnern • Beschreibung von Beziehungen durch logische Formeln 90 Beispiel: Bank-Anwendung in Z Bank kstd: Konto −→ IN Bank0 kstd0: Konto −→ IN ∆Bank = ˆ Bank ∧ Bank0 ΞBank ∆Bank kstd0 = kstd InitBank Bank ∀ i: Konto • kstd(i) = 0 91 Zustandstransformation • durch Schemata lassen sich neben dem Zustandsraum auch Zustandstransformationen, Fehlerbehandlung und Verfeinerungen beschreiben Überweisung1 ∆Bank betrag?: IN von?, nach?: Konto von? 6= nach? kstd0 = kstd ⊕ {von? 7→ kstd(von?) − betrag?, nach? 7→ kstd(nach?) + betrag?} kstd(von?)≥betrag? 92 Fehlerbehandlung Ok ausgabe!: Nachricht ausgabe! = ”OK” GleichesKonto ΞBank von?, nach?: Konto ausgabe!: Nachricht von? = nach? ausgabe! = ”gleiche Kontonr.” Unzureichend ΞBank betrag?: IN von?: Konto ausgabe!: Nachricht kstd(von?) < betrag? ausgabe! = ”Kontostand unzureichend” Überweisung = ˆ (Überweisung1 ∧ Ok) ∨ GleichesKonto ∨ Unzureichend analog: Abheben = ˆ (Abheben1 ∧ Ok) ∨ Unzureichend 93 Beweisen von Systemeigenschaften Behauptung: nach Überweisung gilt: kstd’(von?) + kstd’(nach?) = kstd(von?) + kstd(nach?) Beweis: (Fallunterscheidung) 1) Fall GleichesKonto bzw. Unzureichend: wegen ΞBank gilt: kstd0 = kstd, Behauptung folgt trivialerweise 2) Fall Überweisung1: kstd0(von?) = kstd(von?) − betrag? kstd0(nach?) = kstd(nach?) + betrag? durch Addition der Gleichungen ergibt sich die Behauptung • Struktur des Beweises orientiert an Struktur der Spezifikation 2 94 Beispiel: Verfeinerung Z → Java int anzahl = 42; int knr[] = new int[anzahl]; int kstand[] = new int[anzahl]; VBank anzahl: IN knr: IN −→ Konto kstand: IN −→ IN Abs Bank VBank kstd = { i: IN | i < anzahl • knr(i) 7→ kstand(i)} VÜberweisung1 ∆VBank betrag?: IN von?, nach?: Konto von? 6= nach? (∃ k:0..anzahl-1 • knr(k) = nach? ∧ (∃ j:0..anzahl-1 • knr(j) = von? ∧ betrag? ≤ kstand(j) ∧ kstand0 = kstand ⊕ {j 7→ kstand(j) − betrag?, k 7→ kstand(k) + betrag?} )) knr0 = knr anzahl0 = anzahl 95 Korrektheitsbeweis zu zeigen: kstd0 = {knr0(i) 7→ kstand0(i) | i:0..anzahl0-1} VBank Abs VÜberweisung1 VBank’ Bank Überweisung1 Abs Bank’ Beweis: kstd0 = kstd ⊕ {von? 7→ kstd(von?) − betrag?, nach? 7→ kstd(nach?) + betrag?} = {knr(i) 7→ kstand(i) | i:0..anzahl−1} ⊕ {von? 7→ kstd(von?) − betrag?, nach? 7→ kstd(nach?) + betrag?} = {knr(i) 7→ kstand(i) | i:0..anzahl−1, i6= j, i6=k} ⊕ {knr(j) 7→ kstand(j) − betrag?, knr(k) 7→ kstand(k) + betrag?} 2 = {knr0(i) 7→ kstand0(i) | i:0..anzahl0 − 1} 96 Implementierung class Bank{ protected int anzahl = 42; protected int knr[] = new int[anzahl]; protected int kstand[] = new int[anzahl]; public void ueberweisen(int von, int nach, int betrag){ int i; int j; if (von == nach) {System.out.println("gleiche Kontonummern"); return;} // Quantoren als Schleifen for(i=0; i<anzahl && knr[i] != von; i++); for(j=0; j<anzahl && knr[j] != nach; j++); if (kstand[i] < betrag) { System.out.println("Kontostand unzureichend"); return;} kstand[i] = kstand[i] - betrag; kstand[j] = kstand[j] + betrag; System.out.println("OK"); } }