Poprawność semantyczna

Podobne dokumenty
Indukcja. Materiały pomocnicze do wykładu. wykładowca: dr Magdalena Kacprzak

Podstawy Informatyki. Algorytmy i ich poprawność

Matematyka Dyskretna. Andrzej Szepietowski. 25 czerwca 2002 roku

Wykład 2. Poprawność algorytmów

Wykład X. Programowanie. dr inż. Janusz Słupik. Gliwice, Wydział Matematyki Stosowanej Politechniki Śląskiej. c Copyright 2016 Janusz Słupik

Matematyka dyskretna

Logika Stosowana. Wykład 1 - Logika zdaniowa. Marcin Szczuka. Instytut Informatyki UW. Wykład monograficzny, semestr letni 2016/2017

ALGORYTMY I STRUKTURY DANYCH

TEORETYCZNE PODSTAWY INFORMATYKI

Wielomiany jednej zmiennej rzeczywistej algorytmy

Algorytm. a programowanie -

Indukcja matematyczna

Wyszukiwanie. Wyszukiwanie binarne

Rekurencja (rekursja)

1 Wprowadzenie do algorytmiki

Definicje. Algorytm to:

Poprawność algorytmów

Obliczenia na stosie. Wykład 9. Obliczenia na stosie. J. Cichoń, P. Kobylański Wstęp do Informatyki i Programowania 266 / 303

Wstęp do Programowania potok funkcyjny

Drzewa poszukiwań binarnych

Programowanie - wykład 4

Uniwersytet Zielonogórski Instytut Sterowania i Systemów Informatycznych. Algorytmy i struktury danych Laboratorium 7. 2 Drzewa poszukiwań binarnych

Matematyka Dyskretna 2/2008 rozwiązania. x 2 = 5x 6 (1) s 1 = Aα 1 + Bβ 1. A + B = c 2 A + 3 B = d

Porządek symetryczny: right(x)

Matematyka Dyskretna Zestaw 2

Indukcja matematyczna, zasada minimum i maksimum. 17 lutego 2017

(1) Poprawność Algorytmów

Zapis algorytmów: schematy blokowe i pseudokod 1

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Analiza Algorytmów - Moduł 2- Ćwiczenia

ALGORYTMY. 1. Podstawowe definicje Schemat blokowy

Wyszukiwanie w BST Minimalny i maksymalny klucz. Wyszukiwanie w BST Minimalny klucz. Wyszukiwanie w BST - minimalny klucz Wersja rekurencyjna

Wskazówki dotyczące zmiennych, tablic i procedur 1

ALGORYTMY. 1. Podstawowe definicje Schemat blokowy

Wykład 1_2 Algorytmy sortowania tablic Sortowanie bąbelkowe

3. Podaj elementy składowe jakie powinna uwzględniać definicja informatyki.

Algorytmy i str ruktury danych. Metody algorytmiczne. Bartman Jacek

Metoda Tablic Semantycznych

n=0 (n + r)a n x n+r 1 (n + r)(n + r 1)a n x n+r 2. Wykorzystując te obliczenia otrzymujemy, że lewa strona równania (1) jest równa

Wstęp do programowania

ALGORYTMY I STRUKTURY DANYCH

WHILE (wyrażenie) instrukcja;

Schemat rekursji. 1 Schemat rekursji dla funkcji jednej zmiennej

Indukcja matematyczna. Zasada minimum. Zastosowania.

Lab 10. Funkcje w argumentach funkcji metoda Newtona. Synonimy nazw typów danych. Struktury. Tablice struktur.

. Podstawy Programowania 2. Drzewa bst - część druga. Arkadiusz Chrobot. 12 maja 2019

Przykładami ciągów, które Czytelnik dobrze zna (a jeśli nie, to niniejszym poznaje), jest ciąg arytmetyczny:

Informatyka 1. Wyrażenia i instrukcje, złożoność obliczeniowa

Algorytm poprawny jednoznaczny szczegółowy uniwersalny skończoność efektywność (sprawność) zmiennych liniowy warunkowy iteracyjny

Podstawowe elementy programu. patrz: następne 2 slajdy. Podstawowe elementy programu. Komendy proste:

WHILE (wyrażenie) instrukcja;

Algorytmika i programowanie. dr inż. Barbara Fryc Wyższa Szkoła Informatyki i Zarządzania w Rzeszowie

Grafy (3): drzewa. Wykłady z matematyki dyskretnej dla informatyków i teleinformatyków. UTP Bydgoszcz

ZASADY PROGRAMOWANIA KOMPUTERÓW ZAP zima 2014/2015. Drzewa BST c.d., równoważenie drzew, kopce.

Programowanie strukturalne i obiektowe. Funkcje

