Grundlagen der Informatik I “Programmierung”

Grundlagen der Informatik I “Programmierung” Grundlagen der Informatik I “Programmierung”

22.08.2013 Aufrufe

Die Grundüberlegung, die zu einem sehr vielseitigen Verifikationskalkül geführt hat, ist die folgende. Gegeben sei eine Folge von Anweisungen inst1;...;instn samt Vorbedingung pre und Nachbedingung post. Um zu beweisen, daß { pre} inst1;...;instn { post} wahr ist, überlegt man sich, was die – im logischen Sinne – schwächste Vorbedingung pren ist, so daß gilt { pren} instn { post} pren ist dann die Nachbedingung für den Algorithmus ohne den letzten Schritt instn und wir können das Verfahren wiederholen, bis wir eine Vorbedingung pre1 für inst1 gefunden haben, die schwächer ist als die Vorbedingung pre, d.h. für die pre ⇒ pre1 gilt. Ist dies gelungen, so ist der Algorithmus als korrekt bewiesen worden. 15 Für Konstrukte wie Schleifen wird dies natürlich etwas aufwendiger, da man hier darüber nachdenken muß, was sich während eines Schleifendurchlaufs verändert und was nicht – also invariant bleibt. In dem Kalkül von Dijkstra [Dijkstra, 1976] geht man sogar noch einen Schritt weiter. Dort wird zu jeder Instruktionsart eine Berechnungsvorschrift angegeben, wie man von einer vorgegebenen Nachbedingung post und einer Instruktion instruction zu derjenigen Vorbedingung pre kommt, welche die geringsten Forderungen stellt und dennoch { pre} instruction { post} garantiert. Diese Berechnungsvorschrift wp (für weakest precondition) ist eine Prädikatentransformation wp : Instruction×Predicate → Predicate derart, daß für alle Anweisungen instruction, alle Nachbedingungen post und alle Vorbedingungen pre gilt: { wp(instruction,post)} instruction { post} und { pre} instruction { post} ⇒ ( pre ⇒ wp(instruction,post) ) D.h. wp(inst,post) ist eine korrekte Vorbedingung und sie ist schwächer als alle anderen. Beispiel 4.2.5 (Weakest Precondition) Für die Nachbedingung x≥5 ∧ y≥0 erhalten wir bei verschiedenen Anweisungen folgende schwächste Vorbedingungen: 16 wp( x:=y+5 , x≥5 ∧ y≥0 ) ≡ y≥0 wp( y:=0 ; x:=y+5 , x≥5 ∧ y≥0 ) ≡ true wp( x:=y+5 ; y:=y-4 , x≥5 ∧ y≥0 ) ≡ y≥4 Leider sind die schwächsten Vorbedingungen für Schleifen und Prozeduren sehr unhandlich, da sie Existenzquantoren einführen und man bei Verwendung der mechanisch konstruierten Vorbedingung in einem Dschungel von Quantoren stecken bleibt. Aus diesem Grunde werden wir nicht direkt im Kalkül von Dijkstra arbeiten sondern in dem etwas schwächeren von Hoare, bei dem man die Vorbedingungen selbst finden muß. Als Vorschläge für Vorbedingungen, die wir nicht mehr beweisen müssen, werden wir dennoch die Prädikatentransformation mitbenutzen. Diese Vorschläge werden wir jedoch meist in stärkere, aber einfachere Zusicherungen überführen müssen, die weniger Quantoren enthalten. Hierzu werden wir ein gehöriges Maß an Intuition benötigen, da die Frage nach einer schematischen, aber korrekten Vereinfachung von Vorbedingungen immer noch ein Thema der Grundlagenforschung ist. Anstelle mit der schwächsten Vorbedingung rückwärts zu gehen, kann man übrigens auch versuchen, vorwärts zu gehen und die stärkste Nachbedingung sp (strongest postcondition) zu finden. Diese spielt aber für die 14 Sinnvoller ist es, ausgehend von der Nachbedingung der Spezifikation, das Programmstück zu konstruieren und im Laufe des Konstruktionsprozesses auf eine Vorbedingung zu kommen, die weniger restriktiv ist als die Vorbedingung der Spezifikation. 15 Diese Vorgehensweise läßt sich auch für die simultane Entwicklung von Programm und Beweis einsetzen, wenn man zu Beginn bereits eine ungefähre Idee im Kopf hat, wie der Algorithmus vorgehen soll. In diesem Fall konstruiert man in jedem Schritt die entsprechende Anweisung insti gleichzeitig mit prei. 16 Wir benutzen das Symbol ≡ anstelle des Gleichheitssymbols =, um Gleichheit von Prädikaten auszudrücken und Verwechs- lungen mit Gleichheiten innerhalb von Zusicherungen zu vermeiden.

