You are on page 1of 0

De la problem la algoritm

Procesul dezvoltrii unui algoritm, pornind de la specificaia unei probleme,


impune att verificarea corectitudinii i analiza detaliat a complexitii algoritmului,
ct i analiza problemei din perspectiv computaional, n scopul determinrii
"duritii" procesului de rezolvare. Etapele menionate, eseniale pentru garantarea
calitii i performanelor soluiei, constituie obiectivul ntregului curs i sunt prezentate
succint n acest curs introductiv.
Aspecte ale construciei unui algoritm
Rutina profesional ne ndeamn, uneori, s considerm algoritmii ca punct de
plecare pe drumul rezolvrii unei probleme i s uitm calea ce trebuie strbtut de
la formularea problemei pn la construcia unui algoritm de rezolvare corect i
performant. n cazurile nebanale, drumul este dificil i impune utilizarea unei baze
logistice impresionante din domenii cum ar fi calculabilitatea, complexitatea i, nu n
ultimul rnd, specificarea problemelor. Dificultatea transpare i dac ne gndim c
descrierea unei probleme este declarativ, n timp ce, n marea majoritate a cazurilor,
algoritmul corespunztor are un caracter imperativ. Descrierea definete proprietile
soluiei problemei, n timp ce algoritmul o construiete (o calculeaz). Etapele
drumului de la problem la algoritm i principalele elemente ce trebuie clarificate n
cursul acestor etape sunt enumerate succint mai jos.

a) Problema este rezolvabil mecanic? Altfel spus, exist o procedur efectiv
care calculeaz soluia problemei?

b) Exist o formulare suficient de clar, complet i neambigu a problemei?
Eventual, n afara unei descrieri efectuate n limbaj natural, poate fi util o
specificaie formal folosind un limbaj de specificare sau de modelare.

c) Problema accept algoritmi tractabili, anume algoritmi care pot fi executai
n timp polinomial n raport cu volumul datelor? Altfel spus, din ce clas de
complexitate face parte problema?

d) Algoritmul construit corespunde specificaiei problemei (este corect)? Care
sunt diferenele n raport cu specificaia, dac exist.

e) Ce cantitate de resurse de calcul, n special spaiu de memorie i timp de
calcul, este consumat de algoritm. Care algoritm este mai performant
pentru problema dat, n eventualitatea existenei mai multor algoritmi de
rezolvare?
2 Cristian Giumale/Note de curs
n afara aspectelor menionate, drumul de la problem la algoritm este dificil i
datorit deciziei delicate a alegerii tipului de limbaj de programare adecvat rezolvrii
problemei i aplicaiei n care este integrat problema, alegere care influeneaz
procesul de dezvoltare a algoritmului. Ultima etap, anume cea a codificrii
algoritmului ntr-un limbaj de programare particular, pare simpl pe lng celelalte
etape premergtoare n drumul de la problem la algoritm.

Exemplele urmtoare ilustreaz civa din paii transformrii unei probleme,
specificat formal, ntr-un algoritm. Ca preambul, detalierea acestor pai impune
precizarea sensului termenilor: problem, procedur efectiv, algoritm, rezolvare
mecanic i complexitate.

Probleme

Prin problem nelegem o mulime de nedeterminri (ntrebri) referitoare
la proprietile dinamice sau structurale ale unor entiti procese sau obiecte
nedeterminri care accept variante de nlturare (rspunsuri) precise, finite i a cror
corectitudine poate fi riguros demonstrat. Entitile formeaz universul problemei.
Acea parte a universului problemei cunoscut apriori reprezint datele problemei, iar
variantele de nlturare a nedeterminrilor sunt soluiile problemei.

Se observ c excludem "problemele" ale cror soluii sunt incerte, n sensul c
soluiile sunt credibile pe baza bunului sim, intuiiei, unor convingeri sociale sau etice,
etc., dei acestea sunt problemele cu care ne confruntm adesea
1
. Mai mult,
deliberat, pentru a evita speculaiile, limitm problemele investigate la mulimea celor
reductibile la urmtoarele tipuri de abstractizri:

1. calculul efectiv al unei funcii i
2. deciderea unei mulimi.

