Wstęp do programowania / Ćwiczenia 6: Różnice pomiędzy wersjami

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Aneczka (dyskusja | edycje)
 
(Nie pokazano 16 wersji utworzonych przez 5 użytkowników)
Linia 1: Linia 1:
{{powrot|Wstęp do programowania| do głównej strony wykładu}}
{{powrot|WDP_Dowodzenie_poprawności_programów|do modułu Dowodzenie poprawności programów}}
 
To są zadania na logikę Hoare'a.
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Oglądaj wskazówki i rozwiązania __SHOWALL__<br>
Ukryj wskazówki i rozwiązania __HIDEALL__
</div>


{{powrot|modul_6|do modułu 6}}


== Zadanie 1 (Flaga trójkolorowa)==
== Zadanie 1 (Flaga trójkolorowa)==
Linia 28: Linia 34:
  '''end'''.
  '''end'''.


{{rozwiazanie|||<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">
Główną trudnością jest wymyślenie odpowiedniego niezmiennika pętli while. Tu, będzie to zdanie:
<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">  
Główną trudnością jest wymyślenie odpowiedniego niezmiennika pętli while. Tu będzie to zdanie:
  &forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and;   
  &forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and;   
  &forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and;   
  &forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and;   
  &forall; k  (w < j &le; N) &rArr;  A[k] > 0 &and;   
  &forall; k  (w < k &le; N) &rArr;  A[k] > 0 &and;   
  1 &le; m &le; r &and;  r-1 &le; w &le; N &and; N > 0
  1 &le; m &le; r &and;  r-1 &le; w &le; N &and; N > 0
oznaczane przez N(m,r,w). Mówi ono, że na indeksach mniejszych od m są wartości ujemne, pomiędzy m a r równe zero a powyżej w dodatnie. Nic nie jest powiedziane o wartościach tablicy pomiędzy r a w, za to wiemy jakie są relacje pomiędzy 1, m, r, w i N.
oznaczane przez N(m,r,w). Mówi ono, że na indeksach mniejszych od m są wartości ujemne, pomiędzy m a r - równe zero, a powyżej w - dodatnie. Nic nie jest powiedziane o wartościach tablicy pomiędzy r a w, za to wiemy jakie są relacje pomiędzy 1, m, r, w i N.


Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem który otaczają są poprawnymi trójkami Hoare'a.
Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem który otaczają są poprawnymi trójkami Hoare'a.
Linia 75: Linia 83:
'''3''' Korzystamy z reguły na '''if''';  trzeba pokazać, że z N(m,r,w) &and; r &le; w po wykonaniu każdej gałęzi zachodzi N(m,r,w).
'''3''' Korzystamy z reguły na '''if''';  trzeba pokazać, że z N(m,r,w) &and; r &le; w po wykonaniu każdej gałęzi zachodzi N(m,r,w).


'''4''' Korzystając z reguły na przypisanie otrzymujemy, że N(m,r+1,w) powinno być prawdziwe przed instrukcją 4. A więc musimy dowieść implikacji   
'''4''' Korzystając z reguły na przypisanie, otrzymujemy, że N(m,r+1,w) powinno być prawdziwe przed instrukcją 4. Musimy więc dowieść implikacji   
  (N(m,r,w) &and; r &le; w &and; A[r] = 0)  &rArr; N(m,r+1,w)
  (N(m,r,w) &and; r &le; w &and; A[r] = 0)  &rArr; N(m,r+1,w)
Rozpatrując części N(m,r+1,w) widzimy, że  
Rozpatrując części N(m,r+1,w) widzimy, że  
Linia 107: Linia 115:
  &forall; k  (w < j &le; N) &rArr;  A[k] > 0 &and;   
  &forall; k  (w < j &le; N) &rArr;  A[k] > 0 &and;   
  1 &le; m+1 &le; r+1 &and; r &le; w &le; N &and; N > 0
  1 &le; m+1 &le; r+1 &and; r &le; w &le; N &and; N > 0
czyli coś co łatwo wynika z  N(m,r,w) &and; r &le; w &and; A[r] < 0.
czyli coś, co łatwo wynika z  N(m,r,w) &and; r &le; w &and; A[r] < 0.


'''8''' Jest to trywialne użycie reguły na przypisanie.
'''8''' Jest to trywialne użycie reguły na przypisanie.
Linia 117: Linia 125:
  &forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and;   
  &forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and;   
  &forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and;   
  &forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and;   
  &forall; k  (w < j &le; N) &rArr;  A[k] > 0 &and; A[r] > 0 &and;   
  &forall; k  (w < k &le; N) &rArr;  A[k] > 0 &and; A[r] > 0 &and;   
  1 &le; m &le; r &and;
  1 &le; m &le; r &and;
  r-1 &le; w-1 &le; N &and; N > 0
  r-1 &le; w-1 &le; N &and; N > 0
Linia 124: Linia 132:
'''11''' Jest to trywialne użycie reguły na przypisanie.
'''11''' Jest to trywialne użycie reguły na przypisanie.


'''12''' Z reguły na '''while''' wiemy, że zachodzi N(m,r,w) i zaprzeczenie dozoru w '''while''' czyli r > w. Z niezmiennika wiemy, że r-1 &le; w, a więc musi być r-1=w.
'''12''' Z reguły na '''while''' wiemy, że zachodzi N(m,r,w) i zaprzeczenie dozoru w '''while''' czyli r > w. Z niezmiennika wiemy, że r-1 &le; w, musi więc być r-1=w.
</div>
</div>
</div>
</div>}}


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Linia 139: Linia 147:
   
   
{{cwiczenie|||
{{cwiczenie|||
Tablica A typu array[1..N] of integer, N >0, zawiera tylko liczby dodatnie. Napisz program który dla danego W typu integer, takiego że W > 0, sprawdza czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W<math>=A[l]+...+A[p-1]</math>).}}
Tablica A typu array[1..N] of integer, N >0  zawiera tylko liczby dodatnie. Napisz program, który dla danego W typu integer takiego, że W > 0 sprawdza, czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W<math>=A[l]+...+A[p-1]</math>).}}


