solver: replace cell DFS with skyline search
Represent partial placements as column heights and branch on the narrowest local valley. This removes the board-area cell state and makes first-solution search substantially smaller for feasible orders. Expose direct-search and candidate-order benchmark controls so the skyline core can be measured independently of odd-order construction. Document the completeness argument and the 10/11 test-tier decision. Tests: Release, Debug, ASan, and UBSan CTest (10 passed each) Refs: #4
This commit was merged in pull request #23.
This commit is contained in:
@@ -343,6 +343,42 @@ namespace {
|
||||
return failures;
|
||||
}
|
||||
|
||||
auto test_skyline_search() -> int {
|
||||
int failures = 0;
|
||||
auto const narrowest =
|
||||
smallest_valley(std::vector<std::uint64_t>{4, 2, 2, 4, 0, 0, 0, 4});
|
||||
failures += expect(
|
||||
narrowest.x == 1 && narrowest.height == 2 && narrowest.width == 2,
|
||||
"skyline did not select the smallest-width valley");
|
||||
|
||||
auto const tie =
|
||||
smallest_valley(std::vector<std::uint64_t>{4, 1, 4, 4, 2, 4});
|
||||
failures += expect(tie.x == 1 && tie.height == 1 && tie.width == 1,
|
||||
"skyline valley tie-break is not deterministic");
|
||||
|
||||
SearchCounters descending_counters;
|
||||
auto const descending = search_solution_instrumented(
|
||||
8, descending_counters, CandidateOrder::descending);
|
||||
auto validation = validate(8, descending);
|
||||
failures += expect(
|
||||
validation.valid(),
|
||||
"descending skyline search returned an invalid order-8 solution:\n" +
|
||||
validation.text());
|
||||
|
||||
SearchCounters direct_nine_counters;
|
||||
auto const direct_nine = search_solution_instrumented(
|
||||
9, direct_nine_counters, CandidateOrder::ascending);
|
||||
validation = validate(9, direct_nine);
|
||||
failures += expect(
|
||||
validation.valid(),
|
||||
"direct skyline search returned an invalid order-9 solution:\n" +
|
||||
validation.text());
|
||||
failures += expect(
|
||||
direct_nine_counters.search_nodes != descending_counters.search_nodes,
|
||||
"direct order-9 coverage unexpectedly reused predecessor construction");
|
||||
return failures;
|
||||
}
|
||||
|
||||
auto test_solver_completion() -> int {
|
||||
int failures = 0;
|
||||
for (auto const order: std::array<std::uint64_t, 2>{1, 8}) {
|
||||
@@ -385,6 +421,9 @@ int main(int argc, char **argv) {
|
||||
if (test == "search-counters") {
|
||||
return test_search_counters();
|
||||
}
|
||||
if (test == "skyline-search") {
|
||||
return test_skyline_search();
|
||||
}
|
||||
std::cerr << "unknown test: " << test << '\n';
|
||||
return 2;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user