Semantyka i weryfikacja programów/Ćwiczenia 14: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Sl (dyskusja | edycje)
Nie podano opisu zmian
m Zastępowanie tekstu – „.↵</math>” na „</math>”
 
(Nie pokazano 4 wersji utworzonych przez 2 użytkowników)
Linia 1: Linia 1:


== Zawartość ==
== Zawartość ==
Linia 26: Linia 25:




{{rozwiazanie||roz1|


<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie</span>
<div class="mw-collapsible-content" style="display:none">


Jako niezmiennik pętli spróbujmy formułę <math>N \, \equiv \, i \leq j \land \exists x. i \leq x \leq j \land A[x] = v</math>.
Jako niezmiennik pętli spróbujmy formułę <math>N \, \equiv \, i \leq j \land \exists x. i \leq x \leq j \land A[x] = v</math>.
Linia 60: Linia 60:




Oprócz samego niezmiennika, musimy też ,,odgadnąć" asercję, którą wpiszemy w miejsce znaku zapytania.
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 104: Linia 104:


<math>
<math>
N \, \equiv \, i \leq j \land (\forall x. 1 \leq x < n \implies A[x] \leq A[x+1]) \land (\exists x. i \leq x \leq j \land A[x] = v).
N \, \equiv \, i \leq j \land (\forall x. 1 \leq x < n \implies A[x] \leq A[x+1]) \land (\exists x. i \leq x \leq j \land A[x] = v)</math>
</math>


Wciąz jest on jednak za słaby! Nie potrafimy skorzystać z wiedzy o tym, że A[1 .. n] jest posortowana, bo nie wiemy, czy i,j nalezą do zakresu tablicy! Oto prawidłowy niezmiennik:
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>
N \, \equiv \, 1 \leq i \leq j \leq n \land (\forall x. 1 \leq x < n \implies A[x] \leq A[x+1]) \land (\exists x. i \leq x \leq j \land A[x] = v).
N \, \equiv \, 1 \leq i \leq j \leq n \land (\forall x. 1 \leq x < n \implies A[x] \leq A[x+1]) \land (\exists x. i \leq x \leq j \land A[x] = v)</math>
</math>


</div></div>
</div></div>
}}




Linia 136: Linia 133:




 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
{{rozwiazanie|(część pierwsza: program)|roz2.1|
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie (część pierwsza: program)</span>
 
<div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">


Oto program znajdujący znakomitość w czasie liniowym względem n:
Oto program znajdujący znakomitość w czasie liniowym względem n:
Linia 165: Linia 161:




Zmieniliśmy warunek instrukcji warunkowej na ,,i zna j".  
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>.


</div></div>
</div></div>
}}


{{rozwiazanie|(część druga: dowód poprawności)|roz2.2|


<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<span class="mw-collapsible-toogle mw-collapsible-toogle-default style="font-variant:small-caps">Rozwiązanie (część druga: dowód poprawności)</span>
<div class="mw-collapsible-content" style="display:none">


Niezmiennik:
Niezmiennik:
<math>N \, \equiv \, i \leq j \land (\exists k. 1 \leq k \leq n \land k \mbox{ jest znakomitością}) \implies (\exists k. i \leq k \leq j \land k \mbox{ jest znakomitością}).</math>
<math>N \, \equiv \, i \leq j \land (\exists k. 1 \leq k \leq n \land k \mbox{ jest znakomitością}) \implies (\exists k. i \leq k \leq j \land k \mbox{ jest znakomitością})</math>.




Linia 210: Linia 205:


<math>
<math>
N \land i \neq j \land i \mbox{ zna } j \, \implies \,  N[i \mapsto i{+}1].
N \land i \neq j \land i \mbox{ zna } j \, \implies \,  N[i \mapsto i{+}1]</math>
</math>


Niemiennik <math>N</math> zawiera w sobie zdanie warunkowe: ,,jeśli wśród 1 .. n istnieje znakomitość to ..".
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 219: Linia 213:


</div></div>
</div></div>
}}


== Inne struktury danych ==
== Inne struktury danych ==
Linia 280: Linia 272:
* 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 320:


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 stranowią strukturę zwaną ''matroidem''.
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 392:


{{cwiczenie|4|cw4.dom|
{{cwiczenie|4|cw4.dom|
Przeprowadź jeszcze jeden dowód poprawności częściowej programu znajującego znakomitość, względem
Przeprowadź jeszcze jeden dowód poprawności częściowej programu znajdującego znakomitość względem
innych asercji:
innych asercji:
}}
}}

Aktualna wersja na dzień 21:35, 11 wrz 2023

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:


{n1(x.1x<nA[x]A[x+1])(x.1xnA[x]=v)}
i := 1; j := n;
while i < j do
  k := (i + j) div 2;
  if A[k] < v then
    i := k + 1
  else
    j := k
{A[i]=v}


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:

j.(1jnji)(j zna ii nie zna j)

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 G=(V,E) 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 X i Y w jedną klasę XY
    • |P| -- 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:


{G=(V,E) jest spójny}

// 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)

{T jest minimalnym drzewem rozpinającym graf G}


Rozwiązanie (szkic)

P


Zadania domowe

Ćwiczenie 1

Przeprowadź jeszcze jeden dowód poprawności częściowej wyszukiwania binarnego.


{n1x.1x<nA[x]A[x+1]}
i := 1; j := n;
while i < j do
  k := (i + j) div 2;
  if A[k] < v then
    i := k + 1
  else
    j := k
{(x.1xnA[x]=v)A[i]=v}


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:


{n1x.1x<nA[x]A[x+1]}
i := 1; p := 0;
while i <= n do
  if A[i] = A[i - p] then
    p := p + 1;
  i := i + 1
{ maksymalna długość stałego odcinka w tablicy A wynosi p}


Ć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ę:


{n0odd(n)}
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
{ jeśli jest zwycięzca to jest nim k}


Ćwiczenie 4

Przeprowadź jeszcze jeden dowód poprawności częściowej programu znajdującego znakomitość względem innych asercji:


{k.1knk jest znakomitością}
i := 1; j := n;
while i <> j do
  if i zna j then
    i := i + 1
  else
    j := j - 1
{i jest znakomitością}