關于 AIT 中最概然與最簡是否一致的Toy模型計算

問題的緣起是這樣的——

網友 @十酒三 在他的文章《自指的剃刀:AIT最深遠的應用》中提出了一個很有意思的觀點,用大白話來說,就是“最可能出現的往往是最簡單的”。

嚴謹一點來說,就是假定存在概率P(s) 代表能生成字符串 s(原文討論的是函數 f,但個人認為不應該要求是函數而只能要求是字符串,畢竟有些函數可能會用到不可計算數,我們只能給出其存在性,而無法構造出來)的程序 p(s)(程序在這里指的就是確定型圖靈機(DTM))在所有可能停機的程序中所占的比例,從而證明了下面這兩個不等式:

\begin{cases} \log_2 P(s) > - K(s) - c\\ \log_2 P(s) < - K(s) + O \end{cases}

其中 c 和 O 是與所選語言相關而和字符串 s 無關的一個常數,而 K(s) 是字符串 s 的K氏復雜度也被稱為算法復雜度不可壓縮長度算法熵

字符串的算法復雜度 K(s) 可以定義為“所有能生成字符串 s 的程序(及輸入)的長度的下界”,寫成公式就是:

K(s) = \min \left\{ \mathrm{len} \left( p_s \right) \right\}

其中 p_s 指能停機并輸出指定字符串 s 的程序。

關于算法復雜度,最重要的是如下兩個命題:

  1. 不存在通用的計算任意程序的算法復雜度的程序,即算法復雜度本身是不可計算的;
  2. 存在一個常數 l,所有長度大于 l 的字符串 s 的算法復雜度都是不可計算的。

這里的關鍵就是:K是不可計算的,即不可能通過一個程序(即圖靈機)來計算任意輸入的目標字符串 s 的算法復雜度。

在 @十酒三 的原文中,其結論(也就是上述兩個不等式)導出了一個推論:

存在概率大的字符串,算法復雜度必然小。

或者反過來說:

越是簡單的字符串,越可能出現。

最后可以和哲學上的奧卡姆剃刀(中文翻譯可以簡寫為“若無必要勿增實體”)聯系在一起。

這里我們不討論外延的拓展,關于這個問題本身我和 @十酒三 存在一定的爭論。于是我在想,是否有可能構造出一個反面例子來。

關鍵就是,原文中為了完成第二個不等式的計算,@十酒三 構造了一個程序 E,E 的作用是將所有字符串 s 以 P(s) 降序排列,但由于 P(s) 是不可計算的,所以用了一系列近似手段。

原始的存在概率 P 的定義為(用U表示所有可停機的程序構成的集合,p_s 代表能輸出 s 的程序,U(s) = \{p_s\} 則表示所有 p_s 構成的集合):

P(s) = \frac{\mathrm{Count} \left( U(s) \right)}{\mathrm{Count} \left( U \right)}

這個函數顯然沒法計算,因為分子和分母都是無窮大,我們能做的是取極限(且假定這個極限存在)——使用 U_L 表示所有長度不大于 L 的程序構成的集合,U(s;L) 表示所有長度不大于 L 且輸出指定字符串 s 的程序構成的集合:

\begin{cases} P(s;L) = \frac{\mathrm{Count} \left( U(s;L) \right)}{\mathrm{Count} \left( U(L) \right)}\\ P(s) = \lim_{L \rightarrow \infty} P(s;L) \end{cases}

但這個極限依然很難計算,因為要找出長度不大于 L 的能停機的程序本身就不可能——你要判定是否能停機,首先就要解決停機問題,而停機問題在圖靈機范疇內是不可計算(不可判定)的。

所以,@十酒三 做了第二次近似(在正文后的討論帖中):用 M(s;L)M(L) 代替原本的 U(s;L)U(L),這里 M(L) 表示所有長度不大于L,且,在執行不超過L步即停機的,圖靈機所構成的集合,而 M(s;L) 則是所有長度不超過L,且,在執行不超過L步即停機,且輸出指定字符串 s 的圖靈機所構成的集合。

為什么要用M代替U?因為U中圖靈機是否可停機是不可判定的問題,而M中因為有“執行不超過L步即停機”這個條件,所以是可判定可計算的,因為,再不濟,執行L步嘛。

用M代替L后,極限是否保持不變?這是一個很重要的問題。如果極限改變了,那么基于M計算出來的關于 P_M(s;L) 的不等式 \lim_{L \rightarrow \infty}\log_2 P_m(s;L) < - K(s) + O 將無法給出關于目標函數 P(s) 的任何有效信息。

