পাঠ ৩৫ · ৫৬-এর মধ্যে · মডিউল ৮

টুরিং মেশিনের ভ্যারিয়েন্ট — মাল্টি-টেপ ও মাল্টি-ট্র্যাক

Variants of Turing machines — multi-tape & multi-track
৮ মিনিট পড়া উচ্চ · Advanced Python কোডসহ সম্পূর্ণ বাংলায়

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

  • মাল্টি-টেপ ও মাল্টি-ট্র্যাক TM-এর ফরমাল সংজ্ঞা এবং তাদের মধ্যকার পার্থক্য
  • মাল্টি-টেপ থেকে সিঙ্গল-টেপ সিমুলেশনের মাল্টি-ট্র্যাক এনকোডিং কৌশল
  • কেন এই ইকুইভ্যালেন্স decidability সংরক্ষণ করে কিন্তু ঠিক সময় (running time) নয়
  • একটি জেনুইন 2-টেপ TM ক্লাস, এবং সেটিকে সিঙ্গল টেপে সিমুলেট করার কোড

১ · মাল্টি-টেপ TM

একটি মাল্টি-টেপ TM-এ একাধিক টেপ থাকে, প্রতিটির নিজস্ব স্বাধীন হেড — একটিমাত্র ট্রানজিশন ফাংশন সব হেডের নিচের সিম্বল একসাথে পড়ে এবং প্রতিটি হেডকে স্বাধীনভাবে সরাতে পারে। এটি ডিজাইন করা অনেক বেশি সুবিধাজনক — যেমন একটি টেপ ইনপুটের জন্য, আরেকটি স্ক্র্যাচ স্পেসের জন্য রাখা যায় — L34-এর ww উদাহরণে যে জটিল a/b-ট্যাগিং কৌশল লাগত, দুই টেপ থাকলে সেটি অনেক সহজ হয়ে যেত (প্রথমার্ধ একটি টেপে, দ্বিতীয়ার্ধ আরেকটিতে রেখে সরাসরি তুলনা করা যেত)।

২ · মাল্টি-ট্র্যাক TM — একটি ভিন্ন ধারণা

মাল্টি-টেপের সাথে গুলিয়ে ফেলবেন না — একটি মাল্টি-ট্র্যাক TM-এ টেপ আসলে একটিই, কিন্তু প্রতিটি টেপ-পজিশন একটি সিম্বলের বদলে একটি টাপল ধরে রাখে (যেমন $(a, b)$ — কনসেপচুয়ালি একই অবস্থানে "স্তুপীকৃত" একাধিক ট্র্যাক)। এটি genuinely উপযোগী — যেমন কোনো পজিশন "চিহ্নিত" কিনা তা মনে রাখতে একটি আলাদা ফিজিক্যাল টেপ ছাড়াই একটি অতিরিক্ত ট্র্যাক ব্যবহার করা যায়।

মাল্টি-টেপ — ২টি আলাদা টেপ প্রতিটির নিজস্ব স্বাধীন হেড মাল্টি-ট্র্যাক — ১টি টেপ প্রতি সেলে (sym1, sym2) টাপল সিঙ্গল-টেপ সিমুলেশন মাল্টি-ট্র্যাক এনকোডিং + হেড-মার্কার প্রতিটি সিমুলেটেড ধাপে সব হেড-মার্কার স্ক্যান করতে হয় -- পলিনোমিয়াল স্লোডাউন, decidability অক্ষত (M10 ফোরশ্যাডো)
মাল্টি-টেপ ও মাল্টি-ট্র্যাক দুটি ভিন্ন ধারণা হলেও, উভয়ই একটি সিঙ্গল-টেপ TM দিয়ে সিমুলেট করা যায় — মাল্টি-ট্র্যাক এনকোডিং কৌশল ব্যবহার করে।

৩ · ইকুইভ্যালেন্স থিওরেম — সুবিধা বাড়ে, ক্ষমতা বাড়ে না

