it-swarm.com.de

Was ist eine Schleifeninvariante?

Ich lese "Introduction to Algorithm" von CLRS. In Kapitel 2 erwähnen die Autoren "Schleifeninvarianten". Was ist eine Schleifeninvariante?

240
Attilah

In einfachen Worten ist eine Schleifeninvariante ein Prädikat (Bedingung), das für jede Iteration der Schleife gilt. Betrachten wir zum Beispiel eine einfache for-Schleife, die wie folgt aussieht:

int j = 9;
for(int i=0; i<10; i++)  
  j--;

In diesem Beispiel stimmt (für jede Iteration) i + j == 9. Eine schwächere Invariante, die auch wahr ist, ist der i >= 0 && i <= 10.

308
Tomas Petricek

Ich mag diese sehr einfache Definition: ( source )

Eine Schleifeninvariante ist eine Bedingung [unter den Programmvariablen], die notwendigerweise unmittelbar vor und unmittelbar nach jeder Iteration einer Schleife wahr ist. (Beachten Sie, dass dies in einer Iteration nichts über seine Wahrheit oder Falschheit aussagt.)

Eine Schleifeninvariante allein macht nicht viel aus. Bei entsprechender Invariante kann sie jedoch dazu verwendet werden, die Korrektheit eines Algorithmus nachzuweisen. Das einfache Beispiel in CLRS hat wahrscheinlich mit dem Sortieren zu tun. Angenommen, Ihre Schleifeninvariante ist etwa so, dass die ersten i-Einträge dieses Arrays zu Beginn der Schleife sortiert werden. Wenn Sie nachweisen können, dass es sich tatsächlich um eine Schleifeninvariante handelt (dh, dass sie vor und nach jeder Schleifeniteration gilt), können Sie die Korrektheit eines Sortieralgorithmus beweisen: Beim Beenden der Schleife ist die Schleifeninvariante noch erfüllt und der Zähler i ist die Länge des Arrays. Daher werden die ersten i-Einträge sortiert, dh das gesamte Array wird sortiert.

Ein noch einfacheres Beispiel: Loops Invarianten, Korrektheit und Programmableitung .

Die Art, wie ich eine Schleifeninvariante verstehe, ist ein systematisches, formales Werkzeug, um über Programme nachzudenken. Wir geben eine einzige Aussage ab, bei der wir uns darauf konzentrieren, wahr zu sein, und wir nennen es die Schleifeninvariante. Dies organisiert unsere Logik. Während wir genauso gut informell über die Korrektheit eines Algorithmus streiten können, zwingt uns die Verwendung einer Schleifeninvariante zum sorgfältigen Nachdenken und stellt sicher, dass unsere Argumentation luftdicht ist.

105
TNi

Es gibt eine Sache, die viele Leute beim Umgang mit Schleifen und Invarianten nicht sofort merken. Sie werden zwischen der Schleifeninvarianten und der Schleifenbedingung (der Bedingung, die die Beendigung der Schleife steuert) verwechselt.

Wie die Leute betonen, muss die Schleifeninvariante wahr sein

  1. bevor die Schleife beginnt
  2. vor jeder Iteration der Schleife
  3. nachdem die Schleife endet

(obwohl es vorübergehend während des Körpers der Schleife falsch sein kann). Andererseits ist die Schleifenbedingung muss falsch, nachdem die Schleife beendet wurde, sonst würde die Schleife niemals beendet werden.

Somit sind die Schleifeninvariante und die Schleifenbedingung muss sein unterschiedliche Bedingungen.

Ein gutes Beispiel für eine komplexe Schleifeninvariante ist die binäre Suche.

bsearch(type A[], type a) {
start = 1, end = length(A)

    while ( start <= end ) {
        mid = floor(start + end / 2)

        if ( A[mid] == a ) return mid
        if ( A[mid] > a ) end = mid - 1
        if ( A[mid] < a ) start = mid + 1

    }
    return -1

}

Die Schleifenbedingung scheint also ziemlich direkt zu sein - wenn Start> Ende die Schleife beendet. Aber warum ist die Schleife korrekt? Was ist die Schleifeninvariante, die ihre Richtigkeit beweist?

Die Invariante ist die logische Aussage:

if ( A[mid] == a ) then ( start <= mid <= end )

Diese Aussage ist eine logische Tautologie - es ist immer wahr im Kontext der spezifischen Schleife/des Algorithmus, den wir zu beweisen versuchen . Und es liefert nützliche Informationen über die Richtigkeit der Schleife nach dem Beenden.