但,這樣的兩步近似都有一定的問題。下面就來看一下這里可能存在的問題。


先來約定一些符號:

  • T 表示所有圖靈機(無論是否停機)構成的集合
  • U 表示所有能停機的圖靈機構成的集合
  • U_s 表示所有能輸出目標字符串 s 的圖靈機構成的集合
  • T(L) 表示所有長度不超過 L 的圖靈機構成的集合
  • U(L) 表示所有長度不超過 L 且能停機的圖靈機構成的集合
  • U_s(L) 表示所有輸出目標字符串 s 且長度不超過 L 的圖靈機構成的集合
  • W(L) 表示所有長度不超過 L 且在執行不超過 L 步時就能停機的圖靈機構成的集合
  • W_s(L) 表示所有長度不超過 L 且在執行不超過 L 步時就能輸出目標字符串 s 的圖靈機構成的集合
  • \mathrm{Count} 表示計算集合元素個數
  • P(s) = \frac{\mathrm{Count} (U_s)}{\mathrm{Count} (T)} 是我們要求目標字符串 s 的“存在概率”
  • P(s;L) = \frac{\mathrm{Count} (U_s(L))}{\mathrm{Count} (T(L))} 是在長度不超過 L 的圖靈機構成的集合中目標字符串 s 的存在概率,成為“L 階存在概率”
  • Q(s;L) = \frac{\mathrm{Count} (W_s(L))}{\mathrm{Count} (W(L))} 是在長度不超過 L 且執行不超過 L 步就能停機的圖靈機構成的集合中目標字符串 s 的存在概率,成為“L 階 L 度存在概率”

于是,第一步近似為:

\lim_{L \rightarrow \infty} P(s;L) = P(s)

而第二步近似是認為

\lim_{L \rightarrow \infty} Q(s;L) = P(s)

其中,第一步近似在證明第一個不等式 \log_2 P(s) > - K(s) - c 時被使用,第二步近似在證明第二個不等式 \log_2 P(s) < - K(s) + O 時被使用。

這兩步近似分別是否成立?是我們要考慮的問題。


先考慮第一部近似。

在此之前,我們先來看一個自然數集中的例子——全體自然數與偶數自然數,到底哪個更多?

直覺上來看,全體自然數集合包含偶數自然數集合,而且后者是前者的真子集,那么我們當然會認為全體自然數比偶數自然數更多,但實際上,這兩個集合是一樣多的。

由于全體自然數與偶數自然數都是可數無窮多,而兩者之間可以建立一一映射,所以全體自然數與偶數自然數這兩個集合是同構的,數量是一樣多。

但如果我們換一個“算法”,取“不大于自然數 L”這個范圍,在這個范圍內比較自然數與偶數自然數的數量,那么這個比例在 L 趨向無窮時的極限就當然顯然是 1/2 了。

同樣的,由于字符集是離散的,所以所有可能的字符串構成的集合當然也是離散的集合,有可數無窮個,而我們在任意兩個不可壓縮程序所拓展出的等價類間都可以建立這種一一映射,所以任意兩個等價類都是同構的,數量相同,都是可數無窮。

具體來說,兩個不可壓縮字符串 k_1k_2,以及返回結果的算符 r,可以構造出兩個等價類 K_1 = \{ k_1 + r + s | s \in S\}K_1 = \{ k_1 + r + s | s \in S\},其中字符串集 S 是任意字符構成的所有可能字符串的集合,很顯然 S 中的任意一個元素都可以對應到 K_1K_2 中各一個不同的元素。所以可以構造映射算符 P(k_1,k_2),將 K_1 中元素的前綴字符串 k_1 替換為 k_2,這樣就可以得到 K_2 中的元素,反之亦然,P(k_2,k_1)K_2 映射到 K_1。容易證明,這兩個映射都是一一對應的,從而可以是等價類 K_1K_2 間的同構映射。

所以很顯然,每個等價類的元素數量都可以認為是相同的。

好了,現在回到 @十酒三 的原文中。

他在證明第一個不等式時,用到了這么一個關鍵的結論:

已知 s 的不可壓縮表達為 k(s),其長度為 K(s),而不可壓縮表達可以張出一個等價類 C_{k(s)} = \{k(s)\},即在 k(s) 后跟一個立刻返回結果的符號,該符號后可以接任意長字符串,這樣得到的圖靈機 k'(s) 一樣可以停機并輸出目標字符串 s。而這個等價類在 T(L) 中的數量為 2^{L - K(s) - c},從而我們有:

P(s;L) = \frac{2^{L - K(s) - c}}{2^L} = 2^{- K(s) - c}