এই কোর্সের একটি বারবার-ফিরে-আসা প্যাটার্ন (M2/L08-এর NFA-DFA থিওরেম, M2/L11-এর ক্লিনির থিওরেমের সরাসরি সমান্তরাল): প্রতিটি মাল্টি-টেপ (বা মাল্টি-ট্র্যাক) TM-এর একটি সমতুল্য সিঙ্গল-টেপ TM আছে। কনস্ট্রাকশন আইডিয়া: $k$টি টেপকে একটিমাত্র টেপে মাল্টি-ট্র্যাক এনকোডিং দিয়ে সিমুলেট করা হয় — $k$টি ট্র্যাক (প্রতিটি সিমুলেটেড টেপের জন্য একটি), প্লাস একটি মার্কার-ট্র্যাক যা প্রতিটি সিমুলেটেড হেডের বর্তমান অবস্থান নির্দেশ করে। মাল্টি-টেপ মেশিনের একটি ধাপ সিমুলেট করতে সিঙ্গল-টেপ মেশিনকে $k$টি হেড-মার্কার পজিশন স্ক্যান করে খুঁজে বের করতে হয়।

গুরুত্বপূর্ণ nuance — decidability সংরক্ষিত, কিন্তু সময় নয়

এই স্ক্যানিং একটি পলিনোমিয়াল স্লোডাউন তৈরি করে — এই ইকুইভ্যালেন্স প্রমাণ করে যে সিঙ্গল-টেপ ও মাল্টি-টেপ TM একই ভাষা ডিসাইড করে (কম্পিউটেবিলিটি থিওরির জন্য এটুকুই যথেষ্ট, যেহেতু এটি শুধু হল্টিং নিয়ে ভাবে, গতি নিয়ে নয়), কিন্তু ঠিক একই সময়ে নয় — এটি M10-এর কমপ্লেক্সিটি থিওরির জন্য একটি গুরুত্বপূর্ণ nuance, যেখানে গতিও গুরুত্বপূর্ণ হয়ে ওঠে।

৪ · কোড — একটি জেনুইন 2-টেপ TM ও তার সিঙ্গল-টেপ সিমুলেশন

নিচে একটি সত্যিকারের 2-টেপ TM — একটি স্ট্রিং কপি করার কাজে (তেপ ১ থেকে পড়ে তেপ ২-তে লেখে, একটিমাত্র পাসে, দুই টেপ থাকায় স্বাভাবিকভাবেই সহজ একটি কাজ)। এরপর সেই একই মেশিনকে একটি সিঙ্গল-টেপে সিমুলেট করা হয়েছে — প্রতিটি টেপ-পজিশনে (track1_symbol, track2_symbol) জোড় রাখা হয়, এবং প্রতিটি সিমুলেটেড ধাপে উভয় হেড-মার্কার টেপ জুড়ে স্ক্যান করে খুঁজে বের করা হয় (কোনো শর্টকাট ছাড়াই)।

Python
B = '_'

class TwoTapeTM:
    """জেনুইন 2-টেপ TM -- দুটি স্বাধীন টেপ-ডিকশনারি, দুটি স্বাধীন হেড,
    একটিমাত্র ট্রানজিশন ফাংশন একসাথে দুটোই পড়ে/লেখে/সরায়।"""
    def __init__(self, trans, start, accept, reject):
        self.trans = trans   # (state, sym1, sym2) -> (state, w1, w2, move1, move2)
        self.start, self.accept, self.reject = start, accept, reject

    def run(self, input_string, max_steps=5000):
        tape1 = {i: c for i, c in enumerate(input_string)}
        tape2 = {}
        h1 = h2 = 0
        state, steps = self.start, 0
        while steps < max_steps:
            if state == self.accept:
                return self._read(tape2), steps
            if state == self.reject:
                return None, steps
            key = (state, tape1.get(h1, B), tape2.get(h2, B))
            if key not in self.trans:
                return None, steps
            ns, w1, w2, m1, m2 = self.trans[key]
            tape1[h1], tape2[h2] = w1, w2
            h1 += 1 if m1 == 'R' else (-1 if m1 == 'L' else 0)
            h2 += 1 if m2 == 'R' else (-1 if m2 == 'L' else 0)
            state, steps = ns, steps + 1
        return "TIMEOUT", steps

    @staticmethod
    def _read(tape):
        if not tape: return ""
        lo, hi = min(tape), max(tape)
        return ''.join(tape.get(i, B) for i in range(lo, hi + 1)).strip(B)

