1
use std::collections::HashSet;
2

            
3
use conjure_macros::register_rule;
4

            
5
use crate::ast::{Expression as Expr, Factor, Literal::*};
6
use crate::rule_engine::{ApplicationResult, Reduction};
7
use crate::Model;
8

            
9
#[register_rule(("Base",9000))]
10
7250595
fn partial_evaluator(expr: &Expr, _: &Model) -> ApplicationResult {
11
    use conjure_core::rule_engine::ApplicationError::RuleNotApplicable;
12
    use Expr::*;
13

            
14
    // NOTE: If nothing changes, we must return RuleNotApplicable, or the rewriter will try this
15
    // rule infinitely!
16
    // This is why we always check whether we found a constant or not.
17
7250595
    match expr.clone() {
18
90
        Bubble(_, _, _) => Err(RuleNotApplicable),
19
5412165
        FactorE(_, _) => Err(RuleNotApplicable),
20
180
        Sum(m, vec) => {
21
180
            let mut acc = 0;
22
180
            let mut n_consts = 0;
23
180
            let mut new_vec: Vec<Expr> = Vec::new();
24
690
            for expr in vec {
25
240
                if let Expr::FactorE(_, Factor::Literal(Int(x))) = expr {
26
240
                    acc += x;
27
240
                    n_consts += 1;
28
270
                } else {
29
270
                    new_vec.push(expr);
30
270
                }
31
            }
32
180
            if acc != 0 {
33
150
                new_vec.push(Expr::FactorE(Default::default(), Factor::Literal(Int(acc))));
34
150
            }
35

            
36
180
            if n_consts <= 1 {
37
120
                Err(RuleNotApplicable)
38
            } else {
39
60
                Ok(Reduction::pure(Sum(m, new_vec)))
40
            }
41
        }
42
105
        Min(m, vec) => {
43
105
            let mut acc: Option<i32> = None;
44
105
            let mut n_consts = 0;
45
105
            let mut new_vec: Vec<Expr> = Vec::new();
46
315
            for expr in vec {
47
30
                if let Expr::FactorE(_, Factor::Literal(Int(x))) = expr {
48
30
                    n_consts += 1;
49
30
                    acc = match acc {
50
15
                        Some(i) => {
51
15
                            if i > x {
52
                                Some(x)
53
                            } else {
54
15
                                Some(i)
55
                            }
56
                        }
57
15
                        None => Some(x),
58
                    };
59
180
                } else {
60
180
                    new_vec.push(expr);
61
180
                }
62
            }
63

            
64
105
            if let Some(i) = acc {
65
15
                new_vec.push(Expr::FactorE(Default::default(), Factor::Literal(Int(i))));
66
90
            }
67

            
68
105
            if n_consts <= 1 {
69
90
                Err(RuleNotApplicable)
70
            } else {
71
15
                Ok(Reduction::pure(Min(m, new_vec)))
72
            }
73
        }
74
60
        Max(m, vec) => {
75
60
            let mut acc: Option<i32> = None;
76
60
            let mut n_consts = 0;
77
60
            let mut new_vec: Vec<Expr> = Vec::new();
78
180
            for expr in vec {
79
15
                if let Expr::FactorE(_, Factor::Literal(Int(x))) = expr {
80
15
                    n_consts += 1;
81
15
                    acc = match acc {
82
                        Some(i) => {
83
                            if i < x {
84
                                Some(x)
85
                            } else {
86
                                Some(i)
87
                            }
88
                        }
89
15
                        None => Some(x),
90
                    };
91
105
                } else {
92
105
                    new_vec.push(expr);
93
105
                }
94
            }
95

            
96
60
            if let Some(i) = acc {
97
15
                new_vec.push(Expr::FactorE(Default::default(), Factor::Literal(Int(i))));
98
45
            }
99

            
100
60
            if n_consts <= 1 {
101
60
                Err(RuleNotApplicable)
102
            } else {
103
                Ok(Reduction::pure(Max(m, new_vec)))
104
            }
105
        }
106
60
        Not(_, _) => Err(RuleNotApplicable),
107
377910
        Or(m, vec) => {
108
377910
            let mut new_vec: Vec<Expr> = Vec::new();
109
377910
            let mut has_const: bool = false;
110
1846710
            for expr in vec {
111
60
                if let Expr::FactorE(_, Factor::Literal(Bool(x))) = expr {
112
60
                    has_const = true;
113
60
                    if x {
114
30
                        return Ok(Reduction::pure(FactorE(
115
30
                            Default::default(),
116
30
                            Factor::Literal(Bool(true)),
117
30
                        )));
118
30
                    }
119
1468770
                } else {
120
1468770
                    new_vec.push(expr);
121
1468770
                }
122
            }
123

            
124
377880
            if !has_const {
125
377850
                Err(RuleNotApplicable)
126
            } else {
127
30
                Ok(Reduction::pure(Or(m, new_vec)))
128
            }
129
        }
130
16755
        And(m, vec) => {
131
16755
            let mut new_vec: Vec<Expr> = Vec::new();
132
16755
            let mut has_const: bool = false;
133
541650
            for expr in vec {
134
60
                if let Expr::FactorE(_, Factor::Literal(Bool(x))) = expr {
135
60
                    has_const = true;
136
60
                    if !x {
137
                        return Ok(Reduction::pure(FactorE(
138
                            Default::default(),
139
                            Factor::Literal(Bool(false)),
140
                        )));
141
60
                    }
142
524835
                } else {
143
524835
                    new_vec.push(expr);
144
524835
                }
145
            }
146

            
147
16755
            if !has_const {
148
16695
                Err(RuleNotApplicable)
149
            } else {
150
60
                Ok(Reduction::pure(And(m, new_vec)))
151
            }
152
        }
153
3675
        Eq(_, _, _) => Err(RuleNotApplicable),
154
195
        Neq(_, _, _) => Err(RuleNotApplicable),
155
225
        Geq(_, _, _) => Err(RuleNotApplicable),
156
315
        Leq(_, _, _) => Err(RuleNotApplicable),
157
        Gt(_, _, _) => Err(RuleNotApplicable),
158
2730
        Lt(_, _, _) => Err(RuleNotApplicable),
159
        SafeDiv(_, _, _) => Err(RuleNotApplicable),
160
105
        UnsafeDiv(_, _, _) => Err(RuleNotApplicable),
161
2820
        SumEq(m, vec, eq) => {
162
2820
            let mut acc = 0;
163
2820
            let mut new_vec: Vec<Expr> = Vec::new();
164
2820
            let mut n_consts = 0;
165
11265
            for expr in vec {
166
75
                if let Expr::FactorE(_, Factor::Literal(Int(x))) = expr {
167
75
                    n_consts += 1;
168
75
                    acc += x;
169
8370
                } else {
170
8370
                    new_vec.push(expr);
171
8370
                }
172
            }
173

            
174
2805
            if let Expr::FactorE(_, Factor::Literal(Int(x))) = *eq {
175
2805
                if acc != 0 {
176
                    // when rhs is a constant, move lhs constants to rhs
177
30
                    return Ok(Reduction::pure(SumEq(
178
30
                        m,
179
30
                        new_vec,
180
30
                        Box::new(Expr::FactorE(
181
30
                            Default::default(),
182
30
                            Factor::Literal(Int(x - acc)),
183
30
                        )),
184
30
                    )));
185
2775
                }
186
15
            } else if acc != 0 {
187
15
                new_vec.push(Expr::FactorE(Default::default(), Factor::Literal(Int(acc))));
188
15
            }
189

            
190
2790
            if n_consts <= 1 {
191
2790
                Err(RuleNotApplicable)
192
            } else {
193
                Ok(Reduction::pure(SumEq(m, new_vec, eq)))
194
            }
195
        }
196
566985
        SumGeq(m, vec, geq) => {
197
566985
            let mut acc = 0;
198
566985
            let mut new_vec: Vec<Expr> = Vec::new();
199
566985
            let mut n_consts = 0;
200
2267760
            for expr in vec {
201
135
                if let Expr::FactorE(_, Factor::Literal(Int(x))) = expr {
202
135
                    n_consts += 1;
203
135
                    acc += x;
204
1700640
                } else {
205
1700640
                    new_vec.push(expr);
206
1700640
                }
207
            }
208

            
209
566835
            if let Expr::FactorE(_, Factor::Literal(Int(x))) = *geq {
210
566835
                if acc != 0 {
211
                    // when rhs is a constant, move lhs constants to rhs
212
                    return Ok(Reduction::pure(SumGeq(
213
                        m,
214
                        new_vec,
215
                        Box::new(Expr::FactorE(
216
                            Default::default(),
217
                            Factor::Literal(Int(x - acc)),
218
                        )),
219
                    )));
220
566835
                }
221
150
            } else if acc != 0 {
222
135
                new_vec.push(Expr::FactorE(Default::default(), Factor::Literal(Int(acc))));
223
135
            }
224

            
225
566985
            if n_consts <= 1 {
226
566985
                Err(RuleNotApplicable)
227
            } else {
228
                Ok(Reduction::pure(SumGeq(m, new_vec, geq)))
229
            }
230
        }
231
547350
        SumLeq(m, vec, leq) => {
232
547350
            let mut acc = 0;
233
547350
            let mut new_vec: Vec<Expr> = Vec::new();
234
547350
            let mut n_consts = 0;
235
2189040
            for expr in vec {
236
150
                if let Expr::FactorE(_, Factor::Literal(Int(x))) = expr {
237
150
                    n_consts += 1;
238
150
                    acc += x;
239
1641540
                } else {
240
1641540
                    new_vec.push(expr);
241
1641540
                }
242
            }
243

            
244
547215
            if let Expr::FactorE(_, Factor::Literal(Int(x))) = *leq {
245
                // when rhs is a constant, move lhs constants to rhs
246
547215
                if acc != 0 {
247
30
                    return Ok(Reduction::pure(SumLeq(
248
30
                        m,
249
30
                        new_vec,
250
30
                        Box::new(Expr::FactorE(
251
30
                            Default::default(),
252
30
                            Factor::Literal(Int(x - acc)),
253
30
                        )),
254
30
                    )));
255
547185
                }
256
135
            } else if acc != 0 {
257
120
                new_vec.push(Expr::FactorE(Default::default(), Factor::Literal(Int(acc))));
258
120
            }
259

            
260
547320
            if n_consts <= 1 {
261
547320
                Err(RuleNotApplicable)
262
            } else {
263
                Ok(Reduction::pure(SumLeq(m, new_vec, leq)))
264
            }
265
        }
266
90
        DivEq(_, _, _, _) => Err(RuleNotApplicable),
267
318075
        Ineq(_, _, _, _) => Err(RuleNotApplicable),
268
        AllDiff(m, vec) => {
269
            let mut consts: HashSet<i32> = HashSet::new();
270

            
271
            // check for duplicate constant values which would fail the constraint
272
            for expr in &vec {
273
                if let Expr::FactorE(_, Factor::Literal(Int(x))) = expr {
274
                    if !consts.insert(*x) {
275
                        return Ok(Reduction::pure(Expr::FactorE(
276
                            m,
277
                            Factor::Literal(Bool(false)),
278
                        )));
279
                    }
280
                }
281
            }
282

            
283
            // nothing has changed
284
            Err(RuleNotApplicable)
285
        }
286

            
287
600
        WatchedLiteral(_, _, _) => Err(RuleNotApplicable),
288
105
        Reify(_, _, _) => Err(RuleNotApplicable),
289
    }
290
7250595
}