n primul caz, problema este formulat ca o relaie funcional ntre date i
soluii. A rezolva problema nsemn a calcula efectiv funcia, unde termenul efectiv
subliniaz folosirea unei maini de calcul. Chestiunea "problema este rezolvabil
mecanic?" este transformat n "funcia este efectiv calculabil?". De exemplu
problema simpl "fiind dat un numr natural x s se calculeze rdcina ptrat
ntreag" poate fi rezolvat folosind funcia isqr:, unde reprezint mulimea
numerelor naturale (inclusiv 0). Intuitiv, funcia isqr poate fi calculat, deci problema
este rezolvabil. Dac notm cu n/4 ctul mpririi n/4, un calcul posibil este:

| 0, dac n=0
isqr(n) = | 2 isqr(n/4), dac n < (2n/4+1)
2

| 2 isqr(n/4)+1, dac n (2n/4+1)
2


n cel de al doilea caz, problema este formulat ca proces de decizie a
apartenenei unui element la o mulime dat. A rezolva problema nsemn a decide

1
n schimb acceptm probleme ale cror soluii sunt incerte n limitele unor probabiliti
riguros controlate sau probleme cu soluii aproximative n limite impuse.
Cristian Giumale/Note de curs 3
dac valoare cu rol de presupus soluie este ntr-adevr o soluie a problemei.
ntrebarea "problema este rezolvabil?" este transformat n "se poate decide dac o
valoare face parte din mulimea soluiilor problemei?". De exemplu, fiind dat un numr
natural x s se testeze dac x este prim sau, altfel spus, fiind dat un numr natural x
s se decid dac x aparine mulimii numerelor prime, mulime definit:

Prime =
def
{x | x > 1 (d2..x-1 x modulo d 0)}

Calculabilitate

Ambele tipuri de probleme ilustrate mai sus se bazeaz pe posibilitatea de a
calcula efectiv o funcie. n cazul (1) funcia este explicit, n cazul (2) deciderea
apartenenei xM implic existena unei funcii, de exemplu test
M
(x), care rentoarce
1 dac xM i 0 altfel.

O funcie f:IO este efectiv calculabil dac exist o procedur efectiv
capabil s calculeze rezultatul funciei pentru fiecare valoare xI.

O procedur efectiv este o mulime finit de instruciuni, finite ca
dimensiune a reprezentrii, a cror execuie se termin n timp finit i implic o
cantitate finit de date, cu reprezentare finit, pentru a obine un rezultat, mereu
acelai pentru date identice.

O procedur efectiv nu corespunde unui anumit model teoretic al
calculabilitii i, deci, unui anumit tip de main de calcul. Conceptul este general,
descriind intuitiv ce nseamn a executa mecanic un proces de calcul, indiferent de
natura mainii folosite. n consecin, calculabilitatea efectiv a unei funcii se refer la
existena unei maini de calcul, oricare ar fi ea, i, implicit, a unui program care, prin
execuie pe maina aleas, s calculeze valoarea funciei n orice punct din domeniul
de definiie al acesteia.

Este interesant de investigat posibilitatea de a dezvolta un formalism astfel
nct orice procedur efectiv intuitiv s poat fi executat conform formalismului i,
reciproc, orice calcul reprezentabil n formalism s corespund unei proceduri efective
intuitive. Acest exerciiu a fost efectuat n 1936 de ctre matematicianul englez Alan
Turing, maina teoretic construit fiind astzi acceptat ca model al procedurii
efective sau, echivalent, ca model de baz al calculabilitii. Dar maina Turing (care
calculeaz funcii parial recursive) nu este singurul model posibil al calculabilitii.
Alte modele sunt:
Funciile recursive, definite de Kleene n 1936
Calculul Lambda, dezvoltat de Church n 1936
Algoritmii normali, dezvoltai de Markov n 1954

Modelele de mai sus sunt echivalente computaional mainii Turing; orice calcul
efectuat conform unui model poate fi efectuat n toate celelalte modele. De aici, deriv
teza important a lui Church-Turing care susine, fr a demonstra, c orice funcie
este efectiv calculabil dac este Turing calculabil. Implicit, teza afirm c funciile
4 Cristian Giumale/Note de curs
efectiv calculabile sunt exact cele parial recursive i c orice procedur efectiv
corespunde unei funcii parial recursive.
Aspectele prezentate intuitiv mai sus sunt proprii teoriei calculabilitii. Aici,
obiectivul central const n investigarea rezolvabilitii mecanice a problemelor
indiferent de particularitile mainii de calcul folosite, n particular maini ce au
resurse finite, dar orict de mari de calcul. Cteva probleme elementare de
calculabilitate sunt prezentate n capitolul 3.

Algoritmi

Specificarea unei proceduri efective, folosind o notaie convenional, conform
particularitilor computaionale ale unui tip de main de calcul este un algoritm.

Un algoritm acceptat de o main de calcul este o mulime finit de
instruciuni cu semnificaie precis, care pot fi executate de ctre maina de calcul n
timp finit pentru a calcula soluia unei probleme reprezentate n mod finit. Altfel spus,
un algoritm este o particularizare a unei proceduri efective n raport cu un model dat al
calculabilitii.

Definiia algoritmului arat diferena esenial ce exist ntre o funcie i un
algoritm, de fapt ntre un model funcional al unei probleme i rezolvarea efectiv a
acesteia.

O funcie matematic f:IO este o mulime de perechi {(x,f(x)) | xI
f(x)O} ce asociaz un rezultat fiecrei valori a parametrului funciei, dar care nu
arat n nici un fel modul n care rezultatul poate fi calculat.

Un algoritm este un ir de simboluri, practic un text, care indic precis modul i
ordinea n care trebuie transformate datele de intrare pentru a obine rezultatul
corespunztor.

Astfel, putem avea algoritmi care primesc ca intrare reprezentarea unui numr
i produc drept rezultat reprezentarea altui numr, relaia dintre cele dou numere
fiind descris de o funcie. Cu alte cuvinte, putem construi algoritmi care s calculeze
funcii. Dar, nu orice funcie este calculabil, deci nu orice funcie accept algoritmi
care s o calculeze. Prin urmare, nu este suficient ca o problem s accepte un
model funcional pentru ca, automat, s fie rezolvabil mecanic, deci s existe un
algoritm de rezolvare. Este necesar s se demonstreze c un astfel de algoritm chiar
exist.

Orice funcie calculabil poate fi reprezentat indirect printr-un algoritm care o
calculeaz. Astfel funcia test
Prime
: de test al apartenenei unui numr x la
mulimea numerelor prime poate fi reprezentat prin urmtorul algoritm, destinat unei
maini de calcul imperative:

test
e
(x){
Prim
if(x 1) return 0;
// x are divizori nebanali?
Cristian Giumale/Note de curs 5
for(d=2; d isqr(x); d++)
if(x modulo d = 0) return 0; // x este divizibil prin d
return 1; // x nu accept divizori diferii de 1 i x
}
Complexitate

Opus teoriei computabilitii, teoria complexitii algoritmilor se ocup de
problemele rezolvabile mecanic, chestiunea principal fiind legat de performanele
dinamice ale algoritmilor de rezolvare.

Performanele statice, precum claritatea algoritmului evaluat, numrul de linii
sau de operaii folosite n textul algoritmului, nivelul de abstractizare al operaiilor,
originalitatea, etc. sunt de mai mic importan, cu att mai mult cu ct unele dintre
aceste caracteristici nu au o msur clar.

Performanele dinamice ale unui algoritm se refer la cantitatea de resurse de
calcul (mai ales timp i spaiu de memorie) necesare execuiei algoritmului i, teoretic,
pot fi msurate exact sau, cel puin practic, pot fi aproximate n limite acceptabile.
Vom spune c un algoritm are o complexitate temporal (respectiv spaial) cu att
mai mare, cu ct timpul (respectiv spaiul de memorie) cerut de algoritm este mai
mare.

Complexitatea este un criteriu esenial n selecia unui algoritm. Astfel, din
perspectiva teoriei complexitii, elaborarea unui algoritm aduce n prim plan chestiuni
precum:
Ce probleme pot fi rezolvate cu limite impuse de timp i spaiu de memorie
i care sunt caracteristicile acestor probleme?
Exist limite ale resurselor de calcul pentru care o anumit problem nu
poate fi rezolvat?
n ce limite de aproximare a soluiei exacte poate fi rezolvat o problem
astfel nct resursele de calcul consumate s fie acceptabile?
Exist probleme sau algoritmi care cer, inerent, mai multe resurse de
calcul?
Care este complexitatea algoritmului dezvoltat pentru rezolvarea unei
probleme? Ce fel de complexitate msurm: n cazul cel mai defavorabil
sau n medie, pentru o secven de operaii care includ cazurile cele mai
defavorabile (complexitate amortizat)?

