Matematyka Dyskretna. Andrzej Szepietowski. 25 czerwca 2002 roku

Podobne dokumenty
Podstawy Informatyki. Algorytmy i ich poprawność

Poprawność semantyczna

Wstęp do Programowania potok funkcyjny

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

Poprawność algorytmów

Wykład 4. Określimy teraz pewną ważną klasę pierścieni.

2.8. Algorytmy, schematy, programy

Programowanie w Turbo Pascal

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

TEMAT: Podejmowanie decyzji w programie instrukcja warunkowa (IF).

Algorytmy i struktury danych. Wykład 4

W. Guzicki Próbna matura, grudzień 2014 r. poziom rozszerzony 1

Ogólne zasady projektowania algorytmów i programowania

Wykład 6. Reguły inferencyjne systemu aksjomatycznego Klasycznego Rachunku Zdań

Zadania do samodzielnego rozwiązania

Wstęp do programowania

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

Algorytm - pojęcie algorytmu, sposób zapisu, poziom szczegółowości, czynności proste i strukturalne. Pojęcie procedury i funkcji.

Zapisywanie algorytmów w języku programowania

Języki programowania zasady ich tworzenia

Elżbieta Kula - wprowadzenie do Turbo Pascala i algorytmiki

Paradygmaty programowania

Algorytm. a programowanie -

Wykład 8. Rekurencja. Iterować jest rzeczą ludzką, wykonywać rekursywnie boską. L. Peter Deutsch

Programowanie i techniki algorytmiczne

Język programowania PASCAL

Wprowadzenie do algorytmiki

Wykład 11a. Składnia języka Klasycznego Rachunku Predykatów. Języki pierwszego rzędu.

Logarytmy. Funkcje logarytmiczna i wykładnicza. Równania i nierówności wykładnicze i logarytmiczne.

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

Definicje. Algorytm to:

Pascal - wprowadzenie

1. Wykład NWD, NWW i algorytm Euklidesa.

Zasada indukcji matematycznej

Wykład 2. Poprawność algorytmów

Andrzej Wiśniewski Logika II. Wykład 6. Wprowadzenie do semantyki teoriomodelowej cz.6. Modele i pełność

JAO - Wprowadzenie do Gramatyk bezkontekstowych

Definicja algorytmu brzmi:

(1) Poprawność Algorytmów

Przeszukiwanie z nawrotami. Wykład 8. Przeszukiwanie z nawrotami. J. Cichoń, P. Kobylański Wstęp do Informatyki i Programowania 238 / 279

Algorytmy. Programowanie Proceduralne 1

1 Wprowadzenie do algorytmiki

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

WHILE (wyrażenie) instrukcja;

Funkcja kwadratowa. f(x) = ax 2 + bx + c = a

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

INSTRUKCJA PUSTA. Nie składa się z żadnych znaków i symboli, niczego nie robi. for i := 1 to 10 do {tu nic nie ma};

Matematyka dyskretna. Andrzej Łachwa, UJ, /14

Procedury i funkcje - powtórzenie i uzupełnienia. Przykład funkcji potęgowanie przy wykładniku naturalnym

Algorytm. Krótka historia algorytmów

Funkcja kwadratowa. f(x) = ax 2 + bx + c,

Matematyka dyskretna

Algorytmy od problemu do wyniku

Algorytmy i struktury danych

Temat 20. Techniki algorytmiczne

Zapis algorytmów: schematy blokowe i pseudokod 1

Schemat rekursji. 1 Schemat rekursji dla funkcji jednej zmiennej

Algorytmy. Programowanie Proceduralne 1

Wykład IV Algorytmy metody prezentacji i zapisu Rzut oka na język PASCAL

O geometrii semialgebraicznej

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Podstawy Programowania

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

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

Programowanie komputerów

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

Indukcja matematyczna

WHILE (wyrażenie) instrukcja;

1 Podstawy c++ w pigułce.

