inteligenta artificiala- teorie
Embed Size (px)
TRANSCRIPT

Introducere in programarea Introducere in programarea nonprocedurala (PNP)
Ruxandra Stoeanhttp://inf.ucv.ro/[email protected]

Motivatia necesitatii PNP
• In cadrul paradigmelor de programare un locaparte il ocupa programarea nonprocedurala.
• Programarea nonprocedurala cuprinde:▫ Programarea logica▫ Programarea functionala.▫ Programarea functionala.
• Programarea nonprocedurala mai poartanumele de programare declarativa.

Plasarea PNP
Programare
Nonprocedurala
ProceduralaOrientata pe
obiecteConcurenta ...
FunctionalaLogica

Avantajele programelor PNP
Sunt orientate catre implementari logice.Sunt orientate catre implementari logice.Sunt extrem de potrivite pentru sistemele expert
apartinand domeniului inteligentei artificiale.Sunt usor de analizat, transformat, verificat,
intretinut.In general, sunt eficiente si competitive inIn general, sunt eficiente si competitive in
comparatie cu programele nedeclarative.Programul este mai degraba “intrebat” decat
executat.

Dezavantajeleprogramelor PNP
Nu sunt usor implementabile si utilizabile pentrualgoritmii matematici de cautare si optimizare dincadrul inteligentei artificiale.
Nu sunt cele mai potrivite pentru exprimareaalgoritmilor folositi in industrie.algoritmilor folositi in industrie.
Au mecanisme mai putin directe decat ale celornedeclarative si sunt considerate de multe ori mai“neprietenoase”.

Programare LOGICA versus programare FUNCTIONALA. Schema
Programare logica Programare functionala
• Adunarea a doua numere • Adunarea a doua numere
Out DirectionatDirectionat
aduna
In In In/Out
aduna
In In
NedirectionatNedirectionat

Programare LOGICA versus programare FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Adunarea a doua numere • Adunarea a doua numere
aduna
3 4 X =
aduna
3 4

Programare LOGICA versus programare FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Adunarea a doua numere • Adunarea a doua numere
7
aduna
3 4 X = 7
aduna
3 4

Programare LOGICA versus programare FUNCTIONALA. Scrierea simbolica
Programare logica Programare functionala
• Adunarea a doua numere
aduna In × In × In/Out
aduna(3, 4, X)
• Adunarea a doua numere
aduna(In, In) Out
aduna(3, 4)
X = 7 7

Programare LOGICA versus programare FUNCTIONALA. Schema
Programare logica Programare functionala
• Patratul sumei a doua numere
patrat
In In/Out
• Patratul sumei a doua numereOut
patratIn
Out
aduna
In In In/Out
aduna
In In

Programare LOGICA versus programare FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Patratul sumei a doua numere
patrat
• Patratul sumei a doua numere
patrat
aduna
3 4
aduna
3 4

Programare LOGICA versus programare FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Patratul sumei a doua numere
patrat
• Patratul sumei a doua numere
patrat
7
aduna
3 4 X = 7
aduna
3 4

Programare LOGICA versus programare FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Patratul sumei a doua numere
patrat
Y = 49
• Patratul sumei a doua numere49
patrat
7
aduna
3 4 X = 7
aduna
3 4

Programare LOGICA versus programare FUNCTIONALA. Scrierea simbolica
Programare logica Programare functionala
• Patratul sumei a doua numere
aduna(3, 4, X), patrat(X, Y)
X = 7 patrat(7, Y)
• Patratul sumei a doua numere
patrat(aduna(3, 4))
patrat(7)
X = 7 Y = 49 49

Programare LOGICA versus programare FUNCTIONALA. Schema
Programare logica Programare functionala
• Testarea egalitatii
succes/esec
• Testarea egalitatiisucces/esec
=
In Out
aduna
In In In
aduna
In In

Programare LOGICA versus programare FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Testarea egalitatii • Testarea egalitatii
=
7
aduna
3 4 7
aduna
3 4

Programare LOGICA versus programare FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Testarea egalitatii
succes
• Testarea egalitatii
=
7 7
aduna
3 4 7
aduna
3 4

Programare LOGICA versus programare FUNCTIONALA. Schema. Exemplu
Programare logica Programare functionala
• Testarea egalitatii
succes
• Testarea egalitatiisucces
=
7 7
aduna
3 4 7
aduna
3 4

Programare LOGICA versus programare FUNCTIONALA. Scrierea simbolica
Programare logica Programare functionala
• Testarea egalitatii
aduna(3, 4, 7)
succes
• Testarea egalitatii
7 = aduna(3, 4)
7 = 7
succes

Scopurile acestui curs
Programare logica Programare functionala
• Notiuni avansate alelimbajului PROLOG.
• Implementari pretabileprogramarii logice.
• Notiuni de baza ale limbajuluiLISP.
• Implementari pretabileprogramarii functionale.
• Intelegerea particularitatilorprogramarii logice.
• Observarea diferentelor fata deprogramarea functionala.
• Intelegerea particularitatilorprogramarii functionale.
• Observarea diferentelor fata deprogramarea logica.

Consecintele acestui curs• Cunostinte elementare asupra programarii
neprocedurale.neprocedurale.• Intelegerea diferentelor fata de programarea
nedeclarativa.• Observarea tipurilor de probleme care sunt
pretabile programarii neprocedurale si a celorcare sunt potrivite programarii nedeclarative.
• Obtinerea unei note bune la examen• Obtinerea unei note bune la examen▫ Proba practica (proba laborator) 50% Dezvoltarea unui program in Prolog Dezvoltarea unui program in Lisp
▫ Test grila (proba scrisa) 50%

PROLOG
• Numele este o abreviere pentru PROgrammation enLOGique.LOGique.
• Prima versiune a fost creata in 1972 de catre Alain Colmerauersi Philippe Roussel, bazandu-se pe interpretarea clauzelorHorn data de catre Robert Kowalski.
• Vom folosi versiunea Swi-Prolog.
• Bibliografie: • Bibliografie: ▫ Leon Sterling, Ehud Shapiro, The Art of Prolog, Second Edition:
Advanced Programming Techniques (Logic Programming), MIT Press, 1994.
▫ Internet.

LISP• Numele provine de la LISt Processing.
• Codul LISP se scrie sub forma listelor parantetizate (sau s -expresii).
• Prima versiune a aparut in 1958 si a fost dezvoltata de catreSteve Russell, Timothy P. Hart si Mike Levin, bazandu-se pecalculul lambda al lui Alonzo Church.
• Vom folosi versiunea CLISP.• Vom folosi versiunea CLISP.
• Bibliografie:▫ Stuart C.Shapiro, Common Lisp: An Interactive Approach,
Computer Science Press, 1992.▫ Internet.

I know what you did last summer… term
• A trecut mult de anul trecut…
• Nu prea mai tinem minte de atunci…
• Prolog, am mai facut noi Prolog?...
• A, Prolog, limbajul acela urat…• A, Prolog, limbajul acela urat…
• Sa recapitulam asadar notiunile de baza dinProlog.

Ce trebuie sa ne amintim din Prolog?
• Fisierul Prolog• Descrierea relatiilor• Descrierea relatiilor
▫ Fapte▫ Reguli
• Numere, atomi, variabile, operatii• Unificare• Recursivitate• Recursivitate• Liste
▫ Accesare elemente▫ Unificare

Fisierul Prolog• Se deschide programul Notepad.• Se acceseaza File / Save As.• Se acceseaza File / Save As.• In cadrul optiunii File Name se va scrie numele
fisierului, urmat de extensia .pl:▫ nume.pl, de exemplu.
• In final, in campul Save as Type se completeaza cuAll Files.
• Se face dublu-click pe fisier:• Se face dublu-click pe fisier:▫ Directorul curent devine cel in care se afla fisierul▫ Fisierul este compilat
• Daca se mai opereaza modificari asupra sa,compilarea se face prin [nume].
Fara extensia .pl!Fara extensia .pl!

Descrierea relatiilor in Prolog
• Faptele – ceea ce stim despre problema:▫ nume_relatie(arg1, arg2, …, argN).
In Prolog, orice
predicat se incheie cu
punct!
In Prolog, orice
predicat se incheie cu
punct!
Numele relatiilor incep cu litera
mica!
▫ nume_relatie(arg1, arg2, …, argN).
▫ nume_relatie este numele relaţiei (alpredicatului) iar arg1, arg2, … - argumentele.
▫ N reprezintă aritatea predicatului nume_relatie.
punct!punct!
▫ Exemplu: frate(dan, maria).
▫ Un predicat de aritate 0 se poate defini simplu:nume_predicat.

Descrierea relatiilor in Prolog
• Regulile (legaturi logice) – definesc predicate pebaza altor predicatebaza altor predicate▫ nume_relatie(arg1, …, argN) :-
nume_relatie_1(…), …, nume_relatie_M(…).• Două predicate care au acelaşi nume, dar un
număr diferit de argumente se consideră că suntpredicate diferite.
• Fiecare predicat dintr-un program este definitde existenţa uneia sau mai multor clauze.
• Clauzele care definesc acelasi predicat se aflauna lângă alta în fişierul sursă.

Tipuri de termeni in Prolog
• Argumentele unui predicat Prolog se numesc termeni si pot avea urmatoarele tipuri:termeni si pot avea urmatoarele tipuri:
▫ Numere pozitive sau negative.
▫ Atomii – text care începe cu literă mică.
▫ Variabilele – încep cu literă mare sau underline ▫ Variabilele – încep cu literă mare sau underline (_).

Tipuri de termeni in Prolog• Numerele:
▫ -12, 7.1, 24 ▫ -12, 7.1, 24
• Atomii:▫ Sunt alcatuiti de obicei din litere şi cifre, având
primul caracter o literă mică. ▫ salut, douaCuvinteAlaturate, un_atom, a2 sunt ▫ salut, douaCuvinteAlaturate, un_atom, a2 sunt
atomi▫ nu-este-atom, 5nu, _faraunderline, Literamare nu
sunt atomi▫ ’acesta-este-atom’, ’inca un atom’, ’Atom’ - atomi

Tipuri de termeni in Prolog• Variabilele:
▫ Sunt asemănatoare atomilor, cu excepţia că ele ▫ Sunt asemănatoare atomilor, cu excepţia că ele încep cu literă mare sau cu underline (_).
▫ Variabila, _variabila, Alta_vaRiabila2 sunt variabile.
• Variabila anonima:▫ Sunt variabilele care incep cu underline (_).▫ Apare in doua cazuri:▫ Apare in doua cazuri: Cand valoarea unei variabile nu este folosita in
cadrul unui clauze. In lucrul cu predicatul fail.

Variabila anonima - continuare• Variabila nu este folosita in cadrul unui predicat:
semn(X, 1) :- X >= 0.semn(X, 1) :- X >= 0.semn(_X, -1).
• In lucrul cu predicatul fail:parinte(andrei, dan).parinte(andrei, laura).copii(Tata) :- parinte(Tata, Copil), tab(2), copii(Tata) :- parinte(Tata, Copil), tab(2),
write_ln(Copil), fail.copii(_OriceVariabila).

Operaţii matematice in Prolog• Pentru evaluarea unei expresii aritmetice, se
foloseste predicatul predefinit is:foloseste predicatul predefinit is:▫ X is <expresie aritmetică>.▫ suma(N1, N2, S) :- S is N1 + N2.
• Operatori matematici utilizati:▫ <, >, =<, >=, == (sau =), =\= (sau \=).▫ Ultimii doi operatori sunt pentru a verifica▫ Ultimii doi operatori sunt pentru a verifica
egalitatea dintre două numere, respectiv pentru averifica dacă două numere sunt diferite.

Operaţii matematice in Prolog• Scrierea 2+3 nu reprezintă o instrucţiune care
păstrează rezultatul acestei adunări.păstrează rezultatul acestei adunări.• Reprezintă mai degrabă atomul ‘adunarea lui 2 cu 3’.• Termenul 2+3 este diferit de termenul 4+1.
numar(3).numar(4).numar(5).? – numar(2 + 1).? – numar(2 + 1).No? – X is 2 + 1, numar(X).X = 3Yes

Unificarea in Prolog• Reprezinta modul în care Prologul realizează
potrivirile între termeni:potrivirile între termeni:▫ X = marian. Yes
▫ marian = andrei. No
▫ place(maria, X) = place(Y, andrei). Y = maria, X = andrei Y = maria, X = andrei
▫ f(X, a) = f(a, X). X = a
▫ place(maria, X) = place(X, andrei). No

Recursivitatea in Prolog
• Programarea în Prolog depinde foarte mult deacest principiu.acest principiu.
• Prolog-ul este important si fiindca ne invata sagandim recursiv.
• Recursivitatea implică definirea unui predicat înfuncţie de el însuşi.
• Mecanismul recursivitatii consta in faptul caîntotdeauna definim predicatul la o scală maiîntotdeauna definim predicatul la o scală maimică.
• Este echivalentă cu demonstrarea prin inducţiedin matematică.

Recursivitatea in Prolog• O definitie recursiva are doua parti:
▫ Conditia elementara.▫ Conditia elementara.▫ Partea recursiva.
• Condiţia elementară defineşte un caz simplu, care ştim că este întotdeauna adevărat.
• Partea recursivă simplifică problema eliminând iniţial un anumit grad de complexitate şi apoi apelându-se ea însăşi.apelându-se ea însăşi.
• La fiecare nivel, condiţia elementară este verificată: ▫ dacă s-a ajuns la ea, recursivitatea se încheie;▫ altfel, recursivitatea continuă.

Recursivitatea in Prolog• Factorialul:
factorial(0,1). factorial(N,F) :- N>0, N1 is N-1, factorial(N1,F1), F factorial(N,F) :- N>0, N1 is N-1, factorial(N1,F1), F
is N * F1.
?- factorial(3, X).X = 6

Recursivitatea in Prolog• Implementarea functiilor recursive, de exemplu,
Fibonacci:Fibonacci:
f(1) = 1, f(2) = 1, f(n) = f(n - 1) + f(n - 2)
fibonacci(1, 1).fibonacci(2, 1).fibonacci(N, F):- N1 is N – 1, N2 is N – 2, fibonacci(N, F):- N1 is N – 1, N2 is N – 2,
fibonacci(N1, F1), fibonacci(N2, F2), F is F1 + F2.
?- fibonacci(3, X).X = 2

Liste in Prolog
• Data viitoare… • Data viitoare…

Liste• Sunt structuri care se folosesc pentru reprezentarea unei
secvenţe ordonate de termeni Prolog.
2/56
secvenţe ordonate de termeni Prolog.▫ [doar, un, exemplu]▫ []▫ [a, b, c, d, e]▫ [1, 21, 4, -17]▫ [4, [6], c, [-1, 12]]
• Virgula folosită în construcţia listelor este doar un• Virgula folosită în construcţia listelor este doar unseparator de argumente.
• Listele sunt secvenţe ordonate de termeni Prolog, decilista [a,b,c] nu este aceeaşi cu lista [a, c, b].

Accesarea elementelor unei liste
• Pentru a accesa elementele unei liste, putem
3/56
• Pentru a accesa elementele unei liste, putem împarţi lista în două părţi: primul element (dacă există unul!) şi restul listei.
• Ce se obtine din apelul urmator:▫ ? - [X|Y] = [a, b, c, d].
X = aY = [b, c, d]

Accesarea elementelor unei liste• Ce se obtine din apelul urmator:
▫ ? - [X|Y] = [a, b, c, d].
4/56
▫ ? - [X|Y] = [a, b, c, d].
• Primul element din listă, a, se numeşte şi capul listei (HEAD).
X = aY = [b, c, d]
• Lista formată prin ştergerea capului reprezintă coadalistei iniţiale (TAIL): [b, c, d].
▫ Ea poate fi mai departe prelucrată si este referita prin variabila Y.

• Presupunem că avem lista X = [b, c, d] şi vrem să
Adaugarea unui element la o lista
5/56
• Presupunem că avem lista X = [b, c, d] şi vrem să adăugăm elementul a la începutul listei X:
• Lista_rezultat = [a | X].• Cum scriem programul care face acest lucru?
adauga(A, X, Y):- Y=[A|X].adauga(A, X, Y):- Y=[A|X].
X – lista initialaA – elementul de adaugatY – lista care se va obtine

• Se pot adăuga (sau elimina) şi mai multe
Adaugarea de elemente la o lista
6/56
• Se pot adăuga (sau elimina) şi mai multeelemente odată.
• Dacă dorim, de exemplu, să adăugam laînceputul listei X elementele a, b şi c, pentruobţinerea unei liste Y:obţinerea unei liste Y:
• Y = [a, b, c | X]

Stergere de elemente dintr-o lista
• Dacă vrem să luam trei elemente din capul listei
7/56
• Dacă vrem să luam trei elemente din capul listeiX astfel încât lista rămasă Y să poată fi folositămai departe în cadrul programului:
• X = [A, B, C | Y]
• Lista vidă se notează cu [ ] si, evident, aceasta nupoate fi descompusă.

Unificarea la liste
• [a, b, c] = [c, a, b] ▫ întoarce No pentru că ordinea termenilor
8/56
▫ întoarce No pentru că ordinea termenilor contează
• [X] = [a, b, c] ▫ întoarce No pentru că cele două liste au lungimi
diferite
• [X|Y] = [doar, un ,exemplu] ▫ întoarce răspuns pozitiv şi X = doar, iar Y = [un,
exemplu]

Unificarea la liste
• [X,Y|Z] = [a, b, c, d] ▫ întoarce Yes şi X = a, Y = b, Z = [c, d]
9/56
▫ întoarce Yes şi X = a, Y = b, Z = [c, d]
• [X|Y] = [] ▫ întoarce No pentru că lista vidă nu poate fi
descompusă
• [X|Y] = [[a, [b, c]],d] • [X|Y] = [[a, [b, c]],d] ▫ întoarce Yes şi X = [a,[b, c]] şi Y = [d]
• [X|Y] = [a] ▫ întoarce Yes şi X = a, Y = []

Unificarea la liste
• [a, b | X] = [A, B, c]
10/56
• [a, b] = [b, a]
• [a | [b, c]] = [a, b, c]
• [a, [b, c]] = [a, b, c]• [a, [b, c]] = [a, b, c]
• [a, X] = [X, b]

Unificarea la liste
• [a | []] = [X]
11/56
• [a, b, X, c] = [A, B, Y]
• [H | T] = [[a, b], [c, d]]
• [[X],Y] = [a, b]• [[X],Y] = [a, b]

Afisarea elementelor unei liste• Pentru afişarea elementelor unei liste vom face
apel la recursivitate.
12/56
apel la recursivitate.
• Luăm elementele din listă, unul câte unul, şi leafişăm.
• Momentul de oprire a algoritmului este atuncicând lista va fi goală.când lista va fi goală.
• Aşadar, condiţia elementară (de oprire arecursivităţii) va fi când lista e vidă.

Afisarea elementelor unei liste
Adauga trei spatii
13/56
afis([]).afis([Prim | Rest]) :- write(Prim), tab(3),
afis(Rest).
spatii

Apartenenta unui element la o lista
Are 2 argumente
14/56
• Vom defini predicatul apartine/2, unde primulargument reprezintă elementul pentru careverificăm apartenenţa, iar al doilea este lista.
• X aparţine listei dacă este capul listei sau dacă
argumente
• X aparţine listei dacă este capul listei sau dacăaparţine coadei acesteia.

Apartenenta unui element la o lista
• Altfel spus, clauza care testeaza unificarea dintre elementuldat si capul listei reprezintă condiţia de oprire a recursivităţii,
15/56
dat si capul listei reprezintă condiţia de oprire a recursivităţii,clauza care se verifică la fiecare reapelare a predicatuluiapartine.
apartine(X, [X | _]).apartine(X, [Y | Rest]) :- apartine(X, Rest).
?- apartine (3, [1, 3, 2]).?- apartine (3, [1, 3, 2]).Yes.
?- apartine (4, [1, 3, 2]).No.

