Documente Academic
Documente Profesional
Documente Cultură
Facultatea de INFORMATICĂ
VASILE PODARU
BUCUREŞTI – 2011
UNIVERSITATEA Titu MAIORESCU Bucureşti
Facultatea de Informatică
Învăţământ la Distanţă
INTELIGENŢĂ ARTIFICIALĂ
Inteligenţa artificială este una din disciplinele de pregătire fundamentală care, pentru
profilul INFORMATICĂ, este esenţială pentru pregătirea studenţilor şi pentru obţinerea
creditelor transferabile prin procedurile de evaluare. Modul de prezentare a acestui material
are în vedere particularităţile învăţământului la distanţă, la care studiul individual este
determinant. Pentru orice nelămuriri faţă de acest material vă rugăm să contactaţi tutorele de
disciplină care are datoria să vă ajute oferindu-vă toate explicaţiile necesare.
Disciplina de Inteligenţa artificială îşi propune următoarele obiective specifice:
Însuşirea noţiunilor fundamentale din domeniile Inteligenţei artificiale.
Formarea deprinderilor de modelare matematică şi de transpunere în programare a
unor probleme de natură tehnică, socială sau economică, cu utilizarea cunoştinţelor
însuşite.
Formarea şi dezvoltarea aptitudinilor şi deprinderilor de analiză logică, formulare
corectă şi argumentare fundamentată, în rezolvarea problemelor tehnico-economice şi
de specialitatecu cu utilizarea cunoştinţelor însuşite prin intermediul metodelor şi
modelelor specifice inteligenţei artificiale;
Insusirea principiilor generale ale programarii logice si insusirea limbajului Prolog;
O comparaţie critică a metodelor de rezolvare evidenţiind, eventual, calea optimă de
soluţionare.
Accentul se va pune pe problemele de cautare si reprezentare a cunostintelor si
respectiv pe programarea logica, limbajul de programare utilizat la laborator fiind
limbajul Prolog (în anexă, modulul 5, se găseşte un îndrumar privind programarea în
PROLOG). Cursul trebuie sa trateze aspecte ale rezolvarii problemelor prin
intermediul cautarii, descriind cele mai importante tehnici de cautare informata si
neinformata. Se vor da exmple de aplicatii ale cautarii, cum ar fi jocurile, tratate ca
probleme de cautare. Se vor prezenta principalele tipuri de cunostinte si principalele
metode de reprezentare a cunostintelor. Se va face legatura dintre reprezentarea
cunostintelor si sistemele expert. Se va da un exemplu de bază de cunoştinţe de sistem
expert cu implementare in Prolog. Vor mai fi tratate, ca modalitati de reprezentare a
cunostintelor, retelele semantice si retelele Bayesiene (cu introducerea rationamentului
statistic). Metodele de învăţare şi reţelele neuronale sunt alte domenii importante pe
care le vom trata în acest material.
3
MODULUL 1
Îndrumări metodice.
4
Unitatea de învăţare nr.1
Elemente de reprezentare a cunoaşterii
Cuprins:
1.0. Domeniul inteligenţei artificiale.................................................................. pag. 5
1.0.1. Scurtă prezentare .................................................................................. ... pag. 5
1.0.2. Testul Turing ........................................................................................... pag. 6
1.0.3. Scurt istoric .............................................................................................. pag. 7
1.0.4. Domenii de interes şi de cercetare pentru IA ........................................... pag. 8
1.0.5. Fundamentele matematice.Domeniile principale de studiu şi
de aplicabilitate ale IA ....................................................................................... pag. 9
1.0.6. Limbaje de programare specifice domeniului .......................................... pag. 9
1.1. Reprezentarea cunoaşterii............................................................................ pag. 9
1.1.0. Introducere ............................................................................................... pag. 9
1.1.1. Reprezentarea cunoaşterii în limbajul calculului cu predicate
de ordinul I. ....................................................................................................... pag.11
1.1.2. Metode procedurale de reprezentare a cunoşterii .................................... pag.15
1.1.3. Reprezentarea cunoşterii prin reguli de producţie.................................... pag.16
1.1.4. Reţele semantice ...................................................................................... pag.19
1.1.5. Reprezentarea cunoaşterii cu ajutorul cadrelor ........................................ pag. 25
5
Definiţiile din a doua clasă se pot rezuma la sisteme care gândesc raţional. Două
dintre aceste definiţii sunt:
studiul facultăţilor mintale folosind modele computaţionale;
studiul operaţiilor computaţionale care permit percepţia, raţiunea şi acţiunea.
Definiţiile din a treia clasă se pot rezuma la sisteme care acţionează ca oamenii. Iată şi
acest gen de definiţii:
arta creării maşinilor care efectuează operaţii pentru care este nevoie de
inteligenţă atunci când sunt efectuate de oameni;
construirea unor calculatoare care să efectueze operaţii pe care oamenii le
realizează acum cu mai mult succes.
Definiţiile din a patra clasă se pot rezuma la sisteme care acţionează raţional. Două
dintre aceste definiţii sunt:
un domeniu care încearcă să explice şi să emuleze comportamentul inteligent
în termeni de procese computaţionale;
ramura informaticii care se ocupă cu automatizarea comportamentului
inteligent.
Toate cele patru abordări au fost urmate de cercetători de-a lungul ultimelor decenii.
Normal, există disensiuni între cei care folosesc abordări care se bazează pe inteligenţa umană
şi cei care folosesc abordări care se bazează pe raţiune.
Există şi numeroase alte definiţii:
construirea de algoritmi accesibili (polinomiali) care să reprezinte aproximări
ale unor probleme inaccesibile (pentru care nu există soluţii polinomiale);
construirea unui sistem fizic care să fie capabil să treacă testul Turing;
ramura informaticii care studiază modul în care pot fi create maşini care
acţionează inteligent;
un domeniu care foloseşte tehnici computaţionale pentru a efectua sarcini care,
aparent, necesită inteligenţă atunci când sunt realizate de oameni
6
ştiinţei calculatoarelor. În fizică, de exemplu, au fost descoperite în natură structurile formale,
şi fiecare din aceste sisteme formale pot să fie interpretate ca o maşină naturală. Opinia unor
savanţi că întregul univers este o maşină gigantică vine în complementarea credinţei că
adevărata inteligenţă a maşinilor, precum şi conştiinţa de sine, ar trebui să survină numai după
ce maşina ar atinge un anumit grad de complexitate.
Acest lucru însă conduce la o serie de dificultăţi. Din moment ce maşinile urmează
doar instrucţiuni, nu este credibil faptul că ele ar putea dintr-o dată, pe baza unui mare număr
de legături dintre unităţile de calcul, să fie înzestrate cu conştiinţă de sine. Pe de altă parte,
dacă se concluzionează că maşinile nu vor deveni niciodată conştiente de sine, s-ar putea pune
întrebarea de ce este conştient creierul uman, în timp ce computerul de silicon nu este?
Probabil că răspunsul la această enigmă este faptul că creierul este un sistem care se auto-
organizează şi care răspunde la natura şi la calitatea interacţiunii sale cu mediul, în timp ce
calculatoarele nu o fac. Dar şi alte sisteme ecologice, care sunt comunităţi biologice cu
interacţiuni complexe între componente, se auto-organizează, dar fără să fie conştiente de
sine. Acest fapt sugerează că deşi auto-organizarea este necesară pentru conştiinţă, ea nu este
şi suficientă.
7
secţia de calculatoare a UPB şi a publicat o serie de materiale specifice domeniului), Institutul
Central de Informatică (prin actualul academician Filip – preşedintele secţiei de Inteligenţă
artificială din Academia Română - şi cercetătorul Ioan Georgescu cu o primă carte în limba
română de inteligenţă artificială), Universitatea Bucureşti (prin preocupările academicianului
Mircea Maliţa şi a altor cadre didactice) şi alte instituţii de învăţământ superior şi de cercetare
din ţară.
Perioada anilor de după 1990 a însemnat o “explozie” a preocupărilor şi produselor
“inteligente”, de apariţie a unei vaste bibliografii, de înfiinţare a unor firme de profil şi a unor
institute şi asociaţii profesionale. Evident că această explozie a fost facilitată şi de dezvoltarea
fără precedent a tehnologiei informaţieia, a produselor soft şi hard, de apariţi a internetului.
8
- rezolvarea problemelor
- strategii şi metode de căutare în spaţiul stărilor
- metode şi algoritmi de inferenţă
1.1.0. Introducere.
Reprezentarea cunoştinţelor într–un calculator constă în găsirea unei corespondenţe
între lumea exterioară şi sistemul simbolic ce permite execuţia raţionamentelor.
În transpunerea de la subiecţii umani la subiecţii cunoscători de tip „program pentru
calculator“ deci de la psihologia gândirii la inteligenţa artificială, conceptul de cunoaştere îşi
9
conservă calităţile, în sensul că, în vederea utilizării unui program cunoaşterea este memorată
sub forma unor piese de cunoaştere ce descriu fapte, fenomene, procese, evenimente dintr–o
parte a lumii reale ce constituie domeniul de competenţă al programului inteligent. Piesele de
cunoaştere alcătuiesc un model al lumii la care programul are acces prin intermediul
procedurilor de organizare, clasificare, căutare şi recunoaştere.
Se poate defini un sistem cognitiv ca totalitatea pieselor de cunoaştere, a modului de
stocare şi a procedurilor de acces la acestea.
Problema fundamentală a inteligenţei artificiale este cea de definire a unor metode
pentru reprezentarea unei mari cantităţi de cunoştinţe într–o formă ce permite stocarea şi
utilizarea eficientă a acestora.
Reprezentarea cunoaşterii poate fi conform celor de mai sus considerată ca o relaţie de
definiţie A B ce stabileşte o legătură între un simbol identificator A (numele entităţii
reprezentate) şi o expresie B formulată în limbajul de reprezentare al sistemului, ce descrie
caracteristicile entităţii şi structura sa cu ajutorul unor termeni primari, termeni purtători de
semnificaţie ai limbajului. Expresia B este o reprezentare a entităţii A sau a piesei de
cunoaştere A în sistemul cognitiv considerat ca gazdă a reprezentării cunoaşterii.
Unul din conceptele de bază de reprezentare a cunoştinţelor este cel de entitate. O
entitate este un obiect al lumii reale, cu o existenţă independentă. O entitate este un obiect cu
existenţă fizică: persoană particulară, automobil, companie, activitate, curs universitar, etc.
Orice entitate are o serie de proprietăţi numite atribute ce particularizează entitatea respectivă.
De exemplu, pentru o entitate automobil se pot enumera o serie de atribute cum sunt marca,
combustibilul utilizat, capacitatea cilindrică etc. Valorile acestor atribute au ca scop
identificarea entităţii.
Unele atribute pot fi împărţite în părţi mai mici cu semnificaţie independentă. Un
astfel de atribut este un atribut complex. Un exemplu este cel al atributului adresa, ce poate fi
subdivizat în atributele componente Oraş, Judeţ, Cod poştal, Stradă. La rândul său atributul
Stradă este definit prin atributele Nume stradă, Număr, Scară, Număr apartament.
Atributele ce nu sunt compuse se numesc atomice. Valoarea atributelor compuse se
formează prin compunerea valorilor atributelor atomice.
Multe atribute au o valoare unică pentru o entitate particulară şi sunt numite atribute
cu o singură valoare. Spre exemplu, vârsta unei persoane. Există atribute ce pot lua mai multe
valori, spre exemplu, culoarea unui automobil. Fiecare atribut al unei entităţi tip are asociat un
set de valori V, numit şi domeniu, ce specifică valorile posibile pe care le poate lua.
Matematic, atributul A al entităţii tip E poate fi definit ca o funcţie de la E la mulţimea
valorilor posibile ale lui V, sau la toate submulţimile lui V.
A: E (V)
(prin (V) s-a notat mulţimea părţilor lui V).
Valoarea atributului A pentru entitatea (e), se va nota A(e). Pentru un atribut simplu
A(e) este o valoare cu un singur element, un atribut nul nu are valoare sau altfel spus are
valoarea null. Pentru un atribut compus A mulţimea de valori este formată ca produsul
cartezian dintre (V1), (V2), …, (Vn) unde V1, V2, …,Vn reprezintă mulţimea valorilor unei
componente simple a lui A, deci
(V) = (V1) × (V2)× …× (Vn).
Între entităţi se pot stabili o serie de relaţii ce pot avea la rândul lor atribute ce le
caracterizează denumite atribute relaţie.
Pentru aplicaţiile de inteligenţă artificială se pot distinge următoarele clase de metode
de reprezentare:
a) metode logice – sunt acele metode ce privesc cunoaşterea ca o serie de aserţiuni
(enunţuri adevărate) privind cunoştinţele şi relaţiile dintre ele. Metoda permite
10
folosirea regulilor de inferenţă direct asupra pieselor de cunoaştere din baza de
cunoştinţe. Are însă dezavantaje prin soluţiile nesatisfăcătoare de sistematizare a
bazei de cunoştinţe, prin inadecvanţa reprezentării cunoaşterii despre acţiuni,
precum şi a reprezentării regulilor euristice;
b) metode relaţionale – sunt metodele prin care cunoaşterea este reprezentată pornind
de la relaţiile dintre obiecte sub formă de grafuri şi reţele. Ele permit organizarea
cunoştinţelor funcţie de omogenitatea acestora ce conduc la clase şi sorturi.
c) metode procedurale – în care cunoaşterea este reprezentată sub formă de proceduri
ce permit obţinerea stărilor la momentele specificate pornind de la stările iniţiale
sau intermediare.
Descrierea formală a unui concept în termenii limbajului de reprezentare, prin care se
diferenţiază de alte concepte sau prin care se poate aprecia echivalenţa cu alte concepte
similare poartă numele de definiţie. Definiţia are ca obiectivitate modelarea obiectelor şi a
relaţiilor dintre ele astfel încât să fie specificate caracteristicile esenţiale ale acestora cât şi
posibilitatea de a facilita operaţiile în care obiectele şi relaţiile sunt frecvent implicate. Este
normal ca pentru un concept să poată fi date mai multe definiţii, fiecare definiţie fiind o
descriere parţială dependentă de perspectiva din care este privită.
Altă informaţie privind un concept este dată de relaţiile acestuia cu entităţi de tip
acţiune. În general un obiect poate să ocupe în cadrul unei acţiuni poziţia de argument, deci
asupra căruia se acţionează cât şi poziţia de rezultat al acţiunii.
Se va numi generalizare a unui concept (C) o definiţie mai puţin restrictivă a acestuia
(D), în care orice instanţă a conceptului (C) este şi o instanţă conceptului (D), concept mai
general. O serie de proprietăţi sunt exprimate printr–un predicat P(x, C, D) în care (x) este o
instanţă de concept, care dacă satisface şi predicatul pentru generalizare va satisface şi
definiţia conceptului C.
DEF(x, D) P(x, D, C) DEF(x, C)
în care, DEF(x, y) este un predicat ce semnifică faptul că (x) satisface definiţia.
Pornind de la aceste observaţii o structură de concepte poate fi reprezentată
arborescent, înaintarea spre frunză reprezentând o specializare, pe când apropierea de rădăcină
o generalizare a conceptului.
11
1.1.1.1. Reprezentarea propoziţională
Exemplu: Să considerăm următoarea descriere (incompletă) în limbajul natural a
piesei de cunoaştere „avionul xyz“.
„Avionul xyz este compus dintr–un fuselaj, aripă, sistem de propulsie, sistemul de
comandă şi sistemul de rulare. Avionul zboară dacă viteza relativă de deplasare faţă de
curentul de aer este mai mare decât 180 km/h. Motorul funcţionează dacă are combustibil în
rezervor iar contactul de pornire este închis.“
Se disting următoarele fraze ce sunt propoziţii elementare:
I. A1 = avionul xyz
II. A2 = avionul zboară
A3 = viteza relativă de deplasare faţă de curentul de aer este mai mare decât
180 km/h
III. A4 = motorul funcţionează
A5 = are combustibil în rezervor
A6 = contactul de pornire este închis
Presupunem că nu cunoaştem alte fapte despre acest avion. Atunci cunoaşterea despre
acest obiect este dată de următoarele formule ale calculului propoziţional:
i) A1
ii) A3 A2
iii) (A5 A6) A4
Analiza aserţiunilor
A1 – Grupul predicativ determină un predicat de tipul ESTE–COMPUS având ca
număr de locuri, numărul de obiecte din grupul nominal, în acest caz de 6 locuri;
– Prin convenţie, primul loc este ocupat de obiectul compus, iar următoarele locuri
vor fi ocupate de componentele sale.
12
– la efectuarea raţionamentelor rareori se tratează simultan toate componentele, cele
mai frecvente situaţii sunt cele care implică o singură componentă;
– numărul de predicate fiind prestabilit, eventuala rafinare ulterioară a cunoaşterii ar
adăuga noi componente, care vor implica redefinirea predicatului, mărindu–i
unitatea la un număr de locuri (argumente) corespunzător noii descrieri.
Instanţa variabilei formale care se regăseşte în A2 face adevărat predicatul care reflectă
aserţiunea
Predicat : FUNCTIONEAZA(X )
A4 :
Subiect : MOTOR
13
A5 : Predicatul are două locuri: ARE (recipient, conţinut)
A6 : ÎNCHIS (contact–electric)
14
unde F este o notaţie: mulţimea de descrieri de fuselaje, diferite ca formă şi caracteristici.
Predicatul ESTE–ELEMENT folosit, semnifică apartenenţa obiectului ataşat variabilei
formale x la mulţimea de fuselaje F.
Rezultă deci definiţia simbolului unar: FUSELAJ : x F şi atunci
15
intermediul predicatelor ce îi stabileşte proprietăţile, apoi se apelează procedura de
determinare a valorii atributelor lui x.
Pentru folosirea reciprocei piesei de cunoaştere, adică dacă se dau faptele: x este
pasăre, nu zboară, înoată, atunci se defineşte o nouă piesă de cunoaştere în reprezentare
procedurală cu următorul conţinut:
16
sau eroare. Concluzia unei reguli este o acţiune ce manipulează date din baza de date şi în
plus, un control al sistemului determină secvenţa regulilor utilizate.
În descriere generală se poate menţiona faptul că sistemele de producţie sunt similare
gramaticilor şi apar chiar în definiţia gramaticilor Chomsky.
Astfel G = (V, , P, S) este o gramatică de structură a frazei, unde:
– V – reprezintă un set finit de simboluri numit adesea şi alfabet total;
– V reprezintă un set finit de simboluri ale alfabetului numite simboluri
terminale sau, simplu, terminale;
– P – o submulţime a produsului cartezian (V– –S) V. Elementele lui P, deci
perechile ordonate (u, w), se mai scriu în mod obişnuit sub forma u w şi sunt
numite producţii sau reguli de rescriere;
– (S) – un simbol iniţial sau simbol de start.
având interpretarea:
Dacă într–o regulă condiţia este satisfăcută, se spune că regula este selectată pentru
declanşare sau regula este aplicabilă. Regulile aplicabile intră într–o mulţime a regulilor
aplicabile, mulţime din care este selectată regula cu cea mai mare prioritate după diverse
criterii. Mecanismul regulilor de producţie este împrumutat din teoria limbajelor formale, este
de natură procedurală şi poate cel mai apropiat de modul de realizare a programelor clasice.
Mecanismul interpretativ al regulilor de producţie conţine următorii paşi:
17
– selectarea tuturor regulilor ce conţin piese de cunoaştere ce satisfac partea de
condiţie numită şi corespondentă. Mulţimea acestor reguli formează mulţimea
candidată, denumire ce are originea în faptul că elementele acestei mulţimi intră
într–o competiţie în urma căreia se decide care regulă este efectiv aplicată.
– Rezolvarea conflictelor prin care din mulţimea regulilor aplicabile se elimină mai
întâi regulile care duc la aceleaşi rezultate, după care în conjuncţie cu
mecanismulde asertare a priorităţii pentru problema respectivă se selectează regula
ce va fi aplicată;
– Execuţia părţii acţiune a regulii cu cea mai mare prioritate, în situaţia în care sunt
producţii aplicabile;
– Pornind de la contextul modificat în urma aplicării regulilor anterioare se reia ciclu
începând cu faza de corespondenţă, atâta timp cât ciclul produce acţiuni
materializate prin modificarea contextului.
Oprirea mecanismului interpretativ poate avea loc dacă acţiunea unei producţii
specifică concret oprirea, sau se selectează o producţie vidă.
Concluzionând, putem da următoarea definiţie:
Un sistem de producţie este un cvintuplu:
SP = ( K, P, , , pS)
în care:
K – reprezintă contextul ca o mulţime de piese de cunoaştere factuală recunoscute de
celelalte componente ale sistemului;
P – baza de reguli ca mulţime finită de reguli de producţie;
– funcţia succesor la îndeplinirea cu succes a condiţiei;
:P P { };
– funcţia succesor în caz de eşec a condiţiei,
: P P { };
pS – regula de producţie iniţială de la care porneşte procesul de selectare a regulilor.
S–a notat cu producţia vidă.
Pentru ca o producţie (p) să fie selectată, ţinând cont de conectiva logică dintre
condiţiile cj , este necesar ca în context să existe piese de cunoaştere ce satisfac toate aceste
condiţii. Dacă regula este selectată atunci acţiunile ak , 1 k p sunt executate.
Controlul sistemelor de producţie este specificat complet de cele trei componente ale
sale şi pS putându-se furniza strategii de control adecvate.
O metodă de strategie de control este inspirată din algoritmi normali Markov:
K = { k1, k2,..., kn }
P = { p1, p2,..., pm }
(pi) = p1 , 1 i n
(pi) = pi+1 , 1 i n-1
(pn) =
pS=p1.
Conform acestei strategii sistemul cercetează condiţiile din context începând cu prima
regulă, iar la întâlnirea primei reguli aplicabile o aplică după care comută controlul de regulă
p1 cu noul context. În situaţia de succes controlul este comutat la regula pi+1 realizând astfel o
18
explorare succesivă. În condiţiile în care nici o regula nu este aplicabila se selectează,
conform funcţiei succesor la eşec, producţia vidă.
O metodă des întâlnită este şi cea utilizată în sistemul expert EXSYS, prin care se
alege din mulţimea candidată producţia cu cel mai mare câştig informaţional. Logica de mai
sus se bazează pe faptul că o astfel de regulă conţine mai multă informaţie, fapt ce va
determina atingerea mai repede a obiectivului.
CONCEPT
X
INSTANŢIERE CONCEPTUALIZARE
(extensiune) (intensiune)
INSTANŢA
W
19
O instanţă poate reprezenta un obiect din lumea reală sau un alt concept. Atunci când
instanţa este un concept poate avea la rândul său instanţe. Se obţine astfel o ierarhie
conceptuală de mai multe nivele.
Conceptul fiind de fapt un obiect cu structură este alcătuit din entităţi formale numite
componente împreună cu relaţiile dintre acestea.
De multe ori este greu a se formula un concept dar se pot descrie clase ce aparţin
mulţimii instanţelor unui concept. Asemănător ierarhiei conceptuale se poate defini o ierarhie
de clasificare între componentele cărora se stabilesc relaţii taxonomice. Descrierea relaţiilor
taxonomice între obiectele plasate în nodurile reţelei se face cu ajutorul primitivelor
taxonomice ce asigură interpretarea uniformă a acestor legături în toată reţeaua. Primitivele
taxonomice sunt specificate ca simboluri relaţionale (predicate) ce etichetează arcele reţelei,
la a căror capete se găsesc noduri între care se defineşte o relaţie de apartenenţă de la obiect la
clasă. Iată principalele primitive taxonomice:
- relaţia de apartenenţă a obiectului la clasă, specificată de regulă printr-un predicat
de forma:
INSTANŢĂ CONCEPT
POPESCU ESTE OM
Relaţie de
intensiune
Apartenenţa persoanei cu numele POPESCU la mai multe clase cum sunt mulţimea
informaticienilor, a cercetătorilor şi a oamenilor este reprezentată de reţeaua
OM
ESTE
ESTE CERCETĂTOR
20
Utilizarea primitivei taxonomice ESTE permite reprezentarea şi în cazul în care mai
multe persoane sunt membre ale unor clase, de exemplu mulţimea oamenilor,
informaticienilor, cercetătorilor cu reprezentarea
POPESCU ESTE OM
ESTE_SUBMULŢIME
ADRIAN INFORMATICIAN
ION CERCETĂTOR
Cu toate că reprezentarea este sugestivă este însă dificil de regăsit direct propoziţia
POPESCU ESTE OM sau altă propoziţie corespunzătoare relaţiilor specificate.
Relaţia taxonomică nu epuizează toate posibilităţile pe care primitiva le oferă
reprezentării cunoaşterii. Pentru aplicaţiile de inteligenţă artificială au fost elaborate o serie
de primitive semantice din care mai cunoscute sunt cele elaborate de Yorrick Wilks şi Roger
Schank.
Sistemul lui Wilks porneşte de la premisa că în limbajul natural există cuvinte cu
semnificaţii primitive cât şi cuvinte fără semnificaţii primitive. Wilks defineşte următoarele
clase de primitive semantice:
- primitive ce semnifică entităţi de tip om, lucru, substanţă, parte;
- primitive ce specifică semnificaţii cu care se reprezintă acţiuni cum sunt cauză,
mutare, curgere, lovire;
- primitive ce specifică semnificaţii cu care se reprezintă relaţii între entităţi de tip
obiect, instrument;
- primitive ce specifică semnificaţii cu care se reprezintă calificative ale entităţilor şi
acţiunilor cum sunt: mult, puţin, bun, rău, mic, mare;
- primitive ce specifică semnificaţii cu care se reprezintă tipuri de entităţi;
- primitive ce specifică clase de primitive, obiecte fizice, oameni, obiecte în interior,
exterior.
Pentru cuvintele ce nu sunt primitive se dau definiţii cu ajutorul primitivelor
semantice. Primitivele semantice trebuie să fie independente în sensul că nu se pot defini cu
ajutorul altor primitive semantice asigurând astfel consistenţa (în sensul că nu sunt definite
circular).
Sistemul lui Schank sau teoria dependenţelor conceptuale foloseşte reprezentarea fără
ambiguităţi a semnificaţiei utilizând 11 acţiuni elementare grupate în categorii. Într-o astfel de
reţea semantică conceptele sunt legate prin relaţii numite dependente, ce se disting prin tip şi
etichetă. Pot exista mai multe tipuri de dependenţe cum sunt:
- dependenţa de tip cauzal materializată prin descrierea relaţiilor conceptuale ale
obiectului şi legătura sa cu actul primitiv;
- dependenţă de tip subiectival care leagă acţiunea primitivă de agentul său numit şi
concept actor;
- dependenţă de tip predicativ ce leagă un concept de un predicat.
Cele trei tipuri de dependenţe se pun în evidenţă prin mascarea cu linii diferite,
etichetele fiind cele ce denumesc arcele cu tipul dependenţei.
Funcţie de structură şi tipul de reprezentare reţelele semantice se pot clasifica în:
- reţele semantice simple;
- reţele semantice sortate;
- reţele semantice extinse.
21
1.1.4.1. Reţele semantice simple
Sunt acele entităţi în care nodurile sunt entităţi individuale, iar arcele relaţii ale
acestora. În aceste reţele nu se introduc specializări ale arcelor şi nodurilor, fapt ce determină
că interpretarea este dată de conţinutul descrierii ce este asociat fiecărui simbol ce figurează
ca etichetă de nod sau arc. La interpretare se asociază fiecărui simbol de etichetă o procedură
proprie de determinare a semnificaţiei, singura trăsătură comună a elementelor reţelei fiind
legată de structură şi se manifestă sub formă de proceduri fizice de parcurgere a reţelei. Cu
ajutorul reţelelor semantice simple se pot reprezenta aserţiuni libere de orice variabilă întrucât
nu se admit noduri specializate aferente reprezentării variabilelor.
Să presupunem reprezentarea piesei de cunoaştere ce specifică faptul că “LA
SUSŢINEREA TEZEI DE DOCTORAT DE CĂTRE ION CARE ESTE UN BUN SPECIALIST,
COLEGUL SĂU VASILE ÎI OFERĂ UN FRUMOS CADOU.” Se obţine următoarea reţea
semantică simplă:
SUSŢINERE TEZĂ
ESTE
ION SPECIALIST
ESTE Referitor agent
EVENIMENT 2 ESTE
COLEG OM
receptor
CAUZEAZĂ
ESTE
EVENIMENT 1 agent VASILE
ACŢIUNE OBIECT
Se observă din studiul reprezentării de mai sus că aceasta nu este realizată în formă
propoziţională. Se cunoaşte faptul că ION şi VASILE sunt oameni, adică aparţin clasei OM.
Acţiunea de oferire a cadoului de către VASILE este un eveniment pentru care VASILE este
agent şi ION este receptor. Pentru ION susţinerea tezei de doctorat este de asemenea un
eveniment. Acest eveniment este în relaţie cauzală cu evenimentul oferirii cadoului.
Reţelele semantice simple nu oferă noduri preferenţiale în iniţierea procesului de
interpretare, selecţia unui nod ca nod iniţial este determinată de aplicaţia pentru care este
construită baza de cunoştinţe. Candidaţii pentru poziţia de nod iniţial sunt selectaţi după
diverse criterii dintre care cele mai întâlnite sunt:
- nodul etichetat cu un simbol identic numelui piesei de cunoaştere;
- selecţia candidaţilor dintre nodurile ce au proprietatea de a fi noduri sursă pentru toate
relaţiile în care sunt implicate.
Pentru descrierea unei reţele semantice simple aceasta este descompusă în triplete de
forma
22
1.1.4.2. Reţele semantice sortate
23
- funcţia semantică a argumentelor exprimate sub forma relaţiilor cauzale;
- restricţii de selecţie a termenilor ce candidează pe poziţia de argumente ale
predicatului.
Starea de lucruri descrisă de o predicţie dă o valoare de adevăr predicatului. Stările de
lucruri ce nu se modifică în timp se numesc statice, spre deosebire de cele dinamice ce sunt
caracterizate de schimbări de timp.
Dacă în cadrul predicatului există un argument numit controlor ce are proprietatea de
a determina starea de lucruri asociată predicţiei se spune că starea este controlată. Dinamismul
şi controlul determină noi sorturi ale predicţiei şi anume:
- acţiunea - stare dinamică şi controlată;
- procesul - corespunde unei stări de lucruri dinamice şi necontrolate;
- poziţia - corespunde unei stări de lucruri statice şi controlate;
- situaţia - corespunde unei stări de lucruri statice, dar necontrolate.
Relaţiile cauzale se pot extinde fără restricţii putând fi definite următoarele tipuri de
relaţii:
- relaţii ce extind specificarea stării de lucruri: calitate, modalitate;
- relaţii ce referă predicţia la alţi participanţi: iniţiator, cunoscător, executor,
terminator;
- relaţii ce extind dimensiunile spaţiale: sub, lângă, deasupra;
- relaţii ce extind dimensiunile temporale: durata, frecvenţa;
- relaţii de interpoziţionare între o stare şi alte stări: cauză, motiv, scop, rezultat,
circumstanţă.
În procesul de instanţiere a pieselor de cunoaştere individuale dintr-o reţea semantică
prin care să reprezentăm cunoaşterea sub toate aspectele sale conceptuale şi factuale, apare
necesară organizarea reţelei semantice în vederea stabilirii ierarhiei între diferitele
componente ale reţelei.
Cea mai simplă organizare împarte reţeaua în două părţi:
- reţeaua conceptuală, în care sunt descrise piesele de cunoaştere care reprezintă
obiecte, acţiuni, procese, stări de lucruri cu caracter generic;
- reţeaua factuală, în care sunt descrise instanţele acestor concepte.
24
OM
Relaţii
X AJUNGE DEPARTE
condiţionale
Reţelele semantice extinse sunt de fapt reţele sortate pe baza unor criterii de logică a
programării.
Diferenţe între reţelele semantice extinse sunt date de criteriile:
- setul primitivelor semantice şi metodele de tratare a neprimitivelor;
- stabilirea sorturilor pentru noduri şi arce;
- mecanismele de definire a altor sorturi (definirea pieselor de metacunoaştere);
- convenţiile de reprezentare grafică.
Reţelele semantice extinse oferă un instrument de realizare mai apropiat decât reţelele
semantice simple.
Prin sortarea nodurilor şi arcelor se introduc mecanisme descriptive puternice capabile
să specifice restricţii implicite, ceea ce au efect favorabil asupra: eficienţei utilizării spaţiului
de reprezentare, simplifică accesul la piesele de cunoaştere şi reduce timpul necesar pentru
procesele inferenţiale.
Simbolurile pot reprezenta proprietăţi ale obiectelor sau relaţiilor, nume de alte cadre,
identificatori de proceduri ataşate. Se disting în reprezentarea prin cadre o serie de primitive
25
semantice ce fac să plaseze cunoaşterea în conceptul mai larg oferit de structura cadrului cum
sunt:
- forme utilizate la descrierea piesei de cunoaştere;
- forme ce exprimă elemente reprezentate de utilizarea cadrului;
- forme corespunzând prezumţiilor considerate adevărate;
- forme corespunzând reorientării continuării în situaţia eşecului.
Relaţiile aferente utilizării formelor, relaţii ce caracterizează piesa de cunoaştere şi
legăturile sale cu universul problemei se pot împărţi după tip în :
- generalizare - specifică concepte cu definiţii mai puţin restrictive;
- specializare - specifică concepte cu descrieri ce satisfac o condiţie dată;
- apartenenţa - indică clasa din care face parte piesa de cunoaştere şi prin care se
moştenesc proprietăţile;
- compoziţia - indică obiectele ce intră în alcătuirea obiectului;
- proprietăţile - reprezintă proprietăţile specifice ale obiectului reprezen-tat.
Un exemplu de reprezentare cadru pentru o universitate cu profil tehnic care foloseşte
forme cadru specifice de descriere se găseşte la sfârşitul acestui modul, probleme rezolvate.
26
Unitatea de învăţare nr.2
Problematica rezolvării problemelor
(sisteme rezolutive)
Cuprins:
2.1. Probleme, raţionamente, strategii ................................................................ pag. 27
2.1.1. Strategia de control înainte..... .................................................................. pag. 28
2.1.2. Strategia de control înapoi ..... .................................................................. pag. 29
2.1.2. Strategia de control combinat înainte-înapoi ..... ...................................... pag. 30
2.2. Tipuri reprezentative de probleme ............................................................... pag. 31
2.3 Cunoaşterea despre problemă în procesul rezolvării .................................... pag. 32
2.4. Reprezentarea problemelor în limbajul calculului cu predicate
de ordinul întâi .................................................................................................... pag. 33
2.4.1. Skolemizarea formulelor ........................................................................... pag. 35
2.5. Reprezentarea problemei în spaţiul stărilor .................................................. pag. 38
2.6. Utilizarea grafurilor ŞI/SAU ........................................................................ pag. 41
2.6.1. Rezolvarea problemelor prin decompoziţie .............................................. pag. 42
2.7. Aplicaţii. Exerciţii rezolvate, teste de autoevaluare, teme de control ..... .... pag. 43
2.8. Bibliografie modul 1 .................................................................................... pag. 47
Rezolvarea problemelor este obiectivul fiecărui sistem inteligent şi se va face atât prin
căutarea unor răspunsuri predefinite la unele întrebări, dar mai ales prin procese complexe de
deducţie, de calcul simbolic şi evaluări numerice, care se bazează pe faptele specificate în
enunţul problemelor şi pe fapte înregistrate a priori în baza de cunoştinţe.
Totalitatea componentelor unui astfel de sistem destinat rezolvării de probleme
formează un sistem rezolutiv.
Problema reprezintă o dificultate de natură cognitivă dată de:
- insuficienţa sau inadecvarea unor răspunsuri la întrebări privind o entitate
necunoscută;
- incapacitatea sistemului rezolutiv de a construi un răspuns prin aplicarea
procedeelor cunoscute.
Problema prezentată spre rezolvare sistemului de inteligenţă artificială este un enunţ
de problemă potenţială. Confirmarea ca problemă reală e dată de apariţia în cadrul sistemului
a unei situaţii problematice.
Constituentele primitive ale problemei sunt:
- aserţiuni ce descriu obiectele ce alcătuiesc universul discursului, numite şi date ale
problemei (aspectul factual);
- aserţiuni referitoare la operaţiile permise sau condiţiile problemei (aspectul
procedural);
- obiecte, proprietăţi sau condiţii reformulate explicit, consecinţă a enunţului sau
necunoscutele problemei.
Obiectivul rezolvării îl reprezintă asocierea unei determinări fiecărei necunoscute.
Indiferent de modul de raţionare utilizat ciclul de bază al unui mecanism de inferenţe cuprinde
patru faze şi anume:
- faza de selecţie a unui subansamblu al bazei de fapte şi reguli ce merită atenţia faţă
de restul bazei. Selecţia oferă o economie de timp considerabilă pentru fazele
următoare;
27
- faza de filtrare ce are ca efect comparaţia între partea de premisă a regulii
considerate şi faptele bazei de fapte pentru determinarea regulilor aplicabile;
- faza de rezolvare a conflictelor are ca obiectiv alegerea acelor reguli ce sunt
aplicate efectiv;
- faza de execuţie constă din aplicarea regulilor alese mai înainte, acţiunea constând
în general în adăugarea de noi fapte în baza de fapte.
Raţionamentul reprezintă constituirea lanţurilor sau a reţelelor inferenţiale între
premise şi concluzie. El este fundamentat pe faptele furnizate de enunţ şi pe cele din baza de
cunoştinţe. Dacă acestea sunt suficiente raţionamentul este direct, altfel se ajunge la impas şi
necesită folosirea altor raţionamente cum ar fi cel metaforic sau prin analogie.
Raţionamentele ce pornesc de la premise la concluzie (se numesc formale) şi studiază
transformările structurale. Raţionamentele informale pornesc de la semnificaţiile factuale şi
procedurale cuprinse în enunţuri. Aceste metode de raţionament surprind interpretări
structurale, semnificaţii de natură relaţională, proprietăţi primitive, structuri ierarhice bazate
pe primitive semantice. Raţionamentul informal este necesar să se valideze prin aplicarea
regulilor specifice simbolurilor folosite actual. Desfăşurarea raţionamentelor are loc pe baza
unei strategii ce asigura succesiunea inferenţelor.
Iată câteva strategii de control al raţionamentelor.
28
R6 : IF A and X THEN H
R7 : IF C THEN D
R8 : IF X and C THEN A
R9 : IF X and B THEN D
R9
R 4 (B)
B, C B, C, X
R8
R 7 (C)
R 7 (C)
R9
B, C, X, D
R 5 (D) R8
R9
B, C, X, D ,E
R8
R 1 (E)
R9
B, C, X, D , E, F
R 3 (F) R8
R9
B, C, X, D , E, F, A,
R8
R6
B, C, X, D , E, F, A H
R4 R8 R6
B, C B, C, X B, C, X, A B, C, X, A, H
R7 R7
R8
R9 R9
Modul de control specificat mai poartă denumirea şi de control dirijat prin obiectivul
problemei sau control de sus în jos. Metoda se mai numeşte şi reductivă.
Raţionarea porneşte de la scop, selectând acele reguli ce au partea dreaptă în
corespondenţă cu obiectivul problemei. Condiţiile necunoscute (partea stângă) devin în acest
mod subscopuri ce se vor demonstra. Procesul continuă până când toate subscopurile se
verifică. În acest caz sistemul poate cere utilizatorului să răspundă la întrebări şi procesul
reîncepe după primirea răspunsurilor. În momentul în care sistemul nu mai poate selecta
reguli, formula întrebări utilizatorului sau utilizatorul nu mai poate răspunde la întrebări se
ajunge la situaţia de eşec.
Pentru exemplul considerat la strategia de control înainte, se poate observa că regulile
R2 , R3 , R8 pot fi utilizate pentru a verifica scopul A. În acest sens regulile sunt aplicate în
ordinea numerotării lor, pentru a încerca să verifice din unul în altul subscopurile produse. În
caz de eşec, cum este subscopul G care nu poate fi dedus, se revine în arbore pentru a selecta
regulile lăsate la prima trecere. În acest fel explorarea încetează atunci când fie a fost
demonstrat obiectivul iniţial, fie când toate selecţiile posibile au condus la eşec. În diversele
faze sistemul poate recurge la chestionări ale utilizatorului asupra subobiectivului nerezolvat.
Avantajele strategiei de căutare înapoi:
- arborele de căutare este adesea mai puţin adânc decât cel aferent strategiei de
control înainte;
- sistemul poate recurge la întrebări adresate utilizatorului, procesul de raţionare
fiind interactiv.
Strategia are şi un mare dezavantaj legat de faptul că există pericolul buclării.
30
2.2 Tipuri reprezentative de probleme
Problemele de tip IXR corespund enunţului: “Ce proces X trebuie aplicat asupra
obiectelor din ipoteze I pentru a obţine rezultatul R ?”. La acest tip se manifestă caracterul
creator, rezolvarea putându-se aborda astfel:
Problemele de tip XPR corespund formulării: “Ce obiecte X trebuie să fie prelucrate
de către procesul P pentru a obţine rezultatul R ?”.
Problema poate fi rezolvată direct doar dacă P este o bijecţie adică ştiind că R = P(X)
soluţia va fi X = P-1(R). Dacă însă P nu este o bijecţie atunci abordarea trebuie făcută prin
metode reductive.
31
(2) – Problemele de tip predicativ – se aseamănă cu cele interogative, diferenţa fiind
că ipoteza şi concluzia sunt entităţi cu valoare de adevăr. Componentele unei probleme de tip
predicativ sunt:
- ipoteza =I=
- procesul inferenţial =R=
- concluzia =C=
Cele trei tipuri de probleme se vor numi astfel:
Problemă de tip IPX – denumită şi deducţie sau derivare. Se întâlneşte frecvent în
aplicarea procedurilor ce vizează descompunerea problemelor în subprobleme;
Problemă de tip IXC – denumită şi demonstraţie. Soluţia unei astfel de probleme este
formată dintr-un lanţ de inferenţe ce porneşte de la ipoteze şi ajunge la concluzie. Aplicarea
unui lanţ inferenţial este caracteristică sistemelor rezolutive pentru demonstrarea automată a
teoremelor.
Problemă de tip XPC – denumită şi inducţie sau învăţare din exemple. Soluţia
presupune descoperirea unor concepte iniţiale, a cauzalităţii sau a altor premise prin
interpretarea rezultatelor ce se obţin pe baza unor reguli de inferenţă cunoscute.
32
conceptuală
factuală
instanţială
transformaţională
Cunoaştere procedurală
inferenţială
pentru structuri
de control
pentru raţionamente
33
- simboluri predicative ce definesc piese cu valoare de adevăr ce descriu proprietăţi
ale obiectelor sau relaţii între obiecte;
- fapte – expresii formale ce exprimă adevăruri despre obiectele implicate;
- obiectivul reprezentat printr-o expresie formală, prin care se exprimă ce se
urmăreşte ca rezultat.
Să considerăm următorul exemplu de problemă:
“ Un grup de excursionişti ajung pe malul stâng al unui râu ce nu poate fi traversat
înot. La acelaşi mal se găsesc doi copii cu o barcă. În barcă poate să fie la un moment dat un
singur excursionist sau doi copii. În final se cere ca grupul excursioniştilor să se găsească pe
malul drept, iar cei doi copii împreună cu barca pe malul stâng. ”
Se propune următoarea grupare de simboluri:
Suportul obiectual format din:
- mulţimea copiilor C = { c1 , c2 }
- mulţimea excursioniştilor E = { e1 , e2 , … , en }
- elementul barcă {b}
- cele două maluri { d , s }
Simbolurile predicative ce se vor asocia proprietăţilor :
C(x) – x este un copil
E(x) – x este un excursionist
D(x) – x este pe malul drept
S(x) – x este pe malul stâng
B(x) – barca este în poziţia x { d , s }
T(x, y, z) – (x) trece cu barca din poziţia (y) în poziţia (z) în care x C E,
y, z { s , d };
Faptele sunt organizate în fapte reprezentând condiţii ale problemei şi fapte relevând
proprietăţi ale obiectelor.
Condiţiile şi expresiile formale ce definesc problema traversării sunt:
- Barca ajunsă pe malul drept trebuie readusă pe malul stâng numai de către un copil,
un excursionist ajuns pe malul drept va rămâne acolo ştiind că numai aşa obiectivul
problemei poate fi atins. Deci:
i) [D(x) C(x)] B(d) T(x, d, s)
- Dacă barca este pe malul stâng şi pe malul drept există un copil care să o readucă
înapoi atunci un excursionist poate traversa râul;
ii) [S(x) E(x)] [D(y) C(y)] B(s) T(x, s, d)
- Dacă cei doi copii se găsesc pe malul stâng aceştia pot traversa râul împreună
utilizând barca, fapt ce se exprimă prin formula:
iii) [S(x) C(x)] [S(y) C(y)] B(s) T(x, s, d) T(y, s, d)
- Poziţia bărcii după o traversare
iv) T(x, y, z) B(z)
- În urma unei traversări obiectele traversate vor fi plasate pe malul destinaţie
v) T(x, s, d) D(x)
vi) T(x, d, s) S(x)
- Dacă ambii copii sunt pe malul drept unul dintre ei va trebui să aducă barca pe
malul stâng
vii) [D(x) C(x)] [D(y) C(y)] B(d) T(x, d, s)
- Faptele care exprimă proprietăţi ale obiectelor sunt date de mulţimea copiilor,
mulţimea excursioniştilor şi de poziţia iniţială a acestora.
viii) C(c1), C(c2), E(e1), E(e2), … , E(en), S(c1), S(c2), S(e1), S(e2), … , S(en), B(s)
- Obiectivele problemei sunt date de poziţia finală a copiilor, bărcii şi
excursioniştilor
34
ix) D(e1) D(e2) … D(en)
şi
x) S(c1) S(c2) B(s)
Forma generală a formulelor în calculul cu predicate de ordinul întâi nu este
convenabilă pentru aplicarea formulelor cunoscute în logică. În acest sens o serie de
transformări sunt aplicate acestor formule pentru a fi aduse la forma convenabilă
mecanismului de interpretare.
Teorema 1. Fie A şi B două formule oarecare. Atunci sunt valabile următoarele reguli:
1) (A B) ( A B);
2) (A B) (A B);
3) (A B) (A B) ( A B).
Teorema 2. Dacă x este o variabilă, iar A, B, A(x) şi B(x) formule, dar A şi B nu conţin
apariţii libere ale variabilei x , atunci:
1) x (A B(x)) A xB(x);
2) x (A(x) B) xA(x) B;
3) x (A B(x)) A xB(x);
4) x (A(x) B) xA(x) B;
5) x (A(x) B(x)) xA(x) xB(x);
Pornind de la o formulă oarecare A se poate găsi o formulă A’ numită şi formă prenex
a lui A cu proprietăţile:
1) A’ este echivalentă cu A, adică A A’.
2) în formula A’, toţi cuantificatorii (în cazul când există) sunt plasaţi grupat în partea
cea mai din stânga a formulei prefixând corpul formulei în care sunt plasate
35
celelalte simboluri logice ( , , , , în cazul când există) care figurau în scopul
fiecărui cuantificator.
Teorema 3. Dacă x şi y sunt variabile distincte, iar A, B, A(x), B(x) şi A(x, y) sunt
formule, dar A şi B nu conţin apariţii libere ale variabilei x şi dacă x este liber pentru y în A(x,
y) (în formulele 5 şi 6), atunci:
1) x A A;
2) x A A;
3) x y A(x, y) y x A(x, y);
4) x y A(x, y) y x A(x, y);
5) x y A(x, y) x A(x, x);
6) x A(x, x) x y A(x, y);
7) x A(x) x A(x);
8) x y A(x, y) y x A(x, y);
9) x A(x) x A(x);
10) x A(x) x A(x);
11) x A(x) x A(x);
12) x A(x) x A(x);
13) x A(x) x B(x) x (A(x) B(x));
14) x A(x) x B(x) x (A(x) B(x));
15) A x B(x) x (A B(x));
16) A x B(x) x (A B(x));
17) A x B(x) x ( A B(x) );
18) A x B(x) x ( A B(x) );
19) x ( A(x) B(x) ) x A(x) x B(x);
20) x A(x) x B(x) x ( A(x) B(x) );
Teorema 4. Dacă x este o variabilă, iar A, B, A(x) şi B(x) sînt formule atunci:
1) x A(x) x A(x);
2) x A(x) x A(x);
3) (A B) A B;
4) (A B) A B;
5) A) A;
Teorema 5 Dacă x este o variabilă, A(x) si B sînt formule cu x liberă în A dar legată în
B, atunci:
1) x (A(x) B) x A(x) B;
36
2) x (B A(x)) B x A(x);
3) x (A(x) B) x A(x) B;
4) x (B A(x)) B x A(x);
5) x (A(x) B) x A(x) B;
6) x (B A(x)) B x A(x);
7) x (B A(x)) B x A(x);
8) x (A(x) B) x A(x) B;
Teorema 6 Dacă x este o variabilă, A(x) şi B(x) sînt formule cu x liberă atât în A(x) cât
şi în B(x), atunci:
1) x (A(x) B(x)) x A(x) x B(x);
2) x (A(x) B(x)) x A(x) x B(x);
Teorema 7 Dacă x şi y sînt variabile A(x, y) şi B(x, y) sînt formule, x este legată în cel
puţin una din formulele A(x, y) şi B(x, y), iar y este liberă atât în A(x, y) cât şi în B(x, y),
atunci:
1) x y (A(x, y) B(x, y)) y x (A(x, y) B(x, y));
2) x y (A(x, y) B(x, y)) y x (A(x, y) B(x, y))
| x1, x2, ….xn ( y ( x1, x2, ….xn) ( x1, x2, ….xn, f ( x1, x2, ….xn)
Astfel se elimină din formula dată cuantificatorul existenţial prin înlocuirea variabilei
cuantificate cu un simbol funcţional inexistent având ca argumente acele variabile ce sînt
cuantificate universal.
| A (B C) (A B) (A C);
37
| (A B) C (A C) (B C);
Astfel, forma Skolem conjunctivă trebuie eventual simplificată pentru a ajunge la cea
mai condensată formă de exprimare a formulei.
38
- definirea unor reguli restrictive pentru procesul generator de stări având ca scop
eliminarea stărilor redundante, a celor care se depărtează de soluţie, a
combinaţiilor absurde ce nu conduc la soluţie;
- definirea unor strategii de căutare a soluţiei în spaţiul generat;
- definirea unor strategii de revenire în caz de eşec;
- alegerea unei reprezentări compacte ca spaţiu de memorie ocupat;
Se prezintă în continuare problema traversării râului (paragraful 2.4) pentru a cărei
rezolvare se va utiliza spaţiul stărilor. Notând cu S şi D stările parţiale ale problemei ce
reprezintă situaţia pe cele două maluri, stâng şi respectiv drept, se obţine starea ca o reuniune
a celor două “stări potenţiale” S D.
Prin aplicarea operatorilor definiţi mai înainte se poate genera spaţiul stărilor, spaţiul
în care prima stare este starea iniţială. Modul de formare a arborelui asociat problemei de
traversare a râului pentru primele trei nivele este următorul:
39
Graful de tranziţie a stărilor cu punctul de plecare starea iniţială are ramuri ce duc la
obiectivul final, operatorii ce conduc la stări redundante fiind eliminate. Soluţia problemei
poate fi privită fie ca o succesiune de stări, fie ca o secvenţă a operatorilor ce conduc la starea
obiectiv. Furnizarea soluţiei ca o secvenţă de operatori ce conduce la obiectiv va da:
În care secvenţa O’’={ T2cd, Tcs, Ted, Tcs} se repetă de un număr egal cu numărul
excursioniştilor.
Din analiza reprezentării în spaţiul stărilor se observă o asemănare între aceasta şi
reprezentarea sistemelor de producţie. Altfel, un operator se aplică numai dacă anumite
criterii prestabilite sînt îndeplinite de starea asupra căreia se aplică (echivalenţă cu
precondiţia), rezultatul aplicării operatorului fiind obţinerea unei stări noi din cea veche
(echivalentul acţiunii sau producţiei). Strategia de control este cea care determină selectarea
operatorilor (regulilor de producţie) şi a modului de aplicare succesivă a acestora pentru
generarea spaţiului stărilor.
Aplicarea unui operator asupra unei stări fără a putea reveni la starea anterioară pentru
a apela un alt operator formează strategia de control irevocabilă. Strategia de control se
numeşte tentativă dacă la un anumit punct se poate lua decizia de revenire la o stare
precedentă în vederea aplicării de noi operatori. Strategia de control cu revenire
(backtracking) este acea strategie prin care punctul de reluare este stabilit din momentul
selectării operatorului, aşa că în caz de eşec se poate relua procesul de la un altfel de punct, nu
neapărat cel mai apropiat. Strategia de control prin căutare în grafuri este cea prin care se
păstrează informaţii privind consecinţele aplicării operatorilor la fiecare pas al generării.
40
2.6. Utilizarea grafurilor ŞI/SAU
Un nod este solvabil dacă este îndeplinită cel puţin una din condiţiile:
- nodul considerat reprezintă o problemă primitivă (terminal);
- nodul considerat este un nod terminal de tip SI, ale cărui noduri succesoare sînt
toate terminale;
- nodul considerat este un nod neterminal de tip SAU, iar cel puţin unu din
succesorii săi este solvabil;
Subgraful conţinând nodurile solvabile ale unui graf ŞI/SAU care reprezintă reducerea
unei probleme, în care este conţinut şi nodul iniţial, demonstrează solvabilitatea problemei şi,
de aceea, este denumit graful soluţiei.
Riguros, f (P, L, f, b) un graf orientat cu mulţimea nodurilor D, mulţimea arcelor L, f -
funcţia de înaintare şi b- funcţia de revenire, evident f, b: L D. Se spune că un graf este un
arbore dacă sînt îndeplinite condiţiile:
1) Graful nu are circularităţi
2) Există un nod p, numit şi rădăcină, pentru care f: L D-{p}.
41
Setul Pk al punctelor nivelului k este definit succesiv funcţie de nivelul k-1. Altfel,
dacă b(xi) Pk-1, pentru i=1, 2, … , j atunci:
Pk ={ f(xi); i= 1, 2, … ,j}
Evident, pentru descrierea unei probleme într-un sistem de calcul, este suficient să se descrie
într-un mod riguros cvadruplul ( P, L, f, b) asociat problemei.
Un nod într-un arbore ŞI/SAU poate fi un nod ŞI al unui nod părinte dat şi în acelaşi
timp un nod SAU al altui nod părinte. Ca urmare, este necesar să se identifice relaţia părinte-
fiu. Vom utiliza expresiile “ni este un nod ŞI al nodului n “ sau ”nodul ni al lui n este un nod
ŞI“.
42
2.7. Aplicaţii – modul 1.
A. Exerciţii rezolvate.
Exerciţiul 1.
Să se reprezinte în limbajul calculului cu predicate de ordinul întâi următoarea frază din
limbajul natural:
Rezolvare:
Puterea de reprezentare a cunoaşterii, pe care o au formulele limbajului calculului
propoziţional de ordinul I se poate cel mai bine aprecia prin considerarea unor exemple
complexe în care este folosită şi forma clauzală care reprezintă un concept nou numit
programare logică, care stă la baza limbajului de programare PROLOG.
Exerciţiul 2.
Să se reprezinte în limbajul calculului cu predicate de ordinul întâi, folosind forma
clauzală, următoarea frază din limbajul natural:
Rezolvare:
Forma de reprezentare numită şi clauză este :
43
Exerciţiul 3. Să se reprezinte sub forma unor liste LISP piesa de cunoaştere din
exemplul dat în paragraful 1.1.4.1., folosind şi reprezentarea sub formă de reşea semantică din
acel paragraf:
“LA SUSŢINEREA TEZEI DE DOCTORAT DE CĂTRE ION CARE ESTE
UN BUN SPECIALIST, COLEGUL SĂU VASILE ÎI OFERĂ UN FRUMOS
CADOU.”
Rezolvare:
Singurul nod sursă din reprezentare este <Eveniment2> ce poate fi considerat nod
iniţial, lista pornind descrierea de la acest nod:
Exerciţiul 4.
Să se reprezinte sub forma unei reţele semantice sortate, folosind relaţiile cauzale
definite în paragraful 1.1.4.2., următoarea piesă de cunoaştere:
44
Rezolvare:
Reţeaua semantică sortată, folosind relaţiile cauzale definite în paragraful 1.1.4.2., este
următoarea:
P
PREDICAŢIE
TIMP
AGENT
RECEPTOR LOC
INSTRUMENT
OBIECT
Exerciţiul 5.
Să se descrie reprezentarea unei universităţi cu profil tehnic cu ajutorul cadrelor,
folosind forme cadru specifice de descriere (paragraful 1.1.5.).
Rezolvare:
Iată o variantă de descriere:
1. Când exprimăm că “George îşi iubeşte câinele” presupunem implicit că George are un
singur câine? Cum am putea reexprima aceasta dacă am dori să spunem că George îşi
iubeşte toţi câinii săi? Aceasta ar fi adevărată dacă George nu are şi alţi câini?
B. Temă de control
Exerciţiul 1.
Să se reprezinte cu ajutorul regulilor de producţie următoarea piesă de cunoaştere:
Exerciţiul 2.
Să se reprezinte cu ajutorul cadrelor următoarea piesă de cunoaştere:
46
Exerciţiul 3.
Pe malul unui râu sunt trei misionari şi trei canibali. Există o singură barcă
disponibilă care poate transporta două persoane şi pe care vor s-o folosească pentru a
traversa râul. Dacă numărul canibalilor depăşeşte numărul misionarilor pe unul din malurile
râului (incluzând şi ocupanţii bărcii), misionarii vor fi mâncaţi. Cum poate fi utilizată barca
pentru a transporta în siguranţă toţi misionarii şi canibalii dincolo de râu?
Exerciţiul 4.
Pe malul unui râu sunt trei misionari şi trei canibali. Există o singură barcă
disponibilă care poate transporta două persoane şi pe care vor s-o folosească pentru a
traversa râul. Dacă numărul canibalilor depăşeşte numărul misionarilor pe unul din malurile
râului (incluzând şi ocupanţii bărcii), misionarii vor fi mâncaţi. Cum poate fi utilizată barca
pentru a transporta în siguranţă toţi misionarii şi canibalii dincolo de râu?
Rezolvaţi problema folosind spaţiul stărilor pe baza unei structuri arborescente.
Indicaţie: Modul de formare a arborelui asociat problemei de traversare a râului de
către misionari şi canibali poate fi vazut ăn exemplul din paragraful 2.5.
Coordonator disciplină:
Prof. univ. dr. Vasile PODARU, email: podaruv@gmail.com
47
UNIVERSITATEA TITU MAIORESCU
Facultatea de INFORMATICĂ
BUCUREŞTI – 2011
UNIVERSITATEA Titu MAIORESCU Bucureşti
Facultatea de Informatică
Învăţământ la Distanţă
INTELIGENŢĂ ARTIFICIALĂ
Inteligenţa artificială este una din disciplinele de pregătire fundamentală care, pentru
profilul INFORMATICĂ, este esenţială pentru pregătirea studenţilor şi pentru obţinerea
creditelor transferabile prin procedurile de evaluare. Modul de prezentare a acestui material
are în vedere particularităţile învăţământului la distanţă, la care studiul individual este
determinant. Pentru orice nelămuriri faţă de acest material vă rugăm să contactaţi tutorele de
disciplină care are datoria să vă ajute oferindu-vă toate explicaţiile necesare.
Disciplina de Inteligenţa artificială îşi propune următoarele obiective specifice:
Însuşirea noţiunilor fundamentale din domeniile Inteligenţei artificiale.
Formarea deprinderilor de modelare matematică şi de transpunere în programare a
unor probleme de natură tehnică, socială sau economică, cu utilizarea cunoştinţelor
însuşite.
Formarea şi dezvoltarea aptitudinilor şi deprinderilor de analiză logică, formulare
corectă şi argumentare fundamentată, în rezolvarea problemelor tehnico-economice şi
de specialitatecu cu utilizarea cunoştinţelor însuşite prin intermediul metodelor şi
modelelor specifice inteligenţei artificiale;
Insusirea principiilor generale ale programarii logice si insusirea limbajului Prolog;
O comparaţie critică a metodelor de rezolvare evidenţiind, eventual, calea optimă de
soluţionare.
Accentul se va pune pe problemele de cautare si reprezentare a cunostintelor si
respectiv pe programarea logica, limbajul de programare utilizat la laborator fiind
limbajul Prolog. Cursul trebuie sa trateze aspecte ale rezolvarii problemelor prin
intermediul cautarii, descriind cele mai importante tehnici de cautare informata si
neinformata. Se vor da exmple de aplicatii ale cautarii, cum ar fi jocurile, tratate ca
probleme de cautare. Se vor prezenta principalele tipuri de cunostinte si principalele
metode de reprezentare a cunostintelor. Se va face legatura dintre reprezentarea
cunostintelor si sistemele expert. Se va da un exemplu de sistem expert cu
implementare in Prolog. Vor mai fi tratate, ca modalitati de reprezentare a
cunostintelor, retelele semantice si retelele Bayesiene (cu introducerea rationamentului
statistic).
49
Întru-cât modulul este privit ca un tot unitar exerciţiile aferente acestui modul se
găsesc la sfârşitul acestui modul. La terminarea parcurgerii acestui modul studenţii trebuie să
prezinte tutorelui de disciplină rezolvarea temei de control propusă spre rezolvare la sfîrşitul
modulului.
Cursul se finalizează prin examen care constă din:
1) o lucrare scrisă sub forma de text grila constând din 9-18 subiecte (ponderea lucrării
scrise este de 70% din nota finală);
2) rezolvarea corectă a temelor de control din cele 4 module (minimum nota 5 pentru
fiecare temă, ponderea mediei celor 5 note în nota finală este de 20%);
3) participarea activă la activităţile tutoriale (apreciată printr-o notă a cărei pondere in
nota finală este de 10%).
50
MODULUL 2
METODE DE CĂUTARE
Îndrumări metodice.
51
Unitatea de învăţare nr.3
52
care acceptă un nod ca intrare şi îi determină succesorii. În figură succesorii nodului iniţial
sunt nodurile c1, c2 şi c3, sunt noduri la care se poate ajunge într-un singur pas plecând de la
nodul i. Astfel intrarea într-o problemă de căutare reprezintă o descriere a nodului iniţial, a
nodului ţintă şi a unei proceduri care furnizează succesorii unui nod oarecare; ieşirea trebuie
să fie o secvenţă legală de noduri începând cu nodul iniţial dat şi terminând cu nodul ţintă.
d=0
..............
P A T M A T B O S
d=1
.......... .........
P A T
O d=2
P
53
Există de asemenea probleme de căutare cu mai multe noduri iniţiale; să considerăm o
problemă în există un grup de careuri şi trebuie completat unul dintre ele. În astfel de
probleme cu mai multe noduri ţintă şi mai multe noduri iniţiale, obiectivul poate fi să se
găsească o cale de la un nod iniţial la un nod ţintă (ca în problema cuvintelor încrucişate), să
se găsească toate căile sau să se găsească cea mai bună cale.
În problemele de căutare din exemplele anterioare s-a etichetat fiecare nod cu o
adâncime care indică numărul de paşi necesari pentru a ajunge la acel nod iniţial. Deci, nodul
ţintă din figura 3.1 este de adâncime 3; spaţiul său de căutare este de adâncime 4. În căutarea
din figura 3.2, toate nodurile ţintă sunt de adâncime 4, pentru că sunt patru cuvinte de
completat în careu. În plus, fiecare nod de adâncime 4 este un nod ţintă.
Problemele de căutare sunt adesea descrise pe baza factorului lor de ramificare. Acesta
se referă la numărul de fii pe care îi are un nod care nu este terminal. În figura 3.1, factorul de
ramificare variază între 1 şi 3.
Factorul de ramificare în problema cuvintelor încrucişate este mult mai mare;
considerăm nodul iniţial din figura 3.3. Sunt 8 pătrate de completat şi 26 de litere care pot fi
puse în fiecare pătrat, astfel că factorul de ramificare pentru nodul iniţial este 8*26=208.
Fiecare din cele 208 noduri de adâncime 1 au 7*26=182 succesori, şi aşa mai departe. Nu
toate nodurile de adâncime 2 au 6*26 succesori pentru că unii dintre ei ar include cuvinte
complete, ceea ce este ilegal. Factorul de ramificare în această problemă variază de la un nod
la altul, dar evident este mai mare decât cel din figura 3.1. Deoarece sunt mai mult de 26 de
alegeri posibile pentru plasarea unui cuvânt corect în careu, factorul de ramificare pentru
figura 3.2 este şi mai mare. Cu excepţia numărului mare de noduri care trebuiesc de obicei
explorate, rezolvarea problemelor de căutare este uşoară. Presupunând că factorul de
ramificare este un număr finit, se poate aplica următoarea procedură.
Această procedură, verifică nodurile pentru a vedea dacă sunt soluţii ale problemei
iniţiale de căutare din momentul în care sunt expandate pentru a genera fii.
Cu excepţia unor modificări nesemnificative a procedurii 3.2.1 prezentată anterior,
toate programele de căutare vor folosii o tehnică asemănătoare ca cea din procedura 3.2.1.
Ceea ce distinge un algoritm de căutare de altul este alegerea făcută la pasul 2 - cum alegem
nodul care va fi expandat în continuare.
Aşa cum se va vedea în cele ce urmează, există două modalităţi prin care se poate face
această alegere. În tehnica de căutare oarbă alegerea este făcută într-un mod dependent doar
de poziţia nodului în arborele de căutare. În căutarea euristică, astfel de informaţii sunt
folosite pentru a decide ce trebuie făcut la următorul pas.
Există o mare varietate de tehnici de căutare oarbă; vom prezenta două dintre ele în
acest paragraf . Cele două tehnici pe care le vom prezenta în continuare sunt căutarea pe
verticală şi căutarea pe orizontală.
54
Figura 3.4 Căutarea pe verticală
Căutarea pe verticală constă în expandarea arborelui de căutare (de exemplu cel din
figura 3.1) în aşa fel încât nodurile terminale să fie examinate de la stânga la dreapta, aşa cum
este prezentat în figura 3.4. Se explorează întotdeauna un fiu al nodului cel mai recent
expandat; dacă acesta nu are fii, procedura revine la pasul anterior înainte de a alege un alt
nod pentru a-l examina. Căutarea se termină când a fost selectat nodul ţintă g.
Căutarea pe verticală poate fi implementată prin inserarea fiilor unui nod dat la
începutul listei L la pasul 4 al procedurii 3.2.1, şi alegerea întotdeauna a primului nod din listă
ca fiind un nod ce trebuie expandat.
PROCEDURA 3.2.2 Căutarea pe verticală.
(Pentru rezolvarea unei probleme folosind căutarea pe verticală):
1. Setează lista L de noduri la nodurile iniţiale din problemă.
2. Fie n primul nod din lista L. Dacă lista L este goală, eşec.
3. Dacă n este un nod ţintă, procedura se termină returnând valoarea n şi calea
de la nodul iniţial până la acesta.
4. Altfel, scoate nodul n din lista L şi adaugă la începutul acesteia toţi fii nodului
n, etichetându-l pe fiecare cu calea de la nodul iniţial până la el. Revenire le
pasul 2.
În căutarea pe orizontală, arborele de căutare este expandat de sus în jos, astfel încât
fiecare nod de adâncime d este examinat înaintea oricărui nod de adâncime d+1. Figura 3.5
prezintă arborele din figura 3.1 indicând ordinea de examinare a nodurilor folosind tehnica de
căutare pe orizontală.
55
Se poate implementa această tehnică prin adăugarea nodurilor noi la sfârşitul listei L.
Procedura 3.2.2 se va modifica astfel:
PROCEDURA 3.2.3 Căutarea pe orizontală.
(Pentru rezolvarea unei probleme folosind căutarea pe orizontală):
56
Figura 3.7 Spaţiul necesar pentru căutarea pe verticală
57
figura 3.9. Prin expandarea nodurilor în această ordine optimă, minimizăm timpul necesar
pentru rezolvarea problemei.
Căutarea euristică este o încercare de a căuta într-un arbore într-o ordine care este mult
mai aproape din punct de vedere al optimalităţii decât căutarea pe verticală sau pe orizontală.
Când alegem un nod din lista L la pasul 2 al procedurii de căutare, ne mutăm de la nodul
rădăcină spre nodul ţintă prin selectarea întotdeauna a nodului care este cel mai apropiat de
nodul ţintă. În unele domenii este posibil să estimăm distanţa până la nodul ţintă şi să folosim
această informaţie pentru a direcţiona căutarea. Totuşi, este imposibil să executăm căutarea în
arbore într-o ordine optimă ca cea din figura 3.9, adesea putem doar să aproximăm această
ordine.
{i}
{ n1, n2, n3 }
{n2, n3, n4, n11, n12, n13, n14 }
{ n2, n3, n4, n11, n12, n13, n14, n21, n22, n23, n24 }
Ordinea completă pentru căutarea din figura 3.10 este arătată în figura 3.11.
58
Deoarece numărul total de noduri pe nivelul k este bk şi trebuie să memorăm toate
aceste noduri înainte ca primul nod de pe nivelul k +1 să fie examinat, căutarea pe orizontală
sau în lăţime are nevoie la nivelul d de bd-1 spaţiu disponibil pentru a explora un arbore de
căutare ca acela din figura 3.10. De notat că, dacă arborele este examinat în continuare la
nivelul d, atunci va fi necesar mult mai mult spaţiu pentru fiecare generare a succesorilor lui
b. Chiar înainte ca nodul ţintă să fie găsit, L va conţine nodul ţintă şi câteva părţi de la nivelul
d+1din arbore.
i
d=0
n1 n2 n3 n4 d=1
Ce volum de timp este necesar pentru căutarea pe orizontală sau în lăţime? Vom
echivala cantitatea de timp consumată de algoritm cu numărul de noduri examinate de el;
reamintim că un nod este considerat verificat dacă el este un nod ţintă chiar înainte ca nodul
să fie expandat pentru generarea succesorilor şi nu este considerat verificat când nodul însuşi
este adăugat la lista L.
1
2 3 4 5
6 7 8 9 10 11 12 13 14 15 16 17 8 19 20 21
Cum trebuie să atingem ţinta la nivelul d, nodurile interne (care nu sunt marginale)
care pot fi examinate sunt toate nodurile de pe nivelul 0,1,2,3,...,d-1. Numărul unor astfel de
noduri este dat de relaţia:
bd 1
1 b b2 bd 1
(3.1)
b 1
Ce ştim despre nodurile marginale? Nu se poate spune exact câte noduri marginale vor
fi examinate, deoarece nu ştim în care margine este localizat nodul ţintă. Cel mai bun caz ar fi
să putem examina numai un nod marginal (ţinta); cel mai rău caz ar fi dacă ar trebui să
examinăm toate bd noduri. Numărul mediu de noduri examinate la margini este atunci
59
1 bd
(3.2)
2
şi numărul total de noduri examinate este suma dintre (3.1) şi (3.2):
bd 1 bd 1 2b d 2 b d 1 b b d 1
+ = =
b 1 2 2(b 1)
bd 1 bd b 3
(3.3)
2(b 1)
Pentru o adâncime mai mare, (3.3) se reduce la aproximativ bd/2, care este
aproximativ acelaşi cu cantitatea de timp consumată la margini, ceea ce era de aşteptat
deoarece în aceste cazuri, mai mult timp va fi consumat cu căutarea la nivelul cel mai de jos al
arborelui. O versiune grafică a acestei argumentări apare în figura 3.12.
spaţiul =bd-1
întreg de la
nivelul
d-1
marginea
stângă =b d/2
3* 2d 1
2
Acest rezultat se poate deduce şi direct. Dimensiunea arborelui intern este
1 2 2d 1
2d
şi numărul de noduri marginale care trebuie examinate este aproximativ 2 d/2. Suma acestor
două valori este (3/2)*2d.
3.2.4. Analiza metodei de căutare pe verticală sau în adâncime
Dacă L este gândit ca o coadă în căutarea pe orizontală sau în lăţime, în căutarea pe
verticală sau în adâncime L este o stivă. Câteva din primele sale valori pe care le căutăm cu
această metodă în arborele din figura 3.10 sunt:
60
{i}
{ n1, n2, n3, n4}
{ n11, n12, n13, n14, n2, n3, n4}
{ n12, n13, n14, n2, n3, n4 }
2 7 12 17
3 4 5 6 8 9 10 11 13 14 15 16 18 19 20 21
d (b 1) 1
61
bd 1 1
1 b b2 bd
b 1
Dacă facem media celor două expresii, putem concluziona că numărul de noduri examinate
este în medie:
bd 1
1 b * d d b 1 bd 1
b*d b d 2
= (3.4)
2(b 1) 2(b 1)
Ca şi în cazul căutării pe orizontală sau în lăţime vom examina situaţia într-un mod
mai restrictiv când d este mare şi b=2 . Pentru d mare relaţia 3.4 este:
bd
2
astfel încât lucrul la marginile arborelui continuă să domine calculele (vezi figura 3.15).
= bd/2
Jumătate
din spaţiul
total
Să notăm că, atâta timp cât termenul bd-1/2 apare în căutarea pe orizontală sau în lăţime
rezultatul (3.3) este înlocuit cu (3.4); o estimare mai exactă pentru timpul necesar căutării pe
orizontală sau în lăţime este:
bd 1
1
2 b
Observăm de aici că, căutarea pe orizontală sau în lăţime comportă un calcul mai mare
decât căutarea pe verticală sau în adâncime cu un factor de
1 b 1
1 (*)
b b
Valorile tipice pentru această expresie apar în figura 3.16.
62
b Raportul (*)
2 1.5
3 1.3
5 1.2
10 1.1
25 1.04
100 1.01
2d 1
2d 2 d 2 2d 1
d
2d
2 2
La căutarea pe orizontală sau în lăţime am obţinut acest rezultat direct. Spaţiul total de
căutare este 2d+1 şi căutarea pe verticală sau în adâncime, în medie, va examina aproape
jumătate din acesta - cu alte cuvinte 2d noduri. Comparând cele două abordări vedem că
căutarea pe verticală sau în adâncime este de câteva ori mai eficientă ca timp şi mult mai
eficientă ca spaţiu decât căutarea pe orizontală sau în lăţime.
Se pune întrebarea dacă există vreo cale de a alege cea mai bună din cele două
abordări, folosind un algoritm care să aibă spaţiul cerut de căutarea pe verticală sau în
adâncime şi proprietăţile de performanţă ale căutării pe orizontală sau în lăţime? Răspunsul
este da; abordarea care face această alegere este cunoscută ca “adâncimea iterativă” şi a fost
investigată mai întâi de Rich Korf.
Există două căi separate de a înţelege adâncimea iterativă. Poate cea mai simplă (deşi
aceasta nu explică numele) este faptul că adâncimea iterativă este asemănătoare cu căutarea
pe orizontală sau în lăţime, cu excepţia că în loc de a stoca toate nodurile la nivelele
intermediare, le regenerăm când este timpul să le expandăm.
De ce este aceasta o abordare viabilă? Dacă cantitatea de timp consumată pentru
regenerarea nodurilor interne ar micşora timpul consumat cu căutarea răspunsului, dar nu
acesta este cazul de aici, cea mai mare parte a efortului de calcul este consumată cu examinrea
nodurilor din margine.
Cealaltă cale de a înţelege adâncimea iterativă este următoarea. În cazurile în care
căutarea pe verticală sau în adâncime nu dă rezultate satisfăcătoare, adâncimea nodului ţintă
este mai mică decât adâncimea întregului arbore deoarece prima ţintă găsită este la o
adâncime mai mare decât cea mai puţin adâncă soluţie a problemei, sau pentru că adâncimea
arborilor este infinită, şi aşa mai departe. Ceea ce face adâncimea iterativă este faptul că are
loc o căutare în arbore pe o cale care garantează că adâncimea ţintei si adâncimea arborelui se
potrivesc.
Ideea este de a căuta în arbore, iniţial cu o adâncime artificială redusă la 1, astfel ca
nici un nod cu adâncime sub nivelul 1 nu este examinat. Dacă această abordare reuşeşte cu
găsirea soluţiei la adâncimea 1, metoda întoarce soluţia. Dacă nu, se caută în arbore cu o
adâncime care este redusă la 2. Fiecare din aceste căutări iterative procedează în modalitatea
de căutare pe verticală sau în adâncime.
63
Procedura 3.3.1.
Căutarea în adâncime iterativă.
Dacă cea mai puţin adânca soluţie este la adâncimea g, căutarea pe verticală sau în
adâncime la acest nivel va reuşi; rezultă din cele discutate până aici că, metoda căutării în
adâncime iterativă va da întotdeauna “soluţia cea mai puţin adâncă” la problema în discuţie.
Deoarece fiecare din căutările individuale este realizată în maniera căutării pe verticală sau în
adâncime, cantitatea de memorie cerută de metodă este aceiaşi cu cea a căutării pe verticală
sau în adâncime.
Cum putem să aflăm numărul de noduri examinate? În general numărul de noduri
examinate în iteraţia finală (care a reuşit) este dat de relaţia 3.4. În iteraţiile anterioare,
căutările nereuşite la adâncimile 1, 2,.., d-1 au examinat întregul arbore la aceste adâncimi;
dimensiunea arborelui la adâncimea j este dată de
bi 1 1
1 b ... b j
b 1
j d 1
bj 1 1 1 d 1 d 1
1 bd 1
b bj 1 b d
j 0 b 1 b 1 0 0 b 1 b 1
bd 1
b d b d
2
b 1
bd 2
bd 1
b2 d b2 4 b d 5 b 3 d 2
2
(3.5)
2 b 1
Pentru valori mari ale lui d, această relaţie este dominată de:
b 1 bd 1
2
2 b 1
Deoarece timpul necesar pentru căutarea pe verticală sau în adâncime este dominat de:
64
bd 1
2 b 1
raportul dintre timpul necesar adâncimii iterative şi cel necesar căutării pe verticală sau în
adâncime este dat de:
b 1
(3.6)
b 1
Valorile tipice obţinute din această expresie sunt arătate în figura 3.17. Aşa cum putem
vedea din tabel, costul repetării lucrului la adâncimi mici nu este mare. Deoarece adâncimea
iterativă evită problemele întâlnite în căutarea pe verticală sau în adâncime, ea este o metodă
care este preferabilă în multe probleme de căutare.
Ca de obicei, examinăm cazul b=2 în detaliu. În cazul căutării pe verticală sau în
adâncime, avem nevoie să examinăm jumătate din întreg arborele; deoarece arborele are
dimensiunea 2d+1, căutarea pe verticală sau în adâncime necesită examinarea a 2d noduri. În
adâncimea iterativă, căutările eşuate iau timpul:
1 2 ... 2 d 2d 1
deoarece acestea sunt dimensiunile subarborilor examinaţi. Deoarece acest timp este de două
ori mai mare decât timpul necesar pentru o căutare reuşită la adâncimea d, factorul general în
cazul b=2 este 3, în concordanţă cu relaţia 3.6 şi figura 3.17.
b raport
2 3
3 2
5 1.5
10 1.2
25 1.08
100 1.02
65
orice algoritm de căutare oarbă necesită spaţiul O(d) dacă se aşteaptă ca el să întoarcă o cale
către răspuns sau nu.
3.2.6. Lăţimea iterativă.
Deşi adâncimea iterativă este optimală, în sensul că funcţia O(bd) în general este cea
mai bună care se poate obţine, există o altă tehnică de căutare oarbă care adesea îmbunătăţeşte
acest rezultat în practică - nu prin reducerea complexităţii problemei, ci prin abordarea
problemei într-un mod corespunzător, şi anume prin aceea că, este examinată doar o mică
porţiune din ramuri dacă există mai multe noduri ţinta. Această tehnică este cunoscută ca fiind
“lăţimea iterativă “.
Aşa cum am observat, este important, acolo unde este posibil, să se recunoască
alegerile greşite înainte de a face căutarea, astfel încât să nu fie nevoie să se extindă arborele
de căutare dincolo de acest nivel înainte de găsirea nodului ţintă. Dar cum să se sezizeze
aceasta dacă algoritmul de căutare este orb? Răspunsul constă în aceea că, în majoritatea
problemelor practice, nodurile ţintă nu sunt dispuse aleator fiind posibil de a se face erori
fatale la începutul căutarii.
Aşa cum adâncimea iterativă impune limite de adâncime artificiale şi creşte gradual
acele limite până este găsită o soluţie, tot aşa lăţimea iterativă impune limite de lăţime
artificiale, crescându-le până se găseşte o soluţie.
Procedura 3.4.1. Lăţimea iterativă.
1. Setează c=2; acesta este lăţimea curentă redusă.
2. Setează L ca fiind lista de noduri iniţiale din problemă .
3. Fie n primul nod din L. Dacă L este vidă, incrementează c şi reia pasul 2.
4. Dacă n este nodul ţintă, atunci STOP şi întoarce nodul n şi calea de la nodul iniţial
la n.
5. Altfel şterge n din L. Adaugă în faţa listei L primul c din fii lui n, etichetând pe
fiecare cu calea sa de la nodul iniţial. Reia pasul 3.
Căutam iniţial arborele cu o lăţime redusă cu 2, cu 3 şi aşa mai departe. O lăţime
redusă cu c înseamnă că maximum c fii ai fiecărui nod dat pot fi examinaţi înainte ca nodul să
fie abandonat ca fiind un eşec. În figura 3.18 este prezentat un arbore cu un factor de
ramificare 4 dar cu o lăţime redusă la 3.
Nodul ordonat dat de lăţimea iterativă din exemplul anterior este arătat în figura 3.19.
66
1, 18, 21
3 4 12 26 6 7 16 31 18 19 20 36 38 39 40 41
10 11 25 14 15 30 33 34 35
23 24 28 29
care este aproximativ bd+1/d pentru un b mare (un factor de b/d mai slab decât la căutarea pe
verticală sau în adâncime) şi este aproximativ b d pentru un d mare.
Lăţimea iterativă poate duce la mari reduceri a volumului de timp necesar rezolvării
problemelor de căutare dacă există noduri ţintă multiple şi dacă este posibil să se facă erori
fatale la începutul căutării. La adâncimi mari este posibil ca metoda să găsească o soluţie mai
uşor decât căutarea pe verticală sau în adâncime, ori de câte ori numărul de noduri ţintă este
mai mare de 3.
În multe situaţii căutarea poate fi făcută mai eficient utilizând informaţiile pentru
reprezentarea problemei. De exemplu, în problema labirintului, dacă se cunoaşte poziţia
obiectivului relativ la punctul de plecare, se va selecta calea ce încarcă cel mai puţin posibil
costul. La problema careului cu opt numere, o informaţie a apropierii de obiectiv este dată de
poziţia punctelor faţă de starea obiectiv. Înformaţia rezultată din predicţia costului faţă de
obiectiv, chiar dacă nu este suficient de precisă, poate fi utilizată.Buclele moarte pot
determina creşterea timpului (şi implicit a costului) de atingere a obiectivului. Astfel de
cunoştinţe sunt de natură euristică, întrucât nu garantează corectitudinea complectă. Căutarea
bazată pe cunoştinţele euristice se numeşte şi căutare euristică.
Se cunosc mai multe tehnici de căutare euristică, tehnici ce vor fi expuse în
continuare.
Ideea de bază a căutării în cazul unei strategii irevocabile este cea prin care, pornind
de la starea iniţială, să se minimizeze distanţa ce separă starea curentă obţinută de starea
obiectiv a problemei. Metodele matematice cunoscute în teoria sistemelor găsesc un bun teren
de aplicabilitate în această situaţie. O metodă des utilizată este metoda gradientului (metoda
hill-climbing) ce se utilizează în procesele de căutare multidimensională a extremelor
funcţiilor de mai multe variabile sau a soluţiilor sistemelor de ecuaţii neliniare. O serie de
probleme duc la complexitate în procesul generării stărilor ce se reflectă în caracterul
67
neterminal al stărilor obţinute. Aceasta nu permite testarea concordanţei cu obiectivul pentru
toate stările posibil de obţinut dintr-un nod dat. Generarea spaţiului stărilor se face după
strategii ce urmăresc două criterii de optimalitate:
optimalitate locală – având ca obiectiv găsirea numărului minim de paşi ce duce la
o stare terminală, fără epuizarea tuturor combinaţiilor posibile. Starea precedentă este marcată
pentru a se aigura revenirea ulterioară în caz de eşec şi reluarea procesului prin generarea unui
nou element terminal;
optimalitate globală – se referă la obţinerea soluţiei problemei cu un număr
minim de reveniri.
Strategiile de control irevocabile se bazează pe cunoaşterea locală, determină
operatorul aplicat de la un pas la altul, noua stare reprezintă un context necunoscut, context
folosit pentru determinarea unui alt operator până se atinge obiectivul. Se poate spune că
secvenţa de operatori defineşte o cunoaştere globală despre soluţia problemei ce se determină
ca urmare a aplicării operatorilor prin strategia de control.
Ideea de bază a acestei metode se bazează pe faptul că disecţia celei mai mari creşteri
a funcţiei f(x1, x2, … xn) este dată de gadientul funcţiei:
f f f
grad f ( x1 , x 2 ,..., x n ) , , ... ,
x1 x2 xn
Aplicarea metodei este dificilă dacă numărul variabilelor este mare, numărul
funcţiilor de cost este mare, funcţia are mai multe valori extreme.
La căutarea într-un graf, strategia traversării pentru atingerea obiectivului prin
alegerea acelor noduri care sunt predictate a fi apropiate de obiectiv este numită metoda de
gradient. Specific pentru alegerea următorului nod după n, se calculează h(nI) pentru toate
nodurile fiu (n1, n2, … nm) ale lui n şi stabileşte ca următor nod acel nod pentru care h(nI)
este mai mic. Funcţia h(n) este o măsură a apropierii de obiectiv. Algoritmul de căutare este:
n = nodul de start;
while (1)
{
if (obiectiv (n) ) exit (succes);
expandează n, calculează h(ni) pentru toate nodurile fiu ni şi face nodul fiu
nod următor (next-n) acel nod care are valoarea minimei;
if ( h(n) h(next-n) ) exit (fail);
n = next-n;
}
Se poate imagina obiectivul ca vârful unui munte şi h(n) ca diferenţa de înălţime între
nodul n şi vârf. Metoda urmăreşte apropierea de obiectiv prin gradient maxim. Dacă există
numai un vârf, metoda permite atingerea obiectivului, însă pot exista vârfuri locale ce sunt
atinse, ce nu permit apoi apropierea de maximul global.
Un exemplu de problemă la care metoda este aplicabilă, este cea a traversării
labirintului. În figura a obiectivul se atinge, iar pentru cel din figura b se obţine eşec.
68
În ambele cazuri, costul de la poziţia caracteristică nodului n la obiectiv, este calculat cu
formula:
h(n) = coordonata x a obiectivului – coordonata x a nodului n coordonata y a
obiectivului – coordonata y a nodului n
În cazul a, obiectivul poate fi atins prin secvenţa de noduri S A B E G, care
este un drum optim ce restrânge aria de căutare. În cazul b, se ajunge la eşec după parcurgerea
secvenţei S A C B, în care B reprezintă un vârf, dar care nu este un obiectiv. Pentru a
ajunge la obiectiv, ar trebui atins punctul E ce determină o depărtare de obiectiv.
În metoda gradientului maxim, dacă sunt şi alte extreme locale (valori minime ale lui
h(n) ) decât obiectivul, nu se poate garanta continuarea algoritmului pentru atingerea acestuia.
Tehnica cunoscută sub numele de metoda celei mai bune prime căutări, se bazează pe luarea
deciziei după examinarea spaţiului stărilor. Toate nodurile ce au fost examinate prin această
tehnică până la momentul curent sunt stocate, urmând ca nodul cel mai apropiat de obiectiv să
fie expandat. Până aici metoda este similară cu cea bazată pe gradient, însă atunci când h(n)
devine constant sau acţiunile permise în starea curentă produc depărtarea de obiectiv, un alt
nod din listă va fi expandat. Algoritmul pentru căutarea în grafuri după această metodă este
următorul:
pune nodul de start S în open_ list;
while (1)
{
if (open-list = lista_vidă) exit (fail);
n = prim-nod (open_list);
if (obiectiv (n) ) exit (succes);
remove (n, open_list);
add (n, closed_list);
expandează n şi generează toate nodurile fiu.
Pune în open_list numai acele noduri ce nu sunt conţinute
în open_list sau closed_list de până atunci.
Pentru fiecare nod sunt asociaţi pointeri la nodul n.
Lista nodurilor este ordonată crescător;
}
69
Aplicarea procedurii de mai sus pentru labirintul din a) obţine aceiaşi secvenţă de
noduri ca prin aplicarea metodei de gradient.
Pentru labirintul din b) se obţine succcesiunea
(S(6)) (A(4)) (B(2)C(3)) (C(3)E(3)) (E(3)D(4)) (H(2)D(4))
(G(0)D(4)F(4))
Pentru utilizarea metodei cele mai bune prime căutări este necesar să se cunoască
costul atingerii obiectivului, adică o serie de cunoştinţe despre problemă.
70
Dacă se consideră h(n)=0 algoritmul are aceeaşi comportare cu algoritmul de căutare
optimă. Dacă graful este finit , se poate arăta prin aceiaşi metodă bazată pe teorema 1 că
drumul optim este găsit atunci când un nod de start şi un nod obiectiv există. Totuşi, nu se
poate garanta că algoritmul va obţine soluţia optimă. În exemplul de graf care urmează sunt
ilustrate în parantezele asociate nodurilor, valorile funcţiei h(n) pentru nodul n.
Mai întâi se expandează nodul S pentru a obţine nodurile sale fiu A şi B. Se calculează
funcţiile respective de evaluare f’(A)=2+3 şi f’(B)=3+4, open_list este (A,B). Când se citeşte
A din open_list şi este expandat se va obţine nodul C. f’(C)’=6+0 aşa că open_list devine
(C,B). Când este preluat C căutarea se termină. Soluţia este drumul S A C. Cu toate
acestea calea nu este cea de cost minim. Raţiunea pentru care drumul de cost minim S B C
nu este găsit este dată de faptul că f(B) devine mai mare decât f’(B). Se poate dovedi că, dacă
h’(n) excede h(n), algoritmul va găsi soluţia optimă. Dacă costul inferenţiat este marginea
inferioară a costului real (h’(n)<=h(n)) algoritmul A se transformă în algoritmul A* .
3.3.4. Algoritmul A*
Să examinăm acum unul dintre cei mai importanţi algoritmi utilizaţi în căutare, şi
anume algoritmul A*.
Să considerăm mai înâi un exemplu simplu în care se găseşte o soluţie suboptimală
care este arătată în figura 3.20. Numărul care urmează numărului de nod în figură este
valoarea euristică asociată acestuia, deci eticheta 3 asignată rădăcinii nodului înseamnă că
acest nod va fi la trei paşi depărtare până la ţintă.
Metodologia devine greşită pentru nodurile de adâncime 1; nodul din stânga este
marcat cu 2 chiar dacă până la ţintă mai sunt 5 paşi, iar cel din dreapta este marcat cu 4, chiar
dacă ţinta poate fi atinsă doar din 2 paşi.
Numerele dintre paranteze din figură arată ordinea în care nodurile sunt expandate.
Rădăcina este expandată prima, după care îl vom expanda pe fiul său din partea stângă,
deoarece se crede că acest fiu este cel mai apropiat de ţintă decât cel din partea dreaptă.
Deoarece fiecare nod din subsecvenţa din partea stângă a arborelui se aşteaptă să fie mai
aproape de ţintă decât nodul din partea dreaptă de adâncime 1, partea stângă a arborelui este
explorată în întregime şi ţinta este găsită la adâncimea 6 în locul ţintei de adâncime 3.
Nu vom fi surprinşi că cea mai bună primă căutare eşuează în găsirea celei mai bune
soluţii în cazuri ca acesta. După acestă remarcă, ideea în cazul celei mai bune prime căutări
este de a găsi unele soluţii cât mai curând posibil prin găsirea oricărui nod care este la distanţa
0 de nodul ţintei; nici o încercare nu este făcută pentru a descoperi ţinta care se află la o
adâncime minimă în arborele căutării. Dacă vrem să facem acest lucru va trebui să modificăm
algoritmul căutării pentru a reflecta interesul de a găsi ţinta cât mai aproape de suprafaţă (la
adâncime minimă). Ordinea în care vom dezvolta nodurile trebuie să ţină cont de faptul că
vrem să dezvoltăm nodurile aflate la o adâncime cât mai mică în detrimentul celor aflate la
adâncime mai mare.
71
3(1)
(2) 2 4
(3) 1 1
(4) 1
(5) 1
(6) 1
(7)
Mai precis, deoarece scopul celei mai bune prime căutări este de a găsi o ţintă cât mai
curând posibil, va conduce la dezvoltarea nodului cât mai apropiat de nodul ţintei. Deoarece
scopul modificat este de a găsi ţinta cea mai puţin adâncă cât mai curând posibil, va trebui să
expandăm nodul care pare cel mai apropiat de ţinta specificată. În loc de ordonarea nodurilor
în termenii distanţei până la ţintă, le vom ordona ţinând seama de calitatea ca ţinta să fie cea
mai apropiată de aceste noduri (aceasta este distanţa aşteptată).
Deci să presupunem că avem un nod n la adâncimea d în arborele căutării şi vom
presupune că distanţa de la cea mai apropiată ţintă la acest nod este h ' (n) (vom porni de la
ideea că h ' este pozitiv, deci că h' (n) 0 pentru toate nodurile n). Această ţintă este de aceea
apreciată că va fi la adâncimea d h ' (n) în spaţiul căutării; rezultă că în loc să alegem pentru
expandare nodul cu cel mai mic h' (n) ca în cea mai bună primă căutare (deoarece h ' (n) este
distanţa aşteptată până la ţintă), vom alege pentru expandare nodul cu cel mai mic d + h’(n).
Adâncimea nodului este considerată de asemenea o funcţie de nod, notată de obicei cu g (n)
şi se apreciază ca fiind „costul” atingerii nodului n de la nodul rădăcină. Deoarece intenţia
este de a găsi o ţintă cu un cost minimal, vom expanda nodurile în ordinea crescătoare a
valorilor date de relaţia (4.1):
f ( n) g ( n) h ' ( n) (4.1)
72
nodului (0 pentru rădăcină, 1 pentru fii etc.) şi distanţa aşteptată până la ţintă. Vom alege apoi
pentru expandare nodul pentru care această sumă este cea mai mică.
0 3(1)
(5) 4+1
5+1
ţinta
Ca şi mai înainte, valoarea optimistă asignată nodului din partea stânga de adâncime 1
ne convinge să expandăm această cale înaintea altora, deoarece ne aşteptăm să găsim nodul
ţintă la adîncimea 3 dedesubtul acestui nod şi aşteptăm nodul ţintă dedesubtul altui fiu care va
fi la adâncimea 5. Oricum, când chiar am ajuns la adâncimea 5 pe calea din partea stângă a
arborelui şi nu s-a atins ţinta, va trebui să credem că o altă cale este mai bună şi să o
examinăm în schimb. Cel mai bun dintre cele două noduri ţintă este găsit acum primul. Sunt
două lucruri de reţinut aici. Primul este acela că nu există nici o diferenţă reală între
etichetarea nodurilor (5) şi (6) în figura 3.21.; amândouă sunt aşteptate să conducă spre ţinte
la adâncimea 5. Am ales să expandăm primul pe (5) deoarece a fost gândit să fie aproape de
nodul ţintă dar algoritmul A* însuşi nu ne cere să facem această alegere.
Un lucru mai important de reţinut este acela că nu este garantat faptul că A* găseşte
cea mai bună soluţie pentru orice problemă particulară de căutare. În figura 3.21., de exemplu,
73
dacă nodul etichetat cu (5) (ceea ce înseamnă că, va fi expandat al cincilea) era nodul ţintă, el
va fi găsit înainte de nodul ţintă optimal pe calea din partea dreaptă.
3.3.4.1. Admisibilitatea
Motivul pentru care evităm expandarea căii din partea dreapta din exemplul din figura
3.21. este că avem o etichetare pesimistă a nodului din partea dreapta de adâncime 1 cu
valoarea 4, aceasta indicându-ne că nu ne putem aştepta să găsim ţinta la orice adâncime mai
mică decât 5 de-a lungul acestei căi. Ca atare, suntem conduşi să examinăm nodurile de
adâncime 4 de-a lungul căii din stânga înainte de a căuta ţinta de adâncime 3 din partea
dreaptă a arborelui. Dacă funcţia care estimează distanţa până la ţintă a fost aleasă ca fiind
optimistă, acest lucru nu se va întâmpla.
Pentru a formaliza aceasta, presupunem că notăm cu h(n) (fără apostrof) actuala
distanţă de la nodul n până la nodul ţintă. Acum funcţia euristică estimată h ' va fi optimistă
doar în cazul când avem întotdeauna h ' h şi în acest caz avem.
Teorema 3.3.1. Dacă h' (n) h(n) pentru orice nod n, algoritmul A* va găsi
întotdeauna un nod ţintă optimal.
Demonstraţie: Presupunând că s este cel mai adânc nod ţintă şi calea de la nodul
rădăcină la această ţintă este
n0 , n1 ,..., nk
unde nk s . Ceea ce putem face este să arătăm că dacă algoritmul A* expandează o parte
din această cale:
n0 , n1 ,..., ni
atunci el expandează de asemenea următorul nod de-a lungul acestei căi şi anume ni 1 .
Deoarece nodul rădăcină n0 este întotdeauna extins, rezultă prin inducţie că şi nodul s nk
este întotdeauna extins. În acest sens luăm s ' ni 1 ca fiind un nod de-a lungul căii spre s şi
luăm x ca fiind orice nod mai rău decât s în sensul g ( x) g ( s ) . Deoarece există doar un
număr finit de noduri cu f (n) c pentru orice constantă c, ştim că procedura va expanda în
final fie pe s ' sau un astfel de nod x. În plus, deoarece a fost expandată calea de la rădăcină la
s ' , trebuie doar să arătăm că valoarea euristică asignată lui s ' (incluzând costul ajungerii
acolo) este mai mică decât valoarea asignată lui x. Cu alte cuvinte, trebuie să arătăm că:
Dar h' ( s ' ) h( s ' ) pentru că h' este optimistă. De aici rezultă că:
Egalitatea apare deoarece suma costurilor ajungerii la s ' şi apoi de la s ' la nodul ţintă optimal
s este chiar costul ajungerii direct la s. Demonstraţia este completă.
O funcţie euristică optimă h ' este numită admisibilă.
Pentru exemplificare, să ne reîntoarcem la spaţiul de căutare din figura 3.21. după
modificarea valorii euristice atribuite nodului din dreapta de adâncime 1 astfel încât funcţia
euristică să fie admisibilă; rezultatul este arătat în figura 3.22.. Nodul ţintă optimal este găsit
într-adevăr în acest caz.
74
3(1)
(3) 2+ 1 2 1 (5)
3+ 1 3+0 (6)
ţinta
4+1 ţinta?
5+1
ţinta
Există de asemenea şi alte exemple interesante. Funcţia “euristică” h' (n) 0 este clar
una admisibilă şi conduce în mod simplu la extinderea nodurilor în ordinea creşterii lui g (n) .
Pentru că g (n) este adâncimea nodului n, algoritmul A* reproduce căutarea pe orizontală sau
în lăţime în acest caz. Deoarece căutarea pe verticală sau în adâncime eşuează adesea în
găsirea celei mai bune soluţii a problemei, este sigur că nu există o euristică admisibilă care să
imite căutarea pe verticală sau în adâncime pe o cale similară.
Euristica perfectă h ' h este de asemenea întotdeauna admisibilă.
Vom încheia discutând câteva extensii ale algoritmului A*. Prima situaţie pe care o
considerăm este aceea în care ”costul” unui nod nu mai este reprezentat de adâncimea lui în
spaţiul de căutare, ci este evaluat în schimb în alte moduri. Vom continua să presupunem
faptul că costul ajungerii la un nod n este suma costurilor arcelor individuale de-a lungul căii
de la rădăcină la n; nu se mai presupune că lungimea fiecărui arc este o unitate de cost.
Nu este greu să observăm că atâta timp cât vom continua să folosim g (n) pentru
costul atingerii nodului n, folosirea algoritmului A* utilizând funcţiile de evaluare obişnuite
date de relaţia 4.1 continuă să găsească soluţiile cu cel mai mic cost. Dacă vom lua h ' (n) 0
în acest caz, vom obţine procedura de căutare cunoscută sub numele de branch and bound
(ramifică şi mărgineşte).
În continuare presupunem că folosim A* pentru a căuta într-un graf în locul unui
simplu arbore, cum este arătat în figura 3.23.. Presupunând că luăm g (n) ca fiind costul celei
mai ieftine căi găsite către nodul n şi să menţinem o listă doar cu nodurilor deschise,
algoritmul rămâne în principiu neschimbat.
75
Figura 3.23. Algoritmul A* folosit la căutarea în graf
Este important să înţelegem că iteraţiile individuale din acest algoritm sunt făcute
folosind convenţionala căutare pe verticală sau în adâncime şi nu folosind A*; funcţia
“euristică“ este folosită pentru a tăia nodurile şi nu pentru a determina ordinea în care ele vor
fi expandate. Cu toate acestea, dacă iteraţiile originale cer ca expandarea să fie făcută folosind
algoritmul A*, o cantitate exponenţială de memorie va fi necesară!
76
Figura 3.24. I.D.A*
Un exemplu de folosire a procedurii 3.3.3. apare în figura 3.24.. Pentru c=1 vom
examina numai nodul rădăcină; pentru c=2 vom examina două noduri şi aşa mai departe.
Căutările individuale sunt conduse în stilul căutării în adâncime, ceea ce explică de ce nodul
12 este extins înaintea nodului 14 în figură deşi estimările euristice indică că nodul 14 este
probabil mai apropiat de o ţintă superficială.
Procedura 3.3.3 este cunoscută ca adâncime iterativă A*, sau simplu I.D.A*. Nu
este foarte greu să arătăm că foloseşte o cantitate de memorie liniară cu adâncimea nodului
ţintă, adică sunt expandate doar nodurile extinse de A* însuşi şi aceasta continuă să caute
soluţiile optimale când este folosită o euristică admisibilă.
77
Unitatea de învăţare 4
Metode avansate de căutare.
Cuprins:
4.1. Căutarea în grafuri ŞI/SAU ....................................................................... pag. 78
4.1.1. Evaluarea şi expandarea grafurilor candidate ......................................... pag. 78
4.1.2. Căutarea în adîncime în grafuri ŞI/SAU ................................................ pag. 79
4.1.3. Căutarea soluţiei optime în grafuri ŞI/SAU ............................................ pag. 81
4.2. Căutarea în arbori pentru jocuri ................................................................. pag. 85
4.2.1. Arbori de joc ........................................................................................... pag. 85
4.2.2. Metoda MINIMAX ................................................................................. pag. 86
4.2.3. Metoda alfa-beta ..................................................................................... pag. 86
4.2.4. Utilizarea metodelor minimax şi alfa-beta în grafuri ŞI/SAU ................ pag. 88
4.3. Execiţii ........................................................................................................ pag.91
Când se caută într-un graf este suficient să se găsească un singur drum, aşa că dacă se
cunosc pointerii de la nodurile părinte către toţi fii săi în drumul parcurs, şi căutarea este
completă, înseamnă că s-a găsit o cale ce constituie o soluţie. Totuşi un graf rezolvent al
grafului ŞI/SAU este la rândul său un graf. Procesul găsirii soluţiei prin căutare corespunde
dezvoltării progresive a soluţiei. Numai unele din grafurile rezolvente posibile sînt găsite în
timpul căutării. Acestea sînt numite grafuri candidate. S-a preferat această denumire în loc de
grafuri rezolvente parţiale întrucât nu se cunoaşte încă dacă acestea sînt parte a soluţiei. Uzual
aceste grafuri sînt găsite în timpul căutării şi structurile lor trebuiesc reprezentate.
Un graf ŞI/SAU poate fi cercetat prin evaluări şi expandări repetate după cum
urmează:
1. Determină dacă nodurile grafurilor candidate sînt solvabile, insolvabile sau
nedecizabile, precum şi costul acestora dacă este cazul.
2. Expandează grafurile candidate.
În primul pas se examinează toate punctele finale (nodurile frunză) ale grafului
candidat. Dacă acestea sînt, noduri terminale ele corespund unei probleme rezolvate şi ca
urmare vor fi marcate în acest sens. Dacă punctele terminale ale grafului candidat sînt puncte
finale ale problemei iniţiale, dar nu noduri terminale, problemele corespunzătoare acestor
noduri sînt insolvabile şi se vor marca printr-un marker UNSOLVED. Dacă nodurile fiu ale
unui nod, altele decât nodurile terminale ale grafului candidat sînt noduri ŞI, şi dacă toţi fii
sînt SOLVED, atunci nodul va fi marcat SOLVED. Dacă cel puţin un fiu este UNSOLVED
atunci nodul părinte va fi marcat UNSOLVED. În cazul în care nodurile fiu, altele decât
punctele terminale sînt noduri SAU şi cel puţin unul a fost marcat SOLVED atunci nodul
părinte va purta aceeaşi marcă.
Când nodul S al unui graf candidat devine SOLVED, graful este o soluţie a problemei.
Dacă este necesar calculul costului, se calculează costul tuturor nodurilor utilizînd costul
punctelor finale ale grafurilor candidate. Costul nodului părinte al unui nod ŞI se calculează
ca suma tuturor nodurilor sale fiu, pe când cel al unui nod fiu SAU ca maximul costurilor
fiilor. Costul nodului de start este costul nodului grafului candidat. În pasul 2 se găsesc
nodurile fiu prin expandarea nodurilor ce sînt puncte terminale ale grafului candidat p şi nu au
fost marcate în nici un fel. Dacă nodurile fiu ale nodului expandat n sînt noduri ŞI un nongraf
78
candidat este generat prin adăugarea tuturor nodurilor fiu la nodul p. Dacă nodurile fiu ale
nodului n sînt noduri SAU adăugarea câte unuia din acestea la p va determina generarea mai
multor grafuri câte noduri fiu are. În acest mod un număr mare de grafuri candidate vor fi
generate prin procesul de căutare.
79
1. 2.
3.
4. 5.
6.
În această procedură grafurile candidate expandate sînt ţinute în open_list, însă nu este
esenţial a face acest lucru în cazul căutării în adâncime. Se poate utiliza un sistem în care
această listă conţine numai un graf parţial SOLVED, pentru formarea soluţiei trebuie
80
combinat corespunzător cu alte grafuri. Pentru realizarea acestui lucru este necesară
construirea unei funcţii care atunci când nodurile sînt expandate toate nodurile fiu ale sale au
fost generate o singură dată. Un singur nod fiu determină un graf parţial la un moment dat de
timp. Pentru formalizare se defineşte funcţia next_fiu. Se presupune că nodul n are nodurile
fiu n1, n2, … , nm şi nodul fiu ni a fost deja generat. Dacă nici un nod fiu nu a fost deja generat
i=0. Aplicarea funcţiei next_fiu(n) la nodul n determină următorul rezultat:
next_fiu(n)= ni-1 0 i m
null i=m
Vom trata în continuare găsirea soluţiei optime în graf, soluţie având cost minim când
costul arcelor către nodurile SAU este definit. Se presupune că pentru fiecare nod al grafului
costul estimat al soluţiei este dat. Aceasta corespunde la h’ în căutarea pentru grafuri
obişnuite. Se va nota costul estimat pentru nodul n în h’(n). Dacă funcţia euristică h’(n) nu
este dată, cazul este similar cu h’(n)=0 şi algoritmul este identic cu cel de căutare în adâncime
pentru grafuri ŞI/SAU.
81
La algoritmul de căutare în adâncime descris anterior diferite grafuri candidate au fost
generate. Valoarea inferenţială f’(p) a costului unui graf candidat p este obţinută prin
evaluarea lui p utilizând valoarea inferenţială a costului punctelor finale. În figura c se arată o
parte a unui graf ŞI/SAU. Un graf candidat p este punctat prin linii punctate. Costul nodurilor
ŞI se calculează utilizând suma costurilor fiilor săi, iar pentru nodurile SAU s-a luat valoarea
1.
(3) (2)
Figura (c) (între paranteze s-a prezentat h’ şi fără paranteze costurile evaluate).
Dacă valorile estimate ale costurilor nodurilor A şi S sunt calculate utilizând valorile
inferenţiale, h’(C)=3 şi h’(D)=2 ale punctelor finale C şi D din (p), se obţine
f’(A)=h’(C)+h’(D),
iar pentru S,
f’(S)=f’(A)+1.
Ca urmare f’(p)=6.
82
Pune în open_list graful candidat (p) format numai din nodul de start S,
f’(p)=h’(S);
while true
{
if (open_list=vidă) exit(fail);
p=prim_graf (open_list); /* aduce primul graf din listă */
if (solved(p)) exit(succes); /* dacă (p) este un graf rezolvent
căutarea se */
/*termină şi (p) este soluţia */
remove (p, open_list);
expandează (p), evaluează toate grafurile candidate (pi) nou
generate şi găseşte f’(pi). Dacă (pi) este UNSOLVED pune-l
în open_list;
}
Pentru a ilustra modul în care algoritmul avansează se consideră exemplul din figura
(d), iar în figura (e) se prezintă conţinutul în open_list prin utilizarea algoritmului de căutare
optimală. În figuri s-au trecut între paranteze costurile estimate, costurile fără paranteze sunt
calculate utilizând costuri estimate. Fiecare candidat este denumit (prin marcarea cu Pi),
pentru a nu desena de mai multe ori acelaşi graf.
(4)
(3) (3)
(3) (2)
(1)
(2)
(1) (1)
t1 (0) t2 (0)
83
În figura (e) sunt arătaţi numai primele şase cicluri. După ultimul ciclu ilustrat, H şi I
sunt expandate şi nodurile terminale (t1) şi (t2) sunt adăugate obţinând graful (p10). Costul
pentru (p10) este f(p10)=5. Dacă nodurile fiu ale unui nod (n) asociat unui graf candidat (p)
sunt noduri ŞI, ele sunt generate la acelaşi moment, cu toate că sunt evaluate la paşi diferiţi.
Ca şi în cazul utilizării algoritmului A în grafuri obişnuite, acest algoritm nu garantează
găsirea soluţiei optime.
1. (4 )
P1:
2. (4 ) (4 )
(3 ) 3
P2: P3:
3. 6
(3 ) (2 )
P3 P4:
4. 4
(2) (1)
P5: P4
5. 4 5
3 4
2 (1 ) 3 (1 )
(1 ) (2 )
P6: P7: P4
6. 5
(1 )
(1 )
P8: P7 P4
Figura (e) Soluţia căutării optimale pentru graful din figura (d) .
84
Totuşi se poate demonstra că soluţia optimă este găsită dacă h’<h pentru toate
nodurile. Dacă în calcularea costurilor inferenţiale ale grafurilor candidate se setează costul
tuturor arcelor egal cu (0), aceasta corespunde încercării de minimizare a viitoarelor costuri de
căutare.
4.2. Căutarea în arbori pentru jocuri
A B
C D ES F
5 2 1 6
Se presupune că obiectivul jucătorului care mută primul (numit MAX) este să obţină
maxima evaluată, iar obiectivul jucătorului care mută al doilea (numit MIN) este de a obţine
cea mai mică valoare evaluată. De asemenea, ambii jucători aleg cea mai bună mutare. În
figura (f) este prezentat un arbore simplu asociat, în care nodurile corespunzând lui MAX sunt
pătrate, iar cele corespunzând lui MIN sunt cercuri. Valorile evaluate sunt date la punctele
finale.
În mod normal arborele are o adâncime mare şi din fiecare nod pleacă mai multe arce.
Chiar pentru jocuri de complexitate medie este practic imposibila generarea arborelui
incluzând toate punctele finale. În astfel de cazuri, valorile evaluate sunt găsite prin generarea
unui arbore în adâncime rezonabilă, în care evaluarea punctelor terminale ale arborilor parţiali
se face prin aceleaşi metode.
Valorile evaluate pe această cale sunt numite valori evaluate static. Dacă jocul este
aproape de terminare se poate atinge un punct final, însă de cele mai multe ori cea mai bună
mutare va fi decisă prin utilizarea valorilor evaluate static. Se ia în considerare faptul că
adversarul determină şi el cea mai bună mutare după generarea unui arbore parţial de
adâncime corespunzătoare. Adâncimea arborelui este restricţionată prin memoria şi timpul de
85
calcul necesare. Valorile evaluate static sunt date de cunoaşterea caracteristicilor jocului.
Pentru a juca ŞAH, SHOGI sau GO este necesară atât investigarea metodelor de căutare cât şi
a metodelor de evaluare adecvate. În cele ce urmează vor fi prezentate numai metode de
căutare pentru cazul în care valorile evaluate sunt considerate cunoscute.
Fie arborele de căutare din figura (g) în care nodurile sunt numerotate şi un scor este
dat la fiecare nod terminal. Dacă se găsesc cele mai bune mutări utilizând algoritmul
minimax, iniţial MAX alege nodul (1), MIN alege nodul (3), MAX alege nodul (8) ce are
valoarea evaluată (5).
1 2
3 4 5 6
7 8 9 10 11 12 13 14 15 16 17 18
3 5 4 4 5 7 4 3 2 5 8 6
86
Presupunând că într-o procedură similară cu cea de căutare în adâncime s-a obţinut
valoarea evaluată (5) pentru nodul (3), în continuare se încearcă găsirea valorii nodului (4). Se
cunoaşte în acest moment faptul că valoarea nodului (1) nu poate fi mai mare decât (5).
Motivul rezidă în faptul că dacă valoarea nodului (4) ar fi mai mare decât (5), MIN nu va
alege nodul (4). Cu toate că se cunoaşte că valorile nodurilor (10) şi (11) sunt obţinute,
valoarea nodului (4) este cel puţin (5). Aşa că nu poate fi mai avantajos pentru MIN să aleagă
nodul (4) în detrimentul nodului (3). Se deduce că MIN va alege nodul (3) fără să mai
examineze nodul (12). în acest mod valoarea ce determină costul nodului (1) este (5) şi ca
urmare valoarea nodului S trebuie să fie cel puţin (5). Considerând acum că valoarea evaluată
(4) este obţinută pentru nodul (5), prin examinarea valorilor tuturor nodurilor fiu ale sale, şi
cum selecţia nodului (2) nu va aduce pentru MAX avantaje, nu mai este necesară inspectarea
nodului (6) şi a celor care sunt fiii săi. Metoda de segmentare a numărului de noduri ce sunt
cercetate este numită şi metoda alfa-beta. Pentru căutarea sistematică a arborilor adânci
metoda este simplu de înţeles dacă se formalizează după cum urmează. Se notează marginea
inferioară a fiecărui nod cu alfa, iar marginea superioară cu beta. În starea iniţială pentru
nodul S, alfa şi beta sunt - , respectiv + . Pentru aceasta se va scrie
(S)=( - , + ). Dacă o valoare (x) este mai mică decât alfa sau mai mare decât beta, se
spune că (x) depăşeşte domeniul ( , ). Când valoarea nodului (3) este determinată, (1) = (-
,5). Dacă se cunoaşte că valorile nodurilor fii ale nodului (1) depăşesc gama (- ,5), condiţia
pentru întreruperea căutării este îndeplinită. Când nodul (11) a fost explorat, (4)=(5, ), deci
în afara gamei (- ,5), deci condiţia de întrerupere a căutării este din nou îndeplinită şi nu va fi
necesară căutarea în continuare a fiilor lui (4). În acest moment (1)=(5,5) şi (5)=(5, ).
Când căutarea continuă, valoarea nodului (5) este găsită ca fiind (4), în afara gamei (5, ) şi se
întrerupe căutarea nodului (2) şi a celor ce pornesc din el.
Prima întrerupere a căutării apare datorită faptului că nodul (4) este cel puţin egal cu
valoarea lui beta şi a părinţilor săi, a doua întrucât valoarea nodului (2) este cel puţin egală cu
valoarea lui alfa. Procedeul este denumit beta-cut, respectiv alfa-cut. Metoda de creştere a
eficienţei căutării utilizând marginile inferioare şi superioare este numită metoda alfa-beta.
Pentru a determina eficienţa căutării se calculează numărul maxim al nodurilor explorate în
cel mai bun caz. Considerând momentul în care s-a găsit valoarea (k) a primului nod fiu de la
un nod MAX, nodul (n), atunci (n)=(k, ). Dacă beta al nodului părinte (m) al lui (n) este
mai mic sau egal cu (k), nu este necesară evaluarea celorlalte noduri fiu ale lui (n). Dacă
nodul (m) nu este primul nod fiu al părintelui său, valoarea beta este deja dată şi nu poate fi
. Concluzii similare pot fi trase pentru nodurile MIN. În consecinţă, în cel mai bun caz, dacă
nodul (m) nu este primul nod al uni nod părinte, nu este necesară examinarea nici unui nod fiu
decât a primului nod al lui (m).
Nodurile terminale sunt reprezentate prin secvenţa de arce ce le leagă. De exemplu
nodul (12) din figura (g) poate fi exprimat prin secvenţa (1,2,3), adică este atins urmărind
primul arc al lui S, al doilea de la nodul (1) şi al treilea de la nodul (4). Ca urmare nodurile
terminale ale arborelui de adâncime (k) se exprimă prin k-uplul (e1,e2,…,ek). Nodurile ce nu
necesită examinarea sunt cele pentru care ei 1, ei+1 1. În consecinţă nodurile care au fost
examinate în cel mai bun caz, fie sunt noduri numere pare care au în secvenţă (1), fie sunt
noduri numere impare care au în secvenţă (1). Noţiunea de par sau impar se referă la numărul
nodului în adâncimea arborelui.
Dacă se presupune că numărul arcelor posibile de la noduri neterminale este (m),
atunci numărul nodurilor pare No(k,m) şi numărul nodurilor impare Ne(k,m) sunt date prin
următoarele formule:
- dacă k este par: No(k,m)=m(k-1)/2, Ne(k,m)=m(k+1)/2
- dacă k este impar: No(k,m)=Ne(k,m)=mk/2.
87
Nodul (1,1,…,1) este numărat pentru ambele No(k,m) şi Ne(k,m), aşa că Ntotal(k,m)
este No(k,m)+Ne(k,m)-1. Cu aceste precizări se obţine:
- pentru k par: Ntotal(k,m)=m(k-1)/2+m(k+1)/2-1
- pentru k impar: Ntotal(k,m)=2mk/2-1.
În cel mai bun caz, numărul nodurilor ce trebuie examinate prin metoda alfa-beta este
aproximativ acelaşi cu numărul nodurilor ce trebuie căutat prin metoda minimax într-un
arbore de adâncime jumătate.
În cazul cel mai defavorabil toate nodurile vor trebui examinate.
Uzual situaţia este cuprinsă între două extreme, valoarea reală fiind dată prin
inegalitatea
mk/2 < N(k,m) <= mk.
A B
C D ES F
5 2 1 6
Figura (h) Arbore ŞI/SAU pentru jocuri
Nodurile fiu ale nodurilor MAX corespund la noduri SAU, cele ale nodurilor MIN la
noduri ŞI (nodul de start este văzut ca un nod ŞI). Ca şi la arborii ŞI/SAU nodurile terminale
au valoarea evaluată dată. Costul arcelor este întotdeauna (0). Utilizând metoda minimax, cea
mai bună mutare este determinată prin următoarele metode:
dacă nodurile fiu ale unui nod dat sunt noduri ŞI, valoarea nodului este dată de cea
mai mică valoare evaluată a fiilor săi;
dacă nodurile fiu sunt noduri SAU, valoarea este dată de valoarea maximă dintre
valorile nodurilor fiu ale sale.
În cazul jocurilor pentru care obiectivul este cel de a face valoarea nodului de start
maximă, valorile evaluate sunt în opoziţie faţă de cost, adică cea mai mare valoare evaluată
este cea mai bună. În consecinţă metoda de calcul a valorilor în diverse noduri ale grafului
este diferită de cea utilizată în metodele descrise anterior pentru arbori ŞI/SAU.
Valoarea evaluată a nodului terminal a soluţiei grafului este însăşi valoarea nodului
terminal. Valoarea într-un nod unde fiii sunt noduri ŞI este valoarea minimă din valorile
asociate nodurilor fiu. Valoarea unui nod unde fiii sunt noduri SAU este aceeaşi cu valoarea
nodului fiu. Dacă se scrie valoarea nodului (n) ca f(n), f(A)=2 şi f(S)=2.
Alte soluţii pot apărea din valorile celorlalte noduri. În cazul de faţă soluţia este (1).
Metoda descrisă anterior referitoare la grafuri ŞI/SAU poate fi aplicată şi la arbori de jocuri.
88
Totuşi h’( ) nu este dată de aceeaşi formulă exceptând nodurile terminale. Pentru a obţine
soluţia optimă condiţia f’(n) >= f(n) este îndeplinită pentru toate nodurile (când se urmăreşte
obţinerea soluţiei de cost minim h’(n) <= h(n) pentru toate nodurile). În consecinţă dacă
valorile punctelor terminale nu sunt date, valorile inferenţiale ale arborilor candidat sunt
infinit de mari. Presupunând că la expandarea nodurilor neterminale ale grafului candidat
nodurile fiu sunt noduri ŞI, ele se expandează în acelaşi moment. Dacă se notează primul nod
fiu cu (n1) (nod ŞI) al lui (ni), se poate lua f’(n) <= f(n1). Aşa se poate calcula f’ şi reactualiza
în timpul procesului de căutare. Asemănător cu metoda de căutare optimală descrisă anterior,
principiul acestei metode este bazat pe faptul că un graf candidat adus din open_list va fi
expandat după cea mai mare valoare inferenţială.
În arbori ŞI/SAU pentru jocuri găsirea soluţiei necesită nu numai nodul terminal care
dă valoarea soluţiei arborelui, ci şi drumul urmat pentru ca pornind de la nodul de start acesta
să fie atins. Pentru transpunerea algoritmului, prin convenţie se va nota cu EXPL nodurile
atinse ce nu au starea SOLVED. În acest context starea nodului (n) este dată de tripletul (n, s,
v) în care (s) indică faptul că nodul (n) este SOLVED sau EXPL, (v) dă valoarea lui f(n) dacă
(n) este SOLVED sau f’(n) dacă el este EXPL. Starea nodului (n) este pusă în open_list
printr-o procedură pe care am notat-o putopen(n, s, v). De asemenea se va scrie pentru nodul
părinte parent(n), nodul terminal n ca terminal(n) şi pentru a detecta un nod (n) ca fiind
ŞI/SAU s-a utilizat funcţia type(n). Algoritmul de căutare în astfel de situaţii este:
putopen (S,EXPL,f’(n));
while true
{
if open=goală then exit(fail);
n=first(open);
if (n=S & SOLVED(n)) then exit(succes);
remove (n,open);
/*1*/ if ((S=EXPL) & (type(n)=AND) & not_terminal(n))
then pentru toate nodurile fiu (ni) ale lui (n)
putopen (n, EXPL, f’(n));
/*2*/ if ((S=EXPL) & (type(n)=OR)) & not_terminal(n))
then
{next_n=next_fiu()
if (next_n=SOLVED) then
putopen (n, SOLVED, f(n));
else putopen (n, EXPL, f’(n));}
/*3*/ if ((S=EXPL) & terminal(n))
putopen (n, SOLVED, min(f’(n), f(n));
/*4*/ if ((S=SOLVED) & (type(n)=AND))
putopen (parent(n), EXPL, f’(n));
/*5*/ if ((S=SOLVED) & (type(n)=OR))
{m=parent(n); /*mută toate nodurile fiu ale lui (m) în open_list
putopen(n, SOLVED, f’(n);}
}
89
0
1 2 3
4 5 6 7 8 9 10 11 12
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
4 3 3 2 6 5 4 2 3 4 3 6 3 5 5 4 6 8
Aşa cum se vede din tabelul de rezultate, metoda alfa-beta este dependentă de ordinea
nodurilor.
În cazul grafului din figura (i) dacă nodul (3) ar fi în locul nodului (1) soluţia optimă
ar fi găsită mult mai rapid. În algoritm au fost notate cele 5 situaţii ce sunt ilustrate şi în
tabelul precedent, pentru a uşura cititorul în înţelegerea algoritmului.
Spre deosebire de căutarea optimală obişnuită care explorează mai întâi nodurile cele mai
promiţătoare şi a cărei eficienţă nu este afectată de aranjarea nodurilor, metoda alfa-beta este
dependentă de aceasta. În al doilea rând memoria necesară pentru algoritmul alfa-beta este
mult mai redusă. Alegerea uneia din cele două metode este dependentă de performanţele
dorite din punctul de vedere al vitezei de calcul şi al memoriei necesare.
90
4.3. Exerciţii
Rezolvare.
Care este, spre exemplu, valoarea nodului o în această poziţie? Este o încercare de
maximizare şi orice mutare care se va face va termina jocul. Se poate muta în oricare dintre
poziţiile p sau r şi se pierde sau se poate muta în poziţia q şi se câştigă. Numim aceasta ca
fiind sensibilitatea jocului; evident că se va alege q. Aceasta înseamnă că, în realitate nodul o
este câştigător pentru maximizare şi poate fi etichetat cu 1.
91
Figura 4.2. Maximizatorul câştigă.
Algoritmul pentru reîntoarcerea valorilor către partea superioară din arbore este acum
evident. Un nod în care maximizatorul este la mutare poate fi etichetat cu valoarea maximă
care etichetează oricare dintre fii săi. Un nod în care minimizatorul mută poate fi etichetat cu
minimumul etichetelor fiilor săi. Acest lucru este făcut în figura 4.2., şi se poate vedea că
poziţia de start este etichetată cu 1, ceea ce într-un joc cu informaţie completă va conduce la
câştigarea jocului de către maximizator.
Înainte de a enunţa procedura de rezolvare, să presupunem că ne întoarcem deasupra
nodului k, determinând că g şi c au valoarea 1. Putem acum să oprim analiza şi să
concluzionăm că valoarea ce va fi atribuită lui a este de asemenea 1! Motivul este acela că
ştim că maximizatorul poate învinge din nodul a printr-o mutare în nodul c şi nu este nici un
motiv să căutăm o altă alternativă pentru această linie câştigătoare.
Iată algoritmul de bază pentru determinarea valorilor ce vor fi ataşate nodurilor interne
într-un arbore de joc .
Dacă jocul se termină în situaţia în care ambii jucători au şanse egale – spre exemplu a
unei remize în jocul de şah - aceasta ar corespunde unei poziţii terminale etichetate cu 0 în loc
de -1 sau 1. Remizele se potrivesc foarte bine cu formalismul mini-max, deoarece fiecare
jucător încearcă, dacă este posibil, o mutare câştigătoare şi va căuta o posibilitate de remiză
dacă nu există câştigători.
92
Ca o problemă de terminologie, printr-o mutare într-un arbore de joc înţelegem o
pereche de acţiuni individuale, una pentru fiecare jucător. O acţiune dusă doar cu un singur
jucător este numită o jumătate de mutare sau un strat. Astfel, adâncimea arborelui din figura
4.2. este de 3 mutări sau de 6 straturi.
Câtă memorie şi cât timp sunt necesare pentru un algoritm mini-max în procedura
4.1.? Deoarece întreg arborele trebuie să fie expandat, ne putem aştepta ca această procedură
să aibă nevoie de o cantitate exponenţială de spaţiu, după cum întreaga ramificaţie, are nevoie
aparent să fie stocată înainte ca valorile superioare să fie refăcute. Să remarcăm faptul că,
spaţiul necesar poate fi redus la o cantitate liniară în adâncime printr-o căutare verticală sau
în adâncime în loc de o căutare orizontală sau în lăţime. De aceea, în figura 4.2. putem
întoarce valoarea -1 nodului superior b înainte de a extinde fiii nodului c, şi aşa mai departe.
Aceasta va produce următorul rezultat, unde se actualizează valorile asignate nodurilor interne
după cum valorile sunt asignate fiilor săi:
Din păcate, procedura 4.2. are nevoie de o cantitate exponenţială de timp pentru a
determina valoarea care va fi ataşată nodului n. În general, nu este practic să se extindă
întregul arbore; ca exemplu, arborele jocului de şah conţine aproximativ 10160 noduri (graful
poziţiilor de şah este întrucâtva mai mic deoarece multe poziţii pot fi atinse în diferite
moduri). Cum reuşesc oamenii să joace un astfel de joc? Nu-i putem analiza toate căile până
la sfârşit; putem doar să privim situaţia astfel încât să putem estima care este jucătorul cel mai
probabil să învingă într-o poziţie neterminală şi să refacem apoi valorile spre partea
superioară a arborelui din poziţiile neterminale pe care le-am găsit. Mini-max se aplică încă;
trebuie doar să-l aplicăm nodurilor interne din arbore .
Exerciţiul 2.
Problema cu privire la căutarea în jocul de şah se rezumă la căutarea în arbori a unor
noduri cu proprietăţi matematice certe. Ca rezultat, multe din nodurile examinate în timpul
căutării pentru o mutare, nu au nici o legătură cu desfăşurarea jocului - ele devin fără sens şi
în cel mai rău caz sinucigaşe. Programul jocului de şah consideră irelevante mişcările pionului
şi piesele fără valoare se sacrifică cu aceeaşi grijă cu care se iau în considerare combinaţiile
învingătoare sau avansările poziţionale prudente. Dacă vrem să îmbunătăţim performanţele
acestor programe, avem nevoie de o cale de a reduce mărimea spaţiului de căutare. Cea mai
93
puternică tehnică cunoscută pentru a face acest lucru este denumită căutarea pe care o
vom aplica pe un set de jocuri reprezentate prin arbori de joc corespunzători.
Rezolvare.
La căutarea din figura 5.5 observăm că, odată ce realizăm că maximizatorul poate
învinge prin mutare la c, nu mai este nevoie să analizeze alte opţiuni ale lui din a. Şi anume,
valorile asignate tuturor nodurilor de sub nodul b cu siguranţă nu afectează valoarea totală
asignată pentru poziţia a.
Dacă atacăm regina adversarului, putem fi făcuţi mat la următoarea mutare, în felul acesta se
sfârşeşte jocul şi rezultatul va fi -1. Evident, nu este nevoie să luăm în considerare nici un alt
nod care este fiu al lui c.
94
În exemplul din figura 5.7. presupunem că analizăm arborele în maniera căutării în
adâncime şi determinăm valoarea care va fi asignată nodului b care este 0.03. Continuăm prin
examinarea opţiunii din c, atacând regina adversarului cu regina proprie.
Primul răspuns considerăm că este d, implicând un schimb de regine. O examinare
viitoare a fiilor lui d, deci a lui e şi f, arată că f este cea mai bună dintre cele două mutări şi
conduce la o valoare de -0.05 pentru nodul d.
Este posibil să fie c selecţia? Dacă mutăm la c, cel mai bun rezultat pe care ne
aşteptăm să-l obţinem este -0.05, deoarece acesta rămâne cel mai bun dacă adversarul replică
cu d. Dacă g este mai bună pentru adversar decât este d, valoarea care va fi asignată lui c va fi
chiar mai mică decât -0.05. De ce trebuie să acceptăm nişte valori slabe când putem obţine un
rezultat de 0.03 prin mutarea la nodul b ?
Ceea ce vrem să arătăm, de fapt, este că nodul c nu este niciodată pe linia principală,
aceasta fiind cursul jocului când ambii jucători joacă optim. Deoarece b este mai bun pentru
maximizator decât este c şi maximizatorul poate selecta între ele, c va fi evitat în mod
garantat. Valorile asignate lui g şi nodurilor de sub el nu pot influenţa niciodată valoarea
finală asignată nodului a iar subarborele de sub g poate fi şters.
Putem găsi aceeaşi soluţie pe cale algebrică. Dacă notăm cu g valoarea anterioară
asignată nodului g, atunci valoarea asignată nodului c va fi :
c = min( -0.05, g)
deoarece el este minimizatorul cel care va alege între alternativele d şi g.
Continuând, valoarea asignată nodului rădăcină a este
a=max[0.03, min( -0.05, g)] = 0.03 (5.2)
unde a doua egalitate se menţine deoarece min(-.05, g) -.05 < .03. Deoarece valoarea
asignată nodului a este independentă de valoarea g, observăm că nodurile de sub g pot fi
şterse.
În exemplul din figura 5.8. valorile asignate lui b şi lui f sunt .03 şi respectiv -1. Ce
putem spune despre fiii nodului g? Se poate arăta că g nu este pe o linie principală?
Dacă g ar fi pe o linie principală, atunci şi strămoşii lui trebuie să fie pe linia
principală, deci şi e va fi pe o linie principală. Dar din e, minimizatorul are şansa de a se muta
în f şi să obţină un rezultat de -.1. Deoarece acesta este mai prost decât rezultatul de .03 pe
care maximizatorul îl poate obţine prin mutarea în b, rezultă că g nu poate fi pe o linie
principală. Notăm că este posibil ca h să fie pe o linie principală, sau ca i să fie, însă putem
spune cu siguranţă că g nu este. O situaţie cum este aceasta, unde nodul şters este la mai mult
95
de un strat sub cel care îl referim ca motivul ştergerii, este cunoscută ca fiind ştergerea
în adâncime.
Ce se poate spune despre acest caz general? Presupunem că n este un nod oarecare
într-un arbore de joc la care maximizatorul ajunge la mutare (cum ar fi nodul g în figura 5.8),
şi că s este frate cu n având o valoare de întoarcere vs (s va putea fi nodul f în figura de
deasupra, astfel că vs = -.1). Presupunem, de asemenea, că (p0, p1, ..., pk) este calea de la nodul
rădăcină în jos spre n, cu p0 - nodul rădăcină şi pk = n.
Vom mai face remarca că nodurile cu indicii impari (p1, p3, …etc.) sunt noduri
minimizante; dacă oricare din aceste noduri are un frate cu o valoare de întoarcere mai mare
decât vs, atunci nodul n poate fi şters. (În figură p1 = c are un frate b cu valoarea .03 > vs). Iată
o altă cale de exprimare a acestei situaţii şi anume procedura de căutare .
Procedura 4.3. Căutarea . Pentru evaluarea unui nod n într-un arbore joc:
1. Pune L = {n}.
2. Fie x primul nod din L. Dacă x = n şi există o valoare asignată lui, returnează
această valoare.
3. Dacă lui x i-a fost asignată o valoare vx, fie p părintele lui x; dacă lui x nu i-a fost
asignată o valoare, treci la pasul 5. Prima dată determinăm dacă p şi fiii săi pot
sau nu să fie şterşi din arbore: dacă p este un nod minimizat, atunci fie
maximul tuturor valorilor curente asignate fraţilor lui p şi nodurilor
minimizante care sunt strămoşii lui p (dacă nu există astfel de valori, luăm
). Dacă vx ştergem pe p şi pe toţi descendenţii săi din L. Dacă p este
un nod maximizant, îl tratăm în mod similar.
4. Dacă p nu poate fi şters, fie vp valoarea curentă asignată lui p. Dacă p este un
nod minimizant, luăm vp= min(vp , vx). Dacă p este un nod maximizant, luăm vp
= max(vp , vx). Ştergem pe x din L şi ne reîntoarcem la pasul 2.
5. Dacă lui x nu i-a fost asignată o valoare şi este fie un nod terminal fie noi
decidem să nu lărgim arborele mai departe, îi calculăm valoarea utilizând
funcţia de evaluare. Reîntoarcere la pasul 2.
96
6. În caz contrar, luăm vx ca fiind - dacă x este un nod maximizant şi + dacă
este un nod minimizant. Adăugăm toţi copiii lui x în fruntea listei L şi ne
întoarcem la pasul 2.
Valoarea care corespunde lui dar care este calculată ţinând cont de strămoşii
maximizanţi ai lui p este cunoscută sub numele de : cele două valori şi conduc
separat la ştergere. Din această cauză, această metodă de reducere a mărimii arborelui de
căutare este cunoscută sub numele de ştergerea .
Deşi am văzut că ştergerea poate reduce mărimea spaţiului de căutare asociat
unui arbore de joc, nu putem realiza cât de mult spaţiu de căutare este redus.
Este clar, de exemplu, că în cel mai rău caz este posibil ca ştergerea să nu poată
reduce dimensiunea spaţiului de căutare la maximum. Dacă suntem perseverenţi în aranjarea
fiilor fiecărui nod astfel încât opţiunile proaste să fie evaluate primele, atunci nodurile
examinate mai târziu vor fi întotdeauna în “linia principală” şi prin urmare nu vor fi niciodată
şterse.
Testul 1
1. Daţi un exemplu de problemă de căutare unde urcarea dealului şi cea mai bună
primă căutare se comportă diferit.
' '
2. Presupunem că h1 şi h2 două euristici admisibile într-o problemă de căutare.
' '
Arătaţi că max(h1 , h2 ) este de asemenea admisibilă. Daţi un exemplu de problemă de căutare
şi două funcţii euristice admisibile nici una din ele întotdeauna să nu fie mai mică decât
cealaltă.
'
3. Cum se comportă algoritmul A* dacă h h ? Demonstraţi afirmaţiile voastre.
4. Acest exerciţiu examinează alegerea între două funcţii euristice admisibile din
' '
care una este mereu mai mică decât alta. Presupunem că h1 şi h2 sunt două funcţii euristice
' '
admisibile pentru un domeniu oarecare şi deci h1 (n) h2 (n) pentru fiecare nod.
(a) Fie S ordinea de căutare pentru care căutarea A* este legală folosind euristica
h1' şi presupunem că aceasta explorează spaţiul de căutare folosind această ordine care
implică expandarea unei mulţimi de N noduri. Arătaţi că există câteva ordine de căutare
'
pentru care A* este legală folosind euristica h2 care examinează o submulţime al lui N în
'
rezolvarea problemei în cauză. Aceasta arată că este întotdeauna posibil ca h2 să conducă
'
către un spaţiu mai mic de căutare decât o face h1 .
' ' '
(b) Găsiţi o problemă de căutare şi două euristici admisibile h1 şi h2 cu h1 h2'
' '
astfel încât deşi este posibil ca h2 să examineze mai puţine noduri decât h1 , este de departe
'
mai ca sigur ca h1 să conducă la căutarea cea mai eficientă.
5. În ce ordine examinează IDA* spaţiul de căutare asociat celor 2 labirinte ce apare
în figura 4.10.
97
Figura 4.10.
B. TEMA DE CONTROL
Indicaţie. Valoarea lui h’(n) este dată în paranteze asociate nodului. Schimbările în open_list
obţinute prin utilizarea algoritmului A* sunt marcate de indicarea lui f’(n) în parantezele
asociate nodurilor. Se va obţine secvenţa de noduri în open_list.
98
3. Să se rezolve prin metode de căutare cu ramificare şi limitare problema comis-
voiajorului.
Un comis voiajor ce lucrează într-un oraş X trebuie să ajungă odată pe lună într-o serie
de oraşe în care are de dus obiecte sau de luat obiecte. Firma la care lucrează suportă costul
transportului de la oraşul X la fiecare din oraşele de destinaţie. Problema comis voiajorului
este de a stabili acel traseu pentru care pornind din oraşul X să atingă toate oraşele din traseu
cu destinaţia finală oraşul X, astfel încât costul transportului să fie minim. În afară de
informaţiile alternative ce reprezintă costul transportului între oraşul X şi oraşele învecinate
sunt necesare informaţii despre costul deplasării între oraşele din traseu.
Considerăm harta asociată circuitului, cu costurile corespunzătoare, ca fiind
următoarea:
F
10 4
6
D A
12 7
15 8
11 5
X
D B
25
17 9
C
Indicaţie. Matricea costurilor care are ca elemente costurile corespunzătoare dintre
două localităţi şi pentru drumul dintre oraşul A şi A (acesta nefiind un drum valid) ca şi în
cazul în care între două oraşe nu există legătură directă este următoarea:
99
X A B C D E F
X ∞ 7 5 25 11 12 6
A 7 ∞ 8 4
B 5 8 ∞ 9
C 25 9 ∞ 17
D 11 17 ∞ 15
K=
E 12 15 ∞ 10
F 6 4 10 ∞
1. Podaru Vasile, Inteligenţă artificială şi siteme expert, Editura Academiei Tehnice Militare,
1997
2. Podaru Vasile, Barnoschi Adriana, Sisteme expert, Editura Academiei Tehnice Militare,
2000, 2004.
3. Ioan Georgescu, Elemente de inteligenţă artificială, Editura Academiei RSR, 1985.
4. Podaru Vasile, Inteligenţă artificială, curs în format electronic, CD-învăţământ la distanţă,
Universitatea Titu Maiorescu, 2010.
5. D. Cîrstoiu, Sisteme expert, editura ALL, 1994.
6. SICSTUS PROLOG USER’S MANUAL. Intelligent Systems Laboratory, Sweedish Institute
of Computer Science:
http://www.sics.se/isl/sicstuswww/site/documentation.html
7. M. Maliţa, Bazele inteligenţei artificiale, editura Academiei Române, 1988.
Coordonator disciplină:
Prof. univ. dr. Vasile PODARU, email: podaruv@gmail.com
100
UNIVERSITATEA TITU MAIORESCU
Facultatea de INFORMATICĂ
BUCUREŞTI – 2011
UNIVERSITATEA Titu MAIORESCU Bucureşti
Facultatea de Informatică
Învăţământ la Distanţă
INTELIGENŢĂ ARTIFICIALĂ
Inteligenţa artificială este una din disciplinele de pregătire fundamentală care, pentru
profilul INFORMATICĂ, este esenţială pentru pregătirea studenţilor şi pentru obţinerea
creditelor transferabile prin procedurile de evaluare. Modul de prezentare a acestui material
are în vedere particularităţile învăţământului la distanţă, la care studiul individual este
determinant. Pentru orice nelămuriri faţă de acest material vă rugăm să contactaţi tutorele de
disciplină care are datoria să vă ajute oferindu-vă toate explicaţiile necesare.
Disciplina de Inteligenţa artificială îşi propune următoarele obiective specifice:
Însuşirea noţiunilor fundamentale din domeniile Inteligenţei artificiale.
Formarea deprinderilor de modelare matematică şi de transpunere în programare a
unor probleme de natură tehnică, socială sau economică, cu utilizarea cunoştinţelor
însuşite.
Formarea şi dezvoltarea aptitudinilor şi deprinderilor de analiză logică, formulare
corectă şi argumentare fundamentată, în rezolvarea problemelor tehnico-economice şi
de specialitatecu cu utilizarea cunoştinţelor însuşite prin intermediul metodelor şi
modelelor specifice inteligenţei artificiale;
Insusirea principiilor generale ale programarii logice si insusirea limbajului Prolog;
O comparaţie critică a metodelor de rezolvare evidenţiind, eventual, calea optimă de
soluţionare.
Accentul se va pune pe problemele de cautare si reprezentare a cunostintelor si
respectiv pe programarea logica, limbajul de programare utilizat la laborator fiind
limbajul Prolog. Cursul trebuie sa trateze aspecte ale rezolvarii problemelor prin
intermediul cautarii, descriind cele mai importante tehnici de cautare informata si
neinformata. Se vor da exmple de aplicatii ale cautarii, cum ar fi jocurile, tratate ca
probleme de cautare. Se vor prezenta principalele tipuri de cunostinte si principalele
metode de reprezentare a cunostintelor. Se va face legatura dintre reprezentarea
cunostintelor si sistemele expert. Se va da un exemplu de sistem expert cu
implementare in Prolog. Vor mai fi tratate, ca modalitati de reprezentare a
cunostintelor, retelele semantice si retelele Bayesiene (cu introducerea rationamentului
statistic).
102
aproximativ 6-8 ore pentru întregul modul , într-un ritm de 3-4 ore pentru fiecare din cele
două unităţi ale modulului.
Întru-cât modulul este privit ca un tot unitar exerciţiile aferente acestui modul se
găsesc la sfârşitul acestui modul. La terminarea parcurgerii acestui modul studenţii trebuie să
prezinte tutorelui de disciplină rezolvarea temei de control propusă spre rezolvare la sfîrşitul
modulului.
Cursul se finalizează prin examen care constă din:
1) o lucrare scrisă sub forma de text grila constând din 9-18 subiecte (ponderea lucrării
scrise este de 70% din nota finală);
2) rezolvarea corectă a temelor de control din cele 4 module (minimum nota 5 pentru
fiecare temă, ponderea mediei celor 5 note în nota finală este de 20%);
3) participarea activă la activităţile tutoriale (apreciată printr-o notă a cărei pondere in
nota finală este de 10%).
103
MODULUL 3
METODE DE ÎNVĂŢARE.
REŢELE NEURONALE.
Îndrumări metodice.
104
Unitatea de învăţare nr.5
Învăţarea.
Cuprins:
5.0. Introducere ................................................................................................. pag. 105
5.1. Învăţarea prin descoperire .......................................................................... pag. 105
5.2. Învăţarea prin generalizare ......................................................................... pag. 107
5.2.1. Învăţarea inductivă ................................................................................. pag. 107
5.2.1.1. Învăţarea probabil aproximativ corectă ................................................ pag. 108
5.2.1.2. Algoritmul lui Mitchell ........................................................................ pag. 111
5.2.1.3. Învăţarea unor inegalităţi ...................................................................... pag. 113
5.2.1.4. Algoritmul lui Quilan ........................................................................... pag. 115
5.0. Introducere.
105
decidea că este interesantă, funcţia x+x ar putea fi probabil o funcţie de un singur argument.
Se spera prin acest tip de reguli ca AM să inventeze înmulţirea o dată ce ar fi descoperit
adunarea.
Scopul lui AM era să dezvolte concepte matematice interesante. Exact asta a şi făcut.
De fapt, dându-i-se doar informaţia de mai sus, a "descoperit":
Întregii. AM a învăţat destul de devreme că e posibil să numeri elementele oricărei
mulţimi şi a decis că imaginea acestei funcţii de numărare- întregii este ea însăşi o mulţime
interesantă.
Adunarea. Mulţimile disjuncte erau interesante şi de asemenea, reuniunea
mulţimilor era interesantă. Imaginea operaţiei "ia reuniunea mulţimilor disjuncte" sub funcţia
de numărare descrisă anterior este adunarea.
Înmulţirea. Aceasta a fost descoperită folosind o regulă ca cea prezentată mai sus.
Lenat a intervenit şi a dat maşinii descrieri mai clare ale adunării şi înmulţirii, care
fuseseră mai înainte descrise în termeni de operaţii laborioase de mulţimi teoretice. Efectul
acestui lucru a fost doar de a face deliberările ulterioare ale maşinii mai eficiente; nu s-a
produs nici o schimbare de fond.
Numerele prime. Descoperind înmulţirea, maşina a descoperit rapid că numerele
pot fi factorizate, fiind cel mai mult interesată de numerele care aveau un singur factor. Dacă
există o funcţie f şi o valoare y în domeniul lui f, mulţimea lui x astfel încât f(x)=y ar putea fi
interesantă. Considerăm f funcţia "cardinalul mulţimii divizorilor" şi y numărul interesant 1.
Desigur, singurul număr cu un singur factor este chiar 1. Dar întregul 2 este aproape la
fel de interesant ca 1, iar numerele prime sunt chiar cele care au exact doi factori.
Ipoteza lui Goldbach. Numărul par 28 poate fi scris ca sumă de două numere
prime 11 şi 17. În 1742 Goldbach a afirmat că orice număr par poate fi scris ca suma a două
numere prime, dar ipoteza este încă nedemonstrată. AM a făcut o presupunere similară.1
În sfârşit, AM a inspirat o "nouă" problemă de matematică. Pe lângă studiul
numerelor prime - numere cu cât mai puţini factori posibil- a examinat şi numerele cu cât mai
mulţi factori posibil, spunând că un întreg k este "maxim divizibil" dacă k are mai mulţi
factori decât orice număr mai mic decât k. Numărul 12 este un exemplu: are 6 divizori (1, 2,
3, 4, 6, 12) şi nu există nici un număr mai mic care să aibă tot atâţia. Mulţimea numerelor
maxim divizibile nu fusese anterior luată în considerare de Lenat sau de alţi membri ai
comunităţii AI, deşi ele fuseseră studiate de matematicianul indian Ramanujan.
AM este o lucrare deosebit de impresionantă, fiind unul din cele mai importante
succese timpurii ale AI. AM este de asemenea un exemplu aproape perfect de AI
experimentală - lucrarea lui Lenat a implicat proiectarea unui program care a manifestat
comportări interesante, surprinzându-şi chiar autorul în timpul rulării!
Ce lecţie trebuie să învăţăm din AM? Care a fost viitorul programului? A purces la
redescoperirea întregii matematici moderne? Au fost aceste idei aplicate cu succes în alte
domenii? Şi în primul rând de ce a avut AM aşa un succes?
Motivul pentru care AM a avut aşa un succes este strânsa legatură dintre limbajul LISP
şi matematică. Parţial, AM a generat funcţii interesante prin modificarea codului unor funcţii
pe care le considera deja interesante.
Dar conexiunea dintre LISP şi matematică este aşa de strânsă încât este destul de
probabil ca modificări arbitrare ale unor fragmente foarte mici de LISP (cum sunt cele cu care
1
AM nu a demonstrat o astfel de ipoteză. AM nu a demonstrat niciodată nimic - doar a remarcat că
multe numere pare ar putea fi scrise ca sumă a două numere prime şi de aici, a speculat că toate
numerele pare ar putea fi la fel. Lenat a fost interesat de descoperire şi nu de demonstrarea automată a
teoriei.
106
a lucrat AM) să producă rezultate interesante. Într-un anume sens, AM a avut succes doarece a
exploatat nedumeririle şi relevaţiile pe care le-a avut John McCarthy când a dezvoltat limbajul
LISP.
Această observaţie are două consecinţe evidente. Prima este că abilitatea lui AM de a
dezvolta noi concepte matematice va scădea rapid pe măsură ce conceptele cu care lucrează
devin tot mai complexe - este mult mai puţin probabil să putem modifica aleator o porţiune
lungă de cod LISP decât una scurtă.
Cealaltă consecinţă spune că este puţin probabil ca tehnici precum cele folosite de AM
să funcţioneze în afara domeniului matematicii, deoarece este puţin probabil ca alte domenii
să afişeze o legatură aşa strânsă între părţi de cod (program) şi idei interesante. Acest lucru a
fost de asemenea observat în practică.
După elaborarea lui AM, Lenat a dezvoltat EURISKO, care se voia a fi o versiune
generalizată a lui AM, care să descopere idei interesante în domenii arbitrare. Dar, în ciuda
aplicaţiilor lui EURISKO într-o varietate de probleme, succesul său a fost destul de limitat.
Ca un exemplu, EURISKO a fost utilizat într-o încercare de a învăţa cum să
construiască circuite integrate tri-dimensionale. Programul a reuşit să genereze un circuit
integrat foarte mic pe suprafaţa unei benzi Möbius, dar în afară de aceasta s-a comportat slab.
EURISKO a fost de asemenea utilizat pentru a juca un joc de conducere a unei flote, în
care fiecare jucător primeşte un buget fix şi trebuie să-şi construiască o flotă furnizând
caracteristicile de mărime, armament, etc. pentru nave. Apoi flotele se luptă şi cea care o
distruge pe cealaltă, câştigă. EURISKO a învăţat să joace acest joc jucând împotriva sa şi apoi
a intrat în campionatul naţional. A câştigat! Dar a câştigat construind nave "ţânţar" - nave
foarte mici şi rapide, fără nici un fel de armament. Când EURISKO întâlnea un adversar
superior, toate navele erau distruse, exceptânnd "ţânţarii", care continuau să "bâzâie" prin
zonă, incapabile să producă vreo distrugere flotei adverse, dar salvând EURISKO de la
înfrângere, doarece regulile spuneau că flota adversă trebuie distrusă în întregime. Această
scăpare a regulilor a fost ceea ce a permis lui EURISKO să fie atât de eficient.
Există ceva comun între acest exemplu şi performanţa originală a lui AM: în ambele
cazuri, programul a trebuit să exploateze o scăpare pentru a avea succes. În cazul lui
EURISKO, scăparea era în regulile jocului cu flote. În cazul lui AM, scăparea era în strânsa
legătură dintre LISP şi matematică. Rezultă că învăţarea prin descoperire, care evită aceste
scăpări se va sprijini pe o înţelegere mult mai dificilă a domeniilor investigate.2
Toate problemele de acest tip au ceva comun: intrarea programului este un set de
instanţe de instruire (care pot fi selectate fie aleator, fie dintr-o încercare de a face învăţarea
cât mai eficace posibil) şi ieşirea se aşteaptă să fie o metodă de clasificare a instanţelor
ulterioare. Pentru acest motiv învăţarea inductivă se mai numeşte şi învăţare prin exemple. Ca
2
Alternativ, se poate argumenta că toată învăţarea prin descoperire-inclusiv cea umană-
funcţionează prin exploatarea vreunei breşe.
107
exemplu de învăţare inductivă vom alege selecţia ciupercilor comestibile de cele otrăvitoare.
Vom presupune că scopul învăţării inductive este să rezolve o problemă de clasificare binară:
comestibil versus otrăvitor (adică proiectarea unui clasificator binar).
Învăţarea inductivă nu seamană niciodată cu cea deductivă. Faptul că spre exemplu din
10.000 de ciuperci galbene întâlnite au fost toate otrăvitoare, nu dovedeşte că următoarea
ciupercă galbenă va fi la fel; ne dă doar o bună dovadă inductivă (în opoziţie cu deductivă) că
aşa va fi. Cu această observaţie, ne punem întrbarea care este următorul cadru de lucru în care
vom măsura performanţa unui sistem care învaţă inductiv?
Un răspuns la această întrebare a fost dezvoltat de Valiant în 1984; el a argumentat că
un sistem de învăţare trebuie să fie probabil aproximativ corect - pe scurt, PAC.
Să începem prin descrierea a ceea ce înseamnă pentru un sistem învăţarea unei reguli
care este aproximativ corectă. Deoarece problema de clasificare pe care încercăm s-o
rezolvăm este binară, răspunsul nu poate fi el însuşi aproximativ: este fie bun, fie greşit. Spre
exemplu, ciuperca este sau nu clasificată corect? Faţă de aceasta, vom spune că o regulă ca
"toate ciupercile galbene sunt otrăvitoare" este aproximativ corectă ori de câte ori rezolvă cele
mai multe din probleme corect. O regulă învăţată este aproximativ corectă, dacă este complet
corectă cea mai mare parte a timpului.
Notăm cu p(x) conceptul binar pe care încercăm să-l învăţăm – spre exemplu,
comestibil sau necomestibil. Notăm cu p' (x) aproximarea lui p, pe care o învaţă de fapt
sistemul. Vom spune că p' este o eroare pentru x dacă p şi p' sunt diferite şi în consecinţă
eroare(x) este definită astfel:
[ p( x ) p' ( x )] [ p( x ) p' ( x )]
[ p( x) p ' ( x)]
O regulă învăţată p' (x) o vom numi aproximativ corectă cu precizia dacă şi numai
dacă
pr(eroare) (5.1)
pr ( m ) 1 (5.2)
m U
108
se poate rescrie
pr ( eroare) pr ( x ) (5.3)
{ x |eroare( x )}
unde am adunat probabilităţile tuturor elementelor x pentru care p'(x) este în eroare.
Dar probabil aproximativ corectă? Aceasta înseamnă că probabil sistemul va învăţa
reguli care sunt corecte aproximativ!
Pentru a rezolva această problemă, se presupune că exemplele de instruire folosite
pentru dezvoltarea regulilor sunt alese cu aceleaşi probabilităţi ca cele care apar deja în (5.2).
Se obţin exemple de instruire folosind probabilităţile pr(m) şi apoi se aplică o procedură de
învăţare L pentru a ajunge la un concept învăţat p'.
Dăm acum următoarea definiţie:
pr [pr(eroare)> ] <
3
Noţiune preluată din electronică care în cazul algoritmilor de învăţare reprezintă un set de ipoteze
care folosesc pentru a prezice rezultate având în vedere intrări cu care nu s-a confruntat (Mitchell,
1980)
109
Dat fiind bias-ul restrictiv asupra spaţiului ipotezelor în care lucrăm, presupunem că
exista un total de H concepte posibile. Deoarece fiecare are probabilitatea de cel mult
(1 ) m atât ca să se potrivească cu data, cât şi ca să nu fie aproximativ corectă, rezultă că
probabilitatea ca să existe oricare astfel de q este marginită de:
H (1 )m
H (1 )m (5.4)
Altfel rescris:
ln
H
m (5.5)
ln 1
unde sensul inegalităţii s-a schimbat pentru că ln(1- ) este negativ. Afirmăm că:
ln(1 ) 0 (5.6)
pentru 0 1 . Pentru a vedea asta, se observa ca (5.6) devine 0 daca =0, si derivata lui
(5.6) faţă de , este
1
1
1 1
care este clar negativă pentru 0 1 . Folosind (5.6), rezultă că ln(1 ) şi (5.5)
devine:
H
ln ln
H
m
Teoremă: Orice propoziţie consistentă cu date de instruire este PAC dacă şi numai dacă:
H
ln
m (5.7)
110
Ca un exemplu, să presupunem că folosim bias-ul ca ţintă şi conceptele învăţate sunt
n
conjunctii într-un spaţiu cu n predicate. Deoarece există 3 astfel de conjunctii, (5.7) ne
spune că orice concept acceptabil va fi PAC dacă
n 3
m ln
Există două caracteristici ale teoremei, care sunt importante. Prima este că nu se mai
menţionează distribuţia probabilităţii, care apare în (5.3); (5.7) merge pentru orice distribuţie,
adică aceeaşi distribuţie este folosită atât pentru a defini funcţia de eroare, cât şi pentru a
selecta exemplele de instruire folosite de procedura de învăţat.
A doua caracteristică este legată de numărul de instanţe de instruire, care sunt necesare
în teoremă şi care creşte logaritmic cu numărul de concepte posibile.
Dar cum am putea găsi precis un concept care se potriveşte cu datele din setul de
instruire ? Este clar că examinarea fiecărui concept acceptabil din punct de vedere sintactic
pentru a vedea dacă se potriveşte sau nu, este în general, complet impracticabil.
111
În cazul în care se presupune că un concept este o conjuncţie de literale pozitive, cel
mai bine cunoscut algoritm pentru producerea unui concept acceptabil este algoritmul lui
Mitchell4.
Ideea algoritmului este cel mai bine descrisă prin următorul exemplu. Să presupunem
că lucrăm cu un pachet de cărţi şi încercăm să identificăm un concept conjunctiv necunoscut.
Predicatele în limbaj sunt fapte ca "roşu", "negru", "cupa", "trefla", "carte pară", "carte
impară", ş.a.m.d. Optul de caro este o carte pară, roşie şi de caro. Setul de instruire constă într-
o colecţie de cărţi: pentru fiecare carte, ni se spune dacă este sau nu în setul ţintă.
Cheia algoritmului este observaţia că, setul de concepte conjunctive din acest domeniu
(sau din oricare altul) poate fi parţial ordonat după specificacitate. Astfel conceptul “negru”
este mai puţin specific decât conceptul “negru impar” sau “trefla”. Cele două concepte “negru
impar” si “trefla” sunt incomparabile unul cu altul, din moment ce nici unul nu este mai
specific decât celălalt. “Negru” este mai specific decât “orice carte”; “orice 7” este mai
specific decât “orice carte impară”. O diagramă parţială a setului tuturor conceptelor din
domeniul nostru este arătată în figura 2, cu conceptele mai puţin specifice desenate în partea
superioară a imaginii.
Algoritmul tratează incremental datele. Pe măsură ce lucrează, el reţine o listă cu cele
mai specifice concepte şi una cu cele mai puţin specifice, care sunt consistente cu toate
instanţele de instruire (exemplele), care au fost întâlnite până acum. În cazul în care p1 şi p2
sunt două concepte conjunctive consistente cu exemplele, atunci conjunctia p1 p2 este mai
specifică, dar şi consistentă în acelaşi timp cu exemplele. Aceasta înseamnă că “cel mai
specific concept consistent cu exemplele” este întotdeauna unic.
Spre exemplu, presupunem că exemplele (datele) de instruire arată astfel:
4
Prin conjuncţia unor literale pozitive, înţelegem conceptul obţinut prin conjuncţia unor
predicate fără negaţiile lor.
112
Tabela 1
Carte Este in setul ţintă
A da
7 da
8 nu
9 da
5 nu
K nu
6 nu
7 da
Iniţial, cel mai specific concept consistent cu datele este mulţimea vidă; cel mai puţin
specific concept este mulţimea tuturor cărţilor. Dar când vedem că A este în setul ţintă, cel
mai specific concept este A singur (cuvântul “as” face parte din limbaj); cel mai puţin
specific concept rămâne încă mulţimea tuturor cărţilor. Când învăţăm că 7 este în setul ţintă,
cel mai specific concept este probabil “cărţi negre impare”; cel mai puţin specific concept este
neschimbat.
Acum vom învăţa că 8 nu este în setul ţintă. Există două concepte consistente cel
mai puţin specifice cu aceasta - toate cărţile impare şi toate cărţile negre. Pe măsură ce
continuăm, se observă că exemplele pozitive determină ca cele mai specifice concepte să
devină treptat mai puţin specifice (spre exemplu, cărţile negre şi impare în locul asului de
pică). Exemplele negative determină ca cele mai puţin specifice concepte să devină mai
specifice. Dacă cele două mulţimi converg, rezultatul este în mod garantat conceptul ţintă.
Trebuie notat că algoritmul este util şi înainte ca cele două seturi să se potrivească
exact. Chiar dacă conceptul ţintă nu a fost identificat în mod unic în acest punct, s-a identificat
un grup de concepte care se potrivesc cu exemplele de instruire şi se poate aplica teorema de
mai sus (5.7) pentru a concluziona inductiv că toate aceste concepte sunt probabil aproximativ
corecte . Când algoritmul a identificat precis conceptul, putem concluziona deductiv că a fost
găsit conceptul ţintă, cu condiţia validităţii presupunerii că acest concept este o conjuncţie de
literale pozitive.
Să aruncăm o privire asupra unui alt fel de spaţiu al ipotezelor restrictive (bias). Se
presupune că argumentul x al predicatului este un număr real şi că bias-ul pe care îl alegem
presupune ca p(x ) este de forma x>c sau x<c pentru o anumită constantă c. Un exemplu
tipic este arătat în figura 3, în care conceptul este “toţi x>5.0” şi exemplele de instruire
indicate sunt consistente cu ipoteza x>c pentru orice c (4.2, 5.3).
113
Chiar dacă dimensiunea spaţiului ipotezei (H din teoremă) este infinită, lucru dovedit
de faptul că putem mărgini domeniul valorilor de intrare posibile x, cele m exemple de
instruire selectate aleator fac probabil o bună şi echitabilă trasare a parantezei în punctul de
tranzitie c şi o analogie cu teorema (5.7) poate fi dovedită în acest exemplu - este posibil să se
înveţe PAC în acest domeniu.
Dar dacă în loc de o caracteristică avem mai multe? O idee similară poate fi aplicată în
acest caz. În loc de a diviza linia în două în punctul c, putem diviza un plan în două cu o linie.
Putem diviza un spaţiu tridimensional în două cu un plan, ş.a.m.d. Un spaţiu n-dimensional
poate fi înjumătăţit cu un hiper-plan (n-1) dimensional.
În general, putem modela această operaţie geometrică descriind hiperplanul în termeni
de n coordonate ( h1 , , hn ) şi spunând că un punct ( x1 , , xn ) este în “dreapta”
hiperplanului dacă şi numai dacă
xi hi (5.8)
i
pentru anumite fixate. Există o oarecare redondanţă în această descriere: putem multiplica
atât cât şi toate valorile hi cu o constantă pozitivă fără a afecta (5.8). În figura 4 am desenat
o reprezentare schematică a trei intrări procesate în acest fel pentru a produce o singură ieşire
care poate fi sau 1 sau 0, în funcţie de (5.8) care evident, poate fi asimilata cu o reţea
neuronală.
114
Pentru a ajunge la aceasta, presupunem că prelucrăm intrările nu o dată, ci de mai
multe ori, ca în figura 5 Rezultatele multiplelor iteraţii pot fi ele însele vazute ca intrări ale
altor iteraţii ale formulei (5.8); am desenat schematic rezultatul în figura 6.
Se observă că acum apare dificultatea: fiecare funcţie a intrărilor multiple poate fi
aproximată cu o funcţie de forma descrisă în figură. Mai mult, există algoritmi pentru
învăţarea valorilor folosite pentru apariţiile hi' şi în diverse versiuni ale (5.8), care sunt
folosite la operaţii.
Ce mod minunat ar fi acesta pentru rezolvarea problemelor de AI. Fiind date intrările
unor senzori, sistemul ar putea simplu să înveţe să-şi clasifice acţiunile posibile ca inteligente
sau non-inteligente, iar apoi să acţioneze inteligent. Din nefericire, nu este clar că această
abordare va reuşi - în principiu va avea succes, dar realizarea practică este deja o altă
problemă. Dimensiunile spaţiilor pot fi extraordinar de mari, timpul necesar pentru a învăţa
conceptele poate fi efectiv infinit, practic nu există nici o modalitate de a decide de cât de
multe nivele interne are nevoie reţeaua, ş.a.m.d.
Mai există o tehnică inductivă de învăţare despre care dorim să discutăm este
algoritmul lui Quinlan, cunoscut sub denumirea prescurtată ID3.
Conform prezumpţiei asupra spaţiului ipotezelor facută în ID3, conceptul care se
învaţă poate fi exprimat cu ajutorul unui arbore de decizie, asemănător celui din figura 7.
Revenim la exemplul acela de clasificare al ciupercilor. În cazul de faţă, pentru a clasifica
ciuperca m, se începe prin a determina dacă m este mare sau nu. Dacă m este mare, adică
mare(m) este adevarat, ne mutăm pe partea stângă a arborelui; dacă mare(m) este fals, ne
mutăm pe partea dreaptă a lui.
115
Figura 7. Un arbore de decizie
Apoi, se vor lua în considerare predicate ca: galbenă(m) sau pătată(m), ş.a.m.d. Când
se ajunge într-un nod frunză (terminal) al acestui arbore, ciuperca va fi clasificată ca
otrăvitoare sau nu. În exemplul din figură, arborele de decizie este echivalent cu regulile de
inferenţă incluzând
Nu este greu de observat că arborii de decizie nu sunt deloc amalgamaţi; orice concept
poate fi reprezentat utilizând unul dintre aceştia. Contribuţia adusă de ID3 constă în realizarea
faptului că, există metode efective de a învăţa conceptele în această formă, ca şi domeniile
variantelor care sunt mijloace efective de a învăţa conceptele conjunctive. Odată alese
predicatele folosite pentru a eticheta arcele, restul este relativ uşor - nodurile marginale sunt
uşor de recunoscut deoarece exemplele de instruire care duc la astfel de noduri satisfac toate
conceptul ţintă, sau toate esuează.
În ID3, arcele sunt etichetate astfel încât să-şi poată executa efectiv sarcina de
împărţire a exemplelor de instruire la fiecare nod, în pozitive şi negative. Aceasta înseamnă că
vrem ca fiecare test să împartă setul de exemple de instruire aproximativ în două (dacă ţinta
este “trefle impare” nu e prea mult de testat pentru un 7 de treflă) şi mai vrem ca testele să fie
relevante pentru conceptul ţintă (dacă ţinta este “cărţi impare”, verificarea culorii unei cărţi
constă în împărţirea exactă a exemplelor de instruire pe culori, împărţire necorelată cu
conceptul de învăţat).
Există vreun mod prin care să se definească precis care atribut ar trebui verificat în
oricare punct al arborelui de decizie? Da, există. Matematic este puţin complicat.
Presupunem că avem o mulţime M cu |M| elemente şi vrem să punem întrebări cu
răspunsuri da/nu despre un element particular pentru a determina care este el. M poate fi
mulţimea întregilor mai mici decât 1000 şi despre un întreg x putem întreba “Este mai mare
decât 500?” Sub 750?” ş.a.m.d. Numărul minim de întrebări pe care va trebui să-l punem
este log 2 | M | , deoarece tot timpul trebuie împărţit în două domeniul rămas de posibilităţi.
116
Să presupunem că M este împărţit în două submulţimi, P şi N şi încercăm să deducem
în care din aceste două submulţimi se află x. Câte întrebări sunt necesare pentru a determina
valoarea lui x?
Dacă x P, sunt necesare log 2 | P | întrebări; dacă este în N, sunt necesare
log 2 | N | . Presupunând că probabilitatea ca x P este p p , şi că probabilitatea ca x N
este p n , numărul total de întrebări care trebuie puse pentru a obţine informaţii suplimentare
despre x este în medie
p p log 2 | P | pn log n | N |
Rezultă că acest număr de întrebări poate fi redus ştiind dacă x este în P sau în N
astfel:
Caracteristic pentru această expresie este valoarea ei mai mică decât 1; se poate
oricând întreba: ”Este x în P sau nu?” Dar dacă dimensiunea lui P este mult diferită de a lui
N, stilul “da/nu” nu va fi foarte folositor.
Într-o problemă de clasificare, scopul nu este de a decide exact care element x din
mulţimea M este luat în considerare, ci numai dacă acel element este sau nu o instanţă din
clasa ţinta T (adică o anumită ciupercă este sau nu otrăvitoare). Mai formal, datorită faptului
că se pot pune o sumedenie de întrebări cu răspunsuri “da/nu” (mare sau mică?,galbenă sau
nu?), atunci putem pune o întrebare care să spună cel mai exact dacă x este sau nu în T. Cu
alte cuvinte, punem întrebarea pentru care să nu existe nici o valoare a informaţiei adiţionale
despre faptul că x se găseşte sau nu în T.
Presupunem acum, că avem un subset U M ; se poate partiţiona U în două
submulţimi U U T şi U U T , unde T este clasa ţinta. Conform (5.11),
informaţia câstigată dacă învăţăm despre obiectul considerat că este în T este dată de:
U U U U
I log log (5.12)
U U U U U U U U U
117
satisface f. Câştigul aşteptat al informaţiei despre învăţarea dacă x se găseşte sau nu în T ,
după ce se foloseşte caracteristica f pentru a împărţi pe V în V f şi V f este dat de:
V V
f f
G I I (5.13)
f V V
V V f V V f
f f f f
În practică, desigur, datele de instruire nu vor include informaţii despre toate obiectele
din domeniu, ci numai despre câteva dintre ele. În aceste condiţii, ID3 poate fi folosit pe
construirea descrierii PAC a conceptului ţintă.
118
Unitatea de învăţare 6.
Reţele neuronale.
Cuprins:
6.1. Introducere
Una din problemele cele mai dificile, pe care trebuie să le rezolve inteligenţa
artificială, este generată de necesitatea dominării complexităţii informaţionale a domeniilor
abordate. O posibilă soluţie este oferită în unele cazuri de sistemele expert. Utilizarea acestora
este însă limitată la domenii bine definite, comportamentul unui sistem expert devenind
fragil la frontierele domeniului pentru care a fost realizat.
În cazul unor aplicaţii mult mai complexe, se conturează o alta abordare: Învăţarea
automată, ca un set de metode utilizate în scopul învăţării de către calculator a modului de
rezolvare a unei probleme prin analogie cu anumite cazuri trecute. Acest obiectiv nu este
deloc simplu. Pe de o parte, există mai multe modele de învăţare şi alegerea unui model
potrivit specificului problemei poate fi extrem de dificilă. Pe de altă parte, cu toate că
învăţarea automată este considerată un domeniu al inteligenţei artificiale, multe din tehnologiile
sale nu sunt caracteristice acesteia.
Cercetările în domeniul învăţării automate s-au intensificat în ultimele patru decenii,
iniţial insistându-se mai degrabă asupra modalităţilor de a realiza un sistem care să se
dovedească inteligent, decât asupra modalităţilor prin care acesta să poată învăţa în scopul
îmbunătăţirii propriilor performanţe. Cea mai mare parte a cercetărilor în domeniul
învăţării automate au fost orientate spre definirea unor paradigme ale învăţării (ca domeniu
care constă într-o investigare a principiilor de bază ale inteligenţei), stabilirea unor relaţii
între acestea şi elaborarea algoritmilor care le caracterizează.
Metodele de învăţare corespund unor tehnici relativ diferite: metode de învăţare
inductivă, sisteme de clasificare, reţele neuronale, algoritmi genetici, sisteme de învăţare
119
bazate pe explicaţii. Aceste tehnici au în comun abilitatea de a modifica performanţele
sistemului odată cu câştigarea experienţei. Herbert Simon a caracterizat procesul de învăţare
într-un mod suficient de abstract pentru a permite utilizarea oricăror metode: „ învăţarea
denotă modificări în cadrul sistemului, care sunt flexibile în sensul că ele permit acestuia să
îndeplinească aceleaşi sarcini, extrase din acelaşi domeniu într-un mod mult mai eficient în
viitor”.
Această nouă abordare a sistemelor inteligente presupune construirea de calculatoare
cu o arhitectură şi capacitate de procesare care să imite anumite abilităţi de procesare ale
creierului. Rezultatul îl constituie reprezentările de cunoştinţe bazate pe o importantă
procesare paralelă, pe acumularea rapidă a unor mari cantităţi de informaţii şi pe capacitatea
de a recunoaşte modele pe baza experienţei. Tehnologia care încearcă să obţină aceste
rezultate este numită procesare neuronală sau reţele neuronale.
Preocuparea pentru reţelele neuronale artificiale, denumite în mod curent „reţele
neuronale”, a fost motivată de recunoaşterea faptului că modul în care calculează creierul
fiinţelor vii este complet diferit de cel al calculatoarelor numerice convenţionale.
Spre deosebire de maşinile von Neumann, unde există o unitate de procesare care
execută instrucţiunile stocate în memorie în mod serial, numai o instrucţiune la un moment
dat, reţelele neuronale utilizează în mod masiv paralelismul.
Fiind modele simplificate ale creierului uman, ele deţin capacitatea de a învăţa, spre
deosebire de calculatoarele convenţionale, care rămân totuşi mai eficiente pentru sarcinile
bazate pe operaţii aritmetice precise şi rapide.
Reţelele neuronale nu dispun de unităţi de procesare puternice, dimpotrivă, acestea
sunt caracterizate printr-o simplitate extremă, însă interacţiunile lor pe ansamblu produc
rezultate complexe datorită numărului mare de conexiuni.
Reţelele neuronale sunt tehnologii de prelucrare a informaţiei bazate pe studiile
asupra creierului uman şi a sistemului nervos. Cercetările în domeniu s-au intensificat în
ultimii ani, cunoscând în prezent o mare popularitate, datorită progreselor înregistrate
atât în tehnologia calculatoarelor, cât şi în domeniul neurologiei, în direcţia unei mai bune
înţelegeri a mecanismelor creierului uman.
În timp ce japonezii caracterizează reţelele neuronale ca aparţinând generaţiei a
VI-a de calculatoare, americanii consideră că pot recâştiga poziţia de lider în domeniul
tehnologiilor informaţionale prin realizarea unor sisteme informatice bazate pe procesele
biologice ale creierului uman. Din ce în ce mai mult, în cercetările din domeniul neurologiei,
se caută identificarea principiilor de prelucrare biologică a informaţiei, în scopul aplicării lor
în cadrul unor sisteme artificiale.
Pentru a înţelege mai bine această abordare, trebuie precizat modul de funcţionare al
sistemului nervos.
Capacitatea de a învăţa şi a reacţiona la schimbările din jurul nostru, necesită
inteligenţă. Gândirea şi comportamentul inteligent sunt controlate de creier şi de sistemul
nervos central. Încercarea de a înţelege modul în care creierul uman poate gestiona într-o
manieră atât de eficientă, o enormă cantitate de cunoştinţe, porneşte de la analiza neuronilor,
ca elemente fundamentale ale sistemului nervos central.
Constituienţii structurali ai creierului sunt neuronii, conectaţi prin sinapse. Se
estimează că în cortexul uman există circa 10 miliarde de neuroni şi 60 de trilioane de sinapse.
Trebuie precizat însă că neuronii nu sunt cele mai numeroase celule din creier. Celulele gliale
sunt de 10 ori mai multe. În mod tradiţional, se considera că acestea au numai funcţii de
120
nutriţie şi protecţie, însă în ultimul timp au demarat cercetări privitoare la influenţa lor
potenţială asupra activităţii de procesare a neuronilor.
Structura biologică a unui neuron (figura 6.1.) include:
nucleul (corpul celular);
axonul (ieşirea din celula neuronală);
dendritele ( intrările în celula neuronală).
Dendritele (numite astfel datorită asemănării cu un copac, „dendron” în greacă) sunt
„intrările” neuronului, fibre scurte ramificate, de câţiva milimetri, care primesc impulsuri.
Axonul („axōn”, axă), „ieşirea”, este o fibră mai lungă, de câţiva centimetri putând
ajunge însă la 1-1,5 metri. Fiecare neuron are un singur axon şi mai multe (10-20) de dendrite.
Conexiunile dintre neuroni se realizează într-un spaţiu numit sinapsă. Acestea sunt
unităţi structurale şi funcţionale elementare care mediază interacţiunile dintre neuroni. Tipul
cel mai răspândit de sinapsă este sinapsa chimică, ce operează astfel: un proces presinaptic
eliberează o substanţă transmiţătoare, care difuzează peste joncţiunea sinaptică dintre neuroni
şi apoi acţionează asupra unui proces postsinaptic. Astfel, o sinapsă converteşte un semnal
electric presinaptic într-un semnal chimic (ioni de sodiu şi potasiu) şi apoi din nou într-un
semnal electric postsinaptic.
În descrierile tradiţionale ale organizării neuronale, se consideră că o sinapsă este o
conexiune simplă care poate impune excitare sau inhibare, dar nu ambele, neuronului
receptor. Ambele efecte sunt locale; ele se propagă pe o distanţă mică în corpul celulei şi sunt
însumate la nivelul axonului. Dacă suma potenţialelor de excitare depăşeşte un anumit prag,
atunci neuronul este activat şi transmite un impuls mai departe.
Fiecare neuron primeşte impulsuri electrice prin intermediul dendritelor sale. Dacă
aceste impulsuri sunt suficient de puternice, axonul va transmite un impuls electric în vederea
excitării diferiţilor neuroni conectaţi care, în funcţie de intensitatea semnalului primit, vor fi
activaţi la rândul lor. Semnalele pot fi transmise nemodificate sau pot fi alterate de sinapse.
O sinapsă este capabilă să intensifice sau să diminueze puterea de conecţie, provocând
excitarea sau inhibarea neuronului respectiv. Abordarea conexionistă în informatică se
bazează pe acest model biologic.
Cea mai importantă trăsătură a reţelei neuronale biologice este plasticitatea. Ca
răspuns la stimulările primite, la nivelul conexiunilor se produc schimbări pe termen lung,
astfel încât conexiunile care ajută la obţinerea de rezultate pozitive sunt întărite, iar cele care
121
determină rezultate nedorite sunt slăbite. De asemenea, neuronii pot forma în timp noi
conexiuni cu alţi neuroni. Aceste mecanisme stau la baza capacităţii de adaptare a creierului la
stimulii primiţi, pe care o numim în mod convenţional învăţare.
122
- Cunoştinţele sunt căpătate de reţea printr-un proces de învăţare;
- Cunoştinţele sunt depozitate nu în unităţile de procesare (neuroni), ci în conexiunile
interneuronale, cunoscute drept ponderi sinaptice.
Procedura folosită pentru a executa procesul de învăţare se numeşte algoritm de
învăţare, funcţia căruia este de a modifica ponderile sinaptice ale reţelei într-un stil sistematic
pentru a atinge obiectivul dorit de proiectare. Printre numeroasele proprietăţi interesante ale
unei reţele neuronale, cea mai semnificativă este abilitatea acesteia de a învăţa prin
intermediul mediului înconjurător, şi prin aceasta să-şi îmbunătăţească performanţele;
creşterea performanţelor are loc în timp şi conform cu unele reguli prestabilite.
O reţea neuronală îşi învaţă mediul printr-un proces iterativ de ajustări aplicate
conexiunilor şi pragurilor sale sinaptice. În mod ideal, reţeaua devine mai „inteligentă” după
fiecare iteraţie a procesului de învăţare.
În contextul reţelelor neuronale vom defini astfel învăţarea: un proces prin care
parametrii variabili ai unei reţele neuronale se adaptează prin continua stimulare din partea
mediului în care este inclusă. Tipul de învăţare este determinat de modul în care au loc
schimbările parametrilor. Aşadar, învăţarea în contextul unei reţele neuronale se
caracterizează prin următoarele elemente:
- Reţeaua neuronală este stimulată de un mediu;
- Reţeaua neuronală suferă schimbări datorită acestor stimulări;
- Reţeaua neuronală răspunde în mod diferit mediului datorită schimbărilor care au
apărut în structura sa internă.
Cu toate că asemănarea între sistemul nervos biologic şi reţelele neuronale artificiale
este relativ mică, reţelele neuronale artificiale prezintă un număr surprinzător de caracteristici
ale creierului. De exemplu, acestea pot învăţa din experienţă, generaliza din anumite exemple
altele noi şi sintetiza caracteristicile esenţiale din intrări ce conţin şi date irelevante. Un mare
avantaj al reţelelor neuronale este că pot să descrie o problemă şi să o rezolve în acelaşi timp,
prin auto-organizarea lor şi nu prin programul explicit. Acest proces de auto-organizare are
loc pe parcursul învăţării datorate topologiei iniţiale, unor reguli de învăţare şi unui număr
mare de antrenamente.
Caracteristicile cele mai importante ale reţelelor neuronale sunt:
- Capacitatea de a învăţa: Reţelele neuronale artificiale nu necesită programe
puternice ci sunt mai degrabă rezultatul unor antrenamente asupra unui set de date.
Reţelele neuronale artificiale au un algoritm de învăţare, după care ponderile
conexiunilor sunt ajustate pe baza unor modele prezentate. Cu alte cuvinte, reţelele
neuronale învaţă din exemple, la fel cum învaţă copiii să recunoască un obiect pe baza
mai multor instanţe ale acelui tip de obiect
- Capacitatea de generalizare: Dacă au fost instruite corespunzător, reţelele sunt
capabile să dea răspunsuri corecte şi pentru intrări diferite faţă de cele cu care au fost
antrenate, atâta timp cât aceste intrări nu sunt foarte diferite;
- Capacitatea de sinteză: Reţelele neuronale artificiale pot lua decizii sau trage
concluzii când sunt confruntate cu informaţii afectate de zgomot, irelevante sau
parţiale.
Datorită acestor trăsături ale prelucrării informaţiei, reţelele neuronale pot rezolva
probleme complexe care sunt dificil de abordat prin metode clasice. Cu toate acestea,
cercetătorii recunosc că mai au un drum lung de parcurs până vor ajunge să construiască un
calculator care să imite creierul omenesc. „Inteligenţa” la care au ajuns în prezent cele mai
sofisticate reţele neuronale este sub nivelul gândirii unui copil de câţiva ani. Cu toate acestea
nu trebuie minimizată sau ignorată importanţa reţelelor neuronale artificiale şi este posibil ca
pe viitor, cu ajutorul lor să se ajungă la o cunoaştere mai aprofundată a fenomenelor ce au loc
123
în creierul uman. Ceea ce recomandă reţelele neuronale artificiale este raportul favorabil
performanţă-complexitate, aflat într-o continuă creştere şi care este superior sistemelor de
inteligenţă artificială implementate prin alte tehnologii.
Începutul reţelelor neuronale artificiale este legat de problema clasificării unor obiecte
definite de o serie de atribute. Cel mai simplu model era funcţia ŞI logic între anumite atribute
(prezente sau absente), care să determine o anumită clasă. Totuşi, unele clase pot avea atribute
comune, iar unele valori, în cazul în care provin dintr-un mecanism perceptual, pot fi afectate
de zgomot. Soluţia s-a bazat pe faptul de bun simţ că unele atribute sunt mai importante decât
altele pentru determinarea unei anumite clase. O clasă era determinată dacă sumarea valorilor
ponderate depăşea un anumit prag, în bună concordanţă cu legea biologică „totul sau nimic”
(dacă un impuls nu depăşeşte un prag minim, el nu produce nici un răspuns).
Neuronii artificiali sunt elemente de procesare neliniare, care operează în paralel. Prin
analogie cu neuronul biologic, fiecare neuron artificial va recepţiona una sau mai multe
intrări, le va prelucra şi va furniza o singura ieşire, care se poate conecta la intrările mai
multor neuroni.
Fiecare intrare corespunde unui singur atribut. De exemplu, dacă problema constă
în a decide asupra acordării unui credit, atributul poate constitui un nivel de activitate, un tip
de garanţie etc. Valoarea numerică a atributului va deveni o intrare în reţea. Se pot utiliza
diferite tipuri de date drept intrări, dar în cadrul reţelei se pot prelucra doar date numerice. În
cazul în care sunt necesare atribute calitative, acestea vor fi transformate în echivalente
numerice. Ieşirea unui element de procesare poate constitui rezultatul final sau poate deveni
intrare într-un alt proces de prelucrare. Pentru exemplul anterior, soluţia problemei
(ieşirea care constituie rezultatul final) poate fi „da” sau „nu”. Reţeaua va atribui valori
numerice de exemplu 1 pentru „da” şi 0 pentru „nu”, scopul constând în evaluarea valorilor
rezultatului obţinut.
Fiecărei intrări îi este asociată o pondere, care reprezintă importanţa relativă a
acesteia. Modalitatea prin care reţeaua „invaţă” este repetata ajustare a acestor ponderi.
Elementul de prelucrare (neuronul) calculează suma ponderată a intrărilor sale, fiind activat
doar dacă această sumă depăşeşte un anumit prag, numit „prag de activare”.
Warren McCulloch şi Walter Pitts (1943) au propus un model, care rămâne până în
prezent fundamentul structural pentru majoritatea reţelelor neuronale numit perceptron, o
„reţea” cu un singur neuron, la fel ca aceea din figura 6.2.
124
Fiecărei conexiuni îi corespunde o valoare reală, numită pondere sinaptică, care
determină efectul intrării respective asupra nivelului de activare a neuronului. Suma ponderată
a intrărilor poartă denumirea de intrare netă (în engleză, „net input”). În figură, x j reprezintă
intrările, w j ponderile sinaptice, f o funcţie de activare, valoarea prag iar y ieşirea, care se
calculează după formula:
n
y f wi xi
i 1
0 X
-1
125
Dacă eroarea e este pozitivă, trebuie să mărim y ; dacă este negativă, y trebuie
micşorat. Având în vedere că fiecare intrare are contribuţia xi wi , atunci dacă xi este
pozitivă, o creştere a ponderii wi va avea ca efect o creştere a ieşirii perceptonului. Invers,
dacă xi este negativă, creşterea ponderii wi va determina scăderea ponderii y . De aici poate
fi stabilită regula de învăţare a perceptonului:
wi ( p 1) wi ( p ) e( p ) xi ( p ) ,
unde (0,1) este numită rata de învăţare.
În prezent, funcţiile cele mai des utilizate sunt sigmoida unipolară (sau logistică):
1
f ( x) x
1 e
kx
1 e
f ( x) kx
, k 0
1 e
0 X
-1
126
Se poate constata că funcţiile sigmoide se comportă aproximativ liniar pentru valori
absolute mici ale argumentului şi se saturează, preluând oarecum rolul de prag, pentru valori
absolute mari ale argumentului. S-a demonstrat (Cybenko, 1989) că o reţea (posibil infinită)
cu un singur strat ascuns este capabilă să aproximeze orice funcţie continuă. Astfel se justifică
proprietatea perceptronului multistrat de aproximator universal. De asemenea, aplicând
teorema Stone-Weierstrass în domeniul reţelelor neuronale, s-a demonstrat că acestea pot
calcula anumite expresii polinomiale: dacă există două reţele care calculează exact două
funcţii f1, respectiv f2, atunci există o reţea mai mare care calculează exact o expresie
polinomială de f1 şi f2.
*altă structură
reiniţializare
Implementare
127
6.4.1. Colectarea datelor.
128
pătratice medii dintre ieşirea reală şi cea dorită cu ajutorul unei metode de tip gradient
descendent numită coborârea cea mai abruptă (engl. “steepest descent”). Actualizarea
ponderilor se face după aceeaşi formulă ca la perceptron, cu precizarea că eroarea e are acum
valori reale. Din punctul de vedere al comportamentului, spre deosebire de perceptron, adaline
converge repede şi învăţarea este în general stabilă chiar în probleme de clasificare
neseparabile liniar. Dezavantajul său principal este faptul că nu poate garanta separarea celor
două clase, chiar dacă acestea sunt liniar separabile.
Widrow a generalizat modelul la o arhitectură cu mai multe straturi numită madaline
(“many adalines”). Aceasta constă dintr-un strat de neuroni adaline care pot fi antrenaţi şi ale
căror ieşiri sunt conectate într-un al doilea strat, stratul de ieşire, format din neuroni care
funcţionează ca porţi logice: ŞI, SAU sau vot majoritar. Ponderile neuronilor din acest strat de
ieşire nu sunt antrenabile, ci fixate, ceea ce conduce la clasificarea arhitecturii madaline tot ca
o reţea cu un singur strat.
Reţelele multinivel au apărut din încercările de rezolvare a problemelor neseparabile
liniar şi au condus la diverse variante privind numărul de straturi de neuroni şi funcţiile de
activare utilizate şi sunt alcătuite dintr-un nivel al neuronilor de intrare, un nivel al neuronilor
de ieşire şi unul sau mai multe nivele intermediare (numite şi nivele ascunse). Un neuron va
putea să-si transmită rezultatul unui alt neuron, situat pe un nivel superior; setul de intrări în
reţea fiind stabilit, rezultatul va fi furnizat în urma parcurgerii succesive a tuturor nivelelor
acesteia. Perceptronul multistrat este tipul de reţea neuronală cel mai cunoscut şi mai des
folosit. De cele mai multe ori, semnalele se transmit în interiorul reţelei într-o singură direcţie:
de la intrare spre ieşire; nu există bucle, ieşirea fiecărui neuron neafectând neuronul respectiv.
Această arhitectură se numeşte cu propagare înainte (engl. “feed-forward”).
Straturile care nu sunt conectate direct la mediu se numesc ascunse. Există în literatura
de specialitate o controversă privind considerarea primului strat (de intrare) ca strat propriu-
zis în reţea, de vreme ce singura sa funcţie este transmiterea semnalelor de intrare spre
straturile superioare, fără a face vreo prelucrare asupra intrărilor. În cele ce urmează, am ales
să numărăm numai straturile formate din neuroni propriu-zişi, însă spunem că intrările sunt
grupate în stratul de intrare.
Dezavantajul principal al acestei structuri ii constituie timpul de învăţare, care sporeşte
odată cu numărul nivelelor intermediare.
129
În cadrul reţelelor cu două nivele, fiecare neuron aparţinând nivelului de intrare va fi
conectat cu fiecare neuron aparţinând nivelului de ieşire; neuronii nivelului de ieşire .vor
modifica valorile furnizate de neuronii nivelului inferior, atribuindu-le diverse ponderi.
În funcţie de arhitectură reţelele neurale se împart în 2 categorii:
a) reţele de tipul feed-forward în care grafurile nu au salturi înapoi.
b) reţele recurente în care apar salturi înapoi din cauza conexiunilor feedback.
În cazul cel mai răspândit al reţelelor de tipul feed forward (numite şi perceptron
multilayer) neuronii sunt organizaţi pe mai multe nivele care au legături unidirecţionale între
ei.
Diversele modalităţi de conectare conduc la diverse comportamente. Vorbind la modul
general reţelele de tipul feed forward sunt statice deoarece produc acelaşi set de valori de
ieşire şi nu o secvenţă de valori pentru o intrare dată. Reţelele de tipul feed forward sunt fără
memorie în sensul că răspunsul acestora la o intrare este independent de starea anterioară a
reţelei. Reţelele recurente sunt sisteme dinamice. Când este prezentat un nou model de intrare
sunt calculate ieşirile neuronului. Datorită căilor de feedback intrările fiecărui neuron sunt
modificate ceea ce conduce reţeaua către o nouă stare. Arhitecturi diferite ale reţelei necesită
algoritmi de învăţare specifici.
130
informaţii a priori în acest sens. Nu există, în acest caz, posibilitatea determinării anterior
procesului de învăţare a valorilor ieşirilor asociate unei clase a intrărilor.
De cele mai multe ori, reţelele neuronale care utilizează această paradigmă de învăţare
sunt foarte simple, cu un singur strat. Neexistând un instructor, reţeaua trebuie să se auto-
organizeze în conformitate cu unele reguli interne ca răspuns la stimulii din mediul extern.
Învăţarea hibridă combină învăţarea supervizată cu cea nesupervizată. O parte din
ponderi sunt determinate prin învăţare supervizată iar cealaltă este obţinută prin învăţare
nesupervizată.
Teoria învăţării trebuie să rezolve trei probleme fundamentale asociate cu învăţarea
din exemple: capacitatea, complexitatea exemplelor şi complexitatea computaţională.
Capacitatea se referă la numărul pattern-urilor care pot fi stocate precum şi la funcţiile şi
deciziile pe care o reţea trebuie să le ia.
Complexitatea mostrelor determină numărul modelelor de antrenament necesare
pentru antrenarea reţelei pentru a garanta o bună generalizare. În acest caz reţeaua se descurcă
bine numai în cadrul setului de date de antrenament dar foarte slab pe alte modele de test
extrase din aceeaşi distribuţie precum modelele de antrenament.
Complexitatea computaţională se referă la timpul necesar unui algoritm de învăţare
pentru a estima o soluţie dintre modelele de antrenament. Mare parte din algoritmii de
învăţare existenţi au o complexitate computaţională ridicată. Proiectarea unor algoritmi
eficienţi pentru învăţare în cadrul reţelelor neurale este o ramură de cercetare foarte activă.
Există patru tipuri de bază de reguli de învăţare: corecţia erorilor, Boltzmann, Hebian
şi învăţarea concurenţială (competitive learning)
În cazul de învăţare supervizată reţelei i se atribuie o ieşire dorită pentru fiecare pattern
de intrare. În timpul procesului de învăţare ieşirea „y” generată de reţea e posibil să fie diferită
de ieşirea dorită „d”. Principiul de bază al regulilor de învăţare este folosirea semnalului de
eroare (d-y) în scopul modificării ponderilor pentru reducerea graduală a erorii.
Regula de învăţare a perceptronului se bazează pe principiul de corecţie a erorii. Un
perceptron constă dintr-un neuron cu ponderi ajustabile wj, j=1,2,...,n şi pragul u. Dându-se un
n
vector de intrare X=(x1, x2,...,xn)t intrarea reţelei în neuron este v= xi wi u.
i 1
Ieşirea perceptronului este 1 daca v>0 şi 0 altfel. Într-o problemă de clasificare în două
clase perceptronul clasifică un model de intrare într-o clasă dacă y=1 şi în cealaltă clasă dacă
n
y=0. Ecuaţia liniară xi wi u 0 defineşte limita de decizie (un hiperplan în spaţiul de
i 1
131
Algoritmul de învăţare „back-propagation” se bazează tot pe principiul corecţiei
erorilor.
Maşinile Boltzman sunt reţele recurente simetrice formate din unităţi binare (+1 pentru
„on” şi -1 pentru „off”). Prin simetrie se înţelege că ponderea conexiunii de la i la j este egală
cu ponderea conexiunii de la j la i (Wij=Wji). Un subset de neuroni „vizibili” interacţionează cu
mediul în timp ce ceilalţi, ascunşi nu interacţionează cu mediul. Fiecare neuron este o unitate
stochastică care generează o ieşire sau stare conform cu distribuţia Boltzman a mecanicii
statistice. Maşinile Boltzman operează în două moduri: fix, în care neuronii vizibili sunt
stabiliţi în stări specifice determinate de mediu iar cel de-al doilea mod liber, în care atât
neuronii vizibili cât şi cei ascunşi operează liber.
Învăţarea de tip Boltzmann este o regulă de învăţare stocastică derivată din teoria
informaţiei şi din principiile termodinamice. Obiectivul învăţarii de tip Boltzmann este
ajustarea ponderilor conexiunilor aşa încât stările unităţilor vizibile satisfac o anumită
distribuţie a probabilităţii dorită. În conformitate cu regulile de învăţare Boltzmann
schimbarea ponderii Wij a unei conexiuni este dată de:
unde n este rata de învăţare iar P 'ij şi Pij sunt corelaţii între stările unităţilor i şi j unde reţelele
operează în modul fix respectiv în modul liber. Valorile lui P 'ij şi Pij sunt de obicei estimate
din experimentele Monte Carlo care însă sunt extreme de încete.
Învăţarea de tip Boltzmann poate fi văzută ca un caz special al învăţarii prin corecţia
erorii în care eroarea este măsurată nu ca diferenţă directă între corelaţiile dintre ieşirile dorite
şi cele actuale, dar ca diferenţă între corelaţii dintre ieşirile a doi neuroni în condiţii de operare
fixă şi liberă.
Cea mai veche regulă de învăţare este postulatul de învăţare al lui Hebb care se
bazează pe următoarea observaţie din experimentele neurobiologice: Dacă neuronii din
ambele părţi ale unei sinapse sunt activaţi sincron şi repetat puterea sinapsei este mărită
selectiv.
Matematic regula Hebbian poate fi descrisă ca:
Wij(t+1)=Wij(t)+nYi(t)Xi(t).
Unde Xi şi Yi sunt valorile de ieşire ale neuronilor i şi j care sunt conectaţi de sinapsa
Wij iar n este rata de învăţare. De observat că Xi este intrarea în sinapsă.
O proprietate importantă a acestei reguli este că învăţarea se face local, aceasta
înseamnă că schimbarea în ponderea sinapsei depinde numai de activitatea celor doi neuroni
132
conectaţi de aceasta. Aceasta simplifică semnificativ complexitatea circuitului de învăţare
într-o implementare VLSI.
Spre deosebire de învăţarea hebbian (în care mai multe unităţi de ieşire pot fi
sincronizate) unităţile de ieşire de învăţare competitivă concurează între ele pentru activare,
aşa încât numai o unitate de ieşire este activă la un anumit moment dat. Acest fenomen este
cunoscut ca „câştigătorul ia totul” De remarcat că s-a descoperit că învăţarea competitivă
există în reţelele neurale biologice.
Învăţarea competitivă de obicei grupează sau categoriseşte datele de intrare. Modelele
similare sunt grupate de către reţea şi reprezentate printr-o singură unitate. Gruparea se face
automat bazându-se pe corelaţia datelor.
Cea mai simplă reţea de învăţare competitivă constă într-un singur nivel de unităţi de
ieşire precum este expus în figura de mai jos.
Fiecare unitate de ieşire i din reţea se conectează la toate unităţile de intrare X 'j S prin
ponderile Wij, j=1,2,...,n. Fiecare unitate de ieşire se conectează de asemenea către toate
celelalte ieşiri prin ponderi inhibitoare dar are un feedback propriu cu o pondere excitantă. Ca
rezultat al competiţiei numai unitatea i ' cu cea mai mare sau cea mai mică intrare de reţea
devine câştigătoare, asta înseamnă că Wi' X Wi X , i sau ||Wi’-X|| ||Wi-X|| i . Când toţi
vectorii ponderilor sunt normalizaţi cele două inegalităţi devin echivalente. O regulă simplă de
învăţare competitivă poate fi formulată astfel:
133
De observat că numai ponderile unităţii câştigătoare sunt actualizate.
Efectul acestei reguli de învăţare este de a muta modelul stocat în unitatea câştigătoare
(ponderile unităţii) un pic mai aproape de modelul de intrare.
Unul dintre cei mai utilizaţi algoritmi de învăţare este algoritmul de propagare înapoi
(backpropagation). Este un algoritm supervizat, aplicat în special reţelelor feedfoward (în care
nu există conexiuni între rezultatul furnizat de un neuron şi un alt neuron situat pe acelaşi
nivel sau pe un nivel anterior).
134
Forma cea mai generală a algoritmului:
135
generalizează automat ca urmare a structurii lor, şi nu pe baza unui program special creat în
acest scop.
Adaptabilitatea este o altă caracteristică a reţelelor neuronale, ele fiind capabile să
înveţe şi în cadrul unor medii noi, să ia decizii sau să tragă concluzii când sunt confruntate
cu informaţii complexe, irelevante sau parţiale.
Un alt avantaj îl constituie posibilitatea de a obţine aproape instantaneu soluţia unei
probleme (pentru anumite tipuri de reţele), fiind suficientă în acest scop o simplă parcurgere a
reţelei.
În ceea ce priveşte limitele reţelelor neuronale, ele nu constituie o alternativă
eficientă în domeniile consacrate tehnologiilor convenţionale .
Reţelele neuronale nu oferă posibilitatea justificării soluţiilor obţinute (ca în cazul
sistemelor expert), deoarece ajustarea ponderilor nu oferă interpretări facile, iar în ceea
ce priveşte recunoaşterea modelelor este foarte dificil să explici logica din spatele deciziilor.
Procesarea neuronală necesită cantităţi mari de date de testare şi pregătire şi în
unele cazuri timpul de antrenare poate deveni excesiv.
Cu toate aceste limite, reţelele neuronale sunt privite din ce în ce mai mult ca o soluţie
pertinentă pentru tot mai multe tipuri de aplicaţii, ţinând cont şi de raportul favorabil
performanţe/complexitate, care este în continuă creştere, fiind mult mai mare decât cel al
sistemelor inteligenţei artificiale implementate cu ajutorul altor tehnologii. Procesarea
neuronală constituie o alternativă pentru celelalte tehnologii ale inteligenţei artificiale în
domeniile în care datele sunt variate, incomplete, prezentând un înalt grad de
interdependenţă sau în care diverse ipoteze trebuie evaluate simultan. Nu trebuie ignorată
nici posibilitatea combinării acestei tehnologii cu alte aplicaţii soft (sisteme expert, baze de
date) în scopul realizării unor sisteme hibrid pentru automatizarea rezolvării unor probleme
complexe.
Atât reţelele neuronale, cât şi sistemele expert constituie aplicaţii ale inteligenţei
artificiale şi nu trebuie privite ca tehnologii care se află în competiţie, chiar dacă în anumite
cazuri utilizarea reţelele neuronale se poate dovedi mai eficientă comparativ cu sistemele
expert. Mai mult decât atât, caracteristicile celor doua tehnologii sunt atât de diferite, încât ele
se pot completa una pe alta în anumite situaţii. în timp ce sistemele expert presupun o
abordare logică, simbolică reţelele neuronale utilizează procese numerice, asociative în scopul
imitării modelelor sistemelor biologice.
Reţelele neuronale pot constitui o alternativă în reprezentarea cunoştinţelor în cadrul
unui sistem expert, principalul dezavantaj constituindu-1 în acest caz opacitatea acestui
formalism, cunoştiinţele fiind reprezentate într-o maniera implicită.
Un domeniu în care reţelele neuronale pot fi mult mai bine utilizate îl constituie
achiziţionarea cunoştinţelor pentru un sistem expert. Cercetările privind psihologia cunoaşterii
şi a comunicării au confirmat ideea conform căreia învăţarea este necesară nu doar pentru a
interpreta faptele, ci şi pentru a le percepe. De asemenea, practica realizării sistemelor expert
a demonstrat că achiziţionarea cunoştinţelor reprezintă una din problemele cele mai delicate în
cadrul acestui proces. Pe de o parte, expertul uman întâmpină serioase dificultăţi în
exprimarea cunoştinţelor sale în termeni uşor de exploatat. Pe de altă parte, structurarea
cunoştinţelor devine o sarcină tot mai dificilă pentru cognitician, mai ales atunci când acestea
au un caracter evolutiv, fiind necesare numeroase revizuiri ale bazei de reguli.
136
Caracteristici Sisteme expert Reţele neuronale
Abordare simbolică numerică
Raţionament logic asociativ
Operaţii mecanice biologice
Explicaţii da nu
Procesare secvenţială paralelă
Sistem închis autoorganizare
Validare şi verificare dificilă rapidă
Prelucrează cunoştiinţe date
Menţinere dificilă facilă
137
aproximări a funcţiei necunoscute. Diverse probleme de modelare ştiinţifică necesită
aproximarea funcţiilor.
Predicţie. Fiind dat un set de n valori {y(t 1 ), y(t 2 ), …, y(t n )} într-o secvenţă de
timp de la t 1 la t n , se cere prezicerea valorii y(t n+1 ) la momentul t n+1 . Predicţia are un
impact semnificativ în luarea deciziilor în afaceri şi ştiinţă.
Optimizare. O mare varietate de probleme în ştiinţă matematică medicină,
economie pot fi considerate probleme de optimizare. Scopul unui algoritm de
optimizare este de a găsi soluţii care să satisfacă un set de constrângeri aşa încât o
funcţie obiectiv să fie maximizată sau minimizată. Un exemplu clasic îl reprezintă
problema comis voiajorului.
Memorie adresabilă pe baza conţinutului. În modelul computaţional von
Neumann o locaţie de memorie este accesată numai prin adresa acesteia care este
independentă de conţinutul acesteia. Mai mult dacă se face o mică eroare în calculul
adresei de memorie se va accesa un element total diferit. Memoria asociativă sau
memoria adresabilă prin conţinut precum reiese chiar din nume poate fi adresată prin
conţinut. Conţinutul memoriei poate fi obţinut chiar prin introducerea unor date de
intrare incomplete sau distorsionate. Memoria asociativă este foarte utilă în construirea
bazelor de date cu informaţii multimedia.
Control. Să considerăm un sistem dinamic definit prin perechea {u(t), y(t)} unde u(t)
este intrarea de control iar y(t) este ieşirea corespunzătoare a sistemului la momentul t. În
modelul de referinţă adaptive-control scopul este generarea intrării de control u(t) astfel încât
sistemul să urmeze traiectoria dorită determinată de modelul referinţă. Un exemplu este
controlul vitezei de relanti al unui motor.
Alte aplicaţii ale reţelelor neuronale. Deoarece reţelele neuronale sunt cele mai bune
în identificarea şabloanelor sau a tendinţelor în date, ele sunt folosite pentru predicţii sau
estimări în: estimarea vânzărilor, controlul proceselor industriale, căutarea clienţilor sau a
pieţelor de desfacere, validarea datelor, managementul riscului, prospectarea pieţii.
Reţelele neuronale sunt folosite şi în alte domenii importante ca: recunoaşterea vocii,
diagnosticarea bolilor, recuperarea unei convorbiri din cauza unui soft defect, interpretarea
sensurilor multiple ale cuvintelor chinezeşti, detectarea minelor marine, analiza textelor,
recunoaşterea obiectelor tri-dimensionale, recunoaşterea scrisului de mână, recunoaşterea
amprentelor, recunoaşterea feţei.
Reţelele neuronale în medicină. În domeniul medicinei există aplicaţii privind:
modelarea corpului uman, identificarea maladiilor din diferite explorări (EKG, RMN, ECO),
aplicaţii în sistemele biomedicale, modelarea şi dignosticul sistemului cardiovascular,
potenţiale aplicaţii ţn telemedicină.
O aplicaţie ce datează din anii 80 este numită "instant physician" antrenată printr-o
reţea neuronală cu memorie asociativă pentru a memora un număr mare de de înregistrări
medicale fiecare din acestea incluzând informaţii despre simptome, diagnostice şi tratamente
pentru diverse cazuri particulare. După antrenament i se prezintă reţelei ca intrare un caz
printr-un set de simptome; ea va căuta cel mai adecvat şablon memorat care să reprezinte " cel
mai bun" diagnostic şi tratament.
Reţelele neuronale în afaceri. În afaceri reţelele neuronale îşi găsesc aplicarea în:
analize financiare, planificarea şi alocarea resurselor, exploatarea bazelor de date prin
intermediul unor şabloane, marketing (spre exemplu, marketingul controlului rezervării
locurilor pentru companiile aeriene), evaluarea creditelor.
138
6.8. Direcţii de cercetare în cadrul reţelelor neurale.
În ultimii ani au fost aduse multe contribuţii care arată ce probleme pot fi rezolvate în
principiu de către reţelele neurale. Susţinerea plauzibilităţii biologice a fost treptat abandonată
în favoarea reţelelor care rezolvau anumite probleme.
Optimizarea proiectării reţelelor neurale. Proiectarea unei reţele neurale făcută în
funcţie de nivelul de cunoaştere al proiectantului nu mai reprezintă o situaţie satisfăcătoare.
De asemenea ar trebui observat că în cele mai multe aplicaţii curente componenta neurală
constă într-un singur sau într-un număr mic de module neurale de obicei de mărime şi
complexitate moderată. Este surprinzător cum sisteme aşa mici pot să îndeplinească cu succes
sarcini complicate. Putem astfel să apreciem la ce ne putem aştepta dacă reuşim să înţelegem
şi să folosim sisteme neurale mai aproape de nivelul de complexitate pe care-l observăm chiar
la sistemele neurale biologice simple. Există 3 metode care abordează această problemă.
Algoritmi genetici şi evoluţionişti care pot fi folosiţi pentru antrenarea reţelei dar şi
pentru a evolua structuri de reţele din populaţii de reţele.
Abordări incrementale în care se porneşte cu reţele foarte mici care cresc până este
îndeplinit un criteriu anume
Abordări de reducere metode opuse celei de deasupra, precum neuro-chirurgia
optimă în care ponderile sau nodurile care nu sunt necesare sunt eliminate dintr-o reţea
iniţială supradimensionată.
Observaţie. Dezvoltarea de sisteme hibride deşi mai multe proiecte pot fi transformate
cu succes în aplicaţii, numărul de reţele neurale folosite în aplicaţii este mic. De obicei
folosirea reţelelor neurale nu conduce la îmbunătăţiri substanţiale a performanţelor aşa încât
nu trebuie abandonate tehnicile folosite în prezent. Aşadar dacă dorim aplicaţii practice
trebuie să acceptăm că reţelele neurale sunt folosite numai pentru rezolvarea sarcinilor
complexe. Din moment ce există o lipsă de metode pentru antrenarea sistemelor mari,
problemele trebuie descompuse în părţi mai mici. De fiecare dată când există cunoştinţe
explicite sau metode exacte acestea trebuie folosite pentru a reduce complexitatea. De fiecare
dată când descompunerea este prea complexă sau nu sunt disponibile cunoştinţe exacte despre
procesul de bază, reţelele neurale trebuie luate în calcul, lucru care necesită o strânsă
cooperare între experţi din diverse domenii.
În concluzie, lumea computerelor are avantaje imense din folosirea reţelelor neuronale.
Abilitatea reţelei de a învăţa din exemple o face foarte flexibilă şi puternică. Reţelele
neuronale au contribiţii importante şi în alte domenii de cercetare cum ar fi neurologia şi
psihologia.Există diferite aplicaţii privind modelarea comportamentelor organismelor vii şi
investigarea mecanismelor interne ale creierului uman. Reţelele neuronale îşi dovedesc în
principal utilitatea în rezolvarea unor probleme dificile, cum sunt cele de estimare, identificare
şi predicţie sau de optimizare complexă. Datorită independenţei efectuării operaţiilor din
interiorul componentelor faţă de celelalte componente din sistem, modelele conexioniste au
un potenţial mare de paralelism. Modul de memorare şi procesare a datelor diferenţiază
reţelele neuronale artificiale de programele clasice, care urmează instrucţiunile într-o ordine
secvenţială predefinită, iar informaţia este memorată în zone bine definite. Datorită capacităţii
lor de a rezolva probleme complexe pe baza unei mulţimi consistente de exemple, sistemele
conexioniste au un spectru larg de aplicabilitate: de la sisteme de recunoaştere de forme
(caractere, semnături, etc.) sau de semnale sonore, până la sisteme pentru controlul unor
procese complexe, cum ar fi sistemele de auto-reglare sau piloţii automaţi.
139
6.9. Exerciţii.
A. EXERCIŢII REZOLVATE.
Din cele douăzeci şi sase de cărţi roşii, una (2 ) este în clasa ţinta şi celelalte douăzeci
şi cinci nu sunt. Deci, valoarea adiţională a informaţiei despre apartenenţa lui x la T este dată
de:
1 1 25 25
IV log log 0.235
rosie 26 26 26 26
Din cele douăzeci şi sase de cărţi negre, paisprezece (cele impare) sunt în T şi
douăsprezece nu sunt. Deci:
14 14 12 12
IV log log 0.996
neagra 26 26 26 26
Gculoare 0.615
1 12
G I I
3 13 V3 13 V 3
Din cele patru cărţi de 3, două (cele negre) sunt în T, iar celelalte două nu sunt.
Aceasta înseamnă că IV 1 . Din cele 48 de cărţi care nu sunt 3, treisprezece sunt în set (12
3
cărţi negre impare ramase plus 2 ) şi restul nu sunt. Aceasta conduce la I 3 0.843 , deci:
G3 0.855
şi rezultă din aceasta că întrebând despre culoare este mai eficient decât întrebând dacă o carte
este un 3. Acest lucru este normal deoarece - întrebând despre culoare se parcurge un drum
140
lung până la decizia dacă o carte este neagră impară, în timp ce întrebarea “dacă este un 3?”
este chiar fără sens.
141
Exerciţiul 3.
Fie următoarea schemă electrică (care poate fi o reprezentare electonică a neuronului
artificial) în care ieşirea este un tranzistor.
E1 E2 Us
(2)
R1 R2 RT
Să se reprezinte această schemă ca o reţea neuronală cu alegerea valorilor în
conformitate cu exerciţiul 2.
Rezolvare.
Us
Alegem intrările x1 E1 şi x2 E2 iar ponderea w0 şi atunci luând ponderile
RT
1 1
w1 şi w2 condiţia (2) de funcţionare a tranzistorului dată în enunţ devine
R1 R2
w1 x1 w2 x2 w0
ceea ce asigură faptul că tranzistorul va fi deschis.
Exerciţiul 4.
Să se reprezinte sub forma unei reţele neuronale următoarea frază „Ion va merge
afară la plimbare dacă şi numai dacă soarele străluceşte sau dacă este frig iar vântul bate
spre vest” folosind reprezentarea predicativă a frazei.
Rezolvare.
Predicatul „Ion va merge afară la plimbare” va fi adevărat dacă condiţiile menţionate
vor fi adevărate. Vom reprezenta în valorile de adevăr, ADEVĂRAT şi respectiv FALS, prin
1 şi respectiv 0. Vom reprezenta de asemenea în valorea de adevăr a propoziţiei „soarele
străluceşte ” prin variabila x1 , valorea de adevăr a propoziţiei „este frig” prin variabila x2 şi
valorea de adevăr a propoziţiei „ vântul bate spre vest” prin variabila x3 şi însfârşit valorea
de adevăr a propoziţiei „Ion va merge afară la plimbare” prin variabila y . Cu aceste notaţii
putem enumera toate situaţiile posibile printr-un tabel de adevăr după cum urmează:
142
Tabelul 2.1.
Dacă considerăm valorile lui x1 , x2 şi x3 ca intrări ale unui neuron artificial simplu şi
y caieşirea sa, atunci putem selecta ponderile w0 , w1 , w2 şi w3 astfel încât acest neuron să
indice la ieşire valorile de adevăr posibile ale propoziţiei „Ion va merge afară la plimbare”
iar reprezentarea neuronală va fi următoarea:
x0 1
x1 w0
w1
x2
w2
y
w3
x3
Precizăm că există metode analitice sau metode prin învăţare care determină valorile
apropiate ale ponderilor.
143
Exerciţiul 5.
Fie o funcţie specificată prin tabela de adevăr următoare.
Tabelul 5
Rezolvare:
Ţinând seama de relaţia (1), exerciţiul 2, este clar că
w0 0, pentru y 0
n (3)
wi xi w0 0, pentru y 1
i 1
144
Pentru acest exemplu este clar că există, evident cu respectarea resticţiilor impuse de
inegalităţile (4), mai multe de posibilităţi de alegere a setului de ponderi ( w0 , w1 , w2 , w3 ) .
Spre exemplu o alegere
( w0 2, w1 4, w2 2, w3 2) i
iar alta ar fi
( w0 1, w1 4, w2 1, w3 1) .
B. TEMA DE CONTROL.
Exerciţiul 1.
Considerăm funcţia logică y f ( x1 , x2 , x3 ) definită prin y 1 dacă numărul de 1 în
lista argumentelor este impar şi y 0 în sens contrar. Această funcţie este cunoscută ca
problema parităţii şi este specificată în tabelul următor:
145
Să se precizece dacă există o funcţie prag de forma y S ( w0 w1 x1 w2 x2 w3 x3 )
care să rezolve problema parităţii şi în caz afirmativ să se reprezinte reţeaua neuronală
corespunzătoare.
Exerciţiul 2.
Considerăm funcţia booleană
1, daca x1 x2
f ( x1 , x2 ) (5)
0, daca x1 x2
Tabelul valorilor de adevăr pentru această funcţie este:
Exerciţiul 3.
Fie funcţia booleană disjuncţie
f ( x1 , x2 ) x1 x2
al cărui tabel de adevăr este următorul:
146
6.10. BIBLIOGRAFIE RECOMANDATĂ LA MODULUL 3:
1. Podaru Vasile, Inteligenţă artificială şi siteme expert, Editura Academiei
Tehnice Militare, 1997
2. Podaru Vasile, Barnoschi Adriana, Sisteme expert, Editura Academiei
Tehnice Militare, 2000, 2004.
3. Ioan Georgescu, Elemente de inteligenţă artificială, Editura Academiei RSR,
1985.
4. Podaru Vasile, Inteligenţă artificială, curs în format electronic, CD-
învăţământ la distanţă, Universitatea Titu Maiorescu, 2010.
5. D. Cîrstoiu, Sisteme expert, editura ALL, 1994.
6. SICSTUS PROLOG USER’S MANUAL. Intelligent Systems Laboratory,
Sweedish Institute of Computer Science:
http://www.sics.se/isl/sicstuswww/site/documentation.html
7. M. Maliţa, Bazele inteligenţei artificiale, editura Academiei Române, 1988.
147
UNIVERSITATEA TITU MAIORESCU
Facultatea de INFORMATICĂ
VASILE PODARU
BUCUREŞTI – 2011
UNIVERSITATEA Titu MAIORESCU Bucureşti
Facultatea de Informatică
Învăţământ la Distanţă
INTELIGENŢĂ ARTIFICIALĂ
Inteligenţa artificială este una din disciplinele de pregătire fundamentală care, pentru
profilul INFORMATICĂ, este esenţială pentru pregătirea studenţilor şi pentru obţinerea
creditelor transferabile prin procedurile de evaluare. Modul de prezentare a acestui material are în
vedere particularităţile învăţământului la distanţă, la care studiul individual este determinant.
Pentru orice nelămuriri faţă de acest material vă rugăm să contactaţi tutorele de disciplină care
are datoria să vă ajute oferindu-vă toate explicaţiile necesare.
Disciplina de Inteligenţa artificială îşi propune următoarele obiective specifice:
Însuşirea noţiunilor fundamentale din domeniile Inteligenţei artificiale.
Formarea deprinderilor de modelare matematică şi de transpunere în programare a unor
probleme de natură tehnică, socială sau economică, cu utilizarea cunoştinţelor însuşite.
Formarea şi dezvoltarea aptitudinilor şi deprinderilor de analiză logică, formulare corectă
şi argumentare fundamentată, în rezolvarea problemelor tehnico-economice şi de
specialitatecu cu utilizarea cunoştinţelor însuşite prin intermediul metodelor şi modelelor
specifice inteligenţei artificiale;
Insusirea principiilor generale ale programarii logice si insusirea limbajului Prolog;
O comparaţie critică a metodelor de rezolvare evidenţiind, eventual, calea optimă de
soluţionare.
Accentul se va pune pe problemele de cautare si reprezentare a cunostintelor si respectiv
pe programarea logica, limbajul de programare utilizat la laborator fiind limbajul Prolog.
Cursul trebuie sa trateze aspecte ale rezolvarii problemelor prin intermediul cautarii,
descriind cele mai importante tehnici de cautare informata si neinformata. Se vor da
exmple de aplicatii ale cautarii, cum ar fi jocurile, tratate ca probleme de cautare. Se vor
prezenta principalele tipuri de cunostinte si principalele metode de reprezentare a
cunostintelor. Se va face legatura dintre reprezentarea cunostintelor si sistemele expert. Se
va da un exemplu de sistem expert cu implementare in Prolog. Vor mai fi tratate, ca
modalitati de reprezentare a cunostintelor, retelele semantice si retelele Bayesiene (cu
introducerea rationamentului statistic).
149
Întru-cât modulul este privit ca un tot unitar exerciţiile aferente acestui modul se găsesc la
sfârşitul acestui modul. La terminarea parcurgerii acestui modul studenţii trebuie să prezinte
tutorelui de disciplină rezolvarea temei de control propusă spre rezolvare la sfîrşitul modulului.
Cursul se finalizează prin examen care constă din:
1) o lucrare scrisă sub forma de text grila constând din 9-18 subiecte (ponderea lucrării
scrise este de 70% din nota finală);
2) rezolvarea corectă a temelor de control din cele 4 module (minimum nota 5 pentru
fiecare temă, ponderea mediei celor 5 note în nota finală este de 20%);
3) participarea activă la activităţile tutoriale (apreciată printr-o notă a cărei pondere in
nota finală este de 10%).
150
MODULUL 4
151
Unitatea de învăţare nr.7
7.1. Biometria.
Biometria (cuvânt derivat din grescul bios = “viaţă” şi metron = “măsură”) constă în
metode automate de recunoaştere a individului, bazate pe caracteristici fizice sau
comportamentale. Printre acestea se numară amprentele, scanarea retinei şi a irisului, geometria
mâinii şi a degetului, recunoaşterea caracteristicilor vocale şi recunoaşterea facială. Astăzi,
tehnologiile biometrice au devenit soluţiile preferate ale unei arii extinse de aplicaţii, în special în
domeniul identificării şi verificării personalului. Este de aşteptat că biometria să fie încorporată în
soluţii de securitate naţională, cum ar fi îmbunătăţirea securităţii aeroporturilor, intărirea
graniţelor, verificarea documentelor de identificare şi a vizelor, prevenirea falsurilor de identitate.
Bineînteles, există domenii de aplicare şi în afara securităţii naţionale, cum ar fi securizarea
reţelelor marilor corporaţii, securizarea e-banking, investiţiile şi alte tranzacţii financiare,
vânzările cu amănuntul, sănătatea şi serviciile sociale. În Occident, toate aceste sfere de activitate
beneficiază deja de aplicaţiile biometrice şi pe lângă aceastea se iau în considerare, ca obiective
de acoperit, parcurile de distracţii, băncile şi alte organizaţii financiare, colegiile, cantinele
şcolare şi multe alte facilităţi.
Definiţie: Biometria – o disciplină recentă – este ştiinţa identificării sau verificării
identităţii unei persoane pe baza caracteristicilor fizice sau comportamentale.
• caracteristici fizice (măsurate la un anumit moment de timp): amprentele digitale,
faţa, geometria mâinii, irisul, retina, forma urechii, mirosul, reflexia pielii, termogramele
• caracteristici comportamentale (variaţia pe o durată de timp): scrisul, vocea,
mersul, modul de tastare, mişcarea buzelor
152
Orice caracteristică umană fizică sau comportamentală poate fi utilizată ca identificator
biometric dacă satisface următoarele cerinţe:
• universalitate;
• unicitate;
• permanenţă;
• colectabilitate.
Într-un sistem biometric practic, există şi alte aspecte care trebuie luate în considerare:
• performanţele sistemului: acurateţea recunoaşterii, viteza, robusteţea realizabilă,
resursele necesare pentru a atinge acurateţea şi viteza dorită, precum şi factorii operaţionali şi de
mediu care afectează acurateţea recunoaşterii şi viteza;
• acceptabilitatea;
• posibilitatea de fraudare a sistemului.
Fiecare din aceste criterii conduc la metode care prezintă avantaje şi dezavantaje cu
privire la securitate, uşurinţă în exploatare şi cost.
Nivelul de securitate oferit de o soluţie biometrică este relativ foarte ridicat, deoarece
administratorul sistemului este singura persoană autorizată să managerizeze datele existente în
sistemul de control al accesului. Prin implementarea unui sistem biometric de securitate se
elimină costurile de administrare a sistemului (carduri, personal autorizat, managementul
înregistrarilor, etc) care, printr-o soluţie clasică, nu pot fi diminuate sau evitate. În al doilea rând,
reducerea costurilor reprezintă o consecinţă directă a scăderii riscurilor de securitate odată cu
implementarea unei asemenea soluţii.
Autentificarea biometrică, adică bazată pe identificarea amprentelor digitale, a irisului, a
amprentei vocale, este cea mai puternică metodă de autentificare a unui utilizator al unui sistem
informatic.Majoritatea metodelor de autentificare utilizate pe scară largă prezintă vulnerabilităţi
şi dezavantaje: cheile se pot pierde, parolele pot fi uitate sau aflate de persoane care nu ar avea
dreptul să le posede. Trăsăturile anatomice nu pot fi copiate uşor şi nici pierdute. Utilizarea
autentificării biometrice este soluţia ideală pentru a asigura securitatea datelor permiţând
renunţarea definitivă la folosirea parolelor şi la riscurile presupuse de acestea, de a fi deconspirate
sau uitate. Dintre toate metodele de autentificare, biometrica cea mai utilizată este cea bazată pe
identificarea amprentelor digitale.
153
Folosirea amprentelor digitale ca metodă infailibilă de identificare coboară în timp în
1880, când Alphonse Bertillon a demonstrat că desenele liniilor de pe buricele degetelor noastre
rămân neschimbate toată viaţa. De la finele secolului al XIX-lea, poliţia a început să folosească
tehnica în descoperirea anumitor infracţiuni, constituindu-şi imense fişiere cu amprente digitale
pe care trebuiau să le foileteze experţi specializaţi. La finele anilor ’70, serviciile de poliţie au
recurs la informatică pentru compararea amprentelor, soluţie care le permite stocarea şi
identificarea a zeci de milioane de amprente. Acum identificarea cu ajutorul amprentei este
folosită cu mare succes în industria telefoanelor mobile, a computerelor şi chiar a automobilelor.
Astfel, au apărut telefoane mobile care nu se deschid decât după verificarea amprentei digitale a
posesorului. Astfel încât, dacă acestea sunt furate, ele nu mai pot fi folosite de către hoţ.
Un sistem de verificare autentifică identitatea unei persoane prin compararea
caracteristicii biometrice capturate cu modelul biometric propriu acelei persoane, stocat anterior
în sistem. Acesta efectuează o comparaţie 1-1 pentru a determina dacă identitatea pretinsă de
către individ este cea adevărată. Sistemul de verificare respinge sau acceptă identitatea susţinută.
Un sistem de identificare recunoaşte un individ prin compararea caracteristicii biometrice
cu întreaga bază de date de modele. Aceasta efectuează comparaţii de tipul 1-N pentru a stabili
identitatea individului. Într-un sistem de identificare, sistemul stabileşte identitatea subiectului
(sau eşuează dacă subiectul nu este înregistrat în baza de date a sistemului) fără ca subiectul să
pretindă o identitate.
154
apăsării tastelor. Tabelul de mai jos (Figura 1.2.1) ne arată o comparaţie între diferite metode
biometrice:
155
Figura 1.3.1 Identificatori biometrici folosiţi pentru sistemele multimodale multi-verificator.
156
Figura 1.4.1 Ratele de eroare ale sistemelor biometrice
157
Figura 1.4.2 Receptor de caracteristici operaţionale(ROC)
Matematic, erorile întru-un sistem de verificare pot fi formulate dupa cum urmează. În
cazul în care şabloanele biometrice stocate ale utilizatorului I sunt reprezentate de X1 şi
achiziţiile de intrare pentru recunoaştere sunt reprezentate de Xq, atunci ipoteze alternante şi
ipotezele zero sunt:
H0 :Intrarea Xq nu provide de la aceeaşi persoană ca a şablonului X1;
H1: Intrarea Xq provine de la aceeaşi persoană ca a şablonului X1;
Deciziile sunt asociate aşa cum urmează:
D0:Persoana nu este cine pretinede a fi;
D1:Persoana este cine pretinde a fi.
Regula decizională este următoarea:dacă scorul de potrivire S(Xq,X1) este mai mic decât
pragul sistem t, atunci este valabilă decizia D0, dacă nu decizia D1. Dacă H0 este ipoteza,atunci
semnalul primit este un semnal de zgomot singur, şi dacă H1 este ipoteza atunci semnalul primit
este un mesaj plus zgomot. O astfel de ipostază de testare formulată în mod inerent conţine două
tipuri de erori:
Tipul 1 : Falsa potrivire (D1 este ales când H0 este adevărat).
Tipul 2 : Falsa nepotrivire (D0 este ales când H1 este adevărat).
FMR este probabilitatea de eroare de tipul 1 şi FNMR este probabilitatea de eroare de
tipul 2.
158
FMR = P(D1|H0 = adevărat);
În afară de ratele de eroare de mai sus, eşecul de a captura rata (FTC) şi eşecul de a
înscrie rata (FTE) sunt de asemenea folosiţi pentru a rezuma precizia unui sistem biometric. Rata
FTC este aplicabilă când dispozitivul biometric are o funcţionalitate automată de capturare
implementată în el şi aceasta denotă numărul de încercari nereuşite ale dispozitivului biometric în
încercarea de a captura un şablon în cazul în care caracteristicile biometrice îi sunt prezentate.
Rata FTE pe cealaltă parte, denotă numărul de încercari nereuşite de înscriere în sistemul de
recunoaştere ale utilizatorilor. Există o legatură între rata FTE şi rata de precizie a sistemului
(FMR şi FNMR).
Acurateţea unui sistem este cea mai importantă caracteristică a acestuia şi, din acest
motiv, este unul din principalii parametrii de diferenţiere între un sistem performant şi unul
defectuos. Din acest motiv, au apărut competiţii şi teste internaţionale care îşi propun clasificări
după criterii foarte stricte a metodelor biometrice.
În cazul evaluării performanţelor unui algoritm de înrolare şi verificare biometrică, se
disting două caracteristici principale, definite la rândul lor de două rate de eroare. Prima este Rata
de Rejecţie falsă (FRR), care defineşte numărul de date autorizate ce sunt excluse de algoritm. A
doua este Rata de Acceptare falsă (FAR), care defineşte numărul de date neautorizate (impostor),
cărora algoritmul le permite accesul.
Pentru fiecare algoritm şi bază de date se raportează o serie de indicatori, cei mai
importanţi dintre ei fiind:
159
REJENROLL (Numărul de date biometrice refuzate în procesul de înrolare);
REJNGRA (Numărul de date biometrice refuzate în cazul testelor de autentificare
autorizată);
REJNIRA (Numărul de date biometrice refuzate în cazul testelor de autentificare
neautorizată);
FMR100 (cea mai mică rată de acceptare falsă pentru FAR<=1%);
FMR1000 (cea mai mică rată de acceptare falsă pentru FAR <=0.1%);
ZeroFMR (cea mai mică rată de acceptare falsă pentru FAR =0%);
ZeroFNMR (cea mai mică rată de rejecţie falsă pentru FRR =0%);
Timpul mediu de înrolare;
Timpul mediu de verificare; Valoarea medie FMR100;
Valoarea medie FMR1000;
Valoarea medie ZeroFMR;
Valoarea medie REJENROLL (numărul mediu de date biometrice refuzate la înrolare);
Valoarea medie REJMATCH (numărul mediu de date biometrice refuzate în cazul
autentificărilor autorizate şi neautorizate);
FTE (Fail To Enroll), imposibilitatea utilizatorului de a se înrola în sistem;
FTA (Fail To Acquire), imposibilitatea utilizatorului de a se autentifica în sistem.
Aceşti indicatori sunt, de fapt, o serie de valori caracteristice ce fac diferenţa dintre un
algoritm, respectiv, un produs sigur şi unul defectuos.
Figura 1.4.3. arată un mod de comportare al acestor indicatori.
160
Figura 1.4.3.
161
aplicaţii biometrice sub un singur standard. Acest consorţiu poartă numele de BioAPI, iar
certificarea BioAPI a devenit un standard necesar pentru orice algoritm biometric.
Rezultatul final al autentificării/verificării este dat, de fapt, de unul din cele patru cazuri
menţionate mai sus: acceptare corectă sau falsă şi rejecţie corectă sau falsă.
Formulele de calcul pentru aceste rate de eroare sunt:
FRR = FTE+ FTA+ FNMR
FAR= (1- FTE) * (1- FTA) * FMR
Valorile astfel calculate pot fi introduse într-un grafic, rezultând astfel un punct de
intersecţie EER (Equal Error Rate-Figura 1.4.3 ), ce poate fi folosit ca o evaluare a
performanţelor simplificate în cazul sistemelor biometrice.
Figura 1.4.3
Realizarea unui sistem biometric pentru câţiva utilizatori poate fi relativ uşoară, dar
adaptarea pentru milioane de utilizatori implică probleme mult mai complicate. Chiar dacă viteza
de verificare şi acurateţea rămân esenţiale atât pentru un sistem cu 100 de utilizatori, cât şi pentru
unul cu 10 milioane, modul de identificare va deveni complet diferit. Adiţional faţă de erorile de
falsă acceptare şi falsă rejecţie, apare un alt tip de eroare ce se referă la falsa identificare (FI); în
acest caz, un utilizator poate fi asociat greşit unei alte înregistrări biometrice. Această rată de
eroare asociată FI va purta denumirea FIR. În ceea ce privesc erorile sistemelor de identificare
sunt de discutat următoarele aspecte.
• În condiţiile unor simplificări, o estimare a performanţelor în modul identificare poate fi
dedusă din evaluarea erorilor în modul verificare.
162
• Să presupunem că nu este disponibil nici un mecanism de indexare/regăsire (deci trebuie
căutată întreaga bază de date conţinând N şabloane) şi că este prezent un singur şablon în baza de
date pentru fiecare utilizator.
Fie FNMRN şi FMRN, rata nepotrivirii false şi respectiv rata potrivirii false în cazul
identificării, atunci:
FNMRN = FNMR: probabilitatea nepotrivirii false a intrării cu şablonul
utilizatorului este aceeaşi ca în modul verificare;
FMRN = 1 (1 FMR)N: o potrivire falsă are loc când intrarea se potriveşte
fals cu unul sau mai multe şabloane din baza de date.
Dacă FMR este foarte mic atunci
FMRN N FMR şi probabilitatea potrivirii false creşte liniar cu mărimea
bazei de date.
• Acest rezultat are implicaţii serioase în proiectarea sistemelor de identificare la scară
largă. Să considerăm o aplicaţie de identificare cu ajutorul amprentelor digitale cu 10.000 de
utilizatori. Să presupunem că, pentru un FNMR acceptabil, FMR-ul algoritmului ales este 10 5
(doar o potrivire falsă la 100.000 de comparări). Atunci probabilitatea acceptării false a unui
individ în timpul identificării este FMRN 10%, şi oricine are o bună şansă de a obţine accesul la
sistem prin încercarea celor zece degete de la cele două mâini.
• Dacă şabloanele din baza de date au fost clasificate/indexate, atunci doar o parte a bazei
de date este căutată în timpul identificării şi aceasta duce la o formulare diferită a FNMRN şi
FMRN:
FNMRN = RER +(1 RER) FNMR, unde RER (rata erorii de regăsire) este
probabilitatea că şablonul căutat să fie depistat greşit de
mecanismul de regăsire;
163
7.5. Securitatea sistemelor biometrice.
1 3 5
Dispozitivul de Extractorul de
intrare / senzorul Comparatorul Aplicaţia
caracteristici
biometric 2 4 6
7
Înscrierea în Baza de date a
caracteristicilor
sistem
9 de referinţă
8 10
Figura 1.4.5.
Pe schemă sunt figurate şi numerele care definesc punctele de atac într-un sistem
biometric. Iată care sunt acestea:
1. La prezentarea caracteristicilor biometrice la senzorul de intrare:
– atac prin constrângere: în care sunt prezentate datele biometrice reale, dar
într-o modalitate neautorizată.
– atac prin simulare: în care un individ neautorizat îşi modifică trăsăturile
biometrice (mai ales în cazul feţei sau vocii) pentru a apărea asemenea
persoanei autorizate.
– atac de tip reluare: în care o înregistrare a datelor biometrice reale este
prezentată dispozitivului de intrare.
Contramăsuri:
– detecţia situaţiile de constrângere prin analiza stresului utilizatorului sau
prin supravegherea sistemului
– detecţia semnelor vitale
– metode multibiometrice
2. Atacul canalului de legătură dintre senzorul biometric şi extractorul de caracteristici:
– Acesta poate fi un atac de tip reluare, prezentarea unui semnal
164
biometric
stocat anterior, sau o simulare electronică. Acesta include ocolirea
senzorului prin reintroducerea imaginii unei amprente sau a feţei sau prin
injectarea unui semnal audio la ieşirea microfonului. Dacă accesul fizic în
acest punct este disponibil, acest atac este mai simplu decât atacul asupra
senzorului. Tehnici de criptare digitală şi indicatori de timp pot contracara
aceste atacuri. Mai mult, sistemul poate detecta potrivirea perfectă cu date
anterioare din sistem.
– Simularea electronică poate consta în introducerea imaginii unei amprente
creată în mod artificial din dispunerea detaliile striaţiilor obţinute din
înregistrarea acestor detalii de pe un card.
3. Atac de tip „cal Troian” asupra extractorului de caracteristici:
– Modulul de extragere a caracteristicilor poate fi atacat astfel încât va
produce un set prestabilit de caracteristici la un anumit moment de timp şi
în anumite condiţii. După extragerea caracteristicilor din semnalul de
intrare, acestea sunt înlocuite cu un set sintetizat de caracteristici diferit,
presupunând că modul de reprezentare este cunoscut.
4. Atacul canalului de legătură dintre extractorul de caracteristici şi comparator.
– În cazul amprentelor dacă detaliile striaţiilor sunt transmise la un
comparator aflat la distanţă (de exemplu în cazul în care se utilizează
smartcarduri pentru stocarea reprezentării de referinţă) această ameninţare
este foarte reală.
5. Atac de tip „cal Troian” asupra comparatorului caracteristicilor de intrare cu cele de
referinţă.
– În acest caz comparatorul produce un scor de similitudine mare sau mic în
mod artificial, astfel falsificând deciziile comparatorului pentru un anumit
utilizator.
6. O ameninţare foarte importantă prin care nu se ţine cont de ieşirea modulului de
comparare. Ieşirea acestui modul poate fi o decizie categorică (da sau nu) sau poate fi
probabilitatea de asemănare, decizia finală fiind lăsată pe seama aplicaţiei.
165
7. Atacul canalului de comunicaţii dintre baza de date (centrală sau distribuită) şi
comparator.
– Reprezentarea biometrică stocată în baza de date este trimisă la comparator
prin acest canal. În cazul în care acest canal de legătură este atacat,
reprezentarea biometrică este modificată înainte de a ajunge la comparator.
8. Atacul la înscrierea în sistem.
– Procesele de înscriere şi de autentificare sunt simulare şi astfel
înregistrarea în sistem este vulnerabilă la atacurile 1…5.
9. Atacul canalului prin care reprezentarea biometrică de referinţă este trimisă bazei de
date.
10. Atacul asupra bazei de date a caracteristicilor de referinţă.
– Baza de date a înregistrărilor reprezentărilor biometrice poate fi disponibilă
local sau la distanţă, distribuită pe mai multe servere. Această ameninţare
constă în modificarea neautorizată a uneia sau mai multor reprezentări din
baza de date. Aceasta poate avea drept consecinţă autorizarea unui
infractor, refuzul serviciului persoanei asociate cu modelul de referinţă
corupt (presupunând că formatul reprezentărilor este cunoscut), sau
eliminarea unor indivizi de pe o listă de supraveghere.
Alte atacuri într-un sistem biometric pot fi următoarele:
• Posibilitatea de atac a sistemului biometric prin evitarea acestuia. În orice sistem
biometric este prevăzută o facilitate de lucru care permite tratarea excepţiilor. De exemplu,
autentificarea persoanelor fără degete într-un sistem de recunoaştere a amprentelor digitale.
• Atacul progresiv. Acest tip de atac implică prezentarea în mod repetat a datelor
biometrice unui algoritm cu uşoare modificări şi păstrarea acelor modificări care au ca rezultat un
scor îmbunătăţit. În final poate fi obţinut un scor care să depăşească pragul de comparare.
Această metodă este potrivită mai ales când atacatorul nu are nici o cunoştinţă referitoare la
datele biometrice ale utilizatorului legitim. Un asemenea atac poate fi împiedicat prin limitarea
încercărilor limitate sau prin furnizarea la ieşire doar a unor răspunsuri categorice de tipul da sau
nu, prin cuantificarea scorurilor de comparare sau prin adăugarea la acestea a unei mici cantităţi
de zgomot.
166
• Atacul prin inundare. Acesta este similar atacului de tip forţă brută în cazul parolelor,
exploatându-se slăbiciunile algoritmului de comparare. De exemplu, în cazul amprentelor
atacatorul poate prezenta o imagine sintetizată conţinând sute de detalii ale striaţiilor în speranţa
că cel puţin un anumit număr N, corespunzător unui prag, vor corespunde cu modelul de referinţă
stocat.
• Înscrierea ilegitimă în sistem. Reprezintă o ameninţare la orice sistem de securitate şi se
realizează prin simpla înregistrare a atacatorului sau prin atribuirea unor drepturi de acces
necorespunzătoare.
Metodele de creştere a securităţii sistemelor biometrice pot fi următoarele:
- Combinarea smartcardurilor şi a metodelor biometrice în aplicaţiile biometrice;
- Mecanisme eficiente de provocare-răspuns la sistemele proiectate;
- Transformări eficiente ale caracteristicilor biometrice:
• în domeniul semnalului biometric;
• în domeniul reprezentărilor biometrice.
167
În industria biometriei, se face o distincţie clară între termenii „identificare“,
„recunoaştere“ şi „verificare“.
Identificarea şi recunoaşterea sunt în esenţă termeni sinonimi şi, în ambele procese, o
probă este prezentată sistemului biometric,care încearcă să determine cui aparţine, prin
compararea acesteia cu probele din baza de date, în speranţa găsirii unei perechi. Acest proces
poartă numele de „comparaţie unu la mai multe“.
Verificarea este o „comparaţie unu la unu“ în care sistemul biometric încearcă să verifice
identitatea unui individ. În acest caz, o nouă probă biometrică este capturată şi comparată cu
modelele anterior stocate. Dacă cele două modele se potrivesc, sistemul confirmă faptul că
individul este cine pretinde a fi.
În concluzie, în timp ce identificarea şi recunoaşterea presupun găsirea perechii unei
mostre într-o bază de date, verificarea implică potrivirea mostrei într-o bază de date, formată
dintr-un singur model. Astfel, în timpul identificării, sistemul biometric întreabă „Cine este
utilizatorul?“ şi stabileşte dacă înregistrarea biometrică există în baza de date, în timp ce la
verificare, sistemul întreabă „Utilizatorul este cine pretinde că este?“.
Înainte de a alege biometria ca soluţie de identificare a individului, o organizaţie trebuie
să-şi evalueze cu atenţie nevoile. Ceea ce trebuie să fie luat în considerare sunt nivelul de
securitate optim, acurateţea, costul şi timpul de implementare, precum şi acceptarea de către
utilizator.
Tehnicile biometrice de identificare a caracteristicilor fizice sunt mult mai precise oferind,
prin urmare, un nivel de securitate mai ridicat.
În ceea ce priveşte acurateţea, scanarea retinală şi identificarea irisului sunt metode de
identificare a individului foarte precise. Cu toate acestea, ambele sunt foarte costisitoare, iar
majoritatea organizaţiilor nu au nevoie de un nivel de siguranţă atât de precis.
Tehnicile de autentificare pe bază de amprentă, scanare facială sau geometria mâinii oferă
o buna acurateţe la un preţ mult mai mic. Schimbările fizice, precum tăieturi, cicatrice,
îmbătrânire, pot afecta precizia anumitor tehnici de determinare biometrică, însă aceste probleme
pot fi soluţionate printr-o continuă actualizare a bazelor de date.
Costul şi timpul de implementare al unui sistem biometric trebuie asociat cu o serie de
factori cum ar fi căutarea, achiziţionarea şi instalarea componentelor hardware şi software de
captură, autentificarea şi menţinerea bazelor de date, timpul de integrare a sistemului în mediul
168
existent, iniţierea personalului IT în utilizarea noului sistem şi familiarizarea utilizatorilor cu noul
protocol de identificare, colectarea şi menţinerea bazei de date necesară autentificării.
Figura 1.4.7.
Acceptarea sistemului biometric de către utilizator este o problemă foarte importantă, iar
în acest sens, organizaţia trebuie să familiarizeze angajaţii cu toate cerinţele sistemului, înainte ca
acesta să fie integrat.
Principalele metode biometrice de autentificare sunt: Recunoaşterea facială, Amprentele
digitale, Geometria mâinii, Scanarea irisului, Scanarea retinei,Modelele de vene, Semnătura,
Verificarea vocii, ADN, Structura dinţilor, Mersul, Urechea, Presiunea şi ritmul apăsării
tastelor.
169
Unitatea de învăţare nr.8.
Sisteme expert
Cuprins:
8.1. Introducere .................................................................................................... pag. 170
8.2. Metodologia de proiectare, implementare şi utilizare a unui sistem expert .. pag. 175
8.3. Studii de caz ................................................................................................... pag. 182
Bibliografie .......................................................................................................... pag. 189
8.1. Introducere.
Un sistem expert este un program de calculator conceput să simuleze unele forme ale
raţiunii umane (prin intermedierea unui motor de deducţie) şi capabil să administreze o
importantă cantitate de cunoştinţe specializate.
Un sistem expert este o aplicaţie de calculator care rezolvă probleme complicate care ar
necesita o vastă expertiză umană. Pentru a face aceasta, el simulează procesul de raţiune umană
prin aplicarea unor interfeţe şi cunoştinţe specifice. Acest raport a explicat procesul de luare a
deciziilor în cazul sistemelor expert pentru a da cele mai bune soluţii în rezolvarea problemelor.
Există şi alte încercări de definiţie a unui sistem expert:
- un sistem care foloseşte cunoştinţele umane captate într-un calculator pentru a rezolva
probleme care în mod curent necesită expertiză umană (Turban & Aronson, 2001);
- un program de calculator conceput să modeleze abilitatea de a rezolva a unui expert
uman (Durkin, 1994);
- un program de calculator inteligent care foloseşte proceduri de cunoaştere şi de deducţie
pentru a rezolva probleme care sunt deosebit de dificile astfel încât să necesite expertiză umană
semnificativă pentru a le rezolva (Feigenbaum).
Aceste capacităţi pentru raţionament şi control permit sistemului să analizeze un număr
mic de ipoteze relevante pentru a găsi o concluzie satisfăcătoare. Două caracteristici ale
sistemului expert sunt necesare pentru a îndeplini această sarcină:
capacitatea de a procesa o cantitate mare de cunoştinţe şi
capacitatea de a simula raţionamentul uman (într-o manieră imperfectă).
Sunt multe avantaje cunoscute în folosirea instrumentelor computerizate şi a sistemelor
expert:
170
reducerea datelor lipsă,
o mai bună culegere a datelor,
neomiterea întrebărilor,
ne-transcrierea datelor,
o acoperire mai largă a diagnosticelor.
Arhitectura generală a unui sistem expert este:
Aşa cum am văzut un sistem expert este un program de calculator creat pentru a simula
comportamentul în rezolvarea problemelor a unui om care este expert într-un domeniu sau o
disciplină anume. Un sistem expert este compus dintr-o bază de cunoştinţe (informaţii, euristică,
171
etc.), motor de decizie (analizează baza de cunoştinţe) şi, interfaţa cu utilizatorul (acceptă intrări,
generează ieşiri).
Calea care duce la dezvoltarea sistemelor expert este diferită de cea a tehnicilor
convenţionale de programare. Conceptele pentru dezvoltarea sistemelor expert vin din domeniul
inteligenţei artificiale (AI), şi necesită o îndepărtare de la practicile convenţionale ale
calculatorului şi tehnicilor de programare. Un program convenţional constă într-un proces
algoritmic pentru a atinge un rezultat specific. Un program AI este făcut dintr-o bază de
cunoştinţe şi o procedură pentru a indica un răspuns.
Sistemele expert sunt capabile să distribuie informaţii cantitative, multe din ele fiind
dezvoltate în urma unor cercetări de bază şi aplicate (ex. praguri economic, modele de dezvoltare
în serie) dar şi euristice pentru a interpreta valorile derivate calitativ, sau pentru folosirea în locul
unor informaţii cantitative. Altă caracteristică este că aceste sisteme pot adresa date imprecise şi
incorecte prin asignarea unor valori de încredere la intrări şi concluzii.
Unul dintre cele mai puternice atribute ale unui sistem expert este abilitatea de a explica
raţional. Deoarece sistemul îşi aminteşte lanţul logic al raţionării, un utilizator va putea cere o
explicaţie a unei recomandări şi sistemul va afişa factorii pe care-i consideră în acea recomandare
particulară. Acest atribut măreşte încrederea utilizatorului în recomandarea făcută de sistem şi în
acceptarea acestuia.
Basri (1999) a notat faptul că un sistem expert încearcă să imite cum un expert uman ar
rezolva o problemă, în special prin manipularea simbolurilor decât a numerelor. În timp ce
programarea algoritmică convenţională înlocuieşte munca analitică, sofisticată a inginerilor,
sistemele expert sunt potrivite în special părţilor mai puţin determinante ale planificării şi
proiectării.
Yang şi Okrent (1991) au afirmat că sistemele expert sunt mai ieftine în comparaţie cu
experţii umani în cazul unui scenariu de durată. Totuşi, sistemele expert sunt costisitoare la
dezvoltare dar sunt uşor şi ieftin de lucrat cu ele. În adiţie, sistemele expert permit automatizarea
mai multor task-uri ce nu pot fi manevrate cu uşurinţă de experţii umani.
Iată câteva diagrame care arată modalitatea de funcţionare unui sistem expert.
172
Figura 8.3. Părţile majore ale unui sistem expert
Figura 8.3. Proces tipic de achiziţie a cunoaşterii pentru construirea unui sistem expert
173
cărţi, rapoarte, baze de date, studii de caz, date empirice şi experienţa personală. Sursa dominantă
de cunoaştere în sistemele expert de azi este dominanta expert. Un inginer de cunoaştere obţine
de obicei cunoaşterea prin interacţiune directă cu expertul.
Sistemele expert sunt folosite în aplicaţii din multe domenii: medical, agricol, juridic,
economie, industrie, învăţămâmt, cercetare, prognoză, guvernamental, poliţie, etc..
174
8.2. Metodologia de proiectare, implementare şi utilizare a unui sistem expert.
Metodologia Ingineriei Cunoaşterii (Knowledge engineering – KE) se referă la
proiectarea, întreţinerea şi dezvoltarea sistemelor bazate pe cunoaştere şi asigură succesul unui
sistem expert în îndeplinirea cerinţelor, obiectivelor şi scopului propus.
175
Sarcina 1: Determinarea motivării organizaţiei
Sarcina 2: Identificarea problemelor
Sarcina 3: Realizarea unor studii de fezabilitate
Sarcina 4: Realizarea unor analize de cost / beneficii
Sarcina 5: Selectarea celui mai bun proiect
Sarcina 6: Scrierea propunerii pentru proiect
176
ipoteze conform informaţiilor disponibile. Cheile pentru un design eficient sunt consistenţa,
claritatea şi controlul.
Faza 4: Testarea
SE va trebui testat periodic şi evaluat pentru a se asigura faptul că performanţa acestuia
converge către scopurile stabilite. Este important ca aceste decizii să fie făcute timpuriu, la un
timp când scopurile originale au fost stabilite.
Stadiul 1: Testarea Preliminară
Studierea bazei de cunoaştere completă
Descoperirea deficienţelor în strategiile de raţionament
Validarea reprezentării cunoştinţelor şi aproximaţia deducţiei
Stadiul 2: Testarea prin Demonstraţie
Alegerea unei probleme cu interval limitat în capacităţile SE
Folosirea demonstraţiei pentru a valida aproximarea sistemului expert
Prezentarea caracteristicilor majore ale SE
Designul interfeţei pentru a fi comod utilizatorului
Stadiul 3: Validarea Testării Informale
Selectarea cazurilor testate anterior
Evaluarea abilităţilor SE în rezolvarea cazurilor tipice şi
Identificarea deficienţelor SE şi obţinerea comentariilor de la utilizator prin
interfaţă
Stadiul 4: Testarea Reevaluării
Selectarea cazurilor neobişnuite din trecut
Evaluarea capacităţii SE în rezolvarea cazurilor neobişnuite
Descoperirea deficienţelor în controlul şi cunoaşterea SE
Identificarea deficienţelor SE
Stadiul 5: Testarea Formală
Selectarea cazurilor din trecut şi definirea criteriilor de test
Rularea SE pentru fiecare caz de test şi întrebarea evaluatorilor despre
performanţa sistemului pentru fiecare caz de test
Obţinerea comentariilor asupra interfeţei
177
Identificarea punctelor forte şi a deficienţilor SE
Stadiul 6: Testarea în timp real
Definirea criteriilor de test pentru testarea în câmp deschis
Determinarea dacă SE îşi îndeplineşte scopurile când este aplicat problemelor real
Faza 6: Întreţinerea
După terminarea design-ului, implementării, testării şi documentării, SE va trebui
perfecţionat sau actualizat pentru a îndeplini cerinţele curente. Este foarte important pentru a
menţine o bună înregistrare a modificărilor care s-au produs la SE. Dacă acest lucru nu este
realizat, se poate pierde urma cunoştinţelor SE. Iar de fiecare dată când SE este modificat,
următoarele piese de informaţii trebuie documentate:
Ce s-a modificat şi cine a realizat modificarea
Când a fost realizată modificarea
De ce a fost realizată modificarea
Sistemul expert menţine domeniul de cunoştinţe expert într-un modul cunoscut ca baza de
cunoştinţe. Acesta foloseşte tehnici şi reguli pentru a codifica cunoştinţele în baza de
cunoştinţe. O regulă este o structură de forma IF/THEN care interpretează logic informaţii
conţinute în partea IF cu Alte caracteristici ale sistemului expert complet sunt memoria
funcţionabilă şi motorul de decizie. Pentru motorul de decizie sunt folosite clase iar pentru
memoria funcţionabilă sunt folosiţi vectori.
SE are de asemenea facilitatea de explicare. Înseamnă că SE poate oferi o explicaţie
utilizatorului despre întrebările care i se adresează şi cum desprinde concluziile pe baza acestor
întrebări. Interacţiunea cu Utilizatorul se face de regulă prin intermediul unor ferestre-ecran
prietenoase cu ajutorul cărora se poartă un dialog utilizator – SE.
Iată exemplu de schemă de dialog SE-utilizator:
178
Figura 8.6. Schemă de dialog SE-utilizator
Sistemele Expert au fost folosite pentru a rezolva o gamă largă de probleme în domenii ca
medicina, matematica, ingineria, geologia, informatica, afaceri, drept, apărare şi educaţie. În
cazul fiecărui domeniu, ele au fost folosite pentru a rezolva diferite tipuri de probleme. Tipurile
de probleme includ diagnostice (ex., a unei erori de sistem, a unei molime sau a unei erori
studenţeşti); proiectare (a unui sistem computerizat, a unui hotel etc.); şi interpretare (de
exemplu, a datelor geologice). Tehnica potrivită de rezolvare tinde să depindă mai mult de tipul
problemei decât de domeniu.
În tabela 1 sunt prezentate avantajele intrinseci ale sistemelor care simulează
comportamentul intelligent şi avantaje datorate tehnologiei.
179
Tabela 1
Un sistem expert poate face greşeli, dar mai puţin decât ar face un om. Mai mult, el
funcţionează mereu consistent, niciodată devenind obosit sau plictisit. Alta diferenţă este că SE
poate fi folosit oriunde spre deosebire de oameni.
Utilizatorul îşi va putea clarifica problema de sincronizare cu SE cu răspuns imediat şi
poate primi diagnoze prin intermediul SE. Această caracteristică îl va asista să recunoască
cauzele care permit nesincronizarea SE. Ei vor putea solicita SE explicaţii la întrebările care li se
pun în timpul interacţiunii.
SE poate fi îmbunătăţit prin convertirea la o aplicaţie web. În loc să lucreze în modul, ar
putea fi accesat prin website care măresc locaţia de acces.
Sistemele expert hibride împreună cu sistemele expert fuzzy pot fi văzute ca noi tehnici ce
vor putea fi folosite de cercetători mai târziu. Implementarea unui sistem expert în mai multe
domenii este puternic influenţată de tehnicile şi metodele care adoptă hypertext şi hypermedia.
Caracteristici ale personalizării, modelarea utilizatorului şi abilitatea de adaptare la mediu vor
180
deveni noi provocări. Vor putea fi folosite ca un ghid în promovarea sistemelor expert în variate
funcţii.
Pe viitor, SE vor putea fi folosite împreună cu reţele neuronale artificiale, logica fuzzy,
algoritmi genetici şi alte metode ale Inteligenţei Artificiale. Aceste metode permit luarea în
considerare a avantajelor lor în sistemul proiectat şi, deci, noile sisteme proiectate sunt
instrumente mai puternice în facilitarea variatelor sarcini care necesită răspunsuri pe moment,
precise şi de încredere.
În dezvoltarea SE sunt folosite atât limbaje convenţionale cât şi tehnicile IA. Iată o
diagramă a procentelor de folosire a acestora în Marea Britanie în ultimul deceniu:
Figura 8.7.
181
8.3. Aplicaţii. Studii de caz.
LISTA 1
cauta pret
if cost_estimat > 0
and mult este gasit
then pret_oferta=cost_estimat* factor_mult ;
pret este gasit
if indice_standard > 0
and factor_dimensiune >= 0
and factor_client >= 0
then indice = indice_standard – factor _dimensiune + factor_client;
valoare_indice este gasit
182
if tip_contract este ‘proiect_propriu’
and data_contract este fixată
then segment_piata este ‘proiect_propriu_datat’
183
if tip_contract este ‘proiect_propriu’
and cost_estimativ < 75000
then factor_marime = 0
if numar_de_invitatii_la_licitatie > 4
and numar_de_licitatii_castigate = 0
then relatia_cu_client este rea
if numar_de_invitatii_la_licitatie > 0
and numar_de_licitatii_castigate > 0
and clientul este nemultumit
then relatia_cu_client este rea
184
if numar_de_invitatii_la_licitatie = 0
then relatia_cu_client este medie
if numar_de_invitatii_la_licitatie > 0
and numar_de_invitatii_la_licitatie < = 4
and numar_de_licitatii_castigate = 0
then relatia_cu_client este medie
if numar_de_invitatii_la_licitatie > 0
and numar_de_licitatii_castigate > 0
and clientul este multumit
then relatia_cu_client este medie
if numar_de_invitatii_la_licitatie > 0
and numar_de_licitatii_castigate > 0
and consumatorul este ‘pe_deplin_satisfăcut’
then relaţia_cu_client este bună.
185
Diagrama pentru situaţia de ofertant al unui produs pe piaţă din baza de cunoştinţe pentru
demonstraţie este aratată în Figura 2. Următoarea etapă este crearea unei liste a tuturor obiectelor
sau variabilelor împreuna cu valorile permise pe care le pot primi. Această listă şi diagramă
formează o structurare importantă a cunoaşterii şi odată realizată, se dezvoltă uşor o serie de
reguli pentru baza de cunoştinţe. Desigur, e necesară o bogată experienţă pentru a aranja regulile
şi clauzele regulilor într-o ordine optimă, iar apoi, pe baza lor, să se poată scrie mai eficient
reguli. Regulile din Lista 1 sunt mai simple decât cele implicate în figura 2.
Compania “Compania_Y” obţine cea mai mare parte din afacerile sale din licitaţii
competitive. Când “Compania_Y” primeşte o invitaţie de licitaţie pentru un contract din partea
unui client, este făcută o analiză preliminară a detaliilor contractului. Scopul acesteia este de a
identifica acele contracte care pot duce la întelegeri neprofitabile.
Analiza preliminară presupune o privire asupra factorilor de decizie cu privire la contract
şi apoi determină dacă firma trebuie să refuze invitaţia de licitaţie, sau să propună o licitaţie
competitivă.
Când a fost întrebat de natura exactă a analizei preliminare, directorul departamentului de
licitaţii a răspuns:
“ În primul rând, scopul analizei primare este de a determina cât de atractiv este contractul
dat companiei, cu privire la mărimea şi termenii acestuia. În general, compania refuză să propună
o licitaţie pentru acele contracte, care sunt considerate prea mici sau prea mari, aceasta
însemnând, acele contracte cu un cost de pornire mai mici decât 100,000$ sau, mai mare decât
1,5 milioane$. Oricum, existând condiţia ca firma să aibă un contract cu clientul, atunci trebuie
considerată o submisiune de licitaţie, aşa numitul ”contract cu valoare mică". Acestea sunt
contractele cu un cost de pornire de cel putin 50,000$, dar mai mic de 100,000$. Ideea este de a
se încerca stabilirea unei relaţii bune cu clienţii existenţi, dar nu mă întrebaţi dacă merge sau nu!
Recent am început să primim o mulţime de invitaţii la licitaţii pentru contracte de la
clienţi străini, iar în prezent invitaţiile din străinătate însumează 15% din toate invitaţiile primite.
Încă nu a fost adoptată o politică clară de selectare, dar în timp scurt am înfiinţat reprezentanţe în
diverse tări străine. Având reprezentant în ţara din care a venit invitaţia, atunci clienţii străini
186
sunt trataţii la fel ca cei din propria piaţă. Dacă nu este disponibil nici un reprezentant al
companiei, atunci declinăm invitaţia la licitaţie “.
Din informaţiile date de discursul directorului compartimentului de licitaţii, se proiectează
şi se construieşte un sistem expert, folosind Prolog apoi se recomandă companiei “Compania_Y”
cea mai potrivită decizie de luat, când se primeşte o invitaţie pentru licitaţie. Aceasta înseamnă că
sistemul expert face o recomandare firmei, cu privire la o ofertă competitivă sau declină invitaţia
la licitaţie.
LISTA 2
Studiul de caz 2 - BAZA DE CUNOŞTINŢE
caută decizie-ofertă
187
if cost_estimativ >= 100000
and cost_estimativ <= 1500000
then contractul este “de_valoare_înalta”
Bibliografie
1. Podaru, V., Inteligenţă artificială şi siteme expert, Editura Academiei Tehnice Militare, 1997
2. Podaru, V., Barnoschi, A., Sisteme expert, Editura Academiei Tehnice Militare, 2000, 2004.
3. Georgescu, I., Elemente de inteligenţă artificială, Editura Academiei RSR, 1985.
188
INTRODUCERE ÎN LIMBAJUL PROLOG
LECŢIA 1.
NOŢIUNI INTRODUCTIVE
place(ion,maria).
place(maria,ion).
Ori de câte ori este folosit un nume, acesta se referă la un anumit obiect particular.
Este clar că numele ion şi maria se referă la indivizi umani. Dar am folosit în faptele de mai
sus şi numele aur şi valoros şi nu rezultă în mod necesar evident ce ar putea însemna. Acest
fel de nume este denumit de către logicieni non-count word (cuvânt non-număr). Atunci
când folosim un nume, trebuie să ne decidem asupra modului în care interpretăm numele.
Să discutăm câteva aspecte privitoare la terminologie. Numele obiectelor cuprinse
între paranteze rotunde în cadrul fiecărui fapt sunt denumite argumente. Numele relaţiei care
se află plasat înaintea perechii de paranteze rotunde se numeşte predicat. Astfel, valoros
este un predicat cu un singur argument, iar place este un predicat care are două argumente.
Numele obiectelor şi relaţiilor sunt complet arbitrare. În locul termenului
place(ion,maria) putem folosi la fel de bine şi cu acceaşi semnificaţie termenul
a(b,c), trebuind doar să ţinem minte că a înseamnă place, b înseamnă ion, iar c
înseamnă maria. Este recomandat să se folosească acele nume care să aibă semnificaţia a
ceea ce ele reprezintă.
Relaţiile pot avea un număr arbitrar de argumente. Spre exemplu, dacă definim un
predicat denumit joaca, în cadrul căruia sunt precizaţi doi jucători şi jocul pe care-l joacă,
vor fi necesare trei argumente. Iată două exemple de astfel de fapte
10
joaca(ion,maria,fotbal).
joaca(jana,jean,badminton).
1.2 Întrebări
Odată definite faptele, se pot formula întrebări asupra acestora. În Prolog, o întrebare
arată la fel ca şi un fapt, deosebirea constând în precedarea acestuia de către un simbol
special. Simbolul special este scris sub forma unui semn de întrebare şi a unei cratime(‘?-“).
Să considerăm întrebarea de mai jos
-are(maria,carte).
place(gogu,peste).
place(gogu,maria).
place(maria,carte).
place(ion,carte).
După ce s-a introdus toate aceste fapte în sistemul Prolog, se pot formula întrebări, iar
Prolog va da răspunsurile (arătate mai jos cu caractere aldine) pe linia imediat următoare
liniei pe care se află scrisă întrebarea)
- place(gogu,bani).
no
- place(maria,gogu).
11
no
- place(maria,carte).
yes
- rege(ion,romania).
no
Răspunsurile la primele trei întrebări sunt clare. Prolog a răspuns, de asemenea, no, şi
la întrebarea dacă Ion este regele Romaniei. Aceasta deoarece nu există nici un fapt relativ la
regalitate în cadrul bazei de date care conţine cele patru relaţii place. În Prolog, răspunsul
no este utilizat pentru a semnifica faptul că nimic nu se potriveşte cu întrebarea. Este
important de reţinut faptul că no nu reprezintă acelaşi lucru cu false.
Să considerăm un alt exemplu, cu o bază de date despre unii dintre cei mai faimoşi
filozofi greci ai antichităţii, bază care conţine următoarele trei fapte
om(socrate).
om(aristotel).
atenian(socrate).
- atenian(socrate).
yes
- atenian(aristotel).
no
- grec(socrate).
no
Deşi în istoria adevărată este adevărat faptul că Aristotel a trăit în Atena, nu se poate
dovedi acest lucru cu ajutorul faptelor care se găsesc în baza de date. Mai mult, deşi se
specifică în baza de date faptul că Socrate este atenian, aceasta nu dovedeşte că este grec,
deoarece nu există informaţii suplimentare în acest sens, în baza de date. Deci, atunci când
Prolog răspunde no la o întrebare, aceasta înseamnă că faptul respectiv nu poate fi dovedit.
1.3 Variabile
În Prolog nu numai că putem da nume unor anumite obiecte particulare, dar putem
folosi nume ca X, care să înlocuiască obiectele ce vor fi determinate de Prolog. Numele din
această a doua categorie sunt denumite variabile. Atunci când Prolog foloseşte o variabilă,
aceasta poate fi instanţiată sau neinstanţiată.
O variabilă este instanţiată atunci când există un obiect pe care variabila îl înlocuieşte.
O variabilă este neinstanţiată atunci când ceea ce este înlocuit de către variabilă este încă
necunoscut. Prolog face deosebire între variabile şi nume ale anumitor obiecte particulare prin
faptul că orice nume care începe cu majusculă este considerat variabilă.
Atunci când i se pune Prolog-ului o întrebare care conţine o variabilă, acesta caută
printre toate faptele un obiect ce ar putea fi înlocuit de către variabilă. Astfel, atunci când
întrebăm Îi place lui Ion obiectul X , Prolog caută printre toate faptele pentru a găsi lucrurile
care îi plac lui Ion.
O variabilă, spre exemplu X, nu desemnează un anume obiect în sine, dar poate fi
folosită pentru a înlocui obiecte pe care nu le putem numi. Prolog permite utilizarea
12
variabilelor, în felul următor
- place(ion,X).
place(ion,flori).
place(ion,maria).
place(paul,maria).
- place(ion,X).
Deci întrebarea are semnificaţia dacă Există ceva care să-i placă lui Ion Atunci când
îi este adresată această întrebare, Prolog va răspunde
X=flori
şi va aştepta instrucţiuni suplimentare, despre care vom vorbi imediat. Cum funcţionează
acest mecanism Atunci când Prolog-ului i se pune această întrebare, variabila X este iniţial
neinstanţiată. Prolog caută prin baza de date un fapt care să se potrivească cu întrebarea. Dacă
în conţinutul întrebării apare o variabilă neinstanţiată ca argument, atunci Prolog va permite
ca potrivirea acestui argument să se facă cu orice alt argument aflat în aceeaşi poziţie în
cadrul declaraţiei faptului. Ceea ce se întâmplă este aceea că Prolog caută orice fapt al cărui
predicat este place şi al cărui prim argument este ion. În acest caz cel de-al doilea argument
poate avea orice valoare, deoarece întrebarea a fost pusă având drept al doilea argument o
variabilă neinstanţiată. Atunci când este găsit un asemenea fapt, variabila X va fi instanţiată cu
cel de-al doilea argument, indiferent de valoarea acestuia. Prolog caută în baza de date în
ordinea în care aceasta a fost scrisă (de sus în jos, în pagină), primul găsit este faptul
place(ion,flori). Variabila X este instanţiată cu obiectul al cărui nume este flori.
Totodată, Prolog marchează locul în care a descoperit o potrivire în cadrul bazei de date, acest
marker fiind folosit atunci când se va efectua o revenire pe care o vom discuta mai târziu.
Odată ce Prolog găseşte un fapt care să se potrivească cu întrebarea, el afişează
variabilele şi obiectele cu care sunt instanţiate. În acest caz X a fost instanţiat cu flori. În
continuare Prolog aşteaptă instrucţiuni suplimentare. Dacă apăsăm tasta Enter, ceea ce
înseamnă că suntem satisfăcuţi cu un singur răspuns, atunci Prolog va opri procesul de
căutare. Dacă apăsăm tasta (urmată de apăsarea tastei Enter), atunci Prolog va relua
căutarea în baza de date după acelaşi principiu, pornind din locul în care a plasat markerul.
Atunci când Prolog începe căutarea dintr-un loc marcat şi nu de la începutul bazei de date,
spunem că Prolog încearcă să resatisfacă întrebarea.
Să presupunem că la primul răspuns al Prolog-ului (X=flori) i-am cerut (apăsând
tasta ) să continue. Aceasta înseamnă că dorim satisfacerea întrebării într-un alt mod (alt
răspuns) dorim să găsim un alt obiect care să fie înlocuit de X. Aceasta însemnă că Prolog
trebuie să „uite“ că variabila X înlocuieşte obiectul flori şi să reia căutarea având din nou
variabila X neinstanţiată. Deoarece căutăm o altă variantă de răspuns, căutarea este reluată din
locul în care este plasat markerul. Următorul fapt care se potriveşte cu întrebarea este
place(ion,maria). Variabila X este acum instanţiată cu valoarea maria, iar Prolog pune
markerul în dreptul faptului place(ion,maria). Prolog va afişa X=maria şi va aştepta
comenzile următoare. Dacă vom continua apăsând din nou tasta ”;”, Prolog va continua
căutarea. În acest exemplu nu mai sunt alte fapte care să afirme ce îi place lui Ion. Astfel,
13
Prolog va opri căutarea, permiţându-ne să formulăm şi alte întrebări sau să adăugăm noi fapte.
Ce se întâmplă dacă, date fiind faptele de mai sus, punem întrebarea:
?- place(X,maria).
1.4 Conjuncţii
place(maria,mancare).
place(maria,vin).
place(ion,vin).
place(ion,maria).
Dorim să întrebăm dacă Ion şi Maria se plac. Pentru aceasta întrebăm O place Ion pe
Maria? şi Îl place Maria pe Ion?. Conjuncţia “şi” (and) exprimă ideea că suntem interesaţi de
conjuncţia dintre cele două scopuri - adică dorim satisfacerea ambelor, unul după altul. Putem
reprezenta acest lucru prin plasarea unei virgule ”,” între cele două scopuri (care va juca rolul
conjuncţiei “şi”):
?- place(ion,maria), place(maria,ion).
Virgula se citeşte ”şi” putând separa oricâte scopuri se doresc a fi satisfăcute, pentru a
răspunde la o întrebare. Atunci când i se transmite sistemului Prolog o secvenţă de scopuri
(separate prin virgule), acesta încearcă satisfacerea fiecăruia pe rând, prin căutarea unei
potriviri în baza de date. Pentru ca secvenţa să fie satisfăcută, toate scopurile ce o compun
trebuie să fie satisfăcute. Folosind lista de fapte anterioară, ce va afişa Prolog atunci când i se
pune întrebarea de mai sus? Răspunsul este no. Este un fapt care afirmă că Ion o place pe
Maria, deci primul scop este satisfăcut (true). Cu toate acestea cel de-al doilea scop nu
poate fi dovedit, deoarece nu există în lista de fapte nici unul de forma
place(maria,ion), care să afirme că Maria îl place pe Ion. Cum am dorit să aflăm dacă
cei doi se plac unul pe celălalt, răspunsul la întrebare este no.
Pentru a rezuma, ne putem imagina o conjuncţie de scopuri aranjate de la stânga la
14
dreapta, scopurile fiind separate prin virgule. Fiecare scop poate avea un vecin aflat la stânga
şi unul aflat la dreapta. Evident, scopul aflat la limita stângă a conjuncţiei nu mai are nici un
vecin în stânga sa, iar cel aflat la limita dreaptă a conjuncţiei nu mai are nici un vecin în
dreapta sa. Atunci când trece la rezolvarea unei conjuncţii de scopuri, Prolog încearcă
satisfacerea fiecărui scop în parte, de la stânga spre dreapta. Dacă un scop este satisfăcut,
Prolog lasă un marker în baza de date care este asociat scopului respectiv. Gândim aceasta ca
şi când am desena o săgeată de la scop până la locul din baza de date în care se află soluţia.
Mai departe, toate variabilele care anterior erau neinstanţiate, pot fi acum instanţiate. Aceasta
s-a produs la pasul 1 din succesiunea prezentată mai sus. Dacă o variabilă devine instanţiată,
atunci toate apariţiile variabilei în cadrul întrebării vor fi înlocuite cu acea valoare. Prolog
încearcă apoi să satisfacă scopul care este vecinul din dreapta al scopului pe care tocmai l-a
satisfăcut, efectuând căutarea de la începutul bazei de date.
Pe măsura satisfacerii scopurilor, pentru fiecare scop satisfăcut rămâne câte un marker
în cadrul bazei de date (o săgeată de la scop până la faptul care se potriveşte), în cazul în care
scopul va trebui resatisfăcut ulterior. Ori de câte ori un scop nu poate fi satisfăcut (nu se poate
găsi un fapt care să se potrivească întrebării), Prolog se întoarce şi încearcă resatisfacerea
vecinului din stânga, începând căutarea de la markerul acestuia. Mai mult, Prolog trebuie să
dezinstanţieze toate variabilele care au fost instanţiate în cadrul scopului respectiv. Cu alte
cuvinte, Prolog trebuie să ”şteargă” conţinutul tuturor variabilelor, atunci când resatisface un
scop. Dacă fiecare scop începând din dreapta, nu mai poate fi resatisfăcut, atunci eşuările se
propagă spre stânga, pe măsură ce scopurile nu pot fi satisfăcute. Dacă şi primul scop (cel mai
din stânga) eşuează, acesta nu mai are un alt vecin, la stânga sa, pe care să încerce să-l
resatisfacă. În acest caz întreaga conjuncţie de scopuri eşuează (nu poate fi satisfăcută). Acest
mod de lucru, în care Prolog încearcă să satisfacă şi să resatisfacă scopurile din compunerea
unor conjuncţii, se numeşte backtracking. Acesta este prezentat sumar în capitolul următor, şi
este tratat pe larg în capitolul 4.
O regulă este o afirmaţie cu caracter general despre obiecte şi despre relaţiile dintre
acestea. De exemplu, putem spune că Nicu este pasăre, dacă Nicu este animal şi dacă Nicu
are pene chiar dacă în lumea reală o astfel de afirmaţie nu-şi are sens. Astfel, putem face ca o
variabilă să înlocuiască un obiect diferit, la fiecare utilizare diferită a regulii. În cadrul unei
singure utilizări a unei reguli, desigur, variabilele sunt interpretate în mod consistent.
Să considerăm un alt exemplu, cu o regulă care utilizează o variabilă şi o conjuncţie.
1.5 Sintaxa
A B C D E F G H I J K L N O P Q R S T U V W X Y Z
a b c d e f g h i j k l n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9
+ - * / \ ” ^ < > : . , ? @ ă $ &
Pimul rând constă în literele mari. Al doilea rând conţine literele mici. Al treilea rând
conţine cifrele, iar al patrulea semnele speciale. De fapt sunt mai multe caractere semn decât
cele din rândul patru, dar ele au întrebuinţare specială care va fi discutată mai jos. Fiecare
termen, fie că este o constantă, fie o variabilă sau structură, are reguli specifice de formare a
numelui lor din caractere. Vom descrie mai departe fiecare categorie de termeni.
1.5.1 Constante
Constantele definesc obiecte sau relaţii specifice. Sunt două tipuri de constante: atomi
şi întregi. Exemple de atomi sunt numele pe care le-am dat în capitolul anterior:
Întregii, altă categorie de constante, sunt folosite pentru a reprezenta numere, astfel
16
încât să poată fi rezolvate operaţiile aritmetice. Întregii sunt numere compuse numai din cifre
şi care nu conţin punctul zecimal, de exemplu:
1.5.2 Variabile
Al doilea tip de termeni folosit în Prolog este variabila. Variabilele sunt asemănătoare
atomilor, cu excepţia faptului că numele lor începe cu literă mare sau cu semnul cratimă “_”.
O variabilă se foloseşte ca un suport pentru un obiect pe care nu îl putem încă nominaliza. În
exemplele pe care le-am dat am folosit variabile cu nume ca X, Y şi Z. Numele variabilelor pot
fi de lungime arbitrară:
Câteodată se simte nevoia folosirii unei variabile, fără a ne interesa numele ei. De
exemplu, dacă vrem să căutăm pe cineva care-l place pe Ion dar nu vrem să ştim cine este,
putem folosi “variabile anonime”. Variabila anonimă se scrie ca un singur caracter “ _ ”.
Exemplul nostru este scris în Prolog ca:
?-place(_,ion).
1.5.3 Structuri
17
Să considerăm următorul fapt, acela că Ion deţine o carte numită Duminica orbului, de Cezar
Petrescu:
are(ion,carte(duminica_orbului,petrescu)).
În interior, faptul are o structură cu numele carte, care are două componente, un titlu şi
un autor. Deoarece structura carte apare în interiorul faptului ca unul din argumentele sale, se
comportă ca un obiect, luând parte la relaţie. Putem avea o altă structură pentru numele
autorului dacă dorim să distingem între doi autori cu numele Petrescu (Camil şi Cezar) ca în
exemplul:
are(ion,carte(duminica_orbului,autor(cezar,petrescu)))
?-are(ion,carte(X,autor(Y,petrescu))).
Dacă este adevărat, X va fi instanţiat la titlul găsit şi Y la prenumele autorului. Sau, putem
folosi variabile anonime:
?-are(ion,carte(_,autor(_,petrescu))).
1.6 Caractere
Numele constantelor şi variabilelor sunt construite din şiruri de caractere. Deşi fiecare
tip de nume (atom, întreg, variabilă) are reguli specifice de construcţie, este bine de ştiut care
sunt caracterele recunoscute de Prolog. Prolog recunoaşte două tipuri de caractere: tipăribile şi
netipăribile. Caracterele tipăribile se exteriorizează prin semne care apar pe display.
Caracterele netipăribile determină execuţia unei acţiuni fără a fi reprezentabile pe ecran.
Tipuri de acţiuni obişnuite sunt: spaţiul, începutul unei noi linii de text şi poate chiar un
semnal sonor. Iată toate caracterele tipăribile care pot fi folosite
A B C D E F G H I J K L N O P Q R S T U V W X Y Z
a b c d e f g h i j k l n o p q r s t u v w x y z
0 1 2 3 4 5 6 7 8 9
! “ ă $ % & ` ( ) = - ” ^ | \ { } ş ţ
_ ‘ @ + ; * : < >,. ? /
Evident un set mai complet decât cel dat la începutul capitolului. Unele caractere au înţelesuri
speciale. De exemplu, parantezele rotunde sunt folosite pentru a exprima componentele unei
structuri. Caracterele pot fi tipărite, citite de la tastatură, comparate, şi pot lua parte la operaţii
aritmetice.
Caracterele sunt tratate ca întregi mici între 0 şi 127. Fiecare caracter are un întreg
asociat, numit codul ASCII. Termenul “ASCII” înseamnă “American Standard Code for
18
Information Interchange”, şi este codul pe care îl folosesc multe calculatoare şi limbaje de
calculatoare. O tabelă cu codurile ASCII poate fi găsită în diverse manuale de calculatoare.
Literele sunt aşezate în ordine alfabetică, astfel că a compara ordinea alfabetică înseamnă a
compara codurile ASCII folosind operatorii relaţionali ce vor fi descrişi în acest capitol.
Caracterele tipăribile au codul ASCII mai mare decât 32.
1.7 Operatori
Un predicat important este egalitatea, care este un operator infix scris astfel: “=“.
Când se încearcă satisfacerea scopului
?- X = Y.
19
potrivesc. Se poate judeca această acţiune ca o încercare de a face pe X şi Y egali. Predicatul
egalitate este predefinit, este deja definit în sistemul Prolog şi lucrează ca şi cum ar fi definit
de următorul fapt:
X = X.
Fiind dat un scop de forma X = Y, unde X şi Y sunt orice doi termeni care pot conţine
variabile neinstanţiate, regulile după care se decide când X şi Y sunt egali sunt următoarele:
dacă X este o variabilă neinstanţiată şi dacă Y este instanţiat cu orice termen, atunci
X şi Y sunt egali. De asemenea X va deveni instanţiat cu valoarea lui Y.
două structuri sunt egale dacă au acelaşi functor şi acelaşi număr de componente, şi
toate componentele corespondente sunt egale. De exemplu, următorul scop reuşeşte, şi face ca
X să fie instanţiat cu bicicleta:
merge(preot,bicicleta) = merge(preot,X)
Structurile pot fi “încuibărite” una în cealaltă pe orice nivel. Dacă asemenea structuri
sunt testate pentru egalitate, testul va dura ceva mai mult deoarece sunt mai multe structuri de
testat. Următorul scop
a(b,C,d(e,F,g(h,i,J))) = a(B,c,d(E,f,g(H,i,j)))
egal(X,X).
Prolog asigură de asemenea un predicat “\=“, care se citeşte “nu este egal”. Scopul
X\=Y reuşeşte dacă X=Y nu reuşeşte, şi nu reuşeşte dacă X=Y reuşeşte. Astfel, X\=Y
înseamnă X nu poate fi făcut egal cu Y.
Simbolul “mai mic sau egal cu” nu este scris ca <= ca în alte limbaje de programare.
Aceasta deoarece Prolog poate folosi în alte scopuri atomul <= (care arată ca o săgeată).
Deoarece aceşti operatori de comparaţie sunt predicate, se poate scrie următorul fapt
Prolog, 2>3, pentru a afirma că 2 este de fapt mai mare ca 3. Un asemenea fapt este legal în
Prolog, din punct de vedere sintactic. Totuşi, Prolog nu permite adăugarea de fapte la
predicatele care sunt predefinite. Asta previne schimbarea într-un mod neaşteptat a sensului
predicatelor predefinite. În capitolul 6 se vor descrie toate predicatele predefinite, inclusiv
cele întâlnite deja.
Operatorul “is” este un operator nou şi este de tip infix. Argumentul din dreapta este
un termen care este interpretat ca o expresie aritmetică. Pentru a satisface un “is”, Prolog-ul
evaluează prima dată argumentul din dreapta în concordanţă cu regulile aritmetice şi această
valoare este atribuită argumentului din stânga. În exemplu de mai sus, Y este necunoscut când
se întâlneşte “is” şi trebuie ca “is” să evalueze expresia şi să atribuie valoarea expresiei lui
Y . Aceasta presupune că valorile tuturor variabilelor din dreapta lui “is” trebuie să fie
cunoscute.
Predicatul “is” trebuie folosit întotdeauna când este necesar să se evalueze o expresie
aritmetică. Reţinem că ceva ca P/A este doar o structură Prolog obişnuită ca şi
autor(cezar,petrescu), spre exemplu. Dacă însă interpretăm o structură ca o expresie
aritmetică, există atunci o operaţie specială care poate fi aplicată la această structură numită
evaluarea expresiei aritmetice şi anume, aceea de a executa operaţiile aritmetice şi de a
calcula rezultatul. Nu toate structurile pot fi evaluate ca expresii aritmetice. Este clar că putem
evalua structuri care au definite operaţii aritmetice.
În funcţie de tipul de calculator folosit se pot folosi diverşi operatori în partea dreaptă
a lui “is”. Toate sistemele Prolog vor avea totuşi următorii operatori:
X + Y suma lui x şi y
X - Y diferenţa lui x şi y
X * Y produsul lui x şi y
X / Y câtul împărţirii întregi a lui x la y
X mod Y restul împărţirii întregi a lui x la y
Prolog încearcă să satisfacă scopurile dintr-o conjuncţie după modul în care apar în
corpul regulii sau al întrebării, în ordinea în care sunt scrise (de la stânga la dreapta). Aceasta
înseamnă că Prolog nu va încerca să satisfacă un scop până când vecinul din stânga nu a fost
satisfăcut. Când va fi satisfăcut se va încerca satisfacerea vecinului său din dreapta. Să
considerăm următorul program care se referă la relaţiile de familie:
femeie(maria).
parinti(C,M,T):-mama(C,M),tata(C,T).
mama(ion,ana).
mama(maria,ana).
tata(maria,stefan).
tata(ion,stefan).
?-femeie(maria),parinte(maria,M,T),
parinte(ion,M,T).
Săgeata indică scopurile care au fost deja satisfăcute şi anume dreptunghiul din care pleacă
săgeata indică scopul care este satisfăcut iar dreptunghiurile care sunt sub vârful săgeţii nu au
22
fost luate încă în considerare. Numim aceasta o diagramă de satisfacere.
În exemplul de mai înainte săgeata pleacă de sus şi trece mai jos la cele trei căsuţe pe
măsură ce cele trei scopuri sunt satisfăcute. Astfel încât situaţia finală va fi cea arătată în
figura 2.2.
1.10.2 Potriviri
Regulile după care se decide dacă un scop se potriveşte cu o clauză sunt prezentate în
continuare. Observăm că într-o clauză iniţial toate variabilele sunt neiniţializate.
O variabilă neiniţializată se va potrivi cu orice obiect. Ca rezultat, acel obiect va
fi cel căutat de către variabilă.
Un număr întreg sau un atom se vor potrivi numai cu ei înşişi.
O structură se va potrivi cu o altă structură dacă au acelaşi functor şi număr de
argumente şi toate argumentele corespondente se potrivesc.
Un caz remarcabil în procesul de potrivire este acela în care două variabile
neiniţializate se potrivesc una cu alta. În acest caz spunem că aceste variabile sunt legate.
Două variabile legate sunt cele care, în cazul în care una este iniţializată şi cealaltă va fi
iniţializată cu aceeaşi valoare. Să observăm o similitudine între potriviri şi egalizarea
argumentelor (secţiunea 2.4). Aceasta deoarece predicatul “=“ încearcă să-şi egalizeze
argumentele prin potrivire.
23
LECŢIA 3.
UTILIZAREA STRUCTURILOR DE DATE
Recursivitatea este o tehnică foarte populară şi puternică în lumea programării. Poate
fi folosită pentru a descrie programe care au nevoie să satisfacă o copie proprie înainte de a se
încheia cu succes ele însele. Poate fi folosită de asemenea pentru a descrie structuri care au
alte structuri ca şi componente. În Prolog, recursivitatea este calea naturală şi normală de
vizualizare a structurilor de date şi a programelor.
1.11 Structuri şi arbori
De obicei este mai uşor de înţeles forma unei structuri complicate dacă o descriem pe
aceasta ca pe un arbore, în care fiecare functor este un nod, iar componentele sunt ramificaţii.
Fiecare ramificaţie poate pointa către o altă structură, astfel încât putem avea structuri în
interiorul altor structuri. De regulă descriem o diagramă-arbore având rădăcina în vârf, iar
ramificaţiile către bază. De exemplu, structura parinti(mihai,elena,carol_2) este
descrisă astfel:
propozitie(substantiv(X),
verb_compus(verb(Y),substantiv(Z))).
Dacă reluăm propoziţia (“Ion place Maria”), şi instanţiem variabilele din structură
folosind cuvintele din propoziţie, obţinem:
Aceasta arată modul cum se pot folosi structurile şi variabilele Prolog pentru a
reprezenta sintaxa unei clase de propoziţii simple. În general dacă se cunosc cuvintele dintr-o
propoziţie, este posibil să se scrie o structură Prolog care descrie explicit relaţiile dintre
cuvintele din propoziţie.
1.12 Liste
Lista este o structură de date foarte utilizată în programare. Lista este o secvenţă
ordonată de elemente care pot o lungime variabilă. Elementele unei liste pot fi orice termeni
(constante, variabile, structuri) care desigur pot include alte liste. Aceste proprietăţi sunt
folositoare atunci când nu se poate prevedea cât de mare trebuie să fie o listă şi ce informaţii
trebuie să conţină. Mai mult, listele pot reprezenta practic orice fel de structură folosită în
25
calculul simbolic. Listele sunt larg folosite pentru a reprezenta arbori de analiză gramaticală,
gramatici, hărţi ale oraşelor, programe de calculator şi entităţi matematice cum ar fi grafice,
formule şi funcţii. În limbajul de programare LISP, singurele structuri de date disponibile sunt
constantele şi listele. În Prolog, lista este o structură particulară de date.
Listele pot fi reprezentate sub forma unui arbore special. O listă este fie vidă, neavând
nici un element, fie este o structură care are două componente: cap şi coadă. Sfârşitul unei
liste este de obicei reprezentat ca o coadă care este ataşată listei vide. Lista vidă este scrisă
sub forma []. Capul şi coada unei liste sunt componente ale functorului denumit “.”(care
este punctul). Astfel, lista care conţine un singur element “a” este reprezentată sub forma
“.(a,[])” iar arborele său asociat are forma următoare:
De asemenea, lista care conţine elementele atomice a,b,c este scrisă sub
forma(a,.(b,.(c,[]))), iar arborele asociat arată astfel:
Unii optează pentru reprezentarea diagramei arborescente a unei liste având arborele
de la stânga la dreapta şi cu ramurile în jos numită şi diagramă “vine”. Lista de mai sus are
următoarea reprezentare printr-o diagramă “vine”:
În această diagramă componenta cap a functorului punct este orientată către în jos iar
componenta coadă este orientată către dreapta. Sfârşitul listei este marcat clar pentru ultima
componentă coadă care reprezintă de fapt lista vidă. Principalul avantaj al celei de a doua
diagrame, în reprezentarea listelor, este acela că listele pot fi scrise de la stânga la dreapta.
Diagrama “vine” poate fi utilizată pentru scrierea listelor atunci când se doreşte să
vedem structura listei, dar asemenea diagrame nu sunt utilizate pentru scrierea listelor în
cadrul programului Prolog. Deoarece notaţia cu “.” este dificilă pentru scrierea listelor mai
26
complicate există o altă sintaxă care poate fi folosită pentru scrierea listelor în cadrul unui
program Prolog. Această notaţie listă se compune din elementele listei separate prin virgule,
întreaga listă fiind cuprinsă între paranteze []. De exemplu, listele de mai sus pot fi
reprezentate cu ajutorul notaţiei listă prin: [a] şi [a,b,c].
Este posibil ca listele să conţină alte liste şi variabile. De exemplu, următoarele liste
sunt corecte din punct de vedere sintactic în Prolog:
[]
[un, om,[place, un, peste]]
[a, V1,b, [X,Y]]
Variabilele din cadrul listelor sunt tratate la fel ca variabilele din oricare altă structură.
Acestea pot fi instanţiate în orice moment astfel încât utilizarea judicioasă a lor poate furniza
o modalitate de a insera în liste elemente vide care să poată fi completate cu date la un
moment ulterior. Pentru a reprezenta structura listelor cuprinse în alte liste, să scriem
diagrama “vine” pentru ultima listă de mai sus:
Este uşor de remarcat din această diagramă că fiecare nivel orizontal al diagramei este
o listă având un anumit număr de elemente. Nivelul cel mai de sus reprezintă o listă ce are 4
elemente, unul dintre acestea fiind o listă. Nivelul al doilea, având 2 elemente, este cel de al
patrulea element al listei de la nivelul cel mai înalt.
Listele pot fi manipulate prin împărţirea lor într-un cap şi o coadă. Capul unei liste
este prima componentă a functorului punct utilizat în construirea listei. Să reţinem faptul că
vorbim despre capul (antetul) unei reguli şi despre capul (antetul) unei liste, aceste două
lucruri fiind însă diferite. Coada unei liste este componenta a doua a functorului “.”. Când o
listă apare în paranteze [] capul listei este reprezentat de primul element al acesteia.
Coada listei este o sublistă care constă din toate elementele cu excepţia primului.
Exemplele din tabelul 3.1. ilustrează câteva capete şi cozi. Observăm că o listă vidă nu are
nici cap nici coadă. În ultimul exemplu, operatorul “+” este folosit ca functor pentru
structurile +(X,Y) şi +(x,y).
Deoarece o operaţie obişnuită asupra listelor este aceea de a împărţii o listă în cap şi
coadă, există o notaţie specială în Prolog pentru a reprezenta “lista cu capul X şi coada Y”.
Aceasta este scrisă [X|Y] unde simbolul care separă pe X de Y este o bară verticală. Un mod
de lucru cu această formă de scriere va iniţializa capul listei cu X şi coada cu Y ca în exemplul
următor:
p([1,2,3]).
P([o,pisica,sta,[pe,o,masa]]).
?- p([X|Y]).
X=1 Y=[2,3];
27
X=o Y=[pisica,sta,[pe,o,masa]]
?- p([_,_,_,[_|X]]).
X=[o,masa]
Uneori este necesar să căutăm în interiorul unei structuri Prolog pentru a găsi anumite
informaţii dorite. Atunci când structura are alte structuri ca şi componente, trebuie efectuată o
căutare recursivă.
Definim în Prolog un predicat ”membru” astfel încât scopul membru(X,Y) este
adevărat dacă termenul reprezentat de X este un membru al listei reprezentate de Y.
Apartenenţa lui X la lista Y se poate verifica în două moduri.
În primul rând este cert că X va fi membru al lui Y dacă X este identic cu capul listei Y.
În Prolog, acesta se scrie:
membru(X,[X|_])
care înseamnă ”X este un membru al listei care îl are pe X ca şi cap”. S-a folosit variabila
anonimă ”_” pentru a reprezenta coada listei, aceasta datorită faptului că nu folosim coada la
nimic. Această regulă poate fi scrisă de asemenea ca:
membru(X,[Y|_]):-X=Y.
membru(X,[_|Y]):-membru(X,Y).
S-a folosit variabila anonimă ”_” deoarece nu interesează numele variabilelor ce constituie
capul listei. Cele două reguli împreună definesc predicatul membru şi spun Prolog-ului cum
să caute într-o listă de la început la sfârşit, urmărind un termen specific.
Cel mai important lucru ce trebuie luat în considerare la definirea unui predicat
recursiv este de a căuta condiţiile de restricţie în cazul recursiv. Există două condiţii
restrictive pentru predicatul membru: prima condiţie restrictivă este conţinută în prima clauză
28
care va determina oprirea căutării în listă dacă primul argument din membru se potriveşte cu
capul celui de al doilea argument; a doua condiţie restrictivă intervine atunci când al doilea
argument al lui membru este o listă vidă.
Prima condiţie restrictivă este recunoscută de către o regulă ceea ce nu implică luarea în
considerare a altor viitoare subscopuri. A doua condiţie restrictivă este recunoscută de către
orice clauză a lui membru astfel încât acesta va eşua.
Este foarte important de reţinut că de fiecare dată când membru foloseşte a doua
clauză pentru a încerca satisfacerea sa, Prolog tratează fiecare ciclare recursivă a scopului
membru ca pe o copie diferită. Aceasta previne faptul că variabilele folosite într-o clauză să
se confunde cu variabilele folosite în altă clauză.
Predicatul membru este important deoarece este unul din cele mai scurte exemple de
predicat recursiv. Definiţiile recursive se întâlnesc frecvent în programe Prolog şi trebuie să
fim atenţi pentru a nu scrie definiţii circulare, ca de exemplu:
parinte(X,Y):-copil(Y,X).
copil(A,B):-parinte(B,A).
Cu toate că acest dialog poate părea ca o conversaţie puţin forţată, este uşor să scriem un
program care să rezolve partea de dialog urmând paşii:
1. Acceptarea propoziţiei introdusă de către utilizator.
2. Schimbarea fiecărui you din propoziţie în “i”.
3. Schimbarea fiecărui are în am not.
4. Schimbarea cuvântului french cu german.
5. Schimbarea cuvântului do cu no.
Aplicată asupra unor propoziţii alese cu grijă cum sunt cele din dialogul de mai sus, această
schemă va produce propoziţiile modificate.
Un program Prolog care schimbă o propoziţie într-o altă propoziţie ar putea fi scris
după cum urmează. În primul rând este necesar să se ţină seama că există o relaţie între
propoziţia originală şi cea modificată. Este nevoie să se definească un predicat, numit
modifica, astfel încât modifica(X,Y) înseamnă că propoziţia X poate fi modificată
pentru a obţine Y. Este convenabil ca X şi Y să fie liste cu elemente atomice corespunzătoare
29
cuvintelor, astfel încât propoziţiile să poată fi scrise sun forma:
[aceasta,este,o,propozitie].
Dacă predicatul modifica este definit, şi ţinând seama şi de regulile de modificare definite
anterior putem pune întrebări Prolog-ului de forma
?-modifica([do,you,know,french],X).
X=[no,i,know,german].
Deoarece modifica lucrează cu liste trebuie să rezolve şi cazul în care lista este vidă
şi anume o listă vidă este modificată şi rezultă o altă listă vidă:
schimba(you,i).
schimba(are,[am,not]).
schimba(french,german).
schimba(do,no).
schimba(X,X).
Reţinem faptul că propoziţia “am not” a fost tratată ca o listă, astfel încât ea ocupă locul
unui singur argument.
Toate considerentele de mai sus se pot translata din pseudo-Prolog într-o secvenţă
Prolog (amintindu-ne notaţia [A|B] pentru lista care are capul A şi coada B). Vom obţine
următoarele:
Prima clauză din această procedură verifică dacă lista este goală. Aceeaşi clauză verifică şi
30
sfârşitul listei. Punând acum întrebarea:
?-modifica([you,are,a,computer],Z).
modifica([a,computer],Y).
?- compara(avocat,cler) va reuşi, şi
?- compara(vin,motor) va eşua.
De asemenea,
?- compara(piua,piua) va eşua.
Compararea a două cuvinte, se face literă cu literă, şi pentru fiecare comparaţie, se determină
care din următoarele condiţii sunt aplicabile:
1. Se poate atinge sfârşitul primului cuvânt fără a atinge sfârşitul celui de-al doilea cuvânt.
Spre exemplu, compara(car,cart), în acest caz compara trebuie să reuşească.
2. Un caracter din primul cuvânt este alfabetic mai mic decât caracterul corespunzător din al
doilea cuvânt caz în care compara reuşeşte. De exemplu,
compara(elefant,elevator), „f”-ul din elefant este alfabetic înaintea lui „v ”
din elevator.
3. Se poate găsi că un caracter din primul cuvânt este alfabetic egal cu caracterul
corespunzător din al doilea cuvânt. În acest caz, trebuie să se încerce compara pe caracterele
rămase din ambele cuvinte. De exemplu, compara(lada,leac), litera „l” este la
începutul ambelor cuvinte, deci va trebui să încercăm compara(ada,eac) ca scop
următor.
4. Se poate întâmpla să ajungă concomitent la sfârşitul primului şi celui de-al doilea cuvânt,
spre exemplu compara(mare,mare), în acest caz compara va eşua deoarece cele două
cuvinte sunt identice.
5. Se poate termina parcurgerea caracterelor din cuvântul al doilea înainte de a se termina
parcurgerea caracterelor din primul cuvânt, cum ar fi compara(alfa,alf). În acest caz
31
compara va eşua.
Condiţiile anterioare pot fi transpuse în Prolog prin reprezentarea cuvintelor ca liste de
caractere (întregi mici), deci trebuie să existe o modalitate de a converti un atom Prolog într-o
listă de caractere. Acesta este scopul predicatului predefinit name. Scopul name(X,Y) este
îndeplinit atunci când atomul instanţiat pentru X consistă dintr-o listă de coduri de caractere
(coduri ASCII) instanţiată pentru Y. Dacă unul din argumente este neinstanţiat, Prolog va
încerca să-l instanţieze prin crearea unei structuri corespunzătoare. De exemplu, cunoscând
codul ASCII pentru „a”, 97, pentru „l”, 108, şi pentru „p”, 112, următoarele întrebări puse
lui name va genera răspunsurile:
?- name(X,[97,108,112]).
X=alp
?- name(alp,X).
X=[97,108,112])
Predicatul de procesare a listei adauga este folosit pentru a uni două liste rezultând
una nouă. Predicatul adauga este definit astfel:
adauga([],L,L).
adauga([X L1],L2,[X L3]):- adauga(L1,L2,L3).
Condiţiile limită apar când prima listă este lista vidă. În acest caz, orice listă adăugată
listei vide rămâne aceeaşi listă.
Cea de a doua regulă lucrează după următoarele principii:
1. Primul element al primei liste (X) va fi întotdeauna primul element al listei a treia.
2. Coada primei liste (L1) va avea întotdeauna al doilea argument (L2) adăugat la ea pentru a
forma coada (L3) a celui de-al treilea argument.
3. Trebuie folosit adauga pentru a realiza unirea arătată la punctul 2.
4. Evident se ia în mod continuu capul din ceea ce a mai rămas din primul argument, şi acesta
va fi gradual redus către lista vidă, ceea ce va conduce la condiţia limită.
În capitolele următoare vom trata diferite proprietăţi şi aplicaţii ale predicatului
adauga.
Uneori este nevoie să se parcurgă o structură Prolog şi să calculeze un rezultat care
depinde de ceea ce este găsit în structură la momentul respectiv. Evident că acest rezultat are
o valoare provizorie, într-un stadiu intermediar al acestei parcurgeri, valoare care trebuie
însă „reţinută” (deci memorată). O tehnică obişnuită de a rezolva această problemă este de a
folosi un argument al predicatului pentru a memora această valoare. Acest argument este
denumit acumulator.
32
LECŢIA 4.
BACKTRACKING (REVENIREA) ŞI TĂIETURA (CUT)
Acest capitol va trata “ backtracking-ul ” (revenirea) în detaliu, de asemenea va trata
un mecanism special, care poate fi utilizat în programele Prolog - „cut” (tăietura). Tăietura
permite programatorului să comunice Prolog -ului care dintre alegerile anterioare e necesar a
nu mai fi considerate din nou.
1.17 Generarea soluţiilor multiple
Cea mai simplă cale prin care un set de fapte poate furniza mai multe soluţii la o
întrebare este atunci când există mai multe fapte care sunt în neconcordanţă cu întrebarea. De
exemplu, dacă avem următoarele fapte în care prin tata(X,Y) înţelegem că tatăl lui X este
Y:
tata(maria,george).
tata(ion,george).
tata(elena,nicu).
tata(george,emil).
Întrebarea
?- tata(X,Y).
va avea mai multe răspunsuri posibile. Prolog ne va da următoarele răspunsuri:
X=maria, Y=george;
X=ion, Y=george;
X=elena, Y=nicu;
X=george,Y=emil;
Aceste răspunsuri au fost afişate căutând în baza de date pentru a găsi faptele şi regula
referitoare la tata în ordinea în care ele au fost date. Prolog nu-şi aminteşte nimic despre
ceea ce a indicat mai înainte. Deci dacă întrebăm
?-tata(_,X).
(pentru care dintre X este X un tată ?) va răspunde:
X=george;
X=george;
X=nicu;
X=emil;
george apărând de două ori deoarece George este tată pentru Maria şi Ion. Dacă Prolog are
două modalităţi de a arăta acelaşi lucru, le tratează ca pe două soluţii diferite.
Backtracking-ul apare exact în acelaşi mod dacă alternativele sunt întipărite mai adânc
în procesare. De exemplu, o regulă pentru definiţia „unul dintre copiii lui X este Y” poate fi:
copil(X,Y):- tata(Y,X).
Apoi, întrebarea
?- copil(X,Y).
va da următorul răspuns:
33
X=george, Y=maria;
X=george, Y=ion;
X=nicu, Y=elena;
X=emil, Y=george;
Deoarece tata(Y,X) are patru soluţii, tot aşa va avea şi copil(X,Y). Mai mult,
soluţiile sunt generate în aceeaşi ordine dar acestea sunt diferite pentru că ordinea
argumentelor este diferită, după cum este specificat în definiţia lui copil. Similar dacă
definim
tata(X):- tata(_,X).
(tata(X) înseamnă că X este un tată), atunci întrebarea
?- tata(X).
va indica:
X=george;
X=george;
X=nicu;
X=emil;
Să considerăm acum un caz şi mai interesant - acolo unde sunt două scopuri, fiecare
din ele având câteva soluţii. Să presupunem că planificăm o petrecere şi că dorim să speculăm
cine cu cine ar putea dansa. Să scriem programul următor:
pereche_posibila(X,Y):-baiat(X),fata(Y).
baiat(ion).
baiat(mitica).
baiat(bebe).
baiat(cosmin).
fata(georgeta).
fata(emilia).
fata(raluca).
Acest program spune că X şi Y formează o pereche posibilă dacă X este un băiat şi Y
este o fată. Acum să vedem care sunt posibilele perechi:
? pereche_posibila(X).
X=ion, Y=georgeta;
X=ion, Y=emilia;
X=ion, Y=raluca;
X=mitica, Y=georgeta;
X=mitica, Y=emilia;
X=mitica, Y=raluca;
X=bebe, Y=georgeta;
X=bebe, Y=emilia;
X=bebe, Y=raluca;
X=cosmin, Y=georgeta;
X=cosmin, Y=emilia;
X=cosmin, Y=raluca
34
Să vedem de ce Prolog produce soluţiile în această ordine. Mai întâi, el îndeplineşte
scopul baiat(X), găsindu-l pe ion, primul băiat. Apoi îndeplineşte scopul fata(Y),
găsind-o pe georgeta, prima fată. În acest punct, cerem o altă soluţie, cauzând un eşec.
Prolog încearcă să resatisfacă ceea ce a făcut anterior, adică scopul fata în interiorul
satisfacerii scopului pereche_posibila. El va găsi alternativa fetei emilia, deci a doua
soluţie este ion şi emilia. Similar, va genera ion şi raluca ca o a treia soluţie. În
momentul următor când va încerca să resatisfacă fata(Y), Prolog va găsi markerul său la
sfârşitul bazei de date şi astfel scopul eşuează. Acum va încerca să resatisfacă baiat(X).
Markerul a fost plasat la primul element pentru băiat, astfel încât următoarea soluţie găsită
este al doilea băiat, mitica. Acum că are îndeplinit acest scop, Prolog priveşte să vadă ce
urmează: trebuie să îndeplinească fata(Y) din nou, de la început. Astfel încât găseşte
georgeta prima fată. Următoarele trei soluţii implică acum pe mitica şi pe cele trei fete.
Mai departe, căutând o alternativă, scopul fata nu poate fi resatisfăcut. Deci un alt băiat este
găsit, iar căutarea printre fete începe din nou de la linia iniţială, ş.a.m.d. Eventual, scopul
fata eşuează şi de asemenea nu mai sunt soluţii pentru scopul baiat, astfel programul nu
mai poate găsi perechi.
Aceste exemple sunt toate foarte simple. Ele implică doar specificarea mai multor
fapte sau utilizarea regulilor pentru accesarea acestor elemente. De aceea, ele pot genera doar
un număr finit de soluţii posibile. Uneori am putea dori să generăm un număr infinit de
posibilităţi, nu pentru că dorim să le considerăm pe toate, ci pentru că am putea să nu ştim
anticipat de câte avem nevoie. În acest, caz avem nevoie de o definiţie recursivă (discutată în
capitolul anterior).
Considerăm următoarea definiţie a ceea ce este un întreg (unde prin întreg înţelegem
un număr nu mai mic decât 0). Scopul este_întreg(N) va fi atins cu condiţia ca N să fie
instanţiat cu un întreg. Dacă N nu este instanţiat în acelaşi timp în care scopul este considerat,
atunci este_întreg(N) va determina să fie ales un întreg, iar N va fi ataşat la acesta:
/*1*/ este_întreg(0).
/*2*/ este_întreg(X):-este_întreg(Y), X is Y+1.
Dacă punem întrebarea
?- este_întreg(X).
vom avea ca răspunsuri posibile toate numerele întregi în ordine crescătoare
( 0, 1, 2, 3,...), dându-se pe rând câte unul din ele. De fiecare dată forţăm backtracking-ul
(imprimând “;”) pentru a obţine cum, este_întreg va fi realizat cu argumentul său
instanţiat cu un nou întreg. Deci, în principiu, această scurtă definiţie generează un număr
infinit de răspunsuri.
Cele mai multe reguli ale lui Prolog vor da naştere la soluţii alternative dacă sunt folosite
pentru scopuri ce conţin o mulţime de variabile neinstanţiate. De exemplu, relaţia membrilor
unei liste (din capitolul 3):
membru(X,[X|_]).
membru(X,[_|Y]):-membru(X,Y).
va genera alternative. Dacă întrebăm
?- membru(a,X).
(notăm că X este neinstanţiat), atunci valorile succesive ale lui X vor fi liste parţial definite,
unde a este primul membru, al doilea, şi aşa mai departe. Vă puteţi da seama de ce ?
35
Un rezultat suplimentar al admiterii acestei definiţii a lui membru este că întrebarea:
?- membru(a,[a,b,r,a,c,a,d,a,b,r,a]).
va primi răspuns de cinci ori. În mod clar, există unele aplicaţii pentru membru unde avem
nevoie doar de o singură realizare şi apoi putem elimina cele patru posibilităţi. Putem spune
Prolog-ului să elimine posibilităţile în acest mod utilizând „tăietura”.
4.2. “Tăietura”(cut)
Acest subcapitol face referiri asupra unui mecanism special care poate fi utilizat în
progamele Prolog-ului -„tăietura”. Tăietura permite programatorului să comunice care opţiuni
anterioare nu trebuie reconsiderate când acesta reia căutarea prin lanţul de scopuri atinse.
Există două motive pentru care este important să facem acest lucru:
- Programul va opera mai repede deoarece nu va mai irosi timp încercând să
îndeplinească scopuri despre care putem spune dinainte că nu vor contribui niciodată la o
soluţionare a problemei;
- Programul poate ocupa mai puţin din spaţiul de memorie al calculatorului deoarece
poate fi realizată o folosire mai economică dacă punctele urmărite nu trebuie să fie
înregistrate pentru o examinare ulterioară.
În unele cazuri, includerea unei tăieturi poate însemna diferenţa între un program care
va merge şi un program care nu va merge.
Din punct de vedere sintactic, o folosire a tăieturii într-o regulă arată exact ca apariţia
unui scop care are predicatul „ ! ” şi fără argumente. Ca scop, acesta este îndeplinit imediat
şi nu poate fi resatisfăcut. Oricum, el are de asemenea efecte secundare, care schimbă modul
în care lucrează backtracking-ul după aceea. Efectul este de a face inaccesibili indicatorii de
loc pentru anumite scopuri astfel încât ele nu vor mai putea fi resatisfăcute.
Definiţia formală a efectului simbolului tăietura este următoarea:
Când o tăietură este întâlnită ca un scop, sistemul devine dedicat tuturor alegerilor
făcute de când scopul părinte a fost invocat. Orice alte alternative sunt eliminate. Din acest
motiv o încercare de resatisfacere a oricărui scop între scopul părinte şi scopul tăietura va
eşua.
Există mai multe modalităţi de descriere a ceea ce se întâmplă cu alegerile care sunt
efectuate de o tăietură. În primul rând că alegerile sunt tăiate sau imobilizate, dacă sistemul se
dedică alegerilor făcute sau se renunţă la alternative. De asemenea putem privi la simbolul
“tăietura” care devine mai degrabă ca un delimitator de scopuri.
Încă o observaţie înainte de a merge mai departe. Deja am spus că dacă tăietura apare
într-o regulă iar scopul este satisfăcut atunci Prolog devine dedicat spre toate alegerile făcute
din momentul în care scopul părinte a fost invocat. Aceasta înseamnă că alegerea acestei
reguli şi toate celelalte alegeri făcute după aceea devin fixe. Vom vedea mai târziu că este
posibil să se furnizeze alternative în interiorul unei singure reguli folosind predicatul
încorporat „ ; ” ( însemnând „ sau ” ). Alegerile introduse în această facilitate sunt afectate
exact în acelaşi mod. Aceasta înseamnă că, când un scop de tăietură este satisfăcut, toate
alegerile ”sau” care au fost făcute din momentul alegerii regulii devin fixe.
4.3. Folosirea comună a tăieturii
Putem împărţi folosirea comună a tăieturii în trei domenii importante:
- Primul implică locurile unde dorim să spunem sistemului Prolog că a găsit regula
potrivită pentru un scop particular. Aici, tăietura spune „ dacă ai ajuns până aici, înseamnă că
ai ales regula corectă pentru acest scop.”
- Al doilea domeniu implică locurile în care dorim să spunem sistemului Prolog să
36
abandoneze un scop particular imediat, fără a încerca soluţii alternative. Aici folosim tăietura
în conjuncţie cu predicatul fail pentru a spune „ dacă ai ajuns aici, trebuie să te opreşti a mai
încerca să satisfaci acest scop.”
- Al treilea implică locurile în care dorim să încheiem generarea soluţiilor alternative
prin backtracking. Aici tăietura spune „ dacă ai ajuns aici, ai găsit singura soluţie la această
problemă şi nu are rost căutarea alternativelor.”
Foarte des într-un program Prolog dorim să asociem mai multe clauze cu acelaşi
predicat. O clauză poate fi potrivită dacă argumentele sunt într-o singură formă, o alta va fi
potrivită dacă argumentele sunt într-o altă formă, ş.a.m.d. Adesea, putem specifica care regulă
trebuie să fie utilizată pentru un scop dat prin furnizarea modelelor în antetele regulei care se
vor potrivi doar cu scopurile ce au tipul corect. Oricum, acest lucru nu poate fi întodeauna
posibil. Dacă nu putem spune în avans ce formă pot lua argumentele sau dacă nu putem
specifica un set exhaustiv de modele, trebuie să realizăm un compromis. Aceasta înseamnă
furnizarea regulilor pentru unele tipuri specifice de argumente şi apoi furnizarea unei reguli
„de prindere” la sfârşit pentru orice altceva.
Ca un exemplu pentru acesta, considerăm următorul program. Regulile definesc
predicatul suma_1_n care furnizează Prolog-ului scopul suma_1_n(N,X) cu N având o
valoare întreagă, determinând instanţierea lui X cu suma numerelor de la 1 la N. Astfel:
?- suma_1_n(5,X).
X=15 ;
yes
deoarece 1+2+3+4+5 este 15. Acesta este programul.
suma_1_n( 1, 1 ):- !.
suma_1_n( N, Rezultat ):-
N1 is N - 1,
suma_1_n( N1,Rezultat1 ),
Rezultat is Rezultat1+N.
Aceasta este o definiţie recursivă. Ideea este că această condiţie limită apare când
primul număr este 1. În acest caz răspunsul este de asemenea 1. A doua clauză introduce un
scop recursiv suma_1_n. Oricum, primul număr al noului scop este cu 1 mai mic decât cel
original. Noul scop pe care acest scop îl va invoca va avea primul său argument din nou cu 1
mai mic, şi aşa mai departe până ce este atinsă condiţia limită. Deoarece primele argumente
sunt întodeauna mai mici, condiţia limită trebuie să fie atinsă eventual (presupunând că scopul
original are un prim argument nu mai mic decât 1), iar programul se va sfârşi.
Un stil bun de programare este de a înlocui tăieturile prin folosirea lui not. Aceasta
deoarece programele ce conţin tăieturi sunt în general mai greu de citit decât programele care
nu le conţin. Dacă unul poate localiza toate apariţiile tăieturilor în interiorul definiţiei lui not
atunci programul va fi mai uşor de înţeles. Oricum definirea lui not implică încercarea de a
arăta că scopul dat poate fi satisfăcut. De aceea, dacă avem un program de forma generală:
A:- B,C.
A:- not(B),D.
Prolog poate foarte bine să termine încercând să satisfacă de două ori pe B. El va
încerca să satisfacă pe B când ia în consideraţie prima regulă. De asemenea, efectuează
37
backtracking şi considerând a doua regulă, va trebui să încerce să satisfacă din nou B pentru a
vedea dacă not(B) poate fi satisfăcut. Această duplicare poate fi foarte ineficientă dacă
condiţia B a fost destul de complicată. Aceasta nu se întâmplă dacă în locul lui avem:
A:- B,!,C.
A:- D.
4.3.2. Combinaţia „tăietură - eşuare” (cut - fail)
38
LECŢIA 5.
INTRĂRI SI IESIRI
Până acum, singura sursă de obţinere a informaţiilor pentru un program Prolog era
prin întrebări puse sistemului Prolog. De asemenea singura metodă de a afla semnificaţia unei
variabile în obţinerea rezultatului final era prin punerea unor întrebări la care Prolog va tipări
răspunsul în forma "X=raspuns". O astfel de legătură directă, prin întrebări, este suficientă
pentru a ne asigura că un program funcţionează corect. Cu toate acestea, în multe cazuri este
util să scriem un program Prolog care să iniţieze singur un astfel de dialog. În acest capitol
descriem diferite metode de scriere şi citire.
Cel mai folositor mod de a afişa termeni pe displayul calculatorului este să folosim
predicatul write. Dacă X este iniţializat cu un termen atunci write(X)va determina
afişarea pe display a termenului. Dacă X nu este iniţializat, o variabilă numerică unică (cum ar
fi '_253') va fi afişată. Dacă două variabile împart acelaşi argument al lui write, atunci
ele vor avea acelaşi număr. Write poate fi asignat o singură dată.
Să ne amintim că un string este reprezentat ca o listă de coduri-caracter. Dacă ar fi să
folosim write lista va fi afişată ca o secvenţă de numere întregi, separate prin virgulă şi
incluse între paranteze drepte.
Alt predicat cu care este dotat Prolog-ul este 'nl' care înseamnă 'new line'. El este
folosit pentru a forţa datele de ieşire ce urmează lui nl să fie tipărite pe următoarea linie a
displayului. Ca şi write, nl are efect o singură dată.
Următorul predicat este tab. Este folosit pentru a tipări un număr de spaţii egale de-a
lungul monitorului. tab(X)are efect o singură dată şi determină cursorul să se deplaseze
spre dreapta cu X spaţii. Se presupune că X este iniţializat cu un număr întreg.
La afişarea listelor trebuie să avem în vedere ca elementele să fie astfel tipărite aşa
încât să poată fi uşor înţelese. Listele ce conţin, la rândul lor, alte liste sunt de regulă dificil de
citit, cu atât mai mult cu cât unele au şi structuri interne.
Predicatul write ţine seama la afişarea unui termen de declaraţiile făcute asupra
operatorilor. De exemplu, dacă am declarat atomul ca pe un operator infix, atunci un termen
al acestui atom este un functor şi două argumente vor fi afişate, cu atomul între cele două
argumente. Mai există un predicat care se comportă în acelaşi fel ca şi write, cu excepţia
faptului că ignoră oricare declaraţii făcute asupra operaţiilor. Acest predicat este display.
Diferenţa dintre cele două este ilustrată în exemplul următor:
Folosirea lui display este recomandată atunci când nu suntem prea siguri despre
precedenţele operatorilor utilizaţi.
39
1.18.2 Citirea termenilor
Dacă X este iniţializat cu un caracter (un cod ASCII reprezentat de un întreg) acesta va
fi afişat când Prolog întâlneşte scopul put(X). Scopul put îşi face întotdeauna efectul dar
numai o singură dată. Ca un "efect secundar", put afişează argumentul ca pe un caracter pe
display-ul terminalului. De exemplu, putem afişa cuvântul salut în următorul fel:
?-put(115),put(97),put(108),put(117),put(116).
salut
Rezultatul acestei conjuncţi de scopuri este că Prolog afişează caracterele s,a, l, u, t.
ştim deja că putem să începem afişarea la începutul liniei următoare folosind nl, care nu are
nici un argument. Ceea ce face, de fapt, nl este să afişeze anumite caractere de control care
determină cursorul să se mute la începutul liniei următoare. Întrebarea:
?-put(108),put(97),nl,put(112),put(101),
put(108),put(101),put(115).
va determina afişarea:
la
peles
O altă soluţie: tab(X), care tipăreşte X spaţii (cod ASCII 32). Bineînţeles, X trebuie
să fie iniţializat cu un număr întreg. tab(X) poate fi definit astfel:
tab(0):-!.
tab(N):-put(32),M is N - 1,tab(M).
Predicatele discutate anterior în acest capitol au fost folosite doar la citirea sau scrierea
pe terminalul calculatorului, dar de fapt ele sunt mult mai larg folosite. Sistemul Prolog
recunoaşte un "şir de intrare curent" din care este citită informaţia de intrare (input curent) şi
un "şir de iesire curent " în care sunt scrise datele de ieşire (outputul curent). În mod normal
tastatura calculatorului este aşa-numitul input curent iar displayul - outputul curent. Deseori
este mult mai util să citeşti sau să scrii fişiere, care reprezintă secvenţe de caractere aflate pe
diferite medii de înmagazinare a informaţiilor, de regulă discuri magnetice. Se presupune că
fiecare fişier are un nume necesar identificării. În Prolog numele de fişiere sunt reprezentate
ca atomi, dar nu putem exclude posibilitatea unor restricţii întâlnite la instalare în legătură cu
aceste nume de fişiere.
Fişierele au o anumită lungime, conţin deci un anumit număr de caractere. La sfârşitul
fiecărui fişier există un "indicator" de sfârşit de fişier: end of file marker. Dacă un
program citeşte informaţii dintr-un fişier, sfârşitul de fişier poate fi detectat dacă programul
citeşte termeni sau caractere. Dacă get0(X) întâlneşte semnul de sfârşit de fişier, X va fi
iniţializat cu un caracter de control, de regulă cel care are codul ASCII 26. Dacă read(X)
întâlneşte sfârşitul de fişier, X va fi iniţializat cu un termen special ce depinde de
particularităţile sistemului Prolog instalat. Acest termen special este, de regulă, atomul
end_of_file. Dacă se încearcă să se citească dincolo de sfârşitul de fişier se generează
eroarea de sfârşit de fişier.
Există un fişier livrat împreună cu sistemul, numit USER. Citirea acestui fişier
determină posibilitatea introducerii unor caractere de la tastatură şi scrierea lor în acest fişier
cu afişarea pe display a caracterelor. Acesta este modul normal de operare. Când inputul
provine de la tastatură, un sfârşit de fişier poate fi generat prin tipărirea caracterului de control
end_of_file (cod ASCII 26 sau CTRL+Z). Aceasta va determina ca get0 şi read să se
comporte ca şi cum ar fi întâlnit semnul de sfârşit de fişier.
Termeni şi caractere pot fi scrise în fişiere folosind aceleaşi predicate discutate mai
sus. Singura diferenţă este că, atunci când dorim să scriem un fişier, trebuie să schimbăm
outputul curent în sensul că acesta trebuie să fie fişierul respectiv şi nu displayul. Acest lucru
este posibil prin folosirea predicatului tell. Dacă X este iniţializat cu un nume de fişier, care
trebuie să fie un atom, tell(X) va determina redirectarea outputului curent astfel încât orice
scriere (realizată cu write, put etc) va fi făcută în fişier în loc să fie făcută pe displayul
calculatorului. Tell(X) are efect o singură dată (nu poate fi reutilizat). Când Prolog-ul
reparcurge fişierul după tell nu va determina resetarea outputului curent la ceea ce a fost
41
iniţial. Tell mai realizează şi alte operaţii în afara acestei redirecţionări a outputului. Prima
oară când se foloseşte tell(X) pentru un anumit X, Prolog presupune că dorim să creem un
fişier cu acel nume. Deci, dacă X este iniţializat cu un atom aceasta presupune că fişierul
există deja şi atunci toate caracterele existente în fişier vor fi şterse. Pe de altă parte, dacă X
este iniţializat cu un atom care nu constituie nume al nici unui fişier existent, atunci va fi creat
un nou fişier cu numele respectiv. În ambele cazuri, fişierul este considerat deschis (pentru
output). Aceasta înseamnă că scrierea în fişier va determina adăugarea de caractere la sfârşitul
fişierului până când vom spune explicit că fişierul este complet (închidem fişierul). În acest
punct dacă încercăm să mai scriem în fişier, Prolog va presupune că vrem să scriem o nouă
versiune după cum am arătat mai sus. Dacă încercăm să folosim tell(X), cu X neiniţializat
sau este iniţializat cu un obiect diferit de un nume de fişier se primeşte un mesaj de eroare.
Predicatul telling este folosit pentru a afla numele fişierului care constituie
outputul curent. Telling(X) are succes când X este iniţializat cu numele fişierului output.
Dacă X nu este iniţializat, atunci telling îl va iniţializa de la sine în aşa fel încât operaţia să
fie realizată cu succes.
Când se termină scrierea în fişier predicatul told va închide fişierul (pentru output).
De asemenea, va redirecţiona outputul spre display. Deci, o secvenţă tipică pentru a scrie
câteva caractere într-un fişier poate fi următoarea:
Dacă şirul de date de ieşire este redirecţionat fără a folosi told asupra fişierului
anterior, acest fişier nu va fi închis, fiind încă disponibil pentru scris. Acest lucru permite
scrierea într-un fişier la momente de timp diferite, ca în exemplul:
...tell(X),write(A),tell(user),
write(B),tell(X),write(C),told.
Scrierea şi citirea fişierelor este de mare ajutor în special când programele folosesc
mai mulţi termeni decât cei pe care putem să-i tastăm manual de fiecare dată când dorim să-i
introducem într-o bază de date. În Prolog, fişierele sunt de regulă folosite pentru programe.
Dacă într-un fişier se salvează textul unui program Prolog se pot citi toate clauzele existente
în fişierul respectiv şi transfera într-o bază de date folosind predicatul consult. Când X este
42
iniţializat cu un nume de fişier, efectul predicatului consult(X) va fi citirea clauzelor
Prolog şi a efectelor acestora din fişierul respectiv. Cele mai multe implementări ale Prolog-
ului au o notaţie specială pentru consult, care permite consultarea unei liste de fişiere unul
după altul. Dacă o listă de atomi este pusă Prolog-ului sub forma unei întrebări, atunci Prolog-
ul va consulta fiecare fişier din listă. Predicatul consult opreşte automat clauzele de citire
când se întâlneşte semnul de sfârşit de fişier. Secţiunea 6.1 descrie în detaliu predicatul
consult.
1.21 Declararea operatorilor
Operatorii sunt consideraţi importanţi în acest capitol " Intări şi Ieşiri " deoarece oferă
uşurinţă sintactică la scrierea sau citirea termenilor. Acesta este motivul principal pentru
folosirea operatorilor.
Sintaxa Prolog conferă operatorilor trei proprietăţi: poziţie, clasă de precedenţă şi
asociativitate. Poziţia poate fi infixă, postfixă sau prefixă (un operator ce are două argumente
poate fi poziţionat între ele; un operator cu un singur argument poate fi poziţionat înainte sau
după acesta). Clasa de precedenţă este un număr întreg a cărei mărime depinde de
implementarea sistemului Prolog, cea mai folosită este de la 1 la 1200. Clasa de precedenţă
este folosită pentru creşterea eficienţei expresiilor în care sintaxa termenilor nu este explicită
prin folosirea parantezelor. Asociativitatea este folosită pentru creşterea eficienţei expresiilor
în care sunt doi operatori, în expresiile care au aceeaşi precedenţă. În Prolog se asociază un
atom special cu un operator, care reprezintă poziţia acestuia şi asociativitatea. Specificatorii
posibili pentru un operator infix sunt:
xfx xfy yfx yfy .
Pentru a înţelege aceşti specificatori, ei ne ajută să-i vedem ca pe posibile "imagini"
ale operatorilor. În aceste imagini, litera f reprezintă operatorul, iar x şi y reprezintă
argumentele. Deci, în exemplul de mai sus, operatorul trebuie să apară între două argumente
deci, este un operator infix. În consecinţă cu această convenţie fx şi fy sunt doi
specificatori pentru operatori-prefix (operatorul apare înaintea argumentului său). De
asemenea, xf şi yf sunt posibili specificatori pentru operatori postfix. Alegerea lui x şi y în
aceste poziţii determină transmiterea informaţiei asociative. Presupunem că nu există
paranteze, un y semnifică faptul că argumentul poate conţine operatori de aceeaşi sau mai
mică clasă de precedenţă decât acest operator. Pe de altă parte, un x semnifică faptul că orice
operatori ai argumentului trebuie să aibă o clasă de precedenţă strict mai mică decât a
operatorului. Imaginaţi-vă ce înseamnă acest lucru pentru operatorul +, declarat ca yfx.
Pentru a+b+c există două interpretări posibile: (a+b)+c sau a+(b+c), a doua
interpretare fiind exclusă deoarece presupunem că argumentul după primul + trebiue să
conţină un operator de aceeaşi precedenţă (încă un +, de exemplu). Acest lucru contrazice
prezenţa unui x după f-ul specificatorului.
În plus, un operator declarat yfx este asociativ la stânga iar un operator declarat xfy
este asociativ la dreapta. Dacă cunoaştem asociativitatea pe care dorim să i-o asigurăm unui
operator infix pe care-l declarăm, aceasta înseamnă că specificatorul este unic determinat.
Semnificaţia lui x şi y este aceeaşi şi în celelalte cazuri. Aceasta înseamnă că, de
exemplu, secvenţa
not not a
este, sintactic posibilă dacă not este declarat ca fy, dar este imposibilă dacă este declarată
fx.
43
LECŢIA 6.
PREDICATE PREDEFINITE
În acest capitol vom introduce câteva din predicatele predefinite pe care un sistem
Prolog le poate încorpora. Ce înţelegem atunci când spunem că un predicat este predefinit?
Aceasta înseamnă că definiţia predicatului este furnizată în avans de către sistemul Prolog, în
loc de a fi furnizată prin propriile clauze. Predicatele predefinite pot furniza facilităţi ce nu pot
fi obţinute cu ajutorul definiţiilor în sistemul Prolog pur. Ele pot furniza facilităţi convenabile
în scopul de a salva programatorul de a le defini el însuşi. Am întâlnit deja anumite predicate
predefinite: predicatele pentru citire şi scriere discutate în capitolul 5. Deasemenea “tăietura”
poate fi considerat ca un predicat predefinit.
1.22 Introducerea de noi clauze
Atunci când scrieţi un program Prolog, veţi dori să spuneţi sistemului ce clauze să
utilizeze, tot atât de bine cum doriţi să puneţi întrebări despre ele. Aţi putea dori ca într-o
clauză nouă să scrieţi ceva la terminal sau să spuneţi sistemului Prolog să preia clauze dintr-
un fişier pe care-l aveţi pregătit în prealabil. De fapt, aceste două operaţii se aseamănă din
punctul de vedere al sistemului Prolog, deoarece terminalul este văzut ca orice alt fişier,
având numele user. Există două predicate predefinite de bază pentru citire în clauzele noi:
consult şi reconsult.
consult(X)
Predicatul predefinit consult este valoros pentru acele situaţii când doriţi ca,
clauzele dintr-un anume fişier (sau care să fie tipărite la terminal) să crească clauzele dintr-o
bază de date. Argumentul trebuie să fie un atom ce furnizează numele fişierului din care să fie
preluate clauzele. Care atomi constituie un nume de fişier legal, aceasta va depinde de tipul
calculatorului.
Când încearcă să satisfacă scopul consult, Prolog citeşte din fişier, adăugând
clauzele pe care le găseşte la sfârşitul bazei de date. Ca rezultat, noile clauze vor apărea după
oricare clauză deja existentă pentru acelaşi predicat. Dacă este găsită o întrebare în fişier,
aceasta va fi tratată ca o întrebare obişnuită, exceptând faptul că răspunsul nu va fi afişat. În
mod obişnuit nu are sens să combinăm întrebările cu clauzele noi într-un fişier, exceptând
situaţia când avem de-a face cu declararea de noi operatori şi afişarea de mesaje utile.
reconsult(X)
Predicatul reconsult este exact la fel ca predicatul consult, exceptând faptul că,
clauzele citite sunt preluate prin suprascrierea tuturor clauzelor existente pentru acelaşi
predicat. Datorită acestui lucru, reconsult este potrivit pentru corectarea greşelilor de
programare. Dacă se citeşte din mai multe fişiere de clauze şi apoi se descoperă că există o
greşeală într-o clauză, aceasta poate fi corectată fără citirea din nou a tuturor fişierelor. Pentru
aceasta, trebuie doar aplicat scopul reconsult fişierului ce conţine setul corect de clauze
pentru predicatul în discuţie. Se poate obţine clauza corectă fie prin scrierea ei la terminal
(reconsult(user)) fie prin editarea unui fişier fără a ieşi din Prolog (posibil doar în
anumite implementări) şi apoi reconsultarea aceluiaşi fişier. Bineînţeles, scrierea clauzei
revizuite la terminal va altera ceea ce Prolog vede în baza de date, dar nu va schimba fişierul
original defect, din care provine clauza.
44
1.23 Succes şi eşec
true
Aceast scop reuşeşte întotdeauna. El nu este de fapt necesar, deoarece clauzele şi
scopurile pot fi reordonate şi recombinate pentru a obţine orice folosire a lui true. Totuşi, el
există prin convenţie.
fail
Aceast scop eşuează întotdeauna. Există două locuri în care el este util. Un loc este
combinaţia tăietură-eşuare, care a fost descrisă în secţiunea 4.3. O conjuncţie de scopuri de
forma
..., !, fail.
este folosită pentru a spune “dacă execuţia continuă din acest punct, atunci cineva poate
abandona încercarea de a satisface acest scop”. Conjuncţia eşuează datorită predicatului
fail, iar scopul părinte eşuează datorită tăieturii.
Un alt loc în care este folosit predicatul fail este acela în care se doreşte în mod explicit să
se utilizeze alt scop pentru a trece prin toate soluţiile. Este posibil să se dorească afişarea
tuturor soluţiilor.
Dacă dorim să definim predicate care vor fi folosite cu o mare varietate de tipuri de
argumente, este util să fim capabili să distingem în definiţie ce trebuie să fie făcut pentru
fiecare tip posibil. Predicatele următoare permit programatorului să includă aceste condiţii
suplimentare în clauzele sale.
var(X)
Scopul var(X) reuşeşte dacă X este în acel moment o variabilă neiniţializată. Astfel
ne putem aştepta la următorul comportament:
?- var(X).
yes
?- var(23).
no
?- X = Y, Y = 23, var(X).
no
nonvar(X)
Scopul nonvar(X) reuşeşte dacă X nu este în acel moment o variabilă neiniţializată.
Predicatul nonvar este în consecinţă opusul predicatului var. Într-adevăr, el poate fi scris
în Prolog prin:
45
nonvar(X):-var(X),!,fail.
nonvar(_).
atom(X)
Scopul atom(X) reuşeşte dacă X înlocuieşte în acel moment un atom Prolog. Drept
rezultat, are loc următorul comportament:
integer(X)
Scopul integer(X) reuşeşte dacă X înlocuieşte în acel moment un întreg
atomic(X)
Scopul atomic(X) reuşeşte dacă X înlocuieşte în acel moment fie un întreg, fie un
atom. Predicatul atomic poate fi definit prin predicatele atom şi integer astfel
atomic(X):-atom(X).
atomic(X):-integer(X).
listing(A)
Satisfacerea unui scop de forma listing(A), unde A este iniţializat cu un atom
determină ca toate clauzele care au atomul drept predicat să fie scrise, în sensul sistemului
Prolog, în fişierul curent de ieşire. Acesta este modul în care se verifică ce clauze sunt folosite
în mod curent pentru un anume predicat. Formatul exact al ieşirii va depinde de
implementarea sistemului Prolog. Să observăm că, se vor vedea toate clauzele în care acel
atom este predicat, fără a ţine seama de cît de multe argumente are. Folosirea scopului
listing poate fi utilă în descoperirea unei greşeli dintr-un program.
46
clause(X,Y)
Satisfacerea unui scop de forma clause(X,Y) determină ca X şi Y să fie identificate
cu antetul şi corpul unei clauze existente în baza de date. Când se face o încercare de a
satisface scopul, X trebuie să fie iniţializat astfel încât predicatul principal al clauzei să fie
cunoscut. Dacă nu există clauze pentru predicat, atunci scopul eşuează. Dacă există mai mult
de o clauză ce se potriveşte, Prolog o va alege pe prima. În acest caz, dacă se face o încercare
de a resatisface scopul, celelalte clauze care corespund vor fi pierdute, câte una la un moment
dat.
Să reţinem că, deşi scopul clause are întotdeauna un argument pentru corpul
clauzei, nu fiecare clauză are întotdeauna un corp. Dacă o clauză nu are corp, se consideră că
are corpul true. Vom numi astfel de clauze “fapte”. Prin furnizarea parametrilor X şi Y
iniţializaţi sau nu, se pot urmări toate clauzele pentru un predicat dat şi numărul de argumente,
sau toate clauzele care se potrivesc cu un anumit şablon. Predicatul clause este foarte
important dacă dorim să construim programe ce examinează sau execută alte programe.
asserta(X), assertz(X)
Cele două predicate predefinite asserta şi assertz permit adăugarea de noi
clauze la baza de date. Cele două predicate acţionează exact în acelaşi mod, exceptând faptul
că asserta adaugă o clauză la începutul bazei de date, în timp ce assertz adaugă o
clauză la sfârşit. Această convenţie poate fi uşor reţinută deoarece a este prima literă a
alfabetului iar z este ultima. În scopul asserta(X), X trebuie să fie deja instanţiat cu ceva
ce reprezintă o clauză; într-adevăr, ca şi pentru clauze, este suficient să fie făcută iniţializarea
astfel încât să fie cunoscut predicatul principal.
Este important de reţinut că acţiunea de adăugare a unei clauze la baza de date nu este
reversibilă atunci când are loc revenirea. În consecinţă, odată ce am utilizat asserta sau
assertz pentru a adăuga o clauză nouă, acea clauză va fi înlăturată doar dacă facem explicit
acest lucru (folosind retract).
retract(X)
Predicatul predefinit retract permite unui program să înlăture clauze din baza de
date. Predicatul are un singur argument, reprezentând un termen care trebuie să se potrivească
cu clauza. Termenul trebuie să fie suficient iniţializat astfel încât să poată fi determinat
predicatul clauzei (la fel ca pentru asserta, clause, etc). Când se încearcă să se satisfacă
scopul retract(X), X este identificat cu prima clauză din baza de date care se potriveşte, şi
acea clauză este înlăturată. Când se face o încercare de resatisfacere a scopului, Prolog
continuă căutarea acestei clauze, căutând alta care se potriveşte. Dacă găseşte una, se întâmplă
acelaşi lucru ca mai înainte. Dacă se face o încercare de resatisfacere a scopului, căutarea
continuă pentru o altă clauză corespunzătoare, şi aşa mai departe. Să reţinem că, odată ce o
clauză a fost înlăturată ea nu mai este niciodată refăcută, chiar şi în cazul în care
backtracking-ul încearcă să resatisfacă scopul retract. Dacă la un moment dat căutarea nu
mai poate găsi nici o clauză care să corespundă, scopul eşuează.
Deoarece argumentul X corespunde cu o clauză care va fi înlăturată, este posibil să
vedem exact ce clauză a fost înlăturată, chiar dacă X indică un obiect cu mai multe variabile
neiniţializate în el. Astfel cineva poate utiliza scopul retract pentru a duplica func ionarea
lui clause, în cazul în care se doreşte înlăturarea clauzei după găsirea ei.
1.26 Crearea şi accesul componentelor unei structuri
În mod normal, atunci când dorim să accesăm o structură de un anumit tip într-un
program Prolog, realizăm acest lucru prin “menţionarea” structurii. Astfel, dacă un predicat
47
are nevoie să lucreze cu o varietate de tipuri diferite de structuri ce apar în calitate de
argument, în mod normal furnizăm doar o clauză separată pentru fiecare tip de structură.
În anumite programe nu putem anticipa toate structurile care pot apare. Elementul
esenţial este că dorim ca acest program să lucreze cu orice tip de structură pe care i-o
furnizăm. Bineînţeles, o posibilitate este de a furniza o clauză pentru fiecare operator pe care
este posibil să-l creem. Dar aceasta este o sarcină pe care nu o vom termina niciodată,
deoarece în anumite programe ar putea exista o infinitate de operatori. Modalitatea de a scrie
un astfel de program este de a folosi predicate predefinite ce realizează operaţii pe structuri
arbitrare. Vom descrie acum câteva dintre acestea predicatele functor, arg şi “=..”. De
asemenea vom descrie un predicat ce lucrează cu atomi, predicatul name.
functor(T,F,N)
Predicatul functor este definit astfel încât functor(T,F,N) înseamnă “T este o
structură care are operatorul F şi numărul de argumente N”. El poate fi utilizat în principiu
în două moduri. În prima modalitate, T este deja iniţializat. Scopul eşuează dacă T nu este un
atom sau o structură. Dacă T este un atom sau o structură, F corespunde operatorului iar N
corespunde cu un întreg egal cu numărul de argumente al operatorului. Să reţinem că în acest
context un atom este considerat a fi o structură cu numărul de argumente egal cu zero.
Trebuie să considerăm o a doua utilizare posibilă a lui functor. Aceasta are loc
atunci când primul argument al scopului (T) este neiniţializat. În acest caz, celelalte două
argumente trebuie să fie iniţializate specificând operatorul şi respectiv numărul de
argumente. Un scop de această formă va reuşi întotdeauna şi ca rezultat T va deveni iniţializat
cu o structură având operatorul şi numărul de argumente furnizate. Acesta este modul de
construire a structurilor arbitrare, dată prin specificarea operatorului şi numărului său de
argumente. Argumentele unei astfel de structuri construită cu ajutorul predicatului functor
are variabile neiniţializate. De aceea structura va corespunde cu orice altă structură având
acelaşi operator şi număr de argumente.
arg(N,T,A)
Predicatul arg trebuie utilizat întotdeauna cu primele două argumente iniţializate. El
este folosit pentru a accesa un argument particular al unei structuri. Primul argument al
predicatului arg specifică ce argument este cerut. Al doilea specifică structura în care va fi
găsit argumentul. Prolog găseşte argumentul corespunzător şi apoi încearcă să-l potrivească
cu al treilea argument. Astfel arg(N,T,A) reuşeşte dacă cel de-al N-lea argument al lui T
este A.
Predicatele functor şi arg furnizează o modalitate de creare şi accesare a
argumentelor unor structuri arbitrare. Predicatul “=..” (pronunţat “univ” din motive istorice)
furnizează o modalitate alternativă, care este utilă dacă se doreşte obţinerea împreună a
tuturor argumentelor unei structuri, sau dacă se doreşte construirea unei structuri după o listă
de argumente. Scopul X=..L semnifică “L este lista constând din operatorul X urmat de
argumentele lui X”. Un astfel de scop poate fi folosit în două moduri, aceleaşi în care poate fi
folosit scopul functor. Dacă X este iniţializat, Prolog construieşte lista corespunzătoare şi
încearcă să o potrivească cu L. Pe de altă parte, dacă X este neiniţializat, lista va fi folosită
pentru a construi o structură corespunzătoare care să corespundă lui X. În acest caz, antetul lui
L trebuie să fie un atom (el va deveni operatorul lui X).
48
name(A,L)
În timp ce predicatele functor, arg şi =.. sunt utilizate pentru construirea şi
accesarea structurilor arbitrare, predicatul name se ocupă cu atomi arbitrari. Predicatul name
leagă un atom de o listă de caractere (coduri ASCII). Aceasta poate fi utilă fie pentru a găsi
caracterele unui atom dat, fie pentru a găsi atomul care are date anumite caractere. Scopul
name(A,L) semnifică faptul că, “caracterele pentru atomul A sunt membrii ai listei L”.
Dacă argumentul A este iniţializat, Prolog crează o listă de caractere şi încearcă să le
potrivească cu L. În caz contrar, Prolog utilizează lista L pentru a realiza un atom pentru a-l
înlocui pe A.
1.27 Modificarea comportamentului la backtracking
Există două predicate predefinite ce modifică secvenţa normală de evenimente care au
loc pe durata revenirii. În principiu, “!” înlătură posibilităţile de resatisfacere a scopurilor, iar
repeat oferă noi alternative care nu existau înainte.
!
Simbolul “ tăietura ” poate fi considerat ca un predicat predefinit ce impune
sistemului Prolog anumite posibilităţi pe care le are. Pentru mai multe detalii despre “ tăietura
” vezi capitolul 4.
repeat
Predicatul predefinit repeat este furnizat ca o modalitate suplimentară de a genera
soluţii multiple cu ajutorul backtracking-ului. Deşi el este predefinit, poate fi gândit ca având
definiţia următoare:
repeat.
repeat:-repeat.
O problemă care apare cu scopul repeat este aceea că întotdeauna are o soluţie de
refăcut atunci când backtracking-ul o reconsideră. Astfel, backtracking-ul nu va fi niciodată
capabil să reconsidere alternativele alese mai devreme de ultimul apel al scopului repeat,
cu excepţia cazului când gestionăm anularea alegerii printr-un anume mod. Datorită acestui
lucru, definiţia de mai sus trebuie rescrisă astfel:
În regulile şi întrebările de forma X:-Y sau ?-Y, termenul care apare drept Y poate
consta dintr-un singur scop, o conjuncţie de scopuri sau o disjuncţie de scopuri. Mai mult, este
posibil să avem variabile drept scopuri şi să satisfacem un scop în cazul în care el eşuează
folosind not. Predicatele descrise în această secţiune furnizează modalităţi de specificare a
acestor căi complicate de exprimare a scopurilor.
X,Y
Operatorul ”,” specifică o conjuncţie de scopuri. Acest operator a fost introdus în
capitolul 1. Dacă X şi Y sunt scopuri, scopul X,Y reuşeşte dacă X reuşeşte şi dacă Y reuşeşte.
Dacă X reuşeşte şi apoi Y eşuează, atunci se face o încercare de resatisfacere a lui X. Dacă X
eşuează, atunci întreaga conjuncţie eşuează. Aceasta este esenţa backtracking-ului. Operatorul
”,” are o declaraţie încorporată ca un operator infix asociativ la dreapta, astfel încât X,Y,Z
este echivalentă cu X,(Y,Z).
49
X;Y
Operatorul ”;” specifică o disjuncţie (cu înţeles de sau) de scopuri. Dacă X şi Y sunt
scopuri, atunci scopul X;Y reuşeşte dacă X reuşeşte sau dacă Y reuşeşte. Dacă X eşuează,
atunci se face o încercare de satisfacere a lui Y. Dacă Y eşuează apoi, atunci întreaga
disjuncţie eşuează. Putem folosi operatorul “;” pentru a exprima alternative în cadrul
aceleiaşi clauze.
call(X)
Se presupune că X este iniţializat cu un termen care poate fi interpretat ca un scop.
Scopul call(X) reuşeşte dacă o încercare de satisfacere a lui X reuşeşte. Scopul call(X)
eşuează dacă o încercare de satisfacere a lui X eşuează. La prima vedere, acest predicat poate
părea redundant, deoarece cineva s-ar putea întreba de ce argumentul scopului call nu poate
pur şi simplu să apară el însuşi drept scop?
not(X)
Se presupune că X este iniţializat cu un termen care poate fi interpretat ca un scop.
Scopul not(X) reuşeşte dacă o încercare de satisfacere a lui X eşuează. Scopul not(X)
eşuează dacă o încercare de satisfacere a lui X reuşeşte. În acest fel, not se aseamănă cu
call, exceptând faptul că succesul sau eşecul argumentului, interpretat ca un scop, este
inversat.
1.29 Egalitate
Această secţiune se ocupă pe scurt cu diverse predicate predefinite pentru testarea
egalităiţii în Prolog.
X=Y
Când Prolog întâlneşte scopul X=Y, el încearcă să facă pe X şi Y egale prin potrivirea
lor împreună. Dacă le poate potrivi, scopul reuşeşte (atât X cât şi Y pot deveni acum mai
iniţializate). În caz contrar scopul eşuează. O discuţie mai completă despre acest predicat este
dată în secţiunea 2.4. Predicatul de egalitate este definit prin
X=X.
X\=Y
Predicatul “X\=Y” este opusul predicatului “=” în termeni de succes şi eşec. Astfel,
X\=Y reuşeşte dacă X=Y eşuează şi invers. Dacă scopul X\=Y reuşeşte (X şi Y nu pot fi
potrivite), iniţializările lui X şi Y nu vor fi deloc schimbate.
X == Y
Predicatul “==” reprezintă un test de egalitate mult mai strict decât “=”. Astfel, dacă
X==Y reuşeşte atunci şi X=Y reuşeşte tot atât de bine. Pe de altă parte, reciproca nu este
adevărată. Modalitatea prin care “==” este mult mai strictă este dată de modul în care se
consideră variabilele. Predicatul “=” va considera o variabilă neiniţializată ca fiind egală cu
orice altceva, deoarece se va potrivi oricum. Pe de altă parte, “==” va considera doar că o
variabilă neiniţializată este egală cu o altă variabilă neiniţializată care este deja partajată cu ea.
În caz contrar testul va eşua.
50
X\==Y
Acest predicat este pentru “==” acelaşi lucru cum este “\=” pentru “=”. Astfel, un
scop implicând acest predicat va reuşi exact atunci când acelaşi scop pentru “==” va eşua şi
invers.
1.30 Intrări şi ieşiri
Predicatele ce sunt disponibile pentru citirea şi scrierea caracterelor şi termenilor au
fost descrise în capitolul 5. Acum le prezentăm pe scurt pe fiecare.
get0(X)
Acest scop reuşeşte dacă X poate fi potrivit cu următorul caracter întâlnit din şirul
curent de intrare. Scopul get0 reuşeşte doar o dată (el nu poate fi resatisfăcut). Operaţia de
mutare a următorului caracter nu este refăcută la backtracking, deoarece nu exită nici o
modalitate de a pune caracterul înapoi în şirul de intrare curent.
get(X)
Acest scop reuşeşte dacă X poate fi potrivit cu următorul caracter afişabil întâlnit în
şirul de intrare curent. Caracterele afişabile au un cod ASCII care este mai mare decât 32.
Orice caracter neafişabil este ignorat. Scopul get reuşeşte doar o dată (el nu poate fi
resatisfăcut). Operaţia executată de get nu este refăcută la backtracking, deoarece nu exită
nici o modalitate de a pune un caracter înapoi în şirul de intrare curent.
skip(X)
Acest scop citeşte şi ignoră caracterele din şirul curent de intrare până când este găsit
un caracter care se potriveşte cu X. Scopul skip reuşeşte doar o dată.
read(X)
Acest scop citeşte următorul termen din şirul curent de intrare şi îl potriveşte cu X. Un
scop read reuşeşte doar o dată. Termenul trebuie să fie urmat de un punct “.”, care nu este
parte a termenului, şi cel puţin un caracter neafişabil. Punctul este înlăturat din şirul de intrare
curent.
put(X)
Acest scop scrie întregul X ca un caracter în şirul de ieşire curent. Scopul put reuşeşte
doar o dată. Dacă X nu este iniţializat are loc o eroare.
nl
Scrie o secvenţă de control în şirul de ieşire curent ce determină o “linie nouă”. Pe
displayul unui calculator, după folosirea scopului nl toate caracterele apar pe următoarea
linie a paginii. Scopul nl reuşeşte doar o dată.
tab(X)
Scrie o cantitate de X “spaţii“ în şirul de ieşire curent. Are loc o eroare dacă X nu este
iniţializat. Scopul tab reuşeşte doar o dată.
write(X)
Acest scop scrie termenul X în şirul de ieşire curent. Scopul write reuşeşte doar o
dată. Orice variabilă neiniţializată din X este scrisă ca un număr unic de variabilă precedat cu
un “_”, cum ar fi “_239”. Variabilele partajate în cadrul aceluiaşi argument pentru write
51
au acelaşi număr la afişare. Predicatul write ţine cont de declaraţiile operatorului curent
când afişează un termen. De exemplu un operator infix va fi afişat între argumentele sale.
display(X)
Predicatul display lucrează exact în acelaşi mod ca şi write exceptând faptul că
ignoră orice declaraţii de operator. Când este utilizat display, orice structură este afişată
având mai întâi operatorul urmat de argumentele sale în paranteză.
op(X,Y,Z)
Aceast scop declară un operator având clasa de precedenţă X, poziţia şi asociativitatea
Y, şi numele Z. Specificarea poziţiei şi asociativităţii este preluată din următoarele seturi de
atomi:
Dacă declaratia operatorului este legală atunci scopul op va reuşi. Vezi secţiunea 5.5.
pentru mai multe detalii.
1.31 Tratarea fişierelor
Predicatele de care dispune Prolog pentru modificarea şirurilor curente de intrare şi
ieşire pentru fişiere au fost prezentate în capitolul 5. Aici prezentăm pe scurt pe fiecare din
ele.
see(X)
Acest scop deschide fişierul X, dacă nu este deja deschis şi defineşte şirul curent de
intrare ca având sursă fişierul X. Dacă X nu este iniţializat sau dacă numele variabilei X nu
reprezintă un fişier existent, are loc o eroare.
seeing(X)
Acest scop reuşeşte dacă numele şirului de intrare curent se potriveşte cu X, şi eşuează
în caz contrar.
seen
Acest scop închide şirul de intrare curent, şi defineşte şirul de intrare curent ca fiind
tastatura terminalului (calculatorului).
tell(X)
Acest scop deschide fişierul X, dacă nu este deja deschis şi defineşte şirul de ieşire
curent pentru scriere în fişier. Dacă X nu este iniţializat are loc o eroare. Mai întâi tell este
utilizat asupra unui fişier care nu este deja deschis, dacă X denumeşte un fişier care nu există,
atunci este creat un fişier cu acel nume. În caz contrar, dacă X denumeşte un fişier care
există, atunci conţinutul anterior al fişierului este distrus.
telling(X)
Acest scop reuşeşte dacă X corespunde cu numele şirului de ieşire curent, şi eşuează în
caz contrar.
told
Acest scop închide şirul curent de ieşire, determinând ca un marker de sfârşit de fişier
să fie scris în fişier. Şirul curent de ieşire redevine displayul calculatorului.
52
1.32 Evaluarea expresiilor aritmetice
Expresiile aritmetice au fost discutate mai întâi în secţiunea 2.5. În această secţiune
vom prezenta pe scurt folosirea predicatului “is”, şi ce operatori sunt disponibili pentru
construirea expresiilor aritmetice.
X is Y
Y trebuie să fie iniţializat cu o structură ce poate fi interpretată ca o expresie aritmetică
aşa cum este descrisă în secţiunea 2.4. Mai întâi, structura iniţializată pentru Y este evaluată
pentru a furniza un întreg, denumit rezultat. Rezultatul este comparat cu X, şi predicatul is
reuşeşte sau eşuează în funcţie de rezultatul comparării. Operatorii pot fi folosiţi pentru a
realiza structuri diferite de predicatul is, după cum urmează:
X+Y
Este operator de adunare. Când este evaluat cu ajutorul predicatului is, rezultatul său
este suma aritmetică a celor două argumente ale sale. Argumentele trebuie să fie iniţializate cu
întregi sau cu structuri care sunt evaluate drept întregi.
X-Y
Este operator de scădere. Când este evaluat cu ajutorul predicatului is, rezultatul său
este diferenţa aritmetică a celor două argumente ale sale. Argumentele trebuie să fie
iniţializate cu întregi sau cu structuri care sunt evaluate drept întregi.
X*Y
Este operator de înmulţire. Când este evaluat cu ajutorul predicatului is, rezultatul său
este produsul aritmetic a celor două argumente ale sale. Argumentele trebuie să fie iniţializate
cu întregi sau cu structuri care sunt evaluate drept întregi.
X/Y
Este operator de împărţire întreagă. Când este evaluat cu ajutorul predicatului is,
rezultatul său este câtul întreg a celor două argumente ale sale. Argumentele trebuie să fie
iniţializate cu întregi sau cu structuri care sunt evaluate drept întregi.
X mod Y
Este operator modulo întreg. Când este evaluat cu ajutorul predicatului is, rezultatul
său este restul întreg care este generat atunci când X este împărţit cu Y. Argumentele trebuie
să fie iniţializate cu întregi sau cu structuri care sunt evaluate drept întregi.
Anumite implementări particulare de Prolog pot include mai multe operaţii aritmetice,
cum ar fi exponenţierea. Exemplele arătate în această carte necesită doar pe cele arătate mai
sus.
1.33 Compararea numerelor
Prolog furnizează şase predicate pentru compararea numerelor (întregi). Aceste
predicate au fost prezentate mai întâi în secţiunea 2.5. unde am discutat aritmetica. Fiecare
predicat este descris ca un operator infix având două argumente.
X = Y
Predicatul de egalitate, descris în secţiunea 6.8, reuşeşte întotdeauna atunci când cele
două argumente de tip întreg sunt aceleaşi.
53
X /= Y
Predicatul de inegalitate, descris şi el în secţiunea 6.8, reuşeşte atunci când cele două
argumente ale sale nu reprezintă acelaşi întreg.
X < Y
Predicatul mai mic reuşeşte când argumentul întreg din membrul stâng este mai mic
decât argumentul întreg din membrul drept. Ambele argumente trebuie să fie iniţializate.
X > Y
Predicatul mai mare reuşeşte când argumentul întreg din membrul stâng este mai
mare decât argumentul întreg din membrul drept. Ambele argumente trebuie să fie iniţializate,
altfel are loc o eroare.
X >= Y
Predicatul mai mare sau egal reuşeşte când argumentul întreg din membrul
stâng este mai mare sau egal decât argumentul întreg din membrul drept. Ambele argumente
trebuie să fie iniţializate.
X =< Y
Predicatul mai mic sau egal reuşeşte când argumentul întreg din membrul stâng
este mai mic sau egal decât argumentul întreg din membrul drept. Ambele argumente trebuie
să fie iniţializate. Să reţinem faptul că predicatul se scrie “=<” şi nu “<=”, astfel încât “<=”
este liber pentru a fi utilizat ca un alt operator.
1.34 Urmărirea Prolog-ului în lucru
Această secţiune descrie predicatele predefinite ce permit urmărirea programelor pe
timpul execuţiei lor. În continuare vom descrie sumar aceste predicate predefinite, urmând ca
în capitolul 8 să fie studiat mai în detaliu depanarea şi trasarea execuţiei programelor.
trace
Efectul de a satisface scopul trace este de a executa o urmărire exhaustivă. Aceasta
înseamnă că din acest moment se poate urmări fiecare scop pe care îl generează programul, în
fiecare din cele patru porturi principale.
notrace
Efectul scopului notrace este de a opri urmărirea exhaustivă din momentul apelării
ei. Totuşi, este continuată orice urmărire datorită prezenţei punctelor de vizualizare.
spy P
Predicatul spy este utilizat atunci când dorim să acordăm o atenţie specială scopurilor
ce implică anumite predicate specifice. Acest lucru se poate realiza prin setarea punctelor de
vizualizare în cadrul lor. Predicatul este definit ca un operator prefix, astfel încât nu este
necesar să se pună paranteze în jurul argumentului. Argumentul poate fi unul din următoarele:
- Un atom. În acest caz, punctul de vizualizare este pus în toate predicatele ce
utilizează acest atom; totuşi sunt utilizate mai multe argumente.
- O structură de forma Nume/Dimensiune, unde Nume este un atom iar
Dimensiune este un întreg.
- O listă. În acest caz, lista trebuie să fie terminată cu “[]”, şi fiecare element al listei
54
trebuie să fie el însuşi un argument permis predicatului spy. Prolog va pune puncte de
vizualizare în toate locurile specificate în listă.
debugging
Predicatul predefinit debugging permite aflarea tuturor punctelor de vizualizare
care sunt setate în mod curent. Lista punctelor de vizualizare este afişată ca un efect lateral al
satisfacerii scopului debugging.
nodebug
Scopul nodebug determină înlăturarea tuturor punctelor de vizualizare curentă.
nospy
Ca şi operatorul spy, nospy este un operator de tip prefix. Acest operator este mult
mai selectiv decât nodebug, deoarece se poate specifica cu exactitate ce puncte de
vizualizare trebuie să fie înlăturate. Acest lucru se poate face prin furnizarea unui argument în
exact aceeaşi formă ca şi pentru predicatul spy.
55
LECŢIA 6
EXEMPLE DE PROGRAME
Vom presupune că numerele camerelor sunt constante, dar nu contează dacă acestea
sunt integer sau atom. Mai întâi, putem rezolva problema căutării numerelor de cameră din
listă folosind predicatul membru definit în secţiunea 3.3, considerând bucata de hârtie ca
listă. Acum putem trata problema căutării în labirint. Iată un mic exemplu în care avem un
etaj de casă, în care camerele sunt etichetate cu litere astfel:
56
Observaţi că orificiile din pereţi sunt uşile iar spaţiul din afara casei este reprezentat ca
fiind camera a. Sunt uşi între camerele a-b, c-d, f-e, şi aşa mai departe. Faptele care
arată unde sunt uşi pot fi reprezentaţi în Prolog astfel:
d(a,b) .
d(b,e) .
d(b,c) .
d(d,e) .
d(c,d) .
d(e,f) .
d(g,e) .
trece(X,X,T).
Pe de altă parte, vom alege câteva camere intermediare, numite Z, şi vedem dacă am
fost în ele anterior. Dacă nu am fost, atunci vom trece din Z în Y, adăugând Z la listă. Toate
acestea se reprezintă prin următoarele clauze:
trece(X,Y,T):-
d(X,Z),not(membru(Z,T)),trece(Z,Y,{Z|T}).
trece(X,X,T).
trece(X,Y,T):-
d(X,Z),not(membru(Z,T)),trece(Z,Y,[Z|T]).
trece(X,Y,T):-
d(Z,X),not(membru(Z,T)),trece(Z,Y,[Z|T]).
trece(X,X,T).
trece(X,Y,T):-
(d(X,Z);d(Z,X)).
not(membru(Z,T)).
trece(Z,Y,[Y|T]).
? - trece(a,X,[ ]),are_telefon(X).
Această întrebare este o “generare şi testare” , pentru găsirea unei posibile camere,
care are telefon. O altă cale este de a satisface are_telefon(X) primul, atunci când trecem
din camera a în X :
? - are_telefon(X),trece(a,X,[ ]).
Această metodă este mult mai eficientă, dar implică cunoaşterea unde se află telefonul
înainte de a începe căutarea. Iniţializând al treilea argument cu o listă vidă aceasta înseamnă
că la început vom avea o listă vidă. Aceasta poate fi schimbată astfel încât să producă
variante: întrebarea “Găsiţi telefonul fără să intraţi în camerele d şi f ” poate fi exprimată în
Prolog astfel:
?-are_telefon(X), trece(a,X,[d,f]).
58
6.2. Turnurile din Hanoi
Turnurile din Hanoi este un joc ce se joacă cu trei axe şi un set de discuri. Discurile
sunt gradate în diametru, şi ca să intri pe ax fiecare disc are în centru o gaură. Iniţial toate
discurile sunt pe axul din stânga. Scopul jocului este să muţi toate discurile pe axul central.
Axul din dreapta poate fi folosit ca ax de schimb, un loc temporar pentru discuri. De fiecare
dată un disc este mutat de la un pol la altul; două “lucruri” trebuie avute în vedere: numai
discul din vârful axului poate fi mutat şi un disc cu diametrul mai mare nu poate fi pus peste
un disc cu diametrul mai mic.
Mulţi oameni care au jucat acest joc n-au descoperit o strategie simplă şi rapidă ca să
joace corect jocul “Turnurile din Hanoi” cu trei axe şi N discuri. Vă scutim de efortul de a
descoperi relevând aici:
condiţia limită se întâmplă atunci când nu avem discuri pe axul sursă (axul
din stânga).
mutaţi N-1 discuri de la axul sursă la axul de rezervă (din dreapta) folosind
destinaţia ca “temporar”. Observaţi că aceasta este o mişcare recursivă.
mutaţi un singur disc de la polul sursă la polul destinaţie.
în final, mutaţi N-1 discuri de pe polul de rezervă la destinaţie, folosind
sursa ca rezervă.
Programul Prolog ce implementează această strategie este definit după cum urmează.
Am definit un predicat hanoi având un argument, astfel că hanoi(N) înseamnă tipărirea
secvenţei mişcărilor când N discuri sunt pe polul sursă. Cele două clauze muta, prima este
condiţia limită descrisă mai sus şi a doua clauză implementează cazurile recursive, predicatul
muta are patru argumente: primul este numărul discurilor ce vor fi mutate. Celelalte trei
reprezintă axele care sunt: sursă, destinaţie şi rezervă pentru mutarea discurilor. Predicatul
inform foloseşte write pentru tipărirea numerelor axelor implicate în mutarea unui disc.
59
6.3. Procesarea listelor
ultim(X,[X]).
ultim(X,[_|Y]:-ultim(X,Y).
?-ultim(X,[caut, un, breloc]).
X=breloc
consecutiv(X,Y,[X,Y|_].
consecutiv(X,Y,[_|Z]):-consecutiv(X,Y,Z).
?-adauga([a,b,c],[d,e,f],Q).
Q=[a,b,c,d,e,f]
?-adauga([ ],L,L).
adauga([X|L1], L2, [X|L3]):-adauga(L1,L2,L3).
Condiţia limită este atunci când primul argument este listă vidă. Aceasta deoarece
adăugând lista vidă la o listă, aceasta din urmă nu se schimbă. Mai mult, ne vom apropia
treptat de condiţia limită deoarece fiecare rechemare a lui adauga mută încă o dată un
element de la capul primului argument. Atenţie că oricare două argumente ale lui adauga
pot fi instanţiate, şi adauga va instanţia al treilea argument la rezultatul cel mai apropiat.
Această proprietate este adevărată pentru multe predicate definite în acest capitol. Datorită
flexibilităţii lui adauga, putem acum să definim alte câteva predicate astfel:
ultim(El,List):-adauga(_,[El],List).
consecutiv(El1,El2,List):-adauga(_,[El1,El2|_],List).
membru(El,List):-adauga(_,[El|_],List).
60
Inversarea unei liste: scopul invers_lista(L,M) reuşeşte dacă rezultatul
inversării elementelor din lista L este lista M. Programul utilizează un standard tehnic, unde
întoarcerea în listă înseamnă schimbarea primului element din listă cu ultimul. {i ce cale mai
bună de a muta ultimul element avem decât folosirea lui invers_lista ! Condiţia limită
este când primul argument este redus la o listă vidă, în care caz rezultatul este lista vidă.
invers_lista([ ], [ ]).
invers_lista([H|T],L):-
invers_lista(T,Z), adauga(Z,[H],L).
invers_lista(L1,L2):-invers_listaac(L1,[ ],L2).
invers_listaac([X|L],L2,L3):-
invers_listaac(L,[X|L2],L3),
invers_listaac([],L,L).
scoate_X_din_Y(A,[A|L],L):- !.
scoate_X_din_Y(A,[B|L],[B|M]):-
scoate_X_din_Y(A,L,M).
Este uşor a adăuga o clauză astfel încât predicatul să nu eşueze când al doilea
argument este redus la o listă vidă. Noua clauză care reprezintă noua condiţie limită este:
scoate_X_din_Y(_,[ ], [ ] ).
61
Substituirea: Aceasta este aproape similară cu sterge înlocuind ştergerea
elementului dorit cu inserarea altui element în locul lui. Scopul substituire(X,L,A,M)
va realiza construirea unei liste noi M făcută din elementele listei L, cu excepţia faptului că
orice apariţie a lui X va fi înlocuită de A. Sunt trei cazuri. Primul este chiar condiţia limită,
întocmai ca la sterge. Al doilea caz este când X este găsit în al doilea argument şi al treilea
caz este când se găseşte altceva decât X.
substituire(_, [ ],_,[ ] ).
substituire(X,[X|L],A,[A|M]):-!,
substituire(X,L,A,M).
substituire(X,[Y|L],A,[Y|M):-
substituire(X,L,A,M).
Subliste: Lista X este o sublistă a listei Y dacă fiecare parte din X apare şi în Y,
consecutiv şi în aceeaşi ordine. Următorul scop reuşeşte:
sublist([la,club],[lume,multa,la,club,astazi]).
Programul sublist necesită două predicate: unul care găseşte primul element care
se potriveşte şi unul care asigură că ceea ce rămâne din prima potrivire a primului argument
se potriveşte element cu element cu ceea ce rămâne din al doilea argument:
sublist([X|L],[X|M]):- prefix(L,M),!
sublist(L,[_|M]):- sublist(L,M).
prefix([ ],_).
prefix([X|L],[X|M]):-prefix(L,M).
Eliminarea duplicatelor: Predicatul elimin_duplicat şterge direct o listă de
orice elemente şi face o listă nouă. Deşi lista poate conţine elemente în duplicat la intrare, la
ieşire lista va conţine câte un exemplar din fiecare element. Scopul
elimin_duplicat(L,M) construieşte din lista L o nouă listă M în care dublurile dispar.
Definiţia foloseşte un predicat auxiliar duplicat_acum în care acumulatorul (vezi
secţiunea 3.7) este argument secund, iniţializat la lista vidă. Se foloseşte de asemenea
predicatul membru de la secţiunea 3.3.
elimin_duplicat(L,M):- duplicat_acum(L,[ ],M).
duplicat_acum([ ],A,A).
duplicat_acum([H|T],A,L):-membru(H,A),
duplicat_acum(T,A,L).
duplicat_acum([H|T],A,L):-
duplicat_acum(T,[H|A],L).
Predicatul duplicat_acum are trei clauze. Prima este condiţia limită, când lista de
intrare este vidă, rezultatul fiind trecut într-un acumulator. A doua clauză verifică dacă
următorul element din listă este un membru al listei acumulate. Dacă este, revenim simplu la
coadă, fără nici o schimbare a acumulatorului. Altfel, folosind următoarea clauză, revenim la
coada listei de intrare, cu un acumulator care are adăugat un nou element (H).
Maparea: o tehnică puternică este capacitatea de a converti o listă în altă listă prin
aplicarea unei funcţii fiecărui element al primei liste, folosind ca rezultate succesive
elementele aflate în cea de-a doua listă. Programul din capitolul 3, pentru schimbarea unei
propoziţii în alta, este un exemplu de mapare. Spunem că facem "maparea unei propoziţii în
alta".
62
6.4. Reprezentarea şi manipularea mulţimilor
Mulţimea este una dintre cele mai importante structuri de date utilizate în matematică,
operaţiile cu mulţimi găsindu-şi aplicaţii în programarea pe calculator. O mulţime este o
colecţie de elemente, asemenea unei liste, în care ordinea enumerării elementelor nu este
importantă.
Astfel, mulţimea {1,2,3} este la fel cu mulţimea {2,3,1}, deoarece problema este
dacă un element dat este sau nu al mulţimii. Mulţimile pot, de asemenea, avea alte mulţimi în
calitate de elemente. Operaţia de bază asupra unui mulţimi este de a determina dacă un
element aparţine unei mulţimi date. Nu este surprinzător faptul că o reprezentare convenabilă
pentru mulţimi este aceea de liste. O listă poate conţine elemente arbitrare, inclusiv alte liste şi
este posibilă definirea unui predicat de apartenenţă la o listă. Cu toate acestea, când
reprezentăm o mulţime ca o listă, vom aranja ca lista să aibă doar un element pentru fiecare
obiect aparţinând mulţimi. Legăturile cu listele, fără duplicarea elementelor, simplifică unele
operaţii cum ar fi ştergerea elementelor. Vom trata doar listele fără duplicate. Predicatele
descrise în această secţiune menţin această proprietate. Este uzuală definirea următoarelor
operaţii peste mulţimi. Vom folosi notaţii matematice uzuale pentru acelea care sunt uzuale:
Apartenenţa: X Y
X este un membru al unui mulţimi Y dacă X este un element al lui Y.
Exemplu: a {c,a,t}
Submulţime: X Y
Mulţimea X este un submulţime a mulţimii Y dacă fiecare element al lui X este de
asemenea element al lui Y. Y poate conţine unele elemente pe care X nu le are.
Exemplu: {x,r,u} {p,q,r,s,t,u,v,w,x,y,z}
Intersecţie: X Y
Intersecţia mulţimilor X şi Y este mulţimea care conţine acele elemente care sunt
comune atât lui X cât şi lui Y.
Exemplu: {r,a,p,i,d} {p,i,c,t,u,r,a}={r,i,p,a}.
Reuniunea: X Y
Reuniunea mulţimilor X şi Y este mulţimea conţinând elementele din X sau Y, sau din
ambele luate o singură dată.
Exemplu: {a,b,c} {c,d,e}={a,b,c,d,e}
Există operaţii de bază care sunt în mod normal folosite pentru manipularea
mulţimilor. Putem scrie acum programe în Prolog care să le implementeze pe fiecare în parte.
Prima operaţie de bază, calitatea de membru, este acelaşi predicat membru pe care l-am
văzut de câteva ori înainte. Totuşi, definiţia sa pe care o folosim nu conţine simbolul
"tăietura" în cazuri limită astfel că putem genera elemente succesive ale listei prin
backtracking.
membru(X,[X|_]).
membru(X,[_|Y]):-membru(X,Y).
submultime[A|X],Y):-membru(A,Y),submultime(X,Y).
submultime([ ],Y).
reuniune([],X,X).
reuniune([X|R,Y,Z):-membru(X,Y),!,reuniune(R,Y,Z).
reuniune([X|R],Y,[X|Z]):-reuniune(R,Y,Z).
Aceasta încheie repertoarul nostru de predicate dedicate procesării unei mulţimi. Deşi
mulţimile nu se pot prezenta în tipul de programare pe care intenţionăm să-l facem, merită
osteneala să studiem aceste exemple pentru a obţine o înţelegere bună a modului cum putem
face recursivitate şi backtracking.
Bibliografie
64