Does this Foo machine halt?

43

9

Determining whether a Turing machine halts is well known to be undecidable, but that's not necessarily true for simpler machines.

A Foo machine is a machine with a finite tape, where each cell on the tape has an integer or the halt symbol h, e.g.

2 h 1 -1

The instruction pointer starts by pointing to the first cell:

2 h 1 -1
^

At every step, the instruction pointer moves forward by the number it points to, then negates that number. So, after one step, it would move forward 2 cells, and turn the 2 into a -2:

-2 h 1 -1
     ^

The Foo machine keeps doing this until the instruction pointer is pointing to the halt symbol (h). So, here is the full execution of this program:

2 h 1 -1
^

-2 h 1 -1
     ^

-2 h -1 -1
         ^

-2 h -1 1
      ^

-2 h 1 1
   ^

The tape is also circular, so if the instruction pointer moves off of one side of the tape, it goes to the other side, e.g.:

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

One interesting thing about these Foo machines is that some do not halt, e.g.:

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

This program will continue looping in those last four states forever.

So, write a program which determines if a Foo machine halts or not! You can use any (reasonable) input format you like for the Foo machines, and you can choose to use 0 as the halt symbol. You can use any two distinct outputs for the case where it does halt and the case where it doesn't. Your program must, of course, output an answer in a finite amount of time for all valid inputs.

This is , so try to make your program as short as possible!

Test cases

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

Leo Tenenbaum

Posted 2019-08-09T05:32:15.493

Reputation: 2 655

5Just so I'm sure, about the algorithm to resolve this. I'm not that of an algorithm master so I prefer asking before going in the wrong direction. Will a non-halting Foo machine always get back to its exact original state? Or are there "chaotic-behaviored" non-halting machines? – V. Courtois – 2019-08-09T06:56:51.137

5@V.Courtois All non-halting Foo machines will end up in a loop of states, because there are only finitely many possible states a Foo machine can be in (there are n possible places the instruction pointer can be, and 2^n possible tape configurations). Each state has one and only one "next state". So, if a Foo machine ends up back in a state it's already been in, it'll just keep looping. Because there are only finitely many states, it can't keep chaotically jumping around between states because it'll end up eventually going to one it's already been in. – Leo Tenenbaum – 2019-08-09T07:09:14.803

Okay, good to know. Thanks! I'll have to write an answer using this now. Or something else, I'm still thinking. – V. Courtois – 2019-08-09T07:37:17.250

Oh no, if I do it like that I have to keep track of all the states (first non-halting test case) because it loops with a known position which is not the start position. – V. Courtois – 2019-08-09T08:53:36.327

In the end, I still did it this way.

– V. Courtois – 2019-08-09T09:22:44.540

3Suggested test case: 1 2 h 42 (does not halt) – Arnauld – 2019-08-09T11:34:53.280

Is there a maximum value for the step-size? Or can it (theoretically) be arbitrary large? – Kevin Cruijssen – 2019-08-09T11:50:48.477

@KevinCruijssen The step size can be any integer (but you can ignore integer overflow). – Leo Tenenbaum – 2019-08-09T11:56:37.360

Thanks @Arnauld you just broke my answer xD. Good thing I haven't published it yet. – IQuick 143 – 2019-08-09T11:57:03.507

6Suggested test case: 3 2 1 1 4 h. This one halts but requires more iterations than twice the number of elements. – Arnauld – 2019-08-09T12:32:20.370

Suggested trivial test case 2 h, which does not halt. – Jitse – 2019-08-09T14:56:24.730

10Suggested extra-long test case: 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, which halts after 786430 steps. – Magma – 2019-08-09T15:13:36.987

Answers

11

C# (Visual C# Interactive Compiler), 71 bytes

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

Try it online!

I don't know if the following is valid, since it requires a custom delegate with a signature of unsafe delegate System.Action<int> D(int* a); and has to be wrapped in an unsafe block to be used, but here it is anyways:

C# (.NET Core), 64 bytes

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

Try it online!

This function takes in an int* and returns a Action; in other words, it is a curried function. The only reason I use pointers is because of codegolf.meta.stackexchange.com/a/13262/84206, which allows me to save bytes by already having a variable already defined with the length of the array.

Saved 9 bytes thanks to @someone

Embodiment of Ignorance

Posted 2019-08-09T05:32:15.493

Reputation: 7 014

@IQuick143 Nice catch, thanks – Embodiment of Ignorance – 2019-08-09T06:27:43.173

