Skip to content

Commit 7bbd90b

Browse files
GiggleLiuclaude
andauthored
Reduce exported functions (closes #77) (#80)
* refactor: internalize reduction structs and gadgets in rules module Remove public re-exports of ~30 ReductionXToY structs, 6 gadget functions, BoolVar, LogicGadget, and JSON serialization types (EdgeJson, NodeJson, ReductionGraphJson) from rules/mod.rs. Users interact with reductions via the ReduceTo trait or ReductionGraph, never referencing these structs by name. Also remove unused ReductionColoringToILP type alias and suppress dead_code warnings on LogicGadget fields only read in tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: internalize unitdiskmapping implementation details Change internal type re-exports (CopyLine, MappingGrid, CellState, Pattern, etc.) from pub to pub(crate) in unitdiskmapping/mod.rs. Change alpha_tensor and pathdecomposition modules to pub(crate). Add #[cfg(test)] guards on re-exports only needed by unit tests. Add #[doc(hidden)] _internal module for the export_mapping_stages example which needs these types. Keep ksg, triangular modules and GridKind/MappingResult as pub. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: internalize polynomial/truth_table, delete unused graph_types module - Change polynomial and truth_table modules from pub to pub(crate) since they are only used internally via crate:: imports. - Delete graph_types.rs and its unit test file (zero internal imports, confirmed by codebase audit; actual graph types live in topology/). - Remove truth_table integration tests from tests/suites/reductions.rs (equivalent coverage exists in src/unit_tests/truth_table.rs). - Remove doc example from TruthTable since the module is now internal. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add is_valid_solution methods to graph problem types Add public is_valid_solution(&self, config: &[usize]) -> bool methods to all graph problem types, delegating to existing private validation helpers. Also add cut_size method to MaxCut for computing partition cut sizes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * feat: add is_valid_solution methods to set and specialized problems Add public is_valid_solution methods to MaximumSetPacking, MinimumSetCovering, BicliqueCover, CircuitSAT, and Factoring. Each delegates to existing validation logic. PaintShop already has count_switches and BMF is skipped per design. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: internalize validation free functions, keep as problem methods Change standalone validation free functions (is_independent_set, is_vertex_cover, is_clique, etc.) from pub to pub(crate) with #[cfg(test)] for test-only functions. Functions still used in non-test code (is_valid_coloring, is_hamiltonian_cycle, cut_size) remain pub(crate) without #[cfg(test)]. - Change 17 validation functions from pub to pub(crate) - Add #[cfg(test)] to 14 functions only used in tests - Remove validation function re-exports from graph/set/specialized mod.rs - Make submodules pub(crate) for crate-internal test access - Update graph_models.rs imports to use full module paths Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: internalize config_to_bits and bits_to_config Change these utility functions from pub to pub(crate) with #[cfg(test)] since they are only used in unit tests. This reduces the public API surface of the config module. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * refactor: slim down prelude to essential items Remove from prelude: config utilities, registry types, variant types, ILP/optimization internals, NumericSize, and WeightElement. These items remain accessible via their full module paths. Add explicit imports to 16 examples, 2 integration test files that previously relied on the broader prelude: - ILP type: 13 examples + 1 test file - K3/K2 variant types: 7 examples + 2 test files - LinearConstraint/ObjectiveSense: 1 example + 1 test file Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: restore PlanarGraph and BipartiteGraph VariantParam tests These tests were dropped when graph_types.rs was deleted but had no equivalent coverage elsewhere. Added them to variant.rs where similar graph type VariantParam tests already exist. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add is_valid_solution and cut_size method tests Cover all 15 new public methods with both valid and invalid cases: - 14 is_valid_solution tests across all problem types - 1 cut_size method test for MaxCut Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent eb92e0a commit 7bbd90b

17 files changed

Lines changed: 188 additions & 3 deletions

src/unit_tests/models/graph/kcoloring.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,3 +178,13 @@ fn test_jl_parity_evaluation() {
178178
assert_eq!(rust_sat, jl_best, "KColoring satisfying solutions mismatch");
179179
}
180180
}
181+
182+
#[test]
183+
fn test_is_valid_solution() {
184+
// Path graph: 0-1-2, 3-coloring
185+
let problem = KColoring::<K3, _>::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)]));
186+
// Valid: neighbors have different colors
187+
assert!(problem.is_valid_solution(&[0, 1, 0]));
188+
// Invalid: adjacent vertices 0 and 1 have same color
189+
assert!(!problem.is_valid_solution(&[0, 0, 1]));
190+
}