'''Program'''
'''Program'''
Linia 150: Linia 158:
   suma:=0;
   suma:=0;
   '''while''' (suma <> W) '''and''' (p <= N) '''do'''
   '''while''' (suma <> W) '''and''' (p <= N) '''do'''
     '''if''' suma < W '''then''' '''begin''' //jeśli suma jest za mała to przesuwamy prawy koniec segmentu
     '''if''' suma < W '''then''' '''begin''' //jeśli suma jest za mała, to przesuwamy prawy koniec segmentu
       suma:=suma+A[p];
       suma:=suma+A[p];
       p:=p+1;
       p:=p+1;
     '''end'''
     '''end'''
     '''else''' '''begin''' //jeśli za duża to przesuwamy lewy koniec segmentu
     '''else''' '''begin''' //jeśli za duża, to przesuwamy lewy koniec segmentu
       suma:= suma-A[l];
       suma:= suma-A[l];
       l:=l-1;
       l:=l+1;
     '''end''';
     '''end''';
   '''while''' (suma > W) '''do''' '''begin'''   
   '''while''' (suma > W) '''do''' '''begin'''   
     suma:= suma-A[l];
     suma:= suma-A[l];
     l:=l-1;
     l:=l+1;
   '''end''';
   '''end''';
   znalezione:=(suma=W);
   znalezione:=(suma=W);
  '''end'''.
  '''end'''.
 
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
{{rozwiazanie|||<div class="mw-collapsible mw-made=collapsible mw-collapsed"><div class="mw-collapsible-content" style="display:none">  
<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">  
Zacznijmy od niezmiennika pierwszej pętli
Zacznijmy od niezmiennika pierwszej pętli
  &forall; k  &forall; m (k < l &and; l &le; m &le; N+1) &rArr;  A[k]+...+A[m-1] <> W &and;
  &forall; k  &forall; m (k < l &and; l &le; m &le; N+1) &rArr;  A[k]+...+A[m-1] <> W &and;
Linia 171: Linia 180:
  1 &le; l &le; p &le; N+1 &and; N,W > 0 &and; suma=A[l]+....A[p-1] &and;
  1 &le; l &le; p &le; N+1 &and; N,W > 0 &and; suma=A[l]+....A[p-1] &and;
  A jest tablicą o wartościach dodatnich
  A jest tablicą o wartościach dodatnich
oznaczanego przez N(l,p,suma). Mówi ono, że wszystkie segmenty o początku mniejszym od l i dowolnym końcu mają sumy różne od W i że wszystkie segmenty o początku w l i końcu mniejszym od p mają sumy mniejsze niż W. Poza tym opisane są zależności między 1, l, p, N i suma.
oznaczanego przez N(l,p,suma). Mówi ono, że wszystkie segmenty o początku mniejszym od l i dowolnym końcu mają sumy różne od W, i że wszystkie segmenty o początku w l i końcu mniejszym od p mają sumy mniejsze niż W. Poza tym opisane są zależności między 1, l, p, N i suma.


Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem który otaczają są poprawnymi trójkami Hoare'a.
Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem, który otaczają, są poprawnymi trójkami Hoare'a.
     // N,W > 0, A jest tablicą o wartościach dodatnich
     // N,W > 0, A jest tablicą o wartościach dodatnich
  1: l:=1; p:=1; suma:=0;
  1: l:=1; p:=1; suma:=0;
Linia 212: Linia 221:
'''3''' Korzystamy z reguły na '''if''';  trzeba zrobić osobne sprawdzenia dla każdej gałęzi.
'''3''' Korzystamy z reguły na '''if''';  trzeba zrobić osobne sprawdzenia dla każdej gałęzi.


'''4''' Zgodnie z regułą na przypisanie musimy dowieść, że  N(l,p,suma) &and; (suma < W) &and; (p &le; N) wynika N(l,p+1,suma+A[p]),czyli
'''4''' Zgodnie z regułą na przypisanie, musimy dowieść, że  N(l,p,suma) &and; (suma < W) &and; (p &le; N) wynika N(l,p+1,suma+A[p]),czyli
  &forall; k  &forall; m (k < l &and; l &le; m &le; N+1) &rArr;  A[k]+...+A[m-1] <> W &and;
  &forall; k  &forall; m (k < l &and; l &le; m &le; N+1) &rArr;  A[k]+...+A[m-1] <> W &and;
  &forall; m (l &le; m < p+1) &rArr;  A[l]+...+A[m-1] < W &and;   
  &forall; m (l &le; m < p+1) &rArr;  A[l]+...+A[m-1] < W &and;   
  1 &le; l &le; p+1 &le; N+1 &and; N,W > 0 &and; suma+A[p]=A[l]+....A[p] &and;
  1 &le; l &le; p+1 &le; N+1 &and; N,W > 0 &and; suma+A[p]=A[l]+....A[p] &and;
  A jest tablicą o wartościach dodatnich
  A jest tablicą o wartościach dodatnich
Jedyna część, która nie jest oczywista to, że A[l]+...A[p-1] < W, ale to wynika z  (suma < W) i suma=A[l]+....A[p-1]
Jedyna część, która nie jest oczywista, to że A[l]+...A[p-1] < W, ale to wynika z  (suma < W) i suma=A[l]+....A[p-1]


'''5''' W drugiej gałęzi wiemy dodatkowo, że suma > W
'''5''' W drugiej gałęzi wiemy dodatkowo, że suma > W


'''6''' Zgodnie z regułą na przypisanie musimy dowieść, że  N(l,p,suma) &and; (suma > W) &and; (p &le; N) wynika N(l+1,p,suma-A[l]),czyli
'''6''' Zgodnie z regułą na przypisanie, musimy dowieść, że  N(l,p,suma) &and; (suma > W) &and; (p &le; N) wynika N(l+1,p,suma-A[l]),czyli
  &forall; k  &forall; m (k < l+1 &and; l+1 &le; m &le; N+1) &rArr;  A[k]+...+A[m-1] <> W &and;
  &forall; k  &forall; m (k < l+1 &and; l+1 &le; m &le; N+1) &rArr;  A[k]+...+A[m-1] <> W &and;
  &forall; m (l+1 &le; m < p) &rArr;  A[l+1]+...+A[m-1] < W &and;   
  &forall; m (l+1 &le; m < p) &rArr;  A[l+1]+...+A[m-1] < W &and;   
Linia 227: Linia 236:
  suma-A[l]=A[l+1]+....A[p-1] &and;
  suma-A[l]=A[l+1]+....A[p-1] &and;
  A jest tablicą o wartościach dodatnich
  A jest tablicą o wartościach dodatnich
Spójrzmy najpierw  na pierwszą linię niezmiennika: dla k < l,  A[k]+...+A[m-1]  <> W z założenia; dla k=l mamy pokazać że dla dowolnych m A[l]+...+A[m-1]  <> W. Ale wiemy, że dla m < p+1 zachodzi A[l]+...A[m-1] < W i że  A[l]+...A[p-1] > W (bo suma > W). A więc tym bardziej dla m > p+1 będzie A[l]+...A[m-1] > W (bo A jest dodatnia).  
Spójrzmy najpierw  na pierwszą linię niezmiennika: dla k < l,  A[k]+...+A[m-1]  <> W z założenia; dla k=l mamy pokazać że dla dowolnych m A[l]+...+A[m-1]  <> W. Ale wiemy, że dla m < p+1 zachodzi A[l]+...A[m-1] < W i że  A[l]+...A[p-1] > W (bo suma > W). Tym bardziej więc dla m > p+1 będzie A[l]+...A[m-1] > W (bo A jest dodatnia).  


Dla uzasadnienia drugiej linii wystarczy zauważyć, że gdy skracamy segment o wartości mniejszejniż W to jego wartość spada, bo A jest tablica dodatnią.
Dla uzasadnienia drugiej linii wystarczy zauważyć, że gdy skracamy segment o wartości mniejszej niż W, to jego wartość spada, bo A jest tablica dodatnią.


Pozostaje uzasadnienie  l+1 &le; p. Ponieważ suma > W to l < p, a więc też l+1 &le; p.  
Pozostaje uzasadnienie  l+1 &le; p. Ponieważ suma > W to l < p, a więc też l+1 &le; p.  


'''7''' Po pętli '''while''' wiemy, że zachodzi N(l,p,suma) i zaprzeczenie dozoru czyli (suma=W &or; p > N). Z niezmiennika wiemy, że p &le; N+1, a więc musi być p=N+1.
'''7''' Po pętli '''while''' wiemy, że zachodzi N(l,p,suma) i zaprzeczenie dozoru, czyli (suma=W &or; p > N). Z niezmiennika wiemy, że p &le; N+1, a więc musi być p=N+1.


'''8''' Pokażemy, że N(l,p,suma) &and; (suma=W &or; p = N+1) jest niezmiennikiem tej pętli.
'''8''' Pokażemy, że N(l,p,suma) &and; (suma=W &or; p = N+1) jest niezmiennikiem tej pętli.
Linia 239: Linia 248:
'''9''' Zauważmy najpierw, że  N(l,p,suma) &and; (suma=W &or; p = N+1) &and; suma > W jest równoważne N(l,p,suma) &and; p = N+1 &and; suma > W.  
'''9''' Zauważmy najpierw, że  N(l,p,suma) &and; (suma=W &or; p = N+1) &and; suma > W jest równoważne N(l,p,suma) &and; p = N+1 &and; suma > W.  


Zgodnie z regułą na przypisanie musimy dowieść, że N(l,p,suma) &and; p = N+1 &and; suma > W implikuje N(l+1,p,suma-A[l])  &and; (suma-A[l]=W &or; p = N+1). Zdanie N(l+1,p,suma-A[l]) dowodzi się tak jak w punkcie '''6'''. Ponieważ p =N+1 to zachodzi (suma-A[l]=W &or; p = N+1).
Zgodnie z regułą na przypisanie, musimy dowieść, że N(l,p,suma) &and; p = N+1 &and; suma > W implikuje N(l+1,p,suma-A[l])  &and; (suma-A[l]=W &or; p = N+1). Zdanie N(l+1,p,suma-A[l]) dowodzi się tak, jak w punkcie '''6'''. Ponieważ p =N+1, to zachodzi (suma-A[l]=W &or; p = N+1).


'''10''' Po wyjściu z pętli mamy N(l,p,suma) &and; (suma=W &or; p = N+1) i zaprzeczenie dozoru, czyli suma &le; W, a więc N(l,p,suma) &and; (suma=W &or; (p=N+1 &and; suma < W)).
'''10''' Po wyjściu z pętli mamy N(l,p,suma) &and; (suma=W &or; p = N+1) i zaprzeczenie dozoru, czyli suma &le; W, a więc N(l,p,suma) &and; (suma=W &or; (p=N+1 &and; suma < W)).
Linia 245: Linia 254:
'''11''' Pozostaje udowodnić, że N(l,p,suma) &and; (suma=W &or; (p=N+1 &and; suma < W)) implikuje  (suma=W) &hArr; (&exist; l &exist; p 1 &le; l &le; p &le; N+1 &and; A[l]+...A[p-1] = W) .
'''11''' Pozostaje udowodnić, że N(l,p,suma) &and; (suma=W &or; (p=N+1 &and; suma < W)) implikuje  (suma=W) &hArr; (&exist; l &exist; p 1 &le; l &le; p &le; N+1 &and; A[l]+...A[p-1] = W) .


Jeśli suma=W to z N(l,p,suma) oczywiście wynika istnienie odpowiednich l i p. Jeśli suma <> W to z założenia mamy p=N+1 i suma < W. I wtedy z niezmiennika wiemy, że
Jeśli suma=W to z N(l,p,suma), oczywiście wynika istnienie odpowiednich l i p. Jeśli suma <> W, to z założenia mamy p=N+1 i suma < W. I wtedy z niezmiennika wiemy, że
* segmenty o początkach mniejszych niż l mają sumy różne od W,
* segmenty o początkach mniejszych niż l mają sumy różne od W,
* segmenty o początkach w l i końcach mniejszych niż p mają sumy mniejsze niż W,   
* segmenty o początkach w l i końcach mniejszych niż p mają sumy mniejsze niż W,   
Linia 252: Linia 261:
Czyli nie isnieje segment o sumie równej W.
Czyli nie isnieje segment o sumie równej W.
</div>
</div>
</div>}}
</div>


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
Linia 266: Linia 275:
== Zadanie 3 (Głosowanie większościowe)==
== Zadanie 3 (Głosowanie większościowe)==
Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.
Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.
 
