1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Tim King, Andrew Reynolds, Alex Ozdemir |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* [[ Add one-line brief description here ]] |
14 |
|
* |
15 |
|
* [[ Add lengthier description here ]] |
16 |
|
* \todo document this file |
17 |
|
*/ |
18 |
|
|
19 |
|
#pragma once |
20 |
|
|
21 |
|
#include <map> |
22 |
|
#include <vector> |
23 |
|
|
24 |
|
#include "context/cdhashset.h" |
25 |
|
#include "context/cdinsert_hashmap.h" |
26 |
|
#include "context/cdlist.h" |
27 |
|
#include "context/cdqueue.h" |
28 |
|
#include "expr/kind.h" |
29 |
|
#include "expr/node.h" |
30 |
|
#include "expr/node_builder.h" |
31 |
|
#include "proof/trust_node.h" |
32 |
|
#include "theory/arith/arith_static_learner.h" |
33 |
|
#include "theory/arith/arith_utilities.h" |
34 |
|
#include "theory/arith/arithvar.h" |
35 |
|
#include "theory/arith/attempt_solution_simplex.h" |
36 |
|
#include "theory/arith/branch_and_bound.h" |
37 |
|
#include "theory/arith/congruence_manager.h" |
38 |
|
#include "theory/arith/constraint.h" |
39 |
|
#include "theory/arith/delta_rational.h" |
40 |
|
#include "theory/arith/dio_solver.h" |
41 |
|
#include "theory/arith/dual_simplex.h" |
42 |
|
#include "theory/arith/error_set.h" |
43 |
|
#include "theory/arith/fc_simplex.h" |
44 |
|
#include "theory/arith/infer_bounds.h" |
45 |
|
#include "theory/arith/linear_equality.h" |
46 |
|
#include "theory/arith/matrix.h" |
47 |
|
#include "theory/arith/normal_form.h" |
48 |
|
#include "theory/arith/partial_model.h" |
49 |
|
#include "theory/arith/proof_checker.h" |
50 |
|
#include "theory/arith/soi_simplex.h" |
51 |
|
#include "theory/arith/theory_arith.h" |
52 |
|
#include "theory/valuation.h" |
53 |
|
#include "util/dense_map.h" |
54 |
|
#include "util/integer.h" |
55 |
|
#include "util/rational.h" |
56 |
|
#include "util/result.h" |
57 |
|
#include "util/statistics_stats.h" |
58 |
|
|
59 |
|
namespace cvc5 { |
60 |
|
|
61 |
|
class EagerProofGenerator; |
62 |
|
|
63 |
|
namespace theory { |
64 |
|
|
65 |
|
class TheoryModel; |
66 |
|
|
67 |
|
namespace arith { |
68 |
|
|
69 |
|
class BranchCutInfo; |
70 |
|
class TreeLog; |
71 |
|
class ApproximateStatistics; |
72 |
|
|
73 |
|
class ArithEntailmentCheckParameters; |
74 |
|
class ArithEntailmentCheckSideEffects; |
75 |
|
namespace inferbounds { |
76 |
|
class InferBoundAlgorithm; |
77 |
|
} |
78 |
|
class InferBoundsResult; |
79 |
|
|
80 |
|
/** |
81 |
|
* Implementation of QF_LRA. |
82 |
|
* Based upon: |
83 |
|
* http://research.microsoft.com/en-us/um/people/leonardo/cav06.pdf |
84 |
|
*/ |
85 |
|
class TheoryArithPrivate { |
86 |
|
private: |
87 |
|
|
88 |
|
static const uint32_t RESET_START = 2; |
89 |
|
|
90 |
|
TheoryArith& d_containing; |
91 |
|
|
92 |
|
/** |
93 |
|
* Whether we encountered non-linear arithmetic at any time during solving. |
94 |
|
*/ |
95 |
|
bool d_foundNl; |
96 |
|
|
97 |
|
BoundInfoMap d_rowTracking; |
98 |
|
/** Branch and bound utility */ |
99 |
|
BranchAndBound& d_bab; |
100 |
|
// For proofs |
101 |
|
/** Manages the proof nodes of this theory. */ |
102 |
|
ProofNodeManager* d_pnm; |
103 |
|
/** Checks the proof rules of this theory. */ |
104 |
|
ArithProofRuleChecker d_checker; |
105 |
|
/** Stores proposition(node)/proof pairs. */ |
106 |
|
std::unique_ptr<EagerProofGenerator> d_pfGen; |
107 |
|
|
108 |
|
/** |
109 |
|
* The constraint database associated with the theory. |
110 |
|
* This must be declared before ArithPartialModel. |
111 |
|
*/ |
112 |
|
ConstraintDatabase d_constraintDatabase; |
113 |
|
|
114 |
|
enum Result::Sat d_qflraStatus; |
115 |
|
// check() |
116 |
|
// !done() -> d_qflraStatus = Unknown |
117 |
|
// fullEffort(e) -> simplex returns either sat or unsat |
118 |
|
// !fullEffort(e) -> simplex returns either sat, unsat or unknown |
119 |
|
// if unknown, save the assignment |
120 |
|
// if unknown, the simplex priority queue cannot be emptied |
121 |
|
int d_unknownsInARow; |
122 |
|
|
123 |
|
bool d_replayedLemmas; |
124 |
|
|
125 |
|
/** |
126 |
|
* This counter is false if nothing has been done since the last cut. |
127 |
|
* This is used to break an infinite loop. |
128 |
|
*/ |
129 |
|
bool d_hasDoneWorkSinceCut; |
130 |
|
|
131 |
|
/** Static learner. */ |
132 |
|
ArithStaticLearner d_learner; |
133 |
|
|
134 |
|
//std::vector<ArithVar> d_pool; |
135 |
|
public: |
136 |
|
void releaseArithVar(ArithVar v); |
137 |
5657963 |
void signal(ArithVar v){ d_errorSet.signalVariable(v); } |
138 |
|
|
139 |
|
|
140 |
|
private: |
141 |
|
// t does not contain constants |
142 |
|
void entailmentCheckBoundLookup(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const; |
143 |
|
void entailmentCheckRowSum(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const; |
144 |
|
|
145 |
|
/** |
146 |
|
* Infers either a new upper/lower bound on term in the real relaxation. |
147 |
|
* Either: |
148 |
|
* - term is malformed (see below) |
149 |
|
* - a maximum/minimum is found with the result being a pair |
150 |
|
* -- <dr, exp> where |
151 |
|
* -- term <?> dr is implies by exp |
152 |
|
* -- <?> is <= if inferring an upper bound, >= otherwise |
153 |
|
* -- exp is in terms of the assertions to the theory. |
154 |
|
* - No upper or lower bound is inferrable in the real relaxation. |
155 |
|
* -- Returns <0, Null()> |
156 |
|
* - the maximum number of rounds was exhausted: |
157 |
|
* -- Returns <v, term> where v is the current feasible value of term |
158 |
|
* - Threshold reached: |
159 |
|
* -- If theshold != NULL, and a feasible value is found to exceed threshold |
160 |
|
* -- Simplex stops and returns <threshold, term> |
161 |
|
*/ |
162 |
|
//std::pair<DeltaRational, Node> inferBound(TNode term, bool lb, int maxRounds = -1, const DeltaRational* threshold = NULL); |
163 |
|
|
164 |
|
private: |
165 |
|
static bool decomposeTerm(Node term, Rational& m, Node& p, Rational& c); |
166 |
|
static bool decomposeLiteral(Node lit, Kind& k, int& dir, Rational& lm, Node& lp, Rational& rm, Node& rp, Rational& dm, Node& dp, DeltaRational& sep); |
167 |
|
static void setToMin(int sgn, std::pair<Node, DeltaRational>& min, const std::pair<Node, DeltaRational>& e); |
168 |
|
|
169 |
|
/** |
170 |
|
* The map between arith variables to nodes. |
171 |
|
*/ |
172 |
|
//ArithVarNodeMap d_arithvarNodeMap; |
173 |
|
|
174 |
|
typedef ArithVariables::var_iterator var_iterator; |
175 |
1664802 |
var_iterator var_begin() const { return d_partialModel.var_begin(); } |
176 |
1664802 |
var_iterator var_end() const { return d_partialModel.var_end(); } |
177 |
|
|
178 |
|
NodeSet d_setupNodes; |
179 |
|
public: |
180 |
4986347 |
bool isSetup(Node n) const { |
181 |
4986347 |
return d_setupNodes.find(n) != d_setupNodes.end(); |
182 |
|
} |
183 |
428042 |
void markSetup(Node n){ |
184 |
428042 |
Assert(!isSetup(n)); |
185 |
428042 |
d_setupNodes.insert(n); |
186 |
428042 |
} |
187 |
|
private: |
188 |
|
void setupVariable(const Variable& x); |
189 |
|
void setupVariableList(const VarList& vl); |
190 |
|
void setupPolynomial(const Polynomial& poly); |
191 |
|
public: |
192 |
|
void setupAtom(TNode atom); |
193 |
|
private: |
194 |
|
void cautiousSetupPolynomial(const Polynomial& p); |
195 |
|
|
196 |
|
/** |
197 |
|
* A superset of all of the assertions that currently are not the literal for |
198 |
|
* their constraint do not match constraint literals. Not just the witnesses. |
199 |
|
*/ |
200 |
|
context::CDInsertHashMap<Node, ConstraintP> |
201 |
|
d_assertionsThatDoNotMatchTheirLiterals; |
202 |
|
|
203 |
|
/** Returns true if x is of type Integer. */ |
204 |
19328995 |
inline bool isInteger(ArithVar x) const { |
205 |
19328995 |
return d_partialModel.isInteger(x); |
206 |
|
} |
207 |
|
|
208 |
|
|
209 |
|
/** Returns true if the variable was initially introduced as an auxiliary variable. */ |
210 |
579647 |
inline bool isAuxiliaryVariable(ArithVar x) const{ |
211 |
579647 |
return d_partialModel.isAuxiliary(x); |
212 |
|
} |
213 |
|
|
214 |
618961909 |
inline bool isIntegerInput(ArithVar x) const |
215 |
|
{ |
216 |
618961909 |
return d_partialModel.isIntegerInput(x) |
217 |
1237923818 |
&& d_preregisteredNodes.contains(d_partialModel.asNode(x)); |
218 |
|
} |
219 |
|
|
220 |
|
/** |
221 |
|
* On full effort checks (after determining LA(Q) satisfiability), we |
222 |
|
* consider integer vars, but we make sure to do so fairly to avoid |
223 |
|
* nontermination (although this isn't a guarantee). To do it fairly, |
224 |
|
* we consider variables in round-robin fashion. This is the |
225 |
|
* round-robin index. |
226 |
|
*/ |
227 |
|
ArithVar d_nextIntegerCheckVar; |
228 |
|
|
229 |
|
/** |
230 |
|
* Queue of Integer variables that are known to be equal to a constant. |
231 |
|
*/ |
232 |
|
context::CDQueue<ArithVar> d_constantIntegerVariables; |
233 |
|
|
234 |
|
Node callDioSolver(); |
235 |
|
/** |
236 |
|
* Produces lemmas of the form (or (>= f 0) (<= f 0)), |
237 |
|
* where f is a plane that the diophantine solver is interested in. |
238 |
|
* |
239 |
|
* More precisely, produces lemmas of the form (or (>= lc -c) (<= lc -c)) |
240 |
|
* where lc is a linear combination of variables, c is a constant, and lc + c |
241 |
|
* is the plane. |
242 |
|
*/ |
243 |
|
TrustNode dioCutting(); |
244 |
|
|
245 |
|
Comparison mkIntegerEqualityFromAssignment(ArithVar v); |
246 |
|
|
247 |
|
/** |
248 |
|
* List of all of the disequalities asserted in the current context that are not known |
249 |
|
* to be satisfied. |
250 |
|
*/ |
251 |
|
context::CDQueue<ConstraintP> d_diseqQueue; |
252 |
|
|
253 |
|
/** |
254 |
|
* Constraints that have yet to be processed by proagation work list. |
255 |
|
* All of the elements have type of LowerBound, UpperBound, or |
256 |
|
* Equality. |
257 |
|
* |
258 |
|
* This is empty at the beginning of every check call. |
259 |
|
* |
260 |
|
* If head()->getType() == LowerBound or UpperBound, |
261 |
|
* then d_cPL[1] is the previous constraint in d_partialModel for the |
262 |
|
* corresponding bound. |
263 |
|
* If head()->getType() == Equality, |
264 |
|
* then d_cPL[1] is the previous lowerBound in d_partialModel, |
265 |
|
* and d_cPL[2] is the previous upperBound in d_partialModel. |
266 |
|
*/ |
267 |
|
std::deque<ConstraintP> d_currentPropagationList; |
268 |
|
|
269 |
|
context::CDQueue<ConstraintP> d_learnedBounds; |
270 |
|
|
271 |
|
/** |
272 |
|
* Contains all nodes that have been preregistered |
273 |
|
*/ |
274 |
|
context::CDHashSet<Node> d_preregisteredNodes; |
275 |
|
|
276 |
|
/** |
277 |
|
* Manages information about the assignment and upper and lower bounds on |
278 |
|
* variables. |
279 |
|
*/ |
280 |
|
ArithVariables d_partialModel; |
281 |
|
|
282 |
|
/** The set of variables in error in the partial model. */ |
283 |
|
ErrorSet d_errorSet; |
284 |
|
|
285 |
|
/** |
286 |
|
* The tableau for all of the constraints seen thus far in the system. |
287 |
|
*/ |
288 |
|
Tableau d_tableau; |
289 |
|
|
290 |
|
/** |
291 |
|
* Maintains the relationship between the PartialModel and the Tableau. |
292 |
|
*/ |
293 |
|
LinearEqualityModule d_linEq; |
294 |
|
|
295 |
|
/** |
296 |
|
* A Diophantine equation solver. Accesses the tableau and partial |
297 |
|
* model (each in a read-only fashion). |
298 |
|
*/ |
299 |
|
DioSolver d_diosolver; |
300 |
|
|
301 |
|
/** Counts the number of notifyRestart() calls to the theory. */ |
302 |
|
uint32_t d_restartsCounter; |
303 |
|
|
304 |
|
/** |
305 |
|
* Every number of restarts equal to s_TABLEAU_RESET_PERIOD, |
306 |
|
* the density of the tableau, d, is computed. |
307 |
|
* If d >= s_TABLEAU_RESET_DENSITY * d_initialDensity, the tableau |
308 |
|
* is set to d_initialTableau. |
309 |
|
*/ |
310 |
|
bool d_tableauSizeHasBeenModified; |
311 |
|
double d_tableauResetDensity; |
312 |
|
uint32_t d_tableauResetPeriod; |
313 |
|
static const uint32_t s_TABLEAU_RESET_INCREMENT = 5; |
314 |
|
|
315 |
|
|
316 |
|
/** This is only used by simplex at the moment. */ |
317 |
|
context::CDList<std::pair<ConstraintCP, InferenceId>> d_conflicts; |
318 |
|
|
319 |
|
/** This is only used by simplex at the moment. */ |
320 |
|
context::CDO<Node> d_blackBoxConflict; |
321 |
|
/** For holding the proof of the above conflict node. */ |
322 |
|
context::CDO<std::shared_ptr<ProofNode>> d_blackBoxConflictPf; |
323 |
|
|
324 |
|
bool isProofEnabled() const; |
325 |
|
|
326 |
|
public: |
327 |
|
/** |
328 |
|
* This adds the constraint a to the queue of conflicts in d_conflicts. |
329 |
|
* Both a and ~a must have a proof. |
330 |
|
*/ |
331 |
|
void raiseConflict(ConstraintCP a, InferenceId id); |
332 |
|
|
333 |
|
// inline void raiseConflict(const ConstraintCPVec& cv){ |
334 |
|
// d_conflicts.push_back(cv); |
335 |
|
// } |
336 |
|
|
337 |
|
// void raiseConflict(ConstraintCP a, ConstraintCP b); |
338 |
|
// void raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c); |
339 |
|
|
340 |
|
/** This is a conflict that is magically known to hold. */ |
341 |
|
void raiseBlackBoxConflict(Node bb, std::shared_ptr<ProofNode> pf = nullptr); |
342 |
|
/** |
343 |
|
* Returns true iff a conflict has been raised. This method is public since |
344 |
|
* it is needed by the ArithState class to know whether we are in conflict. |
345 |
|
*/ |
346 |
|
bool anyConflict() const; |
347 |
|
|
348 |
|
private: |
349 |
15787067 |
inline bool conflictQueueEmpty() const { |
350 |
15787067 |
return d_conflicts.empty(); |
351 |
|
} |
352 |
|
|
353 |
|
/** |
354 |
|
* Outputs the contents of d_conflicts onto d_out. |
355 |
|
* The conditions of anyConflict() must hold. |
356 |
|
*/ |
357 |
|
void outputConflicts(); |
358 |
|
|
359 |
|
/** |
360 |
|
* A copy of the tableau. |
361 |
|
* This is equivalent to the original tableau if d_tableauSizeHasBeenModified |
362 |
|
* is false. |
363 |
|
* The set of basic and non-basic variables may differ from d_tableau. |
364 |
|
*/ |
365 |
|
Tableau d_smallTableauCopy; |
366 |
|
|
367 |
|
/** |
368 |
|
* Returns true if all of the basic variables in the simplex queue of |
369 |
|
* basic variables that violate their bounds in the current tableau |
370 |
|
* are basic in d_smallTableauCopy. |
371 |
|
* |
372 |
|
* d_tableauSizeHasBeenModified must be false when calling this. |
373 |
|
* Simplex's priority queue must be in collection mode. |
374 |
|
*/ |
375 |
|
bool safeToReset() const; |
376 |
|
|
377 |
|
/** This keeps track of difference equalities. Mostly for sharing. */ |
378 |
|
ArithCongruenceManager d_congruenceManager; |
379 |
|
context::CDO<bool> d_cmEnabled; |
380 |
|
|
381 |
|
/** This implements the Simplex decision procedure. */ |
382 |
|
DualSimplexDecisionProcedure d_dualSimplex; |
383 |
|
FCSimplexDecisionProcedure d_fcSimplex; |
384 |
|
SumOfInfeasibilitiesSPD d_soiSimplex; |
385 |
|
AttemptSolutionSDP d_attemptSolSimplex; |
386 |
|
|
387 |
|
bool solveRealRelaxation(Theory::Effort effortLevel); |
388 |
|
|
389 |
|
/* Returns true if this is heuristically a good time to try |
390 |
|
* to solve the integers. |
391 |
|
*/ |
392 |
|
bool attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit); |
393 |
|
bool replayLemmas(ApproximateSimplex* approx); |
394 |
|
void solveInteger(Theory::Effort effortLevel); |
395 |
|
bool safeToCallApprox() const; |
396 |
|
SimplexDecisionProcedure& selectSimplex(bool pass1); |
397 |
|
SimplexDecisionProcedure* d_pass1SDP; |
398 |
|
SimplexDecisionProcedure* d_otherSDP; |
399 |
|
/* Sets d_qflraStatus */ |
400 |
|
void importSolution(const ApproximateSimplex::Solution& solution); |
401 |
|
bool solveRelaxationOrPanic(Theory::Effort effortLevel); |
402 |
|
context::CDO<int> d_lastContextIntegerAttempted; |
403 |
|
bool replayLog(ApproximateSimplex* approx); |
404 |
|
|
405 |
|
class ModelException : public Exception { |
406 |
|
public: |
407 |
|
ModelException(TNode n, const char* msg); |
408 |
|
~ModelException() override; |
409 |
|
}; |
410 |
|
|
411 |
|
/** |
412 |
|
* Computes the delta rational value of a term from the current partial |
413 |
|
* model. This returns the delta value assignment to the term if it is in the |
414 |
|
* partial model. Otherwise, this is computed recursively for arithmetic terms |
415 |
|
* from each subterm. |
416 |
|
* |
417 |
|
* This throws a DeltaRationalException if the value cannot be represented as |
418 |
|
* a DeltaRational. This throws a ModelException if there is a term is not in |
419 |
|
* the partial model and is not a theory of arithmetic term. |
420 |
|
* |
421 |
|
* precondition: The linear abstraction of the nodes must be satisfiable. |
422 |
|
*/ |
423 |
|
DeltaRational getDeltaValue(TNode term) const |
424 |
|
/* throw(DeltaRationalException, ModelException) */; |
425 |
|
public: |
426 |
|
TheoryArithPrivate(TheoryArith& containing, |
427 |
|
context::Context* c, |
428 |
|
context::UserContext* u, |
429 |
|
BranchAndBound& bab, |
430 |
|
ProofNodeManager* pnm); |
431 |
|
~TheoryArithPrivate(); |
432 |
|
|
433 |
|
//--------------------------------- initialization |
434 |
|
/** |
435 |
|
* Returns true if we need an equality engine, see |
436 |
|
* Theory::needsEqualityEngine. |
437 |
|
*/ |
438 |
|
bool needsEqualityEngine(EeSetupInfo& esi); |
439 |
|
/** finish initialize */ |
440 |
|
void finishInit(); |
441 |
|
//--------------------------------- end initialization |
442 |
|
|
443 |
|
/** |
444 |
|
* Does non-context dependent setup for a node connected to a theory. |
445 |
|
*/ |
446 |
|
void preRegisterTerm(TNode n); |
447 |
|
|
448 |
|
void propagate(Theory::Effort e); |
449 |
|
TrustNode explain(TNode n); |
450 |
|
|
451 |
|
Rational deltaValueForTotalOrder() const; |
452 |
|
|
453 |
|
bool collectModelInfo(TheoryModel* m); |
454 |
|
/** |
455 |
|
* Collect model values. This is the main method for extracting information |
456 |
|
* about how to construct the model. This method relies on the caller for |
457 |
|
* processing the map, which is done so that other modules (e.g. the |
458 |
|
* non-linear extension) can modify arithModel before it is sent to the model. |
459 |
|
* |
460 |
|
* @param termSet The set of relevant terms |
461 |
|
* @param arithModel Mapping from terms (of real type) to their values. The |
462 |
|
* caller should assert equalities to the model for each entry in this map. |
463 |
|
*/ |
464 |
|
void collectModelValues(const std::set<Node>& termSet, |
465 |
|
std::map<Node, Node>& arithModel); |
466 |
|
|
467 |
|
void shutdown(){ } |
468 |
|
|
469 |
|
void presolve(); |
470 |
|
void notifyRestart(); |
471 |
|
Theory::PPAssertStatus ppAssert(TrustNode tin, |
472 |
|
TrustSubstitutionMap& outSubstitutions); |
473 |
|
void ppStaticLearn(TNode in, NodeBuilder& learned); |
474 |
|
|
475 |
|
std::string identify() const { return std::string("TheoryArith"); } |
476 |
|
|
477 |
|
EqualityStatus getEqualityStatus(TNode a, TNode b); |
478 |
|
|
479 |
|
/** Called when n is notified as being a shared term with TheoryArith. */ |
480 |
|
void notifySharedTerm(TNode n); |
481 |
|
|
482 |
|
Node getModelValue(TNode var); |
483 |
|
|
484 |
|
|
485 |
|
std::pair<bool, Node> entailmentCheck(TNode lit, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out); |
486 |
|
|
487 |
|
//--------------------------------- standard check |
488 |
|
/** Pre-check, called before the fact queue of the theory is processed. */ |
489 |
|
bool preCheck(Theory::Effort level); |
490 |
|
/** Pre-notify fact. */ |
491 |
|
void preNotifyFact(TNode atom, bool pol, TNode fact); |
492 |
|
/** |
493 |
|
* Post-check, called after the fact queue of the theory is processed. Returns |
494 |
|
* true if a conflict or lemma was emitted. |
495 |
|
*/ |
496 |
|
bool postCheck(Theory::Effort level); |
497 |
|
//--------------------------------- end standard check |
498 |
|
/** |
499 |
|
* Found non-linear? This returns true if this solver ever encountered |
500 |
|
* any non-linear terms that were unhandled. Note that this class is not |
501 |
|
* responsible for handling non-linear arithmetic. If the owner of this |
502 |
|
* class does not handle non-linear arithmetic in another way, then |
503 |
|
* setIncomplete should be called on the output channel of TheoryArith. |
504 |
|
*/ |
505 |
|
bool foundNonlinear() const; |
506 |
|
|
507 |
|
/** get the proof checker of this theory */ |
508 |
|
ArithProofRuleChecker* getProofChecker(); |
509 |
|
|
510 |
|
private: |
511 |
|
/** The constant zero. */ |
512 |
|
DeltaRational d_DELTA_ZERO; |
513 |
|
|
514 |
|
/** propagates an arithvar */ |
515 |
|
void propagateArithVar(bool upperbound, ArithVar var ); |
516 |
|
|
517 |
|
/** |
518 |
|
* Using the simpleKind return the ArithVar associated with the assertion. |
519 |
|
*/ |
520 |
|
ArithVar determineArithVar(const Polynomial& p) const; |
521 |
|
ArithVar determineArithVar(TNode assertion) const; |
522 |
|
|
523 |
|
/** |
524 |
|
* Splits the disequalities in d_diseq that are violated using lemmas on demand. |
525 |
|
* returns true if any lemmas were issued. |
526 |
|
* returns false if all disequalities are satisfied in the current model. |
527 |
|
*/ |
528 |
|
bool splitDisequalities(); |
529 |
|
|
530 |
|
/** A Difference variable is known to be 0.*/ |
531 |
|
void zeroDifferenceDetected(ArithVar x); |
532 |
|
|
533 |
|
|
534 |
|
/** |
535 |
|
* Looks for the next integer variable without an integer assignment in a |
536 |
|
* round-robin fashion. Changes the value of d_nextIntegerCheckVar. |
537 |
|
* |
538 |
|
* This returns true if all integer variables have integer assignments. |
539 |
|
* If this returns false, d_nextIntegerCheckVar does not have an integer |
540 |
|
* assignment. |
541 |
|
*/ |
542 |
|
bool hasIntegerModel(); |
543 |
|
|
544 |
|
/** |
545 |
|
* Looks for through the variables starting at d_nextIntegerCheckVar |
546 |
|
* for the first integer variable that is between its upper and lower bounds |
547 |
|
* that has a non-integer assignment. |
548 |
|
* |
549 |
|
* If assumeBounds is true, skip the check that the variable is in bounds. |
550 |
|
* |
551 |
|
* If there is no such variable, returns ARITHVAR_SENTINEL; |
552 |
|
*/ |
553 |
|
ArithVar nextIntegerViolation(bool assumeBounds) const; |
554 |
|
|
555 |
|
/** |
556 |
|
* Issues branches for non-auxiliary integer variables with non-integer assignments. |
557 |
|
* Returns a cut for a lemma. |
558 |
|
* If there is an integer model, this returns Node::null(). |
559 |
|
*/ |
560 |
|
TrustNode roundRobinBranch(); |
561 |
|
|
562 |
1438 |
bool proofsEnabled() const { return d_pnm; } |
563 |
|
|
564 |
|
public: |
565 |
|
/** |
566 |
|
* This requests a new unique ArithVar value for x. |
567 |
|
* This also does initial (not context dependent) set up for a variable, |
568 |
|
* except for setting up the initial. |
569 |
|
* |
570 |
|
* If aux is true, this is an auxiliary variable. |
571 |
|
* If internal is true, x might not be unique up to a constant multiple. |
572 |
|
*/ |
573 |
|
ArithVar requestArithVar(TNode x, bool aux, bool internal); |
574 |
|
|
575 |
|
public: |
576 |
|
const BoundsInfo& boundsInfo(ArithVar basic) const; |
577 |
|
|
578 |
|
|
579 |
|
private: |
580 |
|
/** Initial (not context dependent) sets up for a variable.*/ |
581 |
|
void setupBasicValue(ArithVar x); |
582 |
|
|
583 |
|
/** Initial (not context dependent) sets up for a new auxiliary variable.*/ |
584 |
|
void setupAuxiliary(TNode left); |
585 |
|
|
586 |
|
|
587 |
|
/** |
588 |
|
* Assert*(n, orig) takes an bound n that is implied by orig. |
589 |
|
* and asserts that as a new bound if it is tighter than the current bound |
590 |
|
* and updates the value of a basic variable if needed. |
591 |
|
* |
592 |
|
* orig must be a literal in the SAT solver so that it can be used for |
593 |
|
* conflict analysis. |
594 |
|
* |
595 |
|
* x is the variable getting the new bound, |
596 |
|
* c is the value of the new bound. |
597 |
|
* |
598 |
|
* If this new bound is in conflict with the other bound, |
599 |
|
* a node describing this conflict is returned. |
600 |
|
* If this new bound is not in conflict, Node::null() is returned. |
601 |
|
*/ |
602 |
|
bool AssertLower(ConstraintP constraint); |
603 |
|
bool AssertUpper(ConstraintP constraint); |
604 |
|
bool AssertEquality(ConstraintP constraint); |
605 |
|
bool AssertDisequality(ConstraintP constraint); |
606 |
|
|
607 |
|
/** Tracks the bounds that were updated in the current round. */ |
608 |
|
DenseSet d_updatedBounds; |
609 |
|
|
610 |
|
/** Tracks the basic variables where propagation might be possible. */ |
611 |
|
DenseSet d_candidateBasics; |
612 |
|
DenseSet d_candidateRows; |
613 |
|
|
614 |
2694712 |
bool hasAnyUpdates() { return !d_updatedBounds.empty(); } |
615 |
|
void clearUpdates(); |
616 |
|
|
617 |
|
void revertOutOfConflict(); |
618 |
|
|
619 |
|
void propagateCandidatesNew(); |
620 |
|
void dumpUpdatedBoundsToRows(); |
621 |
|
bool propagateCandidateRow(RowIndex rid); |
622 |
|
bool propagateMightSucceed(ArithVar v, bool ub) const; |
623 |
|
/** Attempt to perform a row propagation where there is at most 1 possible variable.*/ |
624 |
|
bool attemptSingleton(RowIndex ridx, bool rowUp); |
625 |
|
/** Attempt to perform a row propagation where every variable is a potential candidate.*/ |
626 |
|
bool attemptFull(RowIndex ridx, bool rowUp); |
627 |
|
bool tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUp, const DeltaRational& bound); |
628 |
|
bool rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP bestImplied); |
629 |
|
//void enqueueConstraints(std::vector<ConstraintCP>& out, Node n) const; |
630 |
|
//ConstraintCPVec resolveOutPropagated(const ConstraintCPVec& v, const std::set<ConstraintCP>& propagated) const; |
631 |
|
void resolveOutPropagated(std::vector<ConstraintCPVec>& confs, const std::set<ConstraintCP>& propagated) const; |
632 |
|
void subsumption(std::vector<ConstraintCPVec>& confs) const; |
633 |
|
|
634 |
|
Node cutToLiteral(ApproximateSimplex* approx, const CutInfo& cut) const; |
635 |
|
Node branchToNode(ApproximateSimplex* approx, const NodeLog& cut) const; |
636 |
|
|
637 |
|
void propagateCandidates(); |
638 |
|
void propagateCandidate(ArithVar basic); |
639 |
|
bool propagateCandidateBound(ArithVar basic, bool upperBound); |
640 |
|
|
641 |
1020 |
inline bool propagateCandidateLowerBound(ArithVar basic){ |
642 |
1020 |
return propagateCandidateBound(basic, false); |
643 |
|
} |
644 |
726 |
inline bool propagateCandidateUpperBound(ArithVar basic){ |
645 |
726 |
return propagateCandidateBound(basic, true); |
646 |
|
} |
647 |
|
|
648 |
|
/** |
649 |
|
* Performs a check to see if it is definitely true that setup can be avoided. |
650 |
|
*/ |
651 |
|
bool canSafelyAvoidEqualitySetup(TNode equality); |
652 |
|
|
653 |
|
/** |
654 |
|
* Handles the case splitting for check() for a new assertion. |
655 |
|
* Returns a conflict if one was found. |
656 |
|
* Returns Node::null if no conflict was found. |
657 |
|
* |
658 |
|
* @param assertion The assertion that was just popped from the fact queue |
659 |
|
* of TheoryArith and given to this class via preNotifyFact. |
660 |
|
*/ |
661 |
|
ConstraintP constraintFromFactQueue(TNode assertion); |
662 |
|
bool assertionCases(ConstraintP c); |
663 |
|
|
664 |
|
/** |
665 |
|
* Returns the basic variable with the shorted row containing a non-basic variable. |
666 |
|
* If no such row exists, return ARITHVAR_SENTINEL. |
667 |
|
*/ |
668 |
|
ArithVar findShortestBasicRow(ArithVar variable); |
669 |
|
|
670 |
|
/** |
671 |
|
* Debugging only routine! |
672 |
|
* Returns true iff every variable is consistent in the partial model. |
673 |
|
*/ |
674 |
|
bool entireStateIsConsistent(const std::string& locationHint); |
675 |
|
bool unenqueuedVariablesAreConsistent(); |
676 |
|
|
677 |
|
bool isImpliedUpperBound(ArithVar var, Node exp); |
678 |
|
bool isImpliedLowerBound(ArithVar var, Node exp); |
679 |
|
|
680 |
|
void internalExplain(TNode n, NodeBuilder& explainBuilder); |
681 |
|
|
682 |
|
void asVectors(const Polynomial& p, |
683 |
|
std::vector<Rational>& coeffs, |
684 |
|
std::vector<ArithVar>& variables); |
685 |
|
|
686 |
|
/** Routine for debugging. Print the assertions the theory is aware of. */ |
687 |
|
void debugPrintAssertions(std::ostream& out) const; |
688 |
|
/** Debugging only routine. Prints the model. */ |
689 |
|
void debugPrintModel(std::ostream& out) const; |
690 |
|
|
691 |
164288 |
inline LogicInfo getLogicInfo() const { return d_containing.getLogicInfo(); } |
692 |
1711471 |
inline bool done() const { return d_containing.done(); } |
693 |
|
inline TNode get() { return d_containing.get(); } |
694 |
375809 |
inline bool isLeaf(TNode x) const { return d_containing.isLeaf(x); } |
695 |
466466 |
inline TheoryId theoryOf(TNode x) const { return d_containing.theoryOf(x); } |
696 |
|
inline void debugPrintFacts() const { d_containing.debugPrintFacts(); } |
697 |
3341335 |
inline context::Context* getSatContext() const { return d_containing.getSatContext(); } |
698 |
|
bool outputTrustedLemma(TrustNode lem, InferenceId id); |
699 |
|
bool outputLemma(TNode lem, InferenceId id); |
700 |
|
void outputTrustedConflict(TrustNode conf, InferenceId id); |
701 |
|
void outputConflict(TNode lit, InferenceId id); |
702 |
|
void outputPropagate(TNode lit); |
703 |
|
void outputRestart(); |
704 |
|
|
705 |
|
inline bool isSatLiteral(TNode l) const { |
706 |
|
return (d_containing.d_valuation).isSatLiteral(l); |
707 |
|
} |
708 |
|
inline Node getSatValue(TNode n) const { |
709 |
|
return (d_containing.d_valuation).getSatValue(n); |
710 |
|
} |
711 |
|
|
712 |
|
/** Used for replaying approximate simplex */ |
713 |
|
context::CDQueue<TrustNode> d_approxCuts; |
714 |
|
/** Also used for replaying approximate simplex. "approximate cuts temporary storage" */ |
715 |
|
std::vector<TrustNode> d_acTmp; |
716 |
|
|
717 |
|
/** Counts the number of fullCheck calls to arithmetic. */ |
718 |
|
uint32_t d_fullCheckCounter; |
719 |
|
std::vector<ArithVar> cutAllBounded() const; |
720 |
|
TrustNode branchIntegerVariable(ArithVar x) const; |
721 |
|
void branchVector(const std::vector<ArithVar>& lemmas); |
722 |
|
|
723 |
|
context::CDO<unsigned> d_cutCount; |
724 |
|
context::CDHashSet<ArithVar, std::hash<ArithVar> > d_cutInContext; |
725 |
|
|
726 |
|
context::CDO<bool> d_likelyIntegerInfeasible; |
727 |
|
|
728 |
|
|
729 |
|
context::CDO<bool> d_guessedCoeffSet; |
730 |
|
ArithRatPairVec d_guessedCoeffs; |
731 |
|
|
732 |
|
|
733 |
|
TreeLog* d_treeLog; |
734 |
|
TreeLog& getTreeLog(); |
735 |
|
|
736 |
|
|
737 |
|
ArithVarVec d_replayVariables; |
738 |
|
std::vector<ConstraintP> d_replayConstraints; |
739 |
|
DenseMap<Rational> d_lhsTmp; |
740 |
|
|
741 |
|
/* Approximate simpplex solvers are given a copy of their stats */ |
742 |
|
ApproximateStatistics* d_approxStats; |
743 |
|
ApproximateStatistics& getApproxStats(); |
744 |
|
context::CDO<int32_t> d_attemptSolveIntTurnedOff; |
745 |
|
void turnOffApproxFor(int32_t rounds); |
746 |
|
bool getSolveIntegerResource(); |
747 |
|
|
748 |
|
void tryBranchCut(ApproximateSimplex* approx, int nid, BranchCutInfo& bl); |
749 |
|
std::vector<ConstraintCPVec> replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth); |
750 |
|
|
751 |
|
std::pair<ConstraintP, ArithVar> replayGetConstraint(const CutInfo& info); |
752 |
|
std::pair<ConstraintP, ArithVar> replayGetConstraint( |
753 |
|
ApproximateSimplex* approx, const NodeLog& nl); |
754 |
|
std::pair<ConstraintP, ArithVar> replayGetConstraint(const DenseMap<Rational>& lhs, Kind k, const Rational& rhs, bool branch); |
755 |
|
|
756 |
|
void replayAssert(ConstraintP c); |
757 |
|
|
758 |
|
static ConstraintCP vectorToIntHoleConflict(const ConstraintCPVec& conflict); |
759 |
|
static void intHoleConflictToVector(ConstraintCP conflicting, ConstraintCPVec& conflict); |
760 |
|
|
761 |
|
// Returns true if the node contains a literal |
762 |
|
// that is an arithmetic literal and is not a sat literal |
763 |
|
// No caching is done so this should likely only |
764 |
|
// be called carefully! |
765 |
|
bool hasFreshArithLiteral(Node n) const; |
766 |
|
|
767 |
|
int32_t d_dioSolveResources; |
768 |
|
bool getDioCuttingResource(); |
769 |
|
|
770 |
|
uint32_t d_solveIntMaybeHelp, d_solveIntAttempts; |
771 |
|
|
772 |
|
RationalVector d_farkasBuffer; |
773 |
|
|
774 |
|
//---------------- during check |
775 |
|
/** Whether there were new facts during preCheck */ |
776 |
|
bool d_newFacts; |
777 |
|
/** The previous status, computed during preCheck */ |
778 |
|
Result::Sat d_previousStatus; |
779 |
|
//---------------- end during check |
780 |
|
|
781 |
|
/** These fields are designed to be accessible to TheoryArith methods. */ |
782 |
|
class Statistics { |
783 |
|
public: |
784 |
|
IntStat d_statAssertUpperConflicts, d_statAssertLowerConflicts; |
785 |
|
|
786 |
|
IntStat d_statUserVariables, d_statAuxiliaryVariables; |
787 |
|
IntStat d_statDisequalitySplits; |
788 |
|
IntStat d_statDisequalityConflicts; |
789 |
|
TimerStat d_simplifyTimer; |
790 |
|
TimerStat d_staticLearningTimer; |
791 |
|
|
792 |
|
TimerStat d_presolveTime; |
793 |
|
|
794 |
|
TimerStat d_newPropTime; |
795 |
|
|
796 |
|
IntStat d_externalBranchAndBounds; |
797 |
|
|
798 |
|
IntStat d_initialTableauSize; |
799 |
|
IntStat d_currSetToSmaller; |
800 |
|
IntStat d_smallerSetToCurr; |
801 |
|
TimerStat d_restartTimer; |
802 |
|
|
803 |
|
TimerStat d_boundComputationTime; |
804 |
|
IntStat d_boundComputations, d_boundPropagations; |
805 |
|
|
806 |
|
IntStat d_unknownChecks; |
807 |
|
IntStat d_maxUnknownsInARow; |
808 |
|
AverageStat d_avgUnknownsInARow; |
809 |
|
|
810 |
|
IntStat d_revertsOnConflicts; |
811 |
|
IntStat d_commitsOnConflicts; |
812 |
|
IntStat d_nontrivialSatChecks; |
813 |
|
|
814 |
|
IntStat d_replayLogRecCount, |
815 |
|
d_replayLogRecConflictEscalation, |
816 |
|
d_replayLogRecEarlyExit, |
817 |
|
d_replayBranchCloseFailures, |
818 |
|
d_replayLeafCloseFailures, |
819 |
|
d_replayBranchSkips, |
820 |
|
d_mirCutsAttempted, |
821 |
|
d_gmiCutsAttempted, |
822 |
|
d_branchCutsAttempted, |
823 |
|
d_cutsReconstructed, |
824 |
|
d_cutsReconstructionFailed, |
825 |
|
d_cutsProven, |
826 |
|
d_cutsProofFailed, |
827 |
|
d_mipReplayLemmaCalls, |
828 |
|
d_mipExternalCuts, |
829 |
|
d_mipExternalBranch; |
830 |
|
|
831 |
|
IntStat d_inSolveInteger, |
832 |
|
d_branchesExhausted, |
833 |
|
d_execExhausted, |
834 |
|
d_pivotsExhausted, |
835 |
|
d_panicBranches, |
836 |
|
d_relaxCalls, |
837 |
|
d_relaxLinFeas, |
838 |
|
d_relaxLinFeasFailures, |
839 |
|
d_relaxLinInfeas, |
840 |
|
d_relaxLinInfeasFailures, |
841 |
|
d_relaxLinExhausted, |
842 |
|
d_relaxOthers; |
843 |
|
|
844 |
|
IntStat d_applyRowsDeleted; |
845 |
|
TimerStat d_replaySimplexTimer; |
846 |
|
|
847 |
|
TimerStat d_replayLogTimer, |
848 |
|
d_solveIntTimer, |
849 |
|
d_solveRealRelaxTimer; |
850 |
|
|
851 |
|
IntStat d_solveIntCalls, |
852 |
|
d_solveStandardEffort; |
853 |
|
|
854 |
|
IntStat d_approxDisabled; |
855 |
|
IntStat d_replayAttemptFailed; |
856 |
|
|
857 |
|
IntStat d_cutsRejectedDuringReplay; |
858 |
|
IntStat d_cutsRejectedDuringLemmas; |
859 |
|
|
860 |
|
HistogramStat<uint32_t> d_satPivots; |
861 |
|
HistogramStat<uint32_t> d_unsatPivots; |
862 |
|
HistogramStat<uint32_t> d_unknownPivots; |
863 |
|
|
864 |
|
IntStat d_solveIntModelsAttempts; |
865 |
|
IntStat d_solveIntModelsSuccessful; |
866 |
|
TimerStat d_mipTimer; |
867 |
|
TimerStat d_lpTimer; |
868 |
|
|
869 |
|
IntStat d_mipProofsAttempted; |
870 |
|
IntStat d_mipProofsSuccessful; |
871 |
|
|
872 |
|
IntStat d_numBranchesFailed; |
873 |
|
|
874 |
|
Statistics(const std::string& name); |
875 |
|
}; |
876 |
|
|
877 |
|
|
878 |
|
Statistics d_statistics; |
879 |
|
};/* class TheoryArithPrivate */ |
880 |
|
|
881 |
|
} // namespace arith |
882 |
|
} // namespace theory |
883 |
|
} // namespace cvc5 |