睡前说:列一个表格

这个问题的缘起,是这样的:
如何证明实数比自然数多?

这个问题没有它看上去那么简单。
比如说,自然数和偶数是否一样多?和能被七整除的自然数是否一样多?
看上去,偶数或者能被七整除的自然数,都是自然数这个大集合的一个子集,是它的一部分,所以应该是自然数更多,但实际情况却不是这样。

我们在比较两个集合是否一样多的时候,采用的是一种“找朋友”的原则。
即,如果存在一个一一映射,可以将A中的元素一个不落地映射到B,同时其逆可以将B中的元素一个不落地映射到A,那么我们就说A和B的元素一样多。
如果不存在这样的映射,那么就说A和B不是一样多。

这样的原则本身应该是没问题的。
于是,自然数和偶数,通过一个简单的乘2,就被一一映射到了一起,一个不多,一个不少,两边的每个元素都可以找到各自在对面的匹配,从而它们具有一样多的元素。。。
我们并不能因为某一个映射不满足这点,而认为所有的映射都无法满足这点,这是这个原则里最有趣的部分。
也所以,自然数和整数也是一样多的。

PS:这个找朋友的原则本身也可以带来很多有意思的东西,比如说在《豪斯道夫-巴拿赫-塔斯基分球怪论》中所介绍的分球怪论,本身也是基于这个原则来做出“相等”的判断的。

所以,谁说一个集合的子集的元素数量一定比这个集合少?

那么,实数和自然数的元素数量呢?
是否可能找到一个映射,将每一个自然数,都与一个实数对应起来,同时也将每一个实数,与一个自然数对应起来?
显然,寻找这么一个函数是一件伤脑筋的事情,尤其是当你不知道这样的函数是否存在的时候。
而更头疼的,就是要证明这样的函数是不存在的。


现在,让我们假定这样的函数是存在的。

这就是说,任意一个实数,都可以通过这么一个映射,映射到一个自然数上,即对于任意不同的实数r1和r2,存在函数f,使得n1=f(r1)、n2=f(r2)为自然熟,且n1不等于n2。
既然如此,那就是说我们可以为实数排一个序——虽然实数集本来就是良序集。
接下来,为了方便讨论,我们假定现在考虑的是[0,1]这个范围里的实数是否可以和自然数一样多——因为整个实数集总可以通过映射和[0,1]内的实数对应起来的,比如f(x)=(0.5-x)/x/(x-1)
然后,我们将这些实数写成二进制的形式,于是就有了一个列表,形如下面这个(下面输入是打个比方):

实数 \ 小数位 1 2 3 4 ...
n1 0 1 1 0 ...
n2 1 1 0 0 ...
n3 0 0 1 1 ...
... ... ... ... ... ...

假如实数可以和自然数一样多,那么这样的事情我们总是可以做到的,而且,这个表格的行数和列数也是相等的,因为第n列就是二进制下实数的小数部分第n位的数值(0或者1)。我们可以用ni_j来表示实数ni的第j位小数的数值。
接着,我们假定有这么一个数x,它的第i位小数记为x_i
这个特殊的数具有这么一个特点:x_i = 1 - ni_i
它自然也是一个实数了,从而存在自然数y=f(x)。而且,很显然,它也是在[0,1]这个区间内的,所以它就在表格的第y行,即x=ny
那么,问题来了,x_y是多少?
按照x的定义,x_y = 1 - ny_y。同时,我们又有x=ny。综上所述,就有ny_y = 1 - ny_y,即:ny_y = 0.5
但,丧勒格笛的,ny_y只能是0或者1啊。
这也就是说,如果x存在,它的第y位小数是1,那么按照x的定义,这一位小数应该是0;反之亦然。
x与其自身在第y位的问题上矛盾冲突了起来。

对于可以像自然数一样一一罗列的数来说,上述表格总是可以建立起来的。
而小数部分也总是可以一位一位地写出来。
因此,表格本身的存在没有问题。
既然表格的存在没有问题,那么对表格中数据的查询也就不应该有问题,从而x是可以通过这个表格定义出来。
所以,在上述矛盾中,唯一的错漏就只可能发生在“实数和自然数一样多”这个假设上了。


这样的做法可以构造出很多有趣的东西,比如下面这个——

自然数中是否存在不属于自然数的数?

