1987年,通用電氣的兩位程式設計師(William E Lorensen 和 Harvey E. Cline)創造了行進立方體演算法(marching cubesalgorithm an algorithm)。這個演算法使得醫生能夠透過CT和MRI掃描的資料進行視覺化處理,從而在醫學診斷中發揮了關鍵作用,挽救了無數生命。
每當你透過程式設計指導機器解決問題時,實際上是在創造演算法。這些演算法透過重新組織資料(如1和0)來執行各種任務,從簡單的如使動物發聲到複雜的如控制機器人行走。儘管許多演算法可能不實用或效率低下,但也有一些演算法既高效又具有美學價值,甚至有的因其獨特性而顯得神奇。文章接下來將介紹十種顛覆式的演算法。
1.波函式塌縮(Wave function collapse)
波函式塌縮是科學中最奇怪的事情之一。在雙縫實驗中,當不對粒子進行觀測時,粒子表現出波動性質,形成干涉圖樣。然而,一旦進行觀測,粒子的行為就會改變,顯示出典型的粒子特性,表現為單個點的撞擊。
這聽起來違反直覺,當我們從“世界是模擬的”的角度去理解量子物理的神秘現象時,例如在雙縫實驗中粒子的波粒二象性,就好像宇宙本身是根據某種節省資源的演算法執行的。這種解釋彷彿宇宙在沒有被觀測時為了效率而採用波動模式,就像一個巨大的計算系統試圖節約其運算資源一樣。這是一個值得哲學上思考的有趣概念,但波函式塌縮的一般思想也可以在程式上實現。
想象有一個影片遊戲的地圖,其中的地圖理論上可以無限延伸。對於這樣的遊戲,製作一個無限大的地圖是不切實際的,因此需要一個演算法來在遊戲進行中實時、程式性地生成地圖。這意味著地圖的每個部分只有在玩家接近時才會被建立。
在量子物理中,波函式描述了一個量子系統(如一個粒子)的所有可能狀態。這個系統在未被觀察時存在於所有可能狀態的“超級位置”。當我們進行觀測時,波函式“塌縮”,系統選擇了一個特定的狀態(比如粒子出現在一個特定位置)。
在遊戲地圖的情況下,可以將整個未生成的地圖視為處於一種“超級位置”狀態,其中包含所有可能的地圖佈局。當玩家移動並觸發地圖生成時,演算法就像波函式塌縮一樣選擇並建立一個特定的地圖區塊。這個過程是隨機的,但又遵循一致的規則(比如確保道路連貫),從而提供既隨機又連貫的結果。
2.擴散演算法(Diffusion algorithm)
擴散演算法是由OpenAI最初開發的一種機器學習演算法,它是像Dolly和Stable Diffusion這樣的影象生成器背後的“魔法”。但擴散的概念實際上來自熱力學,在熱力學中,擴散是一個自然過程,其中粒子從高濃度區域自然地移動到低濃度區域,直到濃度均勻分佈。這種擴散過程是朝著熵(無序度)增加的方向進行的,因為粒子從有序的集中狀態分散到更無序的均勻分佈。
在人工智慧中,尤其是在影象生成的擴散演算法中,這一過程被逆轉了。演算法的起點是生成高熵的狀態,即充滿隨機噪聲的影象,這類似於粒子在空間中均勻且隨機分佈的高熵狀態。接著,演算法逐步減少這種無序度,去除噪聲,最終產生一個低熵、高度結構化的影象。這個過程就像是將熵減少,將粒子從隨機分佈轉變為有序的集中分佈,與熱力學中的擴散過程相反。
在使用擴散演算法之前,首先需要訓練一個機器學習模型。這個模型需要學會如何從噪聲中重構出清晰、連貫的影象。擴散演算法分為兩個階段。
首先,模型在前向階段學習如何向清晰影象新增噪聲,直到影象變得完全隨機;隨後,在逆向階段,模型再逆轉這一過程,從噪聲影象中重構出清晰、連貫的影象。經過大量標記影象的訓練後,這種演算法能夠生成新的、獨特的影象,適用於高計算強度的任務,如音訊和影片內容生成。
3.(Simulated Annealing)
程式設計和最佳化問題中一個常見的挑戰是,對於很多問題,存在多個可能的解決方案,而找到最佳解決方案通常並不簡單。
這裡提到的“退火”一詞源自冶金學,是一種處理金屬的技術。這個過程涉及將金屬加熱到一定溫度,使其內部結構變得柔軟和可塑,然後緩慢冷卻。這樣做的目的是減少金屬內部的應力和缺陷,從而改善其效能,如增強韌性和減少硬度。在最佳化演算法中,特別是模擬退火演算法中,這個退火過程被用作尋找問題最優解的隱喻。演算法開始時,類似於冶金中的高溫退火階段,允許對解決方案空間進行廣泛的隨機探索。這意味著演算法不僅可以探索看起來有前景的解決方案,而且可以跳出區域性最優解,探索那些初看起來可能不是最佳的方案。
尋找最優解就像是在一個充滿高峰和低谷的山脈中尋找最高點。簡單的區域性搜尋方法,如爬山演算法,可能會陷入最近的區域性最高點(區域性最優解),而無法達到真正的最高點(全域性最優解)。退火演算法透過在初期允許一些“壞”的移動(即使是朝向更低的點),增加了逃離區域性最優並最終找到全域性最優的可能性。隨著時間的推移,演算法逐漸減少這種探索性質,趨向於穩定在最優解上。
因為初始時有許多區域性峰值,所以溫度開始很高,允許演算法自由探索。隨著時間的推移,溫度降低了,這減少了接受更差解決方案的可能性。這裡的權衡是探索與利用。
4.睡眠排序(sleep sort)
有史以來最巧妙的排序演算法無疑是睡眠排序。絕大多數排序演算法,如快速排序、歸併排序等,都使用了一些經典的計算機科學策略,比如分治法。這些演算法透過將陣列分解成較小的子陣列來遞迴地進行排序,最終合併得到完整的有序陣列。
然而,某位天才找到了一個更好的方法,但它有點不尋常。以下是Bash中的程式碼樣子,它非常簡單。
它遍歷陣列,然後對於每個元素,它開啟一個新執行緒,睡眠時間與其元素值成比例,最後醒來後列印該元素。這是天才之舉,在這種排序方法中,每個陣列元素被分配到一個獨立的執行緒,並根據其值進行相應時間長度的睡眠。睡眠時間結束後,元素被輸出。這個過程實際上是利用了作業系統的CPU排程器來“排序”這些元素,因為值較小的元素會先被喚醒和輸出。這種方法的獨特之處在於它完全依賴於作業系統的執行緒管理和排程機制來實現排序,而不是傳統的比較和交換操作。
雖然這種方法在理論上可行並且創意十足,但它在實踐中效率低下、不可靠,並且受到作業系統排程策略的極大影響。在實際程式設計應用中,依賴CPU排程器進行排序不僅效率低下,而且結果的準確性無法保證,特別是在處理大資料集時。
5.量子BOGO排序
另一個奇怪的排序演算法是量子BOGO排序,它嘗試透過反覆隨機猜測來排序陣列,就像玩彩票一樣。但如果我們將相同的演算法與量子力學應用到多元宇宙,那麼每一種可能的結果,比如一個數組的所有潛在排序方式,都已經在某個平行宇宙中實現。在這種情況下,一個開發者面對一個未排序的陣列,理論上在某個平行宇宙中已經存在一個排好序的版本。雖然我們的技術還無法實現跨宇宙觀察或旅行,但如果能做到這一點,我們或許能夠簡單地觀察到其他宇宙中的已排序陣列,並透過一種假想的傳送技術前往那個宇宙,從而獲得排序後的陣列。這個思路雖然純屬幻想,但在理論上提供了一個有趣的解決大型陣列排序問題的可能途徑。
6.shor演算法
有史以來最實用和優秀的演算法之一是RSA演算法(Rivest-Shamir-Adleman)。RSA演算法是公鑰密碼系統中最著名和廣泛使用的演算法之一。它在數字安全領域發揮著關鍵作用,特別是在網際網路通訊中。RSA允許人們在網際網路上加密資料(如電子郵件),並用數字簽名來驗證身份和資訊的完整性。
RSA演算法的安全性基於一個數學上的事實:將兩個大質數相乘相對容易,但反過來,要從它們的乘積中找出這兩個原始的質數卻極其困難和耗時。這種單向函式的特性使得RSA成為一個強大的加密工具。
儘管目前的計算機需要非常長的時間(例如300萬億年)來破解RSA加密,但量子計算的發展可能改變這一局面。量子計算機可以執行Shor演算法(Peter Shor在1994年提出的一種量子演算法)。Shor演算法利用了量子計算的獨特特性來執行質因數分解。它依賴於量子位(qubits)、疊加態和量子糾纏等概念。量子位與經典計算中的位不同,它可以同時表示0和1的疊加態。量子糾纏是量子位之間的一種特殊關聯,使得量子計算能夠並行執行大量的計算,遠超傳統計算機。儘管Shor演算法在理論上非常強大,但在實際應用中還面臨著一些限制。到目前為止,使用量子計算機分解的最大數字是21。即使是像IBM的最先進的Q系統這樣的量子計算機,在嘗試分解稍大的數字(如35)時也未能成功。
隨著量子計算技術的進步,未來可能需要新的加密方法來替代或增強RSA,以保持網路通訊的安全。這意味著網路安全領域可能會經歷重大變革,尤其是在量子計算機變得更加強大和實用時。
7.行進立方體演算法(Marching Cubes)
文章開頭,我提到了行進立方體演算法。演算法從一個三維標量場開始,這裡的“標量場”指的是一個三維空間,其中每個點都有一個數字值(標量)。在醫學成像的上下文中,這些標量值可以代表不同的組織密度或其他醫學相關的度量。
演算法選取空間中的一個點,並考慮該點及其周圍的八個相鄰點,共同構成一個立方體。這九個點的標量值(實際上是立方體角上的八個點)被用來確定立方體如何與所需的等值面相交。這些值被看作是一個8位整數中的位(0或1),代表了這個點是在等值面的內部還是外部。
由於每個點可以是0或1,這樣一個立方體有2^8=256種不同的配置方式。每種配置對應於一個特定的多邊形(或多邊形組合),這些多邊形用於表示透過該立方體的等值面的部分。演算法沿著整個標量場移動,對每個立方體重複這個過程,從而創建出一系列多邊形。這些多邊形拼接在一起,形成了一個完整的三維網格,代表了整個標量場中的等值面。
在醫學成像(特別是MRI)中,這個過程特別有價值,因為它允許從二維資料切片中重建出精確的三維模型,為醫生提供了更詳細的檢視來進行診斷和治療規劃。
8.拜占庭容錯機制(Byzantine Fault Tolerance)
然而,在現代,我們常常處理的是雲中的分散式系統,這就引出了拜占庭將軍問題(Byzantine Generals Problem)。想象一下,你是拜占庭軍隊中的一名將軍,你和其他幾位將軍一起在一個城市周圍紮營,計劃在第二天早上發動攻擊。但如果其中一個將軍喝醉了,整個系統可能會崩潰。計算機有同樣的問題,有時它們可能會失敗或被駭客入侵,你永遠不知道何時何地會發生。
幸運的是,像PBFT(Practical Byzantine Fault Tolerance,實用拜占庭容錯)這樣的演算法被設計出來解決這個問題,它們可以保證分散式網路即使高達三分之一的節點出問題也能正常工作。
它的工作原理是,一個節點向其他節點廣播一個準備訊息,表明它已準備好執行將改變系統的程式碼。其他節點回應同意,然後在達到一定閾值後形成共識。一旦達成共識,原始節點向所有其他節點發送提交訊息,然後它們就可以執行更改,使整個系統的狀態保持一致。這樣的演算法對區塊鏈技術和分散式雲資料庫等至關重要。
9.Boids演算法
然而,演算法真正厲害的地方在於,它們還可以反映自然界,就像Boyd的人工生命程式。它創造於1986年,模擬了鳥類的群體行為。
Boids演算法之所以引人注目,是因為它能夠從幾條簡單的行為規則出發,自然地產生出複雜且有組織的群體動態。
在Boids模型中,每個“boid”(代表一個個體,如一隻鳥)遵循以下三條基本規則:
- 分離:為了避免擁擠,每個個體會避免與附近的其他個體太接近。這有助於防止碰撞和過度擁擠。
- 對齊:每個個體傾向於與周圍個體的平均方向和速度保持一致。這有助於群體保持同一方向上的協調運動。
- 聚合:個體會向其附近群體的平均位置移動,以保持群體的凝聚性。
這些規則雖然簡單,但當應用於群體的每個個體時,會產生出意想不到的複雜行為模式。這些行為模式包括有序的群體形態、群體的規避障礙行為等,這些複雜的圖案並不是直接透過程式設計指定的,而是從個體遵循簡單規則的集體行為中自然形成的。因此,Boids演算法展示了從簡單規則到複雜系統行為的演化,這在計算機模擬和人工生命研究中是一個非常重要的成就。
10.Boyer-Moore演算法
最後,讓我們看一個古老演算法——Boyer-Moore字串搜尋演算法。Boyer-Moore演算法的一個令人驚訝的特性是,它在處理較大的文字時,效率反而更高。這看似違反直覺,因為通常我們會期望資料量越大,搜尋所需的時間越長。
Boyer-Moore演算法之所以高效,是因為它採用了一種從右到左掃描文字的方法。這與大多數字符串搜尋演算法從左到右的掃描方式不同。
演算法的兩條規則:
- 壞字元規則:當演算法在文字中遇到不在搜尋模式中的字元時(稱為“壞字元”),它會使用一個預處理表來決定可以安全跳過多少字元。這可以顯著減少比較的次數。
- 好字尾規則:當演算法找到部分匹配但隨後出現不匹配時,它會利用另一個預先計算的表來決定跳過的字元數,這也有助於減少不必要的比較。
Boyer-Moore演算法使用的這些規則被稱為啟發式方法。它們不保證在每個場景中都是最優的,但通常比逐個字元比較的方法更有效。隨著文字長度的增加,Boyer-Moore演算法通常可以跳過更多的字元,因此搜尋速度更快。這使得它在實際應用中(如UNIX系統中的grep命令)非常高效。