Apartenenta unui element la o lista
16/56

Numarul elementelor dintr-o lista
• Dacă lista este vidă, numarul elementelor sale
17/56
• Dacă lista este vidă, numarul elementelor saleeste zero: aceasta este condiţia de oprire arecursivităţii.
• În clauza recursiva, primul element din listă nune interesează, vrem doar să îl eliminăm ca sănumărăm câte elemente are lista rămasă.numărăm câte elemente are lista rămasă.
• N-ul curent va fi, de fiecare data, egal cu 1 plusnumărul elementelor din lista rămasă.

Numarul elementelor dintr-o lista
18/56
nr_elem([], 0). nr_elem([_ | Rest], N) :- nr_elem(Rest, N1), N is
N1 + 1.
?- nr_elem([1, 2, 3], X).
X = 3

Suma elementelor dintr-o lista• Dacă lista este vidă, suma elementelor sale este
zero: aceasta este condiţia de oprire a
19/56
zero: aceasta este condiţia de oprire arecursivităţii.
• În clauza recursiva, primul element din listă neinteresează de data aceasta, dupa care calculamsuma elementelor din lista rămasă.
• S-ul curent va fi, de fiecare data, egal cuelementul curent plus suma elementelor dinlista rămasă.

Suma elementelor dintr-o lista
20/56
suma([], 0).suma([P|Rest], S) :- suma(Rest, S1), S is S1 + P.
?- suma([1, 2, 3], X).?- suma([1, 2, 3], X).
X = 6

Media elementelor unei liste
• Media unei liste se calculeaza drept suma elementelor din lista / numarul acestora.
21/56
elementelor din lista / numarul acestora.
media(L) :- nr_elem(L, N), suma(L, S), Media is S/N, write('Media este '), write(Media).
?- media([1, 2, 3]).?- media([1, 2, 3]).
Media este 2.

Ultimul element dintr-o lista
22/56
• Condiţia de oprire este ca X să fie ultimul element din listă – coada listei este o listă vidă.
• Daca restul listei curente nu este vid, ignoram capul listei.capul listei.

Ultimul element dintr-o lista
ultim([X | []], X).
23/56
Echivalent putem scrie ultim([X],X).
ultim([X | []], X).ultim([_ | Rest], X) :- ultim(Rest, X).
?- ultim([1, 2, 3], X).
X = 3X = 3

Maximul unei liste
• Consideram primul element al listei ca fiind maximul.
24/56
• Apelam un alt predicat ce are drept argumente lista ramasa si elementul considerat.
• Parcurgem restul listei; daca gasim un element (capul listei curente) mai mare decat maximul, acesta va deveni noul maxim.
• Altfel, mergem mai departe in restul listei.
• Recursivitatea se incheie cand ajung la lista vida si afisez argumentul corespunzator maximului.

Maximul unei liste
max([P|Rest]) :- Max = P, max1(Rest, Max).
25/56
max1([], Max) :- write('Maximul este '), write(Max).
max1([P|R], Max) :- P > Max, max1(R, P); max1(R, Max).
?- max([4, 2, 5, 1]).Maximul este 5.

Pozitia pe care se afla maximul unei liste
26/56
• Consideram primul element al listei ca fiindmaximul si stabilim pozitia maximului drept 1.
• Apelam un alt predicat ce are drept argumente:▫ lista ramasa▫ elementul considerat drept maxim▫ elementul considerat drept maxim▫ pozitia pe care se afla acesta▫ si un contor care va numara elementele.

