praca_magisterska/pytania/odpowiedzi/01-automaty-jezyki.md

13 KiB
Raw Blame History

Pytanie 1: Porównanie automatów i rozpoznawanych klas języków

Pytanie

"Porównać 'siłę wyrazu' automatu skończonego, automatu ze stosem oraz maszyny Turinga. Jakie klasy języków rozpoznaje każdy z nich?"

Przedmiot: AISDI (Algorytmy i Struktury Danych)


📚 Odpowiedź główna

Hierarchia Chomsky'ego - fundament teoretyczny

Noam Chomsky w 1956 roku zaproponował hierarchię czterech klas języków formalnych, gdzie każda kolejna klasa zawiera poprzednią:

Typ 0: Języki rekurencyjnie przeliczalne (Recursively Enumerable)
   ⊃
Typ 1: Języki kontekstowe (Context-Sensitive)
   ⊃
Typ 2: Języki bezkontekstowe (Context-Free)
   ⊃
Typ 3: Języki regularne (Regular)

1. Automat Skończony (Finite Automaton - FA)

Definicja formalna

Automat skończony to piątka: M = (Q, Σ, δ, q₀, F)

  • Q - skończony zbiór stanów
  • Σ - alfabet wejściowy (skończony zbiór symboli)
  • δ - funkcja przejścia: Q × Σ → Q (DFA) lub Q × Σ → P(Q) (NFA)
  • q₀ - stan początkowy (q₀ ∈ Q)
  • F - zbiór stanów akceptujących (F ⊆ Q)

Rozpoznawana klasa języków

Języki regularne (Typ 3) - najsłabsza klasa w hierarchii Chomsky'ego

Charakterystyka

  • Pamięć: Brak pamięci pomocniczej - tylko aktualny stan
  • Moc obliczeniowa: Nie potrafi "liczyć" (porównywać ilości)
  • Równoważne formalizmy:
    • Wyrażenia regularne (regex)
    • Gramatyki regularne (prawo- lub lewostronnie liniowe)
    • DFA ≡ NFA ≡ ε-NFA (równoważne pod względem mocy)

Przykłady języków rozpoznawalnych

  • L = {w ∈ {a,b}* : w zawiera podciąg "ab"}
  • L = {w ∈ {0,1}* : w jest podzielne przez 3 (interpretowane binarnie)}
  • Identyfikatory w językach programowania: [a-zA-Z_][a-zA-Z0-9_]*

Przykłady języków NIEROZPOZNAWALNYCH

  • L = {aⁿbⁿ : n ≥ 0} - wymaga liczenia
  • L = {ww : w ∈ {a,b}*} - wymaga zapamiętania w
  • Poprawnie zagnieżdżone nawiasy

Lemat o pompowaniu (Pumping Lemma) dla języków regularnych

Dla każdego języka regularnego L istnieje stała p (długość pompowania), taka że: każde słowo w ∈ L, gdzie |w| ≥ p, można podzielić na w = xyz, gdzie:

  1. |y| > 0
  2. |xy| ≤ p
  3. ∀i ≥ 0: xyⁱz ∈ L

2. Automat ze Stosem (Pushdown Automaton - PDA)

Definicja formalna

Automat ze stosem to siódemka: M = (Q, Σ, Γ, δ, q₀, Z₀, F)

  • Q - skończony zbiór stanów
  • Σ - alfabet wejściowy
  • Γ - alfabet stosowy
  • δ - funkcja przejścia: Q × (Σ ∪ {ε}) × Γ → P(Q × Γ*)
  • q₀ - stan początkowy
  • Z₀ - początkowy symbol na stosie
  • F - zbiór stanów akceptujących

Rozpoznawana klasa języków

Języki bezkontekstowe (Typ 2) - Context-Free Languages (CFL)

