"haltingproblem" Contradiction Proof - computation-theory

I recently came across the halting problem contradiction proof.
In the proof, we have to feed the Turing machine a copy of the program and a copy of the input to decide whether that program halts on the input. In the contradiction, why does it have to be the program as the program and the input? Sorry if it sounds confusing. I can simply feed the machine with a program and a random input and come to the same conclusion.
Can anyone tell me why? Is there a specific reason I didn't think of?

First let me come back on the proof itself.
HALT_TM is undecidable
Assume that any machine has a description which takes the form of a string. Let HALT_TM = {<M, w>| M is a TM and M halts on input w}, and A_TM = {<M,w>| M is a TM and accepts w}. Here I assume that we know that A_TM is undecidable (the proof can be done by diagonalization and realizing that as there are more languages than Turing Machines, and as a given TM only decide one language, then some language are not decided).
Assume by contradiction that HALT_TM is decidable, meaning that we dispose of a decider D for this language. Then we would be able to build a machine M which decides A_TM. On input <M', w>, M does the following:
Run D on input <M',w>
If D reject, reject, otherwise run M' on w (until it halts, which we know because D did not reject!)
If M' accepts, accept, if it rejects, reject.
There we see the contradiction with our assumption
Universal Turing Machines
Now the core of your question: you actually feed M any valid machine description M', not necessarily <M> itself. Remember that a TM and "a program" are actually equivalent: See this nice answer for more details. Quoting this same answer: "A Turing Machine is the formal analogue of an algorithm".
One power of Turing Machines is that they can be encoded as a string, allowing another Turing Machine (called an "Universal Turing Machine") to execute them. Because the given machine is an algorithm, you see that you are actually feeding your "top-level" TM a program, and a input of your choice.

Related

Why do we define equivalent turing machines as two turing machines with the same accepted languages?

