1
use conjure_core::ast::Expression;
2
use conjure_core::metadata::Metadata;
3
use conjure_core::rule_engine::{
4
    register_rule, ApplicationError, ApplicationError::RuleNotApplicable, ApplicationResult,
5
    Reduction,
6
};
7
use itertools::{izip, Itertools as _};
8

            
9
use crate::ast::{Domain, SymbolTable};
10
use crate::{bug, into_matrix_expr};
11

            
12
/// Converts an unsafe index to a safe index using a bubble expression.
13
#[register_rule(("Bubble", 6000))]
14
316098
fn index_to_bubble(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
15
316098
    let Expression::UnsafeIndex(_, subject, indices) = expr else {
16
315756
        return Err(RuleNotApplicable);
17
    };
18

            
19
342
    let domain = subject
20
342
        .domain_of(symbols)
21
342
        .ok_or(ApplicationError::DomainError)?;
22

            
23
216
    let Domain::DomainMatrix(_, index_domains) = domain else {
24
        bug!("subject of an index expression should have a matrix domain. subject: {:?}, with domain: {:?}", subject, domain);
25
    };
26

            
27
216
    assert_eq!(index_domains.len(),indices.len(),"in an index expression, there should be the same number of indices as the subject has index domains");
28

            
29
216
    let bubble_constraints = Box::new(into_matrix_expr![izip!(index_domains, indices)
30
324
        .map(|(domain, index)| {
31
324
            Expression::InDomain(Metadata::new(), Box::new(index.clone()), domain)
32
324
        })
33
216
        .collect_vec()]);
34
216

            
35
216
    let new_expr = Box::new(Expression::SafeIndex(
36
216
        Metadata::new(),
37
216
        subject.clone(),
38
216
        indices.clone(),
39
216
    ));
40
216

            
41
216
    Ok(Reduction::pure(Expression::Bubble(
42
216
        Metadata::new(),
43
216
        new_expr,
44
216
        Box::new(Expression::And(Metadata::new(), bubble_constraints)),
45
216
    )))
46
316098
}
47

            
48
/// Converts an unsafe slice to a safe slice using a bubble expression.
49
#[register_rule(("Bubble", 6000))]
50
316098
fn slice_to_bubble(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
51
316098
    let Expression::UnsafeSlice(_, subject, indices) = expr else {
52
315792
        return Err(RuleNotApplicable);
53
    };
54

            
55
306
    let domain = subject
56
306
        .domain_of(symbols)
57
306
        .ok_or(ApplicationError::DomainError)?;
58

            
59
306
    let Domain::DomainMatrix(_, index_domains) = domain else {
60
        bug!("subject of a slice expression should have a matrix domain. subject: {:?}, with domain: {:?}", subject, domain);
61
    };
62

            
63
306
    assert_eq!(index_domains.len(),indices.len(),"in a slice expression, there should be the same number of indices as the subject has index domains");
64

            
65
    // the wildcard dimension doesn't need a constraint.
66
306
    let bubble_constraints = Box::new(into_matrix_expr![izip!(index_domains, indices)
67
612
        .filter_map(|(domain, index)| {
68
612
            index
69
612
                .clone()
70
612
                .map(|index| Expression::InDomain(Metadata::new(), Box::new(index.clone()), domain))
71
612
        })
72
306
        .collect_vec()]);
73
306

            
74
306
    let new_expr = Box::new(Expression::SafeSlice(
75
306
        Metadata::new(),
76
306
        subject.clone(),
77
306
        indices.clone(),
78
306
    ));
79
306

            
80
306
    Ok(Reduction::pure(Expression::Bubble(
81
306
        Metadata::new(),
82
306
        new_expr,
83
306
        Box::new(Expression::And(Metadata::new(), bubble_constraints)),
84
306
    )))
85
316098
}