Add verified diamond and heart pattern examples
This commit is contained in:
parent
7952207735
commit
2eeb2ff0d4
7 changed files with 189 additions and 1 deletions
|
|
@ -8,7 +8,7 @@ make bench
|
||||||
--position-batch 128 --devices all --repeat 3
|
--position-batch 128 --devices all --repeat 3
|
||||||
```
|
```
|
||||||
|
|
||||||
自定义图案用 `--pattern` 或 `--pattern-file`,支持史莱姆、非史莱姆和忽略格;见 [6×6 苦力怕示例](bench/README.md#自定义图案6x6-苦力怕)。
|
自定义图案用 `--pattern` 或 `--pattern-file`,支持史莱姆、非史莱姆和忽略格;见 [已验证的 5×5 爱心](bench/README.md#已验证实例5x5-爱心)、[4×4 菱形](bench/README.md#已验证实例4x4-菱形)及 [6×6 苦力怕示例](bench/README.md#自定义图案6x6-苦力怕)。
|
||||||
|
|
||||||
H100 编译:`make -C bench -B CUDA_ARCH=90`。需要 CUDA Toolkit 和 C++17 编译器。普通分支不包含拒绝重抽补扫,不能将它的结果声明为严格完整目录;参数和计时口径见 [CLI 使用说明](bench/README.md)。
|
H100 编译:`make -C bench -B CUDA_ARCH=90`。需要 CUDA Toolkit 和 C++17 编译器。普通分支不包含拒绝重抽补扫,不能将它的结果声明为严格完整目录;参数和计时口径见 [CLI 使用说明](bench/README.md)。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,56 @@ mkdir -p artifacts
|
||||||
|
|
||||||
默认编译 `sm_86` 并附带 PTX,适合本机 RTX 3060 Laptop。换架构时用 `-B` 强制重建;仅改变 Make 变量不会使已有文件自动过期。
|
默认编译 `sm_86` 并附带 PTX,适合本机 RTX 3060 Laptop。换架构时用 `-B` 强制重建;仅改变 Make 变量不会使已有文件自动过期。
|
||||||
|
|
||||||
|
## 已验证实例:5×5 爱心
|
||||||
|
|
||||||
|
种子 **`22428888508636`**,左上角区块 **`(-5,-147)`**(方块原点 `(-80,-2352)`)。每格一个区块,向右为 `+X`、向下为 `+Z`;16 格 `#` 必须是史莱姆,9 格 `.` 必须不是:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.#.#.
|
||||||
|
#####
|
||||||
|
#####
|
||||||
|
.###.
|
||||||
|
..#..
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
./bench/bin/slime-bench --radius 256 \
|
||||||
|
--pattern-file bench/patterns/heart-5x5.txt \
|
||||||
|
--position-batch 256 --max-results 1000
|
||||||
|
|
||||||
|
# 单点复查,收集全部普通分支匹配:应得到 1,181 个种子
|
||||||
|
./bench/bin/slime-bench --x -5 --z -147 --radius 0 \
|
||||||
|
--pattern-file bench/patterns/heart-5x5.txt --max-results 2000
|
||||||
|
```
|
||||||
|
|
||||||
|
RTX 3060 Laptop 实测:131,585 个锚点,普通分支共找到 1,456 个种子/位置匹配,扫描约 2.439 秒(含设备初始化的端到端约 2.620 秒)。保存的 1,000 个搜索样本,以及单点复查的全部 1,181 个种子,都通过独立 Python 实现的 Java 整数回绕及 `Random.nextInt(10)` 精确逐格验证。已知种子及计时见 [results/heart-5x5-example.json](results/heart-5x5-example.json)。GPU 回归检查单点计数、已知种子及全部样本,搜索计数不包含拒绝重抽补扫。
|
||||||
|
|
||||||
|
## 已验证实例:4×4 菱形
|
||||||
|
|
||||||
|
种子 **`126066202091224`**,左上角区块 **`(-1,-63)`**(方块原点 `(-16,-1008)`)。每格是一个区块,向右为 `+X`、向下为 `+Z`;`#` 为史莱姆,`.` 必须不是:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.##.
|
||||||
|
####
|
||||||
|
####
|
||||||
|
.##.
|
||||||
|
```
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 搜索原点周围;这里只限制保存的样本数,仍会完整扫描
|
||||||
|
./bench/bin/slime-bench --radius 64 \
|
||||||
|
--pattern-file bench/patterns/diamond-4x4.txt \
|
||||||
|
--position-batch 128 --max-results 1000
|
||||||
|
|
||||||
|
# 单点复查:普通分支应得到 11,142 个种子
|
||||||
|
./bench/bin/slime-bench --x -1 --z -63 --radius 0 \
|
||||||
|
--pattern-file bench/patterns/diamond-4x4.txt --max-results 64
|
||||||
|
```
|
||||||
|
|
||||||
|
RTX 3060 Laptop 实测:8,321 个锚点,普通分支找到 2,457,370 个种子/位置匹配,扫描约 0.924 秒(含设备初始化的端到端约 1.098 秒)。保存的 1,000 个样本全部通过独立 Python 实现的 Java 整数回绕及 `Random.nextInt(10)` 精确验证,包括四个非史莱姆角。样本顺序由 GPU 调度决定,不保证固定种子在截取的前 64 个样本中。已知种子及验证记录见 [results/diamond-4x4-example.json](results/diamond-4x4-example.json),GPU 回归会核对单点计数并独立验证返回样本。
|
||||||
|
|
||||||
|
此实例证明自定义正负约束搜索可行;搜索计数仍不包含拒绝重抽补扫。
|
||||||
|
|
||||||
## 自定义图案:6×6 苦力怕
|
## 自定义图案:6×6 苦力怕
|
||||||
|
|
||||||
`--pattern` 接受 `/` 分隔的行,或用 `--pattern-file` 读取每行一排的文本文件。`#` 必须是史莱姆区块,`.` 必须不是,`?` 不限制。支持非正方形,宽、高分别为 1~64,至少含一个 `#`;不能与 `--size` 同时指定。不自动旋转或镜像。
|
`--pattern` 接受 `/` 分隔的行,或用 `--pattern-file` 读取每行一排的文本文件。`#` 必须是史莱姆区块,`.` 必须不是,`?` 不限制。支持非正方形,宽、高分别为 1~64,至少含一个 `#`;不能与 `--size` 同时指定。不自动旋转或镜像。
|
||||||
|
|
|
||||||
4
bench/patterns/diamond-4x4.txt
Normal file
4
bench/patterns/diamond-4x4.txt
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.##.
|
||||||
|
####
|
||||||
|
####
|
||||||
|
.##.
|
||||||
5
bench/patterns/heart-5x5.txt
Normal file
5
bench/patterns/heart-5x5.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
.#.#.
|
||||||
|
#####
|
||||||
|
#####
|
||||||
|
.###.
|
||||||
|
..#..
|
||||||
49
bench/results/diamond-4x4-example.json
Normal file
49
bench/results/diamond-4x4-example.json
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
{
|
||||||
|
"pattern": [
|
||||||
|
".##.",
|
||||||
|
"####",
|
||||||
|
"####",
|
||||||
|
".##."
|
||||||
|
],
|
||||||
|
"seed48": 126066202091224,
|
||||||
|
"chunk_x": -1,
|
||||||
|
"chunk_z": -63,
|
||||||
|
"block_origin": [
|
||||||
|
-16,
|
||||||
|
-1008
|
||||||
|
],
|
||||||
|
"verified_rows": [
|
||||||
|
".##.",
|
||||||
|
"####",
|
||||||
|
"####",
|
||||||
|
".##."
|
||||||
|
],
|
||||||
|
"verification": {
|
||||||
|
"method": "independent Python implementation of Java int overflow and Random.nextInt(10) rejection loop",
|
||||||
|
"verified_sample_count": 1000,
|
||||||
|
"slime_cells": 12,
|
||||||
|
"non_slime_cells": 4
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"center": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"radius_chunks": 64,
|
||||||
|
"anchors": 8321,
|
||||||
|
"matches": 2457370,
|
||||||
|
"scan_wall_ms": 924.202261,
|
||||||
|
"elapsed_ms": 1097.678503,
|
||||||
|
"gpu": "NVIDIA GeForce RTX 3060 Laptop GPU",
|
||||||
|
"rejection_tail_included": false
|
||||||
|
},
|
||||||
|
"single_anchor": {
|
||||||
|
"matches": 11142,
|
||||||
|
"root_jobs": 235
|
||||||
|
},
|
||||||
|
"source_sha256": {
|
||||||
|
"bench/slime_bench.cu": "3c70cbe2e5babc3e737199fb5e62b78ea9c5daadc0020af77292c2d59516259e",
|
||||||
|
"include/slime/solver_core.hpp": "feb1200518716b4d796fb60f60a83b6b798155bbd4e795531793181a5c7f9eba",
|
||||||
|
"include/slime/upper_interval.hpp": "af3fddf7705295d91ffd6e2190f542004a3ecff847fce9d4c9b13125bdbdc2d5"
|
||||||
|
}
|
||||||
|
}
|
||||||
52
bench/results/heart-5x5-example.json
Normal file
52
bench/results/heart-5x5-example.json
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"pattern": [
|
||||||
|
".#.#.",
|
||||||
|
"#####",
|
||||||
|
"#####",
|
||||||
|
".###.",
|
||||||
|
"..#.."
|
||||||
|
],
|
||||||
|
"seed48": 22428888508636,
|
||||||
|
"chunk_x": -5,
|
||||||
|
"chunk_z": -147,
|
||||||
|
"block_origin": [
|
||||||
|
-80,
|
||||||
|
-2352
|
||||||
|
],
|
||||||
|
"verified_rows": [
|
||||||
|
".#.#.",
|
||||||
|
"#####",
|
||||||
|
"#####",
|
||||||
|
".###.",
|
||||||
|
"..#.."
|
||||||
|
],
|
||||||
|
"verification": {
|
||||||
|
"method": "independent Python implementation of Java int overflow and Random.nextInt(10) rejection loop",
|
||||||
|
"verified_search_sample_count": 1000,
|
||||||
|
"verified_single_anchor_count": 1181,
|
||||||
|
"slime_cells": 16,
|
||||||
|
"non_slime_cells": 9
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"center": [
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
],
|
||||||
|
"radius_chunks": 256,
|
||||||
|
"anchors": 131585,
|
||||||
|
"matches": 1456,
|
||||||
|
"scan_wall_ms": 2438.534811,
|
||||||
|
"elapsed_ms": 2619.994137,
|
||||||
|
"gpu": "NVIDIA GeForce RTX 3060 Laptop GPU",
|
||||||
|
"rejection_tail_included": false
|
||||||
|
},
|
||||||
|
"single_anchor": {
|
||||||
|
"matches": 1181,
|
||||||
|
"root_jobs": 405
|
||||||
|
},
|
||||||
|
"source_sha256": {
|
||||||
|
"bench/slime_bench.cu": "3c70cbe2e5babc3e737199fb5e62b78ea9c5daadc0020af77292c2d59516259e",
|
||||||
|
"include/slime/solver_core.hpp": "feb1200518716b4d796fb60f60a83b6b798155bbd4e795531793181a5c7f9eba",
|
||||||
|
"include/slime/upper_interval.hpp": "af3fddf7705295d91ffd6e2190f542004a3ecff847fce9d4c9b13125bdbdc2d5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -40,8 +40,36 @@ def main():
|
||||||
with tempfile.TemporaryDirectory() as tmp:
|
with tempfile.TemporaryDirectory() as tmp:
|
||||||
path=Path(tmp)/'pattern.txt';path.write_bytes(b'?##.\r\n#..?\r\n..#?\r\n')
|
path=Path(tmp)/'pattern.txt';path.write_bytes(b'?##.\r\n#..?\r\n..#?\r\n')
|
||||||
assert run('--radius',0,'--pattern-file',path,'--dry-run')['pattern']==pattern.split('/')
|
assert run('--radius',0,'--pattern-file',path,'--dry-run')['pattern']==pattern.split('/')
|
||||||
|
diamond_fixture=json.loads((HERE/'results/diamond-4x4-example.json').read_text())
|
||||||
|
assert (HERE/'patterns/diamond-4x4.txt').read_text().splitlines()==diamond_fixture['pattern']
|
||||||
|
assert all(slime(diamond_fixture['seed48'],diamond_fixture['chunk_x']+dx,diamond_fixture['chunk_z']+dz)==(ch=='#')
|
||||||
|
for dz,row in enumerate(diamond_fixture['pattern']) for dx,ch in enumerate(row))
|
||||||
|
heart_fixture=json.loads((HERE/'results/heart-5x5-example.json').read_text())
|
||||||
|
assert (HERE/'patterns/heart-5x5.txt').read_text().splitlines()==heart_fixture['pattern']
|
||||||
|
assert all(slime(heart_fixture['seed48'],heart_fixture['chunk_x']+dx,heart_fixture['chunk_z']+dz)==(ch=='#')
|
||||||
|
for dz,row in enumerate(heart_fixture['pattern']) for dx,ch in enumerate(row))
|
||||||
summary={'cli_scope_and_errors':True,'pattern_inputs':True}
|
summary={'cli_scope_and_errors':True,'pattern_inputs':True}
|
||||||
if args.gpu:
|
if args.gpu:
|
||||||
|
heart_poc=run('--x',heart_fixture['chunk_x'],'--z',heart_fixture['chunk_z'],'--radius',0,
|
||||||
|
'--pattern-file',HERE/'patterns/heart-5x5.txt','--max-results',2000)
|
||||||
|
heart_hits=heart_poc['rounds'][0]
|
||||||
|
assert heart_hits['matches']==heart_fixture['single_anchor']['matches']
|
||||||
|
assert heart_hits['root_jobs']==heart_fixture['single_anchor']['root_jobs']
|
||||||
|
assert not heart_hits['sample_truncated'] and len(heart_hits['sample'])==heart_hits['matches']
|
||||||
|
assert len(set(map(tuple,heart_hits['sample'])))==heart_hits['matches']
|
||||||
|
assert [heart_fixture['seed48'],heart_fixture['chunk_x'],heart_fixture['chunk_z']] in heart_hits['sample']
|
||||||
|
for seed,x,z in heart_hits['sample']:
|
||||||
|
assert all(slime(seed,x+dx,z+dz)==(ch=='#') for dz,row in enumerate(heart_fixture['pattern']) for dx,ch in enumerate(row))
|
||||||
|
summary['heart_pattern_verified_matches']=heart_hits['matches']
|
||||||
|
diamond_poc=run('--x',diamond_fixture['chunk_x'],'--z',diamond_fixture['chunk_z'],'--radius',0,
|
||||||
|
'--pattern-file',HERE/'patterns/diamond-4x4.txt','--max-results',64)
|
||||||
|
diamond_hits=diamond_poc['rounds'][0]
|
||||||
|
assert diamond_hits['matches']==diamond_fixture['single_anchor']['matches']
|
||||||
|
assert diamond_hits['root_jobs']==diamond_fixture['single_anchor']['root_jobs']
|
||||||
|
assert len(diamond_hits['sample'])==64
|
||||||
|
for seed,x,z in diamond_hits['sample']:
|
||||||
|
assert all(slime(seed,x+dx,z+dz)==(ch=='#') for dz,row in enumerate(diamond_fixture['pattern']) for dx,ch in enumerate(row))
|
||||||
|
summary['diamond_pattern_verified_matches']=diamond_hits['matches']
|
||||||
# A mixed-mask regression fixture; this is not the target creeper pattern.
|
# A mixed-mask regression fixture; this is not the target creeper pattern.
|
||||||
fixture=json.loads((HERE/'testdata/mixed-mask-regression.json').read_text())
|
fixture=json.loads((HERE/'testdata/mixed-mask-regression.json').read_text())
|
||||||
face=run('--x',fixture['chunk_x'],'--z',fixture['chunk_z'],'--radius',0,
|
face=run('--x',fixture['chunk_x'],'--z',fixture['chunk_z'],'--radius',0,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue