পাঠ ২৯ · ৫৬-এর মধ্যে · মডিউল ৭
Home / Courses / Formal Language & Automata Theory / Theory of Computation / কনটেক্সট-সেনসিটিভ গ্রামার

কনটেক্সট-সেনসিটিভ গ্রামার ও লিনিয়ার বাউন্ডেড অটোমাটা

Context-sensitive grammars & linear bounded automata
৮ মিনিট পড়া উচ্চ · Advanced Python কোডসহ সম্পূর্ণ বাংলায়

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

  • কনটেক্সট-সেনসিটিভ গ্রামারের দুটি সমতুল্য সংজ্ঞা — context-dependent রুল ও নন-কন্ট্রাক্টিং রুল
  • লিনিয়ার বাউন্ডেড অটোমাটা কী এবং কেন এটি চমস্কি হায়ারার্কির ঠিক এই স্তরের recognizing automaton
  • কেন বাউন্ডেড টেপ CSG মেম্বারশিপকে ডিসাইডেবল রাখে — M9-এর প্রথম সরাসরি foreshadowing
  • $\{a^nb^nc^n\}$-এর জন্য একটি real CSG, যা L26-এ context-free নয় বলে প্রমাণিত — এবং তার কোড-ভেরিফায়েড ডেরিভেশন

১ · কনটেক্সট-সেনসিটিভ গ্রামার — দুই সমতুল্য সংজ্ঞা

L17-এর CFG রুল $A \to \alpha$-এ ভেরিয়েবল $A$ যেকোনো কনটেক্সটে থাকলেই রিপ্লেস করা যায় — "কনটেক্সট-ফ্রি" নামটার উৎস ঠিক এখানেই। কনটেক্সট-সেনসিটিভ গ্রামারContext-Sensitive Grammarএকটি গ্রামার যার প্রতিটি রুলে একটি ভেরিয়েবল শুধু একটি নির্দিষ্ট বাম-ডান কনটেক্সটে থাকলেই রিপ্লেস করা যায়। (CSG, Type 1) এই স্বাধীনতা সরিয়ে নেয় — প্রতিটি রুল এই আকৃতির:

$$\alpha A \beta \to \alpha\gamma\beta \quad \text{যেখানে } \gamma \neq \varepsilon$$

অর্থাৎ ভেরিয়েবল $A$ শুধু তখনই $\gamma$ দিয়ে রিপ্লেস করা যায় যখন এটি বাম দিকে ঠিক $\alpha$ ও ডান দিকে ঠিক $\beta$ দিয়ে ঘেরা থাকে — "context-sensitive" নামের উৎস।

একটি সমতুল্য, অনেক সময় বেশি ব্যবহারিক বিকল্প সংজ্ঞা আছে — নন-কন্ট্রাক্টিং (noncontracting) গ্রামার: প্রতিটি রুল $\alpha \to \beta$ এই শর্ত মেনে চলে —

$$|\beta| \geq |\alpha|$$

অর্থাৎ ডেরাইভড স্ট্রিং কখনো ছোট হয় না, শুধু বড় হতে পারে বা একই দৈর্ঘ্যে থাকতে পারে। এই দুই সংজ্ঞা প্রমাণযোগ্যভাবে সমতুল্য (mention only — বিস্তারিত প্রমাণ এই পাঠের সুযোগের বাইরে)। এই কোর্স "নন-কন্ট্রাক্টিং" রূপটি ব্যবহার করবে, কারণ এটি কোডে ডিরেক্টলি চেক করা সহজ।

২ · লিনিয়ার বাউন্ডেড অটোমাটা (LBA)