其中 c 為立刻返回結果的算符的長度與語言相關(和 s 無關的常數)部分內容的長度的和,是一個和 s 無關而只和語言相關的常數。

這步計算有兩個問題。

首先第一個,是之前在原文的回復中提到的,那就是 U_s 并不只是 k(s) 的等價類,還有別的元素,即 U_s \supset C_{k(s)}。所以由此得到的 P(s;L) 只是下界。

當然,這個不是什么大問題,因為存在概率的下界比目標結果大等價于存在概率比目標結果大。

另一個問題是更主要的——等價類 C_{k(s)} 的元素數量真的反比于 2^{K(s) + c} 么?

由于每個等價類的元素數是相等的,所以顯然等價類在全集中的占比也應該是相等的,不會由于不可壓縮表述的長度不同發生改變。

事實上,如果我們不取“長度不大于 L 的字符串”這個約束,而是取“等價類中后綴無效字符串的長度不大于 L”,那么無論 L 是有限值還是無窮,等價類中元素的數量都是相等的,而不會有前面那個約束中得到的反比于 2^K 的結論。

從這點來看,“在所有字符串中等價類的占比”這個涉及到分母分子兩個無窮的比值,在很大程度上取決于如何取這兩個值趨向無窮的方式。

就個人來看,這里目標占比函數 P(s) 應該正比于所有能生成 s 的不可壓縮字符串(即程序)的數量。但這個數量是非常難以計算的。


如果說上面的例子還存在商榷的空間,畢竟“長度不大于 L”這個約束加上“L 趨向無窮”這個極限,看上去還是很自然的。

所以,我們下面來看一個更有趣的例子,同時看一下第二條近似是否有道理。

讓我們來構造這樣一門語言,其中只有4個符號:

  • 數字 1
  • 加法算符 +
  • 回滾算符 *
  • 返回算符 r

除此之外,字符串對應的程序在執行時,會有一個記錄結果的寄存器,初始值為 0,而整個字符串默認會在開頭加上一個加法算符并在結尾加上一個返回算符。

其中連續數字 1 構成的字符串代表一個非負整數 n,n 的值就是字符串的長度,也即連續 1 的個數。比如說,字符串“11111”代表的就是非負整數 5。又比如字符串“+*11”,其中包含了三個數字,分別是“+”前的 0、“+”和“*”之間的 0,以及最后的 2。

加法算符 + 的工作規則,是將后一個字符串中的第一個 1 搬到前一個字符串的末尾,如果后一個字符串沒有 1,則執行完畢,開始執行下一個算符的指令。

比如說,字符串“111+11111”,第一步運算后的結果是“1111+1111”,第二步運算的結果是“11111+111”,第三步運算的結果是“111111+11”,第五步運算的結果是“11111111+”,從而最終輸出結果就是“11111111”,即非負整數 8。

回滾算法 * 的工作規則,則是將其后的代表數字的字符串扣掉一個 1,如果結果對應的數大于 0,則在當前寄存器不清空的情況下,整個程序從頭開始執行;否則,則該算符相關流程執行完畢,開始執行之后的算符。

比如說,字符串“1*11”,第一步執行的是字符串“1”,即將寄存器的值置為 1,然后遇到回滾算符 *,其后的值是2,于是第二步的執行結果是將后續的“11”變成“1”,同時將寄存器的 1 不清空,程序回到開始,遇到字符串“1”,此時根據上面提到的特殊規則,實際上是字符串“+1”,從而第三步的執行結果是“2”,第四步是將 * 之后的 1 扣為 0,于是執行完畢,最終這個字符串的執行結果就是 2。

可以看到,回滾算符其實就是乘法運算,只不過執行步驟比較多。

最后的返回算符則很容易理解,就是忽略其后的所有字符串,直接將當前寄存器結果返回。

因此,比如字符串“11+111111+11r111+1111+111r11”,實際上需要執行的只有開頭的“11+111111+11”這部分,而這部分的執行結果,寫成普通非負整數加法乘法表示,就是:“(02+3)*3+2”,結果 11。

而在執行步驟方面,加法算符的執行次數與加數相等,回滾算符的執行次數是得到被乘數的執行次數乘上乘數,回滾算符的執行步驟數量永遠是 1,而數字部分可以認為不需要執行次數。因此上面的例子中,程序需要執行的總次數為(別忘了開頭會自動添加一個 + 算符)17 步。

這個字符串解析規則有如下三個顯著的特點:

  1. 任意字符串都可以停機并輸出有限結果
  2. 可以表達任意有限非負整數
  3. 字符串執行的次數,不小于字符串最后輸出的結果

