多次提到彭罗斯将哥德尔不完备性定理(Gödel's incompleteness theorems)作为核心论点之一,下面谈一下全本(笔者)理解的这个定理及其意义。全本未必能用最严格的数学/逻辑定义来说明,同时全本也对一些问题存有疑问,但这里不影响对该定理框架的描述。证明和论述的来源:http://plato.stanford.edu/entries/goedel-incompleteness/。
首先长话短说,这个定理的基础是面向一组可数(通常是无限的,原因下面会简述)的命题和推演的罗列(本来是集合,但因为有限/可数,所以就可以编序,这也是哥德尔定理的必需的基础)。最能够想象的也是这个定理本身所依靠的最小系统即皮亚诺算术公理系统(Peano axioms)。不清楚的话,只要想想可以不断加一往上长的自然数和数学归纳法就是这个系统的最重要组成部分。对于命题和推演的集合在逻辑学上有一个比较牛逼的名称叫形式系统(Formal System)。
在形式系统中大致可能会有以下这些内容条目,
- 基本符号,比如a,b,数字之类。这些东西由于罗列和引用的意义不大,甚至可以被剔除。
- 基本符号的组合,包括代数式,函数等。因为不成为独立的命题,也没必要罗列。
- 命题(逻辑表达式)。在数学尤其逻辑学中,这经常包括存在头和任意头。
- 含参命题(断言)。在参数代入后,就变成命题。注意,这不同于函数,下面会谈到。只含有一个参数的是一元命题,以下论证反复用到。
- 公理。就是这个系统认为真的基本条款。公理和逻辑推演是这个形式系统一致性发展的基础。
- 推演式(真命题),就是把存在推演关系逻辑表达式串起来。如果是基于公理推演的,那么就是真命题(定理)了,这也是比较有意义的部分。如果是基于纯逻辑的(比如a^b=>a),也不是不可以,但是意义不很大,空推有什么好推的。
需要注意的是,我们这里的系统,通常是无限的。原因是我们考虑系统的完备性,所以各种符号组合的可能性都需要考虑。所以任何一个能够给出的合法的符号组合,尤其是命题,它必须必然需要被包括在内。同理含参命题也一样。
这个有点像什么?打个比方,我们在学校里学数学,做证明题,有的证明题那个难啊,还有什么奥数什么的。但在这里,我们可以设想有一部机器不断依照一定顺序地制造基本符号组合,从短的到长的,按照字典序什么的(以下的细化讨论用了这个方案),这样对于任意固定长度的符号序列,它总能被触及到,只是早晚问题,而我们这里是逻辑/理论数学上讨论的,这是理想机器,只要序列有限,都是“秒完成”(只有可行/不可行的问题,不存在什么运算复杂性之类的问题)。当然有一个“算法”可以检查并确保生成的是合法的序列。然后这么一条条地生成,那么很显然任何一个证明,无论多艰深,只要是有限的(废话,证明当然是有限的),都无一例外能最终被罗列到!(但,这个系统本身不一定能确认之,有的能,有的不能,这是后面要说明的中心问题)
所以,虽然条目可以是无限的,但是可数的。所以我们能将这些条目编号。这个编号很有讲究,编法当然不是唯一的,就像证明“自然数和有理数一样多”,编法不对是出不了结果的。一个合法的编号就是能够罗列出所有合法的符号组合。比方讲,如果我们知道有一个东西是可数但无限的,比如自然数(虽然自然数作为简单符号不编也没关系),你就不能盯着它编,这样你就编不了别的东西了。至少要夹花编。
其实我们会发现,无论从逻辑讨论还是对于哥德尔定理的讨论,很多条目逻辑上不必关心,当然真要编进去,只要编号合理也无伤大雅。我们比较关心的包括以下这些:
- 公理(无参真命题)
- 推演式(无参真命题)
- 无参命题
- 一元含参命题:A(x)
其中一元含参命题A(x)需要讲一下。它不同于返回真假值的逻辑函数,它只是一个对参数的断言,比如A(x):=x如何如何。当参数代入后,它退化为无参命题,则是有一个真假,这个由系统(论证链)来决定。它和逻辑函数的关系是:
- 如果有一个一元逻辑函数f(x),则“f(x)=真”就是一个一元含参命题,当然“f(x)=假”,“f(x)=g(x)”也都是。
- 如果一个含参命题A(x),对于每一个x的实例,在系统中都能找到A(x)或!A(x)的证明,那么我们也就得到了一个x到真/假的映射,即逻辑函数f(x)。
- 对于一个一元逻辑函数f(x),如果系统能够证明“对任意x如果f(x)则有A(x)否则!A(x)”,那么我们知道f(x)是个关于A(x)的“真函数”(实现)。
既然有了编号,我们对这个系统中任意一个条目m, 我们有它的一个编号[m](别处用上方括号,这里简便起见用一般方括号),我中文里称它为m门,当然这是一个自然数。这里定义如果自然数[m] = n,则<n> = m。
接下来我们来看几个比较有趣的函数和命题。注意这里的函数未必编号在系统中,只是对命题起到一个辅助(例如4和5)。
- “证明成立”函数P([a],[b]):如果a是b的一个证明则返回真,否则为假。注意这里编号的一个作用是用作为条目的ID,函数一般形式是接收自然数,这样形式上比较统一(虽然函数内部实现是去引用那两个条目的,所以从计算机科学上讲,这还是完完全全的函数式)。在表达正则化的前提下,这个函数的实现大意还是简单的,只要比较命题和推演式的结论。显然如此“实现”,这个函数成为一个真函数(不和这个系统矛盾)。
- “证明存在”含参命题Prov([b]):系统中存在条目b的证明。有没有对应函数实现(即对任意b可证与否命题成立)?最简单幼稚的实现,显然就是遍历所有的条目调用P([a],[b])即可。当条目有限,则完全没有问题,(无参)条目无限可数就麻烦了,因为除非有“洞察力”或特定的前提条件,否则永远不能保证证明不在后面,所以是个停机问题。这是即便在形式系统中也是不允许的,因为证明必须是有限表达的。所以在系统中要实现这个,办不到。所以我们在进行形式逻辑生成的时候,是换一个思路的。如果存在一个推演式最后有 =>b,那么就可以加一条Prov([b])是定理。实际系统中必然还有一个定理:对任意b,存在定理" ...=>b" <=> Prov([b]),由它推出上面的伴随定理。
- “证明不存在”含参命题NoProv([b])(相当于!Prov([b]),但注意不是证伪b):系统中不存在条目b的证明。是上面的否命题。
- “跳代”函数subst([a],n):如果a是一个一元函数a(x),则这个函数返回的是[a(n)],即用n实例化a后的无参命题的编号。当然如果a不是一元函数,则异常返回(例如负数)。这个函数依赖编号系统有明确的“实现”。
- “跳代检查(测试)”含参命题S([a],b,c):a是一个一元函数且[a(b)] = c。相当于命题:subst([a],b)=c。这个命题在依赖编号系统有明确的“函数实现”(即调用subst:func_s(x,y,z) { return subst(x,y)==z; })。
但是,我们会发现,如果对编号系统及其作用不进行比较严格的限定,这个问题的一致性讨论是会成问题的。于是我们再对编号和编集进行如下细化,
我们假设系统的符号有限。于是我们可以将系统的条目进行字典排序,于是依此的罗列产生的可数集完成对所有可能的条目的罗列。在未经说明之前,这个“可数集”就是“系统”的代名词,可互换使用。
我们不特别使用=>符号(根据后面的讨论可以容易地发现使用之是没有必要的),于是推演式剔除,系统的条目精简为仅含有公式(即命题,或前面说的“声明”。它根据一定依据可以为真或假),当然含参公式必须允许,否则无法完成哥德尔矛盾的构筑。当然系统还要包含公理,公理中必须包含逻辑公理从而可以实现推演。公理是有限的,排在系统之首,位于字典序的其他条目之前。公式包含Prov()。而Prov()依赖的Prv(,)二元含参公式则作为一个实用函数没有实际用途,但作为合法条目可以存在于系统中(正如一元含参公式)。
我们必须假设存在一个“算法1”可以判决条目是否是“语法”合法的公式(因为Prv(,)等后续公式必然作用于语法合法的公式,所以我们必须认定这个“算法”存在),如果这个可数集包含不合法的公式。但这个“算法1”的存在性和可以构造一个不含不合法公式的可数集是等价的。于是由“算法1”存在,我们可以过滤去无意义的条目。但我们可能对“语法”合法这个概念存在疑问,于是我们不得不假设包含“算法1”的“算法2”存在。
这样可数集中的条目除了公理就是公式(含参或不含参)。
接下来外于这个可数集,我们有一个“算法2”,它能够根据集合的内容确定一个公式是否为真。对于含有->的公式,如果基于公理,就可以直接成真,这个式子实际是一个证明。这个“算法2”能够“检测”出此,而将这个逻辑式条目标记为真。就如上一个“算法1”能将语法非法的滤除,这个“算法2”则可判真(如果“算法1”的存在性存在疑问,我们必须假设“算法2”承担“算法1”的功能)。同样我们设定这个算法是“超越的”,即作用于整个可数集瞬间完成的。
注意,这样的假设未能指出这个“算法2”必能把真命题都找出来,因为它是基于公理和推演式的。(但是希尔伯特规划则显然需要这个“算法2”具有这个能力,否则我们就已经达到我们要否证的目的)。于是我们要假设“算法2”最终找出所有的真命题。原则上这个“算法2”和Prov()是要一致的,但哥德尔定理要说明这个一致性不存在。
至此,我们需要的基础设施有了。接下来要导出哥德尔定理,主要靠对角线引理。这个方法就是康托(Georg Cantor)在论证无理数多于有理数中使用的著名的方法。只是在这里不是那么直观而已。
这个引理结论很简单:
【对角线引理】
对任意上述“自称完备”的系统(有一定的基本限定条件,例如纳入编号函数相关条目;不自称完备则不用证明,因为已经不完备),对于任意合法编号,对其中任意一个一元命题A(x)(简称A逻辑),都存在一个(依赖于编号函数的)D条款,使得D<=>A([D])。
根据这个引理,那么如果将A设为证明不存在函数NoProv(),就会出现D<=>NoProv([D]),即:
- D如果成立,它能导出NoProv([D]),也就是说证明了NoProv([D]),即证明了D是不能证明的;
- D如果不成立,它能导出!NoProv([D]),也就是Prov([D]),即证明了D是能够证明的。
这显然是一个矛盾,也是哥德尔定理揭示的问题。
要分析理解这个现象,我们先看这个引理是怎么来的。以下是这个对角线引理的证明。
【对角线引理证明】
首先我们看跳代检查声明S([a],b,c),所有参数显然都是自然数,虽然第一个参数的含义是对函数的引用,故而这里一开始用[a]标出作为提示。所以跳代检查函数本身实际是S(x,y,z)。我们可以设想其一个特殊的实例S(x,x,y),即对每一个一元函数(编号为x),跳代检查声明这个函数编号代入函数本身产生的无参命题的编号是y。这里实际做的是subst(x,x),这称作自跳代。
然后我们构造一个一元命题B(x):=存在y使得A(y)^S(x,x,y),简称B逻辑。容易看出,这个命题含义是对一个一元函数(编号为x)进行声明,其自跳代(编号)代入一元逻辑函数A()得到的不含参命题为真。
由于B(x)本身也是一个一元函数,我们考虑将其代入B(x)自身(参数x设为B(x)本身的编号),即自跳代subst([B(x)],[B(x)]),亦即B([B(x)])。自然这是一个不含参命题,可将其记作D。从B(x)的定义看,这个自跳代D=B([B(x)])考察了(等价于)B(x)的B逻辑值,亦即B(x)的自跳代(编号)(亦即[D])代入A()得到的命题。从而有D<=>A([D])。证毕。
接下来我们看为什么它是对角线,从而能看出这个引理的“几何特征”。
首先我们列一个表,每一行的行号和每一列的列号对应于相应的哥德尔编号,均向着无限伸展。对于m行n列元素,假设m是一元逻辑命题M(x)的哥德尔编号(即[M(x)]=m),则这个元素为M(n)(对于不是一元命题的行,我们忽略,或标记一个负数之类即可)。于是上述(将NoProv()作为A()代入后的)B(x)就在[B(x)]=b行。然后我们再来看对角线,它实际上都是上述的自跳代 。最后我们看b行b列的元素。这个元素值,作为对角线上元素,它代表B(x)的自跳代命题;作为b行的元素,它代表(作为NoProv()的参数的)“B(x)的自跳代命题”不可证明这一命题。所以说这两者是同一个条目。(即D==A([D]),这和上面的D<=>A([D])表述并不矛盾,实际上是一致的。“D<=>A([D])”本身是基于逻辑推演的真命题)
接下来我们再用更通俗的语言来看看B([B(x)])是怎么回事。B(x)是声明:自己(x)对自己关于某件事是真的是不可证明的(和其他一元命题一样,对每个具体的x,其真假与否由系统决定)。问题就是,B(x)自己说自己呢?(这个直接导致矛盾,系统也爱莫能助)
具体来看:
<b>: 存在y,!Prov(y)^S(x,x,y) (即以!Prov为A的的B(x)一元含参公式)
<g>: 存在y,!Prov(y)^S(b,b,y) (即以!Prov为A的D公式) (注意有且仅有g使得S(b,b,g)为真)
<b>通俗地说是:一个人(他对各个人会有个声称)对它自己的声称,是无法证明的。而<g>通俗地说是:(因为<b>本身也是在对各个人做声称)<b>说他自己(说的这话),是无法证明的,但这个无法证明又被他自己声明为真的。
其实我们可以用这个方法构造一个更简单的矛盾:
<b'>: 存在y, !<y>^S(x,x,y)
<g'>: 存在y, !<y>^S(b',b',y) (注意有且仅有g'使得S(b',b',g')为真)
这里<b'>通俗地说:一个人(它对各人会有个声称)对它自己的声称,总是假的(关于自己的话都是假的)。而<g'>通俗地说是:(因为<b'>本身也是在对个人做声称)<b'>说他自己说的这话,也是假的。但如果这是假的,那它又变真了。
注意这里的讨论几乎语义上对这个矛盾赋予了新的意义,从而几乎脱离了编号系统。这个其实是有点像“我在撒谎”或罗素悖论,而的确哥德尔定理的确和罗素悖论结构上有相通之处(对角线引理)。所以,一种观点可以认为,哥德尔定理只不过是一个逻辑笑话。
上述需要注意的是,B(x)本身,对于不同x的实例,既有可能是真(可证明),也有可能假(可否证)。比如,在一个编号系统中,如果第2条是含参命题:x是偶数;而第四条是含参命题:x是奇数。那么B(2)就是假的,B(4)就是真的。
那么B([B(x)])到底是真是假呢?我倾向于认为:
它是真的(因为出了系统我们知道系统给不出它的证明,因为如果系统给出它的证明,系统就不一致了)。但是系统不能给出证明(或者等价地,否证)(但是系统连这个结论也无法作出),也就是在系统的观点上无法知道其真假。
系统本身要是一致的,那么它至少其中会有一条如是的命题,它是真的,但是系统本身无法证明。而系统要一致,又必须去除这条矛盾的命题。所以系统是不完备的。
哥德尔定理给出的这种真的,但系统无法证明的命题,是利用了“证明”断言构筑的命题。但这构筑是合法的。
但这不是系统中唯一的这类命题(真却无法证明)。其他的这类命题(也是关于皮亚诺算术系统的)著名的如古德斯坦定理(Goodstein's Theorem)。
但是问题还没完。正如某逻辑学家(名字忘了)说的,哥德尔定理有一难,一容易。一难是很难理解,一容易是很容易,其实极其容易误解。就上面这段论证和说明的思路,不同的逻辑学家和相关学者都有不同的解释。最关键的一点是关于这个证明存在含参命题Prov()的意义和存在方式,以及由此引申的关于彭罗斯的“数学洞察力”的问题。
笔者的一个想法/思路/对上述问题的看法是(不严格但不完全离谱):重申这里Prov()的存在必须从逻辑学角度来理解,但是它具有深刻而微妙的“计算”牵连。从逻辑一致性上讲,很显然Prov()本身作为一个逻辑声明其为真的充要条件是系统中存在证明链(语句)。而从机械(计算)“实现”的角度,它要求一个遍历。这对于一个(在有限位置)真存在证明链(或证伪链也一样)问题不算太大,但对于系统本身无法给出的证明呢?这从遍历是无法实现的。于是我们必须假设系统的Prov()具有超出这种机械方法的能力,即如果一个证明存在,Prov()当然要反应出来;而证明不存在,Prov()也反应出来(即为非)(即使如果用“计算”无法发现这一点)。但这么一来,这个系统就真有无法证明的命题了(不管是真的还是伪的),而由此,由于伪命题的反命题就是真命题,于是系统就肯定无法证明的真命题,从而系统不完备。那我们只能假设这个系统能够证明所有问题,也就是说Prov()对真命题返回真,对伪命题返回假,而不存在不能证明的命题。至于这个假设有没有问题——其实这应该是很有问题的,如果能导致矛盾(反证法),那我们会及早发现这个问题从而得出“系统总存在无法证明的真命题”——我们暂时不去管他(等于我们将对这个系统的要求放松很多/将这个系统的机能提高了很多)。但哥德尔定理这时候就基于Prov()构造出了一个会使得这个系统形成矛盾的命题。在逻辑上这时候唯一的一个尝试的是通过将上述D(一般文献中称为GF。其中F是系统的代号,G代表哥德尔,即这个GF是系统F的哥德尔命题)直接列为公理,但如此,很显然,Prov()如果要有效,就会认定D可证明(公理本身是“0级证明链”),但D可证明直接导致D为否。笔者这里认为,逻辑上说,这说明Prov()是无效的或者说逻辑一致的Prov()是不存在的。总之笔者认为这足以说明一个机械系统(非但)总存在无法证明的(真)命题,其实根本不存在一个它自己能可靠掌握的(一致的)证明声明Prov(),(从而引申到)更别提它能理解证明是怎么回事了。而这正是彭罗斯需要的。
在进一步细究之前,我们来看更诡异的哥德尔第二定理。
第二定理根据上述第一定理其过程看似很简单。第一定理实际产生了一个真声明(定理):如果一个系统是一致的,则F不能包含GF(即上述D)。这个定理在系统F中有一个证明链(当然这个证明链是难以想象的复杂的)。于是在这个系统中一个不一致的声明X比如算式0=1,其不可证的声明为!Prov(X),另记作Cons(F)。Cons(F)要求系统一致,从而Cons(F)导出GF,但这与第一定律矛盾,从而Cons(F)也不成立。
(未完待续)
补充阅读
[1] 图灵机的局限性的讨论 (A Brief Review on a Limiatation of Turing Machine)