图灵机
图灵机(Turing Machine, TM)在自动机领域也只是大大小小机器中的一个,但因其与可计算函数的等价性使得它成为自动机领域一类比较特殊的机器。
# 确定的图灵机的形式化定义
M = ( Q , Σ , Γ , δ , q 0 , B , F )
- Q :有穷状态集
- Σ :字母表(有穷输入符号集)
- Γ :所有可以放置在输入字符串中的字符(有穷带符号集), Σ ⊆ Γ 包含字母表和空格符号
- δ :状态转移函数, δ : Q × Γ → Q × Γ × { L , R }
- q 0 :初始状态, q 0 ∈ Q
- B :空格符号, B ∈ Γ − Σ
- F :终结状态集(接受状态集), F ⊆ Q
状态转移函数 δ 表示当前状态和输入符号的笛卡尔积到下一个状态、写入符号和移动方向的映射;它的输入是当前状态+字符串中的一个符号,输出下一个状态+要将字符串中的当前符号改变为什么符号+接下来读取该字符左边还是右边的字符(不能停止不动,字符串向左向右都是无限长)。
当图灵机到达 F 中的某个状态时结束。
例如 ( q 1 , Y , L ) = δ ( q 0 , X ) 表示当前状态为 q 0 、当前读取的字符为 X ,然后图灵机的状态改变为 q 1 、将当前字符修改为 Y 、接下来读取左边的字符(“ L ”)。在状态转移图中表示为:
# 确定的图灵机的瞬时描述(Instantaneous Description, ID)
图灵机的输入虽然是有限长,在有限步内所到达的字符串的非空内容总是有限的,因此可以使用字符串和状态 q 以及 q 在字符串上的位置定义图灵机的瞬时描述:
X 1 X 2 . . . X i − 1 q X i X i + 1 . . . X n
- q 为图灵机的当前状态
- i 为图灵机当前读取的位置
- X i , i ∈ [ 1 , n ] 为图灵机在有限步内所到达的字符串的非空内容
# ID转移: ⊢
在图灵机 M 中, ( q 1 , Y , L ) = δ ( q 0 , X ) 的ID转移表示为:
X 1 X 2 . . . X i − 1 q 0 X i X i + 1 . . . X n ⊢ M X 1 X 2 . . . X i − 2 q 1 X i − 1 Y X i + 1 . . . X n
在图灵机 M 中, ( q 1 , Y , R ) = δ ( q 0 , X ) 的ID转移表示为:
X 1 X 2 . . . X i − 1 q 0 X i X i + 1 . . . X n ⊢ M X 1 X 2 . . . X i − 1 Y q 1 X i + 1 X i + 2 . . . X n
若某ID I 1 是由另一个ID I 0 经过有限步(包括0步)转移得到的,则记为 I 0 ⊢ M ∗ I 1 。
# 图灵机的语言
某个 图灵机 定义为 M = ( Q , Σ , Γ , δ , q 0 , B , F ) ,则所有的可以让 M 通过 有限步 ID转移到接受状态的字符串的集合,称为图灵机 M 的 语言 :
L ( M ) = { w ∈ Σ ∗ ∣ ( ∃ p ∈ F , α ∈ Γ ∗ , β ∈ Γ ∗ ) q 0 w ⊢ M ∗ α p β }
- 递归可枚举语言/图灵可识别语言 : L = L ( M )
- 递归语言/可判定语言 : L = L ( M ) ∧ ( ∀ w ∈ Γ ∗ ) M 能停机
注:图灵机不保证对所有字符串输入都停机。保证停机的图灵机在实际应用中是算法的好模型,是算法概念的形式化。
# 图灵机变种
以下的图灵机都可证明与确定的图灵机等价 ,但可以让图灵机的设计更加简单。
# 可以存储有限个符号的图灵机
M = ( Q ′ , Σ , Γ , δ , q 0 ′ , B , F )
- Q ′ = Q × Γ × . . . × Γ :图灵机的状态是由一个状态和多个符号组成的序列(元组)
- q 0 ′ = [ q 0 , B , . . . , B ] :图灵机的初始状态由一个状态和多个空白符组成
# 多道图灵机
M = ( Q , Σ , Γ ′ , δ , q 0 , B ′ , F )
- Γ ′ = Γ × Γ × . . . × Γ :图灵机的输入不是一个字符串而是一个固定长度的字符元组串
# 半无穷带图灵机
字符串输入只有一侧是无穷的
# 多带图灵机
- 字符串输入有多个
- 图灵机在每个字符串上可以处于不同的位置
- 图灵机在每个字符串上的位置移动相互独立
- 图灵机在字符串上的移动除向左向右外,还可以是停止状态
# 非确定的图灵机(Nondeterministic Turing Machine, NTM)
M = ( Q , Σ , Γ , δ , q 0 , B , F )
-
δ
:状态转移函数,
δ
:
Q
×
Γ
→
2
Q
×
Γ
×
{
L
,
R
}
- 类比NDA,NTM的状态转移函数输出为TM状态转移函数输出元组的集合,表示当前所有可能的状态转移过程
# 计算复杂性引入
-
运行时间 :图灵机在某个输入上停机前移动的步数
-
时间复杂度 T ( n ) :图灵机 M 在所有长度为 n 的输入上的运行时间的最大值。
-
只有保证停机的图灵机 T ( n ) 才有意义
-
只有多项式时间的 T ( n ) 才能在实际的计算机上可解
上面这些图灵机变种都与确定的图灵机等价,它们都能用来模拟确定的图灵机(显然),也都能被确定的图灵机所模拟。接下来看看如何模拟并分析一下模拟的时间复杂度。
# 用确定的图灵机模拟可以存储有限个符号的图灵机
显然,令确定的图灵机的状态集合为可以存储有限个符号的图灵机的所有可能的状态和存储符号的组合即可。模拟移动 n 步的时间复杂度为 O ( n ) 。
# 用确定的图灵机模拟多道图灵机
显然,令确定的图灵机的输入为字符元组就是一个多道图灵机了。模拟移动 n 步的时间复杂度为 O ( n ) 。
# 用确定的图灵机模拟可以存储有限个符号的多道图灵机
显然,令确定的图灵机的状态集合为可以存储有限个符号的图灵机的所有可能的状态和存储符号的组合,并令其输入为字符元组即可。模拟移动 n 步的时间复杂度为 O ( n ) 。
# 用可以存储有限个符号的多道图灵机模拟多带图灵机
思路:对于 k 带图灵机,用 2 k 道图灵机模拟之。对于每个带,都用两个道模拟,一个道存带的内容,一个道存图灵机在当前带的位置。
- 从左到右扫描一次,存储图灵机在所有带的位置和对应位置的输入
- 执行状态转移函数,存储图灵机在所有带的移动状态和要修改动作
- 从右到左扫描一次,按照移动状态修改道上的位置记录、按照修改动作修改道上的数据
- 重复1~3直到可接受状态
模拟移动1步需要左右扫描一次,时间复杂度 O ( n ) ,因此模拟移动 n 步的时间复杂度为 O ( n 2 ) 。
# 用多带图灵机 M 模拟NTM N :广度优先搜索
思路:同NDA一样,NTM的运行过程也可以看作是树,其节点是ID,分支是由于NTM选择了多个状态转移而产生多个ID转移进而产生多个ID。若要用“串行”的图灵机模拟之,则可考虑对NTM运行时树上的ID进行广度优先搜索。
M 有两条带,第一条带保存 N 中产生而未处理的ID,第二条带用于对ID进行处理。
- 把第一条带开头的ID复制到第二条带
- 若第二条带上的ID可接受则停止
- 否则将第二条带上的可能的ID转移复制到第一条带的末端
- 抹去第二条带开头的ID
- 重复1~4
模拟每个ID都要读取复制和删除长度为 n 的ID,时间复杂度 O ( n ) ,若每一个ID至多产生 m 个选择,那经过 n 步要模拟 ∑ i = 1 n m i = m − 1 m n + 1 − 1 个ID,总的时间复杂度为 O ( n m n ) 。
# P = N P 问题
前面分析出来了用NTM能用多带图灵机进行模拟,但模拟需要指数时间,但这只是一种最直观的模拟方法,是否存在多项式时间的模拟方法?目前还是未知的。
这个问题可以概括为:NTM以多项式时间解决的问题,TM是否也可以以多项式时间解决?
简称 P = N P 问题。其中
- P 表示“Polynomial”——“多项式”,指 确定的图灵机 在 多项式时间内 可以解决的问题的问题类
- N P 表示“Non-Deterministic Polynomial”——“非确定的多项式”,指 非确定的图灵机 在 多项式时间内 可以解决的问题的问题类
- “ N P 完全”表示任何NP问题都可以在多项式时间内规约到这个问题
虽然问题目前还没解决,但是实际应用中通常认为 P = N P 。
# 图灵机的二进制表示
显然,由 0 和 1 组成的字符串可以编码任何的字符系统,因此所有的图灵机都可以编码为 Σ = { 0 , 1 } 上的图灵机。
# 对 Σ ∗ = ( 0 + 1 ) ∗ 中的字符串编码
将 ( 0 + 1 ) ∗ 按长度和字典序进行排序,可以发现第 i 个串 w i 开头加1就是 i 的二进制表示:
( i ) 2 = 1 w i
因此可以构造如下编码
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | … |
---|---|---|---|---|---|---|---|---|
( i ) 2 | 1 ε | 1 0 | 1 1 | 1 0 0 | 1 0 1 | 1 1 0 | 1 1 1 | … |
w i | ε | 0 | 1 | 0 0 | 0 1 | 1 0 | 1 1 | … |
# 对图灵机的状态转移函数编码
-
令
Q
=
{
q
1
,
q
2
,
…
,
q
∣
Q
∣
}
,从而每一个状态可以由一个数字表示
- 开始状态为 q 1 ,终止状态为 q 2
- 令 Γ = { X 1 , X 2 , … , X ∣ Γ ∣ } ,从而输入字符串的每一个符号可以由一个数字表示
- 令移动方向 L = D 1 、 R = D 2 ,从而移动方向可以由一个数字表示
因此,图灵机的每一个状态、输入符号和移动方向都可以由一个数字表示,进而根据 0 1 字符串的编码规则,它们也都可以由 ( 0 + 1 ) ∗ 中的字符串表示。
由于图灵机的状态转移函数 δ : Q × Γ → 2 Q × Γ × { L , R } 是离散的,因此可以被表示为一系列 状态转移规则 的集合:
Δ = { ( q , X ) → ( q ′ , X ′ , D ) ∣ q , q ′ ∈ Q ∧ X , X ′ ∈ Γ ∧ D ∈ { L , R } }
在此定义下的状态转移函数则表示为:
δ ( q , X ) = ( q ′ , X ′ , D ) ( q , X ) → ( q ′ , X ′ , D ) ∈ Δ
而根据上述编码规则,任何一个转移规则 ( q i , X j ) → ( q k , X l , D m ) ∈ Δ 都可以用一个五元组 ( i , j , k , l , m ) 唯一表示。因此,我们可以将状态转移规则编码为5个由字符 0 构成的字符串,中间以字符 1 分隔:
C = 0 i 1 0 j 1 0 k 1 0 l 1 0 m δ ( q i , X j ) = ( q k , X l , D m )
# 对图灵机编码
根据上面的分析可以看出,所有的图灵机的状态、输入符号和移动方向都可以由相同的编码方式表示,不同的图灵机本质上只在转移规则上有所不同,因此对一个图灵机的编码就是对其转移规则的编码。
因此,根据上述对图灵机的状态转移函数编码规则,我们可以将图灵机编码为一个由状态转移规则的编码组成的字符串,中间用两个字符 1 分隔:
C 1 1 1 C 2 1 1 C 3 1 1 … C n − 1 1 1 C n
即得到图灵机编码,也即图灵机的二进制表示。
进而根据对 Σ ∗ = ( 0 + 1 ) ∗ 中的字符串编码规则,我们又可以将图灵机的编码对应到一个数字 i ,进而又可以定义“第 i 个图灵机” M i :
图灵机 M i : = 编码为 w i 的图灵机
# 通用图灵机
# 对角化语言 L d
对角化语言是所有不能接受自身编码的图灵机的编码组成的集合:
L d = { w i ∣ w i ∈ L ( M i ) }
注: L d 为什么叫做“对角化”?把编码按顺序排成一张表,行为图灵机,列为编码字符串,表内容为“接受”或“拒绝”, L d 就是对角线上的内容为“接受”的格所对应的列。
图灵机 → | ||||||
---|---|---|---|---|---|---|
字符串 ↓ | M 1 | M 2 | M 3 | M 4 | M 5 | … |
w 1 | 拒绝 | 拒绝 | 接受 | 接受 | 拒绝 | |
w 2 | 接受 | 拒绝 | 拒绝 | 接受 | 拒绝 | |
w 3 | 拒绝 | 接受 | 接受 | 拒绝 | 拒绝 | |
w 4 | 拒绝 | 拒绝 | 接受 | 接受 | 接受 | |
w 5 | 接受 | 接受 | 拒绝 | 拒绝 | 拒绝 | |
⋮ |
# 证明对角化语言不是图灵可识别语言(不存在识别它的图灵机)
假设有一个图灵机 M i 识别对角化语言:
L d = L ( M i )
那么有对于它的编码 w i :
⇔ ⇔ ⇔ ⇒ w i ∈ L d w i ∈ { w i ∣ w i ∈ L ( M i ) } w i ∈ L ( M i ) w i ∈ L d 矛盾 L d 的定义 L d 的定义 L d = L ( M i )
因此识别对角化语言的图灵机不存在,故对角化语言不是递归可枚举语言。
# 通用语言 L u
根据上文所属的编码方式,我们可以将图灵机 M i 的编码 w i 和这个图灵机接受的某个输入串 w ∈ Γ ∗ 的编码组成一个字符串,中间以三个字符 1 进行分隔:
w i 1 1 1 w
进而构造一种“通用语言”:
L u = { w i 1 1 1 w ∣ w ∈ L ( M i ) ∧ i ∈ N }
# 证明通用语言是图灵可识别语言(通用图灵机 U )
可以构造一个多带图灵机 U ,当输入 w i 1 1 1 w ∈ L u 时:
- 读取 w i 写到第一条带上
- 读取 w 写到第二条带上
- 第三条带存储 M i 的状态
从而模拟图灵机 M i 在 w 上的活动。进而 w ∈ L ( M i ) ⇒ w i 1 1 1 w ∈ L ( U ) ⇒ L u = L ( U ) 。因此通用语言是图灵可识别语言。
这里的 U 被称为“通用图灵机”,是现代计算机的理论基础。 U 的编码是可以写出来的,罗杰 · 彭罗斯在《皇帝的新脑》中就给出过一个 U = M i 的十进制 i 值,一共有1654位。
# 证明通用语言不是可判定语言(不能保证所有输入全部停机)
我们可以用通用语言 L u 的编码方式表示 L d ,它显然是 L u 的子集:
L d u = { w i 1 1 1 w i ∣ w i ∈ L ( M i ) } ⊂ L u
进而: