1
//! Preserve numeric table relations until library clause generation.
2
use crate::shared::utils::{
3
    checked_short_table_row, table_operand, table_ordered_entries, table_rows,
4
};
5
use conjure_cp::ast::{Atom, Expression as Expr, Literal, SatEncodingDecision, SymbolTable};
6
use conjure_cp::rule_engine::{
7
    ApplicationError::RuleNotApplicable, ApplicationResult, RuleEffect, register_rule,
8
};
9

            
10
/// Omitted short-table positions compare the input with itself rather than expanding its domain.
11
#[register_rule("SAT", 18500, [ShortTable])]
12
18641
fn expand_short_table(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
13
18641
    let Expr::ShortTable(_, tuple, rows) = expr else {
14
21
        return Err(RuleNotApplicable);
15
    };
16
18620
    let inputs = table_ordered_entries(tuple).ok_or(RuleNotApplicable)?;
17
14700
    let rows = table_rows(rows).ok_or(RuleNotApplicable)?;
18
14700
    let rows = rows
19
14700
        .into_iter()
20
22540
        .map(|row| {
21
22540
            let mut values = inputs.clone();
22
22540
            for (position, value) in checked_short_table_row(&row, inputs.len())? {
23
38220
                values[position] = value;
24
            }
25
22540
            Some(conjure_cp::into_matrix_expr!(values))
26
22540
        })
27
        .collect::<Option<Vec<_>>>()
28
14700
        .ok_or(RuleNotApplicable)?;
29
14700
    Ok(RuleEffect::pure(Expr::Table(
30
14700
        conjure_cp::ast::Metadata::new(),
31
14700
        tuple.clone(),
32
14700
        conjure_cp::ast::Moo::new(conjure_cp::into_matrix_expr!(rows)),
33
14700
    )))
34
18641
}
35

            
36
300524
fn cell_value(expression: &Expr) -> Option<i64> {
37
300524
    let expression = table_operand(expression);
38
300524
    match expression {
39
248864
        Expr::Atomic(_, Atom::Literal(Literal::Int(value))) => Some(i64::from(value)),
40
        Expr::Atomic(_, Atom::Literal(Literal::Bool(value))) => Some(i64::from(value)),
41
        expression => {
42
51660
            let view = super::pseudo_boolean::integer_view(&expression)?;
43
36750
            view.terms.is_empty().then_some(view.constant)
44
        }
45
    }
46
300524
}
47

            
48
/// Both signs retain a Boolean output for nested and reified uses.
49
#[register_rule("SAT", 18500, [Table, NegativeTable])]
50
332577
fn select_table(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
51
332577
    let (tuple, rows, negative) = match expr {
52
270851
        Expr::Table(_, tuple, rows) => (tuple, rows, false),
53
61705
        Expr::NegativeTable(_, tuple, rows) => (tuple, rows, true),
54
21
        _ => return Err(RuleNotApplicable),
55
    };
56
332556
    let tuple = table_ordered_entries(tuple).ok_or(RuleNotApplicable)?;
57
326676
    let inputs = tuple
58
326676
        .iter()
59
326676
        .map(super::pseudo_boolean::integer_view)
60
326676
        .collect::<Option<Vec<_>>>()
61
326676
        .ok_or(RuleNotApplicable)?;
62
81158
    let rows = table_rows(rows).ok_or(RuleNotApplicable)?;
63
81158
    let row_expressions = rows
64
81158
        .iter()
65
229838
        .map(|row| {
66
229838
            let row = table_ordered_entries(row)?;
67
229838
            (row.len() == inputs.len()).then_some(row)
68
229838
        })
69
        .collect::<Option<Vec<_>>>()
70
81158
        .ok_or(RuleNotApplicable)?;
71
81158
    let constants = row_expressions
72
81158
        .iter()
73
131138
        .map(|row| row.iter().map(cell_value).collect::<Option<Vec<_>>>())
74
        .collect::<Option<Vec<_>>>();
75
81158
    let (rows, row_views) = if let Some(rows) = constants {
76
29498
        (rows, None)
77
    } else {
78
51660
        let views = row_expressions
79
51660
            .iter()
80
92470
            .map(|row| {
81
92470
                row.iter()
82
92470
                    .map(super::pseudo_boolean::integer_view)
83
92470
                    .collect::<Option<Vec<_>>>()
84
92470
            })
85
            .collect::<Option<Vec<_>>>()
86
51660
            .ok_or(RuleNotApplicable)?;
87
12740
        (vec![], Some(views))
88
    };
89
42238
    let mut symbols = symbols.clone();
90
42238
    let output = super::boolean::create_bool_aux(&mut symbols);
91
42238
    Ok(RuleEffect::sat(
92
42238
        output.clone(),
93
42238
        vec![SatEncodingDecision::Table {
94
42238
            output,
95
42238
            inputs,
96
42238
            rows,
97
42238
            row_views,
98
42238
            negative,
99
42238
            encoding: None,
100
42238
            pb_encoding: None,
101
42238
        }],
102
42238
        symbols,
103
42238
    ))
104
332577
}