I'm not sure if there are any edge cases for which it won't work, but without breaking any of the current test cases you could replace 1<<f with 2*f to save a byte. – Kevin Cruijssen – 2019-08-09T09:13:58.003

If what I say in my comment above is correct, 2 bytes can actually be saved like this: int k=0,f=x.Count,i=f;for(;i-->-f; – Kevin Cruijssen – 2019-08-09T09:29:20.883

Fails for the suggested test case of Arnauld: 1 2 h 42. The +f in the +f)%f isn't larger enough to make the index positive in that case. Should probably be something like +max*f)%f, but will see if I can find something else to fix it.. My ported Java answer is deleted for now (my two golfs above still stand, though). – Kevin Cruijssen – 2019-08-09T11:54:11.837

177 bytes with horrible LINQ magic and Arnauld's fix. I have no idea how does this solution work, so I may have broken it. – my pronoun is monicareinstate – 2019-08-09T12:08:08.603

@Arnauld Ah nice, that's just 1 byte longer. :) Fixed it in my Java answer. – Kevin Cruijssen – 2019-08-09T12:08:23.110

@someone The 1<< can be 2* in your version. PS: For an explanation of this method, see my ported Java answer. (I don't think you've broken it, so nice golf!) – Kevin Cruijssen – 2019-08-09T12:08:52.907

71; I don't see why you need unsafe – my pronoun is monicareinstate – 2019-08-09T12:25:02.950

@someone You need unsafe because you are dealing with pointers – Embodiment of Ignorance – 2019-08-09T12:36:12.533

1

63 bytes via a normal sane 1-byte golf and changing IO to error/no error. Link to link

– my pronoun is monicareinstate – 2019-08-09T13:13:43.567

@someone It seems I have been pretty rusty lately, missing these easy golfs; I really need to golf more! – Embodiment of Ignorance – 2019-08-09T13:19:57.987

7

Python 3, 63 89 bytes

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

Try it online!

Also works for Python 2; a byte can be saved in Python 2 by replacing return with print and having the function print to stdout instead of returning. R turns True for halting and False for non-halting.

Thanks to @Neil and @Arnauld for noting that I needed to check longer for halting. Thanks to @Jitse for pointing out a problem with [2,0]. Thanks to @mypetlion for noting that the absolute of the tape values could exceed the tape length.

Nick Kennedy

Posted 2019-08-09T05:32:15.493

Reputation: 11 829

5OK, I'll bite: how do you know x+x is enough? – Neil – 2019-08-09T11:12:44.670

4@Neil It's actually not enough. A counter-example is [ 3, 2, 1, 1, 4, 0 ], which does halt in more than 12 iterations. – Arnauld – 2019-08-09T12:33:20.787

Wouldnt len(x)*x be sufficient? – Jitse – 2019-08-09T14:47:22.127

Also, it doesn't seem to work for [2,0] – Jitse – 2019-08-09T14:53:15.977

1@Jitse len(x)*x would not work. For instance, [8,7,6,5,7,4,0,3,6] halts in more than $9^2$ iterations. – Arnauld – 2019-08-09T14:59:17.390

2Isn't 2**len(x) still a bit short of the maximum? I calculate the number of states as n*(2**n) (with n=len(x)-1). – O.O.Balance – 2019-08-09T15:07:28.360

The machine 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 after 786430 steps. – Magma – 2019-08-09T15:20:35.680

1@O.O.Balance I see what you mean, since each state can have a pointer in each cell... however, I feel likes there's some other limit applied by the fact that each cell can only possibllly transition to two other cells. As a side note: nothing in the challenge says there has to be a halting state in the input – Jo King – 2019-08-09T15:24:44.900

1More generally, if you take a machine of the shape 1, -1, -2, -3, ..., -(p-1)such that 2 is a primitive root modulo the prime p, and replace the middle cell with the halt command, then the resulting machine will require at least 2**((p-1)/2) steps to halt. – Magma – 2019-08-09T15:27:44.813

@Jitse Fixed at a cost of 2 bytes – Nick Kennedy – 2019-08-09T15:51:49.280

1This doesn't work for cases of a tape having a value that's larger than the length of the tape. [10,0,1,-1] should return True because it's functionally the same as [2,0,1,-1], but it returns False. – mypetlion – 2019-08-14T22:45:26.480

6

Jelly, 15 11 bytes

N1¦ṙ⁸ḢƊÐLḢẸ

