Skip to content

【代码贡献】优化量子核矩阵与量子距离计算:去除采样噪声、复用模拟器并修复多处缺陷 - #56

Open
HongbinGu wants to merge 3 commits into
OriginQ:developfrom
HongbinGu:optimize-quantum-kernel-exact-and-reuse
Open

【代码贡献】优化量子核矩阵与量子距离计算:去除采样噪声、复用模拟器并修复多处缺陷#56
HongbinGu wants to merge 3 commits into
OriginQ:developfrom
HongbinGu:optimize-quantum-kernel-exact-and-reuse

Conversation

@HongbinGu

Copy link
Copy Markdown

变更动机

QSVMQSVRQKmeans 三个机器学习类模块在构建量子核矩阵 / 计算量子距离时,存在同一类实现问题:逐点新建模拟器用有限次采样代替精确态矢量,以及若干处会导致静默错误结果的 Bug。本 PR 在不改变任何公开 API 的前提下,统一修复这些问题。

所有改动均为 drop-in 替换:类名、方法名、参数、返回类型保持不变。


一、QSVM/quantum_kernel_svm.py

# 问题 修复
1 _run_circuit() 每个矩阵元都新建一个 CPUQVM 整个矩阵复用同一个模拟器
2 程序中含 measure,概率来自 1024 次采样,核矩阵每次运行都不同 去掉测量指令,直接取态矢量精确振幅
3 np.linalg.eig 作用于实对称矩阵,返回复数 dtype;投影后对角线不再为 1,甚至出现 >1 的"概率" 改用 np.linalg.eigh;投影后 clip[0,1] 并恢复单位对角线
4 非对称调用(指定 y_vec)时,若某测试点与训练点完全相同,该处保真度被跳过而留 0(应为 1) 显式写入 1.0
5 _build_circuit() 暴露 n_qbits 参数,但纠缠块硬编码 CNOT(qlist[0], qlist[1]),传入 n_qbits != 2静默给出错误核矩阵 显式抛出 ValueErrorn_qbits=None 同样报错,此前会在 "0" * None 处崩溃)
6 except: 裸捕获,异常时把概率静默置为魔数 0.0001 移除,改为显式取值

二、QSVR/QSVR.py

# 问题 修复
7 dist() 每次调用都新建 CPUQVM(20×20 核矩阵 = 400 次) 通过可选参数共享同一个模拟器
8 k_kernel() 对对称矩阵重复计算整个下三角 对称时只算上三角并镜像(sklearnfit 阶段正是这种情况),约省一半线路模拟
9 绘图越界 Bugx0_testx1_test 两个 np.linspace 都写成 min(x[:,0])max(x[:,1]),第 0 维的上界取自第 1 维 各自使用本维度的取值范围
10 get_res() / show_res() 各自重复构建并训练一次 SVR 抽出 _fit() 共用
11 未使用的导入 train_test_splitmean_squared_errorr2_score 移除

三、QKmeans/QuantumKmeans.py

# 问题 修复
12 热路径上无条件调用 draw_qprog(prog)——该函数返回线路图字符串,而返回值被直接丢弃,等于每个(样本 × 质心)组合白算一次 移除
13 每个(样本 × 质心)组合都新建 CPUQVM fit() 全程复用同一个模拟器
14 程序含 measure,ancilla 概率为 1024 次采样值(如 0.7939453125 = 813/1024),边界样本的簇归属会抖动 去掉测量指令,取精确边缘概率
15 _point_centroid_distances() 使用 2 空格缩进,违反 PEP8 修正为 4 空格

四、test/pytest.ini

# 问题 修复
16 testpaths 中写的是 QRAM,而真实目录名是 QARM。pytest 对不存在的路径静默忽略,导致 test/QARM/Test_qarm.py 从未被执行 修正为 QARM
17 QKmeans 未纳入收集范围 补入 QKmeans

五、新增 / 扩充的单元测试

  • test/QKmeans/Test_qkmeans.py新增,该模块此前无任何测试):概率归一化、精确性、可复现性、相同态距离为 0、单一模拟器复用、聚类形状与簇数。
  • test/QSVM/Test_qsvm.py(扩充):对称性与单位对角线、确定性、实数值与值域、非对称分支相同行、n_qbits 校验、单一模拟器复用、作为 sklearn 核回调可用。
  • test/QAlgBase/Test_class_qsvr_Quantum_SVR.py(扩充):核矩阵性质、dist 对称性、单一模拟器复用,以及针对 show_res 网格越界的回归测试。

验证数据

环境:Windows 10 / Python 3.13.14 / pyqpanda3 0.4.1。

性能与模拟器实例化次数

场景 修改前 修改后 提升
QSVR 20×20 核矩阵 0.061 s / 400CPUQVM 0.028 s / 1 2.2×
QSVM 15×15 核矩阵 0.112 s / 105 0.026 s / 1 4.3×
QKmeans 12 点 / k=2 0.038 s / 48 0.0040 s / 1 9.5×

数值正确性

指标 修改前 修改后
QSVM 两次运行最大差异 5.26e-02(不可复现) 0.0
QSVM max|diag - 1| 9.919e-03 0.0
QSVM 核值上界 1.009919(概率越界) 1.000000
QSVM 返回 dtype complex128 float64
QSVR 对称性 max|K - Kᵀ| 1.332e-15 0.0
QKmeans 单次距离值 0.7939453125(= 813/1024,采样值) 精确值

测试套件

修改前 修改后
收集到的用例数 17(QARM 被静默跳过) 41
结果 41 passed in 81.72 s

说明:.github/workflows/main.ymlpull_request 触发器仅覆盖 main, master,不含 develop,因此本 PR 不会自动触发 CI。以上数据为本地以 cd test && pytest 实测所得,供审核参考。


兼容性

  • 三个模块的公开类与方法签名、返回类型均未改变,属 drop-in 替换。
  • 唯一的行为收紧:QuantumKernel_vqnet(n_qbits!=2) 现在显式报错。此前该输入会静默产生错误的核矩阵,因此这一变化只影响本来就不正确的结果。
  • 私有辅助函数 _run_circuit 的返回值由「计数字典」改为「精确概率字典」,调用方 evaluate 已同步更新。

备注(未在本 PR 修改)

pyqpanda_alg.QKmeans.QuantumKmeans 这一属性被 QKmeans/__init__.py 导出的同名遮蔽,导致 import pyqpanda_alg.QKmeans.QuantumKmeans as m 拿到的是类而非模块。修正它需要重命名模块或类,属破坏性变更,故本 PR 未改动,仅在测试中通过 sys.modules 规避。

- 修复 show_res() 绘图网格越界:原实现两个 np.linspace 均使用
  min(x[:,0]) 与 max(x[:,1]),第 0 维上界取自第 1 维
- dist() 不再每次调用新建 CPUQVM,整个核矩阵复用同一个模拟器
  (20x20 核矩阵由 400 次构造降为 1 次)
- k_kernel() 对对称矩阵只计算上三角并镜像,fit 阶段约省一半线路模拟
- 抽出 _fit() 供 get_res()/show_res() 共用,消除重复的 SVR 拟合
- 移除未使用的导入 train_test_split/mean_squared_error/r2_score
- 补充核矩阵数值性质与绘图网格回归测试
- _run_circuit() 去掉 measure 指令,改用态矢量精确概率;
  原实现 1024 次采样导致核矩阵每次运行结果不同(实测两次差异 5.26e-02)
- 整个核矩阵复用同一个 CPUQVM(15x15 由 105 次构造降为 1 次)
- 对称矩阵的 PSD 投影改用 np.linalg.eigh(原 np.linalg.eig 返回复数
  dtype,且投影后对角线偏离 1、出现大于 1 的"概率");
  投影后 clip 到 [0,1] 并恢复单位对角线
- 修复非对称调用(指定 y_vec)时相同样本对的保真度被跳过而留 0 的问题
- _build_circuit() 的纠缠块硬编码 CNOT(qlist[0], qlist[1]),
  n_qbits != 2 会静默产生错误核矩阵,现显式抛出 ValueError
- 移除裸 except 与魔数 0.0001
- 补充对称性/单位对角线/确定性/值域/n_qbits 校验/单模拟器复用等回归测试
- 移除 _QuantumKmeansCircuit() 中被无条件调用的 draw_qprog():
  该函数返回线路图字符串而调用方未使用返回值,等于每个
  (样本 x 质心)组合都白算一次
- 去掉 measure 指令,ancilla 概率由 1024 次采样值(如 0.7939453125
  = 813/1024)改为精确值;12 点/k=2 耗时 0.038s 降至 0.0040s
- fit() 全程复用同一个 CPUQVM(原每个组合新建一个,48 次降为 1 次)
- _point_centroid_distances() 缩进由 2 空格修正为 4 空格(PEP8)
- test/pytest.ini:testpaths 中 QRAM 为拼写错误(真实目录为 QARM),
  pytest 对不存在的路径静默忽略,导致 QARM 测试从未被执行;
  修正为 QARM 并补入 QKmeans
- 新增 test/QKmeans/Test_qkmeans.py(该模块此前无任何单元测试)
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