Wyklad4_studentx

Download Report

Transcript Wyklad4_studentx

Slide 1

Wprowadzimy teraz pojęcie niezmiennika pętli, które jest często
wykorzystywane do projektowania algorytmów i dowodzenia ich
poprawności. Rozważmy pętlę „while”, która ma postać:


Slide 2


Slide 3


Slide 4

Ostatnie stwierdzenie dotyczące prawdziwości zdania g po zakończeniu
pętli jest tak oczywistym, że często się o nim zapomina.
Jednak dostarcza ono ważnych informacji pozwalających uzasadnić
semantyczną poprawność algorytmów. Dlatego zostało umieszczone w
treści twierdzenia.


Slide 5

k=4;
while(k>=4)
k=k+1;


Slide 6

Przykład 1.

Algorytm NWD Euklidesa.
Zapis w pseudokodzie

Jak znaleźć niezmiennik
pętli?


Slide 7

Najpierw należy pokazać, że


Slide 8


Slide 9


Slide 10


Slide 11


Slide 12


Slide 13

Ćwiczenie


Slide 14


Slide 15


Slide 16

Przykład 2.
Rozważmy algorytm dzielenia całkowitego liczb naturalnych.
void dzielenie (int x,y)
{
//: 0<=x i 0<=y
int q,r;
q=0;
r=x;
while(y<=r)
//p: x=q*y+r i 0<=r i 0<=y
{
q=q+1;
r=r-y;
};
}
//: x=q*y+r i 0<=r
Pokażemy, że algorytm ten jest częściowo poprawny względem
warunku początkowego  i końcowego .


Slide 17

Należy udowodnić pewną własność obliczeń algorytmu, która łączy
zachodzenie warunku początkowego z warunkiem końcowym.

Jaki warunek spełniają x, y, q, r w pętli „while” w chwili
sprawdzenia warunku „y<=r” sterującego iteracją?
Określamy niezmiennik p.
Wykażemy, że za każdym razem, gdy obliczenie algorytmu
rozpoczyna się stanem spełniającym warunek początkowy oraz
dochodzi do warunku iteracji, to spełniony jest warunek p.


Slide 18

bezpośrednio z
void dzielenie (int x,y)
początku
{
//: 0<=x i 0<=y
algorytmu
int q,r;
q=0;
r=x;
while(y<=r)
//p: x=q*y+r i 0<=r i 0<=y
{
z pętli
q=q+1;
r=r-y;
};
}
//: x=q*y+r i 0<=rMożemy dojść do p
dwiema drogami:


Slide 19

void dzielenie (int x,y)
{
//: 0<=x i 0<=y
int q,r;
q=0;
r=x;
while(y<=r)
//p: x=q*y+r i 0<=r i 0<=y
{
q=q+1;
r=r-y;
};
}
//: x=q*y+r i 0<=r
Wtedy zostaje wykonana instrukcja
złożona: q’=q+1;r’=r-y.
Trzeba sprawdzić, czy dla q’ i r’
zachodzi warunek p:
p: x=q’*y+r’ i 0<=r’ i 0<=y .

Jeśli dojdziemy do p z
początku algorytmu, to q=0,
r=x i p jest spełniony, bo
zachodzi .
Jeśli już przejdziemy przez
pętlę „while” i dojdziemy do
p, to wiemy, że y<=r i zaszedł
już warunek p: x=q*y+r i
0<=r i 0<=y .
Ale
x=(q+1)*y+(r-y)=q*y+r
0<=r’=r-y, bo y<=r i 0<=y.


Slide 20

void dzielenie (int x,y)
{
//: 0<=x i 0<=y
int q,r;
q=0;
r=x;
while(y<=r)
//p: x=q*y+r i 0<=r i 0<=y
{
q=q+1;
r=r-y;
};
}
//: x=q*y+r i 0<=r
Stosując teraz indukcję
względem liczby wykonanych
sprawdzeń warunku iteracji
„y<=r”, wnioskujemy, że
przy każdym sprawdzeniu
warunku iteracji zachodzi p.

Zatem, albo cały czas zachodzi „y<=r”i wtedy nie dochodzimy
do , albo w pewnej chwili „y>r” i wtedy dochodzimy do , ale
ponieważ p był spełniony, więc musi być spełniony .
Zwróćmy uwagę, że jeśli x=0 i y=0, to obliczenie algorytmu jest
nieskończone, a więc według podanych warunków algorytm jest
tylko częściowo poprawny i ma własność określoności obliczeń,
ale nie ma własności stopu!


Slide 21

Dowodzenie własności stopu

Kryterium liczników iteracji

Kryterium malejących wielkości


Slide 22

Załóżmy, że dany jest algorytm:
M:{
l=c;
while(p)do
{
K;
l=l+1;
}

zmienna l jest
licznikiem iteracji,
służy do
obliczania liczby
wykonań instrukcji
iterowanej K

Dobieramy teraz dwie wielkości:
 takie, że l<= oraz  takie,
które wyjaśnia zależność między
wartościami zmiennych w chwili
sprawdzania warunku
(niezmiennika) p.

}
Kryterium liczników iteracji

