সরাসরি পর্বে যান
পর্ব ৭৫ · ৮৩-এর মধ্যে · মডিউল ১৩

Turing machine-এর পরিচয় — computability আর halting problem

Introduction to Turing Machines — Computability, Decidability and the Halting Problem

Taught in Bangla, this lesson defines a Turing machine by tape, head, states and transition table, and traces machines for binary increment, unary addition and aⁿbⁿcⁿ with correctness arguments. It explains the Church–Turing thesis and the universal machine, separates decidable from recognizable languages, proves the halting problem undecidable by diagonalisation, and introduces reductions and Rice's theorem. In-page Python simulates the machines and finds the busy beaver value S(2) = 6 by brute force.

এই পর্বে যা শিখবেন

  • Turing machine-এর ৭-tuple সংজ্ঞা, configuration, গ্রহণ, বর্জন আর চিরকাল চলা
  • Binary increment, unary যোগ আর aⁿbⁿcⁿ-এর যন্ত্র নকশা, হাতে trace আর সঠিকতার প্রমাণ
  • Church–Turing thesis, multi-tape ও nondeterministic যন্ত্র, আর universal machine-এর ধারণা
  • Decidable আর recognizable language-এর পার্থক্য, গণনার যুক্তি, আর halting problem-এর পূর্ণ প্রমাণ
  • Reduction, Rice-এর উপপাদ্য, সফটওয়্যারের সীমা, busy beaver আর P, NP-এর প্রথম পরিচয়

১ · ফিতা, মাথা আর নিয়মের টেবিল — Turing machine কী

বাজারঘরের গুদামে একজন হিসাবরক্ষকের সামনে খুব লম্বা একটি খাতা, ঘরে ঘরে ভাগ করা, প্রতিটি ঘরে একটি চিহ্ন। তিনি একবারে একটি ঘরই দেখেন, মাথায় রাখেন খুব অল্প কিছু (“এখন হাতে এক আছে”), আর দেয়ালে টাঙানো একটি নিয়মের তালিকা মানেন: “এই অবস্থায় এই চিহ্ন দেখলে এটা লিখুন, এক ঘর ডানে বা বাঁয়ে যান, এই অবস্থায় চলে যান।” Alan Turing ১৯৩৬ সালে ঠিক এমন একজন হিসাবরক্ষকের ছবি থেকে তাঁর যন্ত্রের কথা ভেবেছিলেন।

পর্ব ৭৩ “Grammar আর formal language — BNF থেকে Chomsky-র শ্রেণি”-তে language মানে Σ*-এর একটি subset, আর পর্ব ৭৪ “Finite automaton আর regular expression-এর পরিচয়”-তে সসীম স্মৃতির যন্ত্র। এখানে স্মৃতিকে অসীম করে জিজ্ঞেস করি: তাহলেও কি কিছু অসম্ভব থাকে? পুরো তত্ত্ব থাকবে পরিকল্পিত Theory of Computation কোর্সে; এখানে discrete math-এর দৃষ্টিতে সংজ্ঞা, ছোট উপপাদ্য আর প্রমাণ।

সংজ্ঞা ১.১ (Turing machine)

একটি Turing machine হলো M = (Q, Σ, Γ, δ, q0, qacc, qrej), যেখানে Q অবস্থার একটি সসীম সেট; Σ ইনপুটের alphabet; Γ ফিতার alphabet, যাতে Σ ⊆ Γ আর একটি বিশেষ ফাঁকা চিহ্ন _ ∈ Γ ∖ Σ; δ : (Q ∖ {qacc, qrej}) × Γ → Q × Γ × {L, R} হলো নিয়মের টেবিল (transition function); q0 শুরুর অবস্থা; qacc গ্রহণের আর qrej বর্জনের অবস্থা, qacc ≠ qrej.

δ(q, a) = (p, b, R) পড়ুন এভাবে: “অবস্থা q-তে মাথার নিচে a থাকলে সেখানে b লিখুন, মাথা এক ঘর ডানে নিন, অবস্থা p-তে যান।” ফিতা দুই দিকেই অসীম (শুধু ডানে অসীম ফিতার সংস্করণও ক্ষমতায় সমান, §৪), শুরুতে ইনপুট w লেখা, বাকি সব ঘর ফাঁকা, মাথা প্রথম চিহ্নে। সুবিধার জন্য আমরা একটি প্রথা নেব: কোনো (q, a)-এর নিয়ম লেখা না থাকলে যন্ত্র সরাসরি qrej-এ যায়।

সংজ্ঞা ১.২ (configuration, গ্রহণ আর language)

যন্ত্রের একটি মুহূর্তের পুরো ছবি হলো configuration: u [q] v লিখলে বোঝায় ফিতায় uv লেখা (তারপর শুধু ফাঁকা), অবস্থা q, আর মাথা v-এর প্রথম চিহ্নে। একটি নিয়ম প্রয়োগে এক configuration থেকে পরেরটি আসে (এক ধাপ)। শুরুর configuration [q0] w. M ইনপুট w গ্রহণ করে, যদি ধাপের ক্রম একসময় qacc-এ পৌঁছায়; বর্জন করে, যদি qrej-এ পৌঁছায়। দুটির কোনোটিতেই না পৌঁছালে M চিরকাল চলে (loop). M-এর language L(M) = {w ∈ Σ* : M, w গ্রহণ করে}.

ফলাফল তিন রকম: গ্রহণ, বর্জন, অথবা কখনো না থামা। Finite automaton ইনপুট ফুরালেই থামে; Turing machine ফিরে আসতে আর লিখতে পারে, তাই চিরকাল ঘুরতেও পারে। এই তৃতীয় সম্ভাবনাই পরের সব কঠিন প্রশ্নের উৎস। নিচের ছবিতে §২-এর binary increment যন্ত্রটি চলার মাঝপথে।

Turing machine-এর অংশ আর একটি নিয়মের টেবিল

ওপরে ফিতা: configuration 10 [q1] 10, অর্থাৎ মাথা তৃতীয় ঘরে, অবস্থা q1 (হাতে এক)। নিচে একই যন্ত্রের অবস্থা-চিত্র: তীরের লেখা “পড়া → লেখা, সরা”।

Turing machine tape, head, control and the state diagram of the binary increment machine _1010_… অবস্থা: q1 q0q1acc 0→0,R1→1,R 1→0,L _→_,L 0→1,L_→1,L

২ · প্রথম যন্ত্র — binary increment আর unary যোগ

বাজারঘরের অর্ডার নম্বর binary-তে রাখা হয়; নতুন অর্ডার এলে নম্বরে এক যোগ করতে হয়। হাতে আমরা যা করি: ডান দিক থেকে শুরু, 1 পেলে 0 লিখে হাতে এক রেখে বাঁয়ে যাই, 0 পেলে 1 লিখে থামি। যন্ত্রকে প্রথমে ডান প্রান্তে পৌঁছাতে হয়, কারণ সে শুরু করে বাঁ প্রান্ত থেকে। পুরো নিয়মের টেবিল:

অবস্থাপড়েলেখেসরেপরের অবস্থামানে
q00 বা 1একইRq0ডান প্রান্তে যাওয়া
q0__Lq1শেষ অঙ্কে ফেরা
q110Lq1হাতে এক থাকল
q10 বা _1Laccহাতের এক বসল
1start: [q0] 10112q0: 0→0,R  1→1,R3q0: _→_,L  goto q14q1: 1→0,L  (carry)5q1: 0→1,L  goto acc
যন্ত্রের অবস্থা
configuration
অবস্থা
মোট ধাপ
  1. শুরু। ফিতায় 1011 (দশমিকে 11), মাথা প্রথম ঘরে, অবস্থা q0. এখনো কোনো ধাপ হয়নি।
  2. ডানে যাত্রা। q0 প্রতিটি 0 বা 1 অপরিবর্তিত রেখে ডানে সরে। চারটি ধাপের পর মাথা ইনপুটের পরের ফাঁকা ঘরে: 1011 [q0] _.
  3. ফেরা। ফাঁকা দেখে q0 বোঝে সংখ্যা শেষ; এক ঘর বাঁয়ে সরে q1-এ যায়। q1 মানে “হাতে এক আছে”। মোট ৫টি ধাপ।
  4. প্রথম carry. শেষ অঙ্ক 1: 1 + 1 = 10, তাই 0 লেখে আর হাতে এক নিয়ে বাঁয়ে যায়। configuration 10 [q1] 10.
  5. দ্বিতীয় carry. আবার 1, আবার 0 লেখা: 1 [q1] 000. ডানের দুটি অঙ্ক এখন 00.
  6. Carry বসল। 0 পেয়ে 1 লেখে, qacc-এ যায়। ফিতায় 1100 = 12 = 11 + 1. মোট ধাপ 8.

দৈর্ঘ্য n আর শেষে পরপর k-টি 1 থাকলে যন্ত্র n ধাপে ডানে যায়, ১ ধাপে ফেরে, k ধাপে carry টানে, ১ ধাপে শেষ 1 বসায়: মোট n + k + 2; 1011-এ 4 + 2 + 2 = 8. (দৈর্ঘ্য ১ থেকে ৮-এর সব ইনপুটে scratch script-এ সূত্রটি মেলানো।)

উপপাদ্য ২.১ (increment যন্ত্র সঠিক)

যেকোনো অশূন্য binary string w-এ যন্ত্রটি থামে, গ্রহণ করে, আর ফিতায় val(w) + 1-এর binary রূপ রেখে যায়; w-এর সব অঙ্ক 1 না হলে দৈর্ঘ্য বদলায় না, তাই শুরুর বাড়তি 0 থাকতে পারে, যেমন 0011 থেকে হয় 0100.

  1. q0-এর অংশ শুধু ডানে সরে, কিছু বদলায় না, আর n ধাপ পর ফাঁকা ঘর পায়; তখন মাথা শেষ অঙ্কে আর অবস্থা q1. — নিয়মের টেবিল
  2. Loop invariant (পর্ব ১৩): মাথা যে ঘরে, তার স্থানীয় মান 2j হলে (ডানের j-টি অঙ্ক প্রক্রিয়া হয়েছে), “ফিতার সংখ্যা + 2j = val(w) + 1”. শুরুতে j = 0, ফিতায় w, তাই val(w) + 1 = val(w) + 1. — ভিত্তি
  3. q1-এ 1 পড়লে 0 লেখা হয়: ফিতার সংখ্যা 2j কমে, আর j এক বাড়ে, তাই নতুন যোগফল (আগের − 2j) + 2j+1 = আগের + 2j, invariant টিকে থাকে। — সংরক্ষণ
  4. q1-এ 0 বা ফাঁকা পড়লে 1 লেখা হয়: ফিতার সংখ্যা 2j বাড়ে, আর invariant থেকে তা ঠিক val(w) + 1; যন্ত্র গ্রহণ করে। — শেষ অবস্থা
  5. q1-এর প্রতিটি ধাপে মাথা বাঁয়ে সরে, আর w-এর বাঁয়ে ফাঁকা ঘর আছে (ফিতা দুই দিকে অসীম), তাই বড়জোর n + 1 ধাপে 0 বা ফাঁকা মিলবেই। যন্ত্র থামে। ∎ — সীমিত ঘর

দ্বিতীয় যন্ত্রটি আরও সরল। Unary লেখায় m সংখ্যাটি m-টি 1: 3 = 111. ইনপুট 1m+1n থেকে 1m+n বানাতে + চিহ্নকে 1 করে দিন, তারপর ডান প্রান্তে গিয়ে শেষ 1টি মুছে দিন। এর জন্য পাঁচটি নিয়মই যথেষ্ট (নিচের কোডে ADD নামের টেবিল)।

