2 * @file NewCovering.cpp
3 * @author Philip Kroll <Philip.Kroll@rwth-aachen.de>
6 * Created on 2021-07-08.
9 #include "NewCoveringModule.h"
12 template<class Settings>
13 NewCoveringModule<Settings>::NewCoveringModule(const ModuleInput* _formula, Conditionals& _conditionals, Manager* _manager)
14 : Module(_formula, _conditionals, _manager) {
15 SMTRAT_LOG_DEBUG("smtrat.covering", "Init New Covering Module");
16 // Pass informations about the settings to the statistics
17 // TODO re-enable statistics
18 // SMTRAT_STATISTICS_CALL(getStatistics().setVariableOrderingType(mcsat::get_name(Settings::variableOrderingStrategy)));
19 // SMTRAT_STATISTICS_CALL(getStatistics().setCoveringHeuristicType(cadcells::representation::get_name(Settings::covering_heuristic)));
20 // SMTRAT_STATISTICS_CALL(getStatistics().setOperatorType(cadcells::operators::get_name(Settings::op)));
21 // SMTRAT_STATISTICS_CALL(getStatistics().setSamplingAlgorithm(get_name(Settings::sampling_algorithm)));
22 // SMTRAT_STATISTICS_CALL(getStatistics().setIsSampleOutsideAlgorithm(get_name(Settings::is_sample_outside_algorithm)));
23 // SMTRAT_STATISTICS_CALL(getStatistics().setIncremental(Settings::incremental));
24 // SMTRAT_STATISTICS_CALL(getStatistics().setBacktracking(Settings::backtracking));
27 template<class Settings>
28 NewCoveringModule<Settings>::~NewCoveringModule() {}
30 template<class Settings>
31 bool NewCoveringModule<Settings>::informCore(const FormulaT& _constraint) {
32 // Gather all possible constraints for the initial (complete!) variable ordering
33 assert(_constraint.type() == carl::FormulaType::CONSTRAINT);
34 mAllConstraints.push_back(_constraint.constraint());
38 template<class Settings>
39 void NewCoveringModule<Settings>::init() {}
41 template<class Settings>
42 bool NewCoveringModule<Settings>::addCore(ModuleInput::const_iterator _subformula) {
44 assert(_subformula->formula().type() == carl::FormulaType::CONSTRAINT);
45 mUnknownConstraints.push_back(_subformula->formula());
46 //std::erase(mRemoveConstraints,_subformula->formula());
47 mRemoveConstraints.erase(std::remove(mRemoveConstraints.begin(), mRemoveConstraints.end(), _subformula->formula()), mRemoveConstraints.end());
48 SMTRAT_LOG_DEBUG("smtrat.covering", "Adding new unknown constraint: " << _subformula->formula().constraint());
52 template<class Settings>
53 void NewCoveringModule<Settings>::removeCore(ModuleInput::const_iterator _subformula) {
55 assert(_subformula->formula().type() == carl::FormulaType::CONSTRAINT);
56 mRemoveConstraints.push_back(_subformula->formula());
57 //std::erase(mUnknownConstraints,_subformula->formula());
58 mUnknownConstraints.erase(std::remove(mUnknownConstraints.begin(), mUnknownConstraints.end(), _subformula->formula()), mUnknownConstraints.end());
59 SMTRAT_LOG_DEBUG("smtrat.covering", "Adding to remove constraint: " << _subformula->formula().constraint());
62 template<class Settings>
63 void NewCoveringModule<Settings>::updateModel() const {
64 carl::carlVariables vars(carl::variable_type_filter::real());
65 rReceivedFormula().gatherVariables(vars);
67 for (const auto& pair : mLastAssignment) {
68 if (vars.has(pair.first)) {
69 mModel.assign(pair.first,carl::convert<typename Poly::RootType>(pair.second));
74 template<class Settings>
75 size_t NewCoveringModule<Settings>::addConstraintsSAT() {
76 SMTRAT_LOG_DEBUG("smtrat.covering", "Adding constraints: " << mUnknownConstraints);
78 // Recheck the unknown constraints with the last satisfying assignment
79 SMTRAT_LOG_DEBUG("smtrat.covering", "Rechecking the unknown constraints with the last satisfying assignment");
80 std::size_t lowestLevelWithUnsatisfiedConstraint = mVariableOrdering.size() + 1;
81 bool foundUnsatisfiedConstraint = false;
83 std::map<size_t, std::vector<ConstraintT>> constraintsByLevel;
85 for (const auto& formula : mUnknownConstraints) {
86 ConstraintT constraint = formula.constraint();
87 size_t level = helper::level_of(mVariableOrdering, constraint.lhs()) - 1;
88 constraintsByLevel[level].push_back(std::move(constraint));
90 mUnknownConstraints.clear();
92 SMTRAT_LOG_DEBUG("smtrat.covering", "Build constraint map: " << constraintsByLevel);
94 // Now iterate over the constraints by level, starting with lowest first (the keys in a std::map are implicitly sorted using std::less)
95 for (const auto& levelConstraints : constraintsByLevel) {
96 SMTRAT_LOG_DEBUG("smtrat.covering", "Checking level " << levelConstraints.first);
97 if (foundUnsatisfiedConstraint) break;
98 for (const auto& constraint : levelConstraints.second) {
99 if (carl::evaluate(carl::convert<cadcells::Polynomial>(*backend.getContext(), constraint.constr()), mLastAssignment) != true) {
100 // This constraint is unsat with the last assignment
101 SMTRAT_LOG_DEBUG("smtrat.covering", "Found unsatisfied constraint on level:" << levelConstraints.first);
102 foundUnsatisfiedConstraint = true;
103 lowestLevelWithUnsatisfiedConstraint = levelConstraints.first;
109 // We can add the new constraints to the backend now
110 for (const auto& levelConstraints : constraintsByLevel) {
111 backend.addConstraint(levelConstraints.first, std::move(levelConstraints.second));
113 constraintsByLevel.clear();
115 return lowestLevelWithUnsatisfiedConstraint;
118 template<class Settings>
119 void NewCoveringModule<Settings>::removeConstraintsSAT() {
120 SMTRAT_LOG_DEBUG("smtrat.covering", "Removing constraints: " << mRemoveConstraints);
122 // we can just remove the constraints and the corresponding stored information
123 // this does not change the current satisfying assignment/ satisfyability of the given set of constraints
124 for (const auto& constraint : mRemoveConstraints) {
125 backend.removeConstraint(std::move(constraint.constraint()));
127 mRemoveConstraints.clear();
130 template<class Settings>
131 void NewCoveringModule<Settings>::addConstraintsUNSAT() {
132 SMTRAT_LOG_DEBUG("smtrat.covering", "Adding constraints: " << mUnknownConstraints);
134 // Add all unknown constraints to backend
135 // We can do this with no further calculations, as the model stays unsatisfiable
136 for (const auto& constraint : mUnknownConstraints) {
137 backend.addConstraint(std::move(constraint.constraint()));
139 mUnknownConstraints.clear();
142 template<class Settings>
143 bool NewCoveringModule<Settings>::removeConstraintsUNSAT() {
144 SMTRAT_LOG_DEBUG("smtrat.covering", "Removing constraints: " << mRemoveConstraints);
145 assert(backend.getCoveringInformation()[0].isFullCovering());
147 // We have to remove the constraints and the corresponding stored information (derivations with the constraint as origin)
148 // This might include information in the stored full coverings
149 // If not: Nothing changes and the model stays unsatisfiable
150 // If yes: the model might become satisfiable or stays unsatisfiable -> Needs recalculation of the covering at level 0
151 // If level 0 is still full after removal of constraints: the model is still unsatisfiable
152 // If level 0 is not full after removal of constraints: the model might become satisfiable or stays unsatisfiable -> Needs recalculation off all the higher levels : TODO Ask Jasper if this is correct
154 // First: remove all constraints from the backend, this also removes the corresponding derivations and invalidates the coverings, if they used a removed derivations
155 for (const auto& constraint : mRemoveConstraints) {
156 backend.removeConstraint(std::move(constraint.constraint()));
158 mRemoveConstraints.clear();
160 // Second: Check if the covering on level 0 has changed/ was invalidated
161 bool hasChanged = backend.getCoveringInformation()[0].isUnknownCovering();
163 SMTRAT_LOG_DEBUG("smtrat.covering", "Covering on level 0 has changed: " << hasChanged);
165 // Third: If the covering has changed, we need to recompute it
167 backend.getCoveringInformation()[0].computeCovering();
170 SMTRAT_LOG_DEBUG("smtrat.covering", "Covering on level is still full: " << backend.getCoveringInformation()[0].isFullCovering());
172 return backend.getCoveringInformation()[0].isFullCovering();
175 template<class Settings>
176 std::optional<Answer> NewCoveringModule<Settings>::doBacktracking() {
177 // This function is called when we have constraints to remove and no constraints to add
178 // assert(mBacktracking);
179 SMTRAT_STATISTICS_CALL(getStatistics().calledBacktrackingOnly());
181 if (mLastAnswer == Answer::SAT) {
183 removeConstraintsSAT();
187 bool stillFullCovering = removeConstraintsUNSAT();
188 if (stillFullCovering) {
189 // The assignment is still unsatisfiable
191 // we have to recompute the infeasible subset
192 mInfeasibleSubsets.push_back(backend.getInfeasibleSubset());
193 SMTRAT_LOG_DEBUG("smtrat.covering", "Infeasible Subset: " << mInfeasibleSubsets.back());
194 return Answer::UNSAT;
196 backend.resetStoredData(1);
202 template<typename Settings>
203 std::optional<Answer> NewCoveringModule<Settings>::doIncremental() {
204 // This function is called when we have constraints to add and no constraints to remove
205 // assert(mIncremental);
206 SMTRAT_STATISTICS_CALL(getStatistics().calledIncrementalOnly());
208 if (mLastAnswer == Answer::SAT) {
210 auto lowestLevel = addConstraintsSAT();
212 if (lowestLevel == mVariableOrdering.size() + 1) {
213 // The assignment is still satisfiable
216 // Remove all the data from the levels higher than lowestLevel
217 SMTRAT_LOG_DEBUG("smtrat.covering", "Removing data from level " << lowestLevel);
218 backend.resetStoredData(lowestLevel);
223 addConstraintsUNSAT();
224 // NOTE: Trivially the infeasible subset did not change
225 return Answer::UNSAT;
229 template<typename Settings>
230 std::optional<Answer> NewCoveringModule<Settings>::doIncrementalAndBacktracking() {
231 // This function is called when we have constraints to add and constraints to remove
232 // assert(mBacktracking && mIncremental);
234 SMTRAT_STATISTICS_CALL(getStatistics().calledIncrementalAndBacktracking());
236 // First make sure that the vectors are disjoint
237 FormulasT intersection;
238 // we need to sort both vectors to make sure that the intersection is correct
239 std::sort(mRemoveConstraints.begin(), mRemoveConstraints.end());
240 std::sort(mUnknownConstraints.begin(), mUnknownConstraints.end());
241 std::set_intersection(mUnknownConstraints.begin(), mUnknownConstraints.end(), mRemoveConstraints.begin(), mRemoveConstraints.end(), std::back_inserter(intersection));
242 assert(intersection.size() == 0);
244 if (mLastAnswer == Answer::SAT) {
245 // first trivially remove the constraints
246 removeConstraintsSAT();
247 // then add the constraints
248 auto lowestLevel = addConstraintsSAT();
249 if (lowestLevel == mVariableOrdering.size() + 1) {
250 // The assignment is still satisfiable
253 // Remove all the data from the levels higher than lowestLevel
254 backend.resetStoredData(lowestLevel);
258 // first trivially add the constraints
259 addConstraintsUNSAT();
260 // then remove the constraints
261 bool stillFullCovering = removeConstraintsUNSAT();
262 if (stillFullCovering) {
263 // The assignment is still unsatisfiable
264 // we have to recompute the infeasible subset
265 mInfeasibleSubsets.push_back(backend.getInfeasibleSubset());
266 SMTRAT_LOG_DEBUG("smtrat.covering", "Infeasible Subset: " << mInfeasibleSubsets.back());
267 return Answer::UNSAT;
269 // delete everything, but keep level 0
270 backend.resetStoredData(1);
276 template<typename Settings>
277 Answer NewCoveringModule<Settings>::checkCore() {
279 SMTRAT_STATISTICS_CALL(getStatistics().called());
281 SMTRAT_LOG_DEBUG("smtrat.covering", "Check Core called with unknown constraints: " << mUnknownConstraints);
282 SMTRAT_LOG_DEBUG("smtrat.covering", "Check Core called with remove constraints: " << mRemoveConstraints);
283 SMTRAT_LOG_DEBUG("smtrat.covering", "Last Answer: " << mLastAnswer);
284 SMTRAT_LOG_DEBUG("smtrat.covering", "Check Core called with last assignment: " << mLastAssignment);
286 // Check if this is the first time checkCore is called
287 if (mVariableOrdering.empty()) {
289 // Init variable odering, we use the variable ordering which was declared in the settings
290 mVariableOrdering = mcsat::calculate_variable_order<Settings::variableOrderingStrategy>(mAllConstraints);
292 SMTRAT_STATISTICS_CALL(getStatistics().setDimension(mVariableOrdering.size()));
293 SMTRAT_STATISTICS_CALL(cadcells::statistics().set_max_level(mVariableOrdering.size()));
295 // We can clear mAllConstraints now, as we don't need it anymore -> Its only needed to calculate the variable ordering
296 mAllConstraints.clear();
298 SMTRAT_LOG_DEBUG("smtrat.covering", "Got Variable Ordering : " << mVariableOrdering);
301 backend.init(mVariableOrdering);
303 // Add unknown constraints to backend
304 for (const auto& constraint : mUnknownConstraints) {
305 // Asserts that it is indeed a constraint
306 backend.addConstraint(constraint.constraint());
309 mUnknownConstraints.clear();
310 } else if (mLastAnswer == Answer::UNSAT || mLastAnswer == Answer::SAT) {
311 if (mUnknownConstraints.empty() && mRemoveConstraints.empty()) {
312 // We dont have any new constraints and can just return the last value derived by the backend
313 // Why does this even happen??
318 if (mRemoveConstraints.empty() && !mUnknownConstraints.empty()) {
319 // we only have constraints to add, and no constraints to remove
320 // INCREMENTAL CALL ONLY
322 if (Settings::incremental) {
323 auto ans = doIncremental();
324 // check if we can trivially deduce the answer
331 // Dont do incremental, just add constraints and delete all stored data
332 backend.resetStoredData(0);
333 for (auto& constraint : mUnknownConstraints) {
334 backend.addConstraint(constraint.constraint());
336 mUnknownConstraints.clear();
339 } else if (!mRemoveConstraints.empty() && mUnknownConstraints.empty()) {
340 // We only have constraints to remove, and no constraints to add
341 // BACKTRACKING CALL ONLY
343 if (Settings::backtracking) {
344 auto ans = doBacktracking();
345 // check if we can trivially deduce the answer
352 // Dont do backtracking, just remove constraints and delete all stored data
353 backend.resetStoredData(0);
354 for (auto& constraint : mRemoveConstraints) {
355 backend.removeConstraint(constraint.constraint());
357 mRemoveConstraints.clear();
360 } else if (!mRemoveConstraints.empty() && !mUnknownConstraints.empty()) {
361 // We have both constraints to add and constraints to remove
362 // INCREMENTAL AND BACKTRACKING CALL
363 if (Settings::incremental && Settings::backtracking) {
365 auto ans = doIncrementalAndBacktracking();
366 // check if we can trivially deduce the answer
373 // Dont do incremental and backtracking, just add/remove constraints and delete all stored data
374 backend.resetStoredData(0);
375 for (auto& constraint : mUnknownConstraints) {
376 backend.addConstraint(constraint.constraint());
378 mUnknownConstraints.clear();
379 for (auto& constraint : mRemoveConstraints) {
380 backend.removeConstraint(constraint.constraint());
382 mRemoveConstraints.clear();
386 // The last call returned UNKNOWN
387 // we have to delete all stored information and completely re-initialize the backend
388 backend.resetStoredData(0);
389 backend.resetDerivationToConstraintMap();
390 for (auto& constraint : mUnknownConstraints) {
391 backend.addConstraint(constraint.constraint());
393 mUnknownConstraints.clear();
394 for (auto& constraint : mRemoveConstraints) {
395 backend.removeConstraint(constraint.constraint());
397 mRemoveConstraints.clear();
400 // As getUnsatCover is recursive we always have to start at level 0
401 mLastAnswer = backend.getUnsatCover(0);
403 SMTRAT_LOG_DEBUG("smtrat.covering", "Check Core returned: " << mLastAnswer);
405 if (mLastAnswer == Answer::UNSAT || mLastAnswer == Answer::SAT) {
408 // Answer is UNKNOWN and something went wrong
409 SMTRAT_LOG_DEBUG("smtrat.covering", "Backend encountered an error: " << mLastAnswer);
411 // remove all stored information in the backend
412 backend.resetStoredData(0);
413 mLastAssignment.clear(); // There is no satisfying assignment
415 // run complete backend
416 for(auto iter_recv = rReceivedFormula().begin(); iter_recv != rReceivedFormula().end(); ++iter_recv) {
417 addReceivedSubformulaToPassedFormula(iter_recv);
419 auto result = runBackends();
420 //assert(result == Answer::SAT || result == Answer::UNSAT);
421 if (result == Answer::SAT) {
423 } else if (result == Answer::UNSAT) {
424 getInfeasibleSubsets();
432 template<typename Settings>
433 void NewCoveringModule<Settings>::processAnswer() {
434 if (mLastAnswer == Answer::UNSAT) {
435 mInfeasibleSubsets.push_back(backend.getInfeasibleSubset());
436 SMTRAT_LOG_DEBUG("smtrat.covering", "Infeasible Subset: " << mInfeasibleSubsets.back());
437 mLastAssignment.clear(); // There is no satisfying assignment
439 } else if (mLastAnswer == Answer::SAT) {
440 mLastAssignment = backend.getCurrentAssignment();
442 updateModel(); // Update the model according to the last assignment from the backend
445 } // namespace smtrat