roadmap: improve time to the first square solution #16

Open
opened 2026-07-30 16:26:18 +01:00 by mcp · 4 comments
Collaborator

Objective

Coordinate the work needed to reduce the time required to find one solution to a square Partridge puzzle. Rectangular puzzles and solution enumeration are out of scope.

The general packing problem remains exponential in the worst case, so work should first remove unnecessary searches, then reduce the search tree, and only then reduce per-node cost or add parallel hardware.

Working rules

  • Carry out each issue on its own topic branch and worktree.
  • Associate every change and pull request with its specific issue.
  • Keep changes as small, independently testable logic units.
  • For each bug, commit the failing regression test before the fix.
  • Use #8 for comparable before/after measurements.
  • Validate every returned solution independently through #1.
  • Do not combine several speculative optimizations into one benchmark result.

Recommended order

Phase 0: establish correctness and measurement

  1. #1 — Add automated solver and construction coverage.
    Establish CTest and an independent validator for dimensions, multiplicities, bounds, overlap and complete coverage. Add only the minimum harness needed for the two bug regressions first; expand the suite incrementally.
  2. #7 — Fix the Results Debug assertion.
    This unblocks Debug builds and assertion-enabled tests.
  3. #14 — Check completion before probing the next square.
    This removes the sanitizer-confirmed heap-buffer overflow. Record a failing sanitizer regression before fixing it.
  4. #8 — Add the repeatable solver benchmark suite.
    Record a clean baseline only after #7 and #14 are fixed. Keep benchmark timing separate from correctness tests.

Gate A: Debug and sanitizer configurations pass, solutions are independently validated, and a reproducible single-thread baseline exists.

Phase 1: take the guaranteed reduction

  1. #6 — Construct odd solutions from even predecessors.
    This avoids direct exponential search for every odd order at least 9 and should be implemented before tuning order-9 search.
  2. #5 — Benchmark CP-SAT as an optional reference solver.
    This is independent research that may proceed once the validator and benchmark conventions exist. It is a comparison point, not the presumed production architecture.

Gate B: Odd requests use the constructive path and benchmark results distinguish search, construction, validation and rendering.

Phase 2: replace the core search

  1. #4 — Replace cell DFS with smallest-valley skyline search.
    Start with a clear scalar implementation. Demonstrate completeness and benchmark it before adding specialized data structures or SIMD.
  2. #12 — Benchmark candidate ordering and portfolio policies.
    Compare ascending, descending and justified best-fit order on the stable skyline implementation. Select the single-thread default from measured time-to-first-solution results.
  3. #3 — Break board dihedral symmetry.
    Apply canonical positioning of the unique 1x1 square once placement/state semantics are stable.

Gate C: The skyline solver is independently validated, has a selected deterministic single-thread policy, and materially improves the baseline.

Phase 3: add pruning from cheapest to more expensive

  1. #10 — Add cheap valley and narrow-gap pruning.
    Implement the proven constant/low-cost checks first and measure each independently.
  2. #15 — Prune states that cannot place remaining large squares.
    Add the monotonic geometric feasibility check, measuring whether incremental maintenance is worthwhile.
  3. #13 — Add component-area feasibility pruning.
    Add gcd or bounded subset-sum component checks last because their per-node cost is potentially higher. Trigger them selectively.

Gate D: Retain a pruning rule by default only when it is sound and produces a measured net improvement on the benchmark set. Record prune counts as well as elapsed time.

Phase 4: parallelize the proven search

  1. #11 — Parallelize a shallow search frontier.
    Parallelize only after the compact state, candidate policy and pruning rules are stable. Use over-decomposed tasks, dynamic scheduling and prompt first-solution cancellation.

Gate E: Thread-safety checks pass and scaling is reported for 1, 2, 4 and available hardware threads without regressing deterministic single-thread operation.

Phase 5: evaluate conditional experiments

  1. #9 — Evaluate failed-state memoization.
    Instrument duplicate-state frequency first. Keep memoization only if its hit rate and wall-time benefit justify memory and contention costs.
  2. #2 — Evaluate packed row-bit occupancy.
    Treat this as an alternative/interim optimization for the old cell solver. Do not implement it automatically if #4 removes the cell grid and makes it redundant.

