solver: prune insufficient valley capacity
A selected valley cannot admit a square wider than itself until it reaches the lower neighbouring rim. Reject states whose remaining narrow-square area cannot fill that strip, including width-one and width-two gaps. Keep an unpruned benchmark mode and dedicated counters so the rule remains independently measurable. Record the soundness argument and the measured default-on improvement. Tests: Debug CTest (12 passed) Tests: ASan+UBSan CTest (12 passed) Refs: #10
This commit was merged in pull request #26.
This commit is contained in:
+23
-5
@@ -29,6 +29,7 @@ namespace {
|
||||
auto solve(std::uint64_t order, bool instrument,
|
||||
SearchPolicy policy, bool direct_search,
|
||||
SymmetryBreaking symmetry,
|
||||
Pruning pruning,
|
||||
SearchCounters &counters)
|
||||
-> TimedSolution {
|
||||
auto const predecessor_order =
|
||||
@@ -37,8 +38,8 @@ namespace {
|
||||
auto predecessor =
|
||||
instrument
|
||||
? search_solution_instrumented(predecessor_order, counters,
|
||||
policy, symmetry)
|
||||
: search_solution(predecessor_order, policy, symmetry);
|
||||
policy, symmetry, pruning)
|
||||
: search_solution(predecessor_order, policy, symmetry, pruning);
|
||||
auto const search_end = Clock::now();
|
||||
|
||||
auto const construction_begin = Clock::now();
|
||||
@@ -94,10 +95,10 @@ namespace {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 3 || argc > 6) {
|
||||
if (argc < 3 || argc > 7) {
|
||||
std::cerr << "usage: partridge_benchmark ORDER counters|plain "
|
||||
"[ascending|descending|best-fit] [public|direct] "
|
||||
"[d4|none]\n";
|
||||
"[d4|none] [valley-capacity|none]\n";
|
||||
return 2;
|
||||
}
|
||||
auto const order = static_cast<std::uint64_t>(std::strtoull(argv[1], nullptr, 10));
|
||||
@@ -134,10 +135,20 @@ int main(int argc, char **argv) {
|
||||
std::cerr << "symmetry mode must be d4 or none\n";
|
||||
return 2;
|
||||
}
|
||||
auto const pruning =
|
||||
argc < 7 || std::string_view(argv[6]) == "valley-capacity"
|
||||
? Pruning::valley_capacity
|
||||
: Pruning::disabled;
|
||||
if (argc == 7 && std::string_view(argv[6]) != "valley-capacity" &&
|
||||
std::string_view(argv[6]) != "none") {
|
||||
std::cerr << "pruning mode must be valley-capacity or none\n";
|
||||
return 2;
|
||||
}
|
||||
|
||||
SearchCounters counters;
|
||||
auto timed =
|
||||
solve(order, instrument, policy, direct_search, symmetry, counters);
|
||||
solve(order, instrument, policy, direct_search, symmetry, pruning,
|
||||
counters);
|
||||
|
||||
auto const validation_begin = Clock::now();
|
||||
auto const validation_ok = valid(order, timed.result);
|
||||
@@ -165,6 +176,9 @@ int main(int argc, char **argv) {
|
||||
<< ",\"symmetry_breaking\":\""
|
||||
<< (symmetry == SymmetryBreaking::d4_unit_square ? "d4" : "none")
|
||||
<< "\""
|
||||
<< ",\"pruning\":\""
|
||||
<< (pruning == Pruning::valley_capacity ? "valley-capacity" : "none")
|
||||
<< "\""
|
||||
<< ",\"solved\":" << boolean(!timed.result.squares().empty())
|
||||
<< ",\"valid\":" << boolean(validation_ok)
|
||||
<< ",\"timing_seconds\":{\"solve\":" << timed.search_seconds
|
||||
@@ -177,6 +191,10 @@ int main(int argc, char **argv) {
|
||||
<< ",\"backtracks\":" << counters.backtracks
|
||||
<< ",\"prune_checks\":" << counters.prune_checks
|
||||
<< ",\"prune_hits\":" << counters.prune_hits
|
||||
<< ",\"valley_capacity_checks\":"
|
||||
<< counters.valley_capacity_checks
|
||||
<< ",\"valley_capacity_prunes\":"
|
||||
<< counters.valley_capacity_prunes
|
||||
<< ",\"generated_tasks\":" << counters.generated_tasks
|
||||
<< ",\"completed_tasks\":" << counters.completed_tasks << "}}\n";
|
||||
return validation_ok ? 0 : 1;
|
||||
|
||||
+10
-1
@@ -80,7 +80,7 @@ def environment(binary):
|
||||
|
||||
|
||||
def run_once(
|
||||
binary, order, mode, search_policy, search_route, symmetry, timeout
|
||||
binary, order, mode, search_policy, search_route, symmetry, pruning, timeout
|
||||
):
|
||||
started = time.monotonic()
|
||||
try:
|
||||
@@ -92,6 +92,7 @@ def run_once(
|
||||
search_policy,
|
||||
search_route,
|
||||
symmetry,
|
||||
pruning,
|
||||
],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
@@ -237,6 +238,11 @@ def main():
|
||||
action="store_true",
|
||||
help="disable unique-unit-square D4 symmetry breaking",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--no-pruning",
|
||||
action="store_true",
|
||||
help="disable valley-capacity pruning",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--measure-overhead",
|
||||
action="store_true",
|
||||
@@ -269,6 +275,7 @@ def main():
|
||||
args.search_policy,
|
||||
"direct" if args.direct_search else "public",
|
||||
"none" if args.no_symmetry else "d4",
|
||||
"none" if args.no_pruning else "valley-capacity",
|
||||
args.timeout,
|
||||
)
|
||||
for trial in range(args.repetitions):
|
||||
@@ -281,6 +288,7 @@ def main():
|
||||
args.search_policy,
|
||||
"direct" if args.direct_search else "public",
|
||||
"none" if args.no_symmetry else "d4",
|
||||
"none" if args.no_pruning else "valley-capacity",
|
||||
args.timeout,
|
||||
)
|
||||
)
|
||||
@@ -310,6 +318,7 @@ def main():
|
||||
"candidate_order": args.search_policy,
|
||||
"search_route": "direct" if args.direct_search else "public",
|
||||
"symmetry_breaking": "none" if args.no_symmetry else "d4",
|
||||
"pruning": "none" if args.no_pruning else "valley-capacity",
|
||||
"stdout": "captured; rendered grid suppressed by probe",
|
||||
},
|
||||
"cases": cases,
|
||||
|
||||
Reference in New Issue
Block a user