পাঠ ৪১ · ৫৬-এর মধ্যে · মডিউল ৯
Home / Courses / Formal Language & Automata Theory / Theory of Computation / রাইসের থিওরেম

রাইসের থিওরেম

Rice's theorem
৮ মিনিট পড়া উচ্চ · Advanced Python কোডসহ সম্পূর্ণ বাংলায়

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

  • রাইসের থিওরেমের সম্পূর্ণ, নির্ভুল বিবৃতি এবং এর দুটো পূর্বশর্ত (ভাষা-প্রপার্টি, নন-ট্রিভিয়াল) নির্ভুলভাবে
  • কেন "M-এর কয়টি state আছে" জাতীয় প্রশ্ন রাইসের থিওরেমের আওতায় পড়ে না — ভাষা-প্রপার্টি বনাম implementation-প্রপার্টির পার্থক্য
  • রাইসের থিওরেম কীভাবে L40-এর $E_{TM}$-সহ অসংখ্য আলাদা রিডাকশন প্রমাণকে একটি একক ফলাফলে একীভূত করে
  • বাস্তব-জগতের প্রভাব — কেন অ্যান্টিভাইরাস সফটওয়্যার কখনো নিখুঁতভাবে সম্পূর্ণ হতে পারে না
  • Python দিয়ে একটি real প্রপার্টি-ক্লাসিফিকেশন টেবিল, এবং L40-এর build_Mw প্যাটার্নের একটি নতুন, ভিন্ন প্রপার্টির জন্য পুনর্ব্যবহার — দেখানো যে বিভিন্ন Rice-instance আসলে একই আন্ডারলাইং রিডাকশন টেকনিক শেয়ার করে

১ · রাইসের থিওরেম — সম্পূর্ণ, নির্ভুল বিবৃতি

রাইসের থিওরেমRice's Theoremএকটি টুরিং মেশিনের ভাষার যেকোনো নন-ট্রিভিয়াল প্রপার্টিই আনডিসাইডেবল বলে —

$$\text{টুরিং মেশিন } M \text{-এর দ্বারা রিকগনাইজড ভাষা } L(M) \text{-এর যেকোনো \textbf{নন-ট্রিভিয়াল} \textbf{প্রপার্টি}ই \textbf{আনডিসাইডেবল}}$$

এই দুটো টার্মকেই একদম নির্ভুলভাবে বোঝা জরুরি —

  • "ভাষা-প্রপার্টি" (property of the language): একটি প্রপার্টি $P$ (ফরমালি, ভাষার একটি সেট) "ভাষার" প্রপার্টি তখনই যখন এটি শুধুমাত্র $L(M)$-এর উপর নির্ভর করে, $M$-এর নিজস্ব অভ্যন্তরীণ গঠন/বাস্তবায়নের উপর নয়। যেমন — "$M$-এর ঠিক ৫টি state আছে কি?" এটি ভাষা-প্রপার্টি নয় — এটা নির্ভর করে $M$ কীভাবে বানানো হয়েছে তার উপর, $L(M)$-এর উপর নয় — রাইসের থিওরেম এই ধরনের প্রশ্নে প্রযোজ্য নয়।
  • "নন-ট্রিভিয়াল": প্রপার্টিটা অন্তত একটি Turing-recognizable ভাষার জন্য সত্য, এবং অন্তত আরেকটির জন্য মিথ্যা (অর্থাৎ vacuously সবসময়-সত্য বা সবসময়-মিথ্যা নয়, যা তুচ্ছভাবেই ডিসাইডেবল হতো — একটি constant উত্তর দিলেই চলত)।

২ · আকর্ষণীয় ফলাফল — অনেক প্রশ্ন একসাথে আনডিসাইডেবল

এই থিওরেমের শক্তি সত্যিই আকর্ষণীয় — "$L(M)$ কি রেগুলার?", "$L(M)$-এ কি একটি নির্দিষ্ট স্ট্রিং আছে?", "$L(M)$ কি খালি?" (L40-এর $E_{TM}$, এখন দেখা যাচ্ছে এটি শুধু একটি উদাহরণ মাত্র এই অনেক-বৃহত্তর থিওরেমের), "$L(M)$ কি একটি নির্দিষ্ট ফিক্সড ভাষার সমান?" — এই সবকটাই আনডিসাইডেবল, কারণ প্রতিটিই একটি genuine নন-ট্রিভিয়াল ভাষা-প্রপার্টি।

