1use crate::graph_types::SimpleGraph;
7use crate::traits::{ConstraintSatisfactionProblem, Problem};
8use crate::types::{EnergyMode, LocalConstraint, LocalSolutionSize, ProblemSize, SolutionSize};
9use petgraph::graph::{NodeIndex, UnGraph};
10use petgraph::visit::EdgeRef;
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct IndependentSet<W = i32> {
38 graph: UnGraph<(), ()>,
40 weights: Vec<W>,
42}
43
44impl<W: Clone + Default> IndependentSet<W> {
45 pub fn new(num_vertices: usize, edges: Vec<(usize, usize)>) -> Self
51 where
52 W: From<i32>,
53 {
54 let mut graph = UnGraph::new_undirected();
55 for _ in 0..num_vertices {
56 graph.add_node(());
57 }
58 for (u, v) in edges {
59 graph.add_edge(NodeIndex::new(u), NodeIndex::new(v), ());
60 }
61 let weights = vec![W::from(1); num_vertices];
62 Self { graph, weights }
63 }
64
65 pub fn with_weights(num_vertices: usize, edges: Vec<(usize, usize)>, weights: Vec<W>) -> Self {
67 assert_eq!(
68 weights.len(),
69 num_vertices,
70 "weights length must match num_vertices"
71 );
72 let mut graph = UnGraph::new_undirected();
73 for _ in 0..num_vertices {
74 graph.add_node(());
75 }
76 for (u, v) in edges {
77 graph.add_edge(NodeIndex::new(u), NodeIndex::new(v), ());
78 }
79 Self { graph, weights }
80 }
81
82 pub fn num_vertices(&self) -> usize {
84 self.graph.node_count()
85 }
86
87 pub fn num_edges(&self) -> usize {
89 self.graph.edge_count()
90 }
91
92 pub fn edges(&self) -> Vec<(usize, usize)> {
94 self.graph
95 .edge_references()
96 .map(|e| (e.source().index(), e.target().index()))
97 .collect()
98 }
99
100 pub fn has_edge(&self, u: usize, v: usize) -> bool {
102 self.graph
103 .find_edge(NodeIndex::new(u), NodeIndex::new(v))
104 .is_some()
105 }
106
107 pub fn weights_ref(&self) -> &Vec<W> {
109 &self.weights
110 }
111}
112
113impl<W> Problem for IndependentSet<W>
114where
115 W: Clone + Default + PartialOrd + num_traits::Num + num_traits::Zero + std::ops::AddAssign + 'static,
116{
117 const NAME: &'static str = "IndependentSet";
118 type GraphType = SimpleGraph;
119 type Weight = W;
120 type Size = W;
121
122 fn num_variables(&self) -> usize {
123 self.graph.node_count()
124 }
125
126 fn num_flavors(&self) -> usize {
127 2 }
129
130 fn problem_size(&self) -> ProblemSize {
131 ProblemSize::new(vec![
132 ("num_vertices", self.graph.node_count()),
133 ("num_edges", self.graph.edge_count()),
134 ])
135 }
136
137 fn energy_mode(&self) -> EnergyMode {
138 EnergyMode::LargerSizeIsBetter }
140
141 fn solution_size(&self, config: &[usize]) -> SolutionSize<Self::Size> {
142 let is_valid = is_independent_set_config(&self.graph, config);
143 let mut total = W::zero();
144 for (i, &selected) in config.iter().enumerate() {
145 if selected == 1 {
146 total += self.weights[i].clone();
147 }
148 }
149 SolutionSize::new(total, is_valid)
150 }
151}
152
153impl<W> ConstraintSatisfactionProblem for IndependentSet<W>
154where
155 W: Clone + Default + PartialOrd + num_traits::Num + num_traits::Zero + std::ops::AddAssign + 'static,
156{
157 fn constraints(&self) -> Vec<LocalConstraint> {
158 self.graph
161 .edge_references()
162 .map(|e| {
163 LocalConstraint::new(
164 2,
165 vec![e.source().index(), e.target().index()],
166 vec![true, true, true, false], )
168 })
169 .collect()
170 }
171
172 fn objectives(&self) -> Vec<LocalSolutionSize<Self::Size>> {
173 self.weights
175 .iter()
176 .enumerate()
177 .map(|(i, w)| LocalSolutionSize::new(2, vec![i], vec![W::zero(), w.clone()]))
178 .collect()
179 }
180
181 fn weights(&self) -> Vec<Self::Size> {
182 self.weights.clone()
183 }
184
185 fn set_weights(&mut self, weights: Vec<Self::Size>) {
186 assert_eq!(weights.len(), self.num_variables());
187 self.weights = weights;
188 }
189
190 fn is_weighted(&self) -> bool {
191 if self.weights.is_empty() {
193 return false;
194 }
195 let first = &self.weights[0];
196 !self.weights.iter().all(|w| w == first)
197 }
198}
199
200fn is_independent_set_config(graph: &UnGraph<(), ()>, config: &[usize]) -> bool {
202 for edge in graph.edge_references() {
203 let u = edge.source().index();
204 let v = edge.target().index();
205 if config.get(u).copied().unwrap_or(0) == 1 && config.get(v).copied().unwrap_or(0) == 1 {
206 return false;
207 }
208 }
209 true
210}
211
212pub fn is_independent_set(
219 num_vertices: usize,
220 edges: &[(usize, usize)],
221 selected: &[bool],
222) -> bool {
223 if selected.len() != num_vertices {
224 return false;
225 }
226 for &(u, v) in edges {
227 if u < selected.len() && v < selected.len() && selected[u] && selected[v] {
228 return false;
229 }
230 }
231 true
232}
233
234#[cfg(test)]
235mod tests {
236 use super::*;
237 use crate::solvers::{BruteForce, Solver};
238
239 #[test]
240 fn test_independent_set_creation() {
241 let problem = IndependentSet::<i32>::new(4, vec![(0, 1), (1, 2), (2, 3)]);
242 assert_eq!(problem.num_vertices(), 4);
243 assert_eq!(problem.num_edges(), 3);
244 assert_eq!(problem.num_variables(), 4);
245 assert_eq!(problem.num_flavors(), 2);
246 }
247
248 #[test]
249 fn test_independent_set_with_weights() {
250 let problem = IndependentSet::with_weights(3, vec![(0, 1)], vec![1, 2, 3]);
251 assert_eq!(problem.weights(), vec![1, 2, 3]);
252 assert!(problem.is_weighted());
253 }
254
255 #[test]
256 fn test_independent_set_unweighted() {
257 let problem = IndependentSet::<i32>::new(3, vec![(0, 1)]);
258 assert!(!problem.is_weighted());
259 }
260
261 #[test]
262 fn test_has_edge() {
263 let problem = IndependentSet::<i32>::new(3, vec![(0, 1), (1, 2)]);
264 assert!(problem.has_edge(0, 1));
265 assert!(problem.has_edge(1, 0)); assert!(problem.has_edge(1, 2));
267 assert!(!problem.has_edge(0, 2));
268 }
269
270 #[test]
271 fn test_solution_size_valid() {
272 let problem = IndependentSet::<i32>::new(4, vec![(0, 1), (2, 3)]);
273
274 let sol = problem.solution_size(&[1, 0, 1, 0]);
276 assert!(sol.is_valid);
277 assert_eq!(sol.size, 2);
278
279 let sol = problem.solution_size(&[0, 1, 0, 1]);
281 assert!(sol.is_valid);
282 assert_eq!(sol.size, 2);
283 }
284
285 #[test]
286 fn test_solution_size_invalid() {
287 let problem = IndependentSet::<i32>::new(4, vec![(0, 1), (2, 3)]);
288
289 let sol = problem.solution_size(&[1, 1, 0, 0]);
291 assert!(!sol.is_valid);
292 assert_eq!(sol.size, 2);
293
294 let sol = problem.solution_size(&[0, 0, 1, 1]);
296 assert!(!sol.is_valid);
297 }
298
299 #[test]
300 fn test_solution_size_empty() {
301 let problem = IndependentSet::<i32>::new(3, vec![(0, 1), (1, 2)]);
302 let sol = problem.solution_size(&[0, 0, 0]);
303 assert!(sol.is_valid);
304 assert_eq!(sol.size, 0);
305 }
306
307 #[test]
308 fn test_weighted_solution() {
309 let problem = IndependentSet::with_weights(3, vec![(0, 1)], vec![10, 20, 30]);
310
311 let sol = problem.solution_size(&[0, 0, 1]);
313 assert!(sol.is_valid);
314 assert_eq!(sol.size, 30);
315
316 let sol = problem.solution_size(&[1, 0, 1]);
318 assert!(sol.is_valid);
319 assert_eq!(sol.size, 40);
320 }
321
322 #[test]
323 fn test_constraints() {
324 let problem = IndependentSet::<i32>::new(3, vec![(0, 1), (1, 2)]);
325 let constraints = problem.constraints();
326 assert_eq!(constraints.len(), 2); }
328
329 #[test]
330 fn test_objectives() {
331 let problem = IndependentSet::with_weights(3, vec![(0, 1)], vec![5, 10, 15]);
332 let objectives = problem.objectives();
333 assert_eq!(objectives.len(), 3); }
335
336 #[test]
337 fn test_brute_force_triangle() {
338 let problem = IndependentSet::<i32>::new(3, vec![(0, 1), (1, 2), (0, 2)]);
340 let solver = BruteForce::new();
341
342 let solutions = solver.find_best(&problem);
343 assert_eq!(solutions.len(), 3); for sol in &solutions {
346 assert_eq!(sol.iter().sum::<usize>(), 1);
347 }
348 }
349
350 #[test]
351 fn test_brute_force_path() {
352 let problem = IndependentSet::<i32>::new(4, vec![(0, 1), (1, 2), (2, 3)]);
354 let solver = BruteForce::new();
355
356 let solutions = solver.find_best(&problem);
357 for sol in &solutions {
359 let size: usize = sol.iter().sum();
360 assert_eq!(size, 2);
361 let sol_result = problem.solution_size(sol);
363 assert!(sol_result.is_valid);
364 }
365 }
366
367 #[test]
368 fn test_brute_force_weighted() {
369 let problem = IndependentSet::with_weights(3, vec![(0, 1), (1, 2)], vec![1, 100, 1]);
371 let solver = BruteForce::new();
372
373 let solutions = solver.find_best(&problem);
374 assert_eq!(solutions.len(), 1);
375 assert_eq!(solutions[0], vec![0, 1, 0]);
377 }
378
379 #[test]
380 fn test_is_independent_set_function() {
381 assert!(is_independent_set(3, &[(0, 1)], &[true, false, true]));
382 assert!(is_independent_set(3, &[(0, 1)], &[false, true, true]));
383 assert!(!is_independent_set(3, &[(0, 1)], &[true, true, false]));
384 assert!(is_independent_set(
385 3,
386 &[(0, 1), (1, 2)],
387 &[true, false, true]
388 ));
389 assert!(!is_independent_set(
390 3,
391 &[(0, 1), (1, 2)],
392 &[false, true, true]
393 ));
394 }
395
396 #[test]
397 fn test_problem_size() {
398 let problem = IndependentSet::<i32>::new(5, vec![(0, 1), (1, 2), (2, 3)]);
399 let size = problem.problem_size();
400 assert_eq!(size.get("num_vertices"), Some(5));
401 assert_eq!(size.get("num_edges"), Some(3));
402 }
403
404 #[test]
405 fn test_energy_mode() {
406 let problem = IndependentSet::<i32>::new(3, vec![(0, 1)]);
407 assert!(problem.energy_mode().is_maximization());
408 }
409
410 #[test]
411 fn test_edges() {
412 let problem = IndependentSet::<i32>::new(4, vec![(0, 1), (2, 3)]);
413 let edges = problem.edges();
414 assert_eq!(edges.len(), 2);
415 assert!(edges.contains(&(0, 1)) || edges.contains(&(1, 0)));
416 assert!(edges.contains(&(2, 3)) || edges.contains(&(3, 2)));
417 }
418
419 #[test]
420 fn test_set_weights() {
421 let mut problem = IndependentSet::<i32>::new(3, vec![(0, 1)]);
422 problem.set_weights(vec![5, 10, 15]);
423 assert_eq!(problem.weights(), vec![5, 10, 15]);
424 }
425
426 #[test]
427 fn test_empty_graph() {
428 let problem = IndependentSet::<i32>::new(3, vec![]);
429 let solver = BruteForce::new();
430
431 let solutions = solver.find_best(&problem);
432 assert_eq!(solutions.len(), 1);
433 assert_eq!(solutions[0], vec![1, 1, 1]);
435 }
436
437 #[test]
438 fn test_is_satisfied() {
439 let problem = IndependentSet::<i32>::new(3, vec![(0, 1), (1, 2)]);
440
441 assert!(problem.is_satisfied(&[1, 0, 1])); assert!(problem.is_satisfied(&[0, 1, 0])); assert!(!problem.is_satisfied(&[1, 1, 0])); assert!(!problem.is_satisfied(&[0, 1, 1])); }
446}