Programmkonstruktion keine Rolle, da die Nachbedingung die Wirkung eines Programmstücks festlegt und damit im Programm “zurückgerechnet” wird. Die “Vorwärtsrechnung” von der Vorbedingung (zumeist true) zur Nachbedingung wirkt ziellos, da die Vorbedingung keine Information über das Ziel in sich trägt. Bei all diesen Überlegungen wurden die folgenden Regeln ohne weitere Begründung verwendet: pre ⇒ pre’, { pre’} instruction { post} { pre} instruction { post} { pre} instruction { post’} , post’ ⇒ post { pre} instruction { post} Verstärkung der Vorbedingung (VV) Abschwächung der Nachbedingung (AN) Abbildung 4.1: Verstärkungs- und Abschwächungsregeln für Programmbeweise Die Verstärkung der Vorbedingung bzw. die Abschwächung der Nachbedingung erlaubt uns, einen Programmbeweis in folgender Form zu beschreiben: Programm Zusicherungen Prämissen { pre} pre ⇒ pre’ { pre’} instruction { post’} post’ ⇒ post { post} Vor jeder und nach jeder Anweisung instruction steht eine Reihe von Zusicherungen, die sich von oben nach unten jeweils abschwächen. Am rechten Rand wird zusätzlich angegeben, warum diese Abschwächung zulässig ist. Das Lesen (und meist das Erzeugen) des Programmbeweises erfolgt dann von unten nach oben. Folgt oberhalb einer Zusicherung wieder eine Zusicherung, so beschreiben die Anmerkungen der oberen Bedingung, warum diese Verschärfung zulässig ist. Folgt eine Instruktion, so ist deren Vorbedingung über die jeweilige Regel für diesen Instruktionstyp z.B. über die schwächste Vorbedingung nachzuweisen. Zwei weitere Regeln sind sinnvoll, falls die Prädikate zu kompliziert werden: { pre} instruction { post} , { pre’} instruction { post} { pre ∨ pre’} instruction { post} Kombination der Vorbedingungen { pre} instruction { post} , { pre} instruction { post’} { pre} instruction { post ∧ post’} Kombination der Nachbedingungen Abbildung 4.2: Regeln für die Kombination von Zusicherungen in Programmbeweisen Diese beiden Regeln erlauben es, ein Programm einzeln für Teilzusicherungen zu prüfen. Die erste Regel gibt an, daß bei mehreren alternativen Vorbedingungen (pre ∨ pre’), die zweite Regel, daß bei mehreren Anforderungen (post ∧ post’) der Beweis einzeln geführt werden kann. Wir wollen nun im folgenden Abschnitt für alle Programmkonstrukte der Sprache Eiffel weitere formale Regeln angeben, die uns sagen, wie die Korrektheit einer komplexeren Anweisung aus Eigenschaften ihrer Bestandteile abgeleitet werden kann. Diese Regeln reichen aber noch nicht aus, um ein Programm zu beweisen. Hinzu kommen müssen die Regeln aus den jeweiligen Anwendungsgebieten. Soll etwas numerisch berechnet werden, so benötigen wir natürlich die Regeln der Arithmetik mit dem zusätzlichen Wissen über die Eigenschaften der Funktionen, die verwendet und berechnet werden sollen: z.B. a>b ⇒ ggt(a-b,b) = ggt(a,b). Diese Regeln werden im folgenden als bekannt vorausgesetzt, ohne deren Kalkül explizit anzugeben. Als Schlußbemerkung wollen wir noch anfügen, daß alle bisherigen Verifikationsmechanismen ausschließlich für Programme mit Copy-Semantik entwickelt wurden. Die Regeln, die wir im folgenden angeben werden, können

Die Grundüberlegung, die zu einem sehr vielseitigen Verifikationskalkül geführt hat, ist die folgende. Gegeben<br />

sei eine Folge von Anweisungen inst1;...;instn samt Vorbedingung pre und Nachbedingung post. Um zu<br />

beweisen, daß<br />

{ pre} inst1;...;instn { post}<br />

wahr ist, überlegt man sich, was die – im logischen Sinne – schwächste Vorbedingung pren ist, so daß gilt<br />

{ pren} instn { post}<br />

pren ist dann die Nachbedingung für den Algorithmus ohne den letzten Schritt instn und wir können das<br />

Verfahren wie<strong>der</strong>holen, bis wir eine Vorbedingung pre1 für inst1 gefunden haben, die schwächer ist als<br />