নিচের ব্লক একটি ছোট simulator লেখে, যা প্রতিটি configuration ছাপে, তারপর দুই যন্ত্রকে সব ছোট ইনপুটে মেলায়। পরের ব্লক এই simulator-ই আবার ব্যবহার করে, তাই আগে এটি চালান। প্রথমবার চালালে ব্রাউজারে Python (Pyodide) নামতে কয়েক সেকেন্ড লাগে।

from itertools import product
def show(tape, pos, q):                   # configuration u[q]v
    lo, hi = min(min(tape), pos), max(max(tape), pos)
    cells = "".join(tape.get(i, "_") for i in range(lo, hi + 1))
    return cells[:pos - lo] + "[" + q + "]" + cells[pos - lo:]
def run(delta, w, cap=10_000, trace=False):
    tape, pos, q, steps = dict(enumerate(w or "_")), 0, "q0", 0
    while q not in ("acc", "rej") and steps < cap:
        if trace: print("  ", show(tape, pos, q))
        key = (q, tape.get(pos, "_"))
        if key not in delta:              # no rule: the machine rejects
            q = "rej"; break
        q, tape[pos], move = delta[key]
        pos += 1 if move == "R" else -1
        steps += 1
    if trace: print("  ", show(tape, pos, q))
    return q, "".join(tape[i] for i in sorted(tape)).strip("_"), steps
INC = {("q0", "0"): ("q0", "0", "R"), ("q0", "1"): ("q0", "1", "R"),
       ("q0", "_"): ("q1", "_", "L"), ("q1", "1"): ("q1", "0", "L"),
       ("q1", "0"): ("acc", "1", "L"), ("q1", "_"): ("acc", "1", "L")}
ADD = {("q0", "1"): ("q0", "1", "R"), ("q0", "+"): ("q1", "1", "R"),
       ("q1", "1"): ("q1", "1", "R"), ("q1", "_"): ("q2", "_", "L"),
       ("q2", "1"): ("acc", "_", "L")}
print("binary increment on 1011:")
print(run(INC, "1011", trace=True))
print("unary 3 + 2 on 111+11:")
print(run(ADD, "111+11", trace=True))
inputs = ["".join(b) for n in range(1, 11) for b in product("01", repeat=n)]
ok_inc = all(int(run(INC, w)[1], 2) == int(w, 2) + 1 for w in inputs)
ok_add = all(run(ADD, "1" * m + "+" + "1" * n)[1] == "1" * (m + n)
             for m in range(10) for n in range(10))
print("increment correct on all", len(inputs), "inputs of length 1..10:", ok_inc)
print("addition correct for all 100 pairs m, n < 10:", ok_add)

আসল আউটপুট (ব্রাউজারের Python):

binary increment on 1011:
   [q0]1011
   1[q0]011
   10[q0]11
   101[q0]1
   1011[q0]_
   101[q1]1_
   10[q1]10_
   1[q1]000_
   [acc]1100_
('acc', '1100', 8)
unary 3 + 2 on 111+11:
   [q0]111+11
   1[q0]11+11
   11[q0]1+11
   111[q0]+11
   1111[q1]11
   11111[q1]1
   111111[q1]_
   11111[q2]1_
   1111[acc]1__
('acc', '11111', 8)
increment correct on all 2046 inputs of length 1..10: True
addition correct for all 100 pairs m, n < 10: True

প্রতিটি লাইন একটি configuration: বন্ধনীর ভেতরে অবস্থা, আর তার ঠিক ডানের চিহ্নটির ওপর মাথা। increment-এর trace stepper-এর সঙ্গে হুবহু মেলে, আর ফলাফল ('acc', '1100', 8) মানে গ্রহণ, ফিতায় 1100, ৮টি ধাপ। unary যোগে 111+11 থেকে 11111 (3 + 2 = 5), এটিও ৮ ধাপে। তারপর পূর্ণ যাচাই: দৈর্ঘ্য ১ থেকে ১০-এর সব 2046টি binary ইনপুটে ফলাফলের মান ঠিক এক বেশি, আর m, n < 10-এর সব ১০০টি যোগ ঠিক। এটি প্রমাণের বদলি নয়, কিন্তু টেবিলের ভুল নিয়ম প্রায় নিশ্চিতভাবে ধরত।

৩ · aⁿbⁿcⁿ — আঁকাবাঁকা পথে দাগ দেওয়ার যন্ত্র

পর্ব ৭৩-এ বলা হয়েছে, L = {anbncn : n ≥ 0} context-free নয়, আর পর্ব ৭৪-এর pumping lemma দেখায় anbn-ও regular নয়। অর্থাৎ সসীম স্মৃতির যন্ত্র বা একটি stack-এর যন্ত্র এই ভাষা চিনতে পারে না। Turing machine পারে, কারণ সে ফিতায় দাগ দিয়ে “কাটা” রাখতে পারে। বাজারঘরের ভাষায়: সমান সংখ্যক বাক্স (a), রসিদ (b) আর ডেলিভারি স্লিপ (c) আছে কি না, প্রতিটি থেকে একটি করে টিক দিয়ে মেলানো।

কৌশল: প্রথম না-কাটা a-কে X করুন, ডানে গিয়ে প্রথম না-কাটা b-কে Y, আরও ডানে প্রথম না-কাটা c-কে Z, তারপর বাঁয়ে X পর্যন্ত ফিরে আসুন। আবার শুরু। যখন X-এর পরে আর a নেই, শুধু Y আর Z আছে কি না দেখে নিন।

অবস্থাকাজনিয়ম (পড়া → লেখা, সরা, পরের অবস্থা)
q0নতুন দফাa → X, R, q1; Y → Y, R, q4; _ → গ্রহণ
q1b খোঁজাa, Y পেরিয়ে ডানে; b → Y, R, q2
q2c খোঁজাb, Z পেরিয়ে ডানে; c → Z, L, q3
q3ফেরাa, b, Y, Z পেরিয়ে বাঁয়ে; X → X, R, q0
q4শেষ পরীক্ষাY, Z পেরিয়ে ডানে; _ → গ্রহণ

অন্য যেকোনো (অবস্থা, চিহ্ন)-এ নিয়ম নেই, তাই বর্জন। যেমন q1 b খুঁজতে গিয়ে c বা ফাঁকা পেলে, বা q4 কোনো a, b, c পেলে।

1q0: a→X,R  goto q12q1: skip a,Y; b→Y,R3q2: skip b,Z; c→Z,L4q3: back to X; X→q05q0: Y→Y,R  goto q46q4: skip Y,Z; _→acc
যন্ত্রের অবস্থা
configuration
কাটা জোড়া
মোট ধাপ
  1. শুরু। ফিতায় aabbcc, অবস্থা q0, মাথা প্রথম a-তে।
  2. a কাটা। q0 প্রথম a-কে X করে ডানে যায়, অবস্থা q1. এক ধাপ।
  3. b কাটা। q1 দ্বিতীয় a পেরিয়ে প্রথম b-কে Y করে, অবস্থা q2. মোট ৩ ধাপ।
  4. c কাটা। q2 দ্বিতীয় b পেরিয়ে প্রথম c-কে Z করে বাঁয়ে ফেরে, অবস্থা q3. মোট ৫ ধাপ।
  5. ফেরা। q3 b, Y, a পেরিয়ে X পর্যন্ত যায়, তারপর এক ঘর ডানে q0. প্রথম দফা শেষ, মোট ৯ ধাপ।
  6. দ্বিতীয় দফা। একই কাজে দ্বিতীয় a, b, c কাটা হয়: XXYYZZ, আর মাথা আবার X-এর ডানে। মোট ১৮ ধাপ।
  7. a ফুরাল। q0 এবার a নয়, Y দেখে; মানে সব a কাটা। q4-এ যায়, যার কাজ শুধু Y আর Z পেরোনো। মোট ১৯ ধাপ।
  8. গ্রহণ। q4 Y, Z পেরিয়ে ফাঁকা পায় আর গ্রহণ করে। মোট ২৩ ধাপ; আবার কোনো a, b বা c থাকলে q4 বর্জন করত।
উপপাদ্য ৩.১ (দাগ দেওয়ার যন্ত্র সঠিক)

যন্ত্রটি প্রতিটি w ∈ {a, b, c}*-এ থামে, আর গ্রহণ করে ঠিক তখন, যখন w = anbncn কোনো n ≥ 0-এর জন্য।

  1. (থামা) প্রতিটি পূর্ণ দফা তিনটি না-কাটা চিহ্ন কমায়, আর দফার ভেতরে মাথা ইনপুট-অংশের বাইরে এক ঘরের বেশি যায় না; q4 শুধু ডানে যায়। তাই সসীম ধাপে থামে। — কমতে থাকা পরিমাণ (পর্ব ১৩-এর variant)
  2. (গ্রহণ ⇒ L-এ আছে) দফা i শুরুর আগে invariant: ফিতা Xi ap Yi bq Zi cr আকারের, যেখানে ai+pbi+qci+r = w. ভিত্তি i = 0-এ ফিতা w-ই, যদি w-এ a, b, c ক্রম মেনে আসে; ক্রম ভাঙলে কোনো এক দফায় q1 বা q2 অপ্রত্যাশিত চিহ্নে আটকে বর্জন করে। — invariant
  3. q0 গ্রহণ করে শুধু দুইভাবে: ফাঁকা দেখে (w = ε, n = 0), অথবা Y দেখে q4-এ গিয়ে শেষে ফাঁকা পেয়ে। দ্বিতীয় ক্ষেত্রে p = 0, আর q4 কোনো b বা c পায়নি, তাই q = r = 0; ফলে w = aibici. — শেষ অবস্থার বিশ্লেষণ
  4. (L-এ আছে ⇒ গ্রহণ) w = anbncn হলে প্রতিটি দফায় একটি করে a, b, c পাওয়া যায়, n দফা পর ফিতা XnYnZn, আর q0 → q4 → গ্রহণ। ∎ — n-এর ওপর induction

যে যন্ত্র প্রতিটি ইনপুটে থামে, সে decider; উপপাদ্য ৩.১ অনুযায়ী L একটি decidable language. ধাপ কয়টি? প্রতিটি দফায় মাথা বড়জোর পুরো ইনপুটের ওপর একবার যায় আর ফেরে, আর দফা n-টি, তাই ধাপের সংখ্যা O(n2). নিচের ব্লক যাচাই করে, আর দেখায় যে মাপা সংখ্যাগুলো ঠিক 4n2 + 3n + 1 সূত্রে বসে।

ABC = {("q0", "_"): ("acc", "_", "R"), ("q0", "a"): ("q1", "X", "R"),
       ("q0", "Y"): ("q4", "Y", "R"),
       ("q1", "a"): ("q1", "a", "R"), ("q1", "Y"): ("q1", "Y", "R"),
       ("q1", "b"): ("q2", "Y", "R"),
       ("q2", "b"): ("q2", "b", "R"), ("q2", "Z"): ("q2", "Z", "R"),
       ("q2", "c"): ("q3", "Z", "L"),
       ("q3", "X"): ("q0", "X", "R"),
       ("q4", "Y"): ("q4", "Y", "R"), ("q4", "Z"): ("q4", "Z", "R"),
       ("q4", "_"): ("acc", "_", "R")}
for s in "abYZ":                          # q3 walks left over these
    ABC[("q3", s)] = ("q3", s, "L")