def build_copy_machine():                 # তেপ ১ -> তেপ ২, একটিমাত্র পাসে কপি
    t = {}
    for a in ('0', '1'):
        t[('q0', a, B)] = ('q0', a, a, 'R', 'R')
    t[('q0', B, B)] = ('accept', B, B, 'R', 'R')
    return TwoTapeTM(t, 'q0', 'accept', 'reject')

class SingleTapeSimulator:
    """মাল্টি-ট্র্যাক এনকোডিং দিয়ে 2-টেপ TM-কে সিঙ্গল টেপে সিমুলেট করে --
    প্রতিটি ধাপে উভয় হেড-মার্কার আসলেই স্ক্যান করে খুঁজে বের করা হয়, কোনো শর্টকাট নেই।"""
    def __init__(self, two_tape_tm):
        self.tm = two_tape_tm

    def run(self, input_string, max_steps=20000):
        track1 = {i: c for i, c in enumerate(input_string)}
        track2 = {}
        marker1 = marker2 = 0
        state, steps, scans = self.tm.start, 0, 0
        while steps < max_steps:
            if state == self.tm.accept:
                return TwoTapeTM._read(track2), steps, scans
            if state == self.tm.reject:
                return None, steps, scans

            # -- সিঙ্গল-টেপ এনকোডিংয়ে হেড-মার্কার খুঁজতে টেপ জুড়ে স্ক্যান --
            lo = min([0, marker1, marker2] + list(track1) + list(track2))
            hi = max([0, marker1, marker2] + list(track1) + list(track2))
            for pos in range(lo, hi + 1):
                scans += 1     # প্রতিটি সিমুলেটেড ধাপে এই স্ক্যান-খরচ যোগ হয়

            s1, s2 = track1.get(marker1, B), track2.get(marker2, B)
            key = (state, s1, s2)
            if key not in self.tm.trans:
                return None, steps, scans
            ns, w1, w2, m1, m2 = self.tm.trans[key]
            track1[marker1], track2[marker2] = w1, w2
            marker1 += 1 if m1 == 'R' else (-1 if m1 == 'L' else 0)
            marker2 += 1 if m2 == 'R' else (-1 if m2 == 'L' else 0)
            state, steps = ns, steps + 1
        return "TIMEOUT", steps, scans

two_tape = build_copy_machine()
sim = SingleTapeSimulator(build_copy_machine())

for s in ["", "0", "0101", "111000", "0110110"]:
    out_native, steps_native = two_tape.run(s)
    out_sim, steps_sim, scans_sim = sim.run(s)
    match = "IDENTICAL" if out_native == out_sim == s else "MISMATCH"
    print(f"{s!r:12s} native={out_native!r:12s}(steps={steps_native:2d})  "
          f"sim={out_sim!r:12s}(steps={steps_sim:2d}, স্ক্যান={scans_sim:3d})  [{match}]")

    
হাতে-যাচাই: প্রতিটি টেস্ট স্ট্রিং-এর জন্য নেটিভ 2-টেপ মেশিন ও সিঙ্গল-টেপ সিমুলেশন — দুটোই একই কপি করা ফলাফল দেয় (এবং দুটোই মূল ইনপুটের সাথে মিলে যায়, যেমনটা কপি-মেশিনের কাছে প্রত্যাশিত)। লক্ষ্য করুন "স্ক্যান" সংখ্যাটি ধাপ সংখ্যার চেয়ে ঢের দ্রুত বাড়ছে (দীর্ঘ স্ট্রিং-এ) — এটিই পলিনোমিয়াল স্লোডাউনের একটি concrete, সংখ্যায়িত উদাহরণ।

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

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

প্র ০১ মাল্টি-টেপ ও মাল্টি-ট্র্যাক — এই দুটি ধারণা কীভাবে মৌলিকভাবে আলাদা?

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

প্র ০২ "এই ইকুইভ্যালেন্স decidability সংরক্ষণ করে কিন্তু সময় নয়" — এই বাক্যটির অর্থ ঠিক কী?

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