这个问题看上去非常地自我矛盾,但,却未必不是一个大问题。
还记得一开始所提的“找朋友”的原则么?或者我们可以稍微正式一点地称它为配对原则。
利用配对原则,我们“似乎”可以在[0,1]内的实数和自然数之间建立起一种一一对应的映射,从而来“证明”自然数和实数一样多——而这一结论刚刚被我们给否定了。
这个映射是这样的:
一个[0,1]内的实数可以在二进制下写为0.10100011...这样的形式,即r(i) = ∑ r(i,j) × 2 ^ (-j)
因此,我们可以将小数点后的0/1序列“反转”一下,整个倒序后搬到小数点前,从而一个这样的实数就可以对应到一个自然数:n(i) = ∑ r(i,j) × 2 ^ (j - 1)。很容易证明这样的映射是一一映射,而且看上去在像和源两边也都是“满”的,从而我们就在自然数和[0,1]内实数之间建立起了一种配对关系,那么,按照配对原则,它们就应该是一样多的——但,这点才被我们给否定。

问题出在哪里呢?是不是这个配对关系我们找的有问题?

好,让我们换一个角度来看这个问题。

将所有的自然数排一个序,从而每个自然数n都对应一个序号i,序号自然也是自然数了,因此我们得到一个从自然数到自然数的映射:f(i)=n
然后,将任意自然数f(i)写成二进制:f(i,j) = ∑ f(i,j) × 2 ^ (j - 1),f(i,j)要么是0,要么是1。j是自然数。
显然,这里的f(i,j)就是上面我们所构造的那个表格。
f(i,j)也可以写为n_j,其中n=f(i)。
于是,我们构造一个数x,它满足:x_j = 1 - f(j,j)
也就是说,这个数x的第i位,和表格中第i个自然数的第i位,加在一起等于1,从而一个是0另一个就必然是1。
这样的定义方式和之前上面一节中我们所作的其实是完全一样的。
然后,我们发现,这个数x必然不能出现在这个表格中。
因为,如果数x在表格中,那么它自己必然有一个序号,即存在一个自然数y使得x=f(y),那么按照定义,x_y=f(y,y)=1-f(y,y)从而f(y,y)既不能是0也不能是1(这里第一个等号是x的第y位数值的定义,第二个等号是x的定义)。
但,这样构造的数x本身却看上去“非常像一个自然数”,因为按照定义,x的每一位要么是0要么是1,而且没有小数部分,怎么能不是一个自然数呢?
但有些东西的确就不是自然数可以表达的。

让我们来看一个实际的排序方式好了,比如:
对于自然数集,排序方式就是从1开始的偏序链,那么我们的表格现在就是:

自然数 \ 数位 1 2 3 4 ...
1 1 0 0 0 ...
2 0 1 0 0 ...
3 1 1 0 0 ...
4 0 0 1 0 ...
... ... ... ... ... ...

我们发现,这个表格的对角线上的值,除了最开始两位是1,别的情况下都是0,因此,按照定义,我们所定义的数x实际上就是∑i=2 2i,即一个无穷大,从而是超出自然数范围的——当然了,如果是在自然数范围的,那么我们上面就得出悖论了。

而,超出自然数范围的一个无穷大这样的数,不免让人想到了一个有趣的东西。


在自然数范围之外的代表无穷大的数,以及由此而引出的整个数字集合,就是超现实数(Surreal Number)
【不熟的朋友可以看这篇介绍:《睡前说:超现实数》】

超现实数中,存在一个比所有自然数都大的数:ω。
它可以被视为是无穷大——当然,它实际上比所有实数都大。
和非标准分析中引入的超实数(Hyperreal Number)相比,两边关于这个定义的无穷大的运算规则存在些许不同。

超现实数n=的定义要求,用于定义n的左集a中没有数字比n大,n也不比其右集b中任何数字大。而,ω的定义就是:ω=<{1,2,3,4...}|>,也就是说,ω的定义就是:比所有自然数都大。
而,最有趣的是,按照超现实数的加减乘除等运算法则的定义,我们可以计算ω-1和ω/2这样的数,而且这样的数字同时还是比任意自然数都大。
甚至于,我们可以构造诸如ωωωω(重幂,即ω的ω次ω幂,参见Knuth表示法)、ω↑ωω(Knuth表示法所表示的极度夸张的大数)这样的庞然大数(但依然可以构造出更夸张更大的数)。
事实上,只要你有一个数n,那么<{n}|>就是比n更大的数。

超现实数中,最基本的数字是0,可以天然通过空集来构造:0=<|>。其左集和右集都是空集,不需要任何别的已知数就可以构造出来。
而后,<{0}|>就可以被定义为1,以此类推。
这样的构造法和基数及序数构造自然数的方法很类似。
让我们将通过n得到<{n}|>的过程成为“后继”,那么只要一个对象可以通过“后继”操作获得另一个与之前已有的对象截然不同的新对象,那么我们就可以将这个对象序列与超现实数对应到一起。
那么,ω的存在其实就是说:存在两个对象A和B,B比A大,但B无法通过A的任意有限或无限次后继来获得。

