1use std::collections::HashMap;
5
6pub type AtomId = u32;
8pub type AgentId = u32;
10pub type AgentMask = u32;
12pub type FormulaId = u32;
14
15#[derive(Clone, PartialEq, Eq, Hash, Debug)]
17pub enum Node {
18 True,
20 Atom(AtomId),
22 Not(FormulaId),
24 And(FormulaId, FormulaId),
26 Knows(AgentId, FormulaId),
28 Believes(AgentId, FormulaId),
30 Safe(AgentId, FormulaId),
32 CondBel(AgentId, FormulaId, FormulaId),
34 Common(AgentMask, FormulaId),
36}
37
38#[derive(Default, Debug, Clone)]
40pub struct Store {
41 nodes: Vec<Node>,
42 map: HashMap<Node, FormulaId>,
43}
44
45impl Store {
46 pub fn mk(&mut self, n: Node) -> FormulaId {
48 if let Some(&i) = self.map.get(&n) {
49 return i;
50 }
51 let i = self.nodes.len() as FormulaId;
52 self.nodes.push(n.clone());
53 self.map.insert(n, i);
54 i
55 }
56
57 pub fn node(&self, f: FormulaId) -> &Node {
62 debug_assert!((f as usize) < self.nodes.len(), "id not produced by this store");
63 &self.nodes[f as usize]
64 }
65
66 pub fn len(&self) -> usize {
68 self.nodes.len()
69 }
70
71 pub fn is_empty(&self) -> bool {
73 self.nodes.is_empty()
74 }
75
76 pub fn tru(&mut self) -> FormulaId {
78 self.mk(Node::True)
79 }
80 pub fn fls(&mut self) -> FormulaId {
82 let t = self.tru();
83 self.mk(Node::Not(t))
84 }
85 pub fn atom(&mut self, a: AtomId) -> FormulaId {
87 self.mk(Node::Atom(a))
88 }
89 pub fn not(&mut self, f: FormulaId) -> FormulaId {
91 self.mk(Node::Not(f))
92 }
93 pub fn and(&mut self, a: FormulaId, b: FormulaId) -> FormulaId {
95 self.mk(Node::And(a, b))
96 }
97 pub fn or(&mut self, a: FormulaId, b: FormulaId) -> FormulaId {
99 let na = self.not(a);
100 let nb = self.not(b);
101 let c = self.and(na, nb);
102 self.not(c)
103 }
104 pub fn implies(&mut self, a: FormulaId, b: FormulaId) -> FormulaId {
106 let na = self.not(a);
107 self.or(na, b)
108 }
109 pub fn all(&mut self, fs: &[FormulaId]) -> FormulaId {
111 match fs.split_first() {
112 None => self.tru(),
113 Some((&h, rest)) => rest.iter().fold(h, |acc, &f| self.and(acc, f)),
114 }
115 }
116 pub fn any(&mut self, fs: &[FormulaId]) -> FormulaId {
118 match fs.split_first() {
119 None => self.fls(),
120 Some((&h, rest)) => rest.iter().fold(h, |acc, &f| self.or(acc, f)),
121 }
122 }
123 pub fn knows(&mut self, i: AgentId, f: FormulaId) -> FormulaId {
125 self.mk(Node::Knows(i, f))
126 }
127 pub fn believes(&mut self, i: AgentId, f: FormulaId) -> FormulaId {
129 self.mk(Node::Believes(i, f))
130 }
131 pub fn safe(&mut self, i: AgentId, f: FormulaId) -> FormulaId {
133 self.mk(Node::Safe(i, f))
134 }
135 pub fn cond_bel(&mut self, i: AgentId, psi: FormulaId, phi: FormulaId) -> FormulaId {
137 self.mk(Node::CondBel(i, psi, phi))
138 }
139 pub fn common(&mut self, g: AgentMask, f: FormulaId) -> FormulaId {
141 self.mk(Node::Common(g, f))
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 #[test]
150 fn identical_subterms_share_one_id() {
151 let mut s = Store::default();
152 let p = s.atom(0);
153 let a = s.believes(0, p);
154 let b = s.believes(0, p);
155 assert_eq!(a, b, "hash-consing must return the same id");
156
157 let before = s.len();
158 let _ = s.believes(0, p);
159 assert_eq!(s.len(), before, "re-making a node must not grow the arena");
160 }
161
162 #[test]
163 fn or_is_built_from_not_and_and() {
164 let mut s = Store::default();
165 let p = s.atom(0);
166 let q = s.atom(1);
167 let disj = s.or(p, q);
168 match s.node(disj) {
170 Node::Not(inner) => match s.node(*inner) {
171 Node::And(x, y) => {
172 assert!(matches!(s.node(*x), Node::Not(f) if *f == p));
173 assert!(matches!(s.node(*y), Node::Not(f) if *f == q));
174 }
175 other => panic!("expected And, got {other:?}"),
176 },
177 other => panic!("expected Not, got {other:?}"),
178 }
179 }
180
181 #[test]
182 fn empty_conjunction_is_true_and_empty_disjunction_is_false() {
183 let mut s = Store::default();
184 let t = s.tru();
185 let f = s.fls();
186 assert_eq!(s.all(&[]), t, "empty conjunction must be verum");
187 assert_eq!(s.any(&[]), f, "empty disjunction must be falsum");
188 }
189}