Tehnologia Proiectarii Sistemelor Expert
CUPRINS
Cap 1. Introducere 1
Cap 2. Caracteristici și componente ale sistemelor expert 3
2.1. Sisteme expert. Generalități. 3
2.2. Caracteristicile unui sistem expert 6
CAP 3. Componenta explicativă și dialog 10
3.1. Conducerea unui dialog 10
3.2. Arborele de inferență și realizarea protocolului intern 13
3.3. Componenta explicativă 14
CAP 4. Experiență și învățare 17
4.1. Modificarea on-line a bazei de cunoștințe 17
4.2. Implementarea euristicilor 19
4.3. Statistici de diagnosticare 21
4.4. Învățare din "experiență" 22
CAP 5. Metodologia dezvoltării programelor bazate pe cunoștințe 24
5.1. Tehnologia programării bazate pe cunoștințe 24
5.2. Prototipul 27
5.3. Strategii de inferență și metasisteme 29
5.4. Concluzii 31
BIBLIOGRAFIE 32
ANEXA 1. 33
ANEXA 2. 42
=== DIPL22 ===
CUPRINS
Cap 1. Introducere 1
Cap 2. Caracteristici și componente ale sistemelor expert 3
2.1. Sisteme expert. Generalități. 3
2.2. Caracteristicile unui sistem expert 6
CAP 3. Componenta explicativă și dialog 10
3.1. Conducerea unui dialog 10
3.2. Arborele de inferență și realizarea protocolului intern 13
3.3. Componenta explicativă 14
CAP 4. Experiență și învățare 17
4.1. Modificarea on-line a bazei de cunoștințe 17
4.2. Implementarea euristicilor 19
4.3. Statistici de diagnosticare 21
4.4. Învățare din "experiență" 22
CAP 5. Metodologia dezvoltării programelor bazate pe cunoștințe 24
5.1. Tehnologia programării bazate pe cunoștințe 24
5.2. Prototipul 27
5.3. Strategii de inferență și metasisteme 29
5.4. Concluzii 31
BIBLIOGRAFIE 32
ANEXA 1. 33
ANEXA 2. 42
CAP 1.
INTRODUCERE
Prin acestã lucrare se doreºte tratarea unor metode de proiectare ºi tehnici de programare noi care s-au nãscut din procesarea datelor bazate pe cunoºtinþe. Intenþionat s-a pus accent pe realizarea unui program ºi nu pe generarea unui sistem expert prin introducerea cunoºtinþelor unui expert într-un shell deja existent. Experienþa a arãtat cã sisteme expert bune cu interfaþã prietenoasã cu utilizatorul, integrabile direct cu bazele de date ºi aplicaþiile existente, pot fi realizate prin crearea tuturor componentelor adiþionale care pot ori lipsi din mediul de dezvoltare ori nu sunt adecvate scopului propus. Aceste tehnici de implementare a sistemelor expert ajutã inginerul soft sã adapteze sistemele existente pentru dezvoltarea sistemelor comerciale de calitate (ºi nu doar de cercetare), sau sã proiecteze integral un nou sistem expert într-un limbaj potrivit de nivel înalt.
S-a folosit limbajul Prolog 2.0 corespunzãtoare standardului Clocksin-Mellish, care este defapt baza tuturor implementãrilor Prolog semnificative de pe piaþã. Existã douã motive pentru asta. Prolog este cel mai productiv ºi economic limbaj þinând cont de resursele sistemului solicitate ºi este mult superior competitorului sãu major, LISP. În acelaºi timp suportul de rulare a Prologului acoperã un spectru larg de hardware, de la IBM-PC ºi Apple Macintosh prin VAX pânã la Amdahl sau Cray2, fiind deasemenea comparabil, din punctul de vedere al dimensiunii codului, sau cel puþin nu mai mare decât oricare alt limbaj de programare.
Utilitatea ºi necesitatea tehnicilor ºi procedurilor de proiectare se oglindeºte în sistemele expert industriale. Aspectele superficiale ale sistemelor expert proiectate au fost în mare mãsurã simplificate, atenþia concentrându-se asupra aspectelor structurale ºi funcþionale ale programãrii, pentru a nu devia prea adânc în domenii nefamiliare ºi nerelevante în acest moment.
Se poate spune cã programarea sistemelor expert bazate pe cunoºtinþe nu este o ramurã specialã a ingineriei programãrii, mai degrabã o metodã folositã de profesioniºti pentru proiectarea ºi realizarea unor programe speciale.
Structura dizertației
Capitolul 2. introduce structura arhitecturii sistemelor expert subliniând caracteristicile ºi componentele principale. De asemenea sunt descrise tipurile de cunoºtinþe, ºi funcþionarea maºinii de inferenþã folosind Interpretorul Prolog.
Capitolul 3. descrie mai pe larg metodele de implementare ale componentei explicative ºi dialog împreunã cu exemplificarea acestor implementãri în cele douã sisteme expert realizate. Se prezintã protocolul intern ierarhic pentru reprezentarea bazei de cunoºtinþe precum ºi ierarhia explicaþiilor aferente regulilor de pe fiecare nivel.
Capitolul 4. ilustreazã cum se poate exploata experienþa utilizatorului pentru a suplimenta cunoºtinþele prin tehnici de direcþionare a procesului de inferenþã folosind "previziunile" iniþiale ale utilizatorului precum ºi implementarea euristicilor prin reþele de legãturi între simptome ºi defecte. Deasemenea se trateazã realizarea componentei de învãþare "din experienþã", adicã din statisticile realizate pe baza frecvenþei succesului diagnosticãrilor.
Capitolul 5. prezintã metodologia dezvoltãrii programelor bazate pe cunoºtinþe, modelului fazelor de realizare a sistemelor expert, etapele acestuia, prototipizarea evolutivã, utilitatea ºi obiectivele realizãrii unui prototip minimal, strategii de inferenþã ºi metasisteme.
Anexa 1. conþine sursa cod a sistemului expert MTA de recomandare a unui tip de bilet pentru transportul urban în funcþie de categorii de cãlãtori, zone, numãrul succesiv de cãlãtorii etc.
Anexa 2. conþine sursa sitemului expert HEATEXP de diagnosticare a defectelor unui automobil. Baza de cunoºtinþe este simplificatã la sistemul de încãlzire-rãcire, obiectivul fiind acela de a realiza un prototip total funcþional cu o "proto-bazã" minimalã.
CAP 2.
CARACTERISTICI ȘI COMPONENTE ALE SISTEMELOR EXPERT
2.1. Sisteme expert. Generalități.
"Sisteme expert" este un termen din ce in ce mai rãspândit folosit pentru descrierea diferitelor produse program. Etimologia cuvântului ofera o prima interpretare. Un expert este cineva având cunoºtinþe profunde despre fapte ºi reguli referitoare la un domeniu particular, cunoºtinþe care sunt mai specifice decât cele ale majoritaþii oamenilor.
În mod similar un sistem expert este un program care poate administra cunoºtinþe expert speifice, stocându-le ºi evaluându-le într-o asemenea manierã încât sã ofere utilizatorului informaþii dedicate sau sã efectueze anumite sarcini, de exemplu conducerea unui proces de producþie. Astfel in loc de sisteme expert se foloseºte termenul de program bazat pe cunoºtinþe. Se subliniazã faptul cã utilizatorul unui sistem expert nu este întotdeauna un neavizat în domeniul respectriv, mai degrabã un sistem expert serveºte ca ajutor pentru un specialist (sistemele de diagnosticare, asistenþã). Una dintre motive constituie faptul cã este mult mai dificil dezvoltarea unui dialog eficient cu un utilizator neavizat decât cu un specialist. În cazul celui din urmã se poate folosi terminologia consacratã în domeniu, terminologie care nu poate fi tradusã instantaneu nici de specialiºtii înºiºi.
Deasemenea chiar ºi aplicaþiile cele mai convenþionale de procesare de date pot conþine cunoºtinþe specifice unui anumit domeniu. Tocmai de accea sunt aºa de bine vândute dacã piaþa le cere. Astfel s-a ivit necesitatea stabilirii anumitor criterii general acceptate pentru diferenþierea sistemelor expert de sistemele convenþionale:
Sistemul prelucreazã mai degrabã o bazã de cunoºtinþe decât o bazã de date. Aceastã bazã de cunoºtinþe poate sã conþinã atât fapte cât ºi reguli ºi chiar metareguli.
Are componente dedicate menþinerii ºi îmbunãtãþirii continue a bazei de cunoºtinþe în mod interactiv prin dialog cu utilizatorul sau automat prin analiza statisticã a rezultatelor consultaþiilor anterioare. Adesea aceste caracteristici sunt referite ca ºi capacitatea activã ºi pasivã de învãþare.
Utilizeazã euristici, mai ales tehnici de procesare ºi strategii de cãutare. Sistemul poate deduce cunoºtinþe noi din cele existente sub formã de fapte ºi reguli. Avem de-a face, în acest caz, cu un sistem de producþie.
Sistemul este capabil sã explice de ce? ºi cum? a ajuns la o anumitã soluþie pentru o problemã specificã. Datoritã acestei componente explicative, un sistem expert bun poate nu numai sã aplice cunoºtinþele expert înglobate în baza sa de cunoºtinþe, dar sã le ºi împãrtãºeascã utilizatorilor sãi. Astfel el poate fi folosit pentru scopuri de antrenare sau învãþare.
Nu toate sistemele expert vor avea toate cerinþele de mai sus, însã pentru a fi considerate sisteme expert, ele trebuie sã satisfacã cel puþin douã dintre ele. În sistemele expert realizate în cadrul lucrãrii, sunt introduse tehnicile de implementare ale tuturor atributelor enumerate. Componentele enumerate sunt înglobate în arhitectura sistemului expert prezentat în fig. 1.1. introdus de W. Reisig (1985). Aceastã arhitecturã este sub formã de reþea de instanþe ºi canale. Este o reprezentare neobiºnuitã, deoarece încearcã sã încorporeze programatorii ºi utilizatorii sistemului ca ºi "instanþe" iar interacþiunea lor cu sistemul ca ºi "canale".
Utilizatorul final consultã sistemul expert funcþional prin intermediul unei componente de dialog prin terminal. În contrast cu sistemele tradiþionale mai avem o a doua categorie de "utilizatori" care sunt defapt persoanele responsabile cu întreþinerea ºi actualizarea bazei de cunoºtinþe. Este vorba despre inginerul de cunoºtinþe ºi expertul în domeniu. Ultimul grup relevant constã din programatori care implementeazã sistemul sub formã de cod sursã sau "shell". Bineînþeles, în cazul sitemelor mai mici inginerul de cunoºtinþe ºi programatorul sunt una ºi aceeaºi persoanã. Structura codului sursã precum ºi conceptele de bazã ºi tehnicile necesare planificãrii ºi implementãrii unor asemenea programe vor fi bazate pe modelul arhitectural prezentat în fig. 1.1.
Metodologiile de programare folosite pentru a realizare asemenea sisteme, diferã în mod substanþial, sub mai multe aspecte, de tehnologiile convenþionale de programare. De aceea majoritatea limbajelor algoritmice tradiþionale nu sunt prea potrivite implementãrii acestor cerinþe.
fig. 2.1. Arhitectura unui sistem expert
Þelul acestei lucrãri este de a demonstra, folosind limbajul cel mai adecvat obiectivului, Prolog, cum se pot echipa sisteme soft cu atributele de mai sus, astfel încât ele pot în mod real califica un sistem ca fiind expert. Cu alte cuvinte am prezentat tehnicile cu ajutorul cãrora dezideratele propuse pot fi atinse. În mod tipic, sistemele expert conþin cunoºtinþe administrate într-un limbaj neprocedural.
Într-adevãr nepotrivirea limbajelor de programare algoritmice tradiþionale pentru reprezentarea cunoºtinþelor "formale", a dus la dezvoltarea programãrii bazatã pe cunoºtinþe. Acest domeniu de dezvoltare este împãrþit de douã limbaje: LISP, una dintre cele mai vechi limbaje de programare care încã joacã un rol important, mai ales în SUA; ºi PROLOG care se bucurã de popularitate crescutã în Europa ºi Japonia. Motivul este acela cã Prolog este un limbaj de "foarte înalt nivel", producând cel mai compact, puþin solicitant, din punctul de vedere al resurselor sistemului, ºi uºor de citit. În Prolog cunoºtinþele sunt formulate în clauze, adicã reprezentarea directã a faptelor ºi regulilor sub forma clauzelor Horn, o formã specialã a logicii de ordinul I. Lisp este însã un limbaj "funcþional". Fiecare expresie într-un program scris în Lisp, este o funcþie, returnând prin definiþie, o singurã valoare.
Sistemele expert implementate vor arãta logica ºi eficienþa modului cum se poate expanda baza de cunoºtinþe ºi astfel implementa o formã primitivã a "învãþãrii" sau a adaptãrii. În Lisp, sau mai mult, în alte limbaje "mai convenþionale", asemenea capabilitãþi sunt mult mai greu implementabile pentru cã, cunoºtinþele sunt "înglobate" în funcþii sau proceduri modificabile mai greu.
2.2. Caracteristicile unui sistem expert
Sistemele expert au abilitatea de a "raþiona" asemenea unui om. Ele utilizeazã simboluri ºi incertitudini. Pot raþiona cu valori necunoscute, cu valori multiple. Pot explica modul cum au raþionat, pot trage concluzii. Astfel o cale mai precisã de a ne gândi la avantajele relative ale sistemelor expert este aceea cã ele se pot ocupa de probleme ce conþin elementele menþionate anterior.
Regulile – elementul de baza al unui sistem expert bazat pe reguli – reprezintã o modalitate naturalã de a exprima tot ceea ce cunoaºtem. Conform clasificãrii dupã E.T.Hall a cunoºtinþelor umane în "neformale", "tehnice" respectiv "formale", ne dãm seama cã informaþia formalã este cea care poate fi descrisã cel mai bine prin intermediul clauselor "if – then". Mediile de dezvoltare a programelor bazate pe cunoºtinþe cautã sã ofere mijloace ºi metode mai bune de procesare a cunoºtinþelor formale, în acceaºi mãsurã în care programarea structuralã o face pentru procesarea cunoºtinþelor tehnice. Bineînþeles, nu trebuie ignorate nici metodologiile ºi cunoºtinþele tehnice din programarea algoritmicã. Ele pot fi utilizate, la fel ºi sistemele de operare existente.
Componenta cea mai semnificativã a unui sistem expert este baza sa de cunoºtinþe, care, în contrast cu bazele de date convenþionale tradiþionale, stocheazã toate aspectele posibile ale cunoºtinþelor expert necesare, într-o formã uºor modificabilã. În cazul sistemelor mari, aceastã cunoºtinþã nu poate fi stocatã integral în memoria principalã. Vorbim despre bancã de cunoºtinþe – analog cu o bancã de date – când ne referim la întreaga cunoºtinþã disponibilã pentru sistem pe suport secundar de memorare. Pe de altã parte, folosim termenul "bazã de cunoºtinþe" pentru desemnarea acelei porþiuni a cunoºtinþelor totale care au fost mai nou "consultate", adicã mutate temporal în memoria principalã.
Din cauzã cã bãncile de cunoºtinþe conþin cunoºtinþe de formã mult mai variatã decât bãncile de date convenþionale, ele nu pot avea o structurã uniformã. Astfel, ele vor conþine o colecþie de diferite subsisteme pentru administrarea datelor, fiecare dintre aceste subsisteme fiind adecvate reprezentãrii ºi procesãrii unui anumit tip specific de cunoºtinþe. În continuare sunt prezentate câteva exemple de asemenea subsisteme de cunoºtinþe:
Cunoºtinþe de tipul reguli:
consistã din premize ºi concluzii, posibil introducând ºi factor de certitudine pentru a exprima cunoºtinþele nesigure. Cunoºtinþele de tipul reguli sunt formale ºi de aceea reprezintã diferenþa fundamentalã faþã de bãncile de date tradiþionale.
Cunoºtinþe tabelare:
corespunzãtoare celor din bãncile de date relaþionale uzuale.
Cunoºtinþe procedurale:
reprezintã ceea ce în trecut a fost referit ca ºi "bancã de metode". Aceºtia sunt algoritmi în limbaje convenþionale de programare care sunt activaþi la nevoie (controlaþi de reguli) ºi returneazã rezultate (de obicei numerice) regulii care i-a declanºat.
Cunoºtinþe taxonomice:
descriind obiectele, atributele ºi ierarhiile lor. Acestã parte a bãncii de date se aseamãnã foarte mult cu "dicþionarele de date", atât în structurã cât ºi în utilizare.
Cunoºtinþe despre formularea textelor în limbaj natural:
conþin texte substituente, se utilizeazã pentru conducerea unui dialog cu utilizatorul. În sisteme expert texte lungi, mai ales, trebuie sã fie administrate separat, extern, ºi nu în contextul bazei interne de cunoºtinþe. Nu e vorba aici doar de faptul cã asemenea texte ocupã o mare parte a mempriei interne, ci ºi de faptul cã, ca ºi fiºiere text externe, sunt mai uºor de întreþinut ºi formatat dacât în cazul în care sunt direct introduse în reguli ºi proceduri.
Cunoºtinþe despre asistenþa utilizatorului:
sunt la fel ca ºi cunoºtinþele despre formularea textelor în limbaj natural, adicã colecþie de texte substituente. Diferenþa fundamentalã faþã de acestea este aceea cã aceste texte sunt asociate direct cunoºtinþelor taxonomice, obiectelor ºi atributelor definite acolo. De aceea ele sunt administrate separat de textele substituente generale.
Sã ne uitãm mai atent la cunoºtinþele de tipul reguli. Fiind diferite de cunoºtinþele procedurale, care pot fi exprimate cu uºurinþã folosind limbeje de programare algoritmice uzuale ºi desemneazã ca ºi soluþia unui task o serie de operaþii de executat, cunoºtinþele bazete pe reguli sunt o formã a cunoºtinþelor declarative. Asta înseamnã cã toate cunoºtinþele ºi nu numai "datele" sunt formulate declarativ. Regulile asociazã fiecare condiþie particularã cu o cauzã (posibilã), astfel se construieºte defapt o reþea de reguli. Noi cunoºtinþe pot fi adãugate uºor la aceastã reþea prin adãugare de noi reguli.
Având în vedere faptul cã regulile, ca ºi cunoºtinþã declarativã, definesc mai degrabã relaþii fãrã a fixa nici o structurã proceduralã, trebuie sã existe o componentã care sã determine o aplicare ºi o evaluare a acestora. Aceastã componentã este maºina de inferenþã, care în ea însãºi reprezintã o cunoºtinþã specialã: una sau mai multe metode de procesare a cunoºtinþelor ºi ordinea adecvatã de aplicare ale acestora, corespunzãtor unor strategii particulare de cãutare a soluþiilor. Aceastã componentã a sistemului este de obicei proceduralã prin naturã, implementatã ca ºi un program tradiþional într-un limbaj algoritmic.
Este, totuºi, posibil ºi exprimarea metodelor ºi strategiilor în mod declarativ ca ºi "reguli de cãutare" (rezolvare de probleme) generale. În acest caz se vorbeºte despre metacunoºtinþe. Aceastã descriere la livel înalt a sistemelor expert permite implementarea lor astfel încât sã se poatã adapta mai flexibil sarcinii de executat. În acelaºi timp, le conferã un anumit grad de capabilitate de învãþare, astfel cã sistemul îºi poate modifica propria bazã de metacunoºtinþe bazându-se pe experienþã sau întrebãri directe puse utilizatorului.
Componenta sistemului expert folositã pentru navigarea în reþeaua de reguli este deci maºina de inferenþã. Prin "inferenþã" se înþelege "a trage concluzii logice": maºina de inferenþã derivã cuoºtinþe noi din faptele ºi regulile existente, care ar putea conduce la un rãspuns la întrebarea utilizatorului.
Un Interpretor Prolog implementeazã o maºinã de inferenþã cu parcurgere Top-Down: începe cu întrebarea utilizatorului ºi încearcã sã "dovedeascã" validitatea ei, folosind o metodã specialã numitã rezoluþie. Acest lucru oferã posibilitatea de a scrie sisteme expert într-un mod simplu ºi compact. Limbajul Prolog conþine în structura sa componente care în alte limbaje (de exemplu în Lisp), trebuie sã fie adãgate cu o creºtere corespunzãtoare a dimensiunii programului. Nu este adevãrat însã faptul cã Prolog este capabil doar de parcurgere Top-Down. Este posibilã scrierea unei maºini de inferenþã în Prolog cu parcurgere Bottom-Up. Mai mult, pot fi implementate la fel de bine ºi alte tehnici de reprezentare ºi parcurgere a cunoºtinþelor.
Interpretorul Prolog poate interpreta/aplica o regulã de tipul "dacã – atunci" în douã forme:
dacã "condiþie" atunci "rezultat" ;
dacã "situaþie" atunci "acþiune" .
în funcþie de necesitãþi. Primul este o interpretare logicã iar al doilea este una proceduralã. Diferenþa se aflã în semantica lui"rezultat" ºi "acþiune" respectiv. Dacã partea dupã atunci este un pseudo-predicat, care cauzeazã anumite efecte laterale ca intrare sau ieºire sau schimbãri în baza de cunoºtinþe, atunci rezoluþia regulii respective este echivalentã cu un apel de procedurã în limbajele tradiþionale algoritmice. Acest lucru este referit ca ºi interpretarea proceduralã a unui limbaj de programre logicã. Jonglarea între interpretarea logicã ºi cea proceduralã a unui text de program oferã o posibilitate largã de manevrare.
CAP 3.
COMPONENTA EXPLICATIVĂ ȘI DIALOG
3.1. Conducerea unui dialog
Sistemul expert trebuie sã fie capabil sã indice utilizatorului cum sã aplice cât mai optimal informaþia bazatã pe reguli. La inceputul unei diagnosticãri sistemul expert se prezintã, în sensul cã precizeazã pentru ce domeniu ºi ce tip de utilizator a fost conceput ºi care este menirea lui. Se afiºeazã apoi opþiunile posibile de continuare a dialogului care pot fi introduse. În cele douã sisteme expert realizate, atât în cel de informare asupra unei alegeri optimale pentru cãlãtori (MTA) cât ºi în cel de diagnosticare a defectelor unui automobil (HEATEXP), aceste sarcini sunt realizate de predicatul assistance. De exemplu în al doilea sistem expert avem:
assistance:-
nl, write("Intrebari posibile:"), nl, nl,
write("start. => Inceperea diagnosticarii"), nl, fail.
assistance:-
write("Rule of thumb. => Cautarea defectului cu teste preparatoare"),
nl,write("reason. => Afiseaza linia de rezolutie"),
write("why_not(N). => De ce regula 'N' nu este aplicabila?"),nl,
nl, fail.
assistance:-
write("rule(N). => Afiseaza regula 'N'."), nl,
write("facts. => Afiseaza toate faptele cunoscute la un moment dat."),
nl, write("restart. => Sterge toate faptele acumulate si reincepe diagnosticarea."),
nl, fail.
assistance:-
write("statistics(N,How_often). => Cat de des a fost defectul 'N' diagnosticat deja?"),
nl, write("assistance. => Afiseaza aceasta lista."),nl.
În afarã de rãpunsurile normale la întrebãrile puse utilizatorului pentru achiziþionarea datelor de caz (referitoare la utilizator), mai existã ºi posibilitatea introducerii intrebãrilor why? ºi how_come? la care sistemul explicã de ce întreabã o anumitã întrebare sau cum a ajuns la un anumit rezultat. Fãrã introducerea comenzii restart controlul dialogului se realizeazã în funcþie de datele deja introduse deci sistemul nu întreabã acelaºi lucru chiar dacã avem o nouã sesiune de intrebãri.
Pentru procesarea unei cereri a utilizatorului, Interpretorul Prolog activeazã regula corespunzãtoare. Dacã cel puþin una din reguli se dovedeºte a fi cu succes în urma rezoluþiei, atunci Prolog, ºi astfel ºi sistemul expert, va rãspunde cu "yes", sau dacã toatã cãutarea în arborele de reguli eºueazã, atunci va rãspunde cu "no". Însã în cazul în care sistemul se comportã mai degrabã ca un consultant, atunci trebuie sã selecteze cea mai adecvatã soluþie dintre mai multe în funcþie de "problema utilizatorului", adicã în funcþie de cunoºtinþele existente în permanenþã în baza de cunoºtinþe sau colectate de la utilizator.
Aspectul de diagnosticare este implementat ca o strategie de soluþie. Folosim maºina de inferenþã implicitã cu parcurgere Top-Down oferitã de Prolog. Din punctul de vedere al interpretorului de reguli, adicã al sistemului Prolog, acest lucru se realizeazã prin ordonarea clauzelor astfel încât ipoteza cea mai improbabilã sau inacceptabilã sã aparã "cât mai jos" în baza de cunoºtinþe. De exemplu:
mta:-
enter_current_rule(100),
is_a_Kiddie_Ticket_possible, recommend_childrens_ticket.
…
mta:-
enter_current_rule(104),
must_one_ride_without_paying, recommend_non_payment_of_fare.
mta:-
enter_current_rule(105),
must_one_walk, recommend_walking.
Strategia "de sus în jos" implicitã de parcurgere a Prologului este deosebit de avantajoasã ºi pentru dezvoltarea programelor adaptive, discutatã în capitolul 4.
Amândouã sisteme expert folosesc aºa numitele informaþii de stare, informaþii referitoare la utilizatorul în cauzã, precum starea consultaþiei actuale. În sistemul MTA acest lucru este rezolvat prin fapte binare status: Acestea se reiniþializeazã cu predicatul restart la valoarea "necunoscut":
restart:-
retractall(status(_,_)),
asserta(status(cash,unknown)), asserta(status(age,unknown)),
asserta(status(distance,unknown)), asserta(status(boldness,unknown)),
retractall(tree(_,_)), assertz(tree(0,0)),
set(step,0), set(level,0), set(increment,2).
unde status(symbol,symbol) reprezintã informaþii de stare;
tree(integer,integer) conþine drumul parcurs în arborele de inferenþã în timpul ultimei consultaþii; primul argument fiind nivelul, iar al doilea regula aplicatã;
level(integer) conþine la fiecare moment nivelul din arbore;
step(integer) pasul actual de parcurgere;
increment(integer) incrementare cu o unitate sau douã.
Baza de reguli ºi fapte este conþinutã în baza de cunoºtinþe. Baza de reguli existã de la bun început ºi rãmîne neschimbatã reprezentând corpul primar al "cunoºtinþelor expert", pe când baza de fapte începe cu anumite informaþii de stare care pe parcurs se schimbã în funcþie de informaþia generatã de interpretorul de reguli în timpul cãutãrii sale de soluþii acceptabile. Sã examinãm mai de aproape clauzele predicatului is_a_Kiddie_Ticket_possible care include regulile pentru posibilitatea utilizãrii biletului pentru copii (intrã în aecastã categorie ºi cãlãtoriile pe distanþe mici – mai mici de 5 km.)
is_a_Kiddie_Ticket_possible:-
status(cash,unknown), query(cash,1), fail.
…
is_a_Kiddie_Ticket_possible:-
status(cash,Money), str_real(Money,M), M>=5,
status(distance,unknown), query(distance,4), fail.
is_a_Kiddie_Ticket_possible:-
status(cash,Money), str_real(Money,M), M>=5, status(distance,near),
enter_current_rule(5).
query(S,N):-
enter_current_rule(N),
set(level,3), ask(S,A), !, asserta(status(S,A)), retract(status(S,unknown)),!.
Se observã cã valorile de stare adãgate în final bazei de fapte prin asserta nu sunt neapãrat aceleaºi cu cele date de utilizator. De exemplu status(distance,near) în mod clar nu conþine valoarea numericã introdusã de utilizator ci mai degrabã rezultatul analizei acestuia. În cazul rãspunsurilor de genul "nu ºtiu" pentru siguranþã se considerã varianta mai nefavorabilã:
test_f2("not sure",far):- !.
3.2. Arborele de inferență și realizarea protocolului intern
Înainte de a intra în amãnunte referitoare la implementarea componentei explicative trebuie examinat mai atent cum îºi derivã maºina de inferenþã soluþiile. Dupã ce sistemul a fost iniþializat ºi utilizatorul introduce "diagnosticare", poate fi condus un dialog conform arborelui de inferenþã reprezentat în fig. 3.2.
fig. 3.2. Arborele de inferenþã
Fiecare nivel ierarhic reprezintã un anumit grad de detaliere ºi îi sunt asociate diferite seturi de reguli din baza de cunoºtinþe. Sistemul trebuie sã ºtie în permanenþã nivelul ºi numãrul regulii. Ca ºi convenþie, regulile de pe nivelul 3 au numãrul mai mic de 100 iar cele de pe nivelul 2 egal, sau mai mare de 100. Sistemul realizeazã o traversare în preorder a arborelui de inferenþã, extinzând arborele, dacã este necesar, pentru realizarea componentei de colectare a datelor de caz. Problema utilizatorului este rezolvatã atunci când faptele cunoscute sau nou achiziþionate pe nivelul 3 satisfac una din ipotezele de pe nivelul 2.
Pentru obiective de testare ºi trasare precum ºi verificarea plauzibilitãþii logicii dinamice utilizate de maºina de inferenþã, se doreºte de obicei reconsituirea drumului parcurs prin arborele de inferenþã. Acest lucru se realizeazã printr-un protocol intern al paºilor individuali prin predicatul intern tree(Pas,Regula). Pas este numãrul acþiunii respective iar Regula este identificatorul numeric al regulii aplicate la o anumitã joncþiune. Exemplu de trasare a unei "cozi de audit" :
?- tree(Pas,Regula)
Pas = 0, Regula = 0, (Nivelul 0)
Pas = 1, Regula = 100, (Nivelul 2)
Pas = 2, Regula = 1, (Nivelul 3)
Pas = 3, Regula = 2, (Nivelul 3)
Pas = 4, Regula = 4, (Nivelul 3)
Pas = 5, Regula = 101, (Nivelul 2)
Pas = 6, Regula = 7, (Nivelul 3)
3.3. Componenta explicativă
O caracteristicã esenþialã a componentei explicative este un anumit nivel de "inteligenþã". Cel puþin atunci când utilzatorul rãspundne why? la o explicaþie datã, sã "ºtie" destul pentru a nu tot repeta explicaþia anterioarã, ci a oferi un rãspuns alternativ, probabil mai detaliat. Explicaþia secundarã este de fapt un alt nivel din sistemul ierarhic din fig. 3.2.: utilizatorul doreºte sã ºtie de ce a întrebat sistemul o anumitã întrebare într-un context "mai înalt" sau "meta". În fig. 3.3. se reprezintã o ierarhie de explicaþii care corespunde cu exactitate nivelelor din arborele de inferenþã din fig. 3.2.
fig. 3.3. Ierarhia de explicaþii a unei diagnoze
Ierarhia de explicaþii începe întotdeauna la nivelul 3, deoarece se aºteaptã de obicei un rãspuns de la utiliozator când acesta are ºi posibilitatea de a rãspunde why?. Fiecare repetare consecutivã a lui why (sau reason în cazul lui HEATEXP) cauzeazã faptul cã explicaþiile sã se refere la nivelul urmãtor superior pânã când este atins nivelul 0 ºi nu mai sunt posibile alte explicaþii semnificative. În consecinþã baza de reguli trebuie suplimentatã cu câte o explicaþie pentru fiecare regulã de pe fiecare nivel astfel încât componenta explicativã sã poatã sã rãspundã corespunzãtor. Aceasta se implementeazã printr-un functor binar explanation(Nivel,Regulã):
explanation(2,Numar):-
member(Numar,[1,2,4]),
write("Pentru ca Kiddie Ticket este cel mai ieftin."), and_so.
explanation(1,_):-
write("Vreau sa gasesc biletul cel mai ieftin pentru calatoria ta"), and_so.
and_so:-
nl, nl, write("Si acum: ").
Pot fi folosite pentru Regula variabile anonime sau chiar variabile a cãror apartenenþã sã fie verificatã de member pentru validitate. Acest lucru este foarte util pentru minimizarea spaþiului de stocare sau efortului de introducere a textelor (Putem avea reguli de ordinul sutelor de mii). Astfel explicaþia de mai sus, de exemplu este acceaºi pentru regulile 1, 2 ºi 4 de pe nivelul 2. La sfârºit sistemul revine la întrebarea iniþialã prin and_so. Explicaþiile sunt afiºate de diferite predicate de test, care verificã rãspunsul utilizatorului, de exemplu:
ask(distance,F2):-
write("Cat de mare este distanta? "), readln(Input),
recognize(Input, Distance), test_f2(Distance,F2).
recognize(Input,why):-
member_str(Input,[why,"Why","how come", "De ce", "de ce"]), !.
test_f2(why,F2):-
!, write_explanation, enter_current_level, ask(distance,F2).
write_explanation:-
level(Level), step(Step), tree(Step,Rule), nl,nl, explanation(Level,Rule), !.
Douã variabile de stare, adicã fapte din baza de cunoºtinþe, step(Pas) ºi level(Nivel) sunt evaluate în funcþie de intrãrile în protocolul arborescent pentru a determina la orice moment pentru ce nivel ºi ce regulã trebuie sã fie datã explicaþia. Tãietura (!) de la sfârºit asigurã unicitatea explicaþiei la un moment dat pe un anumit nivel. Dupã fiecare explicaþie este utilizat predicatul enter_current_level pentru a decrementa variabila de stare level(Nivel) care se apeleazã recursiv:
enter_current_level:-
retract(level(Old)), increment(Increment),
New = Old – Increment, assertz(level(New)).
În funcþie de unde s-a început iniþial secvenþa de întrebãri de tipul why?, nivelul 1 sau 2, increment este setat pe 2 sau 1 respectiv, altfel explicaþiile n-ar avea sens:
enter_current_rule(Rule_Number):-
retract(step(State)), New = State +1, assertz(step(New)),
assertz(tree(New,Rule_Number)), set_incr(Rule_Number), !.
set_incr(Rule_Number):-
Rule_Number > 99, set(increment,1), !.
set_incr(Rule_Number):- !.
Un sistem expert trebuie sã ºtie sã "interpreteze" diferite rãspunsuri, astfel cã utilizatorul nu este forþat sã cunoascã rãspunsuri standarde "acceptabile". Predicatul recognize este cel care are menirea de a recunoaºte un rãspuns dintre mai multe similare, adicã detecteazã sinonimele.
În cazul în care utilizatorul nu ºtie sã rãspundã la o anumitã întrebare, poate fi intrucþionat sã realizeze anumite teste înainte de a rãspunde. Aceste instrucþii s-au construit din întrebarea originalã la care utilizatorul n-a ºtiut sã rãspundã, un predicat test (aceste predicate test sunt prezentate în modulul TESTAIDS.PRO în anexa 2), conþinând textul intrucþional relevant cauzei respective selectat în corespondenþã cu frazele necesare construirii întrebãrii originale ºi componente text standard definite în display_test.
CAP 4.
EXPERIENȚĂ ȘI ÎNVĂȚARE
4.1. Modificarea on-line a bazei de cunoștințe
Baza de cunoștințe a unui sistem expert nu este una statică, ci mai degrabă dinamică, actualizabilă frecvent, așa cum s-a văzut și din modelul arhitectural din fig. 2.1. Schimbările pot apărea în urma activității componentei de modificare și învățare pentru a stoca date de caz sau pentru a înregistra o stare particulară. Vorbim aici de cunoștințe dinamice care apar în cursul unei consultații particulare sau a unei sesiuni și suplimentează "temporal" cunoștințele statice care au fost încapsulate în baza de cunoștințe de către expertul în domeniu sau inginerul de cunoștințe.
Partea staticã a cunoºtinþelor nu este defapt constantã. Unul din motive pentru a o face dinamicã este creºterea substanþialã a vitezei de execuþie. În cazul unei recursivitãþi, calculele de la paºii urmãtori se bazeazã pe rezultatele paºilor intermediari stocate dinamic, evitând astfel salvãrile ºi revenirile excesive din stiva de lucru. De exemplu timpul necesar calculãrii numerelor Fibonacci (dublu rescursiv) poate fi redus de circa 2500 (!) ori – bineînþeles aceastã reducere nu este întotdeauna aºa de spectaculoasã.
Chiar ºi cel mai simplu sistem de învãþare presupune modificarea bazei de cunoºtinþe statice existente. Prin înregistrarea frecvenþei cu care diferite clauze ale aceluiaºi predicat au fost aplicate cu succes, se poate îmbunãtãþi eficienþa sistemului prin exploatarea acestei experienþe. Acest lucru se poate atinge prin reorganizarea regulilor ºi faptelor din baza de cunoºtinþe astefel încât cele mai "probabile" (mai frecvent cu succes) sã fie întâlnite "mai devreme" de strategia de inferenþã. Resortarea conþinutului bazei de cunoºtinþe se poate implementa cu douã predicate:
retract(Predicat_cu_Succes)
asserta(Predicat_cu_Succes)
Modificarea on-line a bazei de date reprezintã o problemã fundamentalã. În domeniul logicii ºi corespunzãtor ºi în programarea logicã se vorbeºte despre logicã nemonotonã dacã în timpul derivãrii unei concluzii axiomele adicã regulile ºi faptele în cazul nostru se schimbã astfel încât nu mai poate fi garantat cã la un anumit punct în procesul de rezoluþie, un rezultat intermediar de mai devreme nu ºi-a pierdut valoarea de adevãr. Apariþia unor asemenea schimbãri în cursul unei consultaþii este foarte criticã. Rezultã necesitatea construirii unui "subsistem de menþinere a adevãrului". Este recomandat sã se considere deja în faza de identificare a probelemei existenþa logicii nemonotone ºi sã se ia mãsuri pentru tratarea consecinþelor de la bun început.
Inconsistenþele introduse de inginerul de cunoºtinþe în timpul procesului de colectare a cunoºtinþelor sunt mai uºor de evitat printr-o procedurã de verificare care controleazã automat fiecare clauzã nouã în vederea asigurãrii compatibilitãþii datelor înainte de a permite memorarea lor finalã în baza de cunoºtinþe.
Pentru a localiza mai rapid un anume defect bãnuit de la început (În cazul sistemului expert HEATEXP de diagnosticare de defectelor unui automobil), un mecanic cu experienþã ºtie sã direcþioneze testãrile astfel încât sã ajungã rapid la rezultat, adicã maºina de inferenþã sã înceapã cãutãrile începând de la o anumitã regulã. Implementarea se realizeazã cu:
check(R_No):-
defect(R_No,A,B,C), increment(R_No),
store_this_step(R_No), print_result(R_No,A,B,C).
În caz de succes dialogul a fost scurtat substanþial, în caz contrar însã sistemul trebuie sã ºtie sã reia ºirul întrebãrilor utilizând ºi datele de caz colectate în prima fazã de diagnosticare. Astfel putem avea douã faze de diagnosticare. În faza a doua se poate include ºi cãutarea defectelor multiple. Astfel predicatul start va avea forma:
start:-
note_phase(1), hypotheses(Hypotheses_List), examine(Hypotheses_List).
start:-
note_phase(2), new_priorities, hypotheses(New_Hypotheses_List),
examine(New_Hypotheses_List).
examine([]):-
phase(2), nl,write("I cannot find any defects.").
examine([Alternatives|_]):-
check(Alternative).
examine(_|Others]):-
examine(Others).
notephase(P):-
retract(phase(_)), asserta(phase(P)).
Astfel aceste "presimþiri" ale mecanicului auto pot fi utilizate pentru a creºte timpul de diagnosticare, iar chiar dacã nu s-au dovedit a fi bune, informaþia de caz introdusã se utilizeazã în faza a doua.
4.2. Implementarea euristicilor
În mod normal mecanicul auto nu are întotdeauna o idee precisã unde se poate afla problema, dar poate vrea sã aplice cãteva "reguli de aur" sau teste iniþiale preparatoare pentru a determina aproximativ unde ar putea fi defectul. Testeazã mai întâi dacã merge motorul, semanlizarea etc.
Unele rãpunsuri primite în faza iniþialã de testere pot creºte sau scade semnificativ probabilitatea unui anumit diagnostic, sau îl pot exclude complet. Aceste teste iniþiale ajutã mult la direcþionarea ulterioarã a ordinii de parcurgere a regulilor, conferând mai multã eficienþã mecanicului pe termen lung. Aceste încercãri "intuitive" sunt euristici ºi reprezintã o parte la fel de importantã a cunoºtinþelor speciale ale sistemului expert ca ºi cele sistematice, formale, structurate în reguli. Euristicile sunt importante pentru a preveni explozia combinatoricã când lucrãm cu o bazã de cunoºtinþe care atinge dimensiunile "utile".
Pentru a varia procedura de parcurgere a bazei de reguli scoatem Hypotheses_List din procedura start iniþialã unde iniþial a servit orientãrii investigaþiei diferitelor defecte potenþiale la nivelul cel mai superior. Lista de ipoteze trebuie sã fie administratã separat prin predicatul hypotheses(Lista_de_defecte) care la orice moment poate fi scos din baza de cunoºtinþe prin retract, resorta apoi reintrodus cu asserta. Utilizând experineþele unui mecanic specialist putem contrui o reþea de legãturi între simptome ca de exemplu cea din fig. 4.2.
fig. 4.2. Un exemplu de reþea relaþionalã între simptome ºi defecte
S-a utilizat o convenþie de punctare a simptomelor stocate în fapte points pentru defectele alternative de forma points(Hypothesis,Points,Possibility), unde Points un contor al puterilor negative ori pozitive ataºate ipotezelor prin reþeaua de legãturi iar Possibility este un indicator, iniþializat la început cu posibil care va fi schimbat în imposibil dacã o simptomã exclude total acestã ipotezã.
Modulul IPOTEZE.PRO conþine predicatele necesare aplicãrii unor euristici de parcurgere a bazei de cunoºtinþe conform reþelei de legãturi între simptome prezentat în fig. 4.2. În continuare se prezintã predicatele de început pentru resortarea listei de ipoteze în funcþie de simptomele iniþiale:
rule_of_thumb:-
make_hypothesis(List), test_hypothesis(List).
make_hypothesis(HypothesesList):-
nl, write("Semnalizatoarele funcþioneazã? "),
read_in(Answer_1), test_question1(Answer_1),
nl, write("Porneºte motorul ? "),
read_in(Answer_2), test_question1(Answer_2),
point(1,A,_), point(2,B,_), point(3,C,_), point(4,D,_),
sort([A,B,C,D],_,[1,2,3,4],HypothesesList),
retract(hypotheses(_)), asserta(hypotheses(HypothesesList)).
test_hypothesis([]):-
nl, write(" I cannot find any defects. ").
test_hypothesis([Next_Alternative|_]):-
point(Next_Alternative,_,possible), check(Next_Alternative).
test_hypothesis([_|Remainder]):-
test_hypothesis(Remainder).
Predicatele test_questionN de evaluare a simptomelor au forma:
test_question2(Answer):-
meaning(Answer,yes), increase_probability(1,4), reduced_probability(3,2).
test_question2(Answer):-
meaning(Answer,no), impossible(4), increase_probability(2,2).
test_question2(_).
În cazul unui rãspuns vag, valoarea lui points rãmâne neschimbatã. Predicate pentru creºterea (respectiv scãderea) sau imposibilitatea posibilitãþii anumitor ipoteze sunt:
increase_probability(Hypo,Points):-
retract(point(Hypo,Old_State,possible)),
New_State = Old_State + Points,
asserta(point(Hypo,New_State,possible)).
increase_probability(_,_).
impossible(Alternative):-
point(Alternative,0,impossible), !.
impossible(Alternative):-
retract(point(Alternative,_,_)), asserta(point(Alternative,0,impossible)).
Sintaxa predicatului de sortare este: sort(Points,New_Points,Hypos,New_Hypos), unde Hypos este lista ipotezelor vechi, New_Hypos este lista acestora resortatã, adicã este variabilã de ieºire din predicat. Points este o listã a punctelor acumulate pentru ipotezele corespunzºtoare în lista Hypos. New_Poinst este o variabilã auxiliarã care conþine punctele corespunzãtoare ipotezelor resortate. Predicatul sort este o variaþie a lui quicksort, aici însã intervin mai multe argumente. (Anexa 2. modulul IPOTEZE.PRO)
4.3. Statistici de diagnosticare
Atât mecanicul cât ºi inginerul de construcþii a automobilelor îºi acumuleazã cunoºtinþele prin experienþa lor de zi cu zi reparând ºi proiectând maºini. De accea ar avea rost sã-i proiectãm ºi sistemului nostru expert o componentã de învãþare cu ajutorul cãreia sã poatã acumula experineþã din diagnosticãrile sale cu succes. În forma cea mai primitivã asta ar însemna colectarea statisticilor despre fiecare defect descoperit ºi causele corespunzãtoare. Aceste date pot fi utilizate apoi pentru a face sistemul sã înveþe în cum sã fie sortatã lista de ipoteze ºi cum sã fie realizatã dignosticarea.
Datele de tip statistici pot fi foarte utile nu numai pentru a fi folosite direct în optimizarea diagnosticãrii, ci pentru a creºte cunoºtinþele expertului uman sau a utilizatorului, mai mult ele pot ajuta producãtorul sã-ºi îmbunãtãþeascã controlul calitãþii ºi procesul de proiectare. Au fost cazuri când colecþia statisticilor despre produse defecte prin interogarea sistemelor locale de diagnosticare din lumea întreagã a fost motivul principal al introducerii de asemenea sisteme de diagnosticare în operaþii comerciale. Se utilizeazã fapte de forma statistic(N,Defect_Frequency_N) care sunt iniþializate când ºi sistemul se reiniþializeazã. Valorile pentru Defect_Frequency_N sunt egale cu 0 atâta timp cât causa unui defect N n-a fost încã întâlnitã. Cu fiecrare dignozã cu succes predicatul increment mãreºte frecvenþa corespunzãtoare cu 1.
increment(Nr):-
retract(statistic(Nr,State)), !, Newer_State = State + 1,
asserta(statistic(Nr,Newer_State)),
increment(_).
Dacã statisticile se colecteazã doar la nivelul cel mai de sus, aºa cum a fost implementat ºi în cazul sistemului expert HEATEXP, atunci predicatul increment poate fi direct inserat în regula check.:
check(R_No):-
defect(R_No,A,B,C),
increment(R_No),
store_this_step(R_No),
print_result(R_No,A,B,C).
Astfel statisticile stocate pot fi direct afiºate la cerere, de exemplu:
?- statistic(Defect,Frecventa).
Defect = 3
Frecventa = 4;
Defect = 2
Frecventa = 20;
Defect = 1
Frecventa = 13;
Defect = 4
Frecventa = 1;
no
Pentru a pãstra aceastã informaþie între sesiuni, un sistem comercial întotdeauna o sã stoceze faptele de tipul statistic în modul urmãtor:
telling(Output),
tell(statistics),
listing(statistic),
told, tell(Output).
În fiºierul de iniþializare se prevede încãrcarea unui fiºier de statistici conþinând valorile cumulative folosind comanda consult(statistics).
4.4. Învățare din "experiență"
Sã examinãm mai de aproape cum se pot utiliza date statistice pentru realizarea optimizãrii automate a strategiei de cãutare a defectelor în funcþie de "experienþa" sistemului expert. În cazul direcþionãrii strategiei de inferenþã prin reþele de legãturi probabilitãþile (adicã punctajul acordat) sunt stabilite de cãtre expertul în domeniu. Folosirea probabilitãþilor predefinite nu este întotdeauna foarte indicatã, deoarece frecvenþa unui defect mai special depinde foarte mult de locul unde este sistemul expert sau maºina utilizatã. (ordinea ipotezelor de defectare nu poate fi acelaºi în Hawai ori în Sahara.)
De aceea se doreºte ca fiecare sistem el însuºi sã-ºi poatã optimiza strategia sa de diagnosticare bazatã pe experienþa "statisticã" acumulatã local. Acesta este avantajul esenþial al controlului nedeterminist într-un sistem expert. În contrast, în cazul controlului determinist în algoritmii convenþionali, fluenþa execuþiei programului este fixatã în structuri statice de control care pot fi modificate doar prin rescrierea codului.
În multe cazuri unde se foloseºte probabilitatea evenimentelor, ca de exemplu apariþia unui anumit defect în cazul nostru, se poate aplica regula binecunoscutã de 20/80%, adicã 20% din defectele posibile sunt cauza a 80% din totalitatea reparaþiilor necesare (ºi cele 20% dintre defectele posibile sunt cele care diferã foarte mult în funcþie de loc). Dupã sortarea paºilor de diagnosticare în funcþie de frecvenþa lor statisticã, vom avea de investigat doar 20%/2 = 10% din toate defectele posibile în 80% dintre cazuri. Pe de altã parte, în cele 20% rãmase dintre cazuri vom avea succes doar dupã investigarea a aproximativ 60% dintre cauzele posibile.
Fãcând o estimare grosierã, se poate deduce cã, folosind o strategie de cãutare optimalã, un defect poate fi descoperit dupã verificarea a aproximativ (80*10+20*60)/100 = 20% din alternative. Acesta este mai puþin decât jumãtate din paºii necesari când se utilizeazã o bazã nesortatã, când ar trebui parcurse cam 50% dintre posibilitãþi. Deci într-adevãr pentru creºterea performanþelor se meritã sã se exploateze statisticile de diagnosticare, nu numai pentru cã scade timpul de execuþie, dar ºi pentru cã evitã testarea costisitoare ºi consumatoare de timp a obiectului de investigat.
În sistemul expert HEATEXP implementarea învãþãrii se bazeazã pe predicatele start pentru cãutarea în douã faze ilustrate în § 4.1. Se introduce în a doua clauzã a lui start un predicat denumit new_priorities care va sorta lista de ipoteze în funcþie de frecvenþele "învãþate":
new_priorities:-
statistic(1,A), statistic(2,B),
statistic(3,C), statistic(4,D),
sort([A,B,C,D],_,[1,2,3,4],New_List),
retract(hypotheses(_)),
asserta(hypotheses(New_List)).
Predicatul new_priorities realizeazã o resortare a listei de ipoteze corespunzãtor valorilor lui statistic curente. Predicatul de sortare este la fel ca ºi cel introdus la aplicarea statisticilor.
Bineînþeles în practicã se doreºte extinderea realizãrii statisticilor ºi la nivele mai de jos al cauzelor potenþiale ºi nu doar la nivelul cel mai de sus aºa cum am implementat pentru simplicitate. Acest lucru ar necesita includerea predicatului increment ºi în regulile cause cu succes. La nivele mai adânci nu se mai poate doar resorta simplu lista de ipoteze. Trebuie schimbatã ordinea diferitelor clause pentru fiecare defect posibil iar în cazul clauzelor ca conþin conjuncþii de alte clauze, ordinea lui cause în interiorul fiecãrui clause în funcþie de frecvenþa acelui cause. O asemenea restructurare a bazei de cunoºtinþe nu ar fi foarte dificil de implementat, dar în mod sigur ar afecta semnificativ performanþele de execuþie. În acest caz este preferabilã realizarea unui program utilitar de optimizare a performanþelor sistemului care poate fi rulat regulat, de exemplu zilnic, deoarece oricum frecvenþele relative de apariþie a unui defect nu se pot schimba în mod radical peste noapte.
CAP 5.
METODOLOGIA DEZVOLTĂRII PROGRAMELOR BAZATE PE CUNOȘTINȚE
Programarea bazatã pe cunoºtinþe necesitã ºi o anumitã formã de management de proiect. Nu se poate presupune însã, cã se poate aplica simplu metodologia "clasicã" de dezvoltare (proiectare) a programelor. Distincþia între algoritmi ºi date pe care se bazeazã multe alte tehnici, nu mai este valabilã. Cunoºtinþele sunt mult mai dinamice decât datele. Fazele de proiectare a unui asemenea program nu mai constituie defapt faze. Una din pãrþile importante ale proiectãrii sistemelor expert este aplicarea "metacunoºtinþelor".
5.1. Tehnologia programării bazate pe cunoștințe
Ingineria programãrii este mai mult decât programare ºi mai mult decât doar proiectare. Existã o necesitate realã de o metodologie sistematicã pentru fabricarea programelor ca ºi produse industriale. Acesta esta cazul ºi în dezvoltarea programelor bazate pe cunoºtinþe. Acest capitol trateazã aspectele metodologice de proiectare. Caracteristica importantã a programãrii sistemelor expert este integrarea ºi administrarea faptelor ºi regulilor, adicã a elementelor de tip datã ºi procedurã, în aceeaºi bazã de cunoºtinþe. Astfel modularizarea programelor este total diferitã. Aceastã modularizare se supune altor reguli decât cea în cazul programãrii algoritmice. Nu se mai potriveºte modelul proiect nici modelul fazã. Se poate aplica mai degrabã modelul "prototipului evolutiv". Acest model implicã "creºterea" programului spre produsul final prin paºi de rafinare ºi extindere a modelului iniþial având la început o bazã de cunoºtinþe corespunzãtor limitatã. În acelaºi timp, cunoºtinþele din majoritatea domeniilor cresc ºi se modificã în mod constant, deci "produsul final" adicã sistemul expert trebuie realizat astfel încât sã fie capabil sã acumuleze continuu aceste modificãri ale cunoºtinþelor.
Fazele nefiind clar limitate, activitãþi de genul: specificare, proiectare, programare, ºi testare nu pot fi fãcute în mod exclusiv, exhaustiv ºi definitiv. Fazele se vor întrepãtrunde, se vor comuta des. Putem totuºi sã definim un plan de proiect propus de P. Jackson (1986) prezentat în fig. 6.1.
fig. 5.1. Modelul fazelor pentru dezvoltarea sistemelor bazate pe cunoºtinþe
Este important faptul cã anumite faze au defapt conþinuturi diferite de cele în programarea algoritmicã.
Specificarea problemei
realizeazã acelaºi lucru ca ºi "Cerinþe/analiza problemei" în modelul proiect tradiþional determinând ce problemã trebuie rezolvatã, dacã are sens procesarea datelor pe calculator (în acest caz introducerea tehnicilor de programare bazate pe cunoºtinþe). Deja în aceastã fazã trebuie sã fie schiþat un "prototip minimal".
Formularea conceptelor de reprezentare
corespunde fazei clasice de "specificare". În aceastã fazã se stabileºte organizarea cunoºtinþelor : ce cunoºtinþe trebuie sã fie formalizate ºi stocate, sub ce formã ºi de la ce fel de experþi vor fi acestea colecþionate, se va folosi un shell existent sau se va scrie programul întreg în Prolog, se justificã necesitatea integrºrii unei banci de date în sistem sau nu, cum sã se modularizeze baza de cunoºtinþe, cum sã fie cunoºtinþele descompuse în fapte, reguli, metacunoºtinþe.
Proiectarea structurilor reprezentaþionale
chiar dacã ar corespunde cel mai bine fazei de "proiectare", aceastã fazã se întrepãtrunde cu faza de dinainte. Aici se planificã reprezentarea cunoºtinþelor, ce structurã sã se utilizeze, cum sã funcþioneze maºina de inferenþã ºi interfaþa de dialog, cum sã fie sticate informaþiile despre starea curentã a diagnosticãrii (analizei) ºi cum sã se realizeze un protocol, o reprezentare sub formã de cadre (dacã e cazul), procesarea cunoºtinþelor vagi. Deciziile luate în aceastã fazã vor determina uºurinþa, eficienþa ºi eleganþa implementãrii ºi rafinãrii ulterioare a procedurilor.
Formularea regulilor
se realizeazã bazându-se pe structurile alese în fazele anterioare. Se creazã prima bazã de cunoºtinþe pentru un sistem preliminar. Aceastã fazã poate fi echivalatã cu faza de "codare ºi implementare" din modelul proiect tradiþional ºi se întrepãtrunde cu fazele anterioare.
Validarea, integrarea ºi extensia
bazei de cunoºtinþe corespunde fazelor convenþionale de "testare, integrare ºi mentenanþã" a sistemului. În cazul programelor clasice "mentenanþa" înseamnã corecþia "bug"-urilor, adãugarea de noi facilitãþi, adaptarea preferinþelor clientului. În cazul programãrii orientate pe cunoºtinþe, însã, actualizarea cunoºtinþelor este o activitate continuã, cuoºtinþele niciodatã nu sunt "complete" ºi se schimbã în permanenþã. Necesitatea modificãrilor fundamentale neproblematice atât a cunoºtinþelor procedurale (bazate pe reguli) cât ºi a celor factuale, a dus la dezvoltarea unor metode ºi limbaje noi.
Actualizarea continuã a cunoºtinþelor nu constituie o problemã dacã organizarea ºi reprezentarea acelor cunoºtinþe sunt fãcute într-o asemenea manierã încât corpul acestora constituit din fapte ºi reguli, al cãror numãr creºte rapid, nu duce la dificultãþi structurale, ineficienþã ºi blocãri. Se observã ºi legãturile înapoi în fig. 6.1. Astfel:
"Actualizarea cunoºtinþelor" în timpul integrãrii bazei de cunoºtinþe în sistemul final necesitã o formulare continuã de noi fapte ºi reguli.
În timpul procesului de umplere a bazei de cunoºtinþe, pot fi descoperite în reprezentarea internã a acesteia diferite slãbiciuni. Acestea trebuiesc corectate prin modificãri ale proiectãrii, adicã introducând structuri reprezentaþionale extinse sau îmbunãtãþite.
Se poate ajunge într-un final în situaþia în care toate aceste modificãri nu mai sunt suficiente pentru a rezolva problema, astfel "Specificarea conceptelor de reprezentare" sau chiar ºi "Specificarea problemei" trebuie modificatã.
Primul tip de feedback este natural, s-a presupus dealtfel de la bun început necesitatea actualizãrii continue a bazei de cunoºtinþe. Ultimele douã tipuri însã, presupun schimbãri fundamentale ale produsului "finit", ceea ce este costisitor ºi dezagreabil în toate metodologiile de proiectare.
5.2. Prototipul
Este de obicei recomandatã evitarea ultimelor douã tipuri de legãturi înapoi menþionate mai înainte, chiar începând din prima fazã a dezvoltãrii unui sistem expert, adicã de la "Specificare problemei": dacã se defineºte corect problema de la început, atunci nu va mai trebui reformulatã mai târziu. Se testeazã ºi posibilitatea implementãrii sistemului definit. Mediul Prolog permite specificaþii formale ale structurilor necesare ºi este un limbaj bun de "prototipizare". Ideea este crearea rapidã a unui prototip care sã fie o bazã fermã pentru fazele urmãtoare în speranþa evitãrii surprizelor neplãcute mai târziu. Specificarea problemei necesitã deci mult mai mult decât cu cât suntem noi obiºnuiþi din metodele clasice de programare.
Multe sisteme expert nici nu ajung mai departe de faza de prototip, din cauza faptului cã integrarea ºi mentenanþa întregii baze de cunoºtinþe se dovedeºte a fi prea costisitoare sau prezintã interes minimal pentru persoanele responsabile cu service-ul. Când producem un prototip avem urmãtoarele trei obiective:
Cunoaºterea gradului de dificultate a colectãrii, formalizãrii, reprezentãrii cunoºtinþelor tipice din domeniul aplicaþiei;
Stabilirea fermã a aspectelor esenþiale ale reprezentãrii conceptelor ºi structurilor precum ºi dezvoltarea suficientã a mecanismelor de manipulare ale acestora astfel încât sã se elimine orice dubiu potenþial referitor la implementabilitatea ºi performanþa acestora;
Interfaþa (de dialog) cu utilizatorul sã fie implementatã ºi testatã pînã într-un grad în care un client sau utilizator final poate sã aibã o idee aproximativã despre comportarea, funcþionalitatea ºi performanþa sistemului.
Aceste obiective sunt mult mai complexe decât cele în cazul prototipului obiºnuit pentru cã dezvoltarea unui sistem expert necesitã trei participanþi diferiþi în afarã de programator: expertul în domeniu, inginerul de cunoºtinþe ºi utilizatorul, interacþiunea lor cu baza de cunoºtinþe find la rândul ei diferitã. Aceste trei aspecte diferite sunt cuplate în mod strâns atât din punct de vedere concepþional cât ºi din punctul de vedere al implementãrii, de aceea trebuie sã fie plãniute ºi dezvoltate în paralel.
Se estimeazã cã un expert sau un specialist cu experienþã poate avea în creierul sãu cunoºtinþe gata disponibile la un moment dat, translatabile în circa 50 pânã la 100 000 de clause Prolog. Astfel, câteva sute de reguli, neluând în considerare cele necesare funcþionãrii sitemului ºi realizãrii interfeþei cu utilizatorul, reprezintã doar o micã porþiune din cunoºtinþele totale ale expertului. De aceea este necesarã definirea clarã ºi neambigoasã a unui subset modest al acestor cunoºtinþe. Se recomandã introducerea, testarea ºi validarea continuã a cunoºtinþelor împreunã cu expertul în domeniu.
Baza preliminarã de cunoºtinþe trebuie sã aibã o stabilitate suficientã înainte de a începe lucrul cu interfaþa. Prezentarea unui model precoce a sistemului expert utilizatorului final poate fi foarte periculoasã. Dacã funcþionalitatea "proto-modelului" nu este adecvatã sau destul de robustã, atunci existã riscul dobândirii unei reputaþii de a fi "trivial" sau de a nu sugera încredere, stare ce este foarte greu de depãºit.
Dacã se intenþioneazã completarea unlterioarã a bazei de cunoºtinþe de cãtre expert sau altã persoanã special educatã în acest scop, atunci cât se poate de repede trebuie planificatã ºi prototipizatã ºi o componentã corespunzãtoare pentru achiziþia interactivã a cunoºtinþelor, în vederea construirii rapide a unei baze de cunoºtinþe netriviale ºi destul de complexã permiþând prezentarea unui prototip care sã ofere o impresie realisticã despre performanþele produsului final. Ca ºi o estimare a timpului de dezvoltare a prototipului se preconizeazã 3-8 sãptãmâni de muncã/om în funcþie de complexitatea aplicaþiei ºi a cunoºtinþelor.
5.3. Strategii de inferență și metasisteme
Cum poate fi implementat o strategie doritã depinde, printre altele, de posibilitãþile existente în limbajul de programare folosit. Lisp ºi Prolog, de exemplu, oferã programatorului o mare libertate în acest sens. Shell-urile permit de obicei folosirea a una sau a câtorva strategii, dar nu ºi implementarea a celor noi, proprii.
Pentru implementarea strategiilor proprii sunt folosite mai frecvent douã metode: inferenþa bazatã pe context sau folosirea metaregulilor. În cazul strategiilor bazate pe context inginerul de cunoºtinþe introduce aplicabilitatea unei reguli direct în corpul fiecãrei reguli. Maºina de inferenþã va compara aceste informaþii cu un focus curent ºi va decide dacã o anumitã regulã se va aplica sau nu. Formatul general al regulilor în acest caz ar fi:
rule(Numere,
Informatia_de_aplicabilitate,
Sectiunea_de_constrangeri_a_regulii,
Sectiunea_de_Actiuni_a_regulii).
Utilizarea metaregulilor presupune includerea unor reguli speciale de control în baza de cunoºtinþe care determinã ce regulã se aplicã în ce condiþii, adicã atribuie unor reguli particulare un anumit accent (focus) al activitãþilor de procesare. Formatul general al unor asemenea metareguli ar putea fi:
regula_aplicabila(Accent,Lista_reguli)
Metacacunoºtinþele sunt foarte importante pentru structurarea ºi implementarea eficientã a sistemelor expert inteligente. Distincþia fundamentalã între cunoºtinþe ºi metacunoºtinþe este aceea cã prin cunoºtinþe înþelegem "know-how"-ul informaþional al expertului uman care este stocat direct sub forma faptelor ºi regulilor iar prin metacunoºtinþe înþelegem "cunoºtinþe despre cunoºtinþe", adicã despre structura sa, utilizarea sa (prin euristici)ºi derivarea de cunoºtinþelor noi din cele existente. Existã deci mai multe nivele de metacunoºtinþe: metacunoºtinþele de nivel mai jos care se ocupã de exemplu de caracteristicile formulelor matematice pot fi utilizate de metacunoºtinþe de nivel mai înalt care utilizeazã formule noi derivate prin aplicarea anumitor operaþii formale, ca ºi diferenþiere ºi integrare.
Existã deci diferite tipuri de metacunoºtinþe ºi mai multe modalitãþi de a le aplica:
dacã existã un anumit numãr de reguli potenþial aplicabili, atunci metacunºtinþele (euristice) determinã ordinea în care acestea trebuie sã fie aplicate. Existã metacunoºtinþe despre calitatea cunoºtinþelor aplicate sau metacunoºtinþe care se referã la succesele de pânã acum a unor reguli specifice în anumite condiþii.
în mod similar în afarã de reordonarea regulilor în funcþie de metacunoºtinþe, chiar ºi regulile pot fi fãcute mai eficiente prin reorganizarea constrângerilor în cadrul regulei respective, astfel ca cele care cauzeazã rejecþia cea mai frecventã sã fie întâlnite mai la început.
alt tip de metacunoºtinþe este cel dupã care se decide ce rezultate intermediare ar putea fi stocate ca ºi fapte independente sau reguli în baza de cunoºtinþe pentru a elimina recalcularea lor repetatã (exemplul calculului numerelor Fibonacci).
Cum metacunoºtinþele reprezintã cunoºtinþe despre ºi peste cunoºtinþele specifice unei domenii specifice, pot fi colectate intr-un pachet, denumit metasistem care poate servi ca ºi superstructurã pentru diverse baze de cunoºtinþe. Conceptul este deja cunoscut sub denumirea de shell. Shell-ul este o abordare mai pragmaticã a metasistemului, într-adevãr multe shell-uri au fost obþinute prin "golirea" sistemului expert de cunoºtinþele specifice domeniului pentru care a fost implementat. Formularea metacunoºtinþelor ºi a implementãrii acestora în metasisteme este însã un proces mai teoretic. Un avantaj al acetuia este uºurinþa de detectare a greºelilor subtile ºi astfel a limitãrilor sistemului.
Pentru a decide între realizarea unui program de sine stãtãtor sau utilizarea unui shell prefabricat Se recomandã testarea urmãtoarelor caracteristici ale shell-ului:
Ce facilitãþi oferã pentru modularizare? Vor fi acestea adecvate pentru urmãtorii cinci, zece ani?
Cum se poate conecta cu bãncile de date existente, pachete soft convenþionale, programe de comunicaþie?
Se pot folosi editoarele, meniurile, interfeþele existente sau acestea trebuie sã fie schimbate cu cel din shell (dacã existã)?
Faciliteazã introducerea ºi scoaterea datelor din respectiv în alte procesoare de date?
Mesajele de explicare, eroare pot fi create, modificate separat ºi traduse în alte limbaje?
Este shell-ul portabil astfel cã existã ºansa ca el sau aplicaþiile produse cu el pot fi rulate pe generaþiile viitoare de calculatoare?
5.4. Concluzii
În aceastã lucrare s-au tratat niºte metode de proiectare ºi tehnici de programare noi pentru realizarea unui sistem expert bazat pe cunoºtinþe. Intenþionat s-a pus accent pe realizarea unui program într-un limbaj de programare de nivel înalt, de exemplu în Prolog, în loc de introducerea simplã a cunoºtinþelor unui expert uman într-un domeniu într-un shell deja existent.
La început s-a introdus structura arhitecturii sistemelor expert subliniând caracteristicile ºi componentele principale. S-a arãtat cã sisteme expert bune cu interfaþã prietenoasã cu utilizatorul, integrabile direct cu bazele de date ºi aplicaþiile existente, pot fi realizate prin crearea tuturor componentelor adiþionale care pot ori lipsi dintr-un mediu de dezvoltare (shell) ori nu sunt adecvate scopului propus. În implementarea practicã a acestor metode s-a folosit jonglarea între interpretarea logicã ºi cea proceduralã a unui text de program într-un limbaj logic. S-au realizat douã sisteme expert (MTA ºi HEATEXP), înglobând toate componentele necesare care pot echipa sisteme soft cu atributele ºi caracteristicile necesare care pot în mod real califica un sistem ca fiind expert.
Dintre aceste componente s-a considerat cã prezintã interes mai mare ºi necesitã tehnici speciale de programare, componenta explicativã ºi dialog precum ºi cea de învãþare ºi modificare, acestea fiind dezbãtute mai pe larg. S-a prezenat cum se conduce un dialog, cum se realizeazã achiziþia, recunoaºterea, validarea, analiza ºi stocarea datelor de caz referitoare la utilizatorul curent precum ºi arborele de inferenþã ºi protocolul intern pe care se bazeazã componenta explicativã.
Componenta adaptivã s-a realizat prin utilizarea euristicilor bazate pe reþele relaþionale între simptome ºi defecte. Învãþarea s-a implementat prin optimizarea strategiei de diagnosticare bazatã pe "experienþa" statisticã acumulatã în timp a frecvenþei de realizare cu succes a anumitor diagnoze. Shell-urile în schimb, care sunt defapt metasisteme, permit de obicei folosirea a una sau a câtorva strategii, dar nu ºi implementarea a celor noi, proprii.
S-a descris metodologia dezvoltãrii programelor bazate pe cunoºtinþe, modelului fazelor de realizare a sistemelor expert, etapele acestuia. S-a arãtat cã mediul Prolog permite specificaþii formale ale structurilor necesare ºi este un limbaj adecvat pentru "prototipizare evolutivã", ceea ce înseamnã crearea cât mai rapidã a unui prototip care sã utilizeze o bazã preliminarã de cunoºtinþe ºi sã ofere toate componentele necesare unui sistem expert funcþionale la performanþele cerute. Cum cunoºtinþele din majoritatea domeniilor cresc ºi se modificã în mod constant, "produsul final" adicã sistemul expert realizat este capabil sã acumuleze în continuu aceste modificãri.
Bibliografie
Joseph Giarratano, Gary Riley, Expert Systems. Principles and Programming, PWS-KENT Publishing Company, Boston, 1989.
Suran Goonatilake, Sukhdev Khebbal, Intelligent Hybrid Systems, John Wiley & Sons, Chichester, England, 1995.
P. Jackson, Introduction to Expert Systems, Addison-Wesley, Wokingham, 1986.
George F. Luger, William Stubblefield, Artificial Intelligence and the Design of Expert Systems, 1994.
Peter Schnupp, Chau Thuy Nguyen Huu, Lawrence W. Bernhard, Expert Systems Lab Course (translation of Expertensystem-Praktikum) Springer-Verlag, 1989.
Anexa 1
/**********************************************************************
Modulul MTA.PRO contine predicatul assistance si include alte doua module, baza de cunostinte si modelul de control din prototipul sistemului expert MTA.
**********************************************************************/
nowarnings
include "rule_b3.pro"
include "controll.pro"
PREDICATES
assistance
CLAUSES
assistance:-
clearwindow, write("I am a small Prolog program, "),
write("my name is MTA."), nl,
write("MTA stands for Munich Transport Authority."), nl,
write("My job is to help you select "), write("the proper ticket "), nl,
write("for travel in the central city zone."), nl,
write("You must cancel 2 fields of a ticket "), write("for a single trip"), nl,
write("The following tickets are available:"), nl,
write("- Single trip tickets, with 2 fields "), write("for 2.30 DM and"), nl,
write("- Type A multiple trip tickets, with "), write("7 fields for 6.50 DM and "),
nl, write("- Type B multiple trip ticket, "), write("with 13 fields for 12 DM."),
nl,nl,write("In addition, for persons under "), write("15 or pets, we have"), nl,
write("- Kiddie tickets, with 8 fields for 5.00 DM."), nl,nl,
write("Passengers travelling less then "), write("5 kilometers can"), nl,
write("use a kiddie ticket regardless of age."), nl,
write("If you would like my help "),
write("in selecting a ticket, "), write("enter 'mta.'"), nl,
write("With 'restart' you can start a "), write("fresh session, i.e."), nl,
write("any recorded facts will be forgotten."), nl, readchar(_), fail.
assistance:-
clearwindow, nl, write("Possible questions are:"), nl, nl,
write("- assistance."),nl,
write("- mta."),nl,
write("- is_a_Kiddie_Ticket_possible."), nl,
write("- is_a_Multi_Trip_Ticket_A_possible."), nl,
write("- is_a_Multi_Trip_Ticket_B_possible."), nl,
write("- is_a_Single_Trip_Ticket_possible."), nl,
write("- must_one_ride_without_paying."), nl,
write("- must_one_walk."), nl,
write("- restart. -> deletion of old data."), nl,
write("- tree(Step,Rule). -> show tree."), nl, nl.
/**********************************************************************
CONTROLL.PRO contine structura de control pentru parcurgerea optiunilor de calatorie
**********************************************************************/
PREDICATES
recommend_multi_trip_ticket_A
recommend_multi_trip_ticket_B
recommend_childrens_ticket
recommend_single_trip_ticket
recommend_non_payment_of_fare
recommend_walking
two_fields
mta
CLAUSES
/* Clausele mta reprezinta ipotezele despre alternativele de trasport ordonate de la cel mai ieftin pana la cel mai scump */
mta:-
enter_current_rule(100),
is_a_Kiddie_Ticket_possible, recommend_childrens_ticket.
mta:-
enter_current_rule(101),
is_a_Multi_Trip_Ticket_B_possible, recommend_multi_trip_ticket_B.
mta:-
enter_current_rule(102),
is_a_Multi_Trip_Ticket_A_possible, recommend_multi_trip_ticket_A.
mta:-
enter_current_rule(103),
is_a_Single_Trip_Ticket_possible, recommend_single_trip_ticket.
mta:-
enter_current_rule(104),
must_one_ride_without_paying, recommend_non_payment_of_fare.
mta:-
enter_current_rule(105),
must_one_walk, recommend_walking.
/*********************************************************************/
/* Recomandarile care vor fi afisate: */
recommend_multi_trip_ticket_A:-
write("\nYou shoud buy a Type A Multi "),
write("Trip Ticket for 6.50 DM."), two_fields.
recommend_multi_trip_ticket_B:-
write("\nYou shoud buy a Type B Multi "),
write("Trip Ticket for 12 DM."), two_fields.
recommend_childrens_ticket:-
write("\nYou shoud buy a Kiddie Ticket "),
write("for 5 DM."), two_fields.
recommend_single_trip_ticket:-
write("\nYou shoud buy a Single Trip Ticket "),
write("for 2.30 DM ."), two_fields.
recommend_non_payment_of_fare:-
write("\nYou should ride without bying a ticket!!!.").
recommend_walking:-
write("\nYou sould go on foot.").
two_fields:-
nl, write("And remember to cancel two fields!\n").
/**********************************************************************
RULE_B3.PRO contine baza de cunostinte = posibilitati de calatorie, parcurs de interpretorul de reguli.
**********************************************************************/
include "aux_p2.pro"
include "dialog.pro"
PREDICATES
query(symbol,integer)
is_a_Kiddie_Ticket_possible
is_a_Multi_Trip_Ticket_B_possible
is_a_Multi_Trip_Ticket_A_possible
is_a_Single_Trip_Ticket_possible
must_one_ride_without_paying
must_one_walk
CLAUSES
/* Regulile pentru posibilitatea utilizarii biletului Kiddie_Ticket continand
si colectarea datelor referitoare la calator = date de caz */
is_a_Kiddie_Ticket_possible:-
status(cash,unknown), query(cash,1), fail.
is_a_Kiddie_Ticket_possible:-
status(cash,Money), str_real(Money,M),
M>=5, status(age,unknown), query(age,2), fail.
is_a_Kiddie_Ticket_possible:-
status(cash,Money), str_real(Money,M), M>=5, status(age,child),
enter_current_rule(3), !.
is_a_Kiddie_Ticket_possible:-
status(cash,Money), str_real(Money,M), M>=5,
status(distance,unknown), uery(distance,4), fail.
is_a_Kiddie_Ticket_possible:-
status(cash,Money), str_real(Money,M), M>=5, status(distance,near),
enter_current_rule(5).
query(S,N):-
enter_current_rule(N),
set(level,3), ask(S,A), !, asserta(status(S,A)), retract(status(S,unknown)),!.
/*********************************************************************/
is_a_Multi_Trip_Ticket_B_possible:-
status(cash,unknown), query(cash,6), fail.
is_a_Multi_Trip_Ticket_B_possible:-
status(cash,Money), str_real(Money,M), M>=12, enter_current_rule(7).
is_a_Multi_Trip_Ticket_A_possible:-
status(cash,unknown), query(cash,8), fail.
is_a_Multi_Trip_Ticket_A_possible:-
status(cash,Money), str_real(Money,M), M>=6.50, enter_current_rule(9).
/************************************************************************/
is_a_Single_Trip_Ticket_possible:-
status(cash,unknown), query(cash,10), fail.
is_a_Single_Trip_Ticket_possible:-
status(cash, Money), str_real(Money,M), M>=2.30, enter_current_rule(11).
/*********************************************************************/
must_one_ride_without_paying:-
status(cash,unknown), query(cash,12), fail.
must_one_ride_without_paying:-
status(cash,Money), str_real(Money,M),
M < 2.30, status(boldness,unknown), query(boldness,13), fail.
must_one_ride_without_paying:-
status(cash,Money), str_real(Money,M),
M < 2.30, status(boldness,daring), enter_current_rule(14).
/*********************************************************************/
must_one_walk:-
status(cash,unknown), query(cash,15), fail.
must_one_walk:-
status(cash,Money), str_real(Money,M),
M< 2.30, status(boldness,unknown), query(boldness,16), fail.
must_one_walk:-
status(cash,Money), str_real(Money,M), M< 2.30, status(boldness,timid),
enter_current_rule(17).
/**********************************************************************
AUX_P2.PRO contine daclararile bazelor de date folosite precum si predicatele utilizate anipularii acestora.
**********************************************************************/
DATABASE
status(symbol,symbol) /* informatii de stare */
tree(integer,integer) /* b.d.d. externa care contine drumul parcurs in
arborele de inferenta la ultima consultatie */
level(integer) /* contine la fiecare moment nivelul din arbore */
step(integer) /* pasul actual de parcurgere */
increment(integer) /* incrementare cu o unitate sau doua */
PREDICATES
restart
set(symbol,integer)
enter_current_rule(integer)
enter_current_level
set_incr(integer)
CLAUSES
/* Cu restart se initializeaza toate cunostintele cu "necunoscut" */
restart:-
retractall(status(_,_)),
asserta(status(cash,unknown)), asserta(status(age,unknown)),
asserta(status(distance,unknown)), asserta(status(boldness,unknown)),
retractall(tree(_,_)), assertz(tree(0,0)),
set(step,0), set(level,0), set(increment,2).
set(step,I):-
retractall(step(_)), asserta(step(I)).
set(level,I):-
retractall(level(_)), asserta(level(I)).
set(increment,I):-
retractall(increment(_)), asserta(increment(I)).
/* Inregistrarea reguli curente consultate: */
enter_current_rule(Rule_Number):-
retract(step(State)), New = State +1, assertz(step(New)),
assertz(tree(New,Rule_Number)), set_incr(Rule_Number), !.
/* Pentru nivelul 2 (Rule_Number>99) incrementul va fi 1, altfel 2 : */
set_incr(Rule_Number):-
Rule_Number > 99, set(increment,1), !.
set_incr(Rule_Number):- !.
/* Inregistrarea nivelului curent: */
enter_current_level:-
retract(level(Old)), increment(Increment),
New = Old – Increment, assertz(level(New)).
/**********************************************************************
DIALOG.PRO contine predicatele de formularea unei intrebari precum si recunoastere si interpretare a raspunsului utilizatorului
**********************************************************************/
include "expl2.pro"
PREDICATES
recognize(string,symbol)
non_interpretable
ask(symbol,symbol)
test_f1(symbol,symbol)
test_f2(symbol,symbol)
test_f3(symbol,symbol)
test_f4(symbol,symbol)
CLAUSES
/* Interpretarea raspunsului utilizatorului acceptand si raspunsuri echivalente
prin detectarea sinonimelor: */
recognize(Input,yes):-
member_str(Input,[yes,y,certainly,"of course", yeah]), !.
recognize(Input,no):-
member_str(Input,[n,no]), !.
recognize(Input,why):-
member_str(Input,[why,"Why","how come"]), !.
recognize(Input,"not sure"):-
member_str(Input,["who knows","not sure","no idea",perhaps]), !.
recognize(Input,Input):- !.
non_interpretable:-
nl,write("I cannot interpret your response."),nl,
write("Please reenter your answer."),nl.
/* Intrebare referitoare la bani, distanta, varsta si curaj cu verificarea si analiza raspunsului: */
ask(cash,F1):-
write("How much money do you have? "), readln(Input),
recognize(Input,Money), test_f1(Money,F1).
ask(age,F3):-
write("How old are you? "), readln(Input),
recognize(Input,Age), test_f3(Age,F3).
ask(boldness,F4):-
write("Are you daring? "), readln(Input),
recognize(Input,Courage), test_f4(Courage,F4).
/* Interprearea raspunsului: */
test_f1(Money,Money):-
str_real(Money,M), !.
test_f1(none,"0"):- !.
test_f1(enough,"13"):- !.
test_f1(why,F1):-
!, write_explanation, enter_current_level, ask(cash,F1).
test_f1(_,F1):-
non_interpretable, ask(cash,F1).
test_f2(Distance,near):-
str_real(Distance,D), D<=5, !.
test_f2(Distance,far):- str_real(Distance,D), !.
test_f2("not sure",far):- !.
test_f2(why,F2):-
!, write_explanation, enter_current_level, ask(distance,F2).
test_f2(_,F2):-
non_interpretable, ask(distance,F2).
test_f3(Age,child):-
str_real(Age,A),A<= 14,!.
test_f3(Age,adult):-
str_real(Age,A),!.
test_f3("not sure",adult):- !.
test_f3(why,F3):-
!, write_explanation, enter_current_level, ask(age,F3).
test_f3(_,F3):-
non_interpretable, ask(age,F3).
test_f4(yes,daring):- !.
test_f4(no,timid):- !.
test_f4("not sure",timid):- !.
test_f4(why,F4):- !,
write_explanation, enter_current_level, ask(boldness,F4).
test_f4(_,F4):-
non_interpretable, ask(boldness,F4).
/**********************************************************************
EXPL2.PRO contine clausele predicatelor folosite in implementarea componentei explicative.
**********************************************************************/
DOMAINS
int_list=integer*
str_list=string*
PREDICATES
member(integer,int_list)
member_str(string,str_list)
write_explanation
and_so
explanation(integer,integer)
CLAUSES
/* Apartenenta la o lista de intregi: */
member(X,[X|_]).
member(X,[_|T]):-member(X,T).
/* Apartenenta la o lista de string: */
member_str(X,[X|_]).
member_str(X,[_|T]):-member_str(X,T).
write_explanation:-
level(Level), step(Step), tree(Step,Rule), nl,nl, explanation(Level,Rule), !.
and_so:-
nl, nl, write("Now: ").
/* Raspunsul la intrebarea "why" difera in functie de nivelul si regula aplicata
din arborele de inferenta: */
/* Nivelul 1 */
explanation(1,_):-
write("I want to find the least expensive "),
write("ticket for your trip."), and_so.
/* Nivelul 2 */
explanation(2,Numar):-
member(Numar,[1,2,4]),
write("Because a Kiddie Ticket is the cheapest."), and_so.
explanation(2,_):-
write("Since you do not have enought money."), write("for a ticket,"), nl,
write("I must look for another solution."), and_so.
/* Nivelul 3 */
explanation(3,1):-
write("To buy a Kiddie Ticket you must: "),nl,
write(" – have at least 5 DM and"),nl,
write(" – be unther 15 years of age."),nl,nl,
write("So I would like to know if you have at least 5 DM."), and_so.
explanation(3,2):-
write("I know that you have more then 5 DM."),nl,
write("Consequently, if you are under 15 years of age, "),nl,
write("you can buy a Kiddie ticket."),nl,
write("So I would like to know if you are under 15."), and_so.
explanation(3,4):-
write("I know that you have more than 5 DM."),nl,
write("Consequently if you are making a short trip"),nl,
write("you can buy a Short Trip Ticket (Kiddie Ticket)."),nl,
write("A short trip is less than 5 kilometers."),nl,
write("So, I would like to know how long the route is."), and_so.
explanation(3,6):-
write("You must have at least 12.00 DM to "),
write("buy a Type B Multi Trip Ticket."),nl,nl,
write("That is why I want to know if you have at least 12 DM? "), and_so.
explanation(3,8):-
write("You must have at least 6.50 DM to "),
write("buy a Type A Multi Trip Ticket."),nl,nl,
write("That is why I want to know if you have at least 6.50 DM? "), and_so.
explanation(3,10):-
write("You must have at least 2.30 DM to "),
write("buy a Single Trip Ticket."),nl,nl,
write("That is why I want to know if you have at least 2.30 DM? "), and_so.
explanation(3,12):-
write("You should only ride without paying "),
write("if you"),nl,
write(" – have less than 2.30 and"),nl,
write(" – are willing to risk a fine if caught. "),nl,nl,
write("Therefore, I first want to know if you have more than 2.30 DM."), and_so.
explanation(3,15):-
write("You must go on foot, if you"),nl,
write(" – have less than 2.30 DM and"),nl,
write(" – are unwilling to risk being caught."),nl,nl,
write("Therefore, I first want to know "),
write("if you have more than 2.30 DM."), and_so.
explanation(3,_):-
write("I want to know if you are willing to take"),nl,
write("a risk to get to your destination quickly?"), and_so.
/* In radacina: */
explanation(_,_):-
write("How about fewer questions and more answers!"), and_so.
Anexa 2
/**********************************************************************
HEATEXP.PRO contine predicatul "assistenta" si include toate celelalte module utilizate in acest prototip de sistem expert de diagnosticare a defectelor unui automobil
**********************************************************************/
code = 10000
nowarnings
include "initial.pro"
include "learn.pro"
include "testaids.pro"
include "dialog.pro"
include "expl.pro"
include "ipoteze.pro"
include "knowb1.pro"
include "main_prg.pro"
PREDICATES
assistance
delete_previous_step
CLAUSES
assistance:-
nl, write("Possible inputs:"),nl,nl,
write("start. => Begin the diagnosis."), nl, fail.
assistance:-
write("Rule of thumb. => Defect search with preparatory tests."),
nl,write("reason. => Display the line of reasoning"),
write("why_not(N). => Why does rule 'N' not apply?"),nl,
nl, fail.
assistance:-
write("rule(N). => Display rule 'N'."),nl,
write("facts. => Display all currently known facts."),nl,
write("restart. => Delete accumulated facts."),
nl, fail.
assistance:-
write("statistics(N,How_often).=>How often has the cause 'N'
already been Diagnosed?"),
nl, write("assistance. => Display this list."),nl.
delete_previous_step:-
retractall(step(1)), retractall(applied_rule(2)), asserta(step(0)).
/**********************************************************************
Modulul INITIAL.PRO contine declararea tuturor domeniilor general utilizate in toate modulele precum si bazele externe folosite pentru reprezentarea cunostintelor si predicatul de initilizare al acestei baze de cunostinte a sistemului expert
**********************************************************************/
DOMAINS
Rule_No=integer
Subject=string
Verb=string
Attribute=string
Status=string
Stringlist=string*
Intlist=integer*
Causes=Causes(Rule_No,Subject,Verb,Attribute)
Causelist=causes*
Triplet=Triplet(string,string,string)
Tripletlist=triplet*
DATABASE
fact(Subject,Verb,Attribute,Status)
do_not_know_entered(string)
phase(integer)
step(integer)
applied_rule(integer,Rule_No)
point(integer,integer,string)
statistic(integer,integer)
hypotheses(Intlist)
PREDICATES
initializare
CLAUSES
initializare:-
retractall(do_not_know_entered(_)),
asserta(do_not_know_entered(no)),
retractall(phase(_)),
asserta(phase(2)),
retractall(step(_)),
asserta(step(2)),
retractall(applied_rule(_,_)),
/* Toate faptele se considera necunoscute la inceperea unei noi sesiuni de
diagnosticare: */
/* The heater is defective */
retractall(fact(_,_,_,_)),
asserta(fact("the heater",is,defective,unknown)),
asserta(fact("the heater blower",is,defective,unknown)),
asserta(fact("the heating regulator",is,defective,unknown)),
asserta(fact("the water pump",is,defective,unknown)),
asserta(fact("the heat exchanger",is,defective,unknown)),
/* The heater blower is defective */
asserta(fact("the fuse",is,defective,unknown)),
asserta(fact("the switch",is,defective,unknown)),
asserta(fact("the cable",is,defective,unknown)),
asserta(fact("the blower",is,stuck,unknown)),
asserta(fact("the jumper cable",is,defective,unknown)),
asserta(fact("the blower motor",is,defective,unknown)),
asserta(fact("the battery",is,empty,unknown)),
/* The heating regulator is defective */
asserta(fact("the Bowden cable",is,broken,unknown)),
asserta(fact("the Bowden cable",is,stuck,unknown)),
asserta(fact("the heater valve",is,stuck,unknown)),
asserta(fact("the heater valve",is,clogged,unknown)),
/* The water pump is defective*/
asserta(fact("the V-belt",is,torn,unknown)),
asserta(fact("the V-belt",is,loose,unknown)),
asserta(fact("the water pump",is,stuck,unknown)),
asserta(fact("the water pump",is,clogged,unknown)),
asserta(fact("the water pump",is,leaky,unknown)),
/* The heat exchanger is defective */
asserta(fact("the heat exchanger",is,"dirty on the outside",unknown)),
asserta(fact("the heat exchanger",is,clogged,unknown)),
asserta(fact("the heat exchanger",is,leaky,unknown)),
asserta(fact("the coolant",is,frozen,unknown)),
asserta(fact("the system",is,"low on coolant",unknown)),
asserta(fact("air","there is","in the coolant",unknown)).
/**********************************************************************
MAIN_PRG.PRO reprezinta programul principal
**********************************************************************/
DOMAINS
Rule_list=Rule_No*
PREDICATES
start
examine(Rule_list)
note_phase(integer)
check(Rule_No)
CLAUSES
/* Regula start pentru masina de inferenta: */
start:- note_phase(1), hypotheses(Hypotheses_List), examine(Hypotheses_List).
start:-
note_phase(2), new_priorities, hypotheses(New_Hypotheses_List),
examine(New_Hypotheses_List).
examine([]):-
phase(2), nl,write("I cannot find any defects.").
examine([Alternatives|_]):- check(Alternative).
examine(_|Others]):- examine(Others).
check(R_No):-
defect(R_No,A,B,C), increment(R_No),
store_this_step(R_No), print_result(R_No,A,B,C).
notephase(P):- retract(phase(_)), asserta(phase(P)).
/**********************************************************************
KNOWB1.PRO contine baza de reguli pentru sistemul expert de diagnosticare a defectelor unui automobil
**********************************************************************/
PREDICATES
defect(Rule_No,Subject,Verb,Attribute)
cause (Rule_No,Subject,Verb,Attribute)
clause_defect(Rule_No,Subject,Verb,Attribute,Causelist)
append_Causelist(Causes,Causelist)
CLAUSES
append_Causelist([],L).
append_Causelist([X|L1],L2,[X|L3]):- append_Causelist(L1,L2,L3).
clause_rule(N,A,B,C,Cslist):-
defect(N,A,B,C), cause(N,CA,CB,CC),
append_Causelist(Causes(N,CA,CB,CC),Cslist,Cslist).
/* Procesarea cauzelor: */
cause(_,A,B,C):-
/* the cause already exists as a fact: */
fact(A,B,C,true),!.
cause(_,A,B,C):-
/* the cause definitely inapplicable: */
fact(A,B,C,false), !,fail.
cause(_,A,B,C):-
/* the cause leads to further causes: */
!,defect(_,A,B,C).
cause(N,A,B,C):-
/* the user must be questioned about the cause: */
fact(A,B,C,unknown), ask(N,A,B,C).
/* Defectele de pe nivelul unu din structura ierarhica */
defect(1,"the heater",is,defective):-
cause(1,"the heater blower",is,defective).
defect(2,"the heater",is,defective):-
cause(2,"the heating regulator",is,defective).
defect(3,"the heater",is,defective):-
cause(3,"the water pump",is,defective).
defect(4,"the heater",is,defective):-
cause(4,"the heat exchanger",is,defective).
/* Nivelul doi: */
defect(11,"the heater blower",is,defective):-
cause(11,"the fuse",is,defective).
defect(12,"the heater blower",is,defective):-
cause(12,"the switch",is,defective),
cause(12,"the cable",is,defective).
defect(13,"the heater blower",is,defective):-
cause(13,"the blower",is,stuck),
cause(13,"the jumper cable",is,defective),
cause(13,"the blower motor",is,defective).
defect(14,"the heater blower",is,defective):-
cause(14,"the blower motor",is,defective),
cause(14,"the battery",is,empty).
defect(21,"the heating regulator",is,defective):-
cause(21,"the Bowden cable",is,broken).
defect(22,"the heating regulator",is,defective):-
cause(22,"the Bowden cable",is,stuck),
cause(22,"the heater valve",is,stuck).
defect(23,"the heating regulator",is,defective):-
cause(23,"the Bowden cable",is,stuck),
cause(23,"the heater valve",is,clogged).
defect(31,"the water pump",is,defective):-
cause(31,"the V-belt",is,torn),
cause(31,"the water pump",is,stuck).
defect(32,"the water pump",is,defective):-
cause(32,"the V-belt",is,loose),
cause(32,"the water pump",is,clogged).
defect(33,"the water pump",is,defective):-
cause(33,"the V-belt",is,loose),
cause(33,"the water pump",is,leaky).
defect(41,"the heat exchanger",is,defective):-
cause(41,"the heat exchanger",is,"dirty on the outside"),
cause(41,"the heat exchanger",is,clogged).
defect(42,"the heat exchanger",is,defective):-
cause(42,"the heat exchanger",is,"dirty on the outside"),
cause(42,"the heat exchanger",is,leaky).
defect(43,"the heat exchanger",is,defective):-
cause(43,"the heat exchanger",is,"dirty on the outside"),
cause(43,"the coolant",is,frozen).
defect(44,"the heat exchanger",is,defective):-
cause(44,"the system",is,"low on coolant"),
cause(44,"air","there is","in the coolant").
/**********************************************************************
Modulul DIALOG.PRO contine toate clausele predicatelor de dialog si interfata cu utilizatorul
**********************************************************************/
GLOBAL PREDICATES
why(Rule_No)-(i) /* Acest predicat este descris in modulul expl.pro */
PREDICATES
ask(integer,Subject,Verb,Attribute)
write_this_sentence_uppercase(string,string,string)
write_this_sentence_lowercase(string,string,string)
read_in(string)
recognize(string,integer,string,string,string)
meaning(string,string)
deal_with_vague_answers(integer,Subject,Verb,Attribute)
display_test(string,string,string)
write_text_module1
write_text_module2
write_text_module3
write_text_module4
write_experiment(Stringlist)
write_this_term_uppercase(string)
write_uppercase(string,string)
write_the_rules_applied
write_rules(Intlist)
write_additional_rule(Intlist)
word_in_list(string,string,Stringlist)
read_word(integer,char,string)
rest_of_word(string,Stringlist,string):-
in_word(dtring)
note_do_not_know_entered(string)
CLAUSES
/* Achizitionarea datelor referitoare la utilizator (date de caz): */
/* Clausa 'ask' realizeaza doua actiuni: */
/* 1. construieste o intrebare si */
/* 2. citeste si evalueaza raspunsul utilizatorului. */
ask(Nr,A,"there is",C):-
write_this_sentence_uppercase("is there",A,C); write(" ? "),
read_in(Answer), !, recognize(Answer,Nr,A,"there is",C).
ask(Nr,A,B,C):-
write_this_sentence_uppercase(B,A,C); write(" ? "),
read_in(Answer), !, recognize(Answer,Nr,A,B,C).
/* Procedura pentru recunoasterea raspunsurilor pozitive si negative ale utilizatorului: */
recognize(Answer,_,A,B,C):-
meaning(Answer,yes), !, retract(fact(A,B,C,unknown)), asserta(fact(A,B,C,true)).
recognize(Answer,_,A,B,C):-
meaning(Answer,no), !, retract(fact(A,B,C,unknown)),
asserta(fact(A,B,C,false)), fail.
recognize(Answer,Nr,A,B,C):-
meaning(Answer,do_not_know), !, deal_with_vague_answers(Nr,A,B,C).
recognize(Answer,Nr,A,B,C):-
meaning(Answer,why), !, why(Nr), ask(No,A,B,C).
recognize(Answer,Nr,A,B,C):-
meaning(Answer,test), !, display_test(A,B,C), ask(Nr,A,B,C).
/* introducere eronata, neinterpretabila: */
recognize(_,Nr,A,B,C):-
nl, write("I do not understand your response."),nl,
write("Please re-enter your answer."), ask(No,A,B,C).
/* Raspunsuri echivalente: */
meaning(y,yes).
meaning(yes,yes).
meaning(yeah,yes).
meaning(n,no).
meaning(no,no).
meaning(nope,no).
meaning(test,test).
meaning("Test",test).
meaning(try,test).
meaning("Try",test).
meaning([do,not,know|_],do_not_know).
meaning(["I",do,not,know|_],do_not_know).
meaning(perhaps,do_not_know).
meaning(maybe,do_not_know).
meaning("",do_not_know).
meaning(C,do_not_know):- C="?".
meaning(why,why).
meaning(how_come,why).
deal_with_vague_answers(Nr,A,B,C):-
/* daca inca nu s-a introdus raspuns vag la acesta intrebare: */
do_not_know_entered(no), display_test(A,B,C), !, ask(Nr,A,B,C).
deal_with_vague_answers(Nr,A,B,C):-
/* dupa explicarea intrebarii daca se raspunde tot cu un raspuns vag,
inseamna ca avem de-a face cu raspuns "nesigur" */
asserta(fact(A,B,C,uncertain)), fail.
note_do_not_know_entered(X):-
retractall(do_not_know_entered(_)),
asserta(do_not_know_entered(X)).
display_test(A,B,C):-
note_do_not_know_entered(yes),
test(A,B,C,Part_1,Part_2), !, write_experiment(Part_1), write_text_module1,
write_this_sentence_lowercase(A,B,C), write(","), write_text_module2,
write_experiment(Part_2), write_text_module3.
display_test(A,B,C):-
write_text_module4, write_this_sentence_lowercase(A,B,C), write("."), nl.
write_experiment([]).
write_experiment([A|B]):-
nl, write(A), write_experiment(B).
write_text_module1:-
nl,nl, write("To see if"), nl.
write_text_module2:-
nl, write("you can check if").
write_text_module3:-
nl,nl, write("Please do the above and"), nl, write("respond to the following question."), nl.
write_text_module4:-
nl, write(" I know of no simple method "), write("for testing"), nl, write("if ").
write_this_sentence_lowercase(A,"there is",C):-
!, write_this_sentence_lowercase("there is",A,C).
write_this_sentence_lowercase(A,B,C):-
write(A), write(" "), write(B),
write(" "), write("C").
write_this_sentence_uppercase(A,"there is","not"):-
!, write_this_sentence_uppercase("there is",no,A).
write_this_sentence_uppercase(A,"there is",C):-
!, write_this_sentence_uppercase("there is",A,C).
write_this_sentence_uppercase(A,B,C):-
nl, write_this_term_uppercase(A),
write(A), write(" "), write(B), write(" "), write("C").
write_this_term_uppercase(Term):-
name(Term, Word), write_uppercase(Word,Uppercase_Word),
name(New_Term,Uppercase_Word), write(New_Term).
write_uppercase([LC_Letter|Rest],[UC|Letter|Rest]):-
[LC_a,LC_z]="az", LC_a<= LC_Letter,
LC_Letter<=LC_z, !, UC_Letter=LC_Letter-32.
write_uppercase(Term,Term).
/* Afisarea regulilor: */
write_the_rules_applied:-
findall(Rule, applied_rule(S,Rule), L),
/*findall(Variable, Atom, Listvariable) */
write_rules(L).
write_rules([A|B]):-
write(" Rule "), write(A), write_additional_rule(B).
write_additional_rule([]):- write(").").
write_additional_rule([A|B]):- write(","), write(" Rule "), write(A), write_additional_rule(B).
read_in(Line):-
get0(C), read_word(C,Word,C1), word_in_list(Word,C1,Line).
word_in_list(char(end),_,[]):- !.
word_in_list(char(white),C,WordList):-
read_word(C,Word,C1), !, word_in_list(Word,C1,WordList).
word_in_list(Word,C,[Word|WordList]):-
read_word(C,Word1,C1), !, word_in_list(Word1,C1,WordList).
read_word(4,char(end),_):- !.
read_word(10,char(end),_):- !.
read_word(9,char(white),C):- get0(C), !.
read_word(32,char(white),C):- get0(C), !.
read_word(C,Word,C2):-
in_word(C), !, get0(C1), rest_of_word(C1|String,C2), name(Word,[C|String]).
read_word(C,char(C),C1):- get0(C1).
rest_of_word(C,[C|String],C2):-
in_word(C), !, get0(C1), rest_of_word(C1|String,C2).
rest_of_word(C,[],C).
in_word(C):- C>64, C<91.
in_word(C):- C>96, C<123.
in_word(C):- C>47, C<58.
/**********************************************************************
TESTAIDS.PRO contine clausele predicatului "test" care ajuta la prepararea instructiilor pentru a realiza un test
**********************************************************************/
PREDICATES
test(Subject,Verb,Attribute,Stringlist,Stringlist)
CLAUSES
test("the heater blower",is,defective,
[], ["no air comes out the vents when", "the blower is switched on."]).
test("the fuse",is,defective,
[], ["voltage cannot be detected", "behind the blower fuse."]).
test("the switch",is,defective,
[], ["the switch cannot be reset"]).
test("the cable",is,defective,
[], ["the fan does not run when the", "cable has been bridged."]).
test("the blower",is,stuck,
[],["the blower does not run smoothly"]).
test("the jumper cable",is,defective,
[], ["12 Volts of power cannot be measured",
"on the jumper cable of the air cooling circuit."]).
test("the blower motor",is,defective,
[], ["the blower motor does not run when",
"directly supplied with operating voltage."]).
test("the battery",is,empty,
[], ["the battery voltage less than 10 volts",
"when the headlights are switched on."]).
test("the heating regulator",is,defective,
["budge the heating regulator"], ["the heating regulator lever does not move"]).
test("the Bowden cable",is,broken,
[], ["the Bowden cable can be pulled out", "toward the motor"]).
test("the Bowden cable",is,stuck,
["detach both ends of the Bowden cable"], ["the Bowden cable is not smooth."]).
test("the heater valve",is,stuck,
["detach the Bowden cable from the valve"],
["the valve cannot be easily actuated."]).
test("the heater valve",is,clogged,
[], ["a blockage is visible once the", "valve has been removed."]).
test("the V-belt",is,torn,
[], ["the belt drive-wheel of the water", "pump does not rotate."]).
test("the V-belt",is,loose,
[], ["the V-belt can be pressed more than 1 cm"]).
test("the water pump",is,defective,
[], ["the temperature gauge is in the red zone",
"after the motor runs 5 minutes."]).
test("the water pump",is,stuck,
[], ["the water pump cannot be turned",
"easily when the V-belt has been loosened."]).
test("the water pump",is,clogged,
["unmount the water pump."], ["some blockage is visible."]).
test("the water pump",is,leaky,
[], ["some coolant is dripping", "out of the water pump."]).
test("the heat exchanger",is,defective,
[], ["there is no temperature gradient",
"between incoming and outgoing", "heating pipe"]).
test("the heat exchanger",is,"dirty on the outside",
["remove the heat exchanger casing."], ["any foreign bodies are visible."]).
test("the heat exchanger",is,clogged,
["unmount the heat exchanger."], ["compressed air cannot be blown",
"trough the heat exchanger."]).
test("the heat exchanger",is,leaky,
[], ["there are traces of water to be seen",
"when the cooling system is under pressure."]).
test("the coolant",is,frozen,
[], ["there is not enough anti-freeze", "in the radiator coolant."]).
test("the system",is,"low on coolant",
[], ["there is no more coolant in the reservoir."]).
test("air","there is","in the coolant",
["loosen the bleeder screw on the heat",
"exchanger while the heater is switched on",
"and the motor is running."], ["the heater runs now."]).
/**********************************************************************
Modulul EXPL.PRO contine clausele predicatelor de explicare cum s-a ajuns la un anumit rezultat si de ce se aplica sau nu se aplica o anumita regula.
**********************************************************************/
PREDICATES
reason
why_not(Rule_No)
write_causes(Causelist)
display_rule(Rule_No)
check_if_still_applicable(Stringlist,Stringlist,Stringlist)
check_applicability(Stringlist,Stringlist,Stringlist)
separate(Causelist,Tripletlist,Tripletlist,Tripletlist,Tripletlist)
write_the_false_facts(Tripletlist)
write_the_uncertain_facts(Tripletlist)
write_the_unknown_facts(Tripletlist)
write_an_false_facts(Tripletlist)
write_an_uncertain_facts(Tripletlist)
write_an_unknown_facts(Tripletlist)
something_is_false(Tripletlist)
something_is_uncertain(Tripletlist)
something_is_unknown(Tripletlist)
CLAUSES
/* Explicarea pas cu pas a rezultatelor obtinute: */
reason:-
step(0), nl, write("It is the logical conclusion"),
nl, write("the facts given me").
reason:-
retract(step(S_No)), applied_rule(S_No,R_No),
clause(defect(R_No,A,B,C),Causes),
nl, write_this_sentence_uppercase(A,B,C),
nl, write("because "), write_causes(Causes), write("."),
New_S_No = S_No-1, asserta(step(New_S_No)).
write_causes([cause(Nr,A,B,C)]):-
write_this_sentence_lowercase(A,B,C).
write_causes([cause(Nr,A,B,C)|Remainder]):-
write_this_sentence_lowercase(A,B,C),
write(","), nl, write("and "), write_causes(Remainder).
display_rule(Nr):-
clause(defect(Nr,A,B,C),Causes),
nl, write("If "), write_causes(Causes), write(","),
nl, write("then "), write_this_sentence_lowercase(A,B,C), write(".").
/* De ce se aplica o anumita regula este defapt acelasi cu afisarea continutului regulii respective: */
why(Nr):- display_rule(Nr).
check_applicability(F,Uncertain, Unkn):-
check_if_still_applicable(F,Uncertain, Unkn),!.
check_applicability(F,Uncertain, Unkn) :- true, !.
why_not(No):-
clause(defect(No,_,_,_),Causes), !,
separate(Causes,T,F,uncertain, Unkn),
something_is_false(F), something_is_uncertain(Uncertain),
something_is_unknown(Unkn), check_applicability(F,Uncertain, Unkn), nl.
why_not(_):-
nl, write("No such rule exists !").
/* Procedura pentru separarea faptelor adevarate, false, nesigure sau necunoscute: */
/* fapte adevarate: */
separate([cause(N,A,B,C)],[(A,B,C)],[],[],[]):-
fact(A,B,C,true), !.
separate([cause(N,A,B,C)|Causes],[(A,B,C)|True],False,Uncertain,Unknown):-
fact(A,B,C,true), !, separate(Causes,True,False,Uncertain,Unknown).
/* fapte false: */
separate([cause(N,A,B,C)],[],[(A,B,C)],[],[]):-
fact(A,B,C,false), !.
separate(cause(N,A,B,C),Causes),True,[(A,B,C)|False],Uncertain,Unknown):-
fact(A,B,C,false), !, separate(Causes,True,False,Uncertain,Unknown).
/* fapte nesigure: */
separate([cause(N,A,B,C)],[],[],[(A,B,C)],[]):-
fact(A,B,C,uncertain), !.
separate(cause(N,A,B,C),Causes),True,False,[(A,B,C)|Uncertain],Unknown):-
fact(A,B,C,uncertain), !, separate(Causes,True,False,Uncertain,Unknown).
/* fapte necunoscute: */
separate([cause(N,A,B,C)],[],[],[],[(A,B,C)]).
separate(cause(N,A,B,C),Causes),True,False,[(A,B,C)|Uncertain,[(A,B,C)|Unknown]):-
separate(Causes,True,False,Uncertain,Unknown).
something_is_false(False):- write_the_false_facts(False).
something_is_false(_).
something_is_uncertain(Uncertain):-
write_the_uncertain_facts(Uncertain),
write(".").
something_is_uncertain(_).
something_is_unknown(Unknown):- write_the_unknown_facts(Unknown), write(".").
something_is_unknown(_).
/* Proceduri pentru afisarea faptelor false, nesigure sau necunoscute: */
write_the_false_facts([(A,B,C)]):-
nl, write_this_sentence_uppercase(A,B,"not"), write(" "), write(C), write(".").
write_the_false_facts([(A,B,C)|Facts]):-
write_the_false_facts([(A,B,C)]), write_the_false_facts(Facts).
write_the_uncertain_facts([]):- !, fail.
write_the_uncertain_facts(Facts):-
nl, write("It is uncertain, if"), nl, write_un_uncertain_fact(Facts).
write_an_uncertain_fact([(A,B,C)]):-
write_this_sentence_lowercase(A,B,C).
write_an_uncertain_fact([Fact,Facts]):-
write_an_uncertain_fact([Fact]), write(" and if"), nl, write_an_uncertain_fact(Facts).
write_the_unknown_facts([]):- !, fail.
write_the_unknown_facts(Facts):-
nl, write("It has not yet been clarified if"), nl, write_un_unknown_fact(Facts).
write_an_unknown_fact([(A,B,C)]):-
write_this_sentence_lowercase(A,B,C).
write_an_unknown_fact([Fact,Facts]):-
write_an_unknown_fact([Fact]), write(" and if"), nl, write_an_unknown_fact(Facts).
check_if_still_applicable([],[],[]):-
nl, write("This rule could still be applied. "), nl.
/**********************************************************************
Modulul AUX_PRED.PRO contine predicatele auxiliare utilizate
**********************************************************************/
PREDICATES
restart
rule(Rule_Nr)
note_phase(integer)
note_do_not_know_entered(string)
increment(integer)
store_this_step(Rule_Nr)
ass_fact(string,string,string,string)
CLAUSES
restart:-
initializare.
rule(Nr):- display_rule(Nr).
note_phase(P):-
retract(phase(_)), asserta(phase(P)).
note_do_not_know_entered(X):-
retract(do_not_know_entered(_)), asserta(do_not_know_entered(X)).
increment(Nr):-
retract(statistic(Nr,State)), !, Newer_State = State + 1, asserta(statistic(Nr,Newer_State)),
increment(_).
store_this_step(R_No):-
retract(step(S_No)), New_S_No = S_No + 1, asserta(step(New_S_No)),
asserta(applied_rule(New_S_No,R_No)), clause(defect(R_No,A,B,C),_),
fact(A,B,C,Degree), ass_fact(A,B,C,Degree).
ass_fact(A,B,C,Degree):- Degree="unknown", !.
ass_fact(A,B,C,Degree):- asserta(fact(A,B,C,true)).
/**********************************************************************
Modulul IPOTEZE.PRO contine predicate pentru aplicarea unor euristici de parcurgere a bazei de cunostinte conform unor retele de legaturi intre simptome
**********************************************************************/
GLOBAL PREDICATES
meaning(string,string)-(i,o)
PREDICATES
rule_of_thumb
make_hypothesis(Intlist)
test_hypothesis(Intlist)
test_question1(string)
test_question2(string)
increase_probability(integer,integer)
reduced_probability(integer,integer)
impossible(integer)
display_hypothesis
write_hypothesis(Intlist)
CLAUSES
rule_of_thumb:-
make_hypothesis(List), test_hypothesis(List).
make_hypothesis(HypothesesList):-
nl, write("Do the headlights work ? "),
read_in(Answer_1), test_question1(Answer_1),
nl, write("Does the motor start ? "),
read_in(Answer_2), test_question1(Answer_2),
point(1,A,_), point(2,B,_), point(3,C,_), point(4,D,_),
sort([A,B,C,D],_,[1,2,3,4],HypothesesList),
retract(hypotheses(_)), asserta(hypotheses(HypothesesList)).
test_hypothesis([]):-
nl, write(" I cannot find any defects. ").
test_hypothesis([Next_Alternative|Remainder]):-
point(Next_Alternative,_,possible), check(Next_Alternative).
test_hypothesis([Next_Alternative|Remainder]):-
test_hypothesis(Remainder).
/* predicate pentru citirea raspunsurilor la intrebarile de 'suprafata' puse initial: */
test_question1(Answer):-
meaning(Answer,yes), increase_probability(3,3), reduced_probability(2,6).
test_question1(Answer):-
meaning(Answer,no), increase_probability(1,5), reduced_probability(4,2).
test_question1(_).
test_question2(Answer):-
meaning(Answer,yes), increase_probability(1,4), reduced_probability(3,2).
test_question2(Answer):-
meaning(Answer,no), impossible(4), increase_probability(2,2).
test_question2(_).
/* predicate pentru cresterea respectiv scaderea posibilitatii anumitor ipoteze: */
increase_probability(Hypo,Points):-
retract(point(Hypo,Old_State,possible)), New_State = Old_State + Points,
asserta(point(Hypo,New_State,possible)).
increase_probability(_,_).
reduced_probability(Hypo,Points):-
retract(point(Hypo,Old_State,possible)), New_State = Old_State – Points,
asserta(point(Hypo,New_State,possible)).
reduced_probability(_,_).
impossible(Alternative):-
point(Alternative,0,impossible), !.
impossible(Alternative):-
retract(point(Alternative,_,_)), asserta(point(Alternative,0,impossible)).
display_hypothesis:-
hypotheses(List), write_hypothesis(List).
write_hypothesis([]).
write_hypothesis([Alternative|Remainder]):-
point(Alternative,_,possible), clause(defect(Alternative,_,_,_),cause(_,A,B,C)),
write_this_sentence_uppercase(A,B,C), fail.
write_hypotheses([Alternative|Remainder]):-
display_hypothesis(Remainder]).
/* la inceput fiecare ipoteza are 0 puncte pentru posibilitate: */
point(1,0,possible).
point(2,0,possible).
point(3,0,possible).
point(4,0,possible).
/* lista de ipoteze: */
hypotheses([1,2,3,4]).
/**********************************************************************
Modulul ENDLESS.PRO asigura cautarea defectelor multiple
**********************************************************************/
PREDICATES
print_result(integer,string,string,string)
determina(string)
CLAUSES
/* determina masina de inferenta sa caute in continuare alte defecte posibile
in bucla inchisa pana cand se raspunde afirmativ la intrebarea de a continua
sau nu: */
print_result(Nr,A,B,C):-
write_this_sentence_uppercase(A,B,C), write_the_rules_applied, nl,nl,
note_phase(2), write("Should more defects be searched for ? "),
read_in(Continue), determina(Continue).
determina(Continue):-
meaning(Continue,yes), ! delete_previous_steps,fail.
determina(Continue):- true.
/**********************************************************************
Modulul LEARN.PRO contine predicatele necesare implementarii componentei de invatare din experienta, adica din statistisi.
**********************************************************************/
PREDICATES
new_priorities.
sort(Intlist,Intlist,Intlist,Intlist)
split(Intlist,Intlist,Intlist,Intlist,Intlist,Intlist,Intlist,Intlist)
CLAUSES
/* cat timp nu s-a mai intalnit defectul respectiv, Defect_Frequency_N = 0 : */
statistic(1,0).
statistic(2,0).
statistic(3,0).
statistic(4,0).
/* Se calculeaza frecventa succesului diagnosticarii si in functie de asta se
adapteaza (se resorteaza) lista de ipoteze: */
new_priorities:-
statistic(1,A), statistic(2,B), statistic(3,C), statistic(4,D), sort([A,B,C,D],_,[1,2,3,4],New_List),
retract(hypotheses(_)), asserta(hypotheses(New_List)).
/* sortarea ipotezelor in functie de punctele acumulate: */
/* este o variatie mai complexa a procedurii de sortare "quicksort" */
/* New_Hypos este generat din [H|Hypos] bazat pe rezultatele resortarii listei
vechi a lui Points: */
sort([],[],[],[]).
sort([P|Points],New_Points,[H|Hypos],New_Hypos):-
split(P,Points,UP1,UP2,H,Hypos,UH1,UH2),
sort(UP1,VP1,UH1,VH1), sort(UP2,VP2,UH2,VH2),
append(VP1,[P|VP2],New_Points), append(VH1,[H|VH2],New_Hypos).
split(_,[],[],[],_,[],[],[]).
split(H,[H1|T1],[H1|U1],U2,HA,[HA1|TA1],[HA1|UA1],UA2):-
H1>H, split(H,T1,U1,U2,HA,TA1,UA1,UA2).
split(H,[H1|T1],U1,[H1|U2],HA,[HA1|TA1],UA1,[HA1|UA2]):-
H1<=H, split(H,T1,U1,U2,HA,TA1,UA1,UA2).
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: Tehnologia Proiectarii Sistemelor Expert (ID: 161711)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
