SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
Projection_Model.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 
10 #include <smtrat-common/model.h>
11 #include <carl-formula/model/Assignment.h>
12 
13 namespace smtrat {
14 namespace cad {
15 
16  /**
17  * This class implements a projection that supports no incrementality and expects backtracking to be in order.
18  *
19  * It is based on the following data structures:
20  * - mPolynomialIDs: maps polynomials to a (per level) unique id
21  * - mPolynomials: stores polynomials as a list (per level) with their origin
22  *
23  * The origin of a polynomial in level zero is the id of the corresponding constraint.
24  * For all other levels, it is the id of some polynomial from level zero such that the polynomial must be removed if the origin is removed.
25  * For a single projection operation, the resulting origin is the largest of the participating polynomials.
26  * If a polynomial is derived from multiple projection operations, the origin is the earliest and thus smallest, at least for this non-incremental setting.
27  */
28  template<typename Settings>
30  private:
32  using typename Super::Constraints;
33  using Super::mLiftingQueues;
34  using Super::mOperator;
35  using Super::callRemoveCallback;
36  using Super::var;
37  public:
38  using Super::dim;
39  using Super::size;
40  private:
41 
42  template<typename S>
43  friend std::ostream& operator<<(std::ostream& os, const ModelBasedProjection<Incrementality::NONE, Backtracking::ORDERED, S>& p);
44  /// Maps polynomials to a (per level) unique ID.
45  std::vector<std::map<UPoly,std::size_t>> mPolynomialIDs;
46  /// Stores polynomials with their origin constraint ids.
47  std::vector<std::vector<std::pair<UPoly,std::size_t>>> mPolynomials;
48 
50 
51  auto& polyIDs(std::size_t level) {
52  assert(level > 0 && level <= dim());
53  return mPolynomialIDs[level - 1];
54  }
55  const auto& polyIDs(std::size_t level) const {
56  assert(level > 0 && level <= dim());
57  return mPolynomialIDs[level - 1];
58  }
59  auto& polys(std::size_t level) {
60  assert(level > 0 && level <= dim());
61  return mPolynomials[level - 1];
62  }
63  const auto& polys(std::size_t level) const {
64  assert(level > 0 && level <= dim());
65  return mPolynomials[level - 1];
66  }
67 
68  /// Inserts a polynomial with the given origin into the given level.
69  void insertPolynomial(std::size_t level, const UPoly& p, std::size_t origin) {
70  assert(level > 0 && level <= dim());
71  assert(polyIDs(level).find(p) == polyIDs(level).end());
72  std::size_t id = polys(level).size();
73  polys(level).emplace_back(p, origin);
74  polyIDs(level).emplace(p, id);
75  mLiftingQueues[level - 1].insert(id);
76  }
77  /// Removed the last polynomial from the given level.
78  void removePolynomial(std::size_t level) {
79  assert(level > 0 && level <= dim());
80  auto it = polyIDs(level).find(polys(level).back().first);
81  assert(it != polyIDs(level).end());
82  mLiftingQueues[level - 1].erase(it->second);
83  polyIDs(level).erase(it);
84  polys(level).pop_back();
85  }
86 
87  /// Finds pids of polynomials with closest roots
88  void findPIDsForProjection(carl::Variable var, std::size_t level, const Model& model, std::pair<std::size_t, std::size_t>& pids) {
89  auto val = mModel.evaluated(var);
90  assert(val.isRational() || val.isRAN());
91  RAN value = val.isRational() ? RAN(val.asRational()) : val.asRAN();
92 
93  for (std::size_t pid = 0; pid < size(level); pid++) {
94  const auto& poly = getPolynomialById(level, pid);
95  auto psubs = carl::substitute(poly, model);
96  if (carl::is_zero(psubs)) continue;
97  auto polyvars = carl::variables(poly);
98  polyvars.erase(poly.main_var());
99  auto list = carl::real_roots(poly, *carl::get_ran_assignment(polyvars, model));
100  if (list.is_nullified()) continue;
101  assert(list.is_univariate());
102 
103  std::optional<std::pair<RAN,bool>> lower;
104  std::optional<std::pair<RAN,bool>> upper;
105  for (const auto& root: list.roots()) {
106  if (root < value) {
107  if (!lower || root > lower->first) {
108  lower = std::make_pair(root, true);
109  pids.first = pid;
110  }
111  } else if (root == value) {
112  lower = std::make_pair(root, true);
113  upper = lower;
114  pids.first = pid;
115  pids.second = pid;
116  } else {
117  if (!upper || root < upper->first) {
118  upper = std::make_pair(root, true);
119  pids.second = pid;
120  }
121  }
122  }
123  }
124  }
125 
126  /// Adds a polynomial with the given origin to the suitable level.
127  void addToCorrectLevel(std::size_t level, const UPoly& p, std::size_t origin) {
128  assert(level > 0 && level <= dim());
129  if (projection::canBeRemoved(p)) return;
130  if ((level > 1) && (level < dim()) && projection::canBeForwarded(level, p)) {
131  addToCorrectLevel(level + 1, carl::switch_main_variable(p, var(level+1)), origin);
132  return;
133  }
134  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding " << p << " to projection level " << level);
135  assert(p.main_var() == var(level));
136  auto it = polyIDs(level).find(p);
137  if (it != polyIDs(level).end()) {
138  // We already have this polynomial.
139  if (level > 0 && !(polys(level)[it->second].second <= origin)) {
140  polys(level)[it->second].second = origin;
141  }
142  return;
143  }
144  insertPolynomial(level, p, origin);
145  }
146 
147  /// Adds a new polynomial to the given level (used to performs the first step of the projection)
148  carl::Bitset addToProjection(std::size_t level, const UPoly& p, std::size_t origin) {
149  assert(level > 0 && level <= dim());
150  if (projection::canBeRemoved(p)) return carl::Bitset();
151  // TODO warum > 1 und nicht > 0?
152  if ((level > 1) && (level < dim()) && projection::canBeForwarded(level, p)) {
153  return addToProjection(level + 1, carl::switch_main_variable(p, var(level+1)), origin);
154  }
155  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding " << p << " to projection level " << level);
156  assert(p.main_var() == var(level));
157  auto it = polyIDs(level).find(p);
158  if (it != polyIDs(level).end()) {
159  // We already have this polynomial.
160  if (level > 0) {
161  assert(polys(level)[it->second].second <= origin);
162  }
163  return carl::Bitset();
164  }
165  carl::Bitset res = carl::Bitset();
166 
167  if (level == 1 && dim() > 1) {
168  mOperator(Settings::projectionOperator, p, var(level + 1),
169  [&](const UPoly& np){ addToCorrectLevel(level + 1, np, origin); }
170  );
171  for (const auto& it: polys(level)) {
172  std::size_t newOrigin = std::max(origin, it.second);
173  mOperator(Settings::projectionOperator, p, it.first, var(level + 1),
174  [&](const UPoly& np){ addToCorrectLevel(level + 1, np, newOrigin); }
175  );
176  }
177  }
178  // Actually insert afterwards to avoid pairwise projection with itself.
179  insertPolynomial(level, p, origin);
180  res.set(level);
181  return res;
182  }
183  public:
184  ModelBasedProjection(const Constraints& c, const Model& model): Super(c), mModel(model) {}
185  /**
186  * Resets all datastructures, use the given variables from now on.
187  */
188  void reset() {
189  Super::reset();
190  mPolynomials.clear();
191  mPolynomials.resize(dim());
192  mPolynomialIDs.clear();
193  mPolynomialIDs.resize(dim());
194  }
195  /**
196  * Adds the given polynomial to the projection with the given constraint id as origin.
197  * Asserts that the main variable of the polynomial is the first variable.
198  */
199  carl::Bitset addPolynomial(const UPoly& p, std::size_t cid, bool) override {
200  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Adding " << p << " from constraint " << cid);
201  assert(p.main_var() == var(1));
202  return addToProjection(1, p, cid);
203  }
204  /**
205  * Removed the given polynomial from the projection.
206  * Asserts that this polynomial was the one added last and has the given constraint id as origin.
207  * Calls the callback function for every level with a mask designating the polynomials removed from this level.
208  */
209  void removePolynomial(const UPoly& p, std::size_t cid, bool) override {
210  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Removing " << p << " from constraint " << cid);
211  assert(polys(1).back().first == p);
212  assert(polys(1).back().second == cid);
213  removePolynomial(1);
214  std::size_t origin = cid;
215  SMTRAT_LOG_DEBUG("smtrat.cad.projection", "Origin is " << origin);
216  callRemoveCallback(1, SampleLiftedWith().set(cid));
217  // Remove all polynomials from all levels that have the removed polynomial as origin.
218  for (std::size_t level = 2; level <= dim(); level++) {
219  carl::Bitset removed;
220  if (polys(level).empty()) continue;
221  while (polys(level).back().second == origin) {
222  std::size_t id = polys(level).size() - 1;
223  mLiftingQueues[level - 1].erase(id);
224  removePolynomial(level);
225  removed.set(id);
226  }
227  assert(polys(level).empty() || polys(level).back().second < origin);
228  callRemoveCallback(level, removed);
229  }
230  }
231 
232  /// Performs the projection model-based for one level, using only polynomials with closest roots.
233  void projectNextLevel(std::size_t level) {
234  assert(level > 1 && level < dim());
235  Model m;
236  for(std::size_t l = dim(); l > level; l--) {
237  carl::Variable v = var(l);
238  if (mModel.find(v) == mModel.end()) continue;
239  m.emplace(v, mModel.evaluated(v));
240  }
241  bool modelBased = m.find(var(level)) != m.end();
242  if (modelBased) {
243  SMTRAT_LOG_INFO("smtrat.cad.projection", "Projection is model-based for " << var(level));
244  } else {
245  SMTRAT_LOG_INFO("smtrat.cad.projection", "Projection is not model-based for " << var(level));
246  }
247 
248  for(const auto& it: polys(level)) {
249  assert(it.first.main_var() == var(level));
250 
251  mOperator(Settings::projectionOperator, it.first, var(level + 1),
252  [&](const UPoly& np){ addToCorrectLevel(level + 1, np, it.second); }
253  );
254 
255  if (modelBased) {
256  // Model-based projection
257  std::pair<std::size_t, std::size_t> pids;
258  findPIDsForProjection(var(level), level, m, pids);
259  for (const auto& itPID: polys(level)) {
260  //if(itPID.second == pids.first || itPID.second == pids.second) {
261  std::size_t newOrigin = std::max(it.second, itPID.second);
262  mOperator(Settings::projectionOperator, it.first, itPID.first, var(level + 1),
263  [&](const UPoly& np){ addToCorrectLevel(level + 1, np, newOrigin); }
264  );
265  //}
266  }
267  } else {
268  // Regular full projection
269  for (const auto& itPID: polys(level)) {
270  std::size_t newOrigin = std::max(it.second, itPID.second);
271  mOperator(Settings::projectionOperator, it.first, itPID.first, var(level + 1),
272  [&](const UPoly& np){ addToCorrectLevel(level + 1, np, newOrigin); }
273  );
274  }
275  }
276 
277 
278  }
279  }
280 
281  /// Returns the number of polynomials in this level.
282  std::size_t size(std::size_t level) const override {
283  return polys(level).size();
284  }
285  /// Returns whether the number of polynomials in this level is zero.
286  bool empty(std::size_t level) const override {
287  return polys(level).empty();
288  }
289 
290  /// Returns false, as the projection is not incremental.
291  carl::Bitset projectNewPolynomial(const ConstraintSelection& = carl::Bitset(true)) {
292  return carl::Bitset();
293  }
294  bool hasPolynomialById(std::size_t level, std::size_t id) const override {
295  assert(level > 0 && level <= dim());
296  return id < polys(level).size();
297  }
298  /// Get the polynomial from this level with the given id.
299  const UPoly& getPolynomialById(std::size_t level, std::size_t id) const override {
300  assert(level > 0 && level <= dim());
301  assert(id < polys(level).size());
302  return polys(level)[id].first;
303  }
304  };
305 
306  template<typename S>
308  for (std::size_t level = 1; level <= p.dim(); level++) {
309  os << level << " / " << p.var(level) << ":" << std::endl;
310  for (const auto& it: p.polys(level)) {
311  os << "\t" << it.first << " [" << it.second << "]" << std::endl;
312  }
313  }
314  return os;
315  }
316 }
317 }
void removePolynomial(const Poly &p, std::size_t cid, bool isBound)
Removes the given polynomial from the projection. Converts to a UPoly and calls the appropriate overl...
ProjectionOperator mOperator
The projection operator.
std::size_t dim() const
Returns the dimension of the projection.
std::size_t size() const
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...
void callRemoveCallback(std::size_t level, const SampleLiftedWith &slw) const
void projectNextLevel(std::size_t level)
Performs the projection model-based for one level, using only polynomials with closest roots.
bool empty(std::size_t level) const override
Returns whether the number of polynomials in this level is zero.
void insertPolynomial(std::size_t level, const UPoly &p, std::size_t origin)
Inserts a polynomial with the given origin into the given level.
carl::Bitset addPolynomial(const UPoly &p, std::size_t cid, bool) override
Adds the given polynomial to the projection with the given constraint id as origin.
const UPoly & getPolynomialById(std::size_t level, std::size_t id) const override
Get the polynomial from this level with the given id.
std::vector< std::vector< std::pair< UPoly, std::size_t > > > mPolynomials
Stores polynomials with their origin constraint ids.
void addToCorrectLevel(std::size_t level, const UPoly &p, std::size_t origin)
Adds a polynomial with the given origin to the suitable level.
std::size_t size(std::size_t level) const override
Returns the number of polynomials in this level.
void reset()
Resets all datastructures, use the given variables from now on.
void removePolynomial(const UPoly &p, std::size_t cid, bool) override
Removed the given polynomial from the projection.
carl::Bitset projectNewPolynomial(const ConstraintSelection &=carl::Bitset(true))
Returns false, as the projection is not incremental.
void findPIDsForProjection(carl::Variable var, std::size_t level, const Model &model, std::pair< std::size_t, std::size_t > &pids)
Finds pids of polynomials with closest roots.
std::vector< std::map< UPoly, std::size_t > > mPolynomialIDs
Maps polynomials to a (per level) unique ID.
carl::Bitset addToProjection(std::size_t level, const UPoly &p, std::size_t origin)
Adds a new polynomial to the given level (used to performs the first step of the projection)
void removePolynomial(std::size_t level)
Removed the last polynomial from the given level.
int var(Lit p)
Definition: SolverTypes.h:64
static bool find(V &ts, const T &t)
Definition: Alg.h:47
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.
smtrat::RAN RAN
Definition: common.h:11
std::ostream & operator<<(std::ostream &os, const SampleIteratorQueue< I, C > &siq)
carl::UnivariatePolynomial< Poly > UPoly
Definition: common.h:17
Incrementality
Definition: Settings.h:7
carl::Bitset SampleLiftedWith
Definition: common.h:15
carl::Bitset ConstraintSelection
Definition: common.h:12
bool substitute(const FormulaT &constr, const carl::Variable var, const carl::vs::Term< Poly > &term, FormulaT &result)
Definition: VSHelper.h:138
Class to create the formulas for axioms.
@ NONE
Definition: types.h:53
const settings::Settings & Settings()
Definition: Settings.h:96
carl::Model< Rational, Poly > Model
Definition: model.h:13
#define SMTRAT_LOG_INFO(channel, msg)
Definition: logging.h:34
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35