مقدمة في علوم الحاسوب النظرية › الشمولية وعدم القابلية للاحتساب 11 / 26 السابق التالي

الشمولية وغياب قابلية الحساب {#chapcomputable }

الشمولية وغياب قابلية الحساب

  • الآلة/البرنامج الشامل (universal machine/program) - «برنامج واحد يحكمها جميعًا»
  • نتيجة جوهرية في علوم الحاسوب وفي الرياضيات: وجود دوال غير قابلة للحساب.
  • مشكلة التوقّف (halting problem): المثال المرجعي لدالة غير قابلة للحساب.
  • مقدّمة إلى تقنية الاختزال_ (reductions).
  • نظرية رايس (Rice's Theorem): «أداة فوقية» (meta tool) لنتائج غياب قابلية الحساب، ونقطة انطلاق لكثير من الأبحاث في المترجَمات (compilers) ولغات البرمجة والتحقق البرمجي (software verification).

"دالة متغيّر كميّ هي تعبير تحليلي مؤلَّف بأي طريقة كانت من المتغيّر الكميّ والأعداد أو الكميات الثابتة."، ليونارد أويلر، 1748.

"أهمية الآلة الشاملة واضحة. فنحن لا نحتاج إلى ما لا نهاية من الآلات المختلفة التي تؤدّي مختلف الأعمال. ... فالمسألة الهندسية في إنتاج آلات مختلفة لأعمال مختلفة تُستبدل بالعمل المكتبي في «برمجة» الآلة الشاملة", آلان تورينج، 1948

من أبرز النتائج التي أثبتناها للدوائر البوليانية (أو بما يكافئها، برامج الأسطر المستقيمة) هو مفهوم الشمولية: هناك دائرة واحدة تستطيع تقييم كل الدوائر الأخرى. لكن هذه النتيجة جاءت مصحوبة بتحفّظ مهم. فظتقييم دائرة ذات ss بوابة يحتاج الدائرة الشاملة إلى عدد من البوابات أكبر من ss. ويبيّن الأمر أن النماذج المنتظمة (uniform) مثل آلات تورينج أو برامج NAND-TM تتيح لنا «الخروج من هذه الحلقة» والوصول إلى آلة تورينج شاملة (universal Turing machine) UU بالشكل الحقيقي، قادرة على تقييم كل الآلات الأخرى، بما في ذلك آلات أكثر تعقيدًا (مثلًا ذات حالات أكثر) من UU نفسها. (وبالمثل، يوجد برنامج NAND-TM شامل U′U' يستطيع تقييم كل برامج NAND-TM، بما في ذلك برامج تحوي أسطرًا أكثر من U′U'.)

ليس في الأمر مبالغة القول إن وجود مثل هذا البرنامج/الآلة الشاملة يكمن وراء ثورة تقنية المعلومات التي بدأت في النصف الثاني من القرن العشرين (ولا تزال مستمرة). حتى تلك الحقبة التاريخية، كان الناس يصنعون أجهزة حساب متخصصة مختلفة مثل العدّاد (abacus) والمسطرة الانزلاقية (slide ruler) وآلات تحسب متسلسلات مثلثية مختلفة. لكن كما لاحظ تورينج (وربما كان هو من رأى نتائج الشمولية بأوضح صورة)، فإن الحاسوب العام الغرض (general purpose computer) أقوى بكثير. فمتى ما بنينا جهازًا يستطيع حساب الدالة الشاملة الواحدة، أملكنا القدرةَ عبر البرمجيات على توسيعه لينفّذ عمليات حسابية اعتباطية. فمثلًا، إذا أردنا محاكاة آلة تورينج جديدة MM، فلا نحتاج إلى بناء آلة فيزيائية جديدة، بل يمكننا تمثيل MM كسلسلة (أي باستخدام شيفرة (code)) ثم إدخال MM إلى الآلة الشاملة UU.

إلى جانب التطبيقات العملية، فإن وجود خوارزمية شاملة له أيضًا نتائج نظرية مدهشة، وخصوصًا يمكن استخدامه لإثبات وجود دوال غير قابلة للحساب، وهو ما ينقض حدس الرياضيين عبر القرون من أويلر إلى هيلبرت. في هذا الفصل سنبرهن على وجود البرنامج الشامل، وسنبيّن أيضًا آثاره على غياب قابلية الحساب، انظر الشكل التوضيحي

في هذا الفصل سنرى نتيجتين من أهم النتائج في علوم الحاسوب:

  1. وجود آلة تورينج شاملة: خوارزمية واحدة تستطيع تقييم كل الخوارزميات الأخرى،

  2. وجود دوال غير قابلة للحساب: دوال (منها «مشكلة التوقّف» (Halting problem) الشهيرة) لا يمكن حسابها بأي خوارزمية.

وفي الطريق، سنطوّر تقنية الاختزال_ (reductions) بوصفها طريقة لإثبات صعوبة حساب دالة. فنّ_الاختزال__ (reduction) يمنحنا طريقة لحساب دالة معيّنة بالاعتماد على «التفكير بالأمنيات» (wishful thinking) وعلى افتراض أن دالة أخرى قابلة للحساب. والاختزال مستخدَم بالطبع على نطاق واسع في البرمجة — فنحن كثيرًا ما نجد خوارزمية لمهمة ما باستخدام مهمة أخرى كإجراء فرعي «صندوق أسود» (black box). غير أننا سنستخدمه في الاتجاه «العكس» (contra positive): فبدلًا من استخدام الاختزال لإثبات أن المهمة الأولى «سهلة»، نستخدمه لإثبات أن المهمة الأخيرة «صعبة». لا تقلق إن وجدت هذا محيّرًا — فالاختزال محيّر فعلاً في البداية — لكنه يمكن إتقانه مع الوقت والممارسة.

/images/introtcs/lec_08_uncomputability-1.webp

الشمولية أو المُقيِّم المُنداخي (meta-circular)

سنبدأ بإثبات وجود آلة تورينج شاملة. إنها آلة تورينج واحدة UU تستطيع تقييم آلات تورينج اعتباطية MM على مدخلات اعتباطية xx، بما في ذلك آلات MM التي قد يكون لها حالات أكثر وأبجدية أكبر من UU نفسها. وبالتحديد، يمكن حتى استخدام UU في تقييم نفسها! وسنرى هذا المفهوم، وهو الإحالة إلى الذات (self reference)، يظهر مرارًا وتكرارًا في هذا الكتاب، وأنه يقود إلى عدة ظواهر مخالفة للحدس في الحوسبة.

مبرهنة — آلة تورينج الشاملة

توجد آلة تورينج UU بحيث إن كان MM سلسلة تمثّل آلة تورينج، و x∈{0,1}∗x\in \{0,1\}^*، فإن U(M,x)=M(x)U(M,x)=M(x).

بمعنى آخر، إذا توقّفت الآلة MM عند xx وأخرجت قيمة y∈{0,1}∗y\in \{0,1\}^* فإن U(M,x)=yU(M,x)=y، وإذا لم تتوقّف MM عند xx (أي M(x)=⊥M(x)=\bot) فإن U(M,x)=⊥U(M,x)=\bot.

الآلة التورينجية الكامنة (Universal Turing Machine) هي آلة تورينج واحدة  تُقيّم، عند إعطائها وصف آلة تورينج اعتباطية  (كنصٍّ) ومدخلًا ، مخرج  على . وبالمقابل للدائرة الكامنة المُصوَّرة في universalcircfig، قد تكون الآلة  أعقد بكثير (مثلًا: حالاتٌ أكثر أو رموزُ حقل رموز شريطٍ أكثر) من .

هناك خوارزمية «شاملة» تستطيع تقييم خوارزميات اعتباطية على مدخلات اعتباطية.

متى ما فهمت ما تقوله هذه النظرية، لا يكون البرهان عليها صعبًا إلى هذا الحد. فالبرنامج المرغوب UU هو مفسِّر (interpreter) لآلات تورينج. أي إن UU يأخذ تمثيلًا للآلة MM (فكّر فيه بوصفه شيفرة مصدرية) ومدخلًا xx، ثم يحتاج إلى محاكاة تنفيذ MM على xx.

تخيّل كيف تكتب UU في لغتك البرمجية المفضّلة. أولًا، ستحتاج إلى اختيار مخطّط تمثيل لـ MM. فمثلًا يمكنك استعمال مصفوفة أو قاموس (dictionary) لترميز دالة الانتقال MM (transition function). ثم تستعمل بنية بيانات، مثل قائمة، لتخزين محتويات شريط MM (tape). الآن تستطيع محاكاة MM خطوة بخطوة، مُحدِّثًا بنية البيانات أثناء سير العملية. سيستمر المفسِّر في المحاكاة حتى تتوقّف الآلة.

ومتى ما فعلت ذلك، يمكن ترجمة هذا المفسِّر من لغتك البرمجية المفضّلة إلى آلة تورينج تمامًا كما رأينا في نماذج حوسبة مكافئة. والنتيجة النهائية هي ما يُعرف بـ«المُقيِّم المنداخي» (meta-circular evaluator): وهو مفسِّر لغة برمجية داخل اللغة نفسها. وهذا مفهوم له تاريخ طويل في علوم الحاسوب يبدأ من آلة تورينج الشاملة الأصلية. وانظر أيضًا الشكل التوضيحي.

إثبات وجود آلة تورينج شاملة

لكي نبرهن على مبرهنة — آلة تورينج الشاملة (بل وحتى لصياغتها بدقّة)، نحتاج إلى تثبيت تمثيل ما لآلات تورينج بوصفه سلاسل. أحد الخيارات الممكنة لهذا التمثيل هو استعمال التكافؤ بين آلات تورينج وبرامج NAND-TM، وبالتالي تمثيل آلة تورينج MM باستعمال ترميز ASCII لشيفرة المصدر لبرنامج NAND-TM المقابل PP. غير أننا سنستعمل ترميزًا أكثر مباشرة.

تعريف — التمثيل السلاسل لآلة تورينج

ليكن MM آلة تورينج ذات kk حالة وأبجدية Σ={σ0,…,σℓ−1}\Sigma = \{ \sigma_0,\ldots,\sigma_{\ell-1}\} من حجم ℓ\ell (ونستخدم الاصطلاح σ0=0\sigma_0 = 0، σ1=1\sigma_1 = 1، σ2=∅\sigma_2 = \varnothing، σ3=▹\sigma_3=\triangleright). نمثّل MM بالثلاثية (k,ℓ,T)(k,\ell,T) حيث TT هو جدول قيم δM\delta_M:

T=(δM(0,σ0),δM(0,σ1),…,δM(k−1,σℓ−1))  ,T = \left(\delta_M(0,\sigma_0),\delta_M(0,\sigma_1),\ldots,\delta_M(k-1,\sigma_{\ell-1})\right) \;,

حيث كل قيمة δM(s,σ)\delta_M(s,\sigma) هي ثلاثية (s′,σ′,d)(s',\sigma',d) مع s′∈[k]s'\in [k]، σ′∈Σ\sigma'\in \Sigma و dd عددًا {0,1,2,3}\{0,1,2,3 \} يرمز لأحد {L,R,S,H}\{ \mathsf{L},\mathsf{R},\mathsf{S},\mathsf{H} \}. وعليه، تُرمَّز هذه الآلة MM بقائمة من 2+3k⋅ℓ2 + 3k\cdot\ell عددًا طبيعيًا. ويُستنتج التمثيل السلاسل لـ MM بلصق تمثيلٍ بادئ-حرّ (prefix free) لهذه الأعداد جميعها. وإذا لم تكن السلسلة α∈{0,1}∗\alpha \in \{0,1\}^* تمثّل قائمة أعداد من الشكل أعلاه، فإننا نتعامل معها وكأنها تمثّل آلة تورينج تافهة ذات حالة واحدة تتوقّف فورًا عند كل مدخل.

ملاحظة — أبرز ما ينبغي تذكّره عن التمثيل

تفاصيل مخطّط تمثيل آلات تورينج بوصفها سلاسل لا أهمية تقريبًا لكل التطبيقات. كل ما تحتاج إلى تذكّره هو النقاط التالية:

  1. يمكننا تمثيل كل آلة تورينج بسلسلة.

  2. معطى التمثيل السلاسل لآلة تورينج MM ومدخل xx، يمكننا محاكاة تنفيذ MM على المدخل xx. (وهذا هو محتوى مبرهنة — آلة تورينج الشاملة.)

وثمّة مسألة بسيطة إضافية وهي أننا نفترض، من أجل الراحة، أن كل سلسلة تمثّل بعضَ آلة تورينج. ومن السهل جدًا ضمان ذلك بمجرد تعيين السلاسل التي لا تمثّل آلة تورينج إلى آلة تافهة ثابتة. ولهذا الافتراض أهمية ضئيلة، لكنه يجعل صياغة بعض النتائج (مثل نظرية رايس: مبرهنة — نظرية رايس) أقل إزعاجًا قليلًا.

باستعمال هذا التمثيل، يمكننا البرهان رسميًا على مبرهنة — آلة تورينج الشاملة.

برهان

سنكتفي بأن نلمّح إلى البرهان، مبرزين الأفكار الرئيسة. أولًا، نلاحظ أننا نستطيع بسهولة كتابة برنامج Python يُدخل تمثيلًا (k,ℓ,T)(k,\ell,T) لآلة تورينج MM ومدخلًا xx، فيقيّم MM على XX. وفيما يلي شيفرة هذا البرنامج لأجل الوضوح (concreteness)، مع أنك حرّ في تخطّيها إن لم تكن على ألفة بـ Python (أو لم تكن مهتمًا بها):

# constants
def EVAL(δ,x):
    '''Evaluate TM given by transition table δ
    on input x'''
    Tape = ["▷"] + [a for a in x]
    i = 0; s = 0 # i = head pos, s = state
    while True:
        s, Tape[i], d = δ[(s,Tape[i])]
        if d == "H": break
        if d == "L": i = max(i-1,0)
        if d == "R": i += 1
        if i>= len(Tape): Tape.append('Φ')

    j = 1; Y = [] # produce output
    while Tape[j] != 'Φ':
        Y.append(Tape[j])
        j += 1
    return Y

عند إدخال جدول انتقال δ\delta، يحاكي هذا البرنامج الآلة MM المقابلة خطوة بخطوة، محافظًا في كل لحظة على الشرط الثابت (invariant) أن المصفوفة Tape تحوي محتويات شريط MM، وأن المتغيّر s يحوي حالة MM الحالية.

ما سبق لا يثبت النظرية كما صيغت، لأننا نحتاج إلى عرض آلة تورينج تحسب EVALEVAL لا برنامج Python. وبجهد كافٍ، يمكننا ترجمة شيفرة Python هذه سطرًا بسطر إلى آلة تورينج. غير أنه لإثبات النظرية لا نحتاج إلى ذلك، بل يمكننا استعمال نموذج «كُلُّ الكعكة وتأكلها أيضًا» (eat the cake and have it too). أي إننا، بينما نحتاج إلى تقييم آلة تورينج، مُسموح لنا في كتابة شيفرة المفسِّر باستعمال نموذج أغنى مثل NAND-RAM، إذ إنه مكافئ في القدرة لآلات تورينج بحسب مبرهنة — آلات تورينج (أي برامج NAND-TM) وآلات RAM (أي برامج NAND-RAM) متكافئة.

ترجمة شيفرة Python أعلاه إلى NAND-RAM أمر مباشر فعلًا. القضية الوحيدة أن NAND-RAM لا تملك بنية بيانات القاموس (dictionary) مدمجة، وقد استعملناها أعلاه لتخزين دالة الانتقال δ. غير أننا يمكننا تمثيل قاموس DD من الشكل {key0:val0,…,keym−1:valm−1}\{ key_0:val_0 , \ldots, key_{m-1}:val_{m-1} \} كقائمة من الأزواج. ولحساب D[k]D[k] نمرّ على جميع الأزواج حتى نجد واحدًا من الشكل (k,v)(k,v)، وعندها نُعيد vv. وبالمثل نمرّ على القائمة لتحديث القاموس بقيمة جديدة، إمّا بتعديله أو بإلحاق الزوج (key,val)(key,val) في النهاية.

ملاحظة — كفاءة المحاكاة

الحجّة في برهان مبرهنة — آلة تورينج الشاملة طريقة غير فَعّالة جدًا في تنفيذ بنية بيانات القاموس عمليًا، لكنها تكفي غرض إثبات النظرية. فقراءة قاموس من mm قيمة والكتابة فيه في هذا التنفيذ تاخذ Ω(m)\Omega(m) خطوة، غير أنه في الواقع من الممكن فعل ذلك في O(log⁡m)O(\log m) خطوة باستعمال بنية بيانات شجرة البحث (search tree)، أو حتى في O(1)O(1) (للحالات «النموذجية») باستعمال جدول تجزئة (hash table). وتطابق NAND-RAM وآلات RAM بنية الحواسيب الإلكترونية الحديثة، ولذلك يمكننا تنفيذ جداول التجزئة وأشجار البحث في NAND-RAM تمامًا كما تُنفَّذ في لغات البرمجة الأخرى.

يبني الإنشاء السابق آلة تورينج شاملة ذات عدد حالات كبير جدًا. غير أنه، وبما أن آلات تورينج الشاملة ذات أهمية فلسفية وتقنية بالغة، فقد حاول الباحثون إيجاد أصغر آلات تورينج شاملة ممكنة، انظر ملاحظات مرجعية.

آثار الشمولية (نقاش)

أ) مثالٌ أنيق بخاصّة على «المُقيِّم فائق الدائرية» (meta-circular evaluator) يأتي من ورقة جون ماكارثي سنة 1960، حيث عرَّف لغة برمجة Lisp وعرض دالةً Lisp تُقيّم برنامج Lisp اعتباطيًا (انظر ما سبق). ولم تكن Lisp مُنوَّطة في الأصل كلغة برمجة عملية، وكان هذا المثال يعني مجرّد إيضاحٍ لكون الدالة الكامنة في Lisp أنيق من الآلة التورينجية الكامنة. وكان طالب الدراسات العليا لدى ماكارثي، ستيفن راسل، هو من اقترح أنّها قابلة للتنفيذ. وكما استذكر ماكارثي لاحقًا: «قلت له: هيهات، أنت تخلط بين النظرية والتطبيق؛ هذه الدالة eval مُنوَّطة للقراءة لا للحساب. لكنّه مضى ونفّذها. أيّ أنّه ترجم eval في ورقتي إلى شيفرة آلة IBM 704، مُصلحًا علّة، ثمّ أعلنها مُفسِّر Lisp، وهي كذلك بالفعل». ب) برنامج C ذاتي التكرار من المقالة الكلاسيكية لطومسون [@thompson1984reflections].

