【轉】談“P=NP?”
阿新 • • 發佈:2018-03-03
遞歸 身邊 圖靈機 產出 數字 pos 整數 amp 關系 “P=NP?” 通常被認為是計算機科學最重要的問題。有一個叫Clay Math的研究所,甚至懸賞 100 萬美元給解決它的人。可是我今天要告訴你的是,這個問題其實是不存在的,它根本不需要解決。
我並不是第一個這樣認為的人。在很早的時候就有個數學家毫不客氣的指出,P=NP? 是個愚蠢的問題,並且為了嘲笑它,專門在愚人節寫了一篇“論文”,稱自己證明了 P=NP。我身邊有一些非常聰明的人,他們基本也都不把這問題當回事。如果我對他們講這些東西,恐怕是 TOO OLD。可是我發現國內的計算機專業學生,提到這個問題總是奉為神聖,一點玩笑也開不得,所以我打算在這裏科普一下。
這是一個不大好解釋的問題。首先,你要搞清楚什麽是“P=NP?” 為此,你必須先了解一下什麽是“算法復雜度”。為此,你又必須先了解什麽是“算法”。
你可以簡單的把“算法”想象成一臺機器,就跟絞肉機似的。你給它一些“輸入”,它就給你一些“輸出”。比如,絞肉機的輸入是肉末,輸出是肉渣。牛的輸入是草,輸出是奶(或者牛米田共)。“加法器”的輸入是兩個整數,輸出是這兩個整數的和。“算法理論”所討論的問題,就是如何設計這些機器,讓它們更加有效的工作。就像是說如何培育出優質的奶牛,吃進相同數量的草,更快的產出更多的奶。
通常所謂的“計算問題”,都需要算法經過一定時間的工作(也叫“計算”),才能得到結果。計算所需要的時間,往往跟輸入的大小有關系。你的牛吃的草越多,它就需要越長時間,才能把草都變成奶。這種草和奶的轉換速度,通常被叫做“算法復雜度”。
算法復雜度通常被表示為一個函數 f(n),其中 n 是輸入的大小。這個函數的值,通常是某種資源的需求量,比如時間或者空間。比如,如果你的算法時間復雜度為 n2,那麽當輸入10個東西的時候,它需要 100 個單元的時間才能完成計算。當輸入 100 個東西的時候,它需要 10000 個單元的時間才能完成。當輸入 1000 個數據的時候,它需要 1000000 個單元的時間。簡單吧。
所謂的“P時間”,就是“Polynomial time”,多項式時間。簡而言之,就是說這個復雜度函數 f(n) 是一個多項式。多項式你該知道是什麽吧?不知道的話就翻一下中學數學課本。
“P=NP?”中的“P”,就是指所有這些復雜度為多項式的算法的“集合”,也就是“所有”的復雜度為多項式的算法。為了簡要的描述以下的內容,我定義一些術語:
“f(n) 時間算法” = “能夠在 f(n) 時間之內,解決某個問題的算法”
當 f(n) 是個多項式(比如 n2)的時候,這就是“多項式時間算法”(P 時間算法)。當 f(n) 是個指數函數(比如 2n)的時候,這就是“指數時間算法”(EXPTIME 算法)。很多人認為 NP 問題就是需要指數時間的問題,而 NP 跟 EXPTIME,其實是風馬牛不相及的。很顯然,P 不等於 EXPTIME,但是 P 是否等於 NP,卻沒有一個結論。
現在我來解釋一下什麽是 NP。通常的計算機都是確定性(deterministic)的,它們在同一個時刻只能有一種行為。如果用程序來表示,那麽它們遇到一個條件判斷(分支)的時候,只能一次探索其中一條路徑。比如:
if (x == 0) { one(); } else { two(); }
在這裏,根據 x 的值是否為零,one() 和 two() 這兩個操作,只有一個會發生。
然而,有人幻想出來一種機器,叫做“非確定性計算機”(nondeterministic computer),它可以同時運行這程序的兩個分支,one() 和 two()。這有什麽用處呢?它的用處就在於,當你不知道 x 的大小的時候,根據 one() 和 two() 是否“運行成功”,你可以推斷出 x 是否為零。
這種非確定性的計算機,在“計算理論”裏面叫做“非確定性圖靈機”。與之相對的就是“確定性圖靈機”,也就是通常所謂的“計算機”。其實,“圖靈機”這名字在這裏完全無關緊要。你只需要知道,非確定性的計算機可以同時探索多種可能性。
這不是普通的“並行計算”,因為每當遇到一個分支點,非確定性計算機就會產生新的計算單元,用以同時探索這些路徑。這機器就像有“分身術”一樣。當這種分支點存在於循環(或者遞歸)裏面的時候,它就會反復的產生新的計算單元,新的計算單元又產生更多的計算單元,就跟細胞分裂一樣。一般的計算機都沒有這種“超能力”,它們只有固定數目的計算單元。所以他們只能先探索一條路徑,失敗之後,再回過頭來探索另外一條。所以它們似乎要多花一些時間才能得到結果。
到這裏,基本的概念都有了定義,於是我們可以圓滿的給出 P 和 NP 的定義。
P 和 NP 是這樣兩個“問題的集合”: P = “確定性計算機”能夠在“多項式時間”解決的所有問題 NP = “非確定性計算機”能夠在“多項式時間”解決的所有問題
(註意它們的區別,僅在於“確定性”或者是“非確定性”。)
定義完畢。現在回到對“P=NP?”問題的討論。
“P=NP?”問題的目標,就是想要知道 P 和 NP 這兩個集合是否相等。為了證明兩個集合(A 和 B)相等,一般都要證明兩個方向:
1. A 包含 B 2. B 包含 A
你也許已經看出來了,NP 肯定包含了 P。因為任何一個非確定性機器,都能被當成一個確定性的機器來用。你只要不使用它的“超能力”,在每個分支點只探索一條路徑就行。所以“P=NP?”問題的關鍵,就在於 P 是否也包含了 NP。也就是說,對於所有的非確定性多項式時間算法能解決的問題(NP),能否找到確定性的多項式時間算法。
首先我們來細看一下什麽是多項式時間(Polynomial time)。我們都知道,n2是多項式,n1000000也是多項式。多項式與多項式之間,卻有天壤之別。把解決問題所需要的時間,用“多項式”這麽籠統的概念來描述,其實是非常不準確的做法。在實際的大規模應用中,n2的算法都嫌慢。能找到“多項式時間”的算法,其實根本不能說明問題。
對此理論家們喜歡說,就算再大的多項式(比如 n1000000),也不能和再小的指數函數(比如 1.0001n)相比,因為總是“存在”一個 M,當 n > M 的時候,1.0001n會超過 n1000000。可是問題的關鍵,卻不在於 M 的“存在”,而在於 它的“大小”。如果你的輸入必須達到天文數字才能讓指數函數超過多項式的話,那麽還不如就用指數復雜度的算法。所以,“P=NP?”這問題的錯誤就在於,它並沒有針對我們的實際需要,而是首先假設了我們有“無窮大”的輸入,有“無窮多”的時間和耐心,可以讓多項式時間的算法“最終”得到優勢。“無窮”和“最終”,就是理論家們的殺手鐧。
為了顯示這個問題,我們可以畫一個坐標曲線,來比較一下 n1000000與 2n,並且解出它們相等時的 n。我不用 1.0001n來比,免得有人說我不公平。我喜歡偷懶,經常用 Mathematica 來解決這些算式。下面就是我用它得出的結果和曲線圖:
你看到了,當 1 < n < 24549200 的時候,我們都有 2n< n1000000(n1000000那根曲線,一超過1就沖上天去了)。 所以只要輸入沒有達到2千萬這個量級,2n的算法都比 n1000000的算法快。
n1000000也許不說明問題,但是“多項式”的範圍實在太大了。n10100,n1010100,…… 都是多項式。實際上,只要 c 是個常數,任何常數,nc就是個多項式。
你也許發現了,其實上面的論述根本沒必要用 n10100這麽大的多項式,只要用一個很大的常數(比如 10100)就夠了,因為常數也算是多項式。使用多項式的原因,只是想演示一下多項式可以有多大。
所以你看到了,常數,指數,輸入的大小,對於算法的性能都是很關鍵的。“P=NP?”的問題就在於它用“多項式”這個籠統的概念抹殺了所有這些細節,以至於即使 P=NP 被證明出來,我們仍然不會得到可以實用的結果。
正確的做法,應該是找到整個算法(代碼)的具體的復雜度函數,最好細致到常數。比如 3.65n2 + 21n + 1000,做出類似上面所示的曲線圖,然後根據具體輸入的大小,看看哪個算法更快一些。在這一點上,Knuth 在 TAOCP 中對算法的細致入微的分析,確實是值得借鑒的(雖然我不贊成他使用機器語言)。
對於“P=NP?”的興趣,到此就應該已經結束了。可是理論家們又搬出來一個很勉強的借口來支持解決它的意義。他們說,如果證明了 P≠NP,那麽人們就不用浪費時間去為 NP 問題尋找多項式時間算法了。推翻這一點本來已經沒有多大意思,不過我發現一個挺有趣的觀點,可以將這問題的正反兩方面一並推翻。
首先,我們已經知道“非確定性計算機”是一個假想出來的機器。我並不是說我們永遠不能造出非確定性計算機,但可以肯定的是,現在這種機器不存在。相反,我們已經有確定性計算機,我們每天都在使用它。
所以要解決“P=NP?”,就是要解決:
“我們現有的計算機能否解決某種不存在的計算機能解決的所有問題?”
你看出這個問題的荒誕性了嗎?
記得在 Cornell 的時候,有一個 MIT 研究量子計算的博士生來求教職,給我們做了一個演講,是關於量子計算機的“局限性”。他演講的副標題叫做:
“What you cannot do with a computer that you do not have?” “你不能用你沒有的機器做什麽?”
你看出這個問題與“P=NP?”的異曲同工之妙了嗎?最後可想而知,Cornell 沒有聘用他。
我並不是第一個這樣認為的人。在很早的時候就有個數學家毫不客氣的指出,P=NP? 是個愚蠢的問題,並且為了嘲笑它,專門在愚人節寫了一篇“論文”,稱自己證明了 P=NP。我身邊有一些非常聰明的人,他們基本也都不把這問題當回事。如果我對他們講這些東西,恐怕是 TOO OLD。可是我發現國內的計算機專業學生,提到這個問題總是奉為神聖,一點玩笑也開不得,所以我打算在這裏科普一下。
這是一個不大好解釋的問題。首先,你要搞清楚什麽是“P=NP?” 為此,你必須先了解一下什麽是“算法復雜度”。為此,你又必須先了解什麽是“算法”。
你可以簡單的把“算法”想象成一臺機器,就跟絞肉機似的。你給它一些“輸入”,它就給你一些“輸出”。比如,絞肉機的輸入是肉末,輸出是肉渣。牛的輸入是草,輸出是奶(或者牛米田共)。“加法器”的輸入是兩個整數,輸出是這兩個整數的和。“算法理論”所討論的問題,就是如何設計這些機器,讓它們更加有效的工作。就像是說如何培育出優質的奶牛,吃進相同數量的草,更快的產出更多的奶。
通常所謂的“計算問題”,都需要算法經過一定時間的工作(也叫“計算”),才能得到結果。計算所需要的時間,往往跟輸入的大小有關系。你的牛吃的草越多,它就需要越長時間,才能把草都變成奶。這種草和奶的轉換速度,通常被叫做“算法復雜度”。
算法復雜度通常被表示為一個函數 f(n),其中 n 是輸入的大小。這個函數的值,通常是某種資源的需求量,比如時間或者空間。比如,如果你的算法時間復雜度為 n2,那麽當輸入10個東西的時候,它需要 100 個單元的時間才能完成計算。當輸入 100 個東西的時候,它需要 10000 個單元的時間才能完成。當輸入 1000 個數據的時候,它需要 1000000 個單元的時間。簡單吧。
所謂的“P時間”,就是“Polynomial time”,多項式時間。簡而言之,就是說這個復雜度函數 f(n) 是一個多項式。多項式你該知道是什麽吧?不知道的話就翻一下中學數學課本。
“P=NP?”中的“P”,就是指所有這些復雜度為多項式的算法的“集合”,也就是“所有”的復雜度為多項式的算法。為了簡要的描述以下的內容,我定義一些術語:
“f(n) 時間算法” = “能夠在 f(n) 時間之內,解決某個問題的算法”
當 f(n) 是個多項式(比如 n2)的時候,這就是“多項式時間算法”(P 時間算法)。當 f(n) 是個指數函數(比如 2n)的時候,這就是“指數時間算法”(EXPTIME 算法)。很多人認為 NP 問題就是需要指數時間的問題,而 NP 跟 EXPTIME,其實是風馬牛不相及的。很顯然,P 不等於 EXPTIME,但是 P 是否等於 NP,卻沒有一個結論。
現在我來解釋一下什麽是 NP。通常的計算機都是確定性(deterministic)的,它們在同一個時刻只能有一種行為。如果用程序來表示,那麽它們遇到一個條件判斷(分支)的時候,只能一次探索其中一條路徑。比如:
if (x == 0) { one(); } else { two(); }
在這裏,根據 x 的值是否為零,one() 和 two() 這兩個操作,只有一個會發生。
然而,有人幻想出來一種機器,叫做“非確定性計算機”(nondeterministic computer),它可以同時運行這程序的兩個分支,one() 和 two()。這有什麽用處呢?它的用處就在於,當你不知道 x 的大小的時候,根據 one() 和 two() 是否“運行成功”,你可以推斷出 x 是否為零。
這種非確定性的計算機,在“計算理論”裏面叫做“非確定性圖靈機”。與之相對的就是“確定性圖靈機”,也就是通常所謂的“計算機”。其實,“圖靈機”這名字在這裏完全無關緊要。你只需要知道,非確定性的計算機可以同時探索多種可能性。
這不是普通的“並行計算”,因為每當遇到一個分支點,非確定性計算機就會產生新的計算單元,用以同時探索這些路徑。這機器就像有“分身術”一樣。當這種分支點存在於循環(或者遞歸)裏面的時候,它就會反復的產生新的計算單元,新的計算單元又產生更多的計算單元,就跟細胞分裂一樣。一般的計算機都沒有這種“超能力”,它們只有固定數目的計算單元。所以他們只能先探索一條路徑,失敗之後,再回過頭來探索另外一條。所以它們似乎要多花一些時間才能得到結果。
到這裏,基本的概念都有了定義,於是我們可以圓滿的給出 P 和 NP 的定義。
P 和 NP 是這樣兩個“問題的集合”: P = “確定性計算機”能夠在“多項式時間”解決的所有問題 NP = “非確定性計算機”能夠在“多項式時間”解決的所有問題
(註意它們的區別,僅在於“確定性”或者是“非確定性”。)
定義完畢。現在回到對“P=NP?”問題的討論。
“P=NP?”問題的目標,就是想要知道 P 和 NP 這兩個集合是否相等。為了證明兩個集合(A 和 B)相等,一般都要證明兩個方向:
1. A 包含 B 2. B 包含 A
你也許已經看出來了,NP 肯定包含了 P。因為任何一個非確定性機器,都能被當成一個確定性的機器來用。你只要不使用它的“超能力”,在每個分支點只探索一條路徑就行。所以“P=NP?”問題的關鍵,就在於 P 是否也包含了 NP。也就是說,對於所有的非確定性多項式時間算法能解決的問題(NP),能否找到確定性的多項式時間算法。
首先我們來細看一下什麽是多項式時間(Polynomial time)。我們都知道,n2是多項式,n1000000也是多項式。多項式與多項式之間,卻有天壤之別。把解決問題所需要的時間,用“多項式”這麽籠統的概念來描述,其實是非常不準確的做法。在實際的大規模應用中,n2的算法都嫌慢。能找到“多項式時間”的算法,其實根本不能說明問題。
對此理論家們喜歡說,就算再大的多項式(比如 n1000000),也不能和再小的指數函數(比如 1.0001n)相比,因為總是“存在”一個 M,當 n > M 的時候,1.0001n會超過 n1000000。可是問題的關鍵,卻不在於 M 的“存在”,而在於 它的“大小”。如果你的輸入必須達到天文數字才能讓指數函數超過多項式的話,那麽還不如就用指數復雜度的算法。所以,“P=NP?”這問題的錯誤就在於,它並沒有針對我們的實際需要,而是首先假設了我們有“無窮大”的輸入,有“無窮多”的時間和耐心,可以讓多項式時間的算法“最終”得到優勢。“無窮”和“最終”,就是理論家們的殺手鐧。
為了顯示這個問題,我們可以畫一個坐標曲線,來比較一下 n1000000與 2n,並且解出它們相等時的 n。我不用 1.0001n來比,免得有人說我不公平。我喜歡偷懶,經常用 Mathematica 來解決這些算式。下面就是我用它得出的結果和曲線圖:
你看到了,當 1 < n < 24549200 的時候,我們都有 2n< n1000000(n1000000那根曲線,一超過1就沖上天去了)。 所以只要輸入沒有達到2千萬這個量級,2n的算法都比 n1000000的算法快。
n1000000也許不說明問題,但是“多項式”的範圍實在太大了。n10100,n1010100,…… 都是多項式。實際上,只要 c 是個常數,任何常數,nc就是個多項式。
你能想象 n 需要多大,2n才能超過 n10100嗎?當 n=2 的時候,n10100就是 210100。你也許已經意識到,這個數相當於 2n復雜度的算法,接受了 10100個輸入。如果你知道 10100(1的後面跟100個0)已經大於宇宙中基本粒子的數目,你也許就會意識到,這是在計算宇宙裏所有的粒子的“冪集”(power set),也就是在枚舉宇宙裏所有粒子的所有組合。通俗一點說,就是在枚舉宇宙裏所有可能出現的物體。當任何超級電腦完成這個任務的時候,宇宙恐怕都已經不存在了。況且這個計算是根本無法完成的,因為即使每個粒子可以提供一次計數所需要的能量(E=MC2),你會在還沒有數到 10100的時候就用光宇宙裏所有的能量。最後,因為這兩個 n 是同步的,所以當 2n的輸入是 10100的時候,n10100等於 (10100)10100。所以即使枚舉了宇宙裏所有可能出現的物體,2n仍然遠遠落後於 n10100。
你也許發現了,其實上面的論述根本沒必要用 n10100這麽大的多項式,只要用一個很大的常數(比如 10100)就夠了,因為常數也算是多項式。使用多項式的原因,只是想演示一下多項式可以有多大。
所以你看到了,常數,指數,輸入的大小,對於算法的性能都是很關鍵的。“P=NP?”的問題就在於它用“多項式”這個籠統的概念抹殺了所有這些細節,以至於即使 P=NP 被證明出來,我們仍然不會得到可以實用的結果。
正確的做法,應該是找到整個算法(代碼)的具體的復雜度函數,最好細致到常數。比如 3.65n2 + 21n + 1000,做出類似上面所示的曲線圖,然後根據具體輸入的大小,看看哪個算法更快一些。在這一點上,Knuth 在 TAOCP 中對算法的細致入微的分析,確實是值得借鑒的(雖然我不贊成他使用機器語言)。
對於“P=NP?”的興趣,到此就應該已經結束了。可是理論家們又搬出來一個很勉強的借口來支持解決它的意義。他們說,如果證明了 P≠NP,那麽人們就不用浪費時間去為 NP 問題尋找多項式時間算法了。推翻這一點本來已經沒有多大意思,不過我發現一個挺有趣的觀點,可以將這問題的正反兩方面一並推翻。
首先,我們已經知道“非確定性計算機”是一個假想出來的機器。我並不是說我們永遠不能造出非確定性計算機,但可以肯定的是,現在這種機器不存在。相反,我們已經有確定性計算機,我們每天都在使用它。
所以要解決“P=NP?”,就是要解決:
“我們現有的計算機能否解決某種不存在的計算機能解決的所有問題?”
你看出這個問題的荒誕性了嗎?
記得在 Cornell 的時候,有一個 MIT 研究量子計算的博士生來求教職,給我們做了一個演講,是關於量子計算機的“局限性”。他演講的副標題叫做:
“What you cannot do with a computer that you do not have?” “你不能用你沒有的機器做什麽?”
你看出這個問題與“P=NP?”的異曲同工之妙了嗎?最後可想而知,Cornell 沒有聘用他。
【轉】談“P=NP?”