dlinear  0.0.1
Delta-complete SMT solver for linear programming
Loading...
Searching...
No Matches
IfThenElseEliminator.cpp
1
7#include "IfThenElseEliminator.h"
8
9#include <map>
10#include <set>
11#include <string>
12#include <utility>
13
14#include "dlinear/libs/libgmp.h"
15#include "dlinear/symbolic/Nnfizer.h"
16#include "dlinear/util/Stats.h"
17#include "dlinear/util/Timer.h"
18
19namespace dlinear {
20
22 const TimerGuard timer_guard(&FormulaVisitor::stats_.m_timer(), FormulaVisitor::stats_.enabled());
24
25 added_formulas_.clear();
26
27 const Formula new_f{VisitFormula(f, Formula::True())};
28 if (f.EqualTo(new_f) && added_formulas_.empty()) return f;
29 return new_f && make_conjunction(added_formulas_);
30}
31std::pair<Expression, Formula> IfThenElseEliminator::Process(const Expression &e) {
32 const TimerGuard timer_guard(&FormulaVisitor::stats_.m_timer(), FormulaVisitor::stats_.enabled());
34
35 added_formulas_.clear();
36
37 const Expression new_e{VisitExpression(e, Formula::True())};
38 if (e.EqualTo(new_e) && added_formulas_.empty()) return {e, {}};
39 return {new_e, make_conjunction(added_formulas_)};
40}
41
42const std::unordered_map<Expression, Variable> &IfThenElseEliminator::variables() const { return ite_to_var_; }
43
44Expression IfThenElseEliminator::VisitExpression(const Expression &e, const Formula &guard) const {
45 return e.include_ite() ? GenericExpressionVisitor::VisitExpression(e, guard) : e;
46}
47
48Expression IfThenElseEliminator::VisitVariable(const Expression &e, const Formula &) const { return e; }
49
50Expression IfThenElseEliminator::VisitConstant(const Expression &e, const Formula &) const { return e; }
51
52Expression IfThenElseEliminator::VisitAddition(const Expression &e, const Formula &guard) const {
53 // e = c₀ + ∑ᵢ cᵢ * eᵢ
54 Expression ret{get_constant_in_addition(e)};
55 for (const auto &p : get_expr_to_coeff_map_in_addition(e)) {
56 const Expression &e_i{p.first};
57 const mpq_class &c_i{p.second};
58 ret += c_i * VisitExpression(e_i, guard);
59 }
60 return ret;
61}
62
63Expression IfThenElseEliminator::VisitMultiplication(const Expression &e, const Formula &guard) const {
64 // e = c₀ * ∏ᵢ pow(eᵢ₁, eᵢ₂)
65 Expression ret{get_constant_in_multiplication(e)};
66 for (const auto &p : get_base_to_exponent_map_in_multiplication(e)) {
67 const Expression &e_i1{p.first};
68 const Expression &e_i2{p.second};
69 ret *= pow(VisitExpression(e_i1, guard), VisitExpression(e_i2, guard));
70 }
71 return ret;
72}
73
74Expression IfThenElseEliminator::VisitDivision(const Expression &e, const Formula &guard) const {
75 return VisitExpression(get_first_argument(e), guard) / VisitExpression(get_second_argument(e), guard);
76}
77
78Expression IfThenElseEliminator::VisitLog(const Expression &e, const Formula &guard) const {
79 return log(VisitExpression(get_argument(e), guard));
80}
81
82Expression IfThenElseEliminator::VisitAbs(const Expression &e, const Formula &guard) const {
83 return abs(VisitExpression(get_argument(e), guard));
84}
85
86Expression IfThenElseEliminator::VisitExp(const Expression &e, const Formula &guard) const {
87 return exp(VisitExpression(get_argument(e), guard));
88}
89
90Expression IfThenElseEliminator::VisitSqrt(const Expression &e, const Formula &guard) const {
91 return sqrt(VisitExpression(get_argument(e), guard));
92}
93
94Expression IfThenElseEliminator::VisitPow(const Expression &e, const Formula &guard) const {
95 return pow(VisitExpression(get_first_argument(e), guard), VisitExpression(get_second_argument(e), guard));
96}
97
98Expression IfThenElseEliminator::VisitSin(const Expression &e, const Formula &guard) const {
99 return sin(VisitExpression(get_argument(e), guard));
100}
101
102Expression IfThenElseEliminator::VisitCos(const Expression &e, const Formula &guard) const {
103 return cos(VisitExpression(get_argument(e), guard));
104}
105
106Expression IfThenElseEliminator::VisitTan(const Expression &e, const Formula &guard) const {
107 return tan(VisitExpression(get_argument(e), guard));
108}
109
110Expression IfThenElseEliminator::VisitAsin(const Expression &e, const Formula &guard) const {
111 return asin(VisitExpression(get_argument(e), guard));
112}
113
114Expression IfThenElseEliminator::VisitAcos(const Expression &e, const Formula &guard) const {
115 return acos(VisitExpression(get_argument(e), guard));
116}
117
118Expression IfThenElseEliminator::VisitAtan(const Expression &e, const Formula &guard) const {
119 return atan(VisitExpression(get_argument(e), guard));
120}
121
122Expression IfThenElseEliminator::VisitAtan2(const Expression &e, const Formula &guard) const {
123 return atan2(VisitExpression(get_first_argument(e), guard), VisitExpression(get_second_argument(e), guard));
124}
125
126Expression IfThenElseEliminator::VisitSinh(const Expression &e, const Formula &guard) const {
127 return sinh(VisitExpression(get_argument(e), guard));
128}
129
130Expression IfThenElseEliminator::VisitCosh(const Expression &e, const Formula &guard) const {
131 return cosh(VisitExpression(get_argument(e), guard));
132}
133
134Expression IfThenElseEliminator::VisitTanh(const Expression &e, const Formula &guard) const {
135 return tanh(VisitExpression(get_argument(e), guard));
136}
137
138Expression IfThenElseEliminator::VisitMin(const Expression &e, const Formula &guard) const {
139 return min(VisitExpression(get_first_argument(e), guard), VisitExpression(get_second_argument(e), guard));
140}
141
142Expression IfThenElseEliminator::VisitMax(const Expression &e, const Formula &guard) const {
143 return max(VisitExpression(get_first_argument(e), guard), VisitExpression(get_second_argument(e), guard));
144}
145
146Expression IfThenElseEliminator::VisitIfThenElse(const Expression &e, const Formula &guard) const {
147 // Both then and else expressions are the same.
148 const auto it = ite_to_var_.find(e);
149 if (it != ite_to_var_.end()) {
150 added_formulas_.push_back(ite_var_to_formulas_.at(it->second));
151 return it->second;
152 }
153 if (get_then_expression(e).EqualTo(get_else_expression(e))) return VisitExpression(get_then_expression(e), guard);
154
155 const Formula c{VisitFormula(get_conditional_formula(e), guard)};
156
157 // If the guard is the same (or inverted) as the current condition, short-circuit the ITE.
158 if (c.EqualTo(guard)) return VisitExpression(get_then_expression(e), guard);
159 if (c.EqualTo(!guard)) return VisitExpression(get_else_expression(e), guard);
160
161 const Variable new_var{"ITE" + std::to_string(counter_++), Variable::Type::CONTINUOUS};
162 const Formula then_guard{guard && c};
163 const Formula else_guard{guard && !c};
164 const Expression e1{VisitExpression(get_then_expression(e), then_guard)};
165 const Expression e2{VisitExpression(get_else_expression(e), else_guard)};
166 added_formulas_.push_back(!then_guard || (new_var == e1)); // then_guard => (new_var = e1)
167 added_formulas_.push_back(!else_guard || (new_var == e2)); // else_guard => (new_var = e2)
168 ite_to_var_.emplace(e, new_var);
169 ite_var_to_formulas_.emplace(new_var, added_formulas_.back() && *(added_formulas_.rbegin() + 1));
170 return new_var;
171}
172
173Expression IfThenElseEliminator::VisitUninterpretedFunction(const Expression &e, const Formula &) const { return e; }
174
175Formula IfThenElseEliminator::VisitFalse(const Formula &f, const Formula &) const { return f; }
176
177Formula IfThenElseEliminator::VisitTrue(const Formula &f, const Formula &) const { return f; }
178
179Formula IfThenElseEliminator::VisitVariable(const Formula &f, const Formula &) const { return f; }
180
181Formula IfThenElseEliminator::VisitEqualTo(const Formula &f, const Formula &guard) const {
182 return VisitExpression(get_lhs_expression(f), guard) == VisitExpression(get_rhs_expression(f), guard);
183}
184
185Formula IfThenElseEliminator::VisitNotEqualTo(const Formula &f, const Formula &guard) const {
186 return VisitExpression(get_lhs_expression(f), guard) != VisitExpression(get_rhs_expression(f), guard);
187}
188
189Formula IfThenElseEliminator::VisitGreaterThan(const Formula &f, const Formula &guard) const {
190 return VisitExpression(get_lhs_expression(f), guard) > VisitExpression(get_rhs_expression(f), guard);
191}
192
193Formula IfThenElseEliminator::VisitGreaterThanOrEqualTo(const Formula &f, const Formula &guard) const {
194 return VisitExpression(get_lhs_expression(f), guard) >= VisitExpression(get_rhs_expression(f), guard);
195}
196
197Formula IfThenElseEliminator::VisitLessThan(const Formula &f, const Formula &guard) const {
198 return VisitExpression(get_lhs_expression(f), guard) < VisitExpression(get_rhs_expression(f), guard);
199}
200
201Formula IfThenElseEliminator::VisitLessThanOrEqualTo(const Formula &f, const Formula &guard) const {
202 return VisitExpression(get_lhs_expression(f), guard) <= VisitExpression(get_rhs_expression(f), guard);
203}
204
205Formula IfThenElseEliminator::VisitConjunction(const Formula &f, const Formula &guard) const {
206 // f := f₁ ∧ ... ∧ fₙ
207 std::set<Formula> new_conjuncts;
208 for (const Formula &f_i : get_operands(f)) {
209 new_conjuncts.emplace(VisitFormula(f_i, guard));
210 }
211 return make_conjunction(new_conjuncts);
212}
213
214Formula IfThenElseEliminator::VisitDisjunction(const Formula &f, const Formula &guard) const {
215 // f := f₁ ∨ ... ∨ fₙ
216 std::set<Formula> new_disjuncts;
217 for (const Formula &f_i : get_operands(f)) {
218 new_disjuncts.emplace(VisitFormula(f_i, guard));
219 }
220 return make_disjunction(new_disjuncts);
221}
222
223Formula IfThenElseEliminator::VisitNegation(const Formula &f, const Formula &guard) const {
224 return !VisitFormula(get_operand(f), guard);
225}
226
227Formula IfThenElseEliminator::VisitForall(const Formula &f, const Formula &) const {
228 // ∃x. ∀y. ITE(f, e₁, e₂) > 0
229 // => ∃x. ¬∃y. ¬(ITE(f, e₁, e₂) > 0)
230 // => ∃x. ¬∃y. ∃v. ¬(v > 0) ∧ (f → (v = e₁)) ∧ (¬f → (v = e₂))
231 // => ∃x. ∀y. ∀v. ¬(¬(v > 0) ∧ (f → (v = e₁)) ∧ (¬f → (v = e₂)))
232 // => ∃x. ∀y. ∀v. (v > 0) ∨ ¬((f → (v = e₁)) ∧ (¬f → (v = e₂)))
233 // => ∃x. ∀y. ∀v. ¬((f → (v = e₁)) ∧ (¬f → (v = e₂))) ∨ (v > 0)
234 // => ∃x. ∀y. ∀v. ((f → (v = e₁)) ∧ (¬f → (v = e₂))) → (v > 0)
235 // => ∃x. ∀y. ∀v. (v > 0) ∨ (f ∧ (v ≠ e₁)) ∨ (¬f ∧ (v ≠ e₂)).
236
237 // Note that we have the following:
238 // => ∃x. ∀y. ∀v. ¬(¬(v > 0)) ∧ ¬(f ∧ (v ≠ e₁)) ∧ ¬(¬f ∧ (v ≠ e₂)).
239 // => ∃x. ∀y. ∀v. ¬(¬(v > 0)) ∧ (¬f ∨ (v = e₁)) ∧ (f ∨ (v = e₂)).
240 // => ∃x. ∀y. ∀v. ¬(¬(v > 0)) ∧ (f → (v = e₁)) ∧ (¬f → (v = e₂)).
241 //
242 // That is, we can first process the negation of the original
243 // formula `ITE(f, e₁, e₂) > 0`, then negate the result again while
244 // collecting the newly introduced variables (`v`s) to treat them as
245 // universally quantified variables (instead of existential
246 // variables). In this way, we can use the existing ITE-elim routine.
247 Variables quantified_variables{get_quantified_variables(f)};
248 const Formula &quantified_formula{get_quantified_formula(f)};
249 IfThenElseEliminator ite_eliminator_forall{FormulaVisitor::config_};
250 const Formula eliminated{ite_eliminator_forall.Process(!quantified_formula)};
251 for (const auto &[_, v] : ite_eliminator_forall.variables()) {
252 quantified_variables.insert(v);
253 }
254 return forall(quantified_variables, Nnfizer{FormulaVisitor::config_}.Process(!eliminated));
255}
256
257} // namespace dlinear
std::size_t counter_
Counter for the number of introduced variables.
Formula Process(const Formula &f)
Returns a equisatisfiable formula by eliminating if-then-expressions in f by introducing new variable...
std::unordered_map< Expression, Variable > ite_to_var_
Mapping from ITE to the corresponding variable obtained by ITE elimination.
std::vector< Formula > added_formulas_
The added formulas introduced by the elimination process.
std::unordered_map< Variable, Formula > ite_var_to_formulas_
Mapping from ITE to the corresponding variable obtained by ITE elimination.
void Increase()
Increase the iteration counter by one.
Definition Stats.cpp:39
The TimeGuard wraps a timer object and pauses it when the guard object is destructed.
Definition Timer.h:129
Represents a symbolic form of an expression.
bool EqualTo(const Expression &e) const
Checks structural equality.
Represents a symbolic form of a first-order logic formula.
bool EqualTo(const Formula &f) const
Checks structural equality.
bool include_ite() const
Returns true if this symbolic formula includes an ITE (If-Then-Else) expression.
@ CONTINUOUS
A CONTINUOUS variable takes a mpq_class value.
Global namespace for the dlinear library.
Formula make_conjunction(const std::vector< Formula > &formulas)
Make conjunction of formulas.
Definition symbolic.cpp:485
Formula make_disjunction(const std::vector< Formula > &formulas)
Make disjunction of formulas.
Definition symbolic.cpp:493