Wenn wir zurückkehren, weil wir das Element im Array gefunden haben, ist die Aussage eindeutig wahr, da wenn A[mid] == a dann a im Array ist und mid zwischen Anfang und Ende liegen muss. Und wenn die Schleife endet, weil start > end, dann kann es keine Nummer geben, die start <= midndmid <= end und daher wissen wir, dass die Anweisung A[mid] == a muss falsch sein. Dies hat jedoch zur Folge, dass die logische Gesamtaussage im Nullsinn immer noch wahr ist. (In der Logik ist die Aussage if (false) then (something) immer wahr.)

Was ist nun mit dem, was ich über die Schleifenbedingung gesagt habe, die unbedingt falsch ist, wenn die Schleife endet? Es sieht so aus, als ob, wenn das Element im Array gefunden wird, die Schleifenbedingung wahr ist, wenn die Schleife endet !? Das ist eigentlich nicht der Fall, da die implizierte Schleifenbedingung wirklich while ( A[mid] != a && start <= end ) ist, aber wir kürzen den eigentlichen Test, da der erste Teil impliziert ist. Diese Bedingung ist nach der Schleife eindeutig falsch, unabhängig davon, wie die Schleife endet.

36

Frühere Antworten haben eine Schleifeninvariante auf sehr gute Weise definiert.

Lassen Sie mich nun versuchen zu erklären, wie CLRS-Autoren Loop Invarianten verwendet haben, um Richtigkeit von Insertion Sort zu beweisen.

Einfügungssortierungsalgorithmus (wie in Buch angegeben):

INSERTION-SORT(A)
    for j ← 2 to length[A]
        do key ← A[j]
        // Insert A[j] into the sorted sequence A[1..j-1].
        i ← j - 1
        while i > 0 and A[i] > key
            do A[i + 1] ← A[i]
            i ← i - 1
        A[i + 1] ← key

Schleifeninvariante in diesem Fall (Quelle: CLRS-Buch): Subarray [1 bis j-1] ist immer sortiert.

Lassen Sie uns dies überprüfen und beweisen, dass der Algorithmus korrekt ist.

Initialisierung : Vor der ersten Iteration ist j = 2. Subarray [1: 1] ist also das zu testende Array. Da es nur ein Element enthält, wird es sortiert. Invariant ist also erfüllt.

Maintanence : Dies kann leicht überprüft werden, indem die Invariante nach jeder Iteration überprüft wird. In diesem Fall ist sie zufriedenstellend.

Terminierung : Dies ist der Schritt, bei dem wir die Richtigkeit des Algorithmus beweisen.

Wenn die Schleife endet, ist der Wert j = n + 1. Wieder ist Loop Invariant erfüllt. Dies bedeutet, dass Subarray [1 bis n] sortiert werden sollte.

Dies ist, was wir mit unserem Algorithmus machen wollen. Deshalb ist unser Algorithmus korrekt.

30
Tushar Kathuria

Neben all den guten Antworten, denke ich, ist ein gutes Beispiel ausHow to Think About Algorithms von Jeff Edmondsdas Konzept sehr gut zu veranschaulichen:

BEISPIEL 1.2.1 Der Find-Max-Zwei-Finger-Algorithmus

1) Spezifikationen: Eine Eingabeinstanz besteht aus einer Liste L(1..n) von Elemente. Die Ausgabe besteht aus einem Index i, so dass L(i) das Maximum .__ hat. Wert. Wenn mehrere Einträge mit demselben Wert vorhanden sind, wird eine beliebige einer von ihnen wird zurückgegeben.

2) Grundlegende Schritte: Sie entscheiden sich für die Zwei-Finger-Methode. Dein rechter Finger läuft die Liste herunter.

3) Maß des Fortschritts: Das Maß des Fortschritts ist, wie weit entlang der liste deinen rechten finger auf.

4) Die Schleifeninvariante: Die Schleifeninvariante gibt an, dass der linke Finger auf einen der größten Einträge zeigt, die bisher von Ihrem .__ gefunden wurden. rechter Finger.

5) Hauptschritte: Bei jeder Wiederholung bewegen Sie Ihren rechten Finger um einen Eintrag in der Liste. Wenn Ihr rechter Finger jetzt auf einen Eintrag zeigt, __. das ist größer als der Eintrag des linken Fingers, dann bewegen Sie Ihren linken Finger mit dem rechten Finger sein.

6) Fortschritt machen: Sie machen Fortschritte, weil sich Ihr rechter Finger bewegt ein Eintrag.

7) Schleifeninvariante beibehalten: Sie wissen, dass die Schleifeninvariante wie folgt gepflegt wurde. Für jeden Schritt das neue linke Fingerelement ist Max (altes linkes Fingerelement, neues Element). Bei der Schleifeninvariante Dies ist Max (Max (kürzere Liste), neues Element). Mathe- matisch ist das Max (längere Liste).

8) Festlegen der Schleifeninvariante: Sie legen die Schleifeninvariante zunächst fest, indem Sie beide Finger auf das erste Element zeigen.

