The halting problem is usually provided as follows:
Given a program and an input it accepts, will this program give me an answer? IE, it will at some point stop its execution?
Note: I have all the time in the world, but not infinite time.
Apparently, the answer should be yes. But... this is not always the case. Sometimes the program enters into an infinite loop. This can happen because the programmer who wrote it made a mistake, or because the programmer chose the wrong approach when dealing with the problem, or simply because the problem in question cannot be solved.
But are there problems that cannot be solved? Yes, there are. They are problems that, given an input, there is the possibility of the program entering into an infinite loop. Regardless of how good the program is. And it does not enter into infinite loop in a simple and trivial way. Some problems, such as recognizing whether a word belongs to an unrestricted grammar, or whether given a finite set of matrices n x n
it is possible to obtain the null matrix by just multiplying (with repetitions) the elements of this set, the programs that solve such problems can enter recursions and never go back to some previous state.
Now, to answer the questions in the text... in the order I think most appropriate. And I’m trying to put the concepts as lightly as possible, but for the sake of correctness it will come at times when I will need to be too technical. Whenever possible I will try to separate a concept in the "lay" part, and leave a more technical and mathematical explanation below or linked.
... why it [Turing machine] would stop?
A Turing machine is a automaton. So the only thing she does is:
And it does this from an initial datum, called input. In decision problems you need a "yes" or "no" answer. And this answer is only useful at the end of the processing, when the Turing machine is stopped. Acceptance or rejection of the entry can be done by writing, but it is usually more useful to know if you are in an accepting state or not.
Why would she [Turing machine] go into infinite loop?
Because there are insoluble/undecidable problems. @Guilherme Bernal proposes a heuristic to look for cases to identify when a software enters an infinite loop in that matter, but I pointed out a case "trivial" failure of the programmer that he could not detect with his heuristic. I also pointed out another "uglier" heuristic that is lighter, but with a smaller amount of false positive for "program in infinite loop".
(Spoiler Alert: technical part started) An example of a problem that is undecidable is whether a word can be obtained from an unrestricted grammar.
An unrestricted grammar is a grammar that accepts productions of any kind. See more here, here.
In other words, this problem is w ∈ L(G)
:
w
is the word we want to know if it can be obtained from grammar
G
is the unrestricted grammar in question
L
is the "language function", which given a language, returns all words that can be generated from it
In infinite language grammars, compute L(G)
in its completeness is... infinite too. Perhaps infinite times some nonzero polynomial?
So there must be some way to check without having to list all the words, right? Well, that depends on the grammar.
In the case of regular grammars, it is trivial. The first step, however, is to transform the problem into a deterministic finite state automaton (see more here). After that, it is just feeding the automaton with the word and, if it stops in an accepting state, the word belongs to the language. Otherwise, it does not belong to the language.
For context-free grammars, you could normalize to Chomsky’s normal form and try to assemble the derivation tree by ascending strategy. If you get the non-terminal S
at the top, then belongs to grammar, otherwise (found another non-terminal or found no answer at all) then does not belong.
For context-sensitive grammar, it starts to get complicated. There is no direct way to go. The most we can do is turn it into a non-recurring grammar. Every context-sensitive grammar can be transformed into a non-recurrent grammar so thatL(Gsc) = L(Gnr)
, where Gsc
is the context-sensitive grammar and Gnr
is the non-recurrent grammar. An interesting property of non-retail grammar is that a sentential form can only be derived in sentential forms of the same size or larger. So if the intermediate sentential form is greater than the length of w
, we already know we’re on the wrong track, so just go back and try another way. And, yes, the most efficient context-sensitive grammar solution is to list in depth all possible transformations and cut when the intermediate form is too large.
For unrestricted grammars... well, they can be written so as to be retractive... even there is nothing prohibiting the consumption of a terminal generated in the middle of a production. So limiting by the size of the sentential form is not a good one for the general case.
What to do in this case? Well, the best that can be done is to construct the derivation graph. This same graph can be used for other restricted grammars as well.
How does this graph work? Well, we start with the initial nonterminal vertex, S
. So we check what are the productions that this vertex can undergo, and for each production we take the vertex P1
, P2
... Pn
for each of the n
possible productions and links with edges to the originator vertex. If one of the productions generates a sentential form Pi
already known, we should connect to this vertex instead of creating a new vertex. Then we add all the vertices in the structure of future visits and mark S
as already visited.
The next step is to take the next vertex of the structure of future visits and, on top of it, make all possible derivations, add the new vertices and new edges in the graph, adding the neighboring vertices in the future visiting structure to, then mark the vertex as visited. Of course, if a vertex has already been visited, one should not do this processing again.
If the vertex being visited is composed only of terminals, then we can check whether Pv = w
. If so, we find the answer, otherwise we know nothing.
In the case of non-retail grammars, the proper structure for storing future visiting vertices is stack, making a deep-sea search. This is because it is known that since grammar is non-recurrent, there is a maximum limit of vertices that can be generated in the middle of the path. If there are n
non-terminal, I just need to examine at most (n+len(w))^len(w)
distinct vertices as there are n+len(w)
distinct symbols in grammar that are relevant to the word w
and any sentence form Pg
such that len(Pg) > len(w)
implies that w
cannot be obtained from Pg
.
In the case of unrestricted grammar, the best structure to do this analysis is the queue. This will allow you to do a search in width of the derivation graph. Using the search in width avoids falling into a hole of perdition that even exploring the infinite possibilities of it does not arrive in w
, because the processing of other paths continues to be done.
If it is possible to answer "yes", occasionally in one of the vertices it will contain w
and guaranteed to pass through it from here until the end of time. If it is not possible, there are two hypotheses:
- All paths have been investigated to the end, so grammar generates a finite language
- At least one of the paths is an endless well and the program will continue to explore this well in width, adding new vertices to be visited
In the second case, the Turing machine will not stop.
All the demonstrations using contradiction don’t make sense in my head.
Well, I guess that means you have doubts about how to prove that the halting problem is undecidable. Let’s use the previous problem to clarify this?
If you, dear reader, have skipped the previous section after seeing the Alert spoiler: technical part started, I will briefly recap what the problem is. I wonder if a word w
can be generated from an unrestricted grammar G
. We then model a graph that represents all the sentential forms that I can obtain from a prior sentential form obeying the rules of production of G
and do a wide search.
The possible results are:
- if
w
can really be generated by G
, after "some" processing we will find w
- if we try to go across all the paths and they ended up not finding
w
, then the language L(G)
generated by G
was finite and we enumerated all its elements and none of them were w
- one of the paths is an endless well, in which the search in width will continue indefinitely generating new vertices aimlessly, without ever leading to
w
We know these results because somehow we know a priori whether w ∈ L(G)
. And what would happen if we really didn’t know the result of the algorithm?
In this case, we will need to wait for the algorithm to give an answer (1), enumerate all possibilities and none of them are w
(2) or that it enters an infinite loop (3).
The cases (1) and (2) are trivial. After all, if it stopped, it stopped, we have the answer. And for the case (3)? @Guilherme Bernal provided a heuristic in that matter. But unfortunately it doesn’t work for the general case.
Looking at it from a different perspective... I’m going to let my Turing machine work for a while. I let it process for... two weeks. After that time I pause it and check its internal state. Well, it says that there are still paths to be cleared, vertices not visited. So I let her process a little bit more. I go back five years later, and then what? Well, now there are two billion vertices to be visited. I’m scared, but that means she’s making progress... or not?
Well, maybe next second she’ll just stop and yell, "I’m done, I thought w
". Maybe it takes another week. Or two centuries. Impossible to determine that by looking at it. Maybe these two billion vertices are two billion endless wells. Or not! Maybe they can all generate w
in the future, near or distant. Maybe processing is leading somewhere, maybe it’s just processing in vain.
By taking a Turing machine that solves the problem of whether w
is generated by G
and it is still in processing, it is impossible to determine whether it is because it is on its way to (1) or (2), or whether it is in perdition in (3).
This is an example that shows the impossibility of determining whether a given Turing machine will one day give an answer. After all, I have all the time in the world, but not infinite time.
This question is opened with an intuitive explanation of the subject: https://answall.com/q/30749/64969 ; helped in understanding?
– Jefferson Quesado
No @jeffersonquesado. It just made me more confused. I’m reading so far, and I can’t understand, why on principle of contraction the halting problem is undecidable.
– Nakamoto
I’m working on an answer to that question, so I’ll get back to your question. By the way the author of the other question suggested a heuristic that could be good enough, and his question was whether his heuristic was really good enough or whether there could be some other heuristic good enough for such
– Jefferson Quesado
Write an A program that reads program B and says if program B never stops. Now suppose A is a program that never stops, not even A will be able to give an answer when you read yourself (the answer is given when the program stops)
– jean
@jean but then you could guess that A does not stop. Victor Stafusa’s answer speaks very well of the subject, even better than mine
– Jefferson Quesado
@Jeffersonquesado A (anti)hypothesis is to prove that A at all times will give an answer (and therefore always stops) finding a possibility already destroys the hypothesis that it is (always) possible to create an infertile program that will always for and always will give the right answer
– jean
Related: What is a decision problem?
– Jéf Bueno