Completion criteria

  • Correctness tests, Debug builds and applicable sanitizers pass.
  • The solver returns a validated first solution and stops; it does not enumerate all solutions.
  • Odd orders use the even-predecessor construction where applicable.
  • The selected single-thread algorithm and parallel strategy have reproducible benchmark evidence.
  • Rejected experiments and their measurements are recorded, so they are not repeatedly reconsidered without new evidence.
  • Documentation explains the algorithm, supported inputs, benchmark method and current results.

Tracked issues

  • #1 testing and independent validation
  • #2 packed row-bit occupancy experiment
  • #3 D4 symmetry breaking
  • #4 smallest-valley skyline redesign
  • #5 CP-SAT reference benchmark
  • #6 even-to-odd construction
  • #7 Debug assertion bug
  • #8 benchmark suite and instrumentation
  • #9 failed-state memoization experiment
  • #10 valley and narrow-gap pruning
  • #11 parallel frontier search
  • #12 candidate ordering and portfolio search
  • #13 component-area pruning
  • #14 completion heap-buffer overflow
  • #15 remaining-large-square feasibility
## Objective Coordinate the work needed to reduce the time required to find one solution to a square Partridge puzzle. Rectangular puzzles and solution enumeration are out of scope. The general packing problem remains exponential in the worst case, so work should first remove unnecessary searches, then reduce the search tree, and only then reduce per-node cost or add parallel hardware. ## Working rules - Carry out each issue on its own topic branch and worktree. - Associate every change and pull request with its specific issue. - Keep changes as small, independently testable logic units. - For each bug, commit the failing regression test before the fix. - Use #8 for comparable before/after measurements. - Validate every returned solution independently through #1. - Do not combine several speculative optimizations into one benchmark result. ## Recommended order ### Phase 0: establish correctness and measurement 1. **#1 — Add automated solver and construction coverage.** Establish CTest and an independent validator for dimensions, multiplicities, bounds, overlap and complete coverage. Add only the minimum harness needed for the two bug regressions first; expand the suite incrementally. 2. **#7 — Fix the `Results` Debug assertion.** This unblocks Debug builds and assertion-enabled tests. 3. **#14 — Check completion before probing the next square.** This removes the sanitizer-confirmed heap-buffer overflow. Record a failing sanitizer regression before fixing it. 4. **#8 — Add the repeatable solver benchmark suite.** Record a clean baseline only after #7 and #14 are fixed. Keep benchmark timing separate from correctness tests. **Gate A:** Debug and sanitizer configurations pass, solutions are independently validated, and a reproducible single-thread baseline exists. ### Phase 1: take the guaranteed reduction 5. **#6 — Construct odd solutions from even predecessors.** This avoids direct exponential search for every odd order at least 9 and should be implemented before tuning order-9 search. 6. **#5 — Benchmark CP-SAT as an optional reference solver.** This is independent research that may proceed once the validator and benchmark conventions exist. It is a comparison point, not the presumed production architecture. **Gate B:** Odd requests use the constructive path and benchmark results distinguish search, construction, validation and rendering. ### Phase 2: replace the core search 7. **#4 — Replace cell DFS with smallest-valley skyline search.** Start with a clear scalar implementation. Demonstrate completeness and benchmark it before adding specialized data structures or SIMD. 8. **#12 — Benchmark candidate ordering and portfolio policies.** Compare ascending, descending and justified best-fit order on the stable skyline implementation. Select the single-thread default from measured time-to-first-solution results. 9. **#3 — Break board dihedral symmetry.** Apply canonical positioning of the unique 1x1 square once placement/state semantics are stable. **Gate C:** The skyline solver is independently validated, has a selected deterministic single-thread policy, and materially improves the baseline. ### Phase 3: add pruning from cheapest to more expensive 10. **#10 — Add cheap valley and narrow-gap pruning.** Implement the proven constant/low-cost checks first and measure each independently. 11. **#15 — Prune states that cannot place remaining large squares.** Add the monotonic geometric feasibility check, measuring whether incremental maintenance is worthwhile. 12. **#13 — Add component-area feasibility pruning.** Add gcd or bounded subset-sum component checks last because their per-node cost is potentially higher. Trigger them selectively. **Gate D:** Retain a pruning rule by default only when it is sound and produces a measured net improvement on the benchmark set. Record prune counts as well as elapsed time. ### Phase 4: parallelize the proven search 13. **#11 — Parallelize a shallow search frontier.** Parallelize only after the compact state, candidate policy and pruning rules are stable. Use over-decomposed tasks, dynamic scheduling and prompt first-solution cancellation. **Gate E:** Thread-safety checks pass and scaling is reported for 1, 2, 4 and available hardware threads without regressing deterministic single-thread operation. ### Phase 5: evaluate conditional experiments 14. **#9 — Evaluate failed-state memoization.** Instrument duplicate-state frequency first. Keep memoization only if its hit rate and wall-time benefit justify memory and contention costs. 15. **#2 — Evaluate packed row-bit occupancy.** Treat this as an alternative/interim optimization for the old cell solver. Do not implement it automatically if #4 removes the cell grid and makes it redundant. ## Completion criteria - Correctness tests, Debug builds and applicable sanitizers pass. - The solver returns a validated first solution and stops; it does not enumerate all solutions. - Odd orders use the even-predecessor construction where applicable. - The selected single-thread algorithm and parallel strategy have reproducible benchmark evidence. - Rejected experiments and their measurements are recorded, so they are not repeatedly reconsidered without new evidence. - Documentation explains the algorithm, supported inputs, benchmark method and current results. ## Tracked issues - #1 testing and independent validation - #2 packed row-bit occupancy experiment - #3 D4 symmetry breaking - #4 smallest-valley skyline redesign - #5 CP-SAT reference benchmark - #6 even-to-odd construction - #7 Debug assertion bug - #8 benchmark suite and instrumentation - #9 failed-state memoization experiment - #10 valley and narrow-gap pruning - #11 parallel frontier search - #12 candidate ordering and portfolio search - #13 component-area pruning - #14 completion heap-buffer overflow - #15 remaining-large-square feasibility
Author
Collaborator

