1
//! Comprehension expansion rules
2

            
3
mod expand_ac;
4
mod expand_simple;
5

            
6
pub use expand_ac::expand_ac;
7
pub use expand_simple::expand_simple;
8

            
9
use std::collections::VecDeque;
10

            
11
use conjure_cp::{
12
    ast::{Expression as Expr, SymbolTable, comprehension::Comprehension},
13
    into_matrix_expr,
14
    rule_engine::{
15
        ApplicationError::RuleNotApplicable, ApplicationResult, Reduction, register_rule,
16
    },
17
};
18
use uniplate::Biplate;
19

            
20
use uniplate::Uniplate;
21

            
22
use conjure_cp::rule_engine::register_rule_set;
23

            
24
// optimised comprehension expansion for associative-commutative operators
25
register_rule_set!("Better_AC_Comprehension_Expansion", ("Base"));
26

            
27
/// Expand compatible comprehensions using ac optimisations / Comprehension::expand_ac.
28
#[register_rule(("Better_AC_Comprehension_Expansion", 2001))]
29
fn expand_comprehension_ac(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
30
    // Is this an ac expression?
31
    let ac_operator_kind = expr.to_ac_operator_kind().ok_or(RuleNotApplicable)?;
32

            
33
    debug_assert_eq!(
34
        expr.children().len(),
35
        1,
36
        "AC expressions should have exactly one child."
37
    );
38

            
39
    let Expr::Comprehension(_, ref comprehension) = expr.children()[0] else {
40
        return Err(RuleNotApplicable);
41
    };
42

            
43
    // unwrap comprehensions inside out. This reduces calls to minion when rewriting nested
44
    // comprehensions.
45
    let nested_comprehensions: VecDeque<Comprehension> =
46
        (**comprehension).clone().return_expression().universe_bi();
47
    if !nested_comprehensions.is_empty() {
48
        return Err(RuleNotApplicable);
49
    };
50

            
51
    // TODO: check what kind of error this throws and maybe panic
52
    let mut symbols = symbols.clone();
53
    let results = expand_ac((**comprehension).clone(), &mut symbols, ac_operator_kind)
54
        .or(Err(RuleNotApplicable))?;
55

            
56
    let new_expr = ac_operator_kind.as_expression(into_matrix_expr!(results));
57
    Ok(Reduction::with_symbols(new_expr, symbols))
58
}
59

            
60
#[register_rule(("Base", 2000))]
61
fn expand_comprehension(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
62
    let Expr::Comprehension(_, comprehension) = expr else {
63
        return Err(RuleNotApplicable);
64
    };
65

            
66
    // unwrap comprehensions inside out. This reduces calls to minion when rewriting nested
67
    // comprehensions.
68
    let nested_comprehensions: VecDeque<Comprehension> =
69
        (**comprehension).clone().return_expression().universe_bi();
70
    if !nested_comprehensions.is_empty() {
71
        return Err(RuleNotApplicable);
72
    };
73

            
74
    // TODO: check what kind of error this throws and maybe panic
75

            
76
    let mut symbols = symbols.clone();
77
    let results =
78
        expand_simple(comprehension.as_ref().clone(), &mut symbols).or(Err(RuleNotApplicable))?;
79

            
80
    Ok(Reduction::with_symbols(into_matrix_expr!(results), symbols))
81
}