লিনিয়ার বাউন্ডেড অটোমাটাLinear Bounded Automaton (LBA)একটি টুরিং-মেশিন-সদৃশ যন্ত্র যার টেপ ব্যবহার ইনপুটের দৈর্ঘ্যেই সীমাবদ্ধ -- অতিরিক্ত টেপ ব্যবহার করা যায় না। হলো একটি টুরিং-মেশিন-সদৃশ যন্ত্র (সম্পূর্ণ ফরমাল সংজ্ঞা M8/L32-এ, কিন্তু LBA-কে এখানেই introduce করা হচ্ছে কারণ চমস্কি হায়ারার্কিতে ঠিক এটাই এর জায়গা) যার টেপ ঠিক ইনপুটের দৈর্ঘ্যে সীমাবদ্ধ — ইনপুটের বাইরে অতিরিক্ত টেপ ব্যবহার করতে পারে না, M8-এর আনরেস্ট্রিক্টেড, অসীম-টেপ টুরিং মেশিনের সরাসরি বৈপরীত্যে।

থিওরেম (L08-এর NFA=DFA ও L24-এর CFG=PDA-এর ঠিক CSG-LBA অ্যানালগ): একটি ভাষা কনটেক্সট-সেনসিটিভ হয় যদি এবং শুধুমাত্র যদি কোনো LBA সেটি চেনে। এই থিওরেমটাই চমস্কি হায়ারার্কির প্রতিটি স্তরের "গ্রামার ⇔ অটোমাটা" প্যাটার্নের ধারাবাহিকতা — regular⇔DFA (M2), context-free⇔PDA (M4-M5), এখন context-sensitive⇔LBA (M7)।

রেগুলার DFA/NFA (M2) কনটেক্সট-ফ্রি PDA (M4-M5) কনটেক্সট-সেনসিটিভ LBA (M7 -- এই পাঠ) টুরিং মেশিন Type 0 (M8, আনবাউন্ডেড টেপ)
প্রতিটি স্তরের নিজস্ব recognizing automaton — regular↔DFA, context-free↔PDA, context-sensitive↔LBA, আর সবশেষে unrestricted↔টুরিং মেশিন (L30)।

৩ · কেন CSG মেম্বারশিপ ডিসাইডেবল — বাউন্ডেড টেপের সরাসরি পরিণতি

এখানেই একটি genuinely গুরুত্বপূর্ণ, forward-looking সত্য দাঁড় করানো যায়। যেহেতু একটি LBA-এর টেপ ইনপুট দৈর্ঘ্যে সীমাবদ্ধ, তার সম্ভাব্য কনফিগারেশনএকটি মুহূর্তে যন্ত্রের সম্পূর্ণ অবস্থা — বর্তমান স্টেট, টেপের বিষয়বস্তু, ও হেড-এর অবস্থান — একসাথে-এর সংখ্যা ফাইনাইট (যদিও সম্ভবত বিশাল)। LBA সিমুলেট করার সময় — যেহেতু ফাইনাইট কনফিগারেশন — মেশিন হয় accept করবে, reject করবে, অথবা একটি কনফিগারেশন পুনরাবৃত্তি (repeat) করবে (যা detectable, তাই "infinite loop" ধরা পড়ে যায়, একে reject হিসেবে গণ্য করা যায়)। এর মানে — মেশিন কখনোই সত্যিকারভাবে চিরকাল নতুন, unrepeat-হওয়া কনফিগারেশনে চলতে পারে না — মেম্বারশিপ প্রশ্ন সবসময় একটি নির্দিষ্ট সময়ে ডিসাইড করা যায়।

M9-এর সরাসরি foreshadowing

এই বাউন্ডেড-টেপ, ফাইনাইট-কনফিগারেশন যুক্তি ঠিক ততটাই কাজ করে না M8-এর সাধারণ টুরিং মেশিনের জন্য, যার টেপ conceptually অসীম — সেখানে কনফিগারেশন সংখ্যা অসীম হতে পারে, তাই মেশিন সত্যিই চিরকাল (কখনো পুনরাবৃত্তি না করেই) চলতে পারে — এটাই ঠিক কেন M9-এর টুরিং-মেশিন মেম্বারশিপ (হল্টিং প্রবলেম-সংক্রান্ত) আনডিসাইডেবল হয়ে যায়, যেখানে এই পাঠের CSG মেম্বারশিপ ডিসাইডেবলই থেকে যায়।