Phase 0 complete — Gate A passed

Implemented each issue sequentially on its own branch/worktree, with review before merge:

  • #1 via PR #17: CTest foundation, independent placement validator, known order-8 and constructed order-9 fixtures, diagnostics, and sanitizer guidance.
  • #7 via PR #18: regression-first Debug rendering test, then the Results::set() assertion fix.
  • #14 via PR #19: regression-first order-1/order-8 completion test reproducing the ASan overflow, then the sentinel-order fix. Returned order-8 solutions now pass independent dimension, multiplicity, bounds, overlap, and coverage validation.
  • #8 via PR #20: opt-in counters and structured repeatable benchmark runner, followed by a clean baseline commit.

Final verification on merged-equivalent ddf07e7:

  • Release CTest: 7/7 passed.
  • Debug CTest with assertions: 7/7 passed.
  • AddressSanitizer CTest: 7/7 passed.
  • UndefinedBehaviorSanitizer CTest: 7/7 passed.
  • Heavyweight benchmarks remain outside default CTest and contain no timing pass/fail threshold.

Clean single-thread Apple arm64 Release baseline against exact framework commit 598667b:

  • order 7: counted median 3.453 s, 110,483,315 nodes, 0.53% counter overhead;
  • order 8: counted median 1.817 s, 60,485,176 nodes, 0.64% counter overhead;
  • stable counts; separate construction, validation, and rendering fields.

Order 9 is supported by the runner; its historical ~158.69 s result is retained rather than spending multiple minutes per repeated local baseline run.

Gate A is satisfied: Debug and applicable sanitizers pass, feasible solver output is independently validated, and a reproducible deterministic single-thread baseline exists. The roadmap remains open for Phase 1.