換言之,它是一個非常好的理想模型,我們在計算字符串所構成的空間時,不需要考慮會出現不停機的結果。而另一方面,這個語言系統也可以表示非負整數集上的加法與乘法,所以已經足夠強(當然,由于沒有減法,所以還沒能強到皮亞諾算術系統的程度)。

這里強調一下:雖然這個模型很不錯,但它其實與原始的問題存在一定的差距:這個語言體系不是圖靈完備的。當然,我們可以在字符集中增加其它的符號,來實現更多的功能,從而將這個語言補充為一個圖靈完備的語言,但這個問題這里暫時先不考慮。

其中最重要的,就是第三點:字符串的執行次數不小于字符串的輸出結果。

事實上,當字符串中所有乘數都不為 0 的情況下,字符串的執行次數恰好等于執行結果,而當出現乘數為 0 的情況時,則需要多執行,多出來之后的步驟數,等于將原來計算過程中所有的 0 替換成 1 后的結果。

下面的一個自然問題,就是這樣一個系統中任意非負整數 n 的 K 氏長度應該是多少?

由于加法運算的介入只會增加字符串的長度——n=a+b的直接表示的長度為 n ,但如果寫成 a 個 1 與 b 個 1 通過加法算符相連的畫,長度為“a + b + 1 = n + 1”,所以反而更長。

所以,我們先來分析乘法的情況,然后再考慮加法的情況會如何。

在只考慮乘法的情況下,n 的最短表達其實直接能想到的就是將 n 盡可能分解成若干個質數相乘。但由于有乘法算符本身占了 1 個字符,所以并不能分解得過于“徹底”。

舉例來說,16可以寫為“4*4”,從而就是“1111*1111”,長度為 9,小于 16 的直接表示。但如果寫為“2*2*2*2”,從而就是“11*11*11*11”,長度為 11,反而更長了。

事實上,如果 n = \prod_{i=1}^m p_i,那么對應的長度為 L(n) = m + \sum_{i=1}^m p_i。因此,既要分解 n,又不能分解得太小。

我們取 n = p * m,其長度就從原本的 pm 變為 p + m + 1,如果這個過程要求長度是縮短的,那么就等于要求下面這個不等式成立:

p^2 - (n - 1)p + n < 0\ \ \ \ and\ p>1

因此,如果 n 有因數 p,那么當 n > p \frac{p + 1}{p - 1} 時可以進一步分解,否則就不能分解了。

這即是說,我們可以將 n 寫為質數乘積的形式:n = \prod_{i=1}^m p_i^{m_i},其中 p_i 表示第 i 個質數,m_i 是其對應的冪次,這樣除了對于 p_1 = 2 要將其寫為 2^{0\ or\ 1} 4^x 的形式,其它質數都完全分解為乘積,就可以做到最短表達。

比如說,對于 4,其最短表達就是“1111”這一 4 的直接表示;5 的最短表達也是它的直接表達;6 比較有趣,它的直接表達“111111”有 6 位,而寫成“11*111”或“111*11”也是6位,從而可以說是“3 重簡并”的;7是質數,最短表達也是它的直接表達;8 可以寫為“11*1111”或“1111*11”,都是 7 位比直接表達短 1 位;9 寫為“111*111”長 7 位;10 寫為“11*11111”或“11111*11”有 8 位;16 寫為“1111*1111”有 9 位,寫成“11*11111111” 有 11 位,這是因為 8 本身可以進一步分解,但寫成“11*11*1111”有 10 位,則是因為 4 分解成 2 * 2 的形式反而更長,因為對于 2 而言,只有在“n > 6”時分解才能更短。

由此可見,在這套語言系統中,非負整數 n 要分解為如下兩種形式:

\begin{cases} n = 4^{s_1} \times \prod_{i=2}^m p_i^{s_i}\\ n = 2 \times 4^{s_1} \times \prod_{i=2}^m p_i^{s_i} \end{cases}

對于第一種形式,最后得到的長度為 L(n) = m + \sum_{i=1}^m p_i s_i,對第二種則長度為 L(n) = 3 + m + \sum_{i=1}^m p_i s_i

而每一種表達都可以有多種等價形式,等于上面這么多質數與 4 以及一個或者零個 2 的排列組合數——換言之,與分解成若干個質數相乘相比,這里的差異就是將質數 2 換成了 4,以及可能會需要額外再乘一個 2,本質上與將自然數分解成質數乘積是相同的。

但,如果只考慮乘法,顯然質數的不可壓縮表達就只能是它的直接表達,比如 17 就只能是 17 個 1 構成的字符串。

但如果考慮上加法,情況就不同了。