Pozitia pe care se afla maximul unei liste
• Parcurgem lista; daca gasim un element (capul noii
27/56
• Parcurgem lista; daca gasim un element (capul noiiliste) mai mare decat maximul:▫ acesta va deveni noul maxim▫ pozitia pe care se afla maximul devine contorul curent▫ si se incrementeaza contorul.
• Altfel, mergem mai departe in restul listei,incrementand contorul.incrementand contorul.
• Recursivitatea se incheie cand ajung la lista vida siafisez argumentul corespunzator pozitiei pe care seafla maximul.

Pozitia maximului unei liste
poz_max([P|Rest]) :- poz_max(Rest, P, 1, 1).
28/56
poz_max([P|Rest]) :- poz_max(Rest, P, 1, 1).
poz_max([], _, _, Poz) :- write('Maximul se gaseste pe pozitia '), write(Poz).
poz_max([P|R], Max, Contor, Poz) :- Contor1 is Contor + 1, Max < P, poz_max(R, P, Contor1, Contor1).
poz_max([_|R], Max, Contor, Poz) :- Contor1 is Contor + 1, poz_max(R, Max, poz_max(R, Max,
Contor1, Poz).
?- poz_max([4, 2, 5, 1]).Maximul se gaseste pe pozitia 3

Compararea lungimilor a doua liste• Predicatul va avea ca
argumente doua liste si va
29/56
argumente doua liste si vaintoarce unul din urmatoareleraspunsuri posibile:▫ Liste egale
▫ Prima este mai lunga▫ A doua este mai lunga▫ A doua este mai lunga
• Se parcurg cele doua liste, ignorand capetele, pana una din ele se termina.

Compararea lungimilor a doua liste
compar([],[]):-write('Cele doua liste au acelasi
30/56
compar([],[]):-write('Cele doua liste au acelasinumar de elemente.').
compar(_L, []):-write('Prima lista are mai multeelemente decat cea de a
doua!').compar([], _L):-write('A doua lista are mai multecompar([], _L):-write('A doua lista are mai multe
elemente decat prima!').compar([_X|R1], [_Y|R2]) :- compar(R1, R2).

Compararea lungimilor a doua liste?- compar([1,2,3], [4, 5]).
31/56
Prima lista e mai lunga
?- compar([1,2], [4, 5]).
Cele doua liste sunt egale
?- compar([1,2], [3, 4, 5]).
A doua lista e mai lunga

Inversarea unei liste
• Se apeleaza un predicat care, pe langa listainitiala si lista in care depunem rezultatul,
32/56
initiala si lista in care depunem rezultatul,contine si o lista temporara care este initial vida.
• Capul listei curente se adauga la inceputul listeitemporare – acesta era initial goala, decielementele se vor adauga in ordine inversa.elementele se vor adauga in ordine inversa.
• Cand lista care trebuie inversata devine vida,unificam lista finala cu cea temporara.

Inversarea unei liste
inv(L, Linv) :- inv1(L, [], Linv).
33/56
inv(L, Linv) :- inv1(L, [], Linv).
inv1([], L, L).inv1([X|Rest], Temp, L) :- inv1(Rest, [X|Temp],
L).
?- inv([1, 2, 3], L).L = [3, 2, 1]

Interclasarea a doua liste
• Ce presupune interclasarea?
34/56
• Ce presupune interclasarea?
• Avem doua liste care trebuie unite intr-una singura.
• Cele doua liste trebuie sa fie ordonate crescator.• Cele doua liste trebuie sa fie ordonate crescator.
• Elementele listei rezultate trebuie sa fie de asemenea in ordine crescatoare.

Interclasarea a doua liste
• Capetele celor doua liste ce trebuie unite se compara.
35/56
compara.
• Cel mai mic dintre ele se va adauga la lista rezultat.
• Daca sunt egale, se adauga doar o data.• Daca sunt egale, se adauga doar o data.
• Daca una dintre ele este vida, lista rezultat este cealalta.

Interclasarea a doua listeinterclasez([], L, L).interclasez(L, [], L).
36/56
interclasez(L, [], L).interclasez([P1|R1], [P2|R2], [P1|R3]) :- P1 < P2,
interclasez(R1, [P2|R2], R3).interclasez([P1|R1], [P1|R2], [P1|R3]) :-
interclasez(R1, R2, R3).
interclasez(R1, [P2|R2], [P2|R3]) :- interclasez(R1, interclasez(R1, [P2|R2], [P2|R3]) :- interclasez(R1,
R2, R3).
?- interclasez([1, 3, 7], [2, 3, 4, 8], L).L = [1, 2, 3, 4, 7, 8]

Prefixul si sufixul unei liste• Prefixul unei liste reprezinta primele N elemente
ale unei liste.
37/56
ale unei liste.
• Sufixul unei liste reprezinta ultimele M elementeale unei liste.
• Prefixul ar putea fi asociat cu primele slide-uridin lista care formeaza acest curs.din lista care formeaza acest curs.
• Iar sufixul… ultimele slide-uri (sufixul e maifrumos)

Prefixul unei liste• Pentru a testa daca o lista e prefixul altei liste,
compar element cu element cele doua liste.
38/56
compar element cu element cele doua liste.
• Adica, verific daca elementul cap al unei listeprefix este egal cu cel al listei complete.
• Daca raspunsul este afirmativ, merg maideparte.departe.
• Prima lista e prefix a celei de-a doua daca, la unmoment dat, lista prefix se incheie.

Prefixul unei liste
prefix([], _L).
39/56
prefix([], _L).prefix([X|R1], [X|R2]) :- prefix(R1, R2).
?- prefix([1,2], [1, 2, 3]).Yes
?- prefix([1,3], [1, 2,3]).No

Sufixul unei liste
• Pentru a testa daca o lista e sufixul altei liste,parcurg lista completa pana intalnesc exact lista
40/56
parcurg lista completa pana intalnesc exact listasufix.
• Adica, scot elementul cap al listei mari, panacand cele doua liste sunt egale.
• Recursivitatea se opreste deci cand cele douaargumente sunt egale.

Sufixul unei liste
sufix(L, L).
41/56
sufix(L, L).sufix(L, [_Y|Rest]) :- sufix(L, Rest).
?- sufix([1,2,3],[1,2]).No
?- sufix([1, 2, 3], [3]).Yes

Sublista unei liste
• O lista va fi sublista unei alte liste daca este
42/56
• O lista va fi sublista unei alte liste daca este sufixul prefixului listei mari.
Prefixul listei mari
Sufixul prefixului listei mari

Sublista unei listesublista(L1, L2):-prefix(L, L2), sufix(L1, L).
?- sublista([1,2], [3,1,2,5,6]).
43/56
?- sublista([1,2], [3,1,2,5,6]).Yes?- sublista([1,2], [3, 1, 4, 5, 2])No
L2
L
L1

Pozitii pare, pozitii impare9 0 3 2 4 5 6 7
44/56
• Enunt problema:
▫ Se dă o listă: să se obţină două liste din aceasta astfel încât prima din ele să conţină elementele de pe poziţiile pare iar a doua pe cele de pe poziţiile impare.
• Vom avea asadar o singura lista ca argument de intrare si doua liste ca argumente de iesire.
• Tratam intai situatia in care lista data contine un singur element, apoi cand lista are doua elemente.

parimpar([X], [], [X]).
Pozitii pare, pozitii impare9 0 3 2 4 5 6 7
45/56
parimpar([X], [], [X]).parimpar([X, Y],[Y], [X]).parimpar([X, Y|R], [Y|R1], [X|R2]) :- parimpar(R, R1, R2).
• In cea de a treia clauza, mutam primul element X din lista data in lista a treia, iar pe cel de-al doilea, Y, in a doua lista.
• Interogare:• Interogare:▫ ? – pare([ion, marius, mananca, invata, mere, prolog], P, I). P = [marius, invata, prolog] I = [ion, mananca, mere]

parimpar([X], [], [X]).
Pozitii pare, pozitii impare9 0 3 2 4 5 6 7
46/56
parimpar([X], [], [X]).parimpar([X, Y],[Y], [X]).parimpar([X, Y|R], [Y|R1], [X|R2]) :- parimpar(R, R1, R2).
• Cea de a treia clauza a programului poate fi scrisa sub forma urmatoare:
parimpar([X, Y|R], Pare, Impare):-parimpar(R, Pare1, Impare1), Pare = [Y|Pare1], Impare=[X|Impare1].

Pozitia i dintr-o lista
• Enuntul problemei:
47/56
• Enuntul problemei:
▫ Dându-se o listă şi un număr întreg pozitiv i, să se găsească elementul aflat pe poziţia i în listă.
• Avem doua argumente de intrare, o lista si un numar care da pozitia care ne intereseaza.
• Cum rezolvam problema: scadem i-ul cu cate o unitate si, in acelasi timp, scoatem cate un element din lista. Cand i-ul este 1, primul element din lista este cel cautat.

Pozitia i dintr-o lista
pozi([X|_], 1, X).
48/56
pozi([X|_], 1, X).pozi([_A|R], I, X) :- I1 is I - 1, pozi(R, I1, X).
• Asadar, al treilea argument al predicatului pozi ia valoarea primului element din lista atunci cand al doilea argument este egal cu 1.
• Altfel, i este scazut, iar din lista data ca primul argument • Altfel, i este scazut, iar din lista data ca primul argument extragem un element la apelarea recursiva.
• Interogarea:▫ ? - pozi([mere, portocale, pere, gutui], 2, Ce). Ce = portocale

Pozitia unui element intr-o lista1 4 6 7 8 9 0 3 2 4 5 6 7
49/56
• Enunt problema:▫ Având date o listă şi un element care aparţine
acestei liste, să se specifice pe ce poziţie este situat elementul în lista dată.
• Avem doua argumente de intrare:▫ Lista in care se gaseste elementul▫ Lista in care se gaseste elementul▫ Elementul pentru care trebuie sa gasim pozitia
• Vom mai construi un predicat care sa contina si o variabila contor care este initial 1.

Pozitia unui element intr-o lista
pozx(L, X, P):- pozx(L, X, 1, P).
1 4 6 7 8 9 0 3 2 4 5 6 7
50/56
pozx(L, X, P):- pozx(L, X, 1, P).pozx([X|_], X, P, P).pozx([_|R], X, C, P) :- C1 is C + 1, pozx(R, X, C1, P).
• Predicatul pozx cu 4 argumente este vazut ca unul diferit de cel cu acelasi nume dar cu 3 argumente.
• Conditia de oprire: primul element din lista corespunde cu elementul dat. elementul dat.
▫ In acest moment, contorul se unifica cu variabila aflata pe pozitia patru.
• In concluzie, ideea este ca se scot elemente din lista pana cand pe prima pozitie se afla chiar ceea ce cautam.

Pozitia unui element intr-o lista1 4 6 7 8 9 0 3 2 4 5 6 7
51/56
pozx(L, X, P):- pozx(L, X, 1, P).pozx([X|_], X, P, P).pozx([_|R], X, C, P) :- C1 is C + 1, pozx(R, X, C1, P).
• Interogarea:▫ ? – pozx([ion, petre, marin, olivia], marin, P).▫ ? – pozx([ion, petre, marin, olivia], marin, P). P = 3

Stergerea aparitiilor unui element dintr-o lista
52/56
• Enunt problema:▫ Să se şteargă toate apariţiile unui element dintr-o
listă.• Avem doua argumente de intrare:
▫ Lista din care se vor sterge aparitiile unui element▫ Elementul care trebuie sters▫ Elementul care trebuie sters
• Argumentul de iesire va fi noua lista carenu va mai contine elementul dat.

Stergerea aparitiilor unui element dintr-o lista
sterg([], _, []).
53/56
sterg([], _, []).sterg([N|Rest], N, Rez) :- sterg(Rest, N, Rez).sterg([M|Rest], N, [M|Rez]) :- sterg(Rest, N, Rez).
• Se parcurge lista data element cu element si, daca elementul aflat in capul listei este chiar cel cautat, nu se copiaza in lista rezultat. Altfel, se copiaza.
• Atunci cand lista data este vida, si lista rezultat este initializata cu • Atunci cand lista data este vida, si lista rezultat este initializata cu lista vida.
• Interogare:▫ ? – sterg([1, 4, 6, 8, 6, 12, 6], 6, L). L = [1, 4, 8, 12]

Eliminarea duplicatelor
• Enunt problema:
54/56
• Enunt problema:▫ Scrieţi un predicat Prolog care să realizeze
eliminarea duplicatelor dintr-o listă dată.• Argument de intrare:
▫ O lista data• Argument de iesire:
▫ Lista rezultata prin eliminarea duplicatelor din ▫ Lista rezultata prin eliminarea duplicatelor din lista data.
• Vom face uz de predicatul apartine/2 prezentat mai devreme.

Eliminarea duplicatelor
duplicate([], []).
55/56
duplicate([], []).duplicate([X|R1], L) :- apartine(X, R1), duplicate(R1, L).duplicate([X|R1], [X|R2]) :- duplicate(R1, R2).
• Luam fiecare element din prima lista si verificam daca apartine restului listei (adica daca mai apare in lista).▫ Daca nu mai apare, atunci il adaugam in lista rezultat▫ Altfel, nu il adaugam.▫ Altfel, nu il adaugam.
• Interogare▫ ? – duplicate([7, 9, 7, 11, 11], L). L = [9, 7, 11]

Pe saptamana viitoare!
56/56
Pe saptamana viitoare!

Ce sunt structurile?
2/41
• Cea mai mare parte din informaţia pe care vrem să o reprezentăm într-un program este compusă, adică ea constă din entităţi care au mai multe atribute diferite
▫ De exemplu, entitatea persoană poate avea mai multe atribute precum vârstă, înăltime, greutate etc.
• În programele realizate până acum, am utilizat numai fapte şi • În programele realizate până acum, am utilizat numai fapte şi reguli care foloseau structuri de date simple.
▫ Argumentele predicatelor folosite au fost atomi sau numere.
• Aceste date simple pot însă fi combinate pentru a construi tipuri de date complexe numite structuri.

• O structură constă dintr-un functor şi un număr fix
3/41
Ce sunt structurile?
• O structură constă dintr-un functor şi un număr fix de argumente:
structura(arg1, arg2, …, argn)
• Fiind un termen, structura poate să apară în cadrul unei clauze oriunde poate apărea o variabilă sau o constantă.
• Precum toţi ceilalţi termeni folosiţi anterior, nici structurile nu trebuie declarate▫ Le folosim direct în cadrul programului, acolo unde
avem nevoie de ele.

4/41
Ce sunt structurile?
• Deşi arată precum predicatele, nu funcţionează ca acestea.
▫ Predicatele sunt relatii, iar structurile sunt obiecte.
▫ Diferenţa dintre cele două este realizată de către Prolog după locul în care apar într-o clauză. Prolog după locul în care apar într-o clauză.
• Structurile nu apar niciodată singure, ci doar ca argumente pentru predicate.

Exemplu de utilizare a unor structuri
5/41
student(adrian, prezente(8), proiect(bun)).student(marius, prezente(2), proiect(copiat)).student(andreea, prezente(9), proiect(bun)).student(ovidiu, prezente(4), proiect(slab)).
• Daca vrem sa aflam care sunt studentii care pot sa ia o nota • Daca vrem sa aflam care sunt studentii care pot sa ia o nota peste 7, putem folosi interogarea:▫ ? – student(X, prezente(Y), proiect(bun)), Y > 6, writeln(X), fail.
adrianandreea

Exemplu de utilizare a unor structuri
6/41
student(adrian, prezente(8), proiect(bun)).student(marius, prezente(2), proiect(copiat)).student(andreea, prezente(9), proiect(bun)).student(ovidiu, prezente(4), proiect(slab)).
• Daca vrem sa aflam care sunt studentii care nu vor intra in • Daca vrem sa aflam care sunt studentii care nu vor intra in examen, putem folosi interogarea:▫ ? – student(X, prezente(_Y), proiect(copiat)), writeln(X), fail.
mariusUnderline-ul indică faptul cănu suntem interesaţi devaloarea cu care este unificatacest câmp.

7/41
Alt exemplu de utilizare a unor structuri
• O structura poate avea si mai mult de un singur argument (cum a fost cazul in exemplul precedent).
• Exemplu:
are(ionut, calculator(asus, ‘3 Ghz’, ‘RAM 1 GB’)).are(ionut, calculator(asus, ‘3 Ghz’, ‘RAM 1 GB’)).
are(ovidiu, calculator(hp, ‘2.7 Ghz’, ‘RAM 512 MB’)).
are(ovidiu, calculator(dell, ‘2.4 Ghz’, ‘RAM 512 MB’)).

Arbori binari• Un arbore binar are proprietatea că pentru un nod
părinte: ▫ fiecare nod aflat în partea stângă a sa are o valoare numerică
8/41
▫ fiecare nod aflat în partea stângă a sa are o valoare numerică mai mică decât a sa şi
▫ fiecare nod aflat în partea dreaptă a nodului părinte are o valoare mai mare decât a sa.
8
4 11
3 6 9 16

Arbori binari
• Pentru reprezentarea în Prolog, presupunem că fiecare nod are câte două legături către alţi arbori:
9/41
câte două legături către alţi arbori: ▫ una către subarborele stâng ▫ una către subarborele drept
arb(8, arb(4, arb(3, n, n), arb(6, n, n)), arb(11, arb(9, n, n), arb(16, n, n)))
Se reprezinta asadar sub forma
8
asadar sub forma unei structuri
compuse. 4 11
3 6 9 16

Arbori binari• Scrieţi un predicat Prolog care să calculeze suma
elementelor arborelui.
10/41
elementelor arborelui.
suma(n, 0).suma(arb(R, n, n), R).suma(arb(Radacina, S, D), Suma) :- suma(S, S1),
suma(D, S2), Suma is Radacina + S1 + S2.

Arbori binari• Scrieţi un predicat Prolog care să verifice
existenta unui număr dat într-un arbore binar.
11/41
existenta unui număr dat într-un arbore binar.
cauta(n, _):- write(‘Nu exista.’).cauta(arb(X, _, _), X):- write(‘Numarul exista.’).cauta(arb(Rad, S, _D), X) :- X < Rad, cauta(S, X).cauta(arb(_Rad, _S, D), X) :- cauta(D, X).cauta(arb(_Rad, _S, D), X) :- cauta(D, X).

Arbori binari• Scrieţi predicate Prolog care să realizeze parcurgerea
unui arbore binar în preordine, în inordine şi în
12/41
unui arbore binar în preordine, în inordine şi în postordine.
• Preordine: 1. Vizitam radacina.2. Vizitam subarborele stang in preordine.3. Vizitam subarborele drept in preordine.3. Vizitam subarborele drept in preordine.
• Parcurgerea:▫ 8, 4, 3, 6, 11, 9, 16.

Parcurgerea in preordine
13/41
• preord(n).• preord(arb(Rad, S, D)) :-writeln(Rad),
preord(S), preord(D).

Parcurgerea in inordine• Inordine:
1. Vizitam subarborele stang in inordine.
14/41
1. Vizitam subarborele stang in inordine.2. Vizitam radacina.3. Vizitam subarborele drept in inordine.
• Parcurgerea:▫ 3, 4, 6, 8, 9, 11, 16

Parcurgerea in postordine• Postordine:
1. Vizitam subarborele stang in postordine.
15/41
1. Vizitam subarborele stang in postordine.2. Vizitam subarborele drept in postordine.3. Vizitam radacina.
• Parcurgerea:▫ 3, 6, 4, 9, 16, 11, 8

Inordine si postordine?
16/41
• Cum se implementeaza in Prolog?
▫ Solutia este triviala si ramane ca tema.

Inserarea unui element intr-un arbore binar
17/41
• Realizaţi un predicat Prolog care să realizeze inserarea unui element in cadrul arborelui.
Unde este locul
meu?...8
4 11
3 6 9 16
10

Inserarea unui element intr-un arbore binar
• Realizaţi un predicat Prolog care să realizeze inserarea unui element in cadrul arborelui.
18/41
inserarea unui element in cadrul arborelui.
8
4 11
3 6 9 16
10

Inserarea unui element intr-un arbore binar
19/41
ins(Val, n, arb(Val, n, n)).ins(Val, arb(Rad, L_T, R_T), Rez) :- Val < Rad,
ins(Val, L_T, Rez1), Rez = arb(Rad, Rez1, R_T).ins(Val, arb(Rad, L_T, R_T), Rez) :- Val > Rad,
ins(Val, R_T, Rez1), Rez = arb(Rad, L_T, Rez1).

Intrari si iesiri in PrologIntrari si iesiri in Prolog
Altfel spus, cum citim dintr-un fisier si cum scriem Altfel spus, cum citim dintr-un fisier si cum scriem intr-unul folosind Prologul.

Intrari si iesiri in Prolog
• Orice sursă sau destinaţie de date este numită în
21/41
• Orice sursă sau destinaţie de date este numită în Prolog stream (canal de intrare, sau de ieşire).
•
• Cele mai utilizate predicate pentru citirea şi scrierea datelor sunt, evident, read şi write.
Vom folosi si altele candvom invata sa lucram cuvom invata sa lucram cucaractere si string-uri inProlog.

Intrari si iesiri in Prolog
22/41
• Atat write/1 cat si read/1 au un singur argument şi folosesc canalul curent de ieşire, respectiv de intrare.
▫ Cele predefinite sunt ecranul şi tastatura. ? – read(X), write(‘Am citit termenul’), tab(1),
write(X).write(X).
▫ La citire, dupa scrierea termenului care trebuie citit, se pune punct (.).

• Pentru a citi dintr-un fişier nu trebuie decât să
Intrari in Prolog
23/41
• Pentru a citi dintr-un fişier nu trebuie decât să facem din fişierul respectiv canalul curent.
• Predicatele care fac acest lucru sunt:
▫ see(F) – fişierul dat ca argument devine fişier de intrare curent. intrare curent. Fişierul F este deschis pentru citire, iar pointerul de
fişier este poziţionat la începutul lui.
▫ seen – închide fişierul de intrare curent şi stabileşte canalul de intrare tastatura.

• Pentru a scrie într-un fişier trebuie să facem din fişierul
Iesiri in Prolog
24/41
• Pentru a scrie într-un fişier trebuie să facem din fişierul respectiv canalul curent.
• Predicatele care fac acest lucru sunt:▫ tell(F) – deschide fişierul F pentru scriere şi îl face fişier
de ieşire curent. Dacă fişierul există deja, conţinutul său este şters, altfel, fişierul
este creat.
▫ append(F) – face acelasi luru ca si tell/1, cu deosebirea ca, daca fisierul exista, continutul sau nu este sters, ci se scrie in continuare.
▫ told – închide fişierul de ieşire curent stabilind ca stream de ieşire ecranul.

Intrari/iesiri in Prolog
• Predicatul read(-Term) citeşte în variabila Term următorul
25/41
• Predicatul read(-Term) citeşte în variabila Term următorul termen din fişierul de intrare. ▫ Termenul citit trebuie să se termine cu caracterul punct în
cadrul fişierului.
• Există o constantă specială în Prolog, end_of_file, care este returnată atunci când s-au citit toate datele dintr-un fişier.
• Un fişier Prolog poate fi încărcat din interiorul unui alt • Un fişier Prolog poate fi încărcat din interiorul unui alt fişier, cu ajutorul predicatului consult(NumeFisier).
• nl provoacă trecerea la o linie următoare (new line), iar tab(N) adaugă N spaţii faţă de poziţia la care este situat pointerul în canalul de ieşire curent.

Exemplu
26/41
• Avem fişierul de intrare in.txt care conţine câte un numărurmat de caracterul punct pe fiecare linie. Scrieţi în fişierulpare.txt numerele conţinute în in.txt care sunt pare, iar înimpare.txt numerele care sunt impare.

Separarea elementelor pare de cele impare
27/41
separ([], [], []).separ([P|R1], L2, [P|R2]) :- Rest is P mod 2, Rest = 1,
separ(R1, L2, R2).separ([P|R1], [P|R2], L2) :- separ(R1, R2, L2).

Afisarea elementelor unei liste
28/41
afis([]).afis([P|R]) :- write(P), nl, afis(R).

Citirea din in.txt si scrierea in pare.txtsi impare.txt
29/41
exemplu :- see('in.txt'), citesc([]), seen, write('Totul este gata').
citesc(L) :- read(N), N \= end_of_file, append(L, [N], Rez), citesc(Rez).
citesc(L) :- separ(L, Pare, Impare), pare(Pare), impare(Impare).citesc(L) :- separ(L, Pare, Impare), pare(Pare), impare(Impare).
pare(L) :- tell('pare.txt'), afis(L), told.impare(L) :- tell('impare.txt'), afis(L), told.

Rularea programului
30/41
• Scriem mai intai intr-un fisier text cateva numere urmate de caracterul punct, fiecare aflate pe cate un rand.▫ Il salvam la aceeasi locatie unde se afla si programul.

Rularea programului
31/41

Alt exemplu
32/41
• Dacă fisierul in.txt conţine câte un număr urmat depunct pe fiecare linie, scrieţi un predicat Prolog care săintroducă în fişierul suma.txt mesajul Suma este urmatde valoarea sumei numerelor din in.txt.
• Cum se rezolva?• Cum se rezolva?▫ Avem acelasi cod de la programul precedent pentru citirea
elementelor intr-o lista.▫ Se calculeaza apoi suma elementelor din lista si se scrie
aceasta in fisierul suma.txt.

Sau… gasim o alta rezolvare
33/41
suma:- see('in.txt'), tell('suma.txt'), calc(0), told, seen.
calc(S) :- read(N), N \= end_of_file, S1 is S + N, calc(S1).calc(S) :- write('Suma este '), write(S).

Selectati numerele prime
34/41
• Având fişierul in.txt dat ca in exemplele precedente, realizaţi un predicat Prolog care să scrie în fişierul prime.txt numai acele numere care sunt prime. ▫ Citim toate numerele intr-o lista, ca la exemplul
initial (predicatul citesc/1), apoi selectam initial (predicatul citesc/1), apoi selectam numerele prime intr-o lista pe care o afisam apoi in fisierul tinta. Simplu, nu?

Verificarea daca un numar este prim
35/41
prim(N) :- prim(N, 2).
prim(N, K) :- I is N/2, K > I.prim(N, K) :- R is N mod K, R \= 0, K1 is K + 1,
prim(N, K1).

Fara sa folosim o lista temporara…
prime :- see('in.txt'), tell('prime.txt'), told, calcul, seen.
calcul :- read(X), X \= end_of_file, verific(X), calcul.calcul.
verific(X) :- prim(X), append('prime.txt'), write_ln(X), verific(X) :- prim(X), append('prime.txt'), write_ln(X), told.
verific(_).

37/41
Selectati numerele prime

Ordonarea unui sir de numere
38/41
• Având în fişierul de intrare in.txt câte un număr urmat de caracterul punct pe fiecare linie, construiţi un predicat Prolog care să scrie în fişierul ordonat.txt şirul de numere ordonat crescător.▫ Citim numerele din in.txt intr-o lista, le ordonam in alta lista
si le scriem apoi in fisierul ordonat.txt.si le scriem apoi in fisierul ordonat.txt.▫ O sa facem in continuare numai ordonarea elementelor unei
liste.▫ Pentru aceasta, vom folosi metoda quicksort care utilizeaza
mecanismul divide et impera.

Ordonarea elementelor unei liste
39/41
sortez([], []).sortez([P|Rest], Lrez):- selectez(P, Rest, Mici, Mari),
sortez(Mici, MiciSort), sortez(Mari, MariSort), append(MiciSort, [P|MariSort], Lrez).
selectez(_, [], [], []).selectez(P, [P1|Rest], [P1|Mici], Mari):- P1 < P,
selectez(P, Rest, Mici, Mari).selectez(P, [P1|Rest], Mici, [P1|Mari]):- selectez(P, Rest,
Mici, Mari).

Rularea algoritmului de sortare
40/41
• Citirea elementelor dintr-un fisier si scrierea elementelor • Citirea elementelor dintr-un fisier si scrierea elementelor sortate in fisierul sortat urmeaza sa fie facute de…

Pe saptamana viitoare!
41/41
Pe saptamana viitoare!

Backtracking - exemplu
• Sa consideram programul:
2/32
• Sa consideram programul:
natural(0).natural(N) :- natural(N1), N is N1 + 1.
• Ce va genera Prolog-ul in urma unui apel de• Ce va genera Prolog-ul in urma unui apel deforma:
? – natural(N), write(N), nl, sleep(1), fail.

Backtracking - exemplu
• Se va genera un ciclu infinit:▫ numerele succesive sunt generate prin
3/32
▫ numerele succesive sunt generate prinbacktracking.
• Primul număr natural este generat şi afişat.
• Apoi fail forţeaza backtracking-ul să acţioneze.• Apoi fail forţeaza backtracking-ul să acţioneze.
• A doua clauză este apelată, generând numerenaturale succesive.

Generare numere naturale
4/32

Un alt exemplu de backtracking
prefixN(N, [N]).
5/32
prefixN(N, [N]).prefixN(N, [N|L]) :- N1 is N + 1, prefixN(N1, L).
• Pentru a folosi backtrackingul, avem nevoie de un apel de forma:
? - prefixN(1, L), write(L), nl, sleep(1), fail.? - prefixN(1, L), write(L), nl, sleep(1), fail.
• Acesta generează o infinitate de liste care încep cu valoarea N.

Generare de liste incrementale care incep cu un element dat
6/32

Backtracking
• Backtracking-ul în Prolog este asadar foarte uşor
7/32
• Backtracking-ul în Prolog este asadar foarte uşor de utilizat.
• Predicatul fail/0 este cel care duce la forţarea backtrackingului: ▫ el întoarce întotdeauna un rezultat negativ şi duce ▫ el întoarce întotdeauna un rezultat negativ şi duce
la reapelarea predicatelor care se află înaintea sa, ori de câte ori este posibil.

Permutari
• Sa generam permutările muţimii {a, b, c, d}folosind backtracking-ul in acest scop.
8/32
folosind backtracking-ul in acest scop.• Mai intai definim cele 4 litere:
litera(a).litera(b).litera(c).litera(c).litera(d).

Permutari
permutare(X, Y, Z, T) :- litera(X), litera(Y), litera(Z), litera(T), X \= Y, X \=Z, Y \= Z, X \=T, Y\=T,Z \=T.
9/32
litera(T), X \= Y, X \=Z, Y \= Z, X \=T, Y\=T,Z \=T.
permutari :- permutare(X, Y, Z, T), write(X), tab(1), write(Y), tab(1), write(Z), tab(1), write(T), nl, fail.
permutari.
• Apelăm simplu, predicatul permutari:• Apelăm simplu, predicatul permutari:
? – permutari.

Permutari
• Iata permutarile rezultate:
10/32

Taietura (Cut)• Uneori însă, din cauza backtracking-ului, sunt
întoarse rezultate nedorite.
11/32
întoarse rezultate nedorite.
• Pentru evitarea acestora, Prologul ne vine înajutor, prin ceea ce se numeşte taietura.
• Cu ajutorul acestui procedeu, Prologul oferăposibilitatea opririi backtrackingului.posibilitatea opririi backtrackingului.
• Procedeul se mai numeşte cut şi se notează cusemnul exclamării (!).

Taietura (Cut)
12/32
• Tăietura face ca Prologul să blocheze toatedeciziile făcute până la momentul apariţiei sale(adică a semnului exclamării).
• Asta înseamnă că, dacă backtracking-ul era îndesfăşurare, el va fi oprit şi nu se vor mai căutadesfăşurare, el va fi oprit şi nu se vor mai căutaalte alternative pentru ce se găseşte înainte detăietură (!).

Exemplulocul(1, simion).locul(2, maria).
13/32
locul(2, maria).locul(3, sorin).locul(3, cristian).
? – locul(3, Nume), write(Nume), nl, fail.sorincristiancristian
? – locul(3, Nume), !, write(Nume), nl, fail.sorin

Mai adaugam:despre(1, ' este castigatorul
concursului.').
14/32
? – spune(3).concursului.').despre(1, ' primeste 100$.').despre(2, ' a câştigat locul II.').despre(2, ' primeste 50$.').despre(3, ' a castigat locul III').despre(3, ' primeste 25$.').spune(Loc) :- locul(Loc, Cine),
? – spune(3).sorin
a castigat locul IIIprimeste 25$.
cristiana castigat locul IIIprimeste 25$.spune(Loc) :- locul(Loc, Cine),
write(Cine), nl, despre(Loc, Despre), tab(3), write(Despre), nl, fail.
primeste 25$.

Cut• Dacă vrem însă să ştim care este primul dintre
cei care au luat locul trei şi câteva lucruri despre
15/32
cei care au luat locul trei şi câteva lucruri despreel, avem nevoie de tăietură - adăugăm lapredicatul spune/1 semnul exclamării astfel:
spune(Loc) :- locul(Loc, Cine), write(Cine), nl, !,despre(Loc, Despre), tab(3), write(Despre), nl,fail.fail.
• Acum, după adăugarea făcută, backtrackingul seva aplica numai asupra predicatelor aflate dupasemnul exclamării.

Taietura• Tăietura se foloseşte de obicei în interiorul unui
predicat unde Prolog-ul a găsit primul răspuns
16/32
predicat unde Prolog-ul a găsit primul răspuns posibil despre care se doresc mai multe detalii.
• Sau pentru a forţa un predicat să întoarcă un răspuns negativ (adică fail) într-o anumită situaţie şi nu vrem să caute alte soluţii.
• Tăietura însă, în general, măreşte complexitatea codului decât să o simplifice, iar utilizarea ei este codului decât să o simplifice, iar utilizarea ei este bine să fie evitată pe cât posibil: ▫ se spune chiar că ea reprezintă goto-ul
programării logice.

1
32
4 5 6 7
Arbori si grafuri
1
2 4
3
5
7
6 8
9

Arbori
18/32
1
32
• Cum reprezentam acest arbore?
4 5 6 7

Arbori
% tata(X,Y) - X este tatal lui Y
19/32
1
32
tata(0,1).tata(1,2).tata(1,3).tata(2,4).tata(2,5).
4 5 6 7
Aceasta confirma faptul ca 1 este radacina arborelui.
tata(2,5).tata(2,6).tata(3,7).
1 este radacina arborelui.

Parcurgere in adancime
20/32
1
32
• Care ar fi parcurgerea in adancime a acestui arbore?
4 5 6 7
• 1, 2, 4, 5, 6, 3, 7

Parcurgere in adancime
21/32
Gaseste toti X care au o anumita relatie cu un Y dat; acestia
se pun in lista L
1
32
findall(X, relatie(X,Y), L)
parcurgere:-tata(0, Rad), p([Rad]).
se pun in lista L
4 5 6 7
p([]).p([Nod|Rest]) :- write(Nod), tab(2), findall(D,
tata(Nod, D), LC), append(LC, Rest, Stiva), p(Stiva).

Parcurgere in adancime
22/32
?-parcurgere.
1
32?-parcurgere.
4 5 6 7

Parcurgere in latime
23/32
1
32
• Care ar fi parcurgerea in latime a acestui arbore?
• 1, 2, 3, 4, 5, 6, 7
4 5 6 7
• 1, 2, 3, 4, 5, 6, 7

Parcurgere in latime
24/32
1
32
parcurgere_latime:-tata(0, Rad), c([Rad]).
c([]).
4 5 6 7
c([]).c([P|Rest]) :- write(P), tab(2), findall(D, tata(P,
D), LC), append(Rest, LC, Coada), c(Coada).

Parcurgere in latime
?-parcurgere_latime.
25/32
1
32
4 5 6 7

Grafuri orientate
26/32
1 5 9
• Cum reprezentam acest graf?
2 4
3 7
6 8
• Cum reprezentam acest graf?

Grafuri orientate
marc(1, 2).marc(1, 4).
27/32
1 5 9
marc(1, 4).marc(1, 5).marc(3, 2).marc(3, 7).marc(4, 3).marc(5, 6).
2 4
3 7
6 8
marc(5, 6).marc(6, 8).marc(7, 6).marc(9, 8).

Grafuri orientate
28/32
1 5 9
• Sa determinam toate drumurile intre doua
2 4
3 7
6 8
• Sa determinam toate drumurile intre doua noduri ale acestui graf.

Grafuri orientate
29/32
1 5 9
drum :- write('Introduceti nodul de start: '), read(X), write('Introduceti nodul destinatie: '),
2 4
3 7
6 8
read(X), write('Introduceti nodul destinatie: '), read(Y), drum(X, Y, L), write_ln(L), fail.
drum.

Grafuri orientate
30/32
1 5 9
drum(X, Y, L) :- drum(X, Y, [X], L).
drum(X, X, L, L).
2 4
3 7
6 8
drum(X, X, L, L).drum(X, Y, L, Lista) :- marc(X, Z),
not(member(Z, L)), append(L, [Z], L1), drum(Z, Y, L1, Lista).

Grafuri orientate
?- drum.
31/32
1 5 9
2 4
3 7
6 8

Pe saptamana viitoare!
32/32
Pe saptamana viitoare!

Scrierea şi citirea caracterelor
• Prologul are predicate predefinite folosite
2/36
• Prologul are predicate predefinite folositepentru scrierea şi citirea câte unui caracter.
• Predicatul put/1 va scrie un singur caracter.
• Din păcate insă, argumentul trebuie să fie unîntreg care reprezintă caracterul ASCII.întreg care reprezintă caracterul ASCII.

Scrierea caracterelor
• Deci, pentru scrierea mesajului merge, ar trebui
3/36
• Deci, pentru scrierea mesajului merge, ar trebui să apelăm:
? - put(109), put(101), put(114), put(103), put(101).
• Evident însă, oricine ar prefera să folosească:• Evident însă, oricine ar prefera să folosească:
? – write(’merge’).

Scrierea caracterelor
4/36
• Dacă folosim însă ca argument la predicatulwrite/1 un mesaj scris între ghilimele:▫ ne vor fi afişate chiar valorile întregi care
reprezintă fiecare caracter în cod ASCII.
? – write(”merge”).? – write(”merge”).[109, 101, 114, 103, 101]

Scrierea caracterelor
5/36
• Având astfel lista de valori numerice, este simplu de realizat un predicat recursiv care sa scrie toate caracterele, rând pe rând.
scriestringul([]).scriestringul([P|R]) :- put(P), tab(1), scriestringul([P|R]) :- put(P), tab(1),
scriestringul(R).

Scrierea caracterelor
? - scriestringul(”merge”).
6/36
? - scriestringul(”merge”).

Citirea caracterelor7/36
• Pentru citirea unui caracter folosim predicatul get/1:▫ acesta citeşte doar primul caracter din cele
introduse.
• Poate fi introdus orice caracter.• Poate fi introdus orice caracter.

Citirea caracterelor
• La citire, nu mai trebuie să incheiem, după ce am
8/36
• La citire, nu mai trebuie să incheiem, după ce am introdus caracterul de citit, cu punct (.).
• Punctul poate fi chiar caracterul de citit.
• Dacă citirea se face dintr-un fişier, verificarea de sfârşit de fişier se face comparând valoarea dată sfârşit de fişier se face comparând valoarea dată ca argument la predicatul get/1 cu –1.

Citirea caracterelor
• Predicatul citesc/0 definit în continuare, citeşte
9/36
• Predicatul citesc/0 definit în continuare, citeşteun caracter şi afişează valoarea sacorespunzătoare în codul ASCII:
citesc :- write('Introduceti un caracter:'), get(C),nl, write(Valoarea caracterului '), put(C), write(’in cod ASCII este:’), write(C).in cod ASCII este:’), write(C).

Citirea caracterelor
?-citesc.
10/36

Predicate predefinite la stringuri
• Deja am folosit mai devreme stringuri:▫ ele sunt atomi simpli, scrişi însă între ghilimele
11/36
• Trecerea de la atomi la lista care conţinenumere întregi în cod ASCII se face prinintermediul predicatului
• string_to_list(+String, -Ascii) sau • string_to_list(+String, -Ascii) sau • string_to_list(-String, +Ascii)

String -> List
? – string_to_list(string, Valoare).
12/36
? - string_to_list(String, [99,101,118,97]).

Concatenare stringuri
• string_concat(+String1, +String2, -String3)
13/36
• string_concat este un predicat similar lui atom_concat/3, cu singura deosebire că argumentul de ieşire aici este de tipul string. ▫ De subliniat faptul că argumentele de intrare sunt ▫ De subliniat faptul că argumentele de intrare sunt
date ca atomi.

Concatenare stringuri
? - string_concat(campu, lung, Tot).
14/36
?- string_concat(campu, Ce, campulung).

Lungime sir de caractere
• string_length(+String, -Lungime)
15/36
? - string_length(‘un string mare de tot’, M).
? - string_length(altceva, M).

String <-> Atom
• string_to_atom(+String, -Atom) sau • string_to_atom(-String, +Atom)
16/36
?- string_to_atom("string de transformat", Atom).
?- string_to_atom(String, exemplu).?- string_to_atom(String, exemplu).

Determinarea subsirului unui sir• sub_string(+String, +Start, +Lungime, -Rest, -
Substring)
• Primul argument este sirul de caractere din care
17/36
• Primul argument este sirul de caractere din care extragem un subşir.
• Start este un întreg pozitiv care dă poziţia de la care selectăm subşirul.
• Al treilea argument dă lungimea subşirului.
• Rest este tot un întreg pozitiv care spune câte poziţii mai sunt până la sfârşitul şirului iniţial.
• Iar ultimul argument reprezintă chiar subşirul căutat.

Determinarea subsirului unui sir
?- sub_string('Alin e tare nebun', 0, 11, Rest, Valoare).
18/36
?- sub_string('Alin e tare nebun', _, 5, 0, Valoare).

Determinarea subsirului unui sir
?- sub_string('Alin e tare nebun', 5, Cat, 6, Valoare).
19/36
?- sub_string('Alin e tare nebun', Inceput,Cat,Rest,nebun).

Determinarea subsirului unui sir
• De subliniat că şi în cazul acestui predicat, ca şi la string_concat/3:▫ argumentele de intrare sunt atomi
20/36
▫ argumentele de intrare sunt atomi▫ doar cel de ieşire reprezentând un string.
• După cum se vede din exemple:▫ numai primul argument trebuie să fie întotdeauna
instanţiatinstanţiat▫ celelalte pot fi calculate.

Transformare data si ora in string21/36
• convert_time(+Timp, -Valoare)
• Primul argument poate fi obţinut prin apelarea predicatului get_time/1: obţinem astfel data şi ora curente.

Transformare data si ora in string
?- get_time(Timp), convert_time(Timp, Data), nl, write('Data este '), write(Data).
22/36

Transformare data si ora in string23/36
• Pentru manevrarea mai uşoară a datei şi orei, mai există şi predicatul
• convert_time(+Timp, -Anul, -Luna, -Ziua, -Ora, -Minute, -Secunde, -Milisecunde).

Transformare data si ora in string
?- get_time(Timp), convert_time(Timp, An, Luna, Zi, Ora, Minute, Secunde, Milisec).
24/36

Palindrom
• Verificaţi cu ajutorul unui predicat dacă un
25/36
• Verificaţi cu ajutorul unui predicat dacă un cuvânt dat este palindrom.
• Un palindrom este un cuvânt care are aceeaşi formă, fie că este citit de la stânga, fie de la dreapta.
• Exemple: capac, lupul, cojoc, rar.

Palindrom
palindrom :- write('Introduceti cuvantul de
26/36
palindrom :- write('Introduceti cuvantul de verificat:'), read(Cuvant), string_to_list(Cuvant, Lista), palindrom(Lista).
palindrom(Lista) :- invers(Lista, Lista), write('Da, cuvantul este un palindrom!').
palindrom(_) :- write('Cuvantul nu este un palindrom(_) :- write('Cuvantul nu este un palindrom!').

Inversarea unei liste - recapitulare
invers(L1, L2) :- inv(L1, [], L2).
27/36
invers(L1, L2) :- inv(L1, [], L2).
inv([], L, L).inv([X|R], Lt, L) :- inv(R, [X|Lt], L).

Palindrom
28/36

Vocale
• Având un text introdus în fişierul intrare.txt, să se numere câte vocale se găsesc în acesta.
29/36
se numere câte vocale se găsesc în acesta.
• Pregatesc fisierul intrare.txt.
• Il deschid in citire.
• Colectez caracter de caracter.• Colectez caracter de caracter.▫ Daca acela care este curent este membru in
multimea data de vocale, il numar;▫ Altfel, parcurgem fisierul mai departe.

Vocale
vocale :- see('intrare.txt'), numar(0), seen.
30/36
numar(N) :- get(Caracter), Caracter \= -1, verific(Caracter, N, N1), numar(N1).
numar(N) :- write('Am gasit '), write(N), write(' vocale.').
verific(Caracter, N, N1) :-verific(Caracter, N, N1) :-string_to_list(aeiouAEIOU,Lista), member(Caracter, Lista), N1 is N + 1.
verific(_, N, N).

Vocale
31/36

Permutari de caractere
32/36
• Având un sir de caractere introdus de la consolă, să se genereze şi să se afişeze toate permutările de caractere posibile.

Permutari de caractere
permut :- write('Introduceti cuvantul pentru care generam permutarea:'), read(Cuvant),
33/36
generam permutarea:'), read(Cuvant), string_to_list(Cuvant, CLista), permut(CLista).
permut(L) :- permut(L, Rez), scr(Rez), nl, fail.permut(_).
scr([]).scr([P|R]) :- put(P), scr(R).

Permutari de caractere
permut([], []).permut(L, P) :- selecteaza(X, L, Rest),
34/36
permut(L, P) :- selecteaza(X, L, Rest), permut(Rest, RestPerm), P = [X|RestPerm].
selecteaza(X, [X|R], R).selecteaza(X, [Y|R], [Y|R1]) :- selecteaza(X, R,
R1).R1).

Permutari de caractere
35/36

Pe saptamana viitoare!
36/36
Pe saptamana viitoare!

Baze de date dinamice
• Este evident faptul ca un program Prolog este obază de date ce conţine predicate.
2/61
bază de date ce conţine predicate.
• Până acum, am introdus clauzele pentrupredicatele realizate de noi din interiorulprogramului.
• Prologul ne oferă însă posibilitatea să manevrămbaza de date în mod direct şi ne oferă predicatepredefinite care fac acest lucru.

Adaugare clauze
• assert(X) – adaugă clauza X ca ultima clauză a
3/61
• assert(X) – adaugă clauza X ca ultima clauză apredicatului din care face parte.
• asserta(X) – clauza X este adăugată ca primaclauză a predicatului.
• assertz(X) – acelaşi efect cu assert(X).

Retragere clauze
4/61
• retract(X) – scoate clauza X din baza de date.
• retractall(X) – sunt eliminate toate faptele sauregulile din baza de date pentru care capulclauzei este unificat cu X.

Exemplu
• Presupunem că avem următoarele fapte într-unfişier Prolog:
5/61
fişier Prolog:
copil(ionut).copil(marian).copil(simona).
• Presupunem că ei sunt introduşi în ordineavârstei lor.

Apelare
• Cu un apel de forma:
6/61
• Cu un apel de forma:
? - copil(C).
• obţinem, evident, C = ionut. • Pentru:
? - copil(C), write(C), nl, fail.
• vor fi afişaţi toţi copiii găsiţi.

Adaugare clauze
• Dacă se iveşte un nou copil, şi anume, Iulia, trebuiesă avem în vedere faptul că ea este cea mai mică.
7/61
să avem în vedere faptul că ea este cea mai mică.Avem nevoie de un apel de forma:
? – asserta(copil(iulia)).
• Putem verifica acum faptul că Iulia a fost inserată înbaza de date dinamică folosind una din cele douăbaza de date dinamică folosind una din cele douăapelări de mai sus, pentru afişarea primului copil,respectiv pentru afişarea tuturor copiilor:
? - copil(C), write(C), nl, fail.

Retragere clauze
• Să luăm în continuare cazul în care Simona atrecut de vârsta la care mai poate fi numită copil.
8/61
trecut de vârsta la care mai poate fi numită copil.Pentru a o elimina din baza de date, apelăm:
? – retract(copil(simona)).
• Din nou putem verifica dacă a fost eliminată,• Din nou putem verifica dacă a fost eliminată,afişând toţi copiii:
? - copil(C), write(C), nl, fail.

Adaugare clauze
• Să presupunem, în continuare, că toatepersonajele prezentate mai sus, cât timp au fost
9/61
personajele prezentate mai sus, cât timp au fostcopii, au fost buni prieteni.
• Pentru a introduce predicatul prieteni/2 descrismai sus, chiar de la consola Prologului, folosimurmătoarea comandă:următoarea comandă:
? – assert((prieteni(X,Y):-copil(X), copil(Y))).

Retragere clauze
10/61
• Când toţi copiii au trecut de vârsta majoratului, pentru a informa şi programul nostru că ei nu mai sunt copii, vom apela:
? – retractall(copil(_)).

Exerciţiu
• Presupunem că avem următoarea schemă a unei
11/61
• Presupunem că avem următoarea schemă a uneicase:

Exerciţiu
• Definiţi:▫ legăturile dintre camere (eventual printr-un
12/61
▫ legăturile dintre camere (eventual printr-unpredicat numit uşă)
▫ locul unde se află subiectul (presupunem că iniţial▫ locul unde se află subiectul (presupunem că iniţialse află în birou).

Exerciţiu• La un moment dat, dacă se apeleaza un predicat
numit mergi/1, sistemul să spună:
13/61
numit mergi/1, sistemul să spună:▫ care este camera în care se află subiectul
▫ dacă nu poate merge în camera specificată caargument,
▫ iar dacă poate, unde poate merge mai departe deacolo.

Exemplu
?- mergi(bucatarie).Esti in birou
14/61
Esti in birouAi mers in bucatariePoti merge in:
birousufrageriesubsolsubsol
? – mergi(hol).Nu poti ajunge direct din bucatarie in hol

Rezolvare
:-dynamic aici/1.
15/61
usa(birou, hol).usa(bucatarie, birou).usa(hol, sufragerie).usa(bucatarie, subsol).usa(sufragerie, bucatarie).
Trebuie specificat faptul ca vom defini un predicat in mod
dinamic.Se declara numele predicatului
conectat(X,Y) :- usa(X,Y).conectat(X,Y) :- usa(Y,X).
aici(birou).
Se declara numele predicatului si numarul sau de argumente.

Rezolvare
mergi(Camera) :- aici(Aici), not(conectat(Aici, Camera)), write('Esti in '), write(Aici), nl, write('Nu
16/61
Camera)), write('Esti in '), write(Aici), nl, write('Nu poti ajunge din '), write(Aici), write(' direct in '), write(Camera).
mergi(Camera) :- aici(Aici), write('Esti in '), write(Aici), nl, write('Ai mers in '), write(Camera), retract(aici(Aici)), assert(aici(Camera)), nl, write('Poti merge in '), nl, unde.write('Poti merge in '), nl, unde.
unde :- aici(Aici), conectat(Aici, Camera), tab(2), write(Camera), nl, fail.
unde.

Rezultate
17/61

Alt exemplu
• Construiţi predicatul declar/1 care are ca
18/61
• Construiţi predicatul declar/1 care are ca argument o listă de numere întregi şi care realizează două alte predicate, par/1 şi impar/1care vor avea ca argumente numai numerele care sunt pare, respectiv numai elementele care sunt impare din cadrul listei.

Rezolvare
19/61
:-dynamic par/1.:-dynamic impar/1.declar([]).declar([P|R]) :- P1 is P mod 2, P1 = 0,
assert(par(P)), declar(R).assert(par(P)), declar(R).declar([P|R]) :- assert(impar(P)), declar(R).

Rezultate
20/61

Functii de memorare
• O functie de memorare salveaza rezultatele unor subcalcule pentru a putea fi folosite direct, in
21/61
subcalcule pentru a putea fi folosite direct, in apelari viitoare, fara a mai fi recalculate.
• Prototipul unei astfel de functii este retin(deductie(arg1, …, argn))
• Implementarea se realizeaza astfel:retin(deductie(arg1, …, argn)):-deductie(arg1, …,
argn), asserta(deductie(arg1, …, argn)).

Functii de memorare
• Se verifica veridicitatea faptului respectiv si, in caz
22/61
• Se verifica veridicitatea faptului respectiv si, in caz afirmativ, se introduce in memoria Prolog-ului.
retin(deductie(arg1, …, argn)):-deductie(arg1, …, argn), asserta(deductie(arg1, …, argn)).
• Data urmatoare cand se doreste atingerea scopului • Data urmatoare cand se doreste atingerea scopului (afirmatia din capul clauzei), solutia va fi gasita direct in memorie, fara a repeta calculele.

Turnurile din Hanoi
• Enunt: Se dau N discuri si 3 cuie: A, B, C.
23/61
cuie: A, B, C.
• Se cere sa se mute toate discurile de pe cuiul A pe cuiul B, folosindu-se drept cui intermediar C. A C Bcui intermediar C.
• Discurile sunt intotdeauna asezate unul peste altul in ordinea crescatoare a marimii.
A C B

Turnurile din Hanoi - solutie
• Problema se rezolva recursiv.
24/61
• Problema se rezolva recursiv.
• Se muta N – 1 discuri de pe cuiul A pe cuiul C.
• Se muta apoi cele N – 1 discuri de pe C pe B.
• In final, se aseaza cuiul 1 de pe A pe B.
• Cand avem 1 disc, se muta de pe A pe B.

Turnurile din Hanoi - Prologhanoi1(N):-hanoi1(N, a, b, c, L), afis(L).
25/61
hanoi1(N,A,B,_C,[(A,B)]):-N = 1.hanoi1(N,A,B,C,M):-N > 1, N1 is N - 1,
hanoi1(N1,A,C,B,M1), hanoi1(N1,C,B,A,M2),append(M1, [(A, B)|M2], M).
afis([]).afis([X|Rest]):-writeln(X), afis(Rest).

Turnurile din Hanoi – functii de memorare:-dynamic(hanoi/5).
26/61
:-dynamic(hanoi/5).
hanoi(N):-hanoi(N, a, b, c, L), afis(L).
hanoi(N,A,B,_C,[(A,B)]):-N = 1.hanoi(N,A,B,C,M):-N > 1, N1 is N - 1,
retin(hanoi(N1,A,C,B,M1)), retin(hanoi(N1,A,C,B,M1)), hanoi(N1,C,B,A,M2),append(M1, [(A, B)|M2], M).
retin(P):-P, asserta(P).

Turnurile din Hanoi
• Se utilizeaza functiile memo pentru a imbunatati performanta programului initial.
27/61
performanta programului initial.
• Solutia acestei probleme, cand sunt N discuri, necesita 2^N – 1 mutari.
• Modul de solutionare al problemei rezolva in mod • Modul de solutionare al problemei rezolva in mod repetat subprobleme prin mutarea unui numar identic de discuri.

Turnurile din Hanoi
• O functie de memorare poate fi folosita pentru a retine mutarile facute pentru fiecare subproblema cu un numar mai mic de discuri.
28/61
cu un numar mai mic de discuri.
• Cand se ajunge la reapelarea unui fapt care a fost deja calculat, se poate folosi secventa de mutari deja retinuta in memorie, in loc de a le recalcula.
• Se memoreaza prima clauza recursiva, de muta N • Se memoreaza prima clauza recursiva, de muta N – 1 discuri, a predicatului hanoi si poate fi folosita de a doua apelare recursiva a sa pentru N – 1 discuri.

Rulare
29/61
A C B

Predicatul REPEAT

Repeat
• Dacă o anumită clauză trebuie satisfăcută demai multe ori, facem apel la predicatul fail care
31/61
mai multe ori, facem apel la predicatul fail careface ca Prologul să încerce să găsească toatesoluţiile (presupunând că nu folosim tăietura).
• Totuşi, în unele situaţii, este necesar să repetămnumai o anumită parte de program, înainte de acontinua procesul cu restul clauzei.continua procesul cu restul clauzei.
• Acest gen de situaţii apar atunci când vrem sărealizăm operaţii iterative, precum citirea dintr-un fişier ori la realizarea unui meniu.

Repeat• În general, predicatul repeat este folosit în construcţii de
forma:
32/61
nume_predicat :- repeat, % încep buclaafisez_meniu, % afişez meniul pentru
utilizatorcitesc_optiunea(N),% citesc data introdusă de
către utilizatorvalidez_optiunea(N), % verific dacă există în
cadrul meniuluiexecut_cerinta(N), % realizez ce era execut_cerinta(N), % realizez ce era
specificat în meniu
pentru Nverific_oprirea(N), % verific dacă este
condiţia de terminare!. % oprirea iteraţiei.

Exemplu
• Următorul predicat citesc/0 face citirea de latastatură a unor valori pe care le afişează apoi
33/61
tastatură a unor valori pe care le afişează apoiutilizatorului.
• Procesul se termină atunci când utilizatorulintroduce gata.
citesc :- repeat, meniu, read(X), write('Am citit '),write(X), write('!'), nl, X == gata, !.
meniu :- nl, write('---------'), nl, write('Exemplubanal!'), nl, write('Orice introduceti, afisam!'), nl,write('Pentru oprirea repeat-ului, tastati gata.'), nl,write('---------'), nl, nl.

Exemplu
34/61

Alt exemplu
• Realizaţi un predicat care să simuleze predicatul
35/61
• Realizaţi un predicat care să simuleze predicatul predefinit consult/1.

Rezolvare
compilez(Fisier) :- see(Fisier), repeat,
36/61
compilez(Fisier) :- see(Fisier), repeat,read(X), assert(X),X == end_of_file,!, seen.

Rezultate
37/61

Alt exemplu
• Avem relaţiile existente într-o familie date
38/61
• Avem relaţiile existente într-o familie dateprintr-un singur predicat, persoana(Nume, Sex,Copii), unde primul argument reprezintă numelepersoanei în cauză, al doilea ne spune dacă estebărbat sau femeie, iar al treilea este o listă(poate fi vidă) care conţine numele copiilorpersoanei la care ne referim.persoanei la care ne referim.

Alt exemplu
• Utilizatorului îi va fi prezentat un meniu care îipermite să facă următoarele operaţii:
39/61
permite să facă următoarele operaţii:
▫ Să adauge o persoană (întreabă dacă estebărbat sau femeie); se validează iniţial dacăexistă sau nu în baza de cunoştinţe introdusă.Presupunem că nu există două persoane cuacelaşi nume.acelaşi nume.
▫ Să şteargă o persoană din baza de cunoştinţe.
▫ Să adauge informaţia că X este copilul lui Y.

Alt exemplu
• Continuare meniu:
40/61
• Continuare meniu:
▫ Eliminarea lui X din lista de copii a lui Y.
▫ Eliminarea tuturor persoanelor din bază.
▫ O opţiune care să-i permită utilizatorului săsalveze baza de cunoştinţe într-un fişier,respectiv să o citească dintr-un fişier.

Faptele
persoana(andrei, barbat, [cristi, elena]).persoana(cristi, barbat, [adriana, marius, ovidiu]).
41/61
persoana(cristi, barbat, [adriana, marius, ovidiu]).persoana(elena, femeie, [ana]).persoana(marius, barbat, []).persoana(ovidiu, barbat, []).persoana(george, barbat, []).persoana(adriana, femeie, []).persoana(adriana, femeie, []).persoana(ana, femeie, [george]).

Adaugarea unei noi persoane
42/61
adaugare :- write('Numele celui ce va fi adaugat: '), read(Nume), not(persoana(Nume, _, _)), write('Sexul '), read(Sex), assert(persoana(Nume, Sex, [])), nl, write('Persoana a fost adaugata!').
adaugare :- write('Exista deja in baza noastra!').

Adaugarea unei noi persoane
43/61

Stergerea unei persoane
44/61
stergere :- write('Numele celui ce va fi sters: '), read(Nume), persoana(Nume, _, _), retract(persoana(Nume, _, _)), write(Nume), write(' a fost sters!').
stergere :- nl, write('Nu exista in baza de stergere :- nl, write('Nu exista in baza de cunostinte!').

Stergerea unei persoane
45/61

Adaugarea copilului X la Y
copil(_X, Y) :- not(persoana(Y, _, _)), write(Y),
46/61
copil(_X, Y) :- not(persoana(Y, _, _)), write(Y), write(' nu exista in baza noastra de cunostinte!').
copil(X, Y) :- retract(persoana(Y, SexY, CopiiY)), assert(persoana(Y, SexY, [X|CopiiY])), nl, write('Acum '), write(X), write(' este copilul lui write('Acum '), write(X), write(' este copilul lui '), write(Y).

Adaugarea copilului X la Y
47/61

Eliminarea copilului X de la Y
elimcopil(_X, Y) :- not(persoana(Y, _, _)),
48/61
elimcopil(_X, Y) :- not(persoana(Y, _, _)), write(Y), write(' nu exista in baza noastra de cunostinte!').
elimcopil(X, Y) :- persoana(Y, _, Copii), not(member(X, Copii)), write(X), write(' nici nu e copilul lui '), write(Y), write('.'). e copilul lui '), write(Y), write('.').

Eliminarea copilului X de la Y
elimcopil(X, Y) :- retract(persoana(Y, SexY,
49/61
elimcopil(X, Y) :- retract(persoana(Y, SexY, CopiiY)), elim(X, CopiiY, CopiiiY), assert(persoana(Y, SexY, CopiiiY)), write('Acum '), write(X), write(' nu mai este copilul lui '), write(Y).
elim(_, [], []).elim(_, [], []).elim(X, [X|R], L) :- elim(X, R, L).elim(X, [P|R], [P|L]) :- elim(X, R, L).

Eliminarea copilului X de la Y50/61

Eliminarea tuturor persoanelor din bazaelimintot :- retractall(persoana(_, _, _)), nl,
51/61
elimintot :- retractall(persoana(_, _, _)), nl, write('Baza de cunostinte este acum goala!').

Salvarea bazei de cunostinte intr-un fisier
52/61
salvez(Fisier) :- tell(Fisier), salvez, told, write('Fisierul a fost salvat').
salvez :- persoana(Nume, Sex, Copii), write('persoana('), write(Nume), write(','), write(Sex), write(','), write(Copii), write(').'), nl, write(Sex), write(','), write(Copii), write(').'), nl, fail.
salvez.

Salvarea bazei de cunostinte intr-un fisier
53/61

Incarcarea unui fisier in memorie
deschid(Fisier) :- consult(Fisier), nl,
54/61
deschid(Fisier) :- consult(Fisier), nl, write('Fisierul '), write(Fisier), write(' a fost incarcat.'), nl.

Meniulmeniu :- nl, nl, tab(15), write('Selectati un numar
din cadrul meniului'), nl, nl, write('1. Listare
55/61
din cadrul meniului'), nl, nl, write('1. Listare baza de cunostinte.'), nl, write('2. Adaugare persoana.'), nl, write('3. Eliminare persoana.'), nl, write('4. Adaugarea lui X ca si copil al lui Y.'), nl, write('5. Stergerea lui X ca si copil al lui Y.'), nl, write('6. Eliminarea tuturor persoanelor.'), nl, write('7. Salvarea bazei de cunostinte intr-un write('7. Salvarea bazei de cunostinte intr-un fisier Prolog.'), nl, write('8. Incarcarea bazei de cunostinte dintr-un fisier Prolog.'), nl, write('9. Incheiere.'), nl, nl.

Partea principalaprincipal :- repeat, meniu, read(Optiune),
proceseaza(Optiune), nl, Optiune == 9, !.
56/61
proceseaza(Optiune), nl, Optiune == 9, !.
proceseaza(1) :- persoana(Nume, Sex, []), write(Nume), write(' este '), write(Sex), write(' si nu are copii.'), nl, fail.
proceseaza(1) :- persoana(Nume, barbat, Copii), Copii \= [], write(Nume), write(' este barbat iar copiii lui sunt: '), afiscopii(Copii), nl, fail.
proceseaza(1) :- persoana(Nume, femeie, Copii), Copii sunt: '), afiscopii(Copii), nl, fail.
proceseaza(1) :- persoana(Nume, femeie, Copii), Copii \= [], write(Nume), write(' este femeie iar copiii ei sunt: '), afiscopii(Copii), nl, fail.
proceseaza(1).

Partea principala
proceseaza(2) :- adaugare, !.
57/61
proceseaza(2) :- adaugare, !.proceseaza(3) :- stergere, !.proceseaza(4) :- write('Copilul X: '), read(X),
write('Parintele Y: '), read(Y), copil(X, Y), !.proceseaza(5) :- write('Copilul X: '), read(X),
write('Parintele Y: '), read(Y), elimcopil(X, Y), !.proceseaza(6) :- elimintot,!.proceseaza(6) :- elimintot,!.

Partea principala
proceseaza(7) :- write('Numele fisierului Prolog
58/61
proceseaza(7) :- write('Numele fisierului Prolog (introduceti-l intre apostrofuri si cu extensia pl): '), read(NumeFis), salvez(NumeFis), !.
proceseaza(8) :- write('Numele fisierului din care se face incarcarea (intre apostrofuri si cu extensia pl): '), read(Fis), deschid(Fis),!.
proceseaza(9).proceseaza(9).

Partea principala
59/61
afiscopii([]).afiscopii([P|R]) :- write(P), write(', '), afiscopii(R).

Rulare60/61

Pe saptamana viitoare!
61/61
Pe saptamana viitoare!

Programare functionala. Fundamentele limbajului LISP
Ruxandra Stoeanhttp://inf.ucv.ro/[email protected]

Bibliografie
• Stuart C. Shapiro, Common Lisp: An InteractiveApproach, Computer Science Press, 1992.
• Internet.

Introducere
• Vom opera cu mediul standard al limbajuluiLISP.LISP.
• Acest lucru presupune ca vom lucra inCOMMON LISP.
• Common Lisp aduce o interfata simpla, de tip• Common Lisp aduce o interfata simpla, de tipDOS.
• In particular, vom lucra cu implementareaCLISP 2.30.

Introducere
• In momentul in care pornim Common Lisp, ne• In momentul in care pornim Common Lisp, nevom afla deja in fata prompterului Lisp.
• Prompterul va astepta sa introducem ceea ce, incadrul programarii functionale, poarta numelede S-expresie (expresie simbolica).
• Dupa ce S-expresia este scrisa, apasam tastaENTER.

Ciclul citire-evaluare-scriere al Lisp
• Atunci cand dam Lisp-ului o S-expresie, acesta va• Atunci cand dam Lisp-ului o S-expresie, acesta vaproduce urmatorii pasi:
▫ Va citi S-expresia.
▫ Va interpreta S-expresia drept reprezentarea scrisaa unui forme (obiect Lisp ce trebuie evaluat).a unui forme (obiect Lisp ce trebuie evaluat).
▫ Va evalua forma drept alt (sau poate chiar acelasi)obiect valoare.

Ciclul citire-evaluare-scriere al Lisp
▫ Va alege o reprezentare scrisa pentru obiectul▫ Va alege o reprezentare scrisa pentru obiectulvaloare.
▫ Va scrie reprezentarea scrisa pe care a ales-o.
• Dupa ce intoarce valoarea, prompterul Lisp va• Dupa ce intoarce valoarea, prompterul Lisp vareaparea si va astepta o noua expresie.

Ciclul citire-evaluare-scriere al Lisp
• Acesta este modul de folosire al Lisp:• Acesta este modul de folosire al Lisp:
▫ Utilizatorul introduce reprezentarea scrisa a uneiforme.
▫ Lisp o evalueaza.▫ Lisp o evalueaza.
▫ Apoi, trimite inapoi o reprezentare scrisa a valoriiformei.

Un prim exemplu• O S-expresie simpla pe care o vom introduce este
numeralul in scriere araba, 3.numeralul in scriere araba, 3.
• Aceasta este una din reprezentarile scrise pe carele folosim pentru numarul 3.
• Oamenii folosesc si numeralul in scriere romanaIII.III.
• Aceasta este deci distinctia pe care o face si Lispintre un obiect si diferitele sale posibilitati dereprezentare scrisa.

Exemplu
• Lisp interpreteaza numeralul 3 ca reprezentand• Lisp interpreteaza numeralul 3 ca reprezentandnumarul 3.
• Evalueaza aceasta forma – adica obiectulnumeric 3.
• In Lisp, numerele sunt evaluate in ele insele.• In Lisp, numerele sunt evaluate in ele insele.
• Lisp va alege o reprezentare scrisa pentru 3 si vautiliza, de asemenea, numeralul arab 3.

Interactiunea cu Lisp

Debugger-ul din Lisp
• Daca in introducerea unei S-expresii se face vreo greseala, va intra debugger-ul Lisp-ului.greseala, va intra debugger-ul Lisp-ului.
• Acesta mai poarta numele si de ciclu (sau pachet) break.
• Acesta arata ca un prompter Lisp obisnuit, doar ca exista aici niste comenzi speciale pentru a obtine exista aici niste comenzi speciale pentru a obtine informatii despre ce presupune eroarea.
• Deocamdata, vom parasi aceste bucle break, tastand :q.

Debugger-ul din Lisp

Terminarea sesiunii de Lisp

Numere in Lisp
• Numerele sunt unul dintre tipurile de baza aleLisp-ului.Lisp-ului.
• Se pot folosi numere intregi sau reale.
• In cadrul intregilor, nu putem folosi insa virgulesau spatii:sau spatii:▫ 12 345 sau 12,345 sunt reprezentari incorecte de
intregi.▫ Vom scrie direct 12345.

Numere in Lisp
• Pentru a scrie un intreg negativ, vom inserasemnul “-” in fata sa, iar pentru unul pozitivsemnul “-” in fata sa, iar pentru unul pozitivputem de asemenea pune semnul “+”:▫ -34, +25 sunt expresii corecte de intregi.
• Un intreg se poate termina cu “.” – acesta va ficitit drept intreg:citit drept intreg:▫ 12. va fi egal cu a scrie 12.▫ 12.0 va fi insa interpretat drept real.

Numere in Lisp
• Numerele reale sunt construite cu ajutorul• Numerele reale sunt construite cu ajutorulsemnului “.” si cu cel putin o cifra dupa punct:▫ 12.9▫ 13.0
• Pot fi scrise si sub forma stiintifica, cu semnul de• Pot fi scrise si sub forma stiintifica, cu semnul deexponent:▫ 0.34e-2 – care inseamna 0.34 × 10-2.

Numere in Lisp

Numere in Lisp
Caracterul “;” se foloseste pentru a
comenta o anumita parte . Rezulta ca ce se
afla dupa el este ignorat.

Liste in Lisp
• LisP = List Processing
• Care este reprezentarea scrisa a unei liste?
• Conform lui S. C. Shapiro, definitia unei S-expresii lista este:▫ O paranteza stanga urmata de zero sau mai multe
S-expresii urmate de o paranteza dreapta este o S-S-expresii urmate de o paranteza dreapta este o S-expresie lista.
• S-expresiile se delimiteaza una de alta prinspatii.

Exemple
• (1 3.2 2 4)
• (1 (2 3.3) 4)
• ()
• ((1 3.2 2 4))• ((1 3.2 2 4))
• (())

Liste
• In acest moment, Lisp-ul citeste expresia care este data de utilizator si incearca sa o evalueze.este data de utilizator si incearca sa o evalueze.
• Pana la a evalua o lista, ii vom cere Lisp-ului doar sa ne afiseze lista introdusa.
• Putem impiedica evaluarea unei liste si, in loc, sa • Putem impiedica evaluarea unei liste si, in loc, sa obtinem printarea ei folosind semnul de apostrof inaintea S-expresiei lista.

Exemple de interactiune cu Lisp
Modul de reprezentare scrisa ales de Lisp pentru lista vida.

Liste
• Lisp-ul va ignora de asemenea spatiile in plus sau ENTER-urile.sau ENTER-urile.
• Daca toate parantezele deschise nu sunt inchise de utilizator, Lisp-ul va astepta in continuare paranteze dreapta.
• Se pot pune mai multe paranteze dreapta decat stanga; Lisp-ul le va ignora pe cele in plus.

Exemple

Expresii aritmetice in Lisp
• Evaluarea obiectelor lista este operatia de baza in Lisp.in Lisp.
• Conform lui S. C. Shapiro:▫ Valoarea unei liste este cea obtinuta prin aplicarea
functiei denumita de primul argument (membru) al listei asupra valorilor celorlalti membri ai listei.al listei asupra valorilor celorlalti membri ai listei.
• Vom incepe evaluarea listelor cu ajutorul operatorilor matematici de baza: +, -, *, /.

Exemplu

Notatia prefixa Cambridge
• Formatul sub care expresiile aritmetice sunt • Formatul sub care expresiile aritmetice sunt scrise sub forma de lista poarta numele de notatie prefixa Cambridge.
• Numele provine de la cel care a dezvoltat aceasta notatie – John McCarthy de la MIT, Cambridge, MA – si de la faptul ca operatorul “prefixeaza” MA – si de la faptul ca operatorul “prefixeaza” (este inaintea) operanzilor sai.

Notatia prefixa Cambridge
• Termenul a fost preluat de la notatia polonezaprefixa, unde functia e scrisa inainteaprefixa, unde functia e scrisa inainteaargumentelor sale.
• Acest format difera de cel matematic clasic de tipinfix:▫ In care operatorul este scris intre operanzii sai (de
ex. 12 + 4)ex. 12 + 4)▫ sau in care functia este scrisa inainte de argumente
dar nu in paranteza cu ele (de ex. f(x, y)).▫ Aceasta din urma se va scrie in Lisp sub forma: (f x
y)

Notatia prefixa Cambridge
• Avantajul major al acestei notatii este ca scrierea ramane foarte simplu de utilizat indiferent de numarul de argumente: ▫ 1, ▫ 2 ▫ sau chiar mai multe ducand la operatii succesive

Exemple de interactiune
Am uitat sa inseram un spatiu!

Evaluarea listelor
• Daca argumentele functiilor aritmetice sunt intregi, rezultatul va fi intreg.
• Daca unul dintre argumente este real, atunci rezultatul va fi real.rezultatul va fi real.

Evaluarea listelor
• Exceptie se face daca incercam sa impartim un • Exceptie se face daca incercam sa impartim un intreg la un alt intreg si valoarea rezultata nu este exacta:▫ Rezultatul va fi ceea ce poarta numele de fractie: 2
numere separate de semnul “/”, pozitive sau negative.
▫ Fractia va fi reprezentata de catre Lisp sub forma ▫ Fractia va fi reprezentata de catre Lisp sub forma simplificata.
• Si utilizatorul poate introduce fractii, chiar si sub forma nesimplificata.

Exemple

Evaluarea listelor• Putem avea expresii aritmetice incluse in alte
expresii aritmetice – cum este natural in matematica, de exemplu, 5 × (3 + 4).matematica, de exemplu, 5 × (3 + 4).
• In Lisp, aceasta expresie se va scrie sub forma:(× 5 (+ 3 4))
• In schimb, 5 × 3 + 4 se scrie:• In schimb, 5 × 3 + 4 se scrie:(+ (× 5 3) 4)
• In general f(x, g(y)) se va scrie sub forma:(f x (g y))

Interactiune

Exercitiu
• Sa calculam radacinile ecuatiei:
2x2 + 7x + 5 = 0• Acestea sunt:
52477 2 22
52477

Exercitiu
• Le vom scrie Lisp-ului sub forma:
• (/ (+ -7.0 (sqrt (- (expt 7 2) (* 4 2 5)))) (* 2 2))
• siFunctia ridicare
la putere – 2 argumente
Functia radical –un singur argument
• (/ (- -7.0 (sqrt (- (expt 7 2) (* 4 2 5)))) (* 2 2))

Interactiune

Testarea egalitatii
• Verificarea egalitatii se face cu operatorul “=”.
• I se pot da 1, 2 sau mai multe argumente.
• Argumentele pot fi de tipuri numerice diferite –“=” testeaza numai egalitatea numerica.
• Intoarce TRUE (T) daca numerele sunt egale si FALSE (NIL) altfel.

Interactiune

Exercitiu
• Utilizand Lisp-ul, gasiti valorile pentru:▫ (25 + 30) × 15/2
▫ 6 × 3.1416
▫ Media numerelor 5, 6.7, -23.2, 75 si 100.3

Pe saptamana viitoare…

Fundamentele limbajului LISP (2)Fundamentele limbajului LISP (2)
Ruxandra Stoeanhttp://inf.ucv.ro/[email protected]

2
Stringuri si caractere
• Un string este un vector de caractere.
• Este scris de catre Lisp ca secventa caracterelor sale inconjurata de ghilimele.
• Ca si numerele, stringurile sunt evaluate in ele insele.
• Sa scriem un string la prompterul de Lisp.
> “Acesta este un string.”

3
Exemplu

4
Stringuri
• Un string poate fi oricat de lung si poate contine• Un string poate fi oricat de lung si poate continecaractere precum ENTER.
• In afara numerelor, Common Lisp are deasemenea functii care opereaza si asupraobiectelor de alt tip.
• De exemplu, pentru a afla numarul de caracteredintr-un string, se foloseste functia length.

5
Exemplu

6
Stringuri
• O alta functie predefinita este string=.
• Aceasta functie intoarce TRUE daca cele douastringuri date ca argumente sunt alcatuite dinaceleasi caractere si FALSE, in caz contrar.aceleasi caractere si FALSE, in caz contrar.

7
Exemple

8
Stringuri
• Pentru a accesa un anumit caracter in string, se utilizeaza formularea (char string index).utilizeaza formularea (char string index).
• char este predefinit, string reprezinta sirul dorit iar index pozitia caracterului care va fi intors.
• Index-ul primului caracter din string e 0.• Index-ul primului caracter din string e 0.
• Index-ul nu trebuie sa depaseasca lungimea sirului.

9
Exemple

10
Caractere
• Se poate observa ca un caracter este scris de catre Lisp cu prefixul #\.
• Tot in acelasi mod va da si utilizatorul caracterele.caracterele.
• Un caracter este evaluat in el insusi.

11
Exemple

12
Caractere
• Pentru testarea faptului ca doua caractere sunt • Pentru testarea faptului ca doua caractere sunt identice, se foloseste functia char=.
• La fel ca la testarea egalitatii pentru numere, dar diferit de aceeasi testare pentru stringuri, aceasta functie poate lua orice numar de argumente.argumente.

13
Exemple

14
Stringuri si caractere
• Pentru a utiliza simbolul “ ca parte a unui string, • Pentru a utiliza simbolul “ ca parte a unui string, va trebui sa folosim caracterul \.
• Pentru a utiliza caracterul \ apoi ca parte a unui string, trebuie sa mai adaugam inca unul in fata sa.sa.

15
Exemple
• Observati ca lungimea stringurilor nu este• Observati ca lungimea stringurilor nu esteinfluentata de caracterul \.

16
Exemple
• Pentru testarea egalitatii a doua stringuri, adoua poate fi si caracter.doua poate fi si caracter.
• Pentru acelasi lucru in cazul caracterelor,amandoua trebuie sa fie de acest fel.

17
Caracterele spatiu si ENTER

18
Simboluri
• Simbolurile sunt un alt tip de data in Lisp.
• Pentru a reprezenta un simbol, se folosesc secvente de litere si caracterele * si -:▫ De exemplu: paul, pi, *read-base*
• Un simbol poate reprezenta ceva pentru care • Un simbol poate reprezenta ceva pentru care dorim sa stocam informatii:▫ De exemplu, paul poate reprezenta o persoana.

19
Simboluri
• Simbolurile sunt de asemenea folosite drept variabile.variabile.
• Astfel, un simbol poate avea o valoare: se spune ca este legat, sau este, dimpotriva, nelegat (fara valoare).
• Unele simboluri legate sunt: pi, *read-base*, *print-base* si *package*.

20
Exemple
• pi reprezinta valoarea simbolului matematic.• *read-base* si *print-base* specifica in ce baza • *read-base* si *print-base* specifica in ce baza
vor fi scrise numerele de catre utilizator, respectiv de Lisp.
• *package* specifica pachetul in care ne aflam curent.

21
Simboluri• Cele mai importante simboluri in Lisp sunt T si
NIL.NIL.
• T reprezinta true, iar NIL desemneaza false si lista vida.
• Aceste simboluri sunt legate chiar la ele insele.

22
Simboluri
• Atunci cand vrem sa utilizam un simbol si nu • Atunci cand vrem sa utilizam un simbol si nu valoarea sa, punem ‘ in fata acestuia.

23
Simboluri
• Putem scrie simbolurile cu litere mici, Lisp le converteste la litere mari.

24
Simboluri
• Pentru a testa egalitatea dintre doua simboluri, se foloseste functia eql. se foloseste functia eql.

25
Functia eql
• Aceasta functie e mai generala chiar, testanddaca sunt identice oricare doua obiecte Lisp:▫ Simboluri▫ Caractere▫ Numere de acelasi tip▫ Numere de acelasi tip

26
Exemple

27
Simboluri
• Orice simbol are un nume reprezentat de unstring.
• Putem afla acest nume utilizand functia symbol-name.

28
Exemplu

29
Simboluri
• Daca se doreste ca un caracter sa ramana scris cu litera mica in cadrul unui simbol, se va folosi \.
• Daca vrem ca Lisp sa pastreze literele exact cum le dam, le vom scrie intre ||.

30
Exemplu
• Pentru a scrie un simbol, Lisp foloseste si ||.
• Acestea nu fac parte din simbol sau din numele sau.

31
Exemplu
• Simbolurile cu litere diferite ca marime sunt la • Simbolurile cu litere diferite ca marime sunt la randul lor diferite.

32
Mai multe exemple

33
Tipul unui obiect
• Pentru a afla care este tipul unui anume obiect,se foloseste functia type-of.se foloseste functia type-of.

34
Mai multe exemple

35
Pachete
• Fiecare multime de simboluri este pastrata intr-• Fiecare multime de simboluri este pastrata intr-un pachet Common Lisp.
• Utilizatorul isi poate crea propriul pachet si il poate exporta pentru ca altii sa il poata utiliza.
• Un pachet poate fi evident importat in alt pachet.

36
Pachete
• Am vazut ca un simbol poate avea diverse• Am vazut ca un simbol poate avea diversereprezentari si totusi sa ramana acelasi simbol,cu acelasi nume.
• In continuare vom vedea ca simboluri diferitepot avea acelasi nume daca sunt in pachetepot avea acelasi nume daca sunt in pachetediferite.

37
Pachete
• Atunci cand interactionam cu Lisp, ne aflam deja intr-un pachet.intr-un pachet.
• Putem vedea pachetul curent verificand valoarea simbolului *package*.

38
Functia describe
• Prin apelul acestei functii Lisp putem afla diverse proprietati despre obiecte.diverse proprietati despre obiecte.
• Printre altele, putem vedea pachetul din care fac parte diferite simboluri.

39
Exemple

40
Exemple

41
Pachete
• Ne putem muta in alt pachet apeland functia in-• Ne putem muta in alt pachet apeland functia in-package.
• Acolo putem referi simboluri existente sau unele noi create de utilizator.

42
Exemplu

43
Pachete• Pentru a referi un acelasi simbol din alt pachet,
folosim exprimarea:folosim exprimarea:
nume_pachet::nume_simbol
• Cele doua simboluri sunt diferite.

44
Pachete• Sa ne intoarcem acum la pachetul common-lisp-
user si sa aflam informatii despre simbolul ‘paul.

45
Pachete
• Cele doua simboluri din pachete diferite nu sunt identice decat ca nume.identice decat ca nume.

46
Pachete
• Un simbol poate fi exportat din pachetul sau prin apelarea functiei export.apelarea functiei export.
• Numele unui simbol extern este de forma:
nume_pachet:nume_simbol

47
Exemplu

48
Pachete
• Pentru a afla daca un simbol a fost exportat sau este inca intern intr-un anumit pachet, se poate proceda precum in cele ce urmeaza.proceda precum in cele ce urmeaza.

49
Pachete• Putem de asemenea defini pachete noi.

50
Pachete• Daca dorim sa importam un simbol extern
dintr-un pachet in altul folosim functia import.

51
Alte observatii
• Atunci cand referim prima data un simbol, Lisp • Atunci cand referim prima data un simbol, Lisp il si construieste; deci, un simbol nou nu trebuie declarat inainte.
• Daca vom incerca sa suprascriem un simbol care deja exista intr-un pachet, vom primi mesaj de eroare.eroare.

52
Exemplu

53
Alte observatii
• Simbolurile standard din pachetul lisp suntexterne si importate automat in alte pachete.externe si importate automat in alte pachete.

54
Pachetele ca tip de data
• Ca tip de data in Lisp, putem afla mai multeinformatii despre pachetul curent.informatii despre pachetul curent.

55
Pachetele ca tip de data
• Pe langa functiile deja cunoscute, find-package nespune pachetul al carui nume prescurtat il stim.spune pachetul al carui nume prescurtat il stim.

56
Procesarea de baza a listelor• Pana acum am discutat despre evaluarea S-
expresiilor care erau date sub forma de liste.
• In continuare, vom discuta despre liste ca tip debaza in Lisp.
• Pentru a crea o lista, se foloseste functia de baza:(cons obiect lista), unde:▫ primul argument poate fi orice obiect Lisp▫ primul argument poate fi orice obiect Lisp▫ al doilea este o lista▫ intoarce o lista cu primul argument inserat ca prim
membru si restul listei fiind al doilea argument

57
Exemplu

58
Primul element si restul listei
• Pentru a accesa primul element al unei liste silista ramasa, se folosesc predicatelelista ramasa, se folosesc predicatele
(first list) si (rest list)

59
Mai multe exemple

60
Procesarea listelor
• Functia equal spune daca elementele a doua liste sunt egale doua cate doua sau nu.liste sunt egale doua cate doua sau nu.

61
Functia de determinare a lungimii unei liste

62
Alte observatii
• Dupa ce am tastat o forma in Lisp, o putemimediat reapela cu *; cu ** putem reapelaimediat reapela cu *; cu ** putem reapelapenultima forma.

63
Pe saptamana viitoare…

2
Definirea propriilor functii
• “Un program Lisp este o colectie de functii scrise de un programator Lisp” - S. C. Shapiro.de un programator Lisp” - S. C. Shapiro.
• Pentru a defini o functie, se foloseste forma defun:
(defun functie lista_variabile string_documentie forma)(defun functie lista_variabile string_documentie forma)
▫ functie este un simbol;▫ lista_variabile este o lista de simboluri;▫ string_documentatie este un string;▫ forma este o forma Lisp.

3
Definirea propriilor functii
(defun functie lista_variabile string_documentie forma)
▫ defun intoarce functie;▫ defineste functie ca fiind numele unei functii;▫ argumentele (atributele) sale formale sunt simbolurile din
lista_variabile;▫ definitia sa se afla in forma;▫ documentatia (explicatiile) pentru aceasta functie sunt in
string_documentatie.
• Observatie: Argumentele formale ale functiei poarta numele de • Observatie: Argumentele formale ale functiei poarta numele de variabile lambda.
• Numele provine de la calculul lambda al lui A. Church care sta la baza Lisp-ului.

4
Exemplu
Simbol
• Se defineste functia lista.• Aceasta ia trei obiecte Lisp ca atribute actuale.• Intoarce o lista care are ca membri cele trei obiecte
Lisp date ca argumente.
Simbol
Lisp date ca argumente.• Dupa ce functia este evaluata, aceasta se poate
folosi ca si cum ar fi una predefinita in Lisp.• Putem afla de asemenea informatii despre functie
cu expresia documentation.

5
Apelarea unei functii
• Cand o functie este apelata, se parcurg urmatorii pasi:▫ Lisp verifica daca primul membru al listei este un simbol care reprezinta
o functie;▫ Obiectele date ca argumente sunt evaluate;▫ Valorile obiectelor devin valorile atributelor formale.▫ Variabilele formale sunt legate la valorile date;▫ Forma care reprezinta definitia functiei este evaluata;▫ Atributele formale sunt dezlegate;▫ Atributele formale sunt dezlegate;▫ Valoarea formei de definitie este intoarsa.

6
Apelarea unei functii - exemplu• Cand o functie este apelata, se
parcurg urmatorii pasi:▫ Lisp verifica daca primul
• Cand functia definita esteapelata, avem urmatorii pasi:
▫ Lisp verifica daca primulmembru al listei este un simbolcare reprezinta o functie;
▫ Obiectele date ca argumente suntevaluate;
▫ Valorile obiectelor devin valorileatributelor formale, adicavariabilele formale sunt legate lavalorile date;
▫ Forma care reprezinta definitiafunctiei este evaluata;
▫ lista este un simbol carereprezinta o functie;
▫ ‘a este evaluat drept A, (cons ‘b‘()) ca (B) si ‘c drept C;
▫ o1 este legat la A, o2 la (B) si o3la C;
▫ (cons o1 ( cons o2 (cons o3 ‘())))este evaluata, fiecare obiectavand valorile de mai sus;
functiei este evaluata;
▫ Atributele formale suntdezlegate;
▫ Valoarea formei de definitie esteintoarsa.
avand valorile de mai sus;▫ o1, o2 si o3 revin la valorile
initiale;▫ Se intoarce (A (B) C).

7
Reversul unei liste de doua numere
• Folosind functiile predefinite first si second caredau primul si cel de-al doilea element al uneidau primul si cel de-al doilea element al uneiliste, sa se defineasca o functie care inverseaza ceidoi membri ai unei liste.

8
Patratul unui numar
• Definiti o functie care sa calculeze patratul unui• Definiti o functie care sa calculeze patratul unuinumar dat n.

9
Reversul unei liste de trei numere
• Folosind functia predefinita third care da• Folosind functia predefinita third care daelementul de pe pozitia a treia dintr-o lista, sa sedefineasca o functie care inverseaza cei treimembri ai unei liste.

10
Definirea de functii in pachete
• Sa definim un nou pachet pentru a defini• Sa definim un nou pachet pentru a definifunctiile personale.
• Ne mutam din pachetul curent in cel nou definit.
• Sa definim, de exemplu, pachetul invatare.• Sa definim, de exemplu, pachetul invatare.
• In interiorul sau sa definim functia fn.

11
Definirea de functii in pachete
• Apelam functia describe pentru a vedea daca fn• Apelam functia describe pentru a vedea daca fneste un simbol mostenit din alt pachet.
• Daca acesta este cazul, apelam functia shadowavand ca argument functia existenta.
• Reapelam describe pentru a fi siguri ca fn esteacum simbol al pachetului invatare.

12
Definirea de functii in pachete
• Definim functia fn.
• Testam functia nou definita.
• Verificam daca functia fn originala se poate incafolosi, utilizand formularea ce include pachetulcare o exporta.care o exporta.
• Exportam simbolul functional nou definit, dacadorim folosirea sa si in alte pachete.

13
Redefinirea functiei predefinite last
• last intoarce o lista formata din ultimul element dintr-o lista data.dintr-o lista data.
• In versiunea noastra, va intoarce al treilea element al unei liste date.

14
Continuare

15
Continuare

16
Alt exemplu• Sa definim o functie care sa recunoasca semnul
intrebarii, ?.

17
Problema!
• Cand am definit functia, ne aflam in pachetulinvatare, in care argumentul sau era invatare::?.invatare, in care argumentul sau era invatare::?.
• Cand il testam in pachetul common-lisp-user,argumentul va fi common-lisp-user::?.
• Cele doua simboluri sunt evident diferite.

18
Reformulare
• Intentionam de fapt nu sa recunoastem simbolul?, ci sa recunoastem orice simbol al carui nume?, ci sa recunoastem orice simbol al carui numede afisare este ?.

19
Salvarea definitiilor intr-un fisier
• Pentru a putea salva functiile definite pentru oreapelare urmatoare, le vom stoca intr-un fisierreapelare urmatoare, le vom stoca intr-un fisiercu extensia *.lisp.
• Acest fisier il putem crea in Notepad, avand grijaca, in momentul salvarii sa alegem optiunea AllFiles.
• Fisierul se salveaza in directorul in care aveminstalat Lisp-ul.

20
Compilarea si incarcarea definitiilor• Pentru a vedea eventualele erori/atentionari,• Pentru a vedea eventualele erori/atentionari,
vom compila fisierul rezultat, prin apelareafunctiei (compile-file “nume.lisp”).
• Pentru incarcarea in memoria Lisp, se folosesteapelarea (load “nume”).
• Se apeleaza apoi functia definita in modul clasicde lucru cu Lisp.

21
Exemplu – Suma a trei numere

22
Inversarea unei liste de 4 membri

23
Calculul discriminantului• Presupunem ca avem o ecuatie de gradul 2 fara
radacini complexe.• Testul complet al tuturor posibilitatilor va• Testul complet al tuturor posibilitatilor va
constitui o parte a cursului viitor.

24
Calculul radacinilor ecuatiei de gradul 2• Presupunem ca ecuatia nu are radacini complexe
si ca a este diferit de 0.

25
Functii predicat
• Acestea sunt functiile care intorc fie True (T), fieFalse (NIL).False (NIL).
• Pana acum, am intalnit exemple de astfel defunctii, =, char=, string=, eql, equal.
• O multime standard de functii predicat sunt celecare verifica tipul obiectelor Lisp.care verifica tipul obiectelor Lisp.
• O astfel de functie intoarce T daca tipulobiectului este cel specificat si NIL, altfel.

26
Exemple

27
Combinarea functiilor predicat
• Pentru a alatura rezultatele functiilor predicat,Lisp utilizeaza operatorii logici and si or.Lisp utilizeaza operatorii logici and si or.
• Acesti operatori lucreaza cu un numar arbitrar deelemente.
• Fiecare se opreste atunci cand intalneste primul • Fiecare se opreste atunci cand intalneste primul rezultat al unui predicat care deja conduce la raspunsul final:▫ Un T in cazul unei disjunctii;▫ Un NIL in cazul unei conjuctii.

28
Testarea raportului a doua numere

29
Compararea a doua numere

30
Lungimea unui string / a unei liste

31
Pe saptamana viitoare…

2
Conditionalul
• Lisp are doua tipuri de expresii conditionale:▫ IF▫ IF▫ COND
• Functia care exprima clasicul IF are formularea (if test then else):▫ if e cuvint cheie.▫ if e cuvint cheie.▫ Daca test e adevarat, atunci se intoarce valoarea
lui then; altfel, vom obtine valoarea lui else.

3
Exemple simple

4
Exemple – Testare raport

5
Exemple – Modulul unui numar

6
Exemplu – Functia semn

7
Conditionalul COND• Expresia IF este potrivita pentru a alege intre
doua calcule pe baza unui singur test.
• Insa, in momentul in care avem de ales intre teste multiple, folosirea lui IF este greoaie si greselile pot aparea foarte usor.
• In aceste cazuri, vom utiliza alternativa lui IF si • In aceste cazuri, vom utiliza alternativa lui IF si anume conditionalul COND.
• Evident, in cazul invers, cand avem un singur test, este mai eficient sa folosim IF.

8
Conditionalul COND
• Functia COND are sintaxa (cond (p1 e1) … (pnen)):en)):▫ Evalueaza pi-urile in ordine pana cand unul dintre
ele, pj, este true.▫ Atunci intoarce ej.▫ Daca niciun pi nu este evaluat ca True, atunci
intoarce False.
• Fiecare lista (pi ei) poarta numele de pereche COND:▫ pi este testul (conditia).▫ ei este expresia.

9
Exemplu – Functia semn - Reluare

10
Asemanare cu IF-ul procedural
if p then e (cond (p e )if p1 then e1
else if p2 then e2
else if p3 then e3
else e4
(cond (p1 e1)(p2 e2)(p3 e3)(t e4))

11
Recursivitate

12
Folosirea functiilor recursive
• Sa calculam recursiv suma a doua numerenenegative.nenegative.

13
Observarea recursivitatii

14
Definirea unei functii recursive
• Fiecare functie recursiva poate avea formularea:▫ (defun functie lista_variabile (cond ▫ (defun functie lista_variabile (cond
perechi_cond))▫ sau (defun functie lista_variabile (if test then
else)).
• In cazul unei functii recursive corect definite, un apel cu parametri nepotriviti poate genera o apel cu parametri nepotriviti poate genera o recursivitate infinita.

15
Functia ASSERT
• Pentru a evita argumente gresite, atunci cand definim o functie putem folosi constructia assert.definim o functie putem folosi constructia assert.
• Sintaxa acesteia este:(assert asertie (variabile_de_schimbat) string
variabile_mentionate)▫ Asertia este evaluata.▫ Daca este True, functia se executa normal.▫ Daca este True, functia se executa normal.

16
Functia ASSERT
(assert asertie (variabile_de_schimbat) stringvariabile_mentionate)▫ Daca este False, Lisp printeaza o eroare:▫ Daca este False, Lisp printeaza o eroare: Ii da utilizatorului optiunea de a termina sau de a
schimba valorile acelor variabile_de_schimbat. Mesajul din string este afisat. In acest string putem mentiona anumite variabile,
scriind ~S pentru fiecare si trecandu-le in cadrulcampului variabile_mentionate.campului variabile_mentionate.

17
Redefinim suma a doua numere

18

19
O alta versiune a sumei

20
Produsul a doi intregi nenegativi

21
Produsul a doi intregi nenegativi

22
Produsul a doi intregi nenegativi

23
Ridicarea unui numar la putere

24
Recursivitatea la liste
• Ca prim exemplu, sa incercam definirea versiuniiproprii a functiei length, care determinaproprii a functiei length, care determinalungimea unei liste.
• Partea recursiva: Lungimea unei liste nevideeste cu o unitate mai mare decat lungimearestului listei.restului listei.
• Conditia de terminare: Lungimea listei vide() este 0.

25
Lungimea unei liste
(

26
Apartenenta unui element la o lista

27
Testarea daca o lista e formata sau nu numai din numere

28
Testarea daca o lista e formata sau nu numai din numere – alta versiune

29
Verificarea egalitatii lungimii a doua liste

30
Verificarea egalitatii lungimii a doua liste - varianta

31
Pe saptamana viitoare…

Testarea daca e1 se afla inaintea lui e2 in lista l

Numarul aparitiilor unui element intr-o lista

Testarea egalitatii elementelor a doua liste

Elementul de pe pozitia n din lista l

Obtinerea listei elementelor de dupa pozitia n

Construirea copiei unei liste

Concatenarea a doua liste

Inversarea unei liste
Transforma un element simplu in
lista ce contine acel element.

Inversa – alta solutie

Substituirea primei aparitii a unui element dintr-o lista cu un element nou

Transformarea din lista in multime

Reuniunea a doua multimi

Lista cu primele n elemente din lista data ca argument

Inserarea unui element intr-o multime

Intersectia a doua multimi

Diferenta a doua multimi

Verificarea daca o multime e submultime a unei alte multimi

Egalitatea a doua multimi – fara a lua in considerare ordinea elementelor

Produsul cartezian a doua multimiVom defini o functie care cupleaza un element dat
cu fiecare membru al unei liste, rezultand o lista a liste, rezultand o lista a
cuplurilor formate.

Cuplarea unui element cu fiecare membru al unei liste

Prefixul unei liste

Sufixul unei liste

Schimbul intre 2 elemente dintr-o lista

Pozitia unui element intr-o listaPozitia unui element intr-o lista
La apelare, contorul se initializeaza cu valoarea 1.

Adunarea succesiva a cate doua elemente dintr-o lista
∑n− 1
�x [ i ]� x [i�1]�∑i= 1
�x [ i ]� x [i�1]�

Impartirea unei liste in doua liste: prima cu elemente pare, cea de-a doua cu impare

Impartirea unei liste in doua liste: prima cu elementele de pe pozitiile pare, cea de-a doua cu cele de pe pozitiile impare

Determinarea tuturor numerelor pana la un numar n dat, care sunt divizibile cu un numar k

Maximul unei liste – Metoda 1

Maximul unei liste – Metoda 2

Maximul unei liste – Metoda 3

Quicksort – sortarea unei liste

Pe saptamana viitoare…

Numarul elementelor dintr-o lista
• Dacă lista este vidă, numarul elementelor sale• Dacă lista este vidă, numarul elementelor saleeste zero: aceasta este condiţia de oprire arecursivităţii.
• În clauza recursiva, primul element din listă nune interesează, vrem doar să îl eliminăm ca sănumărăm câte elemente are lista rămasă.numărăm câte elemente are lista rămasă.
• Numărul curent va fi, de fiecare data, egal cu 1plus numărul elementelor din lista rămasă.

Numarul elementelor dintr-o listaPROLOG
nr_elem([], 0). nr_elem([_ | Rest], N) :- nr_elem(Rest, N1), N is N1 + 1.
?- nr_elem([1, 2, 3], X).
X = 3
LISP
(defun lungime(l)(if (null l) 0 (+ 1 (lungime (rest l)))) )
>(lungime ‘(1 5 6 4))4

Suma elementelor dintr-o lista• Dacă lista este vidă, suma elementelor sale este
zero: aceasta este condiţia de oprire azero: aceasta este condiţia de oprire arecursivităţii.
• În clauza recursiva, primul element din listă neinteresează de data aceasta, dupa carecalculam suma elementelor din lista rămasă.
• Suma curentă va fi, de fiecare data, egală cuelementul curent plus suma elementelor din listarămasă.

Suma elementelor dintr-o listaPROLOG
suma([], 0).suma([P|Rest], S) :- suma(Rest, S1), S is S1 + P.
?- suma([1, 2, 3], X).
X = 6
LISP
(defun suma (l)(if (null l) 0 (+ (first l) (suma (rest l))))) >(suma ‘(1 5 6 4))16

Media elementelor unei liste
• Media unei liste se calculeaza drept suma elementelor din lista / numarul acestora.elementelor din lista / numarul acestora.
PROLOG
media(L) :- nr_elem(L, N), suma(L, S), Media is S/N, write('Media este '), write(Media).
LISP
(load “suma”)(load “lungime”)(defun media (l)(/ (suma l) (lungime l))
?- media([1, 2, 3]).
Media este 2.
(/ (suma l) (lungime l)))
>(media ‘(1 5 6 4))4

Apartenenta unui element la o lista
7/56
• Vom defini predicatul apartine/2, unde primulargument reprezintă elementul pentru careverificăm apartenenţa, iar al doilea este lista.
• X aparţine listei dacă este capul listei sau dacă• X aparţine listei dacă este capul listei sau dacăaparţine coadei acesteia.
12:15 PM

Apartenenta unui element la o lista
PROLOG
8/56
LISP
(defun membru (n l)apartine(X, [X | _]).apartine(X, [Y | Rest]) :- apartine(X, Rest).
?- apartine (3, [1, 3, 2]).Yes
?- apartine (4, [1, 3, 2]).
(defun membru (n l)(cond ((null l) nil)((eql n (first l)) t)(t (membru n (rest l)))))
>(membru 3 ‘(1 4 3 5 6))TNo
12:15 PM
T
>(membru 3 ‘(1 5 6 8))NIL

Inversarea unei liste
• Pe langa lista initiala si lista in care depunemrezultatul, se considera si o lista temporara care
9/56
rezultatul, se considera si o lista temporara careeste initial vida.
• Capul listei curente se adauga la inceputul listeitemporare – acesta era initial goala, decielementele se vor adauga in ordine inversa.elementele se vor adauga in ordine inversa.
• Cand lista care trebuie inversata devine vida,unificam lista finala cu cea temporara.
12:15 PM

Inversarea unei listePROLOG
inv(L, Linv) :- inv1(L, [], Linv).inv1([], L, L).inv1([], L, L).inv1([X|Rest], Temp, L) :- inv1(Rest, [X|Temp], L).
?- inv([1, 2, 3], L).L = [3, 2, 1]
LISP
(defun inversa (l)(inv l '()))
(defun inv(l1 l2)(if (null l1) l2 (inv (rest l1) (cons (first l1) l2))))
>(inversa ‘(1 2 3 4))(4 3 2 1)

Pozitia i dintr-o lista
• Enuntul problemei:• Enuntul problemei:
▫ Dându-se o listă şi un număr întreg pozitiv i, să se găsească elementul aflat pe poziţia i în listă.
• Avem doua argumente de intrare, o lista si un numar care da pozitia care ne intereseaza.
• Cum rezolvam problema: scadem i-ul cu cate o unitate si, in acelasi timp, scoatem cate un element din lista. Cand i-ul este 1, primul element din lista este cel cautat.

Pozitia i dintr-o listaPROLOG
pozi([X|_], 1, X).pozi([X|_], 1, X).pozi([_A|R], I, X) :- I1 is I - 1, pozi(R, I1, X).
? - pozi([mere, portocale, pere, gutui], 2, Ce).Ce = portocale
LISP
(defun elemi(i l)(if (= n 1) (first l) (elemi (- n 1) (rest l))))
>(elemi 3 ‘(1 4 5 6))5

Pozitia unui element intr-o lista1 4 6 7 8 9 0 3 2 4 5 6 7
13/56
• Enunt problema:▫ Având date o listă şi un element care aparţine
acestei liste, să se specifice pe ce poziţie este situat elementul în lista dată.
• Avem doua argumente de intrare:▫ Lista in care se gaseste elementul▫ Lista in care se gaseste elementul▫ Elementul pentru care trebuie sa gasim pozitia
• Vom mai construi un predicat care sa contina si o variabila contor care este initial 1.

Pozitia unui element intr-o listaPROLOGpozx(L, X, P):- pozx(L, X, 1, P).
1 4 6 7 8 9 0 3 2 4 5 6 7
14/56
pozx(L, X, P):- pozx(L, X, 1, P).pozx([X|_], X, P, P).pozx([_|R], X, C, P) :- C1 is C + 1, pozx(R, X, C1, P).
? – pozx([ion, petre, marin, olivia], marin, P).P = 3
LISP(defun pozitia (l el p)(defun pozitia (l el p)(if (eql el (first l)) p (pozitia (rest l) el (+ p 1))))
(defun poz (l el)(poz l el 1))
>(poz ‘(a b c d e) ‘d 1)4

Stergerea aparitiilor unui element dintr-o lista
15/56
• Enunt problema:▫ Să se şteargă toate apariţiile unui element dintr-o
listă.• Avem doua argumente de intrare:
▫ Lista din care se vor sterge aparitiile unui element▫ Elementul care trebuie sters▫ Elementul care trebuie sters
• Argumentul de iesire va fi noua lista carenu va mai contine elementul dat.

Stergerea aparitiilor unui element dintr-o lista
PROLOG
16/56
sterg([], _, []).sterg([N|Rest], N, Rez) :- sterg(Rest, N, Rez).sterg([M|Rest], N, [M|Rez]) :- sterg(Rest, N, Rez).? – sterg([1, 4, 6, 8, 6, 12, 6], 6, L).L = [1, 4, 8, 12]
LISP(defun sterg (l el)(defun sterg (l el)(cond ((null l) ‘())((eql (first l) el) (sterg (rest l) el))(t (cons (first l) (sterg (rest l) el))) )>(sterg ‘(1 4 6 8 6 12 6) 6)(1 4 8 12)

Eliminarea duplicatelor dintr-o lista• Enunt problema:
▫ Să se realizeze eliminarea duplicatelor dintr-o listă dată.dată.
• Argument de intrare:▫ O lista data
• Argument de iesire:▫ Lista rezultata prin eliminarea duplicatelor din lista
data.data.• Luam fiecare element din prima lista si verificam
daca apartine restului listei (adica daca mai apare in lista).▫ Daca nu mai apare, atunci il adaugam in lista rezultat▫ Altfel, nu il adaugam.
12:15 PM

Eliminarea duplicatelor dintr-o lista
PROLOGduplicate([], []).duplicate([X|R1], L) :- apartine(X, R1),
duplicate(R1, L).duplicate(R1, L).duplicate([X|R1], [X|R2]) :- duplicate(R1, R2).
? – duplicate([7, 9, 7, 11, 11], L).L = [9, 7, 11]
LISP
(defun duplicate(l)(defun duplicate(l)(cond ((null l) '())((member (first l) (rest l)) (duplicate (rest l)))(t (cons (first l) (duplicate (rest l)))))))>(duplicate ‘(7 9 7 11 11))(9 7 11)

Maximul unei liste
• Consideram primul element al listei ca fiind maximul.
19/56
• Apelam un alt program ce are drept argumente lista ramasa si elementul considerat.
• Parcurgem restul listei; daca gasim un element (capul listei curente) mai mare decat maximul, acesta va deveni noul maxim.
• Altfel, mergem mai departe in restul listei.
• Recursivitatea se incheie cand ajung la lista vida si se intoarce argumentul corespunzator maximului.

Maximul unei listePROLOG
max([P|Rest]) :- Max = P, max1(Rest, Max, M).
20/56
max([P|Rest]) :- Max = P, max1(Rest, Max, M).max1([], Max, Max).max1([P|R], Max, M) :- P > Max, max1(R, P, M); max1(R, Max, M).
?- max([4, 2, 5, 1]).Maximul este 5. LISP
(defun maxim2 (l max)(cond ((null l) (cond ((null l)
max)
((> (first l) max) (maxim2 (rest l) (first l)))
(t (maxim2 (rest l) max))))
(defun maxim1 (l)
(maxim2 (rest

Pozitia pe care se afla maximul unei liste
21/56
• Consideram primul element al listei ca fiind maximul sistabilim pozitia maximului drept 1.
• Apelam un alt predicat ce are drept argumente:▫ lista ramasa▫ elementul considerat drept maxim▫ elementul considerat drept maxim▫ pozitia pe care se afla acesta▫ si un contor care va numara elementele.

Pozitia pe care se afla maximul unei liste
• Parcurgem lista; daca gasim un element (capul noii liste)
22/56
• Parcurgem lista; daca gasim un element (capul noii liste)mai mare decat maximul:▫ acesta va deveni noul maxim▫ pozitia pe care se afla maximul devine contorul curent▫ si se incrementeaza contorul.
• Altfel, mergem mai departe in restul listei, incrementandcontorul.contorul.
• Recursivitatea se incheie cand ajung la lista vida siafisez argumentul corespunzator pozitiei pe care se aflamaximul.

Pozitia maximului unei listePROLOG
poz_max([P|Rest]) :- poz_max(Rest, P, 1, 1).
23/56
poz_max([P|Rest]) :- poz_max(Rest, P, 1, 1).
poz_max([], _, _, Poz) :- write('Maximul se gaseste pe pozitia '), write(Poz).
poz_max([P|R], Max, Contor, Poz) :- Contor1 is Contor + 1, Max < P, poz_max(R, P, Contor1,
Contor1).poz_max([_|R], Max, Contor, Poz) :- Contor1 is Contor + 1, poz_max([_|R], Max, Contor, Poz) :- Contor1 is Contor + 1,
poz_max(R, Max, Contor1, Poz).
?- poz_max([4, 2, 5, 1]).Maximul se gaseste pe pozitia 3

Pozitia maximului unei listeLISP
(defun pozmax(l)
24/56
(defun pozmax(l)(pozm (rest l) (first l) 1 2))
(defun pozm (l m p c)(cond ((null l) p)((> (first l) m) (pozm (rest l) (first l) c (+ c 1)))(t (pozm (rest l) m p (+ c 1)))(t (pozm (rest l) m p (+ c 1)))))> (poz_max ‘(4 2 5 1)3

Interclasarea a doua liste
• Ce presupune interclasarea?
25/56
• Ce presupune interclasarea?
• Avem doua liste care trebuie unite intr-una singura.
• Cele doua liste trebuie sa fie ordonate crescator.
• Elementele listei rezultate trebuie sa fie de asemenea in • Elementele listei rezultate trebuie sa fie de asemenea in ordine crescatoare.

Interclasarea a doua liste
• Capetele celor doua liste ce trebuie unite se compara.
26/56
• Capetele celor doua liste ce trebuie unite se compara.
• Cel mai mic dintre ele se va adauga la lista rezultat.
• Daca sunt egale, se adauga doar o data.
• Daca una dintre ele este vida, lista rezultat este cealalta.• Daca una dintre ele este vida, lista rezultat este cealalta.

Interclasarea a doua listePROLOG
27/56
interclasez([], L, L).interclasez(L, [], L).interclasez([P1|R1], [P2|R2], [P1|R3]) :- P1 < P2,
interclasez(R1, [P2|R2], R3).interclasez([P1|R1], [P1|R2], [P1|R3]) :- interclasez(R1, R2, R3).interclasez(R1, [P2|R2], [P2|R3]) :- interclasez(R1, R2, R3).
?- interclasez([1, 3, 7], [2, 3, 4, 8], L).?- interclasez([1, 3, 7], [2, 3, 4, 8], L).L = [1, 2, 3, 4, 7, 8]

Interclasarea a doua listeLISP
28/56
(defun interclasez (l1 l2)(cond ((null l1) l2)((null l2) l1)((< (first l1) (first l2)) (cons (first l1) (interclasez (rest l1) l2)))((= (first l1) (first l2)) (cons (first l1) (interclasez (rest l1) (rest l2))))(t (cons (first l2) (interclasez (rest l1) l2))))
> (interclasez ‘(1 3 7) ‘(2 3 4 8))(1 2 3 4 7 8)

Prefixul unei liste
• Pentru a testa daca o lista e prefixul altei liste,
29/56
• Pentru a testa daca o lista e prefixul altei liste,compar element cu element cele doua liste.
• Adica, verific daca elementul cap al unei liste prefixeste egal cu cel al listei complete.
• Daca raspunsul este afirmativ, merg mai departe.• Daca raspunsul este afirmativ, merg mai departe.
• Prima lista e prefix a celei de-a doua daca, la unmoment dat, lista prefix se incheie.

Prefixul unei listePROLOG
prefix([], _L).
30/56
prefix([X|R1], [X|R2]) :- prefix(R1, R2).
?- prefix([1,2], [1, 2, 3]).Yes
?- prefix([1,3], [1, 2,3]).No LISP
(defun prefix (l1 l2)(cond ((null l) t)
((eql (first l1) (first l2)) (prefix (rest l1) (rest l2)))(t nil)))
>(prefix ‘(1 2) ‘(1 2 3)) t>(prefix ‘(1 3) ‘(1 2 3)) nil

Sufixul unei liste
• Pentru a testa daca o lista e sufixul altei liste,
31/56
• Pentru a testa daca o lista e sufixul altei liste,parcurg lista completa pana intalnesc exact listasufix.
• Adica, scot elementul cap al listei mari, pana candcele doua liste sunt egale.
• Recursivitatea se opreste deci cand cele douaargumente sunt egale.

Sufixul unei listePROLOG
sufix(L, L).sufix(L, [_Y|Rest]) :- sufix(L, Rest).
32/56
sufix(L, [_Y|Rest]) :- sufix(L, Rest).
?- sufix([1,2,3],[1,2]).No?- sufix([1, 2, 3], [3]).Yes LISP
(defun sufix (l1 l2)(cond ((null l2) nil)(cond ((null l2) nil)((equal l1 l2) t)(t (sufix l1 (rest l2)))))
>(sufix ‘(2 3) ‘(1 2 3)) t
>(sufix ‘(1 3) ‘(1 2 3))nil

Numere pare, numere impare
• Enunt problema: • Enunt problema:
▫ Se dă o listă: să se obţină două liste din aceasta astfel încât prima din ele să conţină elementele pare iar a doua pe cele impare.
• Vom avea asadar o singura lista ca argument de intrare si doua liste ca argumente de iesire.

Numere pare, numere impare
PROLOG
pareimpare([], [], []).pareimpare([X|Rest], [X|R1], L2):-X1 is X mod 2, X1=0,
pareimpare(Rest, R1, L2).pareimpare([X|Rest], L1, [X|R2]):-pareimpare(Rest, L1, R2).
?- pareimpare([1, 2, 3, 4, 5, 6], L1, L2).L1=[2, 4 , 6]L1=[2, 4 , 6]L2=[1, 3, 5]

Numere pare, numere impareLISP(defun pare (l)(defun pare (l)(cond ((null l) '())((= (mod (first l) 2) 0) (cons (first l) (pare (rest l))))(t (pare (rest l)))))
(defun impare (l)(cond ((null l) '())((/= (mod (first l) 2) 0) (cons (first l) (impare (rest l))))(t (impare (rest l)))))(t (impare (rest l)))))
(defun pareimpare (l)(cons (pare l) (cons (impare l) '())))
>(pareimpare ‘(1 2 3 4 5 6))((2 4 6) (1 3 5))

Pozitii pare, pozitii impare
• Enunt problema:
▫ Se dă o listă: să se obţină două liste din aceasta astfel încât prima din ele să conţină elementele de pe poziţiile pare iar a doua pe cele de pe poziţiile impare.
• Vom avea asadar o singura lista ca argument de • Vom avea asadar o singura lista ca argument de intrare si doua liste ca argumente de iesire.

PROLOGparimpar([X], [], [X]).parimpar([X, Y],[Y], [X]).
Pozitii pare, pozitii impare
parimpar([X, Y],[Y], [X]).parimpar([X, Y|R], [Y|R1], [X|R2]) :- parimpar(R, R1, R2).? – pare([ion, marius, mananca, invata, mere, prolog], P, I).P = [marius, invata, prolog]I = [ion, mananca, mere]
LISP(defun impar(l)(if (null l) '() (cons (first l) (impar (rest (rest l))))))))(defun par(l)(if (null l) '() (cons (second l) (par (rest (rest l))))))(defun parimpar(l)(cons (impar l) (cons (par l) '())))>(parimpar ‘(1 5 6))((1 6) (5))

Ordonarea unui sir de numere
38/41
• Având în fişierul de intrare in.txt câte un număr urmat de caracterul punct pe fiecare linie, construiţi un predicat Prolog care să scrie în fişierul ordonat.txt şirul de numere ordonat crescător.▫ Citim numerele din in.txt intr-o lista, le ordonam in alta lista
si le scriem apoi in fisierul ordonat.txt.si le scriem apoi in fisierul ordonat.txt.▫ O sa facem in continuare numai ordonarea elementelor unei
liste.▫ Pentru aceasta, vom folosi metoda quicksort care utilizeaza
mecanismul divide et impera.

Ordonarea elementelor unei liste
39/41
PROLOG
sortez([], []).sortez([P|Rest], Lrez):- selectez(P, Rest, Mici, Mari), sortez(Mici,
MiciSort), sortez(Mari, MariSort), append(MiciSort, [P|MariSort], Lrez).
selectez(_, [], [], []).selectez(P, [P1|Rest], [P1|Mici], Mari):- P1 < P, selectez(P, Rest, Mici,
Mari).selectez(P, [P1|Rest], Mici, [P1|Mari]):- selectez(P, Rest, Mici, Mari).
?-sortez([2, 4, 5, 3, 1], L).L=[1, 2, 3, 4, 5]

Ordonarea elementelor unei listeLISP
(defun sortez (l)(if (null l) '()(append (sortez (selectMici (first l) (rest l))) (list (first l)) (sortez
40/41
(append (sortez (selectMici (first l) (rest l))) (list (first l)) (sortez (selectMari (first l) (rest l))))))
(defun selectMari (el l)(cond ((null l) '())((< el (first l)) (cons (first l) (selectMari el (rest l))))(t (selectMari el (rest l)))))
(defun selectMici (el l)(cond ((null l) '())((> el (first l)) (cons (first l) (selectMici el (rest l))))(t (selectMici el (rest l)))))
>(sortez ‘(1 4 5 3 2))(1 2 3 4 5)

Pana saptamana viitoare…

Avantajele programelor PNP
Sunt orientate catre implementari logice.Sunt orientate catre implementari logice.Sunt extrem de potrivite pentru sistemele expert
apartinand domeniului inteligentei artificiale.Sunt usor de analizat, transformat, verificat,
intretinut.In general, sunt eficiente si competitive inIn general, sunt eficiente si competitive in
comparatie cu programele nedeclarative.Programul este mai degraba “intrebat” decat
executat.

Dezavantajeleprogramelor PNP
Nu sunt usor implementabile si utilizabile pentrualgoritmii matematici de cautare si optimizare dincadrul inteligentei artificiale.
Nu sunt cele mai potrivite pentru exprimareaalgoritmilor folositi in industrie.algoritmilor folositi in industrie.
Au mecanisme mai putin directe decat ale celornedeclarative si sunt considerate de multe ori mai“neprietenoase”.

O privire de ansamblu
• Cursul prezent incearca formularea uneiconcluzii finale asupra:concluzii finale asupra:▫ Diferentelor intre programarea procedurala si cea
nonprocedurala▫ Avantajelor si dezavantajelor fiecareia
• Se doreste asadar:▫ Rezolvarea unei probleme reale▫ Utilizarea unui algoritm clasic de inteligenta▫ Utilizarea unui algoritm clasic de inteligenta
artificiala▫ Comparatia intre implementarile in Prolog, Lisp
(programare nonprocedurala) si Java (programareprocedurala)

Hill-climbing
• Este ca si cand ai urca un munte, este ceata foarte deasa si ai avea foarte deasa si ai avea amnezie.
• Este vorba de o miscare continua inspre valori mai bune, mai mari (de aici, urcusul pe munte).
• Algoritmul nu mentine un arbore de cautare, un arbore de cautare, prin urmare, pentru fiecare nod se retine numai starea pe care o reprezinta si evaluarea sa.

Hill-climbing
A
B
functia hill_climbing(problema) intoarce o solutieSe pastreaza la fiecare reapelare: nodul curent si nodul urmator.
curent = genereaza_nod(stare_initiala[problema])
Cat timp este posibil executaurmator = un succesor al nodului curent
6/17
urmator = un succesor al nodului curentDaca eval(urmator) < eval(curent) atunci
intoarce curentcurent = urmator
Sfarsit cat timp

Dezavantaje hill-climbing
• Maxime locale: este vorba de un varf care este mai mic decat cel mai inalt varf din spatiul mai mic decat cel mai inalt varf din spatiul starilor. Cand se ajunge la maxime locale, algoritmul se opreste pentru ca nu mai poate cobori dealul.▫ Solutia gasita poate fi foarte slaba!
7/17

Problema comis-voiajorului• Problema:
▫ Se dau n oraşe
▫ Să se găsească un tur ▫ Să se găsească un tur complet de lungime minimală
• Reprezentare:
▫ Etichetăm oraşele 1, 2, … , n
▫ Un tur complet este o permutare (pt. n =4:permutare (pt. n =4:[1,2,3,4], [3,4,2,1])
• Spaţiul de căutare este imens:pentru 30 de oraşe sunt 30! 1032 tururi posibile!

Implementarea in Prolog
• Inregistrarea oraselor si a distantelor dintre
dist(1,2,10).dist(1,3,25).
dist(3,4,5).dist(3,5,20).
si a distantelor dintre acestea se va realiza prin adaugarea de fapte si formularea comutativitatii.
dist(1,3,25).dist(1,4,30).dist(1,5,15).dist(1,6,30).dist(1,7,40).dist(2,3,20).dist(2,4,10).
dist(3,5,20).dist(3,6,25).dist(3,7,7).dist(4,5,30).dist(4,6,15).dist(4,7,20).dist(5,6,17).comutativitatii. dist(2,4,10).
dist(2,5,25).dist(2,6,35).dist(2,7,45).
dist(5,6,17).dist(5,7,10).dist(6,7,10).orase(7).d(A,B,X):-dist(A,B,X).
d(A,B,X):-dist(B,A,X).

Predicatul principal
• Apeleaza algoritmul de hill-climbing si afiseaza drumul optim si costul sau.optim si costul sau.
• Se specifica de asemenea configuratia principala si numarul de iteratii (considerat drept conditie de oprire).
go:-start(Drum), hill_climber(Drum, 0, DrumOpt), writeln('Drumul optim este'), writeln(DrumOpt), write('Costul sau este '), eval(DrumOpt, FOpt), write('Costul sau este '), eval(DrumOpt, FOpt), writeln(FOpt).
start([1, 2, 3, 4, 5, 6, 7]).iteratii(200).

Algoritmul de hill-climbing
• Se implementeaza functia definita in algoritm.• Daca nu s-a ajuns la numarul de iteratii maxim, se • Daca nu s-a ajuns la numarul de iteratii maxim, se
incearca “urcarea” intr-o configuratie succesoare.• Daca se va reusi, nodul curent devine cel nou gasit si se
reapeleaza predicatul recursiv.
hill_climber(Drum, GenAnt, Drum):-iteratii(No), GenAnt == No.== No.
hill_climber(Drum, GenAnt, DrumOpt):-iteratii(No), GenAnt \= No, eval(Drum, F), climb(Drum, F, DrumNou),GenNou is GenAnt + 1, hill_climber(DrumNou, GenNou, DrumOpt).

Predicatul de urcare
• Se cauta un succesor al nodului curent.• Daca evaluarea acestuia este mai buna decat a • Daca evaluarea acestuia este mai buna decat a
celui curent, nodul curent devine cel nou generat.• Altfel, nodul curent ramane neschimbat.
climb(Drum, F, DrumNou):-mutatie(Drum, Drum1), eval(Drum1, FNou), FNou < F, Drum1), eval(Drum1, FNou), FNou < F, DrumNou = Drum1.
climb(Drum, _, Drum).

Evaluarea unei configuratii
• Evaluarea presupune costul drumului asociat unei configuratii, adica suma distantelor dintre unei configuratii, adica suma distantelor dintre orasele din circuit.
eval([X|Rest], F):-eval1([X|Rest], F1), ultim([X|Rest], U), d(U, X, D), F is F1 + D.
eval1([_], 0).eval1([_], 0).eval1([X,Y|Rest], F):-d(X,Y,C), eval1([Y|Rest], F1),
F is F1 + C.ultim([X], X).ultim([_|Rest], X):-ultim(Rest, X).

Mutarea intr-un nod succesor
• Presupune, de fapt, aplicarea unui operator de mutatie asupra configuratiei curente.asupra configuratiei curente.
• Se genereaza aleator doua pozitii si valorile corespunzatoare sunt interschimbate.
mutatie(Drum, Drum1):-orase(N), genereaza(N, Poz1, Poz2), cauta(Drum, Poz1, X),
cauta(Drum, Poz2, Y), schimba(Drum, X, Y, Drum1).cauta(Drum, Poz2, Y), schimba(Drum, X, Y, Drum1).
genereaza(N, Poz1, Poz2):- repeat, P1 is random(N) + 1, P2 is random(N) + 1, P1 \= P2, !, Poz1 = P1, Poz2 = P2.

Interschimbare
• Se cauta in configuratia curenta care sunt valorile de pe cele doua pozitii generate aleator.cele doua pozitii generate aleator.
• Cele doua valori se schimba intre ele.
cauta([X|_], 1, X).cauta([_|Rest], Poz, El):-Poz1 is Poz - 1, cauta(Rest, Poz1,
El).
schimba([], _, _, []).schimba([X|Rest], A, B, [B|Rest1]):- X == A, schimba(Rest, schimba([X|Rest], A, B, [B|Rest1]):- X == A, schimba(Rest,
A, B, Rest1).schimba([X|Rest], A, B, [A|Rest1]):- X == B, schimba(Rest,
A, B, Rest1).schimba([X|Rest], A, B, [X|Rest1]):- X \= A, X \= B,
schimba(Rest, A, B, Rest1).

Implementarea in Lisp• Inregistrarea conexiunilor dintre orase si costurilor asociate.
(setf (get 'n1 'conectat) '(n2 n3 n4 n5 n6 n7))(setf (get 'n1 'conectat) '(n2 n3 n4 n5 n6 n7))(setf (get 'n1 'costuri) '(10 25 30 15 30 40))(setf (get 'n2 'conectat) '(n1 n3 n4 n5 n6 n7))(setf (get 'n2 'costuri) '(10 20 10 25 35 45))(setf (get 'n3 'conectat) '(n1 n2 n4 n5 n6 n7))(setf (get 'n3 'costuri) '(25 20 5 20 25 7))(setf (get 'n4 'conectat) '(n1 n2 n3 n5 n6 n7))(setf (get 'n4 'costuri) '(30 10 5 30 15 20))(setf (get 'n5 'conectat) '(n1 n2 n3 n4 n6 n7))(setf (get 'n5 'conectat) '(n1 n2 n3 n4 n6 n7))(setf (get 'n5 'costuri) '(15 25 20 30 17 10))(setf (get 'n6 'conectat) '(n1 n2 n3 n4 n5 n7))(setf (get 'n6 'costuri) '(30 35 25 15 17 10))(setf (get 'n7 'conectat) '(n1 n2 n3 n4 n5 n6))(setf (get 'n7 'costuri) '(40 45 7 20 10 10))

Functia principala si ciclul de hill-climbing
• Se incepe cu o configuratie initiala si iteratia 0.• Pana cand se ajunge la numarul de iteratii maxim,
se incearca “urcarea” intr-o configuratie mai buna.se incearca “urcarea” intr-o configuratie mai buna.• Atunci cand algoritumul se opreste, se intoarce
drumul optim si costul sau.
(defun porneste ()(hill_climber '(n1 n2 n3 n4 n5 n6 n7) 0))
(defun hill_climber (l it)(if (= it 200) (cons (performanta l) l) (hill_climber (climb l) (+ it 1))))

“Urcarea” intr-o configuratie mai buna• Se genereaza o noua configuratie a drumului prin
schimbul valorilor intre doua pozitii aleator selectate.selectate.
• Daca evaluarea acesteia este mai buna decat cea a nodului curent, se retine noul drum drept cel curent.
(defun climb (l)(if (< (performanta (mutatie l)) (performanta l)) (get (if (< (performanta (mutatie l)) (performanta l)) (get
'lista 'mut) l))
(defun mutatie (l)(setf (get 'lista ' mut) (schimba l (cauta l (+ (random
7) 1)) (cauta l (+ (random 7) 1)))))

Evaluarea unei configuratii• Drumul va fi permanent dat de lista nodurilor.• Pentru a calcula costul sau, va trebui sa gasim lista
costurilor asociata acestei succesiuni de noduri, ce va fi costurilor asociata acestei succesiuni de noduri, ce va fi apoi insumata.
(defun performanta (l)(evaluare (append (transforma l) (fl l))))
(defun evaluare (l)(if (null l) 0(if (null l) 0(+ (first l) (evaluare (rest l)))))
(defun fl (l)(cons (gaseste (first (last l)) (first l)) '()))

Lista costurilor asociate drumului
• Pentru doua orase, se cauta pozitia celui de-al doilea in lista de conexiuni a primului.doilea in lista de conexiuni a primului.
• Apoi se cauta costul corespunzator acestei pozitii in lista costurilor asociat primului oras.
(defun transforma (l)(if (null (rest l)) '() (cons (gaseste (first l) (second l))
(transforma (rest l)))))
(defun gaseste (x y)(cauta (get x 'costuri) (cauta2 (get x 'conectat) y 1)) )

Doua functii de cautare
; intoarce elementul de pe pozitia poz din lista l(defun cauta (l poz)(defun cauta (l poz)(if (= poz 1) (first l) (cauta (rest l) (- poz 1))))
; intoarce pozitia elementului el din lista l(defun cauta2 (l el p)(defun cauta2 (l el p)(if (eql el (first l)) p (cauta2 (rest l) el (+ p 1))))

Mutatia asupra unei configuratii
• Se genereaza aleator doua pozitii in vector si se interschimba elementele de la aceste locatii.interschimba elementele de la aceste locatii.
• Se retine noua configuratie, pentru cazul in care este mai performanta.
(defun mutatie (l)(setf (get 'lista ' mut) (schimba l (cauta l (+ (random 7) 1))
(cauta l (+ (random 7) 1)))))
(defun schimba (l p1 p2)(cond ((null l) '())((eql (first l) p1) (cons p2 (schimba (rest l) p1 p2)))((eql (first l) p2) (cons p1 (schimba (rest l) p1 p2))) (t (cons (first l) (schimba (rest l) p1 p2)))))

Implementarea in Java
• Inregistrarea conexiunilor intre
d[0][1] = 10;d[0][2] = 25;d[0][3] = 30;
d[2][3] = 5;d[2][4] = 20;d[2][5] = 25;conexiunilor intre
orase si a costurilor asociate, plus comutativitatea.
d[0][3] = 30;d[0][4] = 15;d[0][5] = 30;d[0][6] = 40;d[1][2] = 20;d[1][3] = 10;d[1][4] = 25;
d[2][5] = 25;d[2][6] = 7;d[3][4] = 30;d[3][5] = 15;d[3][6] = 20;d[4][5] = 17;d[4][6] = 10;for (int i = 0; i < n; i++) d[1][4] = 25;
d[1][5] = 35;d[1][6] = 45;
d[4][6] = 10;d[5][6] = 10;
for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)
d[j][i] = d[i][j];

Functia principalapublic void go()
{int t = 1;int t = 1;
// initializarea drumului - primei solutii potentialefor (int i = 0; i < n; i++)
drum[i] = i;evalD = eval(drum);
while (t < it){
for (int i = 0; i < n; i++) // se lucreaza cu un drumTemp pentru modificaridrumTemp[i] = drum[i];
climb();climb();t++;
}
// afisam solutia finala si costul acesteiafor (int i = 0; i < n; i++)
System.out.print(drum[i] + " ");System.out.println(" cu evaluarea " + evalD);
}

Urcarea intr-o noua solutie
public void climb(){{mutatie();double evalNou = eval(drumTemp);if (evalNou < evalD){
for (int i = 0; i < n; i++)drum[i] = drumTemp[i];drum[i] = drumTemp[i];
evalD = evalNou;}
}

Evaluarea unei solutii
public double eval(int[] sol)public double eval(int[] sol){double evaluare = 0;
for (int i = 0; i < n - 1; i++)evaluare += d[sol[i]][sol[i + 1]];
evaluare += d[sol[n - 1]][sol[0]];evaluare += d[sol[n - 1]][sol[0]];
return evaluare;}

Mutatia asupra unei solutiipublic void mutatie()
{int p1 = -1, p2 = -1;
{int p1 = -1, p2 = -1;
// se genereaza doua pozitii aleatoare in vectorul drumTemp,// adica se aleg doua orase care se vor schimba in traseul posibilwhile (p1 == p2){
p1 = (int)Math.round((n - 1)* Math.random());p2 = (int)Math.round((n - 1)* Math.random());
}}
// schimba pozitiile p1 si p2 in drumTempint temp;temp = drumTemp[p1];drumTemp[p1] = drumTemp[p2];drumTemp[p2] = temp;
}

Ce sa alegem?
Programare procedurala Programare nonproceduralaProgramare procedurala Programare nonprocedurala Implementare directa/clasica a algoritmilor Eficienta Portabilitate Implementare dificila a cunostintelor despre
Prolog Inregistrare directa a cunostintelor despre problema Recursivitate Gandire speciala
cunostintelor despre problema
Lisp Apropiere de gandirea matematica Recursivitate Sintaxa dificila

Pana la examen…