1use super::functions::*;
6#[allow(dead_code)]
11pub struct TruthTableChecker {
12 pub num_vars: usize,
14}
15#[allow(dead_code)]
16impl TruthTableChecker {
17 pub fn new(n: usize) -> Self {
19 Self { num_vars: n }
20 }
21 pub fn all_assignments(&self) -> Vec<Vec<bool>> {
23 let n = 1usize << self.num_vars;
24 (0..n)
25 .map(|mask| (0..self.num_vars).map(|i| (mask >> i) & 1 == 1).collect())
26 .collect()
27 }
28 pub fn is_tautology(&self, formula: &NnfFormula) -> bool {
30 self.all_assignments().iter().all(|a| formula.eval(a))
31 }
32 pub fn is_satisfiable(&self, formula: &NnfFormula) -> bool {
34 self.all_assignments().iter().any(|a| formula.eval(a))
35 }
36 pub fn is_contradiction(&self, formula: &NnfFormula) -> bool {
38 !self.is_satisfiable(formula)
39 }
40 pub fn find_satisfying_assignment(&self, formula: &NnfFormula) -> Option<Vec<bool>> {
42 self.all_assignments().into_iter().find(|a| formula.eval(a))
43 }
44 pub fn count_satisfying(&self, formula: &NnfFormula) -> usize {
46 self.all_assignments()
47 .iter()
48 .filter(|a| formula.eval(a))
49 .count()
50 }
51}
52#[allow(dead_code)]
57#[derive(Clone, Debug, PartialEq, Eq)]
58pub enum NnfFormula {
59 Atom(usize),
61 NegAtom(usize),
63 And(Box<NnfFormula>, Box<NnfFormula>),
65 Or(Box<NnfFormula>, Box<NnfFormula>),
67 Top,
69 Bot,
71}
72#[allow(dead_code)]
73impl NnfFormula {
74 pub fn is_literal(&self) -> bool {
76 matches!(self, NnfFormula::Atom(_) | NnfFormula::NegAtom(_))
77 }
78 pub fn atom_count(&self) -> usize {
80 match self {
81 NnfFormula::Atom(_) | NnfFormula::NegAtom(_) => 1,
82 NnfFormula::And(a, b) | NnfFormula::Or(a, b) => a.atom_count() + b.atom_count(),
83 NnfFormula::Top | NnfFormula::Bot => 0,
84 }
85 }
86 pub fn connective_count(&self) -> usize {
88 match self {
89 NnfFormula::Atom(_) | NnfFormula::NegAtom(_) | NnfFormula::Top | NnfFormula::Bot => 0,
90 NnfFormula::And(a, b) | NnfFormula::Or(a, b) => {
91 1 + a.connective_count() + b.connective_count()
92 }
93 }
94 }
95 pub fn variables(&self) -> Vec<usize> {
97 let mut vars = Vec::new();
98 self.collect_vars(&mut vars);
99 vars.sort();
100 vars.dedup();
101 vars
102 }
103 fn collect_vars(&self, acc: &mut Vec<usize>) {
104 match self {
105 NnfFormula::Atom(i) | NnfFormula::NegAtom(i) => acc.push(*i),
106 NnfFormula::And(a, b) | NnfFormula::Or(a, b) => {
107 a.collect_vars(acc);
108 b.collect_vars(acc);
109 }
110 _ => {}
111 }
112 }
113 pub fn eval(&self, assignment: &[bool]) -> bool {
115 match self {
116 NnfFormula::Atom(i) => assignment.get(*i).copied().unwrap_or(false),
117 NnfFormula::NegAtom(i) => !assignment.get(*i).copied().unwrap_or(false),
118 NnfFormula::And(a, b) => a.eval(assignment) && b.eval(assignment),
119 NnfFormula::Or(a, b) => a.eval(assignment) || b.eval(assignment),
120 NnfFormula::Top => true,
121 NnfFormula::Bot => false,
122 }
123 }
124 pub fn simplify(self) -> NnfFormula {
126 match self {
127 NnfFormula::And(a, b) => {
128 let a = a.simplify();
129 let b = b.simplify();
130 match (&a, &b) {
131 (NnfFormula::Bot, _) | (_, NnfFormula::Bot) => NnfFormula::Bot,
132 (NnfFormula::Top, _) => b,
133 (_, NnfFormula::Top) => a,
134 _ => NnfFormula::And(Box::new(a), Box::new(b)),
135 }
136 }
137 NnfFormula::Or(a, b) => {
138 let a = a.simplify();
139 let b = b.simplify();
140 match (&a, &b) {
141 (NnfFormula::Top, _) | (_, NnfFormula::Top) => NnfFormula::Top,
142 (NnfFormula::Bot, _) => b,
143 (_, NnfFormula::Bot) => a,
144 _ => NnfFormula::Or(Box::new(a), Box::new(b)),
145 }
146 }
147 other => other,
148 }
149 }
150}
151#[allow(dead_code)]
156#[derive(Clone, Debug)]
157pub struct Sequent {
158 pub antecedent: Vec<NnfFormula>,
160 pub succedent: Vec<NnfFormula>,
162}
163#[allow(dead_code)]
164impl Sequent {
165 pub fn empty() -> Self {
167 Self {
168 antecedent: vec![],
169 succedent: vec![],
170 }
171 }
172 pub fn new(antecedent: Vec<NnfFormula>, succedent: Vec<NnfFormula>) -> Self {
174 Self {
175 antecedent,
176 succedent,
177 }
178 }
179 pub fn axiom(p: NnfFormula) -> Self {
181 Self {
182 antecedent: vec![p.clone()],
183 succedent: vec![p],
184 }
185 }
186 pub fn is_initial(&self) -> bool {
188 for a in &self.antecedent {
189 if self.succedent.contains(a) {
190 return true;
191 }
192 }
193 false
194 }
195 pub fn is_classically_valid(&self, num_vars: usize) -> bool {
197 let checker = TruthTableChecker::new(num_vars);
198 checker.all_assignments().iter().all(|assign| {
199 let ant_false = self.antecedent.iter().any(|f| !f.eval(assign));
200 let suc_true = self.succedent.iter().any(|f| f.eval(assign));
201 ant_false || suc_true
202 })
203 }
204 pub fn size(&self) -> usize {
206 self.antecedent.len() + self.succedent.len()
207 }
208 pub fn with_assumption(mut self, f: NnfFormula) -> Self {
210 self.antecedent.push(f);
211 self
212 }
213 pub fn with_conclusion(mut self, f: NnfFormula) -> Self {
215 self.succedent.push(f);
216 self
217 }
218 pub fn has_false_in_antecedent(&self) -> bool {
220 self.antecedent.contains(&NnfFormula::Bot)
221 }
222 pub fn has_true_in_succedent(&self) -> bool {
224 self.succedent.contains(&NnfFormula::Top)
225 }
226}
227#[allow(dead_code)]
234pub struct KripkeModel {
235 pub num_worlds: usize,
237 pub num_vars: usize,
239 pub access: Vec<Vec<bool>>,
241 pub val: Vec<Vec<bool>>,
243}
244#[allow(dead_code)]
245impl KripkeModel {
246 pub fn reflexive(num_worlds: usize, num_vars: usize) -> Self {
248 let mut access = vec![vec![false; num_worlds]; num_worlds];
249 for i in 0..num_worlds {
250 access[i][i] = true;
251 }
252 let val = vec![vec![false; num_vars]; num_worlds];
253 Self {
254 num_worlds,
255 num_vars,
256 access,
257 val,
258 }
259 }
260 pub fn set_val(&mut self, world: usize, var: usize, truth: bool) {
262 if world < self.num_worlds && var < self.num_vars {
263 self.val[world][var] = truth;
264 }
265 }
266 pub fn set_access(&mut self, from: usize, to: usize) {
268 if from < self.num_worlds && to < self.num_worlds {
269 self.access[from][to] = true;
270 }
271 }
272 pub fn satisfies_at(&self, formula: &NnfFormula, world: usize) -> bool {
274 formula.eval(&self.val[world])
275 }
276 pub fn is_reflexive(&self) -> bool {
278 (0..self.num_worlds).all(|i| self.access[i][i])
279 }
280 pub fn is_transitive(&self) -> bool {
282 for i in 0..self.num_worlds {
283 for j in 0..self.num_worlds {
284 for k in 0..self.num_worlds {
285 if self.access[i][j] && self.access[j][k] && !self.access[i][k] {
286 return false;
287 }
288 }
289 }
290 }
291 true
292 }
293 pub fn is_symmetric(&self) -> bool {
295 for i in 0..self.num_worlds {
296 for j in 0..self.num_worlds {
297 if self.access[i][j] && !self.access[j][i] {
298 return false;
299 }
300 }
301 }
302 true
303 }
304 pub fn is_euclidean(&self) -> bool {
306 for i in 0..self.num_worlds {
307 for j in 0..self.num_worlds {
308 for k in 0..self.num_worlds {
309 if self.access[i][j] && self.access[i][k] && !self.access[j][k] {
310 return false;
311 }
312 }
313 }
314 }
315 true
316 }
317 pub fn accessible_count(&self, world: usize) -> usize {
319 if world < self.num_worlds {
320 self.access[world].iter().filter(|&&b| b).count()
321 } else {
322 0
323 }
324 }
325}