这台Foo机器会停止吗?


43

众所周知,确定Turing机器是否停止运行还不确定,但是对于较简单的机器而言并不一定如此。

富机是一台具有有限带,其中在磁带上的每个小区具有整数或halt符号h,例如

2 h 1 -1

指令指针从指向第一个单元格开始:

2 h 1 -1
^

在每一步中,指令指针都向前移动其指向的数字,然后取反该数字。因此,经过一步,它将向前移动2单元格,并将其2变为-2

-2 h 1 -1
     ^

Foo机器会继续执行此操作,直到指令指针指向暂停符号(h)。因此,这是该程序的完整执行:

2 h 1 -1
^

-2 h 1 -1
     ^

-2 h -1 -1
         ^

-2 h -1 1
      ^

-2 h 1 1
   ^

磁带也是圆形的,因此,如果指令指针从磁带的一侧移开,它将移到另一侧,例如:

3 h 1 3
^
-3 h 1 3
       ^
-3 h 1 -3
     ^
-3 h -1 -3
         ^
-3 h -1 3
 ^
3 h -1 3
  ^

这些Foo机器的有趣之处在于,有些机器不会停止运行,例如:

1 2 h 2
^
-1 2 h 2
   ^
-1 -2 h 2
        ^
-1 -2 h -2
    ^
-1 2 h -2
        ^
-1 2 h 2
   ^

该程序将永远在最后四个状态中继续循环。

因此,编写一个确定Foo机器是否停止的程序!您可以为Foo机器使用任何(合理的)输入格式,也可以选择0用作停止符号。您可以在停止和不停止两种情况下使用任意两个不同的输出。当然,您的程序必须在有限的时间内为所有有效输入输出答案。

这是,所以请尝试使程序尽可能短!

测试用例

2 h 1 -1
Halts
3 h 1 3
Halts
h
Halts
1 1 1 1 h
Halts
2 1 3 2 1 2 h
Halts
3 2 1 1 4 h
Halts
1 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 h -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36
Halts

2 h
Does not halt
1 2 h 2
Does not halt
8 1 2 3 3 4 8 4 3 2 h
Does not halt
1 2 4 3 h 2 4 5 3
Does not halt
3 1 h 3 1 1
Does not halt
1 2 h 42
Does not halt

5
我敢肯定,关于解决这个问题的算法。我不是算法高手,所以我更倾向于在错误方向之前询问。不会停止运行的Foo机器会始终恢复到其原始状态吗?还是有“混乱的”非停止机器?
V. Courtois

5
@ V.Courtois所有非停止的Foo机器都将陷入状态循环,因为Foo机器只能处于有限的许多可能状态(指令指针可以存在n个可能的位置,而2 ^ n个可能的状态磁带配置)。每个状态只有一个“下一个状态”。因此,如果Foo机器最终回到它已经处于的状态,它将一直循环播放。因为只有有限个状态,它不能保持无序状态之间跳来跳去,因为它最终会最终将一个它已经英寸
利奥·特南鲍姆

3
建议的测试用例:(1 2 h 42不停止)
Arnauld

6
建议的测试用例:3 2 1 1 4 h。这个暂停,但需要的迭代次数大于元素数量的两倍。
Arnauld

10
建议的超长测试用例:1 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 h -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36,在786430步骤之后停止。
岩浆

Answers:


11

C#(Visual C#交互式编译器),71字节

x=>{for(int i=0,k=0,f=x.Count;i++<1<<f;k%=f)k-=(x[k]*=-1)%f-f;i/=x[k];}

在线尝试!

我不知道以下内容是否有效,因为它需要具有签名的自定义委托,unsafe delegate System.Action<int> D(int* a); 并且必须包装在unsafe要使用的块中,但是无论如何这里都是这样:

C#(.NET Core),64字节

x=>f=>{for(int i=0,k=0;i++<1<<f;k%=f)k-=(x[k]*=-1)%f-f;k/=x[k];}

在线尝试!

该函数接受一个int *并返回一个Action;换句话说,这是一个咖喱函数。我使用指针的唯一原因是因为codegolf.meta.stackexchange.com/a/13262/84206,它使我可以通过已经有一个定义了数组长度的变量来节省字节。

@someone节省了9个字节


由2个字节Golfed代码:tio.run/...
IQuick 143

@ IQuick143好的收获,谢谢
无知的体现

我不知道是否有任何优势的情况下为它不会工作,但没有违反任何的电流测试情况下,你可以取代1<<f2*f保存字节。
凯文·克鲁伊森

1
77字节,带有可怕的LINQ魔术和Arnauld的修复程序。我不知道此解决方案如何工作,所以我可能已经破解了。
某人

1
通过正常的1字节高尔夫正常传输63字节,并将IO更改为错误/无错误。链接到链接
某人

7

Python 3中63 89个字节

def f(x):
 for i in range(2**len(x)):a=x[0];x[0]=-a;b=a%len(x);x=x[b:]+x[:b]
 return a==0

在线尝试!

