1
//! Select native encodings beneath asserted conjunctions without flattening the worklist.
2
use conjure_cp::ast::{
3
    AbstractLiteral, Expression as Expr, Metadata, Moo, SatEncodingDecision, SymbolTable,
4
};
5
use conjure_cp::rule_engine::{ApplicationError::RuleNotApplicable, ApplicationResult, RuleEffect};
6

            
7
/// Extract one asserted decision, preserving conjunctions and other Boolean contexts.
8
21143311
pub(super) fn select_asserted(
9
21143311
    expr: &Expr,
10
21143311
    symbols: &SymbolTable,
11
21143311
    select: impl Fn(&Expr) -> Option<SatEncodingDecision>,
12
21143311
) -> ApplicationResult {
13
21143311
    let Expr::Root(_, children) = expr else {
14
63
        return Err(RuleNotApplicable);
15
    };
16
21143248
    for (index, child) in children.iter().enumerate() {
17
174657781
        let Some((replacement, decision)) = select_conjunct(child, &select) else {
18
171492330
            continue;
19
        };
20
3165451
        let mut children = children.clone();
21
3165451
        if replacement == true.into() {
22
3006516
            children.remove(index);
23
        } else {
24
158935
            children[index] = replacement;
25
        }
26
3165451
        return Ok(RuleEffect::sat(
27
3165451
            Expr::Root(Metadata::new(), children),
28
3165451
            vec![decision],
29
3165451
            symbols.clone(),
30
3165451
        ));
31
    }
32
17977797
    Err(RuleNotApplicable)
33
21143311
}
34

            
35
191149536
fn select_conjunct(
36
191149536
    expr: &Expr,
37
191149536
    select: &impl Fn(&Expr) -> Option<SatEncodingDecision>,
38
191149536
) -> Option<(Expr, SatEncodingDecision)> {
39
191149536
    if let Some(decision) = select(expr) {
40
3165451
        return Some((true.into(), decision));
41
187984085
    }
42
187984085
    let Expr::And(metadata, inner) = expr else {
43
179911426
        return None;
44
    };
45
    let Expr::AbstractLiteral(matrix_metadata, AbstractLiteral::Matrix(entries, domain)) =
46
8072659
        inner.as_ref()
47
    else {
48
2867921
        return None;
49
    };
50
5204738
    for (index, entry) in entries.iter().enumerate() {
51
16491755
        let Some((replacement, decision)) = select_conjunct(entry, select) else {
52
16328354
            continue;
53
        };
54
163401
        let mut entries = entries.clone();
55
163401
        entries[index] = replacement;
56
        // Keep the same matrix labels and size; evaluator normalisation removes true later.
57
163401
        let inner = Expr::AbstractLiteral(
58
163401
            matrix_metadata.clone(),
59
163401
            AbstractLiteral::Matrix(entries, domain.clone()),
60
163401
        );
61
163401
        return Some((Expr::And(metadata.clone(), Moo::new(inner)), decision));
62
    }
63
5041337
    None
64
191149536
}