هناك أكثر من آلة تورينج واحدة UU تستوفي شروط مبرهنة — آلة تورينج الشاملة، لكن وجود آلة واحدة فقط من هذا النوع يكوّن بالفعل أمرًا أساسيًا إلى حد بعيد، لنظرية علوم الحاسوب وتطبيقاتها العملية. أثر مبرهنة — آلة تورينج الشاملة يتجاوز نموذج آلات تورينج بعينه. لأننا نستطيع محاكاة كل آلة تورينج ببرنامج NAND-TM وبالعكس، فإن مبرهنة — آلة تورينج الشاملة يعني فورًا وجود برنامج NAND-TM شامل PUP_U بحيث PU(P,x)=P(x)P_U(P,x)=P(x) لكل برنامج NAND-TM PP. كما يمكننا أيضًا «المزج والمطابقة» بين النماذج. فمثلًا، بما أننا نستطيع محاكاة كل برنامج NAND-RAM بآلة تورينج، وكل آلة تورينج بحساب λ\lambda (lambda calculus)، فإن مبرهنة — آلة تورينج الشاملة يعني وجود تعبير λ\lambda ee بحيث لكل برنامج NAND-RAM PP ومدخل xx يُحقّق P(x)=yP(x)=y، فإن رمزنا (P,x)(P,x) على صورة تعبير λ\lambda ff (باستعمال ترميز السلاسل في حساب λ\lambda كقوائم من الأصفار والواحدات) فإن (e  f)(e\; f) يُقيَّم إلى ترميز لـ yy. وبشكل أعم، يمكننا القول إن لكل X\mathcal{X} و Y\mathcal{Y} في المجموعة {\{ آلات تورينج، آلات RAM، NAND-TM، NAND-RAM، حساب λ\lambda، JavaScript، Python، …\ldots }\} من النماذج المتكافئة تورينجيًا، يوجد برنامج/آلة في X\mathcal{X} يحسب الخرائط (P,x)↦P(x)(P,x) \mapsto P(x) لكل برنامج/آلة P∈YP \in \mathcal{Y}.

فكرة «البرنامج الشامل» ليست بالطبع محصورة في النظرية. فمثلًا تُستعمل مترجَمات (compilers) لغات البرمجة في أحيان كثيرة لترجمة نفسها، فضلًا عن ترجمة برامج أعقد من المترجم نفسه. (ومن الأمثلة المتطرفة لذلك مُترجم C المُموَّه (Obfuscated Tiny C Compiler) لفابريس بيلار، وهو برنامج C بطول 2048 بايت يستطيع ترجمة مجموعة كبيرة من لغة C، وبالذات يستطيع ترجمة نفسه.) وهذا أيضًا مرتبط بحقيقة أنه من الممكن كتابة برنامج يطبع شيفرته المصدرية الخاصة، انظر الشكل التوضيحي. وهناك آلات تورينج شاملة معروفة تتطلب عددًا صغيرًا جدًا من الحالات أو من رموز الأبجدية، وبالخصوص هناك آلة تورينج شاملة (بالنسبة إلى اختيار معيّن لتمثيل آلات تورينج بوصفها سلاسل) أبجديتها {▹,∅,0,1}\{ \triangleright, \varnothing, 0, 1 \} ولديها أقل من 2525 حالة (انظر ملاحظات مرجعية).

هل كل دالة قابلة للحساب؟

في مبرهنة — شمولية NAND رأينا أن برامج NAND-CIRC تستطيع حساب كل دالة منتهية f:{0,1}n→{0,1}f:\{0,1\}^n \rightarrow \{0,1\}. وعليه فإن التخمّن الطبيعي هو أن برامج NAND-TM (أو بما يكافئها، آلات تورينج) تستطيع حساب كل دالة لا نهائية F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\}. غير أن الأمر يتبيّن أنه غير صحيح. أي إن توجد دالة F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} غير قابلة للحساب!

وجود الدوال غير القابلة للحساب مدهش إلى حد كبير. فتصوّرنا الحدسي لـ«الدالة» (والتصوّر الذي كان لدى معظم الرياضيين حتى القرن العشرين) هو أن الدالة ff تعرّف طريقة ضمنية أو صريحة لحساب الخرج f(x)f(x) انطلاقًا من المدخل xx. وهكذا يبدو مفهوم «الدالة غير القابلة للحساب» متناقضًا في ذاته، لكن النظرية التالية تُظهر هذه الكائنات موجودة فعلًا:

مبرهنة — الدوال غير القابلة للحساب

توجد دالة F∗:{0,1}∗→{0,1}F^*:\{0,1\}^* \rightarrow \{0,1\} لا يمكن حسابها بأي آلة تورينج.

الفكرة وراء البرهان تتبع عن قرب برهان كانتور على أن الأعداد الحقيقية غير عدّية (مبرهنة — مبرهنة كانتور)، بل ويمكن في الواقع استخراج هذه النظرية إلى حد كبير من تلك النتيجة مباشرةً (انظر تمرين — ليست كل الدوال قابلة للحساب). غير أنه مفيد أن نرى البرهان المباشر. والفكرة هي إنشاء F∗F^* بطريقة تضمن أن كل آلة ممكنة MM ستفشل فعلًا في حساب F∗F^*. ونفعل ذلك بتعريف F∗(x)F^*(x) مساويًا للعدد 00 إذا كان xx يصف آلة تورينج MM تُحقّق M(x)=1M(x)=1، وتعريف F∗(x)=1F^*(x)=1 بغير ذلك. وبالإنشاء، إذا كانت MM أي آلة تورينج و xx هي السلسلة التي تصفها، فإن F∗(x)≠M(x)F^*(x) \neq M(x) وبالتالي فإن MM لا تحسب F∗F^*.

برهان

يتضح البرهان في الشكل التوضيحي. نبدأ بتعريف الدالة التالية G:{0,1}∗→{0,1}G:\{0,1\}^* \rightarrow \{0,1\}:

لكل سلسلة x∈{0,1}∗x\in\{0,1\}^*، إذا كانت xx تُحقِّق (1) xx تمثيلًا صالحًا لبعض آلة تورينج MM (وفق مخطّط التمثيل أعلاه) و (2) عند تنفيذ البرنامج MM على المدخل xx يتوقّف وينتج خرجًا، فإننا نعرّف G(x)G(x) بأنّها البت الأولى لهذا الخرج. بغير ذلك (أي إذا لم تكن xx تمثيلًا صالحًا لآلة تورينج، أو أن الآلة MxM_x لا تتوقّف أبدًا عند xx) فإننا نعرّف G(x)=0G(x)=0. ونعرّف F∗(x)=1−G(x)F^*(x) = 1 - G(x).

نطالب بأنه لا توجد آلة تورينج تحسب F∗F^*. والحق، لنفرض، طلبًا للتناقض، توجد آلة MM تحسب F∗F^*، وليكن xx السلسلة الثنائية التي تمثّل الآلة MM. من جهة، بما że بافتراضنا MM تحسب F∗F^*، فإن الآلة MM عند المدخل xx تتوقّف وتُخرج F∗(x)F^*(x). ومن جهة أخرى، تبعًا لتعريف F∗F^*، وبما أن xx هي تمثيل الآلة MM، F∗(x)=1−G(x)=1−M(x)F^*(x) = 1 - G(x) = 1 - M(x)، مما ينتج تناقضًا.

/images/introtcs/lec_08_uncomputability-2.webp

هناك بعض الدوال التي لا يمكن حسابها بواسطة أيّ خوارزمية.

توقّف وتأمّل

