slime/research/README.md

202 lines
8 KiB
Markdown

# Slime pattern reverse-search prototype
当前范围测速 CLI 见 [bench/README.md](../bench/README.md),共用算法实现见 [include/](../include/README.md)。本目录保留研究入口与历史路径;近期实验见 [实验导航](experiments/README.md)。
This directory retains fixed-coordinate seed solvers and fixed-seed coordinate scanners.
It is not a complete all-seed world-border catalog generator.
- `slime_pattern_prototype.py`: readable reference/oracle.
- `slime_pattern_cpp.cpp`, `slime_pattern_cuda.cu`: fixed-coordinate seed search.
- `slime_position_cuda.cu`: direct vs tiled outer-sum coordinate scans.
- `slime_position_residue_cuda.cu`: fixed-seed coordinate-residue filtering.
- `slime_bruteforce_cpp_bench.cpp`, `slime_bruteforce_cuda_bench.cu`: baseline benchmarks.
- `slime_solver_core.hpp`: shared arithmetic and upper13 solver.
See [优化摘要](OPTIMIZATION_SUMMARY.md) and [BENCHMARK.md](BENCHMARK.md).
The independent X/Z filter/join route and its middle-bit experiments have been removed;
method, historical results and stopping reasons are consolidated in
[X/Z 筛轴试错报告](XZ_FILTER_TRIAL_REPORT.md).
## What is implemented
- Minecraft/Java-compatible coordinate overflow and `Random.nextInt(10)`
verification.
- Arbitrary patterns using `#` (slime), `.` (non-slime), and `?` (ignored).
- Lower-seed 2-adic lifting from 18 bits toward the 35-bit boundary.
- The analytic `35 + 13` split. For `seed = lower35 + m * 2^35`, all pattern
cells share the same upper-state displacement. Substituting
`n = 1645*m mod 8192` turns each required-slime cell into a piecewise
`n mod 5` constraint with one threshold. Sorting those thresholds solves all
upper 13 bits without scanning 8192 values.
- The position outer-sum identity modulo `2^32`, used to reuse coordinate
arithmetic in fixed-seed scans.
- A full-world fixed-seed position search: filter the `2^36` pairs
`(x mod 2^18, z mod 2^18)` on CUDA, expand only surviving residue classes,
then perform exact Java verification.
## Run it
The known public 5x5 sample is:
```bash
python3 research/slime_pattern_prototype.py verify \
--seed 61692151016558 --x 51069 --z 419124 -n 5
```
Recover the 12 upper-bit solutions belonging to one known lower-35-bit value:
```bash
python3 research/slime_pattern_prototype.py upper \
--lower35 16420645998 --x 51069 --z 419124 -n 5
```
Show the 18-to-24-bit lifting counts:
```bash
python3 research/slime_pattern_prototype.py roots \
--x 51069 --z 419124 -n 5 --bits 24
```
Use a custom pattern (rows are separated by `/`):
```bash
python3 research/slime_pattern_prototype.py verify \
--seed 61692151016558 --x 51069 --z 419124 \
--pattern '##?/..#/#?#'
```
Check and print the outer-sum position signature:
```bash
python3 research/slime_pattern_prototype.py signature \
--x 51069 --z 419124 -n 5
```
Run the tests:
```bash
python3 -m unittest discover -s research -p 'test_*.py'
```
## C++ and CUDA
Build both native implementations:
```bash
make -C research
```
The CPU CLI exposes the same important stages as the Python oracle:
```bash
research/slime_pattern_cpp verify \
--seed 61692151016558 --x 51069 --z 419124 -n 5
research/slime_pattern_cpp roots \
--x 51069 --z 419124 -n 5 --bits 24
research/slime_pattern_cpp upper \
--lower35 16420645998 --x 51069 --z 419124 -n 5
```
`search` performs the complete fixed-position pipeline. For the public 5x5
sample it expands 84 lower-18 roots into 11,010,048 lower-35-bit values and
recovers all 24 known seeds:
```bash
research/slime_pattern_cpp search \
--x 51069 --z 419124 -n 5 -p 16 --max-results 32
```
On the development machine this CPU run took about 0.68 seconds with 16 worker
threads. Treat that as a local sanity benchmark, not a portable performance
claim.
The CUDA program performs the same complete fixed-position search and accepts
the same compact arbitrary-pattern syntax:
```bash
research/slime_pattern_cuda \
--x 51069 --z 419124 -n 5 --threads 128 --max-results 32
research/slime_pattern_cuda \
--x 0 --z 0 --pattern '##?/..#/#?#' --threads 128
```
CUDA 12 compilation was verified, and the solver was subsequently benchmarked
on an RTX 3060 Laptop GPU. See [BENCHMARK.md](BENCHMARK.md) for the old/new CPU
and CUDA comparison, methodology, commands, and limitations. GPU execution
from a sandboxed session may still require host GPU permission.
## Coordinate-side outer-sum experiment
For a fixed world seed, compare a direct position scan against a tiled
outer-sum scan over an inclusive rectangle:
```bash
research/slime_position_cuda \
--seed 61692151016558 \
--x0 46973 --x1 55165 --z0 415028 --z1 423220 \
-n 5 --repeats 5
```
Both kernels run on every invocation. Their sorted hit lists must be exactly
equal or the program fails. The direct kernel recomputes the full coordinate
term at each tested cell. The outer kernel assigns a 16x16 position tile to a
CUDA block and shares the expanded `F(x+i)` and `G(z+j)` axis arrays across the
block. On the development RTX 3060 Laptop GPU, the 67,125,249-position command
above took 1.608 ms direct versus 1.332 ms outer-sum (median of five), a 1.21x
kernel speedup, and found only `(51069, 419124)`.
This result is intentionally modest. A solid pattern rejects almost every
position on its first one or two chunks, so the direct kernel seldom evaluates
all 25 coordinate polynomials. Outer-sum removes duplicated coordinate work,
but does not change the asymptotic rectangle area. It remains a fixed-seed arithmetic-reuse baseline; full seed/coordinate catalog generation is unresolved.
## Full-world fixed-seed residue search
The low output parity used by the seed lifting depends on coordinates only
modulo `2^18`. The residue solver checks that fixed `2^36` space once, then
expands the surviving residue pairs into the requested world rectangle:
```bash
research/slime_position_residue_cuda --seed 61692151016558 -n 5
```
The default bounds are `[-1875000, 1874999]` on both axes. For the public seed
on the development RTX 3060 Laptop GPU, the residue kernel took 1.93 seconds,
retained 180,476 of 68,719,476,736 residue pairs, and expanded them into
36,937,048 exact candidates out of 14,062,500,000,000 world positions. Exact
CPU verification took another 284 ms and found only `(51069, 419124)`.
Across four tested seeds, the kernel stayed between 1.92 and 1.94 seconds and
retained 175,992--195,672 residue pairs. Including axis-table preparation and
exact verification, a full run took about 2.5 seconds. A measured `2^34`
direct-position CUDA run projects to about 429 seconds over the same world, so
the residue method is about 170x faster end-to-end for this fixed-seed 5x5
workload.
## Removed experiments
Failed and inferior approaches are not part of the active build. Their data,
failure reasons, and key implementation snippets are preserved in
[`REJECTED_EXPERIMENTS.md`](REJECTED_EXPERIMENTS.md).
## Prototype limitations
1. The upper-bit candidate generator describes the first `next(31)` draw.
Java rejects only the final eight of the `2^31` possible values before
drawing again. Every emitted seed is checked with the exact rejection loop,
so there are no false positives, but a solution whose first draw is rejected
and whose later draw succeeds can be missed. An exhaustive catalog builder
must add a tiny exceptional-state branch.
2. Ordinary lifting is weak after the output parity becomes known: modulo 5 can
still be repaired by unknown binary bits. A solid 5x5 sample has 84 roots at
18 bits and 5,376 at 24 bits, then grows to roughly 11 million lower-35
low-bit values. The CLI therefore has a candidate safety limit.
3. Full-world position enumeration is implemented only for a fixed seed and a
solid square of size 1--8. Joint unknown `(seed, x, z)` catalog generation
is still unresolved; the X/Z independent-filter route was retired; see the trial report.
4. The residue parity filter shares the first-draw rejection-tail caveat from
item 1. Exact verification prevents false positives, but the rare solution
whose first draw is rejected can be filtered out before verification.