def in_lang(w):                           # the set-theoretic definition
    k = len(w) // 3
    return w == "a" * k + "b" * k + "c" * k
total = wrong = accepted = 0
for n in range(9):
    for t in product("abc", repeat=n):
        w = "".join(t); total += 1
        verdict = run(ABC, w)[0] == "acc"
        accepted += verdict
        wrong += verdict != in_lang(w)
print("strings of length 0..8:", total, " accepted:", accepted, " disagreements:", wrong)
for w in ["aabbcc", "aabbc", "abcabc", "acb"]:
    print(f"{w:7}", run(ABC, w))
print("steps on a^n b^n c^n, n = 0..6:",
      [run(ABC, "a" * n + "b" * n + "c" * n)[2] for n in range(7)])

আসল আউটপুট (ব্রাউজারের Python; আগের ব্লকের simulator ব্যবহার করে):

strings of length 0..8: 9841  accepted: 3  disagreements: 0
aabbcc  ('acc', 'XXYYZZ', 23)
aabbc   ('rej', 'XXYYZ', 13)
abcabc  ('rej', 'XYZabc', 7)
acb     ('rej', 'Xcb', 1)
steps on a^n b^n c^n, n = 0..6: [1, 8, 23, 46, 77, 116, 163]

দৈর্ঘ্য ০ থেকে ৮-এর সব 1 + 3 + 9 + ⋯ + 6561 = 9841টি string-এ যন্ত্রের রায় আর সেটের সংজ্ঞা (in_lang) একটিতেও আলাদা নয়। গ্রহণ মাত্র ৩টি: ε, abc আর aabbcc, কারণ দৈর্ঘ্য ৮-এর মধ্যে আর কোনো সদস্য নেই। aabbc-তে দ্বিতীয় দফায় c নেই; abcabc-তে q4 একটি a পায়; acb-তে q1 প্রথমেই c পায়। শেষ লাইনের 1, 8, 23, 46, 77, 116, 163-এর পরপর পার্থক্য 7, 15, 23, 31, 39, 47, প্রতিবার 8 করে বাড়ে, তাই দ্বিঘাত বহুপদী: 4n2 + 3n + 1 (n = 2-এ 16 + 6 + 1 = 23). এটি মাপা মান থেকে পাওয়া সূত্র; প্রমাণিত শুধু O(n2) সীমা।

৪ · Church–Turing thesis, অন্য রকম যন্ত্র আর universal machine

এত সরল যন্ত্র দিয়ে কি সব গণনা হয়? উত্তরটি একটি বিশ্বাস, যার পক্ষে প্রচুর প্রমাণ জমেছে।

Church–Turing thesis

যেকোনো ফাংশন, যা একটি স্পষ্ট, যান্ত্রিক, সসীম নিয়মের পদ্ধতিতে (অ্যালগরিদমে) গোনা যায়, তা একটি Turing machine দিয়েও গোনা যায়।

Church–Turing thesis উপপাদ্য নয়, কারণ “স্পষ্ট যান্ত্রিক পদ্ধতি” একটি অনানুষ্ঠানিক ধারণা; গাণিতিক সংজ্ঞা ছাড়া কোনো কিছুর প্রমাণ হয় না। এর পক্ষে প্রমাণ হলো মিল: ১৯৩৬ সালে Alonzo Church-এর λ-calculus, প্রায় একই সময়ে Turing-এর যন্ত্র, Gödel ও Kleene-এর recursive function, Emil Post-এর পদ্ধতি, সবগুলো ঠিক একই ফাংশন গুনতে পারে বলে প্রমাণিত হয়েছে। আজকের ভাষায়: যেকোনো সাধারণ প্রোগ্রামিং ভাষা (অসীম মেমরি ধরে নিলে) Turing machine-এর সমান ক্ষমতার, যাকে বলে Turing-complete.

ক্ষমতায় সমান রূপভেদ

উপপাদ্য ৪.১ (রূপভেদ, এখানে প্রমাণের ধারণা মাত্র)

(ক) k-টি ফিতা আর k-টি মাথার multi-tape Turing machine t ধাপে যা করে, একটি সাধারণ এক-ফিতার যন্ত্র তা O(t2) ধাপে করতে পারে। (খ) একটি nondeterministic Turing machine (যার এক অবস্থা-চিহ্নে একাধিক নিয়ম থাকতে পারে, আর কোনো এক পথ গ্রহণে পৌঁছালেই গ্রহণ) যে language চেনে, একটি deterministic যন্ত্রও তা চেনে, তবে সময় সূচকীয় হারে বাড়তে পারে। (গ) এক দিকে অসীম ফিতা, বড় ফিতা-alphabet বা “না নড়া” চাল যোগ করলেও ক্ষমতা বদলায় না।

(ক)-এর ধারণা: k-টি ফিতাকে এক ফিতায় k-টি “ট্র্যাক” হিসেবে লিখুন, মাথাগুলো দাগ দিয়ে চিহ্নিত; এক ধাপ নকল করতে O(t) দৈর্ঘ্যের ব্যবহৃত অংশ একবার পড়ুন, মোট O(t2). (খ)-এর ধারণা: সব সম্ভাব্য পথ একটি গাছ, যাকে deterministic যন্ত্র স্তরে স্তরে (BFS) ঘোরে, যাতে অসীম শাখায় আটকে না যায়; শাখা গুণে বাড়ে, তাই সূচকীয় সময়। এই সূচকীয় ব্যবধান মুছে ফেলা যায় কি না, সেটাই §৮-এর P বনাম NP প্রশ্নের এক রূপ।

যন্ত্রও একটি string — universal machine

একটি যন্ত্রের নিয়মের টেবিল সসীম, তাই তাকে একটি string হিসেবে লেখা যায়; লেখা হয় ⟨M⟩. একটি সহজ পদ্ধতি: অবস্থা qi-কে 0i, চিহ্ন নম্বর j-কে 0j, L-কে 0, R-কে 00 লিখুন, আর প্রতিটি নিয়ম δ(qi, sj) = (qk, sl, D)-কে 0i1 0j1 0k1 0l1 0d লিখে নিয়মগুলো 11 দিয়ে জুড়ুন। ফলে প্রতিটি যন্ত্র {0, 1}*-এর একটি সদস্য। যন্ত্র আর তার ইনপুট একসঙ্গে লিখলে ⟨M, w⟩.

উপপাদ্য ৪.২ (Turing, ১৯৩৬)

এমন একটি universal Turing machine U আছে, যা ইনপুট ⟨M, w⟩ পেলে M-কে w-এর ওপর নকল করে: M গ্রহণ করলে U গ্রহণ করে, M বর্জন করলে U বর্জন করে, M চিরকাল চললে U-ও চিরকাল চলে।

প্রমাণের ধারণা: U একটি ফিতায় ⟨M⟩, আরেকটিতে M-এর ফিতার নকল, তৃতীয়টিতে M-এর বর্তমান অবস্থা রাখে; প্রতি ধাপে টেবিলে মিলে যাওয়া নিয়মটি খুঁজে প্রয়োগ করে (উপপাদ্য ৪.১-ক দিয়ে এক ফিতায় নামানো যায়)। ওপরের Python-এর run ফাংশনও তা-ই করে। “প্রোগ্রামও ডেটা”, এই ধারণা interpreter আর stored-program কম্পিউটারের তাত্ত্বিক ভিত্তি।

৫ · Decidable আর recognizable — আর কেন বেশিরভাগ ভাষার কোনো যন্ত্র নেই

সংজ্ঞা ৫.১

একটি language L ⊆ Σ* recognizable (Turing-recognizable; অন্য নাম semi-decidable বা recursively enumerable), যদি এমন যন্ত্র M থাকে যাতে L(M) = L: L-এর সদস্যে M একসময় গ্রহণ করে, আর বাকিদের ক্ষেত্রে বর্জন করে বা চিরকাল চলে. L decidable, যদি এমন M থাকে যা প্রতিটি ইনপুটে থামে আর L(M) = L.

পার্থক্যটি দোকানের দুই ধরনের কর্মীর মতো। Decidable-এর কর্মী প্রতিটি প্রশ্নে একসময় “হ্যাঁ” বা “না” বলেন। Recognizable-এর কর্মী “হ্যাঁ” হলে একসময় বলবেন, কিন্তু “না” হলে হয়তো চিরকাল খুঁজতেই থাকবেন, আর আপনি কখনো নিশ্চিত হবেন না যে তিনি আর একটু পরে “হ্যাঁ” বলবেন না। প্রতিটি decidable language recognizable; উল্টোটি নয় (§৬)।

উপপাদ্য ৫.২ (গণনার যুক্তি)

যেকোনো alphabet Σ-এর ওপর এমন language আছে, যা recognizable নয়।

  1. প্রতিটি যন্ত্র M-এর একটি সসীম বিবরণ ⟨M⟩ ∈ {0, 1}* (§৪)। আলাদা language-এর যন্ত্র আলাদা, তাই recognizable language-এর সেট থেকে {0, 1}*-এ একটি one-to-one ফাংশন আছে (প্রতিটি language-এর জন্য একটি যন্ত্রের বিবরণ বেছে নিন)। — encoding
  2. {0, 1}* countable: দৈর্ঘ্য অনুযায়ী, তারপর অভিধানের ক্রমে সাজালে প্রতিটি string একটি স্বাভাবিক সংখ্যা পায় (পর্ব ১৮; পর্ব ৭৩-এ Σ*-এর জন্য একই যুক্তি)। তাই recognizable language countable-অনেক। — countable-এর subset
  3. সব language-এর সেট হলো P(Σ*), Σ*-এর power set. Σ* countably infinite, তাই Cantor-এর উপপাদ্যে P(Σ*) uncountable. — পর্ব ১৮-এর উপপাদ্য ৬.১
  4. একটি uncountable সেট তার countable subset-এর সমান হতে পারে না, তাই কিছু language recognizable নয়। ∎

পর্ব ১৮-এর §৮-এ এই যুক্তি “প্রোগ্রাম” দিয়ে বলা হয়েছিল। এটি শুধু অস্তিত্ব দেখায়। নির্দিষ্ট উদাহরণ পেতে সরাসরি Cantor-এর diagonal লাগে। নিচের ব্লক একটি সসীম টেবিলে কৌশলটি দেখায়: সারি i একটি language Li, কলাম j একটি string sj, আর ঘরে 1 মানে sj ∈ Li. কর্ণ উল্টে বানানো D প্রতিটি সারি থেকে অন্তত এক ঘরে আলাদা।

strings = ["", "0", "1", "00", "01", "10"]       # s0..s5 in shortlex order
languages = [                                   # L0..L5, each with a decider
    ("even length",   lambda s: len(s) % 2 == 0),
    ("starts with 1", lambda s: s[:1] == "1"),
    ("contains 0",    lambda s: "0" in s),
    ("palindrome",    lambda s: s == s[::-1]),
    ("all strings",   lambda s: True),
    ("empty set",     lambda s: False)]
n = len(strings)
table = [[int(f(s)) for s in strings] for _, f in languages]
print("column j: is s_j in L_i ?  (1 = yes)")
print(" " * 18 + "".join(f"{s or 'e':>4}" for s in strings))
for i, (name, _) in enumerate(languages):
    print(f"L{i} {name:<15}" + "".join(f"{b:>4}" for b in table[i]))
D = [1 - table[j][j] for j in range(n)]          # flip the diagonal
print(f"{'D = flipped diag':<18}" + "".join(f"{b:>4}" for b in D))
for i in range(n):
    print(f"D vs L{i}: column {i} has {table[i][i]} in L{i} but {D[i]} in D",
          "-> different" if D[i] != table[i][i] else "-> same?!")
