Skip to main content

Module search

Module search 

Source
Expand description

Unified monomorphized search kernel.

Tests: tests/solver.rs (general solve correctness), tests/solution_set_invariance.rs (solution-set property test).

One tree-search skeleton — [search] — parameterized by a zero-sized [SearchPolicy]. The policy decides the four things that actually differ between the crate’s search modes:

axis[Feasibility][BranchBound]
leaf actionrecord, stop at maxscore, keep best, never stop
node prunenoneoptimistic-bound cutoff
value orderraw domain ordercost-sorted

Every hook is #[inline] and every implementor is (near) zero-sized, so monomorphization inlines the whole policy — no dispatch cost, the same devirtualization the crate already applies to ConstraintEnum.

This kernel replaces the three near-verbatim recursive DFS functions that preceded it (backtrack_recurse, backjump_recurse, bb_recurse) whose propagate match, validity-check loop, and restore sweep were byte-identical. Undo now runs off the shared [Trail] (touched-variable list) rather than an O(num_vars) per-node sweep, and read-only state (weights, var_cids, adjacency) is borrowed rather than deep-cloned per solve.

§Waiver: this file stays whole (CLOSED)

At 504 LOC the module sits four lines over the file budget, and the two policies are visually fenced — a BranchBound-out split looks free. It isn’t. BranchBound impls [SearchPolicy] and calls [search], so extracting it to a sibling module forces trait SearchPolicy, fn search, and likely Step — all currently private kernel internals — to widen to pub(super). That re-widens three internals to buy a cosmetic file cut: an encapsulation regression inside an encapsulation pass. The single reason to change here is the one search skeleton; [Feasibility] and [BranchBound] are its co-designed leaves, not separable concerns. Waiver recorded, closed.