## Phase 0 complete — Gate A passed Implemented each issue sequentially on its own branch/worktree, with review before merge: - #1 via PR #17: CTest foundation, independent placement validator, known order-8 and constructed order-9 fixtures, diagnostics, and sanitizer guidance. - #7 via PR #18: regression-first Debug rendering test, then the `Results::set()` assertion fix. - #14 via PR #19: regression-first order-1/order-8 completion test reproducing the ASan overflow, then the sentinel-order fix. Returned order-8 solutions now pass independent dimension, multiplicity, bounds, overlap, and coverage validation. - #8 via PR #20: opt-in counters and structured repeatable benchmark runner, followed by a clean baseline commit. Final verification on merged-equivalent `ddf07e7`: - Release CTest: 7/7 passed. - Debug CTest with assertions: 7/7 passed. - AddressSanitizer CTest: 7/7 passed. - UndefinedBehaviorSanitizer CTest: 7/7 passed. - Heavyweight benchmarks remain outside default CTest and contain no timing pass/fail threshold. Clean single-thread Apple arm64 Release baseline against exact framework commit `598667b`: - order 7: counted median 3.453 s, 110,483,315 nodes, 0.53% counter overhead; - order 8: counted median 1.817 s, 60,485,176 nodes, 0.64% counter overhead; - stable counts; separate construction, validation, and rendering fields. Order 9 is supported by the runner; its historical ~158.69 s result is retained rather than spending multiple minutes per repeated local baseline run. Gate A is satisfied: Debug and applicable sanitizers pass, feasible solver output is independently validated, and a reproducible deterministic single-thread baseline exists. The roadmap remains open for Phase 1.
Author
Collaborator

Phase 1 complete — Gate B passed

Implemented each issue sequentially on its own branch/worktree, with review before commit and merge:

  • #6 via PR #21 (3e667d6): odd orders N >= 9 now search only the even predecessor, geometrically translate its placements, and construct the enlarged border. Search and construction are explicit internal paths and separate benchmark fields. Order-9 search counters exactly match order 8.
  • #5 via PR #22 (0a7ce1e): optional OR-Tools CP-SAT reference model with NoOverlap2D, exact fill, edge exclusions, equal-copy ordering, independent validation, repeat benchmarking, model/memory/worker reporting, and documented keep-as-reference / defer-DLX decisions. OR-Tools is not a native or default-test dependency.

Verification:

  • #6 Release, Debug, AddressSanitizer, and UndefinedBehaviorSanitizer CTest: 8/8 passed in each configuration.
  • #5 merged-base Release CTest with system Python and no OR-Tools: 9/9 passed.
  • Optional Python 3.13 / OR-Tools 9.15.6755 tests and independent order-8/order-9 solution validation passed.

Measured results:

  • Native order 9: 1.778 s counter-free predecessor-search median plus 0.458 microseconds construction in the #6 comparison, versus the historical 158.69 s direct search (about 89x faster).
  • CP-SAT order 8, 8 workers: 2.080 s median across three valid runs, versus 1.854 s native counted median on one worker.
  • CP-SAT order 9, 8 workers: one valid 54.623 s observation, versus 1.846 s native predecessor-search median plus 0.250 microseconds construction in the #5 comparison.

Gate B is satisfied: applicable odd requests use the constructive route, and benchmarks separately report search, construction, independent validation, and rendering. The roadmap remains open for Phase 2.