৪ · CFG বনাম CSG — একটি তুলনা

নিচের কোডে CFG ও CSG-এর মূল বৈশিষ্ট্যগুলো পাশাপাশি তুলনা করা একটি রেফারেন্স টেবিল বানানো হয়েছে, এবং $\{a^nb^nc^n : n \geq 1\}$-এর জন্য একটি real CSG বানিয়ে তার ওপর একটি জেনুইন derivation-search চালানো হয়েছে — L26 প্রমাণ করেছিল এই ভাষা context-free নয়; এখানেই ঠিক দেখানো হচ্ছে কেন Type 1-এ এক ধাপ ওপরে ওঠা দরকার হয়েছিল এই ভাষা জেনারেট করতে।

Python
# CFG বনাম CSG -- মূল বৈশিষ্ট্যের তুলনা টেবিল
comparison = {
    'CFG (Type 2)': {
        'rule_form': 'A -> alpha  (একটি ভেরিয়েবল, যেকোনো কনটেক্সটে রিপ্লেসযোগ্য)',
        'growth_property': 'কন্ট্রাক্টিং অনুমোদিত (A -> eps সম্ভব)',
        'recognizing_automaton': 'PDA (M5)',
        'example_language': '{0^n 1^n}  -- L14/L22',
    },
    'CSG (Type 1)': {
        'rule_form': 'alpha A beta -> alpha gamma beta  (কনটেক্সট-নির্ভর)',
        'growth_property': 'নন-কন্ট্রাক্টিং -- |beta| >= |alpha| সবসময়',
        'recognizing_automaton': 'Linear Bounded Automaton (এই পাঠ)',
        'example_language': '{a^n b^n c^n}  -- L26-এ context-free নয় প্রমাণিত',
    },
}
for grammar_type, features in comparison.items():
    print(grammar_type)
    for key, value in features.items():
        print("   ", key, ":", value)
    print()

# {a^n b^n c^n : n >= 1}-এর জন্য একটি real CSG (নন-কন্ট্রাক্টিং রুল)
#   S  -> a S B C
#   S  -> a B C
#   CB -> BC
#   aB -> ab
#   bB -> bb
#   bC -> bc
#   cC -> cc
RULES = [
    (('S',), ('a', 'S', 'B', 'C')),
    (('S',), ('a', 'B', 'C')),
    (('C', 'B'), ('B', 'C')),
    (('a', 'B'), ('a', 'b')),
    (('b', 'B'), ('b', 'b')),
    (('b', 'C'), ('b', 'c')),
    (('c', 'C'), ('c', 'c')),
]
START = ('S',)

from collections import deque

def csg_can_derive(rules, start, target_string, max_len_bound, max_steps=200000):
    """BFS স্ট্রিং-রিরাইটিং সার্চ -- start থেকে ঠিক target_string ডেরাইভ করা যায় কি না।
    সব রুল নন-কন্ট্রাক্টিং (RHS দৈর্ঘ্য >= LHS দৈর্ঘ্য) বলে, দৈর্ঘ্য টার্গেটের চেয়ে বড় হয়ে গেলে
    আর কখনো ছোট হবে না -- তাই দৈর্ঘ্য-ভিত্তিক pruning নিরাপদ।"""
    target = tuple(target_string)
    queue = deque([start])
    seen = {start}
    steps = 0
    while queue and steps < max_steps:
        steps += 1
        form = queue.popleft()
        if form == target:
            return True
        if len(form) > max_len_bound:
            continue
        for lhs, rhs in rules:
            L = len(lhs)
            for i in range(0, len(form) - L + 1):
                if form[i:i + L] == lhs:
                    new_form = form[:i] + rhs + form[i + L:]
                    if new_form not in seen and len(new_form) <= max_len_bound:
                        seen.add(new_form)
                        queue.append(new_form)
    return False