3. Wykład 3: Dowody indukcyjne, strategie dowodowe Dowody indukcyjne. Dotychczas zobaczyliśmy w jaki sposób można specyfikować definicje

Metoda tabel semantycznych. Dedukcja drogi Watsonie, dedukcja... Definicja logicznej konsekwencji. Logika obliczeniowa.

... [a n,b n ] kn [M 1,M 2 ], gdzie a i M 1, b i M 2, dla i {1,..., n}. Wówczas: [a 1,b 1 ] k [a n,b n ] kn =(a 1 b 1 a 1

Instrukcje sterujące

Za pierwszy niebanalny algorytm uważa się algorytm Euklidesa wyszukiwanie NWD dwóch liczb (400 a 300 rok przed narodzeniem Chrystusa).

Obóz Naukowy Olimpiady Matematycznej Gimnazjalistów

Pętle i tablice. Spotkanie 3. Pętle: for, while, do while. Tablice. Przykłady

PODSTAWY INFORMATYKI 1 PRACOWNIA NR 6

Drzewa wyszukiwań binarnych (BST)

Programowanie w języku C++ Grażyna Koba

LX Olimpiada Matematyczna

Matematyka dyskretna. Andrzej Łachwa, UJ, a/15

Algorytmy i struktury danych. Wykład 4

Zasada indukcji matematycznej

Algorytm. Krótka historia algorytmów

Algorytmika i programowanie. Wykład 2 inż. Barbara Fryc Wyższa Szkoła Informatyki i Zarządzania w Rzeszowie

TEORETYCZNE PODSTAWY INFORMATYKI

Podstawy Programowania C++

Wysokość drzewa Głębokość węzła

Matematyka dyskretna. Andrzej Łachwa, UJ, /15

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

REKURENCJA W JĘZYKU HASKELL. Autor: Walczak Michał

Teoretyczne podstawy informatyki

Podstawy programowania 2. Temat: Drzewa binarne. Przygotował: mgr inż. Tomasz Michno

Wstęp do programowania. Drzewa podstawowe techniki. Piotr Chrząstowski-Wachtel

Podstawy programowania. Wykład: 13. Rekurencja. dr Artur Bartoszewski -Podstawy programowania, sem 1 - WYKŁAD

Podstawy Programowania

Języki programowania zasady ich tworzenia

Programowanie komputerowe. Zajęcia 2

Anatomia definicji rekursywnej. Anatomia definicji rekursywnej. int silnia(intn){ if(n==0) return 1; else return n*silnia(n-1); }

FUNKCJA REKURENCYJNA. function s(n:integer):integer; begin if (n>1) then s:=n*s(n-1); else s:=1; end;

4 Klasyczny rachunek zdań

F t+ := s>t. F s = F t.

Indukcja matematyczna. Matematyka dyskretna

Znaleźć wzór ogólny i zbadać istnienie granicy ciągu określonego rekurencyjnie:

Strategia "dziel i zwyciężaj"

Andrzej Wiśniewski Logika I Materiały do wykładu dla studentów kognitywistyki. Wykład 10. Twierdzenie o pełności systemu aksjomatycznego KRZ

Język C zajęcia nr 5

Wprowadzenie do algorytmiki

Informacje wstępne #include <nazwa> - derektywa procesora umożliwiająca włączenie do programu pliku o podanej nazwie. Typy danych: char, signed char

E-learning - matematyka - poziom rozszerzony. Funkcja wykładnicza. Materiały merytoryczne do kursu

Klasa 2 INFORMATYKA. dla szkół ponadgimnazjalnych zakres rozszerzony. Założone osiągnięcia ucznia wymagania edukacyjne na. poszczególne oceny

Matematyka dyskretna - 7.Drzewa

Matematyka dyskretna. Andrzej Łachwa, UJ, /14

Transkrypt:

Poprawność składniowa Poprawność semantyczna Poprawność algorytmu Wypisywanie zdań z języka poprawnych składniowo Poprawne wartościowanie zdań języka, np. w języku programowania skutki wystąpienia wyróżnionych części programu, jak definicje typów, deklaracje stałych i zmiennych, zmian wartościowania zmiennych będących instrukcjami programu.

Algorytm jako napis może być poprawny składniowo, ale niepoprawny semantycznie, co jest równoznaczne z niemożnością poprawnego deklarowania i wartościowania zmiennych. Powody: w wyrażeniu występuje argument nie należący do typu związanego z tym wyrażeniem (np. w wyniku działania funkcji otrzymujemy liczbę rzeczywistą, a funkcja miała zwracać wartości całkowite); wystąpienie w algorytmie pętli o wyrażeniu logicznym stale wartościowanym jako prawdziwe (pętla będzie wykonywana bez końca); końcowe wartościowanie zmiennych nie odpowiada oczekiwaniom (program poprawnie kończy obliczenia, ale wyniki nie rozwiązują postawionego zadania).

Niech A oznacza algorytm-program, -warunek (warunki), jakie powinny spełniać dane wejściowe (początkowe wartościowania zmiennych) algorytmu A, -warunek, jaki powinny spełniać końcowe wartościowania zmiennych (własności danych wyjściowych i ich związek z danymi wejściowymi)

Semantyczna poprawność nazywana jest też inaczej pełną poprawnością. Dowodzenie jest trudne. Niekiedy zadowalamy się sprawdzeniem elementów tej definicji. Częściowa semantyczna poprawność Własność określoności dla warunku początkowego Własność stopu Semantyczna poprawność

Definicje elementów:

Dowodzenie Indukcja Definicja 1 Metoda niezmienników Częściowa poprawność Własność stopu

W dowodzeniu indukcyjnym semantycznej poprawności algorytmu przeprowadza się zwykle indukcję względem liczby powtórzeń instrukcji iteracyjnej lub poziomu zagnieżdżenia realizacji procedury rekurencyjnej. Przykład. Rozważmy algorytm przeszukiwania drzewa binarnego DB zadanego przez wskaźnik na korzeń DB określonego przez zmienną typu el_drzewa zdefiniowanego następująco: struct element { int wartosc; element *pien; element *konar_lewy; element *konar_prawy; } typedef element, *el_drzewa;

struct element { int wartosc; element *pien; element *konar_lewy; element *konar_prawy; } typedef element, *el_drzewa; int preorder (el_drzewa korzen, int x) { //{ : korzen!=null} int pom=0; if ((*korzen).wartosc==x) return 1; if ((*korzen).konar_lewy!=null) //2 pom=preorder((*korzen).konar_lewy,x); if (pom) return 1; //3 else if ((*korzen).konar_prawy!=null) //4 pom=preorder((*korzen).konar_prawy,x); if (pom) return 1; //5 else return 0; //{ : funkcja zwraca 1, gdy "x jest elementem drzewa"}, // zwraca 0, gdy "x nie jest elementem drzewa".} } Rozważmy następujący algorytm przeszukiwania drzewa binarnego:

Dowód przeprowadzimy indukcyjnie względem parametru określającego wysokość drzewa. Oznaczmy wysokość drzewa przez wd. Dla dowodu poprawności semantycznej algorytmu preorder sformułujmy własność: Własność. Dla dowolnego drzewa binarnego o wysokości wd będącej liczbą naturalną wd>0, algorytm preorder dla danych spełniających w skończonej liczbie kroków dochodzi do wartościowania końcowego i to wartościowanie spełnia.

Dowód: Przeprowadzimy go metodą indukcji matematycznej. Krok 1 sprawdzenie poprawności algorytmu dla początkowej wartości. Należy pokazać, że preorder(korzen) poprawnie określa wynik końcowy dla dowolnego drzewa binarnego o określonym adresie korzenia i wysokości wd=1. Istotnie, jeśli (*korzen).wartosc==x, to nastąpi koniec wartościowania funkcji i wartością funkcji będzie 1, co będzie oznaczać zajście. Jeśli (*korzen).wartosc!=x, to wobec i założenia, że wd=1 mamy (*korzen).konar_lewy==null oraz (*korzen).konar_prawy==null. Zatem wobec początkowego wartościowania zmiennej pom=0, nie wykona się żadna z pięciu instrukcji warunkowych i funkcja zwróci 0, co będzie oznaczało zajście. Ponieważ jedynym miejscem elementem w drzewie, gdzie może znajdować się pole wartościujące równe x jest pole korzenia, zatem dla wd=1 program jest semantycznie poprawny.

Krok2 założenie i teza indukcyjna z dowodem. Zał. ind. Załóżmy, że algorytm preorder jest poprawnie określony dla drzew binarnych o wysokości wd<=n. Teza. ind. Udowodnimy, że jest wtedy poprawnie określony dla drzew binarnych o wysokości wd=n+1.

Istotnie. Rozważmy drzewo binarne o wysokości wd=n+1. Jeśli (*korzen).wartosc==x, to nastąpi koniec wartościowania funkcji i wartością będzie 1, co oznacza zajście. Jeśli (*korzen).wartosc!=x, to nastąpi ewentualne wykonanie kolejnych instrukcji programu (2,3,4,5). Wobec założenia indukcyjnego, ponieważ lewe i prawe poddrzewo drzewa o wysokości n+1, będą drzewami o wysokościach mniejszych lub równych n, więc instrukcje 2,3,4 zostaną wykonane poprawnie i spowodują wartościowanie funkcji spełniające. Instrukcja 5 dokona wartościowania funkcji jako 0, jeśli x nie będzie elementem lewego i prawego poddrzewa, czyli nie będzie elementem drzewa. Zatem wartością funkcji będzie 1, gdy x jest elementem drzewa, 0 gdy nie jest elementem drzewa, co oznacza zajście.

Zatem na mocy zasady indukcji matematycznej ma miejsce teza własności dla drzew binarnych o dowolnej wysokości wd, co jest równoważne całkowitej poprawności semantycznej algorytmu preorder wobec definicji 1.

Przykład. Algorytm obliczający wartość wyrażenia 2 n +1 int POTEGA_2(int n) { // : n>=0 if((n==0) (n==1)) return n+2; return 3*POTEGA_2(n-1)-2*POTEGA_2(n-2); } // : wartością funkcji jest 2 n +1. Przykład algorytmu rekurencyjnego (poprzedni też taki był)

Dowód przeprowadzimy indukcyjnie względem parametru n określającego wykładnik potęgi 2. Dla dowodu poprawności semantycznej algorytmu POTEGA_2 sformułujmy własność: Własność. Dla dowolnego wykładnika potęgi o podstawie 2 będącego liczbą naturalną n>=0, algorytm POTEGA_2 dla danych spełniających w skończonej liczbie kroków dochodzi do wartościowania końcowego i to wartościowanie spełnia.

Dowód: Przeprowadzimy go metodą indukcji matematycznej. Krok 1 sprawdzenie poprawności algorytmu dla początkowej wartości. Należy pokazać, że POTEGA_2(n) poprawnie określa wynik końcowy dla potęgi o podstawie 2 i wykładniku n=0 lub n=1. Istotnie, jeśli n=0, to zachodzi warunek if((n==0) (n==1)) i nastąpi koniec wartościowania funkcji i wartością funkcji będzie n+2, czyli 2, co będzie oznaczać zajście. Jeśli natomiast n=1, to również zachodzi warunek if((n==0) (n==1)) i nastąpi koniec wartościowania funkcji i wartością funkcji będzie również n+2, czyli 3, co także będzie oznaczać zajście. Zatem dla n=0 lub n=1 program jest semantycznie poprawny.

Krok2 założenie i teza indukcyjna z dowodem. Zał. ind. Załóżmy, że algorytm POTEGA_2 jest poprawnie określony dla potęgi o podstawie 2 i wykładniku k<=n, n=1,2,3. Teza. ind. Udowodnimy, że jest wtedy poprawnie określony dla potęgi o wykładniku n+1.

Istotnie. Rozważmy potęgę o podstawie 2 i wykładniku n+1. Ponieważ n+1>1, to POTEGA_2(n+1) zwróci wartościowanie funkcji spełniające 3*POTEGA_2 ((n+1)-1)-2*potega_2((n+1)-2). Policzmy: 3*POTEGA_2((n+1)-1)-2*POTEGA_2((n+1)-2)=3*POTEGA_2(n)-2*POTEGA_2(n-1). Wobec założenia indukcyjnego, ponieważ POTEGA_2(n) i POTEGA_2 (n-1) będą funkcjami obliczającymi wartość potęgi dla wykładników mniejszych lub równych n, więc zostaną wykonane poprawnie i spowodują wartościowanie funkcji spełniające. Zatem POTEGA_2(n) zwróci 2 n +1, a POTEGA_2(n-1) zwróci 2 n-1 +1. Możemy więc napisać: 3*POTEGA_2 ((n+1)-1)-2*potega_2 ((n+1)-2)= =3*POTEGA_2 (n)-2*potega_2 (n-1) = =3*(2 n +1)-2*(2 n-1 +1) =3*2 n +3-2 n -2=2*2 n +1=2 n+1 +1, co oznacza zajście.

Zatem na mocy zasady indukcji matematycznej ma miejsce teza własności dla algorytmu POTEGA_2 dla dowolnego wykładnika potęgi n, co jest równoważne całkowitej poprawności semantycznej algorytmu POTEGA_2 wobec definicji 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ć:

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.

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

Przykład 1. Algorytm NWD Euklidesa. Zapis w pseudokodzie Jak znaleźć niezmiennik pętli?

Najpierw należy pokazać, że

Ćwiczenie

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<y. Pokażemy, że algorytm ten jest częściowo poprawny względem warunku początkowego i końcowego.

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.

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; z pętli r=r-y; }; } // : x=q*y+r i 0<=r<y. bezpośrednio z początku algorytmu Możemy dojść do p dwiema drogami:

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<y. 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.

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<y. 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!