Brainfuck是一种图灵完整的编程语言,仅使用8个符号(如果忽略I / O,则使用6个符号)。
将其推向图灵完整性的两个最著名的要素是[
和]
,本质上是Brainfuck的标签和goto。
通常,Brainfuck中的程序使用多套[]
,但是我想知道到底要使用多少对这些括号才能使Brainfuck Turing完整?
更简单地说,模拟n状态图灵机所需的最少支架数是多少(给定1、2和3状态图灵机的支架数)?
笔记:
我们假设磁带无限且没有计算限制。
这是一个2符号的图灵机
Brainfuck是一种图灵完整的编程语言,仅使用8个符号(如果忽略I / O,则使用6个符号)。
将其推向图灵完整性的两个最著名的要素是[
和]
,本质上是Brainfuck的标签和goto。
通常,Brainfuck中的程序使用多套[]
,但是我想知道到底要使用多少对这些括号才能使Brainfuck Turing完整?
更简单地说,模拟n状态图灵机所需的最少支架数是多少(给定1、2和3状态图灵机的支架数)?
笔记:
我们假设磁带无限且没有计算限制。
这是一个2符号的图灵机
Answers:
这是@ ais523答案的进一步发展,将其简化为仅两组括号,并且还使用了基于Golomb标尺理论的更紧凑的单元格放置方式。ais523 为该构造以及此TIO会话制作了编译器,该会话显示了通过TWM计数器的调试跟踪运行的示例所得BF程序。
像原始版本一样,这从The Waterfall Model中的程序开始,但有一些不失一般性的限制:
我们将Erdős-Turán构造与Welch-Costas数组的置换函数结合在一起,以获得具有必要属性的Golomb标尺。
(我确信这种结合的结构不是一个新主意,但我们只是从维基百科中找到并整合了这两个部分。)
让是的原根。定义功能
对于每个TWM计数器,我们分配两个BF磁带单元位置,一个后备单元和一个值单元:Ù (X )v (X )
通过的第二个属性,确实有两个不同的值可供选择。
备用单元的内容大部分时间将保持为,除非刚刚访问了其计数器,否则其值为,即计数器自复位值的两倍。值单元格将保持为相应TWM计数器值的两倍。
BF程序执行可以到达的所有其他单元格(有限数量)将保持为奇数值,因此它们始终测试为非零。初始化后这是自动的,因为所有单元格的调整都是偶数。
如果需要,可以将所有单元位置向右移动一个常数,以避免移动到初始BF磁带位置的左侧。
令为暂停计数器的值与后备单元格之间的距离,令为足以使所有计数器。那么基本的BF程序结构是
初始化 调整
[
>
[
<
]
<
]
在初始化阶段设置,就好像过去的计数器刚刚被访问和刚刚的活动单元格的回落小区所有单元到达由程序为初始值,在状态:
然后,在我们到达程序的第一个指针之前,将磁带指针移动到位置(始终为非零单元)。[
在外循环迭代的开始,磁带指针将位于计数器或。
令是下一个要访问的计数器。
移动将磁带指针放置在的位置,而不是的左侧。>
现在,内循环在步骤中向左搜索零单元格。如果计数器为零,则它将在(零)值单元格处停止;否则,它将找到备用单元。[
<
]
找到的任何一个单元将成为新的活动单元。
的调整相位调整基于相对于所述活动单元格的位置来在磁带上的各种细胞。本节仅包含+-><
命令,因此这些调整是无条件发生的。但是,由于所有与计数器相关的单元格都处于Golomb标尺模式,因此不适用于当前活动单元格的任何调整都将错过所有重要单元格,而是调整一些不相关的单元格(同时使其保持奇数)。
因此,必须为程序中的每对可能的活动单元和已调整单元对提供单独的代码,但活动单元的自我调整除外,因为自我调整仅基于相对位置,因此必须在它们之间共享。
所需的调整是:
由于所有活动单元必须以相同的值进行自我调整,因此上述第一和第二调整是必要的,对于值单元,因此对于后备单元,该值也是。这需要准备并清理后备单元格,以确保它们在value和后备分支中都恢复为。
移动表示在调整阶段结束时,磁带指针被移到活动单元的左侧。<
对于所有活性细胞其它比停止计数器的值单元,这是不相关的细胞,所以奇数和不为零,并且外循环继续进行另一迭代。
对于,指针被放置在其对应的后备单元格,对此我们在上面作了例外处理,以使其保持为零,因此程序从final退出并暂停。]
我不确定100%不能使用两组支架来做到这一点。但是,如果BF磁带的单元格允许无限制的值,那么三组括号就足够了。(为简单起见,我还假设我们可以将磁带头移到其起点的左侧,尽管由于这种构造仅使用磁带的有限区域,所以我们可以通过在磁带>
的开头添加足够多的命令来解除此限制。下面的结构需要假设Artin的猜想能够编译任意大型程序;但是,即使Artin的猜想是错误的,仍然有可能通过使用以下构造将图灵完成语言的解释器翻译为BF并通过将任意程序作为输入提供给该解释器来间接显示图灵完成性。
我们正在编译为无界BF的图灵完备语言是瀑布模型,它是最简单的已知计算模型之一。对于还不了解它的人,它由许多计数器(以及它们的初始值)以及从计数器对到整数的函数组成;程序执行包括从每个计数器中重复减去1,然后如果任何计数器为0,则将加到每个计数器(以这样的方式编写程序,即该操作不会同时发生在多个计数器上)。我的链接后面有此语言的图灵完整性证明。在不失一般性的前提下,我们假设所有计数器都具有相同的自复位值(即对于所有都是相同的;这是一个安全的假设,因为对于任何特定的,向每个添加相同的常量不会改变程序的行为。
设为计数器的数量;在不失一般性的前提下(假设Artin猜想),假设具有原始根 2。设为,其中是2的最低幂,大于。不失一般性,将小于(是多项式有界的,呈指数增长,因此任何足够大的都将起作用)。
磁带安排如下:我们用的整数对每个计数器进行编号(并且在不失一般性的前提下,我们假设只有一个停止计数器并将其编号为)。除了存储在磁带单元上的计数器0以外,大多数计数器的值都存储在磁带单元上。对于从单元-1到每个奇数编号的磁带单元,则该磁带单元始终保持为1,除非它紧接在计数器的左侧,在这种情况下,它始终保持为0。未被用作计数器的偶数个磁带单元具有不相关的值(可能为0,也可能为0) ); 超出规定范围的奇数个带单元也具有无关的值。请注意,将磁带设置为适当的初始状态仅需要将有限数量的磁带元素初始化为常数,这意味着我们可以通过一系列<>+-
指令(实际上只>+
需要)来进行初始化,因此无需括号。在初始化结束时,我们将磁带指针移到单元格-1。
我们程序的总体形状如下所示:
初始化 调整
[>>>[
>
[
<
]>-]
<<<]
初始化将磁带放入期望的形状,并将指针放在单元格-1上。这不是计数器左侧的单元格(0并非2的幂),因此它的值为1,我们进入循环。这个最外层循环的循环不变性是磁带指针(在每个循环迭代的开始和结束处)在计数器的左边三个单元格中。可以看出,只有在计数器2左侧有3个单元格时,循环才会退出(每个其他计数器的左侧有3个单元格为1,值为0意味着两个计数器的磁带位置相隔2个像元; 2的仅有的2的幂之间相差2是和,并且的二进制表示形式从的字符串变为字符串至少四次,反之亦然,因此不能与2的幂乘以1。
第二个循环重复循环计数器,使它们递减。循环不变性是磁带指针始终指向计数器。因此,当某个计数器变为0时,循环将退出-
。我们从一个柜台到另一个柜台的方式更加复杂。基本思想是从向右移动空格将把我们放在一个奇数单元格,该单元格在任何计数器的右边(是最后一个计数器,因为为正,所以为正);取模,该值等于(根据费马小定理)。最内层的循环反复向左移动空格,也不会更改模态的带单元格的索引,并且必须最终找到与模的单元格,该单元格具有该值(它将是某个计数器左侧的单元格);的,因为我们的原始根要求有完全一个这样的小区(是全等模,和是全等为任何其他,其中是以2为模的离散对数)。此外,可以看到磁带指针的位置以模在中间循环中每次增加。因此,磁带指针必须在所有计数器之间循环(按其值对取模的顺序)。因此,每次迭代,我们就会减少每个计数器(根据需要)。如果循环在迭代过程中中断,我们将在重新进入循环时继续减小操作(因为最外层循环的其余部分不会对磁带指针位置产生任何净变化)。
当计数器达到0时,中间循环中断,将我们带到“调整”代码。这基本上只是的编码;对于每对,它将到磁带元素,该元素与当前磁带指针的左/右距离相同,因为计数器的磁带位置位于计数器的左/右位置磁带位置(然后将磁带指针移回其开始位置)。每当,该距离就变成唯一的:
对于,我们显然发现移动的距离为0。但是因为所有相等,所以我们可以将其用作当前像元的调整。并且可以看出,调整代码因此为每个计数器实现了“当计数器为0时”的效果;实际代表计数器的所有单元格都将调整正确的数量,所有其他调整将影响非计数器偶数单元格(两个偶数之间的差为偶数),这对程序的行为没有影响。
因此,我们现在仅使用三对括号,就可以得到瀑布模型中到BF的任何程序的有效工作编译(包括停止行为,但不包括I / O,这对于图灵完整性而言是不需要的)。的括号足以满足图灵完整性。
2p*2^i+2i
。
[0, 1, 3, 7, 20, 32, 42, 53, 58]
p = 9)。