Sunteți pe pagina 1din 106

Universitatea Danubius din Galaţi

Automate, Calculabilitate şi Complexitate

Prof. dr. ing. Viorel Ariton

Copyright 2023 Toate drepturile asupra acestei ediții sunt rezervate autorului
Descrierea CIP a Bibliotecii Naţionale a României
ARITON, VIOREL
Automate, calculabilitate şi complexitate : note de
curs - specializarea Informatică / Viorel Ariton. - Galaţi :
Editura Universitară ―Danubius‖, 2023
Conţine bibliografie
ISBN 978-606-533-590-5
004

2023
Cuprins

1 Introducere....................................................................................................................................... 4
1.1 Puţină istorie ............................................................................................................................ 4
1.2 Concepte şi formalizare pentru mulţimi şi relaţii .................................................................... 6
1.3 Elemente de logică şi formalizare matematice ...................................................................... 10
1.3.1 Probleme şi soluţii ......................................................................................................... 10
1.3.2 Limbaje în modelare şi raţionament .............................................................................. 11
1.3.3 Noţiuni în logică ............................................................................................................ 12
1.3.4 Formă şi conţinut în Logica Propoziţiilor...................................................................... 14
1.4 Limbaj şi expresii în logica propoziţională ........................................................................... 16
1.4.1 Sintaxa limbajului propoziţíonal ................................................................................... 16
1.4.2 Interpretarea unui ansamblu de fbf ................................................................................ 19
1.4.3 Inferenţe......................................................................................................................... 22
2 Automate ....................................................................................................................................... 27
2.1 Automate Finite fără memorie .............................................................................................. 29
2.1.1 Exemple simple şi critica lor ......................................................................................... 29
2.1.2 Automate Finite Deterministe DFA (Deterministic Finite Automata) .......................... 31
2.1.3 Automate Finite Ne-deterministe NFA (Non-deterministic Finite Automata) .............. 35
2.1.4 Definirea formală a nedeterminărilor NFA şi a acceptării unui cuvânt ......................... 37
2.1.5 Echivalenţa NFA – DFA ............................................................................................... 41
2.1.6 Stabilitatea automatelor acceptoare la operaţii obişnuite (regulate) .............................. 44
2.2 Automate cu stivă PDA (Push Down Automata) .................................................................. 47
2.2.1 Tranziţii de stare la PDA ............................................................................................... 48
2.2.2 PDA deterministe şi nedeterministe .............................................................................. 50
2.2.3 Descrierere formală a PDA .......................................................................................... 51
2.2.4 Definirea acceptării unui şir de caractere de către PDA ................................................ 53
2.3 Maşini cu stări finite şi ieşiri – Traductori ............................................................................ 53
2.3.1 Maşini Mealy................................................................................................................. 54
2.3.2 Maşini Moore ................................................................................................................ 56
3 Limbaje formale şi gramatici .................................................................................................... 58
3.1 Limbaje – definiţii şi proprietăţi ............................................................................................ 59
3.1.1 Simbol, alfabet, cuvânt .................................................................................................. 59

2
3.1.2 Limbaje şi operaţii cu limbaje ....................................................................................... 61
3.2 Reprezentarea Limbajelor ..................................................................................................... 63
3.2.1 Expresii regulate, Limbaje regulate ............................................................................... 63
3.2.2 DFA şi NFA reprezintă expresii regulate ...................................................................... 65
3.2.3 Conversia regEx - NFA ................................................................................................. 66
3.2.4 Conversia DFA - regEx ................................................................................................. 67
3.3 Gramatici ............................................................................................................................... 69
3.3.1 Structuri gramaticale comune ........................................................................................ 69
3.3.2 Gramatici formale.......................................................................................................... 73
3.4 Familii de limbaje .................................................................................................................. 75
3.4.1 Gramatici şi Limbaje Regulate ...................................................................................... 76
3.4.2 Gramatici şi Limbaje Independente de Context ............................................................ 77
3.4.3 Gramatici Sensibile la Context şi Gramatici Nerestrictive ............................................ 77
3.4.4 Ierarhia Chomsky ....................................................................................................... 78
4 Calculabilitate şi Complexitate ................................................................................................. 81
4.1 Calculabilitate - Decidabilitate .............................................................................................. 81
4.2 Maşina Turing TM ................................................................................................................ 84
4.2.1 Descriere formală a TM................................................................................................. 85
4.2.2 Descriere instantanee şi calcul....................................................................................... 85
4.2.3 Utilizarea TM ................................................................................................................ 87
4.3 Complexitate ......................................................................................................................... 89
4.3.1 Parametri ai complexităţii algoritmilor ......................................................................... 90
4.3.2 Evaluare absolută şi relativă a complexităţii algoritmilor ............................................. 92
4.3.3 Notaţii asimptotice ........................................................................................................ 93
4.3.4 Clase de complexitate .................................................................................................... 97
5 Bibliografie ................................................................................................................................ 102

3
1 Introducere

Obiectul cursului este Teoria Ştiinţei Calculatoarelor (Theory of Computer Science) –


aceasta fiind suma de abordări şi cunoştinţe privitoare la modalităţi prin care se pot rezolva
probleme de calcul (ce se poate calcula şi cu ce costuri) dar se şi abstractizează maşina de
calcul – căpătând o exprimare formală. Rădăcinile acestei ştiinţe se găsesc în Teoria
Calculabilităţii (Theory of Computability) denumită şi Teoria Recurenţei (Recursion Theory)
care abordează calculabilitatea în logica matematică. De fapt, recurenţa (însemnând
repetitivitate până la o condiţie de oprire) este cheia rezolvării problemelor de calcul (şi nu
numai) utilizând sisteme de calcul. De notat că există cuvânt recursie în română dar este un
termen medical iar recurent este şi termen juridic.

1.1 Puţină istorie


În esenţă, calculabilitatea înseamnă posibilitatea de obţinere a rezultatelor numerice pentru
o problemă anume, aplicând un procedeu mecanic ce poate fi executat de oricine, fără
cunoştinţe speciale în domeniu. O primă abordare de acest fel a matematicii a avut-o a
Gottfried Wilhelm Leibniz în secolul XVII, nemulţumit de Regulile lui Descartes pentru
direcția minții (Regulae ad directionem ingenii) pe care Leibniz le vede ca pe o colecție de
precepte vagi, care necesită efort intelectual, precum și ingeniozitate din partea agenților care
urmează regulile. Astfel, consideră că o metodă de raționament ar trebui să ofere caracter
universal, fără a necesita nici perspicacitate, nici efort intelectual, doar urmarea unui fir
mecanic al raționamentului care ghidează pe oricine poate percepe și manipula configurații
concrete de simboluri1.
S-au realizat maşini mecanice de calcul, începând cu Leibniz (şi Stepped Reckoner, 1672)
şi apoi Charles Babbage (Difference Engine, 1822 apoi Analytical Engine). Ada Lovelace
traduce în engleză şi adnotează Analytical Engine prin mai multe pagini de observaţii
pertinente legate de maşini de clacul, realizând că ar trebui separate operaţiile de calcul de
datele de intrare şi rezultate – în ideea de algoritm, devenid (se spune) „primul programator‖.
Începând cu secolul XIX se dezvoltă preocupările de logică matematică atât în abordare
algebrică (Boole, De Morgan) cât şi pornind de la o abordare axiomatică spre teorii formale.
Aşa cum Euclid a demonstrat o abordare axiomatică a geometriei, David Hilbert (în anii
1930) a formulat die Entscheidungsproblem fiind încredinţat că matematica ar putea fi
definită ca un sistem axiomatic care să fie (1) consecvent, (2) complet, (3) dovedit consecvent
în cadrul sistemului și (4) să prezinte o procedură de decizie pentru toate declarațiile posibile.
În matematică o importanță esențială o are exprimarea cunoștințelor (acestei științe) în
limbaj scris. Însă fiindcă formulările colocviale pot fi neclare şi prezintă riscul înțelegerii
greşite, în matematică a prevalat o utilizare formalizată a construcţiilor lingvistice. Logica
Propoziţiilor asociază formulărilor obişnuite simboluri care apoi pot fi folosite cu operaţii
logice (ŞI, SAU); pe un plan superior, logica predicatelor (de ordinul I) permite o descriere
formală nuanţată, conective logice, cuantificatori. Astfel, logica de ordinul întâi este un limbaj
matematic în care pot fi formulate aserţiuni - enunțuri cu sens afirmativ sau negativ, care sunt
adevărate sau false în structuri logice adecvate. Aserţiunile care sunt adevărate în fiecare
1
Sieg Wilfried, Computability Theory, 1994-2002 (citeseerx.ist.psu.edu)

4
structură corespunzătoare sunt numite valide; o formulare Φ este validă dacă negația ei ¬ Φ
nu este validă.
Formulând problema de decizie pentru depistarea (decidabilitatea) validităţii aserţiunilor
din logica de ordinul întâi Hilbert considera că se poate găsi o „procedură eficientă‖ care ar
avea ca intrare un enunț matematic precis și, după un număr finit de pași, va decide dacă
aserţiunea este validă sau nu: aceasta este die Entscheidungsproblem – problema deciziei.
În 1930, un alt german – Kurt Gödel (în SUA), a prezentat în teza sa de doctorat o
axiomatizare completă a logicii de ordinul întâi și a formulat „teorema de completitudine‖,
anume că o formulă poate fi demonstrată din axiome dacă și numai dacă este validă. Astfel,
printr-o procedură mecanică se pot parcurge pe rând toate aserţiunile (liniile) dintr-o
demonstraţie matematică şi, întrucât axiomele sunt ușor de recunoscut, se aplică reguli de
inferență simple care conduc către o nouă aserţiune; astfel într-o demonstraţie aserţiunile sunt
ori axiome ori provin din aserţiuni precedente prin inferenţă. În felul acesta, problema pusă de
Hilbert a căpătat o parte de răspuns.
Aserţiunile sunt şiruri de caractere pe care le putem verifica dacă sunt evidente sau nu.
Putem enumera sistematic toate şirurile de caractere de lungime 1, 2, 3 ş.a.m.d. şi putem
verifica dacă fiecare şir este valid; dacă da, putem adăuga ultima linie în lista de formulări a
demonstraţiei. Putem deci astfel lista toate teoremele, adică toate formulele valide ale logicii
de ordinul I printr-o procedură mecanică simplă. Altfel zis, setul de formule valide este
domeniul unei funcții calculabile. În terminologia modernă spunem că mulţimea de formule
valide ale logicii de ordinul întâi este recursiv-(re)numărabilă (calculabilă recursiv).
Pe de altă parte, studenți și colaboratori ai lui Hilbert (Ackermann, Behmann, Bernays) au
lucrat la problema deciziei (denumită în termeni actuali decidabilitate - decidability), legând-o
de o algebră a logicii care oferă mai mult decât un limbaj precis ci „este posibilă o prelucrare
computațională a formulelor logice corespunzând aproximativ teoriei ecuațiilor din algebră‖2.
Teorema de completitudine a lui Gödel nu a fost suficientă pentru a rezolva în mod pozitiv
problema deciziei. În cele din urmă, având în vedere o formulă, F dacă F este validă,
procedura de mai sus le-ar enumera și astfel ar putea răspunde: „Da, F este valid‖. Totuși,
dacă F nu ar fi valid, s-ar putea să nu aflăm niciodată acest fapt. Ceea ce lipsea era o metodă
de a enumera toate formulele nevalide sau, în mod echivalent, de a enumera toate formulele
satisfăcute. Se spune că (interpretarea) α satisface o formulă F (Satisfiability - Erfüllbarkeit)
dacă α(F)=1 „valoare de adevăr‖; sau F satisfiabilă dacă există o atribuire α care satisface F,
în caz contrar F nesatisfiabilă. O tautologie este o formulă F satisfăcută de orice atribuire, F
denumită atunci validă. Exemplu: F1 = (A1 ∨ ¬A1) este oricând satisfiabil – valid.
În 1931 Gödel a demonstrat „teorema de incompletitudine‖: „nu există o axiomatizare
completă și calculabilă a teoriei de ordinul I a numerelor naturale‖. Altfel spus, nu există o
listă rezonabilă de axiome din care să putem dovedi exact toate afirmațiile adevărate ale
teoriei numerelor3.
Folosindu-se de teorema de incompletitudine şi de λ-calculus elaborat de el, Alonzo
Church (SUA), a dovedit că Entscheidungsproblem este de nerezolvat. Alan Turing (Anglia) a
elaborat o maşină abstractă prin a cărei funcţionare să se poată decide (mecanic) validitatea

2
în Stanley Burris, Notes Hilbert and Ackermann’s 1928 Logic Book, 2001 (www.math.uwaterloo.ca)
3
Berechenbarkeit Und Komplexität (edustanford.com/5797003-computability-and-complexity)

5
şirurilor de caractere pentru Entscheidungsproblem. A dat astfel o definiție formală a unui
proces de calcul, cu ajutorul acestuia dovedind şi el că problema este de nerezolvat. Astfel,
speranţele lui Hilbert au fost spulberate.

1.2 Concepte şi formalizare pentru mulţimi şi relaţii


Vom prezenta în continuare concepte familiare privind mulţimi dar scopul este de a obţine
precizia matematică necesară atât în definirea noţiunilor cât şi în simbolistica formalizării.

1. O mulţime este o colecţie de obiecte bine definite. Exemple comune: „mulţimea


studenţilor de la specializarea Informatică‖, „mulţimea magazinelor Kaufland din România‖.
Un element (un obiect) oarecare poate aparţine unei mulţimi A şi spunem că este membru
al ei: x A; în caz contrar, un element oarecare y  A. De remarcat că a ≠{a} şi elementul vid
 este diferit de mulţimea vidă  ≠ {} – care se înscrie simplu .

Mulţimi „celebre‖:
2. Mulţimea numerelor naturale (întregi) pozitive N = {1, 2, 3, . . .},
iar naturale ne-negative N0 = {0, 1, 2, 3, . . .}
3. Mulţimea numerelor întregi Z = {. . . ,−3,−2,−1, 0, 1, 2, 3, . . .}.
4. Mulţimea numerelor raţionale Q = {m/n | m ∈ Z, n ∈ Z, n ≠ 0}.
5. Mulţimea numerelor reale – notată R.
Se reamrcă faptul că o mulţime se poate descrie atât prin înşiruirea elementelor sale (ca
mai sus) dar şi prin proprietăţi specifice ale membrilor ei:
{x  R | -2 < x < 5 }

6. Fie A şi B mulţimi. A este o submulţime (subset) a lui B, scris formal A⊂B, dacă orice
membru al A este şi membru al B. Exemplu: mulţimea numerelor naturale N este submulţime
a numerelor întregi Z.
(a) Orice mulţime A este o submulţime a sa, adică A⊆ A (⊆ înseamnă „inclus sau egal‖).
(b) Mulţimea vidă  este o submulţime a oricăreia:  ⊂ A (⊂ înseamnă „inclus strict‖).
(c) Două mulţimi A şi B sunt disjuncte dacă A  B = .
• mulţimile A1, …, An sunt disjunte perechi (pairwise disjoint) dacă Ai  Aj = 
pentru toţi i, j  {1, …, n}, cu i  j.
(d) O colecţie de mulţimi {A1, …, An} este o partiţie a mulţimii A dacă:
• A1  …  An = A, şi
• A1, …, An sunt disjuncte perechi.
Exemplu {A0, A1, A2} este o partiţie a Z dacă:
– A0 = {n  Z | n = 3k, k  Z }.
– A1 = {n  Z | n = 3k + 1, k  Z }.
– A2 = {n  Z | n = 3k + 2. k  Z }.
7. Dacă B este mulţime, P(B) este mulţimea putere (power set) a sa, definită ca mulţimea
tuturor submulţimilor lui B: P (B) = {A | A ⊂ B}.
Se observă că  ∈ P(B) şi B ∈ P(B) iar P(B) = 2B.

6
Dacă B este finită şi are n elemente, atunci şi P (B) este finită şi are 2n elemente.
Dacă B este infinită şi numărabilă, P (B) este infinită şi ne-numărabilă (v. pct. 15).

8. Dacă A şi B sunt mulţimi iar U este universul de discurs (mulţimea „întreg‖) atunci:
(a) reuninea lor (grafic ∪ sau ) este defintă: A∪ B = {x | x ∈ A ∨ x ∈ B},
(b) intersecţia lor (grafic ∩ sau ) este defintă: A ∩ B = { x | x ∈ A ∧ x ∈ B},
(c) diferenţa lor este defintă: A \ B = { x | x ∈ A ∧ x ∉ B},
(d) complementul lui A, faţă de universul de discurs U este: A = { x | x ∉ A}.

9. Proprietăţi
(a) Comutativitatea
• A  B = B  A.
• A  B = B  A.
(b) Distributivitatea
• A  (B  C) = (A  B)  (A  C).
• A  (B  C) = (A  B)  (A  C).
(c) Identitatea (―elementul neutru‖ în limbaj comun, aşa cum este 0 faţă de adunare)
• A  U = A, unde U este ―universul de discurs‖ – mulţimea ―întreg‖.
• A   = A.
(d) Asociativitatea
• (A  B)  C = A  (B  C).
• (A  B)  C = A  (B  C).
(e) Idempotenţa
• A  A = A.
• A  A = A.
(f) Mărginire în Univers (de discurs)
• A   = .
• A  U = U.

10. Cardinalitatea unei mulţimi finite A notată |A| este numărul de elemente din A. Avem:
|A × B| = |A| · |B| şi |2A | = 2|A| .
Exemplu. fie A = {−2, 3, 5}. atunci |A| = 3:
A
2 = {, {−2}, {3}, {5}, {−2, 3}, {−2, 5}, {3, 5}, A} mulţimea putere iar produsul cartezian
A × A = {(−2, −2), (−2, 3), (−2, 5), (3, −2), (3, 3), (3, 5), (5, −2), (5, 3), (5, 5)}.

11. Produsul Cartezian al A şi B este definit: A × B = {(x, y) | x ∈ A ∧ y ∈ B}, adică


mulţimea tuturor perechilor (ordonate) cu elemente ale celor două mulţimi.
12. O relaţie între două mulţimi A şi B este o submulţime: R ⊂ A × B.
O relaţie binară peste A este o submulţime a produsului cartezian A × A, prin care se
asociază două elemente ale aceleiaşi mulţimi. De exemplu, relaţia ―<‖ peste mulţimea R a
numerelor reale este relaţia ―mai mic decât‖ exprimată (x, y) ∈ ―<‖ sau < (x, y) sau x < y.
Câteva tipuri de relaţii speciale sunt:

7
i) Reflexive: Dacă (a, a) ∈ R pentru toţi a, atunci R este reflexivă.
De exemplu, relaţia ―⊆‖ peste o mulţime, unde fiecare mulţime este submulţime a ei.
ii) Ne-reflexive: Dacă (a, a) ∉ R pentru toţi a, atunci R este ne-reflexivă. De exemplu
relaţia ―<‖ peste R.
iii) Simetrice: dacă (b, a) ∈ R, pentru oricare (a, b) ∈ R, atunci R este simetrică. De
exemplu relaţia ―coleg cu‖ pentru studenţi din aceeaşi grupă.
iv) Antisimetrice: Dacă (b, a) ∉ R, pentru oricare (a, b) ∈ R şi a ≠ b, atunci R este
antisimetrică. De exemplu, relaţia ―<‖ peste R.
v) Tranzitive: Dacă (a, c) ∈ R, pentru oricare (a, b), (b, c) ∈ R, atunci R este tranzitivă. De
exemplu, relaţia ―⊆‖ peste mulţimi.
vi) Total ordonate: Dacă R este tranzitivă, ne-reflexivă şi astfel încât exact una din:
(a, b) ∈ R şi (b, a) ∈ R este adevărată pentru toţi a şi b,
atunci R este denumită strict sau total ordonată. De exemplu, relaţia ―<‖ peste R.
vii) Echivalenţe: o relaţie binară R ⊂ A × A este o relaţie de echivalenţă dacă satisface
următoarele trei condiţii:
R este reflexivă: pentru fiecare element din a ∈ A, avem (a, a) ∈ R.
R este simetrică: pentru toate a şi b din A, dacă (a, b) ∈ R, atunci şi (b, a) ∈ R.
R este tranzitivă: pentru toate a, b, şi c din A, dacă (a,b) ∈ R şi (b, c) ∈ R, atunci (a, c) ∈ R.

13. O funcţie  de la A la B, notată  : A → B, este o relaţie R, având proprietatea ca


pentru orice element a ∈ A, există o pereche ordonată în R, a cărui prim component este a.
Vom spune că (a) = b, ori că  mapează a la b, ori imaginea lui a prin  este b. Mulţimea A
este numită domeniu al  iar mulţimea B este definită:
{b ∈ B | există un a ∈ A cu  (a) = b}
şi denumită codomeniul (domeniul în care funcţia ia valori - range) al .
Se poate descrie o funcţie în diferite feluri: ca înşiruire de elemente, ca o expresie
matematică (formulă de calcul în care o ieşire se obţine prin transformarea unor intrări) sau
printr-o tabelă care pune în corespondenţă elemente ale domeniului şi codomeniului funcţiei:
Fie funcţia  : {0, 1, 2, 3, 4. 5, 6, 7} → {0, 1, 2, 3}.
n  (n)
0 0
1 1
2 2
3 3
4 0
5 1
6 2
7 3

Tabel 1.1 Descriere funcţie prin tabela de corespondenţă.


Această funcţie adună 1 la intrare şi scoate la ieşire rezultatul modulo 4 adică restul
împărţirii prin 4 a adunării efectuate, în prima etapă. Cu aceste domeniu şi codomeniu funcţia
se poate înscrie:
 : Z → Z4

8
14. O funcţie  : A → B este injectivă (face corespondenţă unu-la-unu), dacă pentru oricare
două elemente distincte a şi a′ din A, avem  (a) ≠  (a′). Funcţia  este surjectivă, dacă
pentru fiecare element b ∈ B, există un element a ∈ A, astfel ca (a) = b; cu alte cuvinte,
codomeniul (range) al  este egal cu mulţimea B. O funcţie  este o bijecţie, daca  este
simultan injectivă şi surjectivă.

15. Mulţimi numărabile, finite şi infinite – se caracterizează prin cardinalitatea acestora.


Fie o mulţime A:
i) Dacă |A| ≤ |N| atunci A este numită numărabilă (sau enumerabilă).
ii) Dacă |A| = |N| atunci A este numită numărabilă infinită.
iii) Dacă |A| > |N0| atunci A este numită nenumărabilă.
De observat că, în cazul infinitudinii, există situații imposibile la mulţimi finite. Astfel,
putem avea situații în care o submultime proprie a unei multimi S (adică submulţime strict
inclusă în S) are aceeaşi cardinalitate ca şi S! De exemplu, fie B mulțimea tuturor numerelor
întregi pozitive pare și fie A = N; B este o submulțime a lui A adică |B| ≤ |A|. Pe de altă parte,
dacă am avea funcția  : A → B cu (n) = 2n (care este unu-la-unu), am avea |A| ≤ |B|. Din
aceste ultime relaţii ar rezulta |A| = |B|. De aceea, de exemplu:
|N| = |N0|.
Un alt exemplu al acestui fenomen este că intervalul real (0, 1) are aceeași cardinalitate cu
cea a întregului set de numere reale R: | (0, 1) | = | R |.
Cu toate acestea, mulţimile infinite pot avea carinalităţi diferite. Se consideră că mulţimea
numerelor întregi ne-negative N0 are cea mai mică cardinalitate infinită |N0|.= 0, cu notaţia
alocată 0 ().
Mulţimea putere P(N) este ne-numărabilă: |P(N)| = |2N| > |N0| - exponenţială de infinituri.

16. Ordinul de mărime O al unei funcţii este similar cardinalităţii unei mulţimi, astfel că se
pot compara „cardinalităţile‖ a două funcţii. În particular ne interesează funcţii de bază
precum logn, √n, n, n2, nk, 2n (vezi Capitolul 4).
Fie funcţia  : A → (0,+∞), cu A ⊆ R şi fie aceasta (n) = 3n2 + 5n; este de înţeles că
termenul n2 are cel mai mare ordin de mărime, astfel că am putea considera ordinul de mărime
(n) = O(n2),  fiind o funcţie pătratică mărginită.
In general, se poate scrie (n) = O(g(n)) în ideea că există o constantă c > 0 astfel încât
(n) ≤ c g(n)
De exemplu, verificăm că 3n + 5n = O(n2) astfel: 3n2 + 5n ≤ 3n2 + 5n2 = 8n2, cu c = 8.
2

Este evident că n2 ≤ 2n, în care caz (n) = O(2n) este o supraestimare al ordinului de
mărime al .
Dacă avem (n) = O(g(n)) şi g(n) = O((n)), atunci se foloseşte notaţia Θ şi spunem că cele
două funcţii au acelaşi ordin de mărime (n) = Θ(g(n)). De exemplu 3n2 + 5n = Θ(n2) .
În concluzie, reprezentarea mulţimilor constă în descrierea membrilor/elementelor ei, care
se poate face: (1) extensiv (înşiruirea elementelor), (2) comprehensiv (prin „înţeleges‖ – o
proprietate comună elementelor), (3) inductiv – elementul curent obţinut funcţie de

9
precedentul printr-o regulă/operaţie de închidere peste mulţime: de exemplu adunare + peste
mulţimea numerelor naturale N={0; x∈ N ⇒ (x+1)∈ N}.

1.3 Elemente de logică şi formalizare matematice


Multe din conceptele şi abordările matematice actuale în practica curentă a
informaticienilor par de la sine înţelese – spre exemplu algebra Booleană. Totuşi aceste
formalizări şi logica din spatele lor au rezultat prin efortul de înţelegere a multor oameni de
ştiinţă apoi sistematizare şi reprezentare simbolică a cunoştinţelor efectuate în mare parte de
matematicieni. În fapt, formalizarea este nu doar un limbaj de abstractizare concis şi precis ci
organizează cunoştinţele şi permite folosirea lor spre acţiuni de obţinere a noi cunoştinţe şi
spre intervenţie în lumea reală – după aducerea în concret a abstractizării.

1.3.1 Probleme şi soluţii


În mod simplist, o problemă este o întrebare iar soluţia ei este un răspuns. Atât problema
cât şi soluţia se formulează într-un context anume, adică într-un sistem de concepte şi pentru o
categorie de situaţii din viaţa reală, de obicei acest context fiind deja abstractizat (reprezentat)
privind obiecte şi fenomene din acea categorie de situaţii. De exemplu căutăm soluţie la
parcurgerea unui traseu montan, caz în care ne folosim de hărţi (reprezentare a terenului), linii
şi simboluri de trasee (reprezentări ale traseelor) – în context geografic. Sau căutăm o soluţie
la completarea unui careu rebus, în care problema este o definiţie enigmă (un rebus) iar
soluţia este cuvântul care satisface definiţia şi în plus are numărul de litere egal cu numărul de
căsuţe ce pot fi completate în acel loc; în acest caz, contextul este vocabularul limbii rebusului
împreună cu careul de linii şi coloane în care sunt marcate căsuţele care nu acceptă litere.
Cel mai adesea, pentru rezolvarea problemelor se recurge la raţionament dar se poate şi
apela direct Google pentru obţinerea soluţiei! În oricare din cazuri trebuie să formulăm
problema ca o propoziţie care poate fi declarativă (afirmaţie – pozitivă sau negativă) sau
interogativă (pune sub semnul întrebării o situaţie sau acţiune).
Pentru desfăşurarea raţionamentului însă, se utilizează doar propoziţii afirmative care se
înlăţuie după o logică specifică contextului (şi domeniului de ştiinţă), desfăşurând atât
secvenţe de supoziţii cât şi ramificaţii sau repetiţii de mai multe secvenţe, până la o situaţie de
oprire (halt) ce indică obţinerea soluţiei (sau mai multe situaţii de oprire pentru soluţii
multiple – dintre care se poate alege cea optimă).
Rezolvarea oricărei probleme este consumatoare de timp şi resurse: timp pentru proiectarea
(dezvoltarea) secvenţelor de afirmaţii şi pentru parcurgerea lor, iar resurse - materiale, ajutor
uman sau financiar, sunt necesare celor doi p. Totuşi, chiar după găsirea soluţiei, sunt
numeroase probleme pentru care verificarea soluţiei este importantă, chiar esenţială. În
anumite situaţii critice trebuie asigurate nu doar soluţia ci şi anumite proprietăţi ale ei, care
pot fi stabilite numai înţelegând modul în care această soluţie poate fi găsită sau construită.
Dacă soluţia găsită trebuie apoi „pusă în operă‖ – adică trebuie realizat ceva practic pentru
a se interveni în lumea reală prin aplicarea soluţiei, atunci trebuie urmată o metodologie şi
apoi aplicată o tehnologie pentru a se „implementa‖ soluţia. Metodologia este o reţetă
exprimată în limbaj natural care adesea este completat cu un limbaj formal (limbaj „artificial‖
– codificat) iar tehnologia este o înşiruire de proceduri care pot fi exprimate în limbaj tehnic.

10
1.3.2 Limbaje în modelare şi raţionament
În modul simplist descris mai sus, s-a considerat în ansablu un context în care se
formulează şi se soluţionează o problemă. Dar rezolvarea unei probleme nu se poate face cu o
mulţime amorfă de cunoştinţe ci acestea trebuie organizate într-un model coerent (fără
contradicţii între cunoştinţe şi combinaţii ale lor) şi, de dorit, complet – fără aspecte
necunoscute sau doar parţial cunoscute. În general, orice model este conceput ca un sistem:
părţi şi relaţii între părţi. „Abordare sistemică‖ este denumirea modernă pentru modalitatea
comună şi veche de când lumea în care omul încearcă înţelegerea şi controlul fenomenelor din
lumea reală şi constă în: (1) delimitarea zonei de interes (cu contur) spre a fi separată de restul
mediului înconjurător; (2) identificarea (cu nume şi proprietăţi) anumitor obiecte (cu cuvinte
şi adjective) aşa-zise entităţi, în zona de interes; (3) identificarea şi caracterizarea relaţiilor
(interacţiunilor) între entităţi prin proprietăţi specifice fiecărei relaţii. Toate acestea sunt
probleme de limbaj pentru că identificarea şi descrierea lor se face prin cuvinte.
După cum se poate observa, atât în rezolvarea problemelor cât şi în aplicarea lor sunt
necesare limbaje; iar dacă în- şi după- rezolvarea problemelor este necesară comunicarea
(între oameni, maşini, civilizaţii) apare cu atât mai evident necesar limbajul.
Se denumeşte univers de discurs mulţimea tuturor obiectelor peste care se formulează şi
se soluţionează problema, aplicabil atât pentru contextul obiectual cât şi pentru contextul de
valori – cantitative şi calitative. De remarcat că valorile cantitative se exprimă prin numere iar
cele calitative prin atribute (denumire generică, pentru că pot fi adjective): mare / mic, cald /
rece; mărimile calitative privesc nu doar calităţi ci şi tendinţe: creşte / scade / constant.
Limbajele se clasifică după diferite criterii, cele mai concise privesc categorii binare4:
(A) Limbaje universale și limbaje speciale: Limbajele universale sunt suficient de
elaborate pentru a descrie orice univers de discurs și pentru a exprima orice soluții la
probleme (ce pot fi descrise și au soluții). Un limbaj universal este limbajul logicii
predicatelor, în sensul că matematica poate fi exprimată în acest limbaj. Limbajele speciale
sunt limbaje relativ simple, și care pot descrie doar universuri limitate dar sunt preferate în
cazuri în care pot exprima problema de interes şi soluţia acesteia în mod simplu. Logica
propozițională, limbajul circuitelor cu comutare sunt astfel de limbaje.
(B) Limbaje descriptive și limbaje algoritmice: se descriu obiecte, situații, cunoștințe prin
limbaje de tipul celui din matematica tradiţională, cu un formalism redus dar sistematic.
Limbajele algoritmice permit descrierea de acțiuni pentru rezolvarea problemelor – cum sunt
limbajele de programare.
(C) Limbaje naturale și limbaje formale: limbajele învățate într-o comunitate umană, cu
modul specific de formulare a propoziţiilor/frazelor (sintaxa), cu semantica şi sistemul de
raționament învăţate în acest context sunt limbaje naturale. În limbajele formale vocabularul,
sintaxa, semantica și sistemul de raționament sunt definite şi descrise precis, iar folosirea lor
este strictă şi orientată spre precizie.
(D) Metalimbaj și limbaj obiect: un limbaj folosit pentru a defini un alt limbaj este denumit
metalimbaj iar limbajul definit este denumit limbaj obiect. Prin metalimbaj se poate raționa
despre proprietățile limbajului obiect, astfel că ideea de metalimbaj este destul de generală;

4
Crăciun A. Logică computaţională, 2020,
https://staff.fmi.uvt.ro/~adrian.craciun/lectures/logica/pdf/noteDeCursLogica.pdf

11
descrierea comună a teoriei mulţimilor este un metalimbaj prin care se poate defini apoi
limbajul formalizat al teoriei mulţimilor.
Pentru că în contextul teoriei informaticii interesează Limbajele Formale, vom preciza că
la aceste limbaje contează în principal forma în care sunt construite cuvintele şi expresiile –
acestea trebuie să fie bine formate – well formed; mai puţin contează semnificaţia (semantica)
lor. Spre exemplu, în limbajul de reprezentare a numerelor naturale cu simboluri
alfanumerice sunt bine formate „123‖, „70800‖ dar nu sunt bine formate „0015‖, „1a3oo‖ –
regula de „bună formare‖ este: secvenţă finită (şir) de cifre care nu încep cu „0‖.
În continuare se prezintă noţiuni de logică cu elemente de limbaj pentru formalizare şi
pentru constituirea de expresii cu rezultat valori logice (adevărat/fals, Da/Nu).

1.3.3 Noţiuni în logică


O propoziție este o declaraţie care este fie adevărată fie falsă – exclusiv una din ele,
apreciată prin valoarea de adevăr – să o notăm ValA. Dacă propoziția este adevărată, atunci
valoarea sa de adevăr ValA=T (True - în engleză, Adevărat) sau în uzanţe informatice
ValA=1, în caz contrar ValA = F (False), respectiv ValA = 0. Exemple de propoziţii sunt:
„pătratul lui 4 este 16‖- notată D, „Timişoara este capitala Europei‖, notată E, cu:
ValA (D) = T şi, ValA (E) = F (Timişoara poate fi doar „capitală europeană‖ a culturii).
Nu sunt propoziţii în contextul acestei logici: „adu-mi un pahar cu apă‖, „uşa e închisă?‖,
adică nu se pot ataşa valori de adevăr la o comandă, o întrebare sau o exclamaţie. Se remarcă
faptul că şi pentru o declaraţie valorea de adevăr nu este obligatoriu certă, altfel spus omul nu
este totdeauna sigur de adevărul cunoştinţelor sale (adesea dependente de context).
În scrierile sale, Aristotel (sec. III BC) pune bazele logicii, enunţând principiile „terţiului
exclus‖ şi „legea contradicţiei‖ iar discipolul său Theophrastus recunoaşte necesitatea
dezvoltării unei doctrine a propoziţiilor complexe folosind conjuncţii de propoziţii (ŞI),
disjuncţii (SAU), ori implicaţii (DACĂ ... ATUNCI). Filozofi şi gânditori medievali au
încercat formalizări ale logicii aristoteliene dar paşii importanţi au fost făcuţi în sec. XIX de
Augustus De Morgan şi George Boole, ultimul interesat în dezvoltarea unei algebre
(matematică) care să înlocuiască silogismul „literar‖ aristotelian. Boole a folosit 1 şi 0 ca
valori, astfel că pentru două variabile x şi y produsul xy să reprezinte intersecţia iar suma x+y
reuniunea, astfel că, de exemplu, x+y=1 dacă oricare din variabile este 1 (suma modulo 2).
Algebra „booleană‖ este folosită la baza logicii propoziţiilor.
Logica propoziţiilor clasică – în care valorile de adevăr sunt binare (T / F), este cea mai
studiată logică, existând şi alte logici cu valori de adevăr altele decât T şi F ori cu valori de
adevăr continui (cum este Logica Fuzzy) sau chiar cu valori de adevăr nedeterminate. Din
logica propoziţiilor derivă logica predicatelor – logica de ordinul întâi.
În limbaj natural este posibil ca o frază să nu poată fi analizată logic uşor, de aceea logica
propoziţiilor clasică foloseşte propoziţii atomice/atomare (adică simple: cu un subiect şi un
predicat), propoziţii care apoi sunt combinate prin conectori (operatori) logici, astfel că
propoziţiile compuse sunt tratate ca funcţii de adevăr.
Spre deosebire de logica propozițională – în care unităţi atomice sunt propoziţii, logica
predicatelor tratează ca unități atomice predicatele, subictele şi complementele (atributele
calitative). Logica predicatelor a fost propusă de Gottlob Frege, introducând cuantificatorii
existențiali (∃x) și universali (∀y), care sunt omologii logici ai cuvintelor în limbaj obișnuit

12
„unii‖ sau „câţiva‖ (cuantificator existențial), respectiv „oricare‖ și „toţi‖ (cuantificator
universal). „Amploarea‖ unui cuantificator este indicată printr-o exprimare între parantezele
care urmează: (∃x)(…) sau (∀y)(…), unde apar notații pentru variabile (x, y), simbolul de
identitate, „=‖ şi un set de predicate (înscrise convențional cu majuscule) pentru a exprima
proprietăți sau relații. Astfel, dacă „R‖ reprezintă proprietatea „... este roșu‖, atunci (∃x)(Rx)
înseamnă (se citeşte): „există un‖ x „astfel încât‖ „este roșu‖. Corespunzător, (∀x)(Rx)
înseamnă: „oricare‖ x, este roșu. Evident, lui x i se va atribui un obiect sau o clasă de obiecte
pentru care relaţia R va fi adevărată (sau nu) – spunem că variabila x va fi instanţiată.
În modul cel mai simplu, cuantificatorii se aplică la indivizii dintr-un grup dat de obiecte,
de bază - „universul de discurs‖; dar cuantificatorii se pot extinde şi la obiecte „de ordin
superior‖, cum ar fi mulțimi (sau clase) de indivizi, proprietăți și relații ale indivizilor,
mulţimi de mulţimi, proprietăți și relații ale unor proprietăți și relații. Sistemul logic care
aplică cuantificarea doar asupra indivizilor este denumit logica [predicatelor] de ordinul întâi
devenind partea de bază a logicii, pe când sistemele logice în care cuantificarea este permisă
și asupra entităților de ordin superior sunt cunoscute ca logici de ordin superior (introduse de
David Hilbert și Wilhelm Ackermann).
Logica predicatelor şi logici de ordin superior au fost introduse pentru că logica
propoziţiilor poate prezenta ambiguităţi. De exemplu, verbul „este‖ poate avea în limbaj
natural mai multe sensuri (nu doar în română) şi poate exprima (1) o descriere a unei
proprietăţi/calităţi [exemplu: „CRBL/cerebel (fie notat c) este Regizor (proprietatea/relaţia
R)‖ care are forma logică/simbolică scrisă R(c)], (2) identitate simplă [ex. eduard notat e -
Mihail Andreianu este (identic cu) CRBL‖ exprimată „e = c‖], (3) existență [ex. „este CRBL‖
sau „există CRBL‖ care are forma (∃x)(x = c) citit „există un x astfel încât x este c‖] și (4)
includerea în clasă [ex. „rapperul este muzicant‖ cu forma (∀x)(Rap(x)⊃Muz(x)) sau „pentru
toți x, dacă x este rapper, atunci x este un muzicant‖ – unde Muz() este clasa „muzicanţi‖].
Raţionamentul este o compunere de declaraţii (propoziţii atomice) şi constă într-un enunţ
cu două părţi: Antecedent ce conţine propoziţii premize şi Consecvent constând în concluzie
ce conţine o propoziţie rezultat; în înţeles obişnuit, un enunţ este o frază compusă din
propoziţii cu legături între ele. Premiza prezintă o situaţie de fapt şi constă dintr-o propoziţie
sau mai multe propoziţii-premize combinate în antecedent prin intermediul unor conectori
logici. Concluzia prezintă o (singură) propoziţie ce rezultă logic din fenomenul care pune în
legătură cunoştinţele din premiză cu cunoştinţa din concluzie. În limbajul comun se folosesc
cuvinte specifice care identifică premiza P şi concluzia C: „dacă‖ P „atunci‖ C, sau „există‖
P1 şi P2 „deci‖ C – cuvintele între ghilimele preced P respectiv C.
Să analizăm două cazuri de inferenţă:
I. este fum (P) deci este foc (C);
II. 10 „negri mititei‖ (P1), 1 a plecat din ei (P2) deci au rămas 9 (C);
În ambele cazuri avem enunţuri care conţin declaraţii dar nu întotdeauna se pot decela
declaraţiile din enunţ; de exemplu cazul I. poate avea forma „este foc, este fum‖ – nu apar
cuvinte care să identifice clar premiza şi concluzia, ba chiar se poate considera că concluzia
apare înaintea premizei dacă am interpreta enunţul „este foc fiindcă este fum‖.
Ca atare este necesară o analiză a enunţului pentru a se decela premizele şi concluzia sau
este necesară o exprimare restrictivă (în limbaj formal) pentru a se înlătura confuziile; mai
mult, o persoană care emite de la sine un enunţ crede (îşi închipuie) că în fenomenul observat

13
concluzia este legată de premize – dar se poate înşela. De aceea este necesar nu doar un
sistem de exprimare precis ci şi un set de cunoştinţe verificat (privind validitatea), totul pe o
bază axiomatică (supoziţii nedemonstrate dar acceptate) consistentă domeniului (adică ideile
din propoziţii să nu fie în contradicţie cu fenomene din domeniu „explicate‖ pe această bază).
Există diferenţe importante în cazurile de inferenţă de mai sus – care vom vedea că privesc
separarea logicii în două ramuri principale. Pe de o parte, în caz I. ştim că apare fum dacă este
foc dar nimic nu garantează că fumul (observat) provine de la un foc (poate fi de la un
eşapament). Este probabil că fumul provine de la un foc dar nu avem cunoştinţe suficiente
spre a stabili cu certitudine aceasta; tradiţional acest tip de inferenţă ţine de logica inductivă
– care extrage din premize concluzii plauzibile (cu marja lor de eroare). Altfel spus, logica
inductivă priveşte enunţuri în care adevărul premizelor par a duce către conluzie.
Raţionamentul inductiv este potrivit în abordări statistice sau probabilistice ale fenomenelor
sau în abordarea posibilistă – ca ramură a inteligenţei artificiale (posibilistic reasoning).
Raţionamentul inductiv nu trebuie identificat cu „metoda inducţiei‖ matematică.
În cazul II. adevărul premizelor face concluzia certă, altfel spus dacă premizele sunt
adevărate obligatoriu concluzia este adevărată; aceasta este logica deductivă: în contextul
cunoştinţelor din domeniul ţintă, se pleacă de la cauze la efect. Acesta este modul „scolastic‖
în care se prezintă fenomenele, ca şi cum cauzele fac parte dintr-un spaţiu închis (nu apar
influenţe neaşteptate/necunoscute din afara acestui spaţiu) şi la fel, efectele aparţin unui spaţiu
închis (doar anume efecte ne interesează – cele utile scopului). Pentru informare, există şi
logică abductivă în care se pleacă de la efecte către cauze (ca în cazul diagnozei – tehnice,
medicale) iar aici avem de a face cu un spaţiu deschis al cauzelor şi un spaţiu deschis al
efectelor, adică trebuie să luăm seama la cauze noi, adăugate celor considerate iniţial, dar şi
efectele se pot reconsidera – pentru că există legături multiple între cauze şi efecte. În timp ce
în logica deductivă putem adesea lega cauzele cu efectele printr-o funcţie (cu cauzele
aparţinând domeniului şi efectele codomeniului) – funcţie care poate avea inversă (dacă este
bijectivă), în logica abductivă acea funcţie nu este sigur bijectivă datorită legăturilor multiple
cauză-efect. De aceea, pentru problemele abductive inteligenţa artificială este aproape singura
modalitate de rezolvare – prin modele conexioniste (reţele neuronale artificiale) etc.

1.3.4 Formă şi conţinut în Logica Propoziţiilor


Aşa cum am văzut la §1.3.3 raţionamentul (inferenţa) constă în obţinerea unei propoziţii
concluzie C din premize P şi am analizat două cazuri de inferenţă. În abordarea logică a
inferenţelor se încearcă a se face abstracţie de conţinutul propoziţiilor P şi C; mai mult, se
caută depistarea valorii de adevăr la enunţuri (compuse) aplicând mecanic reguli şi operatori.
Se poate lesne constata că inferenţe care nu ţin cont de cunoştinţele din domeniul ţintă duc la
concluzii false şi chiar rupte de realitate. Să analizăm încă două inferenţe:
III. toate pisicile sunt câini (P1), toţi câinii sunt reptile (P2) deci toate pisicile sunt
reptile (C);
IV. toţi peştii sunt vertebrate (P1), toate mamiferele sunt vertebrate (P2) deci peştii sunt
mamifere (C);
Evident, premizele enunţului III, sunt false faptic adică nu sunt conforme cunoştinţelor în
domeniul biologiei. În enunţul IV. premizele sunt adevărate faptic dar concluzia nu rezultă

14
necesar din premize pentru că din cunoştinţele în domeniu clasa vertebrate este mai
cuprinzătoare decât submulţimea ei clasa mamifere iar concluzia este falsă.
Din aceste exemple rezultă că nu orice enunţ poate fi tratat prin logica propoziţiilor (sau
orice altă logică). În aceste condiţii se pun următoarele întrebări: (1) sunt premizele
adevărate? (2) concluzia rezultă din premize? Pentru a răspunde corect la aceste întrebări se
vor defini următoarele condiţii:
I. un enunţ este faptic corect dacă şi numai dacă toate premizele sunt adevărate;
II. un enunţ este valid dacă şi numai dacă concluzia rezultă din premize;
III. un enunţ este valabil dacă şi numai dacă este simultan faptic corect şi valid.
Se poate spune că un enunţ faptic corect are conţinut conform (domeniului) şi un enunţ
valid are o formă conformă (logicii) iar un enunţ valabil le are pe ambele. Se poate apoi spune
că: „un enunţ este valid dacă şi numai dacă este imposibil să aibă o conluzie falsă în timp ce
premizele sunt adevărate‖, sau alternativ „la premize adevărate concluzia este necesar
adevărată‖. Se observă că „adevărul‖ în premize P şi concluzie C nu constă în „valoarea de
adevăr‖ ValA = T | F (True | False) ca rezultat al unei expresii logice ci „adevăr‖ relativ la
conformitatea cu cunoştinţele din domeniu – iar din analiza aceasta rezultă în fapt T | F (True
| False) pentru P şi C. Termenul VALABIL, utilizat mai sus, corespunde celui din engleză
sound (iar ca substantiv „valabilitate‖: în engleză soundness, în franceză solidité).
Pentru ca aspectele expuse mai sus să fie bine înţelese se face în continuare o recapitulare
scurtă a noţiunilor prezentate:
PROPOZIŢII şi ENUNŢURI:
a) Propoziţie atomică: este structura gramaticală obişnuită formată din (1) subiect, (2)
predicat, (3) complement - de mod, de loc etc.
b) Complement: este o calitate anume şi poate fi din punct de vedere gramatical un
adjectiv, un atribut sau chiar un substantiv care exprimă (apartenenţa la) o clasă, o mulţime;
de exemplu: ―toţi savanţii sunt oameni‖ - aici ―oameni‖ este clasa tipului de fiinţe de care
aparţinem şi astfel exprimă o mulţime înţeleasă drept ―calitate‖.
c) Enunţ: este un ansamblu de propoziţii structurat în două părţi: Antecedent (constituit din
una sau mai multe propoziţii premiză) şi Consecvent/Concluzie (constituită dintr-o singură
propoziţie) şi este rezultat aşteptat al raţionamentului efectuat prin enunţ. Pentru lizibilitate,
fiecare propoziţie din antecedent şi din consecvent se scriu pe linii separate. De obicei,
consecventul este separat de antecedent prin cuvinte de identificare precum „deci‖, „ca
urmare‖ etc. sau prin simbolul  plasat între antecedent şi consecvent (în faţa liniei
concluzie).
d) Cunoştinţă: este exprimată printr-o propoziţie şi ea reflectă înţelegerea umană a unei
situaţii, astfel, cunoştinţa poate fi conformă cu realitatea (dintr-un domeniu ţintă) sau nu;
poate fi adevărată sau falsă – atenţie o cunoştinţă din antecedent este adevărată sau falsă dacă
este conformă cu realitatea (faptic corectă) sau nu, pe când o cunoştinţă din consecvent este
adevărată sau falsă dacă provine logic din antecedent.
Enunţ FAPTIC CORECT, VALID, VALABIL:
i) Enunţ FAPTIC CORECT este cel în care toate premizele sunt faptic corecte, adică sunt
conforme cunoştinţelor din domeniul ţintă.
ii) Enunţ VALID este cel în care concluzia rezultă clar (este consecinţă logică) din
premize; cel mai adesea consecinţa logică există atunci când în premize un complement este

15
ataşat unei întregi mulţimi/clase şi concluzia se referă la o submulţime a acesteia; în caz
contrar – când o premiză se referă la o submulţime/subclasă iar concluzia se referă la o întregă
mulţime/clasă atunci concluzia poate fi şi falsă (invalidată) pentru că pot exista elemente din
mulţime care nu au calitatea remarcată pentru elemente din acea submulţime.
iii) Enunţ VALABIL este cel care este ŞI faptic corect ŞI valid.
Există cazuri în care suntem puşi în situaţia de a evalua cunoştinţe de care nu suntem siguri
(de exemplu părerea sau credinţa unei persoane mai-puţin-cunoscute) sau cunoştinţe dintr-un
domeniu străin preocupărilor noastre; atunci este legitimă evaluarea ―nu pot spune‖ – care
dacă se referă la oricare din premizele din ascendent, automat se aplică şi la consecvent.

1.4 Limbaj şi expresii în logica propoziţională


În timp ce în paragrafele §1.3.3 şi §1.3.4 am fost preocupaţi de conţinutul logicii
propoziţiilor, în acest paragraf înaităm spre abstractizare, preocuparea fiind aici spre forma de
exprimare, spre formalizarea limbajului pentru operarea cu propoziţii (sau predicate).
Ca în orice formalizare, vom asocia variabilelor literali, variabilele fiind aici propoziţii în
general, instanţierea lor putând avea loc, eventual, în cazuri concrete (interpretări). Folosind
literalii şi apoi simboluri pentru conectori logici (operatori) vom constitui expresii care vor
avea rezultat o valoare de adevăr (valoare logică: adevărat T / 1, fals F / 0). Expresiile sunt
astfel, formulări (formule) compuse din variabile şi operatori constituite după reguli anume,
adică să fie „bine formate‖ – la fel ca expresiile din matematică (z=x+y) sau în limbaje de
programare (x*y pentru înmulţire, x^y pentru ridicarea la putere). Conectorii logici sunt
denumiţi şi „constante‖ în limbaj propozţional, în opoziţie cu „variabilele‖ – relativ la
capacitatea ultimelor de a primi interpretări, dar această denumire poate duce la confuzii.

1.4.1 Sintaxa limbajului propoziţíonal


Limbajul calculului propozițional este alcătuit din:
— simboluri propoziționale {p, q, . . .}, {p1, p2, . . .};
— conectori logici { , ∧, ∨, , };
— simboluri auxiliare: paranteze () virgula și spațiu.
O variabilă propoziţională p1, este o declaraţie cu valoare de adevăr (T sau F, 0 sau 1).
Conectori (operatori) logici sunt:
– conjuncția AND: corespunde lui „... și...‖ în limbaj natural, notată „∧‖ (sau „&‖ sau „‖).
– disjuncția OR: corespunde lui „...sau...‖ în limbaj natural, notată cu „∨‖.
– negația NOT: „ nu este...‖ în limbaj natural notată „¬‖ (sau „∼‖, sau „¯‖).
– implicația: corespunde expresiei „dacă... atunci...‖, notată → (sau „⊃‖).
– echivalenţa (bicondiționalul), corespunde expresiei „...dacă și numai dacă...‖ în limbaj
natural, notată „↔‖.
Alți operatori mai rar utilizaţi ai logicii propoziționale sunt:
– disjuncția exclusivă (SAU exclusiv), corespunde expresiei „ori...ori...dar nu ambele‖ din
limbajul natural, și care se notează „∨∨‖ sau „⊕‖.
– incompatibilitate, care corespunde expresiei „nu în același timp... și...‖, care interzice ca
două propoziții să fie adevărate împreună. Se notează incompatibilitatea cu „|‖, care se mai
numește și „Sheffer bar‖.

16
– rejectarea, corespunde expresiei „nici... nici...‖ în limbajul natural, notată „↓‖.
Limbajul conţine formule în care apar variabilele (literalii ataşaţi propoziţiilor) şi conectori
logici ca mai sus, care trebuie să fie corecte sintactic, adică să fie formule bine formate –
prescurtat fbf (în engleză well formed formula – wff). Cu fbf se pot construi propoziţii cu
valoare de adevăr ce derivă din propoziţiile constituente.
Fbf este un şir format conform următoarelor reguli:
 Un simbol propoziţional p este fbf (wff) – denumită şi variabilă propoziţională.
 Dacă p este fbf, atunci p este fbf.
 Dacă p şi q sunt fbf, atunci sunt fbf p  q, p  q, p  q, şi p  q.
 Dacă p este fbf, atunci (p) este fbf.

Exemplul 1.1: p, p  q,  (p  q) sunt fbf, pe când  ( q) sau f(x)  g(x) nu sunt fbf.

Evaluarea booleană v() a unei formule F este o aplicație a acestora peste {0, 1}: valoarea 0
denotă „fals‖, iar valoarea 1 denotă „adevărat‖. Evaluarea v() se mai numeşte interpretare,
pentru că propoziţiile p q, r ... - care intră ca variabile în formula F, vor avea fiecare o
anumită „interpretare‖ şi din acestea rezultă valoarea de adevăr (poate fi ori adevărată ori
falsă); în abordarea generală ce urmează nu interesează doar anumite propoziţii ci se vor lua
în calcul toate posibilităţile pe care aceste variabile le prezintă ca valori de adevăr (binare – 0
sau 1), prin tabele de adevăr; astfel, pentru 2 variabile p şi q în formula F avem 22 cazuri (v.
Tabel 1.2), pentru n variabile 2n cazuri care trebuie studiate.
Mai jos, tabela de adevăr pentru evaluări de formule elementare, care pot fi folosite în
algebra Boole-ană cu operatorii uzuali de adunare + şi înmulţire  :

p q p pq pq pq pq


1 1 0 1 1 1 1
1 0 0 1 0 0 0
0 1 1 1 0 1 0
0 0 1 0 0 1 1

Tabel 1.2 Tabela de adevăr pentru conectorii logici uzuali


Analizând valorile de adevăr pentru conectorii logici din Tabel 1.2, se observă că esenţa
acestora se poate exprima astfel:
I. negaţia p: „adevărată dacă şi numai dacă (prescurtat ddacă) p falsă‖;
II. disjuncţia p  q: „adevărată dacă oricare p, q adevărate‖;
III. conjuncţia p  q: „adevărată ddacă ambele p, q adevărate‖;
IV. implicaţia p  q: „falsă ddacă p adevărată şi q falsă‖;
V. bicondiţional p  q: „adevărat ddacă p, q au aceeaşi valoare de adevăr‖.
Aceste exprimări pot fi folosite la analiza valorii de adevăr a unui ansamblu de formule (v.
§ 1.4.2) prin demonstraţie deductivă.
Pentru alţi operatori: disjuncția exclusivă (SAU exclusiv) „⊕‖, incompatibilitatea „|‖ şi
rejectarea „↓‖ se dau mai jos tabele de adevăr:

17
p q p⊕q p|q p↓q
1 1 0 0 0
1 0 1 1 0
0 1 1 1 1
0 0 0 1 1

Tabel 1.3 Tabela de adevăr pentru: sau exclusiv, incompatibilitate, rejectare.

La operatorul condiţional p  q se citeşte şi „p este suficient pentru q„ (q dacă p) pe când


―q este necesar pentru p‖. La operatorul bicondiţional p↔q se citeşte şi ―dacă p atunci q şi
viceversa‖ adică ―p este necesar şi suficient pentru q‖, ―p ddacă q‖.
Echivalenţa poate fi privită ca operator (cum este indicat mai sus) dar poate fi privită şi ca
o declaraţie: spunem că două fbf p şi q sunt echivalente, notând p  q, ddacă ele au aceeaşi
valoare de adevăr indiferent de valorile de adevăr ale variabilelor conţinute.
De exemplu, (p  q)  (p  q) conform tabelei demonstraţie de mai jos, în care se
observă că valorile de adevăr ale celor doi termeni sunt identice pentru toate cazurile posibile.

p q p  q p p  q
1 1 1 0 1
1 0 0 0 0
0 1 1 1 1
0 0 1 1 1

Tabel 1.4 Tabela de adevăr pentru echivalenţa (p  q)  (p  q).

p p  ( p ) p (dubla negaţie) r ( p p ) r 


p p 0 p  p  p r ( p p ) r
p 0 p p p  p r ( p p ) 1
p  1 p ( q r) ( p q ) r  r ( p p ) 0
p 0 0 ( p q )  (p q) p q (p q)
p 1 p (p q )  (( p q) ( q p )) ( p q )  (p q)
p q  (q p )
( p q )  (( p q) (p q ))

Tabel 1.5 Echivalenţe

Operatorii Booleeni au proprietăţile:


 Operatorii  şi  sunt comutativi şi asociativi.
 Operatorul  este comutativ dar nu asociativ.
 Operatorii  şi  sunt idempotenţi (adică, (p  p)  p).
 Operatorii  şi  distribuie reciproc:
 p  (q  r)  (p  q)  (p  r)
 p  (q  r)  (p  q)  (p  r)
 Legi de Absorbţie:

18
 p  (p  q)  p
 p  (p  q)  p
 Legile De Morgan:
 (p  q)  (p  q)
 (p  q)  (p  q)

De notat că în Logica Propoziţiilor nu se folosesc cuantificatorii propuşi de Fregge pentru


logica de ordinul I, care desemnează „gradul‖ de apartenenţă la mulţimi: cuantificator
universal ∀ („oricare‖) poate desemna întreaga mulţime, respectiv cuantificatorul existenţial
∃ („există un/o‖) care desemnează submulţimi în înţelesul „cel puţin un/o‖.
În logica propoziţiilor se utilizează cuvinte „obişnuite‖ care desemnează mulţimi şi
submulţimi, cum sunt: „toţi/toate‖ – indicând întreaga mulţime, respectiv „unii/câţiva‖
„unele/câteva‖ – indicând o submulţime. Se pot întâlni şi exprimări de tipul „numai membrii
clubului au intrare gratuită la meciul de astăzi‖ unde particula numai are rol de egalitate a
două mulţimi: mulţimea celor cu intrare gratuită şi mulţimea membrilor clubului; o asemenea
exprimare presupune că, la meciuri în alte ocazii, mulţimea celor cu intrare gratuită este mai
largă: include mulţimea membrilor clubului dar include şi anumiţi suporteri, jurnalişti etc.

1.4.2 Interpretarea unui ansamblu de fbf


Un anasamblu A de formule este satisfiabil (adevărat funcțional) ddacă există cel puțin o
evaluare booleană v astfel încât pentru fiecare formulă F a lui A, v(F) = 1.
Pentru interpretarea unui ansamblu A de formule (expresia A) se pot folosi: fie Tabela de
adevăr – în care apar 2n cazuri pentru cele n variabile din ansamblu, fie Demonstraţia – prin
care se analizează pas cu pas condiţiile în care ansamblul A primeşte valoare 1 (Adevărat T)
pentru fiecare formulă, folosind esenţa conectorilor (v. Tabel 1.2 şi pct. I. – V.).

Exemplul 1.2: Ansamblul E = {a, ((b→a) ∨ c), ¬c, (b∨ c)} este satisfiabil?
E este satisfiabil ddacă există o evaluare booleană v astfel încât:
(a) v(a) = 1
(b) v(b→a) ∨ c) = 1
(c) v(¬c) = 1
(d) v(b∨ c) = 1

Metoda tabelei de adevăr:


a b c b→a ((b→a) ∨ c) ¬c (b ∨ c) {a, ((b→a) ∨ c), ¬c, (b ∨ c)}
1 1 1 1 1 0 1 0
1 1 0 1 1 1 1 1
1 0 1 0 1 0 1 0
1 0 0 0 0 1 0 0
0 1 1 1 1 0 1 0
0 1 0 1 1 1 1 0
0 0 1 1 1 0 1 0
0 0 0 1 1 1 0 0

Tabel 1.6 Tabela de adevăr pentru formulele din expresia E.

19
Concluzie: din Tabel 1.6 rezultă expresia adevărată (valoare de adevăr 1) pentru evaluări
a=1, b=1 şi c=0 pe linia 2; cel puţin o interpretare este adevărată, ca atare E este satisfiabil.

Metoda demonstraţiei:
(1) v(¬c) = 1 ddacă v(c) = 0.
(2) v((b→a) ∨ c) = 1 ddacă v(b→a) = 1 sau v(c) = 1
(3) v(b∨ c) = 1 ddacă v(b) = 1 sau v(c) = 1.
Din (2) şi (3), se rejectează cazul în care v(c) = 1 datorită (1).
În (2), v(b→a) = 1 ddacă v(b) = 0 când v(a) = 1. Prin (a), se ştie că
v(a) = 1, deci clauza v(b) = 1 din (3) nu generează o contradicție.
Concluzie: formulele lui E sunt adevărate într-o evaluare booleană v astfel încât v(a) = 1,
v(b) = 1 și v(c) = 0. Ansamblul E este așadar satisfiabil.

Am văzut că o propoziţie simplă, atomică (sau atomară) p are o valoare de adevăr ataşată
(1 sau 0) corespunzător conţinutului semantic. O propoziţie compusă F este o formulă bine
formată (fbf) din propoziţii atomice (variabile) şi conectori logici (constante). Valoarea de
adevăr a propoziţiei compuse depinde de valorile de adevăr ale variabilelor şi de modul cum
conectorii (operatorii) afectează apoi valorea de adevăr, astfel că propoziţiile compuse sunt
tratate ca funcţii de adevăr.
Pentru evaluarea propoziţiilor compuse este necesar să se respecte ordinea de precedenţă a
operatorilor (aşa cum în algebră avem ordinea de precedenţă: ridicare la putere, înmulţire,
adunare). Operatorii logici au următoarea ordine de precedenţă:
1. prima este negaţia  ,
2. apoi conjuncţia ,
3. apoi disjuncţia ,
4. apoi implicaţia  şi bicondiţionalul .
Pentru a explicita precedenţa se folosesc paranteze: vezi cazul (b→a)∨ c din Exemplul 1.2.
De remarcat că în exemplul anterior ansamblul E de fbf nu este în sine o propoziţie
compusă F ci o alăturare de propoziţii (simple şi compuse) care constituie un context de lucru.

Ansamblurile de fbf şi propoziţiile compuse fbf Boolene pot fi caracterizate, referitor la


cazul când sunt adevărate, astfel:
 validă ddacă (în engleză iff) este adevărată în toate atribuirile de valori de adevăr
pentru variabilele din formulă.
 satisfiabilă ddacă este adevărată în cel puţin o atribuire de valori de adevăr pentru
variabilele din formulă.
 nesatisfiabilă ddacă este falsă în toate atribuirile de valori de adevăr pentru variabilele
din formulă.
 consistentă ddacă există o realizare în care toate fbf componente sunt adevărate.

Aceste caracterizări prezintă în tabela de adevăr TabA, ataşată ansamblului fbf, valori în
coloane şi linii corespunzător fiecăreia, astfel:
 validă – ultima coloană din TabA (rezultatul final) are valori 1 pe toate liniile.

20
 satisfiabilă – ultima coloană TabA prezintă cel puţin o valoare 1 (cel putin o linie 1).
 nesatisfiabilă – ultima coloană TabA are valori 0 pe toate liniile.
 consistentă – există o linie în TabA cu valori 1 la fiecare coloană fbf şi la ultima.

Pentru categorii de mai sus se folosesc uzual denumirile:


 Tautologie: atunci când fbf este validă. De exemplu: p  p este o tautologie:
este totdeauna adevărată. Se poate demonstra aceasta prin tabela de adevăr, luând în
considerare cele două cazuri posibile (p = 1, p =0):

p p p  p
1 0 1
0 1 1

Tabel 1.7 Tabela de adevăr pentru tautologia p  p.

De exemplu p  q este satisfiabilă la p =1, q = 0; dar nu este o tautologie.


 Contradicţie: atunci când fbf este nesatisfiabilă. De exemplu, p  p este
nesatisfiabilă – este o absurditate; deci este 0 şi în caz că p = 1 şi în caz că p = 0.
 Contingenţă: atunci când fbf Booleană nu este nici tautologie nici contradicţie
– este o eventualitate. De exemplu fbf p→ p : adică p este adevărată în anumite
interpretări şi falsă în altele. În ultima coloană TabA există cel puţin un 0 şi cel puţin
un 1. Tabel 1.8 indică interpretări pentru p → p.

p p p → p
1 0 0
0 1 1

Tabel 1.8 Tabela de adevăr pentru contingenţa p → p.


Orice propoziţie atomică p trebuie să fie contingentă – să aibă valori 0 sau 1.
Conceptele Tautologie şi Contradicţie sunt esenţiale în Logică (nu doar a propoziţiilor)
pentru că ambele ajută la raţionament: prima prin faptul că adevărul este valid (totdeauna
Concluzia este o consecinţă logică din Premize), a doua pentru că indică o absurditate, deci
trebuie eliminat enunţul prin care ipotezele (adică premizele) ar duce la concluzia considerată.
Cele două concepte sunt folosite curent în demonstraţii ale teoremelor – teorema fiind un
enunţ în care o concluzie este extrasă din premize exprimate explicit (ipoteze pe de-o parte,
consecinţă pe de alta). Astfel, în general, teoremele pot fi demonstrate:
a) prin tautologie: se parcurg în paşi consecinţe logice ale ipotezelor date prin ipoteze
cunoscute ce conduc la enunţuri valide, până la concluzia vizată (deducţie);
b) prin contradicţie: se parcurg în paşi consecinţe logice ale ipotezelor date prin ipoteze
cunoscute ce conduc la enunţuri valide dar care contravin în final cu enunţul dat
(reducere la absurd);
c) prin inducţie: în cazul unor situaţii cu aspect repetitiv, se verifică enunţul (a fi valid)
pentru pasul iniţial şi apoi considerând valid pasul k se aplică situaţia pentru pasul k+1
şi se constată dacă coincide cu enunţul (tautologie de pas iniţial şi de pas k+1).
Cu excepţia axiomelor, toate teoremele trebuie demonstrate, adică pretind justificări
fundmentate şi complete care folosesc numai enunţuri valide deja cunoscute.
21
Revenim la interpretările pe care le pot avea propoziţiile:
 propoziţia atomică are 21 interpretări (implicit contingentă: prezintă valoare 0 ori 1).
 fbf cu 2 propoziţii are 22 interpretări (v. Tabel 1.4), 4+1 linii.
 fbf cu 3 propoziţii are 23 interpretări (v. Tabel 1.6), 8+1 linii.
 fbf cu 20 de variabile are 220 interpretări, 1.048.576 +1 linii deci se poate rezolva
căutarea în asemenea TabA doar cu calculatorul.
 fbf cu 200 de variabile are 2200 interpretări, „număr cu 60 de cifre‖ linii +1!

Se observă că pentru a verifica măcar satisfiabilitatea unei fbf cu un număr foarte mare de
variabile ar trebui ca un calculator să construiască TabA uriaşă – ce arată complexitatea de
calcul implicată. În asemenea situaţie se spune că problema satisfiabilităţii (pe scurt, SAT)
pentru Logica Propoziţiilor este decidabilă (rezolvabilă ca răspuns DA este satisfiabilă, sau
NU) şi s-ar dori găsirea unui algoritm pentru care complexitatea timp să fie „rezonabilă‖ –
însă din simplele observaţii de mai sus, se constată decidabilitatea SAT în timp exponenţial.

1.4.3 Inferenţe
Inferenţa este un sistem de propoziţii în care o propoziţie derivă din altele.
Am văzut la §1.3.3 că într-un raţionament propoziţia care derivă este Concluzia iar
propoziţiile din care derivă constituie Premize; dacă premiza este o singură propoziţie avem
inferenţă imediată iar dacă premiza este o propoziţie compusă avem inferenţă mediată.
Am văzut apoi că o inferenţa este validă (dacă este „în formă‖ corect construită) şi am
constatat mai sus că o inferenţă validă este o tautologie.
Raţionamentele cu propoziţii compuse se împart în mai multe categorii, în funcţie de felul
propoziţiilor compuse ce intră în alcătuirea lor. În cazul comun, concluzia la o inferenţă validă
este consecinţă logică a propoziţiilor premize conectate cu  între ele. Într-un sistem de
raţionament există o mulţime de „inferenţe‖ care indică adevăruri şi care sunt demonstrate cu
ajutorul unor inferenţe pe care acestea se bazează; în final, se ajunge (mergând spre înapoi) la
un set de adevăruri care sunt considerate la baza sistemului de raţionament denumite axiome.

O axiomă este o fbf considerată a priori adevărată (nu trebuie demonstrată). La o mulţime
de axiome date, se pot aplica reguli de inferenţă pentru a crea noi fbf, la care se pot aplica
apoi reguli de inferenţă ş.a.m.d 5 . Enunţuri astfel rezultate se numesc teoreme iar o
demonstraţie este o aplicare de reguli de inferenţă pe baza axiomelor şi teoremelor anterioare.
Însă demonstraţia – ca secvenţă de aplicări a unor reguli de inferenţă, trebuie să ne convingă
de adevărul parcursului ei, iar pentru aceasta ea ar trebui să fie validă. Acest lucru se întâmplă
când fiecare din inferenţele ce compun demonstraţia este validă – au toate valori de adevăr 1.
La un set de axiome A, un set de reguli de inferenţă R este complet ddacă toate enunţurile
detereminate de A se pot demonstra aplicând setul de reguli R. Dacă se poate defini un set de
reguli de inferenţă ce sunt simultan valide şi complete, atunci setul de teoreme poate fi
demonstrat pe baza A fără a contraveni acestuia (obligatoriu adevărate cu A adevărate).

5
Elaine Rich, Automata, Computability and Complexity: Theory and Applications, 2019
https://www.cs.utexas.edu/~ear/cs341/automatabook/AutomataTheoryBook.pdf

22
Inferenţe ipotetice sunt cele care în sistemul de propoziţii prezintă formule condiţionale –
implicaţii6.
Dacă formulele condiţionale apar şi în antecedent (premize) şi în consecvent, atunci
această inferenţă se numeşte silogism ipotetic, exprimat ca mai jos pe fiecare linie câte o
afirmaţie – premizele şi apoi concluzia (precedată de simbolul ):
p→q
q→r
p→r
care se poate exprima prin formula: ((p → q)  (q → r)) → (p → r).
În cazul acestui tip de inferenţă, acţionează regula: consecinţa consecinţei (adică r) este
consecinţă a condiţiei (adică a implicaţiei iniţiale – prima premiză).
Dacă doar o premiză este propoziţie ipotetică iar a doua premiză şi concluzia sunt
propoziţii enunţiative, atunci vorbim de o inferenţă ipotetică mixtă care se poate prezenta în
două moduri distincte – relativ la formula condiţională din premiza ipotetică:
 Modus Ponendo Ponens când se raţionează direct– scris scurt Modus Ponens (MP):
p→q
p
q
care se poate exprima prin formula: ((p → q)  p) → q.
În acest caz, ştiind că implicaţia este adevărată, afirmăm în premize condiţia (implicaţia) şi
precedentul acestiea (p) pentru a afirma în concluzie subsecventul ei (q) adică consecinţa
implicaţiei – modul afirmativ.
 Modus Tollendo Tollens când se raţionează revers – scris scurt Modus Tollens (MT):
p→q
q
p
care se poate exprima prin formula: ((p → q)  q) → p.
În acest caz, ştiind că implicaţia este adevărată, negarea subsecventului (q) a condiţiei
(implicaţiei) atrage negarea precedentului condiţiei (p) – modul negativ (în sensul de negare).
Atenţie, însă, că inferenţele de mai jos (care înlocuiesc nepermis subsecvent cu precedent
în condiţie) sunt invalide pentru că în implicaţie → subsecventul q este necesar precedentului
p dar nu şi suficient (însă p este suficient lui q):
p→q ((p → q)  q) → p p→q ((p → q)  p) → q
q non valid p non valid
p q
Se verifică invaliditatea cu Tabel 1.2, de exemplu, imaginând q şi operator  cu p → q.

Inferenţe disjunctive sunt cele în care apar formule disjunctive în premize. Mai des
întâlnite sunt inferenţele disjunctive mixte, în care o premiză este propoziţie disjunctivă, iar
cealaltă premiză şi concluzia sunt propoziţii simple, enunţiative, care şi aici se pot prezenta în
două moduri distincte – relativ la tipul disjuncţiei: exclusivă (⊕) sau inclusivă (∨):

6
Dima, Teodor (ed.), Logica generală, EDP, Bucureşti, 1991

23
 Modus Ponendo Tollens când acţionează pincipiul non-contradicţiei pentru disjuncţia
excluivă ⊕:

p⊕q ((p ⊕ q)  p) → q p⊕q ((p ⊕ q)  q) → p


p q
 q p

În acest caz, ori p este adevărată ori q fiindcă se exclud reciproc.


 Modus Tollendo Ponens când acţionează principiul terţiului exclus pentru disjuncţia
inclusivă ∨:

pq ((p  q)  p) → q pq ((p  q)  q) → p


p q
q p

O inferenţă se poate înscrie în mod concis, pe o singură linie, folosind simbolul „⊢‖. De
exemplu, inferenţa Modus Ponens se exprimă:
p → q, p ⊢ q
unde ⊢ indică deducţia şi se citeşte „deducem‖ ori „deduce‖.
Folosid astfel de exprimări pentru inferenţe, prezentăm mai jos „Reguli de inferenţă‖ într-o
listă concisă, cu prescurtări (indicate îngroşat mai jos) şi cu explicaţii formale:
 MP Modus ponens: p → q, p ⊢ q este validă.
 MT Modus tollens: p → q, q ⊢ p este validă.
 DN Dubla negare: ( p ) p şi reciproca p  (( p )) sunt valide.
 ∨I Sau introdus (Or introduction): p ⊢ (p  q) şi p ⊢ (q  p) sunt valide.
 I Şi introdus (And introduction): p, q ⊢ (p  q) este validă.
 E Şi eliminat (And elimination): (p  q) ⊢ p şi (p  q) ⊢ q sunt valide.
 ∨E Sau eliminat (Or elimination): (p  q), p → r, q → r ⊢ p este validă.
Oricare două enunţuri de forma p şi p constituie o contradicţie.

Inferenţele sunt untilizate în demonstraţii ale teoremelor şi înlănţuirea lor este un proces
care cel mai adesea ţine de creativitatea omului – în alegerea cea mai potrivită a supoziţiilor
şi apoi a propoziţiilor (simple sau compuse) care vor intra în lanţul de inferenţe spre a ajunge
la scopul final: o confirmare a concluziei teoremei. Ulterior, această teoremă deja demonstrată
poate fi folosită ca „supoziţie‖ în lanţul demonstraţiei altei teoreme.
Este o întreagă discuţie privind termenul „supoziţie‖ – care în literatura din România este
întâlnit mai ales ca „presupoziţie‖ (provenind din franceză), termen care în engleză este
assumption. Supoziţia este o consecinţă colaterală a unei alte inferenţe – pe care ne-am putea
baza în demonstraţie, prin aceasta înţelegând că adevărul unui enunţ oarecare într-un domeniu
ţintă se bazează deja pe o serie de „cunoştinţe‖ – alte enunţuri din domeniul ţintă, care sunt
sub-înţelese ca fiind parte din context şi de care ne putem folosi după voie dar cum „ar fi
necesar‖ în mersul demonstraţiei spre a ajunge cât mai aproape de final.

24
Supoziţiile pot fi deci Adevăruri exprimate de teoreme demonstrate anterior sau pot fi
Axiome – în cazul când se continuă lanţul de teoreme până la baza axiomantică. De aceea,
vom nota generic supoziţia prin A, astfel referită şi în justificarea paşilor de la Exemplul 1.3.
Dăm mai jos un exemplu de demonstraţie formală, în paşi, la fiecare pas justificând
supoziţia sau raţionamentul făcute.

Exemplul 1.3: p  (s  ( r )), p → r, p ⊢ (¬ s)


Demonstraţia decurge în paşi numerotaţi la care vom face referire în justificarea fiecărui
pas indicând pe ce se bazează: supoziţie A sau regula de inferenţă (v. mai sus prescurtările)
aplicată unor paşi anteriori:
1 p   A
2 p→r A
3 r MP 1,2
4 p → (s → (¬ r)) A
5 s → (¬ r) MP 1,4
6 ¬ (¬ r) DN 3
7 ¬s MT 5,6
Ansamblul enunţat fiind deci valid.

Revenind la supoziţii: se observă în exemplul de mai sus acestea au fost chiar propoziţii
din enunţul dat dar trebuie subliniat faptul că în realitatea faptică există probleme în care
introducerea supoziţiilor este o alegere ce nu ţine doar de domeniul ţintă. Spre exemplu, într-
un Caiet de fizica pentru clasa a VII-a 7 apare problema „Un urs cu masa de 500 Kg are
greutatea de 4915 N. Ce culoare are blana ursului?‖ Aparent nu este o problemă de fizică ci
de perspicacitate însă, prin calculul forţei gravitaţiei G=4915 N relativ la masa m=500 Kg
rezultă din Legea a II-a a Dinamicii g=G/m acceleraţia gravitaţională g=9,83 N/Kg valoare
întâlnită la Polul Nord – deci este vorba de un urs polar: [g > 9,81 ⊢ blana de culoare albă].
Cunoştinţele despre urşi polari însă, nu fac parte din domeniul ştiinţei Fizică; deci supoziţiile
pot ţine de „vaste‖ cunoştinţe în diverse domenii.
Problema demonstrării teoremelor cu ajutorul maşinii este o problemă de calculabilitate, în
sensul că trebuie găsită o metodă ca traseul de inferenţe să se poată „mecaniza‖ iar supoziţiile
ce intră în constituţia demonstraţiei să fie selectate dintr-un set predefinit disponibil, după
criterii specifice – care la rândul lor pot rezulta în urma unor calcule (de exemplu calcululul
„distanţei‖ faţă de nucleul domeniului ţintă sau al contextului dat, spre a se alege criteriul „cel
mai apropiat‖).
Fiecare linie dintr-o demonstraţie este un şir de caractere (de exemplu expresie logică
exprimată în Exemplul 1.2 şi Exemplul 1.3) care se poate determina dacă este valid(ă) sau nu;
mulţimea de formule valide este domeniul unei funcţii calculabile iar în terminologia actuală
„mulţimea de formule valide ale logicii de ordinul întâi este recursiv (re)numărabilă‖.
Şi ne întoarcem astfel la Entscheidungsproblem (problema deciziei - decidabilitate) care ar
fi rezolvată dacă există un procedeu eficient (algoritm) ce poate decide într-un număr finit de
paşi dacă o afirmație matematică (o expresie) este validă sau satisfiabilă (Principles of

7
Iancu Lucică, Logica, Editura tehnică, colecţia Cogito, Bucureşti, 2008

25
Mathematical Logic – Hilbert și Ackermann). Prin teorema de completitudine, Gödel a arătat
că o formulă este demonstrabilă din axiome dacă și numai dacă este validă iar un sistem logic
este decidabil dacă există o metodă eficientă pentru a determina dacă formulele sunt valide în
acel sistem. Logica propozițională este decidabilă, deoarece prin metoda tabelului de adevăr
se poate determina dacă o formulă propozițională este validă sau nu.
O soluție generală la Entscheidungsproblem este însă imposibilă, Church şi Turing
demonstrând independent aceasta – aşa numita Teză Church-Turing. Pe de altă parte, un
sistem formal ar trebui să aibă trei proprietăţi: completitudine, consistenţă şi axiomatizare
eficentă; prin teorema de incompletitudine Gödel a demonstrat că un sistem în „teoria
numerelor‖ nu le poate avea pe toate trei simultan. Totuşi, noțiunea intuitivă de „calculabil
efectiv‖ este surprinsă de funcţionarea unei Mașini Turing, care, atunci când verifică
validitatea unei formule exprimată într-un limbaj dat (prin parcurgerea şirului de caractere ce
descrie formula), va atinge starea de oprire halt şi se spune că limbajul este decidabil; dacă
Maşina Turing nu atinge starea halt, limbajul este nedecidabil.

Scopul acestui capitol nu a fost de „Introducere‖ în sensul comun de prezentare generală a


celor ce vor urma ci de introducere în sensul de iniţiere în domeniul mai general al
calculabilităţii: rezolvarea problemelor în mod mecanizat cu procedee (şi maşini) construite
de om. În acest demers, prima etapă este cea de formalizare a problemei – exprimarea sa în
mod simbolic dar şi concis şi precis, cu scopul de transpunere a problemei „pentru calcul‖
adică descrierea rezolvării problemei printr-un procedeu eficient (algoritm / program). Prima
întrebare la care trebuie însă să se răspundă este: are problema soluţie? (răspuns: Da ⊕ Nu)
iar a doua: cât de complex este calculul?
Deja aceste întrebări şi modalităţi de răspuns s-au exprimat (ca iniţiere) în acest capitol:
vezi valididate, satisfiabilitate §1.4.2, respectiv necesar de calcul pentru o funcţie §1.2 sau
pentru construirea şi căutarea într-o tabela de adevăr (2n variante) §1.4.1.

Am sacrificat în acest capitol prezentarea „formală‖ a definiţiilor (cu taguri-etichete:


Definiţa 1.1, Definiţa 1.2. etc.) pentru că mulţimea acestora, în succesiunea lor, ar fi făcut
greu lizibil textul, împiedicându-ne la fiecare pas de aceste etichete; însă, din păcate, căutarea
şi referirea acestor noţiuni este mai dificilă astfel, pentru că aceste operaţii se vor face prin
conţinut şi nu prin „tag‖ – caz în care am avea posibilitatea de indexare şi căutare eficientă.

26
2 Automate

Fenomenele naturale se petrec în mod continuu, adică prametrii ce caracterizează


fenomenul cresc sau scad fără a avea întreruperi. Astfel, dacă dorim să parcugem distanţa
dintre două oraşe vom trece prin toate localităţile de pe parcurs, de fapt vom parcurge drumul
în mod continuu prin toate puntele (oricât de apropiate) de pe traseu. Similar, prin apăsarea
pedalei de acceleraţie, viteza va creşte continuu (cu grandient mai mare sau mai mic – adică
mai repede sau mai lent). Distanţa şi viteza din exemplele date sunt parametri ce caraterizează
mişcarea (automobilului) iar evoluţia acestora se poate reprezenta grafic prin curbe continui.
O anumită categorie de artefacte (produse făcute de mâna omului) prezintă însă funcţionare
cu parametri care evoluează discret – adică în trepte şi/sau cu întreruperi, iar reprezentarea
grafică a evoluţiei acestora se face cu linii frânte (trepte sau impulsuri). De exemplu, un lacăt
are două moduri de funcţionare: deschis şi închis; iar dacă lacătul este cu cifru (combinaţie
mecanică), starea deschis se obţine prin setarea unui şir de cifre (şir de caractere) bine definit.
Putem considera că lacătul funcţionează pe baza a două stări: deschis şi închis; iar
evenimentele care produc tranziţii între stări sunt acţionarea cheii sau cifrului corect –
deschiderea lacătului, respectiv blocarea lacătului.
Automatele fac parte din categoria „Sisteme cu Evenimente Discrete‖ (DES Discrete Event
Systems), din familia de dispozitive de calcul abstracte cunoscute sub numele de Mașini cu
Stări Finite FSM (Finite State Machines) sau Automate Finite FA (Finite Automata) – în
ideea că prezintă un set finit de stări. FA au proprietăți comune multor dispozitive mecanice:
reacţionează la intrări și produc ieșiri discrete de tip Da/Nu, Acceptat/Neacceptat. Intrările
sunt piese discrete – de exemplu şiruri de caractere precum cifrul de la un lacăt cu combinaţii
mecanice.
Cea mai largă utilizare o au Automatele Finite fără memorie, adică FA care reacţionează la
un „stimul‖ exterior cu răspuns Acceptat sau Neacceptat – ca şi lacătul care se deschide doar
la combinaţia corectă de cifre. O formulă în Logica propoziţiilor poate fi considerată o
―maşină de calcul‖ fără memorie – în sensul că aplicând la ―intrare‖ valori pentru variabile
vom obţine (imediat) la ―ieşire‖ rezultatul formulei: 1 (adevărat) sau 0 (fals) corespunzător
expresiei logice ce conţine variabile (propoziţii) şi constante (conectori/operatori logici).
Dacă se doresşte ―calculul‖ pentru mai multe formule succesiv (ieşirile unor formule fiind
intrări pentru altele în continuare), aceste formule au o aşezare pe ―etaje‖ iar calculul pe
fiecare etaj are loc comandat de un ceas (clock) care produce impulsuri pentru marcarea
paşilor numărabili: la primul pas se produc calcule pe primul etaj apoi la pasul 2 pe etajul al
doilea ş.a.m.d.. Ieşiri ale unor etaje superioare pot fi intrări în etaje inferioare, făcând astfel
calcule complexe secvenţial, şi obţinând un rezultat dorit după un număr de repetări.
Automatele au caracteristică generală funcţionarea bazată pe stări şi tranziţii între stări –
tranziţiile fiind treceri de la o stare la alta funcţie de intrarea şi starea curentă sau doar de
starea curentă. Starea este o „poziţie‖ în traseul de funcţionare al automatului iar intrarea este
o piesă de date (simbol) care poate fi de exemplu valoarea de adevăr a unei propoziţii
(Boolean 1 sau 0) sau poate fi un caracter dintr-un şir de caractere care atacă succesiv intrarea
automatului; la un şir de caractere valid (de exemplu un cifru corect) are loc activarea ieşirii –
valoare Da/Acceptat, în caz contrar ne-activarea ieşirii – valoare Nu/Neacceptat.

27
Într-o prezentare sintetică se amintesc următoarele tipuri de automate:
 Acceptor: automat care calculează o funcție booleană. Stările unui acceptor
acceptă ori resping intrările furnizate. Relativ la capacitatea de memorie pot fi:
o fără memorie (de fapt, memorie doar pentru starea curentă): Automat Finit
Determinist DFA (Deterministic Finite Automaton) şi Automat Finit Ne-
determinist NFA (Non-deterministic Finite Automaton). DFA are tranziţii
de stare bine determinate la intrări date, pe când la NFA pentru o intrare
dată poate avea tranziţii către mai multe stări, dintre care doar una activată.
o memorie infinită: Automat Stivă PDA (Push Down Automaton) care
foloseşte o stivă pentru memorarea stării curente şi precedentelor; PDA pot
fi deterministe şi ne-deterministe.
 Clasificator: automat care are mai mult de două stări acceptoare și oferă o singură
ieșire la una din aceste stări care, activată, reprezentă clasa depistată.
 Traductor: automat care produce ieșiri pe baza intrării curente și/sau a stării
anterioare. Acestea pot fi:
o Mealy Machine: automat la care ieșirea depinde atât de starea curentă, cât
și de intrarea curentă: o tranziţie – o ieşire.
o Moore Machine: automat la care ieșirea depinde doar de starea curentă: o
stare – o ieşire.

Un caz special de acceptor, cu grad mare de generalitate, este Mașina Turing (TM) ca
model matematic constând dintr-o bandă de lungime infinită, împărțită în celule, prin care se
furnizează intrarea (simboluri de intrare); are apoi un cap de citire care citește banda de intrare
şi un registru ce memorează starea mașinii. După citirea unui simbol de intrare, TM îl va
înlocui cu un alt simbol şi va face tranziţie de stare mutând capul de citire pe următoarea
celulă a benzii de intrare (spre dreapta sau spre stânga). Dacă TM ajunge într-o stare finală
acceptoare, șirul de intrare este acceptat, în caz contrar respins.
Există şi Maşini cu Stări Finite Extinse EFSM (Extended Finite State Machines). În timp
ce FSM efectuează întotdeauna o tranziție de stare pe o anumită intrare, EFSM efectuează o
tranziție numai atunci când un anumit set de condiții a fost îndeplinit. EFSM permite
utilizarea de variabile, de exemplu, pentru a implementa o buclă „for‖; astfel se pot modela cu
ușurință algoritmi care altfel ar necesita o explozie combinatorială de stări.

Utilizarea automatelor este foarte largă; de fapt orice calculator este un automat – cu un
număr uriaş de stări dar finit (infinitul nu este fezabil – este o abstracţie). Între aplicaţii ale
automatelor (în special DFA) amintim:
 Automate de vânzări (diverse produse preambalate) şi automate bancare (ATM)
 Procesare text,
 Analiză lexicală
 Jocuri video
 Analiza protocoalelor (TCP-IP)
 Prelucrarea limbajului natural (NLP Natural Language Processing)
 Recunoaşterea vorbirii

28
 Semafoare de trafic
 Verificarea modelelor (PDA)
 Prelucrarea documentelor XML (PDA)
 Traducere limbaje artificiale (PDA)

2.1 Automate Finite fără memorie


Un automat este un dispozitiv capabil să reprezinte un limbaj conform unor reguli bine
definite. Aceast capitol se concentrează pe definiția formală a automatelor iar legătura dintre
automate şi limbaje se va face din acest capitol şi vor fi detaliate în capitolul următor.
Structura de stări şi legături de tranziţie a automatelor se face prin grafuri orientate iar
funcţionarea se prezintă ca tabelă de tranziție a stărilor.

2.1.1 Exemple simple şi critica lor


Pentru înţelegerea modului de reprezentare grafică şi a funcţionării FA, dăm un exemplu
simplu de automat, cunoscut şi folosit de oricine:
Exemplul 2.1 Dispozitiv automat BA de umplere a unui Bazin de Apă cu flotor.
Considerăm starea bazinului funcţie de nivelul apei: gol la nivel apă insuficient respectiv plin
la nivel apă suficient. Putem considera poziţia flotorului jos (0) respectiv sus (1) ca intrare în
dispozitivul automat LA iar starea [de încărcare] „gol‖ respectiv „pli‖ (codificare din trei
litere), cu funcţionarea simplă:
- în starea „gol‖ cât timp intrarea este 0 starea se menţine „gol‖;
- în starea „gol‖ când intrarea este 1 are loc tranziţia din starea „gol‖ în starea „pli‖;
- în starea „pli‖, cât timp intrarea este 1 starea se menţine „pli‖;
- în starea „pli,‖ când intrarea este 0 are loc tranziţia din starea „pli‖ în starea „gol‖;
Reprezentarea BA sub formă de graf orientat – diagramă de stare (state diagram), este dată
în Figura 2.1, unde săgeata din stânga la starea „gol‖ reprezintă deschiderea robinetului de
alimentare cu apă şi start funcţionare BA (umplere – golire – umplere ...).

0 1 1
gol pli
0

Figura 2.1 Diagrama de stare pentru BA.


În diagrama de stare stările sunt reprezentate prin cercuri (noduri) ce conţin etichete cu
identificatorul stării iar arcele orientate indică tranziţiile de stare, fiecare arc având ca etichetă
evenimentul (intrarea) la care va avea loc tranziţia respectivă.

Dacă însă am dori ca dispozitivul BA să nu funcţioneze la nesfârşit? De exemplu, se pleacă


de acasă şi se doreşte ca bazinul să fie gol, spre a nu se consuma apă prin scurgeri accidentale.
Ar trebui ca prin comandă vocală un alt dispozitiv (simbolizat CV) să recunoscă (presupunem
noi) literele comenzii „start‖ şi va deschide valva robinetului de alimentare cu apă doar când
dorim funcţionarea continuă a BA.

29
Exemplul 2.2 Dispozitiv automat CV are la intrare litere iar atunci când şirul de caractere
depistat este start se ajunge în starea de acceptare (a şirului) şi ca urmare de execuţie a
comenzii „deschide robinet‖; oricare alte şiruri de caractere sunt rejectate, CV „aşteptând‖
doar succesiunea de caractere validă; şi când spunem validă ne gândim la consecinţa logică
(v.§ 1.4.3) care aici este secvenţa de „tranziţii de stare‖ la intrări, până la starea acceptoare.
Dispozitivul CV are graful orientat din Figura 2.2, unde:
 stările sunt reprezentate cu cercuri;
 tranziţiile sunt reprezentate prin săgeţi: tranziţia către starea următoare are loc la fiecare
stare corespunzător literei citite la intrare – cea ―aşteptată‖.

Figura 2.2 Diagrama de stare pentru CV.


Se observă în graful pentru CV în Figura 2.2 că, pe lângă stările de „recunoaştere‖ a
literelor şi constituire succesivă a şirului valid, există o stare iniţială q0 în care CV primind la
intrare diferite caractere nu provoacă tranziţie către starea următoare decât la apariţia unui „s‖
caz în care trece în starea denumită aici „s‖. Apoi, intrarea caracterelor continuă iar dacă CV
în starea „s‖ are ca intrare caracterul „t‖ automatul va trece în starea „st‖ şi aşa mai departe,
până la „descoperirea‖ şirului valid şi trecerea în starea finală ŞI acceptoare „start‖.
Atenţie, să nu consideraţi graful orientat din Figura 2.2 ca un sistem prin care caracterele
intră în primul cerc q0 apoi în al doilea etc. (ca şi cum ar fi dispozitive la care ieşirea unuia
este intrarea celuilalt)! Cercurile indică doar stări prin care (poate) trece dispozitivul CV.
Cele două dispozitive CV şi BA vor fi cascadate (unite, conectate una după alta) iar starea
acceptoare „start‖ a CV iniţiază funcţionarea BA. Proiectarea noastră cu cele două dispozitive
CV şi BA este incompletă pentru că ar trebui să asigurăm şi oprirea alimentării cu apă în
bazin – eventual, cu un dispozitiv ce „recunoaşte‖ şirul de caractere „stop‖.

Critica celor două dispozitive „automate” BA şi CV:


Automatele sunt sisteme cu „evenimente discrete‖ care, aşa cum am arătat mai sus, privesc
procese ce se petrec la momente de timp separate (adică cu pauze între ele (pauze oricât de
mici dar evidente) sau fenomene ce privesc piese disparate (obiecte). Automatul CV prezintă
clar această caracteristică: literele din şirul de caractere sunt piese disparate care apar la
intrare în momente separate. Despre automatul BA însă, aţi putea spune că nu priveşte un
fenomen discret ci unul continuu: nivelul apei din bazin creşte/scade în mod continuu şi nu în
trepte. Facem însă observaţia că în mod similar, celula de bit într-o memorie DRAM prezintă
un condensator (de capacitate foarte mică 50 fF) care se încarcă cu electricitate statică în mod
continuu. Prin construcţie ambele dispozitive amintite (flotor-nivel apă, respectiv celula bit
DRAM) prezintă pentru nivelul de încărcare un prag inferior – ce semnifică „0‖ şi un prag
superior – ce semnifică „1‖. În general, fenomenele naturale sunt continui şi nu discrete, însă
omul procedează la „discretizare‖ pentru că doar astfel poate gândi: în cuvinte şi propoziţii
(discrete), cu piese (obiecte) şi evenimente (care au nume - identificatori). Deci fenomenul
subiect al BA este discretizat prin „starea‖ asociată volumului apei: gol sau plin.

30
În multe cărţi despre automate iniţierea se face pe exemple simple precum un întrerupător
pentru „aprins lumina‖ cu cele două stări: deschis şi închis – precum o uşă; totuşi un
întrerupător şi o uşă nu sunt nici pe departe automate, pe când bazinul cu flotor este un
dispozitiv automat (poate nu elegant dar bine cunoscut).
Pe de o parte, BA nu este automat (conform Teoriei Automatelor) pentru că nu prezintă o
stare cu „decidabilitate‖ (acceptoare) – cele două stări fiind ne-diferenţiate şi interschimbând
la infinit (BA nu se opreşte). Asemenea tip de sistem cu evenimente discrete este denumit
semi-automat sau sistem de tranziţii.
Pe de altă parte, CV are o stare acceptoare, şi se observă că nu ia în seamă toate intrările
(orice literă în şirul de caractere de intrare) ci doar cele din şirul valid (s t a r t), pe toate
celelalte le „aruncă la coş‖ – la fiecare din stările corespunzătoare pentru litera „aşteptată‖.
Subliniem că la fiecare stare CV nu face prelucrări – de exemplu comparaţii între intrarea
curentă şi litera „aşteptată‖ ci starea este pur şi simplu o „poziţie‖ în care se va afla automatul,
ca reacţie la o intrare anume.
Din aceste exemple ne putem lămuri „ce sunt‖ dar şi ce „nu sunt‖ automatele. Exemplele
sunt orientate spre familiarizarea cu reprezentarea grafică şi cu ideile de stare, tranziţie şi stare
iniţială (de start) şi stare acceptoare (unele stări finale nefiind acceptoare).

2.1.2 Automate Finite Deterministe DFA (Deterministic Finite Automata)


Definiţia 2.1 Un automat finit determinist DFA este un 5-tuplu (Q, Σ, δ, q0, F) cu:
 O mulţime finită de stări: Q
 O mulţime finită de simboluri de intrare denumit alfabet: Σ
 O funcţie de tranziţie: δ : Q × Σ → Q
 O stare de start: q0∈ Q
 O mulţime de stări acceptoare: F  Q
Prin definiţie, DFA prezintă o singură stare iniţială (de start) şi una sau mai multe stări
finale acceptoare. Mulţimea stărilor Q şi alfabetul Σ sunt finite iar determinismul indică faptul
că orice intrare provoacă o tranziţie şi numai una, deci se poate determina starea curentă la
orice pas în parcurgerea şirului de simboluri la intrare.

Exemplul 2.3 Reluând Exemplul 2.1 şi „echipându-l‖ cu o stare acceptoare putem să


exemplificăm 5-tuplul din Definiţia 2.1, urmărind Figura 2.3 pentru automate finite
deterministe DFA:

0 1 1 b a a
q0 q1 q0 q1
0 b

Figura 2.3 Diagrame de stare M01 şi Mba.


Automatul M01 are Q = {q0, q1}, Σ = {1, 0}, starea acceptoare F = {q1} iar funcţia de
tranziţie δ01 este reprezentată ca relaţie între mulţimile Q şi Σ în Figura 2.4 a).
Automatul Mba are Q = {q0, q1}, Σ = {a, b}, starea acceptoare F = {q1} iar funcţia de
tranziţie δba este reprezentată ca relaţie între mulţimile Q şi Σ în Figura 2.4 b).

31
M01 şi Mba sunt Automate Finite Deterministe DFA pentru că fiecare stare are câte o
tranziţie (şi numai una) pentru fiecare intrare posibilă. Prin diferenţă, automatele care prezintă
mai multe tranziţii posibile pentru o intrare anume sau prezintă tranziţii ne-legate de intrări
sunt automate nedeterministe (v. § 2.1.3).

δ01 Intrare δba Intrare


Stare 0 1 Stare a b
q0 q0 q1 q0 q0 q1
q1 q0 q1 q1 q0 q1
a) b)
Figura 2.4 Funcţiile de tranziţie pentru automatele M01 şi Mba.
Fiind dat cuvântul w = a1 a2 ... ai ... an – şir de caractere peste alfabetul Σ, un DFA acceptă
w dacă o secvenţă de stări r0, r0, ... rn există în Q şi îndeplineşte condiţiile:
i. r0 = q0
ii. ri+1 = δ(ri, ai+1), i ∈ {0, ..., n−1}
iii. rn ∈ F, |F|  1.
Textual, prima condiţie este ca maşina să înceapă funţionarea cu starea q0, a doua
condiţie este ca fiecare caracter din şir să producă o tranziţie de stare şi numai una prin funcţia
de tranziţie δ – deci la DFA δ este o funcţie bijectivă; numărul de simboluri din şirul de
intrare este egal cu numărul de tranziţii. A treia condiţie este ca maşina să accepte cuvântul w
şi să se oprească: ultima tranziţie (către starea finală rn) se face către starea acceptoare care
aparţine mulţimii F de stări acceptoare; cardinalitatea lui F este 1 sau mai mare indicând o
singură stare acceptoare sau mai multe. Şirurile ne-acceptate (rejectate) sunt cele pentru care
ultimul caracter din şir nu produce tranziţie către starea acceptoare ci către oricare altă stare: o
starea finală rn  F. Starea finală – acceptoare sau nu, se atinge la sfârşit de şir: NULL (\0).
Cele două automate prezentate acceptă şiruri astfel: M01 acceptă orice şir care se termină în
1: 01, 001, 01011, constituid limbajul L(M01) = {01, 001, 01011 ...} iar Mba acceptă orice şir
care se termină în a: ba, bba, babaa, constituid limbajul L(Mba) = { ba, bba, babaa ...}.
Constataţi că mulţimea şirurilor de caractere pe care le acceptă automatele sunt de fapt
cuvinte w şi de aceea este de înţeles că mulţimea acestor cuvinte este denumită limbaj.

Pentru a sublinia importanţa stării acceptoare, să observăm că dacă la automatul Mba din
Figura 2.4 b) starea q0 ar fi starea acceptoare şi nu q1 (adică cercul pentru q0 ar fi dublu),
atunci şirul de caractere valid se termină în b; în acest caz, maşina DFA va fi denumită Mab.
Starea acceptoare fiind esenţială pentru AUTOMATE, face ca uneori acestea să fie denumite
în literatura de specialitate Acceptoare Deterministe Finite (Finite Deterministic Acceptors)8.
Să observăm că în cazul maşinii Mab (care are starea iniţială stare acceptoare) aceasta va
accepta şirul vid ε (şir doar cu NULL) şi se va opri, pentru că imediat ce maşina începe citirea
şi la intrare apare ε avem final de funcţionare Mab. Astfel, limbajul acceptat de Mab este8:

L(Mab) = {w | w = ε ∨ „şir care se termină în b‖}

8
M. Sipser, Introduction to the Theory of Computation Course Technology, Boston, MA, Third edition, (2013)

32
Un limbaj L peste un alfabet Σ, este de fapt o submulţime a mulţimii exhaustive de cuvinte,
mulţime notată Σ* (sigma star) – care este mulţimea tuturor combinaţiilor posible de
simboluri din alfabetul Σ. Deşi mulţimea Σ este finită, mulţimea Σ* este infinită.

Propoziţia 2.1 Pentru orice alfabet Σ finit, limbajul exhaustiv Σ* este infinit, numărabil.
Pentru a demonstra aceasta este suficient să considerăm o funcţie surjectivă:
f : N0  Σ*
şi să observăm că se poate ataşa fiecărui număr natural un cuvânt din Σ* (şir de caractere
constituit din elementele alfabetului Σ) iar mulţimea Σ* fiind sortată în ordine lexicografică.
Fie alfabetul Σ = {0, 1},
cu limbajul exhaustiv: Σ* = { ε, 0. 1, 00, 01, 10, 11, 000, 001, ...}
şi f cu valori: f(0) = ε, f(1) = 0, f(2) = 1, f(3) = 00, f(4) = 01, ... f(199) = 1001000, ...
adică generic f(n) se obţine scriind codul binar pentru (n+1) din care se înlătură cel mai
semnificativ 1. N0 este numărabilă, deci mulţimea exhaustivă Σ* este numărabilă.

Definiţia 2.2 Un limbaj L peste un alfabet Σ este este o mulţime de şiruri de caractere w cu
simboluri din Σ, astfel ca:
 L  Σ*
 L ∈ P(Σ*)
unde P(Σ*) este mulţimea putere a Σ*, adică mulţimea tuturor limbajelor posibile peste Σ.
Mulţimea putere P(N0) este nenumărabilă (v. § 1.2 pct. 15). Prin funcţia f definită mai sus,
care face corespondenţă între N0 şi Σ*, se poate demonstra că P(Σ*) este nenumărabilă.
În Figura 2.5 este prezentată diagrama de stare a DFA, să-l denumim MSTEA, care pentru
alfabetul Σ = {1, 0} recunoaşte orice limbaj din Σ* (mulţime desfăşurată la Propoziţia 2.1).

0,1

q0

Figura 2.5 Diagrama de stare pentru automatul MSTEA cu L(MSTEA) = Σ*.

Definiţia 2.3 Fie Σ un alfabet şi fie A  Σ* un limbaj peste Σ. Limbajul A este obişnuit
(regulat - regular) dacă există un DFA M pentru care A = L(M).
Ce caracterizează un limbaj obişnuit? Expresiile cu sens! În cazul nostru, expresia este un
cuvânt, adică un şir specific de caractere – care în limbaj natural are o semnificaţie: este nume
de obiect (substantiv comun), este nume de persoană (substantiv propriu), este o acţiune
(verb), etc. Şi denumim expresie şirul de caractere specific unui limbaj aşa cum o expresie fbf
- formulă bine formată (vezi Exemplul 1.1) nu putea avea simbolurile puse alandala ci după
reguli (în acel caz, sintactice). La fel, nu orice înşiruire de caractere este o expresie
obişnuită/regulată – adică un cuvânt inteligibil în limba respectivă (să zicem română), cum nu
este „expresie regulată‖ un cuvânt din altă limbă (să zicem chineză, chiar scris cu litere
latine). Iar într-un limbaj de programare un şir de caractere este o linie de program –
instrucţiune sau declaraţie de tip de date, care trebuie să respecte sintaxa limbajului respectiv.
Exemplificarea limbajelor regulate cu detalii şi utilitatea lor se vor discuta la Capitolul 3.

33
În contextul celor specificate, MSTEA nu este un DFA ci doar poate reprezenta orice
înşiruire de caractere, adică orice cuvânt şi „regulat‖ (obişnuit) şi „ne-regulat‖ (ne-obişnuit).
De remarcat că limbajul obişnuit A este numărabil iar limbajul lui MSTEA este ne-numărabil
pentru că A este strict conţinut în Σ*, deci |A| < | Σ* | (vezi condiţiile de la § 1.2 pct. 15).
Vom da în continuare câteva exemple DFA interesante9 şi care în plus ne vor putea ajuta la
înţelegerea automatelor finite ne-detereministe NFA.

Exemplul 2.4 DFA M2_4 care acceptă toate şirurile cu cel puţin doi de 0.

1 1 0,1
q0 0 q1 0 q2

Figura 2.6 Diagrama de stare DFA M2_4.

Se poate observa că M2_4 în starea q1 a numărat un 0, în starea q2 a numărat al doilea şi


apoi nu mai contează intrarea (1 sau 0), orice tranziţie se face către starea acceptoare q2.

Exemplul 2.5 DFA M2_5 acceptă şirurile cu cel mult doi de 0.

1 1 1 0,1
0 0 0
q0 q1 q2 q3

Figura 2.7 Diagrama de stare DFA M2_5.

În acest exemplu M2_5 prezintă mai multe stări acceptoare: în starea q0 încă nu a numărat
nici un 0, în q1 a numărat un 0, în q2 a numărat doi 0 şi orice alt 0 numărat prin q3 rămâne în
acesată stare ne-acceptoare.
Aparent, DFA prezentate până la M2_5 au starea acceptoare pe ultima poziţie în diagrama
de stare dar la M2_5 acestea (fiind şi mai multe) nu. Deci nu poziţia în diagramă contează ca
stare finală şi/sau stare acceptoare şi nu trebuie făcută confuzie între cele două.

Exemplul 2.6 DFA M2_6 acceptă şirurile ce încep cu o succesiune 01.


0,1
q0 0 q1 1 q2

1
0

coş 0,1

Figura 2.8 Diagrama de stare DFA M2_6.

9
Brian Heinold, An Informal Introduction to Formal Languages, Licensed under a Creative Commons
Attribution, 2018

34
Pentru DFA M2_6 stările din linia de sus: q0, q1, q2, sunt cele care înregistrează
succesiunea 01 ce trebuie să se afle în şirul de caractere valid (acceptat); toate celelalte sunt
aruncate la „coş‖, de aceea starea ce ar trebui notată q3 este denumită astfel. De fapt, starea
coş este o stare de ne-acceptare şir, pentru că s-a dovedit a nu fi unul valid, începând cu
situaţia în care primul caracter din şir ar fi 1 (în
Figura 2.8 arcul care duce de la q0 la coş).

Exemplul 2.7 DFA M2_7 acceptă şiruri în care fiecare 1 este urmat de cel puţin doi de 0.

0
0
1 0
q0 q1 q2

1
1

0,1
coş

Figura 2.9 Diagrama de stare DFA M2_7.

Se observă că M2_7 acceptă şi şirurile de caractere care nu au nici un 1, pentru că q0 –


stare acceptoare, „se menţine‖ cât timp nu apare la intrare 1. Din moment ce apare 1 la intrare
se trece în starea q1 de unde apoi la primul 0 intrat se trece în starea q2 unde se urmăreşte
sosirea celui de-al doilea 0 ce provoacă salt la starea q0 unde pot intra oricâţi de 0 până la
sosirea primului 1 – care produce iar tranziţie la q1 şi aşa mai departe. Orice 1 urmat tot de 1
este aruncat (din q1) la coş; la orice unic 0 (urmează 1) se aruncă (din q2) la acel 1 în coş,

2.1.3 Automate Finite Ne-deterministe NFA (Non-deterministic Finite Automata)


Definiţia 2.4 Un automat finit ne-determinist NFA este un 5-tuplu (Q, Σ, δ, q0, F) cu:
 O mulţime finită de stări: Q
 O mulţime finită de simboluri de intrare denumit alfabet: Σ
 O funcţie de tranziţie: δ : Q × {Σ ∪ ε } → P(Q)
 O stare de start: q0∈ Q
 O mulţime de stări acceptoare: F  Q

Se observă că definiţia NFA este similară cu cea a DFA prvind mulţimea stărilor Q şi
alfabetul Σ finite, precum şi privind o stare iniţială (de start) şi una sau mai multe stări
acceptoare.
Nedeterminismul se constată din modul cum au loc tranziţiile: una, zero sau una din mai
multe (la „alegere‖). Există trei cazuri de nedeterminare:
Nd1. O intrare anume (adică un caracter din şirul de intrare) produce tranziţie către mai
multe stări posibile (deci un set – o mulţime de stări) prin tranziţii-directe şi nu se ştie care
din aceste stări va surveni în urma apariţiei intrării respective (în cazul DFA o tranziţie avea
loc către o stare clar definită la o intrare anume); la NFA tranziţia nu este deterministă, relativ
la starea către care va duce. Această situaţie este indicată în descrierea formală a funcţiei de

35
tranziţie δ prin domeniul în care funcţia ia valori: la NFA nu este Q (ca la DFA) ci este
mulţimea putere a Q: P(Q) adică mulţimea de submulţimi a lui Q.
Nd2. Însă la NFA mai poate apare o sursă de nedeterminism şi anume poate apare o
tranziţie care are loc „fără motiv‖, adică fără să fie provocată de o intrare anume. Acest tip de
tranziţie este denumită tranziţie-ε (epsilon) pentru că apare „din vid‖ (de aceea notată la fel
ca şirul vid ε). Însă „tranziţia-ε‖ este altceva decât „şirul vid‖ şi pentru a nu apare confuzii
unii autori denumesc aceasta tranziţie-λ.
Nd3. La NFA exită şi cazuri cu 0 tranziţii, anume atunci când, datorită unei tranziţii
precedente s-a ajuns la starea „coş‖ (notată ): orice intrare la această stare nu mai produce
tranziţii în sensul că se rămâne la starea „coş‖ – ca o blocare a NFA pentru tot restul şirului de
caractere de intrare. Oarecum, este o situaţie similară cu exemplele DFA cu stare coş doar că
se consideră că nu au loc tranziţii, deşi uneori (pentru claritate) sunt explicitate şi la NFA
precum au fost la DFA (v.
Figura 2.8 şi Figura 2.9).
Să înţelegem clar comportamentul NFA: acesta are cazuri când face tranziţie NU către mai
multe stări SIMULTAN ci doar către o singură stare dintr-un set dar nu se ştie care stare din
set va urma la momentul dat. Pentru clarificare să urmărim exemplele9 de mai jos.

Exemplul 2.8 NFA N2_8 la intrare caracter 0 face traziţie către q0, sau către q1.

0
0
q0 q1

Figura 2.10 Diagrama de stare a N2_8, nedeterminismul tranziţiei la intrare 0 (Nd1).

După startul automatului N2_8 el se va găsi (aşa cum este convenit la orice automat) în
starea q0 iar la apariţia unui 0 va avea loc tranziţia directă către q1 sau va rămâne în q0 – în
sensul că are loc tranziţia buclă către q0.

Exemplul 2.9 NFA N2_9 tranziţia de la q0, către q1, are loc fără (caracter de) intrare.

ε
q0 q1

Figura 2.11 Diagrama de stare a N2_9, nedeterminismul tranziţiei fără intrare (Nd2).

Tranziţia lui N2_9 din starea q0 în starea q1 are loc fără a avea o intrare anume (0 sau 1) ci
apare „din vid‖. Pentru a lămuri tranziţia-ε şi a stabili diferenţa dintre aceasta faţă de şirul vid
ε, să constatăm că în reprezentarea unui şir de caractere acesta este încheiat cu un simbol
„sfârşit de şir‖ NULL (\0 în limbajul C) şi în acest caz „şirul vid‖ este doar caracterul „\0‖.
Să remarcăm apoi că tranziţia-ε survine fără intrare adică, în cazul nostru, la „caracterul vid‖
(lipsă caracter) – ce este clar o abstracţie pentru că nu avem o reprezentare pentru caracterul
vid (cum avem pentru şirul vid: „\0‖).
Aceste „nedeterminări‖ şi automatele nedeterministe NFA au fost introduse de Michael O.
Rabin și Dana Scott (în 1959), care au arătat şi echivalența NFA cu DFA. NFA sunt şi ele
36
utilizate în implementarea expresiilor regulate: Thompson a construit un algoritm pentru a
obţine NFA dintr-o expresie regulată (şiruri de caractere) în mod eficient.
Pe de o parte NFA este un model care poate fi întâlnit în realitate: există comportări ale
sistemelor reale în care starea curentă se obţine (apare) cu realizări diferite deşi intrarea
aplicată este aceeaşi (nedeterminarea Nd1); sau apar modificări de stare naşteptate, fără
aplicarea unei intrări anume sistemului (nedeterminarea Nd2). Evident, aceste situaţii apar în
realitate datorită cunoştinţelor incomplete asupra contextului de funcţionare a sistemului –
factori interni respectiv factori externi puţin- sau ne-cunoscuţi.
Pe de altă parte, „nedeterminismul‖ NFA este şi un mijloc prin care factori cunoscuţi
(interni sau externi) se pot „desconsidera‖ în model pentru că ori sunt sub-înţeleşi ori sunt
cazuri de „aruncat la coş‖.
Astfel, NFA este şi un model util pentru că permite descrierea unui automat în mod mai
simplu decât la descrierea DFA – care este detaliată pentru orice tranziţie posibilă; totuşi, la
implementarea unui automat real acesta trebuie să fie „proiectat‖ ca DFA, adică NFA să fie
adus la forma echivalentă DFA – pentru a obţine scopul vizat în mod „determinat‖.
În exemplul următor se va lămuri cum trebuie înţeleasă descrierea unui NFA, procedând la
descrierea în forma echivalentă DFA.

Exemplul 2.10 NFA N2_10 tranziţia de la q0, către q1 are loc fără (caracter de) intrare.

0
q0 q1

1 0,1

0
q0 q1 coş 0,1

Figura 2.12 Diagrama de stare NFA N2_10 (stânga) şi echivalentul DFA (dreapta).

În figura de mai sus se observă că în diagrama de stare a N2_10 (NFA) în stânga nu apare
deloc intrare 1 deşi alfabetul Σ = {1, 0}, conţine şi acest caracter. Se poate înţelege de ce, dacă
analizăm M2_10 (DFA echivalent din dreapta), la start M2_10 acesta intră în starea q0 iar la
intrare 0 are loc tranziţia în starea q1; nu interesează intrarea 1 pentru că va fi „aruncată la
coş‖ – vezi echivalenul DFA din Figura 2.12 dreapta. Similar, în starea q1 nu interesează cum
vor decurge tranziţiile pentru că orice intrare 0 sau 1 ar apare în q1 nu vor fi acceptate ci
„aruncate la coş‖.
Deci înţelegem descriere NFA mult simplificat, prin faptul că sub-înţelegem că în starea q0
o intrare 1 nu interesează iar în starea q1 nici 0 şi nici 1 nu interesează.

2.1.4 Definirea formală a nedeterminărilor NFA şi a acceptării unui cuvânt


Pentru descrierea formală a acceptării unui cuvânt de către NFA, într-un mod similar
definirii acesteia la DFA, vor trebui definite câteva concepte speciale privind nedeterminările.
Fiind dat cuvântul w = a1, a2, ... a, ... an – şir de caractere peste alfabetul Σ, un automat
nedeterminist NFA parcurge la acceptarea cuvântului w secvenţa de stări r0, r0, ... r, ...rm,
unde se consideră a o intrare oarecare (generică) şi respectiv r o stare oarecare (generică).

37
Atunci, prin nedeterminarea Nd1, la o stare r oarecare vom avea pentru NFA o mulţime R
de stări către care aceasta poate tranzita (şi nu doar o singură stare ca la DFA).
Prin nedeterminarea Nd2 se poate ajunge de la o stare r la o mulţime de stări:
εR={δ(r, ε)},
unde εR este mulţimea de stări accesibile din r doar prin tranziţii-ε. Facem observaţia că
mulţimea εR conţine nu doar stările prin care au loc tranziţii directe către alte stări ci toate
stările obţinute pe căile „deschise‖ de tranziţii-ε.
Definiţia 2.5 Se numeşte închidere-ε (ε-closure / epsilon-closure) pentru starea r
mulţimea εR a tuturor stărilor accesibile prin tranziţii-ε pornind de la r, inclusiv r:
εR={δ(r, ε)}∪ {r}.
Se poate interpreta că εR  P(Q) este cea mai mică submulţime a Q în care orice tranziţie-ε
din starea r rămâne tot în submulţimea εR. De aceea se numeşte închidere – precum
închiderea unor mulţimi la operaţii anume: de exemplu închiderea mulţimii N la operaţia de
adunare, în care oricare z = x + y , pentru x, y ∈ N, şi z ∈ N (z se află tot în N); N nu este
închisă la operaţii de scădere sau împărţire: când se produc numere negative şi respectiv reale.
Închiderea ε este un concept definit şi utilizat în literatură, în general pentru aplicarea unei
proceduri eficiente la transformarea NFA în DFA echivalent.
Existenţa măcar a unei tranziţii-ε este indicată prin faptul că |εR| > 1, adică există cel puţin
două stări legate prin tranziţie-ε. La DFA putem considera |εR|=1, adică nu există o a doua
stare la care putem ajunge prin tranziţii-ε (deşi nici nu este cazul).

Să definim acum un concept similar pentru nedeterminarea Nd1, prin care la o stare r pot
exista mai multe tranziţii-directe (spre alte stări) la intrare a, deci mai multe stări „destinaţie‖.
Prin nedeterminarea Nd1 se poate ajunge de la o stare r la o mulţime de stări:
R={δ(r, a)},
unde R este mulţimea de stări accesibile din r prin tranziţii directe provocate de intrarea a,
similar cu mulţimea εR de stări accesibile prin Nd2 – dar spre deosebire de aceasta, stările
accesibile din r, către celelalte ce aparţin lui R, prezintă doar tranziţii directe din r.
Definiţia 2.6 Se numeşte închidere- (-closure) la tranziţii pe intrarea a pentru starea r,
mulţimea R a tuturor stărilor accesibile prin tranziţii-directe pe a plecând din r, inclusiv r:
R={δ(r, a)}∪ {r}.
Se consideră R  P(Q) ca submulţimea Q de stări accesibile din r ddacă există tranziţii-
directe datorate intrării a. Existenţa nedeterminării Nd1 se poate constata prin cardinalitatea
închiderii- (alpha-closure): dacă |R| > 2 atunci există nu doar două stări între care are loc o
tranziţie datorată intrării a ci cel puţin încă una (adică 3 sau mai multe).
Se poate spune astfel, că un DFA este o maşină cu stări finite ddacă |R| = 2, pentru oricare
r; altfel spus oricare stare r prezintă o stare şi numai una către care tranzitează la apariţia
oricărui simbol de intrare a.

Prin nedeterminarea Nd3 se poate ajunge de la o stare r la o mulţime de stări vidă, cu alte
cuvinte mulţimea R conţine doar starea r, adică formal |R| = 1. Trebuie să constatăm că
lipsa tranziţiilor pentru unele intrări face ca la NFA relaţia δ între cele două mulţimi: de stare
Q şi de intrări Σ, să prezinte situaţia:

38
|{δ(r, a)}| < |P(QΣ)|, altfel spus |{δ(r, a)}| < | 2QΣ |
Se poate spune că NFA prezintă nedeterminarea Nd3 ddacă există r altfel încât |R| = 1.
Din contră, DFA nu prezintă astfel de cazuri, cu alte cuvinte la DFA nu există tranziţii
către nicăieri ci de la o stare r anume pentru intrarea a există cel puţin o tranziţie buclă – o
tranziţie către ea-însăşi. Totuşi, în acest caz |R| = 1, pentru că reuniunea (ca operaţie pe
mulţimi) între starea r şi ea-însăşi ar reţine elementul r doar o singură; deci nu am putea face
diferenţia DFA de NFA doar prin criteriul cardinalităţii închiderii- ci mai trebuie adăugată
condiţia specifică la DFA:
|{δ(r, a)}| = |P(QΣ)|, sau mai precis |{δ(r, a)}| = | 2QΣ |
adică orice intrare provoacă obligatoriu o tranziţie.
Formalismul de mai jos pentru cuvântul acceptat de NFA, este o abordare proprie,
completă, bazată pe noul concept „închidere-‖ (R Definiţia 2.6) utilizat în ii. şi iii mai jos.
Fie NFA (Q, Σ, δ, q0, F), cu închideri εR şi R specifice nedeterminărilor Nd1, Nd2 şi Nd3;
cuvântul w = a1 a2 ... ai ... an este acceptat dacă există secvenţa de stări r0, r0, ... rj, ...rm,
(m∈N) corespunzătoare tranziţiilor δ, care îndeplinesc condiţiile:
i. r0 = q0
ii. ∃ r ∈ {R astfel ca |R| > 3 ∨ |R| = 1 ∨ | εR| > 2 }, R  P(Q)
iii. rj+1 ∈ { δ(Rj, ai+1)} ∪ {δ(rj, ε)}, i ∈ {0, ..., n−1}, j ∈ {0, ..., m−1},
iv. rm ∈ F, |F|  1.
Textual, prima condiţie este ca maşina să înceapă funţionarea cu starea q0. A doua condiţie
arată că există cel puţin o stare r care prezintă nedeterminări (Nd1, Nd2 sau Nd3) la care este
ataşată o submulţime R de stări (conţinută în mulţimea putere P(Q)), pentru care închiderile
R şi εR au cardinalităţi ce indică existenţa acestor nedeterminări. A treia condiţie arată că
starea rj+1 se obţine ori ca o realizare din mulţimea de stări Rj prin tranziţie datorată intrării
ai+1 [adică prin tranziţia δ(Rj, ai+1)] ori ca o tranziţie-ε „din vid‖ [prin tranziţia δ(ε)]. A patra
condiţie este ca maşina să accepte cuvântul w şi să se oprească: ultima tranziţie rm se face
către starea acceptoare; alte şiruri sunt rejectate pentru că ultimul caracter din şir nu produce
tranziţie către starea acceptoare ci către oricare altă stare: rm  F sau pur şi simplu NFA
rămâne într-o stare ne-acceptoare rm  F urmare a unor tranziţii-ε.
Subliniem că tranziţia din starea rj se poate face în oricare din stările aparţinând mulţimii Rj
dar o tranziţie δ are loc către o singură stare rj+1 şi doar una – element al mulţimii Rj; iar
această tranziţie apare ca urmare a intrării ai+1 sau tranziţiei vide ε (drept cauze).
Corespunzător rj submulţimea Rj a mulţimii Q are |Rj | = 2 – caz în care tranziţia ar fi similară
celei de la DFA (de la o stare către o unică alta). Funcţia de tranziţie δ la NFA este o funcţie
surjectivă dar nu injectivă, adică unui element din domeniul de definiţie îi pot corespunde
mai multe elemente din domeniul în care funcţia ia valori.
Definiţia 2.7 Se numeşte traziţie extinsă δ*(q0, w) pentru un cuvânt w acceptat, mulţimea
de stări { r0, ... rm} parcursă ca trasee de tranziţii la intrări a∈w şi/sau tranziţii-ε, de la q0 până
la o stare acceptoare.

La NFA numărul de tranziţii nu este egal cu numărul de simboluri de intrare m  n. Doar la


nedeterminarea Nd1 m = n pentru că o intrare produce sigur o tranziţie chiar dacă nu se ştie
către ce stare din R, dar la nedeterminarea Nd2 sunt posibile m>n tranziţii, pentru că unele

39
nu corespund unor caractere din şirul de intrare – sunt datorate (în plus) „tranziţiei vid‖. Dacă
însă au loc intrări şi automatul NFA se găseşte în  - nedeterminarea Nd3 (starea „coş‖),
atunci m < n pentru că deşi intrările se „adaugă‖ şi n creşte, numărul m de tranziţii înregistrat
rămâne acelaşi: din starea coş nu mai au loc tranziţii indiferent de intrare (zero tranziţii).
Funcţionarea unui NFA este diferită de cea a DFA; şi traseele de stări diferă.

Exemplul 2.11 NFA N2_11 acceptă toate șirurile care se termină cu 1.

0,1
1
q0 q1

Figura 2.13 Diagrama de stare NFA N2_11

Să considerăm pentru N2_11 șirul de intrare 11. Există mai multe căi la care poate duce
acest șir: prima este , a doua este unde, aşa cum s-a arătat,
într-o stare anume orice tranziție neindicată pentru o intrare anume, duce la starea coş. Prima
cale duce la o stare de acceptare, în timp ce a doua nu.
Regula generală este: la NFA un șir este considerat a fi acceptat dacă există cel puțin o
cale care duce la o stare acceptoare, chiar dacă există şi alte căi – pentru aceleaşi intrări,
care duc la alte stări decât (cele) acceptoare.
Din această regulă se poate vedea că șirurile acceptate de NFA N2_11 sunt cele care se
termină cu 1. NFA N2_11 rămâne în starea q0 până ce se ajunge la ultimul caracter din șir,
moment în care se trece la q1 dacă acest ultim caracter este 1.
O modalitate de a înțelege funcționarea unui NFA este să construim o diagramă
arborescentă, în care, de fiecare dată când există o alegere între mai multe variante se crează o
ramură în arbore. În Figura 2.14 este ilustrat arborele care arată toate căile posibile pe care
șirul de intrare 1101 le poate produce la NFA N2_11.

Figura 2.14 Arborele de tranziţii de stare NFA N2_11

După cum se poate vedea, există patru căi posibile din care una duce la starea de acceptare
q1, deci șirul 1101 este acceptat de NFA N2_11.
S-ar putea desena o diagramă „arborescentă‖ similară pentru un DFA, dar ar fi inutilă,
pentru că automatul fiind determinist nu lasă loc la alegeri sau ramificații şi diagrama sa
arborescentă ar fi o simplă cale dreaptă.

40
Nondeterminismul este un mod diferit de a gândi despre calculabilitate decât cel cu care
suntem obișnuiți. Uzual, descrierea unui NFA se face desfăşurând toate căile posibile în
paralel şi căutând apoi una care se termină într-o stare acceptoare. O modalitate de a vedea
diferența dintre DFA și NFA este să privim modul în care un program simulează DFA şi unul
care simulează NFA:
a. la DFA, programul ar avea ca variabilă starea curentă și un tabel de tranziții; se începe
de la starea inițială și, pe măsură ce se citesc caractere din șirul de intrare, se consultă
tabelul și se schimbă starea în consecință.
b. la NFA, programul ar fi similar, doar că de fiecare dată când apare o tranziţie către mai
multe stări şi trebuie făcută o alegere, se generează un nou fir (thread); dacă oricare
dintre fire se termină într-o stare acceptoare, șirul de intrare este acceptat.
Acest paralelism permite ca NFA-urile să fie, într-un anumit sens, mai rapide decât DFA.
NFA pot fi considerate un super-set, o generalizare a DFA.

2.1.5 Echivalenţa NFA – DFA


Se pune întrebarea: există limbaje pe care nu le acceptă un DFA? Răspunsul este Da! sunt
multe asemenea limbaje. De exemplu, nu este posibil să se construiască un DFA care acceptă
limbajul 0n1n – care constă din toate șirurile cu un număr de 0-uri urmat de același număr de
1-uri. Un DFA nu este capabil să contabilizeze exact câte 0-uri a parcurs pentru a le compara
cu numărul de 1-uri (nu are memorie!). Deasemenea, pentru un DFA este imposibil un limbaj
al palindroamelor: șiruri care sunt identice parcurse spre înainte și spre înapoi, cum ar fi
„capac‖ sau „110101011‖.
Apoi se poate pune întrebarea dacă NFA sunt mai puternice (privind limbajele acceptate)
decât DFA; altfel spus există limbaje pe care le acceptă NFA şi pe care DFA să nu le accepte?
Răspunsul este Nu! NFA permite construirea mai facilă a unui automat care acceptă un
anumit limbaj, dar nu face nimic mai mult decât un DFA.
Pentru orice NFA se poate construi DFA echivalent, folosind aşa-numita „construcţie a
mulţimii putere‖ (power set construction).

Regulile generale pentru conversia unui NFA în DFA sunt:


1. Starea inițială a DFA va fi etichetată cu starea inițială a NFA împreună cu orice stare
care este accesibilă din acesta printr-o tranziție ε.
2. Pentru a afla tranziția de la o stare S a DFA cu simbolul x (simbol de intrare a sau ε) se
parcurg toate stările spre care duc tranziţii din S. Pentru fiecare dintre aceste stări, se urmăresc
tranzițiile x de la acea stare la NFA şi se colectează toate stările la care se ajunge din S printr-
o tranziție x, împreună cu orice stări la care se poate ajunge din aceasta; se crează o stare nouă
în DFA a cărei etichetă este colecţia de etichete ale stărilor deja colectate (cu excepția cazului
în care acea stare a fost deja creată) și se adaugă o tranziție x de la S la acea stare.
3. Dacă la pasul 2 singura stare colectată este o stare „coş‖ atunci se crează o stare nouă cu
eticheta ∅ - „coş‖ (cu excepția cazului în care a fost deja creată) și se adaugă o tranziție x de la
S la acea stare. Acest nouă stare acţionează ca o stare „coş‖ și toate tranzițiile posibile din
acea stare ar trebui să revină la ea.
4. O stare din DFA va fi marcată drept acceptoare dacă oricare dintre stările (colectate) în
eticheta sa este o stare acceptoare în NFA.

41
Exemplul 2.12 Fie NFA N cu diagrama de stare din Figura 2.15 (stânga). Descrierea
formală a acestuia este:
N = (QN, Σ, δN, q0, FN)
unde QN = {q0, q1}, Σ = {0, 1}, FN = {q1}, şi δN : QN  (Σ ∪ {ε}) → P(QN)
iar funcţia de tranziţie δN către diferite stări descrisă mai jos (cu  s-a notat starea „coş‖):
δN (q0, 0) = {q0, q1}, δN (q0, 1) = {q1}, δN (q0, ε) = ,
δN (q1, 0) = , δN (q1, 1) = {q0}, δN (q1, ε) = ,
δN (q1, 0) = , δN (q1, 1) = { q0}, δN (q1, ε) = .

Vom defini DFA M având o stare pentru fiecare subset de stări ale lui N. Putem denumi
stările lui M oricum dorim10, așa că le putem numi direct cu submulțimile lui QN cărora le vor
corespunde prin „transformarea‖ NFA N în DFA M. Cu alte cuvinte, mulțimea de stări ale M
va face parte din mulțimea putere P(Q) a lui N – în cazul nostru chiar mulţimea putere P(QN).

Figura 2.15 Diagrame de stare pentru NFA N şi DFA M echivalent.

Pentru diagrama de stare din Figura 2.15 la DFA M (în dreapta) vom avea definite:
M = (P(QN), Σ, δM, { q0}, {{ q1}, { q0, q1}})
deci QM = P(QN), FM = {{ q1}, { q0, q1}} iar funcţia de tranziţie δM : QM  Σ → QM este:
δM ({q0}, 0) = {q0, q1}, δM ({q0}, 1) = {q1},
δM ({q1}, 0) = , δM ({q1}, 1) = {q0},
δM ({q0, q1}, 0) = { q0, q1}, δM ({q0, q1}, 1) = {q0, q1},
δM (, 0) = , δM (, 1) = .

Se obţine astfel la DFA M câte o tranziţie bine definită pentru fiecare intrare. Să explicăm:
La momentul iniţial N este în starea q0 (încă nu s-a citit vre-un caracter). Dacă se citește un
0, este posibil fie să urmeze bucla proprie și să rămână în starea q0, fie să urmeze tranziția
către q1. Din acest motiv există o tranziție etichetată 0 de la starea {q0} la starea {q0, q1} în M;
starea {q0, q1} în M reprezintă faptul că N se poate găsi fie în starea {q0} fie în starea {q1}.
Pe de altă parte, dacă N este în starea q1 și se citește un 0, nu există tranziții posibile de
urmat și de aceea M are o tranziție etichetată 0 de la starea {q1} la starea  - care în M

10
John Watrous, Introduction to the Theory of Computing - Lecture notes, cs.uwaterloo.ca/~watrous/ToC-
notes/ (2020)

42
reprezintă „coş‖ pentru că în starea q1 N nu efectuează tranziţii pentru 0 (N este un NFA). În
diagrama de stare pentru M (dreapta în figură) starea „coş‖  este completată cu tranziţii care
ar putea surveni la intrări (0 sau 1) prin bucla10 indicată la starea „coş‖  - care, în fapt, ar
putea lipsi pentru că din starea coş nu se poate „ieşi‖ orice intrare ar apare.
Pentru cazurile în care la DFA M echivalent la starea {q0, q1} ar apare intrări 0 sau 1 se
menţine această stare (prin bucla etichetată 0,1) atât pentru că intrare 0 duce la stare q0, cât şi
intrare 1 duce la stare q0, iar pentru asemenea intrări se „rămâne‖ în stare acceptoare deşi q0
nu ar fi una dar aici q0{q0, q1} care este acceptoare.
Există, uneori probleme privitoare la starea iniţială a DFA M, apoi la stabilirea stărilor
acceptoare ale M. Dar rezolvarea este, în general, simplă: starea iniţială a lui M va corespunde
stărilor lui N în care acesta se află când încă nu a citit simboluri – care în exemplul nostru este
{q0}; apoi stările acceptoare ale M sunt acele stări corespunzătoare oricărei sub-mulţimi de
stări ale lui N care include cel puțin un element al lui F – în exemplul nostru {q1}. NFA N şi
DFA M echivalent acceptă şiruri care încep cu 0 şi ori nu conţin 1 ori conţin o secvenţă cu
număr impar de 1-uri.
Să remarcăm că la transformarea NFA N în DFA M echivalent, va trebui să luăm în
considerare pentru M mulţimea de stări QM ca mulţimea putere P(QN) – care în cazuri cu |QN|
mare |QM| creşte exponențial. Mulţimea de stări al DFA M echivalent al NFA N este:
|QM| = 2|QN|
unde pentru Exemplul 2.12: |QM| = 2|QN| = 22 = 4, însă pentru un număr mare de stări al NFA
N – să zicem |QN| = 1000, numărul de stări al DFA M ar fi |QM| = 21000 care, se spune, ar fi
numărul de particule din univers! Deci nu este fezabil un DFA echivalent în acest caz.
În plus, se poate ca multe dintre aceste stări să fie inaccesibile din starea iniţială a lui M; în
acest caz se va considera starea de start a lui M care corespunde închiderii-ε pentru starea start
a lui N și apoi se caută noi stări ale lui M pentru construcţia acestuia.

NFA pot prezenta stări de blocaj din care nu pot ieşi decât printr-o „resetare‖; acestea nu
sunt neapărat erori de proiectare ci necesare limbajului asociat. Există două tipuri de blocaj:

Figura 2.16 Diagrama de stare pentru automat cu blocaje.

a. „blocaj mort‖ (punct-mort deadlock) atunci când automatul intră într-o stare ne-
acceptoare din care nici un eveniment nu este prevăzut spre a o părăsi;
b. „blocaj viu‖ (livelock) atunci când automatul intră într-un ciclu de stări ne-acceptoare
cu tranziţii numai între acestea.

43
Exemplul 2.13 NFA cu diagrama de stare din Figura 2.16 prezintă două stări stări de blocaj:
punct mort şi blocaj viu, care pot fi descoperite ca exerciţiu.

2.1.6 Stabilitatea automatelor acceptoare la operaţii obişnuite (regulate)


Tranziţia-ε se poate considera ca o tranziţie opţională, un exemplu fiind un automat care
acceptă cuvântul colour (în ortografie engleză) şi color (în ortografie americană) (precum în
Exemplul 2.2 cuvântul „start‖), care ar avea între starea „colo‖ (ex. „star‖) şi starea acceptoare
„colo(u)r‖ (ex. „star()t‖) două tranziţii în paralel: una pentru „u‖, una ε.
Tranziţia-ε este utilă pentru definirea de operaţii obşnuite (regulate) unare sau binare, care
păstrează rezultatele operatorilor obişnuiţi (pentru mulţimi) asupra limbajelor acceptate de
automatele operanzi, adică stabilitatea limbajelor automatelor la operatori de tip uniune,
intersecţie, concatenare, etc.

Uniunea
Fie în Figura 2.17 stânga reprezentarea concisă a unui automat A oarecare, în care s-au
indicat doar starea iniţială q0 (de start) şi mulţimea de stări acceptoare F11.



q0 q0

A F A F

Figura 2.17 Reprezentare NFA concisă (stânga) şi cu stări iniţiale comasate (dreapta).

În Figura 2.17 dreapta se reprezintă un NFA cu mai multe stări iniţiale care pot fi comasate
cu ajutorul tranziţiilor-ε, astfel că obţinem un automat echivalent doar cu o stare iniţială q0.
Fie două NFA A şi B; ele se pot reuni ca în Figura 2.18 şi acceptă limbajul: L(A)∪L(B) –
adică va accepta limbajele L(A) SAU L(B) ale celor două automate (v. Exemplul 2.14 şi
Figura 2.19). Starea iniţială va fi comună iar stările acceptoare vor fi mulţimea F ∪ F '.


A F



B F’

Figura 2.18 Reprezentare concisă a uniunii NFA A şi NFA B.


11
Michel Rigo, Théorie des automates et langages formels, 2010,
www.discmath.ulg.ac.be/cours/main_autom.pdf

44
Exemplul 2.14 NFA N2_13 care acceptă toate șirurile care se termină cu 1 sau au număr
impar de simboluri, obţinut prin „combinarea‖ a două NFA care execută separat cele două
funcţii, fiind reunite prin tranziţii-ε de la starea iniţială comună q0.

0,1
q1 1 q2
ε
q0
ε 0,1

q3 q4
0,1

Figura 2.19 Diagrama de stare a două NFA reunite.

Practic, exemplul acesta şi diagrama de stare din Figura 2.19 prezintă două NFA care sunt
reunite prin cele două tranziţii-ε din q0: un automat care acceptă șirurile terminate cu 1 (sus) şi
respectiv un automat care acceptă un număr impar de simboluri (jos).

Concatenarea
Fie două NFA A şi B; ele se pot adăuga unul altuia (concatena) ca în Figura 2.20 şi acceptă
limbajul: L(A)L(B) – adică starea iniţială a NFA B nu va mai fi stare de start iar stările NFA
A din mulţimea F nu mai sunt acceptoare.




A F B F’

Figura 2.20 Reprezentare concisă a concatenării NFA A şi NFA B.

Operatorul * stea (Kleene star)


S-a folosit în Definiţia 2.2 mulţimea putere a alfabetului Σ care a fost notată cu Σ* (sigma
star). Matematicianul american Stephen Cole Kleene a introdus „operatorul‖ Kleene sau
„închiderea‖ Kleene, care este un operator unar (monoid) ce generează mulţimea tuturor
submulţimilor cu elemente din alfabetul Σ, adică limbajul exhaustiv peste Σ: toate cuvintele
posibile peste Σ, ca urmare toate limbajele posibile peste acel alfabet (de exemplu peste
alfabetul latin – alfabet utilizat pentru scriere în engleză şi în chineză şi în altele).

Fie NFA A; Kleene star aplicat A este reprezentat în Figura 2.21 şi generează limbajul
(L(A))∗. Starea iniţială a automatului din Figura 2.21 este o nouă stare iar mulţimea de stări
finale este F la care se adaugă şirul vid, adică va fi F∪{ε}.
Se observă în Figura 2.21 că starea iniţială nou introdusă (care ―alimentează‖ vechea stare
inițială) este şi stare acceptoare, tocmai pentru a include şirul vid ε în mulţimea tuturor

45
combinaţiilor posibile generate de Kleene-star; buclele introduse de la mulţimea F la noua
stare iniţială sunt tranziţii-ε.



A F

Figura 2.21 Reprezentare concisă a NFA A cu Kleene star.

Acceptarea şirului vid ε poate avea și consecințe nedorite dacă unele stări au tranziții în
starea inițială, caz în care unele șiruri ar putea fi acceptate, ceea ce nu ar trebui să se întâmple;
acastă situaţie nedorită apare dacă în desenul din Figura 2.21 buclele introduse de la mulţimea
F de stări acceptoare ar duce la noua stare iniţială (cum veţi mai găsi în literatură la
reprezentarea NFA cu Kleene star) – nu şi în modul cum apare în Figura 2.21.

Intersecţia – produsul a două automate finite


Fie două automate A şi B cu limbaje L(A) şi L(B). Limbajul acceptat de produsul cartezian
AB al celor două automate este L(A)∩L(A). La produsul cartezian al celor două automate se
iau în considerare stări de la ambele automate (perechi de stări aşa cum sunt perechi de
elemente la produsul cartezian al mulţimilor). O stare (a,b) – pereche din cele două automate,
este starea acceptoare dacă amblele a şi b sunt acceptoare la automatele corespunzătoare.
Automatul produs P = AB va avea:
QP = QA  QB, q0P = (q0A , q0B), FP = FA  FB .
Cuvintele w acceptate de automatul produs P vor fi cele obţinute prin tranziţii extinse:
*A (q0A, w)  FA şi *B (q0B , w)  FB .
Reamintim că tranziţiia extinsă este o reprezentare a seriei de tranziţii prin care trece o
intrare w până la o stare acceptoare (trase de tranziţii şi stări pentru w acceptat –Definiţia 2.7).
Vom da mai jos un exemplu de produs AB a două automate A şi B.

1 1 0,1 0,1
0 0
0 1 2 P 0,1 I

A B
0

0,P 1,P 2,P

0 0
1 1 1 1 1 1
0 0
0,I 1,I 2,I
0

Figura 2.22 Două automate A, B şi produsul lor cartezian AB.

46
Exemplul 2.15 În Figura 2.22, automatul A acceptă toate şirurile cu cel puţin doi 0 iar
automatul B acceptă toate şirurile cu un număr par de simboluri. Se observă că la automatul
produs P=AB în Figura 2.22 jos, starea acceptoare este perechea (2, P) care reuneşte cele
două stări acceptoare de la automatele A şi B; tranziţiile reprezentate în cruce reacţionează
toate la 0.
Pentru că această abordare a intersecției nu va funcționa, în general, pentru NFA ar trebui
mai întâi transformat NFA în DFA echivalent și apoi să se aplice această construcție9.

Complementul
Fie automatul finit A cu alfabet Σ şi limbajul acceptat L(A)  Σ*; limbajul Σ* \ L(A) este şi
el acceptat de un automat finit – inversul automatului A. Complement este definit faţă de
„întreg‖, care aici este limbajul exhaustiv Σ*, iar „\‖ este operatorul diferenţă. La automatul
„complement A‖ se inversează stările acceptoare-neacceptoare.

Exemplul 2.16 În Figura 2.23, automatul DFA din stânga acceptă toate şirurile a căror
număr de simboluri este multiplu de 3; în dreapta complementul său, care nu acceptă şiruri cu
număr de simboluri multiplu de 3 (însă oricare celelalte).

Figura 2.23 DFA din stânga are inversul DFA din dreapta.

Ca şi în cazul intersecţiei, această construcţie nu funcţionează, în general, pentru NFA care


ar trebui întâi transformat în DFA echivalent pentru a obţine apoi inversul.

2.2 Automate cu stivă PDA (Push Down Automata)


Am văzut că un NFA are o capacitate limitată de memorie – doar pentru o singură stare,
cea curentă. Prin urmare, aceste automate nu pot recunoaște multe limbaje, de exemplu un
limbaj în care apar simbolurile a şi b de un număr egal de ori fiecare, adică în forma anbn.
Dacă la NFA se va adăuga memorie se va obţine o mașină mai puternică la care citirea
caracterelor se face unul câte unul din cuvântul w de intrare, se vor contabiliza în memorie
apariţii de interes ale caracterelor de intrare spre a fi apoi folosite în decizie (şir valid sau şir
invalid), iar ieşirea este valoarea logică: acceptare/neacceptare cuvânt w.

O stivă este o memorie LIFO (Last In First Out) în care se adugă (push) şi se scoate (pop)
câte o piesă de date (un simbol) – aşa cum la o stivă de farfurii în bucătărie se adaugă câte una
la spălare şi se scoate câte una la servire. Se poate citi doar simbolul din capul stivei, care
odată citit este eliminat. Stiva este „alimentată‖prin capul stivei şi „consumată‖ tot din capul
stivei. Capătul stivei este semnificat (în Figura 2.24) prin simbolul Z care, atunci când se află
în capul stivei spunem că stiva este goală (ε) – aşa cum este iniţal sau a ajuns în capul stivei
prin „consumare‖.

47
Figura 2.24 PDA şi specificarea tranziţiei între stări.

Un automat stivă PDA (Push Down Automaton) este, informal, un NFA plus o stivă. Se
presupune că stiva are o dimensiune nelimitată (memorie infinită). Funcţionarea unui PDA
(tranziţia între stări) depinde nu doar de simbolul de intrare (fie el şi ε) ci şi de starea stivei:
simbolul din capul ei şi operaţia asupra ei: push, pop sau nop (no operation)9.

2.2.1 Tranziţii de stare la PDA


Pentru partea de automat finit propriu-zisă se vor folosi diagrame de stare similare cu cele
de la NFA, doar că tranziţiile sunt specificate în plus cu operaţia în legătură cu stiva (Figura
2.24 dreapta), astfel va apare tripletul: („intrare‖ - 0, „simbol cap-stivă‖- x, „operaţie‖).

Figura 2.25 Diagrama de stare pentru PDA ce recunoaşte limbajul 0n1n.

Exemplul 2.17. Cel mai uzual exemplu pentru prezentarea PDA este limbajul 0n1n: cu
Σ={0, 1}, cu diagrama de stare în Figura 2.25 şi cu evoluţia stărilor în Tabel 2.1pentru 0313.

simbol intrare stare rezultat stivă


(start citire şir) q0 ε (goală)
0 q0 0
0 q0 00
0 q0 000
1 q1 00
1 q1 0
1 q1 ε (goală)
(sfârşit şir) q2 ε (goală)

Tabel 2.1 Evoluţia stărilor şi stivei funcţie de şirul de intrare – exemplu 000111 = 0313.

48
Concret, dacă la tranziţia de la q0 la q1 avem specificat pe tranziţie (1, 0, pop) aceasta va
avea loc doar dacă simbolul de intrare ar fi 1 ŞI în capul stivei ar fi 0 – care va fi extras pop;
capul stivei este indicat de săgeata Figura 2.24. O tranziţie depinde de starea stivei sau nu:
dacă stiva este goală în locul simbolului x vom pune ε iar dacă stiva nu contează vom pune 
(„orice simbol‖) – adică tranziţia are loc indiferent de starea stivei (de simbolul din capul ei).
În Figura 2.25 starea q0 este cea în care se acumulează 0-uri din 0n1n și foloseşte stiva cu
push pentru a le memora (contabiliza). Odată ce la intrare apare un 1, are loc tranziţia la starea
q1, în care se citesc 1-uri și cu fiecare 1 se scoate (pop) câte un 0 din stivă. Dacă stiva devine
goală și s-au terminat de citit simboluri la intrare (sfârşit şir), atunci se trece la starea de
acceptare q2. În Tabel 2.1 se arată stările automatului și ale stivei pentru intrarea 000111.
Presupunem că avem acum șirul de intrare 10. Se începe în q0, dar nu există nicio tranziție
pentru q0 la o intrare 1, astfel că se ajunge la o stare „coş‖ iar șirul nu va fi acceptat.
Să presupunem că avem șirul de intrare 011. Din starea q0, se pune (push) un 0 în stivă, se
trece la q1 și folosind intrarea 1 ce urmează, se scoate (pop) acel 0, golind astfel stiva. Apare
acum încă un 1 la intrare dar nu se poate folosi tranziția buclei pe q1 de forma (1, 0, pop)
deoarece necesită un 0 în capul stivei şi stiva este acum goală – deci nu poate avea loc
tranziţie către q2, astfel că automatul (care este un NFA) trimite la starea „coş‖; de fapt, chiar
dacă stiva fiind goală (ε) ar avea loc tranziţia (ε,ε,nop) la q2, în această stare nu există nici o
specificare ce se face la intrarea 1 deci oricum se ajunge la starea „coş‖. Astfel șirul nu este
acceptat.

Exemplul 2.18. Un alt exemplu specific pentru PDA este cel care acceptă un limbaj cu
palindroame – cuvinte care se pot citi şi înainte şi înapoi la fel („capac‖, „001100‖) – pe care
un NFA nu le poate „recunoaşte‖.

Figura 2.26 Diagrama de stare pentru PDA ce recunoaşte limbaj „palindrom‖, Σ = {0, 1}.

Pentru a depista mijlocul şirului palindrom se introduce simbolul #, astfel că pentru


exemple precum 001#100 sau 1011#1101 automatul din Figura 2.26 va proceda astfel:
1. în starea q0 se pun în stivă – push (prin tranziţia buclă la q0) intări 0 şi 1 indifierent de
starea stivei , deci se vor memora în stivă toate cracterele intrate, astfel încât să putem
compara ulterior aceste simboluri cu omologii lor din a doua jumătate a șirului;
2. când apare la intrare simbolul #, acesta va provoca tranziţia (#, , nop) la starea q1, prin
care practic trecem la a doua jumătate a șirului – din nou, indiferent de starea stivei ;
3. în starea q1, se începe compararea simbolul de intrare curent cu simbolul de pe stivă,
adică tranziţia buclă va menţine starea q1 a PDA având loc doar dacă intarea şi
simbolul (curent) din capul stivei coincid (0 la 0 şi 1 la 1) care este extras - pop;

49
4. dacă cele două caractere „intrare curentă‖ – „cap stivă‖ nu sunt identice (nu se
potrivesc) PDA nu mai rămâne în starea q1 ci trece în starea „coş‖ – la oricare
nepotrivire, rămânând în această stare până la sfârşit şir de intrare
5. dacă în starea q1 s-a ajuns la sfârşit de şir cu toate caracterele intrate corespunzând cu
cele din stivă, atunci are loc tranziţia către starea q2 (vezi Figura 2.26) prin condiţia
dublă: „nimic la intrare‖ (primul ε) ŞI „stivă vidă‖ (al doilea ε) – stare a stivei care este
de fapt provocată de prezenţa acelui caracter Z (sfârşit stivă / capăt stivă) indicată în
Figura 2.24, ce a ajuns acum în capul stivei prin operaţiile pop.
Se observă că prin folosirea caracterului # introdus în mijlocul şirului de intrare putem să
obţinem un PDA care să recunoască doar cuvinte w palindrom care au număr par de caractere
|w| = par dar nu putem recunoaşte palindroame de tipul „capac‖ sau „1001001‖ adică la care
|w| = impar, pentru că nu avem cum plasa acest caracter # indicând „mijloc palindrom‖.

2.2.2 PDA deterministe şi nedeterministe


Pentru ca PDA din Exemplul 2.18 să accepte palindroame fără să se introducă un caracter
de „mijloc palindrom‖ #, ar trebui ca PDA să „ghicească‖ unde este mijlocul de şir – până la
care să introducă în stivă caractere de intrare şi de la care apoi să le compare pe cele ce
urmează cu cele din stivă. Evident, această operaţie de „ghicire‖ nu se poate implementa!
Putem însă schimba acest PDA pentru a accepta orice palindrom (de lungime pară dar şi
impară) fără să adăugăm simbolul # ci înlocuindu-l cu simbolul ε în tranziția de la q0 la q1,
adică introducând tranziţie-ε. Acest lucru face ca mașina să nu fie deterministă ci ne-
detereministă.
Cu alte cuvinte, PDA ilustrat în Exemplul 2.18 în care tranziţia q0 → q1 este (#, , nop) va
fi înlocuită cu (ε, , nop); În primul caz PDA va fi detereminst DPDA iar în al doilea caz ne-
determinist NPDA. Unii autori folosesc simbol  şi tranziţia (, , nop) pentru a evita
confuzia între tranziţii-ε şi cazurile „vid‖: ε pentru caracter intrare şi stivă.
La fel ca în cazul NFA, atunci când există tranziţii-ε se poate „ghici‖ dacă un şir este
acceptat sau nu prin faptul că se generează un arbore de evoluţie a tranziţiilor (vezi Figura
2.14) iar dacă măcar o cale în arbore duce la acceptarea şirului, automatul a rezolvat
problema. În cazul NPDA din exemplul nostru, se vor genera căi diverse (pentru fiecare din
caracterele de intrare) care să „încarce‖ stiva cu instanţele acestora şi apoi să o „descarce‖
citind caracterele rămase în şirul de intrare, astfel că doar una din aceste căi va reuşi să
„descopere‖ că şirul este un palindrom, la aceasta ajungându-se în starea q2; la restul se va
ajunge în starea „coş‖ pentru că nu se vor descoperi „potriviri‖ între caractere de intrare şi
cele din stivă.
Deci este nevoie de un PDA nedeterminist pentru limbaje ale palindroamelor; o mașină
deterministă nu va funcționa pentru acest tip de limbaje. Acesta este un domeniu în care PDA-
urile diferă de NFA și DFA – la care există o procedură care convertește orice NFA într-un
DFA, deci sunt echivalente. În general, orice poate face un NFA poate fi făcut și de către
DFA (echivalent). Dar în cazul PDA există unele NPDA (nedeterministe) care pot face
„recunoaşteri‖ pe care DPDA (deterministe) nu le pot face.
În timp ce limbajele acceptate de ambele DFA sau NFA sunt „limbaje obişnuite‖ (regular),
automatele pushdown PDA acceptă „limbaje independente de context‖ CFL (Context Free
Languages). În fapt, NPDA (nedeterministe) sunt strict mai puternice decât DPDA

50
(deterministe) şi de aceea modelul mașinii naturale pentru limbajele independente de context
este NPDA dar nu şi DPDA (care nu recunoaşte unele limbaje independente de context).

2.2.3 Descrierere formală a PDA


Nu există o descriere formală standard, privind PDA, astfel că în cele ce urmează vă
propun o combinaţie între reprezentarea formală în abordarea Jean Gallier12 şi forma explicită
în abordarea John Watrous13, cu abordare proprie a construcţiei formalismului pentru §2.2.4.
După cum am arătat mai sus, PDA constă dintr-o bandă citită la intare (conţinând şirul de
caractere w) o memorie (posibil infinită) de tip stivă, şi o unitate de control de tip automat
finit nedeterminist.
Definiţia 2.8 Un automat de tip stivă PDA (pushdown automaton) este 7-tuplul:
P = (Q, Σ, Γ, δ, q0, Z0, F ), unde
• Q este o mulţime finită de stări;
• Σ este o mulţime finită de simboluri numită alfabetul intrărilor;
• Γ este o mulţime finită de simboluri numită alfabetul stivei;
• q0 ∈ Q este starea iniţială (de start)
• Z0 ∈ Γ este simbolul de iniţiere a stivei (marcaj capăt stivă);
• F ⊆ Q este mulţimea finită de stări acceptoare;
• δ: Q × (Σ ∪ {ε}) × Γ → P(Q × Γ∗) este funcţia de tranziţie.

Spre deosebire de NFA la PDA avem de a face cu două tipuri de alfabete:


• Σ care este un alfabet de simboluri ce apar în şirul de intrare, de exemplu Σ ={0,1};
• Γ care este un alfabet de operaţiuni asupra stivei dar conţine şi simboluri asociate
celor de intrare (ce pot fi identice cu acelea dar pot fi alte simboluri care le reprezintă pe
acelea - doar pentru stivă) şi care vor fi puse (push) şi scoase (pop) din stivă.
Pentru exemplificarea alfabetului Γ, să reprezentăm operaţiile asupra stivei astfel:
push ≡  (pune), pop ≡  (scoate), nop ≡  (nici-o acţiune),
iniţializare stivă ≡ Z0, verificare/indicare stivă vidă ≡ ε,
adică reprezentăm operaţiile ca simboluri în sub-alfabetul stivei ΓOP = {, , , Z0, ε}.
Simbolurile asociate intrărilor ΓIN = {x, y} corespund fiecărui element al alfabetului de intrare
Σ, astfel: x ↔ 0, y ↔ 1, adică în stivă nu se încarcă neapărat simboluri din Σ ci unele asociate
acestora; în cazul comun x ≡ 0, y ≡ 1. Cele două sub-mulţimi de simboluri reunite constituie
alfabetul stivei Γ = ΓIN ∪ ΓOP, adică:
Γ = { x, y} ∪ {, , , Z0, ε},
Relativ la simbolurile x, y asociate intrărilor se remarcă faptul că în cazul în care PDA trebuie
să recunoască şiruri de tip anbn se poate folosi un singur simbol x care este un marcaj „pus‖ în
stivă (push) la contabilizarea de simboluri a, marcaj ce va fi apoi „scos‖ (pop) din stivă pe
măsura citirii de simboluri b; deci se poate folosi un singur simbol şi nu două.
Reprezentarea formală a acţiunii asupra stivei se face prin perechea:
z = (in, op), z ∈ ΓIN × ΓOP,
adică perechea: in „simbol asociat intării‖ şi op „simbol operaţie pe stivă‖, cu in, op ∈ Γ.

12
Jean Gallier, Andrew Hicks, The Theory of Languages and Computation, University of Pennsylvania, 2006
13
John Watrous Introduction to the Theory of Computing - Lecture notes, University of Waterloo, 2020

51
Dăm mai jos exemple de şiruri valide şi invalide de perechi z pentru x ≡ 0, y ≡ 1.
Şiruri valide:
cazul (0, )(1, )(1, )(0, )(0, )(0, ), apoi cazul (0, )(1, )(1, )(0, )(0, ).
care ar produce următoarele actualizări ale stivei:
ε → 0 → 10 → 0 → 00 → 0 → ε respectiv ε → 0 → 10 → 0 → 00 → 0,
adică în primul caz se încarcă şi se descarcă stiva parcurgând toate simbolurile şirului de
intrare până stiva rămâne goală (un caz de acceptare), respectiv, în al doilea caz, se încarcă şi
se descarcă stiva parcurgând toate simbolurile şirului de intrare fără a lăsa stiva goală (un caz
în care mai sunt caractere de citit la intrare sau un caz de neacceptare). La acceptare şir de
intrare w, ultima pereche este z = (ε, ) – la funcţionarea PDA din Figura 2.25 şi Figura 2.26.
Şiruri invalide:
(0, )(1, )(0, )(0, )(1, )(0, ),
(0,)(1, )(1, )(0, )(0, )(0, )(1, ).
unde în primul caz se încearcă la pasul 3 să se scoată din stivă 0 când în capul stivei este 1 pus
anterior (mai departe pot fi şi alte situaţii invalide dar şirul de intrare oricum nu are condiţii de
acceptare); în cazul doi, se încearcă la ultimul pas să se scoată din stivă 1 deşi stiva era goală.

Funcţia de traziţie δ ia valori în mulţimea putere a produsului cartezian P(Q × Γ∗), adică
mulţimea stărilor în relaţie (produs cartezian) cu submulţimi posibile ale alfabetului stivei
(atenţie, doar cele valide!) – pentru cazul unui DPDA. În cazul unui NPDA nedeterminismul
prin care apar mai multe căi de tranziţie de la o stare anume către alte stări (aşa cum s-a arătat
la §2.2.2), funcţia de tranziţie ia valori în mulţimea putere P(Q* × Γ*).
O tranziţie este descrisă în forma:
(q, γ) ∈ δ(p, a, z)
unde p, q ∈ Q, z ∈ Γ × Γ şi a ∈ Σ ∪{ε}, adică relaţia de mai sus indică o tranziţie de la
IN OP

starea p (termen dreapta) la starea q (termen stânga), pe baza simbolului de intrare curent a ŞI
pe baza perechii curente z relativ la stivă – pereche formată din operaţie op şi simbol in din
stivă pe care aici îl notăm generic γ. Se observă că γ este simbolul nou care se va afla în capul
stivei şi apare ca rezultat alături de starea nouă q.
O tranziţie de forma:
(q, γ) ∈ δ(p, ε, z)
este numită tranziţie-ε (se observă că este independentă de intrarea curentă a).
Intuitiv, PDA parcurge şirul de intrare caracter cu caracter de la stânga la dreapta, citind
simbolul de intrare curent şi făcând tranziţii de stare funcţie de acesta şi de simbolul din capul
stivei, după care actualizează capul stivei ( - pune sau  - scoate un simbol) şi în final:
(a) mută capul de citire a intrărilor pe următoarea poziţie în şirul de caractere sau
(ε) nu mută capul de citire atunci când este o tranziţie-ε (are loc independent de intrare).

Modul de funcţionare al PDA este explicat în termeni de „Descrieri Instantanee‖ ID


(Instantaneous Descriptions), prin care se prezintă tripletul la un moment dat al PDA:
(p „starea curentă‖, u „sirul de caractere rămas de citit‖,  „starea/încărcarea stivei‖):
(p, u, ) ∈ Q  Σ*  Γ*
şi apoi prin relaţia cauzală ⊢ (deducerea) între două descrieri instantanee ID.

52
Definiţia 2.9 O relaţie de deducere între două descrieri instantanee ID ale PDA este SAU
EXCLUSIV între cele trei cazuri de mai jos:
(a) tranziţie (q, γ) ∈ δ(p, au, z) – tranziţie push la intrare cu deducerea:
(p, au, ) ⊢ (q, u, γ),
unde a este simbolul de intrare curent care este „consumat‖ şi u restul de şir rămas de citit, iar
z este acţiunea asupra capului stivei cu γ simbolul nou din capul stivei şi  restul stivei
(implicit se consideră deci operaţia  - push);
(ε) tranziţie (q, γ) ∈ δ(p, ε, z) – tranziţie-ε push cu deducerea:
(p, u, ) ⊢ (q, u, γ),
unde se observă în termenul stânga că avem doar restul şirului de intrare u (nu contează
simblul curent a – tranziţia nu „consumă‖ din intrare) însă poate apare o modificare a stivei:
cu γ simbolul nou pus în capul stivei peste restul  existent deja (implicit operaţia  - push);
() tranziţie (q, ) ∈ δ(p, au, z) – tranziţie pop cu deducerea:
(p, au, γ) ⊢ (q, u, ),
unde se observă că la noua stare q nu contează cum va fi stiva (de aceea  - orice simbol
rămas în capul ei) dar tranziţia se peterece ca urmare a citirii (şi „consumării‖) simbolului
curent a din şirul de intrare şi care corespunde simbolului curent γ din capul stivei ce va fi
„consumat‖/extras prin acţiunea perechii z curente (din funcţia δ), după care stiva rămâne
(doar) cu restul  ce era în ea după extragere (în termenul din dreapta).

2.2.4 Definirea acceptării unui şir de caractere de către PDA


Să facem acum descrierea formală la acceptarea unui cuvânt de către PDA.
Fie un automat de tip stivă P = (Q, Σ, Γ, δ, q0, Z0, F) şi un cuvânt w ∈ Σ*, PDA P acceptă
şirul de caractere w = a1 a2 ... ai ... an cu ai∈Σ dacă există o secvenţă de stări r0, r1, ... rj, ... rm
cu rj ∈ Q şi o secvenţă de perechi (op, in) relativ la stivă z1, z2, ... zj, ... zm , cu zj ∈ Γ ∪ {ε} şi
se îndeplinesc condiţiile:
i. r0 = q0 şi rm ∈ F,
ii. şirul de simboluri z1, z2, ... zj, ... zm este valid,
iii. prin parcurgerea şirului z1, z2, ... zm-1 se consumă întreg cuvântul w,
iv. după citirea simbolului an al w perechea zm = (ε, ).
Textual, prima condiţie (dublă) este ca maşina să aibă prima stare cea de start şi ultima
stare o stare acceptoare. A doua condiţie este ca operaţiile în stivă să constituie un şir valid
indiferent dacă se referă la tranziţii datorate intrărilor sau tranziţii-ε. A treia şi a patra condiţie
impun ca prin parcurgerea şirului de operaţii asupra stivei să se fi citit (consumat) întreg
cuvântul w iar după ultimul caracter din şirul w şi după orice tranziţii-ε posibile, stiva să fie
goală şi nici o operaţie de efectuat asupra stivei.
Automatele PDA acceptă limbaje independente de context CFL (Context Free Languages)
care sunt o clasă mai largă de limbaje decât cele obişnuite (regulate).

2.3 Maşini cu stări finite şi ieşiri – Traductori


Automatele prezentate în subcapitolele precedente nu aveau o ieşire propiru-zisă,
structurată- adică un şir de caractere; DFA, NFA, DPDA, NPDA prezentau toate o decizie:

53
Da sau Nu – şirul de intrare era acceptat (valid) sau nu. Putem spune doar că „ieşirea‖ lor era
o valoare de adevăr.
Automatele pe care le prezentăm în continuare se numesc traductori, pentru că ele pot
„traduce‖ ori un limbaj de intrare (şir de caractere cu anumite simboluri – un alfabet anume)
într-un limbaj de ieşire (şir de caractere cu alte simboluri – alt alfabet) – cum sunt maşinile
Mealy; sau pot „traduce‖ o anume succesiune de stări într-un limbaj de ieşire (şir de caractere
cu simboluri – peste un alfabet) cu succesiune corespondentă – cum sunt maşinile Moore.
De remarcat că ieşirile Traductorilor sunt simboluri care – deşi pot fi asociate unor alfabete
de ieşire, pot reprezenta comenzi specifice pentru controlul (comanda) unor dispozitive fizice,
de exemplu pentru comada unui robinet de încarcare cu apa a unui bazin: „robinet deschis
parţial‖, „robinet deschis complet‖, „robinet închis‖.

2.3.1 Maşini Mealy


Automatele Mealy sunt automate de intrare/ieșire, la care tranzițiile sunt etichetate prin
„evenimente‖ de forma „eveniment de intrare / eveniment de ieşire‖ – vezi Figura 2.27,
mulţimea evenimentelor de ieșire Eout nu trebuie să fie aceași ca a evenimentelor de intrare
Ein. Interpretarea unei tranziții ei/eo de la starea x la starea y se face astfel: când sistemul este
în starea x, dacă automatul „primește‖ intrare evenimentul ei, va face o tranziție la starea y și
în acel proces va „emite‖ evenimentul de ieșire eo.

Figura 2.27 Automat de comunicaţie semi-duplex.

Exemplul 2.19. Se prezintă în Figura 2.27 un automat de comunicaţie semi-duplex prin


care se transmit mesaje pe un singur canal de comunicaţie între două entităţi (E1, R1) şi (E2,
R2) care pot emite mesaje dar nu simultan pentru că împart acelaşi canal de comunicaţie aşa
cum de exemplu are loc comunicaţia în LAN (prin cablu sau WIFI).
Entitatea 1 emite (vezi săgeata de start!) prin emiţătorul E1 un mesaj şi aşteaptă
confirmarea de primire p2 a mesajului de către entitatea 2, entitatea 1 intrând în starea de
aşteptare Emi1; dacă după o durată pre-stabilită nu a recepţionat semnalul p2=„mesaj primit
de către 2‖, are loc tranziţia buclă de „time-out‖ to/e1 către Emi1 şi totodată se dă comanda e1
către emiţătorul E1 pentru a re-emite mesajul (care probabil se pierduse). Primirea confirmării
p2 de recepţie a mesajului este însoţită de comanda de intrare a receptorului R1 în stare de
recepţie, şi prin tranziţia cu aceeaşi etichetă p2/r1 se trece de la starea Emi1 la starea Rec1.

54
Pe partea cealaltă, la entiatatea 2, se trece în starea Emi2 prin care se comandă emiţătorului
E2 emisia mesajului către entitatea 1 şi apoi se aşteaptă (la rândul său) confirmarea p1 de
„primire a mesajului de către R1‖; dacă după o perioadă de „time-out‖ această confirmare nu
a sosit, se re-emite mesajul de către E2 prin comanda e2 din bucla to/e2. După confirmare,
entiatea 2 trece în starea de recepţie Rec2 aşteptând mesaj emis de către E1 ş.a.m.d.
Se observă în Exemplul 2.19 că acest automat face tranziţii între stări la o anumită intrare
dar execută şi câte o ieşire la fiecare. Alfabetul de intrare este Σ = {p1, p2, to} iar alfabetul
de ieşire este O = {e1, e2, r1, r2}.
Definiţia 2.10 Un automat Mealy este 6-tuplul:
M = (Q, Σ, O, δ, , q0), unde:
• Q este o mulţime finită de stări;
• Σ este o mulţime finită de simboluri numită alfabetul de intrare;
• O este o mulţime finită de simboluri numită alfabetul de ieşire;
• δ: Q × Σ → Q este funcţia de tranziţie;
• : Q × Σ → O este funcţia de ieşire;
• q0 ∈ Q este starea iniţială (de start).
De remarcat că funcţia de ieşire ataşează un simbol (din alfabetul de ieşire) la fiecare
tranziţie, pentru un simbol de intrare anume.
Dacă ar fi să considerăm intrările preluate de pe o bandă de intrare, Maşina Mealy ar fi
dotată şi cu o bandă de ieşire, unde se înscriu simbolurile de ieşire.

Aşa cum la NFA s-a definit tranziţia extinsă, se poate defini o extensie a funcţiei de
ieşire λ̂ către un şir de ieşire (nu doar pentru un caracter de ieşire), corespunzătoare unui şir
de intrare dat. Formal14, această funcţie de ieşire extinsă va fi:
λ̂ : Q × Σ∗ → O∗
definită prin: λ̂ (q, ε) = ε, şi λ̂ (q, xa) = λ̂ (q, x) λ(δ̂ (q, x), a), pentru toate q∈Q, x∈Σ∗ şi
a∈Σ. Adică, dacă şirul de intrare x = a1a2 · · · an este aplicat în starea q a maşinii Mealy,
atunci secvenţa de ieşire va fi:
λ̂ ( q, x) = λ(q1, a1) λ(q2, a2) · · · λ(qn, an)
unde q1 = q şi qi+1 = δ(qi, ai), pentru 1 ≤ i < n, cu |x| = | λ̂ (q, x)|.

Exemplul 2.20. Fie automatul My_1 din Figura 2.28, cu Q = {q0, q1, q2}, Σ = {a, b},
O={0, 1} iar funcţia de tranziţie δ şi funcţia de ieşire λ definite prin Tabel 2.2.

Figura 2.28 Automat Mealy My_1 de conversie litere-cifre, cu „1 la perechi ab‖ .

14
D. Goswami, K. V. Krishna, Formal Languages and Automata Theory, 2010

55
δ a b λ a b
q0 q1 q0 q0 0 0
q1 q1 q2 q1 0 1
q2 q1 q0 q2 0 0

Tabel 2.2 Funcţii de tranziţie δ şi de ieşire λ pentru automatul My_1.

La automatul My_1, pentru un şir de intare baababa ieşirea este 0001010, fiindcă la
apariţia perechii ab, la intrarea My_1 acesta dă la ieşire 1 iar în rest 0.

Automatele Mealy pot fi privite ca automate standard în care evenimentele sunt sub formă
de intrare/ieșire. Adică, vedem mulţimea E de evenimente ca mulţimea tuturor etichetelor
asociate intrărilor şi ieșirilor automatului Mealy. În acest context, limbajul generat de automat
va fi setul tuturor șirurilor de intrare/ieșire care pot fi generate de automat.

2.3.2 Maşini Moore


Automatele Moore sunt o clasă adecvată de modele pentru sisteme de control industrial sau
aparatură casnică, unde ieșirea este corespunzătoare unei stări a automatului ca urmare a citirii
senzorilor pentru sistemul aflat într-o anumită stare fizică.

Figura 2.29 Automat Moore pentru controlul debitului

Exemplul 2.21. Un automat Moore pentru controlul umplerii unui bazin într-o instalaţie
industrială ar avea ca ieşire debitul de fluid (NUL, MEDIU, MARE) – care este şi indicat de
senzorul de debit ataşat instalaţiei, iar ca stări are gradul de închidere-deschidere robinet
(etichete în cercuri: „Robinet închis‖, „Robinet parţial deschis‖, „Robinet deschis‖) iar ca
intrări comenzile deschide_ / închide_robinet provenite din exterior (indicate ca etichete la
săgeţi). Tranziţiile sunt efectuate funcţie de intrări, iar starea automatului (deci a robinetului)
va produce şi ieşirea corespunzătoare (mărimea debitul de fluid); deci ieşirile sunt rezultat
(doar) al stărilor respective.

56
Figura 2.30 Automat Moore (stânga) şi echivalentul Mealy (dreapta).

Un automat Moore se poate transforma în echivalentul său Mealy – care este o superclasă a
acetui tip de automate. În Figura 2.30 se prezintă în partea stângă un automat Moore cu ieşiri
01, 02, 03 (indicate îngroşat în figură) şi în partea dreaptă automatul Mealy echivalent.
Conceptele de stare și eveniment de ieșire pot fi utile în construirea modelelor unor
Sisteme cu Evenimente Discrete DES (Discrete Event Systems), iar acestea pot fi întâlnite în
practică la diverse componente electro-mecanice care interacționează între ele (de exemplu,
sisteme de fabricație, sisteme de control al proceselor, unităţi de încălzire şi aer condiţionat).
Atât maşinile Moore cât şi maşinile Mealy sunt adecvate ca modele ale acestora.

57
3 Limbaje formale şi gramatici

Ori de câte ori interacţionăm cu un calculator sau cu un telefon mobil se foloseşte un


limbaj de comunicare anume – ori constituit din şiruri de caractere ori dintr-o înşiruire de
„apăsări‖ pe pictograme, limbaj care are un set de reguli simple şi fixe – o sintaxă. Cu atât
mai mult, scrierea unui program folosind un limbaj de programare oarecare (C, Java, HTML,
XML) respectă reguli stricte de înşiruire a caracterelor – deşi suntem conştienţi că acel limbaj
este mai simplist însă mai precis decât limbajul natural.
Sintaxa unui limbaj priveşte setul de simboluri folosit în acel limbaj – alfabet (tipurile de
caractere – de exemplu latine sau chirilice) şi ordinea de principiu a cuvintelor (şirurilor de
caractere): subiect, predicat, complement. Însă este posibil ca o expresie în limbajul dat să fie
corectă sintactic dar semantic incorectă.
Semantica se referă la înţelesul expresiei (propoziţiei), care ţine de logică şi de conţinut al
mesajului (de) transmis. De exemplu, ―fata iubeşte băiatul‖ are un înţeles, pe când ―băiatul
iubeşte fata‖ are un altul. Aici intervine gramatica, care prin legăturile între cuvinte şi acordul
între ele, corespunzător înţelesului vizat, aduce consistenţă (corectitudine) mesajului; în
scopul preciziei, părţile de cuvânt şi combinarea lor respectă reguli morfologice specifice
părţilor de cuvânt respective (substantiv – acord şi declinare, verb – conjugare şi timp etc.).
Gramatica – în sensul comun, este setul de reguli sintactice şi morfologice prin folosirea
cărora se aduce consistenţă exprimării mesajului dorit; de fapt, o gramatică generează un
limbaj cu specificitatea sa – aşa cum în germană verbul este adesea la sfârşit şi nu imediat
după subiect (în predicat) aşa cum este în engleză.
Precum în exemplele date mai sus, ordinea cuvintelor este deci foarte importantă pentru a
se obţine înţelesul dorit mesajului, apoi regulile de acord între cuvinte şi în cele din urmă
logica de combinare a acestora. Totuşi, la o gramatică elaborată (cu reguli sintactice şi
morfologice cuprinzătoare) se poate ca ordinea cuvintelor să nu aibă importanţă; în limba
latină exemplul dat mai sus ar fi ―puella amat puerum ‖, unde puella înseamnă ―fata‖ dar
schimbând locul acesteia în formele ―puerum puella amat‖ sau ―amat puella puerum‖ sau
―amat puerum puella‖ sau ―puella puerum amat‖, înţelesul rămâne acelaşi datorită acordului
explicit la ―puerum‖ – particula ―-um‖ indică obiectul verbului.
Limbajele naturale sunt cele vorbite curent de oameni: româna, engleza, germana. Nu au
fost proiectate de oameni (deși oamenii încearcă să le impună o anumită ordine); ele au
evoluat natural şi s-au transformat din unele în altele – în timp ce unele au şi dispărut. Deşi au
mare expresivitate şi sunt uşor de învăţat de oameni, aceste limbaje au ambiguitate şi lungime
mare a expresiei (frazei) când se doreşte a le da precizie; germana este o limbă „precisă‖, cu
fraze complicate şi lungi, încât Mark Twain spunea „eternitatea a fost inventată ca să învăţ eu
limba germană‖. Dar cunoaşterea unui limbaj nu înseamnă cunoaşterea tuturor propoziţiilor
din limbaj (mulţime infinită) ci este cunoaşterea unei reprezentări finite: alfabet (finit),
formarea cuvintelor (şi semantica lor), reguli de combinare a cuvintelor (gramatica).
Limbajele formale sunt limbaje care sunt concepute de oameni pentru aplicații specifice.
De exemplu, notația pe care o folosesc matematicienii este un limbaj formal care este deosebit
de concis şi precis în descrierea relațiilor dintre numere și simboluri. Chimiștii folosesc un
limbaj formal pentru a reprezenta structura chimică a moleculelor. Și cel mai important:

58
limbajele de programare sunt limbaje formale care au fost concepute pentru a exprima
calcule. Limbajele formale au o sintaxă strictă, o semantică ne-ambiguă şi pot fi prelucrate de
o maşină, însă nu au expresivitate şi necesită efort de învăţare şi cunoaştere a contextului (de
aplicare).
Tematica „Limbaje formale‖ constituie astfel modalităţi standard de a trata definirea,
caracterizarea și validarea comunicării bazate pe text între om și calculator, precum și între
calculatoare. Nu doar că astfel de tip de comunicare este aproape omniprezent în lumea de
astăzi, dar formalizarea problematicii acesteia ne permite să pătrundem fără dificultăţi în
unele dintre domeniile de bază ale informaticii teoretice – cum ar fi gramatica formală,
legătura cu teoria automatelor și complexitatea computațională.
Teoria limbajelor formale este considerată ca fiind o dezvoltare a contribuţiilor lingvistului
Noam Chomsky în anii 1950, când a încercat să ofere o caracterizare precisă a structurii
limbajelor naturale, adică să definească sintaxa limbajelor folosind reguli matematice simple
și precise. Mai târziu s-a constatat că sintaxa limbajelor de programare poate fi descrisă
folosind unul dintre modelele lui Chomsky numite gramatici independente de context.
La scurt timp după apariția calculatoarelor electronice moderne, oamenii de ştiinţă și-au
dat seama că toate formele de informații – fie că sunt numere, nume, imagini sau unde sonore
– pot fi reprezentate ca șiruri. Apoi, colecțiile de șiruri – cunoscute sub numele de limbaje, au
devenit esențiale pentru informatică.
Acest capitol face o introducere în problematica proprietăților matematice fundamentale
ale limbajelor (formale) şi ale gramaticilor generatoare de limbaje. Orice limbaj de
programare de la Fortran la Java poate fi descris cu precizie printr-o gramatică. Mai mult,
gramatica ne permite să scriem un program (numit analizor de sintaxă într-un compilator)
pentru a determina dacă un șir de instrucțiuni este corect din punct de vedere sintactic în
limbajul de programare respectiv.

3.1 Limbaje – definiţii şi proprietăţi


Orice limbaj natural este exprimat în scris printr-o mulţime finită de simboluri (litere,
cifre, semne de punctuaţie, etc.) care se numeşte alfabet. Sunt cunoscute diferenţele de
pronunţie a unor grupuri de litere în diferite limbi, deşi literele sunt aceleaşi; cu atât mai mult
înţelesul cuvintelor este diferit de la o limbă la alta – deşi toate sunt grupuri de litere ce
desemnează obiecte, acţiuni, etc. Limbajul matematic este primul care s-a dorit a fi
independent de limbajul unui popor şi foloseşte expresii constituite din simboluri care pot fi
înţelese de oricine are o educaţie minimală în domeniul matematicii.
Limbajele formale îşi propun prin revers: să ataşeze şirurilor de caractere (desemnând
cuvinte, propoziţii, şiruri de comenzi mecanice) proprietăţi matematice prin care să se
caracterizeze diferite limbaje şi să se poată manipula aceste limbaje în comunicarea omului cu
maşini şi între maşini. Astăzi, cele mai multe maşini sunt electro-mecanice dar în viitor ele
vor fi cuantice, bio-mecanice sau în cine ştie ce forme tehnologice ale viitorului, însă
abordările teoretice de limbaj vor fi cu siguranţă aceleaşi.

3.1.1 Simbol, alfabet, cuvânt


Definiţia 3.1 Un simbol este o entitate abstractă (adică simbolul abstractizează o idee) şi
este reprezentat grafic şi/sau printr-un cod numeric anume.

59
Literele alfabetului latin, cifrele şi alte simboluri, au fost reprezentate codificat şi înscrise
în tabele precum Morse, Baudot, ASCII. Noul standard mondial este un alfabet numit
UNICODE, care furnizează simboluri pentru toate limbile lumii, până acum incluzând peste
38.000 de simboluri. Cel mai important aspect ale limbajelor formale este că ele pot fi
modelate/reprezentate folosind doar simbolurile 0 şi 1, adică alfabetul {0,1}.
Literele latine reprezintă (de obicei) sunete vorbite, pe când pictogramele chinezeşti
reprezintă concepte şi idei. Dacă punem la socoteală şi semnele de punctuaţie şi alte simboluri
(matematice, cărţi de joc, etc.) simbolurile se vor numi generic caractere.
Definiţia 3.2 Un alfabet este o mulţime finită de simboluri, constituit din caractere
suficiente descrierii unui context de comunicare/comandă/calcul anume.
Vom nota un alfabet cu Σ şi va fi specificat ca mulţime indicată explicit sau prin
proprietăţile elementelor sale. (v. §1.2 ). Exemple:
Σ = {0, 1}
Σ = {a, b, c, ... z}
Σ = {x | x = vocală}
Definiţia 3.3 Un cuvânt sau şir de caractere este o secvenţă finită de simboluri ale unui
alfabet Σ, cu un început (nemarcat) şi un „sfârşit de şir‖ marcat (uzual, prin NULL).
Cuvântul este o secvenţă x = a1a2 ··· an de simboluri în care ordinea acestora este
importantă (esenţială) faţă de mulţimi, la care ordinea nu contează – cum nu contează atunci
când se explicitează alfabetul Σ din care un cuvânt preia simboluri. Astfel, pentru cuvântul x
se poate defini cuvântul oglindă xR = anan-1 ··· a1 adică se inversează ordinea caracterelor.
Palindroamele sunt cuvinte sieşi oglindă x = xR .
Lungimea cuvântului este numărul de simboluri pe care le conţine; deşi este o secvenţă,
cuvântul este caracterizat prin cardinalitatea sa (ca şi la o mulţime) care indică lungimea
acestuia. Exemplu: |abc| = 3, |abba| = 4, |01001| = 5.
Cuvântul de lungime 0 |w| = 0 este notat ε - şirul vid (constituit doar din NULL): | ε | = 0.
Se defineşte cardinalitatea unui cuvânt w față de un simbol a  Σ şi notată |w|a numărul de
apariții ale lui a în w. De exemplu, |abc|a = 1, |aabba|b = 2.

Definiţia 3.4 Fie două şiruri x=a1a2 · · · an şi y=b1b2 · · · bm. Concatenarea lor este notată xy
sau x.y şi este şirul a1a2 · · · anb1b2 · · · bm cu NULL - sfârşit de şir, ce apare doar după bm.
Proprietăţi ale concatenării şirurilor. Fie şirurile de caractere: w1, w2, w3:
– |w1.w2| = | w1| + | w2| ;
– ∀ a∈ Σ : | w1 . w2|a = | w1|a + | w2|a ;
– (w1 . w2) . w3 = w1.( w2 . w3) (concatenarea este asociativă) ;
– w.ε = ε.w = w (ε este element neutru pentru concatenare) .
Prin concatenarea multiplă de n ori obţinem şirul de exponent n adică wn; iar w0 = ε.

Definiţia 3.5 Mulţimea tuturor şirurilor posible peste un alfabet Σ este notată Σ+ iar dacă
include şi şirul vid ε este notată Σ* şi este denumită închiderea stea (Kleene star).
Atât Σ+ cât şi Σ* sunt mulţimi infinite pentru că sunt închideri care se obţin astfel:
∀ ar fi u  Σ+ , u  Σ*, ∃ x  y | u = xy .
Mulţimea fără nici un şir este notată:  - mulţimea vidă.

60
3.1.2 Limbaje şi operaţii cu limbaje
Definiţia 3.6 O mulţime L de cuvinte w peste un alfabet Σ se numeşte limbaj.
Fiind mulţime, un limbaj se poate descrie prin specificarea elementelor (cuvintelor) sale
sau prin indicarea proprietăţilor pe care acestea le prezintă. Limbajele pot fi finite sau infinite.
Exemplul 3.1. Fie limbajele LM = {01, 11, 0110} şi LP = {0n1n | n ≥ 0} peste alfabetul
binar Σ={0, 1}. LM are trei cuvinte - este finit, LP este infinit. Şirul 01 este cuvânt al ambelor
limbaje, iar cuvântul 11 se găseşte în LM dar nu şi în LP, acesta din urmă prezentând cuvinte
cu multiple apariţii ale elementelor din alfabetul Σ.

Dacă prin An se desemnează mulţimea tuturor şirurilor de lungime n, atunci putem spune
că un limbaj va conţine cuvinte cu diferite lungimi, fiind preluate din mulţimile:
 A0 mulţimea şirului de lungime 0: A0 = {ε}, diferită de mulţimea vidă  = {}.
 A1 = A, mulţimea de şiruri de lungime 1 (simbolul însuşi).
 An prin care notăm mulţimea tuturor şirurilor de lungime n.
 A* prin care notăm mulţimea tuturor şirurilor de orice lungime.
 A+ prin care notăm mulţimea şirurilor de orice lungime dar ne-vide.
Exemplul 3.2. Fie alfabetul A = {a, b}, cazurile de mai sus vor fi:
  = {}, || = 0 – deci zero elemente;
 A0 = { ε }, | A0 | = 20 – deci 1 element;
 A1 = {a, b}, | A1 | = 21 – deci 2 elemente;
 A2 = {aa, ab, ba, bb}, | A2 | = 22 – deci 4 elemente;
 A3 = {aaa, aab, aba, abb, baa, bab, bba, bbb}; | A3 | = 23 – deci 8 elemente;
 A+ = {a, b, aa, ab, ba, bb, aaa, ...}, | A+ | = 2N = ∞ – mulţime infinită;
 A* = { ε, a, b, aa, ab, ba, bb, aaa, ...}=A+∪ {ε}, |A*| = 2N0 = ∞ – mulţime infinită.
Un limbaj L peste un alfabet A este o submulţime a A*; pentru L avem:
 Ln - limbajul cu cuvinte wi ∈ L, fiecare cuvânt conţinând exact n caractere din
alfabetul A – mulţime finită.
 L* - limbajul cu toate cuvintele posibile de orice lungime (inclusiv şirul de
lungime 0: ε) – mulţime infinită.
 L+ - limbajul cu toate cuvintele nevide posibile – mulţime infinită.
L* este numită închiderea Kleene a L sau Kleene star, însemnând ―orice peste A‖.

Fiind mulţimi, pentru limbaje avem operaţii cu mulţimi:


Fie L, L1 şi L2 limbaje definite peste alfabetul Σ. Operaţii pentru mulţimi:
– Uniunea: notată ∪ sau + obţine: L1 + L2 = {w | w  L1 ∨ w  L2 }
– Intersecţia: L1 ∩ L2 = {w | w  L1 ∧ w  L2 }
– Complementul: L = {w | wΣ* ∧ w  L}
Pentru limbaje putem avea însă şi alte operaţii decât cele pentru mulţimi:
– Concatenarea: L1. L2 = {w | ∃ u  L1, ∃ v  L2 : w = uv}
– Exponent: Ln = L.L...L (de n ori) = {w | ∃ u1, u2, ... un  L : w = u1 u2 ... un}
– Limbaj oglindă: LR = {w | ∃ u  L : w = uR }
– Închiderea ne-tranzitivă L+ = ⋃i>0 Li .

61
– Închiderea tranzitivă Kleene notată:
L* = ⋃i0 Li.
În particular L = Σ* , când se obíne mulţimea tuturor cuvintelor posibile peste alfabetul Σ.
Închiderea Kleene pentru un limbaj este mulţimea tuturor şirurilor ce pot fi formate prin
concaternarea a zero sau mai multe cuvinte din L.
De exemplu, L={0, 01} apoi LL={00, 001, 010, 0101} iar mulţimea infinită L* cuprinde
toate şirurile binare în care 1 este precedat de 0, dar şi cuvântul vid ε.
Pe de altă parte, închiderea ne-tranzitivă L+ ar însemna: mulţimea tuturor şirurilor ce pot fi
formate prin concaternarea a unul sau mai multe cuvinte din L, iar L* = L+ ∪ {ε}.

Proprietăţi ale operaţiilor pe limbaje. Fie L, L1, L2, L3 limbaje definite pe alfabetul Σ:
– L* =L++{ε};
– L1.(L2.L3) = (L1.L2).L3 ;
– L1.(L2 + L3) = (L1.L2) + (L1.L3) ;
– L.L  L;
– L1.(L2 ∩ L3)  (L1 ∩ L2).(L1 ∩ L3) ;
– L1.L2  L2.L1.
– (L*)* = L* ;
– L*.L* = L* ;
– L1.(L2.L1) * = (L1.L2) *.L1 ;
– (L1 + L2) * = (L*1L*2) * ;
– L*1 + L*2  (L1 + L2) * .

Exemplul 3.3. Dăm în continuare câteva exemple de cuvinte care se pot afla (sau nu)
în limbajul aritmetic şi pot fi valide sau nu; pentru simplitate, să alegem doar alfabetul
Σ={1, 2, +, =}. Să caracterizăm şirurile (de caractere) de mai jos:
w1 este ―1+1=2‖, cuvânt valid de tip declaraţie (statement) cu valoare ―Adevărat‖;
w2 este ―21+2122‖, cuvânt valid de tip expresie (expression) - nu are o valoare de adevăr;
w3 este ―22+12=11‖, cuvânt valid de tip declaraţie cu valoare de adevăr ―Fals‖;
w4 este ―=+1+=+‖, cuvânt valid care nu semnifică ceva (expresie neobişnuită);
w5 este ―1+2=3‖, cuvânt invalid (―3‖ nu aparţine alfabetului A);
w6 este ―aceasta este numărul 1‖, cuvânt invalid dar cu sens în limba română;
În problematica limbajelor (fie naturale, fie formale) întâi de toate trebuie să se verifice pentru
un cuvânt w:
1. validitatea (relativ la formă): w5 şi w6 sunt invalide, restul valide;
2. tipul de cuvânt (relativ la conţinut: înţeles - semantică):
a. declaraţie cu semnificaţie: w1 şi w3 care, în plus, au o valoare de adevăr;
b. expresie cu semnificaţie: w2 expresie obişnuită (regulată);
c. expresie fără semnificaţie: w4 expresie ne-obişnuită (ne-regulată).
După cum se observă în w6, ―un cuvânt‖ poate fi o propoziţie din limbaj natural LN,
reţinând faptul că în propoziţia-LN sfârşitul de cuvânt-LN este indicat de ―spaţiu‖ (⌴ blanc)
sau de un semn de punctuaţie. Observaţie: de aceea nu se pune spaţiu înainte de un semn de
punctuaţie! nu este ―valid ortografic‖ pentru că am avea marcat ―sfârşit şir‖ de două ori – deci

62
al doilea marcaj ar putea duce la impresia falsă că avem de aface cu un şir vid ε. Totuşi, se
poate accepta încălcarea acestei reguli pentru că limbajul natural ţine de LN+ nu de LN*.

Problema decidabilităţii unui limbaj este tocmai ―capacitatea‖ unui limbaj de a rezista la o
verificare a unuia din cuvintele sale, adică procedura de verificare să se oprească (halt)
producând un răspuns: ―acceptat‖ / ―neacceptat‖ (valoare de adevăr cu terţiul exclus).

3.2 Reprezentarea Limbajelor


Am văzut în Exemplul 3.1 că limbajele pot fi reprezentate aşa cum se descriu mulţimile:
prin înşiruierea elementelor componente (limbajul LM – finit) sau prin indicarea unor
proprietăţi ale elementelor componente (limbajul LP – infinit). Fiind vorba de limbaj este
indicat ca la un moment dat să constituim un „vocabular‖ de cuvinte, deci ar trebui ca
elementele componente ale limbajului să poată fi enumerate. Cele două limbaje LM şi LP pot fi
enumerate – LP este infinit dar am văzut la § 1.2 pct. 15 că mulţimi infinite sunt numărabile.
Există însă şi limbaje ne-enumerabile.
Pe de altă parte, fiind mulţimi, limbajele ar trebui să permită operaţiile uzuale pe mulţimi,
însă în timp ce un limbaj ca LM permite uniune, intersecţie etc., limbajul LP nu permite
intersecţie.
Rezultă deci că reprezentarea limbajelor este diferită pentru diferite clase de limbaje,
pentru unele fiind posibil să găsim o reprezentare finită, pentru altele nu. Cea mai puternică
reprezentare finită pentru diferite limbaje este prin Gramatici care, vom vedea ulterior, că
acestea de fapt generează limbaje.
Există şi reprezentări directe ale limbajelor – prin operaţii algebrice asociate operaţiilor pe
mulţimi – denumite expresii regulate (regular expressions) şi de aici limbaje regulate, acestea
putând fi recunoscute de Automate finite de stare de tip DFA / NFA şi care vor fi prezentate
în continuare. Pentru că problema generării limbajelor prin gramatici este foarte importantă,
aceasta se va prezenta într-un subcapitol separat.

3.2.1 Expresii regulate, Limbaje regulate


Limbajele regulate sunt descrise prin expresii regulate (prescurtat regEx), adică expresii
care sunt stabile la toate operaţiile cu mulţimi, cu alte cuvinte sunt închise la aceste operaţii. O
expresie regulată este un șir de caractere care descrie o mulţime de șiruri (elementele
limbajului regulat corespunzător), conform anumitor reguli de sintaxă.
Există mai multe tipuri de sintaxă pentru expresiile regulate. Cele mai multe dintre ele sunt
echivalente și diferă doar prin simbolurile pe care le folosesc, însă în principal se folosesc
simboluri de operaţii algebrice: adunarea algebrică ―+‖care este aici reuniune (SAU inclusiv)
iar înmulţirea algebrică ―.‖ (simbolul poate lipsi ca şi în algebră) care este aici concatenare
(ŞI). Se adaugă operatorul * care indică multiplicitate în orice număr.
Fie Σ un alfabet.
Definiţia 3.7 O expresie regulată regEx peste Σ şi limbajul pe care îl reprezintă sunt
definite inductiv cu următoarele cazuri:
1. Mulţimea vidă  este regEx şi reprezintă limbajul vid.
2. Şirul vid ε este regEx şi reprezintă limbajul cu un element şirul vid {ε}.

63
3. Fiecare a  Σ, este regEx şi reprezintă limbajul {a}, cu unic element şirul constituit
din caracterul a.
4. Dacă r şi s sunt regEx şi reprezintă limbajele R şi S, atunci (r+s) este regEx şi
reprezintă limbajul R ∪ S.
5. Dacă r şi s sunt regEx şi reprezintă limbajele R şi S, atunci (rs) este regEx şi reprezintă
limbajul RS.
6. Dacă r este regEx şi reprezintă limbajul R atunci (r∗) este regEx şi reprezintă limbajul
R*.

Reluăm cu explicaţii. Expresiile regulate regEx peste Σ folosesc simbolurile:


 - reprezintă mulţimea vidă { }
ε - reprezintă mulţimea {ε} – cu element şirul vid
a - reprezintă mulţimea {a}, un şir de lungime 1, pentru orice simbol a  Σ.
Cu r şi s regEx iar mulţimile R şi S, respectiv:
r+s - reprezintă mulţimea uniune R ∪ S, (ordine de precedenţă 3)
rs - reprezintă mulţimea concatenare RS, (ordine de precedenţă 2)
*
r - reprezintă mulţimea R*, (ordine de precedenţă 1 – cea mai înaltă)
(r) - reprezintă mulţimea R, nu este operator ci explicitează ordinea de precedenţă
Dacă r este o regEx, atunci L(r) poate fi folosit pentru a indica limbajul correspondent.
De exemplu, ((0(0 + 1)∗) + ((0 + 1)∗0)) este regEx peste {0, 1} care reprezintă limbajul
constând din toate şirurile binare care încep sau se sfârşesc cu un 0. Pentru că operaţiile pe
mulţimi uniune şi concatenare sunt asociative, şi pentru că închiderea Kleene are precedenţă
asupra acestora, multe din paranteze se pot omite din regEx de mai sus, astfel că aceasta se
poate scrie: 0(0+1)∗ +(0+1)∗0. Expresia rr∗ se va abrevia r+.

Exemplul 3.4.Fie alfabetul Σ = {0, 1}. Mai jos sunt exemple regEx cu semnificaţia lor:
0 - un 0
1 - un 1
(0 + 1) - 0 sau 1
(0 + 1)1 - 0 sau 1 urmat de 1
(0+ε)(1+ ε) - 0 sau vid şi 1 sau vid
(0 + 1)* - orice combinaţie de 0 şi 1
01* - 0 urmat de oricâţi 1
(01)* - oricâte perechi 01
(0*10*) - oricâţi de 0, 1, apoi oricâţi de 0
0(0 + 1)* - orice combinaţie de 0 şi 1 care încep cu un 0
(0 + 1)*1 - orice combinaţie de 0 şi 1 care se încheie cu 1
(0 + 1)*0(0 + 1)*0(0 + 1)* - orice combinaţie de 0 şi 1 ce conţine cel puţin doi 0.
Limbajele regulate generate de regEx de mai sus sunt explicitate în mulţimile:
0 = {0}
1 = {1}
(0+1) = {0, 1}

64
(0+1)1 = {01, 11}
(0+ε)(1+ ε) = {ε, 0, 1, 01}
(0+1)* = {ε, 0, 1, 01, 10, 001, 101, 101001, ...}
01* = {0, 01, 011, 0111, ...}
(01)* = {ε, 01, 0101, 010101, …}
(0*10*) = {1, 01, 10, 010, 0010, 00100, …}
0(0 + 1)* = {0, 00, 01, 010, 0010, 00100, …}
(0 + 1)*0(0 + 1)*0(0 + 1)* = {00, 000, 0100, 00100, 00101, …}

Orice limbaj care poate fi notat printr-o expresie regulată regEx este un limbaj regulat;
reciproc, orice limbaj regulat poate fi notat printr-o expresie regulată. Prin urmare, expresii
precum 01* sau (01)* sunt folosite pentru a desemna mulțimi care altfel ar putea fi prea
greoaie pentru a le scrie prin enumerarea elementelor lor (vezi mai sus).

3.2.2 DFA şi NFA reprezintă expresii regulate


Un limbaj este regulat dacă poate fi reprezentat printr-o expresie regulată regEx.
Am văzut că NFA N şi DFA D echivalent acceptă anumite (tipuri de) şiruri de caractere
după cum sunt proiectate, adică limbaje L(N) = L(D).
Pentru orice DFA D există regEx r astfel încât L(r)=L(D) – Teorema 1; astfel, pentru
regEx r există un εNFA cu L(r) = L(N) – Teorema 2. Aceste teoreme stabilesc echivalența
expresiilor regulate și a automatelor cu stări finite în reprezentarea limbajelor, provenid din
teorema cunoscută sub numele de Teorema lui Kleene (după S.C. Kleene, care a demonstrat-o
în anii 1950) v. Figura 3.1. Există tehnici algoritmice pentru a converti o expresie regulată
dată într-un automat care acceptă limbajul corespunzător și invers.

Figura 3.1 Automate cu stări finite şi regEx sunt inter-schimbabile.

Deci clasa de limbaje reprezentabile prin automate NFA este exact aceeași cu clasa de
limbaje reprezentabile prin automate DFA; aceasta nu înseamnă că automatele nedeterministe
sunt „inutile‖, pentru că am văzut că NFA pot fi descrise cu mai puține stări decât DFA pentru
a recunoaşte un anume limbaj, iar acest lucru le face destul de utile – deşi pentru o
implementare fizică numai DFA sunt adecvate, pentru a duce în mod ―determinist‖ la
rezultatul dorit (şi nu a avea, de exemplu, tranziţii-ε „de aiurea‖).
Clasa de limbaje reprezentabile prin automate NFA/DFA sunt deci Limbajele Regulate
care constituie o submulțime proprie a mulţimii putere P(Σ*) = 2Σ*. Această clasă este foarte
importantă deoarece delimitează limbajele care posedă reprezentări prin automate cu memorie
finită atât pentru cazul când sunt realizate fizic cât şi când sunt programate pe un calculator

65
universal. Cu alte cuvinte, automatele sunt un mijloc practic de manipulare a limbajelor
obișnuite în probleme de analiză sau de sinteză a controlerelor pentru sisteme discrete. Pe de
altă parte, NFA nu sunt un mijloc practic de reprezentare a limbajelor neregulate, care
necesită memorie infinită (cum sunt PDA).

3.2.3 Conversia regEx - NFA


Pentru conversia regEx în NFA trebuie să considerăm cazurile prin care este defintă regEx,
adică prin Definiţia 3.7.
Exemplul 3.5. Fie expresia regulată (ab+a)*. Vom realiza pas cu pas automatul NFA M
care o reprezintă15, plecând de la definiţie.
Caz 1 regEx r = . Automatul M = (Q, Σ, δ, q, F) care acceptă acest limbaj are definite:
Q = {q}, q stare de start, F =  (adică nu există stări acceptoare) şi δ(q, a) =  pentru oricare
a ∈ Σ; diagrama de stare este indicată în figura de mai jos:

Figura 3.2 Diagrama de stare M pentru regEx r = .

Caz 2 regEx r = ε. Automatul M = (Q, Σ, δ, q, F) care acceptă acest limbaj are definite:
Q = {q}, q stare de start, F = q (adică starea acceptoare este şi cea de start) şi δ(q, a) = 
pentru oricare a ∈ Σ; diagrama de stare este indicată în figura de mai jos:

Figura 3.3 Diagrama de stare M pentru regEx r = ε.

Caz 3 regEx r = a, a ∈ Σ. Automatul M1 = (Q, Σ, δ, q, F) care acceptă acest limbaj are


definite: Q = {q1, q2}, q1 este stare de start, F={q2} (o stare acceptoare alta decât cea de start)
şi funcţia de tranziţie δ, şi diagrama de stare mai jos:
δ(q1, a) = {q2},
δ(q1, b) =  pentru oricare b ∈ Σ \ {a},
δ(q2, b) =  pentru oricare b ∈ Σ.
a
q1 q2

Figura 3.4 Diagrama de stare M1 pentru regEx r = a.

Similar, se poate construi automatul M2 unde regEx r = b, b ∈ Σ.


Se aplică apoi Caz 5 regEx pentru situaţia de concatenare rs cu limbajele corespondente
concatenate RS ale automatelor NFA respective, conform Figura 2.20, obţinând automatul M3
care descrie regEx ab din figura de mai jos:

15
Anil Maheshwari, Michiel Smid, Introduction to Theory of Computation, Carleton University, 2019

66
a ε b

Figura 3.5 Diagrama de stare M3 pentru regEx concatenare ab.

Se aplică Caz 4 regEx pentru situaţia de uniune r+s pentru automatele M1 şi M3, cu
limbajele respective, conform Figura 2.19, obţinând automatul M4 care descrie regEx ab+a,
adică şir ce conţine ab sau a - Figura 3.6.

a ε b
ε

ε
a

Figura 3.6 Diagrama de stare M4 pentru regEx uniune ab+a.

În final, se aplică Caz 6 regEx pentru situaţia de operator stea r* cu limbajul


corespondent R*, conform Figura 2.21, obţinând automatul M5 care descrie regEx (ab+a)*,
adică toate şirurile ce conţin ab sau a. Se observă că în Figura 3.7. tranziţiile-ε s-au plasat de
la stări finale către starea de start a M4 (şi nu către starea de start nou introdusă), pentru a se
evita ca la tranziţii interne ale M4 către starea de start, aceasta să devină stare acceptoare.

a ε b
ε
ε

ε
a

Figura 3.7 Diagrama de stare M5 pentru regEx operator stea (ab+a)*.

S-a obţinut astfel εNFA care recunoaşte limbajul conform regEx (ab+a)*.

3.2.4 Conversia DFA - regEx


Am văzut cum se poate converti un regex în NFA iar la capitolul anterior am văzut că un
NFA se poate converti în DFA echivalent. Să vedem cum se poate converti un DFA într-o
regEx, pentru că toate cele trei concepte DFA, NFA și regex sunt trei moduri diferite de a
reprezenta același lucru.
Pentru a converti DFA-uri în regEx, se foloseşte aşa-numitul NFA-generalizat GNFA9
(Generalized Non-deterministic Finite Automaton), un NFA ale cărui tranziții sunt etichetate
cu regEx în loc de simboluri individuale. De exemplu, GNFA de mai jos înseamnă că se trece
de la starea 1 la starea 2 ori de câte ori se citeşte orice secvență de 0 urmată de un 1.

67
0∗1
*
q0 q1

Figura 3.8 Diagrama de stare pentru GNFA cu regEx 0*1,

Pentru a converti un DFA într-un GNFA care acceptă acelaşi limbaj se vor lua în
considerare cazuri pentru operatorii regEx (+), (.), (*):

r
r+s
q0 q1 q0 q1
s

Figura 3.9 Diagrame de stare pentru GNFA cu operator regEx (+).

Tranziţia între două stări GNFA pot fi combinate prin SAU în Figura 3.9 stânga, adică
uniune pentru expresiile regulate r şi s prin operator regEx (+) în Figura 3.9 dreapta.

s
q0 r q1 t q2 q0 rs*t q2

Figura 3.10 Diagrame de stare pentru GNFA cu operatori regEx (.) şi (*).

Tranziţia între două stări GNFA pot fi combinate prin operator regEx stea (*) - în cazul
buclei din Figura 3.10 stânga pentru s* şi operator concatenare între r şi s* apoi cu t (.) tot în
Figura 3.10 stânga, pentru a obţine tranziţia regEx indicată în Figura 3.10 dreapta.

Se pot combina aceşti operatori în procesul de conversie DFA – regEx, astfel:


1. Dacă starea iniţială a DFA prezintă orice tranziţie imergentă („vine la ea‖) atunci se
crează o nouă stare iniţială cu o tranziţie-ε către vechea stare.
2. Dacă starea acceptoare prezintă o tranziţie ce pleacă din ea sau dacă sunt mai multe
stări acceptoare, atunci se crează o nouă stare acceptoare cu tranziţii-ε venind
dinspre stările foste acceptoare spre cea nou introdusă.
3. În mod repetat, se trece prin stări şi se combină aşa cum se descriu mai sus (practic
eliminându-le), până ce rămân doar stările iniţială şi finală. Expresia regulată
înscrisă pe tranziţia între aceste două stări este regEx care acceptă limbajul original
al DFA. Stările pot fi traversate şi eliminate în orice ordine.

În Figura 3.11 se ilustrează intuitiv16 modul cum decurge această procedură pentru DFA cu
diagrama în partea de sus, către regEx 1*00*1(0+1)* indicată în partea de jos a figurii.

16
Ananth Kalyanaraman, Automata and Formal Languages, Washington State University, 2017

68
Figura 3.11 Conversie DFA – regEx pentru cazul 1*00*1(0+1)*.

3.3 Gramatici
Am văzut până aici că limbajele – fiind mulţimi de cuvinte, se pot descrie/reprezenta la fel
ca mulţimile; (1) extensiv - prin înşiruirea elementelor (ca în cazul vocabularelor), (2)
comprehensiv - prin indicarea unor proprietăţi comune cuvintelor (ca în cazul palindroamelor
sau regEx) şi în final (3) inductiv - prin definirea unei reguli (cu proprietăţi de închidere) prin
care se construieşte un limbaj infinit cu un număr restrâns de concepte. Inductivitatea
(inducţia) este repetitivitatea plecând de la un element de bază spre elementul de interes (şi
spre infinit) iar recursivitatea este repetitivitate în sens invers, de la un element de interes
către elementul de bază (repetiţia are o condiţie de oprire).
Cel mai important avantaj al definițiilor recursive este că ele fac posibilă înțelegerea
structurilor unei limbi, ceea ce facilitează şi înțelegerea limbii; aceásta face Gramatica. Într-
adevăr, chiar independent de contextul unui limbaj, regulile inductive, prin gramatică, sunt un
mijloc de a descrie construcția şirurilor de caractere: fie ele cuvinte, propoziţii, fraze şi fie în
limbaj natural sau în limbaj formal. În plus, existenţa şi folosirea unei gramatici face posibilă
raționarea despre limbaj, face posibilă construirea de algoritmi eficienți pentru procesarea
limbajului și, în final, facilitează învățarea limbilor/limbajelor.
O gramatică nu doar descrie un limbaj ci îl generează; cu ajutorul gramaticii limbajul poate
fi apoi verificat – dacă este folosit corect sau nu.

3.3.1 Structuri gramaticale comune


Gramatica limbii nu este o creaţie a omului ci este un dat la care omul doar a analizat şi a
rescris unele reguli, în decursul istoriei [limbilor]. De ramarcat că Patañjali, unul dintre cei
mai cunoscuţi filozofi indieni ca punând bazele sistemului Samkhya (Yoga Sutra) în sec, II
î.d.C., era de fapt grămătic – adică a studiat şi evidenţiat reguli de gramatica sanskrită.
Similar, în vremurile noastre, Avram Noam Chomsky (lingvist şi filozof american, la data
cand scriu având 95 de ani) a încercat – şi reuşit cu succes şi răsunet, să facă o descriere
formală a gramaticilor şi o clasificare ierarhică a acestora (vom vedea mai departe).
Aşa cum am văzut în partea introductivă – capitolul 1, forma validă declaraţiilor o dă de
fapt garmatica, deci aceasta este este sămânţa logicii; astfel, raţionamentul şi logica umană „se
învârt‖, de fapt, în jurul Cuvântului.
Există diverse gramatici pentru diverse limbi dar – deşi sunt diferenţe în plasarea
determinanaţilor (articole hotărâte/nehotărâte, adjective) sau chiar a verbelor, structura

69
propoziţiilor este relativ aceeaşi privind sintaxa. În continuare, ne vom referi în prezentare la
gramatica română dar vom face trimiteri la gramatica engleză – la care Chomsky şi cercetători
ai limbajelor formale fac referire şi care (având o gramatică mai simplă şi cu puţine excepţii)
se pretează mai bine formalizării. În demersul său, Chomsky a decelat în gramatica limbii
(engleze) forme generice pe care le-a denumit NP – noun phrase (exprimare substantivală) şi
VP – verb phrase (exprimare verbală), cu care apoi se pot construi propoziţii, fraze; de
exemplu, în exprimarea substantivală se pot include articole (hotărât/nehotărât), adjective (în
general, determinanţi) – funcţie de detaliile ce se doresc adăugate preciziei mesajului.

Exemplul 3.6. Fie propoziţia „un câine roade un os.‖; scrisă în engleză ar fi „a dog chews
a bone.‖ dar poate avea şi alte forme the dog chews a bone sau a white dog chews a bone, sau
a white lazy dog chews a bone, prin adăugarea în partea stângă a subiectului (în faţa
substantivului dog) articole hotărât/nehotărât sau adjectiv(e). Această adăugare spre stânga a
diverselor particole permite o descriere arborescentă care va lua în considerare left most – cea
mai din stânga, formulare. În limba română, articolul hotărât (spre exemplu) este sufix
(adăugat la dreapta) şi nu prefix, deci o descriere ca aceasta este mai puţin „regulată‖; similar
pentru adjective: se adaugă la dreapta substantivului (deşi spre sublinierea acelei calităţi se
poate adăuga la stânga – dar articulat). Pe de altă parte, sintaxa propoziţiei în engleză este
fixă: întâi subiectul (cel mai spre stânga) apoi predicatul (verbul) apoi obiectul care suferă
acţiunea. În limba română însă, locul subiectului şi predicatului nu sunt fixe. Prin aceste
caracteristici limba engleză se pretează mai bine la formalizare decât alte limbi.
Pentru exemplul dat, în Figura 3.12 se descrie „morfologic‖ propoziţia în limba română, în
care N indică substantiv (noun), V – verb, Det – determinant (aici articol nehotărât), Punc –
semn de punctuaţie (poate fi şi ! sau ?) 17.

Det N V Det N Punc

un câine roade un os ∙

the
Figura 3.12 Exemplu.de structură gramaticală comună.

Sintactic, propoziţia se compune arborescent din subiect S (câine), predicat V (verb -


roade) şi obiect O (os), care se prezintă generic în Figura 3.13, şi descompus în Figura 3.14.

S V O

Figura 3.13 Structură sintactică generică.

17
Rolf Pfeifer, Rudolf Füchslin, Formal Methods for Computer Science, University of Zurich, 2013

70
S V O Punc

Det N Det N

un câine roade un os ∙

Figura 3.14 Structură sintactică pentru Exemplul 3.6.

Cu ajutorul sintaxei şi semantica se poate descoperi uşor; sintaxa impune reguli de scriere
dar şi privind ordinea cuvintelor – foarte importantă pentru înţelegerea unui mesaj. La un
program scris într-un limbaj de programare semantica este aproape imposibil de verificat însă
sintaxa da – de la care programatorul poate apoi înţelege prelucrarea propusă de program.
Propoziţia – de fapt fraza, este mesajul şi unitatea de bază a limbajului. Deşi, sintaxa este o
modalitate convenabilă de a reprezenta structura unei propoziţii/fraze, ea nu poate fi folosită
pentru a descrie întregul limbaj în sine – adică setul tuturor structurilor posibile, cum ar fi
toate frazele corecte într-o limbă (română, engleză ...).
Aici intră în joc regulile gramaticale şi analiza gramaticală (parsing). În Figura 3.15 este
ilustrat un arbore de derivare (derivaiton tree = parsing tree) ca instrument în înţelegerea
modului de generare a şirurilor de caractere într-o gramatică. Se parcurge arborele de sus în
jos, de la simbolul de start (reprezentat printr-un cerc), trecând prin toate simbolurile
neterminale (reprezentate prin casete) care sunt înlocuite succesiv cu un set de simboluri
terminale (reprezentate prin romburi), până când rămân doar simboluri terminale. Fiecare
dintre aceste înlocuiri poate fi reprezentată de o regulă de producție sau de rescriere:
P → S V O.
Secvenţa de aplicare a regulilor de producţie constituie, în sine, derivarea (derivation).

P Punc

S V O

Det N Det N

un câine roade un os .

Figura 3.15 Arborele de derivare pentru Exemplul 3.6.

71
În Tabel 3.1 prima coloană este un set posibil de reguli de producţie pentru exemplul dat
(unde | semnifică SAU) – adică o gramatică generativă, iar în ultima coloană apare derivarea
– parcurgerea arborelui de derivare dinspre stânga (left most) şi spre adâncime (depth first).

Reguli de producţie Propoziţia (Sentence) Derivarea


I → P Punc Start – I  P Punc
P→SVO [arbore stânga] P  S V O Punc
S→ Det N  Det N V O Punc
O→ Det N  un N V O Punc
 un câine V O Punc
V→ roade
 un câine roade O Punc
Det → un  un câine roade Det N Punc
N → câine | os  un câine roade un N Punc
Punc → . un câine roade un os  un câine roade un os Punc
[arbore dreapta] Punc  un câine roade un os .

Tabel 3.1 Reguli de producţie şi derivarea recursivă pentru Exemplul 3.6.

Regulile de producţie de mai sus nu pot genera un întreg limbaj dar pot genera o clasă de
propoziţii şi dau o idee cum se poate extinde o gramatică la una mai cuprinzătoare.
În Tabel 3.2 se indică setul de reguli de producţie de mai sus pentru generarea unei clase de
propoziţii, pentru care s-a introdus încă un simbol neterminal Aux ce apare la începutul
propoziţiei, astfel că se pot genera următoarele propoziţii:
I. „un câine roade un os!‖ (lipsă Aux)
II. „adesea un câine roade un os.‖ („adesea‖ - Aux)
III. „un cal trage la căruţă;‖ (lipsă Aux)
IV. „poate un cal trage la căruţă?‖ („poate‖ - Aux)
V. „uneori o broască stă pe mal?!?‖ („uneori‖ - Aux)
şi alte combinaţii (mai mult sau mai puţin hazlii).

I → P Punc | Pi Punci
P → SVO
Pi → Aux S V O
S → Det N
O → Det N
V → roade | trage | stă
Aux → adesea | poate | uneori
Det → un | o | la | pe
N → câine | os | cal | broască | căruţă | mal
Punc → ; | !
Punci → . | ? | ?!?
Tabel 3.2 O gramatică generativă cu reguli de producţie recursive.

72
După cele prezentate până aici, rezultă pentru Gramatici următoarele concepte – care în
lista de mai jos sunt structurate relativ la rolul pe care îl joacă:
 Definirea Gramaticii: descrierea formală a modului de generare a unui limbaj.
o Simboluri Terminale: caractere sau subşiruri de caractere din care se
constituie şiruri de caractere (cuvinte) în limbajul generat (fie ele şi
propoziţii); terminalele se înscriu cu litere mici sau cifre (după alfabet).
o Variabile sau simboluri Neterminale: care – după cum au şi numele, vor
primi instanţieri ca secvenţe de terminale şi de variabile, într-o ordine
dependentă de tipul gramaticii (vezi mai jos). Variabilele se înscriu cu
litere mari şi sunt înlocuite cu instanţieri prin procedura de derivare.
o Reguli de producţie sau producţii: formule care indică prin → în ce mod şi
eventual în ce ordine au loc instanţierile variabilelor.
o Simbol de start: folosit atât pentru a desemna începutul şirului de caractere
cât şi startul formării lui prin derivare.
 Funcţionarea Gramaticii: obţinerea cuvintelor – elemente ale limbajului generat.
o Arbore de derivare: structurare pe categorii gramaticale a variabilelor şi a
terminalelor (ca scop final al instanţierii variabilelor), de regulă dezvoltat
cu ramuri spre stânga simbolului de start.
o Derivare: procedură recursivă de instanţiere a variabilelor printr-o secvenţă
finită de paşi, cu o singură instanţiere la un pas de derivare  dat.
Instanţierea are loc prin aplicarea unei reguli de producţie care poate
produce ramificarea procesului de derivare prin | (SAU) prezent în formula
regulii de producţie.
o Produs: şir de caractere obţinut prin procesul de derivare, fiecare element al
şirului fiind frunză a arborelui de derivare; elementul şirului poate fi un
subşir, de aceea pentru un limbaj apropiat de cel natural produsul este
denumit propoziţie (sentence) – constituită din cuvinte, spaţii, punctuaţie.
Gramaticile pentru generarea limbajelor formale sunt mai simple decât pentru limbaje
apropiate de cele naturale, iar produsele primelor sunt în fapt şiruri de caractere amorfe sau
expresii (matematice, instrucţiuni) şi nu structurate ca propoziţii – în cazul al doilea.

3.3.2 Gramatici formale


Pentru a reprezenta şi opera cu limbaje formale se vor defini în continuare gramatici pentru
patru categorii speciale de constituire şi verificare a limbajelor, conform „ierarhiei Chomsky‖,
despre care vom discuta mai târziu (v. § 3.4.4)

Definiţia 3.8 O gramatică este 4-tuplul (Σ, V, S, P ), unde:


1) Σ este o mulţime finită ne-vidă de simboluri denumită alfabet; elementele lui Σ sunt
denumite terminale.
2) V este o mulţime finită ne-vidă de simboluri disjunctă de Σ: V ∩ Σ = . Elementele
lui V sunt denumite neterminale sau variabile
3) S ∈ V este un neterminal special, denumit simbol de start.
4) P este o mulţime finită reguli de producţie (sau producţii) de forma:
α→β
73
unde α ∈ (Σ∪V )*V (Σ∪V )* şi β ∈ (Σ∪V )*, adică. α este un şir de terminale şi neterminale
conţinând cel puţin un neterminal şi β este un şir de terminale şi neterminale.
Să remarcăm că α şi β sunt secvenţe de simboluri (ordinea este importantă şi de aceea nu le
denumim pur şi simplu şiruri): xy – terminale şi XY – neterminale (variabile), plasate în ordine
diferită pentru diferite categorii Chomsky. De exemplu, într-un caz α = X şi β = xyX, sau în alt
caz α = xXy şi β = xXYxy, sau în alt caz α = xXy şi β = xXxYy. Dependent de configuraţia de
simboluri terminale şi neterminale dar şi de cardinalităţile |α| şi |β| ale celor doi termeni ai
unei producţii, gramatica şi limbajul corespunzător vor cădea într-o categorie sau alta.

Pentru a explica cum funcţionează formalismul la reprezentarea/generarea unui limbaj prin


gramatică, să definim următoarele concepte:
Definiţia 3.9 Fie o gramatică G = (Σ, V, S, P). O formă propoziţională (sentential form) a
G este orice secvenţă de terminale şi neterminale, adică un şir de simboluri peste Σ ∪ V .
Definiţia 3.10 Fie o gramatică G = (Σ, V, S, P) şi fie γ1, γ2 două forme propoziţionale ale
G. Spunem că γ1 derivă direct γ2, şi scriem γ1 ⇒ γ2, dacă γ1 = ζαη , γ2 = ζβη , şi α → β este o
producţie în P .
Definiţia 3.11 Fie γ1 şi γ2 două forme propoziţionale ale gramaticii G. Spunem că γ1 derivă
γ2 şi scriem γ1 ⇒∗γ2, dacă există o secvenţă ζ1, . . . , ζn de zero sau mai multe forme
propoziţionale astfel ca: γ1 ⇒ ζ1 ⇒ · · · ⇒ ζn ⇒ γ2, sevenţă denumită derivarea γ2 din γ1.
În această secvenţă atât γ1 şi γ2, cât şi fiecre din ζ1, . . . , ζn sunt forme propoziţionale.
Acestea sunt concepte pe care le-am întâlnit deja iar prin exemplele care urmează se vor
lămuri scopul şi formalizarea lor.

Definiţia 3.12 Fie o gramatică G = (Σ, V, S, P). Limbajul generat de G şi notat L(G) este
definit astfel:
L(G) = {w | w ∈ Σ*, S ⇒∗ w}.
Cuvintele w din L(G) sunt denumite şi propoziţíi (sentences) ale L(G).

Exemplul 3.7. Fie G1 = ({0, 1}, {S, T, O, I}, S, P), unde P conţine următoarele producţii:
S → OT
S → OI
T → SI
O→ 0
I→ 1
Această gramatică generează limbajul L1= {0n1n | n ≥ 1} pe care îl vom exemplifica pe
18

cazul unei derivări pentru forma propoziţională (şirul) 0011 (vezi Definiţia 3.9).
Mai jos este ilustrată derivarea prin G1 către şirul exemplu: S ⇒* 0011:
S ⇒ OT ⇒ 0T ⇒ 0SI ⇒ 0S1 ⇒ 0OI1 ⇒ 00I1 ⇒ 0011
În acestă secvenţă fiecare pas este o derivare directă conform cu Definiţia 3.10, de exemplu
18
Tao Jiang, Ming Li, Formal Grammars and Languages, in Algorithms and Theory of Computation Handbook,
2010.

74
la primul pas O este înlocuit direct (imediat) cu 0 (vezi pasul următor 0T). Toată secvenţa
(indicată prescurtat mai sus prin ⇒* ) este derivarea (completă) conform cu Definiţia 3.11. Se
observă la acestă secvenţă că partea stângă a producţiei relevante la fiecare derivare în parte
este subliniată, pentru a se descoperi clar instanţierea vizată (la pasul următor).

Definiţia 3.13 O derivare dinspre stânga (leftmost derivation) este cea în care se
înlocuieşte cea mai din stânga variabilă a formei propoziţionale; dacă însă la fiecare pas se
înlocuieşte cea mai din dreapta variabilă, atunci este o derivare dinspre dreapta (rightmost).

Exemplul 3.8. Gramatica G2 = ({a, b}, {S,A, B}, S, P), unde ε este situaţie „vid‖ – oprire
opţională, cu producţiile P:
S → aAB
A → bBb
B→A | ε
Derivarea dinspre stânga pentru şirul abbbb este:
S ⇒ aAB ⇒ abBbB ⇒ abAbB ⇒ abbBbbB ⇒ abbbbB ⇒ abbbb
Derivarea dispre dreapta pentru şirul abbbb este:
S ⇒ aAB ⇒ aA ⇒ abBb ⇒ abAb ⇒ abbBbb ⇒ abbbb

Peter Linz19 a emis şi demonstrat o teoremă prin care, pentru orice gramatică independentă
de context (v. §3.4.2), la fiecare cuvânt w∈ L(G), există un arbore de derivare care va produce
w; dacă w are punct iniţial simbolul de start S el este o formă propoziţională. Această
concluzie este importantă pentru aplicaţii de analiză sintactică (parsing) la compilatoare, unde
(prin ―parser‖) se analizează fiecare linie de program (propoziţie) pentru:
I. verificarea sintactică a programului în limbajul respectiv,
II. construirea arborelui de derivare necesar execuţiei programului – adică generarea
codului la nivel maşină pentru respectivul program.
Deci o gramatică este necesară nu doar pentru generarea limbajului ci şi pentru verificarea sa.
Totuşi, arborele de derivare se poate genera pentru un acelaşi cuvânt w (şir de caractere) în
mai multe feluri, astfel că o gramatică prezintă ambiguitate – atunci când există două sau mai
multe derivări dinspre stânga sau dinspre dreapta sau chiar ambele.
De ce este ambiguitatea o problemă? Pentru că aşa cum s-a văzut, înţelesul (semantica)
unei expresii este asociată structurii expresiei – care determină la rândul ei generarea codului
maşină prin care se execută programul (determină calculabilitatea). În limbajele de
programare, ambiguitatea se elimină de obicei prin introducerea şi folosirea ordinii de
precedenţă – care însă este în afara limbajului (independent de context). În mod normal, ar
trebui să se rescrie gramatica pentru a genera un alt limbaj – care va elimina ambiguitatea.

3.4 Familii de limbaje


Am amintit deja de lingvistul Noam Chomsky, un fondator al teoriei limbajului formal,
care a oferit o clasificare inițială în patru tipuri de limbaj, de la tipul 0 la tipul 3. Această
19
Peter Linz, An Introduction to Formal languages and Automata, Jones and Bartlett Publ., 2012

75
terminologie originală a persistat și se găsesc referiri frecvente la ea, dar tipurile numerice
sunt de fapt nume diferite pentru familii de limbaje. O familie de gramatici este definită de
forma regulilor și de condițiile în care acestea sunt aplicabile. O regulă specifică o
transformare de șir, iar șirurile de caractere ale unui limbaj sunt generate de o secvență de
reguli aplicate. Flexibilitatea oferită de reguli s-a dovedit a fi potrivită pentru definirea
sintaxei limbajelor de programare.
După definirea limbajelor prin generarea de șiruri, este de interes verificarea mecanică
dacă un șir satisface o condiție dorită sau se potrivește cu un model dorit. Familia de automate
finite deterministe este prima dintr-o serie de mașini abstracte utile pentru recunoaşterea
modelelor și definirea limbajului.
La fiecare din familii se va face referire la mașini (ca fiind abstracte), pentru că este de
interes determinarea capacităţii de calcul a unei maşini, nu doar construirea ei - implementare
hardware sau software. Intrarea într-o mașină abstractă este un șir, iar rezultatul unui calcul
indică acceptabilitatea șirului de intrare. Limbajul unei mașini este setul de șiruri acceptate
prin calculele mașinii.
În continuare se vor prezenta aceste familii succint şi cu caracteristicile esenţiale, pentru ca
în final să ilustrăm modul cum relaţionează ele prin incluziune.

3.4.1 Gramatici şi Limbaje Regulate


Prima categorie de limbaje şi gramaticile lor generative este denumită regulată (regular).
Definiţia 3.14 Toate regulile de producţie pentru o gramatică regulată stânga au forma:
A → Xxyz . . .
unde A este un simbol neterminal, xyz . . . zero sau mai multe simboluri terminale şi X zero
sau un (singur) simbol neterminal.
O gramatică regulată dreapta are reguli de producţie de forma:
A → xyz . . . X
Un limbaj regulat RL (Regular Language) este limbajul generat de o gramatică regulată.

Textual, gramaticile regulate RG (Regular Grammars) au partea α a regulilor de producţie


formată doar dintr-o singură variabilă iar în partea β o singură variabilă cu oricâte terminale
de o parte SAU EXCLUSIV de cealată (stânga ⨂ dreapta). RG generează elementele
limbajelor prin adăugarea şi înlocuirea de simboluri începând dinspre stânga, respectiv
dinspre dreapta, în procesul derivării la fiecare din cele două cazuri.

Exemplul 3.9. Fie gramatica G3 cu Σ = {a, b} , V = { S, A}, cu producţiile P:


S → aS | aA
A → bA | ε
Această gramatică generează limbajul regulat (şi arhetipal pentru RG):
L = {ambn | m > 0, n ≥ 0}
adică limbajul cu un număr m de simboluri a şi un număr n (diferit de m) de simboluri b – ca
şir de a compact cu şir de b compact concatenate (atenţie: cel mai scurt cuvânt este a).
Se observă că a doua regulă de mai sus prezintă variabila A şi în stânga şi în dreapta →,
adică A derivă prin ea însăşi, caz în care regula/producţia se numeşte recursivă. Pentru
gramaticile regulate o producţie recursivă derivă o formă propoziţională (adică cea din

76
dreapta →) cu variabila [A] alături de terminale doar de o parte sau cealaltă a ei.
Această familie de limbaje este reprezentată (şi recunoscută) de automatele finite de stare
DFA şi NFA, care au memorie doar pentru starea curentă, citesc caracterul curent la intrare (o
singură dată – şi se deplasează la următorul) apoi execută doar o reacţie (ca tranziţie de stare)
funcţie de intrarea citită şi starea curentă (excepţie εNFA), pentru ca în final să accepte (sau
nu) cuvântul de intrare dacă aparţine limbajului pentru care automatul a fost proiectat.
Automatele finite au multe aplicații, între care analiza lexicală a programelor de calculator,
proiectarea circuitelor digitale, căutare în text și recunoașterea formelor. Teorema lui Kleene
arată că limbajele acceptate de automatele finite sunt tocmai acelea care pot fi descrise prin
expresii regulate și sunt generate de gramaticile regulate RG.

3.4.2 Gramatici şi Limbaje Independente de Context


O familie mai largă de limbaje o constituie familia Gramaticilor Independente de Context
CFG (Context Free Grammars) şi limbajelor CFL (Context Free Languages).
Definiţia 3.15 O gramatică independentă de context CFG este cea care acceptă
combinaţii de variabile şi terminale în forma propoziţională derivată, între care cel puţin una
are forma:
A → xy ... XY .... vw ...
Textual, gramaticile independete de context CFG au partea α a regulilor de producţie
formată doar dintr-o singură variabilă iar partea β formată din combinaţii de oricâte variabile
şi oricâte terminale plasate la stânga SAU dreapta (SAU INCLUSIV) variabilelor. CFG
generează limbaje independete de context CFL (Context Free Languages).
Spre deosebire de gramaticile regulate, CFG permit descrierea de şiruri simetrice (precum
palindroamele). Exemplul 3.7 descrie setul de reguli (indirecte) pentru CFG care generează
limbajul simetric 0n1n , dar care poate fi descris şi direct prin exemplul de mai jos.

Exemplul 3.10. CFG G4 = ({a, b}, {S}, S, P) cu producţiile:


S → aSb | ϵ
descrie prin reguli directe limbajul arhetipal L4= {anbn | n ≥ 1} adică:
L4 = {ϵ, ab, aabb, aaabbb, . . .}.

Familia de limbaje CFL este reprezentată de o clasă mai puternică de mașini – automatele
cu stivă PDA (pushdown), care citesc tot (doar) o singură dată caracterul de intrare la poziţia
curentă şi trec la următoarea poziţie iar acceptarea şirului se face folosind în funcţionare o
memorie stivă – potenţial infinită.
Aparent, limbajul ambn acceptat de DFA/NFA nu este diferit de limbajul anbn acceptat de
PDA dar în fapt, la al doilea este necesară memorie pentru contabilizarea caracterelor b spre a
compara numărul lor cu cel al caracterelor a, memorie pe care DFA sau NFA nu o deţin.

3.4.3 Gramatici Sensibile la Context şi Gramatici Nerestrictive


Aceste familii de gramatici au reguli de producţie mai puţin sau de loc restrictive şi sunt
puţin folosite, pentru că au mai mult rol taxonomic (de clasificare).
Am văzut că fiecare familie este reprezentabilă printr-o clasă de Maşini cu Stări Finite,
clasa generică (şi cea mai complexă) fiind Maşina Turing TM, care citeşte fieare caracter din

77
şirul de intrare (de pe banda de intrare) dar poate şi scrie în locaţia respectivă şi poate deplasa
capul de citire spre înainte (dreapta) şi spre înapoi (stânga).

Definiţia 3.16 O gramatică sensibilă la context CSG (Context Sensitive Grammar)


acceptă orice combinaţii de variabile şi terminale, având reguli de producţie de forma:
u→v, unde u, v∈ (Σ∪ V )+, şi |u| ≤ |v|.
Textual, familia CSG au atât partea α cât şi partea β a regulilor de producţie formate din
combinaţii de oricâte variabile şi oricâte terminale, singura condiţie fiind ca partea α să fie cel
mult de lungimea părţii β. O gramatică sensibilă la context generează un limbaj sensibil la
context CSL (Context Sensitive Language).
Exemplul 3.11. Limbajul arhetipal CSL este:
L5 = { anbncn | n > 0 }
generat de gramatica G5 sensibilă la context:
S→ aAbc | abc
A → aAbC | abC
Cb → bC
Cc → cc
Ultima din regulile G5 ilustrează motivul pentru care această familie de gramatici sunt
denumite ―sensibile la context‖ (context-sensitive): C poate fi înlocuit de terminal c doar într-
un context particular (deci dependent de context) – anume când este urmat de un c.
Maşinile care corespund acestor limbaje sunt Automatele Mărginite Linear LBA (Linear
Bounded Automata) – maşini Turing TM la care banda de intrare este mărginită pe porţiuni (şi
nu nemărginită ca la TM) iar lungimea porţiunii este o funcţie liniară de intrare. Prin această
caracteristică LBA sunt un model mai apropiat de funcţionarea calculatoarelor actuale decât
maşinile Turing

Definiţia 3.17 O gramatică nerestrictivă UG (Unrestricted Grammar) G = (Σ, V, S, P),


are fiecare regulă de producţie de forma:
u → v, unde u, v ∈ (Σ ∪ V )+, şi u ≠ ε.
Aşa cum arată şi numele, nu există practic restricţii asupra regulilor de producţie ci doar să
existe partea α (să nu fie şirul vid ε). Aceste gramatici generează familia de limbaje
nerestrictive UL (Unrestricted Languages), care pot fi recunoscute de Maşini Turing TM.
Un exemplu de limbaj generat de o asemnea gramatică este:
L6 = { an | n perfect }
cu n „număr perfect‖ adică un număr întreg pozitiv la care suma divizorilor săi minus
numărul însuși este egală cu numărul; de exemplu 28 are divizorii 1, 2, 4, 7, 14 (proprii) şi 28
(im-propriu) iar suma divizorilor săi este 1 + 2 + 4 + 7 + 14 + 28 = 56, care este 2 × 28.

3.4.4 Ierarhia Chomsky


Cele patru familii de limbaje, generate de gramaticile corespondente, constituie un model
încuibat (nested) cunoscut sub numele de „Ierarhia Chomsky‖ (Chomsky Hierarchy), o
clasificare ce permite flexibilitate în definirea unei reguli de producţie.
Pentru un alfabet Σ dat, cele patru familii se pot reprezenta una incluzând pe cealaltă şi
toate incluse în mulţimea putere a Σ*, adică în mulţimea tuturor limbajelor posibile peste acel

78
alfabet:
RL ⊂ CFL ⊂ CSL⊂ UL ⊂ P(Σ*)

În Tabel 3.3 se prezintă sintetic familiile de limbaje cu tipul numeric în care le-a încadrat
Chomsky, cu specificul producţiilor, cu exemple arhetipale şi automatele respective.

Tip Gramatici Reguli Producţie Exemplu de Limbaj Automate


0 Nerestrictive α→β { an | n perfect } Maşini Turing TM
1 Sensibile-Context αAβ → αγβ {anbncn , n ≥ 0} TM Mărginite Linear LBA
2 Indep. de Context A→γ {anbn , n ≥ 0} Automate Stivă PDA
3 Regulate A → ϵ | a | aB {ambn, m>0, n ≥ 0} Maşini cu Stări Finite NFA

Tabel 3.3 Ierarhia Chomsky cu exemple de limbaje arhetipale şi automate.

În figura de mai jos (Figura 3.16) este reprezentată intuitiv incuibarea familiilor de limbaje
formale20 dincolo de ierarhia Chomsky, cu indicarea maşinii cu stări finite corespondente şi
caracteristici eventuale – de exemplu maşini Turing care se opresc-halt (sau nu), recursivitate
şi enumerabilitate, ce limbaje/probleme nu sunt decidabile.

Figura 3.16 Limbaje formale dincolo de ierarhia Chomsky.

Privind relaţia dintre limbaje formale şi maşini cu stări finite (pentru fiecare familie) se
pune întrebarea: fiind dat un limbaj de un tip anume, care este complexitatea necesară a
maşinii abstracte corespondente pentru a recunoaşte elementele/cuvintele acelui limbaj?
Deasemenea, se pune întrebarea la ce nivel se află decidabilitatea pentru un tip Chomsky
anume de limbaj? Apar adică patru probleme17:
1. Problema recunoaşterii:
Fiind dat un şir w şi o gramatică G, se află w∈ L(G)?
2. Problema inexistenţei (vidului – lipsei) limbajului:
Dată fiind o gramatică G, este L(G) = ?
3. Problema echivalenţei:
20
Ananth Kalyanaraman, Automata and Formal Languages, Washington State University, 2017

79
Pentru două gramatici date G1 şi G2, este L(G1) = L(G2)?
4. Problema ambiguităţii:
Dată fiind o gramatică G, este G ambiguă?

În Tabel 3.4 se indică pentru fiecare din aceste probleme şi pentru fiecare tip de limbaj în
ierarhia Chomsky dacă problema este decidabilă sau nu.

Tip Problema: (D = decidabil, N = ne-decidabil)


1. Recunoaştere 2. Vid 3. Echivalenţă 4. Ambiguitate
0 N N N N
1 D N N N
2 D D N N
3 D D D D

Tabel 3.4 Decidabilitatea problemelor la Ierarhia Chomsky.

Ierarhia Chomsky este un concept important în științele cognitive deoarece oferă o


modalitate utilă de evaluare a abordărilor teoretice la nivel computațional şi un instrument
pentru determinarea complexităţii unei anumite gramatici în raport cu alte modele. Prin ea se
pot clasifica limbajele formale în funcție de complexitatea și expresivitatea lor și astfel ajută
la dezvoltarea algoritmilor de analiză și a altor instrumente pentru lucrul cu limbaje formale în
informatică și lingvistică.

80
4 Calculabilitate şi Complexitate

Calculul efectuat cu maşini amplifică şi diversifică gândirea umană. Prin folosirea


calculatoarelor moderne se accelerează accesul, producerea şi prelucrarea informaţiilor, ba
chiar puterea de raționament a omului creşte la un nivel calitativ diferit de cel pe care îl aveam
fără aceste mașini. Există patru teorii majore sub termenul umbrelă „Teoria calculului‖
(Theory of Computation), din care două sunt fundamentale şi instrumentale:
1. Teoria limbajului - cum sunt exprimate calculele?
2. Teoria automatelor - cum se efectuează calculele?
Următoarele două au anumite specificități de studiu şi evaluare:
3. Teoria calculabilității - care sunt limitele fundamentale ale calculului?
4. Teoria complexității - ce resurse sunt necesare pentru a efectua anumite calcule?
Teoriile 3 şi 4 nu sunt instrumentale – în sensul că nu sunt folosite curent spre a produce
rezultate prin calcule, ci spre a evalua posibilitatea de rezolvare a problemelor prin calcul şi a
evalua resurse pentru calcul: timp, memorie, echipament. Dacă 3 caută răspuns la „ce poate fi
calculat?‖, 4 caută răspuns la „cât de bine poate fi calculat?‖

4.1 Calculabilitate - Decidabilitate


Reluăm caracterizarea unei Probleme începută la §1.3.1 dar pe un plan superior, folosind
cunoştinţele căpătate până aici:
I. O problemă este o sarcină de rezolvare prin (1) o metodă ce pune în corespondenţă
(„mapare‖) valori (instanţieri) sau (2) o metodă ce transformă un set de intrări către un
set de ieşiri – prelucrări de valori. Dacă intrările şi ieşirile sunt generice atunci avem
rezolvarea unei clase de probleme iar dacă intrările sunt cu valori date (instanţiate)
atunci avem rezolvarea doar a unei instanţe a problemei.
II. Problema este adesea văzută ca o funcţie matematică (o relaţie): intrările sunt domeniul
de definiţie (domain) iar ieşirile domeniul în care funcţia ia valori (range). Intrările şi
ieşirile – fiind şiruri de simboluri (cuvinte), putem considera o problemă un limbaj; la
o problemă de decizie, ieşirea este Da/Nu – cuvânt de intrare acceptat/neacceptat.
În Teoria Calculabilității o funcție poate fi reprezentată ca un șir de simboluri care s-ar
putea prelucra cu o mașină (din intrări se obţin ieşiri). Însă, există un program pentru fiecare
funcție? răspunsul este nu. Există funcții care nu pot fi calculate de o mașină de calcul.
Dar ce funcții pot fi calculate? De pe la începutul sec. XX diverşi cercetători au creat, de-a
lungul anilor, multe modele de calcul: calculul Lambda, sistemele post-producție, gramaticile
structurii frazelor, funcțiile recursive parțiale, mașinile cu acces aleatoriu și altele. După ce
Alan Turing a dat o definiție formală unui proces de calcul, toate metodele amintite s-au
dovedit a fi egale ca putere cu mașina Turing (privind ceea ce pot calcula). Adăugarea ne-
determinismului la mașina Turing sau adăugarea la aceasta a mai multor benzi nu i-a crescut
puterea de calcul. Acestea sugerează că în fapt, clasa funcțiilor calculabile este cea susţinută
de Teza Church-Turing, anume: O funcție este calculabilă dacă și numai dacă există o mașină
Turing care are ieşire pentru orice şir de intrare (de exemplu, îl acceptă sau nu).
Maşina Turing este o formalizare a unui algoritm, astfel că putem defini:
III. Algoritm este o metodă sau un proces de rezolvare a unei probleme; există mai mulţi

81
algoritmi posibili pentru aceeaşi problemă: unii mai eficienţi ca alţii – relativ la
necesarul de resurse în rezolvare (timp, memorie, echipament).
IV. Condiţiile unui algoritm sunt:
o Corectitudine – să adreseze explicit problema şi rezolvarea cerută;
o Secvenţă – operaţiile sunt clar definite în paşi (enumerabili);
o Ambiguitate zero – privind paşii necesari (următori) în proces;
o Număr finit de paşi – orice secvenţă este fezabilă (finită);
o Oprire – procesul se încheie (nu apar bucle infinite).
În teoria calculabilităţii și teoria complexității computaționale, o problemă de decizie are
un răspuns: da ori nu, în funcție de valorile unor parametri de intrare. De exemplu, problema
„date două numere x și y, împarte x egal pe y?‖ este o problemă de decizie. Răspunsul depinde
de valorile (instanţierile) pentru x și y.
Însă decidabilitatea se poate referi la întrebarea există o metodă eficientă de a determina
măcar dacă o problemă are soluţie? De exemplu, aparţine un obiect la o mulțime? Multe
dintre problemele importante din matematică sunt ne-decidabile.
În logica matematică decidabilitatea priveşte două concepte:
- decidabilitatea logică referitoare la demonstrarea adevărului unei propoziţii sau a
negaţiei ei; propoziţia este indecidabilă dacă pentru unele instanţieri este adevărată şi
pentru altele falsă (în contexte faptic corect şi valid);
- decidabilitate algoritmică referitoare la existenţa unei proceduri mecanice (reţete) care
se încheie după un număr finit de paşi şi răspunde Da ori Nu problemei date.
Problemele de decizie sunt strâns legate de problemele funcționale, care pot avea
răspunsuri mai complexe decât un simplu „da‖ sau „nu‖. O metodă de rezolvare a unei
probleme de decizie dată sub forma unui algoritm se numește procedură de decizie pentru
acea problemă. O procedură de decizie pentru exemplul de mai sus ar corespunde cu pașii
prin care se determină restul împărţirii lui x prin y şi verificarea dacă acesta este 0 (da/nu). O
problemă de decizie care poate fi rezolvată printr-un algoritm se numește decidabilă.

În cazul problemei de decizie pentru exemplul cu divizorii, se dă o mulţime Z1 de numere


întregi iar problema de decizie este o relaţie:
(Z1  Z1)  {0,1}, unde 0 indică „rest 0 → divide‖ iar 1 indică „rest  0 → nu divide‖.
O problemă de decizie este orice întrebare arbitrară pe un set infinit de intrări. Din această
cauză, este obişnuit să se definească problema de decizie în mod echivalent ca: setul de intrări
pentru care problema returnează „da‖. Intrările pot fi șiruri de caractere peste un alfabet:
binar: {0,1} sau o altă mulţime finită de simboluri {a, ... z}. Subsetul de șiruri pentru care
problema returnează „da‖ este un limbaj formal și adesea problemele de decizie sunt definite
în acest fel ca limbaje formale. În acest caz, problema de decizie este o partiţie a domeniului
de intrare (aici mulţimea cuvintelor – şiruri, combinaţii de simboluri) care fac parte din limbaj
şi sunt acceptate, respectiv care nu fac parte din limbaj – şi nu sunt acceptate.
În acest context, Charles Hughes face o argumentare 21 asupra ne-decidabilităţii, (şi ne-
calculabilităţii) problemelor funcţionale din care rezultă (adică de ce unele problemele sunt
ne-decidabile/ne-calculabile), fără a se folosi de maşina Turing. Astfel:

21
Charles E. Hughes, Computability & Complexity Theory, University of Central Florida, 2015

82
1. Fiind dat un alfabet Σ peste care se construişte limbajul exhaustiv Σ*, mulţimea
limbajelor posibile este P(Σ*) = 2Σ*.
2. Am văzut la Propoziţia 2.1. că, în timp ce Σ este finit, Σ* este infinit dar numărabil,
3. însă mulţimea tuturor limbajelor posibile P(Σ*) este infintă şi ne-numărabilă.
4. Un limbaj L definit peste alfabetul Σ este o submulţime a Σ*, deci numărabil:
L ⊂ Σ* , | L | ≤ | Σ* | < | P(Σ*) |
5. Un program P în limbajul de programare L poate fi reprezentat ca un şir de caractere
peste alfabetul ΣP – cu respectarea regulilor de construcţie a programului conform limbajului
L. Pentru că PΣ*P, există cel mult un număr infinit şi numărabil de programe care pot fi
realizate cu limbajul de programare L, conform pct. 2 .
6. Fiecare program P defineşte în limbajul L („programează‖) o funcţie FP: Σ*I → Σ*O,
unde ΣI este alfabetul de intrare şi ΣO alfabetul de ieşire.
7. Corespunzător intrărilor efective furnizate programului P se defineşte un limbaj de
intrare PI pentru care funcţia FP este proiectată – producând oprire şi ieşire (acceptare). În
terminologia funcţiilor, acesta este domeniul de definiţie (domain) şi este conţinut în ΣI – care
este universul de discurs, iar domeniul în care funcţia FP ia valori (range) este
PO = {y |  x PI şi y = FP (x)}.
8. Pentru că pot exista doar o mulţime numărabilă de programe P, există cel mult o
mulţime numărabilă de funcţii FP şi ca urmare un număr anume de limbaje de intrare PI şi de
ieşire PO asociate – adică mulţimi numărabile de fiecare asemenea limbaje definite pentru
oricare program P.
9. Dar în fapt am văzut că numărul de limbaje posibile este ne-numărabil (pct. 3) pentru
un alfabet finit dat.
10. Rezultă, din pct. 8 şi 9, că există (şi alte) limbaje peste alfabetul dat care nu au
descriere în termeni de program (sau de algoritm), altfel zis, există doar o mulţime numărabilă
de limbaje calculabile în mulţimea ne-numărabilă a limbajelor posibile.
Problema enumerării, elementelor unei mulţimi sau cuvintelor unui limbaj, este importantă
pentru că astfel se pot desfăşura mulţimea sau limbajul şi descoperi dacă un element/cuvânt se
află în mulţime/limbaj. Pentru enumerarea facilă se pot folosi metode precum cea din
Propoziţia 2.1. pentru a se face ordonarea lexicografică şi corespondenţa cu mulţimea N.
Introducem noţiuni din calculabilitate, începând cu limbaje semi-decidabile – adică ale
căror cuvinte sunt enumerate unul câte unul printr-un algoritm A.
Definiţia 4.1 Un limbaj L ⊂ Σ* este recursiv-enumerabil RE (sau semi-decidabil sau semi-
calculabil) dacă există un algoritm A care enumeră cuvintele lui L.
Dacă limbajul este infinit, atunci un astfel de algoritm de enumerare nu se termină. Se
poate da o definiție echivalentă limbajelor semi-decidabile, în care algoritmul ia un cuvânt ca
intrare și răspunsul este; Da-aparţine L ori Nu-aparţine L.
Definiţia 4.2 Un limbaj L ⊂ Σ* este recursiv (sau decidabil, sau calculabil) dacă există un
algoritm A care, avînd ca intrare un cuvânt wΣ, se termină și produce: Da w aparţine L ori
Nu. Spunem că „algoritmul A decide limbajul L‖.
Evident, orice limbaj decidabil este și semi-decidabil; dar nu orice limbaj este neapărat
semi-decidabil și nu orice limbaj semi-decidabil este neapărat decidabil.

83
Pe de altă parte, orice limbaj regulat este decidabil – însemnând că se poate determina
preccis dacă un şir dat aparţine sau nu limbajului.
Pentru un limbaj regulat, chiar infinit, cum este limbajul corespunzător regEx a*b* (oricâţi
de a urmaţi de oricâţi de b) se poate decide dacă un şir de intrare aparţine sau nu limbajului.
De exemplu, s-ar putea folosi un algoritm simplu de a decide limbajul a*b* :
i. citeşte şirul dinspre stânga spre dreapta iar dacă s-a întâlnit sfârşit de şir (NULL)
întoarce ACCEPT (return TRUE).
ii. citeşte şirul până s-a întâlnit un caracter ce nu este a; dacă nu este b întoarce REJECT
(return FALSE).
iii. altfel, continuă citirea până când s-a întâlnit un caracter ce nu este b; întoarce REJECT
(return FALSE).
Avem deci o procedură de decizie privind apartenenţa şirului de caractere de tipul dat la acest
limbaj – limbajul este decidabil.

4.2 Maşina Turing TM


O Mașină Turing TM (Turing Machine) constă dintr-o unitate de control și o bandă infinită
pe care sunt scrise simboluri. Unitatea de control guvernează calculele mașinii având un
număr finit de stări şi tranziții posibile între acestea. Simbolurile de pe bandă sunt citite și
scrise printr-un cap de citire şi scriere – care în continuare va fi numit simplu „cap de citire‖.

Figura 4.1 Maşina Turing TM cu o bandă.


Mașina Turing este o abstractizare a calculatoarului universal (de astăzi): unitatea de
control ar reprezinta [micro]procesorul iar banda – memoria. Numărul finit de stări al
unităţii de control corespunde numărului determinat de stări ale registrelor micro-
procesorului şi dimensiunilor fixe ale lor. Banda reprezintă atât memoria internă cât şi
cea externă. Capul de citire reprezintă magistrala care conectează microprocesorul la
memorie. Spre deosebire de un calculator real, memoria unei mașini Turing este infinită –
dar aceasta ar însemna că se pot adăuga memorii (interne/externe) într-un mod (aproape)
nelimitat unui calculator. O diferență majoră între TM și calculator este că la TM capul
de citire se mișcă doar o poziție la fiecare operație, în timp ce la calculator memoria se
poate accesa într-un mod direct - numit și aleatoriu (random access).
Unitatea de control a TM funcţionează parcurgând seria de stări finite q0, ... qn – o stare la
un moment dat, cu starea q0 stare iniţială sau de start. Calculul efectuat de TM constă dintr-o
serie de etape de calcul, fiecare etapă constând din schimbarea stării unităţii de control,
scrierea unui simbol prin capul de citire/scriere şi deplasarea capului de citire: spre dreapta
(către următorul simbol de pe bandă) sau spre stânga (simbolul precedent). Într-un fel,
tranziţiile ar constitui programul TM.

84
4.2.1 Descriere formală a TM
Definiţia 4.3 O Maşină Turing TM este un 7-tuplu ( Q, Σ, Γ, E, q0, F, #), unde:
 Q = {q0, . . . , qn } este o mulţime finită de stări de control.
 Σ este alfabetuld de intrare, ca mulţime finită de simboluri, care însă nu conţine şi
simbolul blanc #. Acest alfabet este folosit pentru scrierea datelor iniţiale pe bandă.
 Γ este alfabetul benzii, ca mulţime finită ce cuprinde toate simbolurile ce se pot înscrie
pe bandă, adică alfabetul de intrare Σ şi simbolul blanc #.
 E est o mulţime finită de tranziţii de forma (p, a, q, b, x) unde p şi q sunt stări, a şi b
sunt simboluri de bandă iar x est un element al mulţimii {, } – deplasare dreapta,
stânga. Tranziţia poate fi notată şi p, a → q, b, x.
 q0  Q este starea iniţială (de start).
 F este mulţimea de stări acceptoare.
 # este simbolul blanc care, la pornirea TM umple toate poziţiile de pe bandă – altele
decât cele ce conţin date.

O Maşină Turing este deterministă dacă pentru toate stările p şi toate simbolurile a, există
cel mult o tranziţie de forma p, a → q, b, x. În acest caz, mulţimea E a tranziţilor este
denumită funcţie de tranziţie şi notată δ. Astfel, funcţia δ asociază fiecărei perechi (p, a) un
triplet unic (q, b, x) – dacă el există, astfel ca p, a → q, b, x este tranziţia corespunzătoare. În
situaţia în care maşina nu este detereministă, mulţimea E poate fi privită ca funcţia de tranziţie
δ, dar atunci funcţia δ asociază fiecărei perechi (p, a) mulţimea de tripleţi (q, b, x) astfel ca
tranziţia în acest caz va fi p, a → {q, b, x}.
Principiul de lucru al TM este următorul: pe bandă se înscrie, poziţie cu poziţie, un cuvânt
format din simboluri ale alfabetului Σ iar restul poziţiilor se completează cu # blanc. Capul de
citire este plasat pe prima poziţie a şirului de intrare, apoi TM începe calculul până ajunge în
starea în care, eventual, va accepta cuvântul de intrare.

4.2.2 Descriere instantanee şi calcul


Funcţionarea TM are loc prin tranziţii succesive între stări care aduc maşina în configuraţii
anume ale parametrilor denumite (ca şi la PDA) Descrieri instantanee ID (Instantaneous
Descriptions), privind:
- Starea unităţii de control – un element al mulţimii Q;
- Poziţia în care se află capul de citire – simbolul curent de pe bandă;
- Conţinutul benzii – relativ la poziţia capului de citire.

Figura 4.2 ID - descrierea instantanee a TM exemplu.

85
Dacă maşina se găseşte în starea q atunci ID va fi uqv, unde u reprezintă sub-cuvântul din
stânga (poziţiei) capului de citire iar v sub-cuvântul din dreapta, conform Figura 4.2, simbolul
de sub capul de citire fiind primul simbol al v, iar în partea dreaptă a acestuia se află o serie
infintă de # blanc care, la descrirea instantanee ID, nu interesează. Astfel ID este o descriere
finită, adică pentru cazul din Figura 4.2., al TM în starea q ID este abBAbabbqbBAaAB, cu
conţinutul benzii anterior capului de citire abBAbabb şi după bBAaAB (urmat de #). La start,
banda are conţinutul iniţial şi capul de citire pe prima poziţie, astfel că ID este q0w.
Calculul TM decurge în etape, o etapă având o tranziţie din E de la o ID la altă ID, cu:
- schimbarea stării curente,
- scrierea unui simbol în locul celui aflat în poziţia curentă (a capului de citire),
- deplsarea cu o poziţie (a capului de citire)  spre stânga ori spre dreapta .
O tranziţie de forma p, a → q, b, x are loc doar dacă în starea p capul de citire are în poziţia
curentă simbolul a, care va duce TM în starea q şi simbolul a va fi înlocuit pe badă cu
simbolul b după care are loc deplasarea capului conform x =  sau x = .
Definiţia 4.4 O etapă de calcul este perechea de ID.uri (C, C′) notată C → C′ unde:
- fie C = ucpav şi C′ = uqcbv la tranziţia p, a → q, b, ,
- fie C = upav şi C′ = uqbv la tranziţia p, a → q, b, ,
cu c caracterul reluat la calcul în stânga iar a caracterul curent „consumat‖ şi devenit b.
Prezenţa simbolurilor blanc la finalul ID este implicită, astfel că se consideră în locul sub-
şirului v un simbol # dacă v este vid, pentru a face o tranziţie de forma p, # → q, b, x.
De remarcat că o tranziţie de forma p, a → q, b,  (cu → deplasarea capului de citire spre
stânga) nu poate fi aplicată la prima poziţie pe bandă.
Definiţia 4.5 Un calcul este o secvenţă de ID-uri C0 → C1 → · · · → Ck. Un calcul este
acceptat dacă C0 este ID iniţială C0 = q0w, cu w ∈ Σ* şi ID Ck finală, cu Ck = uqv cu q ∈ F.
ID de forma uqv cu q ∈ F este considerată descriere instantanee acceptoare. TM ar putea
continua calculul după o ID acceptoare, dar nu este de interes dacă acceptarea a avut loc.
○ ○

○ ○
○ ○

○ ○

○ ○
● ○○ ●○ ○ ○ ○ ○ ○
DTM NTM
Figura 4.3 Traseul de stări parcurs la DTM şi la NTM până la starea acceptoare.

Secvenţa de ID-uri diferă la TM determinstă faţă de cele la TM ne-deterministă similar


situaţiei secvenţei de stări la automate detereministe DFA faţă de cele ne-deterministe NFA.
În Figura 4.3 sunt ilustrate traseele stărilor parcurse de la starea iniţială prin stări intermediare
(pot fi stări ne-acceptoare ○ dar şi acceptoare ●) până la starea finală acceptoare ●. La TM
Deterministă (DTM) – în stânga, fiecare tranziţie este unic determinată către o stare anume şi
în final la starea acceptoare (traseul este o dreaptă), pe când la TM Ne-deterministă (NTM) –

86
în dreapta, există un arbore de trasee (indicate prin triunghiul ce le cuprinde) ducând către
stări neacceptoare şi doar un traseu (indicat prin curbă) duce la starea acceptoare (pentru
simplitate, mulţimea F a stărilor acceptoare are cardinalitate |F|=1).
Acum se pot redefini conceptele recursiv-enumerabil şi decidabil pe baza TM:
Definiţia 4.6 Un limbaj L este recursiv enumerabil RE (Recursively Enumerable) dacă
există o Maşină Turing M astfel ca L(M) = L; pentru orice cuvânt wL obligatoriu M se
opreşte (halt) dar pentru wL nu este obligatoriu ca M să se oprească.
Definiţia 4.7 Un limbaj L este decidabil dacă există o Maşină Turing M astfel ca L(M) = L
şi se opreşte la toate intrările wL. Spunem că M decide L.

4.2.3 Utilizarea TM
Reamintim că există două categorii principale de probleme (vezi şi §4.1):
I. Problemă de funcţie (Function Problem) care este o abstractizare a relaţiei R între
limbaje peste Σ - alfabet de intrare şi Γ - alfabet de ieşire, adică R  Σ*  Γ*, având
ca scop (task - sarcină) ca la o intrare dată x să găsească ieşirea y cu (x, y)  R.
II. Problemă de decizie (Decision Problem) care este o abstractizare a limbajului L
peste alfabetul Σ cu L  Σ*, având ca scop/sarcină ca la o intrare dată x să decidă
dacă xL. O problemă de decizie relativ la o problemă de funcţie R este definită:
L(R) = {x | ∃ y : (x, y)  R }.
Pe lângă aceste probleme principle mai există două probleme secundare:
III. Problemă de enumerare (Enumerator) care este o acţiune de generare/tipărire a
mulţimii E a tuturor cuvintele unui limbaj L; dacă acestea ar fi ordonate
lexicografic s-ar folosi o funcţie definită peste Σ* cu valori în mulţimea numerelor
naturale N0 (inclus şi 0 pentru că L poate conţine şirul vid ε), astfel ca:
E = {wi | w  Σ*, i  N0, : (w, i) }
deci o problemă de funcţie cu alfabetul de ieşire Σ* (cardinalitate 1) combinată cu
|L| probleme de decizie pentru fiecare cuvânt acceptat de L.
IV. Problemă de verificare (Verifier) care este o acţiune de certificare prin cuvântul c
dat (denumit martor – witness sau certificat – certificate) a existenţei limbajului L
(cL), adică se decide „problema opririi‖ (halting problem) în cazul limbajului L.
Ca urmare, există patru moduri de a folosi mașinile Turing: în mod calculator, în mod
acceptor, în mod enumerator şi în mod verificator.

În modul calculator, un cuvânt de intrare este furnizat mașinii și aceasta returnează unul
sau mai multe cuvinte de ieșire, ca pentru o problemă funcţie. Când TM oferă întotdeauna un
singur cuvânt de ieșire, atunci calculează valoarea funcției - cuvântul de ieșire, pentru
cuvântul de intrare dat. Cuvintele de ieșire sunt prin convenție conținutul benzii ultimelor ID-
uri ale calculelor acceptate. Prin urmare, se înscrie la început cuvântul de intrare pe bandă,
mașina efectuează calcul până când ajunge într-o stare finală în care conținutul benzii este
cuvântul de ieșire corespunzător.
Definiţia 4.8 O funcţie f : Σ*→ Σ* este o funcţie calculabilă dacă există o Maşină Turing M
astfel ca la intrarea w obligatoriu M se opreşte (halt) cu f(w) înscris pe bandă.
Definiţia 4.9 Fie A şi B limbaje. O reducţie (reduction) de la A la B este o funcţie

87
calculabilă f : Σ*→ Σ* astfel încât wA ddacă f(w)B. Spunem că A este reductibil la B şi
notăm A  B, dacă există o reducţie f de la A la B.
Reducţia pune în legătură complexitatea limbajelor urmărind să transforme instanţe din
domeniul lui A în domeniul lui B; dacă se poate obţine această transformare se poate
soluţiona A cu ajutorul lui B. Anticipând chestiunea complexităţii (prezentată la §4.3) putem
spune că soluţionarea B are cel puţin acelaşi grad de dificultate ca A; de aceea A  B dar
aceasta înseamnă şi că dacă B este decidabil şi A este decidabil; dacă B nu este decidabil nici
A nu este decidabil.

În modul acceptor, un cuvânt de intrare este furnizat mașinii și acesta răspunde da ori nu.
Când TM răspunde da, spunem că aparatul acceptă cuvântul. Prin structura unităţii de
comandă mașina definește apoi setul de cuvinte care sunt acceptate. Prin convenție, se spune
că mașina acceptă un cuvânt w dacă există cel puțin un calcul care acceptă w ca intrare, adică
care începe cu configurația q0w. Elementul important al acestei definiții este că un singur
calcul de acceptare este suficient pentru ca mașina să accepte chiar dacă alte calcule se
blochează sau nu ajung niciodată la o configurație de acceptare; evident, acesta este modul de
lucru pentru o maşină Turing ne-determinstă.
Definiţia 4.10 Spunem că w, un cuvânt din Σ*, este acceptat de o mașină Turing M dacă
există un calcul acceptant cu ID inițială q0w. Mulțimea cuvintelor acceptate de M este
limbajul acceptat şi se notează L(M).
La o TM deterministă, există cel mult un singur calcul de acceptare și deci cel mult un
singur cuvânt de ieșire. La o TM ne-deterministă (NTM) există mai multe calcule (pe mai
multe fire de execuţie), unele ducând la acceptare altele nu, similar funcţionaării NFA – vezi
Figura 2.14. şi Figura 4.3. De remarcat, la fel ca în cazul automatelor, noțiunea de acceptare la
NTM este asimetrică: dacă există atât calcule de acceptare, cât și de neacceptare pentru
aceeași intrare, acceptarea este cea care contează. Această asimetrie pune probleme la
complementare. Ca și în cazul automatelor, trebuie să reducem NTM la una deterministă.

În modul enumerator TM face de fapt tipărirea şirurilor acceptate într-un limbaj L pe o


badă de ieşire – adică desfăşoară/înşiruie toate cuvintele posibile al L ⊂ Σ*. Ca enumerator,
TM este prevăzut în plus cu un dispozitiv de tipărire şi o stare de tipărire în care intră de
fiecare dată când un cuvânt wL(TM) – în caz contrar w nu este tipărit. În mod normal, TM
ca enumerator trimite la tipărire cuvinte în orice ordine şi de mai multe ori.
Astfel, cu o maşină Turing se poate „descoperi‖ dacă un cuvânt w dat aparţine sau nu L,
prin enumerarea acestuia şi a complementului său L. Un limbaj L este enumerat de o TM
ddacă este recursiv enumerabil.

În modul verificator TM este util atât în definirea clasei de complexitate NP (polinomial


ne-determinist – v. §4.3.1) cât şi pentru stabilirea decidabilităţii unui limbaj L pentru NTM.

Deşi există variante ale maşinii Turing precum TM universală, TM cu bandă bi-infinită,
TM cu mai multe benzi, acestea nu o fac „mai puternică‖.
Specificul TM cu „memorie‖ de intrare-prelucrare-ieşire ca bandă şi faptul că accesul unei

88
„celule de memorie‖ se face doar de la o poziţie la alta (deplasare stânga ori dreapta) aduc
limitări în funcţionarea unităţii de control al TM – care, la rândul ei, are memorie doar pentru
starea curentă şi este un automat finit. Spre deosebire de TM, calculatoarele actuale permit
accesul direct la celulele de memorie după dorinţă (aleator) prin adresă în RAM (Random
Access Memory). Pe de altă parte şi memoria de program (adică de control) al calculatorului
este mult extinsă iar controlul este mult mai flexibil.
TM este o maşină de calcul abstractă – un model de calcul, cu utilitate în definirea
conceptelor legate de calculabilitate: decidabilitate, solvabilitate, complexitate.

4.3 Complexitate
Teoria complexității priveşte studiul dificultăţii problemelor de calcul, pe de o parte
privind determinarea necesarului de resurse (timp, memorie), pe de altă parte privind
raportarea la dificultăţi relative între probleme22. Primul tip de obiective se referă la răspunsuri
„absolute‖ referitoare la fenomene de calcul specifice (individualizate), în timp ce al doilea tip
se preocupă de situaţii „relative‖ dintre fenomene computaționale în evaluare aproximativă şi
asimptotică – adică pentru volume de mari date (ce tind spre infinit). De fapt, nerezolvarea
întrebărilor de tip absolut a condus la succesul metodelor de tip relativ.

Exemplul 4.1. Fie o problemă simplă care se rezolvă folosind două metode diferite (doi
algoritmi diferiţi), pentru comparaţie: înmulţirea a două numere ab. Pentru a =652 şi b=435,
vom aplica algoritmul A1 – adunarea repetată şi apoi algoritmul A2 – metoda de şcoală –
ilustrate în Tabel 4.1. Se observă că pentru A1 avem de efectuat a-1=651 operaţii de adunare
(limita superioară) sau b-1=434 operaţii (limita inferioară) – caz prezentat în tabel. Pentru A2
avem însă doar 9 înmulţiri de câte o cifră (eventual adunare transport de 9 ori) şi 3 operaţii de
adunare deci cel mult k=21 de operaţii. Evident, A2 este mai eficient ca A1.

Adunări repetate A1 Metoda de şcoală A2


652 + 6 5 2 
652 + 4 3 5
652 + 3 2 6 0
de încă 432 + 1 9 5 6
de ori 2 6 0 8
283620 2 8 3 6 2 0

Tabel 4.1 Metode de înmulţire a două numere.

Numărul de operaţii de bază (adunări şi înmulţiri cu cifre) pentru două numere generice de
rang n (numere cu n cifre cuprinse între 10n-1 şi 10n) va fi de cel puţin n10n-1 pentru adunări
repetate şi de cel mult 2n2 pentru metoda obişnuită (de şcoală). Pentru numere de rang n=11
un calculator de buzunar aplicând A2 va fi mult mai rapid decât un super-calculator aplicând

22
Oded Goldreich, A brief overview of Complexity Theory, 2005,
https://www.wisdom.weizmann.ac.il/~oded/cc-over.html

89
A1. Rezultă deci că eficienţa unui algoritm este mult mai importantă decât tehnologia de
calcul utilizată23.
Teoria complexității nu a reușit să determine complexitatea intrinsecă a problemelor, cum
ar fi determinarea satisfiabilităţii unei formule propoziționale date sau colorarea în contrast a
hărţilor (grafurilor), dar a stabilit că aceste două probleme de calcul, aparent diferite, sunt
echivalente din punct de vedere computațional (de calcul). Din experiența obişnuită, se ştie că
este mai greu să rezolvi o problemă decât să verifici corectitudinea unei soluții (existente).
Teoria complexităţii caută astfel să descopere dificultatea de rezolvare a unei probleme (în
special la un număr mare de date de intrare) fără a soluţiona problema ci a o compara cu alta
(din aceeaşi clasă sau din clase diferite) şi a răspunde la întrebări de tipul: este rezolvabilă
problema? Dacă da, cât de complexă este în comparaţie cu o altă problemă? Există probleme
şi probleme, astfel că se poate pune şi întrebarea: este rezolvarea mai facilă decât verificarea?

4.3.1 Parametri ai complexităţii algoritmilor


Complexitatea se referă la nivelul de dificultate în rezolvarea problemelor sau, echivalent,
eficienţa algoritmilor. Complexitatea se referă la următoarele aspecte:
1. Dimensiunea intrărilor: numărul n de elemente de intrare pentru care se doreşte
rezolvată problema. Uneori, se poate defini ca numărul de biți necesari pentru a stoca
mărimile de intrare, care deşi este incomod fiind la un nivel scăzut, este mai precis
decât numărul de elemente pentru că nu ignoră dimensiunea elementelor individuale
care vor fi prelucrate. De modul de reprezentare a dimensiunii intrărilor depinde
funcția f(n) care descrie complexitatea timpului de execuţie a unui algoritm.
2. Complexitatea algoritmică: numărul de pași necesari pentru a rezolva o problemă. De
fapt, aceasta determină cât timp este necesar pentru a rezolva problema. Un algoritm în
mai mulți pași este complex și mai costisitor decât un algoritm cu pași mai puţini. Un
algoritm recursiv are puţini paşi dar este mai greu de înţeles decât unul descriptiv cu
mai mulţi paşi; în plus, primul pune probleme de memorie (dimensiunea stivei).
3. Complexitatea timpului: durata de execuţie pentru obţinerea soluţiei problemei
(running time). Timpul este o resursă importantă și un algoritm este considerat mai bun
dacă rezolvă problema în timp mai scurt.
4. Complexitatea spațiului: volumul de memorie solicitat; de exemplu, algoritmul care
implică o dimensiune mare a stivei este mai complex în termeni de spațiu. Acest lucru
se datorează faptului că există resurse limitate de spațiu pentru calcul. Deci, ar trebui să
existe o echilibrare între timp, pași și spațiu pentru un algoritm bun.
Algoritmul cu rezultatul fiecărei operații determinat în mod unic este cunoscut drept
algoritm determinist. Algoritmul al cărui rezultate nu sunt definite în mod unic, dar sunt
limitate la un mulţime specificată de posibilități este cunoscut drept algoritm nedeterminist.

Complexitatea timpului în cazul cel mai defavorabil al unui algoritm este o funcţie:
T(n): N →N
unde T(n) este numărul maxim de paşi în oricare din execuţiile algoritmului la intrări de
dimensiune n. Intuitiv, timpul cantitativ necesitat de execuţia unui algoritm depinde de

23
Sanjeev Arora, Boaz Barak, Computational Complexity, Cambridge University Press, 2009

90
cantitatea intrărilor: sortarea unui set mare de date necesită mai mult timp decât la un set
restrâns; înmulţirea matricilor mari durează mai mult decât a celor de mici dimensiuni.
Pentru diferite cazuri de algoritmi dependenţa timpului consumat nu este neapărat liniară
faţă de volumul intrărilor – adică durata nu creşte într-o proporţie constantă cu creşterea n. În
cazul algoritmului A2 din Exemplul 3.11, creşterea este polinomială 2n2 – suită de termeni,
fiecare fiind factori de constante şi puteri ale n, cum ar fi n2 + 2n + 1 ca dependenţă posibilă a
timpului pentru un alt algoritm.

Figura 4.4 Funcţii ce pot exprima dependenţa timp – dimensiune n intrări24.

La valori mari ale lui n termenul de putere 1 şi termenul liber, ba chiar şi coeficientul
termenului de putere 2 pot fi neglijaţi (nu au influenţă notabilă), astfel că la dependenţa
polonomială interesează doar termenul n2 (cu coeficient 1). O dependenţă exponenţială 2n faţă
de una polinomială n2 prezină o creştere mult mai mare (vezi Figura 4.4); cu atât mai mult o
dependeţă exponenţială de forma 10n-1 – cum este la algoritmul A1 din acel exemplu, creşte
incomparabil mai repede ca cea polinomială. În Figura 4.4 eticheta „1‖ este reprezentarea in-
dependenţei timpului de execuţie de dimensiunea n a intrării – caz puţin probabil în realitate.
În concluzie, dacă dimensiunea intrării este n, timpul necesar poate fi exprimat în funcție
de n. Deoarece timpul necesar pentru diferite intrări de aceeași dimensiune poate fi diferit,
complexitatea timpului în cel mai defavorabil caz T(n) este definită ca fiind timpul maxim
luat pentru toate intrările de dimensiunea n. Dacă T(n) este un polinom în n, atunci algoritmul
se spune că este un algoritm de timp Polinomial şi face parte din clasa P.
Teza Cobham-Edmonds susține că o problemă poate fi rezolvată cu o cantitate fezabilă de
resurse dacă admite un algoritm de timp polinomial – altfel spus, problema admite un
algoritm eficient, problema este considerată „uşoară‖. O problemă de decizie de acest tip
aplicată maşinii Turinig (deterministă) este rezolvată în timp polinomial.
Pe de altă parte, o problemă de decizie poate avea cazuri pentru care există răspuns „da‖
(dar şi unele „nu‖), adică au algoritmi ne-determinişti. Dacă pentru un astfel de algoritm
există o demonstraţie care poate fi verificată în timp polinomial, se spune că problema este
decisă printr-un algoritm de timp Polinomial-Nedeterminist şi face parte din clasa NP
(Non-deterministic Polynomial). Aceasta înseamnă că, dacă cineva oferă o instanță a
problemei și certifică răspunsul „da‖, se poate verifica în timp polinomial corectitudinea. O
24
https://codeyz.com/algorithms/the-big-o-notation

91
problemă de decizie de acest tip se consideră cu rezultat al funcţionării unei maşini Turing ne-
deterministe. Deoarece mașinile Turing deterministe sunt mașini Turing speciale ne-
deterministe, rezultă că fiecare problemă din clasa P este membră a clasei NP.
Exemplul 4.2. O problemă din clasa NP este factorizarea unui întreg; date numerele întregi
a și b, există un număr întreg c cu 1 < c < b astfel încât c împarte întreg pe a (c este divizor al
a)? Aceasta este o problemă de decizie deoarece răspunsul este da ori nu. Dacă se furnizează
o instanță a problemei (deci se dau numere a și b) și un număr întreg c care se susține că este
divizor al a, se poate verifica în timp polinomial aceasta prin efectuarea operaţiei a/c.
Clasa de complexitate NP conține multe probleme pentru care se doreşte (la fiecare în
parte) o rezolvare eficientă dar pentru care nu se cunoaște un algoritm eficient; astfel este
problema satisfiabilităţii booleene (vezi §1.4.2 la final) sau problema drumului hamiltonian
(găsirea unui traseu prin toate vârfurile unui graf parcurgând arce o singură dată).

4.3.2 Evaluare absolută şi relativă a complexităţii algoritmilor


Am văzut la Exemplul 4.1 că pentru rezolvarea unei probleme putem avea mai mulţi
algoritmi, unul mai eficient ca altele. Totuşi, pentru un acelaşi algoritm A, timpul de rulare
(running time) depinde de structura intrărilor (modul de „aranjare‖ a celor n piese de date):
rularea poate fi rapidă – favorabilă, sau lentă – defavorabilă, la acelaşi n (Figura 4.5):
1. Cazul cel mai favorabil – complexitatea rezolvării problemei pentru cea mai bună
(prietenoasă) structură a intrării de dimensiune n – timp minim de execuţie pentru A.
2. Cazul mediu – complexitatea pentru diverese intrări (aleatoare), de aceea definită în
raport cu o distribuție de probabilitate peste intrări. De exemplu, dacă se presupune că toate
intrările de aceeași dimensiune sunt la fel de probabil să apară, complexitatea medie a cazului
poate fi definită în raport cu distribuția uniformă pe toate intrările de dimensiune n.
3. Cazul cel mai defavorabil – complexitatea rezolvării problemei pentru cea mai dificilă
(neprietenoasă) structură a intrării de dimensiune n – timp maxim de execuţie pentru A.

Figura 4.5 Timp de rulare pentru un algoritm A, funcţie de structura intrărilor.

Există şi o evaluare „ponderată‖ – relativ la timpi de rulare, pentru cazurile intermediare:


4. Analiza amortizată, care ia în considerare atât operațiunile cu un cost de timp ridicat, cât
și cele cu cost de timp scăzut peste întreaga serie de operații ale algoritmului.
Aceste cazuri dar şi încadrarea algoritmilor în clase P şi NP se referă la o caracterizare
„absolută‖ a algoritmilor. Din păcate, nu se poate face întotdeauna o asemnea caracterizare
92
sau chiar dacă se face este un efort mare care nu aduce informaţie relevantă prvind evaluarea
complexităţii pentru o decizie practică – algoritm „greu‖ sau „uşor‖, fezabil sau nu.
O caracterizare „relativă‖ a algoritmilor – cu referire mai generală la dificultatea acestora
dar şi cu posibilitatea de comparaţie între ele, este aşa-zisa notaţie asimptotică, prin care se
evaluează diferiţi algoritmi A1 .. Am pentru rezolvarea aceleaşi probleme, prin intermediul
funcţiilor de „mărginire‖ relative la „complexitatea timp‖ (durata de rulare) a algoritmilor
respectivi, pentru n foarte mare (n →∞): mărginire superioară, inferioară, altele.
Astfel, pentru a compara şi clasifica timpul de calcul (sau resurse similare, cum ar fi
consumul de spațiu de memorie), sunt de interes limitele superioare (și/sau inferioare) ale
funcţiilor de n ce modelează dependenţa timpului de rulare al fiecărui algoritm A1 .. Am.
Complexitatea unui algoritm este de obicei considerată a fi complexitatea sa în cel mai
defavorabil caz, dacă nu se specifică altfel.
Pentru a indica o limită superioară a complexității timp T(n) a unei probleme, este suficient
să arătăm că există un anumit algoritm cu timp de rulare cel mult T(n). Pe de altă parte,
demonstrarea limitelor inferioare este mult mai dificilă, deoarece limitele inferioare fac o
afirmație despre toți algoritmii posibili care rezolvă o problemă dată: pentru a indica o limită
inferioară a lui T(n) pentru o problemă, este necesar să se arate că niciun algoritm nu poate
avea o complexitate de timp mai mică decât acel T(n) – adică nu doar algoritmii cunoscuți
astăzi ci şi orice algoritm care ar putea fi descoperit în viitor.
Măsurarea experimentală a timpului consumat de algoritm introduce dependenţa de
hardware/software, în sensul că va conta maşina pe care se rulează programul, limbajul în
care algoritmul este programat – care nu ţin de calitatea intrinseca a algoritmului şi de aceea
se preferă o estimare matematică a numărului de paşi parcurşi de algoritm, asociat T(n). Dar
numărul exact de paşi este dificil de calculat şi se impun o serie de simplificari prin care se
ţine cont numai de operatiile critice din algoritm (acele operatii care prin natura lor sunt foarte
consumatoare de timp, sau prin faptul ca sunt efectuate de un numar semnificativ de ori); de
exemplu, într-un algoritm de sortare o operaţie critică este comparaţia între elemente, pentru
că se produce de foarte multe ori. De aceea, nu se face un calcul efectiv al numărului de paşi
ci interesează ―cam de ce ordin‖ este funcţia de complexitate f(n) – funcţie modelatoare a
complexităţii faţă de n. Altfel spus, interesează cum creşte funcţia de complexitate f(n),
„ordinul de creştere‖ (cât de repede / cum creşte? - liniar, logaritmic, exponenţial), pentru a
deduce cum se va comporta algoritmul la dimensiuni mari ale intrărilor, acolo unde
diferenţele se simt cel mai puternic.
În practică, problemele au particularităţi care pot conduce la alegerea unui algoritm mai
puţin performant matematic (cu ordin de complexitate mai mare), dar mai performant pentru
necesităţile problemei în cauză – de exemplu dacă un algoritm începe sa fie mai rapid de la
n>1000000 iar problema reală nu ajunge niciodata la un n atât de mare, se alege un algoritm
care în teorie este mai puţin performant dar mai simplu sau mai uşor de controlat.

4.3.3 Notaţii asimptotice


Estimarea „relativă‖ a complexităţii algoritmilor se face prin „ordinul de creştere‖ al
necesarului de resurse (timp, spaţiu), în dependenţă de dimensiunea intrării, prin stabilirea
limitelelor superioare și/sau inferioare ale acestei creşteri. Notaţiile asimptotice folosesc o
literă cu semnificaţie, din categoria numită O-Mare (Big O), prin care se „ascund‖ termenii

93
neglijabili: constante, puteri mici ale n (considerând funcţia modelatoare un polinom). Acest
lucru face ca limitele să fie independente de detaliile specifice ale modelului de calcul utilizat
şi să se poată face comparaţia între algoritmi, independent de maşina pe care ar rula.
Notaţia asimptotică clasifică algoritmii pe baza ratei de creștere relativă la n (mare şi în
creştere) deci nu este utilă pentru analiza intrărilor de dimensiune fixă.
Literele folosite pentru notaţiile asimptotice şi semnificaţiile lor privind mărginirea funcţiei
modelatoare a complexităţii f(n) – adică ordinul dependent de dimensiunea n a intrării (adică
de numărul n de piese de prelucrat), se prezintă sintetic în Tabel 4.2., funcţie modelatoare
evaluată pentru n foarte mari relativ la o altă funcţie g(n) cu creştere cunoscută şi monotonă.

Notaţia Mărginirea f(n) de către g(n) Creşterea comparativă


(Theta) Θ() superioară şi inferioară (bilateral) a f(n) relativ egală cu a g(n)
(O-Mare) O() superioară (bilateral necunoscut) a f(n) mai mică sau egală cu a g(n)
(o-mic) o() superioară (nu bilateral) a f(n) mai mică decât a g(n)
(Omega-Mare) Ω() inferioară (bilateral necunoscut) a f(n) mai mare sau egală cu a g(n)
(omega mic) ω() inferioară (nu bilateral) a f(n) mai mare decât a g(n)
Tabel 4.2 Notaţii asimptotice cu mărginirea creşterii funcţiei de complexitate.

Definiţia 4.11 Notaţiile asimptotice de complexitate cu mărginire se notează şi se definesc:


Θ(g(n)) = { f :N→ R+ | c1, c2R+, c1>0, c2>0, n0N :n≥n0, 0≤ c1g(n) ≤ f(n) ≤ c2g(n)},
cu reprezentare grafică intuitivă în Figura 4.6 (a);
O(g(n)) = { f :N→ R+ | cR+, c>0, n0N : n≥n0, 0 ≤ f(n) ≤ cg(n)}, cu reprezentare
grafică intuitivă în Figura 4.6 (b);
Ω(g(n)) = { f :N→ R+ | cR+, c>0, n0N :  n≥n0, 0 ≤ cg(n) ≤ f(n)}, cu reprezentare
grafică intuitivă în Figura 4.6 (c).

Figura 4.6 Ordine de complexitate cu notaţii asimptotice aferente.

Funcţia de complexitate f(n) se consideră în Figura 4.6 ca funcţie polinomială: sumă de


termeni, fiecare cu factori constanţi şi puteri ale n; de exemplu f(n) = 3n3 + 2n2 + n +5. Aşa
cum am arătat mai sus, nu interesează termenii care ar fi „neglijabili‖ adică puteri mici ale n
sau termeni liberi, astfel că este suficient să evaluăm funcţia de complexitate f(n) faţă de o
funcţie de complexitate g(n)=n3 unde păstrăm doar termenul de putere maximă, mai precis
vom face comparaţia cu cg(n)=5n3, unde c=5. În aceste condiţii este de înţeles graficul
funcţiei f(n) în Figura 4.6, adică având „cocoaşe‖ (astfel arată graficul unei funcţii

94
polinomiale cu mai mulţi termeni), faţă de graficul funcţiei g(n) care este monotonă (are doar
termenul de putere maximă). Tot din aceste motive trebuie determinat un n0 de la care funcţia
f va fi mărginită superior de g: de la n≥n0 funcţia cg este mai mare ca f în cazul (b) iar în
exemplul dat n0=2.
Vom spune f(n)O(g(n)) sau f(n)O(g(n)) însemnând f are ordinul de complexitate
(mărginit superior) al g, pentru că la valori mari ale dimensiunii intrării cg(n) este o limită
superioară pentru f(n); adică algoritmul va avea un timp de execuţie mai mic decât această
limită. În general – pentru orice resursă timp sau spaţiu, înţelegem că algoritmul se va
comporta mai bine decât acea limită.
Similar, f(n)(g(n)) înseamnă că pentru valori n mari ale dimensiunii intrării, cg(n) este
o limită inferioară pentru f(n); algoritmul se va comporta mai rău decât această limită. În cazul
f(n)Θ(g(n)), pentru valori mari ale dimensiunii intrarii, c1g(n) este o limită inferioară pentru
f(n) şi c2g(n) o limită superioară; algoritmul tinde să se comporte ca şi g(n).

Definiţia 4.12 Notaţiile asimptotice de complexitate stricte se notează şi se definesc:


o(g(n)) = { f :N→ R+ |cR+, c>0, n(c)N :  n≥n(c), 0 ≤ f(n) < cg(n)},
cu f(n)o(g(n)) însemnând că g(n) creşte strict mai repede decât f(n);
ω(g(n)) = { f :N→ R+ | cR+, c>0, n(c)N :  n≥n(c), 0 ≤ cg(n) < f(n)},
cu f(n)ω(g(n)) însemnând că f(n) creşte strict mai repede decât g(n).

Astfel, f(n)o(g(n))  (f(n)O(g(n)) /\ f(n)Θ(g(n)).


Similar, f(n)ω(g(n))  (f(n)(g(n)) /\ f(n)Θ(g(n)).

Proprietăţi ale notaţiilor asimptotice de complexitate


Tranzitivitatea
f(n)Ο(h(n)) /\ h(n)Ο(g(n))  f(n)Ο(g(n))
f(n) (h(n)) /\ h(n) (g(n))  f(n)(g(n))
f(n)Θ(h(n)) /\ h(n)Θ(g(n))  f(n)Θ(g(n))
f(n)(h(n)) /\ h(n)(g(n))  f(n)(g(n))
f(n)ω(h(n)) /\ h(n)ω(g(n))  f(n)ω(g(n))
Reflexivitatea
f(n)Ο(f(n))
f(n)(f(n))
f(n)Θ(f(n))
Simetria
f(n)Θ(g(n))  g(n)Θ(f(n))
Antisimetria
f(n)Ο(g(n))  g(n)( f(n))

Exemplul 4.3. În general, funcţia g faţă de care se face evaluarea complesităţii asimptotice
este o funcţie de tipul celor indicate în Figura 4.4. Dăm mai jos eemple de „ordin de creştere‖
corespunzător fiecărei asemnea funcţii de n – dimensiunea intrării algoritmilor.

95
 O(1): Timp constant: timpul de rulare nu depinde de n, astfel că O(1)= O(10)= O(2100),
pentru că chiar dacă constanta este foarte mare nu există creştere cu n.
 O(n): Timp linear: timpul de rulare creşte direct proporţional cu n – fiecare nouă piesă
de date (din intrare) aduce o singură prelucrare în plus.
 O(lg n): Timp logarithmic; creşterea este mai rapidă faţă de timpul linear; în acest caz
avem O(log10 n)= O(ln n)= O(lg n); în mod tradiţional în Informatică, intersează lg n
fiindcă se lucrează în baza-2 – ex. mărginirea celei mai mari creşteri cu n la căutare.
 O(n lg n): ex. mărginirea celei mai mari creşteri cu n la sortare.
 O(n2): Timp pătratic: creştere geometrică cu n – mărginire întâlnită la bucle încuibate.
 O(2n): creştere foarte rapidă cu n – complexitate foarte mare.

Figura 4.7 Ordine de creştere pentru diferite funcţii de mărginire şi eficienţa asociată.

Privitor la notaţiile asimptotice sunt indicate câteva lămuriri: deşi adesea complexitatea
este exprimată prin f(n)O(g(n)) semnul egal nu indică o identitate în acest caz ci este doar un
indicator privind ordinul de complexitate – în acest caz mărginirea superioară; de aceea este
poate mai potrivită exprimarea f(n)O(g(n)). Însă şi exprimarea cu = şi cea cu nu reflectă
suficient situaţia funcţiei de complexitate [timp] pentru că – în cazul ordinului de mărginire
superioară, de fapt f(n) ≤ g(n), cu o constantă de multiplicare, adică nici = nici .
În acest context, se pot citi:
 funcţia f(n) are creştere cel mult logaritmică dacă f(n) = O(log n);
 funcţia f(n) are creştere cel mult pătratică dacă f(n) = O(n 2);
 funcţia f(n) are creştere cel mult polinomială dacă f(n) = O(n k), cu kN, k > 1;
 funcţia f(n) are creştere cel mult exponenţială dacă există c>1 şi dacă f(n) = O(cn);
 funcţia f(n) are creştere cel mult factorială dacă f(n) = O(n!).
Chiar dacă notaţia asimptotică O() ar părea că se referă la cazul cel mai defavorabil (relativ
la structura intrărilor) cel mai adesea ea priveşte „timpul de rulare aşteptat‖ şi nu cazul cel mai
dificil; de exemplu, QuickSort în cazul aleator are complexitatea O(nlogn) pentru timpul de
rulare aşteptat dar şi O(n2) poate fi la fel de adevărat pentru complexitatea cazului celui mai
defavorabil – deci funcţie de scopul evaluării se poate folosi ordinul cu o funcţie sau alta.
Pe de altă parte, notaţia asimptotică nu se referă doar la timpul de execuţie ci la orice
resursă necesară evaluării eficienţei unei prelucrări şi – mai general, la orice funcţie calculată.

96
4.3.4 Clase de complexitate

În proiectarea algoritmilor, analiza complexității resurselor implicate este un aspect


esențial. Am văzut că, în principal interesează performanța timp: cât de repede sau lent
funcționează algoritmul; dar complexitatea unui algoritm descrie eficiența algoritmului şi în
ceea ce privește cantitatea de memorie necesară prelucrării datelor. De aceea, complexitatea
unui algoritm este analizată în două perspective: timp și spațiu.
Complexitatea timpului este o funcție care descrie cantitatea de timp necesară pentru a rula
un algoritm dependent de dimensiunea intrării. „Timp‖ poate însemna numărul de accesări la
memorie efectuate, numărul de comparații între numere întregi, numărul de execuţii ale unei
bucle; sau exprimare în unităţi naturale de timp real pe care îl necesită algoritmul.
Complexitatea spațiului este o funcție care descrie cantitatea de memorie pe care o solicită
un algoritm, din nou în ceea ce privește dimensiunea intrării. Adesea vorbim de memorie
„suplimentară‖ necesară, în afara memoriei necesare pentru a stoca intrarea în sine. Şi aici se
folosesc unități naturale (dar cu lungime fixă) pentru a măsura cantitatea de memorie necesară
(octeţi, megaocteţi). Complexitatea spațiului este uneori ignorată deoarece spațiul utilizat este
evident și extensibil, totuși uneori devine o problemă la fel de importantă ca și timpul.

O clasă de complexitate este definită de patru parametri: modelul, modul de calcul,


limitarea resursei şi mărginirea asimptotică pentru cazul cel mai defavorabil, care interesează
pentru limbaje ale unor maşini Turing deterministe (DTM) şi ne-deterministe (NTM):
Clasa DTIME(f(n)) - Limbaje decidabile în timp O(f(n)) de către o DTM
Clasa NTIME(f(n)) - Limbaje decidabile în timp O(f(n)) de către o NTM
Clasa SPACE(f(n)) - Limbaje decidabile în spaţiu O(f(n)) de către o DTM
Clasa NSPACE(f(n)) - Limbaje decidabile în spaţiu O(f(n)) de către o NTM
Aşa cum am arătat mai sus, problema care se pune îndeosebi este complexitatea timpului,
adică ne interesează clasele DTIME şi NTIME. Pentru definirea acestora şi a claselor de
complexitate P, NP şi NP-complete vom relua definirea unei probleme de decizie (amintită la
§4.2.3 pct. II) definită ca limbaj astfel:
Definiţia 4.13 (Decision Problem) Fie Σ un alfabet şi fie L ⊂ Σ*. Spunem că limbajul L
este o problemă de decizie. (reamintim că decizia priveşte acceptarea cuvintelor din L).

Clasele de complexitate P şi NP se referă la probleme de decizie, altfel spus ele sunt


mulţimi de limbaje. În contextul desfăşurării unui algorim, complexitatea se referă la calcul
dar în abstractizare ca limbaj formal este mai uşor de formulat25.
De exemplu, problema determinării [existenţei] unui Traseu Hamiltonian într-un graf G
(traseu de arce parcurse o singură dată trecând prin toate nodurile) se defineşte ca limbajul:
LCH = {(G) : G =” graf cu Traseu Hamiltonian” },
codifică trasee Hamiltoniene prin şiruri [de noduri] iar şirul (H)LCH este o decizie: „H este
ciclu Hamiltonian‖.
Chiar şi din punct de vedere computaţional (al reprezentării pentru calcul) un graf este o
structură de date, folosită în program, iar această structură poate fi şir-cuvânt (string).

25
Michael Levet, Theory of Computation- Lecture Notes, michaellevet.github.io/Lecture_Notes.pdf

97
Figura 4.8 Traseu Hamiltonian într-un graf.

Spre exemplu, complexitatea timpului la bucle imbricate (nested loops) este de ordin O(n2)
iar la mergesort de ordin O(n log(n)) – privind timpul de execuţie (runtime). În general, se poate
defini funcţia de timp-runtime T relativ la funcţionarea unei Maşini Turing TM, astfel:
Definiţia 4.14 Fie T:N → N şi fie DTM o TM care se opreşte (halt) la toate intrările.
Spunem că DTM are complexitate timp O(T(n)) dacă pentru oricare n  N, DTM se opreşte în
cel mult T(n) paşi, la oricare şir de intrare de lungime n. Astfel:
DTIME(T (n)) = {L ⊂ Σ∗ :” L decis de o TM deterministă DTM în timp O(T (n))” }.

Să observăm că orice clasă de complexitate trebuie să aibă un model de calcul subsumat –


în cazul DTIME o Maşină Turing deterministă; cu alte cuvinte, trebuie să ştim ce algoritm
rezolvă problema adică ce anume rulează calculatorul/programul. Cadrul general de limbaj
formal dă o idee ce [şir] anume citeşte calculatorul – intuitiv, acesta fiind un şir binar
reprezentând un program în limbaj de asamblare sau text în Python ori Java. În orice caz,
calculatorul lucrează pe baza unei reprezentări ca şir a algoritmului – şi a problemei.

În continuare se vor defini şi caracteriza clasele de complexitate P şi NP.


Definiţia 4.15 Clasa de complexitate P este mulţimea limbajelor decidabile în timp
polinomial cu Maşini Turing deterministe (DTM). Formal:
P = ⋃k∈N DTIME(nk).
Exemplul 4.4. Problema Cale: determinarea unui traseu într-un graf G, este definită:
LCale = {(G, u, v) : G graf; u, v ∈ Nod(G) ∧ ” G prezintă cale de la u la v” }.
şi este decidabilă în timp polinomial, folosind ori un algoritm de căutare pe lărgime (breadth-
first) ori pe adâncime (depth-first), ambele rulând în timp O(|V|2) – V mulţime vârfuri-noduri.
Astfel, LCale ∈ P, pentru că algoritmul necesită un timp polinomial spre a decide LCale.
În acest exemplu se consideră un algoritm implementat pe o maşină de calcul actuală – o
maşină RAM, care are memoria cu acces aleator şi nu memorie bandă ca TM; modelul RAM
este pentru TM echivalent unui model de calcul în timp polinomial25 iar TM poate fi simulat
pe o maşină RAM, pe când reciproca nu este valabilă.
Reamintim că o problemă poate fi soluţionată prin mai mulţi algoritmi – unul mai eficient
decât ceilalţi relativ la numărul n de intrări în creştere (de exemplu n=|w| lungimea cuvintelor
dintr-un limbaj). Dacă pentru o problemă anume s-a găsit un algoritm care o rezolvă într-un
timp polinomial T(n)=p(n) – unde p este un polinom oarecare, se spune că avem un algoritm
eficient şi problema aparţine clasei P.
Problemele din clasa P sunt considerate probleme de calcul cu grad mic de dificultate, dar
aceasta nu înseamnă că sunt uşoare ci pot avea algoritmi sofisticaţi de rezolvare dar cu un

98
calcul de „complexitate mică‖, rulând în timp polinomial de n – dimensiunea intrării.
Cele mai multe probleme practice sunt probleme P: căutarea unui element într-un
vector/matrice cu (O(n)), inserarea unui element la finalul unei liste înlănţuite cu (O(n)),
sortare folosind ―selection sort‖ cu (O(n2)); apoi găsirea adâncimii unui arbore cu (O(log2n)),
sortare folosind ―merge sort‖ cu (O(nlog2n)), înmulţirea matricilor cu O(n3).
Un algoritm cu complexitate O(2n) necesită un timp dublu la testare pe o problemă de
dimensiune (n + 1);astfel de probleme nu aparţin clasei P. Sunt astfel excluse orice probleme
ce nu pot fi rezolvate în timp polinomial – de exemplu ―problema rucsacului‖ (knapsack)
folosind căutare brută, nu poate fi rezolvată în timp polinomial, deci nu aparţine clasei P.

În cazul problemelor ne-deterministe, soluţiile presupun parcurgerea mai multor căi către o
rezoluţie Da sau Nu a problemei de decizie (v. Figura 2.14) şi apare evident că un algoritm de
rezolvare a unei asemenea probleme necesită mai mult timp; se consideră că dacă parcurgerea
celei mai lungi ramuri din arbore are loc în timp polinomial aceasta se poate verifica/certifica.
Definiţia 4.16 Un limbaj L este în clasa de complexitate NP (LNP) dacă există o Maşină
Turing ne-deterministă NTM care acceptă un cuvânt wL într-un timp funcţie polinom p(|w|).
De fapt, acesată definiţie este generalizată în contextul utilizării TM ca verificator pentru
limbajul L (v. §4.2.3 pct.IV), adică dacă soluţionarea problemei se face prin algoritmul A,
există un algoritm V şi un şir c martor sau certificat (witness / certificate) astfel ca pentru
orice cuvânt wL şi c algoritmul V(w, c) dă răspuns Da – acceptat. Cu alte cuvinte există o
Maşină Turing V care în timp plinomial acceptă w ddacă este acceptată (w, c), cu |c| ≤ p(|ω|).
Astfel, Definiţia 4.16 se reformulează: Clasa de complexitate NP este mulţimea
limbajelor care are verificatori în timp polinomial. Clasa NP se poate defini similar clasei P:
NP = ⋃k∈N NTIME(nk).
Probleme care nu aparţin clasei P dar ţin de clasa NP sunt: „problema rucsacului‖
(knapsack problem) cu (O(2n)), ―problema comisului voiajor‖ (travelling salesman problem
TSP) cu (O(n!)), ―turnurile din Hanoi‖ cu (O(2n – 1)), ―ciclul Hamiltonian‖ cu (O(n!)).
Problemele deterministe sunt cazuri speciale ale celor ne-deterministe, astfel că PNP dar
răspunsul la întrebarea „pot fi rezolvate în timp polinomial problemele care pot fi verificate în
timp polinomial?‖ nu are încă răspuns; se consideră însă că există probleme din clasa NP care
sunt mai dificil de calculat decât de verificat şi nu pot fi soluţionate în timp polinomial.
De fapt, problemele se pot caracteriza privind complexitatea de calcul şi prin aspectul
denumit trasabilitate: o problemă este trasabilă (tractable) dacă poate fi calculată într-un
timp finit; problemele soluţionate la cel mai rău caz în timp exponenţial – cu O(2n), O(nn)),
sunt denumite probleme ne-trasabile (intractable problems) adică nu pot fi urmărite în timp
finit în desfăşurarea calculului. Probleme din clasa NP fiind probleme ne-deterministe
expandează mult arborele de traziţii de stare (Figura 2.14) la creşterea dimensiunii n a intrării,
iar căutarea în arborele expandat este denumită adesea „ghicire‖ a deciziei (guessing).

Plecând de la aspectul trasabilităţii se pot defini clasele de probleme NP-Hard (NP-Grele)


şi NP-Complete. Problemele NP-Complete (NP-C) sunt cele mai dificile probleme privind
complexitatea de calcul şi considerate ne-trasabile (intractable), iar pentru definirea lor revenim
la noţiunea de reducţie (reduction) – v. Definiţia 4.9, de data aceasta definind funcţia

99
calculabilă f(w) din Definiţia 4.8 drept funcţie calculabilă în timp polinomial, astfel TM
utilizat drept calculator va avea f(w) înscrisă pe bandă. Definiţia 4.9 va fi reformulată:
Definiţia 4.17 Fie A, B ⊂ Σ*. Spunem că problema A este reductibilă la B în timp
polinomial (polynomial time reducible) notând A ≤p B dacă există o funcţie calculabilă în timp
polinomal (polynomial time computable function) f : Σ* → Σ* astfel ca w ∈ A ddacă f(w) ∈ B.
Conceptul de reductibilitate asigură o ordine parţială problemelor de calcul relativ la
dificultate (hardness). Astfel, dacă A şi B sunt probleme astfel ca A ≤p B, atunci un algoritm
ce soluţionează B poate fi folosit pentru soluţionarea A. Dar fiindcă am definit problemele ca
limbaje se pot astfel defini acum conceptele NP-H şi NP-C în aceşti termeni:
Definiţia 4.18 O problemă A este NP-Hard (NP-Grea) dacă pentru orice L ∈ NP, L ≤p A.
Definiţia 4.19 Un limbaj L este NP-Complet dacă L∈NP şi L este NP-Hard.
Se poate nota că orice problemă NP-Completă este o problemă de decizie dar în general,
problemele NP-Hard nu sunt neapărat probleme de decizie. Optimizările şi enumerările sunt
exemple comune de probleme NP-Hard. De altfel, dacă două probleme/limbaje NP-C sunt
reductibile în timp polinomial unul la celălalt şi avem o soluţie rapidă la o problemă NP-C am
putea rezolva orice problemă, a cărei soluţie o putem înţelege uşor, folosind soluţia primei25.
Într-o reprezentare intuitivă a locului problemelor NP-C în contextul problemelor NP şi P
se consideră că (v.şi reprezentarea grafică mai jos):

P  NP, NPC  NP, P  NPC = 

Figura 4.9 Reprezentare grafică a muţimilor P, NP şi NPC

Fie L1 şi L2 două probleme; problema L1 se reduce la L2 ddacă există o modalitate de a


soluţiona L1 printr-un algoritm determinist în timp polinomial ce soluţioneză L2 în timp
polinomial, adică L1 ≤p L2 cu L1 mai greu cu cel mult un factor polinomial decât L2.
Astfel:
 L1 este cel mult la fel de greu ca L2 şi este posibil să soluţionăm L1 printr-un algoritm
pentru L2
 L2 este cel puţin la fel de greu ca L1 şi dacă este cunoscut că L1 este greu atunci
reducţia L1 ≤p L2 duce la concluzia că şi L2 este greu.
şi pentru cele două probleme avem cazurile din Tabel 4.3:

100
dacă: atunci:
L1 este ne-rezolvabil L2 este ne-rezolvabil
L1 este rezolvabil Nu ştim nimic despre L2
L2 este rezolvabil L1 este rezolvabil
L2 este ne-rezolvabil Nu ştim nimic despre L1
Tabel 4.3 Cazuri de soluţionare presupunând L1 reductibil la L2.

Prin proprietatea de „reductibilitate în timp polinomial‖, problemele NP-C sunt echivalente


şi astfel apare perspectiva soluţionării unei arii largi de probleme, cu semnificaţie practică şi
economică. Conceptul de NP-Completitudine este important pentru proiectantul de algoritmi
pentru că dacă se poate stabili că o problemă este NP-C s-a găsit o dovadă a ne-trasabilităţii
sale şi ca urmare este mai profitabil să se dezvolte un algoritm aproximativ care să ofere o
soluţie acceptabilă aproape-optimală decât să se caute o soluţie exactă care să fie şi rapidă.

101
5 Bibliografie

1. Adrian Atanasiu, Limbaje formale si automate, Ed. Infodata, Cluj 2007.


2. Adrian Crăciun, Logică computaţională, 2020.
3. Anil Maheshwari, Michiel Smid, Introduction to Theory of Computation, Carleton
University, Canada, 2019.
4. Ananth Kalyanaraman, Automata and Formal Languages, Washington State
University, 2017.
5. *** Berechenbarkeit Und Komplexität (edustanford.com/5797003-computability-and-
complexity).
6. Brian Heinold, An Informal Introduction to Formal Languages, Licensed under a
Creative Commons Attribution, 2018.
7. Charles E. Hughes, Computability & Complexity Theory, University of Central
Florida, 2015.
8. Daniel Cohen, Introduction to computer theory, John Wiley & Sons,1986.
9. David Hilbert, Wilhelm Ackermann, Grundzüge der Theoretischen Logik, Springer
(1938) în Stanley Burris, Hilbert and Ackermann’s 1928 Logic Book.
https://www.math.uwaterloo.ca/~snburris/htdocs/scav/hilbert/hilbert.html, 1997.
10. D. Goswami, K. V. Krishna, Formal Languages and Automata Theory, Indian IoTech
Guwahati, 2010.
11. Elaine Rich, Automata, Computability and Complexity: Theory and Applications,
2019.
12. Jean Gallier, Andrew Hicks, The Theory of Languages and Computation, University
of Pennsylvania, 2006.
13. John Martin, Introduction to languages and the theory of computation, 4th
Ed.,McGraw-Hill, 2011.
14. John Watrous Introduction to the Theory of Computing - Lecture notes, University of
Waterloo, 2020.
15. K.L.P. Mishra, N. Chandrasekaran, Automata, Languages and Computation, 3rd. Ed.,
Prentice'Hall Of India, New Delhi, 2008.
16. Lucică Iancu, Logica, Editura tehnică, colecţia Cogito, Bucureşti, 2008.
17. Martin Davis, Ron Sigal, Elaine Weyuker, Computability, Complexity, and
Languages: Fundamentals of Theoretical Computer Science, 2nd Ed. Academic Press
1994,
18. Michael Levet, Theory of Computation - Lecture Notes, College of Charleston, 2020.
19. Michael Sipser, Introduction to the Theory of Computation Course Technology,
Boston, MA, Third edition, 2013.
20. Michel Rigo, Théorie des automates et langages formels, 2010,
http://www.discmath.ulg.ac.be/cours/main_autom.pdf.
21. Oded Goldreich, A brief overview of Complexity Theory, 2005,
https://www.wisdom.weizmann.ac.il/~oded/cc-over.html
22. Olivier Bournez, Gilles Dowek, Rémi Gilleron, Serge Grigorieff, Jean-Yves Marion,
et al.. Décidabilité et Complexité, in IA Handbook, Cépaduès, pp.1-63, 2010.

102
23. Olivier Carton, Langages formels, Calculabilité et Complexité, Éditions Vuibert,
2014.
24. Peter Linz, An Introduction to Formal languages and Automata, Jones and Bartlett
Publ., 2012.
25. Rolf Pfeifer, Rudolf Füchslin, Formal Methods for Computer Science, University of
Zurich, 2013
26. Sanjeev Arora, Boaz Barak, Computational Complexity: A Modern Approach,
Cambridge University Press, 2009.
27. Sieg Wilfried, Computability Theory, 1994-2002 (citeseerx.ist.psu.edu).
28. Stavros Konstantinidis, Classical-Theoretical Foundations Of Computing, Saint
Mary’s University May 2011.
29. Tao Jiang, Ming Li, and Bala Ravikumar, Formal models and Computability, in
Handbook of Computer Science, CRC Press, 1996.
30. Tao Jiang, Ming Li, Formal Grammars and Languages, in Algorithms and Theory of
Computation Handbook, 2010.
31. Teodor Dima (ed.), Logica generală, EDP, Bucureşti, 1991.
32. Viorel Ariton, Reţele de calculatoare, Ed. Evrika Galati, 1999.
33. Viorel Ariton, Prelucrarea Distribuită a Datelor, Ed. Evrika, Galati, 1999.
34. Viorel Ariton, Fundamente ale Tehnologiei Informaţiei şi Comunicaţiilor, Editura
Didactică şi Pedagogică, 2003.

103
Lista Figurilor

Figura 2.1 Diagrama de stare pentru BA. .............................................................................................. 29


Figura 2.2 Diagrama de stare pentru CV. .............................................................................................. 30
Figura 2.3 Diagrame de stare M01 şi Mba. .............................................................................................. 31
Figura 2.4 Funcţiile de tranziţie pentru automatele M01 şi Mba. ........................................................... 32
Figura 2.5 Diagrama de stare pentru automatul MSTEA cu L(MSTEA) = Σ*. ........................................... 33
Figura 2.6 Diagrama de stare DFA M2_4. ............................................................................................ 34
Figura 2.7 Diagrama de stare DFA M2_5. ............................................................................................ 34
Figura 2.8 Diagrama de stare DFA M2_6. ............................................................................................ 34
Figura 2.9 Diagrama de stare DFA M2_7. ............................................................................................ 35
Figura 2.10 Diagrama de stare a N2_8, nedeterminismul tranziţiei la intrare 0 (Nd1). ........................ 36
Figura 2.11 Diagrama de stare a N2_9, nedeterminismul tranziţiei fără intrare (Nd2). ........................ 36
Figura 2.12 Diagrama de stare NFA N2_10 (stânga) şi echivalentul DFA (dreapta). .......................... 37
Figura 2.13 Diagrama de stare NFA N2_11.......................................................................................... 40
Figura 2.14 Arborele de tranziţii de stare NFA N2_11 ......................................................................... 40
Figura 2.15 Diagrame de stare pentru NFA N şi DFA M echivalent. ................................................... 42
Figura 2.16 Diagrama de stare pentru automat cu blocaje. ................................................................... 43
Figura 2.17 Reprezentare NFA concisă (stânga) şi cu stări iniţiale comasate (dreapta). ...................... 44
Figura 2.18 Reprezentare concisă a uniunii NFA A şi NFA B. ............................................................ 44
Figura 2.19 Diagrama de stare a două NFA reunite. ............................................................................. 45
Figura 2.20 Reprezentare concisă a concatenării NFA A şi NFA B. .................................................... 45
Figura 2.21 Reprezentare concisă a NFA A cu Kleene star. ................................................................. 46
Figura 2.22 Două automate A, B şi produsul lor cartezian AB. ......................................................... 46
Figura 2.23 DFA din stânga are inversul DFA din dreapta. .................................................................. 47
Figura 2.24 PDA şi specificarea tranziţiei între stări. ........................................................................... 48
Figura 2.25 Diagrama de stare pentru PDA ce recunoaşte limbajul 0n1n. ............................................. 48
Figura 2.26 Diagrama de stare pentru PDA ce recunoaşte limbaj „palindrom‖, Σ = {0, 1}. ................ 49
Figura 2.27 Automat de comunicaţie semi-duplex................................................................................ 54
Figura 2.28 Automat Mealy My_1 de conversie litere-cifre, cu „1 la perechi ab‖ . ............................. 55
Figura 2.29 Automat Moore pentru controlul debitului ........................................................................ 56
Figura 2.30 Automat Moore (stânga) şi echivalentul Mealy (dreapta). ................................................ 57
Figura 3.1 Automate cu stări finite şi regEx sunt inter-schimbabile. .................................................... 65
Figura 3.2 Diagrama de stare M pentru regEx r = . ........................................................................... 66
Figura 3.3 Diagrama de stare M pentru regEx r = ε. ............................................................................. 66
Figura 3.4 Diagrama de stare M1 pentru regEx r = a. ........................................................................... 66
Figura 3.5 Diagrama de stare M3 pentru regEx concatenare ab. ........................................................... 67
Figura 3.6 Diagrama de stare M4 pentru regEx uniune ab+a. ............................................................... 67
Figura 3.7 Diagrama de stare M5 pentru regEx operator stea (ab+a)*. ................................................. 67
Figura 3.8 Diagrama de stare pentru GNFA cu regEx 0*1, ................................................................... 68
Figura 3.9 Diagrame de stare pentru GNFA cu operator regEx (+). ..................................................... 68
Figura 3.10 Diagrame de stare pentru GNFA cu operatori regEx (.) şi (*)............................................ 68
Figura 3.11 Conversie DFA – regEx pentru cazul 1*00*1(0+1)*. .......................................................... 69
Figura 3.12 Exemplu.de structură gramaticală comună. ....................................................................... 70
Figura 3.13 Structură sintactică generică. ............................................................................................. 70
Figura 3.14 Structură sintactică pentru Exemplul 3.6. .......................................................................... 71
Figura 3.15 Arborele de derivare pentru Exemplul 3.6. ........................................................................ 71

104
Figura 3.16 Limbaje formale dincolo de ierarhia Chomsky. ................................................................. 79
Figura 4.1 Maşina Turing TM cu o bandă............................................................................................. 84
Figura 4.2 ID - descrierea instantanee a TM exemplu. ......................................................................... 85
Figura 4.3 Traseul de stări parcurs la DTM şi la NTM până la starea acceptoare. ............................... 86
Figura 4.4 Funcţii ce pot exprima dependenţa timp – dimensiune n intrări. ......................................... 91
Figura 4.5 Timp de rulare pentru un algoritm A, funcţie de structura intrărilor. .................................. 92
Figura 4.6 Ordine de complexitate cu notaţii asimptotice aferente. ...................................................... 94
Figura 4.7 Ordine de creştere pentru diferite funcţii de mărginire şi eficienţa asociată. ....................... 96
Figura 4.8 Traseu Hamiltonian într-un graf. ......................................................................................... 98
Figura 4.9 Reprezentare grafică a muţimilor P, NP şi NPC ................................................................ 100

105
Lista Tabelelor

Tabel 1.1 Descriere funcţie prin tabela de corespondenţă. ...................................................................... 8


Tabel 1.2 Tabela de adevăr pentru conectorii logici uzuali ................................................................... 17
Tabel 1.3 Tabela de adevăr pentru: sau exclusiv, incompatibilitate, rejectare. ..................................... 18
Tabel 1.4 Tabela de adevăr pentru echivalenţa (p  q)  (p  q)..................................................... 18
Tabel 1.5 Echivalenţe ............................................................................................................................ 18
Tabel 1.6 Tabela de adevăr pentru formulele din expresia E. ............................................................... 19
Tabel 1.7 Tabela de adevăr pentru tautologia p  p. .......................................................................... 21
Tabel 1.8 Tabela de adevăr pentru contingenţa p → p. ...................................................................... 21
Tabel 2.1 Evoluţia stărilor şi stivei funcţie de şirul de intrare – exemplu 000111 = 0313. .................... 48
Tabel 2.2 Funcţii de tranziţie δ şi de ieşire λ pentru automatul My_1. ................................................. 56
Tabel 3.1 Reguli de producţie şi derivarea recursivă pentru Exemplul 3.6. .......................................... 72
Tabel 3.2 O gramatică generativă cu reguli de producţie recursive. ..................................................... 72
Tabel 3.3 Ierarhia Chomsky cu exemple de limbaje arhetipale şi automate. ........................................ 79
Tabel 3.4 Decidabilitatea problemelor la Ierarhia Chomsky. ............................................................... 80
Tabel 4.1 Metode de înmulţire a două numere. ..................................................................................... 89
Tabel 4.2 Notaţii asimptotice cu mărginirea creşterii funcţiei de complexitate. ................................... 94
Tabel 4.3 Cazuri de soluţionare presupunând L1 reductibil la L2. ....................................................... 101

106

S-ar putea să vă placă și