Skip to content

【代码贡献】修正 Grover 最优迭代次数计算,补充输入校验与依赖声明 - #36

Open
CREVIOS wants to merge 1 commit into
OriginQ:developfrom
CREVIOS:fix/grover-optimal-iterations
Open

【代码贡献】修正 Grover 最优迭代次数计算,补充输入校验与依赖声明#36
CREVIOS wants to merge 1 commit into
OriginQ:developfrom
CREVIOS:fix/grover-optimal-iterations

Conversation

@CREVIOS

@CREVIOS CREVIOS commented Aug 3, 2026

Copy link
Copy Markdown

关联 Issue:#13 (【本源杯项目】优化/新增算法、开发创新应用)
参赛队伍:DU_Fanta


一、问题描述

1. Grover.iter_num 返回的迭代次数并非最优

iter_num 使用 floor(pi/4 * sqrt(N/M))。该式是最优解在 M << N 时的小角度近似,解集稠密时会失效。

Grover 搜索经过 k 次迭代后的成功概率为 sin^2((2k+1)*theta/2),其中 theta = 2*arcsin(sqrt(M/N)),因此第一个极大值出现在 k* = pi/(2*theta) - 1/2(四舍五入取整)。

遍历所有 q_num <= 141 <= sol_num < 2**q_num 的组合:

对比 数量
新实现严格更优 4154
结果相同 28598
新实现更差 0

差距最大的情形为 q_num=13, sol_num=5053

迭代次数 成功概率
修改前 1 0.175
修改后 0 0.617

稀疏解集(单解)下两者结果一致,文档示例 iter_num(3, 2) == 1 不变。

此外 sol_num=0 原会抛出 ZeroDivisionError

2. mark_data_reflection 会静默标记错误的量子态

mark_data 中某一项的长度大于量子比特数时,代码只取其低位,静默标记了错误的态,没有任何提示:

# 3 个量子比特,却传入 4 位字符串
mark_data_reflection(qubits=[0, 1, 2], mark_data=['1010'])
# 修改前:正常返回,实际标记的是 '010'
# 修改后:ValueError: mark_data entry '1010' has length 4, but 3 qubits were given

长度不足时则抛出难以理解的 IndexError

3. mark_data_reflection 中的 BARRIER 阻碍编译优化

原实现在每个 '1' 位置插入 BARRIER。它们不改变量子态(已验证酉矩阵完全一致),但会阻止转译器合并相邻门。以 optimization_level=2 转译后:

量子比特数 标记态数 修改前门数/深度 修改后门数/深度 减少
3 2 32 / 22 26 / 20 6 门, 2 层
4 2 96 / 70 90 / 68 6 门, 2 层
5 3 298 / 227 282 / 224 16 门, 3 层
6 4 734 / 560 693 / 552 41 门, 8 层

4. 全新安装无法 import pyqpanda_alg

QSVD.py 在模块层 import pandasQSVR.py 在模块层 from sklearn... import,但二者均不在 requirements.txt 中:

>>> import pyqpanda_alg
ModuleNotFoundError: No module named 'pandas'

5. test/pytest.initestpaths 配置有误

testpaths 列出了并不存在的 QRAM,而实际存在的 QARM 测试从未被收集。


二、修改内容

文件 修改
pyqpanda_alg/Grover/Grover_core.py iter_num 改用精确最优公式并校验参数;mark_data_reflection 校验 mark_data 长度与字符集,移除 BARRIER;同步更新 docstring
pyqpanda-algorithm/requirements.txt 补充 pandasscikit-learn
test/pytest.ini QRAM 更正为 QARM
test/QAlgBase/Test_grover_iter_num.py 新增 6 个用例
test/QAlgBase/Test_grover_mark_data_reflection.py 恢复被整体注释掉的测试,并新增 6 个用例

Test_grover_mark_data_reflection.py 此前被整体注释,但在当前 API 下可以正常通过,本 PR 予以恢复。