প্র ০৩ উপরের কোডের কপি-মেশিনে দুটি হেডই সবসময় একসাথে ডানে সরে (লকস্টেপে) — যদি সাধারণভাবে দুটি হেড ভিন্ন গতিতে সরত, তাহলে সিমুলেশনের "স্ক্যান" ধাপে কী পরিবর্তন হতো?

মূল লজিকটি অপরিবর্তিতই থাকত — প্রতিটি সিমুলেটেড ধাপে সিঙ্গল-টেপ মেশিনকে এখনও উভয় হেড-মার্কারের বর্তমান অবস্থান খুঁজে বের করতেই হতো, স্ক্যান করেই। পার্থক্য শুধু এটুকু যে দুই মার্কারের মধ্যবর্তী দূরত্ব (আর তাই প্রতি ধাপে স্ক্যানের দৈর্ঘ্য) সময়ের সাথে বাড়তে পারত, যদি হেডগুলো একে অপরের থেকে ক্রমশ দূরে সরে যায় — কিন্তু কৌশলটি (মার্কার-স্ক্যানিং) সাধারণ যেকোনো মাল্টি-টেপ TM-এর জন্যই সমানভাবে কাজ করে, শুধু এই কপি উদাহরণে হেডগুলো লকস্টেপে থাকায় সেটি সবচেয়ে সহজ কেস হয়ে দাঁড়িয়েছে।

অনুশীলন

  1. চিন্তা করুন: L34-এর ww ভাষার TM-টিকে যদি একটি 2-টেপ মেশিন হিসেবে পুনরায় ডিজাইন করেন (একটি টেপে প্রথমার্ধ, আরেকটিতে দ্বিতীয়ার্ধ), তাহলে কি L34-এর মার্কিং কৌশল (a0/a1/b0/b1/X0/X1) এখনও দরকার হবে? কেন বা কেন নয়?

    অনেকটাই দরকার হবে না — মিডপয়েন্ট খুঁজে বের করার জটিল দুই-দিক-থেকে-ক্রলিং ধাপটি আর প্রয়োজন হবে না, কারণ ইনপুট স্ট্রিং প্রথমেই দুই টেপে ভাগ করে রাখা যায় (একটি প্রাথমিক পাস দিয়ে প্রথমার্ধ তেপ ১-এ, দ্বিতীয়ার্ধ তেপ ২-এ), তারপর দুই টেপের হেড একসাথে ডানে সরিয়ে সরাসরি তুলনা করা যায় — এটি ঠিক এই পাঠের মূল বার্তা: মাল্টি-টেপ থাকলে ডিজাইন অনেক সহজ হয়, যদিও চূড়ান্ত ক্ষমতা একই থাকে।

  2. পরীক্ষা করুন: কোডে "1"*12 (১২টি 1) টেস্ট করে দেখুন scans_sim সংখ্যাটি স্ট্রিং-এর দৈর্ঘ্যের তুলনায় কীভাবে বাড়ে (আনুমানিকভাবে গুণমান হিসাব করুন — এটি linear, quadratic, নাকি অন্য কিছু?)।

    এটি মোটামুটি quadratic (দৈর্ঘ্যের বর্গের সমানুপাতিক) — কারণ প্রতিটি ধাপে স্ক্যানের দৈর্ঘ্য (মার্কার ১ থেকে মার্কার ২-এর দূরত্ব) ধাপের সাথে সাথে বাড়তে থাকে (যেহেতু উভয় মার্কার একসাথে ডানে সরছে, ধাপ $i$-এ স্ক্যানের দৈর্ঘ্য প্রায় $i$), আর মোট ধাপ সংখ্যাও ইনপুটের দৈর্ঘ্যের সমানুপাতিক — তাই মোট স্ক্যান-খরচ $O(n) \times O(n) = O(n^2)$ — এটিই এই পাঠে বলা "পলিনোমিয়াল স্লোডাউন"-এর একটি concrete সংখ্যায়িত উদাহরণ।

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

আগের পাঠ
টুরিং মেশিন ডিজাইন করা — worked examples