UOJ Logo ljt12138的博客

博客

Pollard-rho算法简要分析

2018-05-19 19:58:59 By ljt12138

Pollard-rho算法简要分析

标签(空格分隔): 数论


概述

Pollard-rho算法是质因数分解的一种有效的蒙特卡洛算法,可以在期望$O(n^{1/4})$的复杂度内找到合数的一个因数。其核心思想就是随机的选取$x\lt n$,试图找到一个$x|n$。但直接利用反复随机的方法是行不通的,为了提高效率,Pollard-rho算法依靠“生日悖论”来找到一个因数。

“生日悖论”

生日悖论是指$k$个人两两生日不同的概率,随着$k$的增长下降的非常快。如果在$n$个数中随机选取$k$个,其两两之差全不为一个常数$c$的概率为$O(\frac{1}{n^{k^2}})$,因而如果通过两两之差去“碰”一个数,只需要期望$k = O(\sqrt n)$次。考虑如果一个数$n$的最小质因子是$O(\sqrt n)$,其小于$n$的倍数有$\Omega (\sqrt n)$个,如果我们随机选取$k$个数,两两作差寻找,碰到的概率为$\Omega(\frac{1}{(\sqrt n)^{k^2}})$,这样只需要期望$k = O(n^{1/4})$次就可以找到一个因数。

弗洛伊德判环

考虑如何在$O(1)$的附加空间内沿着环走一周,考虑用两个指针,一个每次移动一步,一个每次移动两步,其位置差每次增加$1$,直到位置差为环长即两个指针相遇,则他们刚好绕环一周,且他们取遍了每一种可能的位置差。

Pollard-rho算法

Pollard-rho算法的核心是构造一个“随机的”函数:

$$f(n) = f(n-1)^2+1$$

我们要用这个函数生成随机数去“碰”一个质因数的倍数,设这个集合为$S$。

注意到$f(x)$在模$n$意义下必然会形成一个环。考虑$f(x)-f(y)=f^2(x-1)-f^2(y-1) = (f(x-1)+f(y-1))(f(x-1)-f(y-1))$,有一个$f(x-1)-f(y-1)$因子。因而如果$f(x-1)-f(y-1)\in S$,就有$f(x)-f(y)\in S$。而根据欧几里得算法$\gcd(x, n)=\gcd(n,x\bmod n)$说明了如果一个数与$n$有公因子,那么模$n$后也有。因为形成环,立刻可以得到对于任意的$x_1, y_1, x_2, y_2$,如果满足$|x_1-y_1| = |x_2-y_2|$,即他们在环上的位置差相等,那么$|f(x_1)-f(y_1)|\bmod n\in S \iff |f(x_2)-f(y_2)|\bmod n\in S$。

换言之,环上的二元组被其之间的距离划分为了若干个$O(k)$个等价类,$k$为环长。那么这显然可以用弗洛伊德判环快速的完成,事实上,弗洛伊德判环每一次移动,都相当于进行了$O(k)$次两两比较。因而最终复杂度就是$O(n^{1/4})$。

算法流程就是,每次随机一个初始解$f(0)$,通过$x=f(x), y = f(f(y))$进行弗洛伊德判环,直到$\gcd(|x-y|, n)\ne 1$找到一个约数,或者$x=y$算法失败。如果找到一个约数,递归的分解两边。为了防止大素数导致时间退化,需要先用$Miller-rabin$素数测试判断是否是素数。

update: 5.21

复杂度分析被hack掉了...详情见评论orz

经过一些实验,看起来使用偶数次多项式同余做$f(x)$要比使用奇数次多项式优秀得多,前者约为$n^{1/4}$,后者约为$n^{1/2}$

评论

liu_cheng_ao
最后一部分关于平方同余的论述并不能说明算法的效率:并没有对等价类的个数 $k$ 作出估计。而事实上,仅利用平方同余的性质的确不能保证算法的效率,如当 $f(n)=f(n-1)^2$ 时,取一个 $p$(如 $1000004123$)满足 $p,2p+1$ 均为质数且 $p$ 具有原根 $2$,那么分解 $(2p+1)^2$ 的复杂度就会退化为 $\Theta(p)$,即 $\Theta(\sqrt{n})$。事实上,这部分效率的估计需要更深入的讨论。
liu_cheng_ao
https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm#Complexity wiki 引用的资料表明,这种伪随机数的严格的复杂度分析是一个未完全解决的问题。![topen.png](https://i.loli.net/2018/05/21/5b027d4eadcea.png)
__stdcall
qaq惨惨啊。。编错了。。尴尬。。

发表评论

可以用@mike来提到mike这个用户,mike会被高亮显示。如果你真的想打“@”这个字符,请用“@@”。