برهان مبرهنة — الدوال غير القابلة للحساب قصير لكنه دقيق. أقترح أن تتوقّف هنا وتعود لقراءته من جديد وتفكّر فيه — فهذا برهان يستحق القراءة مرّتين على الأقل إن لم تكن ثلاثًا أو أربعًا. فمن النادر أن تثبت بضعة أسطر من التفكير الرياضي حقيقةً عميقة الخطوات، أي أنّ هناك مسائل لا نستطيع ببساطة حلّها.

نوع الحجّة المستخدَمة لإثبات مبرهنة — الدوال غير القابلة للحساب يُعرف بـ_الحَجّ القطري_ (diagonalization)، إذ يمكن وصفه بأنه تعريف دالة بالاعتماد على مداخل القطر في جدول كما في الشكل التوضيحي. ويمكن التفكير في البرهان بوصفه نسخة لا نهائية من حجّة العدّ (counting) التي استعملناها لإثبات الحدّ الأدنى لبرامج NAND-CIRC في مبرهنة — حدٌّ أدنى من عدِّ الدوال. أي أننا نبيّن أنه من المستحيل حساب كل الدوال من {0,1}∗→{0,1}\{0,1\}^* \rightarrow \{0,1\} بآلات تورينج، لمجرّد أن هناك عددًا من هذه الدوال أكبر من عدد آلات تورينج.

وكما ذُكر في ملاحظة — الدوال مقابل اللغات، فإن كثيرًا من الكتب تستعمل مصطلح «اللغة» (language)، ومن ثمّ فإنها تسمّي مجموعة L⊆{0,1}∗L \subseteq \{0,1\}^* لغةً غير قابلة للقرار أو غير تكرارية (non-recursive) إذا كانت الدالة F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} التي تحقّق F(x)=1↔x∈LF(x)=1 \leftrightarrow x\in L غير قابلة للحساب.

مشكلة التوقّف

تبيّن مبرهنة — الدوال غير القابلة للحساب أن هناك بعضَ دالة لا يمكن حسابها. لكن هل هذه الدالة هي ما يعادل «الشجرة التي تسقط في الغابة دون أن يسمعها أحد»؟ أي إنها ربما دالة لا يريد أحد فعلًا حسابها. ويتبيّن أن هناك دوال غير قابلة للحساب طبيعية:

مبرهنة — عدم قابلية حساب دالة التوقّف

لتكن HALT:{0,1}∗→{0,1}HALT:\{0,1\}^* \rightarrow \{0,1\} الدالة التي لكل سلسلة M∈{0,1}∗M\in \{0,1\}^* يكون HALT(M,x)=1HALT(M,x)=1 إذا توقّفت آلة تورينج MM عند المدخل xx، و HALT(M,x)=0HALT(M,x)=0 بغير ذلك. إذن HALTHALT غير قابلة للحساب.

قبل أن ننتقل إلى إثبات مبرهنة — عدم قابلية حساب دالة التوقّف، نلاحظ أن HALTHALT دالة طبيعية جدًا نرغب في حسابها. فمثلًا يمكن التفكير في HALTHALT على أنها حالة خاصة من مهمة إدارة «متجر تطبيقات» (App store). أي إن، معطى شيفرة بعض التطبيقات، يحتاج حارس المتجر إلى أن يقرّر ما إذا كانت هذه الشيفرة آمنة بما يكفي للسماح بدخولها المتجر أم لا. على أقل تقدير، يبدو أنه علينا التحقق من أن الشيفرة لن تدخل في حلقة لا نهائية.

إحدى طرق التفكير في هذا البرهان هي كالتالي: Uncomputability of F∗  +  Universality  =  Uncomputability of HALT \text{Uncomputability of $F^*$} \;+\; \text{Universality} \;=\; \text{Uncomputability of $HALT$} أي إننا سنستعمل آلة تورينج الشاملة التي تحسب EVALEVAL لاستخراج عدم قابلية حساب HALTHALT من عدم قابلية حساب F∗F^* المبيَّنة في مبرهنة — الدوال غير القابلة للحساب. وبالتحديد، سيكون البرهان بالبرهان بالتناقض. أي إننا سنفرض، طلبًا للتناقض، أن HALTHALT قابلة للحساب، ونستعمل هذا الافتراض مع آلة تورينج الشاملة في مبرهنة — آلة تورينج الشاملة لاستخراج أن F∗F^* قابلة للحساب، مما يناقض مبرهنة — الدوال غير القابلة للحساب.

إذا كانت دالة FF غير قابلة للحساب، يمكننا أن نبيّن أن دالة أخرى HH غير قابلة للحساب، وذلك بإعطاء طريقة لاختزال مهمة حساب FF في مهمة حساب HH.

برهان

سيستعمل البرهان النتيجة المثبتة سابقًا مبرهنة — الدوال غير القابلة للحساب. وتذكّر أن مبرهنة — الدوال غير القابلة للحساب تُبيّن أن الدالة التالية F∗:{0,1}∗→{0,1}F^*: \{0,1\}^* \rightarrow \{0,1\} غير قابلة للحساب:

