Documente Academic
Documente Profesional
Documente Cultură
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
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.
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)}.
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.
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ă.
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}.
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).
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.
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.
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 :
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
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
18
p (p q) p
p (p q) p
Legile De Morgan:
(p q) (p q)
(p q) (p q)
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
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.
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.
p p p p
1 0 1
0 1 1
p p p → p
1 0 0
0 1 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ă ⊕:
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.
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.
26
2 Automate
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)
0 1 1
gol pli
0
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ă‖.
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).
0 1 1 b a a
q0 q1 q0 q1
0 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).
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:
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
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
1 1 1 0,1
0 0 0
q0 q1 q2 q3
Î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ă.
1
0
coş 0,1
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ş
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
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ă.
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.
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ă.
0,1
1
q0 q1
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.
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.
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).
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:
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.
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’
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
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’
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
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.
1 1 0,1 0,1
0 0
0 1 2 P 0,1 I
A B
0
0 0
1 1 1 1 1 1
0 0
0,I 1,I 2,I
0
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=AB î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.
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.
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.
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}.
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‖.
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).
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).
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).
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‖.
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.
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
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.
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
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.
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‖.
61
– Închiderea tranzitivă Kleene notată:
L* = ⋃i0 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).
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*.
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).
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).
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:
15
Anil Maheshwari, Michiel Smid, Introduction to Theory of Computation, Carleton University, 2019
66
a ε b
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
a ε b
ε
ε
ε
a
S-a obţinut astfel εNFA care recunoaşte limbajul conform regEx (ab+a)*.
67
0∗1
*
q0 q1
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
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.
Î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.
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.
un câine roade un os ∙
the
Figura 3.12 Exemplu.de structură gramaticală comună.
S V O
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 ∙
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 .
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).
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.
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.
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.
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.
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.
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).
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.
Î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.
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.
80
4 Calculabilitate şi Complexitate
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ă.
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.
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.
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.
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 wL obligatoriu M se
opreşte (halt) dar pentru wL 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 wL. 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ă xL. 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
(cL), 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 wA 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ă.
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 ab. 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.
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?
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.
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ă).
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ă.
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).
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 kN, 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
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))” }.
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 (LNP) dacă există o Maşină
Turing ne-deterministă NTM care acceptă un cuvânt wL î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 wL ş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ă PNP 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).
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):
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.
101
5 Bibliografie
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
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
106