print("D equals some row:", any(D == row for row in table))

আসল আউটপুট (ব্রাউজারের Python; e মানে খালি string ε):

column j: is s_j in L_i ?  (1 = yes)
                     e   0   1  00  01  10
L0 even length       1   0   0   1   1   1
L1 starts with 1     0   0   1   0   0   1
L2 contains 0        0   1   0   1   1   1
L3 palindrome        1   1   1   1   0   0
L4 all strings       1   1   1   1   1   1
L5 empty set         0   0   0   0   0   0
D = flipped diag     0   1   1   0   0   1
D vs L0: column 0 has 1 in L0 but 0 in D -> different
D vs L1: column 1 has 0 in L1 but 1 in D -> different
D vs L2: column 2 has 0 in L2 but 1 in D -> different
D vs L3: column 3 has 1 in L3 but 0 in D -> different
D vs L4: column 4 has 1 in L4 but 0 in D -> different
D vs L5: column 5 has 0 in L5 but 1 in D -> different
D equals some row: False

কর্ণের ঘরগুলো (L0-এর e, L1-এর 0, L2-এর 1, …) হলো 1, 0, 0, 1, 1, 0; উল্টে D = 0, 1, 1, 0, 0, 1. D সারি i থেকে ঠিক কলাম i-তে আলাদা, তাই টেবিলের কোনো সারি নয়। এটি সচিত্র উদাহরণ মাত্র। সারিগুলো সব যন্ত্রের পূর্ণ তালিকা আর কলামগুলো সব string হলে D = {si : si ∉ L(Mi)} কোনো যন্ত্রের language নয়। একই কাঠামোয় “ঘরে 1 মানে প্রোগ্রাম i ইনপুট j-তে থামে” বসালেই §৬-এর halting প্রমাণ।

উপপাদ্য ৫.৩

L decidable ⇔ L আর তার complement L̄ = Σ* ∖ L দুটিই recognizable.

  1. (⇒) L-এর decider M সবসময় থামে, তাই সে L-কে চেনে। M-এর গ্রহণ আর বর্জন অদলবদল করলে যে যন্ত্র পাই, সেটিও সবসময় থামে আর L̄-কে decide করে, তাই চেনে। — অবস্থা অদলবদল
  2. (⇐) M1 L-কে আর M2 L̄-কে চেনে। নতুন যন্ত্র N ইনপুট w-এ পালা করে M1-এর এক ধাপ, M2-এর এক ধাপ চালায় (দুই ফিতায়)। — পাশাপাশি চালানো
  3. w ∈ L অথবা w ∈ L̄, ঠিক একটি; তাই M1 বা M2-এর একটি সসীম ধাপে গ্রহণ করবে। N সেই মুহূর্তে থামে: M1 গ্রহণ করলে গ্রহণ, M2 গ্রহণ করলে বর্জন। — সসীম অপেক্ষা
  4. N প্রতিটি ইনপুটে থামে আর ঠিক উত্তর দেয়, তাই L decidable. ∎

৬ · Halting problem — নিজের কোড নিজেকে খাওয়ালে কী হয়

বাজারঘরের ডেভেলপার দল একটি টুল চায়: যেকোনো প্রোগ্রাম আর ইনপুট দিলে বলবে “থামবে” বা “চিরকাল আটকে থাকবে”, যাতে চেকআউটের কোডে অসীম লুপের ভয় না থাকে। নিচের উপপাদ্য বলে, এমন টুল সম্ভব নয়।

উপপাদ্য ৬.১ (halting problem undecidable)

HALT = {⟨M, w⟩ : যন্ত্র M ইনপুট w-তে একসময় থামে}. HALT decidable নয়: এমন কোনো যন্ত্র H নেই, যা প্রতিটি ⟨M, w⟩-এ থেমে ঠিক বলে দেয় M, w-তে থামে কি না।

  1. বিরোধের জন্য ধরুন এমন H আছে: H(⟨M, w⟩) সবসময় থামে, আর “থামে” বলে ঠিক যখন M, w-তে থামে, নইলে “থামে না”। — অনুমান
  2. H ব্যবহার করে নতুন যন্ত্র D বানান। ইনপুট ⟨M⟩ পেলে D চালায় H(⟨M, ⟨M⟩⟩), অর্থাৎ জিজ্ঞেস করে “M নিজের কোডে থামে কি?”। উত্তর “থামে” হলে D ইচ্ছা করে একটি অসীম লুপে ঢোকে; উত্তর “থামে না” হলে D সঙ্গে সঙ্গে থামে। — নির্মাণ
  3. D একটি বৈধ যন্ত্র: H-কে একটি উপ-অংশ হিসেবে চালানো, একটি string নকল করা আর একটি লুপ, সবই যন্ত্রে করা যায়। তাই D-এরও একটি সসীম কোড ⟨D⟩ আছে। — H থাকলে D-ও থাকে
  4. এখন D-কে তার নিজের কোড দিন: D(⟨D⟩). এটি H(⟨D, ⟨D⟩⟩)-কে জিজ্ঞেস করে “D নিজের কোডে থামে কি?” — নিজের ওপর প্রয়োগ
  5. H যদি বলে “থামে”, তাহলে D লুপে ঢোকে, অর্থাৎ D(⟨D⟩) থামে না; H ভুল। H যদি বলে “থামে না”, তাহলে D থামে; H আবার ভুল। H-এর আর কোনো উত্তর নেই, কারণ সে সবসময় থামে। — দুই ক্ষেত্র
  6. দুই ক্ষেত্রেই ধাপ ১-এর অনুমানের বিরোধ। তাই H নেই, HALT undecidable. ∎ — বিরোধ দিয়ে প্রমাণ
1assume H(M, w) always answers2def D(M):3  if H(M, M) == "halts": loop forever4  else: halt5run D(D)6both cases fail: no such H
কে কী বলে
H(D, D)-এর উত্তর
D(D) আসলে
H ঠিক?
  1. অনুমান। ধরুন একটি যন্ত্র H আছে, যা যেকোনো যন্ত্র M আর ইনপুট w-এর জন্য সবসময় থেমে ঠিক বলে “থামে” বা “থামে না”।
  2. উল্টো যন্ত্র D. D একটি যন্ত্র M-এর কোড নেয়, H-কে জিজ্ঞেস করে M নিজের কোডে থামে কি না, তারপর ঠিক উল্টো কাজ করে। H আছে বলে D-ও আছে।
  3. নিজের ওপর। D-এর কোড একটি সসীম string, তাই সেটিও ইনপুট হতে পারে। প্রশ্ন: H(D, D) কী বলবে? এটি diagonal-এর ঘর: সারি D, কলাম D.
  4. ক্ষেত্র ১. H বলে “থামে”। তাহলে D-এর ৩ নম্বর লাইন চলে: D(D) চিরকাল লুপে থাকে। অর্থাৎ D(D) থামে না, আর H ভুল বলল।
  5. ক্ষেত্র ২. H বলে “থামে না”। তাহলে ৪ নম্বর লাইন: D(D) সঙ্গে সঙ্গে থামে। H আবার ভুল।
  6. উপসংহার। H-কে কোনো একটি উত্তর দিতেই হয়, আর দুটিই ভুল। দোষ D-এর নয়, D তো H থেকেই বানানো; দোষ অনুমানের। তাই এমন H নেই। ∎

“নিজের কোড নিজেকে খাওয়ানো” রহস্য নয়: ⟨D⟩ একটি সসীম string. আর প্রমাণ বলে না যে কোনো নির্দিষ্ট প্রোগ্রামের থামা বোঝা অসম্ভব; বলে, সব প্রোগ্রামের জন্য একটিমাত্র নির্ভুল পদ্ধতি নেই।

উপপাদ্য ৬.২ আর অনুসিদ্ধান্ত ৬.৩

HALT recognizable. ফলে HALT-এর complement (যেসব ⟨M, w⟩-এ M থামে না) recognizable নয়।

প্রমাণ: universal machine U দিয়ে M-কে w-তে চালান; M থামলে (গ্রহণ বা বর্জন যেভাবেই) গ্রহণ করুন। M থামলে এটি গ্রহণ করে, না থামলে চিরকাল চলে, ঠিক recognizable-এর সংজ্ঞা। এখন complement-ও recognizable হলে উপপাদ্য ৫.৩ অনুযায়ী HALT decidable হতো, যা উপপাদ্য ৬.১-এর বিরোধী। ∎

ইতিহাস, সাবধানে: Turing-এর ১৯৩৬ সালের প্রবন্ধ “On Computable Numbers, with an Application to the Entscheidungsproblem” আজকের halting problem-এর হুবহু রূপ প্রমাণ করেনি; সেখানে একটি ঘনিষ্ঠ সমস্যা (একটি যন্ত্র অসীম সংখ্যক অঙ্ক ছাপে কি না) undecidable দেখানো হয়েছিল। “Halting problem” নাম আর আজকের রূপটি পরে, ১৯৫০-এর দশকের পাঠ্যবইয়ে (প্রায়ই Martin Davis-এর নামে) জনপ্রিয় হয় বলে ইতিহাসবিদরা উল্লেখ করেন।

৭ · Reduction, Rice-এর উপপাদ্য আর সফটওয়্যারের সীমা

একটি undecidable সমস্যা হাতে পেলে আরও অনেক পাওয়া যায়, প্রতিবার নতুন diagonal ছাড়াই। কৌশলটির নাম reduction: “B সমাধান করতে পারলে A-ও পারতাম; A অসম্ভব, তাই B-ও অসম্ভব।”

সংজ্ঞা ৭.১ আর লেমা ৭.২

A ≤m B (A, B-তে mapping reducible), যদি একটি গণনাযোগ্য ফাংশন f থাকে (সবসময় থামে এমন যন্ত্র যা f গোনে), যাতে সব x-এর জন্য x ∈ A ⇔ f(x) ∈ B. লেমা: A ≤m B আর B decidable হলে A decidable. সমতুল্যভাবে, A undecidable হলে B-ও undecidable.

লেমার প্রমাণ এক লাইনের: A-র decider = “x থেকে f(x) গুনুন, তারপর B-এর decider চালান”; দুটি অংশই থামে, আর উত্তর ঠিক, কারণ x ∈ A ⇔ f(x) ∈ B. ∎ দিক গুলিয়ে ফেলা খুব সাধারণ ভুল: জানা কঠিন সমস্যা A থেকে নতুন সমস্যা B-তে reduce করতে হয়, উল্টো নয়।

উপপাদ্য ৭.৩ (“hello” ছাপে কি?)

HELLO = {⟨P⟩ : প্রোগ্রাম P খালি ইনপুটে চালালে কোনো এক সময় ঠিক “hello” ছাপে}. HELLO undecidable.

  1. HALT ≤m HELLO দেখাব। ⟨M, w⟩ থেকে প্রোগ্রাম PM,w বানান: “M-কে w-তে নকল করো, এর মধ্যে M যা কিছু ছাপতে চায় তা চেপে রাখো (ছেপো না); M থামলে hello ছাপো।” — নির্মাণ
  2. এই রূপান্তর যান্ত্রিক: ⟨M⟩ আর w-কে একটি নির্দিষ্ট ছাঁচে বসানো মাত্র, PM,w-কে চালাতে হয় না। তাই f(⟨M, w⟩) = ⟨PM,w⟩ গণনাযোগ্য আর সবসময় থামে। — f গণনাযোগ্য
  3. M, w-তে থামলে PM,w hello ছাপে। না থামলে PM,w নকলেই আটকে থাকে, আর ছাপার সব চেষ্টা চেপে রাখা হয়েছে, তাই কখনো hello ছাপে না। অর্থাৎ ⟨M, w⟩ ∈ HALT ⇔ ⟨PM,w⟩ ∈ HELLO. — শর্ত মিলল
  4. HELLO decidable হলে লেমা ৭.২ অনুযায়ী HALT decidable হতো, যা উপপাদ্য ৬.১-এর বিরোধী। ∎