Charakterystyka

  • Pamięć: Stos (LIFO) - pamięć potencjalnie nieskończona, ale z ograniczonym dostępem
  • Moc obliczeniowa: Potrafi "liczyć" (porównywać pary ilości)
  • DPDA ⊂ NPDA: Deterministyczne PDA są SŁABSZE niż niedeterministyczne!
  • Równoważne formalizmy: Gramatyki bezkontekstowe (CFG)

Dwa tryby akceptacji

  1. Przez stan końcowy: automat jest w stanie z F po przeczytaniu całego słowa
  2. Przez pusty stos: stos jest pusty po przeczytaniu całego słowa

Oba tryby są równoważne pod względem mocy.

Przykłady języków rozpoznawalnych

  • L = {aⁿbⁿ : n ≥ 0} - klasyczny przykład
  • L = {w ∈ {a,b}* : #a(w) = #b(w)} - równa liczba a i b
  • Poprawnie zagnieżdżone nawiasy: (), (()), (()()), ...
  • Palindromy: L = {wwᴿ : w ∈ {a,b}*}

Przykłady języków NIEROZPOZNAWALNYCH

  • L = {aⁿbⁿcⁿ : n ≥ 0} - wymaga liczenia trzech rzeczy
  • L = {ww : w ∈ {a,b}*} - kopiowanie (nie odwracanie!)
  • L = {aⁱbʲcᵏ : i = j lub j = k} - to jest CFL! (suma dwóch CFL)

DPDA vs NPDA

Deterministyczne PDA rozpoznają właściwy podzbiór języków bezkontekstowych:

  • DPDA: L = {aⁿbⁿ : n ≥ 0} ✓
  • NPDA only: L = {wwᴿ : w ∈ {a,b}*} - palindromy parzyste

3. Maszyna Turinga (Turing Machine - TM)

Definicja formalna

Maszyna Turinga to siódemka: M = (Q, Σ, Γ, δ, q₀, qaccept, qreject)

  • Q - skończony zbiór stanów
  • Σ - alfabet wejściowy (nie zawiera symbolu pustego ␣)
  • Γ - alfabet taśmowy (Σ ⊂ Γ, ␣ ∈ Γ)
  • δ - funkcja przejścia: Q × Γ → Q × Γ × {L, R}
  • q₀ - stan początkowy
  • qaccept - stan akceptujący
  • qreject - stan odrzucający

Rozpoznawana klasa języków

Języki rekurencyjnie przeliczalne (Typ 0) - Recursively Enumerable (RE)

Podklasa: Języki rekurencyjne (rozstrzygalne) - TM zawsze się zatrzymuje

Charakterystyka

  • Pamięć: Taśma nieskończona z dostępem swobodnym (R/W)
  • Moc obliczeniowa: Maksymalna możliwa (teza Churcha-Turinga)
  • DTM ≡ NTM: Deterministyczne i niedeterministyczne TM są RÓWNOWAŻNE pod względem mocy (ale różnią się złożonością czasową)

Warianty równoważne

  • Wielotaśmowa TM
  • Niedeterministyczna TM
  • RAM (Random Access Machine)
  • Języki programowania (Turing-complete)

Przykłady języków rozpoznawalnych

  • L = {aⁿbⁿcⁿ : n ≥ 0}
  • L = {ww : w ∈ {a,b}*}
  • Wszystkie języki bezkontekstowe
  • Wszystkie języki kontekstowe
  • Problem stopu (HP) - ale TM może się nie zatrzymać!

Przykłady języków NIEROZPOZNAWALNYCH

  • Komplement problemu stopu: L = {⟨M,w⟩ : M nie zatrzymuje się na w}
  • Problem odpowiedniości Posta (PCP)

📊 Tabela porównawcza

Cecha FA PDA TM
Pamięć Brak (tylko stan) Stos (LIFO) Taśma (R/W swobodny)
Klasa języków Regularne (Typ 3) Bezkontekstowe (Typ 2) Rek. przeliczalne (Typ 0)
Gramatyka Regularna Bezkontekstowa (CFG) Nieograniczona
DET = NIEDET? TAK NIE TAK (moc), NIE (złożoność)
Domknięcie ∪ TAK TAK TAK
Domknięcie ∩ TAK NIE TAK
Domknięcie ¬ TAK NIE NIE (RE), TAK (rekurencyjne)
Rozstrzygalność pustości TAK TAK NIE
Zastosowanie Leksery, regex Parsery, kompilatory Obliczenia ogólne

🔄 Relacje między klasami

┌─────────────────────────────────────────────────────────────┐
│                    Typ 0: Rekurencyjnie przeliczalne (TM)   │
│  ┌───────────────────────────────────────────────────────┐  │
│  │              Rekurencyjne (TM zatrzymująca się)       │  │
│  │  ┌─────────────────────────────────────────────────┐  │  │
│  │  │           Typ 1: Kontekstowe (LBA)              │  │  │
│  │  │  ┌───────────────────────────────────────────┐  │  │  │
│  │  │  │      Typ 2: Bezkontekstowe (PDA)          │  │  │  │
│  │  │  │  ┌─────────────────────────────────────┐  │  │  │  │
│  │  │  │  │   Deterministyczne CFL (DPDA)       │  │  │  │  │
│  │  │  │  │  ┌───────────────────────────────┐  │  │  │  │  │
│  │  │  │  │  │   Typ 3: Regularne (FA)       │  │  │  │  │  │
│  │  │  │  │  └───────────────────────────────┘  │  │  │  │  │
│  │  │  │  └─────────────────────────────────────┘  │  │  │  │
│  │  │  └───────────────────────────────────────────┘  │  │  │
│  │  └─────────────────────────────────────────────────┘  │  │
│  └───────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

🧠 Mnemoniki

"STOS LIFO"

  • Skończony automat - Stan tylko (bez pamięci)
  • Tylko regex - języki regularne
  • Ograniczony PDA - Odnosi się do stosu
  • Stos = bezkontekstowe

"TuRing = Total Random access"

  • Taśma nieskończona
  • Random access (czytanie i pisanie)
  • Total - wszystko może obliczyć (co jest obliczalne)

"3-2-1 START"

  • 3 = Typ 3 = FA = regex (najsłabszy)
  • 2 = Typ 2 = PDA = CFG (parser)
  • 1 = Typ 1 = kontekstowe (LBA)
  • 0 = Typ 0 = TM = wszystko (START od zera = najpotężniejszy)

"FA NIC nie pamięta, PDA pamięta ALE odwraca, TM pamięta WSZYSTKO"

  • FA: nie liczy
  • PDA: liczy ale LIFO (stąd aⁿbⁿ tak, aⁿbⁿcⁿ nie)
  • TM: liczy wszystko

Akronim "CHOMSKY" dla hierarchii:

  • Computable all (Typ 0 - TM)
  • Hard context-sensitive (Typ 1)
  • OK with stack (Typ 2 - PDA)
  • Minimal - regex only (Typ 3 - FA)
  • Strict inclusion (każda klasa zawiera niższą)
  • Key for compilers (zastosowania)
  • Years of theory (od 1956)

❓ Możliwe pytania dodatkowe (follow-up)

Q1: "Udowodnij, że język L = {aⁿbⁿ} nie jest regularny"

Odpowiedź: Stosujemy lemat o pompowaniu. Załóżmy, że L jest regularny z długością pompowania p.

Weźmy w = aᵖbᵖ ∈ L, |w| = 2p ≥ p

Według lematu: w = xyz, gdzie |xy| ≤ p, |y| > 0

Ponieważ |xy| ≤ p, to xy składa się tylko z 'a' (pierwsze p znaków to same 'a'). Zatem y = aᵏ dla pewnego k > 0.

Pompujemy: xy²z = aᵖ⁺ᵏbᵖ

Ale p + k ≠ p, więc xy²z ∉ L. Sprzeczność! ∎


Q2: "Dlaczego DPDA ⊂ NPDA, ale DFA = NFA?"

Odpowiedź:

DFA = NFA:

  • Można przekształcić NFA w DFA przez konstrukcję potęgową (subset construction)
  • Każdy stan DFA odpowiada podzbiorowi stanów NFA
  • Wykładniczy wzrost stanów, ale ta sama moc

DPDA ⊂ NPDA:

  • PDA ma stos - niedeterminizm pozwala "zgadywać" środek palindromu
  • DPDA nie może rozpoznać {wwᴿ} bo nie wie, kiedy kończy się w
  • DPDA rozpoznaje języki z własnością prefiksową
  • Niedeterminizm w PDA NIE daje się wyeliminować (brak konstrukcji analogicznej do potęgowej dla stosów)

Q3: "Co to jest LBA i gdzie się mieści w hierarchii?"

Odpowiedź: Linear Bounded Automaton (LBA) - maszyna Turinga z ograniczoną taśmą:

  • Taśma ograniczona do długości liniowej względem wejścia: O(n)
  • Rozpoznaje języki kontekstowe (Typ 1)
  • NLBA > DLBA? - otwarty problem!
  • Przykład: L = {aⁿbⁿcⁿ} - kontekstowy, ale nie bezkontekstowy

Q4: "Jakie są praktyczne zastosowania każdego typu automatu?"

Odpowiedź:

Automat Zastosowania praktyczne
FA/DFA Leksery (tokenizacja), walidacja regex, kontrolery stanów w grach, protokoły sieciowe, automaty w VHDL/Verilog
PDA Parsery (analiza składniowa), kompilatory (CFG), walidacja XML/JSON, sprawdzanie nawiasów
TM Model teoretyczny obliczeń, dowody nierozstrzygalności, złożoność obliczeniowa (P vs NP)

Q5: "Co to jest teza Churcha-Turinga?"

Odpowiedź: Teza Churcha-Turinga (nieformalnie):

"Każda funkcja, która może być obliczona przez jakikolwiek algorytm, może być obliczona przez maszynę Turinga."

Równoważne formalizmy:

  • Maszyna Turinga
  • Rachunek lambda (Church)
  • Funkcje rekurencyjne (Gödel)
  • Maszyna RAM
  • Języki Turing-complete (C, Python, Java...)

To jest TEZA, nie twierdzenie - nie można jej udowodnić, bo "algorytm" nie ma formalnej definicji.


Q6: "Czy istnieje język, który nie jest rekurencyjnie przeliczalny?"

Odpowiedź: TAK! Argument przekątniowy (diagonalizacja):

L_d = {⟨M⟩ : M nie akceptuje ⟨M⟩}

Ten język nie jest RE (rekurencyjnie przeliczalny).

Dowód: Załóżmy, że TM M_d rozpoznaje L_d.

  • Czy M_d akceptuje ⟨M_d⟩?
  • Jeśli TAK → ⟨M_d⟩ ∉ L_d → M_d nie powinno akceptować (sprzeczność)
  • Jeśli NIE → ⟨M_d⟩ ∈ L_d → M_d powinno akceptować (sprzeczność)

Zatem M_d nie istnieje, więc L_d ∉ RE. ∎


🎯 Kluczowe punkty do zapamiętania

  1. Hierarchia jest ścisła: Reg ⊂ CFL ⊂ CSL ⊂ RE
  2. Pamięć = moc: brak < stos < taśma
  3. FA: DET = NIEDET, PDA: DET < NIEDET, TM: DET = NIEDET (moc)
  4. Domknięcie na dopełnienie: FA tak, CFL nie, RE nie
  5. Praktyka: FA = regex/lexer, PDA = parser, TM = teoria

📖 Źródła do pogłębienia

  1. Hopcroft, Motwani, Ullman - "Introduction to Automata Theory, Languages, and Computation"
  2. Sipser - "Introduction to the Theory of Computation"
  3. Kozen - "Automata and Computability"