一次加法運算雖然不能縮短表達 n 的字符串的長度,反而會增加 1 個加法算符,但加法可以將大質數分解成若干合數的和,情況就會不同。

比如,還是質數 17,只考慮乘法時就是 17 個 1,但考慮加法時,情況就會很不同。比如將 17 分解為
8 + 9,那么總共就需要 17 位;而如果分解為 9 + 8,總共需要 16 位,少了一位;分解為 12 + 5 則需要 15 位,分解為 14 + 3 需要 14 位,分解為 15 + 2 需要 12 位,分解為 16 + 1 則最短,只需要 11 位:“1111*1111+1”。

因此,雖然加法會增加字符,但卻可以通過分解為合數的形式將字符串縮短。顯然,由于這種語言的運算特性,我們只能分解為 n = m + p 的形式,其中 m 可以進一步表達為乘積,而 p 無法進一步分解。因此小于 n 的所有數字中表達最短的那個,就可以用來構造 n 的最短表達。

最后,我們來看一下這個語言系統中的“等價類”。

顯然,雖然任意字符串都能停機并輸出一個非負整數,但并不是字符串中的每一個部分對最終結果都有意義的。我們可以將一個字符串寫為如下形式:

s = \sum_{i=0} q_i + s_0 + (r + nonce)

其中,r 是返回算符,nonce 是任意字符串,這個是之前提到過的。由于返回算符之后的任意字符串的存在都不會影響最后結果,也不會參與計算,所以這部分對字符串的輸出與執行步驟都沒有貢獻,只改變字符串的長度。

對于 i>0q_i 是以至少一個“*”并后接一個“+”結尾的字符串,且除了結尾部分外,前面的結果中乘法算符后必須跟數字,且沒有返回算符。這部分字符串的特點,是它們會參與運算,但由于最后是“*+”的形式,等于是將之前的運算結果乘上 0,在加上后續的操作,所以等于是對最終結果不產生任何影響。

q_0 則是任意以“*”開頭的字符串,其計算結果一樣是 0,且計算次數取決于“*”后跟的數字,從而一樣不會改變整個字符串的計算結果,但會增加計算步驟與字符串長度。

當然,前綴部分中不得含有返回算符 r。

中間的 s_0 則是整個字符串的真正“有效部分”。

也就是說,前綴與后綴都不會改變最終計算結果,但兩者的存在都會改變字符串的總長度;而前綴會參與運算,改變字符串的執行步數,而后綴則不會。

顯然,任何一個不可壓縮字符串的前綴與后綴都必須為空。

我們將整個前綴作為一個整體,此時前綴部分可以化簡為兩種情況:要么是以“*”開頭以“+”結尾,要么是不以“*”開頭但以“*+”結尾,當前綴長度為 L 時候,這部分的總共可能情況數為:

pre = 2 \times 3^{L-2} - 3^{L - 3} = 5 \times 3^{L - 3}

而對于后綴來說,如果其長度為 L ,則總共可能的情況數為:

post = 4^{L - 1}

另一方面,在操作步驟方面,我們取每個 q 在結尾的乘法算符之前的部分的計算結果為 Q,結尾部分乘法與加法算符的數量為 W,則操作步驟數就是所有 Q + W 的乘積。

其中最主要的,就是長 l 的字符串可以表達的數字能有多大,我們可以在任意有效字符串的末尾加上一個后綴來構造出這里的 q 字符串,從而加到任意其它有效字符串前,來構造出一個包含無用前綴的字符串。

可以估算,對于一個長 l 的字符串,其最小可以表達 1,比如 1 后面跟 l - 1 個加法算符,而且這樣的表達不唯一,可以有很多種形式。而這樣的字符串最大可以表達的數,取決于之前計算的不可壓縮表示,因此我們現在需要做一個估算。

將 n 分解為 p^k \times m 的形式,則長度從 n 變為 k(p + 1) + \frac{n}{p^k},因此我們可以以 p 和 k 兩個方向的極值做分解后長度下限的估算,此時考慮 l 足夠大的情況,即 n 足夠大:

\begin{cases} p \approx e^\sqrt {\ln n}\\ k \approx \sqrt {\ln n} - 1 \end{cases}

從而,可以估算出 n 的不可壓縮表示的長度大約為:

K(n) \approx \left( e^\sqrt {\ln n} + 1 \right) \sqrt {\ln n}

換言之,長 l 的字符串可以表示的數最大可以到大約 N(l) \approx \exp [ W(l)^2 ],其中 W 是 Lambert 函數,即 f(x) = x e^x 的反函數。