রাইসের থিওরেম যেকোনো নন-ট্রিভিয়াল ভাষা-প্রপার্টি L(M) খালি? (E_TM, L40) L(M)-এ 'ab' আছে? L(M) রেগুলার? L(M) = Σ*? প্রতিটি প্রশ্নের জন্য পৃথক রিডাকশন লাগে না -- সবকটাই একই থিওরেমের প্রয়োগ
রাইসের থিওরেম একটি ছাতার মতো — L40-এর $E_{TM}$-সহ অসংখ্য পৃথক আনডিসাইডেবিলিটি ফলাফলকে একটি একক, সাধারণ বিবৃতিতে একীভূত করে।

৩ · বাস্তব-জগতের প্রভাব — কেন অ্যান্টিভাইরাস কখনো নিখুঁত হতে পারে না

এই থিওরেমের একটি সরাসরি, বাস্তব-জগতের প্রভাব আছে — cross-ref ../cybersecurity/। "এই প্রোগ্রামটির আচরণ কি কোনো ম্যালিশিয়াস প্যাটার্নের সাথে মেলে?" — এটি একটি genuine নন-ট্রিভিয়াল ভাষা-প্রপার্টি (কিছু প্রোগ্রামের আচরণ মেলে, কিছুর মেলে না, এবং এটা শুধু প্রোগ্রামটার আচরণের উপর নির্ভর করে, তার সোর্স কোডের নির্দিষ্ট গঠনের উপর নয়) — রাইসের থিওরেম অনুযায়ী এটি আনডিসাইডেবল। এই কারণেই বাস্তব অ্যান্টিভাইরাস সফটওয়্যার কখনোই একটি নিখুঁত, সাধারণ-উদ্দেশ্যে ডিসিশন প্রসিডিউর ব্যবহার করে না — বরং হিউরিস্টিক ও আংশিক (incomplete) approximation ব্যবহার করে, ঠিক কারণ কোনো নিখুঁত সমাধান থাকতেই পারে না।

৪ · কোড সেল — প্রপার্টি ক্লাসিফিকেশন ও রিডাকশন প্যাটার্নের পুনর্ব্যবহার

নিচের কোড সেলে প্রথমে কয়েকটি উদাহরণ প্রপার্টি রাইসের থিওরেমের দুটো শর্ত (ভাষা-প্রপার্টি? নন-ট্রিভিয়াল?) অনুযায়ী ক্লাসিফাই করা হচ্ছে। তারপর L40-এর build_Mw কনস্ট্রাকশনই আবার ব্যবহার করে — এবার $E_{TM}$-এর বদলে "$L(M)$-এ অন্তত একটি স্ট্রিং আছে" প্রপার্টির জন্য — দেখানো হচ্ছে একই রিডাকশন টেকনিক ভিন্ন প্রপার্টির জন্যও কাজ করে। (এখানে bounded_nonempty_property_checker একটি বাউন্ডেড approximation — একটি সসীম দৈর্ঘ্য-সীমা পর্যন্ত স্ট্রিং খুঁজে দেখে, সত্যিকারের কোনো সাধারণ-উদ্দেশ্যে decider নয়, যা রাইসের থিওরেম অনুযায়ী থাকতেই পারে না — কিন্তু এই ছোট, নির্দিষ্ট টেস্ট কেসগুলোর জন্য এটি সঠিক উত্তর দেয়, যথেষ্ট প্রমাণ করার জন্য যে রিডাকশন কনস্ট্রাকশনটাই সঠিক)।

Python
import itertools

BLANK = '_'

class TuringMachine:
    """L32/L37-এর ধাঁচের একটি জেনেরিক TM।"""
    def __init__(self, transitions, start, accept, reject, blank=BLANK):
        self.transitions = transitions
        self.start, self.accept, self.reject, self.blank = start, accept, reject, blank

    def run(self, input_string, max_steps=3000):
        tape = {i: c for i, c in enumerate(input_string)}
        head, state, steps = 0, self.start, 0
        while state != self.accept and state != self.reject and steps < max_steps:
            symbol = tape.get(head, self.blank)
            key = (state, symbol)
            if key not in self.transitions:
                return 'reject', steps
            new_state, write_symbol, direction = self.transitions[key]
            tape[head] = write_symbol
            head += 1 if direction == 'R' else -1
            state = new_state
            steps += 1
        if state == self.accept:
            return 'accept', steps
        elif state == self.reject:
            return 'reject', steps
        else:
            return 'timeout', steps


