solver: prune unplaceable large squares

A skyline may retain enough total empty area while no longer containing a box for its largest remaining square. Scan for the required consecutive low columns and reject such monotonic dead states.

Keep each pruning combination independently measurable and record the small public-path gain, the direct-order-9 regression, and the rejected periodic schedule.

Tests: Debug CTest (13 passed)

Tests: ASan+UBSan CTest (13 passed)

Refs: #15
This commit was merged in pull request #27.
This commit is contained in:
Codex instance
2026-07-31 08:25:36 +01:00
parent e27427d231
commit 220cec06a9
6 changed files with 264 additions and 43 deletions
+52 -2
View File
@@ -21,8 +21,9 @@ and `--candidate-order`. The choices are `ascending`, `descending`, and
The production default also removes equivalent D4 board orientations by
constraining the unique unit square. Pass `--no-symmetry` to obtain an
otherwise identical unconstrained baseline.
The production default also applies the valley-capacity rule described below.
Pass `--no-pruning` to obtain an otherwise identical unpruned search.
The production default also applies the pruning rules described below.
Use `--pruning valley-capacity`, `--pruning large-square`, or
`--no-pruning` to measure each rule alone or obtain an unpruned search.
Order 9 uses the constructive odd-order path, searching order 8 and then tiling
the enlarged border, so it is suitable for normal local benchmarking:
@@ -107,6 +108,55 @@ The rule reduced nodes by 7.8% for order 7 and 7.1% for order 8. Its low
per-node cost also reduced median counted solve time by 10.3% and 9.9%,
respectively, so it remains enabled by default.
## Remaining-large-square pruning
For a remaining side `k`, a skyline can contain an empty `k`-by-`k` box only
if it has `k` consecutive columns whose filled heights are no greater than the
board height minus `k`. A single linear scan tracks qualifying consecutive
columns. If no such run exists, the square cannot be placed and the state is
infeasible even when its total empty area is sufficient.
Empty-box feasibility is monotonic in the side length: a box which fits the
largest remaining square also fits every smaller remaining size. The solver
therefore invokes only one `O(board width)` scan per surviving node, after the
cheaper valley-capacity check. It does not attempt an unproven multiplicity
bound. `--pruning large-square` measures the rule independently;
`--pruning valley-capacity` provides the production baseline without it.
Instrumented output records `large_square_checks` and
`large_square_prunes`.
Measurements used the issue #15 working tree based on commit `e27427d`, Apple
Clang 21.0.0, `-O3 -DNDEBUG`, macOS arm64, one worker, one warm-up, and seven
measured repetitions. Counter-free and counted runs were interleaved; the
table reports the counter-free production instantiation. The baseline keeps
valley-capacity pruning enabled, so it isolates the new rule. All results
passed independent validation and counters were stable:
| Search | Large-square check | Median solve | Nodes | Checks | Prunes |
| --- | --- | ---: | ---: | ---: | ---: |
| Order 7 exhaustive | enabled | 0.946 s | 13,221,239 | 6,163,390 | 227,321 |
| Order 7 exhaustive | disabled | 0.947 s | 13,833,048 | 0 | 0 |
| Order 8 first solution | enabled | 0.195 s | 2,597,678 | 1,063,472 | 38,177 |
| Order 8 first solution | disabled | 0.197 s | 2,724,096 | 0 | 0 |
| Order 9 direct | enabled | 1.225 s | 14,840,146 | 5,592,843 | 54,900 |
| Order 9 direct | disabled | 1.208 s | 14,995,127 | 0 | 0 |
The rule reduced nodes by 4.4% for order 7, 4.6% for order 8, and 1.0% for
direct order 9. Counter-free median time improved by 0.12% and 0.89% on the
two distinct searches in the public benchmark set. Public order 9 constructs
from the improving order-8 search. Direct order 9, which bypasses that public
route, regressed by 1.39%; it remains documented as a caution for future
policy tuning.
Checking only every fourth placement depth was also measured. It retained
fewer prunes and was slower than checking every surviving node by 2.2% for
order 7, 2.3% for order 8, and 0.6% for direct order 9, so the periodic
schedule was rejected. Incremental maintenance would need additional
per-size window state and undo logic for an `O(W)` scan whose public net cost
is already recovered; it was not added without evidence that the complexity
would improve elapsed time. The simple every-node scan remains enabled by
default for the measured public benchmark benefit.
## D4 board symmetry
Every solution contains exactly one 1-by-1 square. Rotations and reflections