9) Beendigungsbedingung: Sie sind fertig, wenn Ihr rechter Finger fertig ist durch die Liste gehen.

10) Ende: Am Ende wissen wir, dass das Problem wie folgt gelöst wird. Durch In der Ausgangsbedingung hat Ihr rechter Finger alle Einträge. Bei der Schleifeninvariante zeigt Ihr linker Finger auf das Maximum von diesen. Gib diesen Eintrag zurück.

11) Beendigung und Laufzeit: Die erforderliche Zeit ist eine gewisse Konstante mal die Länge der Liste.

12) Sonderfälle: Prüfen Sie, was passiert, wenn mehrere Einträge vorhanden sind mit dem gleichen Wert oder wenn n = 0 oder n = 1 ist.

13) Angaben zur Codierung und Implementierung: ...

14) Formaler Beweis: Die Richtigkeit des Algorithmus ergibt sich aus der über den Schritten.

16
Vahid Rafiei

Es sollte beachtet werden, dass eine Schleifeninvariante beim Entwurf iterativer Algorithmen hilfreich sein kann, wenn eine Assertion betrachtet wird, die wichtige Beziehungen zwischen den Variablen ausdrückt, die zu Beginn jeder Iteration wahr sein müssen und wenn die Schleife endet. Wenn dies zutrifft, ist die Berechnung auf dem Weg zur Effektivität. Bei false ist der Algorithmus fehlgeschlagen.

6
Eric Steen

Invariante bedeutet in diesem Fall eine Bedingung, die an einem bestimmten Punkt in jeder Schleifeniteration wahr sein muss.

Bei der Vertragsprogrammierung ist eine Invariante eine Bedingung, die vor und nach dem Aufruf einer öffentlichen Methode (vertraglich) erfüllt sein muss.

5
Mark Rushakoff

Die Bedeutung von Invariante ändert sich nie

Hier bedeutet die Schleifeninvariante "Die Änderung, die mit der Variablen in der Schleife (Inkrementieren oder Dekrementieren) geschieht, ändert die Schleifenbedingung nicht, d. H. Die Bedingung ist zufriedenstellend", so dass das Konzept der Schleifeninvariante gekommen ist 

4
sasidhar

Sorry, ich habe keine Erlaubnis für Kommentare.

@Tomas Petricek wie Sie erwähnt haben

Eine schwächere Invariante, die auch wahr ist, ist, dass i> = 0 && i <10 ist (weil dies die Fortführungsbedingung ist!) " 

Wie ist es eine Schleifeninvariante?

Ich hoffe, dass ich mich nicht irre, soweit ich es verstehe[1], Die Schleifeninvariante ist zu Beginn der Schleife wahr (Initialisierung), vor und nach jeder Iteration (Wartung) ist wahr und ist auch nach dem Beenden der Schleife wahr (Beendigung). Aber nach der letzten Iteration wird i 10. Dann wird die Bedingung i> = 0 && i <10 falsch und beendet die Schleife. Es verstößt gegen die dritte Eigenschaft (Termination) der Schleifeninvariante.

[1] http://www.win.tue.nl/~kbuchin/teaching/JBP030/notebooks/loop-invariants.html

1
Mahmudul Haque

Es ist schwer zu verfolgen, was mit Loops passiert. Schleifen, die nicht enden oder enden, ohne ihr Zielverhalten zu erreichen, sind ein häufiges Problem bei der Computerprogrammierung. Schleifeninvarianten helfen. Eine Schleifeninvariante ist eine formale Aussage über die Beziehung zwischen Variablen in Ihrem Programm, die direkt vor dem Ausführen der Schleife (Festlegen der Invariante) wahr ist und am unteren Ende der Schleife immer wieder wahr ist, jedes Mal durch die Schleife (wobei die Invariante beibehalten wird) Hier ist das allgemeine Muster der Verwendung von Schleifeninvarianten in Ihrem Code:

... // Die Schleifeninvariante muss hier wahr sein
während (TESTZUSTAND) {
// oben in der Schleife
...
// unten in der Schleife
// Die Schleifeninvariante muss hier wahr sein
}
// Terminierung + Schleifeninvariante = Ziel
...
Zwischen dem oberen und unteren Ende der Schleife wird vermutlich ein Schritt in Richtung des Ziels der Schleife gemacht. Dies kann die Invariante stören (falsch machen). Der Punkt der Schleifeninvarianten ist das Versprechen, dass die Invariante wiederhergestellt wird, bevor der Schleifenrumpf jedes Mal wiederholt wird .. __ Es gibt zwei Vorteile:

