3 * @author YOUR NAME <YOUR EMAIL ADDRESS>
6 * Created on 2019-02-20.
11 #include <carl-arith/poly/umvpoly/functions/Factorization.h>
12 #include <carl-formula/model/substitutions/ModelConditionalSubstitution.h>
19 template<class Settings>
20 void LVEModule<Settings>::count_variables(std::map<carl::Variable, std::size_t>& count, const ConstraintT& c) const {
21 carl::carlVariables vars;
22 carl::variables(c, vars);
28 template<class Settings>
29 std::map<carl::Variable, std::size_t> LVEModule<Settings>::get_variable_counts() const {
30 std::map<carl::Variable, std::size_t> counts;
31 for (const auto& f: rReceivedFormula()) {
32 carl::visit(f.formula(), [&counts,this](const auto& f){
33 if (f.type() == carl::FormulaType::CONSTRAINT) {
34 count_variables(counts, f.constraint());
41 template<class Settings>
42 std::vector<carl::Variable> LVEModule<Settings>::get_lone_variables() const {
43 std::vector<carl::Variable> vars;
44 for (const auto& c: get_variable_counts()) {
46 vars.emplace_back(c.first);
52 template<class Settings>
53 std::optional<FormulaT> LVEModule<Settings>::eliminate_variable(carl::Variable v, const ConstraintT& c) {
54 auto res = eliminate_linear(v, c);
56 #ifdef SMTRAT_DEVOPTION_Statistics
57 ++mStatistics.elim_linear;
61 res = eliminate_from_factors(v, c);
62 #ifdef SMTRAT_DEVOPTION_Statistics
64 ++mStatistics.elim_factors;
70 template<class Settings>
71 FormulaT LVEModule<Settings>::eliminate_from_separated_weak_inequality(carl::Variable v, const Poly& with, const Poly& without, carl::Relation rel) {
72 auto res = lve::get_root(v, with);
74 SMTRAT_LOG_DEBUG("smtrat.lve", "Satisfying equality by selecting root " << v << " = " << *res);
75 mPPModel.assign(v, *res);
76 return FormulaT(carl::FormulaType::TRUE);
78 SMTRAT_LOG_DEBUG("smtrat.lve", "Factor " << with << " has no real root. Set " << v << " = 0 and eliminate factor.");
79 mPPModel.assign(v, 0);
80 carl::Sign sgn = lve::sgn_of_invariant_poly(v, with);
81 assert(sgn == carl::Sign::NEGATIVE || sgn == carl::Sign::POSITIVE);
82 if (sgn == carl::Sign::NEGATIVE) {
84 case carl::Relation::EQ: rel = carl::Relation::EQ; break;
85 case carl::Relation::LEQ: rel = carl::Relation::GEQ; break;
86 case carl::Relation::GEQ: rel = carl::Relation::LEQ; break;
87 default: assert(false);
89 SMTRAT_LOG_DEBUG("smtrat.lve", "-> " << FormulaT(without, rel));
90 return FormulaT(without, rel);
91 } else if (sgn == carl::Sign::POSITIVE) {
92 SMTRAT_LOG_DEBUG("smtrat.lve", "-> " << FormulaT(without, rel));
93 return FormulaT(without, rel);
101 template<class Settings>
102 FormulaT LVEModule<Settings>::eliminate_from_separated_disequality(carl::Variable v, const Poly& with, const Poly& without) {
103 auto val = lve::get_non_root(v, with);
104 SMTRAT_LOG_DEBUG("smtrat.lve", "Remove factor " << with << " from disequality by selecting non-root " << v << " = " << val);
105 mPPModel.emplace(v, val);
106 return FormulaT(without, carl::Relation::NEQ);
109 inline carl::Sign sign_of(carl::Relation rel, bool invert) {
111 case carl::Relation::LESS:
112 return invert ? carl::Sign::POSITIVE : carl::Sign::NEGATIVE;
113 case carl::Relation::GREATER:
114 return invert ? carl::Sign::NEGATIVE : carl::Sign::POSITIVE;
117 return carl::Sign::ZERO;
121 template<class Settings>
122 FormulaT LVEModule<Settings>::eliminate_from_separated_strict_inequality(carl::Variable v, const Poly& with, const Poly& without, carl::Relation rel) {
123 if (without.is_constant()) {
124 SMTRAT_LOG_DEBUG("smtrat.lve", "Remaining part " << without << " is constant, we choose a proper value for " << v);
125 carl::Sign target = sign_of(rel, without.constant_part() < 0);
126 auto val = lve::get_value_for_sgn(v, with, target);
128 SMTRAT_LOG_DEBUG("smtrat.lve", "Found proper value " << v << " = " << *val << " such that " << with << " " << rel << " 0");
129 mPPModel.emplace(v, *val);
130 return FormulaT(carl::FormulaType::TRUE);
132 SMTRAT_LOG_DEBUG("smtrat.lve", "No value exists for " << v << " such that " << with << " " << rel << " 0");
133 return FormulaT(carl::FormulaType::FALSE);
136 SMTRAT_LOG_DEBUG("smtrat.lve", "Remaining part " << without << " is not constant, we construct a conditional model for " << v);
137 auto posval = lve::get_value_for_sgn(v, with, carl::Sign::POSITIVE);
138 auto negval = lve::get_value_for_sgn(v, with, carl::Sign::NEGATIVE);
139 assert(posval || negval);
141 SMTRAT_LOG_DEBUG("smtrat.lve", "Cannot make " << with << " positive.");
142 mPPModel.emplace(v, *negval);
144 case carl::Relation::LESS: return FormulaT(without, carl::Relation::GREATER);
145 case carl::Relation::GREATER: return FormulaT(without, carl::Relation::LESS);
146 default: assert(false);
151 SMTRAT_LOG_DEBUG("smtrat.lve", "Cannot make " << with << " negative.");
152 mPPModel.emplace(v, *posval);
153 return FormulaT(without, rel);
155 SMTRAT_LOG_DEBUG("smtrat.lve", "Possible values for " << v << " are " << *posval << " and " << *negval);
156 if (FormulaT(without, carl::Relation::LESS).is_false()) {
157 SMTRAT_LOG_DEBUG("smtrat.lve", "Cannot make " << without << " negative.");
159 case carl::Relation::LESS: mPPModel.emplace(v, *negval); break;
160 case carl::Relation::GREATER: mPPModel.emplace(v, *posval); break;
161 default: assert(false);
163 return FormulaT(without, carl::Relation::GREATER);
165 if (FormulaT(without, carl::Relation::GREATER).is_false()) {
166 SMTRAT_LOG_DEBUG("smtrat.lve", "Cannot make " << without << " positive.");
168 case carl::Relation::LESS: mPPModel.emplace(v, *posval); break;
169 case carl::Relation::GREATER: mPPModel.emplace(v, *negval); break;
170 default: assert(false);
172 return FormulaT(without, carl::Relation::LESS);
174 std::vector<std::pair<FormulaT, ModelValue>> subs;
176 case carl::Relation::LESS:
177 subs.emplace_back(FormulaT(without, carl::Relation::LESS), *posval);
178 subs.emplace_back(FormulaT(without, carl::Relation::GREATER), *negval);
180 case carl::Relation::GREATER:
181 subs.emplace_back(FormulaT(without, carl::Relation::LESS), *negval);
182 subs.emplace_back(FormulaT(without, carl::Relation::GREATER), *posval);
184 default: assert(false);
186 mPPModel.emplace(v, carl::createSubstitution<Rational,Poly,carl::ModelConditionalSubstitution<Rational,Poly>>(subs));
187 SMTRAT_LOG_DEBUG("smtrat.lve", "Constructed conditional model: " << mPPModel);
188 return FormulaT(without, carl::Relation::NEQ);
192 template<class Settings>
193 std::optional<FormulaT> LVEModule<Settings>::eliminate_from_separated_factors(carl::Variable v, const Poly& with, const Poly& without, carl::Relation rel) {
194 SMTRAT_LOG_DEBUG("smtrat.lve", "Considering " << v << " in " << with << " and " << without << " and relation " << rel);
195 if (carl::is_weak(rel)) {
196 return eliminate_from_separated_weak_inequality(v, with, without, rel);
197 } else if (rel == carl::Relation::NEQ) {
198 return eliminate_from_separated_disequality(v, with, without);
200 assert(carl::is_strict(rel));
201 return eliminate_from_separated_strict_inequality(v, with, without, rel);
206 template<class Settings>
207 std::optional<FormulaT> LVEModule<Settings>::eliminate_from_factors(carl::Variable v, const ConstraintT& c) {
208 Poly with_v = Poly(1);
209 Poly without_v = Poly(1);
210 for (const auto& factor: c.lhs_factorization()) {
211 carl::carlVariables vars = carl::variables(factor.first);
212 if (vars == carl::carlVariables({ v })) {
213 with_v *= carl::pow(factor.first, factor.second);
214 } else if (std::find(vars.begin(), vars.end(), v) == vars.end()) {
215 without_v *= carl::pow(factor.first, factor.second);
220 assert(!is_zero(with_v) && !is_zero(without_v));
221 SMTRAT_LOG_DEBUG("smtrat.lve", "Separated " << c << " into " << with_v << " and " << without_v);
222 return eliminate_from_separated_factors(v, with_v, without_v, c.relation());
225 template<class Settings>
226 std::optional<FormulaT> LVEModule<Settings>::eliminate_linear(carl::Variable v, const ConstraintT& c) {
227 assert(c.maxDegree(v) > 0);
228 if (c.maxDegree(v) > 1) {
231 // Decompose a * v - b ~ 0
232 carl::Relation rel = c.relation();
233 auto a = c.lhs().coeff(v, 1);
234 auto b = a*v - c.lhs();
235 // Now consider a * v ~ b
236 SMTRAT_LOG_DEBUG("smtrat.lve", "Considering " << a << " * " << v << " " << rel << " " << b);
238 if (a.is_constant()) {
239 if (a.constant_part() < 0) {
241 case carl::Relation::EQ: rel = carl::Relation::EQ; break;
242 case carl::Relation::NEQ: rel = carl::Relation::NEQ; break;
243 case carl::Relation::LESS: rel = carl::Relation::GREATER; break;
244 case carl::Relation::LEQ: rel = carl::Relation::GEQ; break;
245 case carl::Relation::GREATER: rel = carl::Relation::LESS; break;
246 case carl::Relation::GEQ: rel = carl::Relation::LEQ; break;
249 b = b / a.constant_part();
251 SMTRAT_LOG_DEBUG("smtrat.lve", "Transformed to " << v << " " << rel << " " << b);
253 case carl::Relation::EQ: break;
254 case carl::Relation::NEQ: b = b + Rational(1); break;
255 case carl::Relation::LESS: b = b - Rational(1); break;
256 case carl::Relation::LEQ: break;
257 case carl::Relation::GREATER: b = b + Rational(1); break;
258 case carl::Relation::GEQ: break;
260 SMTRAT_LOG_DEBUG("smtrat.lve", "Eliminated with " << v << " = " << b);
261 mPPModel.emplace(v, carl::createSubstitution<Rational,Poly,ModelPolynomialSubstitution>(b));
262 return FormulaT(carl::FormulaType::TRUE);
269 template<class Settings>
270 LVEModule<Settings>::LVEModule(const ModuleInput* _formula, Conditionals& _conditionals, Manager* _manager):
271 PModule( _formula, _conditionals, _manager, SettingsType::moduleName )
274 template<class Settings>
275 LVEModule<Settings>::~LVEModule()
278 template<class Settings>
279 void LVEModule<Settings>::updateModel() const
282 if( solverState() != Answer::UNSAT )
285 SMTRAT_LOG_DEBUG("smtrat.lve", "Got model from backend: " << mModel);
286 SMTRAT_LOG_DEBUG("smtrat.lve", "Merging local model: " << mPPModel);
287 mModel.update(mPPModel);
291 template<class Settings>
292 Answer LVEModule<Settings>::checkCore()
294 std::vector<carl::Variable> vars = get_lone_variables();
295 if (is_minimizing()) {
296 SMTRAT_LOG_DEBUG("smtrat.lve", "Ignore objective variable " << objective());
297 vars.erase(std::find(vars.begin(), vars.end(), objective()));
299 #ifdef SMTRAT_DEVOPTION_Statistics
300 mStatistics.lone_variables = std::max(mStatistics.lone_variables, vars.size());
302 for (const auto& f: rReceivedFormula()) {
303 if (f.formula().type() == carl::FormulaType::CONSTRAINT) {
304 const auto& c = f.formula().constraint();
305 carl::Variable target = carl::Variable::NO_VARIABLE;
307 if (c.variables().has(v)) {
312 if (target != carl::Variable::NO_VARIABLE) {
313 auto res = eliminate_variable(target, c);
315 SMTRAT_LOG_DEBUG("smtrat.lve", "Elimination: " << f.formula() << " -> " << *res);
316 addSubformulaToPassedFormula(*res, f.formula());
321 SMTRAT_LOG_DEBUG("smtrat.lve", "No elimination for " << f.formula());
322 addSubformulaToPassedFormula(f.formula(), f.formula());
324 auto res = runBackends();
325 if (res == UNSAT) getInfeasibleSubsets();
326 #ifdef SMTRAT_DEVOPTION_Statistics
327 mStatistics.eliminated = std::max(mStatistics.eliminated, mPPModel.size());