1use crate::graph_types::SimpleGraph;
7use crate::traits::{ConstraintSatisfactionProblem, Problem};
8use crate::types::{EnergyMode, LocalConstraint, LocalSolutionSize, ProblemSize, SolutionSize};
9use serde::{Deserialize, Serialize};
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub struct CNFClause {
22 pub literals: Vec<i32>,
24}
25
26impl CNFClause {
27 pub fn new(literals: Vec<i32>) -> Self {
32 Self { literals }
33 }
34
35 pub fn is_satisfied(&self, assignment: &[bool]) -> bool {
40 self.literals.iter().any(|&lit| {
41 let var = lit.unsigned_abs() as usize - 1; let value = assignment.get(var).copied().unwrap_or(false);
43 if lit > 0 {
44 value
45 } else {
46 !value
47 }
48 })
49 }
50
51 pub fn variables(&self) -> Vec<usize> {
53 self.literals
54 .iter()
55 .map(|&lit| lit.unsigned_abs() as usize - 1)
56 .collect()
57 }
58
59 pub fn len(&self) -> usize {
61 self.literals.len()
62 }
63
64 pub fn is_empty(&self) -> bool {
66 self.literals.is_empty()
67 }
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
103pub struct Satisfiability<W = i32> {
104 num_vars: usize,
106 clauses: Vec<CNFClause>,
108 weights: Vec<W>,
110}
111
112impl<W: Clone + Default> Satisfiability<W> {
113 pub fn new(num_vars: usize, clauses: Vec<CNFClause>) -> Self
115 where
116 W: From<i32>,
117 {
118 let num_clauses = clauses.len();
119 let weights = vec![W::from(1); num_clauses];
120 Self {
121 num_vars,
122 clauses,
123 weights,
124 }
125 }
126
127 pub fn with_weights(num_vars: usize, clauses: Vec<CNFClause>, weights: Vec<W>) -> Self {
129 assert_eq!(clauses.len(), weights.len());
130 Self {
131 num_vars,
132 clauses,
133 weights,
134 }
135 }
136
137 pub fn num_vars(&self) -> usize {
139 self.num_vars
140 }
141
142 pub fn num_clauses(&self) -> usize {
144 self.clauses.len()
145 }
146
147 pub fn clauses(&self) -> &[CNFClause] {
149 &self.clauses
150 }
151
152 pub fn get_clause(&self, index: usize) -> Option<&CNFClause> {
154 self.clauses.get(index)
155 }
156
157 pub fn count_satisfied(&self, assignment: &[bool]) -> usize {
159 self.clauses
160 .iter()
161 .filter(|c| c.is_satisfied(assignment))
162 .count()
163 }
164
165 pub fn is_satisfying(&self, assignment: &[bool]) -> bool {
167 self.clauses.iter().all(|c| c.is_satisfied(assignment))
168 }
169
170 fn config_to_assignment(config: &[usize]) -> Vec<bool> {
172 config.iter().map(|&v| v == 1).collect()
173 }
174}
175
176impl<W> Problem for Satisfiability<W>
177where
178 W: Clone + Default + PartialOrd + num_traits::Num + num_traits::Zero + std::ops::AddAssign + 'static,
179{
180 const NAME: &'static str = "Satisfiability";
181 type GraphType = SimpleGraph;
182 type Weight = W;
183 type Size = W;
184
185 fn num_variables(&self) -> usize {
186 self.num_vars
187 }
188
189 fn num_flavors(&self) -> usize {
190 2 }
192
193 fn problem_size(&self) -> ProblemSize {
194 ProblemSize::new(vec![
195 ("num_vars", self.num_vars),
196 ("num_clauses", self.clauses.len()),
197 ])
198 }
199
200 fn energy_mode(&self) -> EnergyMode {
201 EnergyMode::LargerSizeIsBetter
204 }
205
206 fn solution_size(&self, config: &[usize]) -> SolutionSize<Self::Size> {
207 let assignment = Self::config_to_assignment(config);
208 let is_valid = self.is_satisfying(&assignment);
209
210 let mut total = W::zero();
212 for (clause, weight) in self.clauses.iter().zip(&self.weights) {
213 if clause.is_satisfied(&assignment) {
214 total += weight.clone();
215 }
216 }
217
218 SolutionSize::new(total, is_valid)
219 }
220}
221
222impl<W> ConstraintSatisfactionProblem for Satisfiability<W>
223where
224 W: Clone + Default + PartialOrd + num_traits::Num + num_traits::Zero + std::ops::AddAssign + 'static,
225{
226 fn constraints(&self) -> Vec<LocalConstraint> {
227 self.clauses
229 .iter()
230 .map(|clause| {
231 let vars = clause.variables();
232 let num_configs = 2usize.pow(vars.len() as u32);
233
234 let spec: Vec<bool> = (0..num_configs)
236 .map(|config_idx| {
237 let local_assignment: Vec<bool> = (0..vars.len())
239 .map(|i| (config_idx >> (vars.len() - 1 - i)) & 1 == 1)
240 .collect();
241
242 let mut full_assignment = vec![false; self.num_vars];
244 for (i, &var) in vars.iter().enumerate() {
245 full_assignment[var] = local_assignment[i];
246 }
247
248 clause.is_satisfied(&full_assignment)
249 })
250 .collect();
251
252 LocalConstraint::new(2, vars, spec)
253 })
254 .collect()
255 }
256
257 fn objectives(&self) -> Vec<LocalSolutionSize<Self::Size>> {
258 self.clauses
260 .iter()
261 .zip(&self.weights)
262 .map(|(clause, weight)| {
263 let vars = clause.variables();
264 let num_configs = 2usize.pow(vars.len() as u32);
265
266 let spec: Vec<W> = (0..num_configs)
267 .map(|config_idx| {
268 let local_assignment: Vec<bool> = (0..vars.len())
269 .map(|i| (config_idx >> (vars.len() - 1 - i)) & 1 == 1)
270 .collect();
271
272 let mut full_assignment = vec![false; self.num_vars];
273 for (i, &var) in vars.iter().enumerate() {
274 full_assignment[var] = local_assignment[i];
275 }
276
277 if clause.is_satisfied(&full_assignment) {
278 weight.clone()
279 } else {
280 W::zero()
281 }
282 })
283 .collect();
284
285 LocalSolutionSize::new(2, vars, spec)
286 })
287 .collect()
288 }
289
290 fn weights(&self) -> Vec<Self::Size> {
291 self.weights.clone()
292 }
293
294 fn set_weights(&mut self, weights: Vec<Self::Size>) {
295 assert_eq!(weights.len(), self.clauses.len());
296 self.weights = weights;
297 }
298
299 fn is_weighted(&self) -> bool {
300 if self.weights.is_empty() {
301 return false;
302 }
303 let first = &self.weights[0];
304 !self.weights.iter().all(|w| w == first)
305 }
306}
307
308pub fn is_satisfying_assignment(
315 _num_vars: usize,
316 clauses: &[Vec<i32>],
317 assignment: &[bool],
318) -> bool {
319 clauses.iter().all(|clause| {
320 clause.iter().any(|&lit| {
321 let var = lit.unsigned_abs() as usize - 1;
322 let value = assignment.get(var).copied().unwrap_or(false);
323 if lit > 0 {
324 value
325 } else {
326 !value
327 }
328 })
329 })
330}
331
332#[cfg(test)]
333mod tests {
334 use super::*;
335 use crate::solvers::{BruteForce, Solver};
336
337 #[test]
338 fn test_cnf_clause_creation() {
339 let clause = CNFClause::new(vec![1, -2, 3]);
340 assert_eq!(clause.len(), 3);
341 assert!(!clause.is_empty());
342 assert_eq!(clause.variables(), vec![0, 1, 2]);
343 }
344
345 #[test]
346 fn test_cnf_clause_satisfaction() {
347 let clause = CNFClause::new(vec![1, 2]); assert!(clause.is_satisfied(&[true, false])); assert!(clause.is_satisfied(&[false, true])); assert!(clause.is_satisfied(&[true, true])); assert!(!clause.is_satisfied(&[false, false])); }
354
355 #[test]
356 fn test_cnf_clause_negation() {
357 let clause = CNFClause::new(vec![-1, 2]); assert!(clause.is_satisfied(&[false, false])); assert!(clause.is_satisfied(&[false, true])); assert!(clause.is_satisfied(&[true, true])); assert!(!clause.is_satisfied(&[true, false])); }
364
365 #[test]
366 fn test_sat_creation() {
367 let problem = Satisfiability::<i32>::new(
368 3,
369 vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1, 3])],
370 );
371 assert_eq!(problem.num_vars(), 3);
372 assert_eq!(problem.num_clauses(), 2);
373 assert_eq!(problem.num_variables(), 3);
374 }
375
376 #[test]
377 fn test_sat_with_weights() {
378 let problem = Satisfiability::with_weights(
379 2,
380 vec![CNFClause::new(vec![1]), CNFClause::new(vec![2])],
381 vec![5, 10],
382 );
383 assert_eq!(problem.weights(), vec![5, 10]);
384 assert!(problem.is_weighted());
385 }
386
387 #[test]
388 fn test_is_satisfying() {
389 let problem = Satisfiability::<i32>::new(
391 2,
392 vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1, -2])],
393 );
394
395 assert!(problem.is_satisfying(&[true, false])); assert!(problem.is_satisfying(&[false, true])); assert!(!problem.is_satisfying(&[true, true])); assert!(!problem.is_satisfying(&[false, false])); }
400
401 #[test]
402 fn test_count_satisfied() {
403 let problem = Satisfiability::<i32>::new(
404 2,
405 vec![CNFClause::new(vec![1]), CNFClause::new(vec![2]), CNFClause::new(vec![-1, -2])],
406 );
407
408 assert_eq!(problem.count_satisfied(&[true, true]), 2); assert_eq!(problem.count_satisfied(&[false, false]), 1); assert_eq!(problem.count_satisfied(&[true, false]), 2); }
412
413 #[test]
414 fn test_solution_size() {
415 let problem = Satisfiability::<i32>::new(
416 2,
417 vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1, -2])],
418 );
419
420 let sol = problem.solution_size(&[1, 0]); assert!(sol.is_valid);
422 assert_eq!(sol.size, 2); let sol = problem.solution_size(&[1, 1]); assert!(!sol.is_valid);
426 assert_eq!(sol.size, 1); }
428
429 #[test]
430 fn test_brute_force_satisfiable() {
431 let problem = Satisfiability::<i32>::new(
433 2,
434 vec![
435 CNFClause::new(vec![1]),
436 CNFClause::new(vec![2]),
437 CNFClause::new(vec![-1, -2]),
438 ],
439 );
440 let solver = BruteForce::new();
441
442 let solutions = solver.find_best(&problem);
443 for sol in &solutions {
446 assert!(!problem.solution_size(sol).is_valid);
448 assert_eq!(problem.solution_size(sol).size, 2);
449 }
450 }
451
452 #[test]
453 fn test_brute_force_simple_sat() {
454 let problem = Satisfiability::<i32>::new(2, vec![CNFClause::new(vec![1, 2])]);
456 let solver = BruteForce::new();
457
458 let solutions = solver.find_best(&problem);
459 assert_eq!(solutions.len(), 3);
461 for sol in &solutions {
462 assert!(problem.solution_size(sol).is_valid);
463 }
464 }
465
466 #[test]
467 fn test_max_sat() {
468 let problem = Satisfiability::with_weights(
471 1,
472 vec![CNFClause::new(vec![1]), CNFClause::new(vec![-1])],
473 vec![10, 1],
474 );
475 let solver = BruteForce::new().valid_only(false); let solutions = solver.find_best(&problem);
478 assert_eq!(solutions.len(), 1);
480 assert_eq!(solutions[0], vec![1]);
481 }
482
483 #[test]
484 fn test_is_satisfying_assignment() {
485 let clauses = vec![vec![1, 2], vec![-1, 3]];
486
487 assert!(is_satisfying_assignment(3, &clauses, &[true, false, true]));
488 assert!(is_satisfying_assignment(3, &clauses, &[false, true, false]));
489 assert!(!is_satisfying_assignment(3, &clauses, &[true, false, false]));
490 }
491
492 #[test]
493 fn test_constraints() {
494 let problem = Satisfiability::<i32>::new(
495 2,
496 vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1])],
497 );
498 let constraints = problem.constraints();
499 assert_eq!(constraints.len(), 2);
500 }
501
502 #[test]
503 fn test_energy_mode() {
504 let problem = Satisfiability::<i32>::new(2, vec![CNFClause::new(vec![1])]);
505 assert!(problem.energy_mode().is_maximization());
506 }
507
508 #[test]
509 fn test_empty_formula() {
510 let problem = Satisfiability::<i32>::new(2, vec![]);
511 let sol = problem.solution_size(&[0, 0]);
512 assert!(sol.is_valid); }
514
515 #[test]
516 fn test_single_literal_clauses() {
517 let problem = Satisfiability::<i32>::new(
519 2,
520 vec![CNFClause::new(vec![1]), CNFClause::new(vec![-2])],
521 );
522 let solver = BruteForce::new();
523
524 let solutions = solver.find_best(&problem);
525 assert_eq!(solutions.len(), 1);
526 assert_eq!(solutions[0], vec![1, 0]); }
528
529 #[test]
530 fn test_get_clause() {
531 let problem = Satisfiability::<i32>::new(
532 2,
533 vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1])],
534 );
535 assert_eq!(problem.get_clause(0), Some(&CNFClause::new(vec![1, 2])));
536 assert_eq!(problem.get_clause(2), None);
537 }
538
539 #[test]
540 fn test_three_sat_example() {
541 let problem = Satisfiability::<i32>::new(
543 3,
544 vec![
545 CNFClause::new(vec![1, 2, 3]),
546 CNFClause::new(vec![-1, -2, 3]),
547 CNFClause::new(vec![1, -2, -3]),
548 ],
549 );
550 let solver = BruteForce::new();
551
552 let solutions = solver.find_best(&problem);
553 for sol in &solutions {
554 assert!(problem.solution_size(sol).is_valid);
555 }
556 }
557
558 #[test]
559 fn test_is_satisfied_csp() {
560 let problem = Satisfiability::<i32>::new(
561 2,
562 vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1, -2])],
563 );
564
565 assert!(problem.is_satisfied(&[1, 0]));
566 assert!(problem.is_satisfied(&[0, 1]));
567 assert!(!problem.is_satisfied(&[1, 1]));
568 assert!(!problem.is_satisfied(&[0, 0]));
569 }
570
571 #[test]
572 fn test_objectives() {
573 let problem = Satisfiability::with_weights(
574 2,
575 vec![CNFClause::new(vec![1, 2])],
576 vec![5],
577 );
578 let objectives = problem.objectives();
579 assert_eq!(objectives.len(), 1);
580 }
581
582 #[test]
583 fn test_set_weights() {
584 let mut problem = Satisfiability::<i32>::new(
585 2,
586 vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1])],
587 );
588 assert!(!problem.is_weighted()); problem.set_weights(vec![1, 2]);
590 assert!(problem.is_weighted());
591 assert_eq!(problem.weights(), vec![1, 2]);
592 }
593
594 #[test]
595 fn test_is_weighted_empty() {
596 let problem = Satisfiability::<i32>::new(2, vec![]);
597 assert!(!problem.is_weighted());
598 }
599
600 #[test]
601 fn test_is_satisfying_assignment_defaults() {
602 let clauses = vec![vec![1, 2]];
604 assert!(is_satisfying_assignment(3, &clauses, &[true]));
606 assert!(!is_satisfying_assignment(3, &clauses, &[false]));
609 }
610
611 #[test]
612 fn test_problem_size() {
613 let problem = Satisfiability::<i32>::new(
614 3,
615 vec![CNFClause::new(vec![1, 2]), CNFClause::new(vec![-1, 3])],
616 );
617 let size = problem.problem_size();
618 assert_eq!(size.get("num_vars"), Some(3));
619 assert_eq!(size.get("num_clauses"), Some(2));
620 }
621
622 #[test]
623 fn test_num_variables_flavors() {
624 let problem = Satisfiability::<i32>::new(5, vec![CNFClause::new(vec![1])]);
625 assert_eq!(problem.num_variables(), 5);
626 assert_eq!(problem.num_flavors(), 2);
627 }
628
629 #[test]
630 fn test_clause_variables() {
631 let clause = CNFClause::new(vec![1, -2, 3]);
632 let vars = clause.variables();
633 assert_eq!(vars, vec![0, 1, 2]); }
635
636 #[test]
637 fn test_clause_debug() {
638 let clause = CNFClause::new(vec![1, -2, 3]);
639 let debug = format!("{:?}", clause);
640 assert!(debug.contains("CNFClause"));
641 }
642}