slime/research/experiments/normal_search/REPORT.md

87 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 普通搜索:16 个中间位候选成组筛选
2026-10-11;RTX 3060 Laptop GPU;CUDA sm_86。仅研究普通首次输出分支,未修改或测试补扫。
结论:保留公共项预计算和 16 候选成组筛选。相对上一轮最优的“输出差过滤+区间求交”,两个独立的 65,536 随机坐标批次,搜索阶段分别加速 6.51×、6.56×。本轮代码在独立实验入口,未替换正式程序。
## 同任务实测
预热后轮换模式顺序,七轮中位数。模式 4~7 每轮重新执行 GPU 预计算,耗时已包括预计算 kernel。所有模式使用相同完整低位根列表,完整输出列表逐项比较。
| 输入 | 旧最优(模式 3) | 32 位预计算(4) | 成组筛选(7) | 3/7 |
|---|---:|---:|---:|---:|
| 已知命中位置 | 0.323584 ms | 0.268288 ms | 0.156672 ms | 2.07× |
| 21 压力/边界位置 | 1.288192 ms | 0.926720 ms | 0.223232 ms | 5.77× |
| 4096 随机位置 | 8.857600 ms | 5.859328 ms | 1.141760 ms | 7.76× |
| 65536 随机位置,原批次 | 130.136063 ms | 98.654205 ms | 19.982336 ms | 6.51× |
| 65536 随机位置,独立新批次 | 134.184967 ms | 102.582275 ms | 20.440063 ms | 6.56× |
另外测试了半差模 5(模式 5),以及半差模 5 配合角落优先检查(模式 6)。均未优于模式 7,不作为最终方案。原批次模式 5/6 分别为 114.548737/108.295166 ms。
这是搜索阶段的 CUDA event 时间,**不包括低位根生成、初始化、显存分配、排序及传输**。同次运行原批次根生成 kernel 为 267.922424 ms;若每个坐标仍单独生成根,则根生成加搜索的 kernel 时间之和从 398.058487 ms 降到 287.904760 ms,仅 1.38×。这个和是阶段计时相加,不是完整应用耗时。
此前已经验证坐标类之间可以复用低位根,但本实验没有实现全世界分组调度;不可把 6.5× 写成现有完整程序的加速倍数。
## 公共项预计算
使用归一化种子,令首格坐标项为 0。固定低 18 位 `root`,中间 17 位记为 `m`:
```
a_i = root + term_i
h_i = a_i >> 18
l_i = (a_i XOR C) & (2^18 - 1)
b_i = (A*l_i + 11) >> 17
c = C >> 18 = 0x1790d
q_i(m) = [b_i + 2*A*((m+h_i) XOR c)] mod 2^31
```
`A=0x5DEECE66D`,`C=0x5E434E432`。`h_i,b_i` 对同一个根的全部 131,072 个 m 共用,每根准备一次。最后公式按 uint32 运算取模即可,无需每个候选重复 64 位乘法。
## 为什么可以 16 个一起筛
`c=0x1790d` 的第 4~7 位为 0(最低位编号为 0)。将全部 m 唯一划分为:
```
base = (g >> 4)*256 + (g & 15), g=0..8191
m = base + 16*j, j=0..15
```
每组仅变化 m 的第 4~7 位:
- 首格 term 为 0,因此 `(m XOR c)` 随 j 线性增加,不会跨 256 边界。
- 对任意其他格,`m+h_i` 在这段长度 240 的范围内最多跨一次 256 边界。
- 同一段内,两格的输出都有相同线性增量。因此 `(q_i-q_0) mod 2^31` 是常数;整组最多两段。
- 只需计算首尾两处差值,并由进位位置求分界,即可准确判断 16 个候选哪些满足 `delta % 10 ∈ {0,8}`。
用 16 位 mask 表示一组的候选,逐格与允许 mask 求交,变成 0 就整组退出。最终剩余的具体 m 才进入原有高位区间求交及精确 Java 验证。
每根筛选线程从 131,072 个减少到 8,192 个。仍覆盖所有 m,每个线程所做的工作有所增加,因此实际收益不是理论 16×。这也没有消除中间位维度,只是利用局部等价批量处理。
## 正确性验证
- 5,000,000 次随机完整输出对照:预计算公式和原 48 位状态公式一致。
- 200,000 个随机组,约束数量循环覆盖 1~25:成组 mask 和逐个检查 16 个候选的差过滤完全一致。包括 159,120 个通过的候选,避免只对照空集。
- 已知位置全部 84 个低位根 × 8192 组,与原逐候选差过滤完全一致,共覆盖 11,010,048 个中间位候选,保留 36 个差过滤候选。
- 以上共验证 888,128 个完整组 mask。
- 五组 GPU 基准,全部模式预热与七轮测量均逐项比较完整结果列表;已知位置与压力批次保留原有 24 个命中;随机批次均无命中。
- 每批最多 64 个坐标的完整低位根列表与 CPU 对照;压力集包括世界边界、int32 边界及原点。
普通分支原有的拒绝重抽覆盖范围未改变。本实验不声称单独覆盖所有 Java 重试解。
## 全世界量级与下一步
若沿用之前的乐观假设:低位根充分复用、初始化充分摊薄,只用本次搜索阶段吞吐外推 `3,750,000²` 个锚点,则两批分别约 **49.6 天、50.8 天**,相比之前约 0.9 年有明显改善。这不是完整全世界运行时间,不含全世界分组、根缓存展开及传输,也不含补扫;不能据此承诺两个月完成。
接下来普通流程优先项:实际接上低位坐标类复用调度,计入分组、候选展开、传输的总成本。随后再研究是否能合并更多中间位组,而不是继续仅压缩高位求解的少量幸存者。
## 复现
```
python3 research/experiments/normal_search/run.py
```
需要可访问 NVIDIA GPU、nvcc、g++。脚本编译程序、运行 CPU 验证、生成独立随机坐标、顺序运行五组 GPU 基准,并写入 `results/`。不会调用补扫 kernel。
实现:`grouped.hpp`(预计算和组 mask)、`cuda_bench.cu`(基准与分组 kernel)、`cpu_verify.cpp`(独立对照)。原始七轮数据在 `results/*.jsonl`,汇总与源码哈希在 `results/summary.json`。
后续已完成计入分组、展开及传输的坐标类复用实验,见 [完整批次流程报告](PIPELINE_REPORT.md)。