8 #include "../debug/DotHelper.h"
15 using Polynomial = std::optional<std::pair<UPoly,Origin>>;
18 if (!p)
return os <<
"--";
19 return os << p->first <<
" " << p->second;
22 template<
typename Settings, Backtracking BT>
27 using Super::mConstraints;
28 using Super::mLiftingQueues;
29 using Super::mOperator;
30 using Super::callRemoveCallback;
31 using Super::canBePurgedByBounds;
40 template<
typename S, Backtracking B>
47 QueueEntry(std::size_t l, std::size_t f, std::size_t s): 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;
52 struct ProjectionCandidateComparator {
58 bool operator()(
const QueueEntry& lhs,
const QueueEntry& rhs)
const {
60 UPoly lp = mPG(lhs.level, lhs.first);
61 UPoly lq = mPG(lhs.level, lhs.second);
62 UPoly rp = mPG(rhs.level, rhs.first);
63 UPoly rq = mPG(rhs.level, rhs.second);
72 struct PurgedPolynomials {
83 auto&
data(std::size_t level) {
84 assert( level < mData.size());
87 const auto&
data(std::size_t level)
const {
88 assert( level < mData.size());
92 template<
typename PurgeCheck>
98 void add(
const QueueEntry&
qe) {
99 assert(
qe.level < mData.size());
100 data(
qe.level).entries.push_back(
qe);
102 void remove(std::size_t level, std::size_t
id) {
103 assert( level < mData.size());
104 data(level).evaluated.reset(
id);
105 data(level).purged.reset(
id);
106 auto it = std::remove_if(data(level).entries.begin(), data(level).entries.end(), [level,
id](
const QueueEntry&
qe){
107 return (qe.level == level) && (qe.first == id || qe.second == id);
109 data(level).entries.erase(it, data(level).entries.end());
111 void setBound(std::size_t level, std::size_t
id,
bool isBound) {
112 assert(level > 0 && level <= mData.size());
113 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Setting " << level <<
"/" <<
id <<
" is a bound to " << isBound);
114 data(level).bounds.set(
id, isBound);
116 bool isPurged(std::size_t level, std::size_t
id)
const {
117 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Checking whether " << level <<
"/" <<
id <<
" is purged.");
118 assert( level < mData.size());
119 if (data(level).bounds.test(
id)) {
120 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Do not purge as " << level <<
"/" <<
id <<
" is a bound.");
123 if (!data(level).evaluated.test(
id)) {
124 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Checking if " << level <<
"/" <<
id <<
" can be purged.");
125 data(level).purged.set(
id, mCanBePurged(level,
id));
126 data(level).evaluated.set(
id);
128 return data(level).purged.test(
id);
132 assert(
qe.level < mData.size());
134 assert(
qe.first ==
qe.second);
135 return mCanBePurged(0,
qe.first);
139 template<
typename Restorer>
141 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Resetting evaluation data and restoring entries.");
142 for (
auto& lvl: mData) {
143 lvl.evaluated = carl::Bitset();
144 lvl.purged = carl::Bitset();
146 for (
auto& lvl: mData) {
147 auto it = std::remove_if(lvl.entries.begin(), lvl.entries.end(),
148 [
this,&r](
const QueueEntry&
qe){
149 if (isPurged(qe)) return false;
153 lvl.entries.erase(it, lvl.entries.end());
168 return std::string(
dim() - level,
'\t');
177 assert(level <
dim());
178 for (
const auto& it: mPolynomialIDs[level]) {
179 mProjectionQueue.emplace(level, it.second,
id);
188 assert(level <
dim());
189 mProjectionQueue.
removeIf([level,
id](
const QueueEntry&
qe){
return (
qe.level == level) && (
qe.first ==
id ||
qe.second ==
id); });
190 if (Settings::simplifyProjectionByBounds) {
191 mPurgedPolys.remove(level,
id);
196 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"Receiving " << p <<
" for level " << level);
198 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"-> but is safely removed.");
199 return carl::Bitset();
202 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"-> but is forwarded to " << (level+1));
203 return insertPolynomialTo(level + 1, carl::switch_main_variable(p,
var(level + 1)), origin, setBound);
205 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"Inserting " << p <<
" into level " << level);
206 assert(level <=
dim());
207 auto it = mPolynomialIDs[level].find(p);
208 if (it != mPolynomialIDs[level].end()) {
209 assert(mPolynomials[level][it->second]);
210 mPolynomials[level][it->second]->second += origin;
211 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"-> Polynomial was already present, merged origins");
212 return carl::Bitset();
214 std::size_t
id =
getID(level);
215 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"-> Got new id " <<
id);
216 if (
id >= mPolynomials[level].
size()) mPolynomials[level].resize(
id + 1);
217 assert(!mPolynomials[level][
id]);
218 mPolynomials[level][id] = std::make_pair(p,
Origin(origin));
220 mPolynomialIDs[level].emplace(p,
id);
222 mPurgedPolys.setBound(level,
id,
true);
225 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"-> Inserting " <<
id <<
" into queue for level " << (level+1));
226 insertIntoProjectionQueue(level,
id);
230 return carl::Bitset({level});
233 template<
typename Iterator>
235 assert(it != mPolynomialIDs[level].end());
236 std::size_t
id = it->second;
237 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"Removing " <<
id <<
" on " << level);
238 assert(mPolynomials[level][
id]);
240 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"-> Purging from queue on level " << (level+1));
241 removeFromProjectionQueue(level,
id);
243 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection", logPrefix(level) <<
"-> Removing polynomial");
245 mPolynomials[level][id] = std::nullopt;
247 return mPolynomialIDs[level].erase(it);
251 while (!mProjectionQueue.empty()) {
252 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Projecting" << std::endl << *
this);
253 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"-> Using next projection candidate " << mProjectionQueue.top());
254 QueueEntry
qe = mProjectionQueue.top();
255 mProjectionQueue.pop();
256 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"-> Checking if can be purged: " << Settings::simplifyProjectionByBounds);
257 if (Settings::simplifyProjectionByBounds && mPurgedPolys.isPurged(
qe)) {
258 mPurgedPolys.add(
qe);
261 carl::Bitset res = projectCandidate(
qe);
263 if (res.any())
return res;
267 return carl::Bitset();
271 assert(
qe.level <
dim());
273 assert(
qe.first ==
qe.second);
274 assert(mPolynomials[
qe.level][
qe.first]);
275 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Moving into level 1: " << mPolynomials[
qe.level][
qe.first]->first);
277 return carl::Bitset({1});
280 if (
qe.first ==
qe.second) {
281 assert(
qe.first < mPolynomials[
qe.level].size());
282 assert(mPolynomials[
qe.level][
qe.first]);
283 const auto& p = *mPolynomials[
qe.level][
qe.first];
284 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Projecting single " << p <<
" into " <<
qe.level);
285 mOperator(Settings::projectionOperator, p.first,
var(
qe.level + 1),
286 [&](
const UPoly& np){ res |= insertPolynomialTo(qe.level + 1, np, Origin::BaseType(qe.level, qe.first)); }
289 assert(
qe.first < mPolynomials[
qe.level].size());
290 assert(
qe.second < mPolynomials[
qe.level].size());
291 assert(mPolynomials[
qe.level][
qe.first] && mPolynomials[
qe.level][
qe.second]);
292 const auto& p = *mPolynomials[
qe.level][
qe.first];
293 const auto& q = *mPolynomials[
qe.level][
qe.second];
294 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Projecting paired " << p <<
", " << q <<
" into " <<
qe.level);
295 mOperator(Settings::projectionOperator, p.first, q.first,
var(
qe.level + 1),
296 [&](
const UPoly& np){ res |= insertPolynomialTo(qe.level + 1, np, Origin::BaseType(qe.level, qe.first, qe.second)); }
305 mProjectionQueue(ProjectionCandidateComparator([&](std::size_t level, std::size_t id){
return getPolynomialById(level,
id); })),
306 mPurgedPolys([
this](std::size_t level, std::size_t
id){
312 mPolynomialIDs.clear();
313 mPolynomialIDs.resize(
dim() + 1);
314 mPolynomials.clear();
315 mPolynomials.resize(
dim() + 1);
316 mProjectionQueue.clear();
317 mPurgedPolys.reset(
dim() + 1);
320 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"Adding " << p <<
" with id " << cid);
321 if (cid >= mPolynomials[0].
size()) {
322 mPolynomials[0].resize(cid + 1);
324 assert(!mPolynomials[0][cid]);
325 mPolynomials[0][cid] = std::make_pair(p,
Origin());
326 mPolynomialIDs[0].emplace(p, cid);
330 mProjectionQueue.emplace(0, cid, cid);
332 return carl::Bitset();
336 assert(mPolynomials[0][cid]);
337 assert(mPolynomials[0][cid]->first == p);
338 mPolynomials[0][cid] = std::nullopt;
339 removeFromProjectionQueue(0, cid);
340 carl::Bitset filter = carl::Bitset().set(cid);
341 for (std::size_t level = 1; level <=
dim(); level++) {
342 for (std::size_t lvl = level; lvl <=
dim(); lvl++) {
343 for (
auto it = mPolynomialIDs[level].begin(); it != mPolynomialIDs[level].end(); it++) {
344 assert(mPolynomials[level][it->second]);
345 mPolynomials[level][it->second]->second.erase(level, filter);
348 carl::Bitset removed;
349 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"-> Purging from level " << level <<
" with filter " << filter);
350 for (
auto it = mPolynomialIDs[level].begin(); it != mPolynomialIDs[level].end();) {
351 std::size_t
id = it->second;
352 assert(mPolynomials[level][
id]);
353 if (mPolynomials[level][
id]->second.empty()) {
354 SMTRAT_LOG_DEBUG(
"smtrat.cad.projection",
"-> Purging " <<
id <<
" from level " << level);
356 it = removePolynomialByIT(level, it);
361 SMTRAT_LOG_TRACE(
"smtrat.cad.projection",
"Calling callback for level " << level <<
", removed [" << removed <<
"]");
365 if (Settings::simplifyProjectionByBounds && isBound) {
366 mPurgedPolys.restore([
this](
const QueueEntry&
qe) {
367 mProjectionQueue.push(
qe);
372 std::size_t
size(std::size_t level)
const override {
373 assert(level <=
dim());
374 return mPolynomialIDs[level].size();
376 bool empty(std::size_t level)
const override {
377 assert(level <=
dim());
378 return mPolynomialIDs[level].empty();
386 assert(level <=
dim());
387 assert(
id < mPolynomials[level].
size());
388 return bool(mPolynomials[level][
id]);
391 assert(level <=
dim());
392 assert(
id < mPolynomials[level].
size());
393 assert(mPolynomials[level][
id]);
394 return mPolynomials[level][id]->first;
399 std::size_t originID = 0;
400 for (std::size_t level = 0; level <=
dim(); level++) {
402 for (std::size_t
id = 0;
id < mPolynomials[level].size();
id++) {
403 const auto& p = mPolynomials[level][id];
405 out <<
"\t\tp_" << level <<
"_" <<
id <<
" [label=\"" << p->first <<
"\"];" << std::endl;
406 dsg.
add(
"p_" + std::to_string(level) +
"_" + std::to_string(
id));
407 for (
const auto& origin: p->second) {
408 std::string target = (origin.level == 0 ?
"orig_" :
"p_" + std::to_string(origin.level-1) +
"_");
409 if (origin.first != origin.second) {
410 out <<
"\t\torigin_" << originID <<
" [label=\"\", shape=point];" << std::endl;
411 out <<
"\t\torigin_" << originID <<
" -> p_" << level <<
"_" <<
id <<
";" << std::endl;
412 out <<
"\t\t" << target << origin.first <<
" -> origin_" << originID <<
";" << std::endl;
413 out <<
"\t\t" << target << origin.second <<
" -> origin_" << originID <<
";" << std::endl;
415 out <<
"\t\t" << target << origin.first <<
" -> p_" << level <<
"_" <<
id <<
";" << std::endl;
420 out <<
"\t" << dsg << std::endl;
425 assert(level < mPolynomials.size());
426 assert(
id < mPolynomials[level].
size());
427 assert(mPolynomials[level][
id]);
428 return mPolynomials[level][id]->second;
432 template<
typename S, Backtracking B>
434 for (std::size_t level = 0; level <= p.
dim(); level++) {
435 if (level == 0) os << level << std::endl;
436 else os << level <<
" / " << p.
var(level) << std::endl;
437 os <<
"\tP: " << p.mPolynomials[level] << std::endl;
442 os <<
"Q: " << p.mProjectionQueue << std::endl;
ProjectionOperator mOperator
The projection operator.
const Constraints & mConstraints
std::size_t dim() const
Returns the dimension of the projection.
void freeID(std::size_t level, std::size_t id)
Frees a currently used polynomial id for the given level.
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.
void removeFromProjectionQueue(std::size_t level, std::size_t id)
Remove projection candidates involving a specific polynomial.
std::vector< std::map< UPoly, std::size_t > > mPolynomialIDs
void exportAsDot(std::ostream &out) const override
Iterator removePolynomialByIT(std::size_t level, Iterator it)
Removes the polynomial given by the iterator from all datastructures.
void removePolynomial(const UPoly &p, std::size_t cid, bool isBound) override
Removes the given polynomial from the projection.
void insertIntoProjectionQueue(std::size_t level, std::size_t id)
Add projection candidates for a new polynomial.
carl::Bitset project(const ConstraintSelection &)
carl::Bitset projectCandidate(const QueueEntry &qe)
std::string logPrefix(std::size_t level) const
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.
bool empty(std::size_t level) const override
std::vector< std::vector< full::Polynomial > > mPolynomials
PurgedPolynomials mPurgedPolys
Projection(const Constraints &c)
Origin getOrigin(std::size_t level, std::size_t id) const override
carl::Bitset addPolynomial(const UPoly &p, std::size_t cid, bool isBound) override
Adds the given polynomial to the projection.
const UPoly & getPolynomialById(std::size_t level, std::size_t id) const override
Retrieves a polynomial from its id.
PriorityQueue< QueueEntry, ProjectionCandidateComparator > mProjectionQueue
std::size_t size(std::size_t level) const override
bool hasPolynomialById(std::size_t level, std::size_t id) const override
carl::Bitset projectNewPolynomial(const ConstraintSelection &cs=carl::Bitset(true))
std::optional< std::pair< UPoly, Origin > > Polynomial
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.
std::ostream & operator<<(std::ostream &os, const SampleIteratorQueue< I, C > &siq)
carl::UnivariatePolynomial< Poly > UPoly
projection_compare::Candidate< Poly > candidate(const Poly &p, const Poly &q, std::size_t level)
carl::Bitset ConstraintSelection
PositionIteratorType Iterator
std::optional< FormulaT > qe(const FormulaT &input)
Class to create the formulas for axioms.
const settings::Settings & Settings()
#define SMTRAT_LOG_TRACE(channel, msg)
#define SMTRAT_LOG_DEBUG(channel, msg)
ProjectionComparator< Settings::projectionComparator > mComparator
bool operator()(const QueueEntry &lhs, const QueueEntry &rhs) const
ProjectionCandidateComparator()=delete
ProjectionCandidateComparator(const PolyGetter &pg)
ProjectionCandidateComparator(const ProjectionCandidateComparator &pcc)
std::function< UPoly(std::size_t, std::size_t)> PolyGetter
std::vector< QueueEntry > entries
std::function< bool(std::size_t, std::size_t)> mCanBePurged
void reset(std::size_t dim)
const auto & data(std::size_t level) const
void restore(const Restorer &r)
bool isPurged(const QueueEntry &qe) const
void remove(std::size_t level, std::size_t id)
std::vector< PurgedLevel > mData
bool isPurged(std::size_t level, std::size_t id) const
auto & data(std::size_t level)
void add(const QueueEntry &qe)
void setBound(std::size_t level, std::size_t id, bool isBound)
PurgedPolynomials(const PurgeCheck &pc)
QueueEntry(std::size_t l, std::size_t f, std::size_t s)
friend std::ostream & operator<<(std::ostream &os, const QueueEntry &qe)
void add(const std::string &n)