ধাপ ১-এর “চেপে রাখা” অংশটি ভুলে গেলে প্রমাণ ভাঙে: M নিজেই hello ছাপতে পারত, থামুক বা না থামুক। একই ছাঁচে “দুটি প্রোগ্রাম কি সব ইনপুটে একই ফল দেয়?” ধরনের বহু প্রশ্ন undecidable; সাধারণ রূপটি নিচে।

উপপাদ্য ৭.৪ (Rice-এর উপপাদ্য, এখানে প্রমাণ ছাড়া)

ধরুন 𝒫 recognizable language-এর একটি ধর্ম, যা অতুচ্ছ (কিছু যন্ত্রের language-এর আছে, কিছুর নেই)। তাহলে {⟨M⟩ : L(M)-এর ধর্ম 𝒫 আছে} undecidable.

Henry Gordon Rice ১৯৫০-এর দশকের শুরুতে (প্রকাশ ১৯৫৩ সালে বলে উল্লেখিত) এটি প্রমাণ করেন; প্রমাণটি ঠিক উপপাদ্য ৭.৩-এর ছাঁচে HALT থেকে reduction. কিন্তু শর্তগুলো খেয়াল করুন। ধর্মটি যন্ত্রের language-এর, কোডের চেহারার নয়: “M-এ ১০টির বেশি অবস্থা আছে কি?” decidable, কারণ টেবিল গুনলেই হয়। “M প্রথম ১০০ ধাপে থামে কি?” decidable, কারণ ১০০ ধাপ চালালেই হয়।

সফটওয়্যারের জন্য মানে

যেকোনো Turing-complete ভাষার প্রোগ্রামের জন্য একটি “নিখুঁত” টুল, যা সবসময় থামে, কখনো ভুল সতর্কবার্তা দেয় না আর কোনো আসল সমস্যা বাদ দেয় না, এমন termination checker, bug-finder বা virus detector সম্ভব নয়: “চিরকাল চলে”, “শূন্য দিয়ে ভাগ করে”, “ক্ষতিকর কাজ করে” সবই অতুচ্ছ আচরণগত ধর্ম। Virus সনাক্তকরণ সাধারণভাবে undecidable, এই ফল ১৯৮০-এর দশকে Fred Cohen-এর কাজে আসে বলে উল্লেখ করা হয়।

তবু বাস্তবের টুল কাজ করে, কারণ তারা ছাড় নেয়: “জানি না” উত্তরের অনুমতি, সন্দেহ হলেই সতর্ক করা (কিছু মিথ্যা সতর্কবার্তাসহ), বা সীমিত ভাষা ও সীমিত সময়। আর একটি নির্দিষ্ট প্রোগ্রামের জন্য মানুষের লেখা loop invariant আর variant (পর্ব ১৩) দিয়ে সঠিকতা আর থামা প্রমাণ করা যায়; Rice তা নিষেধ করে না। পর্ব ৭৭ “SAT আর SMT solver — discrete math দিয়ে software যাচাই”-এ এমন যন্ত্র-সহায়ক যাচাই দেখা যাবে, যা formal verification-এর অংশ।

৮ · Busy beaver আর জটিলতার এক ঝলক — P, NP

Halting problem-এর একটি সংখ্যাগত রূপ আছে। n-টি অবস্থা (থামার অবস্থা বাদে) আর চিহ্ন {0, 1}-এর যেসব যন্ত্র ফাঁকা ফিতায় শুরু করে একসময় থামে, তাদের মধ্যে সবচেয়ে বেশি ধাপ যে নেয়, সেই ধাপ-সংখ্যা S(n); আর থামার সময় ফিতায় সবচেয়ে বেশি যতটি 1 থাকে, তা Σ(n). এদের নাম busy beaver ফাংশন, Tibor Radó ১৯৬২ সালে প্রস্তাব করেন। প্রতিটি n-এ S(n) একটি নির্দিষ্ট সংখ্যা, তবু:

উপপাদ্য ৮.১

S(n) গণনাযোগ্য নয়: এমন কোনো যন্ত্র নেই যা প্রতিটি n-এর জন্য থেমে S(n) দেয়।

  1. বিরোধের জন্য ধরুন S গণনাযোগ্য। “n-অবস্থার যন্ত্র M ফাঁকা ফিতায় থামে কি?” প্রশ্নটি এভাবে decide করুন: S(n) গুনুন, তারপর M-কে S(n) ধাপ চালান। — অনুমান
  2. এর মধ্যে থামলে উত্তর “থামে”। না থামলে, S(n)-এর সংজ্ঞা অনুযায়ী কোনো থামা n-অবস্থার যন্ত্র এর বেশি ধাপ নেয় না, তাই M কখনো থামবে না। — S-এর সংজ্ঞা
  3. ফলে ফাঁকা ফিতার halting problem decidable হতো। কিন্তু সেটি undecidable (⟨M, w⟩ থেকে “আগে w লিখে তারপর M চালাও” যন্ত্র বানিয়ে HALT থেকে reduction করা যায়)। বিরোধ। ∎

আসলে আরও বেশি সত্য: S যেকোনো গণনাযোগ্য ফাংশনের চেয়ে শেষমেশ দ্রুত বাড়ে। জানা মান (Radó-এর প্রথায়, শেষের থামার ধাপসহ গোনা): S(1) = 1, S(2) = 6, S(3) = 21, S(4) = 107; Σ(1) = 1, Σ(2) = 4, Σ(3) = 6, Σ(4) = 13. S(5) = 47,176,870 আর Σ(5) = 4098, যা ২০২৪ সালে bbchallenge নামের অনলাইন সহযোগী দলের কাজে প্রমাণিত, আর Coq নামের proof assistant-এ যন্ত্রে যাচাই করা হয়েছে বলে জানা যায়। S(6) অজানা; শুধু জানা যে এটি কল্পনাতীত বড়। নিচের ব্লক n = 2-এর সব যন্ত্র গুনে S(2) আর Σ(2) বের করে।

from itertools import product
from collections import Counter
# one action = (symbol to write, head move, next state); H means halt
actions = [(w, m, nxt) for w in (0, 1) for m in (-1, 1) for nxt in "ABH"]
keys = [("A", 0), ("A", 1), ("B", 0), ("B", 1)]
CAP = 50                        # we stop watching a machine after 50 steps
best_ones = halted = 0
by_steps = Counter(); champion = (0, 0, None)
for table in product(actions, repeat=4):
    rule = dict(zip(keys, table))
    tape, pos, q, steps = {}, 0, "A", 0
    while q != "H" and steps < CAP:
        write, move, q = rule[(q, tape.get(pos, 0))]
        tape[pos] = write; pos += move; steps += 1
    if q == "H":
        halted += 1; by_steps[steps] += 1
        ones = sum(tape.values())
        best_ones = max(best_ones, ones)
        if (steps, ones) > champion[:2]:
            champion = (steps, ones, table)
total = len(actions) ** 4
print("2-state, 2-symbol machines:", total)
print("halted within", CAP, "steps:", halted, " still running:", total - halted)
print("halting machines by step count:", sorted(by_steps.items()))
print("max steps S(2) =", max(by_steps), "  max ones Sigma(2) =", best_ones)
print("a champion (steps, ones, rules for A0 A1 B0 B1):", champion)
for n in (1, 2, 3, 4):
    print(f"n = {n} states: (4(n+1))^(2n) = {(4 * (n + 1)) ** (2 * n):,} machines")

আসল আউটপুট (ব্রাউজারের Python):

2-state, 2-symbol machines: 20736
halted within 50 steps: 9784  still running: 10952
halting machines by step count: [(1, 6912), (2, 2304), (3, 384), (4, 128), (5, 16), (6, 40)]
max steps S(2) = 6   max ones Sigma(2) = 4
a champion (steps, ones, rules for A0 A1 B0 B1): (6, 4, ((1, -1, 'B'), (1, 1, 'B'), (1, 1, 'A'), (1, -1, 'H')))
n = 1 states: (4(n+1))^(2n) = 64 machines
n = 2 states: (4(n+1))^(2n) = 20,736 machines
n = 3 states: (4(n+1))^(2n) = 16,777,216 machines
n = 4 states: (4(n+1))^(2n) = 25,600,000,000 machines

প্রতিটি (অবস্থা, চিহ্ন) জোড়ার 2 × 2 × 3 = 12টি সম্ভাব্য কাজ, আর জোড়া চারটি, তাই 124 = 20,736টি যন্ত্র। 9784টি ৫০ ধাপের মধ্যে থামে, সবচেয়ে দেরিতে ৬ ধাপে (৪০টি যন্ত্র), আর থামার সময় সর্বোচ্চ ৪টি 1. বাকি 10,952টি ৫০ ধাপেও থামেনি। সৎ সতর্কতা: এই কোড একা প্রমাণ করে না যে ওগুলো কখনো থামবে না; ৫১তম ধাপে থামলে আমরা টের পেতাম না। S(2) = 6 হওয়ার প্রমাণ আলাদা: প্রতিটি না-থামা যন্ত্রের জন্য একটি যুক্তি (যেমন পুনরাবৃত্ত configuration) দেখাতে হয়। champion-এর নিয়ম: A0 → 1, বাঁয়ে, B; A1 → 1, ডানে, B; B0 → 1, ডানে, A; B1 → 1, বাঁয়ে, থামা। শেষ লাইনগুলো (4(n + 1))2n: n = 3-এ প্রায় ১.৭ কোটি, n = 4-এ ২,৫৬০ কোটি যন্ত্র; brute force এখানেই ভেঙে পড়ে।

গণনাযোগ্যের ভেতরে: সময়ের প্রশ্ন

Decidable হলেই কাজের নয়: 2n ধাপের decider n = 100-এ কার্যত কখনো শেষ হবে না। P হলো সেই language-গুলো, যাদের একটি deterministic Turing machine polynomial time-এ, অর্থাৎ কোনো স্থির k-এর জন্য O(nk) ধাপে decide করে; §৩-এর anbncn (O(n2)) তার একটি। NP হলো যাদের প্রতিটি “হ্যাঁ” উত্তরের একটি ছোট সাক্ষী (certificate) polynomial time-এ যাচাই করা যায়; সমতুল্যভাবে, nondeterministic যন্ত্র polynomial time-এ চেনে। Hamilton cycle (পর্ব ৬০) আর 3-colouring (পর্ব ৬৩) NP-তে আছে।

উপপাদ্য ৮.২ (Cook–Levin, প্রমাণ ছাড়া)

CNF-এর satisfiability (SAT) NP-complete: SAT ∈ NP, আর NP-এর প্রতিটি language polynomial time-এ SAT-এ reduce হয়।

Stephen Cook ১৯৭১ সালে এটি প্রকাশ করেন, আর Leonid Levin স্বাধীনভাবে প্রায় একই ফল পান (প্রকাশ ১৯৭৩)। মূল ধারণা: যন্ত্রের পুরো চলাকে configuration-এর টেবিল হিসেবে লিখে “প্রতিটি সারি আগেরটি থেকে একটি নিয়মে আসে” শর্তকে CNF clause দিয়ে বাঁধা। P = NP কি না, তা আজও অজানা। SAT আর NP-completeness-এর ব্যবহারিক দিক পর্ব ০৭-এ দেখেছেন, পর্ব ৭৭-এ আরও গভীরে যাবেন, আর reduction-এর অ্যালগরিদমিক দিক DSA কোর্সের পর্ব ৬৪-এ।

৯ · পরীক্ষার অঙ্ক আর একটি ভুল প্রমাণ

অঙ্ক ১: increment যন্ত্রের trace

§২-এর যন্ত্রে ইনপুট 111. সব configuration লিখুন, ফলাফল আর ধাপ-সংখ্যা বলুন।

  1. ডানে যাত্রা: [q0]111 → 1[q0]11 → 11[q0]1 → 111[q0]_ (৩ ধাপ)।
  2. ফেরা: 11[q1]1 (৪); carry: 1[q1]10 (৫), [q1]100 (৬), তারপর বাঁয়ের ফাঁকা ঘরে [q1]_000 (৭)।
  3. ফাঁকা পেয়ে 1 লেখে, গ্রহণ: ফিতায় 1000 (7 + 1 = 8), মোট ৮ ধাপ; সূত্রে n + k + 2 = 3 + 3 + 2 = 8. (scratch script-এ trace মেলানো।)

অঙ্ক ২: যন্ত্রের সংখ্যা

n-টি অবস্থা (থামা বাদে), চিহ্ন {0, 1}, প্রতিটি নিয়মে লেখা চিহ্ন, L/R আর পরের অবস্থা (n-টির একটি বা থামা)। কয়টি আলাদা নিয়মের টেবিল?

  1. (অবস্থা, চিহ্ন) জোড়া 2n-টি। প্রতিটির জন্য 2 × 2 × (n + 1) = 4(n + 1)টি পছন্দ। — গুণের নিয়ম
  2. মোট (4(n + 1))2n. n = 1: 82 = 64; n = 2: 124 = 20,736; n = 3: 166 = 16,777,216 (§৮-এর ব্লকে মেলানো)।

অঙ্ক ৩: শ্রেণিবিভাগ

প্রতিটি language decidable, শুধু recognizable, নাকি recognizable-ও নয়? (ক) {anbncn}; (খ) {⟨M⟩ : M ফাঁকা ফিতায় ১০০ ধাপের মধ্যে থামে}; (গ) HALT; (ঘ) HALT-এর complement.

  1. (ক) decidable: §৩-এর decider. (খ) decidable: ১০০ ধাপ চালিয়ে দেখলেই হয়, সীমা নির্দিষ্ট।
  2. (গ) recognizable, decidable নয়: উপপাদ্য ৬.১ আর ৬.২. (ঘ) recognizable নয়: অনুসিদ্ধান্ত ৬.৩.

প্রমাণের ভুল ধরুন: “HALT-এর complement recognizable”

একজন লিখলেন: “যন্ত্র N: ইনপুট ⟨M, w⟩ পেলে M-কে w-তে চালাও। M থামলে বর্জন করো; M না থামলে গ্রহণ করো। তাই N ঠিক সেই ⟨M, w⟩ গ্রহণ করে যেখানে M থামে না। ∎”

ভুল কোথায়: “M না থামলে গ্রহণ করো” কোনো যন্ত্রের নিয়ম হতে পারে না। যন্ত্র প্রতিটি মুহূর্তে শুধু জানে M এখন পর্যন্ত থামেনি; “কখনো থামবে না” জানার কোনো মুহূর্ত আসে না। M না থামলে N-ও চিরকাল M-কে চালাতে থাকে, কখনো গ্রহণ করে না। তাই N আসলে কিছুই গ্রহণ করে না। অনুসিদ্ধান্ত ৬.৩ বলে কোনো সংশোধনেই এটি বাঁচবে না।

আরও গভীরে: Undecidable সমস্যার মধ্যেও স্তর আছে: halting-এর সমাধান “উপহার” পাওয়া যন্ত্রেরও নিজের halting problem আছে, যা থেকে arithmetical hierarchy আর Turing degree-র তত্ত্ব আসে। Hilbert-এর দশম সমস্যাও (পূর্ণসংখ্যার বহুপদী সমীকরণের সমাধান আছে কি না) undecidable, Matiyasevich ১৯৭০ সালে প্রমাণটি সম্পূর্ণ করেন। আবার Yedidia আর Aaronson ২০১৬ সালে কয়েক হাজার অবস্থার একটি যন্ত্র দেখান, যার থামা না-থামা প্রচলিত সেট তত্ত্ব (ZFC) দিয়ে প্রমাণ করা যায় না, ধরে নিয়ে যে ZFC সামঞ্জস্যপূর্ণ; পরে অবস্থার সংখ্যা অনেক কমানো হয়েছে বলে জানা যায়।

পরীক্ষা ও ইন্টারভিউতে: বিশ্ববিদ্যালয়, চাকরি বা ইন্টারভিউর পরীক্ষায় এই ধরনের প্রশ্ন প্রায়ই আসে:

  • Turing machine-এর ৭-tuple লিখুন। (Q, Σ, Γ, δ, q0, qacc, qrej), δ : Q × Γ → Q × Γ × {L, R}.
  • Decidable আর recognizable-এর পার্থক্য? Decider সব ইনপুটে থামে; recognizer “না”-এর ক্ষেত্রে চিরকাল চলতে পারে।
  • Halting problem কেন undecidable? H থাকলে “H-এর উল্টো কাজ করা” D বানিয়ে D(⟨D⟩)-তে বিরোধ।
  • Church–Turing thesis কেন প্রমাণ করা যায় না? “অ্যালগরিদম”-এর অনানুষ্ঠানিক ধারণাকে একটি গাণিতিক সংজ্ঞার সঙ্গে মেলায়।
  • Rice-এর উপপাদ্য কী বলে? যন্ত্রের language-এর যেকোনো অতুচ্ছ ধর্ম undecidable; কোডের চেহারার ধর্ম এর বাইরে।

১০ · AI-এর যুগে — computability-র যুক্তি যাচাই

AI সহকারী halting problem-এর গল্প সুন্দর বলে, কিন্তু প্রমাণের সূক্ষ্ম জায়গায় আর trace-এ ভুল করে:

AI-এর ভুলকীভাবে ধরবেন
Reduction-এর দিক উল্টো: নতুন সমস্যা B থেকে HALT-এ reduce করে বলা “B undecidable”লেমা ৭.২ মিলিয়ে দেখুন: জানা কঠিন A ≤ নতুন B হতে হবে
“না থামলে গ্রহণ করো”-ধাঁচের অসম্ভব নিয়ম, বা “লুপ ধরা পড়লে” ধরে নেওয়াপ্রতিটি নিয়ম কোন সসীম মুহূর্তে কাজ করে, জিজ্ঞেস করুন
Rice-এর উপপাদ্য কোডের চেহারা বা সীমিত-ধাপের প্রশ্নে খাটানোধর্মটি language-এর কি না, আর অতুচ্ছ কি না, আলাদা করে দেখুন
Trace-এ মাথার অবস্থান বা ধাপ-সংখ্যায় এক কম-বেশিছোট simulator-এ একই যন্ত্র চালিয়ে configuration মেলান
Busy beaver-এর মান, সাল বা কে প্রমাণ করেছেন, আত্মবিশ্বাসের সঙ্গে বানানোমূল প্রবন্ধ বা নির্ভরযোগ্য উৎসে মেলান; না পেলে “অনিশ্চিত” লিখুন

AI-এর কাছে computability-র প্রশ্ন করলে এমন কাঠামো দিন, যাতে প্রতিটি দাবি আলাদা করে যাচাই করা যায়:

নিচের computability-র প্রশ্নের উত্তর ধাপে ধাপে দাও: প্রশ্ন: [যেমন "প্রমাণ করো যে 'P কোনো ইনপুটে hello ছাপে' undecidable"] ১. কোন জানা undecidable সমস্যা থেকে reduce করছ, আর reduction-এর দিক (A ≤ B) স্পষ্ট লেখো। ২. Reduction ফাংশন f কেন সবসময় থামে, আর কেন x ∈ A ⇔ f(x) ∈ B, দুই দিকই আলাদা করে দেখাও। ৩. কোনো উপপাদ্য (Rice, উপপাদ্য ৫.৩) ব্যবহার করলে তার সব শর্ত লেখো আর মিলিয়ে দেখাও। ৪. যন্ত্রের trace দিলে প্রতিটি configuration u[q]v আকারে লেখো, আর ধাপ গুনে দাও। ৫. শুধু standard library দিয়ে একটি ছোট Python simulator দাও, যাতে আমি trace নিজে চালাতে পারি। ৬. কোনো সাল, নাম বা সংখ্যা নিয়ে নিশ্চিত না হলে স্পষ্ট বলো।

AI-এর উত্তর হাতে পেলে — যাচাইয়ের চেকলিস্ট

মনে রাখুন, simulator “থামে” প্রমাণ করতে পারে, “কখনো থামে না” পারে না; সেটির জন্য সবসময় একটি যুক্তি লাগে।

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

প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।

প্র ০১১৯৩৬ সালে Church আর Turing প্রায় একসঙ্গে একই প্রশ্নের উত্তর দিলেন। প্রশ্নটি কী ছিল, আর দুটি উত্তর কেন একই সময়ে এল?

প্রশ্নটি এসেছিল David Hilbert-এর কাছ থেকে। ১৯২৮ সালে Hilbert আর Wilhelm Ackermann-এর বইয়ে Entscheidungsproblem (“সিদ্ধান্তের সমস্যা”) স্পষ্টভাবে লেখা হয়: first-order logic-এর যেকোনো বাক্য দিলে, সেটি সব ক্ষেত্রে সত্য কি না, তা একটি যান্ত্রিক পদ্ধতিতে বের করা যায় কি? Hilbert-এর আশা ছিল উত্তর “হ্যাঁ”, যাতে গণিতের প্রশ্ন একসময় হিসাবের প্রশ্নে পরিণত হয়।

কিন্তু “না” প্রমাণ করতে হলে আগে বলতে হয় “যান্ত্রিক পদ্ধতি” বলতে ঠিক কী বোঝায়; নইলে কোনো পদ্ধতি নেই, এটা দেখাবেন কীভাবে? ১৯৩১ সালে Kurt Gödel-এর অসম্পূর্ণতা উপপাদ্য দেখিয়েছিল যে গণিতের প্রমাণ-ব্যবস্থার নিজস্ব সীমা আছে, আর তাঁর পদ্ধতিতে সূত্রকে সংখ্যা দিয়ে লেখার (Gödel numbering) কৌশল এসেছিল, যা §৪-এর ⟨M⟩ encoding-এর পূর্বসূরি।

Alonzo Church ১৯৩৬ সালের শুরুর দিকে λ-calculus দিয়ে সংজ্ঞা দিয়ে Entscheidungsproblem-এর নেতিবাচক উত্তর প্রকাশ করেন। Alan Turing তখন কেমব্রিজের তরুণ গবেষক; তিনি স্বাধীনভাবে মানুষের হাতে হিসাব করার প্রক্রিয়া বিশ্লেষণ করে তাঁর যন্ত্রে পৌঁছান, আর Church-এর কাজ প্রকাশিত হওয়ার পর তাঁর প্রবন্ধে একটি পরিশিষ্ট যোগ করে দেখান যে দুটি সংজ্ঞা সমতুল্য। পরে Turing প্রিন্সটনে Church-এর অধীনে PhD করেন। Emil Post-ও ১৯৩৬ সালে প্রায় একই রকম একটি মডেল প্রকাশ করেন।

অনেকের মতে Turing-এর মডেল বেশি বিশ্বাসযোগ্য হয়েছিল, কারণ তিনি দেখিয়েছিলেন কেন একজন মানুষের হিসাবরক্ষকের প্রতিটি সীমা (একসঙ্গে অল্প চিহ্ন দেখা, সসীম মনের অবস্থা) যন্ত্রের অংশে পরিণত হয়।

মূল উপলব্ধি: “কোনো পদ্ধতি নেই” প্রমাণ করতে “পদ্ধতি”-র নির্ভুল সংজ্ঞা লাগে; ১৯৩০-এর দশকে কয়েকটি আলাদা সংজ্ঞা একই জায়গায় পৌঁছানোই Church–Turing thesis-এর সবচেয়ে বড় প্রমাণ।

প্র ০২Quantum computer বা মানুষের মস্তিষ্ক কি Turing machine-এর সীমা পার হতে পারে?

প্রথমে দুটি প্রশ্ন আলাদা করা দরকার: কী গোনা যায় (computability), আর কত দ্রুত গোনা যায় (complexity), এই দুটি। Church–Turing thesis মূলত প্রথমটির কথা বলে। একটি “physical” রূপও আলোচিত হয়: প্রকৃতির যেকোনো ভৌত প্রক্রিয়া দিয়ে যা গোনা যায়, তা Turing machine দিয়েও যায়। এটি গণিতের দাবি নয়, পদার্থবিজ্ঞানের একটি অনুমান।

Quantum computer-এর ক্ষেত্রে উত্তর তুলনামূলক পরিষ্কার। একটি quantum বর্তনীর আচরণ জটিল সংখ্যার বিশাল matrix-এর গুণ দিয়ে লেখা যায়, আর একটি সাধারণ কম্পিউটার (অনেক সময় নিয়ে) তা হুবহু গুনতে পারে। তাই quantum computer কোনো নতুন সমস্যা decidable করে না; halting problem তার কাছেও undecidable. পার্থক্য সময়ে: Peter Shor ১৯৯৪ সালে দেখান যে পূর্ণসংখ্যার উৎপাদক বের করা quantum computer-এ polynomial সময়ে হয়, অথচ সাধারণ কম্পিউটারে এমন কোনো দ্রুত অ্যালগরিদম জানা নেই। অর্থাৎ quantum computing “strong” বা complexity-র রূপের thesis-কে চ্যালেঞ্জ করে, মূল thesis-কে নয়।

মস্তিষ্কের প্রশ্নটি বেশি দার্শনিক। কেউ কেউ, যেমন Roger Penrose, Gödel-এর উপপাদ্য টেনে যুক্তি দিয়েছেন যে মানুষের গাণিতিক অন্তর্দৃষ্টি কোনো অ্যালগরিদম নয়; বেশিরভাগ গণিতবিদ আর দার্শনিক এই যুক্তিকে বিশ্বাসযোগ্য মনে করেন না, কারণ মানুষ নিজেও ভুল করে আর নিজের সামঞ্জস্য প্রমাণ করতে পারে না। অনেকের মতে মস্তিষ্ক নীতিগতভাবে নকলযোগ্য, যদিও বাস্তবে তা অসম্ভব রকম কঠিন।

“Hypercomputation” নামে কিছু তাত্ত্বিক মডেল আছে, যেমন অসীম সূক্ষ্ম বাস্তব সংখ্যা রাখা যন্ত্র, যা halting decide করতে পারত; কিন্তু এদের কোনোটি ভৌতভাবে বানানো যায় বলে কোনো প্রমাণ নেই।

মূল উপলব্ধি: Quantum computer কী গোনা যায় তা বদলায় না, কিছু সমস্যার সময় বদলাতে পারে; মস্তিষ্ক Turing machine-এর বাইরে, এমন দাবির পক্ষে আজ পর্যন্ত কোনো দৃঢ় প্রমাণ নেই।

প্র ০৩Halting problem undecidable হলে compiler আর static analyzer কীভাবে “এই লুপ কখনো থামবে না” সতর্কবার্তা দেয়?

উপপাদ্য ৬.১ একটি খুব নির্দিষ্ট জিনিস নিষেধ করে: একটি টুল, যা সব প্রোগ্রামে থামে আর সবসময় ঠিক উত্তর দেয়। বাস্তবের টুল এই তিন শর্তের অন্তত একটি ছেড়ে দেয়, আর সেভাবেই কাজের হয়।

প্রথম কৌশল: সহজ ক্ষেত্র চেনা। while (1) বা শর্তে কখনো না বদলানো চলক থাকলে compiler নিশ্চিতভাবে বলতে পারে লুপটি থামবে না। এটি সব অসীম লুপ ধরে না, কিন্তু যেটি ধরে, সেটি ঠিক। দ্বিতীয় কৌশল: তিন রকম উত্তর। আধুনিক termination prover (যেমন গবেষণায় পরিচিত কিছু টুল) প্রতিটি লুপের জন্য একটি “ranking function” খোঁজে, অর্থাৎ এমন একটি অঋণাত্মক পূর্ণসংখ্যার রাশি যা প্রতি ঘূর্ণনে কমে, ঠিক পর্ব ১৩-এর variant. পেলে উত্তর “থামবে”, না পেলে “জানি না”। অনেক বাস্তব লুপ (অ্যারে ঘোরা, গণক বাড়ানো) এভাবে প্রমাণ হয়।

তৃতীয় কৌশল: সাবধানী অনুমান, যাকে বলে sound analysis. যেমন একটি type checker বা memory-safety checker এমন সব প্রোগ্রাম বাতিল করে, যেখানে ভুলের সম্ভাবনা উড়িয়ে দেওয়া যায় না। ফলে কিছু সঠিক প্রোগ্রামও বাতিল হয় (false positive), আর প্রোগ্রামারকে কোড একটু বদলে লিখতে হয়। উল্টো দিকে কিছু bug-finder শুধু নিশ্চিত ভুল দেখায়, কিছু বাদ দেয়। দুটোই Rice-এর সঙ্গে সামঞ্জস্যপূর্ণ।

চতুর্থ কৌশল: ভাষাকে সীমিত করা। যে ভাষায় লুপ শুধু আগে থেকে জানা সংখ্যক বার চলে (যেমন কিছু configuration ভাষা বা SQL-এর কিছু অংশ), সেটি Turing-complete নয়, তাই সেখানে থামা নিশ্চিত।

মূল উপলব্ধি: Halting problem “সবকিছু, সবসময়, নির্ভুল” টুল নিষেধ করে; “কখনো কখনো জানি না” বলার অনুমতি দিলে, বা সাবধানী হয়ে কিছু ঠিক প্রোগ্রাম বাতিল করলে, খুব কাজের বিশ্লেষণ সম্ভব।

প্র ০৪BB(5)-এর প্রমাণে অনলাইন সহযোগিতা আর proof assistant লেগেছে। এতে গাণিতিক প্রমাণের ধারণা কি বদলাচ্ছে?

পাঁচ অবস্থার যন্ত্র প্রায় ৬৩ লাখ কোটি (অঙ্ক ২-এর সূত্রে (4 · 6)10, প্রতিসাম্য বাদ দিলে অনেক কম)। ১৯৮৯ সালে Heiner Marxen আর Jürgen Buntrock একটি যন্ত্র পান, যা 47,176,870 ধাপে থামে আর 4098টি 1 রেখে যায়। উত্তর দিতে হলে বাকি প্রতিটি যন্ত্রের জন্য দেখাতে হয় সেটি কম ধাপে থামে, অথবা কখনো থামে না; দ্বিতীয়টির জন্য প্রতিবার একটি যুক্তি লাগে, কারণ simulator একা “কখনো না” প্রমাণ করতে পারে না।

bbchallenge নামের একটি উন্মুক্ত অনলাইন প্রকল্প যন্ত্রগুলোকে স্বয়ংক্রিয় “decider” দিয়ে ভাগ করে: পুনরাবৃত্ত configuration খোঁজা, ফিতার নিয়মিত প্যাটার্ন চেনা, finite automaton দিয়ে “থামার অবস্থায় কখনো পৌঁছায় না” সার্টিফিকেট বানানো ইত্যাদি। শেষে অল্প কিছু কঠিন যন্ত্রের জন্য আলাদা যুক্তি লাগে। ২০২৪ সালে দলটি জানায় যে পুরো যুক্তিটি Coq proof assistant-এ লেখা ও যাচাই করা হয়েছে, অর্থাৎ প্রতিটি যুক্তির ধাপ একটি ছোট, বিশ্বস্ত যাচাই-প্রোগ্রাম মিলিয়ে দেখেছে।

গণিতে কম্পিউটার-সহায়ক প্রমাণ নতুন নয়। ১৯৭৬ সালে Appel আর Haken-এর চার রঙের উপপাদ্যের প্রমাণ (পর্ব ৬৩) হাজারো ক্ষেত্র কম্পিউটারে পরীক্ষা করেছিল, আর তখন অনেকে অস্বস্তি প্রকাশ করেছিলেন: কোনো মানুষ পুরোটা পড়তে পারে না। পরে Georges Gonthier আর সহকর্মীরা ২০০৫ সালের দিকে সেটিও Coq-এ যাচাই করেন। প্রবণতাটি হলো, “কম্পিউটার গুনেছে, বিশ্বাস করুন” থেকে “কম্পিউটার প্রতিটি যুক্তির ধাপ যাচাই করেছে” দিকে যাওয়া।

অন্যদিকে, BB(6) সম্পর্কে জানা যায় যে এটি কল্পনাতীত বড়, আর কিছু ৬-অবস্থার যন্ত্রের আচরণ Collatz-ধাঁচের খোলা সমস্যার সঙ্গে জড়িত বলে আলোচিত হয়।

মূল উপলব্ধি: প্রমাণের মানদণ্ড বদলায়নি, প্রতিটি ধাপ যুক্তিসিদ্ধ হতেই হবে; বদলেছে যাচাইয়ের উপায়, যেখানে proof assistant মানুষের চোখের জায়গায় একটি ছোট, পরীক্ষিত যাচাই-প্রোগ্রাম বসায়।

প্র ০৫একটি সমস্যা NP-complete প্রমাণ হলে কি হাল ছেড়ে দিতে হয়? বাস্তবে এর মানে কী?

১৯৭১ সালে Stephen Cook দেখান SAT NP-complete, আর ১৯৭২ সালে Richard Karp ২১টি পরিচিত combinatorial সমস্যা (clique, Hamilton cycle, graph colouring ইত্যাদি) NP-complete প্রমাণ করেন। সোভিয়েত ইউনিয়নে Leonid Levin স্বাধীনভাবে একই ধারণায় পৌঁছান। তারপর থেকে হাজারো সমস্যা এই তালিকায় যোগ হয়েছে। P = NP কি না, তা Clay Mathematics Institute-এর সাতটি Millennium Prize সমস্যার একটি (২০০০ সালে ঘোষিত)।

NP-complete প্রমাণের আসল মানে: “সব ইনপুটে দ্রুত আর নির্ভুল” অ্যালগরিদম পাওয়া গেলে NP-এর সব সমস্যাই দ্রুত হয়ে যেত, আর বহু দশকের চেষ্টাতেও কেউ তা পায়নি। তাই সেটি খোঁজার বদলে অন্য প্রশ্ন করা ভালো।