由于 Lambert 函數可以近似寫為 W(x) \approx \ln x - \ln \ln x + o(1),所以不難證明 N(l) 肯定是隨著 l 快速增長的,且增長速度肯定大于線性。

雖然我們目前仍不清楚所有長為 l 的字符串對應的輸出結果(都是非負整數)的分布究竟如何,但從前面的分析可以看到,長 l 的字符串能表示的數字肯定是以大于線性的速度增長的,從而 q 的部分的運算步驟數肯定隨前綴長度的增長而超線性增長。

下面,我們終于可以回到這么兩個問題上了:

  1. 在長度不超過 L 的所有上述字符串中,能表達指定非負整數 n 的字符串的數量為多少?
  2. 在長度不超過 L 且執行次數不超過 f(L) 的所有上述字符串中,能表達指定非負整數 n 的字符串的數量為多少?

最主要的是,我們要來看一下這兩個情況在 L 趨向無窮的極限情況下,是如何增長的。

我們假定對于第一個問題,得到的答案是 N(n;L),即所有能得到非負整數 n 且長度不超過 L 的字符串構成的集合為 C(n;L),其中元素數量為 N(n;L)。我們可以將 C(n;L) 中的元素寫為如下形式:

s(n;L) = q(l_q) + s_0(n;l) + r(l_r)

其中存在長度約束 l_q + l + l_r = LN(n;L) 本身很難計算,我們暫時也先不去做詳細計算。

下面來看第二個問題中,所有長度不超過 L 且運算次數不超過 f(L) 而最終結果又能輸出 n 的字符串的數量,記為 M(n;L,f(L))

其中,影響計算數量的,除了有效部分 s_0,另就是前綴部分 q 了,且我們知道前綴部分增加的計算量,最少也等于前綴部分中除了結尾的回滾算符與最后結尾的加法算符之外的部分的計算值,從而可以認為是隨 N(l_q) 一同增長的,而這部分的增長速度前面提到過,是隨著 l_q 的增加而超線性飛速增長的(只要 l_q 足夠大,它的增長速度可以超過 l_q 的任意有限次冪)。

這就是說,在計算 N(n;L) 時包含在 C(n;L) 中的很大一部分具有大前綴的字符串,在計算 M(n;L,f(L)) 時將被剔除,從而對后者不做貢獻。

我們可以做一個估算。

由于要求運算次數不得超過 f(L),而前綴的 l_q 位長的字符串對應的計算量為 \lambda N(l_q),同樣的,有效部分的計算次數我們之前介紹過,基本與最后計算結果相同,從而就意味對有小部分而言存在約束 n < f(L) - \lambda N(l_q)。因此,就算這里被前綴消耗的計算步驟不影響最后有效字符串的數量,這也會使得長度 L 的字符串能表示的數字的范圍受到極大的限制,從原本的 N(L - l_r - l_q) 下降到 f(L) - \lambda N(l_q)N(L - l_r - l_q) 的較小值。

進一步,我們可以認為當前綴長為 l_q 時,總長度不超過 L 且執行次數不超過 L 的、能得到目標非負整數 n 的字符串的數量約為 M(n;L,f(L);l_q) \approx N(n;L) \min \left[ \frac{f(L) - \lambda N(l_q)}{N(L - l_r - l_q)}, 1 \right]

最后,考慮到長為 l_q 的前綴字符串的數量為 5 \times 3^{l_q - 3},所以大致可以估算出:

M(n;L,f(L)) = \frac{\sum_{i = 0}^{L_q} 3^i M(n;L,f(L);i)}{\sum_{i = 0}^{L} 3^i}

其中 L_q 為前綴長度極限,約為 L_q \approx \sqrt{\ln \frac{f(L)}{\lambda}} \exp \left[ \sqrt{\ln \frac{f(L)}{\lambda}} \right] + \sqrt{\ln \frac{f(L)}{\lambda}}

當 L 足夠大的時候,M(n;L,f(L);i) 隨 i 下降到 0 的速度是飛快的,所以我們可以近似認為求和的非 0 部分始終是 1,而從 1 到 0 則是瞬間的,因此有:

\frac{M(n;L,L)}{N(n;L)} \approx \frac{\sum_{i = 0}^{L_q} 3^i}{\sum_{i = 0}^{L} 3^i} = \frac{3^{L_q + 1} - 1}{3^{L + 1} - 1} \approx 3^{L_q - L}

所以,就可以回到上面的兩個問題了——

L 趨向無窮時,如果“長度不超過 L 且能輸出目標結果 n”的字符串在全部字符串中的占比為 P(n),則“長度不超過 L、執行次數不超過 f(L) 且能輸出目標結果 n”的字符串在全部字符串中的占比為 Q(n) \approx 3^{L_q - L} P(n)