# L37-এর M -- L = {0^n 1^n : n >= 0}
zn_transitions = {
    ('q_find0', 'X'): ('q_find0', 'X', 'R'), ('q_find0', 'Y'): ('q_find0', 'Y', 'R'),
    ('q_find0', '0'): ('q_goright', 'X', 'R'), ('q_find0', '1'): ('q_reject', '1', 'R'),
    ('q_find0', BLANK): ('q_accept', BLANK, 'R'),
    ('q_goright', '0'): ('q_goright', '0', 'R'), ('q_goright', '1'): ('q_goright', '1', 'R'),
    ('q_goright', 'X'): ('q_goright', 'X', 'R'), ('q_goright', 'Y'): ('q_goright', 'Y', 'R'),
    ('q_goright', BLANK): ('q_findlast', BLANK, 'L'),
    ('q_findlast', 'X'): ('q_findlast', 'X', 'L'), ('q_findlast', 'Y'): ('q_findlast', 'Y', 'L'),
    ('q_findlast', '1'): ('q_gohome', 'Y', 'L'), ('q_findlast', '0'): ('q_reject', '0', 'L'),
    ('q_findlast', BLANK): ('q_reject', BLANK, 'L'),
    ('q_gohome', '0'): ('q_gohome', '0', 'L'), ('q_gohome', '1'): ('q_gohome', '1', 'L'),
    ('q_gohome', 'X'): ('q_gohome', 'X', 'L'), ('q_gohome', 'Y'): ('q_gohome', 'Y', 'L'),
    ('q_gohome', BLANK): ('q_find0', BLANK, 'R'),
}
M = TuringMachine(zn_transitions, 'q_find0', 'q_accept', 'q_reject')


class TMEncoder:
    SEP_FIELD, SEP_RULE, SEP_PARTS, SEP_ARROW = ';;', '|', ',', '>'

    @staticmethod
    def encode(tm):
        parts = ['START=' + tm.start, 'ACCEPT=' + tm.accept,
                 'REJECT=' + tm.reject, 'BLANK=' + tm.blank]
        rules = []
        for (state, symbol), (ns, ws, d) in tm.transitions.items():
            lhs = TMEncoder.SEP_PARTS.join([state, symbol])
            rhs = TMEncoder.SEP_PARTS.join([ns, ws, d])
            rules.append(lhs + TMEncoder.SEP_ARROW + rhs)
        parts.append('TRANS=' + TMEncoder.SEP_RULE.join(rules))
        return TMEncoder.SEP_FIELD.join(parts)

    @staticmethod
    def decode(encoded):
        fields = dict(f.split('=', 1) for f in encoded.split(TMEncoder.SEP_FIELD))
        transitions = {}
        if fields['TRANS']:
            for rule in fields['TRANS'].split(TMEncoder.SEP_RULE):
                lhs, rhs = rule.split(TMEncoder.SEP_ARROW)
                state, symbol = lhs.split(TMEncoder.SEP_PARTS)
                ns, ws, d = rhs.split(TMEncoder.SEP_PARTS)
                transitions[(state, symbol)] = (ns, ws, d)
        return transitions, fields['START'], fields['ACCEPT'], fields['REJECT'], fields['BLANK']


class UniversalSimulator:
    def __init__(self, encoded_tm):
        (self.transitions, self.start, self.accept,
         self.reject, self.blank) = TMEncoder.decode(encoded_tm)

    def run(self, input_string, max_steps=3000):
        tape = {i: c for i, c in enumerate(input_string)}
        head, state, steps = 0, self.start, 0
        while state != self.accept and state != self.reject and steps < max_steps:
            symbol = tape.get(head, self.blank)
            key = (state, symbol)
            if key not in self.transitions:
                return 'reject', steps
            ns, ws, d = self.transitions[key]
            tape[head] = ws
            head += 1 if d == 'R' else -1
            state = ns
            steps += 1
        if state == self.accept:
            return 'accept', steps
        elif state == self.reject:
            return 'reject', steps
        else:
            return 'timeout', steps