'''Zadanie'''
{{cwiczenie|||
Dana jest tablica A typu array[1..N] of integer, N > 0. Sprawdź czyjest w niej element wystepujący więcej niż N/2 razy i jeśli tak wskażgo.
Dana jest tablica A typu array[1..N] of integer, N > 0. Sprawdź, czy jest w niej element występujący więcej niż N/2 razy i jeśli tak, wskaż go.}}


'''Program'''
'''Program'''
Linia 293: Linia 302:
       '''end''';
       '''end''';
   '''end''';
   '''end''';
   ile:=0; //sprawdzamy czy kandydat jest liderem
   ile:=0; //sprawdzamy, czy kandydat jest liderem
   '''for''' i:=1 '''to''' '''do'''  
   '''for''' i:=1 '''to''' n '''do'''  
     '''if''' A[i]=kand '''then''' ile:=ile+1;  
     '''if''' A[i]=kand '''then''' ile:=ile+1;  
   '''if''' (ile >= (N div 2 + 1) '''then''' '''begin'''  
   '''if''' (ile >= (N div 2 + 1) '''then''' '''begin'''  
Linia 303: Linia 312:
     lider:=0;
     lider:=0;
  '''end'''.
  '''end'''.
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie''' 
<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">  
<div class="mw-collapsible-content" style="display:none">  
Sprawdzenie czy kandydat jest liderem jest proste, skoncentrujemy się więc na pierwszej części i wykażemy, że jeśli w tablicy jest lider to pierwsza część go znajduje.
Sprawdzenie, czy kandydat jest liderem, jest proste. Skoncentrujemy się więc na pierwszej części i wykażemy, że jeśli w tablicy jest lider to pierwsza część go znajduje.


Zacznijmy od niezmiennika pierwszej pętli oznaczanego przez N(i,ile,kand).  
Zacznijmy od niezmiennika pierwszej pętli oznaczanego przez N(i,ile,kand).  
Linia 314: Linia 324:




Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem który otaczają są poprawnymi trójkami Hoare'a.
Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem, który otaczają, są poprawnymi trójkami Hoare'a.
     // N > 0
     // N > 0
  1: kand:=A[1];
  1: kand:=A[1];
Linia 345: Linia 355:
     //Jeśli w tablicy istnieje lider to jest nim kand
     //Jeśli w tablicy istnieje lider to jest nim kand
   
   
'''1''' Korzystając z reguły na przypisanie. Mamy pokazać, że N(1,1,A[1]). Szukana permutacja jest identycznościowa, reszta jest pusta, i oraz ile są w wymaganych zakresach.
'''1''' Korzystając z reguły na przypisanie mamy pokazać, że N(1,1,A[1]). Szukana permutacja jest identycznościowa, reszta jest pusta, i oraz ile są w wymaganych zakresach.


'''2''' Będziemy pokazywać, że N(i,ile,kand) jest niezmiennikiem pętli.
'''2''' Będziemy pokazywać, że N(i,ile,kand) jest niezmiennikiem pętli.


'''3''' Trzeba osobno rozpatrzeć gałezie '''if'''.
'''3''' Trzeba osobno rozważyć gałęzie '''if'''.


'''4''' Korzystając z reguły na przypisanie mamy do pokazania, że N(i,ile,kand) &and; i &le; N &and; A[i]=kand implikuje N(i+1,ile+1,kand). Jesli P to permutacja z N(i,ile,kand) to
'''4''' Korzystając z reguły na przypisanie, mamy do pokazania, że N(i,ile,kand) &and; i &le; N &and; A[i]=kand implikuje N(i+1,ile+1,kand). Jeśli P to permutacja z N(i,ile,kand), to
szukana permutacja to P', gdzie P'(ile+1)=A[i], P'(i)=P(ile+1), P'(x)=P(x) dla x<>i lub x<>ile+1. Ogon pozostaje nie zmieniony czyli nadal nie ma tam lidera. Ponieważ i &le; N to i+1 &le; N+1; oczywiście ile > 0.
szukana permutacja to P', gdzie P'(ile+1)=A[i], P'(i)=P(ile+1), P'(x)=P(x) dla x<>i lub x<>ile+1. Ogon pozostaje niezmieniony, czyli nadal nie ma tam lidera. Ponieważ i &le; N to i+1 &le; N+1; oczywiście ile > 0.


'''5''' Kolejny '''if'''; dowód znów się rozgałęzia.
'''5''' Kolejny '''if'''; dowód znów się rozgałęzia.


'''6''' Korzystając z reguły na przypisanie mamy do pokazania, że N(i,ile,kand) &and; i &le; N &and; A[i]<> kand i &and; ile > 0 implikuje N(i+1,ile-1,kand). Jesli P to permutacja z N(i,ile,kand) to
'''6''' Korzystając z reguły na przypisanie, mamy do pokazania, że N(i,ile,kand) &and; i &le; N &and; A[i]<> kand i &and; ile > 0 implikuje N(i+1,ile-1,kand). Jeśli P to permutacja z N(i,ile,kand), to
szukana permutacja to P rozszerzona o identyczność na i. W nowym ogonie mamy dodatkowo A[i] i kand. Z tego wynika, że gdyby A[i] był liderem w nowym ogonie to A[i] byłby liderem w starym ogonie co jest niemożliwe. Oczywiście i+1 &le; N+1; oraz ile > 0.
szukana permutacja to P rozszerzona o identyczność na i. W nowym ogonie mamy dodatkowo A[i] i kand. Z tego wynika, że gdyby A[i] był liderem w nowym ogonie, to A[i] byłby liderem w starym ogonie, co jest niemożliwe. Oczywiście i+1 &le; N+1; oraz ile > 0.


'''7''' Wpierw zauważmy, że ile &le; 0 oraz ile &ge; 0 implikują ile=0. Korzystając z reguły na przypisanie mamy do pokazania, że
'''7''' Wpierw zauważmy, że ile &le; 0 oraz ile &ge; 0 implikują ile=0. Korzystając z reguły na przypisanie, mamy do pokazania, że
N(i,ile,kand) &and; i &le; N &and; A[i] <> kand &and; ile =0  
N(i,ile,kand) &and; i &le; N &and; A[i] <> kand &and; ile =0  
implikuje N(i+1,1,A[i]). Ponieważ ile=0 to w tablicy A[1..i-1] nie ma lidera. A więc szukaną permutacją jest na przykład A[i]@A[1..i-1].
implikuje N(i+1,1,A[i]). Ponieważ ile=0, to w tablicy A[1..i-1] nie ma lidera. Szukaną permutacją jest więc na przykład A[i]@A[1..i-1].
Oczywiście i+1 &le; N+1; oraz ile > 0.
Oczywiście i+1 &le; N+1; oraz ile > 0.


'''8''' Po wyjściu z pętli mamy N(i,ile,kand) i zaprzeczenie dozoru, czyli i > N. To oznacza, że i=N+1. Czy mozliwe jest by liderem była
'''8''' Po wyjściu z pętli mamy N(i,ile,kand) i zaprzeczenie dozoru, czyli i > N. To oznacza, że i=N+1. Czy możliwe jest, by liderem była
wartośc w <> kand. Jeśli tak przypuścimy to niezależnie od ile, w musiałaby być liderem w ogonie, co jest sprzeczne z niezmiennikiem. a więc jedynym kandydatem an lidera jest rzeczywiście kand.
wartość w <> kand? Jeśli tak przypuścimy, to niezależnie od ile, w musiałaby być liderem w ogonie, co jest sprzeczne z niezmiennikiem. Jedynym kandydatem na lidera jest więc rzeczywiście kand.


</div>
</div>
Linia 373: Linia 383:
Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.
Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.
   
   
'''Zadanie'''
{{cwiczenie|||
Dla zadanych x,n > 0 wyznacz x<sup>n</sup> (oczywiscie bez exp i ln).
Dla zadanych x,n > 0 wyznacz x<sup>n</sup> (oczywiscie bez exp i ln).}}


'''Program'''
'''Program'''
Linia 391: Linia 401:
   BinPower:=z;
   BinPower:=z;
  '''end''';
  '''end''';
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie''' 
<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">  
<div class="mw-collapsible-content" style="display:none">  
Zacznijmy od niezmiennika pętli oznaczanego przez N(z,y,i):  
Zacznijmy od niezmiennika pętli oznaczanego przez N(z,y,i):  
  x<sup>n</sup>=z*y<sup>i</sup> &and; i&ge; 0
  x<sup>n</sup>=z*y<sup>i</sup> &and; i&ge; 0


Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem który otaczają są poprawnymi trójkami Hoare'a.
Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem, który otaczają, są poprawnymi trójkami Hoare'a.
     // x,n > 0
     // x,n > 0
  1: z:=1; y:=x; i:=n;
  1: z:=1; y:=x; i:=n;
Linia 412: Linia 421:
     // z= x<sup>n</sup>
     // z= x<sup>n</sup>


'''1''' Korzystając z reguły na przypisanie. Mamy pokazać, że N(1,x,n). Ponieważ n>0 to n&ge; 0
'''1''' Korzystając z reguły na przypisanie, mamy pokazać, że N(1,x,n). Ponieważ n>0 to n&ge; 0


'''2''' Będziemy pokazywać, że N(z,y,i) jest niezmiennikiem pętli.
'''2''' Będziemy pokazywać, że N(z,y,i) jest niezmiennikiem pętli.


'''3''' Choć mamy instrukcję '''if''' bez '''else''' musimy pokazać dwie implikacje  
'''3''' Choć mamy instrukcję '''if''' bez '''else''', musimy pokazać dwie implikacje  
  N(z,y,i) &and; i>0 &and; i mod 2 = 1 &rArr; N(z*y, y*y, i div 2)
  N(z,y,i) &and; i>0 &and; i mod 2 = 1 &rArr; N(z*y, y*y, i div 2)
  N(z,y,i) &and; i>0 &and; i mod 2 = 0 &rArr; N(z, y*y, i div 2)
  N(z,y,i) &and; i>0 &and; i mod 2 = 0 &rArr; N(z, y*y, i div 2)


Dla pierwszej z nich zauważmy, ze jeśli i mod 2 = 1 to i=2*(i div 2) +1. Wtedy  z*y<sup>i</sup>= (z*y) * (y*y)<sup>(i div 2)</sup>. Oczywiście jeśli i > 0 to i div 2 &ge; 0.
Dla pierwszej z nich zauważmy, że jeśli i mod 2 = 1 to i=2*(i div 2) +1. Wtedy  z*y<sup>i</sup>= (z*y) * (y*y)<sup>(i div 2)</sup>. Oczywiście jeśli i > 0 to i div 2 &ge; 0.


Dla drugiej, mamy  i=2*(i div 2). Wtedy  z*y<sup>i</sup>= z * (y*y)<sup>(i div 2)</sup>. Podobnie jeśli i > 0 to i div 2 &ge; 0.
Dla drugiej mamy  i=2*(i div 2). Wtedy  z*y<sup>i</sup>= z * (y*y)<sup>(i div 2)</sup>. Podobnie, jeśli i > 0 to i div 2 &ge; 0.


'''4''' Jest to dwa razy użyta reguła na przypisanie.
'''4''' Jest to dwa razy użyta reguła na przypisanie.

Aktualna wersja na dzień 16:00, 28 maj 2020

<<< Powrót do modułu Dowodzenie poprawności programów

To są zadania na logikę Hoare'a.

Oglądaj wskazówki i rozwiązania __SHOWALL__
Ukryj wskazówki i rozwiązania __HIDEALL__


Zadanie 1 (Flaga trójkolorowa)

Udowodnij częściową poprawność podanego poniżej rozwiązania zadania o fladze trójkolorowej.

Ćwiczenie

Dana jest tablica A typu array[1..N] of integer (N > 0). Należy tak poprzestawiać w niej elementy, żeby najpierw były elementy ujemne, potem równe zero, a na końcu dodatnie.

Program

program FlagaTrójkolorowa(N:integer; A:array[1..N] of integer);
var m,r,w,pom : integer;
begin
  m:=1; r:=1; w:=N;
  while r <= w do 
    if A[r]=0 then r:=r+1			//przedłużamy segment liczb dodatnich	
    else 
      if A[r]<0 then begin			
        pom:=A[r]; A[r]:=A[m]; A[m]:=pom;	//zamieniamy wartości w A[r] i A[m], po zamianie A[r]=0 i A[m] < 0  
        m:=m+1;					//więc zwiększamy oba indeksy r i m
        r:=r+1;
      end
      else begin
        pom:=A[r]; A[r]:=A[w]; A[w]:=pom;	//zamieniamy wartości w A[r] i A[w]
        w:=w-1;					//po zamianie A[w]>0,  ale o A[r] nic nie wiemy
      end;			     
end.

Rozwiązanie

Całkowita poprawność

Zadanie 2 (Segment o danej sumie)

Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.

Ćwiczenie

Tablica A typu array[1..N] of integer, N >0 zawiera tylko liczby dodatnie. Napisz program, który dla danego W typu integer takiego, że W > 0 sprawdza, czy w A istnieje segment o sumie W (czyli czy istnieją l, p takie, że W=A[l]+...+A[p1]).

Program

program SegmentODanejSumie2(N,W:integer; A:array[1..N] of integer);
//Tablica A zawiera tylko liczby dodatnie
var l,p,suma: integer;
    znalezione: boolean;
begin
  l:=1; p:=1;
  suma:=0;
  while (suma <> W) and (p <= N) do
    if suma < W then begin		//jeśli suma jest za mała, to przesuwamy prawy koniec segmentu
      suma:=suma+A[p];
      p:=p+1;
    end
    else begin			//jeśli za duża, to przesuwamy lewy koniec segmentu
      suma:= suma-A[l];
      l:=l+1;
    end;
  while (suma > W) do begin  
    suma:= suma-A[l];
    l:=l+1;
  end;
  znalezione:=(suma=W);
end.

Rozwiązanie

Całkowita poprawność

Zadanie 3 (Głosowanie większościowe)

Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.

Ćwiczenie

Dana jest tablica A typu array[1..N] of integer, N > 0. Sprawdź, czy jest w niej element występujący więcej niż N/2 razy i jeśli tak, wskaż go.

Program

program Głosowanie2(N,W:integer; A:array[1..N] of integer);
var ile,i,kand,lider: integer;
begin
  kand:=A[1];		//szukamy kandydata na lidera
  ile := 1;
  i:=2;
  while i <= N do begin	
    if A[i]=kand then begin
      ile:=ile+1;
      i:=i+1;
    end
    else
      if ile > 0 then begin
        ile:=ile-1;
        i:=i+1;
      end
      else begin
        kand:=A[i];
        ile:=1;
        i:=i+1;
      end;
  end;
  ile:=0;		//sprawdzamy, czy kandydat jest liderem
  for i:=1 to n do 
    if A[i]=kand then ile:=ile+1; 
  if (ile >= (N div 2 + 1) then begin 
    lider:=kand;
    write('Liderem jest: ', kand);
  end 
  else 
    lider:=0;
end.

Rozwiązanie

Zadanie 4 (BinPower)

Udowodnij częściową poprawność dla podanego poniżej zadania i jego rozwiązania.

Ćwiczenie

Dla zadanych x,n > 0 wyznacz xn (oczywiscie bez exp i ln).

Program

function BinPower(x,n:integer):integer;
// Dla x,n > 0 wyznaczamy x do potęgi n 
var z,y,i: integer;
begin
  z:=1;
  y:=x;
  i:=n;
  while i > 0 do begin
    if (i mod 2 = 1) then z:=z*y;
    y:=y*y;
    i:=i div 2;
  end;
  BinPower:=z;
end;

Rozwiązanie