পাঠ ৩৪ · ৪৪-এর মধ্যে · মডিউল ৭
Home / Courses / Discrete Mathematics / ফিনাইট স্টেট অটোমাটা

ফিনাইট স্টেট অটোমাটা

Finite state automata
৯ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • DFA-র আনুষ্ঠানিক (formal) ৫-টাপল সংজ্ঞা এবং প্রতিটি অংশের অর্থ
  • "জোড় সংখ্যক 1" চেনার একটি সম্পূর্ণ worked DFA — স্টেট, ট্রানজিশন, এবং ধাপে-ধাপে রান
  • একটি DFA-র "ভাষা (language)" বলতে ঠিক কী বোঝায়
  • NFA কী এবং কেন NFA ও DFA-র গণনাশক্তি (computational power) সমান

১ · DFA-র আনুষ্ঠানিক সংজ্ঞা

একটি Deterministic Finite Automaton (DFA)DFAএকটি গাণিতিক মডেল যা এক-এক করে ইনপুট সিম্বল পড়ে, প্রতিটি সিম্বলে একটি নির্দিষ্ট (deterministic) নিয়মে এক স্টেট থেকে আরেক স্টেটে যায়, এবং শেষে একটি accepting স্টেটে থাকলে ইনপুটটি "গ্রহণ" করে। একটি ৫-টাপল $(Q, \Sigma, \delta, q_0, F)$ দিয়ে সংজ্ঞায়িত —

$Q$
সসীম সংখ্যক স্টেটের সেট (finite set of states)
$\Sigma$
বর্ণমালা (Alphabet)Alphabet (Σ)ইনপুট স্ট্রিং তৈরি করতে ব্যবহৃত সিম্বলের সসীম সেট — যেমন {0,1}। — ইনপুট সিম্বলের সসীম সেট, যেমন {0,1}
$\delta$
ট্রানজিশন ফাংশন (δ)Transition Function$\delta: Q \times \Sigma \rightarrow Q$ — বর্তমান স্টেট ও পঠিত সিম্বল থেকে পরবর্তী স্টেট নির্ধারণ করে। — $Q \times \Sigma \rightarrow Q$, বর্তমান স্টেট ও সিম্বল থেকে পরবর্তী স্টেট বলে দেয়
$q_0$
শুরুর স্টেট (start state), $q_0 \in Q$
$F$
গ্রহণযোগ্য (accepting/final) স্টেটের সেট, $F \subseteq Q$

২ · Worked উদাহরণ — জোড় সংখ্যক 1 চেনা

লক্ষ্য: এমন একটি DFA বানানো যা শুধু সেই বাইনারি স্ট্রিং-গুলো গ্রহণ করবে যেখানে 1-এর সংখ্যা জোড় (even) — শূন্যও একটি জোড় সংখ্যা হিসেবে গণ্য, তাই খালি স্ট্রিং ও সব-0 স্ট্রিং-ও গ্রহণযোগ্য।

DFA সংজ্ঞা

$Q = \{q_{even}, q_{odd}\}$,   $\Sigma = \{0, 1\}$,   $q_0 = q_{even}$,   $F = \{q_{even}\}$

ট্রানজিশন ফাংশন $\delta$:   $\delta(q_{even}, 0) = q_{even}$,   $\delta(q_{even}, 1) = q_{odd}$,   $\delta(q_{odd}, 0) = q_{odd}$,   $\delta(q_{odd}, 1) = q_{even}$

অন্তর্দৃষ্টি: 0 পড়লে স্টেট অপরিবর্তিত থাকে (0 সংখ্যায় প্রভাব ফেলে না), 1 পড়লে স্টেট টগল হয় (এক-একটি 1 জোড়/বিজোড় অবস্থা উল্টে দেয়)।

start q_even (accept) q_odd (reject) 1 1 0 0
দুই-স্টেট DFA: q_even (গ্রহণযোগ্য) ও q_odd। প্রতিটি "1" স্টেট টগল করে, প্রতিটি "0" স্টেট অপরিবর্তিত রাখে।

ধাপে-ধাপে রান — ইনপুট "1010": শুরু $q_{even}$ → পড়ি 1 → $q_{odd}$ → পড়ি 0 → $q_{odd}$ → পড়ি 1 → $q_{even}$ → পড়ি 0 → $q_{even}$। শেষ স্টেট $q_{even} \in F$ — গ্রহণ (accept)। সত্যিই, "1010"-এ দুটি 1 আছে — জোড়।