## Phase 1 complete — Gate B passed Implemented each issue sequentially on its own branch/worktree, with review before commit and merge: - #6 via PR #21 (`3e667d6`): odd orders `N >= 9` now search only the even predecessor, geometrically translate its placements, and construct the enlarged border. Search and construction are explicit internal paths and separate benchmark fields. Order-9 search counters exactly match order 8. - #5 via PR #22 (`0a7ce1e`): optional OR-Tools CP-SAT reference model with `NoOverlap2D`, exact fill, edge exclusions, equal-copy ordering, independent validation, repeat benchmarking, model/memory/worker reporting, and documented keep-as-reference / defer-DLX decisions. OR-Tools is not a native or default-test dependency. Verification: - #6 Release, Debug, AddressSanitizer, and UndefinedBehaviorSanitizer CTest: 8/8 passed in each configuration. - #5 merged-base Release CTest with system Python and no OR-Tools: 9/9 passed. - Optional Python 3.13 / OR-Tools 9.15.6755 tests and independent order-8/order-9 solution validation passed. Measured results: - Native order 9: 1.778 s counter-free predecessor-search median plus 0.458 microseconds construction in the #6 comparison, versus the historical 158.69 s direct search (about 89x faster). - CP-SAT order 8, 8 workers: 2.080 s median across three valid runs, versus 1.854 s native counted median on one worker. - CP-SAT order 9, 8 workers: one valid 54.623 s observation, versus 1.846 s native predecessor-search median plus 0.250 microseconds construction in the #5 comparison. Gate B is satisfied: applicable odd requests use the constructive route, and benchmarks separately report search, construction, independent validation, and rendering. The roadmap remains open for Phase 2.
Author
Collaborator

Phase 2 complete — Gate C passed

Implemented each issue sequentially on its own branch/worktree, with independent review before commit and fast-forward merge:

  • #4 via PR #23 (d751d1b): replaced the board-area cell DFS with a scalar smallest-width-valley skyline, exact undo, public/direct benchmark routes, and independently validated ascending/descending coverage.
  • #12 via PR #24 (74bde26): compared ascending, descending, and exact-width-first best-fit policies. Ascending remains the deterministic single-thread default; best-fit's slightly smaller tree was slower, descending was materially worse, and unsupported randomized/duplicate-work portfolios were deferred.
  • #3 via PR #25 (f37e087): constrained the unique 1x1 square to a closed D4 fundamental triangle, with all eight transforms and even/odd boundary stabilizers covered. No repeated square copies are labeled.

Final D4-enabled counted measurements on Apple arm64 Release, with independent validation and stable counters:

  • order 8: 0.245 s median, 2,931,203 nodes;
  • order 9 direct: 1.705 s median, 16,231,918 nodes.

For comparison, the Gate A cell-DFS order-8 baseline was 1.817 s and 60,485,176 nodes. The final order-8 search is therefore about 7.4x faster with 95.2% fewer nodes on the recorded machine. D4 alone reduced the stable skyline tree by 62.1% for order 8 and 64.6% for direct order 9.

Verification on the final merged-equivalent tree:

  • Release CTest: 11/11 passed;
  • Debug CTest: 11/11 passed;
  • AddressSanitizer CTest: 11/11 passed;
  • UndefinedBehaviorSanitizer CTest: 11/11 passed;
  • benchmark self-test, Python byte-compilation, and diff checks passed;
  • every completed benchmark solution passed independent dimensions, multiplicity, bounds, overlap, and coverage validation.

10x10/11x11 decision: testing was explicitly evaluated in all three issues. Public order 10 with the final D4 skyline still exceeded a 45-second cap. Public order 11 performs exactly that order-10 predecessor search before cheap odd construction, so neither is suitable for routine CTest yet. They remain bounded opt-in heavyweight benchmarks. Direct order 11 is a distinct larger-core experiment and must not be reported as public order-11 performance.

Gate C is satisfied: the skyline solver is independently validated, ascending is the measured deterministic single-thread policy, D4 canonicalization is sound, and the implementation materially improves the recorded baseline. The roadmap remains open for Phase 3 pruning.

