Scooping the Loop Snooper: Proof That the Halting Problem Is Undecidable (2000)
lel.ed.ac.uk
lel.ed.ac.uk
You can check for repeating a previous state by running two copies in lockstep, one running twice as fast as the other. If the states of the two match, you're in an infinite loop. In the 1970s, a batch system intended for beginning programmers actually did that. The college had discovered that the successful jobs ran about a second, and the ones in a loop ran out the 30 second timer. So it was a win to take a 2x speed penalty to catch simple loops.
You can make a program cycle through a very large number of states, so you don't always get a practical halting check, but in theory, and often in practice, you do repeat a state eventually.
Undecidability requires infinities.
Not in any reasonably modern system. The state in this case is the exact sequence of bits contained in RAM and on your hard drive, which might as well be infinite (lets ignore for a moment that your computer is connected to the Internet and to real entropy sources, which really do make things infinite).
Some napkin math: if you've got a terabyte hard drive and 32 gigs of RAM, then there are approximately 2^(1,032 * 1024 * 1024) states your computer might be in, which is about 1.79 * 10 ^ 325,753,719. It can be hard to conceptualize numbers at that scale, but a fun illustration is that it is so big that the number itself would not fit on many laptops. It is infinite for any useful sense.
For comparison, there are an estimated 10^86 atoms in the observable universe -- if each atom in the universe was in fact its own universe, and each atom in all of those universes was its own universe, and so on... you'd have to go four layers deep to start talking comparable numbers here.
All programs that halt, therefore, must do so in less than #states steps, and the rest certainly never will, so we could show, in finite time, whether any given program on that machine will halt. We know, therefore, that the halting problem on this machine is decidable, even if we could not, in practice, demonstrate it.
The halting problem was not posed because we want to know if a given program will halt; it was posed as a means of attacking a much deeper problem.
Note also that any NFA can be converted to an equivalent DFA by powerset construction.
More practically, if you stick to structurally recursive loops, it's trivial to determine those loops will terminate. Structural recursion is when the recursive calls acts on smaller parts of the original input (e.g. map, reduce and filter functions do this), so you know it'll terminate eventually.
I find it pretty rare that I write loops with complex looping conditions.
As does the Turing machine itself, or any other turing complete computation model for that matter.
Heck, even the study of computational complexity forces you to accept some arbitrarily large value of n, which implies any fixed finite storage capacity is unacceptably small.
Modern programming does a pretty good job at approximating infinite memory (by using the cloud as a data store)
There's also https://en.wikipedia.org/wiki/Primitive_recursive_function implemented in https://en.wikipedia.org/wiki/LOOP_(programming_language)
I didn't think there was any provision in pure Turing machines for referencing external data, so to reference itself, Q must contain itself recursively on the tape to start with.
If every copy of Q contains a full copy of Q within it then it must be an infinite length program, and any Turing machine will require infinite steps to even read it.
I don't believe this "proof" for this reason.
Try running this Python program and see what it prints:
w = "print('w = ' + chr(34) + w + chr(34) + chr(10) + w)"
print('w = ' + chr(34) + w + chr(34) + chr(10) + w) P(input: Program): Boolean = ???
Q(input: Program) = if(P(input)) loop() else stop()
A() = Q(A)
Writing the above program on a tape (source code file) can be done in fixed space (I've just done it above, no recursive definition required)While running the program a turing machine can inspect the piece of tape with the program input. It's as if a program is inspecting its own code, which is not only possible in a turing machine, but common to various degrees in languages like Lisp, Scala, Javascript, Java, PHP, Ruby and Python. You might know it as reflection or macros.
You can test a system with a bigger system, but that is generally economically infeasible, since testing costs are exponential in system size.