ইনপুট "111": $q_{even} \to q_{odd} \to q_{even} \to q_{odd}$। শেষ স্টেট $q_{odd} \notin F$ — প্রত্যাখ্যান (reject)। "111"-এ তিনটি 1 — বিজোড়, ঠিক আছে।

Python
delta = {
    ('q_even', '0'): 'q_even',
    ('q_even', '1'): 'q_odd',
    ('q_odd', '0'): 'q_odd',
    ('q_odd', '1'): 'q_even',
}

def run_dfa(s):
    state = 'q_even'  # start state q0
    for ch in s:
        state = delta[(state, ch)]
    return state == 'q_even'  # F = {q_even}

for s in ["1010", "111", "0", "11011"]:
    ones = s.count("1")
    result = "accept (গ্রহণযোগ্য)" if run_dfa(s) else "reject (প্রত্যাখ্যাত)"
    print(f"'{s}' -> {ones}টি 1 -> {result}")

    

৩ · DFA-র "ভাষা" (Language)

একটি DFA যে ভাষা চেনে (recognize করে) তা হলো সেই সব স্ট্রিং-এর সেট যা $q_0$ থেকে শুরু করে চালালে $F$-এর কোনো স্টেটে গিয়ে থামে। উপরের DFA-র ভাষা হলো "জোড় সংখ্যক 1 সম্বলিত সব বাইনারি স্ট্রিং" — একটি অসীম সেট (infinite set), কিন্তু মাত্র দুটি স্টেট দিয়ে সসীমভাবে (finitely) বর্ণনা করা গেছে।

৪ · NFA — সংক্ষিপ্ত পরিচিতি

একটি NFA (Nondeterministic Finite Automaton)NFADFA-র মতোই, কিন্তু একটি স্টেট থেকে একই সিম্বলে একাধিক পরবর্তী স্টেটে যাওয়া যায় (বা কোনোটিতেই না) — "nondeterministic" আচরণ। -এ একটি স্টেট থেকে একই ইনপুটে একাধিক (বা শূন্য) পরবর্তী স্টেটে যাওয়া সম্ভব। বিস্ময়করভাবে, এই বাড়তি নমনীয়তা গণনাশক্তি বাড়ায় না — প্রতিটি NFA-র জন্য একটি সমতুল্য DFA আছে (subset construction পদ্ধতিতে বানানো যায়, এখানে বিস্তারিত ডেরাইভ করব না)। তাই DFA ও NFA ঠিক একই শ্রেণীর ভাষা চেনে — regular languages, যা L35-এ আরও বিস্তারিত দেখব।

মূল কথা · Key takeaway

একটি DFA হলো "সসীম মেমরি"-র সবচেয়ে বিশুদ্ধ গাণিতিক মডেল — এটি ইনপুট পড়ার সময় শুধু বর্তমান স্টেট মনে রাখে, পুরো ইতিহাস নয়। তবুও এই সীমাবদ্ধ মেমরি দিয়ে অসীম সংখ্যক স্ট্রিং-এর একটি অর্থবহ প্যাটার্ন (জোড় সংখ্যক 1) নির্ভুলভাবে চেনা যায় — এই সরল কিন্তু শক্তিশালী মডেলই প্রতিটি regex ইঞ্জিন ও কম্পাইলারের lexical analyzer-এর ভিত্তি (L35-এ বিস্তারিত)।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ এই DFA-তে "0" পড়লে স্টেট কখনো বদলায় না, শুধু "1" পড়লে বদলায়। এই ডিজাইন সিদ্ধান্তটি কেন সঠিক — অর্থাৎ কেন এটি সত্যিই "জোড় সংখ্যক 1" গণনা করে?

কারণ শুধু 1-ই "কতগুলো 1 দেখা হলো তার প্যারিটি (parity)" পরিবর্তন করে — প্রতিটি নতুন 1 জোড়/বিজোড় অবস্থা উল্টে দেয়। 0 মোট 1-এর সংখ্যায় কোনো অবদান রাখে না, তাই এটি পড়লে প্যারিটির কোনো পরিবর্তন হওয়া উচিত নয় — আর ঠিক এটাই self-loop ($\delta(q,0)=q$) নিশ্চিত করে।

এই "শুধু প্রাসঙ্গিক তথ্য মনে রাখা" নীতিই DFA ডিজাইনের মূল দক্ষতা — এখানে সম্পূর্ণ ইতিহাস (প্রতিটি বিট) মনে রাখার দরকার নেই, শুধু এখন পর্যন্ত 1-সংখ্যার প্যারিটি (মাত্র ২টি সম্ভাব্য মান) মনে রাখলেই যথেষ্ট।

