1use std::rc::Rc;
2
3use conjure_core::ast::{Atom, Expression as Expr, Literal as Lit, SymbolTable};
4use conjure_core::metadata::Metadata;
5use conjure_core::rule_engine::{
6 register_rule, register_rule_set, ApplicationError, ApplicationError::RuleNotApplicable,
7 ApplicationResult, Reduction,
8};
9use uniplate::Uniplate;
10
11use Atom::*;
12use Expr::*;
13use Lit::Bool;
14
15use crate::ast::Declaration;
16use crate::{into_matrix_expr, matrix_expr};
17
18register_rule_set!("Base", ());
19
20#[register_rule(("Base", 8800))]
31fn remove_empty_expression(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
32 if matches!(
34 expr,
35 Atomic(_, _)
36 | Root(_, _)
37 | Comprehension(_, _)
38 | FlatIneq(_, _, _, _)
39 | FlatMinusEq(_, _, _)
40 | FlatSumGeq(_, _, _)
41 | FlatSumLeq(_, _, _)
42 | FlatProductEq(_, _, _, _)
43 | FlatWatchedLiteral(_, _, _)
44 | FlatWeightedSumGeq(_, _, _, _)
45 | FlatWeightedSumLeq(_, _, _, _)
46 | MinionDivEqUndefZero(_, _, _, _)
47 | MinionModuloEqUndefZero(_, _, _, _)
48 | MinionWInIntervalSet(_, _, _)
49 | MinionElementOne(_, _, _, _)
50 | MinionPow(_, _, _, _)
51 | MinionReify(_, _, _)
52 | MinionReifyImply(_, _, _)
53 | FlatAbsEq(_, _, _)
54 | Min(_, _)
55 | Max(_, _)
56 | AllDiff(_, _)
57 | FlatAllDiff(_, _)
58 | AbstractLiteral(_, _)
59 ) {
60 return Err(ApplicationError::RuleNotApplicable);
61 }
62
63 if !expr.children().is_empty() {
64 return Err(ApplicationError::RuleNotApplicable);
65 }
66
67 let new_expr = match expr {
68 Or(_, _) => Atomic(Metadata::new(), Literal(Bool(false))),
69 _ => And(Metadata::new(), Box::new(matrix_expr![])),
70 };
71
72 Ok(Reduction::pure(new_expr))
73}
74
75#[register_rule(("Base", 6000))]
82fn min_to_var(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
83 let Expr::Min(_, inside_min_expr) = expr else {
84 return Err(RuleNotApplicable);
85 };
86
87 let Some(exprs) = inside_min_expr.as_ref().clone().unwrap_list() else {
89 return Err(RuleNotApplicable);
90 };
91
92 let mut symbols = symbols.clone();
93 let new_name = symbols.gensym();
94
95 let mut new_top = Vec::new(); let mut disjunction = Vec::new(); for e in exprs {
98 new_top.push(Leq(
99 Metadata::new(),
100 Box::new(Atomic(Metadata::new(), Reference(new_name.clone()))),
101 Box::new(e.clone()),
102 ));
103 disjunction.push(Eq(
104 Metadata::new(),
105 Box::new(Atomic(Metadata::new(), Reference(new_name.clone()))),
106 Box::new(e.clone()),
107 ));
108 }
109 new_top.push(Or(
111 Metadata::new(),
112 Box::new(into_matrix_expr![disjunction]),
113 ));
114
115 let domain = expr
116 .domain_of(&symbols)
117 .ok_or(ApplicationError::DomainError)?;
118 symbols.insert(Rc::new(Declaration::new_var(new_name.clone(), domain)));
119
120 Ok(Reduction::new(
121 Atomic(Metadata::new(), Reference(new_name)),
122 new_top,
123 symbols,
124 ))
125}
126
127#[register_rule(("Base", 6000))]
134fn max_to_var(expr: &Expr, symbols: &SymbolTable) -> ApplicationResult {
135 let Expr::Max(_, inside_max_expr) = expr else {
136 return Err(RuleNotApplicable);
137 };
138
139 let Some(exprs) = inside_max_expr.as_ref().clone().unwrap_list() else {
140 return Err(RuleNotApplicable);
141 };
142
143 let mut symbols = symbols.clone();
144 let new_name = symbols.gensym();
145
146 let mut new_top = Vec::new(); let mut disjunction = Vec::new(); for e in exprs {
149 new_top.push(Geq(
150 Metadata::new(),
151 Box::new(Atomic(Metadata::new(), Reference(new_name.clone()))),
152 Box::new(e.clone()),
153 ));
154 disjunction.push(Eq(
155 Metadata::new(),
156 Box::new(Atomic(Metadata::new(), Reference(new_name.clone()))),
157 Box::new(e.clone()),
158 ));
159 }
160 new_top.push(Or(
162 Metadata::new(),
163 Box::new(into_matrix_expr![disjunction]),
164 ));
165
166 let domain = expr
167 .domain_of(&symbols)
168 .ok_or(ApplicationError::DomainError)?;
169 symbols.insert(Rc::new(Declaration::new_var(new_name.clone(), domain)));
170
171 Ok(Reduction::new(
172 Atomic(Metadata::new(), Reference(new_name)),
173 new_top,
174 symbols,
175 ))
176}