src/unit_tests/models/graph/max_cut.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,3 +128,12 @@ fn test_jl_parity_evaluation() {
128128
assert_eq!(rust_best, jl_best, "MaxCut best solutions mismatch");
129129
}
130130
}
131+
132+
#[test]
133+
fn test_cut_size_method() {
134+
let problem = MaxCut::new(SimpleGraph::new(3, vec![(0, 1), (1, 2), (0, 2)]), vec![1, 2, 3]);
135+
// Partition {0} vs {1, 2}: cuts edges (0,1)=1 and (0,2)=3
136+
assert_eq!(problem.cut_size(&[0, 1, 1]), 4);
137+
// All same partition: no edges cut
138+
assert_eq!(problem.cut_size(&[0, 0, 0]), 0);
139+
}

src/unit_tests/models/graph/maximal_is.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,13 @@ fn test_jl_parity_evaluation() {
163163
assert_eq!(rust_best, jl_best, "MaximalIS best solutions mismatch");
164164
}
165165
}
166+
167+
#[test]
168+
fn test_is_valid_solution() {
169+
// Path graph: 0-1-2
170+
let problem = MaximalIS::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)]), vec![1i32; 3]);
171+
// Valid: {0, 2} is maximal (independent and no vertex can be added)
172+
assert!(problem.is_valid_solution(&[1, 0, 1]));
173+
// Invalid: {0} is independent but not maximal (vertex 2 can be added)
174+
assert!(!problem.is_valid_solution(&[1, 0, 0]));
175+
}

src/unit_tests/models/graph/maximum_clique.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,3 +269,18 @@ fn test_clique_problem() {
269269
assert_eq!(p.evaluate(&[1, 0, 0]), SolutionSize::Valid(1));
270270
assert_eq!(p.direction(), Direction::Maximize);
271271
}
272+
273+
#[test]
274+
fn test_is_valid_solution() {
275+
// Triangle: 0-1-2 all connected
276+
let problem = MaximumClique::new(
277+
SimpleGraph::new(3, vec![(0, 1), (1, 2), (0, 2)]),
278+
vec![1i32; 3],
279+
);
280+
// Valid: all three form a clique
281+
assert!(problem.is_valid_solution(&[1, 1, 1]));
282+
// Now path graph: 0-1-2 (no 0-2 edge)
283+
let problem2 = MaximumClique::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)]), vec![1i32; 3]);
284+
// Invalid: {0, 2} not adjacent
285+
assert!(!problem2.is_valid_solution(&[1, 0, 1]));
286+
}

src/unit_tests/models/graph/maximum_independent_set.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,13 @@ fn test_jl_parity_evaluation() {
161161
assert_eq!(rust_best, jl_best, "IS best solutions mismatch");
162162
}
163163
}
164+
165+
#[test]
166+
fn test_is_valid_solution() {
167+
// Path graph: 0-1-2
168+
let problem = MaximumIndependentSet::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)]), vec![1i32; 3]);
169+
// Valid: {0, 2} is independent
170+
assert!(problem.is_valid_solution(&[1, 0, 1]));
171+
// Invalid: {0, 1} are adjacent
172+
assert!(!problem.is_valid_solution(&[1, 1, 0]));
173+
}

