ফিনাইট স্টেট অটোমাটা
এই পাঠে যা শিখবেন
- 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)$ দিয়ে সংজ্ঞায়িত —
সসীম সংখ্যক স্টেটের সেট (finite set of states)
বর্ণমালা (Alphabet)Alphabet (Σ)ইনপুট স্ট্রিং তৈরি করতে ব্যবহৃত সিম্বলের সসীম সেট — যেমন {0,1}। — ইনপুট সিম্বলের সসীম সেট, যেমন {0,1}
ট্রানজিশন ফাংশন (δ)Transition Function$\delta: Q \times \Sigma \rightarrow Q$ — বর্তমান স্টেট ও পঠিত সিম্বল থেকে পরবর্তী স্টেট নির্ধারণ করে। — $Q \times \Sigma \rightarrow Q$, বর্তমান স্টেট ও সিম্বল থেকে পরবর্তী স্টেট বলে দেয়
শুরুর স্টেট (start state), $q_0 \in Q$
গ্রহণযোগ্য (accepting/final) স্টেটের সেট, $F \subseteq Q$
২ · Worked উদাহরণ — জোড় সংখ্যক 1 চেনা
লক্ষ্য: এমন একটি DFA বানানো যা শুধু সেই বাইনারি স্ট্রিং-গুলো গ্রহণ করবে যেখানে 1-এর সংখ্যা জোড় (even) — শূন্যও একটি জোড় সংখ্যা হিসেবে গণ্য, তাই খালি স্ট্রিং ও সব-0 স্ট্রিং-ও গ্রহণযোগ্য।
$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 জোড়/বিজোড় অবস্থা উল্টে দেয়)।
ধাপে-ধাপে রান — ইনপুট "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 — বিজোড়, ঠিক আছে।
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-এ আরও বিস্তারিত দেখব।
একটি 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 স্টেট থাকতে হবে।
অনুশীলন
-
হাতে চালান: ইনপুট
"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 — জোড়)। কোড সেল চালিয়ে দুটোই মিলিয়ে দেখুন। -
নিজে ডিজাইন করুন: এমন একটি 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-এ আপনার পরবর্তী পদক্ষেপ
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৪৪টি পাঠ পরবর্তী পাঠ — এই একই DFA-কে একটি regular expression দিয়ে কীভাবে ঠিক সমানভাবে বর্ণনা করা যায় তা দেখাবে।
- Data Structures & Algorithms কোর্স সঙ্গী কোর্স DFA-র মতো state-machine ধারণা বাস্তব প্রোগ্রামে (parser, lexer) কীভাবে বাস্তবায়িত হয় তা দেখতে DSA কোর্সটিও দেখুন।
- সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, DBMS, HTML & CSS ও Discrete Mathematics — সব এক জায়গায়।