1
use conjure_core::{ast::Expression as Expr, rule::RuleApplicationError};
2
use conjure_rules::register_rule;
3

            
4
/***********************************************************************************/
5
/*        This file contains rules for converting logic expressions to CNF         */
6
/***********************************************************************************/
7

            
8
/**
9
* Distribute `not` over `and` (De Morgan's Law):
10

            
11
* ```text
12
* not(and(a, b)) = or(not a, not b)
13
* ```
14
 */
15
#[register_rule]
16
fn distribute_not_over_and(expr: &Expr) -> Result<Expr, RuleApplicationError> {
17
    match expr {
18
        Expr::Not(contents) => match contents.as_ref() {
19
            Expr::And(exprs) => {
20
                let mut new_exprs = Vec::new();
21
                for e in exprs {
22
                    new_exprs.push(Expr::Not(Box::new(e.clone())));
23
                }
24
                Ok(Expr::Or(new_exprs))
25
            }
26
            _ => Err(RuleApplicationError::RuleNotApplicable),
27
        },
28
        _ => Err(RuleApplicationError::RuleNotApplicable),
29
    }
30
}
31

            
32
/**
33
* Distribute `not` over `or` (De Morgan's Law):
34

            
35
* ```text
36
* not(or(a, b)) = and(not a, not b)
37
* ```
38
 */
39
#[register_rule]
40
fn distribute_not_over_or(expr: &Expr) -> Result<Expr, RuleApplicationError> {
41
    match expr {
42
        Expr::Not(contents) => match contents.as_ref() {
43
            Expr::Or(exprs) => {
44
                let mut new_exprs = Vec::new();
45
                for e in exprs {
46
                    new_exprs.push(Expr::Not(Box::new(e.clone())));
47
                }
48
                Ok(Expr::And(new_exprs))
49
            }
50
            _ => Err(RuleApplicationError::RuleNotApplicable),
51
        },
52
        _ => Err(RuleApplicationError::RuleNotApplicable),
53
    }
54
}
55

            
56
/**
57
* Apply the Distributive Law to expressions like `Or([..., And(a, b)])`
58

            
59
* ```text
60
* or(and(a, b), c) = and(or(a, c), or(b, c))
61
* ```
62
 */
63
#[register_rule]
64
fn distribute_or_over_and(expr: &Expr) -> Result<Expr, RuleApplicationError> {
65
    fn find_and(exprs: &Vec<Expr>) -> Option<usize> {
66
        // ToDo: may be better to move this to some kind of utils module?
67
        for (i, e) in exprs.iter().enumerate() {
68
            match e {
69
                Expr::And(_) => return Some(i),
70
                _ => (),
71
            }
72
        }
73
        None
74
    }
75

            
76
    match expr {
77
        Expr::Or(exprs) => match find_and(exprs) {
78
            Some(idx) => {
79
                let mut rest = exprs.clone();
80
                let and_expr = rest.remove(idx);
81

            
82
                match and_expr {
83
                    Expr::And(and_exprs) => {
84
                        let mut new_and_contents = Vec::new();
85

            
86
                        for e in and_exprs {
87
                            // ToDo: Cloning everything may be a bit inefficient - discuss
88
                            let mut new_or_contents = rest.clone();
89
                            new_or_contents.push(e.clone());
90
                            new_and_contents.push(Expr::Or(new_or_contents))
91
                        }
92

            
93
                        Ok(Expr::And(new_and_contents))
94
                    }
95
                    _ => Err(RuleApplicationError::RuleNotApplicable),
96
                }
97
            }
98
            None => Err(RuleApplicationError::RuleNotApplicable),
99
        },
100
        _ => Err(RuleApplicationError::RuleNotApplicable),
101
    }
102
}