Jump to content

Rice's theorem: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
Simplify the formal statement, don't introduce unnecessary notations
Zvavybir (talk | contribs)
Explained that it is possible to not have false positives and false negatives at the same time
 
(13 intermediate revisions by 2 users not shown)
Line 2: Line 2:
In [[computability theory]], '''Rice's theorem''' states that all non-trivial semantic properties of programs are [[undecidable problem|undecidable]]. A ''semantic'' property is one about the program's behavior (for instance, "does the program [[halting problem|terminate]] for all inputs?"), unlike a syntactic property (for instance, "does the program contain an [[if-then-else]] statement?"). A ''non-trivial'' property is one which is neither true for every program, nor false for every program.
In [[computability theory]], '''Rice's theorem''' states that all non-trivial semantic properties of programs are [[undecidable problem|undecidable]]. A ''semantic'' property is one about the program's behavior (for instance, "does the program [[halting problem|terminate]] for all inputs?"), unlike a syntactic property (for instance, "does the program contain an [[if-then-else]] statement?"). A ''non-trivial'' property is one which is neither true for every program, nor false for every program.


The theorem generalizes the undecidability of the [[halting problem]]. It has far-reaching implications on the feasibility of [[static program analysis|static analysis]] of programs. It implies that it is impossible, for example, to implement a tool that checks whether a given program is [[correctness (computer science)|correct]], or even executes without error.
The theorem generalizes the undecidability of the [[halting problem]]. It has far-reaching implications on the feasibility of [[static program analysis|static analysis]] of programs. It implies that it is impossible, for example, to implement a tool that checks whether a given program is [[correctness (computer science)|correct]], or even executes without error (it is possible to implement a tool that always overestimates or always underestimates e.g. the correctness of a program, so in practice one has to decide what is less of a problem).


The theorem is named after [[Henry Gordon Rice]], who proved it in his doctoral dissertation of 1951 at [[Syracuse University]].
The theorem is named after [[Henry Gordon Rice]], who proved it in his doctoral dissertation of 1951 at [[Syracuse University]].


==Introduction==
==Introduction==
Rice's theorem puts a theoretical bound on which types of [[static program analysis|static analysis]] can be performed automatically. One can distinguish between the [[syntax (programming languages)|syntax]] of a program, and its [[semantics (computer science)|semantics]]. The syntax is the detail of how the program is written, or its "intension", and the semantics is how the program behaves when run, or its "extension". Rice's theorem asserts that it is impossible to decide a property of programs which depends only on the semantics and not on the syntax, unless the property is trivial (true of all programs, or false of all programs).
Let {{var|p}} be a property of a [[formal language]] {{var|L}} that is nontrivial, meaning
# there exists a [[recursively enumerable language]] having the property ''p'',
# there exists a recursively enumerable language not having the property ''p'',
(that is, ''p'' is neither uniformly true nor uniformly false for all recursively enumerable languages).


By Rice's theorem, it is impossible to write a program that automatically verifies for the absence of [[software bug|bugs]] in other programs, taking a program and a [[formal specification|specification]] as input, and checking whether the program satisfies the specification.
Then it is [[decision problem|undecidable]] to determine for a given [[Turing machine]] ''M'', whether the language recognized by it has the property ''p''.


This does not imply an impossibility to prevent ''certain types'' of bugs. For example, Rice's theorem implies that in [[dynamic programming language|dynamically typed programming languages]] which are [[Turing completeness|Turing-complete]], it is impossible to verify the absence of type errors. On the other hand, [[static typing|statically typed programming languages]] feature a type system which statically prevents type errors. In essence, this should be understood as a feature of the ''syntax'' (taken in a broad sense) of those languages. In order to type check a program, its source code must be inspected; the operation does not depend merely on the hypothetical semantics of the program.
In practice, this means that there is no machine that can always decide whether the language of a given Turing machine has a particular nontrivial property. Special cases include e.g. the undecidability of whether the language recognized by a Turing machine could be recognized by a nontrivial simpler machine, such as a [[finite automaton]] (meaning, it is undecidable whether the language of a Turing machine is [[regular language|regular]]).


