solver: add optional component-area pruning

Full-height skyline columns partition the remaining board. Add sound gcd and bounded subset-sum checks for the resulting component areas, with boundary-event and periodic benchmark schedules.

Keep the rules disabled by default because their small tree reductions do not recover their measured cost. Record the rejected default and scheduling evidence so it can be revisited only with new data.

Tests: Debug CTest (14 passed)

Tests: ASan+UBSan CTest (14 passed)

Refs: #13
This commit was merged in pull request #28.
This commit is contained in:
Codex instance
2026-07-31 08:40:39 +01:00
parent 220cec06a9
commit 39ff5cb340
6 changed files with 491 additions and 53 deletions
+32 -1
View File
@@ -80,7 +80,16 @@ def environment(binary):
def run_once(
binary, order, mode, search_policy, search_route, symmetry, pruning, timeout
binary,
order,
mode,
search_policy,
search_route,
symmetry,
pruning,
component_pruning,
component_schedule,
timeout,
):
started = time.monotonic()
try:
@@ -93,6 +102,8 @@ def run_once(
search_route,
symmetry,
pruning,
component_pruning,
component_schedule,
],
check=False,
capture_output=True,
@@ -249,6 +260,18 @@ def main():
action="store_true",
help="disable all pruning (compatibility alias for --pruning none)",
)
parser.add_argument(
"--component-pruning",
choices=("subset-sum", "gcd", "none"),
default="none",
help="select component-area pruning strength",
)
parser.add_argument(
"--component-schedule",
choices=("boundary", "periodic-8"),
default="boundary",
help="trigger component checks on boundaries or every eighth depth",
)
parser.add_argument(
"--measure-overhead",
action="store_true",
@@ -282,6 +305,8 @@ def main():
"direct" if args.direct_search else "public",
"none" if args.no_symmetry else "d4",
"none" if args.no_pruning else args.pruning,
"none" if args.no_pruning else args.component_pruning,
args.component_schedule,
args.timeout,
)
for trial in range(args.repetitions):
@@ -295,6 +320,8 @@ def main():
"direct" if args.direct_search else "public",
"none" if args.no_symmetry else "d4",
"none" if args.no_pruning else args.pruning,
"none" if args.no_pruning else args.component_pruning,
args.component_schedule,
args.timeout,
)
)
@@ -325,6 +352,10 @@ def main():
"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 args.pruning,
"component_pruning": (
"none" if args.no_pruning else args.component_pruning
),
"component_schedule": args.component_schedule,
"stdout": "captured; rendered grid suppressed by probe",
},
"cases": cases,