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
fn remove_dimension_from_matrix_indexing(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
16
    let Expr::SafeIndex(_, subject, mut indices) = expr.clone() else {
17
        return Err(RuleNotApplicable);
18
    };
19

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

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

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

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

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

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