print("CSG দিয়ে 'aabbcc' (a^2b^2c^2) ডেরাইভ করা যায়?", csg_can_derive(RULES, START, "aabbcc", max_len_bound=6))
print("CSG দিয়ে 'aabbc' (ভুল প্যাটার্ন) ডেরাইভ করা যায়?", csg_can_derive(RULES, START, "aabbc", max_len_bound=6))
print("CSG দিয়ে 'abc' (a^1b^1c^1) ডেরাইভ করা যায়?", csg_can_derive(RULES, START, "abc", max_len_bound=3))

    
লক্ষ্য করুন csg_can_derive কোনো hardcoded উত্তর দেয় না — এটি সত্যিই স্টার্ট সিম্বল $S$ থেকে শুরু করে সবগুলো সম্ভাব্য রুল-অ্যাপ্লিকেশন BFS-এ অনুসন্ধান করে দেখে target স্ট্রিং-এ পৌঁছানো যায় কি না। "aabbcc" (n=2, বৈধ প্যাটার্ন) থেকে "True" আসে, কিন্তু "aabbc" (ভুল প্যাটার্ন — সমান a,b,c সংখ্যা নয়) থেকে "False" আসে — এটাই কনক্রিট প্রমাণ এই CSG ঠিক $\{a^nb^nc^n\}$ জেনারেট করছে, অন্য কিছু নয়।
মূল কথা · Key takeaway

কনটেক্সট-সেনসিটিভ গ্রামার (Type 1) নন-কন্ট্রাক্টিং রুল ব্যবহার করে, LBA দিয়ে চেনা যায় — CFG=PDA-এর ঠিক পরের স্তরের সমতুল্যতা। LBA-এর বাউন্ডেড টেপ, ফাইনাইট কনফিগারেশন, তাই CSG মেম্বারশিপ ডিসাইডেবল — টুরিং মেশিনের আনবাউন্ডেড টেপের বিপরীতে, যেখানে এই একই প্রশ্ন M9-এ আনডিসাইডেবল হয়ে যাবে।

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

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

প্র ০১ CFG-তে $A \to \varepsilon$ (একটি ভেরিয়েবলকে খালি স্ট্রিং দিয়ে রিপ্লেস) একটি সাধারণ, বৈধ রুল — কিন্তু CSG-তে কেন এটি সাধারণভাবে অনুমোদিত নয়?

কারণ $A \to \varepsilon$ একটি কন্ট্রাক্টিং রুল — বাম দিকের দৈর্ঘ্য ($|A|=1$) ডান দিকের দৈর্ঘ্যের ($|\varepsilon|=0$) চেয়ে বেশি, যা নন-কন্ট্রাক্টিং শর্ত ($|\beta| \geq |\alpha|$) ভঙ্গ করে। CSG-এর সংজ্ঞাই দাবি করে ডেরাইভড স্ট্রিং কখনো ছোট হবে না — এই কড়াকড়ির বিনিময়েই LBA-এর বাউন্ডেড-টেপ সিমুলেশন সম্ভব হয় (§৩) — যদি স্ট্রিং সংকুচিত হতে পারত, তাহলে টেপের দৈর্ঘ্য ইনপুটের দৈর্ঘ্যেই বাউন্ড করে রাখা আর নিরাপদ হতো না।

প্র ০২ একটি LBA-এর "কনফিগারেশন সংখ্যা ফাইনাইট" — এটা কেন সত্যি, যদিও গণনা করলে সংখ্যাটা বিশাল হতে পারে?