Mai multe convenii stau la baza demersului teoretic implicat de ntrebrile de
mai sus. Una dintre convenii se refer la metrica folosit pentru a msura resursele
de calcul consumate de un algoritm; alta precizeaz cum se msoar complexitatea
unui algoritm: exact sau aproximativ, folosind notaii de complexitate care ajut la
compararea algoritmilor chiar atunci cnd complexitatea lor exact difer. De
asemenea, este important de precizat ce se nelege prin complexitate acceptabil
sau, altfel spus, calcul tractabil.

6 Cristian Giumale/Note de curs
Metrica msurrii resurselor de calcul folosite de un algoritm stabilete
cantitatea resurselor consumate de operaiile elementare ale algoritmului i modul n
care aceste cantiti sunt combinate pentru a calcula complexitatea de ansamblu a
algoritmului. Metrica depinde n mare msur de natura mainii de calcul care execut
algoritmul. De exemplu, pentru un algoritm destinat unei maini imperative, gen
C/C++ sau Java, se poate accepta modelul costului unitar pe operaie, considernd c
timpul sau spaiul consumat de fiecare operaie elementar este o unitate de timp sau
spaiu, iar costul unui algoritm se calculeaz ca sum a costurilor pailor si. Este
important ca metrica aleas s conduc la o complexitate ct mai apropiat de cea
real.

Complexitatea exact a unui algoritm este caracterizat de o funcie (de
complexitate) f:R
+
, unde este mulimea numerelor naturale, iar R
+
este
mulimea realilor pozitivi. Valoarea f(n) desemneaz cantitatea de resurse
consumate de algoritm pentru dimensiunea n a datelor (a problemei rezolvate).

Dimensiunea unei probleme desemneaz o msur compus a acelor date
care influeneaz major performanele dinamice ale algoritmului. Dimensiunea este
definit ca lungime a irului de simboluri ce reprezint datele respective, simbolurile
fiind considerate atomice din punctul de vedere al prelucrrilor efectuate de algoritm.

De exemplu, dimensiunea dim(G) a unei probleme de prelucrare a unui graf
G=(V,E) este lungimea unui ir de simboluri care reprezint nodurile V i arcele E ale
grafului. Dac graful are n noduri i m arce atunci lungimea irului este proporional
cu n+m. n cazul n care simbolurile sunt considerate atomice, este puin important
cum sunt reprezentate. De exemplu, un nod poate fi reprezentat printr-un ntreg ce
identific nodul, iar un arc poate fi reprezentat printr-o pereche de ntregi ce
corespund nodurilor de la capetele arcului. n acest caz, irul care codific graful are
lungime n+2m, fiind format cu n simboluri (numere ntregi) distincte. ntr-adevr, aceste
simboluri pot fi considerate atomice, deoarece algoritmul de prelucrare a grafului nu le
modific. Dimensiunea grafului este dim(G) = n+2m.

Dac problema este cea a verificrii "n este prim", unde n este un ntreg
pozitiv, atunci lungimea irului de simboluri necesare reprezentrii valorii n poate fi
dim(n)=lg(n)+1, dac reprezentm numrul n binar, sau dim(n)=log
10
(n)+1,
dac numrul este reprezentat n zecimal. Cele dou valori ale dimensiunii difer doar
printr-o constant i reprezint numrul cifrelor binare sau zecimale necesare
reprezentrii numrului. Simbolul ce corespunde codului lui n nu este atomic,
algoritmul aferent problemei lucrnd cu pri ale simbolului. n schimb, cifrele
reprezentrii numrului pot fi considerate simboluri atomice. n acest caz, afirmaia
"dimensiunea problemei este n" devine discutabil. Bunoar, exceptnd calculul
isqr(n), algoritmul test
Prime
execut un numr de operaii elementare proporional
cu valoarea n . Dac timpul necesar oricrei operaii elementare cu numere pe k bii
dureaz cel mult t(k), t:R
+
, atunci rezult c timpul de calcul efectiv este
proporional cu t(k)
k
2 . Pentru n relativ mic, putem accepta t(k)c, cu c o
constant, iar timpul consumat de algoritm devine proporional cu
k
2 , adic cu n ,
unde n desemneaz valoarea numrului testat. n schimb, pentru n mare, test
Prime