回到上一节的那个表格。
自然数当然可以通过“后继”操作,从1开始整个地被找出来,从而一行行地写入表格中。
但ω以及所有通过ω构造出的数(比如ω+1)则不能从1开始通过“后继”操作来获得——它是全然跳出这个序列的,虽然我们知道它比任何一个实数(自然也就包括了自然数)都大,从而原则上是在上述序列之“后”的。
也因此,ω不能写在这张表格内,要写下ω,就必须在这张表格之外另取一张表格——但此时,每一行的每个空格到底要写什么,却也是并不清楚的。
同样的,在证明[0,1]内的实数不可数时,我们通过表格所构造出的矛盾中,那个奇特的数x本质上也是游离在自然数之外的,是比所有自然数都大的数。

事实上,实数集的势为ℵ1,而大家普遍相信ℶ1=ℵ1(连续统假设,但即便该假设不对,我们也有ℶ1≥ℵ1)。又有ℶ1=20=2ω,所以实数的数量显然是远大于所有自然数的,但依然可以使用超现实数来表达。

你看,一旦引入超现实数,我们就发现那张无限乘无限的表格似乎不够用了。


让我们换一个问题来考虑。

我们现在有一个遍历可枚举语言L,它总共有l个字母。
然后,我们有一个接受L的通用图灵机U,它接受两个参数u和d,分别表示一个特殊功能的图灵机,以及它所接受的参数数据。u和d都可以表达为字符串s,从而总可以表达为一个l进制数n,即:p(s)=n。同样的,自然数n也总可以对应到一个字符串s_n。
如果我们要在U上运行具有特定输入d的特定图灵机u,那么就可以表达为U(u,d)。
图灵机本身当然也是一种数据,但数据却未必都是图灵机,因此如果一个d不是U上可运行的图灵机,则可以视为U(d,*)直接停机,输出为空。
这么一来,我们就可以建立如下表格:

  1. 将所有可能的字符串s根据p(s)排序,作为表格的每一行与每一列的指标;
  2. 表格第i行第j列的内容,为U(s_i,s_j)是否停机,停机则为true,不能停机则为false;

这样一张表格其实就对应了一个停机判定机HaltCheck:

HaltCheck = (machine) ->
    if (machine can halt) return true
    else return false

在最传统的证明停机判定机不存在的方法中,我们假定HaltCheck存在,于是构造下面这样的图灵机:

paradox = () ->
    while (HaltCheck(paradox))

你看,如果paradox被HaltCheck判定为可以停机,则paradox会陷入while true的死循环,从而不会停机;而如果paradox被HaltCheck判定为不会停机,则paradox立刻跳出while循环立即停机。
这一自相矛盾的唯一解释,就是HaltCheck不存在。

这个非常传统的证明方法,也可以通过上面的表格来给出:
上述表格本身也可以视为一组数据(记为table),其对角线(记为diag),也就是第i行i列的数据,也构成一组数据。
再加上图灵机本身也是一组数据,因此,每台图灵机都可以获得自身所对应的序号,然后通过查询上述表格的对角线数据,来获知自身是否可能停机,从而构成悖论:

paradox = () ->
    while (diag[p(paradox)])

这一自相矛盾指出:如果表格可以将自身作为元素(从而表格本身是图灵机可接受的数据,从而也可以表示为字符串),或者任意字符串都可以被对应到一个自然数(从而p函数存在),那么这个表格就必然是不自洽的。

由于第二点看上去似乎完全没有问题,那么有问题的就必然是第一条了,即使:
上述构造的表格不能作为数据存在,从而无法以字符串的形式给出。
但,这又怎么可能呢?我们不是正是以字符串的形式来写下、构建这个表格的么?
这其实和实数的问题一样:我们不也是以十进制小数的形式写下一个[0,1]范围内的实数的呢?可它依然不能对应到一个自然数。
因此,能以字符串的形式来写下表格的一部分,并不表示表格本身可以对应到某个字符串。
换言之,表格本身是这张表格之外的东西,表格无法自指。

让我们这么来想:
任意一个非空字符串,都可以通过另一个字符串通过以下两种方式之一来获得:
如果字符串的最后一个字母不是字母表的最后一个字母,则将该最后一个字母变换到一个它的后继字母;如果最后一个字母是字母表最后一个字母,则在该字符串之后添加字母表上的第一个字母。
字母表的第一个字母就可以通过空字符串以第二条途径获得。
因此,我们可以说,任意非空字符串都可以表达为某一确定字符串的“后继”,后继方法就是上面这条方法。
因此,任意字符串都可以对应到一个自然数——也就是说,字符串不可能对应到ω,而ω因为不对应任何字符串。
在上述体系下,ω所对应的东西是字符串表达能力之外的东西,但它和字符串同属一个体系——超现实数。

