solver: select skyline candidate policy
Make candidate ordering an explicit deterministic policy and benchmark ascending, descending, and exact-width-first choices. Keep ascending as the default because it produces the best measured time to first solution despite best-fit's slightly smaller tree. Retain the benchmark v1 interface and document why randomized and duplicate-work portfolio policies are deferred. Tests: Release and Debug CTest (10 passed each) Refs: #12
This commit was merged in pull request #24.
This commit is contained in:
@@ -154,9 +154,12 @@ namespace {
|
||||
size_t completed_tasks = 0;
|
||||
};
|
||||
|
||||
enum class CandidateOrder {
|
||||
/** Deterministic order in which a skyline node tries fitting squares. */
|
||||
enum class SearchPolicy {
|
||||
ascending,
|
||||
descending,
|
||||
/** Close the selected valley when possible, then try smaller sizes first. */
|
||||
best_fit,
|
||||
};
|
||||
|
||||
/** A maximal level skyline segment which is lower than its neighbours. */
|
||||
@@ -199,7 +202,7 @@ namespace {
|
||||
|
||||
template<bool Instrument>
|
||||
auto search_skyline(size_t const n, size_t const length,
|
||||
CandidateOrder const candidate_order,
|
||||
SearchPolicy const policy,
|
||||
std::vector<size_t> &skyline, Avail &available,
|
||||
std::vector<Square> &squares,
|
||||
SearchCounters *const counters) noexcept -> bool {
|
||||
@@ -231,7 +234,7 @@ namespace {
|
||||
side, valley.height + side);
|
||||
squares.emplace_back(valley.x + valley.height * length, side);
|
||||
|
||||
if (search_skyline<Instrument>(n, length, candidate_order, skyline,
|
||||
if (search_skyline<Instrument>(n, length, policy, skyline,
|
||||
available, squares, counters)) {
|
||||
return true;
|
||||
}
|
||||
@@ -246,8 +249,15 @@ namespace {
|
||||
return false;
|
||||
};
|
||||
|
||||
if (candidate_order == CandidateOrder::ascending) {
|
||||
if (policy == SearchPolicy::best_fit && largest == valley.width &&
|
||||
try_side(largest)) {
|
||||
return true;
|
||||
}
|
||||
if (policy != SearchPolicy::descending) {
|
||||
for (size_t side = 1; side <= largest; ++side) {
|
||||
if (policy == SearchPolicy::best_fit && side == valley.width) {
|
||||
continue;
|
||||
}
|
||||
if (try_side(side)) {
|
||||
return true;
|
||||
}
|
||||
@@ -272,7 +282,7 @@ namespace {
|
||||
* O(board width + n^2) local work per node and the same total state.
|
||||
*/
|
||||
template<bool Instrument>
|
||||
auto search_solution_impl(size_t const n, CandidateOrder const candidate_order,
|
||||
auto search_solution_impl(size_t const n, SearchPolicy const policy,
|
||||
SearchCounters *const counters) noexcept
|
||||
-> Results {
|
||||
auto const length = triangle_num(n);
|
||||
@@ -284,25 +294,25 @@ namespace {
|
||||
std::vector<Square> squares;
|
||||
squares.reserve(length);
|
||||
static_cast<void>(search_skyline<Instrument>(
|
||||
n, length, candidate_order, skyline, available, squares, counters));
|
||||
n, length, policy, skyline, available, squares, counters));
|
||||
|
||||
return {length, std::move(squares)};
|
||||
}
|
||||
|
||||
auto search_solution(
|
||||
size_t const n,
|
||||
CandidateOrder const candidate_order = CandidateOrder::ascending) noexcept
|
||||
SearchPolicy const policy = SearchPolicy::ascending) noexcept
|
||||
-> Results {
|
||||
return search_solution_impl<false>(n, candidate_order, nullptr);
|
||||
return search_solution_impl<false>(n, policy, nullptr);
|
||||
}
|
||||
|
||||
auto search_solution_instrumented(size_t const n,
|
||||
SearchCounters &counters,
|
||||
CandidateOrder const candidate_order =
|
||||
CandidateOrder::ascending) noexcept
|
||||
SearchPolicy const policy =
|
||||
SearchPolicy::ascending) noexcept
|
||||
-> Results {
|
||||
counters = {};
|
||||
return search_solution_impl<true>(n, candidate_order, &counters);
|
||||
return search_solution_impl<true>(n, policy, &counters);
|
||||
}
|
||||
|
||||
/** Construct an odd-order solution from its even-order predecessor. */
|
||||
@@ -335,20 +345,25 @@ namespace {
|
||||
return n >= 9 && n % 2 == 1;
|
||||
}
|
||||
|
||||
auto find_solution(size_t const n) noexcept -> Results {
|
||||
auto find_solution(
|
||||
size_t const n,
|
||||
SearchPolicy const policy = SearchPolicy::ascending) noexcept -> Results {
|
||||
if (uses_odd_construction(n)) {
|
||||
return construct_odd_solution(n, search_solution(n - 1));
|
||||
return construct_odd_solution(n, search_solution(n - 1, policy));
|
||||
}
|
||||
return search_solution(n);
|
||||
return search_solution(n, policy);
|
||||
}
|
||||
|
||||
auto find_solution_instrumented(size_t const n,
|
||||
SearchCounters &counters) noexcept -> Results {
|
||||
SearchCounters &counters,
|
||||
SearchPolicy const policy =
|
||||
SearchPolicy::ascending) noexcept
|
||||
-> Results {
|
||||
if (uses_odd_construction(n)) {
|
||||
return construct_odd_solution(
|
||||
n, search_solution_instrumented(n - 1, counters));
|
||||
n, search_solution_instrumented(n - 1, counters, policy));
|
||||
}
|
||||
return search_solution_instrumented(n, counters);
|
||||
return search_solution_instrumented(n, counters, policy);
|
||||
}
|
||||
} // anon namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user