Cristian Giumale/Note de curs 7
are complexitatea temporal exponenial t(k)
k
2 n funcie de dimensiunea k a
reprezentrii lui n. Aa se explic de ce problema factorizrii unui numr mare care nu
este prim este dificil i st la baza unor algoritmi de criptare.

n carte, considerm c operaiile elementare ale unui algoritm au cost unitar.
Implicit, considerm c problemele analizate satisfac aceast convenie.
Cele dou exemple de mai sus arat c dimensiunea unei probleme trebuie
stabilit cu atenie atunci cnd algoritmul este numeric. Aici trebuie fcut diferena
dintre valoarea datelor prelucrate i dimensiunea reprezentrii lor. n schimb, pentru
algoritmii care prelucreaz structuri de date reprezentate prin simboluri atomice,
numrul de elemente din structur desemneaz chiar dimensiunea problemei.

n ceea ce privete cantitatea de resurse consumate, aceasta depinde de
operaiile critice ale algoritmului, cele care cost cel mai mult sau sunt executate
intensiv. Deseori, n analiza unui algoritm sunt contabilizate doar aceste operaii
critice, costul celorlalte fiind fie ignorat, fie absorbit n costul operaiilor critice.

Determinarea funciei exacte de complexitate, notat f, este dificil chiar i
pentru probleme simple, aa cum sunt isqr i test
Prime
. Soluia care permite
evitarea acestor complicaii, deseori inutile, const n aproximarea funciei f printr-o
alt funcie mai simpl, dar suficient de apropiat de complexitatea exact pentru
valori mari ale dimensiunii problemei. ntr-adevr, performanele algoritmilor se
degradeaz atunci cnd dimensiunea crete foarte mult. Aadar, este important ca
aproximarea s fie suficient de bun mai ales n aceste cazuri, motiv pentru care
complexitatea aproximat este numit asimptotic.

Aproximarea asimptotic se bazeaz pe notaii de complexitate dintre care cele
mai frecvent folosite sunt , i . Spunem c un algoritm are complexitatea
(g(n)) dac funcia exact de complexitate este mrginit asimptotic superior de
funcia g(n), proporional n raport cu o constant, deci f(n) c g(n) pentru valori
mari ale lui n. Algoritmul are complexitatea (g(n)) dac funcia exact de
complexitate este mrginit asimptotic inferior de funcia g(n), proporional n raport
cu o constant, deci f(n) c g(n) pentru valori mari ale lui n. Algoritmul are
complexitatea (g(n)) dac funcia exact de complexitate este mrginit asimptotic,
inferior i superior, de funcia g(n), proporional n raport cu dou constante, anume
c g(n) f(n) c' g(n) pentru valori mari ale lui n. De exemplu, pentru numere
relativ mici, problema isqr(x) poate fi rezolvat cu complexitate temporal
(log
4
(x)), deci timpul consumat de calculul funciei isqr(x) este proporional cu
log
4
(x).

n privina complexitii acceptabile, se consider c un algoritm este tractabil
dac are complexitate polinomial (n
k
), cu k o constant. Altfel, algoritmul este
catalogat drept intractabil. Se spune c o problem rezolvabil cu un algoritm tractabil
este tractabil, altfel problema este intractabil. Convenia este discutabil, deoarece
pentru valori mari ale lui k complexitatea devine impracticabil chiar i pentru mainile
de calcul foarte puternice.

