4. Shor算法整体流程剖析
Shor算法并不是一台“从头到尾都在量子计算机上跑”的机器。它更像一条装配线:两端是普通计算机完成的经典数论工作,中间一段才是真正调用量子线路的周期求解。理解这条装配线的接口在哪里、数据以什么形式交接、量子部分失败时如何回退,是写出可运行实现的关键。本节把从随机数选取到因子提取的完整链路拆开,重点讲清“经典归约—量子核心—经典后处理”三段之间的衔接条件。
一、整体三段式结构
设待分解的奇合数为 N。算法的骨架可以概括为:
- 经典预处理:检查 N 是否为偶数、是否为素数幂;若是则用经典方法直接处理,否则进入下一步。
- 随机选取底数 a:在 2 ≤ a ≤ N−2 中随机取 a,先计算 g = gcd(a, N)。若 g > 1,直接得到非平凡因子,算法提前结束;若 g = 1,说明 a 与 N 互素,进入量子核心。
- 量子求阶:构造函数 f(x) = ax mod N,用量子相位估计求出它的周期 r,即满足 ar ≡ 1 (mod N) 的最小正整数。
- 经典后处理:若 r 为奇数,或 ar/2 ≡ −1 (mod N),则本次尝试失败,换一个 a 重来;否则计算 gcd(ar/2 ± 1, N),得到 N 的非平凡因子。
这条链路里,量子部分只负责“求周期”这一件事,其余全部是经典计算。也正因如此,Shor算法的实现可以拆成两个可独立测试的模块:一个纯经典的数论模块,一个量子求阶模块,二者通过参数 (a, N) 和返回值 r 衔接。
二、经典预处理:先把“不该用量子”的情况排除
在调用任何量子资源之前,必须先做三项检查。第一,若 N 为偶数,直接返回因子 2,并把 N 除以 2 继续处理。第二,若 N 是某个素数的幂,即 N = pk,可用整数开方配合试除在经典侧解决。第三,若 N 为素数,则不存在非平凡因子,应直接报告。只有通过这三项检查的奇合数才值得进入量子求阶。
这一步看似琐碎,实际决定了实现的健壮性。很多教学实现直接对任意 N 调用求阶子程序,结果在 N 为偶数或素数幂时得到无意义的周期,后处理阶段反复失败却找不到原因。把预处理写成独立函数,并在其中返回“已解决/需量子处理”的明确标志,是工程上更清晰的做法。
三、随机底数 a 的选取与提前退出
取 a 之后立刻计算 g = gcd(a, N)。这一步是“免费”的经典计算,却可能直接给出答案。例如 N = 15、a = 6 时,gcd(6,15) = 3,因子当场得到,无需量子线路。若 g = 1,则 a 属于模 N 的乘法群,其阶 r 存在且整除欧拉函数 φ(N),此时才具备求阶的前提条件。
需要强调:a 的选取必须是真随机或高质量伪随机,且每次失败后重新选取,不能固定为某个“好用的”值。固定 a 会让算法退化为对特定输入的硬编码,失去一般性。实践中可记录已尝试过的 a,避免重复选取同一个失败值。
四、量子核心:求阶子程序的输入输出契约
量子部分接收 (a, N),输出一个候选周期 r。其内部通常包含:两个量子寄存器(一个用于存放 x 的叠加态,一个用于存放 f(x) = ax mod N 的值)、受控模幂运算、逆量子傅里叶变换,以及最后的测量。测量得到的是与 r 相关的相位信息,需通过连分数展开从测量值 s/Q 中还原出 r 的候选值(Q 为第一个寄存器的维度,通常取 2 的幂)。
这里有一个容易被忽略的衔接细节:量子测量给出的 r 未必是真实周期,可能是真实周期的倍数或约数。因此求阶子程序的输出应被视为“候选周期”,其正确性由后处理阶段用 ar mod N 是否等于 1 来验证。把验证责任放在经典侧,可以让量子模块的实现更简单,也便于用经典模拟器单独测试。
五、经典后处理:从周期到因子的判定与提取
拿到候选 r 后,按以下顺序判断:
- 验证 ar mod N = 1,若不成立,说明 r 不是周期,换 a 重试。
- 若 r 为奇数,无法取 r/2,换 a 重试。
- 计算 t = ar/2 mod N。若 t = N−1(即 ≡ −1),换 a 重试。
- 否则计算 p = gcd(t−1, N)、q = gcd(t+1, N),二者即为 N 的非平凡因子。
以 N = 15、a = 2 为例(示例参数,用于说明流程):2 与 15 互素,2 的幂模 15 依次为 2, 4, 8, 1,周期 r = 4。r 为偶数,t = 22 mod 15 = 4,不等于 14。于是 gcd(4−1, 15) = gcd(3,15) = 3,gcd(4+1,15) = gcd(5,15) = 5,得到 15 = 3 × 5。这个例子完整走通了“互素判定—求阶—偶数判定—非 −1 判定—双 gcd 提取”的全链路。
再看一个失败例子:N = 15、a = 4。4 的幂模 15 为 4, 1,周期 r = 2。t = 41 mod 15 = 4,仍不等于 14,gcd(3,15)=3、gcd(5,15)=5,居然成功。而 a = 14 时,14 ≡ −1,周期 r = 2,t = 14 = N−1,触发失败分支,必须换 a。这说明失败分支并非罕见,实现中必须有重试循环和最大尝试次数保护。
六、衔接处的工程要点
把上述链路写成代码时,建议明确三个边界:其一,经典预处理函数返回枚举状态(已分解/需量子/输入非法),避免用特殊返回值混淆语义;其二,求阶函数只依赖 (a, N) 两个参数,内部不读取全局状态,便于替换为真实量子后端或模拟器;其三,后处理函数接收 (a, N, r),返回因子或失败标志,失败时由外层循环决定是否重选 a。这样三段可以分别单元测试:预处理用偶数、素数幂、素数用例;求阶用已知周期的小 N 验证;后处理用构造的 (a, r) 组合验证成功与失败分支。
总结来看,Shor算法的“量子优势”集中在求阶这一步,而算法的正确性、鲁棒性和可测试性主要由两端的经典代码保证。把接口契约定清楚——输入是什么、输出是什么、谁来验证、失败如何回退——比纠结量子线路的细节更能让一个实现真正跑通。