conjure_core/rules/normalisers/
bool.rs1use 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};
14
15#[register_rule(("Base", 8400))]
21fn remove_double_negation(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
22 match expr {
23 Not(_, contents) => match contents.as_ref() {
24 Not(_, expr_box) => Ok(Reduction::pure(*expr_box.clone())),
25 _ => Err(ApplicationError::RuleNotApplicable),
26 },
27 _ => Err(ApplicationError::RuleNotApplicable),
28 }
29}
30
31#[register_rule(("Base", 8400))]
37fn distribute_or_over_and(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
38 fn find_and(exprs: &[Expr]) -> Option<usize> {
39 for (i, e) in exprs.iter().enumerate() {
41 if let And(_, _) = e {
42 return Some(i);
43 }
44 }
45 None
46 }
47
48 match expr {
49 Or(_, exprs) => match find_and(exprs) {
50 Some(idx) => {
51 let mut rest = exprs.clone();
52 let and_expr = rest.remove(idx);
53
54 match and_expr {
55 And(metadata, and_exprs) => {
56 let mut new_and_contents = Vec::new();
57
58 for e in and_exprs {
59 let mut new_or_contents = rest.clone();
61 new_or_contents.push(e.clone());
62 new_and_contents.push(Or(metadata.clone_dirty(), new_or_contents))
63 }
64
65 Ok(Reduction::pure(And(
66 metadata.clone_dirty(),
67 new_and_contents,
68 )))
69 }
70 _ => Err(ApplicationError::RuleNotApplicable),
71 }
72 }
73 None => Err(ApplicationError::RuleNotApplicable),
74 },
75 _ => Err(ApplicationError::RuleNotApplicable),
76 }
77}
78
79#[register_rule(("Base", 8400))]
85fn distribute_not_over_and(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
86 for child in expr.universe() {
87 if matches!(
88 child,
89 Expr::UnsafeDiv(_, _, _) | Expr::Bubble(_, _, _) | Expr::UnsafeMod(_, _, _)
90 ) {
91 return Err(RuleNotApplicable);
92 }
93 }
94 match expr {
95 Not(_, contents) => match contents.as_ref() {
96 And(metadata, exprs) => {
97 if exprs.len() == 1 {
98 let single_expr = exprs[0].clone();
99 return Ok(Reduction::pure(Not(
100 Metadata::new(),
101 Box::new(single_expr.clone()),
102 )));
103 }
104 let mut new_exprs = Vec::new();
105 for e in exprs {
106 new_exprs.push(Not(metadata.clone(), Box::new(e.clone())));
107 }
108 Ok(Reduction::pure(Or(metadata.clone(), new_exprs)))
109 }
110 _ => Err(ApplicationError::RuleNotApplicable),
111 },
112 _ => Err(ApplicationError::RuleNotApplicable),
113 }
114}
115
116#[register_rule(("Base", 8400))]
122fn distribute_not_over_or(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
123 match expr {
124 Not(_, contents) => match contents.as_ref() {
125 Or(metadata, exprs) => {
126 if exprs.len() == 1 {
127 let single_expr = exprs[0].clone();
128 return Ok(Reduction::pure(Not(
129 Metadata::new(),
130 Box::new(single_expr.clone()),
131 )));
132 }
133 let mut new_exprs = Vec::new();
134 for e in exprs {
135 new_exprs.push(Not(metadata.clone(), Box::new(e.clone())));
136 }
137 Ok(Reduction::pure(And(metadata.clone(), new_exprs)))
138 }
139 _ => Err(ApplicationError::RuleNotApplicable),
140 },
141 _ => Err(ApplicationError::RuleNotApplicable),
142 }
143}
144
145#[register_rule(("Base", 8800))]
151fn remove_unit_vector_and(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
152 match expr {
153 And(_, exprs) => {
154 if exprs.len() == 1 {
155 return Ok(Reduction::pure(exprs[0].clone()));
156 }
157 Err(ApplicationError::RuleNotApplicable)
158 }
159 _ => Err(ApplicationError::RuleNotApplicable),
160 }
161}
162
163#[register_rule(("Base", 8800))]
169fn remove_unit_vector_or(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
170 match expr {
171 Or(_, exprs) if exprs.len() == 1 && !matches!(exprs[0], Or(_, _)) => {
173 Ok(Reduction::pure(exprs[0].clone()))
174 }
175 _ => Err(ApplicationError::RuleNotApplicable),
176 }
177}
178
179#[register_rule(("Base", 8800))]
186fn normalise_implies_contrapositive(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
187 let Expr::Imply(_, e1, e2) = expr else {
188 return Err(RuleNotApplicable);
189 };
190
191 let Expr::Not(_, p) = e1.as_ref() else {
192 return Err(RuleNotApplicable);
193 };
194
195 let Expr::Not(_, q) = e2.as_ref() else {
196 return Err(RuleNotApplicable);
197 };
198
199 if !e1.is_safe() || !e2.is_safe() {
201 return Err(RuleNotApplicable);
202 }
203
204 Ok(Reduction::pure(Expr::Imply(
205 Metadata::new(),
206 q.clone(),
207 p.clone(),
208 )))
209}
210
211#[register_rule(("Base", 8800))]
219fn normalise_implies_negation(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
220 let Expr::Not(_, e1) = expr else {
221 return Err(RuleNotApplicable);
222 };
223
224 let Expr::Imply(_, p, q) = e1.as_ref() else {
225 return Err(RuleNotApplicable);
226 };
227
228 if !e1.is_safe() {
230 return Err(RuleNotApplicable);
231 }
232
233 Ok(Reduction::pure(Expr::And(
234 Metadata::new(),
235 vec![*p.clone(), Expr::Not(Metadata::new(), q.clone())],
236 )))
237}
238
239#[register_rule(("Base", 8800))]
251fn normalise_implies_left_distributivity(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
252 let Expr::Imply(_, e1, e2) = expr else {
253 return Err(RuleNotApplicable);
254 };
255
256 let Expr::Imply(_, r1, p) = e1.as_ref() else {
257 return Err(RuleNotApplicable);
258 };
259
260 let Expr::Imply(_, r2, q) = e2.as_ref() else {
261 return Err(RuleNotApplicable);
262 };
263
264 let r1_atom: &Atom = r1.as_ref().try_into().or(Err(RuleNotApplicable))?;
268 let r2_atom: &Atom = r2.as_ref().try_into().or(Err(RuleNotApplicable))?;
269
270 if !(r1_atom == r2_atom) {
271 return Err(RuleNotApplicable);
272 }
273
274 Ok(Reduction::pure(Expr::Imply(
275 Metadata::new(),
276 r1.clone(),
277 Box::new(Expr::Imply(Metadata::new(), p.clone(), q.clone())),
278 )))
279}
280
281#[register_rule(("Base", 8400))]
308fn normalise_implies_uncurry(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
309 let Expr::Imply(_, p, e1) = expr else {
310 return Err(RuleNotApplicable);
311 };
312
313 let Expr::Imply(_, q, r) = e1.as_ref() else {
314 return Err(RuleNotApplicable);
315 };
316
317 Ok(Reduction::pure(Expr::Imply(
318 Metadata::new(),
319 Box::new(Expr::And(Metadata::new(), vec![*p.clone(), *q.clone()])),
320 r.clone(),
321 )))
322}