Program, który się uczy.

Transkrypt

Program, który się uczy.
Program, który się uczy.
Korzystając z omówionych poleceń, jesteśmy w stanie zaprojektować program, który nauczy się nowych informacji do swojej bazy wiedzy, a także zapisze je w taki sposób, aby mogły być dostępne w następnej sesji.
W skrócie, program działa następująco:
1. Wczytujemy bazę wiedzy poprzez reconsult
2. Wywołujemy funkcję która pyta o kraj i wczytujemy tekst z klawiatury (read).
3. W przypadku otrzymania ciągu znakowego „stop.” program przełącza się w zapis do pliku bazy wiedzy (tell), następuje listing predykatów, told zamyka plik i kończy się działanie programu.
4. W zależności od tego, czy podany kraj jest już w naszej bazie, wyświetlamy jego stolicę lub pytamy o nią, dopisując nową informację poprzez assertz.
5. Przechodzimy ponownie do kroku drugiego.
Program, który się uczy.
Kod programu:
start :- reconsult('baza.pl'), nl,
write('Podaj nazwę kraju z małej litery i z kropką na
końcu.'), nl,
write('Napisz "stop." aby przerwać działanie
programu.'), nl, nl,
zapytanie.
zapytanie :- write('Kraj? '),
read(Kraj),
odpowiedz(Kraj).
odpowiedz(stop) :- write('Zapisywanie bazy wiedzy...'), nl,
tell('baza.pl'),
listing(stolica),
told,
write('Gotowe!'),nl.
Program, który się uczy.
Kod programu (c.d.):
odpowiedz(Kraj) :- stolica(Kraj,Miasto),
write('Stolicą '),
write(Kraj),
write(' jest '),
write(Miasto),nl,
nl,
zapytanie.
odpowiedz(Kraj) :- \+ stolica(Kraj,_),
write('Nie znam stolicy tego kraju.'),nl,
write('Proszę, podaj mi ją!'),nl,
write('Stolica? '),
read(Miasto),
write('Dziękuję.'),nl,nl,
assertz(stolica(Kraj,Miasto)),
zapytanie.
Program, który się uczy.
Przykładowe wywołanie programu.
Podaj nazwę kraju z małej litery i z kropką na końcu.
Napisz "stop." aby przerwać działanie programu.
Kraj? polska.
Stolicą polska jest warszawa
Kraj? dania.
Stolicą dania jest kopenhaga
Kraj? rosja.
Nie znam stolicy tego kraju.
Proszę, podaj mi ją!
Stolica? moskwa.
Dziękuję.
Kraj? rosja.
Stolicą rosja jest moskwa
Kraj? stop.
Zapisywanie bazy wiedzy...
Gotowe!
true Wejście/wyjście znaków (get, get0, put)
Wbudowany predykat put wyświetla znak ASCII podany jako liczbę. Przykład:
?- put(42).
*
True.
Przeciwieństwem put jest get który pobiera znak od użytkownika i wyświetla jego liczbową reprezentację. Przykład:
?- get(X).
|: Ę
X = 280.
Wejście/wyjście znaków (get, get0, put)
W zależności od interpretera Prologa, program może się zachowywać w dwa sposoby. Pierwszym z nich jest wczytanie buforowane. Znak zostanie odczytany dopiero po wciśnięciu i zatwierdzeniu go klawiszem enter.
W przypadku wejścia klawiatury, które nie jest buforowane, znak zostanie wczytany bezpośrednio po jego wciśnięciu.
Predykat get automatycznie opuszcza znaki puste, nowej linii (enter), lub inne które są znakami specjalnymi, których się nie da wyświetlić. Jeżeli chcemy wczytać dowolny znak, istnieje dodatkowy predykat get0. Przykład:
?- get0(X), get0(Y).
|: Ω
X = 937,
Y = 10.
Znak nowej linii \n (10) jest poprzedzony znakiem omega (w reprezentacji UTF­8).
Wejście/wyjście znaków (get, get0, put)
Tablica znaków ASCII (7­bit)
Wejście/wyjście znaków (get, get0, put)
Standard ISO definiuje jedynie put_code (odpowiednik put) oraz get_code (odpowiednik get0).
Predykat get, może być zdefiniowany w sposób następujący:
get(Code) :- repeat, get_code(Code), Code>32, !.
Zgodnie z tablicą kodów ASCII pomijamy znaki o wartości mniejszej lub równej 32.
Tworzenie menu wyboru
Dzięki funkcji wczytującej znak od użytkownika, możemy napisać proste menu wyboru. Oto przykładowy kod:
stolica(polska, warszawa).
stolica(niemcy, berlin).
stolica(szwecja, sztokholm).
stolica(dania, kopenhaga).
start :-
pokaz_menu,
pobierz_z_menu(Stolica),
stolica(Stolica,Miasto),
nl,
write('Stolicą '),
write(Stolica),
write(' jest '),
write(Miasto),
nl.
pokaz_menu :- write('O jakim kraju chcesz się dowiedzieć?'),nl,
write(' 1 Polska'), nl,
write(' 2 Niemcy'), nl,
write(' 3 Szwecja'), nl,
write(' 4 Dania'), nl,
write('Podaj liczbe od 1 do
4 -- ').
Tworzenie menu wyboru
Kod (c.d.)
pobierz_z_menu(Stolica) :- get(Code), % wczytaj znak
get0(_),
% opuść znak nowej linii
interpretuj(Code,Stolica).
interpretuj(49,polska).
interpretuj(50,niemcy)
.
interpretuj(51,szwecja).
interpretuj(52,dania).
/*
/*
/*
/*
ASCII
ASCII
ASCII
ASCII
49
50
51
52
Przykładowe wywołanie:
?- start.
O jakim kraju chcesz się dowiedzieć?
1 Polska
2 Niemcy
3 Szwecja
4 Dania
Podaj liczbe od 1 do 4 -- 1
Stolicą polska jest warszawa
true.
=
=
=
=
'1'
'2'
'3'
'4'
*/
*/
*/
*/
Tworzenie menu wyboru
Inne prostsze menu „Tak lub Nie” można zaimplementowane następująco:
tak_lub_nie(Result) :- get(Char),
get0(_),
interpret(Char,Result),
!.
% wczytaj znak
tak_lub_nie(Result) :- nl,
write('Y czy N?:'),
tak_lub_nie(Result).
interpret(89,yes).
interpret(121,yes).
interpret(78,no).
interpret(110,no).
%
%
%
%
ASCII
ASCII
ASCII
ASCII
89
121
78
110
=
=
=
=
'Y'
'y'
'N'
'n'
W tym przypadku menu powtarza się dopóki nie podamy litery Y, y, N, lub n.
Wywołanie:
?- write('Czy chcesz kontynuować? [Y/N] '), tak_lub_nie(X).
Czy chcesz kontynuować? [Y/N] x
Y czy N?:n
X = no.
Systemy ekspertowe
Używając języka Prolog możemy wykonać w prosty sposób system ekspertowy. Można w nim wyróżnić poniższe elementy:
interfejs użytkownika
● baza wiedzy
● mechanizm wnioskujący, który odnajduje rozwiązanie/odpowiedź
● mechanizm wyjaśniający, dlaczego jest to odpowiedź poprawna/dopuszczalna
●
Systemy ekspertowe
Używając języka Prolog możemy wykonać w prosty sposób system ekspertowy. Można w nim wyróżnić poniższe elementy:
interfejs użytkownika
● baza wiedzy
● mechanizm wnioskujący, który odnajduje rozwiązanie/odpowiedź
● mechanizm wyjaśniający, dlaczego jest to odpowiedź poprawna/dopuszczalna
●
Systemy ekspertowe
Jednym z przykładowych systemów ekspertowych, jest diagnozowanie przyczyny awarii samochodu.
W przypadku tego systemu elementy systemu ekspertowego są odwzorowane przez następujące predykaty:
problem/1 → baza wiedzy
probuj_wszystkie_mozliwosci/0 → wnioskujący
wytlumacz/1 → mechanizm wyjaśniania
zadaj_pytanie/1 i uzytkownik_mowi/2 użytkownika
mechanizm → interfejs Systemy ekspertowe
Program diagnozowanie przyczyny awarii samochodu w Prologu ma dwie zalety, które były by trudne do zaimplementowania w konwencjonalnych językach programowania.
●
●
wyświetla on listę wszystkich możliwych diagnoz, nie tylko jedną
nie pyta użytkownika o informacje, które nie są w danej chwili potrzebne
Aby to osiągnąć, program nie wywołuje bezpośrednio predykatu zapisana_odp, ale używa uzytkownik_mowi, który albo pozyskuje odpowiedź użytkownika z obecnej bazy wiedzy, albo pyta się go o nią.
Systemy ekspertowe
Kod programu:
:- reconsult('taknie.pl').
start :write('Program diagnozuje
Odpowiadaj na pytania Y lub N'),
wyczysc_odpowiedzi,
probuj_wszystkie_mozliwosci.
dlaczego
samochód
nie
chce
ruszyć.
probuj_wszystkie_mozliwosci :problem(D),
wytlumacz(D),
fail.
% wróć się do wszystkich mozliwosci
probuj_wszystkie_mozliwosci.
% ...następnie zakończ.
Systemy ekspertowe
Kod programu:
problem(rozladowana_bateria) :uzytkownik_mowi(rozruch_byl_ok,yes),
uzytkownik_mowi(rozruch_jest_ok,no).
problem(rozladowana_bateria) :uzytkownik_mowi(rozruch_byl_ok,yes),
uzytkownik_mowi(rozruch_jest_ok,no).
problem(zly_bieg) :uzytkownik_mowi(rozruch_byl_ok,no).
problem(uklad_rozruchu) :uzytkownik_mowi(rozruch_byl_ok,no).
problem(uklad_paliwa) :uzytkownik_mowi(rozruch_byl_ok,yes),
uzytkownik_mowi(paliwo_jest_ok,no).
problem(uklad_zaplonowy) :uzytkownik_mowi(rozruch_byl_ok,yes),
uzytkownik_mowi(paliwo_jest_ok,yes).
Systemy ekspertowe
Kod programu:
wyczysc_odpowiedzi :- retract(zapisana_odp(_,_)),fail.
wyczysc_odpowiedzi.
uzytkownik_mowi(Q,A) :- zapisana_odp(Q,A).
uzytkownik_mowi(Q,A) :- \+ zapisana_odp(Q,_),
nl, nl,
zadaj_pytanie(Q),
tak_lub_nie(Odp),
asserta(zapisana_odp(Q,Odp)),
Odp = A.
zadaj_pytanie(rozruch_byl_ok) :- write('Czy rozrusznik odpalał samochód
na początku normalnie?\n').
zadaj_pytanie(rozruch_jest_ok) :- write('Czy rozrusznik odpala nadal
normalnie?\n').
zadaj_pytanie(paliwo_jest_ok) :- write('Zajrzyj go gaźnika. Czy widzisz
lub czujesz benzyne?\n').
Systemy ekspertowe
Kod programu:
wytlumacz(zly_bieg) :write('Samochód może być na złym biegu.'), nl.
wytlumacz(uklad_rozruchu) :write('Sprawdź baterie, akumulator i alternator.\nJeżeli wszystko jest
OK, problemem może być rozrusznik.'), nl.
wytlumacz(rozladowana_bateria) :write('Twoje próby odpalenia samochodu rozładowały akumulator. Naładuj
go.'), nl.
wytlumacz(uklad_paliwa) :write('Sprawdź czy masz paliwo w baku.
Jeśli tak sprawdź czy przewód lub filtr paliwowy nie jest zatkany.
Może to być też problem pompy paliwowej.'), nl.
wytlumacz(uklad_zaplonowy) :write('Sprawdź świece zapłonowe, kable i inne elementy
układu zapłonowego. Jeśli jakakolwiek część wygląda
na uszkodzoną lub straciła date ważności - wymień ją.
W przypadku nierozwiązania problemu skontaktuj się z mechanikiem.'),
nl.
:- dynamic(zapisana_odp/2).

Podobne dokumenty