def build_Mw(m_encoded, w, buffer=60):
    """L40-এর রিডাকশন কনস্ট্রাকশনের হুবহু পুনর্ব্যবহার -- M_w তার নিজের ইনপুট ignore
    করে, নিরাপদে দূরে সরে গিয়ে w লেখে, তারপর M-কে সেই w-এর উপর চালায়।"""
    transitions, start, accept, reject, blank = TMEncoder.decode(m_encoded)
    new_transitions = dict(transitions)
    seek_len = buffer + max(len(w), 1)
    for i in range(seek_len):
        cur = f'mw_seek_{i}'
        nxt = f'mw_seek_{i+1}' if i + 1 < seek_len else 'mw_write_0'
        for sym in ('0', '1', blank):
            new_transitions[(cur, sym)] = (nxt, sym, 'L')
    if len(w) == 0:
        for sym in ('0', '1', blank):
            new_transitions[('mw_write_0', sym)] = ('mw_return_0', sym, 'R')
    else:
        for i, ch in enumerate(w):
            cur = f'mw_write_{i}'
            nxt = f'mw_write_{i+1}' if i + 1 < len(w) else 'mw_return_0'
            for sym in ('0', '1', blank):
                new_transitions[(cur, sym)] = (nxt, ch, 'R')
    return_len = max(len(w), 1)
    for i in range(return_len):
        cur = f'mw_return_{i}'
        nxt = f'mw_return_{i+1}' if i + 1 < return_len else start
        for sym in ('0', '1', blank):
            new_transitions[(cur, sym)] = (nxt, sym, 'L')
    return TMEncoder.encode(TuringMachine(new_transitions, 'mw_seek_0', accept, reject, blank))


def bounded_nonempty_property_checker(m_encoded, max_len=4, max_steps=500):
    """(বাউন্ডেড approximation, সত্যিকারের general decider নয় -- রাইসের থিওরেম অনুযায়ী
    এমন কিছু থাকতেই পারে না) -- max_len পর্যন্ত সব স্ট্রিং খুঁজে দেখে, প্রথম accept পেলেই True।"""
    sim = UniversalSimulator(m_encoded)
    for length in range(max_len + 1):
        for bits in itertools.product('01', repeat=length):
            candidate = ''.join(bits)
            result, _ = sim.run(candidate, max_steps=max_steps)
            if result == 'accept':
                return True
    return False


def reduces_to_halt_via_rice_pattern(m_encoded, w, property_checker):
    """L40-এর build_Mw প্যাটার্নই পুনরায় ব্যবহার -- এবার E_TM-এর বদলে 'L(M)-এ অন্তত
    একটি স্ট্রিং আছে' প্রপার্টির জন্য -- রাইসের থিওরেমের অনেক instance-ই যে একই
    আন্ডারলাইং রিডাকশন টেকনিক শেয়ার করে, তা কংক্রিটভাবে দেখায়।"""
    mw_encoded = build_Mw(m_encoded, w)
    return property_checker(mw_encoded)


# --- ১) রাইসের থিওরেমের দুই শর্ত অনুযায়ী কয়েকটি উদাহরণ প্রপার্টি ক্লাসিফাই করা ---
properties = {
    "L(M) খালি (E_TM)": {
        "is_language_property": True, "is_nontrivial": True,
        "note": "কিছু TM-এর ভাষা খালি, কিছুর নয় -- L40-এ সরাসরি আনডিসাইডেবল প্রমাণিত",
    },
    "L(M)-এ 'ab' স্ট্রিং আছে": {
        "is_language_property": True, "is_nontrivial": True,
        "note": "কিছু TM-এর ভাষায় 'ab' আছে, কিছুর নেই",
    },
    "L(M) = Sigma* (সব স্ট্রিং accept করে)": {
        "is_language_property": True, "is_nontrivial": True,
        "note": "কিছু TM সব স্ট্রিং accept করে, কিছু করে না",
    },
    "L(M) রেগুলার": {
        "is_language_property": True, "is_nontrivial": True,
        "note": "কিছু TM-এর ভাষা রেগুলার (যেমন Sigma*), কিছুর নয় (যেমন 0^n1^n)",
    },
    "M-এর ঠিক ৫টি state আছে": {
        "is_language_property": False, "is_nontrivial": True,
        "note": "L(M)-এর উপর নির্ভর করে না, M-এর নিজস্ব বর্ণনার উপর -- Rice প্রযোজ্য নয়",
    },
    "L(M) একটি ভাষা (সবসময় সত্য)": {
        "is_language_property": True, "is_nontrivial": False,
        "note": "প্রতিটি TM-এর জন্যই vacuously সত্য -- trivial, তাই Rice প্রযোজ্য নয়",
    },
}

