রাইসের থিওরেম
এই পাঠে যা শিখবেন
- রাইসের থিওরেমের সম্পূর্ণ, নির্ভুল বিবৃতি এবং এর দুটো পূর্বশর্ত (ভাষা-প্রপার্টি, নন-ট্রিভিয়াল) নির্ভুলভাবে
- কেন "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 নন-ট্রিভিয়াল ভাষা-প্রপার্টি।
৩ · বাস্তব-জগতের প্রভাব — কেন অ্যান্টিভাইরাস কখনো নিখুঁত হতে পারে না
এই থিওরেমের একটি সরাসরি, বাস্তব-জগতের প্রভাব আছে — cross-ref ../cybersecurity/। "এই প্রোগ্রামটির
আচরণ কি কোনো ম্যালিশিয়াস প্যাটার্নের সাথে মেলে?" — এটি একটি genuine নন-ট্রিভিয়াল ভাষা-প্রপার্টি (কিছু
প্রোগ্রামের আচরণ মেলে, কিছুর মেলে না, এবং এটা শুধু প্রোগ্রামটার আচরণের উপর নির্ভর করে, তার সোর্স কোডের
নির্দিষ্ট গঠনের উপর নয়) — রাইসের থিওরেম অনুযায়ী এটি আনডিসাইডেবল। এই কারণেই বাস্তব
অ্যান্টিভাইরাস সফটওয়্যার কখনোই একটি নিখুঁত, সাধারণ-উদ্দেশ্যে ডিসিশন প্রসিডিউর ব্যবহার করে না — বরং হিউরিস্টিক
ও আংশিক (incomplete) approximation ব্যবহার করে, ঠিক কারণ কোনো নিখুঁত সমাধান থাকতেই পারে না।
৪ · কোড সেল — প্রপার্টি ক্লাসিফিকেশন ও রিডাকশন প্যাটার্নের পুনর্ব্যবহার
নিচের কোড সেলে প্রথমে কয়েকটি উদাহরণ প্রপার্টি রাইসের থিওরেমের দুটো শর্ত (ভাষা-প্রপার্টি? নন-ট্রিভিয়াল?)
অনুযায়ী ক্লাসিফাই করা হচ্ছে। তারপর L40-এর build_Mw কনস্ট্রাকশনই আবার ব্যবহার করে — এবার
$E_{TM}$-এর বদলে "$L(M)$-এ অন্তত একটি স্ট্রিং আছে" প্রপার্টির জন্য — দেখানো হচ্ছে একই
রিডাকশন টেকনিক ভিন্ন প্রপার্টির জন্যও কাজ করে। (এখানে bounded_nonempty_property_checker একটি
বাউন্ডেড approximation — একটি সসীম দৈর্ঘ্য-সীমা পর্যন্ত স্ট্রিং খুঁজে দেখে, সত্যিকারের কোনো
সাধারণ-উদ্দেশ্যে decider নয়, যা রাইসের থিওরেম অনুযায়ী থাকতেই পারে না — কিন্তু এই ছোট, নির্দিষ্ট টেস্ট
কেসগুলোর জন্য এটি সঠিক উত্তর দেয়, যথেষ্ট প্রমাণ করার জন্য যে রিডাকশন কনস্ট্রাকশনটাই সঠিক)।
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-টা বদলে গেছে ("খালি?" থেকে "অন্তত একটি স্ট্রিং আছে?")। এটাই রাইসের থিওরেমের
গভীর অন্তর্দৃষ্টি — একটাই রিডাকশন প্যাটার্ন, ভিন্ন ভিন্ন নন-ট্রিভিয়াল ভাষা-প্রপার্টির জন্য বারবার প্রযোজ্য।
রাইসের থিওরেম 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 নয়।
অনুশীলন
-
চিন্তা করুন: "$L(M)$ ফাইনাইট (সসীম)" প্রপার্টিটা কি রাইসের থিওরেমের আওতায় পড়ে? এটা কি
ভাষা-প্রপার্টি? এটা কি নন-ট্রিভিয়াল? আপনার যুক্তি দিন।
হ্যাঁ, এটা রাইসের থিওরেমের আওতায় পড়ে। এটা একটি ভাষা-প্রপার্টি — "$L(M)$ ফাইনাইট কি না" সম্পূর্ণভাবে $L(M)$-এর উপর নির্ভর করে, $M$-এর নির্দিষ্ট বাস্তবায়নের উপর নয়। এটা নন-ট্রিভিয়ালও — কিছু TM-এর ভাষা ফাইনাইট (যেমন একটি TM যা শুধু "01" accept করে), আবার কিছু TM-এর ভাষা ইনফাইনাইট (যেমন $\Sigma^*$ accept করা একটি TM)। দুটো শর্তই পূরণ হওয়ায়, রাইসের থিওরেম অনুযায়ী "$L(M)$ ফাইনাইট কি না" আনডিসাইডেবল।
-
পরীক্ষা করুন: কোড সেলে
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-এ আপনার পরবর্তী পদক্ষেপ
- পাঠ ৪২ · পোস্ট করেসপন্ডেন্স প্রবলেম পরের পাঠ M9-এর শেষ পাঠ — একটি ভিন্ন ধরনের, TM-এর বাইরের আনডিসাইডেবল সমস্যা, যেখানে রাইসের থিওরেম সরাসরি প্রযোজ্য নয়।
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৬টি পাঠ DFA থেকে টুরিং মেশিন, ডিসাইডেবিলিটি ও P বনাম NP পর্যন্ত — সম্পূর্ণ পাঠক্রম।
- Cybersecurity কোর্স বাস্তব প্রয়োগ অ্যান্টিভাইরাস ও ম্যালওয়্যার শনাক্তকরণের বাস্তব কৌশল — কেন হিউরিস্টিক লাগে, তার তাত্ত্বিক ভিত্তি এই পাঠে।
- পাঠ ৪০ · রিডাকশন ও আনডিসাইডেবিলিটি প্রুফ আগের পাঠ এই পাঠের build_Mw কনস্ট্রাকশনের মূল উৎস — $E_{TM}$-এর সম্পূর্ণ ওয়ার্কড উদাহরণ।