প্র ০২ যদি "জোড় সংখ্যক 1" এর বদলে "1 এবং 0 উভয়ই ঠিক সমান সংখ্যকবার" থাকা স্ট্রিং চেনাতে চাইতেন, তাহলে কি এই একই দুই-স্টেট DFA কাজ করত?

না। "1 ও 0 সমান সংখ্যক" জানতে হলে DFA-কে ঠিক কত সংখ্যক অতিরিক্ত 1 বা 0 আছে তা মনে রাখতে হবে — এবং এই সংখ্যা ইনপুট যত লম্বা হোক না কেন বাড়তে পারে (আনবাউন্ডেড)। কিন্তু একটি DFA-র স্টেট সংখ্যা সসীম ও নির্দিষ্ট (fixed আগে থেকেই) — তাই এটি অসীম সংখ্যক ভিন্ন "কাউন্ট" আলাদাভাবে মনে রাখতে পারে না।

বাস্তবে, "সমান সংখ্যক 1 ও 0" ভাষাটি regular ভাষাই নয় — এটি চেনার জন্য একটি স্ট্যাক (আনবাউন্ডেড মেমরি) দরকার, যা একটি Pushdown Automaton (DFA-র চেয়ে শক্তিশালী মডেল, এই কোর্সের বাইরে) দিতে পারে। এটি L35-এ উল্লেখিত "non-regular languages"-এর একটি ভালো উদাহরণ।

প্র ০৩ একটি DFA-তে কি একাধিক accepting স্টেট ($|F|>1$) থাকতে পারে? একটি বাস্তব উদাহরণ চিন্তা করুন।

হ্যাঁ, সংজ্ঞা অনুযায়ী $F \subseteq Q$ হতে পারে যেকোনো সাবসেট, এমনকি পুরো $Q$-ও (যদিও তাহলে DFA সবকিছু গ্রহণ করবে, যা সাধারণত অর্থহীন)। উদাহরণ: এমন একটি DFA যা "দৈর্ঘ্য 3-এর গুণিতক নয় এমন স্ট্রিং" চেনে — তিনটি স্টেট $\{q_0, q_1, q_2\}$ (দৈর্ঘ্য mod 3 ট্র্যাক করে), এবং $F = \{q_1, q_2\}$ (দুটি accepting স্টেট, শুধু $q_0$ non-accepting)।

মূল কথা: $F$-এর আকার সমস্যার প্রকৃতির উপর নির্ভর করে — কোনো ফিক্সড নিয়ম নেই যে ঠিক একটি accepting স্টেট থাকতে হবে।

অনুশীলন

  1. হাতে চালান: ইনপুট "0" এবং "11011"-এর জন্য উপরের DFA হাতে-কলমে চালান (প্রতিটি ধাপের স্টেট লিখুন), তারপর accept/reject সিদ্ধান্ত দিন।

    "0": $q_{even} \to q_{even}$ (শুধু একটি 0 পড়া হলো, কোনো 1 নেই)। শেষ স্টেট $q_{even} \in F$ — accept (শূন্যটি 1 — জোড়)।

    "11011": $q_{even} \to q_{odd} \to q_{even} \to q_{even} \to q_{odd} \to q_{even}$ (চারটি 1 আছে: অবস্থান ১,২,৪,৫)। শেষ স্টেট $q_{even} \in F$ — accept (চারটি 1 — জোড়)। কোড সেল চালিয়ে দুটোই মিলিয়ে দেখুন।

  2. নিজে ডিজাইন করুন: এমন একটি DFA-র স্টেট ডায়াগ্রাম বর্ণনা করুন যা "3 দিয়ে বিভাজ্য দৈর্ঘ্যের বাইনারি স্ট্রিং" চেনে (দৈর্ঘ্য mod 3 == 0)।

    তিনটি স্টেট দরকার: $Q=\{r_0, r_1, r_2\}$ (দৈর্ঘ্য mod 3 ট্র্যাক করে), $q_0=r_0$, $F=\{r_0\}$। ট্রানজিশন উভয় সিম্বলের (0 এবং 1) জন্যই একই: $\delta(r_i, 0)=\delta(r_i, 1)=r_{(i+1) \bmod 3}$ — কারণ দৈর্ঘ্যের হিসাবে সিম্বলের মান (0 না 1) গুরুত্বপূর্ণ নয়, শুধু সংখ্যা গুরুত্বপূর্ণ। এটি দেখায় কীভাবে DFA ডিজাইনের প্রথম প্রশ্ন সবসময় হওয়া উচিত: "ঠিক কোন তথ্যটুকু মনে রাখা যথেষ্ট?"

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
বুলিয়ান অ্যালজেব্রা ও লজিক গেট