1
//! Generic normalising rules for associative-commutative operators.
2

            
3
use std::mem::Discriminant;
4

            
5
use crate::utils::{single_vec_child, with_single_vec_child};
6
use conjure_cp::ast::{Expression as Expr, SymbolTable};
7
use conjure_cp::rule_engine::{
8
    ApplicationError::RuleNotApplicable, ApplicationResult, Reduction, register_rule,
9
};
10

            
11
/// Normalises associative_commutative operations.
12
///
13
/// For now, this just removes nested expressions by associativity.
14
///
15
/// ```text
16
/// v(v(a,b,...),c,d,...) ~> v(a,b,c,d)
17
/// where v is an AC vector operator
18
/// ```
19
#[register_rule("Base", 8900, [And, Or, Product, Sum])]
20
2430989
fn normalise_associative_commutative(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
21
2430989
    if !expr.is_associative_commutative_operator() {
22
2228334
        return Err(RuleNotApplicable);
23
202655
    }
24

            
25
    // remove nesting deeply
26
601104
    fn recurse_deeply(
27
601104
        root_discriminant: Discriminant<Expr>,
28
601104
        expr: Expr,
29
601104
        changed: &mut bool,
30
601104
    ) -> Vec<Expr> {
31
        // if expr a different expression type, stop recursing
32
601104
        if std::mem::discriminant(&expr) != root_discriminant {
33
411667
            return vec![expr];
34
189437
        }
35

            
36
189437
        let Some(children) = single_vec_child(&expr) else {
37
1900
            return vec![expr];
38
        };
39
187537
        let old_len = children.len();
40

            
41
187537
        let new_children = children
42
187537
            .into_iter()
43
415847
            .flat_map(|child| recurse_deeply(root_discriminant, child, changed))
44
187537
            .collect::<Vec<_>>();
45
187537
        if new_children.len() != old_len {
46
2200
            *changed = true;
47
185337
        }
48

            
49
187537
        new_children
50
601104
    }
51

            
52
202655
    if single_vec_child(expr).is_none() {
53
17398
        return Err(RuleNotApplicable);
54
185257
    }
55

            
56
185257
    let mut changed = false;
57
185257
    let new_children = recurse_deeply(std::mem::discriminant(expr), expr.clone(), &mut changed);
58

            
59
185257
    if !changed {
60
183287
        return Err(RuleNotApplicable);
61
1970
    }
62

            
63
1970
    let new_expr = with_single_vec_child(expr, new_children);
64

            
65
1970
    Ok(Reduction::pure(new_expr))
66
2430989
}