F∗(x)={0x(x)=11otherwise F^*(x) = \begin{cases}0 & x(x)=1 \\ 1 & \text{otherwise} \end{cases}

حيث x(x)x(x) يدل على خرج آلة تورينج الموصوفة بالسلسلة xx عند المدخل xx (مع الاصطلاح المعتاد بأن x(x)=⊥x(x)=\bot إذا لم تتوقّف هذه العملية الحسابية).

سنبيّن أن عدم قابلية حساب F∗F^* يعني عدم قابلية حساب HALTHALT. وبالتحديد، سنفرض، طلبًا للتناقض، أن هناك آلة تورينج MM تستطيع حساب الدالة HALTHALT، ونستعمل ذلك للحصول على آلة تورينج M′M' تحسب الدالة F∗F^*. (ويُعرف هذا بالبرهان بالاختزال (reduction)، لأننا نختزل مهمة حساب F∗F^* في مهمة حساب HALTHALT. وبالعكس، يعني هذا أن عدم قابلية حساب F∗F^* يعني عدم قابلية حساب HALTHALT.)

والحق، لنفرض أن MM آلة تورينج تحسب HALTHALT. يصف خوارزمية — F∗ to HALT reduction آلة تورينج M′M' تحسب F∗F^*. (ونستعمل وصفًا «عالي المستوى» لآلات تورينج، تمسّكًا بنموذج «كُلُّ الكعكة وتأكلها أيضًا»، انظر eatandhavecake.)

خوارزمية — F∗F^* to HALTHALT reduction

INPUT: $x\in \{0,1\}^*$
OUTPUT: $F^*(x)$
# Assume T.M. $M_{HALT}$ computes $HALT$

Let $z \leftarrow M_{HALT}(x,x)$. # Assume $z=HALT(x,x)$.
If{$z=0$}
return $1$
endif
Let $y \leftarrow U(x,x)$ # $U$ universal TM, i.e., $y=x(x)$
If{$y=1$}
return $0$
endif
Return $1$

نطالب بأن خوارزمية — F∗ to HALT reduction يحسب الدالة F∗F^*. والحق، لنفرض أن x(x)=1x(x)=1 (وبالتالي F∗(x)=0F^*(x)=0). في هذه الحالة، HALT(x,x)=1HALT(x,x)=1 وبالتالي، وفق افتراضنا M(x,x)=HALT(x,x)M(x,x)=HALT(x,x)، ستساوي القيمة zz العدد 11، وبالتالي سيضبط خوارزمية — F∗ to HALT reduction القيمة y=x(x)=1y=x(x)=1، ويُخرج القيمة الصحيحة 00.

ولنفرض بغير ذلك أن x(x)≠1x(x) \neq 1 (وبالتالي F∗(x)=1F^*(x)=1). في هذه الحالة هناك احتمالان:

  • الحالة 1: الآلة الموصوفة بـ xx لا تتوقّف عند المدخل xx (وبالتالي F∗(x)=1F^*(x)=1). في هذه الحالة، HALT(x,x)=0HALT(x,x)=0. وبما أننا نفترض أن MM تحسب HALTHALT، فإن ذلك يعني أن الآلة MM عند المدخل x,xx,x يجب أن تتوقّف وتُخرج القيمة 00. وهذا يعني أن خوارزمية — F∗ to HALT reduction سيضبط z=0z=0 ويُخرج 11.

  • الحالة 2: الآلة الموصوفة بـ xx تتوقّف عند المدخل xx وتُخرج قيمة ما y′≠1y' \neq 1 (وبالتالي F∗(x)=0F^*(x)=0). في هذه الحالة، بما أن HALT(x,x)=1HALT(x,x)=1، فإننا وفق افتراضاتنا سيضبط خوارزمية — F∗ to HALT reduction القيمة y=y′≠1y=y' \neq 1 وبالتالي يُخرج 11.

نرى أن في جميع الحالات M′(x)=F∗(x)M'(x)=F^*(x)، وهذا يناقض الحقيقة القائلة بأن F∗F^* غير قابلة للحساب. وعليه نصل إلى تناقض مع افتراضنا الأصلي بأن MM تحسب HALTHALT.

توقّف وتأمّل

مرة أخرى، هذا برهان يستحق القراءة أكثر من مرة. عدم قابلية حساب مشكلة التوقّف إحدى النظريات الأساس في علوم الحاسوب، وهي نقطة انطلاق لكثير من الدراسات التي سنراها لاحقًا. ومن أفضل الطرق لفهم مبرهنة — عدم قابلية حساب دالة التوقّف فهمًا أفضل مراجعة برهان مباشر لعدم قابلية حساب HALT (اختياري)، التي تقدّم برهانًا بديلًا للنتيجة نفسها.

هل مشكلة التوقّف صعبة حقًا؟ (نقاش)

أول ما يخطر بمخالب كثيرين عند رؤية برهان مبرهنة — عدم قابلية حساب دالة التوقّف هو ألّا يصدّقوه. أي إن معظم الناس يصدّقون العبارة الرياضية، لكنهم لا يشعرون حدسيًا بأن مشكلة التوقّف صعبة إلى هذا الحد. بعد كل شيء، عدم قابلية الحساب لا تعني سوى أن HALTHALT لا يمكن حسابها بآلة تورينج.

لكن المبرمجين يبدو أنهم يحلّون HALTHALT في كل وقت، وذلك بالجدال — رسميًا أو غير رسمي — في أن برامجهم تتوقّف. ومن الصحيح أن برامجهم مكتوبة بـ C أو Python، لا بآلات تورينج، لكن هذا لا يحدث أي فرق: فنحن نستطيع بسهولة الترجمة ذهابًا وإيابًا بين هذا النموذج وأي لغة برمجية أخرى.

وإن كان كل مبرمج يصطدم بحلقة لا نهائية في وقت ما، فهل حقًا لا توجد أي طريقة لحل مشكلة التوقّف؟ يقول بعض الناس إن هم أنفسهم يستطيعون، إن فكّروا بجدّية كافية، تحديد ما إذا كان أي برنامج ملموس يُعطَون له سيتوقّف أم لا. بل ذهب بعضهم إلى القول إن الإنسان بشكل عام يملك هذه القدرة، وبالتالي فإن الإنسان بذكاء يتفوّق بطبيعته على الحواسيب وعلى أي شيء آخر يُنمذَج بآلات تورينج.[1]

أفضل إجابة لدينا حتى الآن هي أنه حقًا لا توجد أي طريقة لحل HALTHALT، سواء باستعمال أجهزة Mac أو PC أو الحواسيب الكمّية أو البشر، أو أي تركيبة أخرى من الأجهزة الإلكترونية والميكانيكية والحيوية. وبالفعل، فإن هذا هو جوهر أطروحة كنغ-تورينج (Church-Turing Thesis). بالطبع لا يعني هذا أن تحديد ما إذا كان برنامج PP محتمل يدخل في حلقة لا نهائية يصعب بالنسبة لكل برنامج PP ممكن. بعض البرامج لا تحوي حلقات أصلًا (وبالتالي تتوقّف على نحو بديهي)، وهناك أمثلة كثيرة أقل إثارةً بكثير لبرامج يمكننا التحقّق من أنها لن تدخل أبدًا في حلقة لا نهائية (أو برامج نعرف بيقين أنها ستدخل في حلقة كهذه). غير أنه لا يوجد إجراء عام (general procedure) يحدّد ما إذا كان برنامج PP اعتباطي يتوقّف أم لا. وفضلا عن ذلك، هناك بعض البرامج البسيطة جدًا التي لا يعرف أحد ما إذا كانت تتوقّف أم لا. فمثلًا، سيتوقّف برنامج Python التالي إذا وفقط إذا كان حدس غولدباخ (Goldbach's conjecture) خاطئًا:

def isprime(p):
    return all(p % i for i in range(2,p-1))

def Goldbach(n):
    return any( (isprime(p) and isprime(n-p))
           for p in range(2,n-1))

n = 4
while True:
    if not Goldbach(n): break
    n+= 2

وبما أن حدس غولدباخ مفتوح منذ عام 1742، فإن من غير الواضح أن للبشر أي قدرة سحرية على القول ما إذا كان هذا البرنامج (أو برامج مشابهة له) سيتوقّف أم لا.

عرض SMBC الساخر لمسألة التوقّف.

برهان مباشر لعدم قابلية حساب HALTHALT (اختياري)

يتبيّن أنه يمكننا جمع أفكار برهاني مبرهنة — الدوال غير القابلة للحساب و مبرهنة — عدم قابلية حساب دالة التوقّف للحصول على برهان قصير للنظرية الأخيرة، لا يلجأ إلى عدم قابلية حساب F∗F^*. وقد ظهر هذا البرهان القصير مطبوعًا في رسالة عام 1965 إلى محرّر مجلة The Computer Journal:

إلى المحرّر، مجلة The Computer Journal.

برنامج مستحيل

سيدي المحترم،

هناك قطعة مشهورة من الحكاية الشائعة بين المبرمجين تقول إنه من المستحيل كتابة برنامج يستطيع فحص أي برنامج آخر ويخبرنا في كل حالة بما إذا كان سينتهي أم سيدخل في حلقة مغلقة عند تشغيله. ولم أَرَ قط برهانًا مطبوعًا لهذا، ومع أن آلان تورينج أعطى لي برهانًا شفويًا مرة (في عربة قطار في طريقنا إلى مؤتمر في NPL عام 1953)، فإنني نسيتُ التفاصيل على نحو لسوء حظّي وحالًا. وهذا ترك لديّ شعورًا مضطربًا بأن البرهان يجب أن يكون طويلًا أو معقّدًا، لكنه في الواقع قصير وبسيط إلى حدّ قد يهمّ القراء العابثين. وتستعمل النسخة أدناه CPL، لكن ليس على أي نحو جوهري.

لنفترض أن T[R] دالة بوليانية تأخذ إجراءً (أو برنامجًا) R مجرّدًا من المتغيّرات الشكليّة أو الحرّة كوسائط لها، وأنها لكل R تحقق T[R] = True إذا كان R ينتهي عند تشغيله، و T[R] = False إذا لم يكن R ينتهي.

اعتبر الإجراء P المعرَّف كالتالي

rec routine P
§L: if T[P] go to L
Return §

إذا كان T[P] = True فسيعمل الإجراء P في حلقة، ولن ينتهي إلا إذا كان T[P] = False. وفي كل حالة تكون القيمة T[P] خاطئة تمامًا، وهذا التناقض يُظهر أن الدالة T لا يمكن أن توجد.

وتفضّلوا بقبول فائق الاحترام،
سي. ستراتشي

كلية تشرشل، كامبريدج

توقّف وتأمّل

حاوِل أن تتوقّف وتستخرج الحجّة التي تثبت مبرهنة — عدم قابلية حساب دالة التوقّف من الرسالة أعلاه.

وبما أن CPL لم يعد شائعًا اليوم، فلنُعد عرض هذا البرهان. الفكرة كالتالي: لنفرض، طلبًا للتناقض، أن هناك برنامجًا T بحيث T(f,x) يساوي True إذا وفقط إذا كان f يتوقّف عند المدخل x. (تعتبر رسالة ستراتشي صيغة HALTHALT بلا مدخلات، لكن كما سنرى، فهذا تمييز غير جوهري.) عندئذ يمكننا إنشاء برنامج P ومدخل x بحيث يعطي T(P,x) الجواب الخاطئ. والفكرة أن البرنامج P عند المدخل x سيفعل ما يلي: ينفّذ T(x,x)، فإذا كان الجواب True دخل في حلقة لا نهائية، وإلا فتوقّف. والآن ترى أن T(P,P) سيعطي الجواب الخاطئ: إذا توقّف P حين يحصل على شيفرته الخاصة كمدخل، فإن T(P,P) يُفترض أن تكون True، لكن عندئذ سيدخل P(P) في حلقة لا نهائية. وإذا لم يتوقّف P، فإن T(P,P) يُفترض أن تكون False، لكن عندئذ سيتوقّف P(P). ويمكننا أيضًا كتابة هذا في Python:

def CantSolveMe(T):
    """
    Gets function T that claims to solve HALT.
    Returns a pair (P,x) of code and input on which
    T(P,x) ≠ HALT(x)
    """
    def fool(x):
        if T(x,x):
            while True: pass
        return "I halted"

    return (fool,fool)

فمثالًا، خُذ بعين الاعتبار برنامج Python البسيط التالي T الذي يخمّن أن دالة معطاة لا تتوقّف إذا كان مدخلها يحتوي while أو for

def T(f,x):
    """Crude halting tester - decides it doesn't halt if it contains a loop."""
    import inspect
    source = inspect.getsource(f)
    if source.find("while"): return False
    if source.find("for"): return False
    return True

والآن إذا جعلنا (f,x) = CantSolveMe(T)، فإن T(f,x)=False بينما f(x) تتوقّف فعلًا. وبالطبع هذا ليس خاصًّا بهذا T بعينه: فلكل برنامج T، إذا شغّلنا (f,x) = CantSolveMe(T)، فسنحصل على مدخل يعطي عنده T جوابًا خاطئًا لـ HALTHALT.

الاختزال

تبيّن أن مشكلة التوقّف هي محور عدم قابلية الحساب، بمعنى أن مبرهنة — عدم قابلية حساب دالة التوقّف استُعمل لإثبات عدم قابلية حساب عدد كبير جدًا من الدوال المثيرة. سنرى في هذا الفصل وفي التمارين عدة أمثلة لمثل هذه النتائج، لكن هناك نتائج أخرى كثيرة (انظر الشكل التوضيحي).

/images/introtcs/lec_08_uncomputability-4.webp

الفكرة وراء نتائج عدم قابلية الحساب هذه بسيطة من الناحية المفاهيمية، لكنها قد تكون محيِّرة في البداية. فإذا كنا نعرف أن HALTHALT غير قابلة للحساب، وأردنا أن نبيّن أن دالة أخرى BLAHBLAH غير قابلة للحساب، فيمكننا فعل ذلك بحجّة عكسية (contrapositive) (أي بالبرهان بالتناقض). أي إننا نبيّن أنّ إن كانت هناك آلة تورينج تحسب BLAHBLAH فإن هناك آلة تورينج تحسب HALTHALT. (وبالفعل، هكذا بيّنا بالضبط أن HALTHALT نفسها غير قابلة للحساب، إذ استخرجنا هذه الحقيقة من عدم قابلية حساب الدالة F∗F^* في مبرهنة — الدوال غير القابلة للحساب.)

فمثلًا، لإثبات أن BLAHBLAH غير قابلة للحساب، يمكننا أن نبيّن أنه توجد دالة قابلة للحساب R:{0,1}∗→{0,1}∗R:\{0,1\}^* \rightarrow \{0,1\}^* بحيث لكل زوج MM و xx، يكون HALT(M,x)=BLAH(R(M,x))HALT(M,x)=BLAH(R(M,x)). ووجود دالة RR كهذه يعني أنّ إن كانت BLAHBLAH قابلة للحساب فإن HALTHALT ستكون قابلة للحساب أيضًا، مما يقود إلى تناقض! والجزء المحيّر في الاختزال أننا نفترض شيئًا نعتقد أنه خاطئ (أنّ BLAHBLAH لها خوارزمية) لنستنتج شيئًا نعرف أنه خاطئ (أنّ HALTHALT لها خوارزمية). ويصف مايكل سيبسر هذه النتائج بأنها تأخذ الشكل «إذا كان الخنازير تستطيع الصفير لأمكنت الخيل أن تحلّق».

يتكوّن البرهان المبني على الاختزال من مكوّنين. للبداية، بما أننا نحتاج إلى أن تكون RR قابلة للحساب، علينا أن نصف الخوارزمية التي تحسبها. وتُعرف الخوارزمية التي تحسب RR بـ_اختزال_ (reduction)، إذ إن التحويل RR يحوّل مدخلًا لـ HALTHALT إلى مدخل لـ BLAHBLAH، وبالتالي يختزل مهمة حساب HALTHALT في مهمة حساب BLAHBLAH. والمكوّن الثاني في البرهان المبني على الاختزال هو التحليل (analysis) للخوارزمية RR: أي برهان على أن RR تستوفي بالفعل الصفات المطلوبة.

البراهين المبنية على الاختزال تشبه غيرها من البراهين بالتناقض، لكن الحقيقة أنها تتضمّن خوارزميات افتراضية غير موجودة فعلًا، وهذا ما يجعل الاختزال محيِّرًا إلى حد كبير. والبُدء الوحيد في الحل هو أن مفهوم الاختزال، في نهاية المطاف، بسيط إلى حد كبير رياضيًا، ولذلك فليس الأمر سيئًا جدًا حتى لو اضطررت إلى العودة إلى المبادئ الأولى كلما احتجت إلى تذكّر الاتجاه الذي يجب أن يسلكه الاختزال.

ملاحظة — الاختزال خوارزميات

الاختزال هو خوارزمية، وهذا يعني، كما نوقش في ملاحظة — المواصفة والتنفيذ وتحليل الخوارزميات.، أن للاختزال ثلاثة مكوّنات:

  • المواصفة (ماذا): في حالة الاختزال من HALTHALT إلى BLAHBLAH، تكون المواصفة هي أن الدالة R:{0,1}∗→{0,1}∗R:\{0,1\}^* \rightarrow \{0,1\}^* يجب أن تحقّق HALT(M,x)=BLAH(R(M,x))HALT(M,x)=BLAH(R(M,x)) لكل آلة تورينج MM ومدخل xx. وعلى وجه العموم، لاختزال دالة FF إلى GG، يجب أن يحقّق الاختزال F(w)=G(R(w))F(w)=G(R(w)) لكل مدخل ww لـ FF.

  • التنفيذ (كيف): وصف الخوارزمية: التعليمات الدقيقة لتحويل مدخل ww إلى الخرج y=R(w)y=R(w).

  • التحليل (لماذا): برهان على أن الخوارزمية تستوفي المواصفة. وبالخصوص، في الاختزال من FF إلى GG، هذا برهان على أن الخرج y=R(w)y=R(w) للخوارزمية، لكل مدخل ww، يحقّق F(w)=G(y)F(w)=G(y).

مثال: مشكلة التوقّف على الصفر

إليك مثالًا ملموسًا على برهان بالاختزال. نعرّف الدالة HALTONZERO:{0,1}∗→{0,1}HALTONZERO:\{0,1\}^* \rightarrow \{0,1\} كالتالي. معطى أي سلسلة MM، يكون HALTONZERO(M)=1HALTONZERO(M)=1 إذا وفقط إذا كانت MM تصف آلة تورينج تتوقّف عند إعطائها السلسلة 00 كمدخل. قبل كل شيء، تبدو HALTONZEROHALTONZERO دالة يحتمل أن تكون أسهل في الحساب من دالة HALTHALT الكاملة، ولذلك قد نأمل ألّا تكون غير قابلة للحساب. لكن، للأسف، تُظهر النظرية التالية أن الأمر ليس كذلك:

مبرهنة — التوقّف دون مدخل

HALTONZEROHALTONZERO غير قابلة للحساب.

توقّف وتأمّل

برهان مبرهنة — التوقّف دون مدخل أدناه، لكن قبل قراءته قد ترغب في التوقّف لدقائق وتفكّر في كيفية إثباته بنفسك. وبالخصوص، حاول أن تتخيّل شكل اختزال من HALTHALT إلى HALTONZEROHALTONZERO. فعل ذلك طريقة ممتازة لاكتساب بعض الاطمئنان الأولي تجاه فكرة البراهين بالاختزال، وهي تقنية سنستعملها مرارًا وتكرارًا في هذا الكتاب. كما يمكنك أيضًا أن ترى الشكل التوضيحي ودفتر Colab التالي لتنفيذ Python لهذا الاختزال.

لِإثبات haltonzero-thm، نُظهر أنّ  غير قابلة للحساب عبر إعطاء اختزال (reduction) من مهمة حساب  إلى مهمة حساب . وهذا يُظهر أنّه لو وُجد خوارزمية افتراضية  تحسب ، لَوُجد خوارزمية  تحسب ، وهو ما يتعارض مع halt-thm. وبما أنّ أيًّا من  و غير موجودين فعليًا، فهذا مثالٌ على استلزامٍ من النمط «لو أمكن للخنازير أن تزقزق لَأمكن للخيول أن تطير».

برهان

البرهان يكون بالاختزال من HALTHALT، انظر الشكل التوضيحي. وسنفرض، طلبًا للتناقض، أن HALTONZEROHALTONZERO قابلة للحساب بخوارزمية ما AA، ونستعمل هذه الخوارزمية الافتراضية AA لإنشاء خوارزمية BB تحسب HALTHALT، فنحصل على تناقض مع مبرهنة — عدم قابلية حساب دالة التوقّف. (وكما نوقش في eatandhavecake، فإننا تمسّكًا بنموذج «كُلُّ الكعكة وتأكلها أيضًا» نستعمل الاسم العام «خوارزمية» فقط بدلًا من القلق بشأن ما إذا كنا نمذذجها بآلات تورينج أم برامج NAND-TM أم NAND-RAM وما إلى ذلك؛ وهذا لا يحدث أي فرق لأن كل هذه النماذج متكافئة فيما بينها.)

وبما أن هذا هو برهاننا الأول بالاختزال انطلاقًا من مشكلة التوقّف، فسنفصّله أكثر من المعتاد. ويتكوّن مثل هذا البرهان بالاختزال من خطوتين:

  1. وصف الاختزال: سنصف عملية خوارزميتنا BB، وكيف تُجري «استدعاءات دوال» إلى الخوارزمية الافتراضية AA.

  2. تحليل الاختزال: سنثبت بعد ذلك أن تحت فرضية أن الخوارزمية AA تحسب HALTONZEROHALTONZERO، فإن الخوارزمية BB ستحسب HALTHALT.

خوارزمية — HALTHALT to HALTONZEROHALTONZERO reduction

INPUT: Turing machine $M$ and string $x$.
OUTPUT: Turing machine $M'$ such that $M$ halts on $x$ iff $M'$ halts on zero

Procedure{$N_{M,x}$}{$w$} # Description of the T.M. $N_{M,x}$
 Return $EVAL(M,x)$ # Ignore the input $w$, evaluate $M$ on $x$.
Endprocedure

Return $N_{M,x}$ # We do not execute $N_{M,x}$: only return its description

تعمل خوارزميتنا BB كالتالي: عند المدخل M,xM,x، تشغّل خوارزمية — HALT to HALTONZERO reduction للحصول على آلة تورينج M′M'، ثم تُعيد A(M′)A(M'). وتتجاهل الآلة M′M' مدخلها zz وتكتفي بتشغيل MM على xx.

وبصيغة الشيفرة الوهمية (pseudocode)، سيبدو البرنامج NM,xN_{M,x} بشكل تقريبي كالتالي:

def N(z):
    M = r'.......'
    # a string constant containing desc. of M
    x = r'.......'
    # a string constant containing x
    return eval(M,x)
    # note that we ignore the input z

أي إن، إذا نظرنا إلى NM,xN_{M,x} على أنها برنامج، فهو برنامج يحوي MM و xx بوصفهما «ثابتين مُثبَّتين» (hardwired constants)، ومعطى أي مدخل zz، يتجاهل المدخل ببساطة ويُعيد دائمًا نتيجة تقييم MM على xx. والخوارزمية BB لا تنفّذ فعليًا الآلة NM,xN_{M,x}. فـ BB تكتفي بكتابة وصف NM,xN_{M,x} كسلسلة (تمامًا كما فعلنا أعلاه) وتغذّي هذه السلسلة كمدخل إلى AA.

ما سبق يُكمل وصفَ الاختزال. أما التحليل فيُحصل عليه بإثبات الادّعاء التالي:

الادّعاء: لكل السلاسل M,x,zM,x,z، تفي الآلة NM,xN_{M,x} التي تبنيها الخوارزمية BB في الخطوة 1 بأن NM,xN_{M,x} تتوقّف عند zz إذا وفقط إذا كان البرنامج الموصوف بـ MM يتوقّف عند المدخل xx.

برهان الادّعاء: بما أن NM,xN_{M,x} تتجاهل مدخلها وتُقيّم MM على xx باستعمال آلة تورينج الشاملة، فإنها تتوقّف عند zz إذا وفقط إذا كانت MM تتوقّف عند xx.

وبالخصوص، إذا عيّنّا هذا الادّعاء بالمدخل z=0z=0 لـ NM,xN_{M,x}، رأينا أن HALTONZERO(NM,x)=HALT(M,x)HALTONZERO(N_{M,x})=HALT(M,x). وعليه، إذا كانت الخوارزمية الافتراضية AA تحقّق A(M)=HALTONZERO(M)A(M)=HALTONZERO(M) لكل MM، فإن الخوارزمية BB التي نبنيها تحقّق B(M,x)=HALT(M,x)B(M,x)=HALT(M,x) لكل M,xM,x، مما يناقض عدم قابلية حساب HALTHALT.

تنفيذ بايثوني للاختزال يُظهر أنّ  غير قابلة للحساب إذا كان  كذلك. انظر هذا دفتر Colab لتنفيذٍ كاملٍ للاختزال.

ملاحظة — تقنية تثبيت المدخلات

في برهان مبرهنة — التوقّف دون مدخل استعملنا تقنية «تثبيت» (hardwiring) مدخل xx في برنامج/آلة PP. أي إننا نأخذ برنامجًا يحسب الدالة x↦f(x)x \mapsto f(x) ونثبّت بعض المداخل عند قيمة ثابتة ما. فمثلًا، إذا كان لديك برنامج يأخذ كمدخل زوجًا من الأعداد x,yx,y ويُخرج حاصل ضربهما (أي يحسب الدالة f(x,y)=x×yf(x,y) =x\times y)، فيمكنك أن «تثبّت» المدخل الثاني على القيمة 1717 فتحصل على برنامج يأخذ كمدخل عدد xx ويُخرج x×17x\times 17 (أي يحسب الدالة g(x)=x×17g(x) = x\times 17). وهذه التقنية شائعة جدًا في الاختزال وفي مواضع أخرى، وسنستعملها مرارًا وتكرارًا في هذا الكتاب.

نظرية رايس واستحالة التحقق البرمجي العام

يتبيّن أن عدم قابلية حساب مشكلة التوقّف حالة خاصة من ظاهرة أعمّ بكثير. أي إنّنا لا نستطيع التصديق على الخصائص الدلالية (semantic properties) للبرامج العامة الغرض. وتعني «الخصائص الدلالية» خصائصَ الدالة التي يحسبها البرنامج، على عكس الخصائص التي تعتمد على الصياغة (syntax) الخاصة المستعملة في البرنامج.

مثال على خاصية دلالية لبرنامج PP هو الخاصية القائلة إن كلما أُعطي PP سلسلة مدخلات فيها عدد زوجي من 11's، فهو يُخرج 00.

ومثال آخر هو الخاصية القائلة إن PP ستتوقّف دائمًا متى ما انتهى المدخل بـ 11. وبالمقابل، الخاصية القائلة إن برنامج C يحتوي على تعليق قبل كل تعريف دالة ليست خاصية دلالية، لأنها تعتمد على الشيفرة المصدرية الفعلية لا على علاقة المدخل/الخرج.

والتحقّق من الخصائص الدلالية للبرامج ذا أهمية بالغة، لأنه يماثل التحقّق مما إذا كان برنامج ما يطابق مواصفة (specification). لكن، للأسف، يتبيّن أن هذه الخصائص غير قابلة للحساب في العموم. لقد رأينا بالفعل بعض الأمثلة على الدوال الدلالية غير القابلة للحساب، وهي HALTHALT و HALTONZEROHALTONZERO، لكن هذه ليست سوى «قمة جبل الجليد». ونبدأ بملاحظة مثال آخر من هذا النوع:

مبرهنة — دالة حساب الكل أصفار

لتكن ZEROFUNC:{0,1}∗→{0,1}ZEROFUNC:\{0,1\}^* \rightarrow \{0,1\} الدالة التي لكل M∈{0,1}∗M\in \{0,1\}^* يكون ZEROFUNC(M)=1ZEROFUNC(M)=1 إذا وفقط إذا كانت MM تمثّل آلة تورينج تُخرج 00 عند كل مدخل x∈{0,1}∗x\in \{0,1\}^*. إذن ZEROFUNCZEROFUNC غير قابلة للحساب.

توقّف وتأمّل

رغم تشابه اسميهما، فإن ZEROFUNCZEROFUNC و HALTONZEROHALTONZERO دالتان مختلفتان. فمثلًا، إذا كانت MM آلة تورينج تتوقّف عند المدخل x∈{0,1}∗x \in \{0,1\}^* وتُخرج «الأو» المنطقي (OR) لإحداثيات xx كلها، فإن HALTONZERO(M)=1HALTONZERO(M)=1 (لأن MM تتوقّف فعلًا عند المدخل 00) لكن ZEROFUNC(M)=0ZEROFUNC(M)=0 (لأن MM لا تحسب دالة الصفر الثابت).

برهان

البرهان يكون بالاختزال من HALTONZEROHALTONZERO. لنفرض، طلبًا للتناقض، أنه كانت هناك خوارزمية AA بحيث A(M)=ZEROFUNC(M)A(M)=ZEROFUNC(M) لكل M∈{0,1}∗M \in \{0,1\}^*. عندئذ سنبني خوارزمية BB تحلّ HALTONZEROHALTONZERO، مما يناقض مبرهنة — التوقّف دون مدخل.

معطى آلة تورينج NN (وهي مدخل HALTONZEROHALTONZERO)، تفعل خوارزميتنا BB ما يلي:

  1. تبني آلة تورينج MM التي، عند المدخل x∈{0,1}∗x\in\{0,1\}^*، تشغّل أولًا N(0)N(0) ثم تُخرج 00.

  2. تُعيد A(M)A(M).

الآن، إذا كانت NN تتوقّف عند المدخل 00، فإن آلة تورينج MM تحسب دالة الصفر الثابت، وبالتالي وفق افتراضنا أن AA تحسب ZEROFUNCZEROFUNC، فإن A(M)=1A(M)=1. وإذا كانت NN لا تتوقّف عند المدخل 00، فإن آلة تورينج MM لن تتوقّف عند أي مدخل، وبالتالي لن تحسب بالذات دالة الصفر الثابت. وعليه، وفق افتراضنا أن AA تحسب ZEROFUNCZEROFUNC، فإن A(M)=0A(M)=0. ونرى أن في الحالتين ZEROFUNC(M)=HALTONZERO(N)ZEROFUNC(M)=HALTONZERO(N)، وبالتالي فإن القيمة التي تُعيدها الخوارزمية BB في الخطوة 2 تساوي HALTONZERO(N)HALTONZERO(N)، وهو ما كنا بحاجة إلى إثباته.

ونتيجة أخرى على خط متوازٍ هي التالية:

مبرهنة — عدم قابلية حساب التحقّق من التكافؤ

الدالة التالية غير قابلة للحساب COMPUTES-PARITY(P)={1P computes the parity function 0otherwise COMPUTES\text{-}PARITY(P) = \begin{cases} 1 & P \text{ computes the parity function } \\ 0 & \text{otherwise} \end{cases}

توقّف وتأمّل

نترك برهان مبرهنة — عدم قابلية حساب التحقّق من التكافؤ تمرينًا (تمرين — حساب التكافؤ). وأحثّك بشدّة على أن تتوقّف هنا وتحاول حلّ هذا التمرين.

نظرية رايس

يمكن تعميم مبرهنة — عدم قابلية حساب التحقّق من التكافؤ إلى ما هو أبعد بكثير من دالة التكافؤ. وفي الواقع، هذا التعميم يستبعد التحقّق من أي نوع من المواصفات الدلالية على البرامج. ونعرّف المواصفة الدلالية (semantic specification) على البرامج بأنها خاصية لا تعتمد على شيفرة البرنامج بل على الدالة التي يحسبها البرنامج فحسب.

فمثالًا، خُذ بعين الاعتبار برنامجَي C التاليين

int First(int n) {
    if (n<0) return 0;
    return 2*n;
}
int Second(int n) {
    int i = 0;
    int j = 0
    if (n<0) return 0;
    while (j<n) {
        i = i + 2;
        j = j + 1;
    }
    return i;
}

First و Second برنامجان مختلفان في C، لكنهما يحسبان الدالة نفسها. والخاصية الدلالية ستكون إما صادقة للبرنامجين معًا أو كاذبة لهما معًا، لأنها تعتمد على الدالة التي يحسبها البرنامجان لا على شيفرتيهما. ومن أمثلة الخاصية الدلالية التي يحققها كلٌّ من First و Second ما يلي: «البرنامج PP يحسب دالة ff تُسقط الأعداد الصحيحة على الأعداد الصحيحة بحيث f(n)≥nf(n) \geq n لكل مدخل nn».

والخاصية غير دلالية إذا كانت تعتمد على الشيفرة المصدرية لا على سلوك المدخل/الخرج. فمثالًا، الخصائص مثل «البرنامج يحوي المتغيّر k» أو «البرنامج يستعمل العملية while» ليست دلالية. فمثل هذه الخصائص قد تكون صادقة لأحد البرنامجين وكاذبة للآخرين. ونعرّف الخصائص الدلالية رسميًا كالتالي:

تعريف — الخصائص الدلالية

زوجا آلات تورينج MM و M′M' يكونان متكافئين وظيفيًا (functionally equivalent) إذا كان لكل x∈{0,1}∗x\in \{0,1\}^* لدينا M(x)=M′(x)M(x)=M'(x). (وبالخصوص، M(x)=⊥M(x)=\bot إذا وفقط إذا كان M′(x)=⊥M'(x)=\bot لكل xx.)

وتكون الدالة F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} دلالية إذا كان لكل زوج من السلاسل M,M′M,M' يمثّلان آلتي تورينج متكافئتين وظيفيًا، لدينا F(M)=F(M′)F(M)=F(M'). (وتذكّر أننا نفترض أن كل سلسلة تمثّل بعضَ آلة تورينج، انظر ملاحظة — أبرز ما ينبغي تذكّره عن التمثيل)

وهناك مثالان تافهان على الدوال الدلالية: دالة الواحد الثابتة ودالة الصفر الثابتة. فمثلًا، إذا كانت ZZ هي دالة الصفر الثابتة (أي Z(M)=0Z(M)=0 لكل MM)، فمن الواضح أن F(M)=F(M′)F(M)=F(M') لكل زوج من آلات تورينج MM و M′M' المتكافئتين وظيفيًا. وها هو مثال غير تافه

تمرين محلول — ZEROFUNCZEROFUNC دلالية

برهن أن الدالة ZEROFUNCZEROFUNC دلالية.

الحل

وتذكّر أن ZEROFUNC(M)=1ZEROFUNC(M)=1 إذا وفقط إذا كان M(x)=0M(x)=0 لكل x∈{0,1}∗x\in \{0,1\}^*. وإذا كانت MM و M′M' متكافئتين وظيفيًا، فإن لكل xx لدينا M(x)=M′(x)M(x)=M'(x). وعليه ZEROFUNC(M)=1ZEROFUNC(M)=1 إذا وفقط إذا كان ZEROFUNC(M′)=1ZEROFUNC(M')=1.

غالبًا ما تكون الخصائص التي تهمّنا أكثر من غيرها في الحساب هي الخصائص الدلالية، لأننا نريد أن نفهم وظائفية البرامج. وللأسف، تخبرنا نظرية رايس أن هذه الخصائص جميعها غير قابلة للحساب:

مبرهنة — نظرية رايس

لتكن F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\}. إذا كانت FF دلالية وغير تافهة فإنها غير قابلة للحساب.

الفكرة وراء البرهان هي إظهار أن كل دالة دلالية غير تافهة FF صعبة الحساب على الأقل بقدر HALTONZEROHALTONZERO. وهذا سيُتمّ البرهان، لأن HALTONZEROHALTONZERO غير قابلة للحساب بحسب مبرهنة — التوقّف دون مدخل. وإذا كانت دالة FF غير تافهة، فإن هناك آلتين M0M_0 و M1M_1 بحيث F(M0)=0F(M_0)=0 و F(M1)=1F(M_1)=1. فالغرض إذن هو أن نأخذ آلة NN ونجد طريقة لتعيينها إلى آلة M=R(N)M=R(N)، بحيث (i) إذا كانت NN تتوقّف على الصفر فإن MM تكون متكافئة وظيفيًا مع M1M_1، و (ii) إذا كانت NN لا تتوقّف على الصفر فإن MM تكون متكافئة وظيفيًا مع M0M_0.

ولأن FF دلالية، فإننا لو حقّقنا ذلك لأوصّنا ضمنًا أن HALTONZERO(N)=F(R(N))HALTONZERO(N) = F(R(N))، وبذلك نبيّن أن إذا كانت FF قابلة للحساب فإن HALTONZEROHALTONZERO ستكون قابلة للحساب أيضًا، مما يناقض مبرهنة — التوقّف دون مدخل.

برهان

لن نعطي البرهان بالشكلية الكاملة، بل سنوضّح فكرة البرهان بالاكتفاء بدالة دلالية بعينها FF. غير أن التقنيات نفسها تتعمّم على كل الدوال الدلالية الممكنة. نعرّف MONOTONE:{0,1}∗→{0,1}MONOTONE:\{0,1\}^* \rightarrow \{0,1\} كالتالي: MONOTONE(M)=1MONOTONE(M)=1 إذا لم يكن هناك عدد n∈Nn\in \N ومدخلان x,x′∈{0,1}nx,x' \in \{0,1\}^n بحيث لكل i∈[n]i\in [n] لدينا xi≤xi′x_i \leq x'_i مع أن M(x)M(x) يُخرج 11 و M(x′)=0M(x')=0. أي إن MONOTONE(M)=1MONOTONE(M)=1 إذا كان من المستحيل إيجاد مدخل xx بحيث يقلّب قلب بعض بتات xx من 00 إلى 11 فيغيّر خرج MM في الاتجاه المعاكس من 11 إلى 00. سنبرهن أن MONOTONEMONOTONE غير قابلة للحساب، لكن البرهان سيتعمّم بسهولة على أي دالة دلالية.

نبدأ بالملاحظة أن MONOTONEMONOTONE ليست دالة الصفر الثابتة ولا دالة الواحد الثابتة:

  • الآلة INFINF التي تدخل ببساطة في حلقة لا نهائية عند كل مدخل تحقّق MONOTONE(INF)=1MONOTONE(INF)=1، إذ إن INFINF غير معرَّفة في أي موضع، ومن ثمّ لا توجد على الخصوص مدخلان x,x′x,x' فيهما xi≤xi′x_i \leq x'_i لكل ii مع أن INF(x)=0INF(x)=0 و INF(x′)=1INF(x')=1.

  • الآلة PARPAR التي تحسب «الأو الحصري» (XOR) أو التكافؤ (parity) لمدخلها ليست رتيبة (monotone) (مثلًا PAR(1,1,0,0,…,0)=0PAR(1,1,0,0,\ldots,0)=0 لكن PAR(1,0,0,…,0)=0PAR(1,0,0,\ldots,0)=0) وبالتالي MONOTONE(PAR)=0MONOTONE(PAR)=0.

(لاحظ أن INFINF و PARPAR آلتان لا دالتان.)

سنقدّم الآن اختزالًا من HALTONZEROHALTONZERO إلى MONOTONEMONOTONE. أي إننا نفرض، طلبًا للتناقض، أن هناك خوارزمية AA تحسب MONOTONEMONOTONE، وسنبني خوارزمية BB تحسب HALTONZEROHALTONZERO. وستعمل خوارزميتنا BB كالتالي:

اقتباس

الخوارزمية BB:

المدخل: سلسلة NN تصف آلة تورينج. (الهدف: حساب HALTONZERO(N)HALTONZERO(N))

الافتراض: إمكانية الوصول إلى الخوارزمية AA لحساب MONOTONEMONOTONE.

العملية:

  1. تبني الآلة التالية MM: «عند المدخل z∈{0,1}∗z\in \{0,1\}^* افعل: (a) نفّذ N(0)N(0)، (b) أعِد PAR(z)PAR(z)».

  2. أعِد 1−A(M)1-A(M).

لإتمام البرهان نحتاج إلى إظهار أن BB تُخرج الجواب الصحيح، تحت افتراضنا أن AA تحسب MONOTONEMONOTONE. بعبارة أخرى، نحتاج إلى إظهار أن HALTONZERO(N)=1−MONOTONE(M)HALTONZERO(N)=1-MONOTONE(M). لنفرض أن NN لا تتوقّف على الصفر. في هذه الحالة، يدخل البرنامج MM الذي تبنيه الخوارزمية BB في حلقة لا نهائية في الخطوة (a)، ولن يبلغ الخطوة (b) أبدًا. وعليه في هذه الحالة تكون NN متكافئة وظيفيًا مع INFINF. (الآلة NN ليست هي الآلة INFINF: فوصفها أو شيفرتها مختلف. لكنها تملك سلوك المدخل/الخرج نفسه (في هذه الحالة) أي أنها لا تتوقّف أبدًا عند أي مدخل. كما أن البرنامج MM سيدخل في حلقة لا نهائية عند كل مدخل، لكن الخوارزمية BB لا تشغّل MM فعليًا أبدًا: فهي لا تنتج سوى شيفرتها وتغذّيها إلى AA. وعليه فلن تدخل الخوارزمية BB في حلقة لا نهائية حتى في هذه الحالة.) وعليه في هذه الحالة يكون MONOTONE(M)=MONOTONE(INF)=1MONOTONE(M)=MONOTONE(INF)=1.

وإذا كانت NN تتوقّف على الصفر، فإن الخطوة (a) في MM ستنتهي في النهاية، وسيحدّد خرجُ MM بالخطوة (b)، حيث يُخرج ببساطة تكافؤ (parity) مدخله. وعليه في هذه الحالة تحسب MM دالة التكافؤ غير الرتيبة (أي أنها متكافئة وظيفيًا مع PARPAR)، فنحصل على MONOTONE(M)=MONOTONE(PAR)=0MONOTONE(M)=MONOTONE(PAR)=0. وفي الحالتين معًا MONOTONE(M)=1−HALTONZERO(N)MONOTONE(M)=1-HALTONZERO(N)، وهو ما كنا باجة إلى إثباثه.

ودراسة هذا البرهان تُظهر أننا لم نستعمل عن MONOTONEMONOTONE شيئًا يتجاوز كونها دلالية وغير تافهة. فلكل دالة دلالية غير تافهة FF، يمكننا استعمال البرهان نفسه، مع استبدال PARPAR و INFINF بآلتين M0M_0 و M1M_1 بحيث F(M0)=0F(M_0)=0 و F(M1)=1F(M_1)=1. وهذه الآلات لا بدّ من وجودها إذا كانت FF غير تافهة.

ملاحظة — الدلالية ليست هي عدم قابلية الحساب

نظرية رايس قوية جدًا وتحظى بشعبية كبيرة كطريقة لإثبات عدم قابلية الحساب، حتى إن الناس يربكون أحيانًا فيظنّون أنها هي الطريقة الوحيدة لإثبات عدم قابلية الحساب. وبالخصوص، هناك سوء فهم شائع يقول إن الدالة FF إن لم تكن دلالية فإنها قابلة للحساب. وهذا ليس صحيحًا البتّة.

فمثالًا، خُذ بعين الاعتبار الدالة التالية HALTNOYALE:{0,1}∗→{0,1}HALTNOYALE:\{0,1\}^* \rightarrow \{0,1\}. وهذه دالة، عند إدخال سلسلة تمثّل برنامج NAND-TM PP، تُخرج 11 إذا وفقط إذا كان كلا الشرطين (i) PP تتوقّف عند المدخل 00، و (ii) لا يحتوي البرنامج PP على متغيّر ذي المعرّف Yale. ومن الواضح أن الدالة HALTNOYALEHALTNOYALE ليست دلالية، لأنها ستُخرج قيمتين مختلفتين عند إدخال أحد البرنامجين المتكافئين وظيفيًا التاليين:

Yale[0] = NAND(X[0],X[0])
Y[0] = NAND(X[0],Yale[0])

و

Harvard[0] = NAND(X[0],X[0])
Y[0] = NAND(X[0],Harvard[0])

غير أن HALTNOYALEHALTNOYALE غير قابلة للحساب، لأن كل برنامج PP يمكن تحويله إلى برنامج مكافئ P′P' (بل ومحسَّن في الواقع :)) لا يحوي المتغيّر Yale. وعليه، لو استطاعنا حساب HALTNOYALEHALTNOYALE لاستطعنا تحديد التوقّف على الصفر لبرامج NAND-TM (وبالتالي لآلات تورينج أيضًا).

وفضلا عن ذلك، كما سنرى في هل كل مبرهنة قابلة للإثبات؟، هناك دوال غير قابلة للحساب مداخلها ليست برامجًا، ولذلك لا ينطبق عليها الصفة «دلالية».

وتُعرف الخصائص مثل «البرنامج يحوي المتغيّر Yale» أحيانًا بالخصائص الصياغية (syntactic). وكلمتا «دلالية» و«صياغية» تُستعملان خارج نطاق لغات البرمجة أيضًا: فمن أشهر الأمثلة على جملة صحيحة صياغيًا لكنها خالية من المعنى الدلالي في الإنجليزية هي جملة تشومسكي الشهيرة "Colorless green ideas sleep furiously." لكن تعريف «الخصائص الصياغية» تعريفًا رسميًا أمر دقيق نوعًا ما، ولن نستعمل هذه المصطلحات في هذا الكتاب، ملتزمين بمصطحلَي «دلالية» و«غير دلالية» فقط.

التوقّف ونظرية رايس لنماذج تورينج الكاملة الأخرى

كما رأينا سابقًا، تبيّن أن كثيرًا من نماذج الحوسبة الطبيعية متكافئة فيما بينها، بمعنى أننا نستطيع تحويل «برنامج» من نموذج (مثل تعبير λ\lambda، أو configurations لعبة الحياة) إلى نموذج آخر (مثل برنامج NAND-TM). وهذا التكافؤ يعني أننا نستطيع ترجمة عدم قابلية حساب مشكلة التوقّف لبرامج NAND-TM إلى عدم قابلية الحساب لمسألة التوقّف في النماذج الأخرى.

فمثالًا:

مبرهنة — توقّف آلة NAND-TM

لتكن NANDTMHALT:{0,1}∗→{0,1}NANDTMHALT:\{0,1\}^* \rightarrow \{0,1\} الدالة التي، عند إدخال سلسلتين P∈{0,1}∗P\in\{0,1\}^* و x∈{0,1}∗x\in \{0,1\}^*، تُخرج 11 إذا كان برنامج NAND-TM الموصوف بـ PP يتوقّف عند المدخل xx وتُخرج 00 بغير ذلك. إذن NANDTMHALTNANDTMHALT غير قابلة للحساب.

توقّف وتأمّل

مرة أخرى، هذه نقطة جيدة لتتوقّف وتحاول إثبات النتيجة بنفسك قبل قراءة البرهان أدناه.

برهان

لقد رأينا في مبرهنة — آلات تورينج وبرامج NAND-TM متكافئة أن لكل آلة تورينج MM يوجد برنامج NAND-TM مكافئ PMP_M بحيث لكل xx لدينا PM(x)=M(x)P_M(x)=M(x). وبالخصوص، هذا يعني أن HALT(M)=NANDTMHALT(PM)HALT(M)= NANDTMHALT(P_M).

والتحويل M↦PMM \mapsto P_M الناتج عن برهان مبرهنة — آلات تورينج وبرامج NAND-TM متكافئة هو تحويل بنّاء (constructive). أي إن البرهان ينتج طريقة لحساب التعيين M↦PMM \mapsto P_M. وهذا يعني أن هذا البرهان ينتج اختزالًا من مهمة حساب HALTHALT إلى مهمة حساب NANDTMHALTNANDTMHALT، وهو ما يعني أن بما أن HALTHALT غير قابلة للحساب فإن NANDTMHALTNANDTMHALT كذلك غير قابلة للحساب.

وينتقل البرهان نفسه إلى نماذج حوسبة أخرى مثل حساب λ\lambda و_المصفوفات الآلية_ (automata) ثنائية البعد (أو حتى أحادية البعد) وغيرها. وعليه فمثلًا لا توجد خوارزمية لتحديد ما إذا كان تعبير λ\lambda يُقيَّم إلى دالة الهوية، ولا خوارزمية لتحديد ما إذا كانت configuration ابتدائية في لعبة الحياة ستؤدي في النهاية إلى تلوين الخلية (0,0)(0,0) بالسواد أم لا.

وبالفعل يمكننا تعميم نظرية رايس على كل هذه النماذج. فمثلًا، إذا كانت F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} دالة غير تافهة بحيث F(P)=F(P′)F(P)=F(P') لكل برنامجَي NAND-TM متكافئين وظيفيًا P,P′P,P'، فإن FF غير قابلة للحساب، وينطبق الأمر نفسه على برامج NAND-RAM وعلى تعبيرات λ\lambda وعلى كل نماذج تورينج الكاملة الأخرى (بحسب تعريفها في تعريف — اكتمال تورينج والتكافؤ (اختياري))، وانظر أيضًا تمرين — نظرية رايس للنماذج المتكافئة تورينجيًا العامة (اختياري).

هل التحقّق البرمجي محكوم بالهزيمة؟ (نقاش)

تُستعمل البرامج على نحو متزايد في الأغراض الحرجة، سواء كانت تشغّل نظامنا المصرفي أو تُقلّع الطائرات أو تراقب المفاعلات النووية. وإذا كنا لا نستطيع حتى تقديم خوارزمية تصديق بأن برنامجًا ما يحسب دالة التكافؤ على نحو صحيح، فكيف يمكننا أبدًا أن نطمئن إلى أن برنامجًا ما يفعل ما يُفترض أن يفعله؟ الفكرة الجوهرية هي أنه يستحيل التصديق على أن برنامجًا عامًا يطابق مواصفة ما، لكنه ممكن كتابة البرنامج من الأساس بطريقة تجعل تصديقه أسهل. فمثالًا تافهًا، إذا كتبت برنامجًا بلا حلقات، فيمكنك التصديق على أنه يتوقّف. كما أنه، وإن كان من المستحيل التصديق على أن برنامجًا اعتباطيًا يحسب دالة التكافؤ، فمن الممكن تمامًا كتابة برنامج بعينه PP يمكننا رياضيًا إثبات أن PP يحسب التكافؤ. وبالفعل، كتابة البرامج أو الخوارزميات وتقديم البراهان على صحتها هو ما نفعله طوال الوقت في أبحاث الخوارزميات.

يهمّ مجالُ التحقّق البرمجي (software verification) التحقّقَ من أن البرامج المعطاة تستوفي شروطًا معيّنة. قد تكون هذه الشروط أن البرنامج يحسب دالة معيّنة، أو أنه لا يكتب أبدًا في موقع ذاكرة خطِر، أو أنه يحترم ثوابت معيّنة (invariants)، وغيرها. ورغم أن المهمّة العامة للتحقّق من ذلك قد تكون غير قابلة للحساب، فقد تمكّن الباحثون من فعل ذلك في حالات كثيرة مهمة، وخصوصًا إذا كان البرنامج مكتوبًا من الأساس بصياغة أو لغة برمجية تجعل التحقّق أسهل. ومع ذلك، يبقى التحقّق — وخاصةً تحقّق البرامج الكبيرة والمعقّدة — مهمّة شديدة الصعوبة عمليًا أيضًا، ولا يزال عدد البرامج التي ثبتت صحتها رسميًا صغيرًا إلى حد بعيد. وفضلا عن ذلك، فإن حتى صياغة النظرية الصحيحة لإثباتها (أي المواصفة) غالبًا ما تكون مهمّة غير تافهة إلى حد كبير.

المجموعة  من الدوال البولية القابلة للحساب (classRdef) مجموعةٌ فرعية صحيحة لمجموعة كلّ الدوال التي تُطابق  إلى . وفي هذا الفصل رأينا أمثلةً قليلةً على عناصرٍ في المجموعة الثانية ليست في الأولى.

خلاصة

  • هناك آلة تورينج (أو برنامج NAND-TM) شاملة UU بحيث، عند إدخال وصف لآلة تورينج MM ومدخل ما xx، تتوقّف U(M,x)U(M,x) وتُخرج M(x)M(x) إذا (وإذا فقط) كانت MM تتوقّف عند المدخل xx. وعلى خلاف الحالة في الحوسبة المنتهية (أي برامج NAND-CIRC / الدوائر)، يمكن أن يكون مدخل البرنامج UU آلة MM لها حالات أكثر من UU نفسها.

  • وعلى خلاف الحالة المنتهية، هناك بالفعل دوال غير قابلة للحساب بطبيعتها بمعنى أنها لا يمكن حسابها بـ_أيّ_ آلة تورينج.

  • وتشمل هذه ليس فقط بعض الدوال «تنازلية» (degenerate) أو «غامضة» (esoteric)، بل تشمل أيضًا دوال اهتمّ بها الناس بعمق وتخَمَّلوا إمكانية حسابها.

  • فإذا كانت أطروحة كنغ-تورينج صحيحة، فإن الدالة FF غير القابلة للحسب بحسب تعريفنا لا يمكن حساب بأي وسيلة في عالمنا الفيزيائي.

التمارين

تمرين — توقّف NAND-RAM

لتكن NANDRAMHALT:{0,1}∗→{0,1}NANDRAMHALT:\{0,1\}^* \rightarrow \{0,1\} الدالة التي، عند إدخال (P,x)(P,x) حيث PP يمثّل برنامج NAND-RAM، يكون NANDRAMHALT(P,x)=1NANDRAMHALT(P,x)=1 إذا وفقط إذا كان PP يتوقّف عند المدخل xx. برهن أن NANDRAMHALTNANDRAMHALT غير قابلة للحساب.

تمرين — التوقّف الموقوت

لتكن TIMEDHALT:{0,1}∗→{0,1}TIMEDHALT:\{0,1\}^* \rightarrow \{0,1\} الدالة التي، عند إدخال ثلاثية (M,x,T)(M,x,T) (ممثَّلة بسلسلة)، يكون TIMEDHALT(M,x,T)=1TIMEDHALT(M,x,T)=1 إذا وفقط إذا كانت آلة تورينج MM، عند المدخل xx، تتوقّف خلال TT خطوة على الأكثر (حيث تُعرَّف الخطوة بأنها تسلسل واحد من قراءة رمز من الشريط، وتحديث الحالة، وكتابة رمز جديد، و(محتملًا) تحريك الرأس).

برهن أن TIMEDHALTTIMEDHALT قابلة للحساب.

تمرين — توقّف المساحة (تحدٍّ)

لتكن SPACEHALT:{0,1}∗→{0,1}SPACEHALT:\{0,1\}^* \rightarrow \{0,1\} الدالة التي، عند إدخال ثلاثية (M,x,T)(M,x,T) (ممثَّلة بسلسلة)، يكون SPACEHALT(M,x,T)=1SPACEHALT(M,x,T)=1 إذا وفقط إذا كانت آلة تورينج MM، عند المدخل xx، تتوقّف قبل أن يبلغ رأسها الموقع TT في شريطها. (لا يهمّنا كم خطوة تعمل MM، ما دام الرأس يبقى داخل المواقع {0,…,T−1}\{0,\ldots,T-1\}.)

برهن أن SPACEHALTSPACEHALT قابلة للحساب. انظر الحاشية للتلميح.[2]

تمرين — التركيبات القابلة للحساب

لنفرض أن F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} و G:{0,1}∗→{0,1}G:\{0,1\}^* \rightarrow \{0,1\} دالتان قابلتان للحساب. لكل واحدة من الدوال التالية HH، إما أن تبرهن أن HH قابلة للحساب بالضرورة، أو تعطي مثالًا على زوج FF و GG من الدوال القابلة للحساب بحيث لا تكون HH قابلة للحساب. برهن أدّعاءاتك.

  1. H(x)=1H(x)=1 إذا وفقط إذا كان F(x)=1F(x)=1 OR G(x)=1G(x)=1.

  2. H(x)=1H(x)=1 إذا وفقط إذا كان هناك سلسلتان غير خاليتين u,v∈{0,1}∗u,v \in \{0,1\}^* بحيث x=uvx=uv (أي إن xx هو لصق uu و vv)، و F(u)=1F(u)=1 و G(v)=1G(v)=1.

  3. H(x)=1H(x)=1 إذا وفقط إذا كان هناك قائمة u0,…,ut−1u_0,\ldots,u_{t-1} من السلاسل غير الخالية بحيث F(ui)=1F(u_i)=1 لكل i∈[t]i\in [t] و x=u0u1⋯ut−1x=u_0u_1\cdots u_{t-1}.

  4. H(x)=1H(x)=1 إذا وفقط إذا كانت xx تمثيلًا سلاسلًا صالحًا لبرنامج NAND++ PP بحيث لكل z∈{0,1}∗z\in \{0,1\}^*، يُخرج البرنامج PP عند المدخل zz القيمة F(z)F(z).

  5. H(x)=1H(x)=1 إذا وفقط إذا كانت xx تمثيلًا سلاسلًا صالحًا لبرنامج NAND++ PP بحيث عند المدخل xx يُخرج البرنامج PP القيمة F(x)F(x).

  6. H(x)=1H(x)=1 إذا وفقط إذا كانت xx تمثيلًا سلاسلًا صالحًا لبرنامج NAND++ PP بحيث عند المدخل xx يُخرج PP القيمة F(x)F(x) بعد تنفيذ ما لا يزيد عن 100⋅∣x∣2100\cdot |x|^2 سطرًا.

تمرين

برهن أن الدالة التالية FINITE:{0,1}∗→{0,1}FINITE:\{0,1\}^* \rightarrow \{0,1\} غير قابلة للحساب. عند إدخال P∈{0,1}∗P\in \{0,1\}^*، نعرّف FINITE(P)=1FINITE(P)=1 إذا وفقط إذا كانت PP سلسلة تمثّل برنامج NAND++ بحيث لا يوجد سوى عدد منته من المداخل x∈{0,1}∗x\in \{0,1\}^* بحيث P(x)=1P(x)=1.[3]

تمرين — حساب التكافؤ

برهن مبرهنة — عدم قابلية حساب التحقّق من التكافؤ دون استعمال نظرية رايس.

تمرين — تكافؤ آلات تورينج

لتكن EQ:{0,1}∗:→{0,1}EQ:\{0,1\}^* :\rightarrow \{0,1\} الدالة المعرَّفة كالتالي: معطى سلسلة تمثّل زوجًا (M,M′)(M,M') من آلات تورينج، يكون EQ(M,M′)=1EQ(M,M')=1 إذا وفقط إذا كانت MM و M′M' متكافئتين وظيفيًا بحسب تعريف — الخصائص الدلالية. برهن أن EQEQ غير قابلة للحساب.

لاحظ أنك لا تستطيع استعمال نظرية رايس مباشرة، لأن هذه النظرية تتناول فقط الدوال التي تأخذ آلة تورينج واحدة كمدخل، بينما EQEQ تأخذ آلتين.

تمرين

لكل من الدالتين التاليتين، حدّد ما إذا كانت قابلة للحساب أم لا:

  1. معطى برنامج NAND-TM PP، ومدخل xx، وعدد kk، عندما نشغّل PP على xx، هل يبلغ متغيّر الفهرس i القيمة kk يومًا ما؟

  2. معطى برنامج NAND-TM PP، ومدخل xx، وعدد kk، عندما نشغّل PP على xx، هل يكتب PP يومًا ما في مصفوفة عند الفهرس kk؟

تمرين

لتكن F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} الدالة المعرَّفة كالتالي. عند إدخال سلسلة PP تمثّل برنامج NAND-RAM وسلسلة MM تمثّل آلة تورينج، يكون F(P,M)=1F(P,M)=1 إذا وفقط إذا كان هناك مدخل xx بحيث يتوقّف PP عند xx لكن MM لا تتوقّف عند xx. برهن أن FF غير قابلة للحساب. انظر الحاشية للتلميح.[4]

تمرين — قابلة للعد التكراري

نعرّف دالة F:{0,1}∗:→{0,1}F:\{0,1\}^* :\rightarrow \{0,1\} بأنها قابلة للعدّ التكراري (recursively enumerable) إذا كانت هناك آلة تورينج MM بحيث لكل x∈{0,1}∗x\in \{0,1\}^*، إذا كان F(x)=1F(x)=1 فإن M(x)=1M(x)=1، وإذا كان F(x)=0F(x)=0 فإن M(x)=⊥M(x)=\bot. (أي إن إذا كان F(x)=0F(x)=0 فإن MM لا تتوقّف عند xx.)

  1. برهن أن كل FF قابلة للحساب هي أيضًا قابلة للعدّ التكراري.

  2. برهن أن هناك FF غير قابلة للحساب لكنها قابلة للعدّ التكراري. انظر الحاشية للتلميح.[5]

  3. برهن أن هناك دالة F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} بحيث FF ليست قابلة للعدّ التكراري. انظر الحاشية للتلميح.[6]

  4. برهن أن هناك دالة F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} بحيث FF قابلة للعدّ التكراري لكن الدالة F‾\overline{F} المعرَّفة بـ F‾(x)=1−F(x)\overline{F}(x)=1-F(x) ليست قابلة للعدّ التكراري. انظر الحاشية للتلميح.[7]