From many textbooks about computability, I see how we define equivalent turing machines as follows:
Two turing machines TM1 and TM2 are equivalent <=> L(TM1) = (TM2)
where L(TM1) is the languages accpeted by TM1, i.e. L(TM1) = {w | TM1(w) = accept}, and so is L(TM2).
My question is: why does the above definition totally ignore the 'rejected languages' {w | TM1(w) = reject} and 'loop languages'{w | TM1(w) goes into infinite loop}?
Intuitively, TM1 and TM2 are equivalent if and only if their input-output relation are exactly the same, which means they output the same thing, or react in the same manner for any possible input. Say, if L(TM1) = L(TM2), then it is still possible that these exists some w0 such that TM1(w0)=reject while TM2(w0) goes into infinite loop, and thus we conclude that TM1 and TM2 are indeed not equivalent. However, according to the definition on textbooks, they are equivalent, which is not intuitive.
I try to obtain some explanation of the counterintuitive definition of equivalent Turing machines on textbooks.
Generally speaking the basic definition of Turing machines does not have a (explicit) notion of reject (see https://en.wikipedia.org/wiki/Turing_machine).
Then, there are many extensions along different directions that lead to slightly different formalizations. In fact, you can label a particular state as the reject state.
Notice that this extension does not change the expressive power of the computational model (see below).
Each extension is better suited to model different scenarios and serve different goals.
In some scenarios it could make perfect sense to employ a definition of equivalence that explicitly distinguishes between accepted and rejected words as you suggest.
I would like to point out that equivalence of Turing machines is all about the accepted languages. Internally, the two machines may behave in a completely different manner.
In addition, it is not completely clear what the output of a Turing machine is; they simply execute on some input and they either accept it or they don't.
Of course, in the basic case in which we define Turing machines without explicit reject states it makes sense to define the language of the machine as the set of words that the machine accepts.
In addition, this is consistent with the definition used in automata theory.
In a more formal manner you can consider the following reduction sketch to compare the two settings.
Let EM0 and EM1 be two Turing machines with an explicit reject state.
Assume we want to solve the problem of deciding whether the two machines accept and reject the same words.
We can reduce this problem to deciding the equivalence of two Turing machines (without explicit reject state).
Define M0 and M1 from EM0 and EM1 respectively by extending the tape alphabet with two fresh symbols R (for reject) and A (for accept).
M0 accepts the language build by all the words accepted by EM0 extended with an additional A at the beginning and all the words rejected by EM0 extended with an additional R at the end.
L(M0) := {Aw | EM0(w) = accept} U {Rw | EM0(w) = reject}
Define M1 similarly such that:
L(M1) := {Aw | EM1(w) = accept} U {Rw | EM1(w) = reject}
where, using your notation, EM(w) = v means that EM on input w terminates on a v state.
Notice that I am skipping the details about how to actually build the two Turing machines with such language.
Finally, M0 is equivalent to M1 iff EM0 and EM1 accept / reject the same words.
Therefore, the standard definition of language and equivalence of Turing machines is already expressive enough to capture the accept / reject scenario you described and it is also simpler in the sense that it does not require the extra definition of rejecting states.

Prove that we can decide whether a Turing machine takes at least 100 steps on some input

We know that the problem “Does this Turing machine take at least this finite number of steps on that input?” is decidable, because it will always answer yes or no, where it will say yes if the machine reaches the given number of steps and no if it halts before that.
Now here is my doubt: if it halts before reaching those many steps — i.e. the input either (1) got accepted or (2) got rejected or maybe (3)if it doesn’t halt but rather goes into an infinite loop — then, when we are in case (3), how can we be sure that it will always be in that loop?
What I mean to say is that if it doesn't run forever but comes out of the loop at some point of time then it might cross the asked number of steps and the decision can be made now which was earlier not possible. If so, then how can we conclude that it's decidable when we know that being stuck in a loop we won’t be able to say anything about the outcome?
(I already more or less answered your question when I edited it.)
The thing is, the decision system (a Turing machine, an algorithm or any other equivalent formalism) that takes as inputs a Turing machine M, a number N and a value X, and returns yes or no, has total control over how it executes M on X. It simulates it step by step. So it can run one step of M(X), increment an instruction counter, compare it to N and, as soon as the given number of steps is reached, it stops and returns yes. At that point, there is no need that the simulated machine M be in a final state, and actually the full computation M(X) could very well diverge. We don’t care, because we only run the first N steps.
Most likely the "conditional structures where not being debuged/developed enough so that multiple conditions often conflicted each other..the error reporting where not as definitive, so it where used semi abstract notions as "decidable" and "undecidable"
as a semi example i writen years ago in vbs a "64 bit rom memory" simulator, as i tried to manage the memory cells, where i/o read/write locations where atributed , using manny formulas and conditions to set conversions from decimal to binary and all the operations, indexing, etc.
I had allso run into bugs becouse that the conditons where not perfect.Why? becouse the program had some unresolved somewhat arbitrary results that could had ended up in :
print.debug "decidable"
On Error Resume h
h:
print.debug "undecidable"
this was a example with a clear scope and with a debatable result.
to resume to your question : > "so how do we conclude that it's decidable??"
wikipedia :
The Turing machine was invented in 1936 by Alan Turing, who called it an "a-machine" (automatic machine). With this model, Turing was able to answer two questions in the negative:
Does a machine exist that can determine whether any arbitrary machine on its tape is "circular" (e.g., freezes, or fails to continue its computational task)?
Does a machine exist that can determine whether any arbitrary machine on its tape ever prints a given symbol?
Thus by providing a mathematical description of a very simple device capable of arbitrary computations, he was able to prove properties of computation in general—and in particular, the uncomputability of the ('decision problem').

what is exactly the halting in turing machines ?

I am new to decidability. I read halting problem of halting problem but didn't get anything what it is actually implying. I am already screwed up with the explaination.
Can anyone provide me any sound explaination or atleast some details, it would be of much help ?
You can think of a Turing machine as a sort of theoretical computer that can execute programs. A program for a Turing machine consists of a set of states and transitions between these states. Programs running on Turing machines have access to a single input source, called the tape, which has some string (possibly empty) the program can process. All programs for Turing machines either return true (halt-accept), return false (halt-reject), or fail to ever return anything at all - while (true) ; return true;. Depending on your definition it may also be possible for the machine to throw an exception (crash); but typically crashing is thought of as something like try { /*crash*/ } catch (Exception) { return false; } so that crashing means halt-reject.
The halting problem, then, is whether you can write a program for a Turing machine, whose input is another program for a Turing machine and some string of input, which returns true or false (halt-accepts or halt-rejects) if the program it has been given halts on the input provided and returns false otherwise (i.e., if the program never halts).
It turns out the answer is that no such general program exists for Turing machines. Suppose one did exist, M. Given inputs m and i it accepts if m halts on i and rejects otherwise. We can make another program specifically designed to fool M:
N(i)
1. if M(N, i) then loop forever;
2. otherwise return true
Now continue whether M works on N:
Suppose M says that N halts on input i. Then N will loop forever, and M will have been wrong.
Suppose M says that N loops forever on input i. Then N will return true and halt, so M will have been wrong.
In either case, M comes up with the wrong answer for our N, and since we made no assumptions about M other than that it exists and solves the halting problem, we may safely conclude that no machine that solves the halting problem exists.
(M may be passed into the program N as input if it is preferred not to reference M directly).

How does this proof, that the halting problem is undecidable, work?

I'm going over the proof for The Halting Problem in Intro to the Theory of Computation by Sipser and my main concern is about the proof below:
If TM M doesn't know when it's looping (it can't accept or reject which is why a TM is Turing Recognizable for all strings), then how would could the decider H decide if M could possibly be in a loop? The same problem will carry through when TM D does its processing.
After reading this and trying to visualize the proof I came up with this code which is a simplified version of the code in this answer to a related question:
function halts(func) {
// Insert code here that returns "true" if "func" halts and "false" otherwise.
}
function deceiver() {
if(halts(deceiver))
while(true) { }
}
If halts(deceiver) returns true, deceiver will run forever, and if it returns false, deceiver will halt, which contradicts the definition of halts. Hence, the function halts is impossible.
This is a "proof by contradiction", a reductio ad absurdum. (Latin phrases are always good in theory classes... as long as they make sense, of course.)
This program H is just a program with two inputs: a string representing a program for some machine, and an input. For purposes of the proof, you simply assume the program H is correct: it simply will halt and accept if M accepts with w. You don't need to think about how it would do that; in fact, we're about to prove it can't, that no such program H can exist, ...
BECAUSE
if such a program existed, we could immediately construct another program H' that H couldn't decide. But, by the assumption, there is no such program: H can decide everything. So, we're forced to conclude that no program defined as we defined H is possible.
By the way, the reductio method of proof is more controversial than you might expect, considering how often its used, especially in Computer Science. You shouldn't be embarrassed to find it a little odd. The magic term is "non-constructive" and if you feel really ambitious, ask one of your professors about Errett Bishop's critique of non-constructive mathematics.

Writing a program that writes a program

Its well known in theoretical computer science that the "Hello world tester" program is an undecidable problem.(Here is a link what i mean by hello world tester
My question is since given a program as input we can't say what the program will do,can we solve the reverse problem:
Given set of input and output,is there an algorithm for writing a program that writes a program to achieve a one to one mapping between the given input and output.
I know about metaprogramming but my question is more of theoretical interest. Something which can apply for a generic case.
With these kind of musings one has to be very careful. A lot of confusion arises from not clearly distinguishing about a program x for which proposition P(x) holds or any program x for which proposition P(x) hold. As long as the set of programs for which P(x) holds is finite there always is a proof, of their correctness (although this proof may not be known).
At this point you also have to distinguish between programs, which are and can be known and programs which can only be shown to exist by full enumeration of all posibilities. Let's make an example:
Take 10 Programs, which take no input and may or may not terminate and produce "hello World". Then there is a program which decides exactly which of these programs are correct, and which aren't. Lets call these programs (x_1,...,x_10). Then take the programs (X_0,...,X_{2^10}) where X_i output true for program x_j if the j-th bit in the binary representation of i is set. One of these programs has to be the one which decides correctly for all ten x_i, there just might not be any way to ever figure out which one of these 100 X_js is the correct one (a meta-problem at this point).
This goes to show that considering finite sets of programs and input/output pairs one can always resolve to full enumeration and all halting-problem type of paradoxies instantly disappear. In your case the set of generated programs for each input is of size one and the set of input/output pairs is of finite size (because you have to supply it to the meta-program). Hence full enumeration solves your problem very simple and you can also easily proof both the correctness of the corrected program as well as the correctness of the meta-program.
Note: Since the set of generated programs is infinite, this is one of the few cases where you can proof P(x) for a infinite set of programs (actually you can proof P(x,input,output) for this set). This shows that the set being infinite is only a necessary, not a sufficient condition for this type of paradoxes to appear.
Your question is ambiguously phrased.
How would you specify "what a program should do"?
Any precise, complete, and machine-readable specification of a program's functionality is already a program.
Thus, the answer to your question is, a compiler.
Now, you're asking how to find a function based on a sample of its input and output.
That is a question about statistical analysis that I cannot answer.
Sounds like you want to generate a state machine that learns by being given an input sequence and then updates itself to produce the appropriate output sequence. Assuming your output sequences are always the same for the same input sequence it should be simple enough to write. If your output is not deterministic, such as changing the output depending on the time of day, then you cannot automatically generate a state machine.
Depends on what you mean by "one to one mapping". (And also, I suppose, "input" and "output".)
My guess is that you're asking whether, given an example of inputs and outputs for a given arbitrary program, can one devise an algorithm to write an equivalent program? If so, the answer is no. Eg, you could have a program with the inputs/outputs of 1/1, 2/2, 3/3, 4/4, and yet, if the next input value was 5, the output would be 3782. There's no way to know, from a given set of results, what the next result might be.
The question is underspecified since you did not say how the input and output are presented. For finite lists, the answer is "yes", as in this Python code:
def f(input,output):
print "def g():"
print " x = {" + ",".join(repr(x) + ":" + repr(y) for x,y in zip(input,output)) + "}"
print " print x[raw_input()]"
>>> f(['2','3','4'],['a','b','x'])
def g():
x = {'2':'a','3':'b','4':'x'}
print x[raw_input()]
>>> def g():
... x = {'2':'a','3':'b','4':'x'}
... print x[raw_input()]
...
>>> g()
3
b
for infinite sets how are you going to present them? If you show only a small sample of input this does not specify the whole algorithm. Guessing the best fit is undecidable. If you have a "magic blackbox" then there are continuum many mappings but only a countable number of programs, so it's impossible.
I think I agree with SLaks, but taking things from a different angle, what does a compiler do?
(EDIT: I see SLaks edited his original answer, which was essentially 'you're describing the identity function').
It takes a program in one source language that describes the intended behaviour of a program, and "writes" another program in a target language that exhibits that behaviour.
We could also think of this in terms of things like process refinement --- given an abstract specification, we can construct a refinement mapping to some "more concrete" (read: less non-deterministic, usually) implementation.
But based on your question, it's really very difficult to tell which of these you meant, if any.

Resources