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

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania
Daria (dyskusja | edycje)
Poczatki flagi trojkolorowej
 
Daria (dyskusja | edycje)
Cala flaga trojkolorowa
Linia 24: Linia 24:
  '''end'''.
  '''end'''.


<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Wskazówka 1''' 
<div class="mw-collapsible-content" style="display:none">
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Rozwiązanie'''   
'''Rozwiązanie'''   
Linia 37: Linia 31:
  &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 < j &le; N) &rArr;  A[k] > 0 &and;   
  1 &le; m &le; r &and;
  1 &le; m &le; r &and;  r-1 &le; w &le; N &and; N > 0
  r-1 &le; w &le; N &and;
N > 0
oznaczane przez N(m,r,w). Poniżej znajduje się program wraz z anotacjami i dowody, że anotacje wraz z kodem który otaczają są poprawnymi trójkami Hoare'a.
oznaczane przez N(m,r,w). 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  
Linia 51: Linia 43:
  4:    r:=r+1
  4:    r:=r+1
       // N(m,r,w)
       // N(m,r,w)
    '''else'''  
5:  '''else'''  
  5:    '''if''' A[r]<0 '''then''' '''begin'''
  6:    '''if''' A[r]<0 '''then''' '''begin'''
         // N(m,r,w) &and; r &le; w &and; A[r] < 0
         // N(m,r,w) &and; r &le; w &and; A[r] < 0
  6:      pom:=A[r]; A[r]:=A[m]; A[m]:=pom;
  7:      pom:=A[r]; A[r]:=A[m]; A[m]:=pom;
         // N(m+1,r+1,w) &and; r &le; w
         // N(m+1,r+1,w)
  7:      m:=m+1; r:=r+1;
  8:      m:=m+1; r:=r+1;
         // N(m,r,w)
         // N(m,r,w)
       '''end'''
       '''end'''
  8:    '''else''' '''begin'''
  9:    '''else''' '''begin'''
         // N(m,r,w) &and; r &le; w &and; A[r] > 0
         // N(m,r,w) &and; r &le; w &and; A[r] > 0
  9:     pom:=A[r]; A[r]:=A[w]; A[w]:=pom;
  10:     pom:=A[r]; A[r]:=A[w]; A[w]:=pom;
         // N(m,r,w-1) &and; r &le; w
         // N(m,r,w-1)
  10:    w:=w-1;
  11:    w:=w-1;
         // N(m,r,w)
         // N(m,r,w)
  11:  '''end''';      
  12:  '''end''';      
   // N(m,r,w) &and; r-1=w
   // N(m,r,w) &and; r-1=w
    
    
# Korzystamy z reguły na przypisanie. N(m,r,w) z wartościami m=1, r=1, w=1 jest równe
'''1''' Korzystamy z reguły na przypisanie. N(m,r,w) z wartościami m=1, r=1, w=1 jest równe
  &forall; i  (1 &le; i < 1) &rArr;  A[i] < 0 &and;   
  &forall; i  (1 &le; i < 1) &rArr;  A[i] < 0 &and;   
  &forall; j  (m &le; j < 1) &rArr;  A[j] = 0 &and;   
  &forall; j  (m &le; j < 1) &rArr;  A[j] = 0 &and;   
  &forall; k  (N < j &le; N) &rArr;  A[k] > 0 &and;   
  &forall; k  (N < j &le; N) &rArr;  A[k] > 0 &and;   
  1 &le; 1 &le; 1 &and;
  1 &le; 1 &le; 1 &and;  0 &le; N &le; N &and; N > 0
  0 &le; N &le; N &and;
i jest trywialnie prawdziwe.
N > 0
i jest trywialnie prawdziwe
# Korzystamy z reguły na while; trzeba pokazać, że N(m,r,w) jest niezmiennikiem ciała pętli, czyli że z N(m,r,w) &and; r &le; w  po wykonaniu pętli zachodzi N(m,r,w)
# Korzystamy z reguły na if;  trzeba pokazać, że z N(m,r,w) &and; r &le; w po wykonaniu każdej gałęzi if-a zachodzi N(m,r,w)
# 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 
N(m,r,w) &and; r &le; w &and; A[r] = 0  &rArr; N(m,r+1,w)