## Phase 2 complete — Gate C passed Implemented each issue sequentially on its own branch/worktree, with independent review before commit and fast-forward merge: - #4 via PR #23 (`d751d1b`): replaced the board-area cell DFS with a scalar smallest-width-valley skyline, exact undo, public/direct benchmark routes, and independently validated ascending/descending coverage. - #12 via PR #24 (`74bde26`): compared ascending, descending, and exact-width-first best-fit policies. Ascending remains the deterministic single-thread default; best-fit's slightly smaller tree was slower, descending was materially worse, and unsupported randomized/duplicate-work portfolios were deferred. - #3 via PR #25 (`f37e087`): constrained the unique 1x1 square to a closed D4 fundamental triangle, with all eight transforms and even/odd boundary stabilizers covered. No repeated square copies are labeled. Final D4-enabled counted measurements on Apple arm64 Release, with independent validation and stable counters: - order 8: 0.245 s median, 2,931,203 nodes; - order 9 direct: 1.705 s median, 16,231,918 nodes. For comparison, the Gate A cell-DFS order-8 baseline was 1.817 s and 60,485,176 nodes. The final order-8 search is therefore about 7.4x faster with 95.2% fewer nodes on the recorded machine. D4 alone reduced the stable skyline tree by 62.1% for order 8 and 64.6% for direct order 9. Verification on the final merged-equivalent tree: - Release CTest: 11/11 passed; - Debug CTest: 11/11 passed; - AddressSanitizer CTest: 11/11 passed; - UndefinedBehaviorSanitizer CTest: 11/11 passed; - benchmark self-test, Python byte-compilation, and diff checks passed; - every completed benchmark solution passed independent dimensions, multiplicity, bounds, overlap, and coverage validation. 10x10/11x11 decision: testing was explicitly evaluated in all three issues. Public order 10 with the final D4 skyline still exceeded a 45-second cap. Public order 11 performs exactly that order-10 predecessor search before cheap odd construction, so neither is suitable for routine CTest yet. They remain bounded opt-in heavyweight benchmarks. Direct order 11 is a distinct larger-core experiment and must not be reported as public order-11 performance. Gate C is satisfied: the skyline solver is independently validated, ascending is the measured deterministic single-thread policy, D4 canonicalization is sound, and the implementation materially improves the recorded baseline. The roadmap remains open for Phase 3 pruning.
Author
Collaborator

Phase 3 / Gate D is complete.

Completed sequentially:

  • #10 via PR #26 (e27427d): generalized valley-capacity pruning, covering width-one and width-two narrow gaps. Default-on after reducing median counted time by 10.3% (order 7) and 9.9% (order 8).
  • #15 via PR #27 (220cec0): largest-remaining-square empty-box feasibility. Default-on after small public-path counter-free gains (0.12% order 7, 0.89% order 8); the 1.39% direct-order-9 regression and portability limitation are documented.
  • #13 via PR #28 (39ff5cb): component detection plus gcd and bounded subset-sum feasibility, with boundary-event and periodic-eight schedules. Both modes remain opt-in/default-off: gcd slowed representative cases about 4.3%, subset sum 6.8-7.5%, and periodic checking was worse.

Each issue used its own branch/worktree, received an issue-specific review, passed Debug and ASan+UBSan suites, recorded correctness arguments and focused exhaustive comparisons, committed with issue references, pushed, opened as a PR, and was fast-forward merged. The final suite has 14 tests. Gate D's default-retention rule is reflected in the production configuration, and rejected component experiments remain reproducible through benchmark modes and dedicated counters.

Phase 3 / Gate D is complete. Completed sequentially: - #10 via PR #26 (`e27427d`): generalized valley-capacity pruning, covering width-one and width-two narrow gaps. Default-on after reducing median counted time by 10.3% (order 7) and 9.9% (order 8). - #15 via PR #27 (`220cec0`): largest-remaining-square empty-box feasibility. Default-on after small public-path counter-free gains (0.12% order 7, 0.89% order 8); the 1.39% direct-order-9 regression and portability limitation are documented. - #13 via PR #28 (`39ff5cb`): component detection plus gcd and bounded subset-sum feasibility, with boundary-event and periodic-eight schedules. Both modes remain opt-in/default-off: gcd slowed representative cases about 4.3%, subset sum 6.8-7.5%, and periodic checking was worse. Each issue used its own branch/worktree, received an issue-specific review, passed Debug and ASan+UBSan suites, recorded correctness arguments and focused exhaustive comparisons, committed with issue references, pushed, opened as a PR, and was fast-forward merged. The final suite has 14 tests. Gate D's default-retention rule is reflected in the production configuration, and rejected component experiments remain reproducible through benchmark modes and dedicated counters.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mgrettondann/partridge-cpp#16