|
| 1 | +Title: 从字符串替换到图灵机:A=B 的完备性构造 |
| 2 | +Date: 2025-10-01 10:00 |
| 3 | +Category: 理论计算机 |
| 4 | +Tags: 图灵完备性, 字符串重写系统, A=B, Thue, Post |
| 5 | +Slug: ab-turing-completeness |
| 6 | + |
| 7 | +## 0. 背景:A=B 是什么 |
| 8 | + |
| 9 | +A=B 是在一款[解谜游戏](https://store.steampowered.com/app/1720850/AB/)中引入的一种极简编程语言。它的语法只有一种形式: |
| 10 | + |
| 11 | +``` |
| 12 | +A = B |
| 13 | +``` |
| 14 | + |
| 15 | +含义是“在字符串中找到子串 `A`,并把它替换为 `B`”。程序运行过程如下: |
| 16 | + |
| 17 | +1. 从输入串开始; |
| 18 | +2. 逐条检查规则,从**第一条规则**开始,寻找**第一个匹配的左部**; |
| 19 | +3. 一旦找到,就立即执行替换; |
| 20 | +4. 然后从头再来(回到规则表开头); |
| 21 | +5. 如果没有任何规则可用,则程序停机,并输出当前字符串。 |
| 22 | + |
| 23 | +在游戏后期,会出现扩展关键字(如 `(start)` 匹配开头、`(end)` 匹配结尾、`(once)` 限制只替换一次、`(return)` 表示立即输出并停机),它们能让表达力更强。但关键是:**即使完全不依赖这些扩展,A=B 也已经足够强大,可以达到图灵完备性**。 |
| 24 | + |
| 25 | +### 什么是“图灵完备”? |
| 26 | + |
| 27 | +**图灵完备**表示该系统能模拟任意图灵机:只要时间与存储足够,任何可计算的算法都能实现。直观地,它意味着: |
| 28 | + |
| 29 | +* 能够存储和操作任意量的信息; |
| 30 | +* 能够分支(条件判断); |
| 31 | +* 能够循环(无限计算,直到停机)。 |
| 32 | + |
| 33 | +证明 A=B 图灵完备,就是证明它并非“替换小游戏”,而是具备通用计算能力的编程语言。 |
| 34 | + |
| 35 | +## 1. 理论背景:字符串重写系统为何图灵完备? |
| 36 | + |
| 37 | +早在 20 世纪初,数学家 **Axel Thue** 就提出了**字符串重写系统**(Thue system),研究如何通过规则替换来生成和变换字符串。后来,**Emil Post** 进一步发展出 **Post 规范系统**,并证明这类系统足以表达任意可计算过程。 |
| 38 | + |
| 39 | +核心结论是:**半 Thue 系统(Semi-Thue system,即字符串重写系统)能够模拟任意图灵机**。其思路是将“图灵机的一个配置(状态 + 带子内容)”编码成一个字符串,再用重写规则逐步执行机器的转移函数。 |
| 40 | + |
| 41 | +下面是维基百科条目给出的一个**标准构造**: |
| 42 | + |
| 43 | +* 用字母表中的若干符号表示带子符号($S_k$); |
| 44 | + |
| 45 | +* 用一个**唯一的**状态标记($q_i$)表示当前机内状态,并保证它在配置中**恰好出现一次**。其右侧符号即为当前读头所在位置的带子符号; |
| 46 | + |
| 47 | +* **向右移动的转移** |
| 48 | +在图灵机里,*“向右移动”* 的意思是:读写头在处理完当前位置后,**把读写位置移动到右边的一个格子**。 |
| 49 | + |
| 50 | + $$ |
| 51 | + \delta(q_i, S_k) = (q_j, S_l, \rightarrow) |
| 52 | + $$ |
| 53 | + |
| 54 | + 对应的重写规则是 |
| 55 | + |
| 56 | + $$ |
| 57 | + q_i S_k \to S_l q_j |
| 58 | + $$ |
| 59 | + |
| 60 | + **解释:** |
| 61 | + |
| 62 | + * $\delta$:转移函数; |
| 63 | + * $q_i$:当前状态; |
| 64 | + * $S_k$:当前读到的符号; |
| 65 | + * $S_l$:要写回去的新符号; |
| 66 | + * $q_j$:更新后的状态; |
| 67 | + * $\rightarrow$:表示读头右移; |
| 68 | + * 规则的含义是:把「状态 + 符号」替换为「新符号 + 新状态」,等价于完成写入并把状态标记移动到右边。 |
| 69 | + |
| 70 | +* **向左移动的转移** |
| 71 | + 在图灵机里,*“向左移动”* 的意思是:读写头在处理完当前位置后,**把读写位置移动到左边的一个格子**。 |
| 72 | + |
| 73 | + $$ |
| 74 | + \delta(q_i, S_k) = (q_j, S_l, \leftarrow) |
| 75 | + $$ |
| 76 | + |
| 77 | + 对应一簇规则(需对左邻符号 $S_p$ 枚举): |
| 78 | + |
| 79 | + $$ |
| 80 | + S_p q_i S_k \to q_j S_p S_l |
| 81 | + $$ |
| 82 | + |
| 83 | + **解释:** |
| 84 | + |
| 85 | + * 当读头左移时,必须知道左边的符号 $S_p$; |
| 86 | + * 左邻符号 + 状态标记 + 当前符号,一起被替换成「新状态 + 左邻符号 + 新符号」; |
| 87 | + * 这使得状态标记成功左移,同时完成写入操作。 |
| 88 | + |
| 89 | +* **无限带子的处理** |
| 90 | +为了模拟“无限长”的带子,需要在两端加哨兵符号 $h$,并加入特殊的延展规则,使得机器在靠近边界时可以“创造”新的空白格子,从而对应无限内存的假设。 |
| 91 | + |
| 92 | +由于**每次重写都必须包含且仅包含一个 $q_i$**,所以在任意时刻都只有**唯一可用的匹配位置**。整个替换过程严格对应图灵机的一步步执行。因此,字符串重写系统具备完整的计算能力,也就是**图灵完备**。 |
| 93 | + |
| 94 | + |
| 95 | +## 2. 核心命题与证明纲要(把任意图灵机编译成 A=B 程序) |
| 96 | + |
| 97 | +**命题.** A=B(即使不用任何关键字)也是图灵完备的。 |
| 98 | + |
| 99 | +**证明思路(构造式归约)** |
| 100 | +给定任意一台**确定性的**单带图灵机: |
| 101 | + |
| 102 | +$$ |
| 103 | +M = (Q, \Gamma, \sqcup, \delta, q_0, q_{\text{halt}}) |
| 104 | +$$ |
| 105 | + |
| 106 | +**解释:** |
| 107 | + |
| 108 | +* $Q$:有限的状态集合; |
| 109 | +* $\Gamma$:带子符号集合; |
| 110 | +* $\sqcup$:空白符; |
| 111 | +* $\delta$:转移函数,定义“遇到某符号时怎么写、状态怎么变、头怎么动”; |
| 112 | +* $q_0$:初始状态; |
| 113 | +* $q_{\text{halt}}$:停机状态。 |
| 114 | + |
| 115 | +构造一组 A=B 规则,使其在任意初始输入编码上**逐步等价**地重写到 $M$ 的后续配置,直到停机。 |
| 116 | + |
| 117 | +1. **编码配置** |
| 118 | + 用字符串来编码一台机器的状态: |
| 119 | + |
| 120 | + $$ |
| 121 | + h , L , q_i , R , h |
| 122 | + $$ |
| 123 | + |
| 124 | + **解释:** |
| 125 | + |
| 126 | + * $L$:读头左边的带内容; |
| 127 | + * $R$:读头当前位置以及右边的内容; |
| 128 | + * $q_i$:当前状态,只出现一次; |
| 129 | + * 两端的 $h$ 是哨兵,确保机器永远不会“掉出带子”。 |
| 130 | + |
| 131 | +2. **生成规则** |
| 132 | + 对每条转移 $\delta(q_i,S_k) = (q_j,S_l,\text{dir})$,生成对应的 A=B 规则: |
| 133 | + |
| 134 | + * 右移: |
| 135 | + $$ |
| 136 | + q_i S_k \to S_l q_j |
| 137 | + $$ |
| 138 | + |
| 139 | + * 左移(对所有 $S_p \in \Gamma$): |
| 140 | + $$ |
| 141 | + S_p q_i S_k \to q_j S_p S_l |
| 142 | + $$ |
| 143 | + |
| 144 | + * 遇到带子右端($S_0=\sqcup$): |
| 145 | + $$ |
| 146 | + h q_i S_k \to h q_j S_0 S_l |
| 147 | + $$ |
| 148 | + |
| 149 | + 如果进入停机状态 $q_{\text{halt}}$,没有进一步规则匹配,程序就自然停机。即使没有 `(return)`,停机时当前字符串就是输出。 |
| 150 | + |
| 151 | +3. **正确性** |
| 152 | + * **唯一匹配位置**:每个串里只有一个 $q_i$,所以只有一个规则能触发;这与 A=B 的“从左到右、按顺序找”完全兼容。 |
| 153 | + * **一步对应**:每条替换规则严格模拟图灵机的一步(写入、移动、更新状态)。 |
| 154 | + * **停机**:进入 $q_{\text{halt}}$ 后没有规则匹配,A=B 程序停机。 |
| 155 | + |
| 156 | +因此,A=B 可以模拟任意图灵机,所以它是**图灵完备的**。 $\square$ |
| 157 | + |
| 158 | +--- |
| 159 | + |
| 160 | +## 3. 举例:计数器程序(用例证法说明完备性) |
| 161 | + |
| 162 | +上节我们给出了严格的归约证明,这里再展示一个**具体程序**: |
| 163 | + |
| 164 | +**把输入的二进制数($1 \leq n \leq 63$)转换成对应数量的 `a`** |
| 165 | + |
| 166 | +### 程序规则 |
| 167 | + |
| 168 | +``` |
| 169 | +0 = $X$ |
| 170 | +1 = $Y$ |
| 171 | +$$ = |
| 172 | +YXXXXX$ = XXXXX$aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa |
| 173 | +YXXXX$ = XXXX$aaaaaaaaaaaaaaaa |
| 174 | +YXXX$ = XXX$aaaaaaaa |
| 175 | +YXX$ = XX$aaaa |
| 176 | +YX$ = X$a |
| 177 | +Y$ = X$a |
| 178 | +$X = |
| 179 | +$ = |
| 180 | +``` |
| 181 | + |
| 182 | +--- |
| 183 | + |
| 184 | +### 与图灵机构造的对应关系 |
| 185 | + |
| 186 | +1. **字母表(Alphabet)** |
| 187 | + * 符号集合 $\Gamma$:`0,1,X,Y,$,a`。 |
| 188 | + * 就像图灵机带子上的有限符号集。 |
| 189 | +2. **状态(States)** |
| 190 | + * 在一般构造中,状态由 $q_i$ 标记。 |
| 191 | + * 在这里,「状态」由当前匹配的模式体现: |
| 192 | + * 匹配 `YXXX$` = “状态 = 等待展开 8 个 a”; |
| 193 | + * 匹配 `YX$` = “状态 = 等待展开 2 个 a”。 |
| 194 | + * 所以规则本身就扮演了转移函数 $\delta$。 |
| 195 | +3. **读写头(Head)** |
| 196 | + * 在 A=B 里没有显式的“头”,但每次替换只能在**一个匹配窗口**里发生: |
| 197 | + * 例如 `YXXX$ → XXX$aaaaaaaa`:可以看成**读写头在 Y 上**,读到右边 3 个 X 和 `$`,然后写出 `a` 并右移。 |
| 198 | + * 例如 `YX$ → X$a`:可以看成**读写头在 Y 上**,它左边的 X 会被保留,头位置连带移动到右边继续展开。 |
| 199 | +4. **右移的体现** |
| 200 | + * 替换 `YXXX$ → XXX$aaaaaaaa`: |
| 201 | + * 相当于图灵机在 Y 所在格写入若干 a; |
| 202 | + * 然后状态标记(匹配窗口)自动“滑到右边的 $”处,继续执行。 |
| 203 | + * 这对应于「写入后头向右移」。 |
| 204 | +5. **左移的体现** |
| 205 | + * 在展开尾部规则 `Y$ → X$a` 中: |
| 206 | + * 当 Y 已经贴近 `$` 时,替换会把 `$`左边的 X 替出来,并在 Y 的左边补上 a; |
| 207 | + * 这等价于**把读写头往左看一格**,再进行展开。 |
| 208 | + * 整个效果就和「写入后头左移」一致。 |
| 209 | +6. **带子与哨兵(Tape & Sentinel)** |
| 210 | + * 符号 `$` 就是带子的边界标记; |
| 211 | + * 末尾两条规则会逐步清理辅助符号,等价于无限带的“空白格”处理。 |
| 212 | +``` |
| 213 | +$X = |
| 214 | +$ = |
| 215 | +``` |
| 216 | + |
| 217 | + |
| 218 | + |
| 219 | +### 为什么这个例子能说明图灵完备性? |
| 220 | + |
| 221 | +* **存储**:输入二进制串被转写成 Y/X/$ 的带子配置。 |
| 222 | +* **分支**:不同的规则(`YXXX$`, `YXX$`, `YX$`, …)体现条件分支。 |
| 223 | +* **循环**:展开过程需要不断触发相同的规则,直到消耗完所有 Y,体现迭代。 |
| 224 | +* **左/右移动**:匹配窗口的替换效果对应于头在带子上左右移动。 |
| 225 | +* **停机**:当所有符号都归约成 `a`,再无规则可用时,程序自然停机。 |
| 226 | + |
| 227 | +所以,这个计数器程序已经在完整地模拟图灵机的运行: |
| 228 | + |
| 229 | +* **字母表** → `{0,1,X,Y,$,a}`; |
| 230 | +* **状态** → 匹配模式决定; |
| 231 | +* **读写头** → 当前匹配窗口位置决定; |
| 232 | +* **左右移动** → 替换结果把窗口推到左/右; |
| 233 | +* **停机** → 无规则可用。 |
| 234 | + |
| 235 | +这说明 A=B 并非“看似字符串替换”,而是真正能模拟一台图灵机。 |
| 236 | + |
| 237 | +## 4. 顺序/左端优先会不会削弱能力? |
| 238 | + |
| 239 | +不会。因为在构造中我们保证了**唯一状态标记 $q_i$**: |
| 240 | + |
| 241 | +* 每条规则都包含且仅包含一个 $q_i$; |
| 242 | +* 串中也只有一个 $q_i$; |
| 243 | +* 因此始终只有唯一匹配。 |
| 244 | + |
| 245 | +所以,不管是左端优先还是其他策略,运行轨迹都是唯一的,能力不受影响。 |
| 246 | + |
| 247 | +--- |
| 248 | + |
| 249 | +## 5. 关系图(理论坐标系) |
| 250 | + |
| 251 | +* **A=B**:一个带优先级与锚点关键字的字符串替换语言。 |
| 252 | +* **Semi-Thue / SRS**:字符串重写系统,图灵完备。 |
| 253 | +* **Post 规范系统**:可化归为 SRS,同样图灵完备。 |
| 254 | +* **Thue 语言**:非确定性重写为核心的怪诞语言,图灵完备。 |
| 255 | + |
| 256 | +--- |
| 257 | + |
| 258 | +## 6. 结语 |
| 259 | + |
| 260 | +* **形式化**:任意图灵机都能编译成 A=B 规则,逐步等价执行 → 图灵完备。 |
| 261 | +* **直观例子**:A+B 展现了进位传播,A–B 展现了借位传播;它们分别是**算术电路的基石**,而算术电路+控制逻辑=通用机。 |
| 262 | + |
| 263 | +因此,A=B 不只是一个小游戏,而是一个极简却**图灵完备**的语言。 |
| 264 | + |
| 265 | +p.s. [一些参考解法](/A2B.html) |
0 commit comments