筆記:A Quick Tutorial on Pollard's Rho Algorithm

漆楚衡發表於2015-03-08

筆記:A Quick Tutorial on Pollard's Rho Algorithm

Pollard's Rho是一種尋找整數真因子的概率化演算法,屬於蒙特卡羅方法的一個例項。

起步

尋找真因子的最簡單的方法是試除,簡單優化後有O(√n)的複雜度(視整數長度為常數)。

試除法是逐個嘗試可能的選項。對其進行隨機化優化,可以從嘗試的方法入手。

我們有一個輸入n,簡單起見,我們設n是合數,並僅有兩個真因子p,q (p * q = n)

簡單的一步:我們直接在隨機一個小於n的數,並檢測它是否可以整除n,這個演算法是常數級的,不過命中的概率是2 / n

雖然我們有一個常數級的演算法,不過它的成功率與輸入成反比,不太可能通過重複來得到一個高效的演算法。

Birthday Trick

解決這個問題的方法用到了Birthday Trick。

設想從 1 ~ 1000 中選一個數,看它是否是常數 48,我們命中的概率是1 / 1000

如果我們一個選擇方法:從 1 ~ 1000 中選兩次,得到兩個數 i, j (i >= j),問i - j是否等於 48,命中的概率是952 * 2 / (1000 * 1000),大概是1 / 500,概率提高了。

試著將這個方法推廣:隨機選擇k個數,並在其中兩兩比較。

(原文中直接給出實際測試的效果:在k = 30左右有一半的命中率。最後得出結論為對於n,在k = √n處有一半的命中率。)

回到原題

現在要把Birthday Trick的方法應用到尋找真因子上來。

我們在起步時給出的概率化演算法其實可以這樣看:從 1 ~ n 中選出一個數並問它是否是 p 或 q。

所以直接推廣,選出√n個數並在之中兩兩比較,尋找到i - j 整除n(即i - j = p 或 q

可以問題沒有這麼簡單,現在我們要儲存√n個數,還要進行√n * √n次比較,而且只有一半的概率找到真因子。

隨機函式

顯然,我們不能儲存√n個數,也不能進行n次比較。

如果我們只是在生成隨機數時,比較生成時間上相鄰的兩個隨機數,就可以同時解決上面的兩個問題。

有偽隨機函式f(x) = (x ^ 2 + a) mod N,其中N是常數,a是隨機生成的常數。 並給出序列x1 = c, x2 = f(x1), x3 = f(x2) ...

(原文沒有解釋為什麼這個函式可以替換上述機制)

GCD

同時我們可以優化檢測手段:對於兩個隨機數xi, xj,我們不檢測xi - xj整除n,而是檢測GCD(xi - xj, n) > 1

為什麼?因為只有p和q整除n,而GCD(xi - xj, n)適用於所有的x = xi - xj

x = p, = 2p, = 3p ... = (q - 1) * p
x = q, = 2q, = 3q ... = (p - 1) * q
(p * q不再內,因為xj <= xi < n)

共有p + q - 2個。

判環

看似大功告成了,不過我們引入的偽隨機函式f還有問題,f生成的數的軌跡有可能有環(這也是演算法名字中Rho(ρ)的來歷)。也就是對f的不斷迭代可能陷入一個死迴圈。

為此我們需要在終點未知而空間有限的條件下判斷是否陷入環中。

好在這個比較簡單,我們可以用Floyd的判環法:設想有兩個人在跑道上同時出發,同向奔跑,一個人的速度是另一個人的兩倍,那麼它們必然相遇。(快的人比慢的人多跑一圈)

如果發現了有環,可以重新(隨機)給出常數x1 = c,再次執行演算法。

原文最後的程式碼

a := 2;
b := 2;
while ( b != a )

   a = f(a); // a runs once
   b = f(f(b)); // b runs twice as fast.
   p = GCD( | b - a | , N);
   if ( p > 1)
       return "Found factor: p";
end

return "Failed. :-("

相關文章