src/unit_tests/models/graph/maximum_matching.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,3 +153,16 @@ fn test_jl_parity_evaluation() {
153153
assert_eq!(rust_best, jl_best, "Matching best solutions mismatch");
154154
}
155155
}
156+
157+
#[test]
158+
fn test_is_valid_solution() {
159+
// Triangle: edges (0,1), (1,2), (0,2) — config is per edge
160+
let problem = MaximumMatching::new(
161+
SimpleGraph::new(3, vec![(0, 1), (1, 2), (0, 2)]),
162+
vec![1i32; 3],
163+
);
164+
// Valid: select edge (0,1) only — no shared vertices
165+
assert!(problem.is_valid_solution(&[1, 0, 0]));
166+
// Invalid: select edges (0,1) and (1,2) — vertex 1 shared
167+
assert!(!problem.is_valid_solution(&[1, 1, 0]));
168+
}

src/unit_tests/models/graph/minimum_dominating_set.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,3 +158,13 @@ fn test_jl_parity_evaluation() {
158158
assert_eq!(rust_best, jl_best, "DS best solutions mismatch");
159159
}
160160
}
161+
162+
#[test]
163+
fn test_is_valid_solution() {
164+
// Path graph: 0-1-2
165+
let problem = MinimumDominatingSet::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)]), vec![1i32; 3]);
166+
// Valid: {1} dominates all vertices (0 and 2 are neighbors of 1)
167+
assert!(problem.is_valid_solution(&[0, 1, 0]));
168+
// Invalid: {0} doesn't dominate vertex 2
169+
assert!(!problem.is_valid_solution(&[1, 0, 0]));
170+
}

src/unit_tests/models/graph/minimum_vertex_cover.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,13 @@ fn test_jl_parity_evaluation() {
144144
assert_eq!(rust_best, jl_best, "VC best solutions mismatch");
145145
}
146146
}
147+
148+
#[test]
149+
fn test_is_valid_solution() {
150+
// Path graph: 0-1-2
151+
let problem = MinimumVertexCover::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)]), vec![1i32; 3]);
152+
// Valid: {1} covers both edges
153+
assert!(problem.is_valid_solution(&[0, 1, 0]));
154+
// Invalid: {0} doesn't cover edge (1,2)
155+
assert!(!problem.is_valid_solution(&[1, 0, 0]));
156+
}

src/unit_tests/models/graph/traveling_salesman.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,16 @@ fn test_brute_force_triangle_weighted() {
222222
assert_eq!(solutions[0], vec![1, 1, 1]);
223223
assert_eq!(problem.evaluate(&solutions[0]), SolutionSize::Valid(30));
224224
}
225+
226+
#[test]
227+
fn test_is_valid_solution() {
228+
// K3 triangle: edges (0,1), (0,2), (1,2) — config is per edge
229+
let problem = TravelingSalesman::new(
230+
SimpleGraph::new(3, vec![(0, 1), (0, 2), (1, 2)]),
231+
vec![1, 2, 3],
232+
);
233+
// Valid: select all 3 edges forms Hamiltonian cycle 0-1-2-0
234+
assert!(problem.is_valid_solution(&[1, 1, 1]));
235+
// Invalid: select only 2 edges — not a cycle
236+
assert!(!problem.is_valid_solution(&[1, 1, 0]));
237+
}

src/unit_tests/models/satisfiability/sat.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,16 @@ fn test_jl_parity_evaluation() {
194194
}
195195
}
196196
}
197+
198+
#[test]
199+
fn test_is_valid_solution() {
200+
// (x1 OR x2) AND (NOT x1 OR x3)
201+
let problem = Satisfiability::new(
202+
3,
203+
vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1, 3])],
204+
);
205+
// Valid: x1=F, x2=T, x3=T → (T) AND (T) = T
206+
assert!(problem.is_valid_solution(&[0, 1, 1]));
207+
// Invalid: x1=T, x2=F, x3=F → (T) AND (F) = F
208+
assert!(!problem.is_valid_solution(&[1, 0, 0]));
209+
}

0 commit comments

Comments
 (0)