显然,上面所构造的表格便是这么一种超出字符串表达能力的东西,它可以被视为对应到ω。
而,任何以表格为基础构建出来的函数或者说“图灵机”,都不对应任何字符串,从而不是可以可以作为数据接受的东西。

或者,我们可以这么来说:

判断所有图灵机是否可以停机的机器,是存在的,但它不是图灵机。

停机判定机是超越图灵机的东西,而所有用上了这个停机判定机的机器也都是超越图灵机的东西,它们都无法被停机判定机判定,因为它们不是图灵机。

是不是觉得我在耍赖?


我们可以进一步来问这么一个问题:是否存在判定这类超越图灵机的机器是否会停机的东西?

比如说,我们将判定任意图灵机是否会停机的机器成为超图灵机(Hyper-Turing Machine),那么是否存在判定任意HTM是否停机的机器?
这就好比从ω到ωω,当然存在,只不过这类机器也不是HTM,而是超越HTM的东西,比如H2TM,二阶超图灵机。
我们总可以构造出更高阶的超图灵机,它们可以判定比它们低阶的超图灵机是否可以停机,但就是不能判定自身。甚至于,由于超现实数允许ω-1的存在,所以我们也可以构造HωTM这样的东西,它的停机判定问题可以交由Hω+1TM处理。
这样的东西,不也是极好的么?

脑洞似乎有点大了。

那么,HTM除了有HaltCheck,还有什么呢?
至少还应该有K:K氏复杂度计算机。

我们知道K氏复杂度是不可计算的,因为假如存在图灵机K(s)可以计算任意字符串的K氏复杂度,那么我们可以构造这样的图灵机:

BadK = () ->
    for (s in AllStrings)
        if (K(s) > len(BadK) + len(K) + ln(len(s)) / ln(l) + C) then return s

其中C是一个固定常数。
这个图灵机输出一个字符串,该字符串的K氏复杂度比这台图灵机输出该字符串所需的长度要长,但一旦能输出这样的字符串,那么它的K氏复杂度就应该等于这台图灵机输出该字符串所需的长度,从而矛盾。
这个矛盾指出了K氏复杂度的不可计算性,但,函数K压根就不是图灵机呢?如果K压根就不能在通用图灵机内表达,K是超越图灵机的某种机器,那么上述不可计算性的证明本身就没有了用武之地,因为len(K)可能是一个ω级甚至更大的无穷大数——而,只要len(K)是无穷大,那么对于任意字符串来说,K氏复杂度的可计算性便能恢复。

事实上,不可计算性本身就表明这样的机器在图灵机范畴内是不存在的,从而如果图灵机总能映射到一个自然数,那么这个不可计算的机器就必然是自然数以外的东西,比如,ω。

可,K本身是否真的具有这种“超越性”呢?
事实上,我们可以写出如下的K:

K = (s) ->
    max = len(s)
    for (u in AllTuringMachines)
        if (u() is s and len(u) < max)
            max = len(u)
    return max

看上去好像很简单,对不对?
但这样的写法本身却可能出现程序根本无法输出结果的困境,而如果K不能停机,那么上面的BadK也就无意义了,K(s)这一步都无法完成计算,又谈何比较大小呢?
而,K的可能不会停机,源自这段代码中u()可能无法停机,从而一个真正可用的K是这样的:

K = (s) ->
    max = len(s)
    for (u in AllTuringMachines)
        if (CanHalt(u) and u() is s and len(u) < max)
            max = len(u)
    return max

你看,我们需要停机判定函数CanHalt(),这样才能构造一个有效的K氏复杂度计算函数,从而K本身至少和CanHalt同属超越图灵机,而且应该同属HTM。
而这也正是其不可计算性的意义:HTM不在TM集中。


好了,今天基本就说这些了。

当然,从超现实数之后开始的内容都是开脑洞的,并不是严格的论证,所以,我只能说开个脑洞发现,如果自然数和图灵机是对应的,那么超现实数中就存在太多太多无法对应到图灵机的东西了,而,停机判定、K氏复杂度这些东西,看上去仿佛就是如超现实数中的ω一般的存在。

至于这个想法对还是不对,呵呵,等啥时候不是睡前了,再来考虑吧。

今天的睡前唠嗑就到这里,欧耶~~~

你可能感兴趣的:(睡前说:列一个表格)