WIADOMOŚCI WSTĘPNE WPROWADZENIE DO JĘZYKA TURBO PASCAL. Klawisze skrótów. {to jest właśnie komentarz, moŝna tu umieścić dowolny opis}

START. Wprowadź (v, t) S:=v*t. Wyprowadź (S) KONIEC

Matematyka dyskretna. Andrzej Łachwa, UJ, /10

Podprogramy. Procedury

Wykład 1. Na początku zajmować się będziemy zbiorem liczb całkowitych

Dwa równania kwadratowe z częścią całkowitą

Technologie informacyjne - wykład 12 -

Wykład z równań różnicowych

Pierścień wielomianów jednej zmiennej

Analiza algorytmów zadania podstawowe

przedmiot kilka razy, wystarczy kliknąć przycisk Wyczaruj ostatni,

Wyszukiwanie. Wyszukiwanie binarne

W. Guzicki Zadanie IV z Informatora Maturalnego poziom rozszerzony 1

Paradygmaty dowodzenia

LISTA 5. C++ PETLE for, while, do while

//warunki początkowe m=500; T=30; c=0.4; t=linspace(0,t,m); y0=[-2.5;2.5];

Luty 2001 Algorytmy (7) 2000/2001

LX Olimpiada Matematyczna

Testy jednostkowe Wybrane problemy testowania metod rekurencyjnych

Programowanie w Baltie klasa VII

Matematyka dyskretna dla informatyków

Obliczenia iteracyjne

Twierdzenia Rolle'a i Lagrange'a

Przykładowe zadania z teorii liczb

Metody numeryczne I Równania nieliniowe