In terms of general software verification, this means that although one cannot algorithmically check whether a given program satisfies a given specification, one can require programs to be annotated with extra information that proves the program is correct, or to be written in a particular restricted form that makes the verification possible, and only accept programs which are verified in this way. In the case of type safety, the former corresponds to type annotations, and the latter corresponds to [[type inference]]. Taken beyond type safety, this idea leads to correctness proofs of programs through proof annotations such as in [[Hoare logic]].
It is important to note that Rice's theorem does not concern the properties of machines or programs; it concerns properties of functions and languages. For example, whether a machine runs for more than 100 steps on a particular input is a decidable property, even though it is non-trivial. Two different machines recognizing exactly the same language might require a different number of steps to recognize the same input string. Similarly, whether a machine has more than five states is a decidable property of the machine, as the number of states can simply be counted. For properties of this kind, which concerns a Turing machine but not the language recognized by it, Rice's theorem does not apply.


Another way of working around Rice's theorem is to search for methods which catch ''many'' bugs, without being complete. This is the theory of [[abstract interpretation]].
Using [[Hartley Rogers, Jr|Rogers]]' characterization of [[Roger's equivalence theorem|acceptable programming system]]s, Rice's theorem may essentially be generalized from Turing machines to most computer [[programming language]]s: there exists no automatic method that decides with generality non-trivial questions on the behavior of computer programs.


Yet another direction for verification is [[model checking]], which can only apply to finite-state programs, not to Turing-complete languages.
As an example, consider the following variant of the [[halting problem]]. Let ''P'' be the following property of partial functions '''F''' of one argument: ''P''('''F''') means that '''F''' is defined for the argument '1'. It is obviously non-trivial, since there are partial functions that are defined at 1, and others that are undefined at 1. The ''1-halting problem'' is the problem of deciding of any algorithm whether it defines a function with this property, i.e., whether the algorithm halts on input 1. By Rice's theorem, the 1-halting problem is undecidable. Similarly the question of whether a Turing machine ''T'' terminates on an initially empty tape (rather than with an initial word ''w'' given as second argument in addition to a description of ''T'', as in the full halting problem) is still undecidable.


==Formal statement==
==Formal statement==
Let ''φ'' be an [[admissible numbering]] of [[partial computable function]]s. Let ''P'' be a subset of . Suppose that:
Let ''φ'' be an [[admissible numbering]] of [[partial computable function]]s. Let ''P'' be a subset of <math>\mathbb{N}</math>. Suppose that:
#. ''P' is ''non-trivial'': ''P'' is neither empty nor itself.
# ''P'' is ''non-trivial'': ''P'' is neither empty nor <math>\mathbb{N}</math> itself.
#. ''P'' is ''extensional'': for all integers ''m'' and ''n'', if ''φ''<sub>''m''</sub> = ''φ''<sub>''n''</sub>, then ''m'' ∈ ''P'' ⟺ ''n'' ∈ ''P''.
# ''P'' is ''extensional'': for all integers ''m'' and ''n'', if ''φ''<sub>''m''</sub> = ''φ''<sub>''n''</sub>, then ''m'' ∈ ''P'' ⟺ ''n'' ∈ ''P''.
Then ''P'' is [[undecidable problem|undecidable]].
Then ''P'' is [[undecidable problem|undecidable]].

A more concise statement can be made in terms of [[index set (computability) | index sets]]: The only decidable index sets are ∅ and <math>\mathbb{N}</math>.


