1
//! Ordered scalar lex operands and their recursive Boolean comparison.
2
use conjure_cp::ast::{Expression as Expr, matrix::safe_index_optimised};
3
use conjure_cp::essence_expr;
4
use conjure_cp::rule_engine::ApplicationError::{DomainError, RuleNotApplicable};
5

            
6
/// Read a one-dimensional lex operand in its declared order.
7
67258
pub(crate) fn lex_operand_elements(
8
67258
    expr: &Expr,
9
67258
) -> Result<Vec<Expr>, conjure_cp::rule_engine::ApplicationError> {
10
    // Representation rules commonly turn a slice into an explicit matrix literal. Consume that
11
    // literal directly: after an element is replaced by its BV representation its inferred
12
    // Essence domain may temporarily be unavailable, but its list order is still explicit and is
13
    // all lexicographic expansion needs.
14
67258
    if let Some(elements) = expr.unwrap_list() {
15
226
        return Ok(elements);
16
67032
    }
17

            
18
67032
    let domain = expr.domain_of().ok_or(RuleNotApplicable)?;
19
67032
    let Some((_, indices)) = domain.as_matrix_ground() else {
20
9611
        return Err(RuleNotApplicable);
21
    };
22
57421
    if indices.len() != 1 {
23
        return Err(RuleNotApplicable);
24
57421
    }
25

            
26
57421
    indices[0]
27
57421
        .values()
28
119
        .map_err(|_| DomainError)?
29
112280
        .map(|index| safe_index_optimised(expr.clone(), index).ok_or(DomainError))
30
        .collect()
31
67258
}
32

            
33
/// Compare ordered scalar entries, including unequal lengths.
34
181289
pub(crate) fn lex_elements_to_recursive_or(
35
181289
    lhs_elements: &[Expr],
36
181289
    rhs_elements: &[Expr],
37
181289
    allow_equality: bool,
38
181289
) -> Expr {
39
181289
    match (lhs_elements, rhs_elements) {
40
74845
        ([], []) => allow_equality.into(),
41
2016
        ([..], []) => false.into(),
42
1036
        ([], [..]) => true.into(),
43
        ([lhs_element, lhs_tail @ ..], [rhs_element, rhs_tail @ ..]) => {
44
103392
            let tail = lex_elements_to_recursive_or(lhs_tail, rhs_tail, allow_equality);
45
103392
            essence_expr!(r"&lhs_element < &rhs_element \/ (&lhs_element = &rhs_element /\ &tail)")
46
        }
47
    }
48
181289
}