تمرين — نظرية رايس: الصيغة القياسية

في هذا التمرين سنبرهن نظرية رايس بالصيغة التي تُصاغ بها عادةً في الأدبيات.

لآلة تورينج MM، عرّف L(M)⊆{0,1}∗L(M) \subseteq \{0,1\}^* لتكون مجموعة كل x∈{0,1}∗x\in \{0,1\}^* بحيث تتوقّف MM عند المدخل xx وتُخرج 11. (وتُعرف المجموعة L(M)L(M) في الأدبيات باسم اللغة التي يتعرّفها MM. ولاحظ أن MM قد تُخرج قيمة غير 11 أو قد لا تتوقّف البتّة عند مدخلات x∉L(M)x\not\in L(M).)

  1. برهن أن لكل آلة تورينج MM، إذا عرّفنا FM:{0,1}∗→{0,1}F_M:\{0,1\}^* \rightarrow \{0,1\} لتكون الدالة التي FM(x)=1F_M(x)=1 إذا وفقط إذا كان x∈L(M)x\in L(M)، فإن FMF_M قابلة للعدّ التكراري بحسب التعريف في تمرين — قابلة للعد التكراري.

  2. استعمل مبرهنة — نظرية رايس لبرهان أن لكل G:{0,1}∗→{0,1}G:\{0,1\}^* \rightarrow \{0,1\}، إذا (a) لم تكن GG دالة الصفر الثابتة ولا دالة الواحد الثابتة، و (b) لكل M,M′M,M' بحيث L(M)=L(M′)L(M)=L(M') كان G(M)=G(M′)G(M)=G(M')، فإن GG غير قابلة للحساب. انظر الحاشية للتلميح.[8]

تمرين — نظرية رايس للنماذج المتكافئة تورينجيًا العامة (اختياري)

ليكن F\mathcal{F} مجموعة كل الدوال الجزئية من {0,1}∗\{0,1\}^* إلى {0,1}\{0,1\}، وليكن M:{0,1}∗→F\mathcal{M}:\{0,1\}^* \rightarrow \mathcal{F} نموذجًا متكافئًا تورينجيًا بحسب التعريف في تعريف — اكتمال تورينج والتكافؤ (اختياري). ونعرّف الدالة F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} بأنها دلالية بالنسبة إلى M\mathcal{M} إذا كانت هناك دالة ما G:F→{0,1}\mathcal{G}:\mathcal{F} \rightarrow \{0,1\} بحيث F(P)=G(M(P))F(P) = \mathcal{G}(\mathcal{M}(P)) لكل P∈{0,1}∗P\in \{0,1\}^*.