একটি কনফিগারেশন = (স্টেট, টেপের বিষয়বস্তু, হেড পজিশন)। স্টেট সংখ্যা ফাইনাইট (গ্রামার/অটোমাটার সংজ্ঞা অনুযায়ী), হেড পজিশন ফাইনাইট (টেপ ইনপুট দৈর্ঘ্য $n$-এ বাউন্ডেড), আর টেপের বিষয়বস্তু — যদিও প্রতিটি সেলে একাধিক সম্ভাব্য সিম্বল থাকতে পারে (ধরুন $|\Gamma|$টি), সেলের সংখ্যা $n$ (ফাইনাইট) বলে সম্ভাব্য টেপ-কন্টেন্টের সংখ্যা $|\Gamma|^n$ — বিশাল, কিন্তু তবুও একটি ফাইনাইট সংখ্যা। ফাইনাইট × ফাইনাইট × ফাইনাইট = ফাইনাইট মোট কনফিগারেশন — এটাই মূল যুক্তি, সংখ্যাটা কতটা বড় তা গুরুত্বপূর্ণ নয়, শুধু এটা যে ফাইনাইট।

প্র ০৩ উপরের কোডে $\{a^nb^nc^n\}$-এর CSG-তে $CB \to BC$ রুলটির উদ্দেশ্য কী?

$S \to aSBC$ রুল বারবার প্রয়োগ করলে সব $B$ ও $C$ সিম্বল মিশ্রিতভাবে ($BCBCBC...$ প্যাটার্নে) তৈরি হয় — কিন্তু চূড়ান্ত স্ট্রিং-এ আমাদের সব $b$ আগে, তারপর সব $c$ দরকার। $CB \to BC$ রুলটি একটি "সর্টিং" ধাপ — এটি পাশাপাশি থাকা $C$ এবং $B$-কে (এই ক্রমে) অদল-বদল করে দেয়, যতক্ষণ না সব $B$ একসাথে ও সব $C$ একসাথে জড়ো হয় (একটি bubble-sort-এর মতো প্রক্রিয়া) — তারপরই $aB \to ab$, $bB \to bb$, $bC \to bc$, $cC \to cc$ রুলগুলো প্রয়োগ করে ধাপে ধাপে সেগুলো টার্মিনালে পরিণত করা যায়।

অনুশীলন

  1. পরীক্ষা করুন: উপরের কোডে csg_can_derive-কে "aaabbbccc" (n=3) দিয়ে চালান, max_len_bound=9 সেট করে। ফলাফল কী প্রত্যাশিত, ও কেন?

    ফলাফল True হবে — "aaabbbccc" ঠিক $a^3b^3c^3$ প্যাটার্ন মেনে চলে, যা এই CSG জেনারেট করার কথা। যদি max_len_bound টার্গেট স্ট্রিং-এর দৈর্ঘ্যের চেয়ে ছোট সেট করা হয় (যেমন ৮), তাহলে সার্চটি সঠিক টার্গেট পর্যন্ত পৌঁছানোর আগেই সব ব্রাঞ্চ prune করে ফেলবে, ভুলভাবে False রিটার্ন করবে — তাই bound সবসময় অন্তত টার্গেট দৈর্ঘ্যের সমান রাখা জরুরি।

  2. চিন্তা করুন: L26-এর পাম্পিং লেমা প্রমাণ করেছিল $\{a^nb^nc^n\}$ context-free নয়। এই পাঠের CSG সেই একই ভাষা জেনারেট করে দেখাল। এই দুটো তথ্য একসাথে কী বলে চমস্কি হায়ারার্কি সম্পর্কে?

    এটি নিশ্চিত করে যে Type 1 (context-sensitive) সত্যিই Type 2 (context-free) থেকে strictly বেশি শক্তিশালী — অন্তত একটি ভাষা ($a^nb^nc^n$) আছে যা Type 1-এ জেনারেট করা যায় কিন্তু Type 2-তে যায় না। এটাই প্রপার কন্টেইনমেন্ট (Type 2 ⊊ Type 1) প্রমাণের একটি সরাসরি, কনক্রিট উপাদান — L31-এ এই সম্পূর্ণ যুক্তিটি একসাথে সাজানো হবে।

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

আগের পাঠ
L28 · কনটেক্সট-ফ্রি ল্যাঙ্গুয়েজের ডিসিশন প্রপার্টি