也适用于Python 2;可以在Python 2中保存一个字节,方法是将print替换为return,并将函数print替换为stdout而不是return。R转为True暂停和False非暂停。

感谢@Neil和@Arnauld指出我需要检查更长的时间才能停止。感谢@Jitse指出的问题[2,0]。感谢@mypetlion指出磁带值的绝对值可能会超过磁带长度。


5
好吧,我咬一口:你怎么知道x+x足够?
尼尔

4
@Neil实际上还不够。一个反例是[ 3, 2, 1, 1, 4, 0 ],它确实停止了12次以上的迭代。
阿尔诺

1
len(x)*x[8,7,6,5,7,4,0,3,6]92

2
是不是2**len(x)仍然是最大的有点短?我将状态数计算为n*(2**n)(和n=len(x)-1)。
OOBalance

1
@OOBalance我明白你的意思了,因为每个状态在每个单元格中都可以有一个指针...但是,我觉得每个单元格只能转换到另外两个单元格这一事实还存在其他限制。作为一个方面说明:没有什么挑战说,有是在输入停止状态
乔金

6

果冻15 11字节

N1¦ṙ⁸ḢƊÐLḢẸ

在线尝试!

将输入作为整数列表(使用0表示暂停)的单子链接。返回0表示停止输入,返回1表示不停止输入。

避免了需要计算迭代次数的问题,因为使用迭代ÐL会一直循环直到看不到新结果。

感谢@JonathanAllan节省了一个字节!

说明

      ƊÐL   | Loop the following as a monad until the result has been seen before:
N1¦         | - Negate the first element
   ṙ⁸       | - Rotate left by each of the elements
     Ḣ      | - Take just the result of rotating by the first element
         Ḣ  | Finally take the first element
          Ẹ | And check if non-zero

通过旋转所有条目来保存字节,然后仅保留第一个结果:N1¦ṙ⁸ḢƊÐLḢẸ
Jonathan Allan

5

Python 3,91字节

def f(a):
	s={0,};i=0
	while{(*a,)}-s:s|={(*a,)};a[i]*=-1;i-=a[i];i%=len(a)
	return a[i]==0

在线尝试!

-40个字节,得益于JoKing和Jitse


通过在第一行中进行变量分配,@ JoKing 109个字节
吉特

通过将元组转换更改为加星标的扩展来获取92个字节,而不是从空集开始并改写while条件。
吉特

@JoKing Damn,我从没学过:p。然后是93个字节
吉特


@JoKing谢谢!
HyperNeutrino

5

Perl 6的46个43 36字节

{$_.=rotate(.[0]*=-1)xx 2**$_;!.[0]}

在线尝试!

表示暂停,0如果机器停止,则返回true。这会重复逻辑2**(length n)时间,如果指针最终停在停止单元格上,它将停留在那里,否则指针将处于非停止单元格上。之所以2**n可行,是因为Foo机器仅处于可能的状态(忽略暂停单元),因为每个非暂停单元只有两个状态。好的,是有状态的,但是由于指针(以及状态)之间可能的转换有限,所以少于2 ** $ _个状态...我认为

说明

{                                  }  # Anonymous codeblock
                     xx 2**$_         # Repeat 2**len(n) times
            .[0]*=-1                  # Negate the first element
 $_.=rotate(        )                 # Rotate the list by that value
                             ;!.[0]   # Return if the first element is 0

2
Foo机器的状态还包括指针的位置,而不仅仅是每个单元格的标志。
岩浆

1
带胶带a_1 ... a_n 0的Foo机器的证明草图。考虑每个单元的正负号的正方体,其顶点(=状态)之间有方向的边(= Foo的迭代),通过任何边的循环访问相同的顶点将导致IP处于与开始时相同的位置。证明:在一个循环中,IP在每个维度上传播偶数次,即,IP对每个维度的变化为k×(a_j +(-a_j))%n≡0,因此它始终返回相同的位置,每个顶点只能在n个状态中看到1个状态,即总共最多2 ^ n个状态(=立方体的顶点数)。
Kritixi Lithos

n2n.log(n)/n

3

05AB1E14 13字节

goFć©(š®._}®_

在线尝试!

将输入作为整数列表,其中0作为暂停指令。返回1表示停止,返回0表示不停止。

感谢@KevinCruijssen节省了2个字节!


哦,很好,这就是您的果冻答案!大量使用旋转和ć!我在等待解释,希望能得到我的答案,但你击败了我,哈哈。; p -1字节,尽管做的高尔夫与我的回答相同:g·Fto «v在线试用。
Kevin Cruijssen

和一个额外的-1使用©®,而不是DŠs«vć©(š®._}®_在线试用。
凯文Cruijssen

正如Arnauld在您的Python答案中指出的那样,仅循环两次长度是不够的。因此您可以将更«v改为goF
凯文·克鲁伊森

@KevinCruijssen谢谢
尼克·肯尼迪

3

Java 8,78 79 73字节

a->{int k=0,l=a.length,i=0;for(;i++<1<<l;k%=l)k-=(a[k]*=-1)%l-l;k/=a[k];}