Podstawy Informatyki. Inżynieria Ciepła, I rok. Iteracja warunkowadopóki(while) Blok instrukcji. Pascal: begin instrukcja1; C: { end;

FUNKCJE. (odwzorowania) Funkcje 1

do instrukcja while (wyrażenie);

Podstawy programowania Laboratorium. Ćwiczenie 2 Programowanie strukturalne podstawowe rodzaje instrukcji

1 Metody rozwiązywania równań nieliniowych. Postawienie problemu

W wielu obliczeniach w matematyce bądź fizyce wykonanie niektórych kroków zależy od spełnienia warunku.

Transkrypt:

Matematyka Dyskretna Andrzej Szepietowski 25 czerwca 2002 roku

Rozdział 1 Poprawność programów Jeżeli projektujemy algorytmy lub piszemy programy, to ważne jest pytanie, czy nasz algorytm lub program jest poprawny, czy nie zawiera błędów. Konkretniej, możemy spytać, czy nasz program jest napisany zgodnie z regułami języka programowania i czy liczy to, co chcemy. 1.1 Poprawność syntaktyczna Jeżeli program jest napisany zgodnie z regułami języka programowania, to mówimy, że jest poprawny pod względem syntaktycznym, a wykroczenia przeciwko składni języka nazywają się błędami syntaktycznymi. Przykładami takich błędów w języku Pascal są: użycie zmiennej, która wcześniej nie została zadeklarowana, lub postawienie średnika przed słowem else w instrukcji warunkowej. Poprawność syntaktyczna nie jest wielkim problemem. Języki programowania mają bardzo ścisłe reguły składni, określające, jak budować poprawne programy, i konstruktorzy tych języków zadbali o to, aby można było łatwo wykryć błędy syntaktyczne. Istnieją kompilatory, które automatycznie sprawdzają poprawność syntaktyczną programów. Kompilatory niektórych języków są dość skomplikowanymi programami i oprócz komunikatu o błędzie dają także wskazówki, jak błąd usunąć. 1.2 Poprawność semantyczna Dużo poważniejszym problemem jest poprawność semantyczna, czyli stwierdzenie, czy program lub algorytm liczy to, co powinien. Problem zaczyna się już wówczas, gdy spytamy, co to znaczy liczy to, co powinien. Zajmiemy się teraz jednym z możliwych podejść do problemu poprawności. Program przekształca dane wejściowe w dane wyjściowe i dlatego możemy go traktować jak funkcję ze zbioru danych wejściowych w zbiór danych wyjściowych. Na przykład dla algorytmu Euklidesa (porównaj rozdział o teorii liczb) danymi wejściowymi są pary liczb 3

4 Rozdział 1. Poprawność programów naturalnych, a danymi wyjściowymi są pojedyncze liczby naturalne. W algorytmie sortującym danymi wejściowymi i wyjściowymi są ciągi liczb. Żeby określić co program robi definiuje się warunki: jeden warunek mówi, jakie powinny być dane wejściowe, a drugi warunek określa, jakie powinny być dane wyjściowe. Problem algorytmiczny możemy więc zdefiniować przez podanie: zbioru danych wejściowych, zbioru danych wyjściowych, predykatu (funkcji zdaniowej), który określa warunki początkowe; przyjmuje wartość prawda, jeżeli dane wejściowe są poprawnie zbudowane, predykatu, który określa relację pomiędzy danymi wyjściowymi i wejściowymi; ma wartość prawda, jeżeli dane wyjściowe są prawidłową odpowiedzią algorytmu na dane wejściowe. W przykładzie algorytmu Euklidesa: dane wejściowe to pary liczb naturalnych, dane wyjściowe to zbiór liczb naturalnych warunek początkowy!#"%$ &('*)+,"-$., relacja!/01324 określa, że 2 jest największym wspólnym dzielnikiem liczb i. Zadanie algorytmiczne sortowania może być zdefiniowane w następujący sposób (dla prostoty zakładamy, że sortujemy ciągi różnowartościowe): i to zbiory wszystkich ciągów długości 5, warunek mówi, że ciąg jest różnowartościowy: 67 98;:=<>?@A< BC >ED warunek G określa, że ciąg jest rosnący i zawiera dokładnie te same elementy co ciąg : G 7 98G:0< > < BH*:0<*@A<B /> 1@, F@1Ä and 8;:=<><B4I;:6(>KJL.>NM:O =P Takiego typu warunki nazywają się specyfikacją algorytmu lub programu. Jednym słowem, specyfikacja mówi nam, co program ma robić. Program działa poprawnie, jeżeli dla każdych danych wejściowych, spełniających warunek wejściowy, daje wynik, który spełnia warunek wyjściowy G3F. Zwykle dowód poprawności programu rozbija się na dwa poddowody. Osobno dowodzi się poprawności przy założeniu, że program zawsze się zatrzyma, a osobno dowodzi się, że program zatrzymuje się dla każdych poprawnie zbudowanych danych wejściowych.

1.3. Niezmienniki 5 Definicja 1.1 Program jest częściowo poprawny względem warunków i, gdy dla każdych danych wejściowych spełniajacych zachodzi następująca implikacja: jeżeli program zatrzymuje się na danych i daje wynik, to zachodzi warunek G3F. Program jest całkowicie poprawny, jeżeli jest częściowo poprawny i ponadto zatrzymuje się dla każdych danych wejściowych spełniających warunek. Jedną z metod dowodzenia częściowej poprawności programu jest metoda niezmienników lub asercji indukcyjnych. 1.3 Niezmienniki Metoda niezmienników polega na wyznaczeniu w programie kilku punktów kontrolnych i związaniu z tymi punktami asercji, czyli pewnych warunków. Wśród punktów kontrolnych dwa są szczególne: jeden punkt zaraz na początku programu z asercją początkową i jeden punkt na końcu programu z asercją końcową. Asercja początkowa zwykle zawiera sformułowania obejmujące warunki na dane początkowe. Asercja końcowa opisuje relację wiążącą dane wejściowe z wyjściowymi. Po wyznaczeniu punktów i asercji dowodzimy, że każda asercja jest spełniona zawsze wtedy, gdy wykonanie programu dojdzie do odpowiadającego jej punktu kontrolnego. W ten sposób dowodzimy, że jeżeli na początku był spełniony warunek początkowy i potem program dojdzie do punktu końcowego, to będzie spełniony warunek. Dowód poprawności może przebiegać w ten sposób, że dla poszczególnych par punktów kontrolnych i (niekoniecznie różnych) dowodzimy następującą implikację: jeżeli w punkcie spełniona jest asercja, a następnie wykonanie programu przejdzie z punktu do, to w punkcie będzie spełniona asercja. Niektóre punkty kontrolne mogą być w trakcie wykonywania programu osiągane wielokrotnie (na przykład punkty znajdujące się wewnątrz pętli). Tak więc asercja powinna być spełniona za każdym odwiedzeniem punktu kontrolnego. Z tego powodu asercje te nazywamy niezmiennikami. Sposób rozmieszczenia punktów kontrolnych i przypisania tym punktom asercji nie jest prosty i nie ma uniwersalnych reguł w tym względzie. Podobnie jak z dowodzeniem twierdzeń, sposób dowodu poprawności programu jest oryginalnym pomysłem autora dowodu. Istnieją w tym względzie pewne reguły heurystyczne, niektóre nawet bardzo złożone, ale nie ma uniwersalnych reguł, które pozwolą udowodnić poprawność lub niepoprawność każdego programu. 1.4 Liczniki Aby udowodnić, że algorytm zawsze się zatrzyma, możemy użyć liczników. Najpierw, podobnie jak poprzednio, wyznaczamy punkty kontrolne i pewną zmienną, zwaną licznikiem lub zbieżnikiem, która może przyjmować tylko wartości całkowite nieujemne. Następnie dowodzimy, że po każdym odwiedzeniu jakiegoś punktu kontrolnego wartość licznika maleje.

6 Rozdział 1. Poprawność programów Nie ma miejsca w tej książce na rozwijanie teorii dowodzenia poprawności programu. Zajmiemy się tylko dwoma przykładami. Pierwszy to algorytm Euklidesa, który był przedstawiony w rozdziale z teorii liczb i tam też przedstawiono dowód jego poprawności. Teraz tylko sformułujemy go w języku asercji. 1.5 Algorytm Euklidesa jeszcze raz Oto jeszcze raz algorytm Euklidesa opisany w języku Pascal: var a,b,p,q:integer; begin readln(a,b); {A} p:=a;q:=b; while p<>q do {C} if p>q then p:=p-q else q:=q-p; {B} writeln( NWD(,a,,,b, )=,p) end. W programie umieściliśmy trzy punkty kontrolne. Punkt na początku, zaraz za instrukcją readln(a,b). Asercja związana z punktem orzeka, że i to dwie dodatnie liczby całkowite. Punkt znajduje się na końcu programu, tuż przed instrukcją writeln. Asercja związana z tym punktem orzeka, że zawiera największy wspólny dzielnik liczb i. Trzeci punkt kontrolny jest wewnątrz pętli, tuż przed instrukcją warunkową if. Asercja orzeka, że para liczb i ma taki sam największy wspólny dzielnik co para i. Dowodzimy cztery implikacje: jeżeli wykonanie programu jest w punkcie i spełniona jest asercja, a następnie program przejdzie do punktu, to spełniona będzie asercja, jeżeli wykonanie programu jest w punkcie i spełniona jest asercja, a następnie program ponownie przejdzie do punktu, to spełniona będzie asercja, jeżeli wykonanie programu jest w punkcie i spełniona jest asercja, a następnie program przejdzie do punktu, to spełniona będzie asercja, jeżeli wykonanie programu jest w punkcie i spełniona jest asercja, a następnie program przejdzie do punktu, to spełniona będzie asercja.

D 1.6. Potęgowanie 7 Naszkicujmy tylko dowód drugiej implikacji, pozostałe dowodzi się podobnie. Załóżmy, że wykonanie programu znajduje się w punkcie i że zmienne i mają wtedy wartości : i :. Jeżeli w wyniku dalszego wykonania program ponownie dojdzie do punktu, to znaczy, że : :, bez straty ogólności możemy założyć, że : " :. Wtedy nowe wartości zmiennych i mają wartości : : oraz :. Z faktu, że wartości : i : spełniają asercję E : :, wynika, że para : i : ma taki sam największy wspólny dzielnik jak para wejściowa i. W rozdziale o teorii liczb pokazano, że para ma taki sam zbiór wspólnych dzielników jak para : :. Tak więc także para ma taki sam największy wspólny dzielnik jak para, więc spełnia asercję. Aby pokazać, że program zatrzymuje się dla każdych danych spełniających warunek #" $, wprowadzimy licznik dla punktu kontrolnego. Licznikiem tym jest wartość &. Jest jasne, że wartość licznika jest zawsze liczbą całkowitą nieujemną i że zmniejsza się przy każdym ponownym odwiedzeniu punktu. Wykonanie programu nie może więc trwać w nieskończoność. 1.6 Potęgowanie Drugim przykładem niech będzie program na podnoszenie liczby dwa do potęgi 5. var n,x,y:integer; begin readln(n); {A} y:=1; x:=n; while x>0 do begin {C} x:=x-1; y:=y+y end; {B} writeln(y) end. na początku, zaraz za instruk- W tym programie też są trzy punkty kontrolne. Punkt cją readln, z asercją: Punkt 5%$.ÄP na końcu programu, tuż przed instrukcją writeln, z asercją: B L ÄP Trzeci punkt kontrolny jest wewnątrz pętli, tuż przed instrukcją x:=x-1, z asercją: B =P

8 Rozdział 1. Poprawność programów Dowód poprawności programu polega teraz na dowodzie tych samych czterech implikacji, które znajdują się w podrozdziale 10.5. Aby udowodnić, że program zawsze się zatrzyma, wystarczy jako licznik przyjąć zmienną, która przyjmuje wartości nieujemne i zmniejsza swoją wartość przy każdym kolejnym odwiedzeniu punktu. 1.7 Czekery W przypadku gdy udowodnimy, że jakiś program działa poprawnie, wówczas mamy pewność, że dla każdych danych wejściowych uzyskany wynik będzie dobry. Inną metodą sprawdzania, że program działa poprawnie, są czekery. Zamiast dowodzić, że program zawsze zadziała dobrze, czekery sprawdzają, czy zadziałał on dobrze w konkretnych przypadkach. Do zadania algorytmicznego projektowane są dwa programy. Program główny, który rozwiązuje zadanie, oraz program, zwany czekerem lub weryfikatorem, który po każdym zadziałaniu programu sprawdza, czy odpowiedź programu jest poprawna. Zakłada się przy tym, że działanie czekera jest dużo prostsze niż działanie programu. W dodatku program może być traktowany jak czarna skrzynka, gdzie nie mamy wglądu w to, jak program działa, tylko dostajemy ostateczne odpowiedzi. Przyjrzyjmy się pomysłowi czekerów na przykładach. Weźmy znowu algorytm Euklidesa, ale teraz wygodniej jest wziąć wersję, gdzie pro- gram bierze parę liczb i i zwraca trzy liczby: 2. 0 sprawdzić, czy 2 dzieli i, oraz czy!a oraz i, takie że 2. Żeby sprawdzić, czy program dobrze obliczył dane wyjściowe, wystarczy O - Inny przykład to czeker dla programu obliczającego zaokrąglenie w górę pierwiastka kwadratowego z liczby naturalnej 5. Przykład takiego programu przedstawiono w rozdziale 3.5. Jeżeli program główny oblicza dla wartości wejściowej 5 wartość wyjściową, to zadanie czekera polega na sprawdzeniu dwóch rzeczy, czy L5 2/P oraz czy JL5KP 1.8 Zadania 1. Udowodnij poprawność programu (przedstawionego w podrozdziale 6.6), który dla danych liczb, " $ oblicza równość / A. A oraz liczby całkowite, spełniające