也就是說,當約束條件從“字符串長度不超過 L”改為“字符串長度不超過 L 且執行次數不超過 f(L)”的話,占比會縮小。

換句話說,就算證明了 \log_2 Q(n;L) < -K(n) + O(1),我們也只得到 \log_2 P(n;L) < (L - L_q) \log_2 3 - K(n) + O(1),當 L-L_q 隨 L 一起增大時,在 L 趨向無窮的極限下,這個結論沒有多大意義。

比如在原本的討論中,@十酒三 提出 f(L) = L,從而就有:

L_q \approx \sqrt{\ln \frac{L}{\lambda}} \exp \left[ \sqrt{\ln \frac{L}{\lambda}} \right] + \sqrt{\ln \frac{L}{\lambda}}

它的增長速度小于 L,從而 L - L_q 是隨著 L 的增長而增長的量,當 L 取無窮這一極限時,我們將得到 \log_2 P(n) < \infty 這一沒多大意義的結論。

由此可見,第二步近似其實并不可靠。

當然,這是建立在一組估算上的一個半定量結論。

那么,是不是繼續保持“長度不超過 L”這個約束而非“長度不超過 L 且執行次數不超過 f(L)”就能得到足夠好的近似了呢?

我們可以繼續做估算。


能輸出目標數字 n 的字符串有很多,其中存在大量是有上述前綴和后綴的。

在計算占比函數 P(n) 的時候,由于現在我們算的語言總能停機并輸出一個非負整數,所以前綴與后綴的貢獻在分子和分母中必然是相同的,這點我們前面已經證明過了。

所以,占比函數 P(n) 實際上可以表達為能輸出目標數字 n 的字符串的有效字符串的數量,在所有有效字符串中的比例,而這里所謂的“有效字符串”,如上所述,就是沒有前綴與后綴的字符串。

此外,還有一類在中間有效字符串內的“無效字段”,是在任意數字之后跟任意個“+0”或“*1”,很顯然,在這套語言規則下,這樣的操作并不會改變最終輸出結果,所以是“有效”的,但它們卻一樣可以構造出一個“等價類”,將任意數字與一串字符串對應起來,且所有這些等價類都彼此同構,具有相等的數量,我們也需要將這類“無效字段”剔除。

在剔除所有“無效”的字段后(它們只會形成等價類),我們可以列出前4個自然數的有效表示:

1: 1
2: 2, 1+1, 12
3: 3, 2+1, 1+1+1, 1
2+1, 1+2, 13
4: 4, 3+1, 2+1+1, 1+1+1+1, 1
2+1+1, 1+2+1, 13+1, 2+2, 1+1+2, 12+2, 1+3

現在,我們用 A(n) 代表所有能輸出目標數字 n 的有效字符串的數量(而非占比),從而容易得到如下遞推關系:

A(n) = 1 + \left[ \sum_{i=1}^{n-1} A(n-i) \right] + \left[ \sum_{i \in F(n)} A \left( \frac{n}{i} \right) \right]

其中 F(n) 是 n 的所有除了 1 之外的因數的集合。

第一部分很好理解,就是將 n 做加法分解,分解為 n-i 與 i,那么 n-i 有多少種表示,這種分解的方式就有多少種,體現在字符串上,就是將能輸出 n-i 的字符串后跟加法算符與 i 的直接表達。

第二部分也很好理解,那就是將 n 做乘法因數分解,分解為 \frac{n}{i} 與 i,從而任何前置的表達后跟回滾算符與 i 的直接表達,就可以得到 n 的表達。

由于有效字符串種能用的算符只有加法算符和回滾算符,所以上面的兩部分便窮盡了 n 的所有可能表達方式。

我們可以做一個估算,將第二部分弱化為 n 的不包括 1 的因數數量函數 Q(n),從而可以得到 A(n) 的下限 B(n) 的遞推公式:

B(n) = 1 + \left[ \sum_{i=1}^{n-1} B(n-i) \right] + Q(n)

不難證明:

B(n) = 2^{n - 1} + Q(n) + \sum_{i = 1}^{n - 1} Q(i) 2^{n - 1 - i}

進一步,如果我們將 n 寫成 n=\prod_{p} p^{m_p} 的形式,則有:

Q \left( \prod_{p} p^{m_p} \right) = \left[ \prod_p (m_p+1) \right] - 1

其中 p 是質數。顯然,Q(n) 在質數點上永遠取最小值 1(不考慮 Q(0)),而其局部極大值,通過近似計算發現有一個很有趣的結果:

