SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
LevelWiseInformation.h
Go to the documentation of this file.
1 /**
2  * @file LevelWiseInformation.h
3  * @author Philip Kroll <Philip.Kroll@rwth-aachen.de>
4  * Created on 2021-12-17.
5  */
6 #pragma once
7 
12 #include "Helper.h"
13 #include "NewCoveringModule.h"
14 #include "NewCoveringSettings.h"
15 #include "NewCoveringStatistics.h"
17 
18 namespace smtrat {
19 
20 using namespace cadcells;
21 
22 // Possible types of covering information
24  partial = 0,
25  full = 1,
26  unknown = 2,
27  failed = 3,
28 };
29 
30 /*
31  * @brief The LevelWiseInformation class
32  *
33  * This class is used to store all calculated information about the given level.
34  * This is used for both backtracking, incrementality and caching in general
35  * We also store a flag to indicate the known status of the level.
36  * Additionally, if the level is not full, we store and compute the sample point outside of the cells.
37  * What covering heuristic is to be used is read from the settings.
38  */
39 template<class Settings>
41 
42  // get the covering heuristic from the settings
43  static constexpr cadcells::representation::CoveringHeuristic covering_heuristic = Settings::covering_heuristic;
44  using op = typename Settings::op;
45  static constexpr SamplingAlgorithm sampling_algorithm = Settings::sampling_algorithm;
46  static constexpr IsSampleOutsideAlgorithm is_sample_outside_algorithm = Settings::is_sample_outside_algorithm;
47  using PropSet = typename op::PropertiesSet;
48 
49 private:
50  // All Information that has been gathered for this level
51  // Implicitly uses the defined operator< (std::less)
52  std::set<datastructures::SampledDerivationRef<PropSet>, SampledDerivationRefCompare> mDerivations;
53 
54  // Do the current set of derivations covering the whole numberline?
56 
57  // The Covering based on the current set of derivations
58  std::optional<datastructures::CoveringRepresentation<PropSet>> mCovering;
59 
60  // sample point outside of the covering if the covering is not a full covering
62 
63 public:
64  // Constructor
66  : mCoveringStatus(CoveringStatus::unknown) {}
67 
68  // Move Constructor
70  : mDerivations(std::move(other.mDerivations)),
71  mCoveringStatus(other.mCoveringStatus),
72  mCovering(std::move(other.mCovering)),
73  mSamplePoint(other.mSamplePoint) {}
74 
75  // Add a new derivation
77  mDerivations.insert(derivation);
78  }
79 
80  // move in a new derivation
82  mDerivations.insert(std::move(derivation));
83  }
84 
85  const std::set<datastructures::SampledDerivationRef<PropSet>, SampledDerivationRefCompare>& getDerivations() const {
86  return mDerivations;
87  }
88 
89  // clear all derivations and the computed covering and set the full covering flag
90  void clear() {
91  mDerivations.clear();
92  mCovering.reset();
93  mCoveringStatus = CoveringStatus::unknown;
94  }
95 
96  /*
97  * @brief Compute the covering based on the current derivations
98  * Also set the covering flag accordingly and the find a sample point if the covering is not a full covering
99  * @returns True, iff the result invalidates the covering of all higher levels (i.e. if the variable assignment of the current level changes)
100  */
102 
103  SMTRAT_TIME_START(startTime);
104 
105  // If there is an already existing covering which is also full, we are done
106  if (isFullCovering()) {
107  SMTRAT_TIME_FINISH(getStatistics().timeForComputeCovering(), startTime);
108  return false;
109  }
110  // We assume that there are new derivations
111 
112  // If we had a partial covering before, we need to check if the sample point is still outside of the cells
113  // If that is the case, we can keep all information is the higher levels
114  if (isPartialCovering()) {
115  // Checking if the old sample point is still valid, i.e. outside if the all derivations
116  if (is_sample_outside<is_sample_outside_algorithm>::is_outside(mSamplePoint, mDerivations)) {
117  // The old sample Point is still valid, we are done
118  SMTRAT_LOG_DEBUG("smtrat.covering", "Sample " << mSamplePoint << " is still outside of the cells");
119  mCoveringStatus = CoveringStatus::partial;
120  SMTRAT_TIME_FINISH(getStatistics().timeForComputeCovering(), startTime);
121  return false;
122  }
123  SMTRAT_LOG_DEBUG("smtrat.covering", "Sample " << mSamplePoint << " not outside of the cells anymore");
124  }
125 
126  // based on the underlying set the vector is already sorted, now remove redundancies of the first kind
127 
128  // Check if the derivations cover the whole numberline
129  // we can convert the return value of sample_outside to CoveringStatus as 0 == partial covering and 1 == full covering
130  mCoveringStatus = CoveringStatus(sampling<sampling_algorithm>::sample_outside(mSamplePoint, mDerivations));
131 
132  if (isPartialCovering()) {
133  SMTRAT_TIME_FINISH(getStatistics().timeForComputeCovering(), startTime);
134  return true;
135  }
136  // The cells cover the numberline -> Compute the covering representation
137  std::vector<datastructures::SampledDerivationRef<PropSet>> derivationsVector(mDerivations.begin(), mDerivations.end());
138  mCovering = representation::covering<covering_heuristic>::compute(derivationsVector);
139  SMTRAT_LOG_DEBUG("smtrat.covering", "Computed Covering: " << mCovering.value());
140  SMTRAT_TIME_FINISH(getStatistics().timeForComputeCovering(), startTime);
141  return true;
142  }
143 
144  // Get the current sample point which is outside of the current covering
146  assert(isPartialCovering());
147  return mSamplePoint;
148  }
149 
150  // Information about the current covering
151  bool isPartialCovering() const {
152  return mCoveringStatus == CoveringStatus::partial;
153  }
154 
155  bool isFullCovering() const {
156  return mCoveringStatus == CoveringStatus::full;
157  }
158 
159  bool isUnknownCovering() const {
160  return mCoveringStatus == CoveringStatus::unknown;
161  }
162 
163  bool isFailedCovering() const {
164  return mCoveringStatus == CoveringStatus::failed;
165  }
166 
168  return mCoveringStatus;
169  }
170 
171  // override the =operator to move the current covering
173  mCovering = std::move(other.mCovering);
174  mDerivations = std::move(other.mDerivations);
175  mCoveringStatus = other.mCoveringStatus;
176  mSamplePoint = other.mSamplePoint;
177  return *this;
178  }
179 
180  // override the current sampled derivations
182  mDerivations = std::move(derivations);
183 
184  // this invalides the other stored information
185  mCovering.reset();
186  mCoveringStatus = CoveringStatus::unknown;
187  }
188 
189  // Remove a single derivations
190  /*
191  * @brief Remove a single derivation from the current set of derivations, if a covering was computed before, and the derivation was used, the covering is invalidated
192  */
194  SMTRAT_LOG_DEBUG("smtrat.covering", "Removing derivation: " << derivation);
195  assert(std::find(mDerivations.begin(), mDerivations.end(), derivation) != mDerivations.end());
196 
197  // If the derivation was used in the current covering, we need to reset it and set the flag accordingly
198  if (mCovering.has_value()) {
199  auto usedDerivations = mCovering.value().sampled_derivations();
200  if (std::find(usedDerivations.begin(), usedDerivations.end(), derivation) != usedDerivations.end()) {
201  SMTRAT_LOG_DEBUG("smtrat.covering", "Derivation to remove was used in the current covering representation");
202  // delete the current covering
203  mCovering.reset();
204  mCoveringStatus = CoveringStatus::unknown;
205  }
206  }
207 
208  // Now remove the derivation from the list
209  mDerivations.erase(derivation);
210  }
211 
212  // Remove a vector of derivations -> Just call removeDerivation for each derivation in the vector
213  void removeDerivation(const std::vector<datastructures::SampledDerivationRef<PropSet>>& derivations) {
214  for (const auto& derivation : derivations) {
215  removeDerivation(derivation);
216  }
217  }
218 
219  /*
220  * @brief Remove all derivations that were created using the given constraint, if a covering was computed before, and the derivation was used, the covering is invalidated
221  */
222  void removeConstraint(const cadcells::Constraint& constraint, const std::map<datastructures::SampledDerivationRef<PropSet>, std::vector<cadcells::Constraint>>& derivationConstraints) {
223  SMTRAT_LOG_DEBUG("smtrat.covering", "Removing constraint: " << constraint);
224  if (mCovering.has_value()) {
225  auto usedDerivations = mCovering.value().sampled_derivations();
226  if (std::find_if(usedDerivations.begin(), usedDerivations.end(), [&](const datastructures::SampledDerivationRef<PropSet>& deriv) {
227  return std::find(derivationConstraints.at(deriv).begin(), derivationConstraints.at(deriv).end(), constraint) != derivationConstraints.at(deriv).end();
228  }) != usedDerivations.end()) {
229  SMTRAT_LOG_DEBUG("smtrat.covering", "Constraint to remove was used in the current covering representation");
230  // delete the current covering
231  mCovering.reset();
232  mCoveringStatus = CoveringStatus::unknown;
233  }
234  }
235 
236  // remove all derivations that use the constraint
237  // TODO: When we switch to C++20, we can use erase_if here
238  for (auto it = mDerivations.begin(); it != mDerivations.end();) {
239  if (std::find(derivationConstraints.at(*it).begin(), derivationConstraints.at(*it).end(), constraint) != derivationConstraints.at(*it).end()) {
240  it = mDerivations.erase(it);
241  } else {
242  ++it;
243  }
244  }
245  // TODO: for memory reasons we could also remove the derivation from the derivationConstraints map -> is this worth it?
246  }
247 
248  /*
249  * @brief Get the constraints used in the current covering
250  * @return A vector of constraints
251  * @param derivationConstraints A map of derivations to constraints which created it
252  * This can only be used for infeasible subset -> so assert that the covering is full and use the last full covering
253  */
254  std::vector<cadcells::Constraint> getConstraintsOfCovering(std::map<datastructures::SampledDerivationRef<PropSet>, std::vector<cadcells::Constraint>>& mDerivationToConstraint) {
255  assert(isFullCovering() && mCovering.has_value());
256 
257  std::vector<cadcells::Constraint> constraints;
258  assert(mCovering.has_value());
259  for (const auto& derivation : mCovering.value().sampled_derivations()) {
260  assert(mDerivationToConstraint.find(derivation) != mDerivationToConstraint.end());
261  std::vector<cadcells::Constraint> new_constraints = mDerivationToConstraint[derivation];
262  constraints.insert(constraints.end(), new_constraints.begin(), new_constraints.end());
263  }
264 
265  // remove duplicates of the constraints
266  std::sort(constraints.begin(), constraints.end());
267  constraints.erase(std::unique(constraints.begin(), constraints.end()), constraints.end());
268  return constraints;
269  }
270 
271  // Construct a new derivation based on the current covering
272  // Asserts that the covering is full
273  /*
274  * @brief Construct a new derivation based on the current covering
275  * @return SampledDerivationRef: Information for the lower dimension, derived from the current covering
276  * @param derivationConstraints A map of derivations to constraints which created it
277  * @note: This represents Section 4.6 in the paper https://arxiv.org/pdf/2003.05633.pdf
278  */
279  std::optional<datastructures::SampledDerivationRef<PropSet>> constructDerivation(std::map<datastructures::SampledDerivationRef<PropSet>, std::vector<cadcells::Constraint>>& mDerivationToConstraint) {
280  SMTRAT_TIME_START(startTime);
281 
282  assert(mCovering.has_value());
283  assert(isFullCovering());
284 
285  auto& fullCovering = mCovering.value();
286 
287  SMTRAT_LOG_DEBUG("smtrat.covering", "Got full covering: " << fullCovering);
288 
289  auto usedConstraints = getConstraintsOfCovering(mDerivationToConstraint);
290  auto cell_derivs = fullCovering.sampled_derivations();
292  if (!op::project_covering_properties(fullCovering)) {
293  SMTRAT_LOG_DEBUG("smtrat.covering", "Could not project properties");
294  SMTRAT_TIME_FINISH(getStatistics().timeForConstructDerivation(), startTime);
295  return std::nullopt;
296  }
297  datastructures::SampledDerivationRef<PropSet> new_deriv = fullCovering.cells.front().derivation->underlying().sampled_ref();
298  if (!op::project_basic_properties(*new_deriv)) {
299  SMTRAT_LOG_DEBUG("smtrat.covering", "Could not project properties");
300  SMTRAT_TIME_FINISH(getStatistics().timeForConstructDerivation(), startTime);
301  return std::nullopt;
302  }
303  op::delineate_properties(*new_deriv);
304  new_deriv->delineate_cell();
305  SMTRAT_LOG_DEBUG("smtrat.covering", "Found new unsat cell for the higher dimension: " << new_deriv->cell());
306 
307  // The origin of the new derivation are all constraints used in the last full covering
308 
309  mDerivationToConstraint.insert(std::make_pair(new_deriv, usedConstraints));
310  SMTRAT_TIME_FINISH(getStatistics().timeForConstructDerivation(), startTime);
311 
312  return new_deriv;
313  }
314 };
315 
316 // override the << operator for CoveringStatus
317 inline std::ostream& operator<<(std::ostream& os, const CoveringStatus& status) {
318  switch (status) {
320  os << "partial";
321  break;
323  os << "full";
324  break;
326  os << "unknown";
327  break;
329  os << "failed";
330  break;
331  default:
332  os << "unknown";
333  break;
334  }
335  return os;
336 }
337 
338 // override the << operator to print the LevelWiseInformation
339 template<typename Settings>
340 inline std::ostream& operator<<(std::ostream& os, const LevelWiseInformation<Settings>& levelWiseInformation) {
341  os << "CoveringStatus: " << levelWiseInformation.getCoveringStatus() << std::endl;
342  if (levelWiseInformation.isPartialCovering()) {
343  os << "SamplePoint: " << levelWiseInformation.getSampleOutside() << std::endl;
344  }
345  if (levelWiseInformation.isFullCovering() || levelWiseInformation.isPartialCovering()) {
346  os << "Derivations: " << levelWiseInformation.getDerivations() << std::endl;
347  }
348  return os;
349 }
350 
351 } // namespace smtrat
void setDerivations(std::vector< datastructures::SampledDerivationRef< PropSet >> &&derivations)
std::vector< cadcells::Constraint > getConstraintsOfCovering(std::map< datastructures::SampledDerivationRef< PropSet >, std::vector< cadcells::Constraint >> &mDerivationToConstraint)
const std::set< datastructures::SampledDerivationRef< PropSet >, SampledDerivationRefCompare > & getDerivations() const
typename op::PropertiesSet PropSet
CoveringStatus getCoveringStatus() const
LevelWiseInformation(LevelWiseInformation &&other)
std::set< datastructures::SampledDerivationRef< PropSet >, SampledDerivationRefCompare > mDerivations
void addDerivation(datastructures::SampledDerivationRef< PropSet > &&derivation)
void removeConstraint(const cadcells::Constraint &constraint, const std::map< datastructures::SampledDerivationRef< PropSet >, std::vector< cadcells::Constraint >> &derivationConstraints)
std::optional< datastructures::SampledDerivationRef< PropSet > > constructDerivation(std::map< datastructures::SampledDerivationRef< PropSet >, std::vector< cadcells::Constraint >> &mDerivationToConstraint)
void removeDerivation(const datastructures::SampledDerivationRef< PropSet > &derivation)
const cadcells::RAN & getSampleOutside() const
void removeDerivation(const std::vector< datastructures::SampledDerivationRef< PropSet >> &derivations)
LevelWiseInformation & operator=(LevelWiseInformation &&other)
void addDerivation(const datastructures::SampledDerivationRef< PropSet > &derivation)
std::optional< datastructures::CoveringRepresentation< PropSet > > mCovering
void sort(T *array, int size, LessThan lt)
Definition: Sort.h:67
static bool find(V &ts, const T &t)
Definition: Alg.h:47
void merge_underlying(std::vector< SampledDerivationRef< Properties >> &derivations)
Merges the underlying derivations of a set of sampled derivations.
Definition: derivation.h:408
std::shared_ptr< SampledDerivation< Properties > > SampledDerivationRef
Definition: derivation.h:25
Polynomial::RootType RAN
Definition: common.h:24
carl::BasicConstraint< Polynomial > Constraint
Definition: common.h:18
Class to create the formulas for axioms.
IsSampleOutsideAlgorithm
Definition: Sampling.h:21
std::ostream & operator<<(std::ostream &os, CMakeOptionPrinter cmop)
SamplingAlgorithm
Definition: Sampling.h:17
#define SMTRAT_LOG_DEBUG(channel, msg)
Definition: logging.h:35
#define SMTRAT_TIME_START(variable)
Definition: Statistics.h:24
#define SMTRAT_TIME_FINISH(timer, start)
Definition: Statistics.h:25
static datastructures::CoveringRepresentation< T > compute(const std::vector< datastructures::SampledDerivationRef< T >> &ders)