SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
LVEModule.tpp
Go to the documentation of this file.
1 /**
2  * @file LVE.cpp
3  * @author YOUR NAME <YOUR EMAIL ADDRESS>
4  *
5  * @version 2019-02-20
6  * Created on 2019-02-20.
7  */
8 
9 #include "LVEModule.h"
10 
11 #include <carl-arith/poly/umvpoly/functions/Factorization.h>
12 #include <carl-formula/model/substitutions/ModelConditionalSubstitution.h>
13 
14 #include "utils.h"
15 
16 namespace smtrat
17 {
18 
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);
23  for (auto v: vars) {
24  count[v] += 1;
25  }
26  }
27 
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());
35  }
36  });
37  }
38  return counts;
39  }
40 
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()) {
45  if (c.second == 1) {
46  vars.emplace_back(c.first);
47  }
48  }
49  return vars;
50  }
51 
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);
55  if (res) {
56 #ifdef SMTRAT_DEVOPTION_Statistics
57  ++mStatistics.elim_linear;
58 #endif
59  return res;
60  }
61  res = eliminate_from_factors(v, c);
62 #ifdef SMTRAT_DEVOPTION_Statistics
63  if (res) {
64  ++mStatistics.elim_factors;
65  }
66 #endif
67  return res;
68  }
69 
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);
73  if (res) {
74  SMTRAT_LOG_DEBUG("smtrat.lve", "Satisfying equality by selecting root " << v << " = " << *res);
75  mPPModel.assign(v, *res);
76  return FormulaT(carl::FormulaType::TRUE);
77  } else {
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) {
83  switch (rel) {
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);
88  }
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);
94  } else {
95  assert(false);
96  return FormulaT();
97  }
98  }
99  }
100 
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);
107  }
108 
109  inline carl::Sign sign_of(carl::Relation rel, bool invert) {
110  switch (rel) {
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;
115  default:
116  assert(false);
117  return carl::Sign::ZERO;
118  }
119  }
120 
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);
127  if (val) {
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);
131  } else {
132  SMTRAT_LOG_DEBUG("smtrat.lve", "No value exists for " << v << " such that " << with << " " << rel << " 0");
133  return FormulaT(carl::FormulaType::FALSE);
134  }
135  } else {
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);
140  if (!posval) {
141  SMTRAT_LOG_DEBUG("smtrat.lve", "Cannot make " << with << " positive.");
142  mPPModel.emplace(v, *negval);
143  switch (rel) {
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);
147  }
148  return FormulaT();
149  }
150  if (!negval) {
151  SMTRAT_LOG_DEBUG("smtrat.lve", "Cannot make " << with << " negative.");
152  mPPModel.emplace(v, *posval);
153  return FormulaT(without, rel);
154  }
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.");
158  switch (rel) {
159  case carl::Relation::LESS: mPPModel.emplace(v, *negval); break;
160  case carl::Relation::GREATER: mPPModel.emplace(v, *posval); break;
161  default: assert(false);
162  }
163  return FormulaT(without, carl::Relation::GREATER);
164  }
165  if (FormulaT(without, carl::Relation::GREATER).is_false()) {
166  SMTRAT_LOG_DEBUG("smtrat.lve", "Cannot make " << without << " positive.");
167  switch (rel) {
168  case carl::Relation::LESS: mPPModel.emplace(v, *posval); break;
169  case carl::Relation::GREATER: mPPModel.emplace(v, *negval); break;
170  default: assert(false);
171  }
172  return FormulaT(without, carl::Relation::LESS);
173  }
174  std::vector<std::pair<FormulaT, ModelValue>> subs;
175  switch (rel) {
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);
179  break;
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);
183  break;
184  default: assert(false);
185  }
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);
189  }
190  }
191 
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);
199  } else {
200  assert(carl::is_strict(rel));
201  return eliminate_from_separated_strict_inequality(v, with, without, rel);
202  }
203  return std::nullopt;
204  }
205 
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);
216  } else {
217  return std::nullopt;
218  }
219  }
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());
223  }
224 
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) {
229  return std::nullopt;
230  }
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);
237 
238  if (a.is_constant()) {
239  if (a.constant_part() < 0) {
240  switch (rel) {
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;
247  }
248  }
249  b = b / a.constant_part();
250  // Now we have v ~ b
251  SMTRAT_LOG_DEBUG("smtrat.lve", "Transformed to " << v << " " << rel << " " << b);
252  switch (rel) {
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;
259  }
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);
263  }
264 
265  return std::nullopt;
266  }
267 
268 
269  template<class Settings>
270  LVEModule<Settings>::LVEModule(const ModuleInput* _formula, Conditionals& _conditionals, Manager* _manager):
271  PModule( _formula, _conditionals, _manager, SettingsType::moduleName )
272  {}
273 
274  template<class Settings>
275  LVEModule<Settings>::~LVEModule()
276  {}
277 
278  template<class Settings>
279  void LVEModule<Settings>::updateModel() const
280  {
281  mModel.clear();
282  if( solverState() != Answer::UNSAT )
283  {
284  getBackendsModel();
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);
288  }
289  }
290 
291  template<class Settings>
292  Answer LVEModule<Settings>::checkCore()
293  {
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()));
298  }
299 #ifdef SMTRAT_DEVOPTION_Statistics
300  mStatistics.lone_variables = std::max(mStatistics.lone_variables, vars.size());
301 #endif
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;
306  for (auto v: vars) {
307  if (c.variables().has(v)) {
308  target = v;
309  break;
310  }
311  }
312  if (target != carl::Variable::NO_VARIABLE) {
313  auto res = eliminate_variable(target, c);
314  if (res) {
315  SMTRAT_LOG_DEBUG("smtrat.lve", "Elimination: " << f.formula() << " -> " << *res);
316  addSubformulaToPassedFormula(*res, f.formula());
317  continue;
318  }
319  }
320  }
321  SMTRAT_LOG_DEBUG("smtrat.lve", "No elimination for " << f.formula());
322  addSubformulaToPassedFormula(f.formula(), f.formula());
323  }
324  auto res = runBackends();
325  if (res == UNSAT) getInfeasibleSubsets();
326  #ifdef SMTRAT_DEVOPTION_Statistics
327  mStatistics.eliminated = std::max(mStatistics.eliminated, mPPModel.size());
328  #endif
329  return res;
330  }
331 }
332 
333