solver: construct odd-order solutions
Avoid repeating the exponential search for odd orders at least nine. Search the even predecessor, translate its row-major placements to the enlarged board, and tile the new border. Keep direct search and construction explicit so benchmarks can report their costs separately. Verify the routed order-9 result independently and require its search counters to match order 8. Tests: Release, Debug, ASan and UBSan CTest (8 passed each) Refs: #6
This commit was merged in pull request #21.
This commit is contained in:
@@ -245,12 +245,12 @@ namespace {
|
||||
size_t completed_tasks = 0;
|
||||
};
|
||||
|
||||
/** Find a solution to the \a n th Partridge problem.
|
||||
/** Search directly for a solution to the \a n th Partridge problem.
|
||||
*
|
||||
* Returns the grid of the solution.
|
||||
*/
|
||||
template<bool Instrument>
|
||||
auto find_solution_impl(size_t const n, SearchCounters *const counters) noexcept
|
||||
auto search_solution_impl(size_t const n, SearchCounters *const counters) noexcept
|
||||
-> Results {
|
||||
/* Implementation is iterative, as opposed to recursive.
|
||||
*
|
||||
@@ -343,14 +343,60 @@ namespace {
|
||||
return {length, sqs};
|
||||
}
|
||||
|
||||
auto search_solution(size_t const n) noexcept -> Results {
|
||||
return search_solution_impl<false>(n, nullptr);
|
||||
}
|
||||
|
||||
auto search_solution_instrumented(size_t const n,
|
||||
SearchCounters &counters) noexcept -> Results {
|
||||
counters = {};
|
||||
return search_solution_impl<true>(n, &counters);
|
||||
}
|
||||
|
||||
/** Construct an odd-order solution from its even-order predecessor. */
|
||||
auto construct_odd_solution(size_t const odd_order, Results predecessor)
|
||||
-> Results {
|
||||
assert(odd_order >= 9);
|
||||
assert(odd_order % 2 == 1);
|
||||
assert(predecessor.length() == triangle_num(odd_order - 1));
|
||||
|
||||
auto const old_length = predecessor.length();
|
||||
auto const new_length = triangle_num(odd_order);
|
||||
std::vector<Square> squares;
|
||||
squares.reserve(predecessor.squares().size() + odd_order);
|
||||
for (auto const &square: predecessor.squares()) {
|
||||
auto const x = square.pos() % old_length;
|
||||
auto const y = square.pos() / old_length;
|
||||
squares.emplace_back(x + y * new_length, square.length());
|
||||
}
|
||||
|
||||
for (size_t y = 0; y < old_length; y += odd_order) {
|
||||
squares.emplace_back(old_length + y * new_length, odd_order);
|
||||
}
|
||||
for (size_t x = 0; x <= old_length; x += odd_order) {
|
||||
squares.emplace_back(x + old_length * new_length, odd_order);
|
||||
}
|
||||
return {new_length, std::move(squares)};
|
||||
}
|
||||
|
||||
[[nodiscard]] auto uses_odd_construction(size_t const n) noexcept -> bool {
|
||||
return n >= 9 && n % 2 == 1;
|
||||
}
|
||||
|
||||
auto find_solution(size_t const n) noexcept -> Results {
|
||||
return find_solution_impl<false>(n, nullptr);
|
||||
if (uses_odd_construction(n)) {
|
||||
return construct_odd_solution(n, search_solution(n - 1));
|
||||
}
|
||||
return search_solution(n);
|
||||
}
|
||||
|
||||
auto find_solution_instrumented(size_t const n,
|
||||
SearchCounters &counters) noexcept -> Results {
|
||||
counters = {};
|
||||
return find_solution_impl<true>(n, &counters);
|
||||
if (uses_odd_construction(n)) {
|
||||
return construct_odd_solution(
|
||||
n, search_solution_instrumented(n - 1, counters));
|
||||
}
|
||||
return search_solution_instrumented(n, counters);
|
||||
}
|
||||
} // anon namespace
|
||||
|
||||
|
||||
Reference in New Issue
Block a user