首页 > 其他分享 >什么是图灵完备?手把手教你证明brainfuck的图灵完备性

什么是图灵完备?手把手教你证明brainfuck的图灵完备性

时间:2024-10-07 13:32:49浏览次数:9  
标签:完备 读写 图灵 t1 brainfuck 格局 图灵机 Gamma

Intro

上篇文章中对图灵机的讨论是错误的,因为那篇文章中试图去使用一个具体的机器去指代图灵机,这会造成极大的误解。
本文将会解决这些问题。

Tips:发现错漏请指出,我尽力修改( ;´д`)

图灵机

图灵机的形式化定义如下

图灵机是一个七元组(\(Q,\Sigma,\Gamma,\delta,q_0,q_{accept},q_{reject}\))其中\(Q,\Sigma,\Gamma\)都是有穷集合。

  1. \(Q\)是状态集
  2. \(\Sigma\)是输入字母表,不包括空白符号\(\sqcup\)
  3. \(\Gamma\)是带字母表,其中\(\sqcup \in \Gamma,\Sigma \subseteq\Gamma\)
  4. \(\delta : Q \times \Gamma \to Q \times \Gamma \times \{L,R\}\)是转移函数
  5. \(q_0 \in Q\)是起始状态
  6. \(q_{accept} \in Q\)是接收状态
  7. \(q_{reject} \in Q\)是拒接状态,并且\(q_{rejecct}\not ={q_{accept}}\)

图灵机\(M\)的工作方式如下:

  1. \(M\)接收方格带上的输入\(w = w_1w_2...w_n \in \Sigma^*\),方格带上除去\(w\)其余保持空白(填入空白符号)。
  2. \(M\)开始运行,按转移函数所描述的规则运行。如果读写头在最左端试图左移,则读写头不动,其他照常运行。
  3. 不断运行直到\(M\)进入接收状态或者拒绝状态。
  4. 如果最终\(M\)无法进入这两种状态,则M将永远运行下去,不会停机。

图灵机可以形式化描述,图灵机的计算过程自然也能形式化描述。这需要引入一个新的概念——格局

图灵机计算过程中,将当前状态、当前带内容与读写头位置组合在一起,称为图灵机的格局。
格局常以特殊的方法表示,对于状态\(q\)与当前带上被读写头分割的两个字符串\(u\)和\(v\),以\(uqv\)表示如下格局:
当前状态是\(q\),当前带内容是\(uv\),读写头当前的位置是\(v\)的第一个附后,带上\(v\)的最后一个符号之后的符号都是空白符。

如果图灵机能从格局\(C_1\)一步进入\(C_2\),则称格局\(C_1\)产生格局\(C_2\)
于是,对图灵机计算进行形式化描述即为:

设\(a,b,c\)均为\(\Gamma\)中的符号,\(u\)和\(v\)是\(\Gamma^*\)中的字符串,\(q_i\)和\(q_j\)是状态,则\(uaq_ibv\)和\(uq_jacv\)是两个格局,如果转移函数满足\(\delta(q_i,b)=(q_j,c,L)\)则说:
\(uaq_ibv\)产生\(uq_jacv\)
上面是左移的情形,下面是右移的情形:
如果\(\delta(q_i,b)=(q_j,c,R)\),则说
\(uaq_ibv\)产生\(uacq_iv\)
当读写头处于左端点或者右端点时,这个情形会发生变化,
左端点下,左移是 \(q_ibv\)产生\(q_jcv\),右移是 \(q_ibv\)产生\(cq_jv\)
右端点下,\(uaq_i\)等价于\(uaq_i\sqcup\),这是由于假设了带子上没有描述的位置都是空白符,这样就只需要正常处理就行了。

M在输入\(w\)上的起始格局是\(q_0w\),表示机器处在起始状态,且读写头在最左端。
处在接受状态的格局是接受格局;处在拒绝状态的格局是拒绝格局。
接受与拒绝状态都是停机状态,它们不产生新的格局。

于是我们形式化了图灵机的工作方式。
此时一个确定的输入\(w\)存在着一个确定的格局序列\(C_1,C_2,C_3...C_k\)。
如果格局序列满足:

  1. \(C_1\)是\(M\)在输入\(w\)上的起始格局。
  2. 每一个\(C_i\)产生\(C_{i+1}\)。
  3. \(C_k\)是接受格局。

我们就认为M接受输入\(w\)。
\(M\)接受的字符串的集合称为M的语言,记作\(L(M)\)

如果一个语言能被某一图灵机识别,则称该语言是图灵可识别的

我们可以很自然的想到,当图灵机接收一个输入,最终只会处在三种状态:接受、拒绝、不停机。

于是,现在我们有了一个较为准确的对图灵机的描述。

图灵完备

众所周知,想要证明一个系统是图灵完备的,就需要使得它能模拟图灵机的所有行为。

本部分思路来自Frans Faase;发现未知宏可参考Alva L. Couch的文章

brainfuck

依据前面的内容我们不难发现,一台确定的图灵机\(M\)在接收一个确定的输入\(w\)时,会产生一个确定的格局序列\(C_1,C_2,C_3...C_k\)

也就是说,图灵机的运行,可以写成一长串的格局序列。这意味着,只要能找到一个方法,让brainfuck正确的表示出这一串格局序列,就能用brainfuck模拟图灵机。

所以,我们需要找到一个办法,来让brainfuck可以描述出每一个格局。并实现格局到下一个格局的产生。

由前面的内容我们可以知道,一个格局记录3种信息:当前状态、读写头位置、当前带内容。

想用brainfuck来表达这些信息,先要做一些简单的准备工作。
我们知道一台图灵机\(M=(Q,\Sigma,\Gamma,\delta,q_0,q_{accept},q_{reject})\)。不难看出,一种图灵机仅有两种符号——\(状态 \in Q\)和\(符号 \in \Gamma\)

  1. 先映射\(\Gamma\)到自然数\(0\) ~ \(n-1\),\(n\)为符号数。特别的,先将空白符\(\sqcup\)映射到\(0\),记作\(\sqcup \to 0\)。
  2. 再映射\(Q\)到自然数\(0\) ~ \(m-1\),\(m\)为状态数。特别的,\(q_0 \to 0;q_{accept} \to 1;q_{reject} \to 2;\)。

这样,我们就能用数字来表达图灵机的全部符号了。
于是乎,我们可以开始用brainfuck来表示格局了。
当前带内容可以是是无限的,但是没关系,brainfuck能操作的数组也是无限长的。但很快我们就发现了,brainfuck的指针并不能储存状态。我们将不得不将一些额外的信息储存在数组上,并且,brainfuck想要对数据进行操作,几乎不可避免地需要一些额外的空间,但brainfuck只有一个数组。好在它是无限长的,就如希尔伯特所提出的无限旅馆问题那样,我们的这个数组完全足够。

我们规定数组的一第个位置用于储存状态,第二个位置用于储存读写头位置,第三个位置用来储存读写头当前指向的字符,第四个位置用来作为新状态的临时储存,第五个位置用来做新的读写头位置的临时储存,第六个位置用来做新字符的临时储存。
并且,由于brainfuck对数据的操作需要一些额外的空间,所以我们额外分配五个位置做临时存储位置。
后续的数组便用来存储当前带上的字符串。
所以,我们的数组是这样的

0 1 2 3 4 5 6 7 8 9 10 11 ...
state head cursymbol newstate newhead newsymbol t1 t2 t3 t4 t5 tape0 ...

我们规定数组前面的部分(0~10)为操作区,后续部分为纸带区。

brainfuck宏

brainfuck的可读性并不好,所以我们需要一些宏,用来提高可读性。

# 首先我们需要一个用来寻址的宏to(),它将展开成多个`<>`,能精确地移动到正确的位置。
# 并且我们规定这个宏只能用在操作区与纸带的第一个位置tape0之间的移动。


# 用to()给循环指定判断位置[]
for(x) = to(X)[;
next(x) = to(X)-];

# 用to()精确操作数
dec(x) = to(x)-;
inc(x) = to(x)+;

# 将s上的数字移动到d。 
move(s,d) = to(s) [ to(d) + to(s) - ];

# 如何拷贝呢?移动不只可以执行一次。
move2(s,d1,d2)= {
	for(s)
		to(d1) +
		to(d2) +
	next(s)
	}

copy(s,d,t) = move2(s,d,t) move(t,s);

# [条件判断是brainfuck唯一的条件判断,我们需要让它变得更加好用一点。

# 首先我们需要一个可以在任意位置写入0的宏。
zero(a) = to(a) [-];

# 于是现在有条件判断了。
if(a) = to(a) [;
endif(a) = zero(a) ];

ifelse(a,t) = inc(t) if(a) dec(t);
else(a,t) = endif(a) if(t);
endelse(t) = endif(t);

# 由于[是一个零跳转,所以我们很自然的认为0是False,而其余的数则是True,于是可以有逻辑运算
# 值得注意的是,三种逻辑操作都会使得原操作数被清零。s是被操作的数,d是结果输出的位置。
or(s1,s2,d) = move(s1,d) move(s2,d);
and(s1,s2,d) = if(s1) move(s2,d) endif(s1) zero(s2);
not(s,d) = inc(d) if(s) dec(d) endif(s);

# 与常数比较
# 与零比较,其实就是进行not()操作,至于其他的数?1-1=0,2-1=1...
isZero(s,d) = not(s,d);
isOne(s,d) = if(s) dec(s) isZero(s,d) endif(s);
isTwo(s,d) = if(s) dec(s) isOne(s,d) endif(s);
isThree(s,d) = if(s) dec(s) isTwo(s,d) endif(s);
....

# 图灵机运行就是不断产生新格局的过程,所以我们还需要另一个循环——while
while(X) = to(X)[;
wend(X)  = to(X)];

# 接下来要处理读写头的读写操作,我们需要新的移动宏,用来移动到纸带上。
# 这是两个特殊的宏,它只有在输入被确定后才替换。
# {(*head)*>}意思是写入head位置储存的值相等数量的'>',后面的同理
totape() = to(tape0){(*head)*>};
back() = {(*head)*<}

# 获取/写入字符
# 其实这是一个改写过的copy(),将纸带上对应的符号复制到操作区里。
getsymbol(x,t1) ={
	totape()[
		back()
		to(d1) +
		back()
		to(d2) +
	totape()-]
	back()
	to(t1) [ totape() + back()to(t1) - ]
}

setsymbol(x) ={
	totape()
	[-]
	back()
	to(x) [ totape() + back()to(x) - ]
}
;

brainfuck is Turing complete

将指针位置存放在操作区,仅在读写纸带时前往纸带区。

依据上面所给的规定,我们来处理程序的主体部分。
它做了5件事:

  1. 判断是否停机
  2. 读取字符
  3. 按照转移函数产生一个新格局
  4. 写入更改
  5. 循环回到开头
IsOne(state,t1)
IsTwo(state,t2)
and(t1,t2,t3)
not(t3,t1)
while(t1)

getsymbol(cursymbol,t1)

/***map***/

setsymbol(newsymbol)

zero(cursymbol)
zero(head) move(newhead,head,t1)
zero(state) move(newstate,state,t1)

IsOne(state,t1)
IsTwo(state,t2)
and(t1,t2,t3)
not(t3,t1)
wend(t1)

接下来我们需要给每一个\(\delta\)定义一个映射函数
我们定义一个映射模板map。它在接受输入后,与自身规则做比较,如果不匹配,则什么都不做。
map用到了十一个参数,其中的astate,asymbol,anewstate,anewsymbol,movement,是根据相应的\(\delta\)填入的。我们需要给每一条转移函数映射一个相应的map,之后,我们只要将所有的map插进循环里,就能完成程序的主体部分了。

map(state,head,cursymbol,
  astate,asymbol,anewstate,anewsymbol,movement,
  newstate,newhead,newsymbol)
=
{
# 判断是否匹配了正确的转移函数,如果不是则直接退出。
copy(state,t1,t1)
write(t2,astate)
Equal(t1,t2,t3,t4,t5)
if(t3)
	copy(cursymbol,t1,t2)
	write(t2,asymbol)
	Equal(t1,t2,t3,t4,t5)
	if(t3)
		# 按规则写入新的符号、状态并进行移动。
		write(newstate,anewstate)
		write(newsymbol,anewymbol)
		copy(head,newhead,t1)
		ifelse(movement,t1)
			inc(newhead)
		else(movement,t1)
			dec(newhead)
		endelse(t1)
	endif(t3)
endif(t3)
}

这样,只要确定图灵机的种类与输入,我们就能将它翻译为一个brainfuck程序。
在完成运行后,只要打印出数组,就能得到这台机器运行的结果。
我们相信这个程序能翻译任何一台图灵机,并且模拟它的运行,因此可以说brainfuck是图灵完备的。

Reference

  1. BF is Turing-complete-Frans Faase:https://www.iwriteiam.nl/Ha_bf_Turing.html
  2. An introduction to programming in BF-Frans Faase:https://www.iwriteiam.nl/Ha_bf_intro.html
  3. Bfmacro: a bf macro-interpreter-Alva L. Couch:http://www.cs.tufts.edu/~couch/bfmacro/bfmacro/
  4. 《计算理论引导》-Michael Sipser -机械工业出版社

标签:完备,读写,图灵,t1,brainfuck,格局,图灵机,Gamma
From: https://www.cnblogs.com/TashiKani/p/18449942

相关文章

  • 图灵完备攻略:第一部分——基础逻辑电路搭建(附带游戏压缩包)
    作者在学习计算机组成原理时了解到了一款名为图灵完备的游戏,这是一款学习处理器架构的游戏,在游戏中你需要从门电路开始,最终搭建出属于自己的计算机。由于学习计算机组成原理的最后目的就是想让我们学会如何搭建一个CPU,因此这款游戏可以作为想要构建属于自己的CPU的前置练习,......
  • 实数完备性公理的六个推论及证明路径
    在本文中,我尝试利用实数的完备性公理,按照一定路径证明六个经典而深刻的命题,分别是单调有界定理、柯西收敛原理、确界原理、闭区间套定理、极限点原理、和有限覆盖定理,以作为我这个月数分学习的总结。也许未必值得指出,我们学校现行数分教材编排体系出现了一定程度的混乱,其根本原因......
  • HACKTHEBOX——Brainfuck
    靶机详情靶机地址:10.10.10.17攻击地址:10.10.16.3端口服务扫描首先依旧要确定攻击主机能否Ping通靶机使用nmap或者其他工具扫描目标开放了哪些端口与服务渗透过程从上图可以看到目标开放了135、139、445端口,开放了Smb服务,这个服务有个大名鼎鼎的漏洞就是永恒之......
  • 实现一个功能完备的 C++ String 类保姆指南
    本篇博客,我们将详细讲解如何从头实现一个功能齐全且强大的C++String类,并深入到各个细节。这篇博客将包括每一步的代码实现、解释以及扩展功能的探讨,目标是让初学者也能轻松理解。一、简介1.1、背景介绍在C++编程中,std::string类是最常用的字符串处理工具,它提供了丰......
  • 图灵奖获得大佬Yann LeCun看好的模型预测控制(MPC)策略是什么?
    图灵奖获得大佬YannLeCun看好的模型预测控制(MPC)策略是什么?模型预测控制(ModelPredictiveControl,MPC)作为一种先进的控制策略,近年来在工业过程控制、自动驾驶、能源系统等多个领域得到了广泛应用。凭借其对系统未来行为的预测能力,MPC在处理多变量系统、显式考虑系统约束......
  • 学习笔记-图灵完备、图灵机与Brainfuck
    前言本文是近日对图灵完备的学习所做的笔记,如有错误还请指正.本文包含以下内容:1.什么是图灵机?什么是图灵完备?什么是Brianfuck?2.对图灵机的简单模拟.3.使用Brianfuck模拟一个简单的图灵机.图灵机?AlanMathisonTuring在1937年提出了一个通用计算设备的猜想.他猜想所有......
  • [240801] 类 C 语言 C3 是一种进化,而不是一场革命 | 趣文: find + mkdir 是图灵完备
    目录类C语言C3是一种进化,而不是一场革命C3编程语言特征C3设计原则安装C3编程语言第一个C3项目趣文:find+mkdir是图灵完备类C语言C3是一种进化,而不是一场革命C3是基于C的编程语言,它是C的一种演变,其目标是在尽可能保留C相同语法情况下进行改......
  • 读人工智能全传02图灵测试
    1. 图灵测试1.1. 模仿游戏1.2. 20世纪40年代末至50年代初,第一台计算机的出现引发了一场公开辩论,辩论主题就是这一现代科学奇迹的潜力如何1.2.1. 这场辩论中最瞩目的贡献当归属于一本名叫《控制论》的书,由麻省理工学院数学教授诺伯特·维纳(NorbertWiener)撰写1.3. 自19......
  • (高清pdf集合)图灵程序设计丛书:大规模数据处理入门与实战(套装全10册)【图灵出品!一套囊括S
    书:pan.baidu.com/s/1tIHXj9HmIYojAHqje09DTA?pwd=jqso提取码:jqso数据处理基础:介绍数据处理的基本概念、流程和应用场景,帮助读者建立对数据处理的整体认识。SQL语言与应用:详细讲解SQL的语法和用法,包括数据查询、数据操作和数据定义等,以及在实际应用中的最佳实践。Python数据挖......
  • 图灵完备&图灵机&现代计算机
    图灵完备(TuringCompleteness)图灵完备是计算理论中的一个概念,用来描述一个系统或编程语言是否具备通用计算能力。一个系统或语言是图灵完备的,当且仅当它可以模拟图灵机,或者说它能够计算任何图灵机可以计算的函数。具体来说,图灵完备的系统必须能够:条件分支(ConditionalBranching......