1
use core::panic;
2
use std::collections::HashMap;
3
use std::env;
4
use std::process::exit;
5

            
6
use conjure_core::rules::eval_constant;
7
use conjure_core::solver::SolverFamily;
8
use conjure_oxide::{
9
    ast::*,
10
    get_rule_by_name, get_rules,
11
    rule_engine::{resolve_rule_sets, rewrite_model},
12
    solver::{adaptors, Solver},
13
    utils::testing::save_stats_json,
14
    Metadata, Model, Rule,
15
};
16
use uniplate::Uniplate;
17

            
18
#[test]
19
fn rules_present() {
20
    let rules = get_rules();
21
    assert!(!rules.is_empty());
22
}
23

            
24
#[test]
25
fn sum_of_constants() {
26
    let valid_sum_expression = Expression::Sum(
27
        Metadata::new(),
28
        vec![
29
            Expression::Constant(Metadata::new(), Constant::Int(1)),
30
            Expression::Constant(Metadata::new(), Constant::Int(2)),
31
            Expression::Constant(Metadata::new(), Constant::Int(3)),
32
        ],
33
    );
34

            
35
    let invalid_sum_expression = Expression::Sum(
36
        Metadata::new(),
37
        vec![
38
            Expression::Constant(Metadata::new(), Constant::Int(1)),
39
            Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
40
        ],
41
    );
42

            
43
    match evaluate_sum_of_constants(&valid_sum_expression) {
44
        Some(result) => assert_eq!(result, 6),
45
        None => panic!(),
46
    }
47

            
48
    if evaluate_sum_of_constants(&invalid_sum_expression).is_some() {
49
        panic!()
50
    }
51
}
52

            
53
fn evaluate_sum_of_constants(expr: &Expression) -> Option<i32> {
54
    match expr {
55
        Expression::Sum(_metadata, expressions) => {
56
            let mut sum = 0;
57
            for e in expressions {
58
                match e {
59
                    Expression::Constant(_, Constant::Int(value)) => {
60
                        sum += value;
61
                    }
62
                    _ => return None,
63
                }
64
            }
65
            Some(sum)
66
        }
67
        _ => None,
68
    }
69
}
70

            
71
#[test]
72
fn recursive_sum_of_constants() {
73
    let complex_expression = Expression::Eq(
74
        Metadata::new(),
75
        Box::new(Expression::Sum(
76
            Metadata::new(),
77
            vec![
78
                Expression::Constant(Metadata::new(), Constant::Int(1)),
79
                Expression::Constant(Metadata::new(), Constant::Int(2)),
80
                Expression::Sum(
81
                    Metadata::new(),
82
                    vec![
83
                        Expression::Constant(Metadata::new(), Constant::Int(1)),
84
                        Expression::Constant(Metadata::new(), Constant::Int(2)),
85
                    ],
86
                ),
87
                Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
88
            ],
89
        )),
90
        Box::new(Expression::Constant(Metadata::new(), Constant::Int(3))),
91
    );
92
    let correct_simplified_expression = Expression::Eq(
93
        Metadata::new(),
94
        Box::new(Expression::Sum(
95
            Metadata::new(),
96
            vec![
97
                Expression::Constant(Metadata::new(), Constant::Int(1)),
98
                Expression::Constant(Metadata::new(), Constant::Int(2)),
99
                Expression::Constant(Metadata::new(), Constant::Int(3)),
100
                Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
101
            ],
102
        )),
103
        Box::new(Expression::Constant(Metadata::new(), Constant::Int(3))),
104
    );
105

            
106
    let simplified_expression = simplify_expression(complex_expression.clone());
107
    assert_eq!(simplified_expression, correct_simplified_expression);
108
}
109

            
110
fn simplify_expression(expr: Expression) -> Expression {
111
    match expr {
112
        Expression::Sum(_metadata, expressions) => {
113
            if let Some(result) =
114
                evaluate_sum_of_constants(&Expression::Sum(Metadata::new(), expressions.clone()))
115
            {
116
                Expression::Constant(Metadata::new(), Constant::Int(result))
117
            } else {
118
                Expression::Sum(
119
                    Metadata::new(),
120
                    expressions.into_iter().map(simplify_expression).collect(),
121
                )
122
            }
123
        }
124
        Expression::Eq(_metadata, left, right) => Expression::Eq(
125
            Metadata::new(),
126
            Box::new(simplify_expression(*left)),
127
            Box::new(simplify_expression(*right)),
128
        ),
129
        Expression::Geq(_metadata, left, right) => Expression::Geq(
130
            Metadata::new(),
131
            Box::new(simplify_expression(*left)),
132
            Box::new(simplify_expression(*right)),
133
        ),
134
        _ => expr,
135
    }
136
}
137

            
138
#[test]
139
fn rule_sum_constants() {
140
    let sum_constants = get_rule_by_name("sum_constants").unwrap();
141
    let unwrap_sum = get_rule_by_name("unwrap_sum").unwrap();
142

            
143
    let mut expr = Expression::Sum(
144
        Metadata::new(),
145
        vec![
146
            Expression::Constant(Metadata::new(), Constant::Int(1)),
147
            Expression::Constant(Metadata::new(), Constant::Int(2)),
148
            Expression::Constant(Metadata::new(), Constant::Int(3)),
149
        ],
150
    );
151

            
152
    expr = sum_constants
153
        .apply(&expr, &Model::new_empty(Default::default()))
154
        .unwrap()
155
        .new_expression;
156
    expr = unwrap_sum
157
        .apply(&expr, &Model::new_empty(Default::default()))
158
        .unwrap()
159
        .new_expression;
160

            
161
    assert_eq!(
162
        expr,
163
        Expression::Constant(Metadata::new(), Constant::Int(6))
164
    );
165
}
166

            
167
#[test]
168
fn rule_sum_mixed() {
169
    let sum_constants = get_rule_by_name("sum_constants").unwrap();
170

            
171
    let mut expr = Expression::Sum(
172
        Metadata::new(),
173
        vec![
174
            Expression::Constant(Metadata::new(), Constant::Int(1)),
175
            Expression::Constant(Metadata::new(), Constant::Int(2)),
176
            Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
177
        ],
178
    );
179

            
180
    expr = sum_constants
181
        .apply(&expr, &Model::new_empty(Default::default()))
182
        .unwrap()
183
        .new_expression;
184

            
185
    assert_eq!(
186
        expr,
187
        Expression::Sum(
188
            Metadata::new(),
189
            vec![
190
                Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
191
                Expression::Constant(Metadata::new(), Constant::Int(3)),
192
            ]
193
        )
194
    );
195
}
196

            
197
#[test]
198
fn rule_sum_geq() {
199
    let flatten_sum_geq = get_rule_by_name("flatten_sum_geq").unwrap();
200

            
201
    let mut expr = Expression::Geq(
202
        Metadata::new(),
203
        Box::new(Expression::Sum(
204
            Metadata::new(),
205
            vec![
206
                Expression::Constant(Metadata::new(), Constant::Int(1)),
207
                Expression::Constant(Metadata::new(), Constant::Int(2)),
208
            ],
209
        )),
210
        Box::new(Expression::Constant(Metadata::new(), Constant::Int(3))),
211
    );
212

            
213
    expr = flatten_sum_geq
214
        .apply(&expr, &Model::new_empty(Default::default()))
215
        .unwrap()
216
        .new_expression;
217

            
218
    assert_eq!(
219
        expr,
220
        Expression::SumGeq(
221
            Metadata::new(),
222
            vec![
223
                Expression::Constant(Metadata::new(), Constant::Int(1)),
224
                Expression::Constant(Metadata::new(), Constant::Int(2)),
225
            ],
226
            Box::new(Expression::Constant(Metadata::new(), Constant::Int(3)))
227
        )
228
    );
229
}
230

            
231
///
232
/// Reduce and solve:
233
/// ```text
234
/// find a,b,c : int(1..3)
235
/// such that a + b + c <= 2 + 3 - 1
236
/// such that a < b
237
/// ```
238
#[test]
239
fn reduce_solve_xyz() {
240
    println!("Rules: {:?}", get_rules());
241
    let sum_constants = get_rule_by_name("sum_constants").unwrap();
242
    let unwrap_sum = get_rule_by_name("unwrap_sum").unwrap();
243
    let lt_to_ineq = get_rule_by_name("lt_to_ineq").unwrap();
244
    let sum_leq_to_sumleq = get_rule_by_name("sum_leq_to_sumleq").unwrap();
245

            
246
    // 2 + 3 - 1
247
    let mut expr1 = Expression::Sum(
248
        Metadata::new(),
249
        vec![
250
            Expression::Constant(Metadata::new(), Constant::Int(2)),
251
            Expression::Constant(Metadata::new(), Constant::Int(3)),
252
            Expression::Constant(Metadata::new(), Constant::Int(-1)),
253
        ],
254
    );
255

            
256
    expr1 = sum_constants
257
        .apply(&expr1, &Model::new_empty(Default::default()))
258
        .unwrap()
259
        .new_expression;
260
    expr1 = unwrap_sum
261
        .apply(&expr1, &Model::new_empty(Default::default()))
262
        .unwrap()
263
        .new_expression;
264
    assert_eq!(
265
        expr1,
266
        Expression::Constant(Metadata::new(), Constant::Int(4))
267
    );
268

            
269
    // a + b + c = 4
270
    expr1 = Expression::Leq(
271
        Metadata::new(),
272
        Box::new(Expression::Sum(
273
            Metadata::new(),
274
            vec![
275
                Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
276
                Expression::Reference(Metadata::new(), Name::UserName(String::from("b"))),
277
                Expression::Reference(Metadata::new(), Name::UserName(String::from("c"))),
278
            ],
279
        )),
280
        Box::new(expr1),
281
    );
282
    expr1 = sum_leq_to_sumleq
283
        .apply(&expr1, &Model::new_empty(Default::default()))
284
        .unwrap()
285
        .new_expression;
286
    assert_eq!(
287
        expr1,
288
        Expression::SumLeq(
289
            Metadata::new(),
290
            vec![
291
                Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
292
                Expression::Reference(Metadata::new(), Name::UserName(String::from("b"))),
293
                Expression::Reference(Metadata::new(), Name::UserName(String::from("c"))),
294
            ],
295
            Box::new(Expression::Constant(Metadata::new(), Constant::Int(4)))
296
        )
297
    );
298

            
299
    // a < b
300
    let mut expr2 = Expression::Lt(
301
        Metadata::new(),
302
        Box::new(Expression::Reference(
303
            Metadata::new(),
304
            Name::UserName(String::from("a")),
305
        )),
306
        Box::new(Expression::Reference(
307
            Metadata::new(),
308
            Name::UserName(String::from("b")),
309
        )),
310
    );
311
    expr2 = lt_to_ineq
312
        .apply(&expr2, &Model::new_empty(Default::default()))
313
        .unwrap()
314
        .new_expression;
315
    assert_eq!(
316
        expr2,
317
        Expression::Ineq(
318
            Metadata::new(),
319
            Box::new(Expression::Reference(
320
                Metadata::new(),
321
                Name::UserName(String::from("a"))
322
            )),
323
            Box::new(Expression::Reference(
324
                Metadata::new(),
325
                Name::UserName(String::from("b"))
326
            )),
327
            Box::new(Expression::Constant(Metadata::new(), Constant::Int(-1)))
328
        )
329
    );
330

            
331
    let mut model = Model::new(
332
        HashMap::new(),
333
        Expression::And(Metadata::new(), vec![expr1, expr2]),
334
        Default::default(),
335
    );
336
    model.variables.insert(
337
        Name::UserName(String::from("a")),
338
        DecisionVariable {
339
            domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
340
        },
341
    );
342
    model.variables.insert(
343
        Name::UserName(String::from("b")),
344
        DecisionVariable {
345
            domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
346
        },
347
    );
348
    model.variables.insert(
349
        Name::UserName(String::from("c")),
350
        DecisionVariable {
351
            domain: Domain::IntDomain(vec![Range::Bounded(1, 3)]),
352
        },
353
    );
354

            
355
    let solver: Solver<adaptors::Minion> = Solver::new(adaptors::Minion::new());
356
    let solver = solver.load_model(model).unwrap();
357
    solver.solve(Box::new(|_| true)).unwrap();
358
}
359

            
360
#[test]
361
fn rule_remove_double_negation() {
362
    let remove_double_negation = get_rule_by_name("remove_double_negation").unwrap();
363

            
364
    let mut expr = Expression::Not(
365
        Metadata::new(),
366
        Box::new(Expression::Not(
367
            Metadata::new(),
368
            Box::new(Expression::Constant(Metadata::new(), Constant::Bool(true))),
369
        )),
370
    );
371

            
372
    expr = remove_double_negation
373
        .apply(&expr, &Model::new_empty(Default::default()))
374
        .unwrap()
375
        .new_expression;
376

            
377
    assert_eq!(
378
        expr,
379
        Expression::Constant(Metadata::new(), Constant::Bool(true))
380
    );
381
}
382

            
383
#[test]
384
fn rule_unwrap_nested_or() {
385
    let unwrap_nested_or = get_rule_by_name("unwrap_nested_or").unwrap();
386

            
387
    let mut expr = Expression::Or(
388
        Metadata::new(),
389
        vec![
390
            Expression::Or(
391
                Metadata::new(),
392
                vec![
393
                    Expression::Constant(Metadata::new(), Constant::Bool(true)),
394
                    Expression::Constant(Metadata::new(), Constant::Bool(false)),
395
                ],
396
            ),
397
            Expression::Constant(Metadata::new(), Constant::Bool(true)),
398
        ],
399
    );
400

            
401
    expr = unwrap_nested_or
402
        .apply(&expr, &Model::new_empty(Default::default()))
403
        .unwrap()
404
        .new_expression;
405

            
406
    assert_eq!(
407
        expr,
408
        Expression::Or(
409
            Metadata::new(),
410
            vec![
411
                Expression::Constant(Metadata::new(), Constant::Bool(true)),
412
                Expression::Constant(Metadata::new(), Constant::Bool(false)),
413
                Expression::Constant(Metadata::new(), Constant::Bool(true)),
414
            ]
415
        )
416
    );
417
}
418

            
419
#[test]
420
fn rule_unwrap_nested_and() {
421
    let unwrap_nested_and = get_rule_by_name("unwrap_nested_and").unwrap();
422

            
423
    let mut expr = Expression::And(
424
        Metadata::new(),
425
        vec![
426
            Expression::And(
427
                Metadata::new(),
428
                vec![
429
                    Expression::Constant(Metadata::new(), Constant::Bool(true)),
430
                    Expression::Constant(Metadata::new(), Constant::Bool(false)),
431
                ],
432
            ),
433
            Expression::Constant(Metadata::new(), Constant::Bool(true)),
434
        ],
435
    );
436

            
437
    expr = unwrap_nested_and
438
        .apply(&expr, &Model::new_empty(Default::default()))
439
        .unwrap()
440
        .new_expression;
441

            
442
    assert_eq!(
443
        expr,
444
        Expression::And(
445
            Metadata::new(),
446
            vec![
447
                Expression::Constant(Metadata::new(), Constant::Bool(true)),
448
                Expression::Constant(Metadata::new(), Constant::Bool(false)),
449
                Expression::Constant(Metadata::new(), Constant::Bool(true)),
450
            ]
451
        )
452
    );
453
}
454

            
455
#[test]
456
fn unwrap_nested_or_not_changed() {
457
    let unwrap_nested_or = get_rule_by_name("unwrap_nested_or").unwrap();
458

            
459
    let expr = Expression::Or(
460
        Metadata::new(),
461
        vec![
462
            Expression::Constant(Metadata::new(), Constant::Bool(true)),
463
            Expression::Constant(Metadata::new(), Constant::Bool(false)),
464
        ],
465
    );
466

            
467
    let result = unwrap_nested_or.apply(&expr, &Model::new_empty(Default::default()));
468

            
469
    assert!(result.is_err());
470
}
471

            
472
#[test]
473
fn unwrap_nested_and_not_changed() {
474
    let unwrap_nested_and = get_rule_by_name("unwrap_nested_and").unwrap();
475

            
476
    let expr = Expression::And(
477
        Metadata::new(),
478
        vec![
479
            Expression::Constant(Metadata::new(), Constant::Bool(true)),
480
            Expression::Constant(Metadata::new(), Constant::Bool(false)),
481
        ],
482
    );
483

            
484
    let result = unwrap_nested_and.apply(&expr, &Model::new_empty(Default::default()));
485

            
486
    assert!(result.is_err());
487
}
488

            
489
#[test]
490
fn remove_trivial_and_or() {
491
    let remove_trivial_and = get_rule_by_name("remove_trivial_and").unwrap();
492
    let remove_trivial_or = get_rule_by_name("remove_trivial_or").unwrap();
493

            
494
    let mut expr_and = Expression::And(
495
        Metadata::new(),
496
        vec![Expression::Constant(Metadata::new(), Constant::Bool(true))],
497
    );
498
    let mut expr_or = Expression::Or(
499
        Metadata::new(),
500
        vec![Expression::Constant(Metadata::new(), Constant::Bool(false))],
501
    );
502

            
503
    expr_and = remove_trivial_and
504
        .apply(&expr_and, &Model::new_empty(Default::default()))
505
        .unwrap()
506
        .new_expression;
507
    expr_or = remove_trivial_or
508
        .apply(&expr_or, &Model::new_empty(Default::default()))
509
        .unwrap()
510
        .new_expression;
511

            
512
    assert_eq!(
513
        expr_and,
514
        Expression::Constant(Metadata::new(), Constant::Bool(true))
515
    );
516
    assert_eq!(
517
        expr_or,
518
        Expression::Constant(Metadata::new(), Constant::Bool(false))
519
    );
520
}
521

            
522
#[test]
523
fn rule_remove_constants_from_or() {
524
    let remove_constants_from_or = get_rule_by_name("remove_constants_from_or").unwrap();
525

            
526
    let mut expr = Expression::Or(
527
        Metadata::new(),
528
        vec![
529
            Expression::Constant(Metadata::new(), Constant::Bool(true)),
530
            Expression::Constant(Metadata::new(), Constant::Bool(false)),
531
            Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
532
        ],
533
    );
534

            
535
    expr = remove_constants_from_or
536
        .apply(&expr, &Model::new_empty(Default::default()))
537
        .unwrap()
538
        .new_expression;
539

            
540
    assert_eq!(
541
        expr,
542
        Expression::Constant(Metadata::new(), Constant::Bool(true))
543
    );
544
}
545

            
546
#[test]
547
fn rule_remove_constants_from_and() {
548
    let remove_constants_from_and = get_rule_by_name("remove_constants_from_and").unwrap();
549

            
550
    let mut expr = Expression::And(
551
        Metadata::new(),
552
        vec![
553
            Expression::Constant(Metadata::new(), Constant::Bool(true)),
554
            Expression::Constant(Metadata::new(), Constant::Bool(false)),
555
            Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
556
        ],
557
    );
558

            
559
    expr = remove_constants_from_and
560
        .apply(&expr, &Model::new_empty(Default::default()))
561
        .unwrap()
562
        .new_expression;
563

            
564
    assert_eq!(
565
        expr,
566
        Expression::Constant(Metadata::new(), Constant::Bool(false))
567
    );
568
}
569

            
570
#[test]
571
fn remove_constants_from_or_not_changed() {
572
    let remove_constants_from_or = get_rule_by_name("remove_constants_from_or").unwrap();
573

            
574
    let expr = Expression::Or(
575
        Metadata::new(),
576
        vec![
577
            Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
578
            Expression::Reference(Metadata::new(), Name::UserName(String::from("b"))),
579
        ],
580
    );
581

            
582
    let result = remove_constants_from_or.apply(&expr, &Model::new_empty(Default::default()));
583

            
584
    assert!(result.is_err());
585
}
586

            
587
#[test]
588
fn remove_constants_from_and_not_changed() {
589
    let remove_constants_from_and = get_rule_by_name("remove_constants_from_and").unwrap();
590

            
591
    let expr = Expression::And(
592
        Metadata::new(),
593
        vec![
594
            Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
595
            Expression::Reference(Metadata::new(), Name::UserName(String::from("b"))),
596
        ],
597
    );
598

            
599
    let result = remove_constants_from_and.apply(&expr, &Model::new_empty(Default::default()));
600

            
601
    assert!(result.is_err());
602
}
603

            
604
#[test]
605
fn rule_distribute_not_over_and() {
606
    let distribute_not_over_and = get_rule_by_name("distribute_not_over_and").unwrap();
607

            
608
    let mut expr = Expression::Not(
609
        Metadata::new(),
610
        Box::new(Expression::And(
611
            Metadata::new(),
612
            vec![
613
                Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
614
                Expression::Reference(Metadata::new(), Name::UserName(String::from("b"))),
615
            ],
616
        )),
617
    );
618

            
619
    expr = distribute_not_over_and
620
        .apply(&expr, &Model::new_empty(Default::default()))
621
        .unwrap()
622
        .new_expression;
623

            
624
    assert_eq!(
625
        expr,
626
        Expression::Or(
627
            Metadata::new(),
628
            vec![
629
                Expression::Not(
630
                    Metadata::new(),
631
                    Box::new(Expression::Reference(
632
                        Metadata::new(),
633
                        Name::UserName(String::from("a"))
634
                    ))
635
                ),
636
                Expression::Not(
637
                    Metadata::new(),
638
                    Box::new(Expression::Reference(
639
                        Metadata::new(),
640
                        Name::UserName(String::from("b"))
641
                    ))
642
                ),
643
            ]
644
        )
645
    );
646
}
647

            
648
#[test]
649
fn rule_distribute_not_over_or() {
650
    let distribute_not_over_or = get_rule_by_name("distribute_not_over_or").unwrap();
651

            
652
    let mut expr = Expression::Not(
653
        Metadata::new(),
654
        Box::new(Expression::Or(
655
            Metadata::new(),
656
            vec![
657
                Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
658
                Expression::Reference(Metadata::new(), Name::UserName(String::from("b"))),
659
            ],
660
        )),
661
    );
662

            
663
    expr = distribute_not_over_or
664
        .apply(&expr, &Model::new_empty(Default::default()))
665
        .unwrap()
666
        .new_expression;
667

            
668
    assert_eq!(
669
        expr,
670
        Expression::And(
671
            Metadata::new(),
672
            vec![
673
                Expression::Not(
674
                    Metadata::new(),
675
                    Box::new(Expression::Reference(
676
                        Metadata::new(),
677
                        Name::UserName(String::from("a"))
678
                    ))
679
                ),
680
                Expression::Not(
681
                    Metadata::new(),
682
                    Box::new(Expression::Reference(
683
                        Metadata::new(),
684
                        Name::UserName(String::from("b"))
685
                    ))
686
                ),
687
            ]
688
        )
689
    );
690
}
691

            
692
#[test]
693
fn rule_distribute_not_over_and_not_changed() {
694
    let distribute_not_over_and = get_rule_by_name("distribute_not_over_and").unwrap();
695

            
696
    let expr = Expression::Not(
697
        Metadata::new(),
698
        Box::new(Expression::Reference(
699
            Metadata::new(),
700
            Name::UserName(String::from("a")),
701
        )),
702
    );
703

            
704
    let result = distribute_not_over_and.apply(&expr, &Model::new_empty(Default::default()));
705

            
706
    assert!(result.is_err());
707
}
708

            
709
#[test]
710
fn rule_distribute_not_over_or_not_changed() {
711
    let distribute_not_over_or = get_rule_by_name("distribute_not_over_or").unwrap();
712

            
713
    let expr = Expression::Not(
714
        Metadata::new(),
715
        Box::new(Expression::Reference(
716
            Metadata::new(),
717
            Name::UserName(String::from("a")),
718
        )),
719
    );
720

            
721
    let result = distribute_not_over_or.apply(&expr, &Model::new_empty(Default::default()));
722

            
723
    assert!(result.is_err());
724
}
725

            
726
#[test]
727
fn rule_distribute_or_over_and() {
728
    let distribute_or_over_and = get_rule_by_name("distribute_or_over_and").unwrap();
729

            
730
    let expr = Expression::Or(
731
        Metadata::new(),
732
        vec![
733
            Expression::And(
734
                Metadata::new(),
735
                vec![
736
                    Expression::Reference(Metadata::new(), Name::MachineName(1)),
737
                    Expression::Reference(Metadata::new(), Name::MachineName(2)),
738
                ],
739
            ),
740
            Expression::Reference(Metadata::new(), Name::MachineName(3)),
741
        ],
742
    );
743

            
744
    let red = distribute_or_over_and
745
        .apply(&expr, &Model::new_empty(Default::default()))
746
        .unwrap();
747

            
748
    assert_eq!(
749
        red.new_expression,
750
        Expression::And(
751
            Metadata::new(),
752
            vec![
753
                Expression::Or(
754
                    Metadata::new(),
755
                    vec![
756
                        Expression::Reference(Metadata::new(), Name::MachineName(3)),
757
                        Expression::Reference(Metadata::new(), Name::MachineName(1)),
758
                    ]
759
                ),
760
                Expression::Or(
761
                    Metadata::new(),
762
                    vec![
763
                        Expression::Reference(Metadata::new(), Name::MachineName(3)),
764
                        Expression::Reference(Metadata::new(), Name::MachineName(2)),
765
                    ]
766
                ),
767
            ]
768
        ),
769
    );
770
}
771

            
772
// #[test]
773
// fn rule_ensure_div() {
774
//     let ensure_div = get_rule_by_name("ensure_div").unwrap();
775

            
776
//     let expr = Expression::Div(
777
//         Metadata::new(),
778
//         Box::new(Expression::Reference(
779
//             Metadata::new(),
780
//             Name::UserName("a".to_string()),
781
//         )),
782
//         Box::new(Expression::Reference(
783
//             Metadata::new(),
784
//             Name::UserName("b".to_string()),
785
//         )),
786
//     );
787

            
788
//     let red = ensure_div.apply(&expr, &Model::new_empty(Default::default())).unwrap();
789

            
790
//     assert_eq!(
791
//         red.new_expression,
792
//         Expression::SafeDiv(
793
//             Metadata::new(),
794
//             Box::new(Expression::Reference(
795
//                 Metadata::new(),
796
//                 Name::UserName("a".to_string())
797
//             )),
798
//             Box::new(Expression::Reference(
799
//                 Metadata::new(),
800
//                 Name::UserName("b".to_string())
801
//             )),
802
//         ),
803
//     );
804
//     assert_eq!(
805
//         red.new_top,
806
//         Expression::Neq(
807
//             Metadata::new(),
808
//             Box::new(Expression::Reference(
809
//                 Metadata::new(),
810
//                 Name::UserName("b".to_string())
811
//             )),
812
//             Box::new(Expression::Constant(Metadata::new(), Constant::Int(0)))
813
//         )
814
//     );
815
// }
816

            
817
///
818
/// Reduce and solve:
819
/// ```text
820
/// find a,b,c : int(1..3)
821
/// such that a + b + c = 4
822
/// such that a < b
823
/// ```
824
///
825
/// This test uses the rewrite function to simplify the expression instead
826
/// of applying the rules manually.
827
#[test]
828
fn rewrite_solve_xyz() {
829
    println!("Rules: {:?}", get_rules());
830

            
831
    let rule_sets = match resolve_rule_sets(SolverFamily::Minion, &vec!["Constant".to_string()]) {
832
        Ok(rs) => rs,
833
        Err(e) => {
834
            eprintln!("Error resolving rule sets: {}", e);
835
            exit(1);
836
        }
837
    };
838
    println!("Rule sets: {:?}", rule_sets);
839

            
840
    // Create variables and domains
841
    let variable_a = Name::UserName(String::from("a"));
842
    let variable_b = Name::UserName(String::from("b"));
843
    let variable_c = Name::UserName(String::from("c"));
844
    let domain = Domain::IntDomain(vec![Range::Bounded(1, 3)]);
845

            
846
    // Construct nested expression
847
    let nested_expr = Expression::And(
848
        Metadata::new(),
849
        vec![
850
            Expression::Eq(
851
                Metadata::new(),
852
                Box::new(Expression::Sum(
853
                    Metadata::new(),
854
                    vec![
855
                        Expression::Reference(Metadata::new(), variable_a.clone()),
856
                        Expression::Reference(Metadata::new(), variable_b.clone()),
857
                        Expression::Reference(Metadata::new(), variable_c.clone()),
858
                    ],
859
                )),
860
                Box::new(Expression::Constant(Metadata::new(), Constant::Int(4))),
861
            ),
862
            Expression::Lt(
863
                Metadata::new(),
864
                Box::new(Expression::Reference(Metadata::new(), variable_a.clone())),
865
                Box::new(Expression::Reference(Metadata::new(), variable_b.clone())),
866
            ),
867
        ],
868
    );
869

            
870
    let rule_sets = match resolve_rule_sets(SolverFamily::Minion, &vec!["Constant".to_string()]) {
871
        Ok(rs) => rs,
872
        Err(e) => {
873
            eprintln!("Error resolving rule sets: {}", e);
874
            exit(1);
875
        }
876
    };
877

            
878
    // Apply rewrite function to the nested expression
879
    let rewritten_expr = rewrite_model(
880
        &Model::new(HashMap::new(), nested_expr, Default::default()),
881
        &rule_sets,
882
    )
883
    .unwrap()
884
    .constraints;
885

            
886
    // Check if the expression is in its simplest form
887
    let expr = rewritten_expr.clone();
888
    assert!(is_simple(&expr));
889

            
890
    // Create model with variables and constraints
891
    let mut model = Model::new(HashMap::new(), rewritten_expr, Default::default());
892

            
893
    // Insert variables and domains
894
    model.variables.insert(
895
        variable_a.clone(),
896
        DecisionVariable {
897
            domain: domain.clone(),
898
        },
899
    );
900
    model.variables.insert(
901
        variable_b.clone(),
902
        DecisionVariable {
903
            domain: domain.clone(),
904
        },
905
    );
906
    model.variables.insert(
907
        variable_c.clone(),
908
        DecisionVariable {
909
            domain: domain.clone(),
910
        },
911
    );
912

            
913
    let solver: Solver<adaptors::Minion> = Solver::new(adaptors::Minion::new());
914
    let solver = solver.load_model(model).unwrap();
915
    solver.solve(Box::new(|_| true)).unwrap();
916
}
917

            
918
#[test]
919
fn rewrite_solve_xyz_parameterized() {
920
    println!("Rules: {:?}", get_rules());
921

            
922
    let rule_sets = match resolve_rule_sets(SolverFamily::Minion, &vec!["Constant".to_string()]) {
923
        Ok(rs) => rs,
924
        Err(e) => {
925
            eprintln!("Error resolving rule sets: {}", e);
926
            exit(1);
927
        }
928
    };
929
    println!("Rule sets: {:?}", rule_sets);
930

            
931
    // Create variables and domain
932
    let variable_a = Name::UserName(String::from("a"));
933
    let variable_b = Name::UserName(String::from("b"));
934
    let variable_c = Name::UserName(String::from("c"));
935
    let domain = Domain::IntDomain(vec![Range::Bounded(1, 3)]);
936

            
937
    // Create a vector of test cases with varying number of OR clauses
938
    let test_cases = vec![1, 2, 3, 4];
939

            
940
    for num_or_clauses in test_cases {
941
        // Construct OR'd expression
942
        let mut or_exprs = Vec::new();
943
        for _i in 0..num_or_clauses {
944
            let expr = Expression::And(
945
                Metadata::new(),
946
                vec![
947
                    Expression::Eq(
948
                        Metadata::new(),
949
                        Box::new(Expression::Sum(
950
                            Metadata::new(),
951
                            vec![
952
                                Expression::Reference(Metadata::new(), variable_a.clone()),
953
                                Expression::Reference(Metadata::new(), variable_b.clone()),
954
                                Expression::Reference(Metadata::new(), variable_c.clone()),
955
                            ],
956
                        )),
957
                        Box::new(Expression::Constant(Metadata::new(), Constant::Int(4))),
958
                    ),
959
                    Expression::Lt(
960
                        Metadata::new(),
961
                        Box::new(Expression::Reference(Metadata::new(), variable_a.clone())),
962
                        Box::new(Expression::Reference(Metadata::new(), variable_b.clone())),
963
                    ),
964
                ],
965
            );
966
            or_exprs.push(expr);
967
        }
968
        let nested_expr = Expression::Or(Metadata::new(), or_exprs);
969

            
970
        let model_for_rewrite = Model::new(HashMap::new(), nested_expr.clone(), Default::default());
971
        let model_for_rewrite_unoptimized =
972
            Model::new(HashMap::new(), nested_expr.clone(), Default::default());
973

            
974
        // Apply rewrite function to the nested expression
975
        let rewritten_expr = rewrite_model(&model_for_rewrite, &rule_sets)
976
            .unwrap()
977
            .constraints;
978

            
979
        env::set_var("OPTIMIZATIONS", "0");
980

            
981
        let rewritten_expr_unoptimized = rewrite_model(&model_for_rewrite_unoptimized, &rule_sets)
982
            .unwrap()
983
            .constraints;
984

            
985
        env::remove_var("OPTIMIZATIONS");
986

            
987
        let info_file_name_optimized = format!("rewrite_solve_xyz_optimized_{}", num_or_clauses);
988
        let info_file_name_unoptimized =
989
            format!("rewrite_solve_xyz_unoptimized_{}", num_or_clauses);
990

            
991
        save_stats_json(
992
            model_for_rewrite.context,
993
            "tests",
994
            &info_file_name_optimized,
995
        )
996
        .expect("Could not save stats!");
997
        save_stats_json(
998
            model_for_rewrite_unoptimized.context,
999
            "tests",
            &info_file_name_unoptimized,
        )
        .expect("Could not save stats!");
        // Check if the expression is in its simplest form
        let expr = rewritten_expr.clone();
        assert!(is_simple(&expr));
        let expr_unoptimized = rewritten_expr_unoptimized.clone();
        assert!(is_simple(&expr_unoptimized));
        // Create model with variables and constraints
        let mut model = Model::new(HashMap::new(), rewritten_expr, Default::default());
        let mut model_unoptimized = Model::new(
            HashMap::new(),
            rewritten_expr_unoptimized,
            Default::default(),
        );
        // Insert variables and domains
        model.variables.insert(
            variable_a.clone(),
            DecisionVariable {
                domain: domain.clone(),
            },
        );
        model.variables.insert(
            variable_b.clone(),
            DecisionVariable {
                domain: domain.clone(),
            },
        );
        model.variables.insert(
            variable_c.clone(),
            DecisionVariable {
                domain: domain.clone(),
            },
        );
        model_unoptimized.variables.insert(
            variable_a.clone(),
            DecisionVariable {
                domain: domain.clone(),
            },
        );
        model_unoptimized.variables.insert(
            variable_b.clone(),
            DecisionVariable {
                domain: domain.clone(),
            },
        );
        model_unoptimized.variables.insert(
            variable_c.clone(),
            DecisionVariable {
                domain: domain.clone(),
            },
        );
        let solver: Solver<adaptors::Minion> = Solver::new(adaptors::Minion::new());
        let solver = solver.load_model(model).unwrap();
        solver.solve(Box::new(|_| true)).unwrap();
        let solver_unoptimized: Solver<adaptors::Minion> = Solver::new(adaptors::Minion::new());
        let solver_unoptimized = solver_unoptimized.load_model(model_unoptimized).unwrap();
        solver_unoptimized.solve(Box::new(|_| true)).unwrap();
    }
}
struct RuleResult<'a> {
    #[allow(dead_code)]
    rule: &'a Rule<'a>,
    new_expression: Expression,
}
/// # Returns
/// - True if `expression` is in its simplest form.
/// - False otherwise.
pub fn is_simple(expression: &Expression) -> bool {
    let rules = get_rules();
    let mut new = expression.clone();
    while let Some(step) = is_simple_iteration(&new, &rules) {
        new = step;
    }
    new == *expression
}
/// # Returns
/// - Some(<new_expression>) after applying the first applicable rule to `expr` or a sub-expression.
/// - None if no rule is applicable to the expression or any sub-expression.
fn is_simple_iteration<'a>(
    expression: &'a Expression,
    rules: &'a Vec<&'a Rule<'a>>,
) -> Option<Expression> {
    let rule_results = apply_all_rules(expression, rules);
    if let Some(new) = choose_rewrite(&rule_results) {
        return Some(new);
    } else {
        let mut sub = expression.children();
        for i in 0..sub.len() {
            if let Some(new) = is_simple_iteration(&sub[i], rules) {
                sub[i] = new;
                return Some(expression.with_children(sub.clone()));
            }
        }
    }
    None // No rules applicable to this branch of the expression
}
/// # Returns
/// - A list of RuleResults after applying all rules to `expression`.
/// - An empty list if no rules are applicable.
fn apply_all_rules<'a>(
    expression: &'a Expression,
    rules: &'a Vec<&'a Rule<'a>>,
) -> Vec<RuleResult<'a>> {
    let mut results = Vec::new();
    for rule in rules {
        match rule.apply(expression, &Model::new_empty(Default::default())) {
            Ok(red) => {
                results.push(RuleResult {
                    rule,
                    new_expression: red.new_expression,
                });
            }
            Err(_) => continue,
        }
    }
    results
}
/// # Returns
/// - Some(<new_expression>) after applying the first rule in `results`.
/// - None if `results` is empty.
fn choose_rewrite(results: &[RuleResult]) -> Option<Expression> {
    if results.is_empty() {
        return None;
    }
    // Return the first result for now
    // println!("Applying rule: {:?}", results[0].rule);
    Some(results[0].new_expression.clone())
}
#[test]
fn eval_const_int() {
    let expr = Expression::Constant(Metadata::new(), Constant::Int(1));
    let result = eval_constant(&expr);
    assert_eq!(result, Some(Constant::Int(1)));
}
#[test]
fn eval_const_bool() {
    let expr = Expression::Constant(Metadata::new(), Constant::Bool(true));
    let result = eval_constant(&expr);
    assert_eq!(result, Some(Constant::Bool(true)));
}
#[test]
fn eval_const_and() {
    let expr = Expression::And(
        Metadata::new(),
        vec![
            Expression::Constant(Metadata::new(), Constant::Bool(true)),
            Expression::Constant(Metadata::new(), Constant::Bool(false)),
        ],
    );
    let result = eval_constant(&expr);
    assert_eq!(result, Some(Constant::Bool(false)));
}
#[test]
fn eval_const_ref() {
    let expr = Expression::Reference(Metadata::new(), Name::UserName(String::from("a")));
    let result = eval_constant(&expr);
    assert_eq!(result, None);
}
#[test]
fn eval_const_nested_ref() {
    let expr = Expression::Sum(
        Metadata::new(),
        vec![
            Expression::Constant(Metadata::new(), Constant::Int(1)),
            Expression::And(
                Metadata::new(),
                vec![
                    Expression::Constant(Metadata::new(), Constant::Bool(true)),
                    Expression::Reference(Metadata::new(), Name::UserName(String::from("a"))),
                ],
            ),
        ],
    );
    let result = eval_constant(&expr);
    assert_eq!(result, None);
}
#[test]
fn eval_const_eq_int() {
    let expr = Expression::Eq(
        Metadata::new(),
        Box::new(Expression::Constant(Metadata::new(), Constant::Int(1))),
        Box::new(Expression::Constant(Metadata::new(), Constant::Int(1))),
    );
    let result = eval_constant(&expr);
    assert_eq!(result, Some(Constant::Bool(true)));
}
#[test]
fn eval_const_eq_bool() {
    let expr = Expression::Eq(
        Metadata::new(),
        Box::new(Expression::Constant(Metadata::new(), Constant::Bool(true))),
        Box::new(Expression::Constant(Metadata::new(), Constant::Bool(true))),
    );
    let result = eval_constant(&expr);
    assert_eq!(result, Some(Constant::Bool(true)));
}
#[test]
fn eval_const_eq_mixed() {
    let expr = Expression::Eq(
        Metadata::new(),
        Box::new(Expression::Constant(Metadata::new(), Constant::Int(1))),
        Box::new(Expression::Constant(Metadata::new(), Constant::Bool(true))),
    );
    let result = eval_constant(&expr);
    assert_eq!(result, None);
}
#[test]
fn eval_const_sum_mixed() {
    let expr = Expression::Sum(
        Metadata::new(),
        vec![
            Expression::Constant(Metadata::new(), Constant::Int(1)),
            Expression::Constant(Metadata::new(), Constant::Bool(true)),
        ],
    );
    let result = eval_constant(&expr);
    assert_eq!(result, None);
}
#[test]
fn eval_const_sum_xyz() {
    let expr = Expression::And(
        Metadata::new(),
        vec![
            Expression::Eq(
                Metadata::new(),
                Box::new(Expression::Sum(
                    Metadata::new(),
                    vec![
                        Expression::Reference(Metadata::new(), Name::UserName(String::from("x"))),
                        Expression::Reference(Metadata::new(), Name::UserName(String::from("y"))),
                        Expression::Reference(Metadata::new(), Name::UserName(String::from("z"))),
                    ],
                )),
                Box::new(Expression::Constant(Metadata::new(), Constant::Int(4))),
            ),
            Expression::Geq(
                Metadata::new(),
                Box::new(Expression::Reference(
                    Metadata::new(),
                    Name::UserName(String::from("x")),
                )),
                Box::new(Expression::Reference(
                    Metadata::new(),
                    Name::UserName(String::from("y")),
                )),
            ),
        ],
    );
    let result = eval_constant(&expr);
    assert_eq!(result, None);
}
#[test]
fn eval_const_or() {
    let expr = Expression::Or(
        Metadata::new(),
        vec![
            Expression::Constant(Metadata::new(), Constant::Bool(false)),
            Expression::Constant(Metadata::new(), Constant::Bool(false)),
        ],
    );
    let result = eval_constant(&expr);
    assert_eq!(result, Some(Constant::Bool(false)));
}