Try it online!

A monadic link that takes the input as a list of integers using 0 to mean halt. Returns 0 for halting inputs and 1 for those that don’t halt.

Avoids the issue of needing to work out number of iterations because of the use of ÐL which will loop until no new result seen.

Thanks to @JonathanAllan for saving a byte!

Explanation

      ƊÐ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

Nick Kennedy

Posted 2019-08-09T05:32:15.493

Reputation: 11 829

Save a byte by rotating by all the entries and then just keeping the first result: N1¦ṙ⁸ḢƊÐLḢẸ – Jonathan Allan – 2019-08-09T16:58:57.263

5

Python 3, 91 bytes

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

Try it online!

-40 bytes thanks to JoKing and Jitse

HyperNeutrino

Posted 2019-08-09T05:32:15.493

Reputation: 26 575

@JoKing 109 bytes by doing the variable assignments in the first line.

– Jitse – 2019-08-09T07:10:58.220

92 bytes by changing tuple conversion to starred expansion, not starting with an empty set and rephrasing the while condition. – Jitse – 2019-08-09T07:51:46.997

@JoKing Damn, I never learn :p. 93 bytes then.

– Jitse – 2019-08-09T07:59:07.253

91 bytes – Jitse – 2019-08-09T15:07:00.320

@JoKing thanks! – HyperNeutrino – 2019-08-09T18:26:08.090

@Jitse thank you – HyperNeutrino – 2019-08-09T18:26:13.420

5

Perl 6, 46 43 36 bytes

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

Try it online!

Represents halt by 0 and returns true if the machine halts. This repeats the logic 2**(length n) times, where if the pointer ends up on the halt cell, it stays there, otherwise it will be on a non-halt cell. This works because there are only 2**n possible states (ignoring halt cells) for the Foo machine to be in, since each non-halt cell has only two states. Okay yes, there are states than that, but due to the limited possible transitions between pointers (and therefore states) there will be less than 2**$_ states... I think

Explanation

{                                  }  # 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

Jo King

Posted 2019-08-09T05:32:15.493

Reputation: 38 234

2The state of the Foo machine also includes the location of the pointer, not just the signs of each cell. – Magma – 2019-08-09T15:29:14.463

1Sketch of a proof for a Foo machine with tape a_1 ... a_n 0 . Consider an n-cube of the signs of each cell with directed edges (= an iteration of Foo) between vertices (= states), visiting the same vertex via any loop of edges will result in the IP being in the same position it started with. Proof: In a loop, the IP travels in each dimension an even number of times, ie the IP changes by k×(a_j + (-a_j)) % n ≡ 0 for each dimension, hence it always returns to the same position, only ever seeing 1 state out of n states for each vertex, ie a total max of 2^n states (= number of vertices of cube). – user41805 – 2019-08-09T17:54:23.053

Just an empirical result, but brute-forcing the longest cycle among halting machines on a tape of length $n$ suggests that a tighter upper bound is $\lfloor2^n.log(n)/n\rceil$. – Arnauld – 2019-08-10T12:34:54.450

3

Java 8, 78 79 73 bytes

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

Straight-forward port of @EmbodimentOfIgnorance's C# .NET answer, so make sure to upvote him!
Thanks to @Arnauld for finding two bugs (which also applies to some other answers).

Results in an java.lang.ArithmeticException: / by zero error when it's able to halt, or no error if not.

Try it online.

Explanation:

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

Kevin Cruijssen

Posted 2019-08-09T05:32:15.493

Reputation: 67 575

2

Just wondering, are you allowed to take the length as an additional argument? The default for IO post on meta doesn't say so, and the only reason my second answer takes a length is because it takes in a int*(from https://codegolf.meta.stackexchange.com/a/13262/84206)

– Embodiment of Ignorance – 2019-08-10T00:26:38.187

@EmbodimentofIgnorance Ah, when I saw your answer I assumed there was some kind of of meta rule that allowed the length to be taken as additional input, but that only applies to pointers. Thanks for letting me know. I've removed the length parameter (but still use the error/no-error to determine the result). – Kevin Cruijssen – 2019-08-10T08:25:08.317

3

05AB1E, 14 13 bytes

goFć©(š®._}®_

Try it online!

Takes the input as a list of integers with 0 as the halting instruction. Returns 1 for halting and 0 for not halting.

Thanks to @KevinCruijssen for saving 2 bytes!

Nick Kennedy