8 Cristian Giumale/Note de curs
Msurarea complexitii asimptotice permite compararea algoritmilor i, implicit,
a problemelor. Astfel, un algoritm cu complexitate (n) este mai "bun" dect unul cu
complexitate (n
2
), iar o problem rezolvabil n (n) este mai puin dificil dect
una rezolvabil n (n
2
). Totui, din perspectiva tractabilitii ne intereseaz o
mprire mai net a problemelor n raport cu dificultatea relativ a rezolvrii. Se obin
astfel clase de complexitate, fiecare clas fiind populat de probleme care sunt
rezolvabile prin algoritmi a cror complexitate asimptotic corespunde unor tipuri de
funcii. Considernd n dimensiunea problemei, exist clasele:
LOGSPACE: probleme rezolvabile determinist n spaiu de memorie (log(n))
NLOGSPACE: probleme rezolvabile nedeterminist n spaiu (log(n))
PTIME (sau P) - probleme rezolvabile determinist n timp (n
k
)
NPTIME (sau NP): probleme rezolvabile nedeterminist n timp (n
k
)
PSPACE: probleme rezolvabile determinist n spaiu (n
k
)
NPSPACE: probleme rezolvabile nedeterminist n spaiu (n
k
)

Rezolvarea determinist impune determinarea exact a instruciunii (sau
instruciunilor) algoritmului executate la un anumit pas al rezolvrii, n raport cu
instruciunile de la pasul anterior. Rezolvarea nedeterminist implic ghicirea
simultan a tuturor soluiilor poteniale, urmat de verificarea determinist, dar
simultan, a eligibilitii fiecrei soluii poteniale ca soluie a problemei.

Exist ierarhia de clase de complexitate:

LOGSPACE NLOGSPACE PTIME NPTIME PSPACE = NPSPACE

O problem dintr-o clas inferioar n ierarhie este rezolvabil cu complexitatea
caracteristic oricrei superclase. Este interesant de menionat c ierarhia de mai sus
este robust pentru majoritatea tipurilor de maini de calcul secveniale de interes
practic. Robusteea este neleas ca invarian a complexitii asimptotice a rezolvrii
problemei n raport cu maina de calcul folosit, n limitele unor factori de
proporionalitate polinomiali i cu unele decizii realiste privind metrica de complexitate
folosit. Astfel, similar tezei Church-Turing, se presupune c o problem tractabil cu
o anumit main de calcul este tractabil pentru orice alt main de calcul sau,
echivalent, clasa PTIME este aceeai pentru orice model al calculabilitii (teza
invarianei, atribuit lui Stephen Cook, un pionier al teoriei complexitii).

Cele mai dure probleme din clasa NP formeaz o clas de echivalen numit
clasa problemelor NP-complete, fiind intractabile determinist. Aceste probleme sunt
reductibile reciproc, n sensul c pentru oricare pereche de probleme exist un
algoritm determinist polinomial care transform una dintre probleme n cealalt
problem. Din acest motiv, dac o problem din clasa NP are un algoritm tractabil de
rezolvare, atunci P=NP. Chestiunea P=NP? este deschis.

Ierarhia de mai sus este util din considerente practice. Clasificarea teoretic a
unei probleme evit cutarea unui algoritm cu performane a cror realizare este cel
puin incert. De exemplu, dac o problem este n clasa problemelor NP-complete,
atunci nu are rost cutarea unui algoritm tractabil de rezolvare care ar exista doar
Cristian Giumale/Note de curs 9
dac P=NP. Problema trebuie rezolvat folosind algoritmi tractabili euristici,
probabilistici sau de aproximare.

Corectitudine

O etap esenial a procesului de dezvoltare a unui algoritm este verificarea
corectitudinii acestuia: rezultatele calculate corespund soluiilor problemei rezolvate
de algoritm? Conceptual verificarea corectitudinii este un obiectiv precis i pare c se
poate efectua lesne avnd la ndemn o specificare a proprietilor soluiei n raport
cu proprietile datelor problemei. Dar simplitatea este doar aparent, corectitudinea
implicnd dou aspecte delicate: terminarea algoritmului i validitatea logic a
acestuia. Terminarea algoritmilor este o problem nerezolvabil mecanic, deci nu ne
putem atepta la o tehnic general de demonstrare, fiecare caz trebuind tratat
aparte. Verificarea validitii logice const n a cerceta dac soluia calculat de
algoritm ndeplinete proprietile cerute. n acest caz, exist tehnici generale de
demonstrare, dar aplicarea lor este, de asemenea, dependent de problem.
Algoritmi i paradigme de programare
Procesul de dezvoltare al unui algoritm este influenat de paradigma de
programare folosit la implementarea acestuia. ntr-adevr, exist maini de calcul
abstracte caracteristice diverselor modele de calculabilitate i care susin teoretic
diverse paradigme de programare, cum ar fi programarea logic, funcional,
imperativ, asociativ. Dei aceste maini sunt echivalente din punct de vedere
computaional, deci pot rezolva aceeai clas de probleme, totui modul de a gndi
rezolvarea unei probleme poart amprenta caracteristicilor mainii utilizate.