Q_M(n) \approx \sqrt{\ln n} \exp \left( \sqrt{\ln n} \right) \approx K(n)

也就是說,我們現在可以給出 A(n) 的下界函數 B(n) 的上下界:

2^n < B(n) \lesssim 2^{n - 1} + K(n) + \sum_{i = 1}^{n - 1} K(i) 2^{n - 1 - i}

進一步,我們有如下關系:

2^{n+1} < B(n+1) \lesssim 2 B(n) + K(n+1) - K(n)

由于 K(n) \approx \sqrt{\ln n} \left[ 1 + \exp \left( \sqrt{\ln n} \right) \right],因此最后的相減項在 n 足夠大的時候,相對于前面的 2 B(n) 而言,是一個小量。

同樣的,對于 A(n) 的上界 C(n),我們也有類似的關系:

A(n) < C(n) = 1 + \left[ \sum_{i=1}^{n-1} C(n-i) \right] + Q(n) C \left( \frac{n}{2} \right)\phantom{ww}\\ \therefore C(n+1) = 2 C(n) - Q(n) C \left( \frac{n}{2} \right) + Q(n+1) C \left( \frac{n+1}{2} \right)\\ \therefore C(n+1) \approx 2 C(n)\ \ \ \ (n \gg 1)\phantom{wwwwwwwwwwwwwwwww}

因此,對于占比函數,當 n 足夠大時也近似地有: P(n+1) \approx 2 P(n),從而有:

\log_2 P(n) \approx \lambda n - C

也就是說,占比函數的對數與目標數字 n 接近正比關系。

而,在原文中,兩個不等式分別為:

\begin{cases} \log_2 P(n) > - K(n) - c\\ \log_2 P(n) < - K(n) + O \end{cases}

由于函數 K(n) 具有如下性質:

K(n) \approx \sqrt{\ln n} \left[ 1 + \exp \left( \sqrt{\ln n} \right) \right]\phantom{wwwwwwwwwwww}\\ \approx \exp \left[ \sqrt{\ln n} + \frac{1}{2} \ln \ln n \right] < \exp \left[ \ln n \right] = n\\ \therefore K(n) < n\phantom{wwwwwwwwwwwwwwwwwwwwwwwwwww}

也即,在這個語言系統中,第二個不等式不成立,而第一個不等式雖然成立,但右側隨 n 減少,左側隨 n 增大,從而最后右側的變化對左側沒有任何指導意義。


當然,最后的結論還有很大的商討空間,其中最主要的一點是,我們所討論的Toy語言體系并不是圖靈完備的。

我們當然可以給這個語言系統增加更多的符號,從而在包括當前語法規則的基礎上,做到圖靈完備。但對于目標數字 n 的生成字符串而言,這么做只能增加更多的可能性,但在 n 足夠大時的兩倍增長規律,很難有質上的突破。

因此,我們可以看到,前面所指出的問題可以說是真實存在的,即:

  1. 兩個近似即“長度不超過 L”與“長度不超過 L 且執行次數不超過 L”在 L 趨向無窮時的極限,并不能很好地給出原問題的近似描述,這是由于等價類的數量是無窮,兩種近似方式都改變了其趨向無窮時的行為方式;
  2. 能得到目標結果 n 的所有字符串中,最短的、不可壓縮的字符串的貢獻并不是最主要的貢獻,有大量非最短、非不可壓縮的字符串的貢獻的總和,可以超過不可壓縮字符串的貢獻。

作為結論,我們可以說:最概然與最精簡,這兩個方向在 AIT 中未必是等同的。復雜可以有更豐富的生存空間。


本文遵守創作共享CC BY-NC-SA 4.0協議

通過本協議,您可以分享并修改本文內容,只要你遵守以下授權條款規定:姓名標示非商業性相同方式分享
具體內容請查閱上述協議聲明。
紙媒與網絡平臺如需轉載必須與本人聯系確認。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 官網 中文版本 好的網站 Content-type: text/htmlBASH Section: User ...
    不排版閱讀 4,440評論 0 5
  • 一、Python簡介和環境搭建以及pip的安裝 4課時實驗課主要內容 【Python簡介】: Python 是一個...
    _小老虎_閱讀 5,808評論 0 10
  • 在C語言中,五種基本數據類型存儲空間長度的排列順序是: A)char B)char=int<=float C)ch...
    夏天再來閱讀 3,402評論 0 2
  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,905評論 0 38
  • 第5章 引用類型(返回首頁) 本章內容 使用對象 創建并操作數組 理解基本的JavaScript類型 使用基本類型...
    大學一百閱讀 3,270評論 0 4