SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
Projection_EC.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <iostream>
4 #include <map>
5 #include <vector>
6 
7 #include "../common.h"
8 #include "BaseProjection.h"
9 #include "ProjectionComparator.h"
10 
11 namespace smtrat {
12 namespace cad {
13 namespace full_ec {
14 using Polynomial = std::optional<UPoly>;
15 }
16 
17 template<typename Settings>
19 private:
21  using Super::callRemoveCallback;
22  using Super::canBePurgedByBounds;
23  using Super::freeID;
24  using Super::getID;
25  using Super::isPurged;
26  using Super::mConstraints;
27  using Super::mInfo;
28  using Super::mLiftingQueues;
29  using Super::mOperator;
30  using Super::var;
31  using typename Super::Constraints;
32 
33 public:
34  using Super::dim;
35  using Super::size;
36 
37 private:
38  template<typename S>
39  friend std::ostream& operator<<(std::ostream& os, const Projection<Incrementality::FULL, Backtracking::HIDE, S>& p);
40  // A projection candidate: a level to project into and two ids that refer to the level above.
41  struct QueueEntry {
42  std::size_t level;
43  std::size_t first;
44  std::size_t second;
45 
46  QueueEntry(std::size_t l, std::size_t f, std::size_t s)
47  : level(l), first(f), second(s) {}
48  friend std::ostream& operator<<(std::ostream& os, const QueueEntry& qe) {
49  return os << "(" << qe.first << "," << qe.second << ")@" << qe.level;
50  }
51  };
52  struct ProjectionCandidateComparator {
53  public:
54  using PolyGetter = std::function<UPoly(std::size_t, std::size_t)>;
56  : mPG(pg) {}
58  ProjectionCandidateComparator(const ProjectionCandidateComparator& pcc)
59  : mPG(pcc.mPG) {}
60  bool operator()(const QueueEntry& lhs, const QueueEntry& rhs) const {
61  assert(mPG);
62  UPoly lp = mPG(lhs.level, lhs.first);
63  UPoly lq = mPG(lhs.level, lhs.second);
64  UPoly rp = mPG(rhs.level, rhs.first);
65  UPoly rq = mPG(rhs.level, rhs.second);
66  return mComparator(cad::candidate(lp, lq, lhs.level), cad::candidate(rp, rq, rhs.level));
67  //return rp < lp;
68  }
69 
70  private:
73  };
74  std::function<bool(std::size_t, std::size_t)> mCanBePurged;
75  // Stores until which level some polynomials might be (not anymore) purged due to adding / removing bounds.
76  std::size_t checkPurged;
77 
78  // Maps polynomials to a (per level) unique ID.
79  std::vector<std::map<UPoly, std::size_t>> mPolynomialIDs;
80  // Stores polynomials with their origins, being pairs of polynomials from the level above.
81  std::vector<std::vector<full_ec::Polynomial>> mPolynomials;
82  // Stores the projection queue for all candidates.
84  // Stores inactive projection queue entries.
86  // Stores whether some inactive queue entries might be active again due to adding/removing a polynomial.
88 
89  std::string logPrefix(std::size_t level) const {
90  return std::string(dim() - level, '\t');
91  }
92  /*
93  * Evaluate whether a queue entry is purged.
94  * @param qe Queue entry.
95  */
96  bool isPurged(const QueueEntry& qe) {
97  return !(active(qe.level, qe.first) && active(qe.level, qe.second));
98  }
99  /*
100  * Evaluates if polynomials are purged, for not yet evaluated polynomials.
101  * @param level Level until which polynomials need to be evaluated.
102  */
103  void computePurgedPolynomials(std::size_t level) {
104  for (std::size_t lvl = 1; lvl <= level; lvl++) {
105  for (const auto& it : mPolynomialIDs[lvl]) {
106  active(lvl, it.second);
107  }
108  }
109  }
110 
111  /*
112  * Returns true when the polynomial is active (if it has an active BaseType and is not purged due to the bounds).
113  * @param level Level of the polynomial.
114  * @param id Id of the polynomial.
115  */
116  bool active(std::size_t level, std::size_t id) const {
117  return mInfo.isActive(level, id);
118  }
119 
120  bool isQueueEntryActive(std::size_t level, std::size_t first, std::size_t second, bool usingEC) const {
121  if (usingEC) {
122  if (!active(level, second)) return false;
123 
124  const auto& ec = mInfo.getUsedEC(level);
125  if (ec.test(first)) {
126  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "First is part of EC");
127  return true;
128  } else if (ec.test(second)) {
129  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Second is part of EC");
130  return true;
131  }
132 
133  if (Settings::semiRestrictedProjection && first == second) {
134  if (!Settings::restrictedIfPossible || (level > 1 && level < dim() - 1)) {
135  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Single projection in semi-restricted projection");
136  return true;
137  }
138  }
139 
140  return false;
141  } else {
142  return active(level, second);
143  }
144  }
145 
146  /**
147  * Add projection candidates for a new polynomial.
148  * @param level Level of the projection candidate.
149  * @param id Id of the new polynomial.
150  */
151  void insertIntoProjectionQueue(std::size_t level, std::size_t id) {
152  assert(level < dim());
153  bool usingEC = mInfo.usingEC(level);
154 
155  for (const auto& it : mPolynomialIDs[level]) {
156  assert(mPolynomials[level][it.second]);
157  if (isQueueEntryActive(level, id, it.second, usingEC)) {
158  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding to PQ (" << it.second << "," << id << ")@" << level);
159  mProjectionQueue.emplace(level, it.second, id);
160  } else {
161  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding to IQ (" << it.second << "," << id << ")@" << level);
162  mInactiveQueue.emplace(level, it.second, id);
163  }
164  }
165  }
166 
167  /**
168  * Delete polynomial in mProjection and all other datastructures.
169  * @param p Polynomial in level 0 that is deleted.
170  * @param cid Id of the polynomial in level 0 that is deleted.
171  */
172  void deletePolynomials(const UPoly& p, std::size_t cid) {
173  assert(mPolynomials[0][cid]);
174  assert(*mPolynomials[0][cid] == p);
175  mInfo.clear(0, cid);
176  mProjectionQueue.removeIf([cid](const QueueEntry& qe) { return (qe.level == 0) && (qe.first == cid || qe.second == cid); });
177  mInactiveQueue.removeIf([cid](const QueueEntry& qe) { return (qe.level == 0) && (qe.first == cid || qe.second == cid); });
178  carl::Bitset filter = carl::Bitset().set(cid);
179  for (std::size_t level = 1; level <= dim(); level++) {
180  for (std::size_t lvl = level; lvl <= dim(); lvl++) {
181  for (auto it = mPolynomialIDs[level].begin(); it != mPolynomialIDs[level].end(); it++) {
182  mInfo(level, it->second).origin.erase(level, filter);
183  }
184  }
185  carl::Bitset removed;
186  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> Purging from level " << level << " with filter " << filter);
187  for (auto it = mPolynomialIDs[level].begin(); it != mPolynomialIDs[level].end();) {
188  std::size_t id = it->second;
189  assert(mPolynomials[level][id]);
190  if (mInfo(level, it->second).origin.empty()) {
191  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> Purging " << id << " from level " << level);
192  removed.set(id);
193  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "Removing " << id << " on " << level);
194  if (level < dim()) {
195  mProjectionQueue.removeIf([level, id](const QueueEntry& qe) { return (qe.level == level) && (qe.first == id || qe.second == id); });
196  mInactiveQueue.removeIf([level, id](const QueueEntry& qe) { return (qe.level == level) && (qe.first == id || qe.second == id); });
197  }
198  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> Removing polynomial");
199  mLiftingQueues[level - 1].disable(id);
200  mInfo.clear(level, id);
201  freeID(level, id);
202  it = mPolynomialIDs[level].erase(it);
203  } else {
204  it++;
205  }
206  }
207  SMTRAT_LOG_TRACE("smtrat.cad.projection", "Calling callback for level " << level << ", removed [" << removed << "]");
208  callRemoveCallback(level, removed);
209  filter = removed;
210  }
211  }
212  /**
213  * Deactivate inactive polynomials in mProjection.
214  * @param level Level at which first deactivation occured.
215  */
216  void deactivatePolynomials(std::size_t level) {
217  for (std::size_t lvl = level; lvl < dim(); lvl++) {
218  // find inactive polynomials in lvl
219  carl::Bitset remove;
220  for (std::size_t id = 0; id < mPolynomials[lvl].size(); ++id) {
221  if (!mPolynomials[lvl][id]) continue;
222  if (!active(lvl, id)) {
223  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> Purging " << id << " from level " << lvl);
224  remove.set(id);
225  }
226  }
227  SMTRAT_LOG_TRACE("smtrat.cad.projection", "Calling callback for level " << level << ", removed [" << remove << "]");
228  if (lvl > 0) {
230  }
231  // deactivate polynomials in following levels due to the inactive polynomials in lvl
232  for (std::size_t l = lvl + 1; l <= dim(); l++) {
233  for (const auto& it : mPolynomialIDs[l]) {
234  assert(mPolynomials[l][it.second]);
235  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> Purging " << l << "/" << it.second << " with " << lvl << " / " << remove);
236  mInfo(l, it.second).origin.deactivate(lvl, remove);
237  // remove inactive polynomials from LiftingQueue
238  if (!active(l, it.second)) {
239  mLiftingQueues[l - 1].disable(it.second);
240  }
241  }
242  }
243  }
244  }
245  /**
246  * Activate active polynomials in mProjection.
247  * @param level Level at which first activation occured.
248  */
249  carl::Bitset activatePolynomials(std::size_t level) {
250  carl::Bitset changed_levels;
251  for (std::size_t lvl = level; lvl < dim(); lvl++) {
252  // find active polynomials in lvl
253  carl::Bitset activate;
254  for (std::size_t id = 0; id < mPolynomials[lvl].size(); ++id) {
255  if (!mPolynomials[lvl][id]) continue;
256  if (active(lvl, id)) {
257  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> " << id << " from level " << lvl << " is active");
258  activate.set(id);
259  changed_levels.set(lvl);
260  } else {
261  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> " << id << " from level " << lvl << " remains inactive");
262  }
263  }
264  // activate polynomials in following levels due to the active polynomials in lvl
265  for (std::size_t l = lvl + 1; l <= dim(); l++) {
266  for (const auto& it : mPolynomialIDs[l]) {
267  assert(mPolynomials[l][it.second]);
268  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> Activating origins for " << it.second << " from level " << lvl << " with " << activate);
269  mInfo(l, it.second).origin.activate(lvl, activate);
270  //add active polynomials to LiftingQueue
271  if (active(l, it.second)) {
272  mLiftingQueues[l - 1].restore(it.second);
273  }
274  }
275  }
276  }
277  updateInactiveQueue = true;
278  return changed_levels;
279  }
280 
281  /**
282  * Deactivate polynomials in the projection (in lvl > level) that become irrelevant due to a new equational constraint.
283  * @param level Level of the equational constraint.
284  */
285  void restrictProjection(std::size_t level) {
286  std::size_t lvl = level;
287  bool restricted = false;
288  while (lvl < dim() && !mInfo.usingEC(lvl) && mInfo(lvl).ecs.hasEC() && (Settings::interruptions || mInfo.usingEC(lvl-1))) {
289  restricted = true;
290  if (!mInfo.selectEC(lvl)) break;
291 
292  const carl::Bitset& eqc = mInfo.getUsedEC(lvl);
293  for (std::size_t l = lvl + 1; l <= dim(); l++) {
294  for (const auto& it : mPolynomialIDs[l]) {
295  assert(mPolynomials[l][it.second]);
296  mInfo(l, it.second).origin.deactivateEC(lvl, eqc);
297  if (!active(l, it.second)) {
298  mLiftingQueues[l - 1].disable(it.second);
299  }
300  }
301  }
302  lvl++;
303  }
304  if (restricted) {
305  deactivatePolynomials(level + 1);
306  }
307  }
308  /**
309  * Activate polynomials in the projection (in lvl > level) that become again relevant if an equational constraint is removed.
310  * (Extend restricted projection if necessary.)
311  * @param p Polynomial that becomes removed.
312  */
313  void extendProjection(const UPoly& p) {
314  std::size_t level = 1;
315  while ((level < dim()) && projection::canBeForwarded(level, carl::switch_main_variable(p, var(level)))) {
316  level += 1;
317  }
318  if (mPolynomialIDs[level].find(carl::switch_main_variable(p, var(level))) == mPolynomialIDs[level].end()) {
319  return;
320  }
321  std::size_t id = mPolynomialIDs[level].find(carl::switch_main_variable(p, var(level)))->second;
322  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Checking if " << p << " is part of an EC in " << level);
323  if (!mInfo.usingEC(level) || !mInfo.getUsedEC(level).test(id)) {
324  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "No, nothing to change.");
325  return;
326  }
327  if (mInfo(level).ecs.hasEC()) {
328  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Level " << level << " is using an EC");
329  std::size_t lvl = level;
330  carl::Bitset eqc;
331  while (lvl == level || (mInfo.usingEC(lvl) && !Settings::interruptions)) {
332  eqc = mInfo.getUsedEC(lvl);
333  for (std::size_t l = lvl + 1; l <= dim(); l++) {
334  for (const auto& it : mPolynomialIDs[l]) {
335  assert(mPolynomials[l][it.second]);
336  mInfo(l, it.second).origin.activateEC(lvl, eqc);
337  if (active(l, it.second)) {
338  mLiftingQueues[l - 1].restore(it.second);
339  }
340  }
341  }
342  mInfo.unselectEC(lvl);
343  lvl++;
344  }
345  activatePolynomials(level + 1);
346  } else {
347  carl::Bitset eqc;
348  eqc = carl::Bitset().set(id);
349  for (std::size_t l = level + 1; l <= dim(); l++) {
350  for (const auto& it : mPolynomialIDs[l]) {
351  assert(mPolynomials[l][it.second]);
352  mInfo(l, it.second).origin.activateEC(level, eqc);
353  if (active(l, it.second)) {
354  mLiftingQueues[l - 1].restore(it.second);
355  }
356  }
357  }
358  mInfo.unselectEC(level);
359  activatePolynomials(level + 1);
360  restrictProjection(level);
361  }
362  }
363 
364  /// Inserts a polynomial with the given origin into the given level.
365  carl::Bitset insertPolynomialTo(std::size_t level, const UPoly& p, const Origin::BaseType& origin, bool setBound = false) {
366  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "Receiving " << p << " for level " << level);
367  if (projection::canBeRemoved(p)) {
368  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> but is safely removed.");
369  return carl::Bitset();
370  }
371  if ((level < dim()) && projection::canBeForwarded(level, p)) {
372  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> but is forwarded to " << (level + 1));
373  return insertPolynomialTo(level + 1, carl::switch_main_variable(p, var(level + 1)), origin, setBound);
374  }
375  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "Inserting " << p << " into level " << level);
376  assert(level <= dim());
377  auto it = mPolynomialIDs[level].find(p);
378  if (it != mPolynomialIDs[level].end()) {
379  assert(mPolynomials[level][it->second]);
380  bool activated = active(level, it->second);
381  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> Polynomial was already present. Already active? " << activated);
382  if (Settings::simplifyProjectionByBounds && setBound) {
383  assert(level > 0 && level <= dim());
384  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Setting " << level << "/" << it->second << " is a bound.");
385  mInfo(level).setBound(it->second, true);
386  }
387  if (Settings::restrictProjectionByEC) {
388  SMTRAT_LOG_INFO("smtrat.cad.projection", "Checking whether " << p << " is from an equational constraint.");
389  mInfo().addToEC(origin, level, it->second);
390  }
391  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> Polynomial was already present, adding origins " << origin);
392  mInfo(level, it->second).origin += origin;
393  // in case p was inactive but becomes active by new BaseType activate successors
394  if (activated == false && active(level, it->second)) {
395  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> Polynomial was inactive and is now active");
396  activatePolynomials(level);
397  mLiftingQueues[level - 1].restore(it->second);
398  updateInactiveQueue = true;
399  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> Restored polynomial");
400  SMTRAT_LOG_INFO("smtrat.cad.projection", *this);
401  return carl::Bitset({level});
402  }
403  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> nothing changed.");
404  return carl::Bitset();
405  }
406  std::size_t id = getID(level);
407  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> Got new id " << id);
408  if (id >= mPolynomials[level].size()) mPolynomials[level].resize(id + 1);
409  assert(!mPolynomials[level][id]);
410  mInfo.emplace(level, id);
411  mInfo(level, id).origin = Origin(origin);
412  mPolynomials[level][id] = p;
413  mLiftingQueues[level - 1].insert(id);
414  mPolynomialIDs[level].emplace(p, id);
415  if (Settings::simplifyProjectionByBounds && setBound) {
416  assert(level > 0 && level <= dim());
417  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Setting " << level << "/" << id << " is a bound.");
418  mInfo(level).setBound(id, true);
419  }
420  isPurged(level, id);
421  if (Settings::restrictProjectionByEC) {
422  SMTRAT_LOG_INFO("smtrat.cad.projection", *this);
423  SMTRAT_LOG_INFO("smtrat.cad.projection", "Checking whether " << p << " is from an equational constraint.");
424  mInfo().addToEC(origin, level, id);
425  }
426  if (level < dim()) {
427  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> Inserting " << id << " into queue for level " << (level + 1));
428  insertIntoProjectionQueue(level, id);
429  }
430 
431  if (Settings::restrictProjectionByEC) {
432  SMTRAT_LOG_INFO("smtrat.cad.projection", "Possibly enabling EC " << p);
433  restrictProjection(level);
434  }
435  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(level) << "-> Done.");
436  return carl::Bitset({level});
437  }
438 
439  carl::Bitset project(const ConstraintSelection&) {
440  while (!mProjectionQueue.empty()) {
441  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> Using next projection candidate " << mProjectionQueue.top());
442  QueueEntry qe = mProjectionQueue.top();
443  mProjectionQueue.pop();
444  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> Checking if the candidate is active.");
445  bool moveToInactive = false;
446  if (Settings::simplifyProjectionByBounds && isPurged(qe)) {
447  moveToInactive = true;
448  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> purged by bounds");
449  } else if (!active(qe.level, qe.first) || !active(qe.level, qe.second)) {
450  moveToInactive = true;
451  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> origins are inactive");
452  } else if (Settings::restrictProjectionByEC && qe.level != 0 && mInfo.usingEC(qe.level)) {
453  if (!mInfo.getUsedEC(qe.level).test(qe.first) && !mInfo.getUsedEC(qe.level).test(qe.second)) {
454  if (Settings::semiRestrictedProjection) {
455  if (qe.first != qe.second) {
456  moveToInactive = true;
457  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> disabled due to semi restricted projection");
458  } else if (qe.level <= 1 || qe.level >= dim()-1) {
459  moveToInactive = true;
460  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> disabled due to restricted projection in first or last level");
461  }
462  } else if (!Settings::semiRestrictedProjection) {
463  moveToInactive = true;
464  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> disabled due to restricted projection");
465  }
466  }
467  }
468  if (moveToInactive) {
469  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> moving to InactiveQueue");
470  mInactiveQueue.push(qe);
471  } else {
472  carl::Bitset res = projectCandidate(qe);
473  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> res = " << res);
474  if (res.any()) return res;
475  }
476  }
477  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> Projection is finished.");
478  return carl::Bitset();
479  }
480  carl::Bitset projectCandidate(const QueueEntry& qe) {
481  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Projecting " << qe);
482  assert(qe.level < dim());
483  carl::Bitset res;
484  if (qe.level == 0) {
485  assert(qe.first == qe.second);
486  assert(mPolynomials[qe.level][qe.first]);
487  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Moving into level 1: " << *mPolynomials[qe.level][qe.first]);
488  Origin::BaseType origin(qe.level, qe.first);
489  bool isBound = mInfo(0).isBound(qe.first);
490  projection::returnPoly(*mPolynomials[qe.level][qe.first],
491  [&](const UPoly& np) { res |= insertPolynomialTo(1, np, origin, isBound); }
492  );
493  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Done, obtained res = " << res);
494  if (Settings::restrictProjectionByEC && mInfo().isEC(origin)) {
495  if (res.count() == 1) {
496  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Got proper EC");
497  } else {
498  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "EC is primitive, removing");
499  mInfo().removeEC(origin);
500  }
501  }
502  }
503  else if (qe.first == qe.second) {
504  assert(qe.first < mPolynomials[qe.level].size());
505  assert(mPolynomials[qe.level][qe.first]);
506  const auto& p = *mPolynomials[qe.level][qe.first];
507  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Projecting single " << p << " into " << qe.level);
508  mOperator(Settings::projectionOperator, p, var(qe.level + 1),
509  [&](const UPoly& np) { res |= insertPolynomialTo(qe.level + 1, np, Origin::BaseType(qe.level, qe.first)); }
510  );
511  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Done, obtained res = " << res);
512  } else {
513  assert(qe.first < mPolynomials[qe.level].size());
514  assert(qe.second < mPolynomials[qe.level].size());
515  assert(mPolynomials[qe.level][qe.first] && mPolynomials[qe.level][qe.second]);
516  const auto& p = *mPolynomials[qe.level][qe.first];
517  const auto& q = *mPolynomials[qe.level][qe.second];
518  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Projecting paired " << p << ", " << q << " into " << qe.level);
519  mOperator(Settings::projectionOperator, p, q, var(qe.level + 1),
520  [&](const UPoly& np) { res |= insertPolynomialTo(qe.level + 1, np, Origin::BaseType(qe.level, qe.first, qe.second), false); }
521  );
522  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Done, obtained res = " << res);
523  }
524  return res;
525  }
526 
527 public:
529  : Super(c),
530  mCanBePurged([this](std::size_t level, std::size_t id) {
531  return canBePurgedByBounds(getPolynomialById(level, id));
532  }),
533  mProjectionQueue(ProjectionCandidateComparator([&](std::size_t level, std::size_t id) { return getPolynomialById(level, id); })),
534  mInactiveQueue(ProjectionCandidateComparator([&](std::size_t level, std::size_t id) { return getPolynomialById(level, id); }))
535  {
536  }
537  void reset() {
538  Super::reset();
539  mPolynomialIDs.clear();
540  mPolynomialIDs.resize(dim() + 1);
541  mInfo.reset(dim() + 1);
542  mPolynomials.clear();
543  mPolynomials.resize(dim() + 1);
544  mProjectionQueue.clear();
545  mInactiveQueue.clear();
546 
547  updateInactiveQueue = false;
548  checkPurged = 0;
549  }
550  carl::Bitset addPolynomial(const UPoly& p, std::size_t cid, bool isBound) override {
551  if (cid >= mPolynomials[0].size()) {
552  mPolynomials[0].resize(cid + 1);
553  } else if (mPolynomials[0][cid]) {
554  mInfo().mInactive.reset(cid);
555  // activate all successors of p
556  activatePolynomials(0);
557  if (Settings::simplifyProjectionByBounds && isBound) {
558  mInfo(0).setBound(cid, true);
559  mInfo(0).restrictEvaluatedToPurged();
560  std::size_t level = 1;
561  while (level <= dim()) {
562  mInfo(level).restrictEvaluatedToPurged();
563  if (!projection::canBeForwarded(level, carl::switch_main_variable(p, var(level)))) break;
564  level += 1;
565  }
566  checkPurged = std::max(level, checkPurged);
567  }
568  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(0) << "-> Polynomial was already present, reactivated");
569  return carl::Bitset();
570  }
571  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding " << p << " with id " << cid);
572  assert(!mPolynomials[0][cid]);
573  mInfo.emplace(0, cid);
574  mPolynomials[0][cid] = p;
575  mPolynomialIDs[0].emplace(p, cid);
576  printPolynomialIDs();
577  if (Settings::simplifyProjectionByBounds && isBound) {
578  mInfo(0).setBound(cid, true);
579  //insertPolynomialTo(1, p, Origin::BaseType(0, cid), true);
580  std::size_t level = 1;
581  while (level <= dim()) {
582  mInfo(level).restrictEvaluatedToPurged();
583  if (!projection::canBeForwarded(level, carl::switch_main_variable(p, var(level)))) break;
584  level += 1;
585  }
586  checkPurged = std::max(level, checkPurged);
587  mProjectionQueue.emplace(0, cid, cid);
588  } else {
589  mProjectionQueue.emplace(0, cid, cid);
590  }
591  return carl::Bitset();
592  }
593  carl::Bitset addEqConstraint(const UPoly& p, std::size_t cid, bool isBound) override {
594  if (cid >= mPolynomials[0].size()) {
595  mPolynomials[0].resize(cid + 1);
596  } else if (mPolynomials[0][cid]) {
597  /// Polynomial already exists.
598  if (Settings::simplifyProjectionByBounds && isBound) {
599  mInfo(0).setBound(cid, true);
600  std::size_t level = 1;
601  while (level <= dim()) {
602  mInfo(level).restrictEvaluatedToPurged();
603  if (!projection::canBeForwarded(level, carl::switch_main_variable(p, var(level)))) break;
604  level += 1;
605  }
606  checkPurged = std::max(level, checkPurged);
607  }
608  mInfo().mInactive.reset(cid);
609  activatePolynomials(0);
610  SMTRAT_LOG_DEBUG("smtrat.cad.projection", logPrefix(0) << "-> Polynomial was already present, reactivated");
611  return carl::Bitset();
612  }
613  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding " << p << " with id " << cid);
614  assert(!mPolynomials[0][cid]);
615  mInfo.emplace(0, cid);
616  mPolynomials[0][cid] = p;
617  mPolynomialIDs[0].emplace(p, cid);
618  mInfo.addECConstraint(cid);
619  mInfo().createEC(Origin::BaseType(0, cid));
620  if (Settings::simplifyProjectionByBounds && isBound) {
621  mInfo(0).setBound(cid, true);
622  std::size_t level = 1;
623  while (level <= dim()) {
624  mInfo(level).restrictEvaluatedToPurged();
625  if (!projection::canBeForwarded(level, carl::switch_main_variable(p, var(level)))) break;
626  level += 1;
627  }
628  checkPurged = std::max(level, checkPurged);
629  mProjectionQueue.emplace(0, cid, cid);
630  } else {
631  mProjectionQueue.emplace(0, cid, cid);
632  }
633  return carl::Bitset();
634  }
635  void removePolynomial(const UPoly& p, std::size_t cid, bool isBound) override {
636  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Removing " << cid);
637  printPolynomialIDs();
638  assert(mPolynomials[0][cid]);
639  assert(*mPolynomials[0][cid] == p);
640  mInfo().mInactive.set(cid);
641  // activates polynomials that were inactive due to p, if p is an equational polynomial
642  if (Settings::restrictProjectionByEC) {
643  extendProjection(p);
644  }
645  if (Settings::deletePolynomials) {
646  deletePolynomials(p, cid);
647  } else {
648  printPolynomialIDs();
649  // deactivates all successors of p
650  deactivatePolynomials(0);
651  }
652  if (Settings::simplifyProjectionByBounds && isBound) {
653  updateInactiveQueue = true;
654  std::size_t level = 1;
655  while (level <= dim()) {
656  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Resetting evaluated on level " << level << ": " << mInfo(level).evaluated << " -= " << mInfo(level).purged);
657  mInfo(level).removePurgedFromEvaluated();
658  if (!projection::canBeForwarded(level, carl::switch_main_variable(p, var(level)))) break;
659  level += 1;
660  }
661  checkPurged = std::max(level, checkPurged);
662  }
663  }
664 
665  std::size_t size(std::size_t level) const override {
666  assert(level <= dim());
667  std::size_t number = 0;
668  for (const auto& it : mPolynomialIDs[level]) {
669  assert(mPolynomials[level][it.second]);
670  if (active(level, it.second)) {
671  number += 1;
672  }
673  }
674  return number;
675  }
676  bool empty(std::size_t level) const override {
677  assert(level <= dim());
678  return mPolynomialIDs[level].empty();
679  }
680 
681  carl::Bitset projectNewPolynomial(const ConstraintSelection& cs = carl::Bitset(true)) {
682  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Projecting new polynomial from constraints " << cs);
683  if (updateInactiveQueue) {
684  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Going through mInactiveQueue...");
685  // activate all QE that became relevant again
686  for (auto it = mInactiveQueue.begin(); it != mInactiveQueue.end();) {
687  if (active(it->level, it->first) && active(it->level, it->second)) {
688  if (it->level == 0 || !mInfo.usingEC(it->level)) {
689  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding to PQ " << *it);
690  mProjectionQueue.push((*it));
691  it = mInactiveQueue.erase(it);
692  } else if (Settings::restrictProjectionByEC && mInfo.usingEC(it->level) && (carl::Bitset(it->first) == mInfo.getUsedEC(it->level) || carl::Bitset(it->second) == mInfo.getUsedEC(it->level))) {
693  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding to PQ " << *it);
694  mProjectionQueue.push((*it));
695  it = mInactiveQueue.erase(it);
696  } else {
697  it++;
698  }
699  } else {
700  it++;
701  }
702  }
703  mInactiveQueue.fix();
704  updateInactiveQueue = false;
705  }
706  if (checkPurged > 0) {
707  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "-> ComputePurgedPolynomials, until level " << checkPurged);
708  computePurgedPolynomials(checkPurged);
709  deactivatePolynomials(1);
710  carl::Bitset levels = activatePolynomials(1);
711  checkPurged = 0;
712  if (levels.any()) return levels;
713  }
714  return project(cs);
715  }
716 
717  bool hasPolynomialById(std::size_t level, std::size_t id) const override {
718  assert(level <= dim());
719  assert(id < mPolynomials[level].size());
720  return bool(mPolynomials[level][id]);
721  }
722  const UPoly& getPolynomialById(std::size_t level, std::size_t id) const override {
723  assert(level <= dim());
724  assert(id < mPolynomials[level].size());
725  assert(mPolynomials[level][id]);
726  return *mPolynomials[level][id];
727  }
728 
729  void exportAsDot(std::ostream& out) const override {
731  std::size_t originID = 0;
732  for (std::size_t level = 0; level <= dim(); level++) {
733  debug::DotSubgraph dsg("level_" + std::to_string(level));
734  for (std::size_t id = 0; id < mPolynomials[level].size(); id++) {
735  const auto& p = mPolynomials[level][id];
736  if (!p) continue;
737  out << "\t\tp_" << level << "_" << id << " [label=\"" << *p << "\"];" << std::endl;
738  dsg.add("p_" + std::to_string(level) + "_" + std::to_string(id));
739  for (const auto& origin : mInfo(level, id).origin) {
740  std::string target = (origin.level == 0 ? "orig_" : "p_" + std::to_string(origin.level - 1) + "_");
741  if (origin.first != origin.second) {
742  out << "\t\torigin_" << originID << " [label=\"\", shape=point];" << std::endl;
743  out << "\t\torigin_" << originID << " -> p_" << level << "_" << id << ";" << std::endl;
744  out << "\t\t" << target << origin.first << " -> origin_" << originID << ";" << std::endl;
745  out << "\t\t" << target << origin.second << " -> origin_" << originID << ";" << std::endl;
746  } else {
747  out << "\t\t" << target << origin.first << " -> p_" << level << "_" << id << ";" << std::endl;
748  }
749  originID++;
750  }
751  }
752  out << "\t" << dsg << std::endl;
753  }
754  }
755 
756  void printPolynomialIDs() const {
757  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "PolynomialIDs:");
758  for (std::size_t lvl = 0; lvl <= dim(); lvl++) {
759  SMTRAT_LOG_DEBUG("smtrat.cad.projection", lvl << ": " << mPolynomialIDs[lvl]);
760  }
761  }
762 };
763 
764 template<typename S>
765 std::ostream& operator<<(std::ostream& os, const Projection<Incrementality::FULL, Backtracking::HIDE, S>& p) {
766  os << "Constraints:" << std::endl << p.mConstraints << std::endl;
767  os << "Global:" << std::endl << p.mInfo() << std::endl;
768  for (std::size_t level = 0; level <= p.dim(); level++) {
769  if (level == 0)
770  os << level << std::endl;
771  else
772  os << level << " / " << p.var(level) << std::endl;
773  os << "\tP: " << p.mPolynomials[level] << std::endl;
774  if (level > 0) {
775  os << "\tL: " << p.mLiftingQueues[level - 1] << std::endl;
776  }
777  os << "\tInfo: " << p.mInfo(level) << std::endl;
778  for (const auto& poly: p.mPolynomialIDs[level]) {
779  os << "\t" << poly.first << " -> " << p.mInfo(level, poly.second) << std::endl;
780  }
781  if (p.mInfo.usingEC(level)) {
782  os << "\tUsing EC " << p.mInfo.getUsedEC(level) << std::endl;
783  }
784  }
785  os << "Q: " << p.mProjectionQueue << std::endl;
786  os << "I: " << p.mInactiveQueue << std::endl;
787  return os;
788 }
789 } // namespace cad
790 } // namespace smtrat
auto erase(typename std::vector< T >::const_iterator it)
ProjectionOperator mOperator
The projection operator.
const Constraints & mConstraints
std::size_t dim() const
Returns the dimension of the projection.
std::size_t size() const
void freeID(std::size_t level, std::size_t id)
Frees a currently used polynomial id for the given level.
ProjectionInformation mInfo
Additional info on projection, projection levels and projection polynomials.
std::size_t getID(std::size_t level)
Returns a fresh polynomial id for the given level.
virtual const UPoly & getPolynomialById(std::size_t level, std::size_t id) const =0
Retrieves a polynomial from its id.
std::vector< PolynomialLiftingQueue< BaseProjection > > mLiftingQueues
List of lifting queues that can be used for incremental projection.
carl::Variable var(std::size_t level) const
Returns the variable that corresponds to the given level, that is the variable eliminated in this lev...
bool canBePurgedByBounds(const UPoly &p) const
Checks whether a polynomial can safely be ignored due to the bounds.
void callRemoveCallback(std::size_t level, const SampleLiftedWith &slw) const
bool isPurged(std::size_t level, std::size_t id)
void exportAsDot(std::ostream &out) const
This class represents one or more origins of some object.
Definition: Origin.h:21
bool usingEC(std::size_t level) const
void emplace(std::size_t level, std::size_t pid)
bool isActive(std::size_t level, std::size_t id) const
const carl::Bitset & getUsedEC(std::size_t level) const
void clear(std::size_t level, std::size_t pid)
bool hasEC(std::size_t level) const
carl::Bitset addPolynomial(const UPoly &p, std::size_t cid, bool isBound) override
Adds the given polynomial to the projection.
void insertIntoProjectionQueue(std::size_t level, std::size_t id)
Add projection candidates for a new polynomial.
std::vector< std::vector< full_ec::Polynomial > > mPolynomials
Definition: Projection_EC.h:81
void extendProjection(const UPoly &p)
Activate polynomials in the projection (in lvl > level) that become again relevant if an equational c...
carl::Bitset activatePolynomials(std::size_t level)
Activate active polynomials in mProjection.
void deactivatePolynomials(std::size_t level)
Deactivate inactive polynomials in mProjection.
carl::Bitset insertPolynomialTo(std::size_t level, const UPoly &p, const Origin::BaseType &origin, bool setBound=false)
Inserts a polynomial with the given origin into the given level.
PriorityQueue< QueueEntry, ProjectionCandidateComparator > mProjectionQueue
Definition: Projection_EC.h:83
carl::Bitset addEqConstraint(const UPoly &p, std::size_t cid, bool isBound) override
Adds the given polynomial of an equational constraint to the projection.
const UPoly & getPolynomialById(std::size_t level, std::size_t id) const override
Retrieves a polynomial from its id.
void removePolynomial(const UPoly &p, std::size_t cid, bool isBound) override
Removes the given polynomial from the projection.
PriorityQueue< QueueEntry, ProjectionCandidateComparator > mInactiveQueue
Definition: Projection_EC.h:85
void deletePolynomials(const UPoly &p, std::size_t cid)
Delete polynomial in mProjection and all other datastructures.
carl::Bitset projectNewPolynomial(const ConstraintSelection &cs=carl::Bitset(true))
bool hasPolynomialById(std::size_t level, std::size_t id) const override
bool isQueueEntryActive(std::size_t level, std::size_t first, std::size_t second, bool usingEC) const
void restrictProjection(std::size_t level)
Deactivate polynomials in the projection (in lvl > level) that become irrelevant due to a new equatio...
int var(Lit p)
Definition: SolverTypes.h:64
static bool find(V &ts, const T &t)
Definition: Alg.h:47
static void remove(V &ts, const T &t)
Definition: Alg.h:36
std::optional< UPoly > Polynomial
Definition: Projection_EC.h:14
bool canBeRemoved(const UPoly &p)
Checks whether a polynomial can safely be ignored.
bool canBeForwarded(std::size_t, const UPoly &p)
Checks whether a polynomial can safely be forwarded to the next level.
void returnPoly(const Poly &p, Callback &&cb)
Definition: utils.h:95
std::ostream & operator<<(std::ostream &os, const SampleIteratorQueue< I, C > &siq)
carl::UnivariatePolynomial< Poly > UPoly
Definition: common.h:17
projection_compare::Candidate< Poly > candidate(const Poly &p, const Poly &q, std::size_t level)
Incrementality
Definition: Settings.h:7
carl::Bitset ConstraintSelection
Definition: common.h:12
std::optional< FormulaT > qe(const FormulaT &input)
Definition: qe.cpp:14
Class to create the formulas for axioms.
const settings::Settings & Settings()
Definition: Settings.h:96
#define SMTRAT_LOG_TRACE(channel, msg)
Definition: logging.h:36
#define SMTRAT_LOG_INFO(channel, msg)
Definition: logging.h:34
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35
friend std::ostream & operator<<(std::ostream &os, const QueueEntry &qe)
Definition: Projection_EC.h:48
void add(const std::string &n)
Definition: DotHelper.h:14