برهن أن كل F:{0,1}∗→{0,1}F:\{0,1\}^* \rightarrow \{0,1\} دلالية بالنسبة إلى M\mathcal{M}، وليست دالة الواحد الثابتة ولا دالة الصفر الثابتة، تكون FF غير قابلة للحساب.

تمرين — آلة بَسِي بَافِر

في هذا السؤال نعرّف الصيغة من نوع NAND-TM لدالة busy beaver (انظر مقال عام 1999 لأارونسون، ومنشور مدونة عام 2017، واستعراضه عام 2020 [@aaronson20beaver]؛ وانظر أيضًا عرض تاو شديد التوصية عن كيفية قياس التقدّم العلمي للحضارة بالمقادير التي نستطيع إدراكها).

  1. ليكن TBB:{0,1}∗→NT_{BB}:\{0,1\}^* \rightarrow \mathbb{N} معرَّفة كالتالي. لكل سلسلة P∈{0,1}∗P\in \{0,1\}^*، إذا كانت PP تمثّل برنامج NAND-TM بحيث إنه عند تنفيذ PP على المدخل 00 يتوقّف خلال MM خطوة، فإن TBB(P)=MT_{BB}(P)=M. وبغير ذلك (إذا لم تكن PP تمثّل برنامج NAND-TM، أو كانت برنامجًا لا يتوقّف على 00)، فإن TBB(P)=0T_{BB}(P)=0. برهن أن TBBT_{BB} غير قابلة للحساب.

  2. ليكن TOWER(n)TOWER(n) تدل على العدد 2⋅⋅⋅2⏟n times\underbrace{2^{\cdot^{\cdot^{\cdot^2}}}}_{n\text{ times}} (أي «برجّ من قوى الاثنين» ارتفاعه nn). ولكي ندرك مدى سرعة نمو هذه الدالة، TOWER(1)=2TOWER(1)=2، و TOWER(2)=22=4TOWER(2)=2^2=4، و TOWER(3)=222=16TOWER(3)=2^{2^2}=16، و TOWER(4)=216=65536TOWER(4) = 2^{16} = 65536، و TOWER(5)=265536TOWER(5) = 2^{65536} وهو نحو 102000010^{20000}. أما TOWER(6)TOWER(6) فهو عدد كبير جدًا بحيث لا يمكن كتابته حتى بالترميز العلمي. عرّف NBB:N→NNBB:\mathbb{N} \rightarrow \mathbb{N} (من أجل «آلة بَسِي بَافِر من نوع NAND-TM») لتكون الدالة NBB(n)=max⁡P∈{0,1}nTBB(P)NBB(n) = \max_{P\in \{0,1\}^n} T_{BB}(P) حيث TBBT_{BB} معرَّفة كما في السؤال 6.1. برهن أن NBBNBB تنمو أسرع من TOWERTOWER، بمعنى أن TOWER(n)=o(NBB(n))TOWER(n) = o(NBB(n)). انظر الحاشية للتلميح[9]

