solver: select skyline candidate policy #24
+54
-1
@@ -16,7 +16,8 @@ The default policy is one unrecorded warm-up followed by five repetitions per
|
|||||||
case, with a 600-second timeout for each process. Solver stdout is captured;
|
case, with a 600-second timeout for each process. Solver stdout is captured;
|
||||||
the probe renders into an in-memory stream so grids do not perturb terminal I/O.
|
the probe renders into an in-memory stream so grids do not perturb terminal I/O.
|
||||||
Override the policy with `--orders`, `--warmup`, `--repetitions`, `--timeout`,
|
Override the policy with `--orders`, `--warmup`, `--repetitions`, `--timeout`,
|
||||||
and `--candidate-order`. Ascending candidate sizes are the production default.
|
and `--candidate-order`. The choices are `ascending`, `descending`, and
|
||||||
|
`best-fit`; ascending candidate sizes are the production default.
|
||||||
Order 9 uses the constructive odd-order path, searching order 8 and then tiling
|
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:
|
the enlarged border, so it is suitable for normal local benchmarking:
|
||||||
|
|
||||||
@@ -114,6 +115,58 @@ search bottleneck, while the existing route-boundary test still verifies that
|
|||||||
11 selects construction. Revisit both sizes when order 10 completes within a
|
11 selects construction. Revisit both sizes when order 10 completes within a
|
||||||
practical test budget.
|
practical test budget.
|
||||||
|
|
||||||
|
## Candidate policy selection
|
||||||
|
|
||||||
|
Candidate ordering is a deterministic search policy and does not alter the
|
||||||
|
smallest-valley selection or set of placements tried. `ascending` tries
|
||||||
|
smaller available squares first and `descending` tries larger ones first.
|
||||||
|
`best-fit` first tries a square exactly as wide as the selected valley, because
|
||||||
|
that placement closes the valley without leaving a shelf remainder, then tries
|
||||||
|
the other sizes in ascending order. If no exact-width square fits, best-fit
|
||||||
|
and ascending are identical at that node.
|
||||||
|
|
||||||
|
The policy comparison used the issue #12 working tree based on commit
|
||||||
|
`d751d1b`, Apple Clang 21.0.0, `-O3 -DNDEBUG`, macOS arm64, and one worker.
|
||||||
|
Order 8 used two warm-ups and seven sequential measured repetitions; direct
|
||||||
|
order 9 used one warm-up and three measured repetitions. All completed
|
||||||
|
results passed independent validation and node counts were stable:
|
||||||
|
|
||||||
|
| Order | Policy | Counted median (range) | Counter-free median | Nodes |
|
||||||
|
| --- | --- | --- | --- | ---: |
|
||||||
|
| 8 | ascending | 0.808 s (0.790–0.852 s) | 0.794 s | 7,735,369 |
|
||||||
|
| 8 | descending | 1.310 s (1.279–1.449 s) | 1.268 s | 12,186,125 |
|
||||||
|
| 8 | best-fit | 0.817 s (0.813–0.857 s) | 0.823 s | 7,679,349 |
|
||||||
|
| 9 direct | ascending | 5.522 s (5.499–5.830 s) | not measured | 45,840,266 |
|
||||||
|
| 9 direct | best-fit | 5.651 s (5.533–5.820 s) | not measured | 45,746,016 |
|
||||||
|
|
||||||
|
The earlier direct-order-9 descending probe exceeded its 15-second limit.
|
||||||
|
Ascending is retained as the stable single-threaded default because it had the
|
||||||
|
lowest measured median time to the first solution at both measured solvable
|
||||||
|
sizes. Best-fit's slightly smaller trees did not compensate for its policy
|
||||||
|
checks, while descending was substantially worse. Exhaustive infeasible
|
||||||
|
order-5 tests visit the same number of nodes under all three policies, which
|
||||||
|
checks that ordering does not affect completeness.
|
||||||
|
|
||||||
|
One policy therefore applies to the currently measured sizes 8 and 9. This
|
||||||
|
does not establish that ascending is optimal for order 10: a bounded best-fit
|
||||||
|
order-9 comparison changed the search tree by only 0.2%, so there was no
|
||||||
|
evidence that repeating the known long order-10/11 search would be useful.
|
||||||
|
Keep 10 and 11 as opt-in benchmark cases. Public order 11 is particularly
|
||||||
|
important to interpret correctly: it constructs from an order-10 search, so it
|
||||||
|
does not independently measure an odd-order candidate policy.
|
||||||
|
|
||||||
|
A worker portfolio was considered but not added. Running identical policies
|
||||||
|
duplicates the same deterministic traversal. Pairing ascending with best-fit
|
||||||
|
adds little diversity on the measured trees, and pairing ascending with
|
||||||
|
descending dedicates a worker to the consistently slower policy. Splitting a
|
||||||
|
shared frontier could avoid duplicated prefixes, but that is the parallel
|
||||||
|
frontier work tracked separately in issue #11. Seeded randomized ordering was
|
||||||
|
also rejected for now: the deterministic alternatives already select a clear
|
||||||
|
default, and there is no measurement showing that seed distributions would
|
||||||
|
improve time to first solution. The benchmark schema retains its nullable
|
||||||
|
seed field so a future evidence-backed randomized policy can report
|
||||||
|
reproducible runs without changing the format.
|
||||||
|
|
||||||
## Post-correctness baseline
|
## Post-correctness baseline
|
||||||
|
|
||||||
This framework starts from commit `ce39d0a` after the rendering assertion fix
|
This framework starts from commit `ce39d0a` after the rendering assertion fix
|
||||||
|
|||||||
+12
-8
@@ -12,14 +12,18 @@ ctest --test-dir build --output-on-failure
|
|||||||
The tests independently check board dimensions, square multiplicities, bounds,
|
The tests independently check board dimensions, square multiplicities, bounds,
|
||||||
overlap, and complete coverage. They cover small unsatisfiable solver inputs, a
|
overlap, and complete coverage. They cover small unsatisfiable solver inputs, a
|
||||||
known order-8 solution, invalid placement diagnostics, and construction of an
|
known order-8 solution, invalid placement diagnostics, and construction of an
|
||||||
order-9 solution from the order-8 fixture. The routed order-9 solver test
|
order-9 solution from the order-8 fixture. The routed best-fit order-9 solver
|
||||||
checks that its search counters exactly match order 8. The skyline tests check
|
test checks that its search counters exactly match order 8. The skyline tests
|
||||||
smallest-width valley selection and deterministic tie-breaking, validate an
|
check smallest-width valley selection and deterministic tie-breaking, validate
|
||||||
order-8 result with descending candidates, and independently validate a direct
|
an order-8 result with descending candidates, and independently validate a
|
||||||
order-9 search with ascending candidates. That direct test is deliberately
|
direct order-9 search with ascending candidates. An
|
||||||
separate from the public order-9 route, which uses even-predecessor
|
exhaustive infeasible order also checks that all three policies visit the same
|
||||||
construction. The rendering test also formats the known order-8 solution and
|
search space. The direct order-9 test is deliberately separate from the
|
||||||
checks the resulting grid dimensions and coverage.
|
public order-9 route, which uses even-predecessor construction. Orders 10 and
|
||||||
|
11 are not routine tests because both public routes require the same long
|
||||||
|
direct order-10 search; the route-boundary test still checks that order 11
|
||||||
|
selects odd construction. The rendering test also formats the known order-8
|
||||||
|
solution and checks the resulting grid dimensions and coverage.
|
||||||
|
|
||||||
When Python is available, `reference-support` also tests the dependency-free
|
When Python is available, `reference-support` also tests the dependency-free
|
||||||
placement JSON validator. If the optional OR-Tools package is present, it
|
placement JSON validator. If the optional OR-Tools package is present, it
|
||||||
|
|||||||
+16
-13
@@ -27,7 +27,7 @@ namespace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto solve(std::uint64_t order, bool instrument,
|
auto solve(std::uint64_t order, bool instrument,
|
||||||
CandidateOrder candidate_order, bool direct_search,
|
SearchPolicy policy, bool direct_search,
|
||||||
SearchCounters &counters)
|
SearchCounters &counters)
|
||||||
-> TimedSolution {
|
-> TimedSolution {
|
||||||
auto const predecessor_order =
|
auto const predecessor_order =
|
||||||
@@ -36,8 +36,8 @@ namespace {
|
|||||||
auto predecessor =
|
auto predecessor =
|
||||||
instrument
|
instrument
|
||||||
? search_solution_instrumented(predecessor_order, counters,
|
? search_solution_instrumented(predecessor_order, counters,
|
||||||
candidate_order)
|
policy)
|
||||||
: search_solution(predecessor_order, candidate_order);
|
: search_solution(predecessor_order, policy);
|
||||||
auto const search_end = Clock::now();
|
auto const search_end = Clock::now();
|
||||||
|
|
||||||
auto const construction_begin = Clock::now();
|
auto const construction_begin = Clock::now();
|
||||||
@@ -95,7 +95,7 @@ namespace {
|
|||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
if (argc < 3 || argc > 5) {
|
if (argc < 3 || argc > 5) {
|
||||||
std::cerr << "usage: partridge_benchmark ORDER counters|plain "
|
std::cerr << "usage: partridge_benchmark ORDER counters|plain "
|
||||||
"[ascending|descending] [public|direct]\n";
|
"[ascending|descending|best-fit] [public|direct]\n";
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
auto const order = static_cast<std::uint64_t>(std::strtoull(argv[1], nullptr, 10));
|
auto const order = static_cast<std::uint64_t>(std::strtoull(argv[1], nullptr, 10));
|
||||||
@@ -104,13 +104,16 @@ int main(int argc, char **argv) {
|
|||||||
std::cerr << "counter mode must be counters or plain\n";
|
std::cerr << "counter mode must be counters or plain\n";
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
auto const candidate_order =
|
auto const policy =
|
||||||
argc < 4 || std::string_view(argv[3]) == "ascending"
|
argc < 4 || std::string_view(argv[3]) == "ascending"
|
||||||
? CandidateOrder::ascending
|
? SearchPolicy::ascending
|
||||||
: CandidateOrder::descending;
|
: std::string_view(argv[3]) == "descending"
|
||||||
|
? SearchPolicy::descending
|
||||||
|
: SearchPolicy::best_fit;
|
||||||
if (argc >= 4 && std::string_view(argv[3]) != "ascending" &&
|
if (argc >= 4 && std::string_view(argv[3]) != "ascending" &&
|
||||||
std::string_view(argv[3]) != "descending") {
|
std::string_view(argv[3]) != "descending" &&
|
||||||
std::cerr << "candidate order must be ascending or descending\n";
|
std::string_view(argv[3]) != "best-fit") {
|
||||||
|
std::cerr << "search policy must be ascending, descending, or best-fit\n";
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
auto const direct_search =
|
auto const direct_search =
|
||||||
@@ -122,8 +125,7 @@ int main(int argc, char **argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SearchCounters counters;
|
SearchCounters counters;
|
||||||
auto timed =
|
auto timed = solve(order, instrument, policy, direct_search, counters);
|
||||||
solve(order, instrument, candidate_order, direct_search, counters);
|
|
||||||
|
|
||||||
auto const validation_begin = Clock::now();
|
auto const validation_begin = Clock::now();
|
||||||
auto const validation_ok = valid(order, timed.result);
|
auto const validation_ok = valid(order, timed.result);
|
||||||
@@ -142,8 +144,9 @@ int main(int argc, char **argv) {
|
|||||||
<< ",\"order\":" << order
|
<< ",\"order\":" << order
|
||||||
<< ",\"instrumented\":" << boolean(instrument)
|
<< ",\"instrumented\":" << boolean(instrument)
|
||||||
<< ",\"candidate_order\":\""
|
<< ",\"candidate_order\":\""
|
||||||
<< (candidate_order == CandidateOrder::ascending ? "ascending"
|
<< (policy == SearchPolicy::ascending
|
||||||
: "descending")
|
? "ascending"
|
||||||
|
: policy == SearchPolicy::descending ? "descending" : "best-fit")
|
||||||
<< "\""
|
<< "\""
|
||||||
<< ",\"search_route\":\""
|
<< ",\"search_route\":\""
|
||||||
<< (direct_search ? "direct" : "public") << "\""
|
<< (direct_search ? "direct" : "public") << "\""
|
||||||
|
|||||||
+7
-6
@@ -79,11 +79,11 @@ def environment(binary):
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def run_once(binary, order, mode, candidate_order, search_route, timeout):
|
def run_once(binary, order, mode, search_policy, search_route, timeout):
|
||||||
started = time.monotonic()
|
started = time.monotonic()
|
||||||
try:
|
try:
|
||||||
process = subprocess.run(
|
process = subprocess.run(
|
||||||
[str(binary), str(order), mode, candidate_order, search_route],
|
[str(binary), str(order), mode, search_policy, search_route],
|
||||||
check=False,
|
check=False,
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
@@ -218,7 +218,8 @@ def main():
|
|||||||
parser.add_argument("--timeout", type=float, default=600.0)
|
parser.add_argument("--timeout", type=float, default=600.0)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--candidate-order",
|
"--candidate-order",
|
||||||
choices=("ascending", "descending"),
|
dest="search_policy",
|
||||||
|
choices=("ascending", "descending", "best-fit"),
|
||||||
default="ascending",
|
default="ascending",
|
||||||
)
|
)
|
||||||
parser.add_argument("--direct-search", action="store_true")
|
parser.add_argument("--direct-search", action="store_true")
|
||||||
@@ -251,7 +252,7 @@ def main():
|
|||||||
args.binary,
|
args.binary,
|
||||||
order,
|
order,
|
||||||
mode,
|
mode,
|
||||||
args.candidate_order,
|
args.search_policy,
|
||||||
"direct" if args.direct_search else "public",
|
"direct" if args.direct_search else "public",
|
||||||
args.timeout,
|
args.timeout,
|
||||||
)
|
)
|
||||||
@@ -262,7 +263,7 @@ def main():
|
|||||||
args.binary,
|
args.binary,
|
||||||
order,
|
order,
|
||||||
mode,
|
mode,
|
||||||
args.candidate_order,
|
args.search_policy,
|
||||||
"direct" if args.direct_search else "public",
|
"direct" if args.direct_search else "public",
|
||||||
args.timeout,
|
args.timeout,
|
||||||
)
|
)
|
||||||
@@ -290,7 +291,7 @@ def main():
|
|||||||
"warmup_runs": args.warmup,
|
"warmup_runs": args.warmup,
|
||||||
"measured_repetitions": args.repetitions,
|
"measured_repetitions": args.repetitions,
|
||||||
"per_run_timeout_seconds": args.timeout,
|
"per_run_timeout_seconds": args.timeout,
|
||||||
"candidate_order": args.candidate_order,
|
"candidate_order": args.search_policy,
|
||||||
"search_route": "direct" if args.direct_search else "public",
|
"search_route": "direct" if args.direct_search else "public",
|
||||||
"stdout": "captured; rendered grid suppressed by probe",
|
"stdout": "captured; rendered grid suppressed by probe",
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -154,9 +154,12 @@ namespace {
|
|||||||
size_t completed_tasks = 0;
|
size_t completed_tasks = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class CandidateOrder {
|
/** Deterministic order in which a skyline node tries fitting squares. */
|
||||||
|
enum class SearchPolicy {
|
||||||
ascending,
|
ascending,
|
||||||
descending,
|
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. */
|
/** A maximal level skyline segment which is lower than its neighbours. */
|
||||||
@@ -199,7 +202,7 @@ namespace {
|
|||||||
|
|
||||||
template<bool Instrument>
|
template<bool Instrument>
|
||||||
auto search_skyline(size_t const n, size_t const length,
|
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<size_t> &skyline, Avail &available,
|
||||||
std::vector<Square> &squares,
|
std::vector<Square> &squares,
|
||||||
SearchCounters *const counters) noexcept -> bool {
|
SearchCounters *const counters) noexcept -> bool {
|
||||||
@@ -231,7 +234,7 @@ namespace {
|
|||||||
side, valley.height + side);
|
side, valley.height + side);
|
||||||
squares.emplace_back(valley.x + valley.height * length, 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)) {
|
available, squares, counters)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -246,8 +249,15 @@ namespace {
|
|||||||
return false;
|
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) {
|
for (size_t side = 1; side <= largest; ++side) {
|
||||||
|
if (policy == SearchPolicy::best_fit && side == valley.width) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (try_side(side)) {
|
if (try_side(side)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -272,7 +282,7 @@ namespace {
|
|||||||
* O(board width + n^2) local work per node and the same total state.
|
* O(board width + n^2) local work per node and the same total state.
|
||||||
*/
|
*/
|
||||||
template<bool Instrument>
|
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
|
SearchCounters *const counters) noexcept
|
||||||
-> Results {
|
-> Results {
|
||||||
auto const length = triangle_num(n);
|
auto const length = triangle_num(n);
|
||||||
@@ -284,25 +294,25 @@ namespace {
|
|||||||
std::vector<Square> squares;
|
std::vector<Square> squares;
|
||||||
squares.reserve(length);
|
squares.reserve(length);
|
||||||
static_cast<void>(search_skyline<Instrument>(
|
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)};
|
return {length, std::move(squares)};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto search_solution(
|
auto search_solution(
|
||||||
size_t const n,
|
size_t const n,
|
||||||
CandidateOrder const candidate_order = CandidateOrder::ascending) noexcept
|
SearchPolicy const policy = SearchPolicy::ascending) noexcept
|
||||||
-> Results {
|
-> 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,
|
auto search_solution_instrumented(size_t const n,
|
||||||
SearchCounters &counters,
|
SearchCounters &counters,
|
||||||
CandidateOrder const candidate_order =
|
SearchPolicy const policy =
|
||||||
CandidateOrder::ascending) noexcept
|
SearchPolicy::ascending) noexcept
|
||||||
-> Results {
|
-> Results {
|
||||||
counters = {};
|
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. */
|
/** Construct an odd-order solution from its even-order predecessor. */
|
||||||
@@ -335,20 +345,25 @@ namespace {
|
|||||||
return n >= 9 && n % 2 == 1;
|
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)) {
|
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,
|
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)) {
|
if (uses_odd_construction(n)) {
|
||||||
return construct_odd_solution(
|
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
|
} // anon namespace
|
||||||
|
|
||||||
|
|||||||
+20
-4
@@ -249,8 +249,10 @@ namespace {
|
|||||||
auto test_odd_solver_route() -> int {
|
auto test_odd_solver_route() -> int {
|
||||||
SearchCounters even_counters;
|
SearchCounters even_counters;
|
||||||
SearchCounters odd_counters;
|
SearchCounters odd_counters;
|
||||||
auto const even = find_solution_instrumented(8, even_counters);
|
auto const even =
|
||||||
auto const odd = find_solution_instrumented(9, odd_counters);
|
find_solution_instrumented(8, even_counters, SearchPolicy::best_fit);
|
||||||
|
auto const odd =
|
||||||
|
find_solution_instrumented(9, odd_counters, SearchPolicy::best_fit);
|
||||||
|
|
||||||
int failures = 0;
|
int failures = 0;
|
||||||
failures += expect(
|
failures += expect(
|
||||||
@@ -358,7 +360,7 @@ namespace {
|
|||||||
|
|
||||||
SearchCounters descending_counters;
|
SearchCounters descending_counters;
|
||||||
auto const descending = search_solution_instrumented(
|
auto const descending = search_solution_instrumented(
|
||||||
8, descending_counters, CandidateOrder::descending);
|
8, descending_counters, SearchPolicy::descending);
|
||||||
auto validation = validate(8, descending);
|
auto validation = validate(8, descending);
|
||||||
failures += expect(
|
failures += expect(
|
||||||
validation.valid(),
|
validation.valid(),
|
||||||
@@ -367,7 +369,7 @@ namespace {
|
|||||||
|
|
||||||
SearchCounters direct_nine_counters;
|
SearchCounters direct_nine_counters;
|
||||||
auto const direct_nine = search_solution_instrumented(
|
auto const direct_nine = search_solution_instrumented(
|
||||||
9, direct_nine_counters, CandidateOrder::ascending);
|
9, direct_nine_counters, SearchPolicy::ascending);
|
||||||
validation = validate(9, direct_nine);
|
validation = validate(9, direct_nine);
|
||||||
failures += expect(
|
failures += expect(
|
||||||
validation.valid(),
|
validation.valid(),
|
||||||
@@ -376,6 +378,20 @@ namespace {
|
|||||||
failures += expect(
|
failures += expect(
|
||||||
direct_nine_counters.search_nodes != descending_counters.search_nodes,
|
direct_nine_counters.search_nodes != descending_counters.search_nodes,
|
||||||
"direct order-9 coverage unexpectedly reused predecessor construction");
|
"direct order-9 coverage unexpectedly reused predecessor construction");
|
||||||
|
|
||||||
|
SearchCounters ascending_exhaustive;
|
||||||
|
SearchCounters descending_exhaustive;
|
||||||
|
SearchCounters best_fit_exhaustive;
|
||||||
|
static_cast<void>(search_solution_instrumented(
|
||||||
|
5, ascending_exhaustive, SearchPolicy::ascending));
|
||||||
|
static_cast<void>(search_solution_instrumented(
|
||||||
|
5, descending_exhaustive, SearchPolicy::descending));
|
||||||
|
static_cast<void>(search_solution_instrumented(
|
||||||
|
5, best_fit_exhaustive, SearchPolicy::best_fit));
|
||||||
|
failures += expect(
|
||||||
|
ascending_exhaustive.search_nodes == descending_exhaustive.search_nodes &&
|
||||||
|
ascending_exhaustive.search_nodes == best_fit_exhaustive.search_nodes,
|
||||||
|
"candidate policy changed the exhaustive skyline search space");
|
||||||
return failures;
|
return failures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user