@EmbodimentOfIgnorance的C#.NET答案的直接端口,因此请确保对他进行投票!
感谢@Arnauld找到了两个错误(这也适用于其他答案)。

java.lang.ArithmeticException: / by zero能够暂停时会导致错误,否则将不会导致错误。

在线尝试。

说明:

a->{                   // Method with integer-array as parameter and no return-type
  int k=0,             //  Index integer, starting at 0
      l=a.length,      //  The length `l` of the input-array
  i=0;for(;i++<1<<l;   //  Loop 2^length amount of times:
          k%=l)        //    After every iteration: take mod `l` of `k`
    k-=                //   Decrease `k` by:
       (a[k]*=-1)      //    Negate the value at index `k` first
                 %l    //    Then take modulo `l` of this
                   -l; //    And then subtract `l` from it
                       //  (NOTE: the modulo `l` and minus `l` are used for wrapping
                       //  and/or converting negative indices to positive ones
  k/=a[k];}            //  After the loop: divide `k` by the `k`'th value,
                       //  which will result in an division by 0 error if are halting

2
只是想知道,是否允许将长度作为附加参数?对元IO后默认没有这么说,我的第二个答案需要长度的唯一原因是因为它的花费int*(从codegolf.meta.stackexchange.com/a/13262/84206
无知的方式

@EmbodimentofIgnorance啊,当我看到您的回答时,我假设存在某种元规则,该规则允许将长度用作附加输入,但这仅适用于指针。谢谢你让我知道。我删除了length参数(但仍然使用错误/无错误来确定结果)。
凯文·克鲁伊森

3

Haskell,79个字节

s x|m<-length x,let g(n:p)=(drop<>take)(mod n m)(-n:p)=iterate g x!!(2^m)!!0==0

在线尝试!

返回True停止机器,False否则返回。以列表的形式输入,0表示停止状态。

假设GHC的版本大于8.4(2018年2月发布)。


2

JavaScript(Node.js)71 67字节

x=>{for(p=l=x.length,i=2**l;i--;)p+=l-(x[p%l]*=-1)%l;return!x[p%l]}

基本上与@EmbodimentOfIgnorance的C#.NET答案相同

@Arnaud节省了4个字节

在线尝试!

JavaScript(Node.js),61字节

x=>{for(p=l=x.length,i=2**l;i--;p+=l-(x[p%l]*=-1)%l)x[p%l].f}

此版本undefined用作停止符号,并TypeError: Cannot read property 'f' of undefined在机器停止时抛出,并在机器不停止时安静地终止。

在线尝试!


1

Scala,156字节

仍然可以打高尔夫球的IMO,但我现在还可以。返回0非停止Foos和1停止Foos。将输入a作为Array[Int],因此h作为0

var u=Seq[Array[Int]]()//Keep track of all states
var i=0//Index
while(u.forall(_.deep!=a.deep)){if(a(i)==0)return 1//Check if we are in a previously encountered step ; Halt
u:+=a.clone//Add current state in the tracker
var k=i//Stock temp index
i=(a(i)+i)%a.length//Move index to next step
if(i<0)i+=a.length//Modulus operator in Scala can return a negative value...
a(k)*=(-1)}//Change sign of last seen index
0//Returns 0 if we met a previous step

由于我进行了多次全阵列查找,.deep而且创建了副本,因此运行时间非常长(所有测试用例大约需要4秒钟),但是您仍然可以在线尝试。



1

附件,40字节

Not@&N@Periodic[{On[0,`-,_]&Rotate!_@0}]

在线尝试!

说明

{On[0,`-,_]&Rotate!_@0}

这将对Foo机器执行一次迭代。它使第一个成员取反,然后通过数组的(原始的,非取反的)第一个元素旋转数组。

Periodic将应用此功能,直到积累重复的结果。机器要么停止,要么陷入微不足道的无限循环。如果停止,则第一个元素将为0。否则,它将为非零。

&N是一种获取数值数组第一个元素的方法。然后,Not返回true0(停止机器)和false其他任何值(非停止机器)。


1

木炭,28字节

≔⁰ηFX²L諧≔θ籧θη≧⁻§θη绬§θη

在线尝试!链接是详细版本的代码。使用Charcoal的默认布尔输出的输出,该输出-为true,否则为false。说明:

≔⁰η

初始化指令指针。

FX²Lθ«

循环尽可能多的状态,理论上是可能的状态。

§≔θ籧θη

在指令指针处取反值。

≧⁻§θηη

从指令指针中减去新值。木炭的数组访问是循环的,因此这会自动模拟Foo的圆形磁带。

»¬§θη

在循环结束时,输出程序是否暂停。



0

Pyth,12个字节

!hu.<+_hGtGh

测试套件!

使用简单明了的方法。递归直到我们两次看到相同状态的列表。对于暂停的程序,该列表最终将处于领先地位,0因为这是递归停止的地方。对于不停止的程序,列表不会以开头0,而是处于周期性处理的状态,因此Foo机器不会停止。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.