ملاحظات مرجعية

كرتونة مشكلة التوقّف في الشكل التوضيحي مأخوذة من موقع تشارلز كوبر، حقوق النشر 2019 تشارلز ف. كوبر.

القسم 7.2 في [@MooreMertens11] يقدّم لمحة عامة موصى بها بشدة عن عدم قابلية الحساب. وكتاب غوبل وإشر وباخ [@hofstadter1999] كتاب علمي شهري كلاسيكي يتناول عدم قابلية الحساب وعدم البرهنة، وتحديدًا نظرية غوبل التي سنراها في هل كل مبرهنة قابلة للإثبات؟. وانظر كذلك كتاب هولت الأخير [@Holt2018].

تاريخ تعريف الدالة متشابك مع تطور الرياضيات بوصفها حقلًا. فعلى مدى سنوات كثيرة، كانت الدالة تُعرَّف (بحسب اقتباس أويلر أعلاه) ببساطةً بوسيلة حساب الخرج من المدخل. وفي القرن التاسع عشر، مع اختراع متسلسلات فورييه ومع الدراسة المنهجية للاستمرارية وقابلية الاشتقاق، بدأ الناس ينظرون إلى أنواع أكثر عمومية من الدوال، لكن التعريف الحديث للدالة على أنها تعيين اعتباطي لم يكن قد لقي قبولًا عامًّا بعد. فمثلًا، في عام 1899 كتب بوانكاري: «لقد رأينا كمًّا هائلًا من الدوال الغريبة التي تبدو مُلزَمة بأقصى حد بالتشابه مع أقل الدوال الصادقة ناطقة بأي وظيفة. ... فقد اخترعت عمدًا لإظهار أن استدلال أسلافنا كان على خطأ، ولن نستخرج منها سوى ذلك دائمًا». ويناقش [@grabiner1983gave, @Kleiner91, @Lutzen2002, @grabiner2005the] بعضًا من هذا التاريخ البديع.

