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 VertexCovering<W = i32> {
38 graph: UnGraph<(), ()>,
40 weights: Vec<W>,
42}
43
44impl<W: Clone + Default> VertexCovering<W> {
45 pub fn new(num_vertices: usize, edges: Vec<(usize, usize)>) -> Self
47 where
48 W: From<i32>,
49 {
50 let mut graph = UnGraph::new_undirected();
51 for _ in 0..num_vertices {
52 graph.add_node(());
53 }
54 for (u, v) in edges {
55 graph.add_edge(NodeIndex::new(u), NodeIndex::new(v), ());
56 }
57 let weights = vec![W::from(1); num_vertices];
58 Self { graph, weights }
59 }
60
61 pub fn with_weights(num_vertices: usize, edges: Vec<(usize, usize)>, weights: Vec<W>) -> Self {
63 assert_eq!(weights.len(), num_vertices);
64 let mut graph = UnGraph::new_undirected();
65 for _ in 0..num_vertices {
66 graph.add_node(());
67 }
68 for (u, v) in edges {
69 graph.add_edge(NodeIndex::new(u), NodeIndex::new(v), ());
70 }
71 Self { graph, weights }
72 }
73
74 pub fn num_vertices(&self) -> usize {
76 self.graph.node_count()
77 }
78
79 pub fn num_edges(&self) -> usize {
81 self.graph.edge_count()
82 }
83
84 pub fn edges(&self) -> Vec<(usize, usize)> {
86 self.graph
87 .edge_references()
88 .map(|e| (e.source().index(), e.target().index()))
89 .collect()
90 }
91
92 pub fn weights_ref(&self) -> &Vec<W> {
94 &self.weights
95 }
96}
97
98impl<W> Problem for VertexCovering<W>
99where
100 W: Clone + Default + PartialOrd + num_traits::Num + num_traits::Zero + std::ops::AddAssign + 'static,
101{
102 const NAME: &'static str = "VertexCovering";
103 type GraphType = SimpleGraph;
104 type Weight = W;
105 type Size = W;
106
107 fn num_variables(&self) -> usize {
108 self.graph.node_count()
109 }
110
111 fn num_flavors(&self) -> usize {
112 2
113 }
114
115 fn problem_size(&self) -> ProblemSize {
116 ProblemSize::new(vec![
117 ("num_vertices", self.graph.node_count()),
118 ("num_edges", self.graph.edge_count()),
119 ])
120 }
121
122 fn energy_mode(&self) -> EnergyMode {
123 EnergyMode::SmallerSizeIsBetter }
125
126 fn solution_size(&self, config: &[usize]) -> SolutionSize<Self::Size> {
127 let is_valid = is_vertex_cover_config(&self.graph, config);
128 let mut total = W::zero();
129 for (i, &selected) in config.iter().enumerate() {
130 if selected == 1 {
131 total += self.weights[i].clone();
132 }
133 }
134 SolutionSize::new(total, is_valid)
135 }
136}
137
138impl<W> ConstraintSatisfactionProblem for VertexCovering<W>
139where
140 W: Clone + Default + PartialOrd + num_traits::Num + num_traits::Zero + std::ops::AddAssign + 'static,
141{
142 fn constraints(&self) -> Vec<LocalConstraint> {
143 self.graph
146 .edge_references()
147 .map(|e| {
148 LocalConstraint::new(
149 2,
150 vec![e.source().index(), e.target().index()],
151 vec![false, true, true, true], )
153 })
154 .collect()
155 }
156
157 fn objectives(&self) -> Vec<LocalSolutionSize<Self::Size>> {
158 self.weights
160 .iter()
161 .enumerate()
162 .map(|(i, w)| LocalSolutionSize::new(2, vec![i], vec![W::zero(), w.clone()]))
163 .collect()
164 }
165
166 fn weights(&self) -> Vec<Self::Size> {
167 self.weights.clone()
168 }
169
170 fn set_weights(&mut self, weights: Vec<Self::Size>) {
171 assert_eq!(weights.len(), self.num_variables());
172 self.weights = weights;
173 }
174
175 fn is_weighted(&self) -> bool {
176 if self.weights.is_empty() {
177 return false;
178 }
179 let first = &self.weights[0];
180 !self.weights.iter().all(|w| w == first)
181 }
182}
183
184fn is_vertex_cover_config(graph: &UnGraph<(), ()>, config: &[usize]) -> bool {
186 for edge in graph.edge_references() {
187 let u = edge.source().index();
188 let v = edge.target().index();
189 let u_covered = config.get(u).copied().unwrap_or(0) == 1;
190 let v_covered = config.get(v).copied().unwrap_or(0) == 1;
191 if !u_covered && !v_covered {
192 return false;
193 }
194 }
195 true
196}
197
198pub fn is_vertex_cover(num_vertices: usize, edges: &[(usize, usize)], selected: &[bool]) -> bool {
205 if selected.len() != num_vertices {
206 return false;
207 }
208 for &(u, v) in edges {
209 if u < selected.len() && v < selected.len() && !selected[u] && !selected[v] {
210 return false;
211 }
212 }
213 true
214}
215
216#[cfg(test)]
217mod tests {
218 use super::*;
219 use crate::solvers::{BruteForce, Solver};
220
221 #[test]
222 fn test_vertex_cover_creation() {
223 let problem = VertexCovering::<i32>::new(4, vec![(0, 1), (1, 2), (2, 3)]);
224 assert_eq!(problem.num_vertices(), 4);
225 assert_eq!(problem.num_edges(), 3);
226 assert_eq!(problem.num_variables(), 4);
227 assert_eq!(problem.num_flavors(), 2);
228 }
229
230 #[test]
231 fn test_vertex_cover_with_weights() {
232 let problem = VertexCovering::with_weights(3, vec![(0, 1)], vec![1, 2, 3]);
233 assert_eq!(problem.weights(), vec![1, 2, 3]);
234 assert!(problem.is_weighted());
235 }
236
237 #[test]
238 fn test_solution_size_valid() {
239 let problem = VertexCovering::<i32>::new(3, vec![(0, 1), (1, 2)]);
240
241 let sol = problem.solution_size(&[0, 1, 0]);
243 assert!(sol.is_valid);
244 assert_eq!(sol.size, 1);
245
246 let sol = problem.solution_size(&[1, 1, 1]);
248 assert!(sol.is_valid);
249 assert_eq!(sol.size, 3);
250 }
251
252 #[test]
253 fn test_solution_size_invalid() {
254 let problem = VertexCovering::<i32>::new(3, vec![(0, 1), (1, 2)]);
255
256 let sol = problem.solution_size(&[0, 0, 0]);
258 assert!(!sol.is_valid);
259
260 let sol = problem.solution_size(&[1, 0, 0]);
262 assert!(!sol.is_valid);
263 }
264
265 #[test]
266 fn test_brute_force_path() {
267 let problem = VertexCovering::<i32>::new(3, vec![(0, 1), (1, 2)]);
269 let solver = BruteForce::new();
270
271 let solutions = solver.find_best(&problem);
272 assert_eq!(solutions.len(), 1);
273 assert_eq!(solutions[0], vec![0, 1, 0]);
274 }
275
276 #[test]
277 fn test_brute_force_triangle() {
278 let problem = VertexCovering::<i32>::new(3, vec![(0, 1), (1, 2), (0, 2)]);
280 let solver = BruteForce::new();
281
282 let solutions = solver.find_best(&problem);
283 assert_eq!(solutions.len(), 3);
285 for sol in &solutions {
286 assert_eq!(sol.iter().sum::<usize>(), 2);
287 assert!(problem.solution_size(sol).is_valid);
288 }
289 }
290
291 #[test]
292 fn test_brute_force_weighted() {
293 let problem = VertexCovering::with_weights(3, vec![(0, 1), (1, 2)], vec![100, 1, 100]);
295 let solver = BruteForce::new();
296
297 let solutions = solver.find_best(&problem);
298 assert_eq!(solutions.len(), 1);
299 assert_eq!(solutions[0], vec![0, 1, 0]);
301 }
302
303 #[test]
304 fn test_is_vertex_cover_function() {
305 assert!(is_vertex_cover(3, &[(0, 1), (1, 2)], &[false, true, false]));
306 assert!(is_vertex_cover(3, &[(0, 1), (1, 2)], &[true, false, true]));
307 assert!(!is_vertex_cover(
308 3,
309 &[(0, 1), (1, 2)],
310 &[true, false, false]
311 ));
312 assert!(!is_vertex_cover(
313 3,
314 &[(0, 1), (1, 2)],
315 &[false, false, false]
316 ));
317 }
318
319 #[test]
320 fn test_constraints() {
321 let problem = VertexCovering::<i32>::new(3, vec![(0, 1), (1, 2)]);
322 let constraints = problem.constraints();
323 assert_eq!(constraints.len(), 2);
324 }
325
326 #[test]
327 fn test_energy_mode() {
328 let problem = VertexCovering::<i32>::new(3, vec![(0, 1)]);
329 assert!(problem.energy_mode().is_minimization());
330 }
331
332 #[test]
333 fn test_empty_graph() {
334 let problem = VertexCovering::<i32>::new(3, vec![]);
335 let solver = BruteForce::new();
336
337 let solutions = solver.find_best(&problem);
338 assert_eq!(solutions.len(), 1);
340 assert_eq!(solutions[0], vec![0, 0, 0]);
341 }
342
343 #[test]
344 fn test_single_edge() {
345 let problem = VertexCovering::<i32>::new(2, vec![(0, 1)]);
346 let solver = BruteForce::new();
347
348 let solutions = solver.find_best(&problem);
349 assert_eq!(solutions.len(), 2);
351 }
352
353 #[test]
354 fn test_is_satisfied() {
355 let problem = VertexCovering::<i32>::new(3, vec![(0, 1), (1, 2)]);
356
357 assert!(problem.is_satisfied(&[0, 1, 0])); assert!(problem.is_satisfied(&[1, 0, 1])); assert!(!problem.is_satisfied(&[1, 0, 0])); assert!(!problem.is_satisfied(&[0, 0, 1])); }
362
363 #[test]
364 fn test_complement_relationship() {
365 use crate::models::graph::IndependentSet;
367
368 let edges = vec![(0, 1), (1, 2), (2, 3)];
369 let is_problem = IndependentSet::<i32>::new(4, edges.clone());
370 let vc_problem = VertexCovering::<i32>::new(4, edges);
371
372 let solver = BruteForce::new();
373
374 let is_solutions = solver.find_best(&is_problem);
375 for is_sol in &is_solutions {
376 let vc_config: Vec<usize> = is_sol.iter().map(|&x| 1 - x).collect();
378 assert!(vc_problem.solution_size(&vc_config).is_valid);
379 }
380 }
381
382 #[test]
383 fn test_objectives() {
384 let problem = VertexCovering::with_weights(3, vec![(0, 1)], vec![5, 10, 15]);
385 let objectives = problem.objectives();
386 assert_eq!(objectives.len(), 3);
387 }
388
389 #[test]
390 fn test_set_weights() {
391 let mut problem = VertexCovering::<i32>::new(3, vec![(0, 1)]);
392 assert!(!problem.is_weighted()); problem.set_weights(vec![1, 2, 3]);
394 assert!(problem.is_weighted());
395 assert_eq!(problem.weights(), vec![1, 2, 3]);
396 }
397
398 #[test]
399 fn test_is_weighted_empty() {
400 let problem = VertexCovering::<i32>::new(0, vec![]);
401 assert!(!problem.is_weighted());
402 }
403
404 #[test]
405 fn test_is_vertex_cover_wrong_len() {
406 assert!(!is_vertex_cover(3, &[(0, 1)], &[true, false]));
408 }
409}