die Vorbedingung pre, d.h. für die pre ⇒ pre1 gilt. Ist dies gelungen, so ist <strong>der</strong> Algorithmus als korrekt<br />

bewiesen worden. 15 Für Konstrukte wie Schleifen wird dies natürlich etwas aufwendiger, da man hier darüber<br />

nachdenken muß, was sich während eines Schleifendurchlaufs verän<strong>der</strong>t und was nicht – also invariant bleibt.<br />

In dem Kalkül von Dijkstra [Dijkstra, 1976] geht man sogar noch einen Schritt weiter. Dort wird zu je<strong>der</strong><br />

Instruktionsart eine Berechnungsvorschrift angegeben, wie man von einer vorgegebenen Nachbedingung post<br />

und einer Instruktion instruction zu <strong>der</strong>jenigen Vorbedingung pre kommt, welche die geringsten For<strong>der</strong>ungen<br />

stellt und dennoch { pre} instruction { post} garantiert. Diese Berechnungsvorschrift wp (für<br />

weakest precondition) ist eine Prädikatentransformation<br />

wp : Instruction×Predicate → Predicate<br />

<strong>der</strong>art, daß für alle Anweisungen instruction, alle Nachbedingungen post und alle Vorbedingungen pre gilt:<br />

{ wp(instruction,post)} instruction { post}<br />

und { pre} instruction { post} ⇒ ( pre ⇒ wp(instruction,post) )<br />

D.h. wp(inst,post) ist eine korrekte Vorbedingung und sie ist schwächer als alle an<strong>der</strong>en.<br />

Beispiel 4.2.5 (Weakest Precondition)<br />

Für die Nachbedingung x≥5 ∧ y≥0 erhalten wir bei verschiedenen Anweisungen folgende schwächste<br />

Vorbedingungen: 16<br />

wp( x:=y+5 , x≥5 ∧ y≥0 ) ≡ y≥0<br />

wp( y:=0 ; x:=y+5 , x≥5 ∧ y≥0 ) ≡ true<br />

wp( x:=y+5 ; y:=y-4 , x≥5 ∧ y≥0 ) ≡ y≥4<br />

Lei<strong>der</strong> sind die schwächsten Vorbedingungen für Schleifen und Prozeduren sehr unhandlich, da sie Existenzquantoren<br />

einführen und man bei Verwendung <strong>der</strong> mechanisch konstruierten Vorbedingung in einem Dschungel<br />

von Quantoren stecken bleibt. Aus diesem Grunde werden wir nicht direkt im Kalkül von Dijkstra arbeiten son<strong>der</strong>n<br />

in dem etwas schwächeren von Hoare, bei dem man die Vorbedingungen selbst finden muß. Als Vorschläge<br />

für Vorbedingungen, die wir nicht mehr beweisen müssen, werden wir dennoch die Prädikatentransformation<br />

mitbenutzen. Diese Vorschläge werden wir jedoch meist in stärkere, aber einfachere Zusicherungen überführen<br />

müssen, die weniger Quantoren enthalten. Hierzu werden wir ein gehöriges Maß an Intuition benötigen, da die<br />

Frage nach einer schematischen, aber korrekten Vereinfachung von Vorbedingungen immer noch ein Thema<br />

<strong>der</strong> <strong>Grundlagen</strong>forschung ist.<br />

Anstelle mit <strong>der</strong> schwächsten Vorbedingung rückwärts zu gehen, kann man übrigens auch versuchen, vorwärts<br />

zu gehen und die stärkste Nachbedingung sp (strongest postcondition) zu finden. Diese spielt aber für die<br />

14 Sinnvoller ist es, ausgehend von <strong>der</strong> Nachbedingung <strong>der</strong> Spezifikation, das Programmstück zu konstruieren und im Laufe des<br />

Konstruktionsprozesses auf eine Vorbedingung zu kommen, die weniger restriktiv ist als die Vorbedingung <strong>der</strong> Spezifikation.<br />

15 Diese Vorgehensweise läßt sich auch für die simultane Entwicklung von Programm und Beweis einsetzen, wenn man zu<br />

Beginn bereits eine ungefähre Idee im Kopf hat, wie <strong>der</strong> Algorithmus vorgehen soll. In diesem Fall konstruiert man in jedem<br />

Schritt die entsprechende Anweisung insti gleichzeitig mit prei.<br />

16 Wir benutzen das Symbol ≡ anstelle des Gleichheitssymbols =, um Gleichheit von Prädikaten auszudrücken und Verwechs-<br />

lungen mit Gleichheiten innerhalb von Zusicherungen zu vermeiden.

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!