'''2''' Korzystamy z reguły na '''while'''; trzeba pokazać, że N(m,r,w) jest niezmiennikiem ciała pętli, czyli że zaczynając z N(m,r,w) &and; r &le; w  po wykonaniu pętli 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 
(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
&forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and; 
&forall; k  (w < j &le; N) &rArr;  A[k] > 0 &and;
1 &le; m &and; w &le; N &and; N > 0
wynikają trywialnie z N(m,r,w). Mamy też
&forall; j  (m &le; j < r+1) &rArr;  A[j] = 0
bo A[r] = 0.Ponieważ r &le; w to
r+1-1 &and; w
a ponieważ m &le; r to
m &le; r+1


N(m,r,w) z wstawionym r+1 na miejsce r ma postać
'''5''' W drugiej gałęzi instrukcji warunkowej z '''3''' znajduje się '''if'''. Schodząc do jego podgałęzi dodajemy do założeń, że A[r] <> 0.
  &forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and;   
 
  &forall; j  (m &le; j < r+1) &rArr;  A[j] = 0 &and;   
'''6''' Ciało podgałęzi spełniającej warunek A[r] < 0 składa się z dwóch grup przypisań.
 
'''7''' Trzeba pokazać, że z  N(m,r,w) &and; r &le; w &and; A[r] < 0 wynika N(m+1,r+1,w) z zamienionymi wartościami A[r] i A[m]. Dokładniej, uzupełniając program o brakujące anotacje zgodnie z regułą na przypisanie, przed instrukcją A[m]:=pom mamy
&forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and; pom < 0  &and; 
&forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and; A[r] = 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
przed A[r]:=A[m]
  &forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and; pom < 0  &and;   
  &forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and; A[m] = 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
a przed pom:= A[r]
&forall; i  (1 &le; i < m) &rArr;  A[i] < 0 &and; A[r] < 0  &and; 
&forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and; A[m] = 0 &and;
  &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 &le; r+1 &and;
  1 &le; m+1 &le; r+1 &and; r &le; w &le; N &and; N > 0
r+1-1 &le; w &le; N &and;
czyli coś co łatwo wynika N(m,r,w) &and; r &le; w &and; A[r] < 0.
N > 0
 
z czego trywialnie wynika
'''8''' Jest to trywialne użycie reguły na przypisanie.
&forall; i (1 &le; i < m) &rArr;  A[i] < 0 &and;  
&forall; j  (m &le; j < r) &rArr;  A[j] = 0 &and; A[r]=0 &and;
&forall; k  (w < j &le; N) &rArr;  A[k] > 0 &and;
1 &le; m &and; w &le; N &and;  r &le;w &and; N > 0
Brakuje


'''9''' Ciało podgałęzi spełniającej warunek A[r] > 0 składa się znów z dwóch grup przypisań.


co jest równoważne
'''10'''  Trzeba pokazać, że z  N(m,r,w) &and; r &le; w &and; A[r] > 0
wynika N(m,r,w-1) z zamienionymi wartościami A[r] i A[w] czyli
  &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; A[r]=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 < j &le; N) &rArr;  A[k] > 0 &and; A[r] > 0 &and;   
  1 &le; m &le; r+1 &and;
  1 &le; m &le; r &and;
  r &le; w &le; N &and;
  r-1 &le; w-1 &le; N &and; N > 0
N > 0
co jest łatwe.


'''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.
</div>
</div>
<div class="mw-collapsible mw-made=collapsible mw-collapsed">
'''Całkowita poprawność''' 
<div class="mw-collapsible-content" style="display:none">
Do udowodnienia całkowitej poprawności brakuje tylko argumentu, że program zawsze się zakończy, czyli że pętla zawsze się zakończy. Można w tym celu użyć miary (w-r)+1, ponieważ maleje ona w każdym obrocie pętli i jest zawsze nieujemna.
</div>
</div>
</div>
</div>

Wersja z 19:44, 19 lip 2006

Zadanie 1 (Flaga trójkolorowa)

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

Zadanie 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ść