conjure_core/rules/matrix/
bubble.rs

1use conjure_core::ast::Expression;
2use conjure_core::metadata::Metadata;
3use conjure_core::rule_engine::{
4    register_rule, ApplicationError, ApplicationError::RuleNotApplicable, ApplicationResult,
5    Reduction,
6};
7use itertools::{izip, Itertools as _};
8
9use crate::ast::{Domain, SymbolTable};
10use crate::{bug, into_matrix_expr};
11
12/// Converts an unsafe index to a safe index using a bubble expression.
13#[register_rule(("Bubble", 6000))]
14fn index_to_bubble(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
15    let Expression::UnsafeIndex(_, subject, indices) = expr else {
16        return Err(RuleNotApplicable);
17    };
18
19    let domain = subject
20        .domain_of(symbols)
21        .ok_or(ApplicationError::DomainError)?;
22
23    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    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    let bubble_constraints = Box::new(into_matrix_expr![izip!(index_domains, indices)
30        .map(|(domain, index)| {
31            Expression::InDomain(Metadata::new(), Box::new(index.clone()), domain)
32        })
33        .collect_vec()]);
34
35    let new_expr = Box::new(Expression::SafeIndex(
36        Metadata::new(),
37        subject.clone(),
38        indices.clone(),
39    ));
40
41    Ok(Reduction::pure(Expression::Bubble(
42        Metadata::new(),
43        new_expr,
44        Box::new(Expression::And(Metadata::new(), bubble_constraints)),
45    )))
46}
47
48/// Converts an unsafe slice to a safe slice using a bubble expression.
49#[register_rule(("Bubble", 6000))]
50fn slice_to_bubble(expr: &Expression, symbols: &SymbolTable) -> ApplicationResult {
51    let Expression::UnsafeSlice(_, subject, indices) = expr else {
52        return Err(RuleNotApplicable);
53    };
54
55    let domain = subject
56        .domain_of(symbols)
57        .ok_or(ApplicationError::DomainError)?;
58
59    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    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    let bubble_constraints = Box::new(into_matrix_expr![izip!(index_domains, indices)
67        .filter_map(|(domain, index)| {
68            index
69                .clone()
70                .map(|index| Expression::InDomain(Metadata::new(), Box::new(index.clone()), domain))
71        })
72        .collect_vec()]);
73
74    let new_expr = Box::new(Expression::SafeSlice(
75        Metadata::new(),
76        subject.clone(),
77        indices.clone(),
78    ));
79
80    Ok(Reduction::pure(Expression::Bubble(
81        Metadata::new(),
82        new_expr,
83        Box::new(Expression::And(Metadata::new(), bubble_constraints)),
84    )))
85}