Problema rezolvat n cele ce urmeaz susine aceast observaie i merit
atenie mai ales din punctul de vedere al caracterului declarativ al rezolvrii.

Rezolvarea este bazat pe afirmaii, care descriu o stare de fapt relativ la
universul problemei, i pe comenzi, care descriu aciuni ce au ca suport astfel de
afirmaii. Afirmaiile i comenzile formeaz baza de cunotine necesar rezolvrii
problemei. Condiiile n care o afirmaie poate fi generat sau o comand poate fi
executat sunt descrise prin reguli, aa cum facem de multe ori noi nine.

Programul de calcul rezultat este asemntor unui compendiu de reguli care
arat ce trebuie fcut n anumite situaii. Aplicarea regulilor este secvenial. O regul
este aplicat imediat ce n baza de cunotine a problemei apar afirmaii conforme
precondiiilor regulii. Numim abloane de identificare aceste precondiii, iar procesul
de testare a conformitii unei afirmaii n raport cu un ablon l numim proces de
identificare. Interpretarea unei reguli CLIPS este:

regul CLIPS interpretare
(defrule r
fapt
1
...
regula r
dac exist fapt
l
...
10 Cristian Giumale/Note de curs
fapt
n
=>

aciune
m
)
aciune
1
...
i exist fapt
n
atunci
execut aciune
1
...
execut aciune
m


Cunotinele faptice fapt
k
i aciunile aciune
k
pot fi parametrizate, adic pot
conine variabile ce vor fi particularizate n funcie de cunotinele faptice existente n
baza de cunotine a rezolvrii problemei. De asemenea, o regul se aplic o singur
dat pentru un grup de afirmaii care i satisfac premisele.

Problem

Fie S o secven de ntregi (elemente din Z). S se determine suma maxim a
subsecvenelor de ntregi coninute n S. Pentru a construi o specificaie a problemei,
numim T Seq mulimea secvenelor cu elemente de tip T i convenim asupra
urmtoarelor notaii:

este secvena vid;
s
1
s
2
... s
n
desemneaz o secven nevid cu elementele s
i
, i=1,n;
#s desemneaz lungimea secvenei s;

De asemenea, fie operatorul
seq
: T Seq T Seq {0,1}, astfel nct
a
seq
s rentoarce 1 dac a este o subsecven n s i 0 altfel. Secvena a este
subsecven n s dac i numai dac a este vid sau exist un indice i>0 astfel nct
numrul elementelor de indice ji din s s fie cel puin egal cu lungimea secvenei a
i a
j
= s
i+j-1
, pentru j=1,2,...,#a. Spus formal:

a
seq
s a = (i
1
| i+#a-1 #s (j1..#a a
j
= s
i+j-1
))

Specificaia problemei sumei maxime a subsecvenelor unei secvene sT Seq
este:
smax(s) =
def
max {aZ Seq | a
seq
s sum(a)},

unde sum(a)= . Specificaia arat c soluia problemei este maximul dintre
sumele elementelor tuturor sub-secvenelor din s, inclusiv secvena vid.

=
a #
i
i
a
1

Funcia C corespunztoare specificaiei smax(s) este ilustrat n figura 1(a).
Corectitudinea este evident, din moment ce sunt parcurse toate subsecvenele
posibile ale secvenei s, reprezentat ca un vector. Complexitatea rezult (n
2
),
unde n este lungimea secvenei
2
.

a) Complexitate (n
2
) b) Complexitate (n)

