1use std::collections::{HashMap, HashSet};
6
7use super::functions::PropVar;
8use super::functions::*;
9
10#[derive(Debug, Clone)]
12pub struct PdlModel {
13 pub kripke: KripkeModel,
15 pub n_programs: usize,
17}
18impl PdlModel {
19 pub fn new(kripke: KripkeModel, n_programs: usize) -> Self {
21 PdlModel { kripke, n_programs }
22 }
23 pub fn reachable(&self, start: usize, prog: &PdlProgram) -> HashSet<usize> {
25 match prog {
26 PdlProgram::Atomic(rel) => self
27 .kripke
28 .frame
29 .successors(*rel, start)
30 .into_iter()
31 .collect(),
32 PdlProgram::Test(phi) => {
33 if self.kripke.satisfies(start, phi) {
34 let mut s = HashSet::new();
35 s.insert(start);
36 s
37 } else {
38 HashSet::new()
39 }
40 }
41 PdlProgram::Sequence(alpha, beta) => {
42 let after_alpha = self.reachable(start, alpha);
43 let mut result = HashSet::new();
44 for w in after_alpha {
45 result.extend(self.reachable(w, beta));
46 }
47 result
48 }
49 PdlProgram::Choice(alpha, beta) => {
50 let mut r = self.reachable(start, alpha);
51 r.extend(self.reachable(start, beta));
52 r
53 }
54 PdlProgram::Star(alpha) => {
55 let mut reachable = HashSet::new();
56 reachable.insert(start);
57 loop {
58 let current: Vec<usize> = reachable.iter().cloned().collect();
59 let mut added = false;
60 for w in current {
61 for v in self.reachable(w, alpha) {
62 if reachable.insert(v) {
63 added = true;
64 }
65 }
66 }
67 if !added {
68 break;
69 }
70 }
71 reachable
72 }
73 }
74 }
75 pub fn box_program(&self, w: usize, prog: &PdlProgram, phi: &ModalFormula) -> bool {
77 self.reachable(w, prog)
78 .iter()
79 .all(|&v| self.kripke.satisfies(v, phi))
80 }
81 pub fn diamond_program(&self, w: usize, prog: &PdlProgram, phi: &ModalFormula) -> bool {
83 self.reachable(w, prog)
84 .iter()
85 .any(|&v| self.kripke.satisfies(v, phi))
86 }
87}
88#[derive(Debug, Clone)]
90pub struct MuCalculusEval {
91 pub model: KripkeModel,
93 pub env: HashMap<PropVar, HashSet<usize>>,
95}
96impl MuCalculusEval {
97 pub fn new(model: KripkeModel) -> Self {
99 MuCalculusEval {
100 model,
101 env: HashMap::new(),
102 }
103 }
104 pub fn least_fixed_point<F>(&self, step: F) -> HashSet<usize>
106 where
107 F: Fn(&HashSet<usize>) -> HashSet<usize>,
108 {
109 let mut current: HashSet<usize> = HashSet::new();
110 loop {
111 let next = step(¤t);
112 if next == current {
113 return current;
114 }
115 current = next;
116 }
117 }
118 pub fn greatest_fixed_point<F>(&self, step: F) -> HashSet<usize>
120 where
121 F: Fn(&HashSet<usize>) -> HashSet<usize>,
122 {
123 let all_worlds: HashSet<usize> = (0..self.model.frame.n_worlds).collect();
124 let mut current = all_worlds;
125 loop {
126 let next = step(¤t);
127 if next == current {
128 return current;
129 }
130 current = next;
131 }
132 }
133 pub fn reachability(&self, phi: &ModalFormula) -> HashSet<usize> {
135 let model = &self.model;
136 self.least_fixed_point(|x| {
137 (0..model.frame.n_worlds)
138 .filter(|&w| {
139 model.satisfies(w, phi)
140 || model.frame.successors(0, w).iter().any(|&v| x.contains(&v))
141 })
142 .collect()
143 })
144 }
145 pub fn safety(&self, phi: &ModalFormula) -> HashSet<usize> {
147 let model = &self.model;
148 self.greatest_fixed_point(|x| {
149 (0..model.frame.n_worlds)
150 .filter(|&w| {
151 model.satisfies(w, phi)
152 && model.frame.successors(0, w).iter().all(|&v| x.contains(&v))
153 })
154 .collect()
155 })
156 }
157}
158#[derive(Debug)]
160pub struct TableauProver {
161 pub nodes: Vec<TableauNode>,
163 pub next_world: usize,
165 pub edges: Vec<(usize, usize)>,
167}
168impl TableauProver {
169 pub fn new() -> Self {
171 let root = TableauNode::new(0);
172 TableauProver {
173 nodes: vec![root],
174 next_world: 1,
175 edges: Vec::new(),
176 }
177 }
178 pub fn is_tautology(&mut self, phi: &ModalFormula) -> bool {
181 let neg = ModalFormula::not(phi.clone());
182 self.nodes[0].add_positive(neg);
183 self.nodes[0].detect_closure();
184 self.nodes[0].closed
185 }
186}
187#[derive(Debug)]
189pub struct CanonicalModel {
190 pub worlds: Vec<MaximalConsistentSet>,
192 pub accessibility: HashSet<(usize, usize)>,
194}
195impl CanonicalModel {
196 pub fn new() -> Self {
198 CanonicalModel {
199 worlds: Vec::new(),
200 accessibility: HashSet::new(),
201 }
202 }
203 pub fn add_world(&mut self, mcs: MaximalConsistentSet) {
205 self.worlds.push(mcs);
206 }
207 pub fn build_accessibility(&mut self) {
209 let n = self.worlds.len();
210 for i in 0..n {
211 let box_formulas: Vec<ModalFormula> = self.worlds[i]
212 .formulas
213 .iter()
214 .filter_map(|f| {
215 if let ModalFormula::Box(0, phi) = f {
216 Some(*phi.clone())
217 } else {
218 None
219 }
220 })
221 .collect();
222 for j in 0..n {
223 let all_contained = box_formulas.iter().all(|phi| self.worlds[j].contains(phi));
224 if all_contained {
225 self.accessibility.insert((i, j));
226 }
227 }
228 }
229 }
230 pub fn size(&self) -> usize {
232 self.worlds.len()
233 }
234}
235#[derive(Debug, Clone)]
237pub struct EpistemicModel {
238 pub n_worlds: usize,
240 pub n_agents: usize,
242 pub agent_relations: Vec<HashSet<(usize, usize)>>,
244 pub valuation: HashMap<PropVar, HashSet<usize>>,
246}
247impl EpistemicModel {
248 pub fn new(n_worlds: usize, n_agents: usize) -> Self {
250 EpistemicModel {
251 n_worlds,
252 n_agents,
253 agent_relations: vec![HashSet::new(); n_agents],
254 valuation: HashMap::new(),
255 }
256 }
257 pub fn add_edge(&mut self, agent: usize, from: usize, to: usize) {
259 if agent < self.n_agents {
260 self.agent_relations[agent].insert((from, to));
261 }
262 }
263 pub fn make_equivalence_relations(&mut self) {
265 for agent in 0..self.n_agents {
266 for w in 0..self.n_worlds {
267 self.agent_relations[agent].insert((w, w));
268 }
269 let edges: Vec<(usize, usize)> = self.agent_relations[agent].iter().cloned().collect();
270 for &(a, b) in &edges {
271 self.agent_relations[agent].insert((b, a));
272 }
273 loop {
274 let edges: Vec<(usize, usize)> =
275 self.agent_relations[agent].iter().cloned().collect();
276 let mut changed = false;
277 for &(a, b) in &edges {
278 for &(c, d) in &edges {
279 if b == c && !self.agent_relations[agent].contains(&(a, d)) {
280 self.agent_relations[agent].insert((a, d));
281 changed = true;
282 }
283 }
284 }
285 if !changed {
286 break;
287 }
288 }
289 }
290 }
291 pub fn knows(&self, agent: usize, w: usize, phi: &ModalFormula) -> bool {
293 if agent >= self.n_agents {
294 return false;
295 }
296 let successors: Vec<usize> = self.agent_relations[agent]
297 .iter()
298 .filter(|&&(f, _)| f == w)
299 .map(|&(_, t)| t)
300 .collect();
301 successors
302 .iter()
303 .all(|&v| self.satisfies_with_agent(v, phi))
304 }
305 fn satisfies_with_agent(&self, w: usize, phi: &ModalFormula) -> bool {
307 match phi {
308 ModalFormula::Top => true,
309 ModalFormula::Bot => false,
310 ModalFormula::Atom(p) => self.valuation.get(p).is_some_and(|s| s.contains(&w)),
311 ModalFormula::Not(psi) => !self.satisfies_with_agent(w, psi),
312 ModalFormula::And(a, b) => {
313 self.satisfies_with_agent(w, a) && self.satisfies_with_agent(w, b)
314 }
315 ModalFormula::Or(a, b) => {
316 self.satisfies_with_agent(w, a) || self.satisfies_with_agent(w, b)
317 }
318 ModalFormula::Implies(a, b) => {
319 !self.satisfies_with_agent(w, a) || self.satisfies_with_agent(w, b)
320 }
321 ModalFormula::Box(rel, psi) => {
322 let agent = *rel;
323 self.knows(agent, w, psi)
324 }
325 ModalFormula::Diamond(rel, psi) => {
326 let agent = *rel;
327 if agent >= self.n_agents {
328 return false;
329 }
330 self.agent_relations[agent]
331 .iter()
332 .filter(|&&(f, _)| f == w)
333 .any(|&(_, v)| self.satisfies_with_agent(v, psi))
334 }
335 }
336 }
337}
338#[derive(Debug, Clone, PartialEq, Eq)]
340pub enum SahlqvistClass {
341 Antecedent,
343 Consequent,
345 Full,
347 NotSahlqvist,
349}
350#[derive(Debug, Clone, PartialEq, Eq)]
352pub enum PdlProgram {
353 Atomic(usize),
355 Test(Box<ModalFormula>),
357 Sequence(Box<PdlProgram>, Box<PdlProgram>),
359 Choice(Box<PdlProgram>, Box<PdlProgram>),
361 Star(Box<PdlProgram>),
363}
364#[derive(Debug, Clone)]
366pub struct FiniteTrace {
367 pub steps: Vec<HashMap<PropVar, bool>>,
369}
370impl FiniteTrace {
371 pub fn new() -> Self {
373 FiniteTrace { steps: Vec::new() }
374 }
375 pub fn push(&mut self, valuation: HashMap<PropVar, bool>) {
377 self.steps.push(valuation);
378 }
379 pub fn len(&self) -> usize {
381 self.steps.len()
382 }
383 pub fn is_empty(&self) -> bool {
385 self.steps.is_empty()
386 }
387 pub fn prop_at(&self, p: PropVar, i: usize) -> bool {
389 self.steps
390 .get(i)
391 .and_then(|s| s.get(&p))
392 .copied()
393 .unwrap_or(false)
394 }
395 pub fn satisfies(&self, i: usize, phi: &ModalFormula) -> bool {
398 if i >= self.steps.len() {
399 return false;
400 }
401 match phi {
402 ModalFormula::Top => true,
403 ModalFormula::Bot => false,
404 ModalFormula::Atom(p) => self.prop_at(*p, i),
405 ModalFormula::Not(psi) => !self.satisfies(i, psi),
406 ModalFormula::And(a, b) => self.satisfies(i, a) && self.satisfies(i, b),
407 ModalFormula::Or(a, b) => self.satisfies(i, a) || self.satisfies(i, b),
408 ModalFormula::Implies(a, b) => !self.satisfies(i, a) || self.satisfies(i, b),
409 ModalFormula::Box(0, psi) => (i..self.steps.len()).all(|j| self.satisfies(j, psi)),
410 ModalFormula::Diamond(0, psi) => (i..self.steps.len()).any(|j| self.satisfies(j, psi)),
411 ModalFormula::Box(1, psi) => i + 1 < self.steps.len() && self.satisfies(i + 1, psi),
412 ModalFormula::Diamond(1, psi) => {
413 i + 1 >= self.steps.len() || self.satisfies(i + 1, psi)
414 }
415 _ => false,
416 }
417 }
418 pub fn check(&self, phi: &ModalFormula) -> bool {
420 self.satisfies(0, phi)
421 }
422}
423#[derive(Debug, Clone)]
425pub struct BeliefRevisionOp {
426 pub beliefs: Vec<ModalFormula>,
428 pub entrenchment: HashMap<ModalFormula, u32>,
430}
431impl BeliefRevisionOp {
432 pub fn new() -> Self {
434 BeliefRevisionOp {
435 beliefs: Vec::new(),
436 entrenchment: HashMap::new(),
437 }
438 }
439 pub fn add_belief(&mut self, phi: ModalFormula, level: u32) {
441 if !self.beliefs.contains(&phi) {
442 self.beliefs.push(phi.clone());
443 }
444 self.entrenchment.insert(phi, level);
445 }
446 pub fn believes(&self, phi: &ModalFormula) -> bool {
448 self.beliefs.contains(phi)
449 }
450 pub fn revise(&self, phi: &ModalFormula) -> BeliefRevisionOp {
452 let mut new_op = self.clone();
453 let neg_phi = ModalFormula::not(phi.clone());
454 let phi_level = self.entrenchment.get(phi).copied().unwrap_or(0);
455 new_op.beliefs.retain(|b| {
456 if b == &neg_phi {
457 let b_level = self.entrenchment.get(b).copied().unwrap_or(0);
458 b_level > phi_level
459 } else {
460 true
461 }
462 });
463 new_op.add_belief(phi.clone(), phi_level.max(1));
464 new_op
465 }
466 pub fn contract(&self, phi: &ModalFormula) -> BeliefRevisionOp {
468 let mut new_op = self.clone();
469 new_op.beliefs.retain(|b| b != phi);
470 new_op.entrenchment.remove(phi);
471 new_op
472 }
473 pub fn size(&self) -> usize {
475 self.beliefs.len()
476 }
477}
478#[derive(Debug, Clone)]
480pub struct KripkeModel {
481 pub frame: KripkeFrame,
483 pub valuation: HashMap<PropVar, HashSet<usize>>,
485}
486impl KripkeModel {
487 pub fn new(frame: KripkeFrame) -> Self {
489 KripkeModel {
490 frame,
491 valuation: HashMap::new(),
492 }
493 }
494 pub fn set_true(&mut self, p: PropVar, w: usize) {
496 self.valuation.entry(p).or_default().insert(w);
497 }
498 pub fn prop_true(&self, p: PropVar, w: usize) -> bool {
500 self.valuation.get(&p).is_some_and(|s| s.contains(&w))
501 }
502 pub fn satisfies(&self, w: usize, phi: &ModalFormula) -> bool {
504 match phi {
505 ModalFormula::Top => true,
506 ModalFormula::Bot => false,
507 ModalFormula::Atom(p) => self.prop_true(*p, w),
508 ModalFormula::Not(psi) => !self.satisfies(w, psi),
509 ModalFormula::And(a, b) => self.satisfies(w, a) && self.satisfies(w, b),
510 ModalFormula::Or(a, b) => self.satisfies(w, a) || self.satisfies(w, b),
511 ModalFormula::Implies(a, b) => !self.satisfies(w, a) || self.satisfies(w, b),
512 ModalFormula::Box(rel, psi) => self
513 .frame
514 .successors(*rel, w)
515 .iter()
516 .all(|&v| self.satisfies(v, psi)),
517 ModalFormula::Diamond(rel, psi) => self
518 .frame
519 .successors(*rel, w)
520 .iter()
521 .any(|&v| self.satisfies(v, psi)),
522 }
523 }
524 pub fn model_valid(&self, phi: &ModalFormula) -> bool {
526 (0..self.frame.n_worlds).all(|w| self.satisfies(w, phi))
527 }
528 pub fn extension(&self, phi: &ModalFormula) -> HashSet<usize> {
530 (0..self.frame.n_worlds)
531 .filter(|&w| self.satisfies(w, phi))
532 .collect()
533 }
534}
535#[derive(Debug, Clone, PartialEq, Eq, Hash)]
537pub struct MaximalConsistentSet {
538 pub id: usize,
540 pub formulas: Vec<ModalFormula>,
542}
543impl MaximalConsistentSet {
544 pub fn new(id: usize, formulas: Vec<ModalFormula>) -> Self {
546 MaximalConsistentSet { id, formulas }
547 }
548 pub fn contains(&self, phi: &ModalFormula) -> bool {
550 self.formulas.contains(phi)
551 }
552 pub fn add(&mut self, phi: ModalFormula) {
554 if !self.contains(&phi) {
555 self.formulas.push(phi);
556 }
557 }
558}
559#[derive(Debug, Clone)]
561pub struct PublicAnnouncement {
562 pub announcement: ModalFormula,
564}
565impl PublicAnnouncement {
566 pub fn new(phi: ModalFormula) -> Self {
568 PublicAnnouncement { announcement: phi }
569 }
570 pub fn update(&self, model: &EpistemicModel) -> EpistemicModel {
573 let surviving: HashSet<usize> = (0..model.n_worlds)
574 .filter(|&w| model.satisfies_with_agent(w, &self.announcement))
575 .collect();
576 let old_to_new: HashMap<usize, usize> = surviving
577 .iter()
578 .enumerate()
579 .map(|(new, &old)| (old, new))
580 .collect();
581 let n_new = surviving.len();
582 let mut new_model = EpistemicModel::new(n_new, model.n_agents);
583 for agent in 0..model.n_agents {
584 for &(from, to) in &model.agent_relations[agent] {
585 if let (Some(&nf), Some(&nt)) = (old_to_new.get(&from), old_to_new.get(&to)) {
586 new_model.agent_relations[agent].insert((nf, nt));
587 }
588 }
589 }
590 for (&p, worlds) in &model.valuation {
591 for &w in worlds {
592 if let Some(&nw) = old_to_new.get(&w) {
593 new_model.valuation.entry(p).or_default().insert(nw);
594 }
595 }
596 }
597 new_model
598 }
599}
600#[derive(Debug, Clone, PartialEq, Eq, Hash)]
602pub enum ModalSystem {
603 K,
605 T,
607 S4,
609 S5,
611 D,
613 KD45,
615 GL,
617 B,
619}
620impl ModalSystem {
621 pub fn name(&self) -> &'static str {
623 match self {
624 ModalSystem::K => "K",
625 ModalSystem::T => "T",
626 ModalSystem::S4 => "S4",
627 ModalSystem::S5 => "S5",
628 ModalSystem::D => "D",
629 ModalSystem::KD45 => "KD45",
630 ModalSystem::GL => "GL",
631 ModalSystem::B => "B",
632 }
633 }
634 pub fn frame_validates(&self, frame: &KripkeFrame, rel: usize) -> bool {
636 match self {
637 ModalSystem::K => true,
638 ModalSystem::T => frame.is_reflexive(rel),
639 ModalSystem::S4 => frame.is_reflexive(rel) && frame.is_transitive(rel),
640 ModalSystem::S5 => {
641 frame.is_reflexive(rel) && frame.is_transitive(rel) && frame.is_symmetric(rel)
642 }
643 ModalSystem::D => frame.is_serial(rel),
644 ModalSystem::KD45 => {
645 frame.is_serial(rel) && frame.is_transitive(rel) && frame.is_euclidean(rel)
646 }
647 ModalSystem::GL => frame.is_transitive(rel),
648 ModalSystem::B => frame.is_reflexive(rel) && frame.is_symmetric(rel),
649 }
650 }
651}
652#[derive(Debug, Clone)]
654pub struct KripkeFrame {
655 pub n_worlds: usize,
657 pub relations: Vec<HashSet<(usize, usize)>>,
659}
660impl KripkeFrame {
661 pub fn new(n_worlds: usize, n_relations: usize) -> Self {
663 KripkeFrame {
664 n_worlds,
665 relations: vec![HashSet::new(); n_relations],
666 }
667 }
668 pub fn add_edge(&mut self, rel: usize, from: usize, to: usize) {
670 if rel < self.relations.len() {
671 self.relations[rel].insert((from, to));
672 }
673 }
674 pub fn accessible(&self, rel: usize, w: usize, v: usize) -> bool {
676 self.relations.get(rel).is_some_and(|r| r.contains(&(w, v)))
677 }
678 pub fn successors(&self, rel: usize, w: usize) -> Vec<usize> {
680 self.relations
681 .get(rel)
682 .map(|r| r.iter().filter(|(f, _)| *f == w).map(|(_, t)| *t).collect())
683 .unwrap_or_default()
684 }
685 pub fn is_reflexive(&self, rel: usize) -> bool {
687 (0..self.n_worlds).all(|w| self.accessible(rel, w, w))
688 }
689 pub fn is_transitive(&self, rel: usize) -> bool {
691 let r = match self.relations.get(rel) {
692 Some(r) => r,
693 None => return true,
694 };
695 let pairs: Vec<(usize, usize)> = r.iter().cloned().collect();
696 for &(a, b) in &pairs {
697 for &(c, d) in &pairs {
698 if b == c && !r.contains(&(a, d)) {
699 return false;
700 }
701 }
702 }
703 true
704 }
705 pub fn is_symmetric(&self, rel: usize) -> bool {
707 let r = match self.relations.get(rel) {
708 Some(r) => r,
709 None => return true,
710 };
711 r.iter().all(|&(a, b)| r.contains(&(b, a)))
712 }
713 pub fn is_serial(&self, rel: usize) -> bool {
715 (0..self.n_worlds).all(|w| !self.successors(rel, w).is_empty())
716 }
717 pub fn is_euclidean(&self, rel: usize) -> bool {
719 let r = match self.relations.get(rel) {
720 Some(r) => r,
721 None => return true,
722 };
723 let pairs: Vec<(usize, usize)> = r.iter().cloned().collect();
724 for &(w, v) in &pairs {
725 for &(w2, u) in &pairs {
726 if w == w2 && !r.contains(&(v, u)) {
727 return false;
728 }
729 }
730 }
731 true
732 }
733 pub fn make_reflexive(&mut self, rel: usize) {
735 for w in 0..self.n_worlds {
736 self.add_edge(rel, w, w);
737 }
738 }
739 pub fn make_transitive(&mut self, rel: usize) {
741 if rel >= self.relations.len() {
742 return;
743 }
744 loop {
745 let current: Vec<(usize, usize)> = self.relations[rel].iter().cloned().collect();
746 let mut added = false;
747 for &(a, b) in ¤t {
748 for &(c, d) in ¤t {
749 if b == c && !self.relations[rel].contains(&(a, d)) {
750 self.relations[rel].insert((a, d));
751 added = true;
752 }
753 }
754 }
755 if !added {
756 break;
757 }
758 }
759 }
760}
761#[derive(Debug, Clone, PartialEq, Eq, Hash)]
763pub enum ModalFormula {
764 Atom(PropVar),
766 Top,
768 Bot,
770 Not(Box<ModalFormula>),
772 And(Box<ModalFormula>, Box<ModalFormula>),
774 Or(Box<ModalFormula>, Box<ModalFormula>),
776 Implies(Box<ModalFormula>, Box<ModalFormula>),
778 Box(usize, Box<ModalFormula>),
780 Diamond(usize, Box<ModalFormula>),
782}
783impl ModalFormula {
784 pub fn atom(p: PropVar) -> Self {
786 ModalFormula::Atom(p)
787 }
788 pub fn necessity(phi: ModalFormula) -> Self {
790 ModalFormula::Box(0, Box::new(phi))
791 }
792 pub fn possibility(phi: ModalFormula) -> Self {
794 ModalFormula::Diamond(0, Box::new(phi))
795 }
796 pub fn implies(a: ModalFormula, b: ModalFormula) -> Self {
798 ModalFormula::Implies(Box::new(a), Box::new(b))
799 }
800 pub fn and(a: ModalFormula, b: ModalFormula) -> Self {
802 ModalFormula::And(Box::new(a), Box::new(b))
803 }
804 pub fn or(a: ModalFormula, b: ModalFormula) -> Self {
806 ModalFormula::Or(Box::new(a), Box::new(b))
807 }
808 pub fn not(a: ModalFormula) -> Self {
810 ModalFormula::Not(Box::new(a))
811 }
812 pub fn subformulas(&self) -> Vec<ModalFormula> {
814 let mut result = vec![self.clone()];
815 match self {
816 ModalFormula::Not(phi) => result.extend(phi.subformulas()),
817 ModalFormula::And(a, b) | ModalFormula::Or(a, b) | ModalFormula::Implies(a, b) => {
818 result.extend(a.subformulas());
819 result.extend(b.subformulas());
820 }
821 ModalFormula::Box(_, phi) | ModalFormula::Diamond(_, phi) => {
822 result.extend(phi.subformulas())
823 }
824 _ => {}
825 }
826 result
827 }
828 pub fn prop_vars(&self) -> HashSet<PropVar> {
830 let mut vars = HashSet::new();
831 self.collect_vars(&mut vars);
832 vars
833 }
834 fn collect_vars(&self, vars: &mut HashSet<PropVar>) {
835 match self {
836 ModalFormula::Atom(p) => {
837 vars.insert(*p);
838 }
839 ModalFormula::Not(phi) => phi.collect_vars(vars),
840 ModalFormula::And(a, b) | ModalFormula::Or(a, b) | ModalFormula::Implies(a, b) => {
841 a.collect_vars(vars);
842 b.collect_vars(vars);
843 }
844 ModalFormula::Box(_, phi) | ModalFormula::Diamond(_, phi) => phi.collect_vars(vars),
845 _ => {}
846 }
847 }
848 pub fn modal_depth(&self) -> usize {
850 match self {
851 ModalFormula::Atom(_) | ModalFormula::Top | ModalFormula::Bot => 0,
852 ModalFormula::Not(phi) => phi.modal_depth(),
853 ModalFormula::And(a, b) | ModalFormula::Or(a, b) | ModalFormula::Implies(a, b) => {
854 a.modal_depth().max(b.modal_depth())
855 }
856 ModalFormula::Box(_, phi) | ModalFormula::Diamond(_, phi) => 1 + phi.modal_depth(),
857 }
858 }
859}
860#[derive(Debug, Clone)]
862pub struct TableauNode {
863 pub world: usize,
865 pub positive: Vec<ModalFormula>,
867 pub negative: Vec<ModalFormula>,
869 pub closed: bool,
871}
872impl TableauNode {
873 pub fn new(world: usize) -> Self {
875 TableauNode {
876 world,
877 positive: Vec::new(),
878 negative: Vec::new(),
879 closed: false,
880 }
881 }
882 pub fn add_positive(&mut self, phi: ModalFormula) {
884 self.positive.push(phi);
885 }
886 pub fn add_negative(&mut self, phi: ModalFormula) {
888 self.negative.push(phi);
889 }
890 pub fn detect_closure(&mut self) {
892 for p in &self.positive {
893 if self.negative.contains(p) {
894 self.closed = true;
895 return;
896 }
897 }
898 if self.positive.contains(&ModalFormula::Bot) || self.negative.contains(&ModalFormula::Top)
899 {
900 self.closed = true;
901 }
902 }
903}
904#[derive(Debug, Clone)]
906pub struct GradedModel {
907 pub model: KripkeModel,
909}
910impl GradedModel {
911 pub fn new(model: KripkeModel) -> Self {
913 GradedModel { model }
914 }
915 pub fn graded_diamond(&self, w: usize, n: usize, phi: &ModalFormula) -> bool {
917 let count = self
918 .model
919 .frame
920 .successors(0, w)
921 .iter()
922 .filter(|&&v| self.model.satisfies(v, phi))
923 .count();
924 count >= n
925 }
926 pub fn graded_box(&self, w: usize, n: usize, phi: &ModalFormula) -> bool {
928 let failures = self
929 .model
930 .frame
931 .successors(0, w)
932 .iter()
933 .filter(|&&v| !self.model.satisfies(v, phi))
934 .count();
935 failures <= n
936 }
937 pub fn count_satisfying(&self, w: usize, phi: &ModalFormula) -> usize {
939 self.model
940 .frame
941 .successors(0, w)
942 .iter()
943 .filter(|&&v| self.model.satisfies(v, phi))
944 .count()
945 }
946}
947#[derive(Debug, Clone)]
949pub struct Bisimulation {
950 pub pairs: HashSet<(usize, usize)>,
952}
953impl Bisimulation {
954 pub fn new() -> Self {
956 Bisimulation {
957 pairs: HashSet::new(),
958 }
959 }
960 pub fn add_pair(&mut self, w: usize, v: usize) {
962 self.pairs.insert((w, v));
963 }
964 pub fn is_bisimulation_pair(
967 &self,
968 _m1: &KripkeModel,
969 _m2: &KripkeModel,
970 w1: usize,
971 w2: usize,
972 ) -> bool {
973 self.pairs.contains(&(w1, w2))
974 }
975 pub fn size(&self) -> usize {
977 self.pairs.len()
978 }
979}