দিক বদলানোর কয়েকটি পথ। (১) বাস্তবের ইনপুট প্রায়ই সবচেয়ে খারাপ ক্ষেত্র নয়: আধুনিক SAT solver লাখো চলকের শিল্প-সমস্যা সমাধান করে (পর্ব ০৭, পর্ব ৭৭)। (২) Approximation: সর্বোত্তমের কাছাকাছি উত্তর polynomial সময়ে, প্রমাণিত নিশ্চয়তাসহ। (৩) ছোট প্রাচল: বাজারঘরের ডেলিভারি রুটে যদি মাত্র ১২টি ঠিকানা থাকে, তবে সূচকীয় অ্যালগরিদমও যথেষ্ট দ্রুত। (৪) বিশেষ গঠন: সাধারণ graph-এ colouring কঠিন, কিন্তু bipartite বা গাছে সহজ।

এই পর্বের মূল শিক্ষার সঙ্গে তুলনা করুন: NP-complete সমস্যা decidable, সময় দিলে সমাধান হয়ই; halting problem-এর মতো undecidable সমস্যার কোনো সময়েই সাধারণ সমাধান নেই।

মূল উপলব্ধি: NP-complete মানে সব ইনপুটে দ্রুত নির্ভুল সমাধানের আশা বাদ, কাজ নয়; heuristics, approximation, ছোট প্রাচল আর বিশেষ গঠন দিয়ে বাস্তবে এগুলো নিয়মিত সমাধান হয়, যা undecidable সমস্যার বেলায় সম্ভব নয়।

অনুশীলন

আগে খাতায় করুন, তারপর উত্তর খুলে মেলান।

  1. প্রমাণ: L1 আর L2 decidable হলে প্রমাণ করুন L1 ∪ L2 decidable. তারপর L1, L2 শুধু recognizable হলে L1 ∪ L2 recognizable কেন, আর একই প্রমাণ কেন খাটে না, ব্যাখ্যা করুন।
    1. M1, M2 দুটি decider. নতুন যন্ত্র: w-এ আগে M1 চালান; গ্রহণ করলে গ্রহণ। নইলে M2 চালান; গ্রহণ করলে গ্রহণ, নইলে বর্জন। — পরপর চালানো
    2. দুটিই সবসময় থামে, তাই নতুন যন্ত্রও থামে; গ্রহণ করে ঠিক যখন w ∈ L1 বা w ∈ L2. ∎
    3. শুধু recognizer হলে পরপর চালানো চলে না: w ∉ L1 কিন্তু w ∈ L2 হলে M1 চিরকাল চলতে পারে, M2-এর পালা আসে না। সমাধান উপপাদ্য ৫.৩-এর মতো পালা করে এক ধাপ করে চালানো; যেকোনোটি গ্রহণ করলে গ্রহণ। w সদস্য হলে কোনো একটি সসীম ধাপে গ্রহণ করবে। ∎
  2. গণনা: §২-এর increment যন্ত্রে (ক) 1111111 আর (খ) 1000000 দিলে ফলাফল আর ধাপ-সংখ্যা কত? (গ) §৩-এর যন্ত্রে a10b10c10-এ কত ধাপ, মাপা সূত্র 4n2 + 3n + 1 ধরে? (ঘ) ৩-অবস্থার ২-চিহ্নের কয়টি নিয়মের টেবিল?

    (ক) n = 7, k = 7: ফলাফল 10000000, ধাপ 7 + 7 + 2 = 16. (খ) k = 0: ফলাফল 1000001, ধাপ 7 + 0 + 2 = 9. (গ) 400 + 30 + 1 = 431. (ঘ) 166 = 16,777,216. সবগুলো scratch-এ simulator চালিয়ে মেলানো; (গ)-এর সূত্রটি মাপা মান থেকে পাওয়া, তাই n = 10-এ আলাদাভাবে চালিয়েও 431 মিলেছে।

  3. আউটপুট অনুমান: কোড না চালিয়ে বলুন কী ছাপা হবে। তারপর যেকোনো Python-এ চালিয়ে মেলান।
    rules = {("s", "1"): ("t", "1", 1), ("t", "1"): ("s", "0", 1),
             ("s", "0"): ("s", "0", 1), ("t", "0"): ("t", "1", 1)}
    tape, pos, q = list("11011"), 0, "s"
    while pos < len(tape):
        q, tape[pos], move = rules[(q, tape[pos])]
        pos += move
    print("".join(tape), q)
    10010 s

    মাথা শুধু ডানে যায়। ঘর 0: s, 1 → t, 1 থাকে। ঘর 1: t, 1 → 0 লিখে s. ঘর 2: s, 0 → 0, s. ঘর 3: s, 1 → t, 1 থাকে। ঘর 4: t, 1 → 0 লিখে s. তাই 10010, শেষ অবস্থা s (CPython 3.14-এ চালিয়ে মেলানো)। এটি আসলে একটি finite-state transducer: মাথা কখনো ফেরে না, তাই এই যন্ত্র Turing machine-এর পুরো ক্ষমতা ব্যবহার করে না।

  4. প্রমাণের ভুল ধরুন: দাবি: “Halting problem আসলে decidable.” যুক্তি: “H′: ⟨M, w⟩ পেলে M-কে w-তে 109 ধাপ চালাও। এর মধ্যে থামলে বলো ‘থামে’, নইলে বলো ‘থামে না’, কারণ এত ধাপেও যে থামে না, সে অসীম লুপে আছে। H′ সবসময় থামে। ∎” ভুল কোথায়? একটি পাল্টা-উদাহরণ দিন।
    • ভুল ধাপ: “এত ধাপেও না থামলে অসীম লুপ” প্রমাণহীন। H′ সবসময় থামে ঠিকই, কিন্তু সব ক্ষেত্রে ঠিক উত্তর দেয় না।
    • পাল্টা-উদাহরণ: একটি যন্ত্র যা ফিতায় 109 + 1 পর্যন্ত গুনে থামে; এটি থামে, কিন্তু H′ বলে “থামে না”। যেকোনো স্থির সীমা N-এর জন্য N + 1 ধাপে থামা যন্ত্র আছে।
    • সঠিক কথা: নির্দিষ্ট সীমার “N ধাপে থামে কি?” decidable; সীমা যদি যন্ত্রের আকার n থেকে গোনা যেত (যেমন S(n)), তবে কাজ হতো, কিন্তু উপপাদ্য ৮.১ বলে S গণনাযোগ্য নয়।

নিজেকে যাচাই করুন

ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।

ক্রম“Halting problem undecidable”, এই প্রমাণের ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)

  1. ধরুন একটি যন্ত্র H সবসময় থেমে বলে M, w-তে থামে কি না
  2. H দিয়ে D বানান: M নিজের কোডে থামলে D লুপে ঢোকে, নইলে থামে
  3. D-কে তার নিজের কোড ⟨D⟩ ইনপুট দিন
  4. H “থামে” বললে D লুপে থাকে, “থামে না” বললে D থামে
  5. দুই ক্ষেত্রেই H ভুল, তাই এমন H থাকতে পারে না

একটি Turing machine ইনপুটের ডান প্রান্তে গিয়ে ফেরে আর binary সংখ্যায় এক যোগ করে; দৈর্ঘ্য n আর শেষে পরপর k-টি 1 থাকলে মোট ধাপ n + k + 2. ইনপুট 0111 হলে ফলাফল আর ধাপ-সংখ্যা কত?

  • 1000, ৮ ধাপ
  • 1000, ৯ ধাপ
  • 10000, ১০ ধাপ
  • 0110, ৬ ধাপ

HALT = {⟨M, w⟩ : M ইনপুট w-তে থামে}. কোন বক্তব্যটি সত্য?

  • HALT decidable, তবে খুব ধীরে
  • HALT recognizable-ও নয়
  • HALT recognizable, কিন্তু decidable নয়
  • HALT আর তার complement দুটিই recognizable

Rice-এর উপপাদ্য অনুযায়ী নিচের কোন প্রশ্নটি (Turing machine M-এর কোড দেওয়া থাকলে) undecidable?

  • L(M) কি খালি সেট?
  • M-এর নিয়মের টেবিলে কি ২০টির বেশি অবস্থা আছে?
  • M কি খালি ইনপুটে ৫০ ধাপের মধ্যে থামে?
  • M-এর শুরুর অবস্থা কি গ্রহণের অবস্থার সমান?

দুটি অবস্থা (থামা বাদে) আর চিহ্ন {0, 1}-এর Turing machine-এ প্রতিটি নিয়ম একটি চিহ্ন লেখে, L বা R সরে, আর দুটি অবস্থা বা থামার একটিতে যায়। কয়টি আলাদা নিয়মের টেবিল?

  • 12
  • 48
  • 4096
  • 20,736

Church–Turing thesis-কে “thesis” বলা হয়, উপপাদ্য নয়। কেন?

  • কারণ এটি মিথ্যা প্রমাণিত হয়েছে, তবু ব্যবহার হয়
  • কারণ এটি একটি অনানুষ্ঠানিক ধারণাকে একটি গাণিতিক সংজ্ঞার সঙ্গে মেলায়
  • কারণ quantum computer এটি ভেঙে দিয়েছে
  • কারণ multi-tape যন্ত্র বেশি ক্ষমতাশালী

A undecidable বলে জানা, আর একটি গণনাযোগ্য f দিয়ে A ≤m B (x ∈ A ⇔ f(x) ∈ B) দেখানো হলো। কী সিদ্ধান্ত নেওয়া যায়?

  • B decidable
  • A আসলে decidable
  • B undecidable
  • কিছুই বলা যায় না

শব্দকোষ

লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:

মনে রাখুন

  1. যন্ত্র: M = (Q, Σ, Γ, δ, q0, qacc, qrej); configuration u[q]v; ফল তিন রকম: গ্রহণ, বর্জন, চিরকাল চলা।
  2. নকশা: increment-এ n + k + 2 ধাপ; aⁿbⁿcⁿ-এ দাগ দিয়ে কাটা, O(n2) ধাপ; সঠিকতা invariant দিয়ে প্রমাণ।
  3. Thesis আর সমতা: Church–Turing একটি thesis; multi-tape (O(t2)) আর nondeterministic যন্ত্র ক্ষমতায় সমান; universal machine যন্ত্রকে ডেটা হিসেবে চালায়।
  4. সীমা: যন্ত্র countable, language uncountable; decidable ⇔ L আর L̄ recognizable; HALT recognizable কিন্তু undecidable, complement recognizable নয়।
  5. ছড়িয়ে পড়া: জানা কঠিন A ≤m নতুন B; Rice: language-এর অতুচ্ছ ধর্ম undecidable; busy beaver গণনাযোগ্য নয়; decidable-এর ভেতরে P, NP আর Cook–Levin-এর উপপাদ্য।

পরের পর্বে: পর্ব ৭৬ “Ramsey theory আর extremal combinatorics-এর পরিচয়”: যথেষ্ট বড় যেকোনো কাঠামোয় শৃঙ্খলা অনিবার্য কেন, R(3, 3) = 6 থেকে Ramsey-র সাধারণ সীমা, triangle ছাড়া graph-এ সর্বোচ্চ edge-এর Mantel-এর উপপাদ্য, আর Sperner-এর উপপাদ্যে সবচেয়ে বড় antichain-এর মাপ।

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

এই পর্বটি শেয়ার করুন:
এই পর্বে ভুল পেয়েছেন? জানান