On 3/1/2021 9:05 PM, olcott wrote:
> On 3/1/2021 8:22 PM, Mike Terry wrote:
>> On 02/03/2021 01:31, olcott wrote:
>>> On 3/1/2021 7:00 PM, Mike Terry wrote:
>>>> On 01/03/2021 23:00, olcott wrote:
>>>>> On 3/1/2021 4:42 PM, Mike Terry wrote:
>>>>>> On 01/03/2021 20:22, olcott wrote:
>>>>>>> On 3/1/2021 1:39 PM, Kaz Kylheku wrote:
>>>>>>>> On 2021-03-01, olcott <No...@NoWhere.com> wrote:
>>>>>>>>> On 3/1/2021 12:25 PM, Kaz Kylheku wrote:
>>>>>>>>>> On 2021-03-01, olcott <No...@NoWhere.com> wrote:
>>>>>>>>>>> On 3/1/2021 10:52 AM, Kaz Kylheku wrote:
>>>>>>>>>>> I already acknowledged this. When an equivalent computation
>>>>>>>>>>> is run on a
>>>>>>>>>>> machine without resource limits (such as a TM) then this
>>>>>>>>>>> computation is
>>>>>>>>>>> infinitely recursive.
>>>>>>>>>>
>>>>>>>>>> That depends on what you mean by "equivalent". Since you have
>>>>>>>>>> tied the
>>>>>>>>>> validity your work to the x86 representation, a Turing Machine
>>>>>>>>>> version
>>>>>>>>>> of your program, to be equivalent, has to contain the x86
>>>>>>>>>> program, and
>>>>>>>>>> the simulator, faithfully reproducing the same resource
>>>>>>>>>> limitations.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> A RASP machine is known to be equivalent to a UTM.
>>>>>>>>>
>>>>>>>>> Thus the RASP is to the RAM as the Universal Turing machine is
>>>>>>>>> to the
>>>>>>>>> Turing machine. The RASP is an example of the von Neumann
>>>>>>>>> architecture.
>>>>>>>>>
https://en.wikipedia.org/wiki/Random-access_stored-program_machine
>>>>>>>>>
>>>>>>>>> The x86 language is another exapmle of the von Neumann
>>>>>>>>> architecture.
>>>>>>>>> All computations implemented using the von Neumann architecture
>>>>>>>>> are
>>>>>>>>> equivalent to one another as long as they do not require more
>>>>>>>>> memory
>>>>>>>>> than is available.
>>>>>>>>>
>>>>>>>>> Thus all computations implemented using the von Neumann
>>>>>>>>> architecture are
>>>>>>>>> equivalent UTM computations as long as they do not require more
>>>>>>>>> memory
>>>>>>>>> than is available.
>>>>>>>>
>>>>>>>> That is true; but an infinite recursion does require
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>>> When I say that the x86 emulator: Simulate() is functionally
>>>>>>>>>>> equivalent
>>>>>>>>>>> to this code:
>>>>>>>>>>>
>>>>>>>>>>> int Simulate(u32 P, u32 I)
>>>>>>>>>>> {
>>>>>>>>>>> ((void(*)(int))P)(I);
>>>>>>>>>>> return 1;
>>>>>>>>>>> }
>>>>>>>>>>>
>>>>>>>>>>> That is all that need be said about the capabilities of the
>>>>>>>>>>> x86 emulator.
>>>>>>>>>>
>>>>>>>>>> Yes; then clearly, the H_Hat(P, P) call (with the right casts
>>>>>>>>>> put in)
>>>>>>>>>> denotes a runaway recursive call.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> So we agree on this point?
>>>>>>>>
>>>>>>>> Why wouldn't we? It's obviously a runaway recursive call.
>>>>>>>>
>>>>>>>>> When we know that Simulate() is an x86 emulator that is
>>>>>>>>> functionally
>>>>>>>>> equivalent to direct execution of its input then from the
>>>>>>>>> execution
>>>>>>>>> trace of the execution of this input (including the inputs to
>>>>>>>>> functions
>>>>>>>>> stored on the stack) alone we can decide that H_Hat() is
>>>>>>>>> infinitely
>>>>>>>>> recursive.
>>>>>>>>
>>>>>>>> Yes.
>>>>>>>>
>>>>>>>> In a static call graph of a program, we can spot loops.
>>>>>>>>
>>>>>>>> For instance a simple infinite loop occurs when a basic block
>>>>>>>> jumps to
>>>>>>>> itself.
>>>>>>>>
>>>>>>>> A basic block has no branching instructions anywhere, except as
>>>>>>>> possibly
>>>>>>>> the last instruction. If that last instruction is an
>>>>>>>> unconditional jump
>>>>>>>> back to that block, that is an infinite loop.
>>>>>>>>
>>>>>>>> Compilers do this kind of control flow analysis to find loops,
>>>>>>>> where certain optimizations can be concentrated (e.g. giving more
>>>>>>>> registers to variables in nested loops).
>>>>>>>>
>>>>>>>> If we monitor the execution dynamically, we can likewise identify
>>>>>>>> "dynamic basic blocks" sequences of unconditionally executed
>>>>>>>> instructions with no branches, and we can detect infinite loops.
>>>>>>>> (Possibly ones that contain a stack push, if the jump is actually
>>>>>>>> a subroutine call.)
>>>>>>>>
>>>>>>>> If we simply identify the situation, but don't interfere in it,
>>>>>>>> then the
>>>>>>>> situation persists: there is runaway recursion.
>>>>>>>>
>>>>>>>
>>>>>>> When this same simulator monitors its own simulation it could
>>>>>>> figure out that the H_Hat() invocation of itself is infinitely
>>>>>>> recursive.
>>>>>>>
>>>>>>
>>>>>> I'm afraid that's "wrong-headed" thinking, because Simulate simply
>>>>>> DOES NOT monitor its own simulation, so you can't talk about when
>>>>>> it does something IT DOESN'T DO. :) The same mental confusion
>>>>>> underlies your ".. /would/ fail to terminate /if/ ABNHBD() didn't
>>>>>> abort the emulation", and other anthropomorphisms you make for TMs.
>>>>>>
>>>>>
>>>>> So in other words you cannot possibly begin to imagine that a
>>>>> software function could be adapted to add functionality.
>>>>>
>>>>>> /We/ can figure out that the above H_Hat is infinitely recursive,
>>>>>> but /we/ are not Simulate, so H_Hat is not our "We_hat", and this
>>>>>> says nothing about the Linz proof.
>>>>>>
>>>>>> The /Simulate/ as you've described it (pure emulation) /cannot/
>>>>>> "figure it out", because it fails to return and so doesn't
>>>>>> "figure" anything. Again, nothing much to say re HP proof.
>>>>>>
>>>>>> We could code a /new/ emulator routine Simulate2 (distinct from
>>>>>> H_Hat and Simulate above) which has monitoring logic, and use it
>>>>>> to examine a simulation of the H_Hat above calling Simulate(H_Hat)
>>>>>> (note: NOT calling Simulate2...), and this Simulate2 could
>>>>>> correctly decide that H_Hat(H_Hat) does not terminate.
>>>>>>
>>>>>> But H_Hat is not the "hatted" machine for Simulate2, so this also
>>>>>> is of little interest. Nobody claims that "no decider can
>>>>>> correctly decide halting for H_Hat", only that H does not
>>>>>> correctly decide halting for its own H_Hat.
>>>>>>
>>>>>> If we "update" H_Hat so that instead of calling Simulate, it calls
>>>>>> the new Simulate2, then we have a /new/ program H_Hat2, and a
>>>>>> /new/ calculation to consider. When H_Hat2 examines the
>>>>>> calculation H_Hat2(H_Hat2), with H_Hat2 calling Simulate2 etc.,
>>>>>> then H_Hat2 /*cannot*/ "figure out" that the calculation has
>>>>>> infinite recursion, BECAUSE IT DOESN'T. It can certainly /decide/
>>>>>> that H_Hat2 is infinitely recursive, but that would just be
>>>>>> Simulate2 deciding incorrectly. All in line with Linz proof.
>>>>>>
>>>>>> Remember, Simulate2 is not a "pure emulator" like Simulate, so the
>>>>>> fact that there may be two nested emulated calls to Simulate2 with
>>>>>> the same argument IS NOT PROOF OF INFINITE RECURSION.
>>>>>
>>>>> When Simulate2() is identical to Simulate() in every way except
>>>>> that it also examines the execution trace of its input to figure
>>>>> out that its input is calling Simulate2() in infinite recursion
>>>>> then by logical necessity H_Hat() is still infinitely recursive.
>>>>
>>>> ?
>>>>
>>>> H_Hat doesn't call Simulate2. Maybe you mean H_Hat2 ?
>>>>
>>>> Obviously the /H_Hat/ calculation is "still" infinitely recursive,
>>>> because that calculation has never changed - by definition it calls
>>>> Simulate (not Simulate2).
>>>>
>>>> Hmm, your phrase "figuring out" isn't a standard CS term - I've
>>>> guessed it to mean that Simulate2 returns some different rc (not 1)
>>>> when it detects the nested calls to Simulate2 with the same input
>>>> data, thus making a different decision to the rc=1 [halts] decision.
>>>> Maybe you mean something else?
>>>>
>>>>
>>>> Mike.
>>>>
>> >
>>> An x86 emulator could keep track of all of the details of the
>>> execution trace of any input. If the original Simulate() was adapted
>>> to have this feature and the names remain the same then H_Hat() would
>>> invoke this updated version of Simulate() and still be infinitely
>>> recursive.
>>
>> So was my guess right? Does "figuring out" mean that Simulate2
>> returns some different rc (not 1) when it detects the nested calls to
>> Simulate2 with the same input data, thus making a different decision
>> to the rc=1 [halts] decision? All you've done is replace "figuring
>> out" with "keep track of" which is no better.
>>
>>>
>>> When software engineers add features to existing functions they do
>>> not change the names.
>>
>> What they do is change the versions. But you are not a software
>> engineer, so maybe you don't know about version numbers.
>>
>> Software engineers use version control systems so that if required
>> they can recreate the software at whatever point in the development
>> cycle is required, so there will not be confusion over what code is
>> being used/discussed at any time.
>>
>
> This is the version number of the whole system at that point in time. I
> worked on defense projects using version control. The function almost
> always keep their original names and merely acquire additional
> functionality.
>
>> In contrast, /you/ habitually use the same name for different
>> programs, and different names for the same programs. I suspect this
>> is because in part your arguments rely on confusing different programs
>> as being the same thing, in various ways. So it seems to me that you
>> do this deliberately. This is the exact opposite to how a software
>> engineer or professional programmer would behave.
>>
>
> There are only three programs that I will be talking about:
>
> // P has the machine address of H_Hat()
> void H_Hat(u32 P)
> {
> u32 Input_Halts = Simulate(P, P);
> if (Input_Halts)
> HERE: goto HERE;
> return;
> }
>
> That calls Simulate(P, P) and as the conversation progresses will
> gradually be adapted step-by-step until it becomes Halts(P, P).
>
> There will not be any version numbers for Simulate() because Simulate()
> is merely a conversational convention used to construct complete
> understanding of Halts() in small incremental steps.
>
>
>> If it is not deliberate, I suggest you just affix versions to the end
>> of your programs e.g. "H_Hat2" when they change. That's easier than
>> full versions, e.g. "H_Hat (V2.1.0.0)" and more appropriate for
>> newsgroup discussions.
>>
>>
>> Mike.
int Simulate_1(u32 P, u32 I);
Emulates the x86 code pointed to by machine address P with data at
machine address I.
int Simulate_2(u32 P, u32 I);
Same as Simulate_1() except keeps track of the execution trace of its
input including the data passed to any function invocations.
int Simulate_3(u32 P, u32 I);
Same as Simulate_2() except examines the saved execution trace
immediately after emulating each x86 language instruction to determine
whether or not this input specifies infinite recursion.
It should be self-evident that whenever any of these versions is
substituted into the body of H_Hat() that H_Hat() remains infinitely
recursive.
It should be self-evident that Simulate_3() can easily determine the
infinite recursion of H_Hat() on the basis its execution trace.