Semantyka i weryfikacja programów/Ćwiczenia 14: Różnice pomiędzy wersjami
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 1: | Linia 1: | ||
== Zawartość == | == Zawartość == | ||
Linia 60: | Linia 59: | ||
Oprócz samego niezmiennika, musimy też | Oprócz samego niezmiennika, musimy też odgadnąć asercję, którą wpiszemy w miejsce znaku zapytania. | ||
Warunek, którego potrzebujemy to <math>N \land i \leq k < j</math>. | Warunek, którego potrzebujemy to <math>N \land i \leq k < j</math>. | ||
Linia 107: | Linia 106: | ||
</math> | </math> | ||
Wciąż jest on jednak za słaby! Nie potrafimy skorzystać z wiedzy o tym, że A[1 .. n] jest posortowana, bo nie wiemy, czy <math>i,j</math> należą do zakresu tablicy! Oto prawidłowy niezmiennik: | |||
<math> | <math> | ||
Linia 165: | Linia 164: | ||
Zmieniliśmy warunek instrukcji warunkowej na | Zmieniliśmy warunek instrukcji warunkowej na "i zna j". | ||
Dzięki temu nie musimy wpisywać do asercji założenia <math>\forall i, j. A[i, j] \in \{ 0, 1 \}</math>. | Dzięki temu nie musimy wpisywać do asercji założenia <math>\forall i, j. A[i, j] \in \{ 0, 1 \}</math>. | ||
Linia 213: | Linia 212: | ||
</math> | </math> | ||
Niemiennik <math>N</math> zawiera w sobie zdanie warunkowe: | Niemiennik <math>N</math> zawiera w sobie zdanie warunkowe: "jeśli wśród 1 .. n istnieje znakomitość to ..". | ||
Zatem w dowodzie tej implikacji najpierw zakładamy przesłankę całej implikacji, a następnie | Zatem w dowodzie tej implikacji najpierw zakładamy przesłankę całej implikacji, a następnie | ||
zakładamy, że wśród 1 .. n istnieje znakomitość. | zakładamy, że wśród 1 .. n istnieje znakomitość. | ||
Linia 280: | Linia 279: | ||
* wierzchołki x, y należą do tej samej klasy abstrakcji podziału P wtw. gdy x i y są połączone ścieżką w <math>T</math> | * wierzchołki x, y należą do tej samej klasy abstrakcji podziału P wtw. gdy x i y są połączone ścieżką w <math>T</math> | ||
* elementy kolejki <math>Q</math> należą do <math>E \setminus T</math> | * elementy kolejki <math>Q</math> należą do <math>E \setminus T</math> | ||
* jeśli krawędź <math>e</math> nie należy do <math>Q</math>, to obydwa końce krawędzi e należą do tej samej klasy podziału <math>P</math>. | * jeśli krawędź <math>e</math> nie należy do <math>Q</math>, to obydwa końce krawędzi <math>e>/math> należą do tej samej klasy podziału <math>P</math>. | ||
Ostatni warunek można też sformułować tak: jeśli krawędź <math>e</math> nie należy do <math>Q</math> i nie należy do drzewa <math>T</math>, to <math>T \cup \{e\}</math> ma cykl. | Ostatni warunek można też sformułować tak: jeśli krawędź <math>e</math> nie należy do <math>Q</math> i nie należy do drzewa <math>T</math>, to <math>T \cup \{e\}</math> ma cykl. | ||
Linia 328: | Linia 327: | ||
Przykładowo, pierwsza implikacja wymaga wykazania, że <math>T \cup \{ e \}</math> jest podzbiorem minimalnego drzewa rozpinającego, | Przykładowo, pierwsza implikacja wymaga wykazania, że <math>T \cup \{ e \}</math> jest podzbiorem minimalnego drzewa rozpinającego, | ||
wiedząc, że T jest takim podzbiorem, że e nie tworzy cyklu z krawędziami z T, oraz że e jest najmniejszą krawędzią | wiedząc, że T jest takim podzbiorem, że <math>e</math> nie tworzy cyklu z krawędziami z <math>T</math>, oraz że <math>e</math> jest najmniejszą krawędzią | ||
o tej własności. | o tej własności. | ||
Prawdziwość tego zdania wynika stąd, że poddzbiory drzew rozpinających | Prawdziwość tego zdania wynika stąd, że poddzbiory drzew rozpinających stanowią strukturę zwaną ''matroidem''. | ||
Pomijamy dalsze szczegóły. | Pomijamy dalsze szczegóły. | ||
Linia 400: | Linia 399: | ||
{{cwiczenie|4|cw4.dom| | {{cwiczenie|4|cw4.dom| | ||
Przeprowadź jeszcze jeden dowód poprawności częściowej programu | Przeprowadź jeszcze jeden dowód poprawności częściowej programu znajdującego znakomitość względem | ||
innych asercji: | innych asercji: | ||
}} | }} |
Wersja z 15:14, 29 wrz 2006
Zawartość
Kontynuujemy ćwiczenie dowodzenia poprawności częściowej prostych programów. Rozważymy programy operujące na tablicach i na innych strukturach danych.
Tablice
Ćwiczenie 1 (wyszukiwanie binarne)
Przeprowadź dowód poprawności częściowej poniższego programu:
i := 1; j := n; while i < j do k := (i + j) div 2; if A[k] < v then i := k + 1 else j := k
Rozwiązanie
Ćwiczenie 2
Dana jest tablica dwuwymiarowa A[1 .. n, 1 .. n] zawierająca tylko liczby 0 i 1, reprezentująca relację znajomości pomiędzy n osobami. Umówmy się, że
- i zna j A[i, j] = 1
- i nie zna j A[i, j] = 0.
Powiemy, że i jest znakomitością jeśli zachodzi warunek:
Napisz program znajdujący znakomitość, o ile istnieje. (Czy mogą być dwie różne znakomitości?) Przeprowadź dowód poprawności częściowej tego programu.
Rozwiązanie (część pierwsza: program)
Rozwiązanie (część druga: dowód poprawności)
Inne struktury danych
Ćwiczenie 3 (algorytm zachłanny)
Niech będzie spójnym grafem nieskierowanym. Krawędziom grafu przypisane są różnowartościowo wagi liczbowe (czyli nie ma dwóch różnych krawędzi o tej samej wadze). Załóżmy, że mamy do dyspozycji następujące struktury danych:
- zbiór T krawędzi grafu, z operacjami:
- inicjuj T jako zbiór pusty
- dodaj nowy element do T
- kolejka priorytetowa Q przechowująca krawędzie grafu, z operacjami:
- inicjuj kolejkę za pomocą zbioru wszystkich krawędzi grafu
- add(Q, e): dodaj krawędż e do Q
- deletemin(Q): usuń z Q namniejszy element (krawędź)
- min(Q): zwróć w wyniku najmniejszy element (krawędź) w Q
- podział P zbioru wierzchołków grafu, z operacjami:
- inicjuj P jako zbiór jednoelementowych klas abstrakcji, po jednej dla każdego wierzchołka grafu
- find(P, x): zwróć klasę abstrakcji wierzchołka x
- union(P, X, Y): połącz klasy abstrakcji i w jedną klasę
- -- zwróć liczbę klas abstrakcji podziału P.
Graf reprezentowany jest przez dwie operacje pocz(e), kon(e) zwracające wierzchołki będące odpowiednio początkiem i końcem krawędzi e.
Przeprowadź dowód poprawności częściowej programu obliczającego minimalne drzewo rozpinające:
// inicjuj P i Q j.w. T := ; while |P| > 1 do e := min(Q); Q := deletemin(Q); x = pocz(e); y := kon(e); X := find(P, x); Y := find(P, y); if X <> Y then T := T {e}; P := union(P, X, Y)
Rozwiązanie (szkic)
Zadania domowe
Ćwiczenie 1
Przeprowadź jeszcze jeden dowód poprawności częściowej wyszukiwania binarnego.
i := 1; j := n; while i < j do k := (i + j) div 2; if A[k] < v then i := k + 1 else j := k
Program pozostał ten sam, ale zmienione zostały asercje.
Ćwiczenie 2
Sformalizuj asercję końcową w poniższym programie i przeprowadź dowód poprawności częściowej:
i := 1; p := 0; while i <= n do if A[i] = A[i - p] then p := p + 1; i := i + 1
Ćwiczenie 3
Dana jest tablica A przechowująca wyniki wyborów: A[i] = j oznacza, że i głosował na j. Ordynacja wyborcza jest większościowa: zwycięzcą jest osoba, na którą głosowała przynajmniej połowa uprawnionych. Sformalizuj asercję końcową i przeprowadź dowód poprawności częściowej programu znajdującego zwycięzcę:
k := A[1]; p := 1; i := 2; while i <= n do if A[i] = k then p := p + 1; else if p > 1 then p := p - 1 else k := A[i]; p := 1; i := i + 1
Ćwiczenie 4
Przeprowadź jeszcze jeden dowód poprawności częściowej programu znajdującego znakomitość względem innych asercji:
i := 1; j := n; while i <> j do if i zna j then i := i + 1 else j := j - 1