conjure_core/rules/normalisers/
bool.rs
1use conjure_core::ast::Expression as Expr;
4use conjure_core::metadata::Metadata;
5use conjure_core::rule_engine::{
6 register_rule, ApplicationError, ApplicationError::RuleNotApplicable, ApplicationResult,
7 Reduction,
8};
9use uniplate::Uniplate;
10
11use Expr::*;
12
13use crate::ast::{Atom, SymbolTable};
14use crate::{into_matrix_expr, matrix_expr};
15
16#[register_rule(("Base", 8400))]
22fn remove_double_negation(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
23 match expr {
24 Not(_, contents) => match contents.as_ref() {
25 Not(_, expr_box) => Ok(Reduction::pure(*expr_box.clone())),
26 _ => Err(ApplicationError::RuleNotApplicable),
27 },
28 _ => Err(ApplicationError::RuleNotApplicable),
29 }
30}
31
32#[register_rule(("Base", 8400))]
38fn distribute_or_over_and(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
39 fn find_and(exprs: &[Expr]) -> Option<usize> {
40 for (i, e) in exprs.iter().enumerate() {
42 if let And(_, _) = e {
43 return Some(i);
44 }
45 }
46 None
47 }
48
49 match expr {
50 Or(_, e) => {
51 let Some(exprs) = e.as_ref().clone().unwrap_list() else {
52 return Err(RuleNotApplicable);
53 };
54
55 match find_and(&exprs) {
56 Some(idx) => {
57 let mut rest = exprs.clone();
58 let and_expr = rest.remove(idx);
59
60 match and_expr {
61 And(metadata, e) => {
62 let Some(and_exprs) = e.as_ref().clone().unwrap_list() else {
63 return Err(RuleNotApplicable);
64 };
65
66 let mut new_and_contents = Vec::new();
67
68 for e in and_exprs {
69 let mut new_or_contents = rest.clone();
71 new_or_contents.push(e.clone());
72 new_and_contents.push(Or(
73 metadata.clone_dirty(),
74 Box::new(into_matrix_expr![new_or_contents]),
75 ))
76 }
77
78 Ok(Reduction::pure(And(
79 metadata.clone_dirty(),
80 Box::new(into_matrix_expr![new_and_contents]),
81 )))
82 }
83 _ => Err(ApplicationError::RuleNotApplicable),
84 }
85 }
86 None => Err(ApplicationError::RuleNotApplicable),
87 }
88 }
89 _ => Err(ApplicationError::RuleNotApplicable),
90 }
91}
92
93#[register_rule(("Base", 8400))]
99fn distribute_not_over_and(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
100 for child in expr.universe() {
101 if matches!(
102 child,
103 Expr::UnsafeDiv(_, _, _) | Expr::Bubble(_, _, _) | Expr::UnsafeMod(_, _, _)
104 ) {
105 return Err(RuleNotApplicable);
106 }
107 }
108 match expr {
109 Not(_, contents) => match contents.as_ref() {
110 And(metadata, e) => {
111 let Some(exprs) = e.as_ref().clone().unwrap_list() else {
112 return Err(RuleNotApplicable);
113 };
114
115 if exprs.len() == 1 {
116 let single_expr = exprs[0].clone();
117 return Ok(Reduction::pure(Not(
118 Metadata::new(),
119 Box::new(single_expr.clone()),
120 )));
121 }
122 let mut new_exprs = Vec::new();
123 for e in exprs {
124 new_exprs.push(Not(metadata.clone(), Box::new(e.clone())));
125 }
126 Ok(Reduction::pure(Or(
127 metadata.clone(),
128 Box::new(into_matrix_expr![new_exprs]),
129 )))
130 }
131 _ => Err(ApplicationError::RuleNotApplicable),
132 },
133 _ => Err(ApplicationError::RuleNotApplicable),
134 }
135}
136
137#[register_rule(("Base", 8400))]
143fn distribute_not_over_or(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
144 match expr {
145 Not(_, contents) => match contents.as_ref() {
146 Or(metadata, e) => {
147 let Some(exprs) = e.as_ref().clone().unwrap_list() else {
148 return Err(RuleNotApplicable);
149 };
150
151 if exprs.len() == 1 {
152 let single_expr = exprs[0].clone();
153 return Ok(Reduction::pure(Not(
154 Metadata::new(),
155 Box::new(single_expr.clone()),
156 )));
157 }
158
159 let mut new_exprs = Vec::new();
160
161 for e in exprs {
162 new_exprs.push(Not(metadata.clone(), Box::new(e.clone())));
163 }
164
165 Ok(Reduction::pure(And(
166 metadata.clone(),
167 Box::new(into_matrix_expr![new_exprs]),
168 )))
169 }
170 _ => Err(ApplicationError::RuleNotApplicable),
171 },
172 _ => Err(ApplicationError::RuleNotApplicable),
173 }
174}
175
176#[register_rule(("Base", 8800))]
182fn remove_unit_vector_and(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
183 match expr {
184 And(_, e) => {
185 let Some(exprs) = e.as_ref().clone().unwrap_list() else {
186 return Err(RuleNotApplicable);
187 };
188
189 if exprs.len() == 1 {
190 return Ok(Reduction::pure(exprs[0].clone()));
191 }
192
193 Err(ApplicationError::RuleNotApplicable)
194 }
195 _ => Err(ApplicationError::RuleNotApplicable),
196 }
197}
198
199#[register_rule(("Base", 8800))]
205fn remove_unit_vector_or(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
206 let Expr::Or(_, e) = expr else {
207 return Err(RuleNotApplicable);
208 };
209
210 let Some(exprs) = e.as_ref().clone().unwrap_list() else {
211 return Err(RuleNotApplicable);
212 };
213
214 if exprs.len() != 1 || matches!(exprs[0], Expr::Or(_, _)) {
216 return Err(RuleNotApplicable);
217 }
218
219 Ok(Reduction::pure(exprs[0].clone()))
220}
221
222#[register_rule(("Base", 8800))]
229fn normalise_implies_contrapositive(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
230 let Expr::Imply(_, e1, e2) = expr else {
231 return Err(RuleNotApplicable);
232 };
233
234 let Expr::Not(_, p) = e1.as_ref() else {
235 return Err(RuleNotApplicable);
236 };
237
238 let Expr::Not(_, q) = e2.as_ref() else {
239 return Err(RuleNotApplicable);
240 };
241
242 if !e1.is_safe() || !e2.is_safe() {
244 return Err(RuleNotApplicable);
245 }
246
247 Ok(Reduction::pure(Expr::Imply(
248 Metadata::new(),
249 q.clone(),
250 p.clone(),
251 )))
252}
253
254#[register_rule(("Base", 8800))]
262fn normalise_implies_negation(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
263 let Expr::Not(_, e1) = expr else {
264 return Err(RuleNotApplicable);
265 };
266
267 let Expr::Imply(_, p, q) = e1.as_ref() else {
268 return Err(RuleNotApplicable);
269 };
270
271 if !e1.is_safe() {
273 return Err(RuleNotApplicable);
274 }
275
276 Ok(Reduction::pure(Expr::And(
277 Metadata::new(),
278 Box::new(matrix_expr![
279 *p.clone(),
280 Expr::Not(Metadata::new(), q.clone())
281 ]),
282 )))
283}
284
285#[register_rule(("Base", 8800))]
297fn normalise_implies_left_distributivity(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
298 let Expr::Imply(_, e1, e2) = expr else {
299 return Err(RuleNotApplicable);
300 };
301
302 let Expr::Imply(_, r1, p) = e1.as_ref() else {
303 return Err(RuleNotApplicable);
304 };
305
306 let Expr::Imply(_, r2, q) = e2.as_ref() else {
307 return Err(RuleNotApplicable);
308 };
309
310 let r1_atom: &Atom = r1.as_ref().try_into().or(Err(RuleNotApplicable))?;
314 let r2_atom: &Atom = r2.as_ref().try_into().or(Err(RuleNotApplicable))?;
315
316 if !(r1_atom == r2_atom) {
317 return Err(RuleNotApplicable);
318 }
319
320 Ok(Reduction::pure(Expr::Imply(
321 Metadata::new(),
322 r1.clone(),
323 Box::new(Expr::Imply(Metadata::new(), p.clone(), q.clone())),
324 )))
325}
326
327#[register_rule(("Base", 8400))]
354fn normalise_implies_uncurry(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
355 let Expr::Imply(_, p, e1) = expr else {
356 return Err(RuleNotApplicable);
357 };
358
359 let Expr::Imply(_, q, r) = e1.as_ref() else {
360 return Err(RuleNotApplicable);
361 };
362
363 Ok(Reduction::pure(Expr::Imply(
364 Metadata::new(),
365 Box::new(Expr::And(
366 Metadata::new(),
367 Box::new(matrix_expr![*p.clone(), *q.clone()]),
368 )),
369 r.clone(),
370 )))
371}