Die Arbeit wird nicht auf komplizierte, datenabhängige Weise in den nächsten Durchgang übernommen. Jeder Durchlauf durch die Schleife erfolgt unabhängig von allen anderen, wobei die Invariante dazu dient, die Durchgänge zu einem funktionierenden Ganzen zusammenzufügen. Die Begründung, dass Ihre Schleife funktioniert, reduziert sich auf die Annahme, dass die Schleifeninvariante bei jedem Durchlauf durch die Schleife wiederhergestellt wird. Dadurch wird das komplizierte Gesamtverhalten der Schleife in kleine, einfache Schritte unterteilt, die jeweils separat betrachtet werden können .. Die Testbedingung der Schleife ist nicht Teil der Invariante. Es ist das, was die Schleife beendet. Sie betrachten getrennt zwei Dinge: warum die Schleife jemals enden sollte und warum die Schleife ihr Ziel erreicht, wenn sie endet. Die Schleife wird beendet, wenn Sie sich jedes Mal durch die Schleife bewegen, um die Beendigungsbedingung zu erfüllen. Es ist oft leicht, dies sicherzustellen: z. eine Zählervariable um eins schrittweise bis zum Erreichen einer festen oberen Grenze. Manchmal ist die Begründung für die Kündigung schwieriger.

Die Schleifeninvariante sollte so erstellt werden, dass das Ziel erreicht wird, wenn die Bedingung der Beendigung erreicht ist und die Invariante wahr ist.

invariante + Kündigung => Ziel
Es erfordert Übung, Invarianten zu erstellen, die einfach sind und in Beziehung stehen und alle Ziele des Ziels außer der Kündigung erfassen. Es ist am besten, mathematische Symbole zum Ausdrücken von Schleifeninvarianten zu verwenden. Wenn dies jedoch zu komplizierten Situationen führt, setzen wir auf klare Prosa und gesunden Menschenverstand.

1
Tilak raj

Die Schleifeninvarianteigenschaft ist eine Bedingung, die für jeden Schritt einer Schleifenausführung gilt (z. B. für Schleifen, while-Schleifen usw.).

Dies ist wichtig für einen schleifeninvarianten Beweis, bei dem gezeigt werden kann, dass ein Algorithmus korrekt ausgeführt wird, wenn diese schleifeninvariante Eigenschaft bei jedem Schritt der Ausführung gilt.

Damit ein Algorithmus korrekt ist, muss die Schleifeninvariante Folgendes beachten:

Initialisierung (der Anfang)

Wartung (jeder Schritt danach)

Kündigung (wenn es fertig ist)

Dies wird verwendet, um eine Reihe von Dingen auszuwerten, aber das beste Beispiel sind gierige Algorithmen für das Durchlaufen von gewichteten Graphen. Damit ein gieriger Algorithmus eine optimale Lösung (einen Pfad über den Graphen) liefert, muss er alle Knoten mit dem niedrigst möglichen Gewichtungspfad verbinden.

Daher ist die schleifeninvariante Eigenschaft, dass der genommene Pfad die geringste Gewichtung hat. Am Beginn haben wir keine Kanten hinzugefügt, daher ist diese Eigenschaft wahr (in diesem Fall ist sie nicht falsch). Bei jedem Schritt folgen wir der Kante mit dem niedrigsten Gewicht (dem gierigen Schritt), also nehmen wir wieder den Pfad mit dem niedrigsten Gewicht. Am Ende haben wir den niedrigsten gewichteten Pfad gefunden, daher ist auch unsere Eigenschaft wahr.

Wenn ein Algorithmus dies nicht tut, können wir beweisen, dass er nicht optimal ist.

1
Alex Mapley

Die Schleifeninvariante ist eine mathematische Formel wie (x=y+1). In diesem Beispiel repräsentieren x und y zwei Variablen in einer Schleife. Angesichts des sich ändernden Verhaltens dieser Variablen während der Ausführung des Codes ist es fast unmöglich, alle möglichen Werte der Variablen x und y zu testen und festzustellen, ob sie einen Fehler erzeugen. Nehmen wir an, dass x eine ganze Zahl ist. Integer kann 32 Bit Speicherplatz enthalten. Wenn diese Anzahl überschritten wird, tritt ein Pufferüberlauf auf. Wir müssen also sicherstellen, dass der Speicherplatz während der gesamten Ausführung des Codes niemals überschritten wird. Dafür müssen wir eine allgemeine Formel verstehen, die die Beziehung zwischen Variablen zeigt. Wir versuchen nur, das Verhalten des Programms zu verstehen.

0
Mehmet YILMAZ

In einfachen Worten ist dies eine LOOP-Bedingung, die in jeder Schleifeniteration wahr ist:

for(int i=0; i<10; i++)
{ }

In diesem können wir sagen, der Zustand von i ist i<10 and i>=0

0
i.maddy

Eine Schleifeninvariante ist eine Assertion, die vor und nach der Ausführung der Schleife wahr ist.

0
timkofu