print(f"{'প্রপার্টি':34s} | ভাষা-প্রপার্টি | নন-ট্রিভিয়াল | Rice প্রযোজ্য?")
print("-" * 92)
for name, info in properties.items():
    rice_applies = info["is_language_property"] and info["is_nontrivial"]
    verdict = "হ্যাঁ -- আনডিসাইডেবল" if rice_applies else "না"
    print(f"{name:34s} | {str(info['is_language_property']):13s} | {str(info['is_nontrivial']):13s} | {verdict}")
    print(f"    ({info['note']})")

# --- ২) L40-এর একই M_w প্যাটার্ন 'L(M)-এ অন্তত একটি স্ট্রিং আছে' প্রপার্টির জন্য ---
print()
m_encoded = TMEncoder.encode(M)
for w, expected_accepts in [("0011", True), ("01001", False)]:
    direct, _ = M.run(w)
    guessed_nonempty = reduces_to_halt_via_rice_pattern(m_encoded, w, bounded_nonempty_property_checker)
    print(f"M({w!r}) সরাসরি = {direct}; M_w-এর property-checker অনুমান করলো nonempty={guessed_nonempty} "
          f"(প্রত্যাশিত M accepts w = {expected_accepts})")
    assert guessed_nonempty == expected_accepts

print("\nRice reduction pattern -- একই M_w কনস্ট্রাকশন ভিন্ন প্রপার্টির জন্যও সঠিকভাবে কাজ করলো।")

    
লক্ষ্য করুন reduces_to_halt_via_rice_pattern-এর ভেতরের কনস্ট্রাকশন (build_Mw) L40-এর $E_{TM}$-এর প্রমাণে ব্যবহৃত কনস্ট্রাকশনের সাথে হুবহু অভিন্ন — শুধু বাইরের property_checker-টা বদলে গেছে ("খালি?" থেকে "অন্তত একটি স্ট্রিং আছে?")। এটাই রাইসের থিওরেমের গভীর অন্তর্দৃষ্টি — একটাই রিডাকশন প্যাটার্ন, ভিন্ন ভিন্ন নন-ট্রিভিয়াল ভাষা-প্রপার্টির জন্য বারবার প্রযোজ্য।
মূল কথা · Key takeaway

রাইসের থিওরেম M9-এর একটি চূড়ান্ত, শক্তিশালী সারসংক্ষেপ — টুরিং মেশিনের ভাষা সম্পর্কে প্রায় যেকোনো অর্থপূর্ণ প্রশ্নই আনডিসাইডেবল, শুধু সেই প্রশ্নগুলো ছাড়া যেগুলো ভাষা সম্পর্কে নয় (implementation-নির্দিষ্ট) বা তুচ্ছভাবে সবসময়-একই-উত্তর। এই কোর্সের পরবর্তী মডিউল (M10, কমপ্লেক্সিটি থিওরি) এখন একটি ভিন্ন প্রশ্নে মনোযোগ দেবে — যেসব প্রশ্ন ডিসাইডেবল, তাদের মধ্যে কোনগুলো বাস্তবে দ্রুত সমাধানযোগ্য।

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

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

প্র ০১ "$M$-এর ঠিক ৫টি state আছে" — এই প্রশ্নটা কেন রাইসের থিওরেমের আওতায় পড়ে না?

কারণ এটি "ভাষা-প্রপার্টি" নয় — রাইসের থিওরেমের প্রথম পূর্বশর্ত অনুযায়ী, প্রপার্টিটা শুধু $L(M)$-এর উপর নির্ভর করতে হবে, $M$-এর নিজের অভ্যন্তরীণ গঠনের উপর নয়। কিন্তু "state সংখ্যা" পুরোপুরি $M$-এর নির্দিষ্ট বাস্তবায়নের (implementation) উপর নির্ভরশীল — একই ভাষা $L(M)$ recognize করে এমন দুটো TM ভিন্ন সংখ্যক state ব্যবহার করতে পারে (একটি অদক্ষ, একটি অপ্টিমাইজড)। যেহেতু এটি ভাষা-প্রপার্টিই নয়, রাইসের থিওরেম এখানে কিছুই বলে না — এবং বাস্তবে এই প্রশ্নটা সহজেই ডিসাইডেবল, শুধু $M$-এর এনকোডিং পড়ে state গুনলেই চলে।

প্র ০২ "ট্রিভিয়াল" প্রপার্টি বলতে কী বোঝায়? একটি উদাহরণ দিন।

