competitive/algorithm/
horn_satisfiability.rs1pub struct HornSatisfiability {
5 literals: Vec<Option<bool>>,
6 clauses: Vec<(usize, usize, bool)>,
7 idx: Vec<Vec<usize>>,
8 satisfiable: bool,
9 stack: Vec<usize>,
10}
11
12impl HornSatisfiability {
13 pub fn new(size: usize) -> Self {
14 Self {
15 literals: vec![None; size],
16 clauses: vec![],
17 idx: vec![vec![]; size],
18 satisfiable: true,
19 stack: vec![],
20 }
21 }
22
23 pub fn add_clause(&mut self, p: impl IntoIterator<Item = usize>, q: usize, f: bool) {
24 let mut count = 0;
25 let id = self.clauses.len();
26 for p_i in p.into_iter() {
27 if self.literals[p_i] != Some(true) {
28 self.idx[p_i].push(id);
29 count += 1;
30 }
31 }
32 self.clauses.push((count, q, f));
33 if count == 0 {
34 self.stack.push(id);
35 self.resolve();
36 }
37 }
38
39 pub fn is_satisfiable(&self) -> bool {
40 self.satisfiable
41 }
42
43 pub fn solve(&self) -> Option<Vec<bool>> {
44 if !self.satisfiable {
45 return None;
46 }
47 Some(self.literals.iter().map(|&x| x.unwrap_or(false)).collect())
48 }
49
50 fn resolve(&mut self) {
51 while let Some(id) = self.stack.pop() {
52 let (_count, q, f) = self.clauses[id];
53 self.satisfiable &= self.literals[q] != Some(!f);
54 self.literals[q] = Some(f);
55 if f {
56 while let Some(i) = self.idx[q].pop() {
57 let (ref mut count, _, _) = self.clauses[i];
58 *count -= 1;
59 if *count == 0 {
60 self.stack.push(i);
61 }
62 }
63 }
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use crate::tools::Xorshift;
72
73 #[test]
74 fn test_horn_satisfiability() {
75 let mut rng = Xorshift::default();
76 for _ in 0..100 {
77 let n = rng.random(1..=10);
78 let mut clauses = vec![];
79 let mut hs = HornSatisfiability::new(n);
80 for _ in 0..100 {
81 let prob = rng.randf();
82 let mut clause: Vec<_> = (0..n).filter(|_| rng.randf() < prob).collect();
83 let cand_q: Vec<_> = (0..n).filter(|x| !clause.contains(x)).collect();
84 let q = if clause.len() == n {
85 clause.remove(rng.random(0..n))
86 } else {
87 cand_q[rng.random(0..cand_q.len())]
88 };
89 let f = rng.gen_bool(0.5);
90 hs.add_clause(clause.iter().cloned(), q, f);
91 clauses.push((clause, q, f));
92
93 let check = |lits: &Vec<bool>| -> bool {
94 for (p, q, f) in &clauses {
95 if p.iter().all(|&p| lits[p]) && lits[*q] != *f {
96 return false;
97 }
98 }
99 true
100 };
101 let res = hs.solve();
102 let satisfiable = (0..1 << n)
103 .map(|bits| (0..n).map(|i| (bits & (1 << i)) != 0).collect())
104 .any(|lits| check(&lits));
105 assert_eq!(res.is_some(), satisfiable);
106 if let Some(lits) = res {
107 assert!(check(&lits));
108 }
109 }
110 }
111 }
112}