You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The same evaluate() pattern (check constraint → sum weights → return SolutionSize::Valid(total))
Suggestion: Extract a VertexWeightedProblem<G, W> wrapper struct or a macro to share the common boilerplate. Each problem would only need to define its constraint check and optimization direction.
These manually implement VariantParam + inventory::submit! (12 lines each) — exactly what impl_variant_param! does. The macro currently requires a cast: closure for the parent: variant, which these ZST marker types can't meaningfully provide.
Suggestion: Add a parent-only (no cast) arm to impl_variant_param!:
Three trivial one-liner wrappers all calling is_subtype() with different category strings. Callers could use is_subtype("graph", ...) directly.
KISS Violations
1. find_shortest_path enumerates all paths
File:src/rules/graph.rs:542-553
Currently finds all simple paths (exponential) then picks the shortest. Dijkstra with MinimizeSteps cost already exists in the same file via find_cheapest_path.
2. Premature cost function zoo
File:src/rules/cost.rs
Defines 5 specialized cost structs plus CustomCost<F>. The closure-based CustomCost already handles any case. Unless the specific strategies are used in multiple call sites, most are speculative generality.
3. Double normalization of empty graph variant
variant_to_map() (src/rules/graph.rs:636-648) normalizes empty "graph" to "SimpleGraph". But source_graph() / target_graph() (lines 202-220) also do the same check. Same concern handled in two places.
4. to_json() is a 190-line monolith
File:src/rules/graph.rs:775-964
Single method doing 5 logically distinct things: collect nodes, collect edges, generate natural edges, sort, resolve indices. Could be split into helper methods.
Suggested Priority
DRY Roadmap #1 (vertex-weighted problem boilerplate) — highest impact, most error-prone
Summary
Code review of the
jg/variant-aware-pathsbranch identified several KISS (Keep It Simple) and DRY (Don't Repeat Yourself) violations worth addressing.DRY Violations
1. Massive boilerplate duplication across vertex-weighted graph problems
Impact: High — ~325 duplicated lines across 5 files.
These files share nearly identical struct shapes, constructors, and accessors:
src/models/graph/maximum_independent_set.rssrc/models/graph/minimum_vertex_cover.rssrc/models/graph/maximum_clique.rssrc/models/graph/maximal_is.rssrc/models/graph/minimum_dominating_set.rsEach repeats ~65 lines of identical code:
new(),with_weights(),from_graph(),from_graph_unit_weights()constructorsgraph(),num_vertices(),num_edges(),edges(),has_edge(),weights_ref(),set_weights(),weights(),is_weighted()accessorsevaluate()pattern (check constraint → sum weights → returnSolutionSize::Valid(total))Suggestion: Extract a
VertexWeightedProblem<G, W>wrapper struct or a macro to share the common boilerplate. Each problem would only need to define its constraint check and optimization direction.2.
PlanarGraph/BipartiteGraphmanualVariantParamimplsFile:
src/graph_types.rs:14-46These manually implement
VariantParam+inventory::submit!(12 lines each) — exactly whatimpl_variant_param!does. The macro currently requires acast:closure for theparent:variant, which these ZST marker types can't meaningfully provide.Suggestion: Add a
parent-only(no cast) arm toimpl_variant_param!:3.
source_graph()/target_graph()onReductionEdgeFile:
src/rules/graph.rs:202-220Two identical methods differing only in which field (
source_variant/target_variant) they search.Suggestion: Extract a single helper:
4.
graph_hierarchy()/weight_hierarchy()File:
src/rules/graph.rs:370-382Same pattern with duplicate
LazyLock<HashMap>statics, differing only in the category key.Suggestion: Replace with
fn hierarchy(&self, category: &str) -> &HashMap<...>.5.
is_graph_subtype()/is_weight_subtype()/is_k_subtype()File:
src/rules/graph.rs:355-367Three trivial one-liner wrappers all calling
is_subtype()with different category strings. Callers could useis_subtype("graph", ...)directly.KISS Violations
1.
find_shortest_pathenumerates all pathsFile:
src/rules/graph.rs:542-553Currently finds all simple paths (exponential) then picks the shortest. Dijkstra with
MinimizeStepscost already exists in the same file viafind_cheapest_path.2. Premature cost function zoo
File:
src/rules/cost.rsDefines 5 specialized cost structs plus
CustomCost<F>. The closure-basedCustomCostalready handles any case. Unless the specific strategies are used in multiple call sites, most are speculative generality.3. Double normalization of empty graph variant
variant_to_map()(src/rules/graph.rs:636-648) normalizes empty"graph"to"SimpleGraph". Butsource_graph()/target_graph()(lines 202-220) also do the same check. Same concern handled in two places.4.
to_json()is a 190-line monolithFile:
src/rules/graph.rs:775-964Single method doing 5 logically distinct things: collect nodes, collect edges, generate natural edges, sort, resolve indices. Could be split into helper methods.
Suggested Priority
to_json()) — readability