1
use conjure_cp::ast::Metadata;
2
use conjure_cp::ast::{Expression as Expr, Moo, SymbolTable};
3
use conjure_cp::into_matrix_expr;
4
use conjure_cp::rule_engine::{
5
    ApplicationError::RuleNotApplicable, ApplicationResult, Reduction, register_rule,
6
};
7

            
8
/// Removes a dimension from a matrix indexing operation, if the subject of the indexing is a
9
/// matrix literal.
10
///
11
/// ```plain
12
/// [[1,2,3],[4,5,6],[7,8,9]][j,i] ~~> [[1,2,3][i],[4,5,6][i],[7,8,9][i]][j]
13
/// ```
14
#[register_rule(("Base", 2000))]
15
105669
fn remove_dimension_from_matrix_indexing(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
16
105669
    let Expr::SafeIndex(_, subject, mut indices) = expr.clone() else {
17
98397
        return Err(RuleNotApplicable);
18
    };
19

            
20
7272
    if indices.len() < 2 {
21
1809
        return Err(RuleNotApplicable);
22
5463
    };
23

            
24
    // the indicies to use in the replacement expression.
25
5463
    let outer_indices = vec![indices.pop().unwrap()];
26

            
27
    // the indicies to use in the inner expressions.
28
5463
    let inner_indices = indices;
29

            
30
5463
    let (mut es, index_domain) = Moo::unwrap_or_clone(subject)
31
5463
        .unwrap_matrix_unchecked()
32
5463
        .ok_or(RuleNotApplicable)?;
33

            
34
108
    for e in es.iter_mut() {
35
108
        *e = Expr::SafeIndex(Metadata::new(), Moo::new(e.clone()), inner_indices.clone());
36
108
    }
37

            
38
36
    Ok(Reduction::pure(Expr::SafeIndex(
39
36
        Metadata::new(),
40
36
        Moo::new(into_matrix_expr![es;index_domain]),
41
36
        outer_indices,
42
36
    )))
43
105669
}