Jeżeli:
1)  i >=l jest w algorytmie M niezmiennikiem instrukcji
iteracyjnej „while” przy warunku początkowym ,
2) K ma własność stopu względem  i p,
to M oraz „while(p)do K” mają własność stopu względem .


Slide 23

Przykład 3.

!!

void dzielenie1 (int x,y)
{
//1: 0<=x i 0int q,r;
q=0;
r=x;
while(y<=r)
//p: x=q*y+r i 0<=r i 0{
q=q+1;
r=r-y;
};
}
//: x=q*y+r i 0<=r
Zmienna q pełni rolę licznika iteracji.

M:{
l=c;
while(p)do
{
K;
l=l+1;
}
}


Slide 24

void dzielenie1 (int x,y)
{
//1: 0<=x i 0int q,r;
q=0;
r=x;
while(y<=r)
//p: x=q*y+r i 0<=r i 0{
q=q+1;
r=r-y;
};
}
//: x=q*y+r i 0<=r
M:{
l=c;
while(p)do
{
K;
l=l+1;
}
}

Określmy : x/y oraz : x=q*y+r i r>=0 i 0Pokażemy, że  i q<=x/y jest niezmiennikiem instrukcji iteracyjnej.
Przy wejściu do instrukcji mamy: q=0, r=x, x>=0, y>0, czyli zachodzi
 i q<=x/y oraz r>=y.
Wtedy dostajemy nowe wartości: q’=q+1 i r’=r-y.


Slide 25

void dzielenie1 (int x,y)
{
//1: 0<=x i 0int q,r;
q=0;
r=x;
while(y<=r)
//p: x=q*y+r i 0<=r i 0{
q=q+1;
r=r-y;
};
}
//: x=q*y+r i 0<=r
M:{
l=c;
while(p)do
{
K;
l=l+1;
}
}

: x/y oraz : x=q*y+r i r>=0 i 0
Ćwiczenie!

Łatwo pokazać, że te nowe zmienne spełniają warunek , a
nierówność q<=x/y wynika z , bo:
x=q*y+r,

y>0

q=x/y-r/y, y>0

(r>=0,y>0)
q<=x/y

Stosując teraz kryterium liczników iteracji wnioskujemy, że algorytm ma
własność stopu względem 1. Ponadto nierówność q<=x/y podaje
ograniczenie na liczbę wykonywanych iteracji.


Slide 26

Załóżmy, że dany jest algorytm:
M:{
i=w+1;
while(p)do
{
i=w;
K;
}

Dobieramy teraz trzy wielkości:
i oraz w będące liczbami
całkowitymi i  takie, które
wyjaśnia zależność między
wartościami zmiennych w chwili
sprawdzania warunku
(niezmiennika) p.

}

Kryterium malejących wielkości
Jeżeli:
1)  i i>w, i w>=0 jest w algorytmie M niezmiennikiem
instrukcji iteracyjnej „while” przy warunku początkowym ,
2) K ma własność stopu względem  i p,
to M oraz „while(p)do K” mają własność stopu względem .


Slide 27

Metodę malejących wielkości stosuje się, gdy w algorytmie zwiększanie
wartości następuje w sposób nieregularny, czyli niekoniecznie o 1.
Zamiast szacować wzrost rozpatruje się jednak te wielkości, które
zmniejszają swoje wartości w trakcie wykonywania algorytmu i dla których
istnieją wartości ograniczające je z dołu.


Slide 28

Przykład 4.
void dzielenie2 (int x,y)
{
//2: 0<=x i 0int q,r; int i;
q=0;
r=x; i=r+1;
while(y<=r)
//p: x=q*y+r i 0<=r i 0{
q=q+1; i=r;
r=r-y;
};
}
//: x=q*y+r i 0<=r
M:{
i=w+1;
while(p)do
{
i=w;
K;
}
}

Zmienna r pełni rolę w. Wprowadzamy też pomocniczą zmienną i.


Slide 29

void dzielenie2 (int x,y)
{
//2: 0<=x i 0int q,r; int i;
q=0;
r=x; i=r+1;
while(y<=r)
//p: x=q*y+r i 0<=r i 0{
q=q+1; i=r;
r=r-y;
};
}
//: x=q*y+r i 0<=r
M:{
i=w+1;
while(p)do
{
i=w;
K;
}
}

Ustalamy : y>0 i (i=r+1 ∨ i=r+y).
Przy wejściu do instrukcji „while” warunek  jest spełniony, bo i=r+1.


Slide 30

void dzielenie2 (int x,y)
{
//2: 0<=x i 0int q,r; int i;
q=0;
r=x; i=r+1;
while(y<=r)
//p: x=q*y+r i 0<=r i 0{
q=q+1; i=r;
r=r-y;
};
}
//: x=q*y+r i 0<=r
M:{
i=w+1;
while(p)do
{
i=w;
K;
}
}

: y>0 i (i=r+1 ∨ i=r+y).

Warunek  zachowuje się przy każdym wykonaniu instrukcji
iterowanej, bo jeśli i’ i r’ są nowymi wartościami, to i’=r oraz
r’=r-y, czyli i’=r’+y.
Zatem  jest niezmiennikiem iteracji.
Ponieważ r>=0, to cały warunek  i r=0 jest niezmiennikiem
iteracji.
Na podstawie kryterium malejących wielkości mamy własność stopu
względem 2.