Posted 2019-08-09T05:32:15.493

Reputation: 11 829

Oh nice, so that's what your Jelly answer does! Great use of the rotate and ć! I was waiting for an explanation in the hope to golf my answer, but you beat me to it, haha. ;p -1 byte by doing the same golf as my answer though: g·F to «v (Try it online.)

– Kevin Cruijssen – 2019-08-09T09:39:47.360

And one additional -1 by using ©® instead of the DŠs: «vć©(š®._}®_ (Try it online.)

– Kevin Cruijssen – 2019-08-09T09:43:32.953

As Arnauld noted on your Python answer, looping two times the length isn't enough. So you can change the «v to goF. – Kevin Cruijssen – 2019-08-09T14:04:24.900

@KevinCruijssen thanks – Nick Kennedy – 2019-08-09T15:44:18.113

3

Haskell, 79 bytes

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

Try it online!

Returns True for halting machines, and False otherwise. Input in the form of a list, with 0 representing a halting state.

Assumes a version of GHC greater than 8.4 (released Feb 2018).

B. Mehta

Posted 2019-08-09T05:32:15.493

Reputation: 763

2

JavaScript (Node.js), 71 67 bytes

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

Basically the same as @EmbodimentOfIgnorance's C# .NET answer

4 byte save thanks to @Arnaud

Try it online!

JavaScript (Node.js), 61 bytes

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

This version uses undefined as a halting symbol and throws a TypeError: Cannot read property 'f' of undefined when the machine halts and terminates quietly when the machine doesn't halt.

Try it online!

IQuick 143

Posted 2019-08-09T05:32:15.493

Reputation: 1 229

1

Scala, 156 bytes

Still golfable IMO, but I'm okay with it for now. Returns 0 for non-halting Foos and 1 for halting Foos. Takes the input in a as an Array[Int], so h is taken as 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

It is pretty long to run (around 4 seconds for all the test cases) because of the multiple full-array lookups I did, plus the .deep that create copies... But you can still try it online.

V. Courtois

Posted 2019-08-09T05:32:15.493

Reputation: 868

1

Charcoal, 28 bytes

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

Try it online! Link is to verbose version of code. Outputs using Charcoal's default Boolean output, which is - for true and nothing for false. Explanation:

≔⁰η

Initialise the instruction pointer.

FX²Lθ«

Loop as many times as there are theoretically possible states.

§≔θ籧θη

Negate the value at the instruction pointer.

≧⁻§θηη

Subtract the new value from the instruction pointer. Charcoal's array accesses are cyclic so this automatically emulates Foo's circular tape.

»¬§θη

At the end of the loop, output whether the program halted.

Neil

Posted 2019-08-09T05:32:15.493

Reputation: 95 035

1

Perl 5 -ap, 88 bytes

for(;$F[$i]&&!$k{"$i|$F[$i]"};$i=($i+$F[$i])%@F){$k{"$i|$F[$i]"}=1;$F[$i]*=-1}$_=!$F[$i]

Try it online!

Xcali

Posted 2019-08-09T05:32:15.493

Reputation: 7 671

1

Attache, 40 bytes

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

Try it online!

Explanation

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

This performs a single iteration of the Foo machine; it negates the first member, then rotates the array by the (original, non-negated) first element of the array.

Periodic will apply this function until a duplicate result is accumulated. A machine either halts, or goes into a trivial infinite loop. If it halts, the first element will be 0. Otherwise, it will be non-zero.

&N is a golfy way of obtaining the first element of a numeric array. Then, Not returns true for 0 (halting machines) and false for anything else (non halting machines).

Conor O'Brien

Posted 2019-08-09T05:32:15.493

Reputation: 36 228

0

Stax, 11 bytes

Ç₧┬òE▐tµ|⌡1

Run and debug it

It takes input in the form of an integer array, with 0 representing halt.

It outputs 1 for a halting and 0 for a non-halting machine.

recursive

Posted 2019-08-09T05:32:15.493

Reputation: 8 616

0

Pyth, 12 bytes

!hu.<+_hGtGh

Test suite!

Uses the straight-forward approach. Recurse until we see the list twice in an identical state. For programs that halt, the list will eventually have a leading 0 because that's where the recursion stops. For programs that don't halt, the list won't begin with the 0, but rather be in a state from which the process would be periodic and therefore the Foo machine wouldn't halt.

Mr. Xcoder

Posted 2019-08-09T05:32:15.493

Reputation: 39 774