ট্রিভিয়াল মানে প্রপার্টিটা প্রতিটি Turing-recognizable ভাষার জন্য একই উত্তর দেয় — হয় সবসময় সত্য, নয়তো সবসময় মিথ্যা। উদাহরণ — "$L(M)$ কি একটি ভাষা?" (সবসময় সত্য, vacuously — যেকোনো $L(M)$ সংজ্ঞানুসারেই একটি ভাষা) বা "$L(M)$ কি $\Sigma^*$-এর একটি সাবসেট?" (সবসময় সত্য, যেহেতু সব ভাষাই সংজ্ঞানুসারে $\Sigma^*$-এর সাবসেট)। এই ধরনের প্রশ্নের উত্তর $M$ না দেখেই বলে দেওয়া যায় — তাই এগুলো তুচ্ছভাবে ডিসাইডেবল, রাইসের থিওরেমের আওতার বাইরে।

প্র ০৩ কেন অ্যান্টিভাইরাস সফটওয়্যার কখনো ১০০% নির্ভুল হতে পারে না — রাইসের থিওরেমের সাথে যুক্ত করে ব্যাখ্যা করুন।

"এই প্রোগ্রামের আচরণ ম্যালিশিয়াস কি না" — এটি প্রোগ্রামটির আচরণ (তার ভাষা/রান-টাইম কম্পিউটেশন) সম্পর্কে একটি প্রশ্ন, তার সোর্স কোডের নির্দিষ্ট syntax সম্পর্কে নয় — তাই এটি একটি ভাষা-প্রপার্টি। এবং এটি নন-ট্রিভিয়াল, কারণ কিছু প্রোগ্রাম ম্যালিশিয়াস, কিছু নয়। রাইসের থিওরেম অনুযায়ী তাই এই প্রশ্নটা আনডিসাইডেবল — কোনো অ্যালগরিদমই প্রতিটি সম্ভাব্য প্রোগ্রামের জন্য নির্ভুলভাবে এই প্রশ্নের উত্তর দিতে পারে না। এই কারণেই বাস্তব অ্যান্টিভাইরাস সফটওয়্যার হিউরিস্টিক, সিগনেচার-ম্যাচিং, ও আচরণগত বিশ্লেষণ ব্যবহার করে — একটি আংশিক approximation, কখনোই একটি নিখুঁত সাধারণ-উদ্দেশ্যে decision procedure নয়।

অনুশীলন

  1. চিন্তা করুন: "$L(M)$ ফাইনাইট (সসীম)" প্রপার্টিটা কি রাইসের থিওরেমের আওতায় পড়ে? এটা কি ভাষা-প্রপার্টি? এটা কি নন-ট্রিভিয়াল? আপনার যুক্তি দিন।

    হ্যাঁ, এটা রাইসের থিওরেমের আওতায় পড়ে। এটা একটি ভাষা-প্রপার্টি — "$L(M)$ ফাইনাইট কি না" সম্পূর্ণভাবে $L(M)$-এর উপর নির্ভর করে, $M$-এর নির্দিষ্ট বাস্তবায়নের উপর নয়। এটা নন-ট্রিভিয়ালও — কিছু TM-এর ভাষা ফাইনাইট (যেমন একটি TM যা শুধু "01" accept করে), আবার কিছু TM-এর ভাষা ইনফাইনাইট (যেমন $\Sigma^*$ accept করা একটি TM)। দুটো শর্তই পূরণ হওয়ায়, রাইসের থিওরেম অনুযায়ী "$L(M)$ ফাইনাইট কি না" আনডিসাইডেবল।

  2. পরীক্ষা করুন: কোড সেলে properties ডিকশনারিতে আপনার নিজের একটি নতুন প্রপার্টি (যেমন "L(M) শুধু '0' স্ট্রিং accept করে") যোগ করুন, তার is_language_property ও is_nontrivial মান ঠিক করে দিন, এবং Run চেপে দেখুন এটা সঠিকভাবে ক্লাসিফাই হচ্ছে কি না।

    "$L(M)$ শুধু '0' স্ট্রিং accept করে" (অর্থাৎ $L(M) = \{\text{"0"}\}$) একটি ভাষা-প্রপার্টি (is_language_property: True) — এটা সম্পূর্ণভাবে $L(M)$-এর উপর নির্ভর করে। এটা নন-ট্রিভিয়ালও (is_nontrivial: True) — কিছু TM-এর ভাষা ঠিক $\{\text{"0"}\}$, কিছুর নয়। তাই এই প্রপার্টিও রাইসের থিওরেম অনুযায়ী আনডিসাইডেবল হওয়ার কথা।

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

আগের পাঠ
রিডাকশন ও আনডিসাইডেবিলিটি প্রুফ