==Examples==
==Examples==
Given a program ''P'' which takes a natural number ''n'' and returns a natural number ''P''(''n''), the following questions are undecidable:
According to Rice's theorem, if there is at least one partial computable function in a particular class ''C'' of partial computable functions and another partial computable function not in ''C'' then the problem of deciding whether a particular program computes a function in ''C'' is undecidable. For example, Rice's theorem shows that each of the following sets of partial computable functions is undecidable (that is, the set is not recursive, or not [[Recursive set|computable]]):
* Does ''P'' terminate on a given ''n''? (This is the [[halting problem]].)
* The class of partial computable functions that return ''0'' for every input, and its complement.
* Does ''P'' terminate on 0?
* The class of partial computable functions that return ''0'' for at least one input, and its complement.
* Does ''P'' terminate on ''all'' ''n'' (i.e., is ''P'' [[general recursive function|total]])?
* The class of partial computable functions that are constant, and its complement.
* Does ''P'' terminate and return 0 on every input?
*The class of partial computable functions that are identical to a given partial computable function, and its complement.
* Does ''P'' terminate and return 0 on some input?
*The class of partial computable functions that diverge (i.e., undefined) for some input, and its complement.
* Does ''P'' terminate and return the same value for all inputs?
* The class of indices for computable functions that are total.<ref>{{cite book |last1=Soare |first1=Robert I. |author-link= Robert I. Soare |title=Recursively Enumerable Sets and Degrees |url=https://archive.org/details/recursivelyenume00soar |url-access=limited |year=1987 |publisher=Springer |page=[https://archive.org/details/recursivelyenume00soar/page/n38 21]|isbn=9780387152998 }}</ref>
* Is ''P'' equivalent to a given program ''Q''?
* The class of indices for [[recursively enumerable set]]s that are cofinite.
* The class of indices for recursively enumerable sets that are recursive.


==Proof by Kleene's recursion theorem==
==Proof by Kleene's recursion theorem==
[[Kleene's recursion theorem#Application to quines|A corollary]] to [[Kleene's recursion theorem]] states that for every [[Gödel number]]ing <math>\phi\colon \mathbb{N} \to \mathbf{P}^{(1)}</math> of the [[computable function]]s and every computable function <math>Q(x,y)</math>, there is an index <math>e</math> such that <math>\phi_e(y)</math> returns <math>Q(e,y)</math>. (In the following, we say that <math>f(x)</math> "returns" <math>g(x)</math> if either <math>f(x)=g(x)</math>, or both <math>f(x)</math> and <math>g(x)</math> are undefined.) Intuitively, <math>\phi_e</math> is a [[Quine (computing)|quine]], a function that returns its own source code (Gödel number), except that rather than returning it directly, <math>\phi_e</math> passes its Gödel number to <math>Q</math> and returns the result.
Assume for contradiction that <math>P</math> is a non-trivial, extensional and computable set of natural numbers. There is a natural number <math>a \in P</math> and a natural number <math>b \notin P</math>. Define a function <math>Q</math> by <math>Q_e(x) = \varphi_b(x)</math> when <math>e \in P</math> and <math>Q_e(x) = \varphi_a(x)</math> when <math>e \notin P</math>. By [[Kleene's recursion theorem]], there exists <math>e</math> such that <math>\varphi_e = Q_e</math>. Then, if <math>e \in P</math>, we have <math>\varphi_e = \varphi_b</math>, contradicting the extensionality of <math>P</math> since <math>b \notin P</math>, and conversely, if <math>e \notin P</math>, we have <math>\varphi_e = \varphi_a</math>, which again contradicts extensionality since <math>a \in P</math>.

Assume for contradiction that <math>F</math> is a set of computable functions such that <math>\emptyset \neq F \neq \mathbf{P}^{(1)}</math>. Then there are computable functions <math>f \in F</math> and <math>g \notin F</math>. Suppose that the set of indices <math>x</math> such that <math>\phi_x \in F</math> is decidable; then, there exists a function <math>Q(x,y)</math> that returns <math>g(y)</math> if <math>\phi_x \in F</math>, and <math>f(y)</math> otherwise. By the corollary to the recursion theorem, there is an index <math>e</math> such that <math>\phi_e(y)</math> returns <math>Q(e,y)</math>. But then, if <math>\phi_e \in F</math>, then <math>\phi_e</math> is the same function as <math>g</math>, and therefore <math>\phi_e \notin F</math>; and if <math>\phi_e \notin F</math>, then <math>\phi_e</math> is <math>f</math>, and therefore <math>\phi_e \in F</math>. In both cases, we have a contradiction.


==Proof by reduction from the halting problem==
==Proof by reduction from the halting problem==


===Proof sketch===
===Proof sketch===
Suppose, for concreteness, that we have an algorithm for examining a program ''p'' and determining infallibly whether ''p'' is an implementation of the squaring function, which takes an integer ''d'' and returns ''d''<sup>2</sup>. The proof works just as well if we have an algorithm for deciding any other nontrivial property of program behavior (i.e. a semantic and non-trivial property), and is given in general below.
Suppose, for concreteness, that we have an algorithm for examining a program ''p'' and determining infallibly whether ''p'' is an implementation of the squaring function, which takes an integer ''d'' and returns ''d''<sup>2</sup>. The proof works just as well if we have an algorithm for deciding any other non-trivial property of program behavior (i.e. a semantic and non-trivial property), and is given in general below.


The claim is that we can convert our algorithm for identifying squaring programs into one that identifies functions that halt. We will describe an algorithm that takes inputs ''a'' and ''i'' and determines whether program ''a'' halts when given input ''i''.
The claim is that we can convert our algorithm for identifying squaring programs into one that identifies functions that halt. We will describe an algorithm that takes inputs ''a'' and ''i'' and determines whether program ''a'' halts when given input ''i''.


The algorithm for deciding this is conceptually simple: it constructs (the description of) a new program ''t'' taking an argument ''n'', which (1) first executes program ''a'' on input ''i'' (both ''a'' and ''i'' being hard-coded into the definition of ''t''), and (2) then returns the square of ''n''. If ''a''(''i'') runs forever, then ''t'' never gets to step (2), regardless of ''n''. Then clearly, ''t'' is a function for computing squares if and only if step (1) terminates. Since we've assumed that we can infallibly identify programs for computing squares, we can determine whether ''t'', which depends on ''a'' and ''i'', is such a program; thus we have obtained a program that decides whether program ''a'' halts on input ''i''. Note that our halting-decision algorithm never executes ''t'', but only passes its description to the squaring-identification program, which by assumption always terminates; since the construction of the description of ''t'' can also be done in a way that always terminates, the halting-decision cannot fail to halt either.
The algorithm for deciding this is conceptually simple: it constructs (the description of) a new program ''t'' taking an argument ''n'', which (1) first executes program ''a'' on input ''i'' (both ''a'' and ''i'' being hard-coded into the definition of ''t''), and (2) then returns the square of ''n''. If ''a''(''i'') runs forever, then ''t'' never gets to step (2), regardless of ''n''. Then clearly, ''t'' is a function for computing squares if and only if step (1) terminates. Since we have assumed that we can infallibly identify programs for computing squares, we can determine whether ''t'', which depends on ''a'' and ''i'', is such a program; thus we have obtained a program that decides whether program ''a'' halts on input ''i''. Note that our halting-decision algorithm never executes ''t'', but only passes its description to the squaring-identification program, which by assumption always terminates; since the construction of the description of ''t'' can also be done in a way that always terminates, the halting-decision cannot fail to halt either.


halts (a,i) {
halts (a,i) {
Line 61: Line 57:
}
}


This method doesn't depend specifically on being able to recognize functions that compute squares; as long as ''some'' program can do what we're trying to recognize, we can add a call to ''a'' to obtain our ''t''. We could have had a method for recognizing programs for computing square roots, or programs for computing the monthly payroll, or programs that halt when given the input <code>"Abraxas"</code>; in each case, we would be able to solve the halting problem similarly.
This method does not depend specifically on being able to recognize functions that compute squares; as long as ''some'' program can do what we are trying to recognize, we can add a call to ''a'' to obtain our ''t''. We could have had a method for recognizing programs for computing square roots, or programs for computing the monthly payroll, or programs that halt when given the input <code>"Abraxas"</code>; in each case, we would be able to solve the halting problem similarly.


===Formal proof===
===Formal proof===
Line 80: Line 76:


Since the halting problem is known to be undecidable, this is a contradiction and the assumption that there is an algorithm ''P''(''a'') that decides a non-trivial property for the function represented by ''a'' must be false.
Since the halting problem is known to be undecidable, this is a contradiction and the assumption that there is an algorithm ''P''(''a'') that decides a non-trivial property for the function represented by ''a'' must be false.

==Rice's theorem, index sets and saturated sets==
Rice's theorem can be succinctly stated in terms of index sets:
<blockquote>
Let <math>\mathcal{C}</math> be a class of partial recursive functions with [[index set (recursion theory)|index set]] <math>C</math>. Then <math>C</math> is [[Recursive set|recursive]] if and only if <math>C = \varnothing</math> or <math>C = \mathbb{N}</math>.
</blockquote>

Here <math>\mathbb{N}</math> is the set of [[natural numbers]], including [[zero]].

If a particular set holds this property, the set is considered '''saturated''', meaning whenever a program with a certain property is in the set, all other programs that compute the same function are also in the set. This implies that the set is "complete" with respect to the property in question for programs computing a particular function.

The property does not depend on the program but on the function it computes. A saturated set contains all the indices (which are infinite) of programs that compute functions with a particular common characteristic.

This property holds extensionally, so it is considered '''extensional''' because it depends only on the elements that belong to a set, not on the specific way those elements are represented or defined. This can be used to prove a set is not recursive with the following statement:

Let <math>A</math> be a set and <math>A \neq \emptyset, A \neq \mathbb{N}, A \subseteq \mathbb{N} </math>. If <math>A</math> is saturated, then <math>A</math> is not recursive.

In simpler terms, the saturation property implies that <math>A</math> contains all the indices of programs that compute functions with a common characteristic. This property holds extensionally, meaning it solely depends on the elements within the set without consideration for their internal representations.

The significance of this in proving non-recursiveness lies in the inherent uncertainty: we cannot definitively determine whether a program possesses a specific property precisely. The extensional nature of saturation highlights the challenge in establishing a recursive enumeration for the set <math>A</math>, reinforcing its non-recursive nature.

==An analogue of Rice's theorem for recursive sets==
One can regard Rice's theorem as asserting the impossibility of effectively deciding for any ''recursively enumerable'' set whether it has a certain nontrivial property.<ref>A set <math>S\subseteq \mathbb{N}</math> is ''[[Recursively enumerable set|recursively enumerable]]'' if
<math>S=W_e:=\textrm{dom}\, \phi_e:=\{x: \phi_e(x)\downarrow \}</math>
for some <math>e</math>, where <math>W_e</math> is the domain <math>\textrm{dom}\, \phi_e</math>
(the set of inputs <math>x</math> such that
<math>\phi_e(x)</math> is defined) of <math>\phi_e</math>.
The result for recursively enumerable sets can be obtained from that for (partial) computable functions by
considering the class <math>\{\phi_e: \textrm{dom}\, \phi_e \in C\}</math>, where <math>C</math> is a class of
recursively enumerable sets.</ref> In this section, we give an analogue of Rice's theorem for [[recursive set]]s'','' instead of recursively enumerable sets.<ref>A recursively enumerable
set <math>S\subseteq \mathbb{N}</math> is ''[[Recursive set|recursive]]'' if its complement is recursively enumerable.
Equivalently, <math>S</math> is recursive if its characteristic function is computable.</ref> Roughly speaking, the analogue says that if one can effectively determine for every ''recursive'' set whether it has a certain property, then only finitely many integers determine whether a recursive set has the property. This result is analogous to the original theorem of Rice, because both results assert that a property is "decidable" only if one can determine whether a set has that property by examining ''for at most finitely many <math>i</math>'' (for no <math>i</math>, for the original theorem), if <math>i</math> belongs to the set.

Let <math>W</math> be a class (called a ''simple game'' and thought of as a property) of recursive sets. If <math>S</math> is a recursive set, then for some <math>e</math>, computable function <math>\phi_e</math> is the characteristic function of <math>S</math>. We call <math>e</math> a ''characteristic index'' for <math>S</math>. (There are infinitely many such <math>e</math>.) Let's say the class <math>W</math> is ''computable'' if there is an algorithm (computable function) that decides
for any nonnegative integer <math>e</math> (not necessarily a characteristic index),
* if <math>e</math> is a characteristic index for a recursive set belonging to <math>W</math>, then the algorithm gives "yes";
* if <math>e</math> is a characteristic index for a recursive set not belonging to <math>W</math>, then the algorithm gives "no".

A set <math>S\subseteq \mathbb{N}</math> ''extends'' a string <math>\tau</math> of 0's and 1's if for every <math>k< |\tau|</math> (the length of <math>\tau</math>), the <math>k</math>th element of <math>\tau</math> is 1 if <math>k\in S</math>; and is 0 otherwise. For example, <math>S=\{1,3,4,7, \ldots \}</math> extends the string <math>01011001</math>. A string <math>\tau</math> is ''winning determining'' if every recursive set extending <math>\tau</math> belongs to <math>W</math>. A string <math>\tau</math> is ''losing determining'' if no recursive set extending <math>\tau</math> belongs to <math>W</math>.

We can now state the following ''analogue of Rice's theorem'':<ref>{{cite book |last1=Kreisel |first1=G. |last2=Lacombe |first2=D. |last3=Shoenfield |first3=J. R. |year=1959 |chapter=Partial recursive functionals and effective operations |editor-last=Heyting |editor-first=A. |title=Constructivity in Mathematics |series=Studies in Logic and the Foundations of Mathematics |publisher=North-Holland |location=Amsterdam |pages=290–297 }}</ref><ref name= kumabe-m08jme>{{Cite journal| last1 = Kumabe | first1 = M.| last2 = Mihara | first2 = H. R.| title = Computability of simple games: A characterization and application to the core| journal = Journal of Mathematical Economics| volume = 44| pages = 348–366| year = 2008| issue = 3–4| doi = 10.1016/j.jmateco.2007.05.012 | url=http://econpapers.repec.org/paper/pramprapa/437.htm| arxiv = 0705.3227| s2cid = 8618118}}</ref>

A class <math>W</math> of recursive sets is computable if and only if there are a recursively enumerable set <math>T_0</math> of losing determining strings and a recursively enumerable set <math>T_1</math> of winning determining strings such that every recursive set extends a string in <math>T_0\cup T_1</math>.

This result has been applied to foundational problems in [[computational social choice]] (more broadly, [[algorithmic game theory]]). For instance, Kumabe and Mihara<ref name= kumabe-m08jme /><ref>{{Cite journal | last1 = Kumabe | first1 = M. | last2 = Mihara | first2 = H. R. | title = The Nakamura numbers for computable simple games| journal = Social Choice and Welfare | volume = 31 | issue = 4 | pages = 621 | year = 2008 | doi = 10.1007/s00355-008-0300-5 | url=http://econpapers.repec.org/paper/pramprapa/3684.htm| arxiv = 1107.0439 | s2cid = 8106333 }}</ref> apply this result to an investigation of the [[Nakamura number]]s for simple games in [[cooperative game theory]] and [[social choice theory]].


==See also==
==See also==
* [[Gödel's incompleteness theorems]]
* [[Halting problem]]
* [[Halting problem]]
* [[Rice–Shapiro theorem]] and [[Rice-Shapiro theorem|Kreisel-Lacombe-Shoenfield-Tseitin theorem]], generalizations of Rice's theorem
* [[Recursion theory]]
* [[Rice–Shapiro theorem]]
* [[Scott–Curry theorem]], an analogue to Rice's theorem in lambda calculus
* [[Scott–Curry theorem]], an analogue to Rice's theorem in lambda calculus
* [[Turing's proof]]
* [[Turing's proof]]
* [[Wittgenstein on Rules and Private Language]]

==Notes==
<references/>


==References==
==References==

Latest revision as of 20:40, 28 October 2024

In computability theory, Rice's theorem states that all non-trivial semantic properties of programs are undecidable. A semantic property is one about the program's behavior (for instance, "does the program terminate for all inputs?"), unlike a syntactic property (for instance, "does the program contain an if-then-else statement?"). A non-trivial property is one which is neither true for every program, nor false for every program.

The theorem generalizes the undecidability of the halting problem. It has far-reaching implications on the feasibility of static analysis of programs. It implies that it is impossible, for example, to implement a tool that checks whether a given program is correct, or even executes without error (it is possible to implement a tool that always overestimates or always underestimates e.g. the correctness of a program, so in practice one has to decide what is less of a problem).

The theorem is named after Henry Gordon Rice, who proved it in his doctoral dissertation of 1951 at Syracuse University.

Introduction

[edit]

Rice's theorem puts a theoretical bound on which types of static analysis can be performed automatically. One can distinguish between the syntax of a program, and its semantics. The syntax is the detail of how the program is written, or its "intension", and the semantics is how the program behaves when run, or its "extension". Rice's theorem asserts that it is impossible to decide a property of programs which depends only on the semantics and not on the syntax, unless the property is trivial (true of all programs, or false of all programs).

By Rice's theorem, it is impossible to write a program that automatically verifies for the absence of bugs in other programs, taking a program and a specification as input, and checking whether the program satisfies the specification.

This does not imply an impossibility to prevent certain types of bugs. For example, Rice's theorem implies that in dynamically typed programming languages which are Turing-complete, it is impossible to verify the absence of type errors. On the other hand, statically typed programming languages feature a type system which statically prevents type errors. In essence, this should be understood as a feature of the syntax (taken in a broad sense) of those languages. In order to type check a program, its source code must be inspected; the operation does not depend merely on the hypothetical semantics of the program.

In terms of general software verification, this means that although one cannot algorithmically check whether a given program satisfies a given specification, one can require programs to be annotated with extra information that proves the program is correct, or to be written in a particular restricted form that makes the verification possible, and only accept programs which are verified in this way. In the case of type safety, the former corresponds to type annotations, and the latter corresponds to type inference. Taken beyond type safety, this idea leads to correctness proofs of programs through proof annotations such as in Hoare logic.

Another way of working around Rice's theorem is to search for methods which catch many bugs, without being complete. This is the theory of abstract interpretation.

Yet another direction for verification is model checking, which can only apply to finite-state programs, not to Turing-complete languages.

Formal statement

[edit]

Let φ be an admissible numbering of partial computable functions. Let P be a subset of . Suppose that:

  1. P is non-trivial: P is neither empty nor itself.
  2. P is extensional: for all integers m and n, if φm = φn, then mPnP.

Then P is undecidable.

A more concise statement can be made in terms of index sets: The only decidable index sets are ∅ and .

Examples

[edit]

Given a program P which takes a natural number n and returns a natural number P(n), the following questions are undecidable:

  • Does P terminate on a given n? (This is the halting problem.)
  • Does P terminate on 0?
  • Does P terminate on all n (i.e., is P total)?
  • Does P terminate and return 0 on every input?
  • Does P terminate and return 0 on some input?
  • Does P terminate and return the same value for all inputs?
  • Is P equivalent to a given program Q?

Proof by Kleene's recursion theorem

[edit]

Assume for contradiction that is a non-trivial, extensional and computable set of natural numbers. There is a natural number and a natural number . Define a function by when and when . By Kleene's recursion theorem, there exists such that . Then, if , we have , contradicting the extensionality of since , and conversely, if , we have , which again contradicts extensionality since .

Proof by reduction from the halting problem

[edit]

Proof sketch

[edit]

Suppose, for concreteness, that we have an algorithm for examining a program p and determining infallibly whether p is an implementation of the squaring function, which takes an integer d and returns d2. The proof works just as well if we have an algorithm for deciding any other non-trivial property of program behavior (i.e. a semantic and non-trivial property), and is given in general below.

The claim is that we can convert our algorithm for identifying squaring programs into one that identifies functions that halt. We will describe an algorithm that takes inputs a and i and determines whether program a halts when given input i.

The algorithm for deciding this is conceptually simple: it constructs (the description of) a new program t taking an argument n, which (1) first executes program a on input i (both a and i being hard-coded into the definition of t), and (2) then returns the square of n. If a(i) runs forever, then t never gets to step (2), regardless of n. Then clearly, t is a function for computing squares if and only if step (1) terminates. Since we have assumed that we can infallibly identify programs for computing squares, we can determine whether t, which depends on a and i, is such a program; thus we have obtained a program that decides whether program a halts on input i. Note that our halting-decision algorithm never executes t, but only passes its description to the squaring-identification program, which by assumption always terminates; since the construction of the description of t can also be done in a way that always terminates, the halting-decision cannot fail to halt either.

 halts (a,i) {
   define t(n) {
     a(i)
     return n×n
   }
   return is_a_squaring_function(t)
 }

This method does not depend specifically on being able to recognize functions that compute squares; as long as some program can do what we are trying to recognize, we can add a call to a to obtain our t. We could have had a method for recognizing programs for computing square roots, or programs for computing the monthly payroll, or programs that halt when given the input "Abraxas"; in each case, we would be able to solve the halting problem similarly.

Formal proof

[edit]
If we have an algorithm that decides a non-trivial property, we can construct a Turing machine that decides the halting problem.

For the formal proof, algorithms are presumed to define partial functions over strings and are themselves represented by strings. The partial function computed by the algorithm represented by a string a is denoted Fa. This proof proceeds by reductio ad absurdum: we assume that there is a non-trivial property that is decided by an algorithm, and then show that it follows that we can decide the halting problem, which is not possible, and therefore a contradiction.

Let us now assume that P(a) is an algorithm that decides some non-trivial property of Fa. Without loss of generality we may assume that P(no-halt) = "no", with no-halt being the representation of an algorithm that never halts. If this is not true, then this holds for the algorithm P that computes the negation of the property P. Now, since P decides a non-trivial property, it follows that there is a string b that represents an algorithm Fb and P(b) = "yes". We can then define an algorithm H(a, i) as follows:

1. construct a string t that represents an algorithm T(j) such that
  • T first simulates the computation of Fa(i),
  • then T simulates the computation of Fb(j) and returns its result.
2. return P(t).

We can now show that H decides the halting problem:

  • Assume that the algorithm represented by a halts on input i. In this case Ft = Fb and, because P(b) = "yes" and the output of P(x) depends only on Fx, it follows that P(t) = "yes" and, therefore H(a, i) = "yes".
  • Assume that the algorithm represented by a does not halt on input i. In this case Ft = Fno-halt, i.e., the partial function that is never defined. Since P(no-halt) = "no" and the output of P(x) depends only on Fx, it follows that P(t) = "no" and, therefore H(a, i) = "no".

Since the halting problem is known to be undecidable, this is a contradiction and the assumption that there is an algorithm P(a) that decides a non-trivial property for the function represented by a must be false.

See also

[edit]

References

[edit]
  • Hopcroft, John E.; Ullman, Jeffrey D. (1979), Introduction to Automata Theory, Languages, and Computation, Addison-Wesley, pp. 185–192
  • Rice, H. G. (1953), "Classes of recursively enumerable sets and their decision problems", Transactions of the American Mathematical Society, 74 (2): 358–366, doi:10.1090/s0002-9947-1953-0053041-6, JSTOR 1990888
  • Rogers, Hartley Jr. (1987), Theory of Recursive Functions and Effective Computability (2nd ed.), McGraw-Hill, §14.8