وجود آلة تورينج الشاملة، وعدم قابلية حساب HALTHALT، برزما لأول مرة عند تورينج في ورقته التأسيسية [@Turing37]، وإن كانت نتائج قريبة جدًا منها قد ظهرت عند تشورش سنة قبل ذلك. وتستند هذه الأعمال إلى نظرية عدم الاكتمال (incompleteness theorem) لغوبل عام 1931، وسنناقشها في هل كل مبرهنة قابلة للإثبات؟.

وتُعطى بعض آلات تورينج الشاملة ذات الأبجدية وعدد الحالات الصغيرين في [@rogozhin1996small]، بما فيها آلة تورينج شاملة بشريط واحد وبأبجدية ثنائية لها أقل من 2525 حالة؛ وانظر أيضًا الاستعراض [@woods2009complexity]. وقد كتب آدم يديديا برمجية للمساعدة في إنتاج آلات تورينج بعدد حالات صغير. وهذا مرتبط بتسلية تصفية الشيفرة "Code Golfing"، أي حلّ مهمة حوسبة معيّنة بأقصر برنامج ممكن. وإيجاد آلة تورينج صغيرة «شديدة التعقيد» مرتبط أيضًا بمشكلة «آلة بَسِي بَافِر»، انظر تمرين — آلة بَسِي بَافِر والاستعراض [@aaronson20beaver].

وحجّة الحَجّ القطري المستخدَمة لإثبات عدم قابلية حساب F∗F^* مشتقّة من حجّة كانتور حول عدم عدّية الأعداد الحقيقية التي نوقشت في الحوسبة والتمثيل.

كان كريستوفر ستراتشي عالم حاسوب إنجليزيًا ومخترع لغة البرمجة CPL. وكان أيضًا من روّاد الذكاء الاصطناعي المبكرين، إذ برمج حاسوبًا ليلعب الداما بل ويكتب رسائل حب في مطلع الخمسينيات من القرن العشرين، انظر هذا المقال في مجلة The New Yorker وهذا الموقع.

برُهنت نظرية رايس في [@rice1953classes]. وهي تُصاغ عادةً بصيغة تختلف قليلًا عن التي استعملناها، انظر تمرين — نظرية رايس: الصيغة القياسية.

لا نناقش في الفصل مفهوم اللغات القابلة للعدّ التكراري، لكنه مغطّى باختصار في تمرين — قابلة للعد التكراري. وكالمعتاد، نستعمل اصطلاح الدالة لا اصطلاح اللغة.


  1. ارتبطت هذه الحجّة أيضًا بقضايا الوعي والإرادة الحرة. وأنا شخصيًا مشكّك في صلتها بتلك القضايا. ولعلّ المنطق هنا أن الإنسان يملك القدرة على حل مشكلة التوقّف لكنه يمارس إرّيته الحرة ووعيه باختياره ألّا يفعل ذلك. ↩︎

  2. الآلة ذات الأبجدية Σ\Sigma يمكن أن يكون لمحتويات أول TT مواقع من شريطها على الأكثر ∣Σ∣T|\Sigma|^T خيارًا. وماذا يحدث إذا أعادت الآلة configuration سبق رؤيته، بمعنى أن محتويات الشريط وموقع الرأس والحالة الحالية كلها مطابقة لما كانت عليه في.configuration سابقة أثناء التنفيذ؟ ↩︎

  3. تلميح: يمكنك استعمال نظرية رايس. ↩︎

  4. تلميح: وإن لم تكن قابلة للتطبيق مباشرة، فيمكنك بـ«تلميع» قليل إثبات ذلك باستعمال نظرية رايس. ↩︎

  5. HALTHALT لها هذه الخاصية. ↩︎

  6. يمكنك إما استعمال طريقة الحَجّ القطري لإثبات ذلك مباشرة أو إظهار أن مجموعة كل الدوال القابلة للعدّ التكراري عدّية. ↩︎

  7. HALTHALT لها هذه الخاصية: أظهر أن إذا كانت HALTHALT و HALT‾\overline{HALT} كلتاهما قابلة للعدّ التكراري فإن HALTHALT ستكون في الواقع قابلة للحساب. ↩︎

  8. أظهر أن أي GG تحقق (b) يجب أن تكون دلالية. ↩︎

  9. لن تحتاج في هذا التمرين إلى استعمال خصائص دقيقة جدًا للدالة TOWERTOWER. فمثلًا، NBB(n)NBB(n) تنمو أيضًا أسرع من دالة أكِرمان. ↩︎