SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
Backend.h
Go to the documentation of this file.
1 /**
2  * @file Backend.h
3  * @author Philip Kroll <Philip.Kroll@rwth-aachen.de>
4  *
5  * @version 2021-07-08
6  * Created on 2021-07-08.
7  */
8 
9 // https://arxiv.org/pdf/2003.05633.pdf
10 
11 #pragma once
12 
14 #include <smtrat-cadcells/common.h>
15 #include "LevelWiseInformation.h"
16 #include "NewCoveringModule.h"
17 #include "NewCoveringSettings.h"
18 #include <carl-arith/constraint/Conversion.h>
19 
20 namespace smtrat {
21 
22 namespace helper {
23 
24 template<typename Pol>
25 static size_t level_of(const VariableOrdering& order, const Pol& poly) {
26  auto poly_variables = carl::variables(poly).as_set();
27  if (poly_variables.empty()) {
28  return 0;
29  }
30  for (std::size_t level = 1; level <= order.size(); ++level) {
31  poly_variables.erase(order[level-1]);
32  if (poly_variables.empty()) return level;
33  }
34  assert(false && "Poly contains variable not found in order"); // precondition violated
35  return 0;
36 }
37 }
38 
39 
40 template<typename Settings>
41 class Backend {
42 
43  using op = typename Settings::op;
44  using PropSet = typename op::PropertiesSet;
45 
46 private:
47  // Context
48  std::shared_ptr<cadcells::Polynomial::ContextType> mContext;
49 
50  // Ordered List of unique unknown Constraints (flat_set by level)
51  std::vector<boost::container::flat_set<cadcells::Constraint>> mUnknownConstraints;
52 
53  // Ordered List of unique known Constraints (flat_set by level)
54  std::vector<boost::container::flat_set<cadcells::Constraint>> mKnownConstraints;
55 
56  // Cache for Polynomials
57  std::shared_ptr<datastructures::PolyPool> mPool;
58 
59  // Cache for polynomial computations
60  std::shared_ptr<datastructures::Projections> mProjections;
61 
62  // Current (partial) satisfying assignment
63  carl::Assignment<cadcells::RAN> mCurrentAssignment;
64 
65  // Current Covering Information, only contains partial coverings
66  std::vector<LevelWiseInformation<Settings>> mCoveringInformation;
67 
68  // Mapping from derivation to the constraints which resulted in its creation
69  std::map<datastructures::SampledDerivationRef<PropSet>, std::vector<cadcells::Constraint>> mDerivationToConstraint;
70 
71 public:
72  // Init with empty variable ordering
73  Backend() {
74  SMTRAT_LOG_DEBUG("smtrat.covering", " Dry Init of Covering Backend");
75  }
76 
77  // Set Variable Ordering and init cache helpers
78  void init(std::vector<carl::Variable>& varOrdering) {
79  mContext = std::make_shared<cadcells::Polynomial::ContextType>(varOrdering);
80 
81  // init Helpers
82  mPool = std::make_shared<datastructures::PolyPool>(*mContext);
83  mProjections = std::make_shared<datastructures::Projections>(*mPool);
84 
85  // Reserve space for the data structures
86  mUnknownConstraints.resize(varOrdering.size());
87  mKnownConstraints.resize(varOrdering.size());
88  mCoveringInformation.resize(varOrdering.size());
89  }
90 
91  std::size_t dimension() {
92  return mContext->variable_ordering().size();
93  }
94 
95  std::shared_ptr<cadcells::Polynomial::ContextType> getContext() {
96  return mContext;
97  }
98 
99  const carl::Assignment<cadcells::RAN>& getCurrentAssignment() {
100  return mCurrentAssignment;
101  }
102 
104  return mCoveringInformation;
105  }
106 
107  // Return all constraints that are reason for the derivation used in the full covering on level 0
109  assert(mCoveringInformation[0].isFullCovering());
110 
111  SMTRAT_LOG_DEBUG("smtrat.covering", "getInfeasibleSubset");
112  // Use Set to avoid duplicates
113  FormulaSetT infeasibleSubset;
114  // We can just take the constraints used in level 0, as all the constraints of higher levels get pushed down if used in the covering
115  for (auto& infeasibleConstraint : mCoveringInformation[0].getConstraintsOfCovering(mDerivationToConstraint)) {
116  auto conv_constraint = carl::convert<Poly>(infeasibleConstraint);
117  infeasibleSubset.insert(FormulaT(ConstraintT(conv_constraint)));
118  }
119  SMTRAT_LOG_DEBUG("smtrat.covering", "getInfeasibleSubset done: " << infeasibleSubset);
120  return infeasibleSubset;
121  }
122 
123  // Adds a constraint into the right level
124  void addConstraint(const ConstraintT& constraint) {
125  // We can substract 1 from level because we dont have constant polynomials
126  std::size_t level = smtrat::helper::level_of(mContext->variable_ordering(), constraint.lhs()) - 1;
127  SMTRAT_LOG_DEBUG("smtrat.covering", "Adding Constraint : " << constraint << " on level " << level);
128  auto conv_constraint = carl::convert<cadcells::Polynomial>(*mContext, constraint.constr()) ;
129  mUnknownConstraints[level].insert(std::move(conv_constraint));
130  }
131 
132  // Adds a constraint into the right level, already given the level
133  void addConstraint(const size_t level, const std::vector<ConstraintT>&& constraints) {
134  SMTRAT_LOG_DEBUG("smtrat.covering", "Adding Constraints : " << constraints << " on level " << level);
135  for (const auto& constraint : constraints) {
136  assert((smtrat::helper::level_of(mContext->variable_ordering(), constraint.lhs()) - 1) == level);
137  auto conv_constraint = carl::convert<cadcells::Polynomial>(*mContext, constraint.constr()) ;
138  mUnknownConstraints[level].insert(std::move(conv_constraint));
139  }
140  }
141 
143  return mUnknownConstraints;
144  }
145 
146  auto& getUnknownConstraints(std::size_t& level) {
147  return mUnknownConstraints[level];
148  }
149 
151  return mKnownConstraints;
152  }
153 
154  auto& getKnownConstraints(std::size_t& level) {
155  return mKnownConstraints[level];
156  }
157 
158  void updateAssignment(std::size_t level) {
159  mCurrentAssignment[mContext->variable_ordering()[level]] = mCoveringInformation[level].getSampleOutside();
160  }
161 
162  // Delete all stored data with level higher or equal
163  void resetStoredData(std::size_t level) {
164  if (level == 0) {
166  }
167  for (std::size_t i = level; i < dimension(); i++) {
168  // Resetting the covering data
169  mCoveringInformation[i].clear();
170  // Resetting the assignment
171  mCurrentAssignment.erase(mContext->variable_ordering()[i]);
172  // Resetting the known constraints
173  for (const auto& constraint : mKnownConstraints[i]) {
174  mUnknownConstraints[i].insert(std::move(constraint));
175  }
176  mKnownConstraints[i].clear();
177  }
178  }
179 
181  mDerivationToConstraint.clear();
182  }
183 
184  // Return true if the constraint to remove was used in the current covering
185  void removeConstraint(const ConstraintT& constraint) {
186  // We can substract 1 from level because we dont have constant polynomials
187  auto conv_constraint = carl::convert<cadcells::Polynomial>(*mContext, constraint.constr()) ;
188 
189  std::size_t level = smtrat::helper::level_of(mContext->variable_ordering(), conv_constraint.lhs()) - 1;
190  SMTRAT_LOG_DEBUG("smtrat.covering", "Removing Constraint : " << conv_constraint << " on level " << level);
191  SMTRAT_LOG_DEBUG("smtrat.covering", "Known Constraints: " << mKnownConstraints);
192  SMTRAT_LOG_DEBUG("smtrat.covering", "Unknown Constraints: " << mUnknownConstraints);
193 
194  // If we find the constraint in the unknown constraints we have the easy case -> Just remove it and not care about the stored data
195  if (mUnknownConstraints[level].find(conv_constraint) != mUnknownConstraints[level].end()) {
196  assert(mKnownConstraints[level].find(conv_constraint) == mKnownConstraints[level].end());
197  // remove all stored information which resulted from the constraint
198  for (std::size_t cur_level = 0; cur_level <= level; cur_level++) {
199  SMTRAT_LOG_DEBUG("smtrat.covering", "Removing on level " << cur_level);
200  mCoveringInformation[cur_level].removeConstraint(conv_constraint, mDerivationToConstraint);
201  }
202  mUnknownConstraints[level].erase(conv_constraint);
203  SMTRAT_LOG_DEBUG("smtrat.covering", "Constraint to remove was in unknown constraints");
204  return;
205  }
206 
207  if (mKnownConstraints[level].find(conv_constraint) == mKnownConstraints[level].end()) {
208  SMTRAT_LOG_DEBUG("smtrat.covering", "Constraint to remove was not in known constraints");
209  // This can happen if the constraint is to be added in the same iteration
210  // TODO: what to do then?
211  return;
212  }
213 
214  // The constraint must be in the known constraints
215  SMTRAT_LOG_DEBUG("smtrat.covering", "Constraint to remove was in known constraints");
216  // remove all stored information which resulted from the constraint
217  for (std::size_t cur_level = 0; cur_level <= level; cur_level++) {
218  SMTRAT_LOG_DEBUG("smtrat.covering", "Removing on level " << cur_level);
219  mCoveringInformation[cur_level].removeConstraint(conv_constraint, mDerivationToConstraint);
220  }
221 
222  // remove the constraint from the known constraints
223  mKnownConstraints[level].erase(conv_constraint);
224  }
225 
226  void setConstraintsKnown(const std::size_t& level) {
227  for (const auto& constraint : mUnknownConstraints[level]) {
228  mKnownConstraints[level].insert(std::move(constraint));
229  }
230  mUnknownConstraints[level].clear();
231  }
232 
233  void setConstraintsUnknown(const std::size_t& level) {
234  // Note: this also resets all higher levels
235  for (std::size_t i = level; i < dimension(); i++) {
236  for (const auto& constraint : mKnownConstraints[i]) {
237  mUnknownConstraints[i].insert(std::move(constraint));
238  }
239  mKnownConstraints[i].clear();
240  }
241  }
242 
243  void processUnknownConstraints(const std::size_t& level, const bool prune_assignment) {
244  SMTRAT_LOG_DEBUG("smtrat.covering", "Processing unknown constraints on level " << level << " with " << mUnknownConstraints[level].size() << " constraints");
245  SMTRAT_LOG_DEBUG("smtrat.covering", "Need to prune the assignment: " << prune_assignment);
246 
247  for (const cadcells::Constraint& constraint : mUnknownConstraints[level]) {
248  std::vector<datastructures::SampledDerivationRef<PropSet>> intervals;
249  if (prune_assignment) {
250  intervals = algorithms::get_unsat_intervals<op>(constraint, *mProjections, mCurrentAssignment);
251  } else {
252  // create copy of the assignment with mContext->variable_ordering()[level] and following not present
253  carl::Assignment<cadcells::RAN> assignment;
254  for (std::size_t i = 0; i < level; i++) {
255  assignment[mContext->variable_ordering()[i]] = mCurrentAssignment[mContext->variable_ordering()[i]];
256  }
257  intervals = algorithms::get_unsat_intervals<op>(constraint, *mProjections, assignment);
258  }
259  for (const auto& interval : intervals) {
260  SMTRAT_LOG_DEBUG("smtrat.covering", "Found UNSAT Interval: " << interval->cell() << " from constraint: " << constraint);
261  // Insert into the derivation to constraint map
262  mDerivationToConstraint.insert(std::make_pair(interval, std::vector<cadcells::Constraint>{constraint}));
263  mCoveringInformation[level].addDerivation(std::move(interval));
264  }
265  }
266 
267  // Set the unknown constraints to be known, as all new derivations have been calculated
268  setConstraintsKnown(level);
269  }
270 
271  Answer getUnsatCover(const std::size_t level) {
272  SMTRAT_LOG_DEBUG("smtrat.covering", " getUnsatCover for level: " << level << " / " << dimension());
273  SMTRAT_LOG_DEBUG("smtrat.covering", " Variable Ordering: " << mContext->variable_ordering());
274  SMTRAT_LOG_DEBUG("smtrat.covering", " Unknown Constraints: " << mUnknownConstraints[level]);
275  SMTRAT_LOG_DEBUG("smtrat.covering", " Known Constraints: " << mKnownConstraints[level]);
276  SMTRAT_LOG_DEBUG("smtrat.covering", " Current Covering Information: " << mCoveringInformation[level]);
277  SMTRAT_LOG_DEBUG("smtrat.covering", " Current Assignment: " << mCurrentAssignment);
278 
279  // incase of incremental solving, we need to check if the current level is already assigned
280  // if it is assigned, the current assignment is satisfying all unknown constraints and we dont need to process the unknown constraints
281  // If we know that the assignment is still satisfying we also dont need to recalculate the (partial!) covering.
282  if (mCurrentAssignment.find(mContext->variable_ordering()[level]) == mCurrentAssignment.end()) {
283  processUnknownConstraints(level, false);
284  SMTRAT_LOG_DEBUG("smtrat-covering", "Computing Covering represenentation")
285  bool invalidates = mCoveringInformation[level].computeCovering();
286  if (invalidates) {
287  SMTRAT_LOG_DEBUG("smtrat.covering", "Computed Covering invalidates all higher levels as the underlying sample point changed");
288  resetStoredData(level + 1);
289  }
290  } else {
291  SMTRAT_LOG_DEBUG("smtrat.covering", "Current variable " << mContext->variable_ordering()[level] << " is assigned, skipping processing of new constraints and computing covering representation");
292  // Possible in the case that SAT was reported before and constraints were removed and invalidated the current partial covering
293  if (mCoveringInformation[level].isUnknownCovering()) {
294  SMTRAT_LOG_DEBUG("smtrat.covering", "Covering was invalidated, recomputing covering representation and processing all unknown constraints");
295  processUnknownConstraints(level, true);
296  bool invalidates = mCoveringInformation[level].computeCovering();
297  if (invalidates) {
298  SMTRAT_LOG_DEBUG("smtrat.covering", "Computed Covering invalidates all higher levels as the underlying sample point changed");
299  resetStoredData(level + 1);
300  }
301  assert(mCoveringInformation[level].isPartialCovering());
302  }
303  }
304 
305  SMTRAT_LOG_DEBUG("smtrat.covering", "Got CoveringStatus: " << mCoveringInformation[level].getCoveringStatus());
306  if (mCoveringInformation[level].isFailedCovering()) {
307  SMTRAT_LOG_DEBUG("smtrat.covering", "Covering failed -> Abort");
308  return Answer::UNKNOWN;
309  }
310 
311  while (mCoveringInformation[level].isPartialCovering()) {
312  SMTRAT_LOG_DEBUG("smtrat.covering", "Sample outside " << mCoveringInformation[level].getSampleOutside());
313  updateAssignment(level);
314  if (mCurrentAssignment.size() == mContext->variable_ordering().size()) {
315  // SAT
316  SMTRAT_LOG_DEBUG("smtrat.covering", "Found satisfying variable assignment: " << mCurrentAssignment);
317  return Answer::SAT;
318  }
319 
320  Answer nextLevelAnswer = getUnsatCover(level + 1);
321  if (nextLevelAnswer == Answer::SAT) {
322  SMTRAT_LOG_DEBUG("smtrat.covering", "Got SAT on level: " << level);
323  // Push down SAT
324  return nextLevelAnswer;
325  } else if (nextLevelAnswer == Answer::UNSAT) {
326 
327  auto new_derivation = mCoveringInformation[level + 1].constructDerivation(mDerivationToConstraint);
328 
329  if (!new_derivation.has_value()) {
330  SMTRAT_LOG_DEBUG("smtrat.covering", "No new derivation found -> Abort");
331  return Answer::UNKNOWN;
332  }
333 
334  SMTRAT_LOG_DEBUG("smtrat.covering", "Found new derivation: " << new_derivation.value()->cell());
335  SMTRAT_LOG_DEBUG("smtrat.covering", "Adding new derivation to Covering Information");
336  mCoveringInformation[level].addDerivation(std::move(new_derivation.value()));
337 
338  // delete the now obsolete data
339  mCurrentAssignment.erase(mContext->variable_ordering()[level]);
340  mCoveringInformation[level + 1].clear();
341  setConstraintsUnknown(level + 1);
342 
343  // If there are unknown constraints on this level, we need to process them now
344  processUnknownConstraints(level, false);
345 
346  // Recalculate the current covering
347  SMTRAT_LOG_DEBUG("smtrat.covering", "Computing covering representation");
348  bool invalidates = mCoveringInformation[level].computeCovering();
349  if (invalidates) {
350  SMTRAT_LOG_DEBUG("smtrat.covering", "Computed Covering invalidates all higher levels as the underlying sample point changed");
351  resetStoredData(level + 1);
352  }
353  SMTRAT_LOG_DEBUG("smtrat.covering", "Got CoveringStatus: " << mCoveringInformation[level].getCoveringStatus());
354  if (mCoveringInformation[level].isFailedCovering()) {
355  SMTRAT_LOG_DEBUG("smtrat.covering", "Covering failed -> Abort");
356  return Answer::UNKNOWN;
357  }
358 
359  } else {
360  // Something went wrong (McCallum failed)
361  return Answer::UNKNOWN;
362  }
363  }
364 
365  assert(mCoveringInformation[level].isFullCovering());
366  SMTRAT_LOG_DEBUG("smtrat.covering", "Cells cover the numberline ");
367 
368  return Answer::UNSAT;
369  }
370 };
371 } // namespace smtrat
auto & getUnknownConstraints(std::size_t &level)
Definition: Backend.h:146
std::vector< LevelWiseInformation< Settings > > mCoveringInformation
Definition: Backend.h:66
void addConstraint(const size_t level, const std::vector< ConstraintT > &&constraints)
Definition: Backend.h:133
void updateAssignment(std::size_t level)
Definition: Backend.h:158
std::shared_ptr< cadcells::Polynomial::ContextType > mContext
Definition: Backend.h:48
std::shared_ptr< datastructures::Projections > mProjections
Definition: Backend.h:60
void resetStoredData(std::size_t level)
Definition: Backend.h:163
typename op::PropertiesSet PropSet
Definition: Backend.h:44
void removeConstraint(const ConstraintT &constraint)
Definition: Backend.h:185
std::vector< boost::container::flat_set< cadcells::Constraint > > mUnknownConstraints
Definition: Backend.h:51
void processUnknownConstraints(const std::size_t &level, const bool prune_assignment)
Definition: Backend.h:243
auto & getKnownConstraints(std::size_t &level)
Definition: Backend.h:154
const carl::Assignment< cadcells::RAN > & getCurrentAssignment()
Definition: Backend.h:99
std::map< datastructures::SampledDerivationRef< PropSet >, std::vector< cadcells::Constraint > > mDerivationToConstraint
Definition: Backend.h:69
void setConstraintsUnknown(const std::size_t &level)
Definition: Backend.h:233
void init(std::vector< carl::Variable > &varOrdering)
Definition: Backend.h:78
std::vector< boost::container::flat_set< cadcells::Constraint > > mKnownConstraints
Definition: Backend.h:54
auto & getCoveringInformation()
Definition: Backend.h:103
std::size_t dimension()
Definition: Backend.h:91
void setConstraintsKnown(const std::size_t &level)
Definition: Backend.h:226
auto & getKnownConstraints()
Definition: Backend.h:150
void resetDerivationToConstraintMap()
Definition: Backend.h:180
typename Settings::op op
Definition: Backend.h:43
Answer getUnsatCover(const std::size_t level)
Definition: Backend.h:271
auto & getUnknownConstraints()
Definition: Backend.h:142
std::shared_ptr< cadcells::Polynomial::ContextType > getContext()
Definition: Backend.h:95
std::shared_ptr< datastructures::PolyPool > mPool
Definition: Backend.h:57
void addConstraint(const ConstraintT &constraint)
Definition: Backend.h:124
carl::Assignment< cadcells::RAN > mCurrentAssignment
Definition: Backend.h:63
FormulaSetT getInfeasibleSubset()
Definition: Backend.h:108
static bool find(V &ts, const T &t)
Definition: Alg.h:47
std::vector< carl::Variable > VariableOrdering
Definition: common.h:11
carl::BasicConstraint< Polynomial > Constraint
Definition: common.h:18
static size_t level_of(const VariableOrdering &order, const Pol &poly)
Definition: Backend.h:25
Class to create the formulas for axioms.
carl::FormulaSet< Poly > FormulaSetT
Definition: types.h:41
carl::Formula< Poly > FormulaT
Definition: types.h:37
Answer
An enum with the possible answers a Module can give.
Definition: types.h:57
@ UNKNOWN
Definition: types.h:57
carl::Constraint< Poly > ConstraintT
Definition: types.h:29
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35