1use crate::graph_types::SimpleGraph;
7use crate::traits::Problem;
8use crate::types::{EnergyMode, ProblemSize, SolutionSize};
9use serde::{Deserialize, Serialize};
10use std::collections::HashSet;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct BicliqueCover {
37 left_size: usize,
39 right_size: usize,
41 edges: Vec<(usize, usize)>,
44 k: usize,
46}
47
48impl BicliqueCover {
49 pub fn new(left_size: usize, right_size: usize, edges: Vec<(usize, usize)>, k: usize) -> Self {
57 for &(l, r) in &edges {
59 assert!(
60 l < left_size,
61 "Left vertex {} out of bounds (max {})",
62 l,
63 left_size - 1
64 );
65 assert!(
66 r >= left_size && r < left_size + right_size,
67 "Right vertex {} out of bounds (should be in {}..{})",
68 r,
69 left_size,
70 left_size + right_size
71 );
72 }
73
74 Self {
75 left_size,
76 right_size,
77 edges,
78 k,
79 }
80 }
81
82 pub fn from_matrix(matrix: &[Vec<u8>], k: usize) -> Self {
86 let left_size = matrix.len();
87 let right_size = if left_size > 0 { matrix[0].len() } else { 0 };
88
89 let mut edges = Vec::new();
90 for (i, row) in matrix.iter().enumerate() {
91 for (j, &val) in row.iter().enumerate() {
92 if val != 0 {
93 edges.push((i, left_size + j));
94 }
95 }
96 }
97
98 Self {
99 left_size,
100 right_size,
101 edges,
102 k,
103 }
104 }
105
106 pub fn num_vertices(&self) -> usize {
108 self.left_size + self.right_size
109 }
110
111 pub fn num_edges(&self) -> usize {
113 self.edges.len()
114 }
115
116 pub fn k(&self) -> usize {
118 self.k
119 }
120
121 fn get_biclique_memberships(
127 &self,
128 config: &[usize],
129 ) -> (Vec<HashSet<usize>>, Vec<HashSet<usize>>) {
130 let n = self.num_vertices();
131 let mut left_bicliques: Vec<HashSet<usize>> = vec![HashSet::new(); self.k];
132 let mut right_bicliques: Vec<HashSet<usize>> = vec![HashSet::new(); self.k];
133
134 for v in 0..n {
135 for b in 0..self.k {
136 let idx = v * self.k + b;
137 if config.get(idx).copied().unwrap_or(0) == 1 {
138 if v < self.left_size {
139 left_bicliques[b].insert(v);
140 } else {
141 right_bicliques[b].insert(v);
142 }
143 }
144 }
145 }
146
147 (left_bicliques, right_bicliques)
148 }
149
150 fn is_edge_covered(&self, left: usize, right: usize, config: &[usize]) -> bool {
152 let (left_bicliques, right_bicliques) = self.get_biclique_memberships(config);
153
154 for b in 0..self.k {
156 if left_bicliques[b].contains(&left) && right_bicliques[b].contains(&right) {
157 return true;
158 }
159 }
160 false
161 }
162
163 pub fn is_valid_cover(&self, config: &[usize]) -> bool {
165 self.edges
166 .iter()
167 .all(|&(l, r)| self.is_edge_covered(l, r, config))
168 }
169
170 pub fn count_covered_edges(&self, config: &[usize]) -> usize {
172 self.edges
173 .iter()
174 .filter(|&&(l, r)| self.is_edge_covered(l, r, config))
175 .count()
176 }
177
178 pub fn total_biclique_size(&self, config: &[usize]) -> usize {
180 config.iter().filter(|&&x| x == 1).count()
181 }
182}
183
184impl Problem for BicliqueCover {
185 const NAME: &'static str = "BicliqueCover";
186 type GraphType = SimpleGraph;
187 type Weight = i32;
188 type Size = i32;
189
190 fn num_variables(&self) -> usize {
191 self.num_vertices() * self.k
193 }
194
195 fn num_flavors(&self) -> usize {
196 2 }
198
199 fn problem_size(&self) -> ProblemSize {
200 ProblemSize::new(vec![
201 ("left_size", self.left_size),
202 ("right_size", self.right_size),
203 ("num_edges", self.edges.len()),
204 ("k", self.k),
205 ])
206 }
207
208 fn energy_mode(&self) -> EnergyMode {
209 EnergyMode::SmallerSizeIsBetter }
211
212 fn solution_size(&self, config: &[usize]) -> SolutionSize<Self::Size> {
213 let is_valid = self.is_valid_cover(config);
214 let size = self.total_biclique_size(config) as i32;
215 SolutionSize::new(size, is_valid)
216 }
217}
218
219pub fn is_biclique_cover(
221 edges: &[(usize, usize)],
222 left_bicliques: &[HashSet<usize>],
223 right_bicliques: &[HashSet<usize>],
224) -> bool {
225 edges.iter().all(|&(l, r)| {
226 left_bicliques
227 .iter()
228 .zip(right_bicliques.iter())
229 .any(|(lb, rb)| lb.contains(&l) && rb.contains(&r))
230 })
231}
232
233#[cfg(test)]
234mod tests {
235 use super::*;
236 use crate::solvers::{BruteForce, Solver};
237
238 #[test]
239 fn test_biclique_cover_creation() {
240 let problem = BicliqueCover::new(2, 2, vec![(0, 2), (0, 3), (1, 2)], 2);
241 assert_eq!(problem.num_vertices(), 4);
242 assert_eq!(problem.num_edges(), 3);
243 assert_eq!(problem.k(), 2);
244 assert_eq!(problem.num_variables(), 8); }
246
247 #[test]
248 fn test_from_matrix() {
249 let matrix = vec![vec![1, 1], vec![1, 0]];
254 let problem = BicliqueCover::from_matrix(&matrix, 2);
255 assert_eq!(problem.num_vertices(), 4);
256 assert_eq!(problem.num_edges(), 3);
257 }
258
259 #[test]
260 fn test_get_biclique_memberships() {
261 let problem = BicliqueCover::new(2, 2, vec![(0, 2)], 1);
262 let config = vec![1, 0, 1, 0];
265 let (left, right) = problem.get_biclique_memberships(&config);
266 assert!(left[0].contains(&0));
267 assert!(!left[0].contains(&1));
268 assert!(right[0].contains(&2));
269 assert!(!right[0].contains(&3));
270 }
271
272 #[test]
273 fn test_is_edge_covered() {
274 let problem = BicliqueCover::new(2, 2, vec![(0, 2)], 1);
275 let config = vec![1, 0, 1, 0];
277 assert!(problem.is_edge_covered(0, 2, &config));
278
279 let config = vec![1, 0, 0, 0];
281 assert!(!problem.is_edge_covered(0, 2, &config));
282 }
283
284 #[test]
285 fn test_is_valid_cover() {
286 let problem = BicliqueCover::new(2, 2, vec![(0, 2), (0, 3)], 1);
287 let config = vec![1, 0, 1, 1];
289 assert!(problem.is_valid_cover(&config));
290
291 let config = vec![1, 0, 1, 0];
293 assert!(!problem.is_valid_cover(&config));
294 }
295
296 #[test]
297 fn test_solution_size() {
298 let problem = BicliqueCover::new(2, 2, vec![(0, 2)], 1);
299
300 let sol = problem.solution_size(&[1, 0, 1, 0]);
302 assert!(sol.is_valid);
303 assert_eq!(sol.size, 2);
304
305 let sol = problem.solution_size(&[1, 0, 0, 0]);
307 assert!(!sol.is_valid);
308 assert_eq!(sol.size, 1);
309 }
310
311 #[test]
312 fn test_brute_force_simple() {
313 let problem = BicliqueCover::new(2, 2, vec![(0, 2)], 1);
315 let solver = BruteForce::new();
316
317 let solutions = solver.find_best(&problem);
318 for sol in &solutions {
319 assert!(problem.is_valid_cover(sol));
320 assert_eq!(problem.total_biclique_size(sol), 2);
322 }
323 }
324
325 #[test]
326 fn test_brute_force_two_bicliques() {
327 let problem = BicliqueCover::new(2, 2, vec![(0, 2), (1, 3)], 2);
330 let solver = BruteForce::new();
331
332 let solutions = solver.find_best(&problem);
333 for sol in &solutions {
334 assert!(problem.is_valid_cover(sol));
335 }
336 }
337
338 #[test]
339 fn test_count_covered_edges() {
340 let problem = BicliqueCover::new(2, 2, vec![(0, 2), (0, 3), (1, 2)], 1);
341 let config = vec![1, 0, 1, 0];
343 assert_eq!(problem.count_covered_edges(&config), 1);
344
345 let config = vec![1, 0, 1, 1];
347 assert_eq!(problem.count_covered_edges(&config), 2);
348 }
349
350 #[test]
351 fn test_is_biclique_cover_function() {
352 let edges = vec![(0, 2), (1, 3)];
353 let left = vec![vec![0].into_iter().collect(), vec![1].into_iter().collect()];
354 let right = vec![vec![2].into_iter().collect(), vec![3].into_iter().collect()];
355 assert!(is_biclique_cover(&edges, &left, &right));
356
357 let left = vec![vec![0].into_iter().collect()];
359 let right = vec![vec![2].into_iter().collect()];
360 assert!(!is_biclique_cover(&edges, &left, &right));
361 }
362
363 #[test]
364 fn test_energy_mode() {
365 let problem = BicliqueCover::new(1, 1, vec![(0, 1)], 1);
366 assert!(problem.energy_mode().is_minimization());
367 }
368
369 #[test]
370 fn test_problem_size() {
371 let problem = BicliqueCover::new(3, 4, vec![(0, 3), (1, 4)], 2);
372 let size = problem.problem_size();
373 assert_eq!(size.get("left_size"), Some(3));
374 assert_eq!(size.get("right_size"), Some(4));
375 assert_eq!(size.get("num_edges"), Some(2));
376 assert_eq!(size.get("k"), Some(2));
377 }
378
379 #[test]
380 fn test_empty_edges() {
381 let problem = BicliqueCover::new(2, 2, vec![], 1);
382 let sol = problem.solution_size(&[0, 0, 0, 0]);
383 assert!(sol.is_valid); assert_eq!(sol.size, 0);
385 }
386}