三、对用户的影响

  1. iter_num 在稠密解集下的返回值会变化(变得更优)。稀疏解集下结果不变。
  2. iter_nummark_data_reflection 新增了 ValueError。原先静默产生错误结果或抛出 ZeroDivisionError / IndexError 的调用,现在会得到明确报错。这是有意的行为变更:静默标记错误的量子态比报错更危险。
  3. mark_data_reflection 生成的电路不再含 BARRIER,酉矩阵不变。

四、测试

$ cd test && python -m pytest QAlgBase QAOA QARM QPCA QSVM
34 passed

修改前为 18 个用例,本 PR 新增 12 个、恢复 4 个。新增测试覆盖:

  • iter_numq_num <= 10 全部组合上等于成功概率的第一个极大值点;
  • iter_num 返回值的左右邻域成功概率均不更优;
  • 稠密解集回归用例(q_num=13, sol_num=5053);
  • 稀疏单解情形仍与经典公式一致;
  • 非法 sol_num / q_num 抛出 ValueError
  • mark_data_reflection 的酉矩阵为对角阵且仅在被标记态上为 -1;
  • mark_data 长度、字符集、空列表的校验;
  • 生成电路中不含 BARRIER。

另已验证全新虚拟环境中 pip install . 后可正常 import pyqpanda_alg


English summary

  • Grover.iter_num used the small-angle limit floor(pi/4 * sqrt(N/M)) instead of the exact first maximum round(pi/(2*theta) - 1/2). Across all q_num <= 14, the new implementation is strictly better in 4154 cases and worse in none; worst previous case q_num=13, sol_num=5053 went from success probability 0.175 to 0.617.
  • mark_data_reflection silently marked the wrong state when a mark_data entry was longer than the qubit register; it now validates length and alphabet.
  • Removed BARRIER gates from mark_data_reflection that do not change the unitary but block transpiler optimisation (up to 41 gates / 8 layers for a 6-qubit, 4-target reflection).
  • Added pandas and scikit-learn to requirements.txt; import pyqpanda_alg failed on a clean install without them.
  • Fixed testpaths in test/pytest.ini (QRAM -> QARM) so the existing QARM tests are collected.
  • Restored Test_grover_mark_data_reflection.py, which was fully commented out but passes against the current API.

Test suite: 18 -> 34 passing.

Grover.iter_num used floor(pi/4 * sqrt(N/M)), which is the small-angle
limit of the exact optimum and only holds while M << N. The success
probability after k iterations is sin^2((2k+1)*theta/2) with
theta = 2*arcsin(sqrt(M/N)), so the first maximum is at
k* = pi/(2*theta) - 1/2 rounded to the nearest integer.

Sweeping every (q_num, sol_num) with q_num <= 14 gives 4154 cases where
the previous formula returned a strictly worse iteration count and no
case where it was better. The largest gap is q_num=13, sol_num=5053,
where the old value k=1 succeeds with probability 0.175 while the
optimum k=0 succeeds with probability 0.617. The single-solution results
that the small-angle limit already got right are unchanged, including
the value shown in the docstring example.

iter_num now also rejects sol_num outside [1, 2**q_num]; previously
sol_num=0 raised ZeroDivisionError.

mark_data_reflection silently marked the wrong state when a mark_data
entry was longer than the qubit register, because only its lowest bits
were consumed, and raised an opaque IndexError when it was shorter. It
now validates the length and alphabet of every entry.

It also emitted a BARRIER on each '1' position. Those do not change the
state but block the transpiler from merging neighbouring gates; for a
6-qubit, 4-target reflection they cost 41 extra gates and 8 extra layers
after transpilation at optimization level 2. They are removed, and a new
test asserts the operator stays diagonal with -1 exactly on the marked
states.

Additionally:
- requirements.txt: add pandas and scikit-learn. QSVD.py and QSVR.py
  import them at module scope, so `import pyqpanda_alg` failed with
  ModuleNotFoundError on a clean install.
- test/pytest.ini: testpaths listed QRAM, which does not exist, while
  the existing QARM tests were never collected.
- Re-enable Test_grover_mark_data_reflection.py, which was commented out
  in full but passes against the current API.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant