What does the expression "Turing Complete" mean?
Can you give a simple explanation, without going into too many theoretical details?
Here's the briefest explanation:
A Turing Complete system means a system in which a program can be written that will find an answer (although with no guarantees regarding runtime or memory).
So, if somebody says "my new thing is Turing Complete" that means in principle (although often not in practice) it could be used to solve any computation problem.
Sometimes it's a joke... a guy wrote a Turing Machine simulator in vi, so it's possible to say that vi is the only computational engine ever needed in the world.
Here is the simplest explanation
Alan Turing created a machine that can take a program, run that program, and show some result. But then he had to create different machines for different programs. So he created "Universal Turing Machine" that can take ANY program and run it.
Programming languages are similar to those machines (although virtual). They take programs and run them. Now, a programing language is called "Turing complete", if it can run any program (irrespective of the language) that a Turing machine can run given enough time and memory.
For example: Let's say there is a program that takes 10 numbers and adds them. A Turing machine can easily run this program. But now imagine that for some reason your programming language can't perform the same addition. This would make it "Turing incomplete" (so to speak). On the other hand, if it can run any program that the universal Turing machine can run, then it's Turing complete.
Most modern programming languages (e.g. Java, JavaScript, Perl, etc.) are all Turing complete because they each implement all the features required to run programs like addition, multiplication, if-else condition, return statements, ways to store/retrieve/erase data and so on.
Update: You can learn more on my blog post: "JavaScript Is Turing Complete" — Explained
Informal Definition
A Turing complete language is one that can perform any computation. The Church-Turing Thesis states that any performable computation can be done by a Turing machine. A Turing machine is a machine with infinite random access memory and a finite 'program' that dictates when it should read, write, and move across that memory, when it should terminate with a certain result, and what it should do next. The input to a Turing machine is put in its memory before it starts.
Things that can make a language NOT Turing complete
A Turing machine can make decisions based on what it sees in memory - The 'language' that only supports +, -, *, and / on integers is not Turing complete because it can't make a choice based on its input, but a Turing machine can.
A Turing machine can run forever - If we took Java, Javascript, or Python and removed the ability to do any sort of loop, GOTO, or function call, it wouldn't be Turing complete because it can't perform an arbitrary computation that never finishes. Coq is a theorem prover that can't express programs that don't terminate, so it's not Turing complete.
A Turing machine can use infinite memory - A language that was exactly like Java but would terminate once it used more than 4 Gigabytes of memory wouldn't be Turing complete, because a Turing machine can use infinite memory. This is why we can't actually build a Turing machine, but Java is still a Turing complete language because the Java language has no restriction preventing it from using infinite memory. This is one reason regular expressions aren't Turing complete.
A Turing machine has random access memory - A language that only lets you work with memory through push and pop operations to a stack wouldn't be Turing complete. If I have a 'language' that reads a string once and can only use memory by pushing and popping from a stack, it can tell me whether every ( in the string has its own ) later on by pushing when it sees ( and popping when it sees ). However, it can't tell me if every ( has its own ) later on and every [ has its own ] later on (note that ([)] meets this criteria but ([]] does not). A Turing machine can use its random access memory to track ()'s and []'s separately, but this language with only a stack cannot.
A Turing machine can simulate any other Turing machine - A Turing machine, when given an appropriate 'program', can take another Turing machine's 'program' and simulate it on arbitrary input. If you had a language that was forbidden from implementing a Python interpreter, it wouldn't be Turing complete.
Examples of Turing complete languages
If your language has infinite random access memory, conditional execution, and some form of repeated execution, it's probably Turing complete. There are more exotic systems that can still achieve everything a Turing machine can, which makes them Turing complete too:
Untyped lambda calculus
Conway's game of life
C++ Templates
Prolog
From wikipedia:
Turing completeness, named after Alan
Turing, is significant in that every
plausible design for a computing
device so far advanced can be emulated
by a universal Turing machine — an
observation that has become known as
the Church-Turing thesis. Thus, a
machine that can act as a universal
Turing machine can, in principle,
perform any calculation that any other
programmable computer is capable of.
However, this has nothing to do with
the effort required to write a program
for the machine, the time it may take
for the machine to perform the
calculation, or any abilities the
machine may possess that are unrelated
to computation.
While truly Turing-complete machines
are very likely physically impossible,
as they require unlimited storage,
Turing completeness is often loosely
attributed to physical machines or
programming languages that would be
universal if they had unlimited
storage. All modern computers are
Turing-complete in this sense.
I don't know how you can be more non-technical than that except by saying "turing complete means 'able to answer computable problem given enough time and space'".
Fundamentally, Turing-completeness is one concise requirement, unbounded recursion.
Not even bounded by memory.
I thought of this independently, but here is some discussion of the assertion. My definition of LSP provides more context.
The other answers here don't directly define the fundamental essence of Turing-completeness.
Turing Complete means that it is at least as powerful as a Turing Machine. This means anything that can be computed by a Turing Machine can be computed by a Turing Complete system.
No one has yet found a system more powerful than a Turing Machine. So, for the time being, saying a system is Turing Complete is the same as saying the system is as powerful as any known computing system (see Church-Turing Thesis).
In the simplest terms, a Turing-complete system can solve any possible computational problem.
One of the key requirements is the scratchpad size be unbounded and that is possible to rewind to access prior writes to the scratchpad.
Thus in practice no system is Turing-complete.
Rather some systems approximate Turing-completeness by modeling unbounded memory and performing any possible computation that can fit within the system's memory.
Super-brief summary from what Professor Brasilford explains in this video.
Turing Complete ≅ do anything that a Turing Machine can do.
It has conditional branching (i.e. "if statement"). Also, implies "go to" and thus permitting loop.
It gets arbitrary amount of memory (e.g. long enough tape) that the program needs.
I think the importance of the concept "Turing Complete" is in the the ability to identify a computing machine (not necessarily a mechanical/electrical "computer") that can have its processes be deconstructed into "simple" instructions, composed of simpler and simpler instructions, that a Universal machine could interpret and then execute.
I highly recommend The Annotated Turing
#Mark i think what you are explaining is a mix between the description of the Universal Turing Machine and Turing Complete.
Something that is Turing Complete, in a practical sense, would be a machine/process/computation able to be written and represented as a program, to be executed by a Universal Machine (a desktop computer). Though it doesn't take consideration for time or storage, as mentioned by others.
A Turing Machine requires that any program
can perform condition testing. That is fundamental.
Consider a player piano roll. The player piano can
play a highly complicated piece of music,
but there is never any conditional logic in the
music. It is not Turing Complete.
Conditional logic is both the power and the
danger of a machine that is Turing Complete.
The piano roll is guaranteed to halt every time.
There is no such guarantee for a TM. This
is called the “halting problem.”
In practical language terms familiar to most programmers, the usual way to detect Turing completeness is if the language allows or allows the simulation of nested unbounded while statements (as opposed to Pascal-style for statements, with fixed upper bounds).
We call a language Turing-complete if and only if (1) it is decidable by a Turing machine but (2) not by anything less capable than a Turing machine. For instance, the language of palindromes over the alphabet {a, b} is decidable by Turing machines, but also by pushdown automata; so, this language is not Turing-complete. Truly Turing-complete languages - ones that require the full computing power of Turing machines - are pretty rare. Perhaps the language of strings x.y.z where x is a number, y is a Turing-machine and z is an initial tape configuration, and y halts on z in fewer than x! steps - perhaps that qualifies (though it would need to be shown!)
A common imprecise usage confuses Turing-completeness with Turing-equivalence. Turing-equivalence refers to the property of a computational system which can simulate, and which can be simulated by, Turing machines. We might say Java is a Turing-equivalent programming language, for instance, because you can write a Turing-machine simulator in Java, and because you could define a Turing machine that simulates execution of Java programs. According to the Church-Turing thesis, Turing machines can perform any effective computation, so Turing-equivalence means a system is as capable as possible (if the Church-Turing thesis is true!)
Turing equivalence is a much more mainstream concern that true Turing completeness; this and the fact that "complete" is shorter than "equivalent" may explain why "Turing-complete" is so often misused to mean Turing-equivalent, but I digress.
As Waylon Flinn said:
Turing Complete means that it is at least as powerful as a Turing Machine.
I believe this is incorrect, a system is Turing complete if it's exactly as powerful as the Turing Machine, i.e. every computation done by the machine can be done by the system, but also every computation done by the system can be done by the Turing machine.
Can a relational database input latitudes and longitudes of places and roads, and compute the shortest path between them - no. This is one problem that shows SQL is not Turing complete.
But C++ can do it, and can do any problem. Thus it is.
Related
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
"Is it possible to create a quine in every turing-complete language?" says that:
Any programming language which is
Turing complete, and which is able to
output any string (by a computable
function of the string as program —
this is a technical condition that is
satisfied in every programming
language in existence) has a quine
program (and, in fact, infinitely many
quine programs, and many similar
curiosities) as follows by the
fixed-point theorem.
If I created Language X that has the following output handler:
public void outputHander( OutputEvent e ){
String msg = e.getMessage();
String src = Runtime.getSource();
if( msg.equals(src) ){
e.setMessage("");
}
}
This prevents the source from being output in any way.
If the interpreter for Language X was checking for its source at all times on the screen and the source was found, it's deleted before it hits the screen.
Given that an empty program will throw a non-blank error, is Language X still Turing complete? Why?
Although a quine can be prevented, it can still, possibly, simulate Turing-complete algorithms that don't require I/O. The Turing-completeness of Language X is unknown.
How can you prove your language cannot be tricked into outputting its own source code? To make this work, your language can't have any way to run external programs, otherwise, it could accidentally be made to send a suitably encoded version of its source code to a command-line tool, like uuencode or rot-13 or something. Just about any UNIX tool could act as a decoder.
Your language won't be capable of running itself either, it can't be an interpreter, it has to be a compiler. Otherwise, it could modify itself to output its own source code. On top of that, your compiler can't be useable for creating an interpreter in an arbitrary language, otherwise, you'll have a quine on your hands.
And once you've crippled the language so that it can't be used to create an interpreter in an arbitrary language, it's hard to see in what sense you would call it Turing complete at that point. In order to be provably crippled from ever outputting a quine, your language has to be extremely weak by Turing standards, and certainly not Turing complete.
EDIT - The conversation has begun to resemble the old argument about how many angels can be placed on the head of a pin. So, I will attempt to settle the question in a rigorous way. Virtualization is not relevant because a Turing machine is an abstract model of a computational device, and the only I/O that's implemented on the original Turing machine model is a movable tape upon which symbols get printed. The same tape is used as the memory - both for data and for the program store. The whole conversation seems to hinge on whether a Turing machine has to be able to output an arbitrary string in order to qualify as Turing complete. I will prove that it does by defining a Turing machine (Turing machine L) that outputs the source code of Language X. A machine that merely compiles code might not qualify as Turing complete, as that code may never be run. So we will define the implementation for Language X to be an interpreter rather than a compiler.
There is a natural question about whether outputting the source code for Language X counts if it's mixed with program code / other data / other output. So we will define this Turing machine to have a zero point on its tape. Anything to the left of the zero point is either code or data. Everything to the right of the zero point is for output. Turing machine L has a number (infinite) of different implementations. But they all have a predefined code section that can contain zero or more bytes of program code and/or data.
It is in all respects a normal Turing machine with a normal set of instructions, except that the instruction that adds two numbers is implemented in a special way. The code for this instruction actually contains a suitably encoded version of the source code for Language X. Under normal circumstances, the adding functionality behaves as usual for a typical Turing machine. But whenever the tape head encounters the string "Happy birthday to you..." in the data section, the addition instruction behaves differently. In this case, it prints out the decoded source code to Language X in the output section of the tape. "Happy birthday to you..." can exist in the code/data section of the tape just fine without triggering the alternate behavior of the addition instruction. It's only when the tape head actually encounters "Happy birthday to you..." that the alternate behavior is triggered. This means that Language X has to solve the halting problem in order to prevent Turing machine L from outputting the source code to language X without otherwise altering its behavior - which it can never do. Language X has to be able to run (simulate) Turing machine L in order to qualify as Turing complete. And that means that if Language X is Turing complete, then it must be capable of running some infinite number of Turing machine L implementations that output the source code to Language X, and can't interfere or it would fail to properly simulate Language X.
Now, it's still valid to ask whether merely erasing the outputted string from memory qualifies as preventing Turing machine L from forcing Language X (supposed to be Turing complete) to output its own source code - while maintaining the Turing completeness of Language X . I maintain that it does not - and I will prove this too. We will simply define a derivative of Turing machine L: Turing machine L'. This one is almost the same as Turing machine L, and like Turing machine L it comes in a number of different implementations. The only difference is that Turing machine L' comes with a mechanism for verifying the integrity of its output section. If the tape head encounters "Happy birthday to you..." then in addition to triggering the alternate behavior of addition, a special register called the "happy birthday register" flips its bit from 0 to 1 (it can flip back too). With this bit flipped, Turing machine L' will read the output section of the tape looking for the decoded source code to Language X. If it finds it, everything behaves as normal. But if it does not, then the machine's JZ (jump if zero) instruction will behave differently (it will move the tape head in a much less predictable fashion, much as though it were malfunctioning) - but only once the "happy birthday register" has flipped back. Additionally, whenever this verification fails to find the needed source code, the addition instruction will behave erratically as well, sometimes doing addition, and sometimes using the alternate behavior of outputting the source code to Language X. Now, because by erasing the output of Turing machine L' (the source code for Language X) you have changed it's behavior, you now have to solve the halting problem in order to properly simulate it while still erasing the source code to Language X every time it appears. And this is impossible. Even worse, Language X cannot know in advance how Turing machine L' is implemented , as there are an infinite number of valid implementations of Turing machine L and Turing machine L'. So Language X must choose between being Turing complete and refusing to output its own source code. It cannot do both.
EDIT2 - Another proof. A Turing machine is defined as a machine having a symbol tape, a non-empty set of symbols, and a non-empty set of transition functions (instructions) defined on subsets of those symbols (moving the tape, adding, multiplying, whatever). A Turing machine is Turing complete if it can simulate any other Turing machine. A Turing machine could be defined as having just two symbols and could still be Turing complete. For example, those symbols could be <blank> and 1. Now let's say that we take any fully functional Turing machine (an infinite number of Turing machines, some Turing complete, some not) defined with symbols <blank> and 1, but instead of 1, we use the source code to language X. So this Turing machine could do any task, in principle. It could calculate fibonacci numbers, print "hello world", play chess, calculate the orbital parameters for satellites in orbit, etc, etc. And whenever it does any of these calculations, it outputs (to its internal data store) some number of copies of the source code to language X, separated by blanks. Language X is either able to simulate this entire class of Turing machines, or it's not. If language X can simulate this entire class of Turing machines, then it could be Turing complete. If it can't then it is not. Every Turing complete machine can simulate every Turing machine in the entire possibility space of Turing machines. An uncountable infinity of Turing machines.
I'm new to programming and I've been told that "Javascript is a Turing complete programming language". What is a "Turing complete" P.language?... I've tried to read some articles in Wiki like Turing complete, or Turing completeness but still couldn't get an asnwer that was enough primal and clear to me...
In layman's terms, you can think of it as a "complete" programming language.
In practice, languages which are not Turing complete have somewhat crippling limitations, such as ones which disallow recursion. It may be fine for a limited-purpose language, but it means that some algorithms cannot be expressed, and some others require tortured workarounds.
In computer science, it is an important principle that complex systems can be "reduced" (proven to be isomorphic, i.e. fundamentally equivalent) to very simple systems which we can reason about. It is fairly easy to reason about what a Turing machine (a very crude theoretical abstraction of a modern computer) can and cannot do; we then know that our conclusions must be true for any system which can be reduced to a Turing machine.
But for your concrete question, this is just a snobbish way to tell the snobs you are one of them, actually.
Turing proved that the halting problem is undecidable over Turing machines. However, real computers are not actually Turing-complete: They would be, if they had an infinite amount of memory.
Given the fact that computers have a finite amount of memory, hence are not quite Turning-complete, does the halting problem become decidable? My intuition tells me that yes, but the program that solves this restricted halting problem might have a time and space complexity exponential to the size of the memory of the targeted computer.
The halting problem can be solved for a Turing machine with finite tape by a Turing machine with infinite tape. All the infinite Turing machine has to do is enumerate every possible state of the finite Turing machine (and there will be a finite, though very large, number of possible states) and mark which states have been visited by the Turing machine in the course of running a program. Eventually, one of two things will happen:
The finite Turing machine will halt.
The finite Turing machine will revisit a state. If it revisits a state, then you know there is an infinite loop, since the machine is deterministic, and the next state is therefore determined entirely by the previous state. If there are n states, the machine is guaranteed to revisit one of them on the n+1th step.
The full definition of "Turing Completeness" requires infinite memory.
Is there a better term than Turing Complete for a programming language and implementation that seems useably complete, except for being limited by finite (say 100 word or 16-bit or 32-bit, etc.) address space?
I guess, you can bring the limited memory into the definition. Something like
A programming language for a given architecture (!) is Limitedly Turing Complete, if for every Turing Machine there exists a program that either
a) simulates the Turing Machine and returns the same result (iff the Turing Machine returns) or
b) at some point uses at least one available limited resource (e.g. memory) completely and returns an arbitrary result.
The question is, whether this intuitive definition really helps, or if it is better to assume that your architecture has unlimited memory (even though it is actually finite). Note that you don't even have to try hard in order to satisfy Limited Turing Completeness (as defined above), if you simply go into an infinite loop that mallocs one byte each time, you found your program for all Turing Machines.
The problem seems to be that you cannot pin implementation specific properties. For instance, if you have 500K ram, you may be able to express a program that computes 1+1 but maybe you're not, who knows.
I'd argue that languages like Haskell and Brainfuck (yes, I'm serious) are actually Turing Complete because they abstract resources away. While languages like C++ are only Limitedly Turing Complete, because at some point the address-space of pointers is exhausted and it is not possible to address any more data (e.g. sort a list of 2^2^2^2^100 items).
You could say that an implementation requires infinite memory to be truly turing complete, but languages themselves have no concept of a memory limit. You can make a compiler for a million-bit machine or a 4-bit machine without changing the language.
What exactly are the advantages and disadvantages to using a register-based virtual machine versus using a stack-based virtual machine?
To me, it would seem as though a register based machine would be more straight-forward to program and more efficient. So why is it that the JVM, the CLR, and the Python VM are all stack-based?
Implemented in hardware, a register-based machine is going to be more efficient simply because there are fewer accesses to the slower RAM. In software, however, even a register based architecture will most likely have the "registers" in RAM. A stack based machine is going to be just as efficient in that case.
In addition a stack-based VM is going to make it a lot easier to write compilers. You don't have to deal with register allocation strategies. You have, essentially, an unlimited number of registers to work with.
Update: I wrote this answer assuming an interpreted VM. It may not hold true for a JIT compiled VM. I ran across this paper which seems to indicate that a JIT compiled VM may be more efficient using a register architecture.
This has already been answered, to a certain level, in the Parrot VM's FAQ and associated documents:
A Parrot Overview
The relevant text from that doc is this:
the Parrot VM will have a register architecture, rather than a stack architecture. It will also have extremely low-level operations, more similar to Java's than the medium-level ops of Perl and Python and the like.
The reasoning for this decision is primarily that by resembling the underlying hardware to some extent, it's possible to compile down Parrot bytecode to efficient native machine language.
Moreover, many programs in high-level languages consist of nested function and method calls, sometimes with lexical variables to hold intermediate results. Under non-JIT settings, a stack-based VM will be popping and then pushing the same operands many times, while a register-based VM will simply allocate the right amount of registers and operate on them, which can significantly reduce the amount of operations and CPU time.
You may also want to read this: Registers vs stacks for interpreter design
Quoting it a bit:
There is no real doubt, it's easier to generate code for a stack machine. Most freshman compiler students can do that. Generating code for a register machine is a bit tougher, unless you're treating it as a stack machine with an accumulator. (Which is doable, albeit somewhat less than ideal from a performance standpoint) Simplicity of targeting isn't that big a deal, at least not for me, in part because so few people are actually going to directly target it--I mean, come on, how many people do you know who actually try to write a compiler for something anyone would ever care about? The numbers are small. The other issue there is that many of the folks with compiler knowledge already are comfortable targeting register machines, as that's what all hardware CPUs in common use are.
Traditionally, virtual machine implementors have favored stack-based architectures over register-based due to 'simplicity of VM implementation' ease of writing a compiler back-end - most VMs are originally designed to host a single language and code density and executables for stack architecture are invariably smaller than executables for register architectures. The simplicity and code density are a cost of performance.
Studies have shown that a registered-based architecture requires an average of 47% less executed VM instructions than stack-based architecture, and the register code is 25% larger than corresponding stack code but this increase cost of fetching more VM instructions due to larger code size involves only 1.07% extra real machine loads per VM instruction which is negligible. The overall performance of the register-based VM is that it takes, on average, 32.3% less time to execute standard benchmarks.
One reason for building stack-based VMs is that that actual VM opcodes can be smaller and simpler (no need to encode/decode operands). This makes the generated code smaller, and also makes the VM code simpler.
How many registers do you need?
I'll probably need at least one more than that.
Stack based VM's are simpler and the code is much more compact. As a real world example, a friend built (about 30 years ago) a data logging system with a homebrew Forth VM on a Cosmac. The Forth VM was 30 bytes of code on a machine with 2k of ROM and 256 bytes of RAM.
It is not obvious to me that a "register-based" virtual machine would be "more straight-forward to program" or "more efficient". Perhaps you are thinking that the virtual registers would provide a short-cut during the JIT compilation phase? This would certainly not be the case, since the real processor may have more or fewer registers than the VM, and those registers may be used in different ways. (Example: values that are going to be decremented are best placed in the ECX register on x86 processors.) If the real machine has more registers than the VM, then you're wasting resources, fewer and you've gained nothing using "register-based" programming.
Stack based VMs are easier to generate code for.
Register based VMs are easier to create fast implementations for, and easier to generate highly optimized code for.
For your first attempt, I recommend starting with a stack based VM.