int summax(int s[], int n) {

int summax(int s[], int n) {

2
Exist i o variant naiv cu complexitate (n
3
), care are un ciclu suplimentar pentru
lungimea subsecveelor parcurse.
Cristian Giumale/Note de curs 11
int smax=0;
for(i=0; i<n; i++) {
int sum=0;
for(j=i; j<n; j++) {
sum+=s[j];
if(sum>smax) smax=sum;
}
return smax;
}
int i,sum,smax;
if(n == 0) return 0;
smax = sum = s[0];
for(i=1; i< n; i++) {
sum = sum < 0? s[i]:sum+s[i];
if(sum > smax) smax = sum;
}
return smax;
}
Figura 1 Funcii C pentru summax
O observaie simpl conduce ns la o rezolvare n timp liniar. Doar o parte din
subsecvenele din s contribuie la soluie. ntr-adevr, n momentul n care suma
subsecvenei curent prelucrate devine negativ, prelucrarea subsecvenei poate fi
abandonat pentru c suma ei nu va putea depi suma oricrei alte subsecvene ce
ncepe cu un numr pozitiv. Figura 2 ilustreaz acest fenomen. Dintr-un total de 120
de subsecvene nevide, doar 5 trebuie prelucrate, anume: 1 3 -2 5 -9, -4,
3 -1 6 -3 5 -7 -8, -3 i 6.


1 3 -2 5 -9 -4 3 -1 6 -3 5 -7 -8 -3 6

Figura 2 Variaia sumei maxime a subsecvenelor

Rezolvarea imperativ, n timp liniar, a problemei corespunde funciei C din
figura 1(b) i are un avantaj suplimentar: este eficient pentru secvene foarte lungi.
Deoarece fiecare numr din secvena s este parcurs o singur dat, nu este necesar
memorarea ntregii secvene. Secvena poate fi citit incremental, doar numrul
curent fiind pstrat pe durata adugrii lui la suma curent calculat.

Dei, intuitiv, funciile - specificate imperativ - din figura 1(b) sunt uor de
neles, drumul de la specificaia formal smax(s) la codul respectiv nu este de loc
uoar. Evitm aceste complicaii i ne concentrm atenia asupra unei rezolvri care
s fie ct mai apropiat de specificaia problemei.

Rezolvarea declarativ de mai jos, n CLIPS, urmrete ad litteram specificaia
problemei, descriind de fapt ce se nelege prin secven de sum maxim. Varianta
declarativ are dou particulariti notabile: (a) n afara sumei maxime, sunt
determinate, fr cod suplimentar, toate subsecvenele de sum maxim; (b) o
singur regul esenial de rezolvare, anume summax, poate prelucra "simultan" mai
multe secvene pentru a le determina suma maxim.

12 Cristian Giumale/Note de curs
(deffunction sum (?subsecventa)
(bind ?s 0)
(progn$ (?n ?subsecventa) (bind ?s (+ ?n ?s)))
?s)

(defrule summax
(secventa ?id $? $?x $?)
(not (summax ?id ?))
(not (secventa ?id $? $?y&:(> (sum $?y) (sum $?x)) $?))
=> (assert (summax ?id (sum $?x)))
(printout t ?id ": sum" $?x "=" (sum $?x) crlf))

(defrule date
=> (printout t "file: ")
(load-facts (readline)))

O secven este reprezentat de afirmaia (secven nume numere). Numele
este necesar pentru a putea calcula "simultan", cu aceeai regul, suma maxim a
fiecrei secvene date. Rezultatul este tiprit i nregistrat n baza de cunotine a
programului sub forma afirmaiei (summax nume valoare). Un exemplu de rulare a
programului este n tabelul 1.

Tabelul 1. Suma maxim a elementelor subsecvenelor unei secvene

fiier sumclp.dat rezultate
(secventa a 4 -1 8 -1)
(secventa b 2 3 4 -1 2 -3 5)
(secventa c 3 -5 -1 2 3 -6 1 15 -1)
(secventa d -1 8 -1 8 -1)
(secventa e)

CLIPS> (reset)
CLIPS> (run)
file: sumclp.dat
e: sum()=0
d: sum(8 -1 8)=15
c: sum(1 15)=16
b: sum(2 3 4 -1 2 -3 5)=12
a: sum(4 -1 8)=11

Programul de mai sus este concis i uor de construit. n contrapartid, preul
pltit este complexitatea semnificativ a rezolvrii. Ignornd timpul necesar identificrii
abloanelor, complexitatea programului declarativ rezult (n
5
) fat de complexitatea
(n) a variantei scrise n C.

You might also like