1 /********************* */
2 /*! \file theory_arith_private.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Tim King, Andrew Reynolds, Morgan Deters
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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.\endverbatim
11 **
12 ** \brief [[ Add one-line brief description here ]]
13 **
14 ** [[ Add lengthier description here ]]
15 ** \todo document this file
16 **/
17
18 #include "theory/arith/theory_arith_private.h"
19
20 #include <stdint.h>
21
22 #include <map>
23 #include <queue>
24 #include <vector>
25
26 #include "base/output.h"
27 #include "context/cdhashset.h"
28 #include "context/cdinsert_hashmap.h"
29 #include "context/cdlist.h"
30 #include "context/cdqueue.h"
31 #include "context/context.h"
32 #include "expr/kind.h"
33 #include "expr/metakind.h"
34 #include "expr/node.h"
35 #include "expr/node_algorithm.h"
36 #include "expr/node_builder.h"
37 #include "options/arith_options.h"
38 #include "options/smt_options.h" // for incrementalSolving()
39 #include "preprocessing/util/ite_utilities.h"
40 #include "smt/logic_exception.h"
41 #include "smt/logic_request.h"
42 #include "smt/smt_statistics_registry.h"
43 #include "smt_util/boolean_simplification.h"
44 #include "theory/arith/approx_simplex.h"
45 #include "theory/arith/arith_ite_utils.h"
46 #include "theory/arith/arith_rewriter.h"
47 #include "theory/arith/arith_static_learner.h"
48 #include "theory/arith/arith_utilities.h"
49 #include "theory/arith/arithvar.h"
50 #include "theory/arith/congruence_manager.h"
51 #include "theory/arith/constraint.h"
52 #include "theory/arith/cut_log.h"
53 #include "theory/arith/delta_rational.h"
54 #include "theory/arith/dio_solver.h"
55 #include "theory/arith/linear_equality.h"
56 #include "theory/arith/matrix.h"
57 #include "theory/arith/nonlinear_extension.h"
58 #include "theory/arith/normal_form.h"
59 #include "theory/arith/partial_model.h"
60 #include "theory/arith/simplex.h"
61 #include "theory/arith/theory_arith.h"
62 #include "theory/ext_theory.h"
63 #include "theory/quantifiers/fmf/bounded_integers.h"
64 #include "theory/rewriter.h"
65 #include "theory/theory_model.h"
66 #include "theory/valuation.h"
67 #include "util/dense_map.h"
68 #include "util/integer.h"
69 #include "util/random.h"
70 #include "util/rational.h"
71 #include "util/result.h"
72 #include "util/statistics_registry.h"
73
74 using namespace std;
75 using namespace CVC4::kind;
76
77 namespace CVC4 {
78 namespace theory {
79 namespace arith {
80
81 static Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum);
82 static bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap);
83
TheoryArithPrivate(TheoryArith & containing,context::Context * c,context::UserContext * u,OutputChannel & out,Valuation valuation,const LogicInfo & logicInfo)84 TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing,
85 context::Context* c,
86 context::UserContext* u,
87 OutputChannel& out,
88 Valuation valuation,
89 const LogicInfo& logicInfo)
90 : d_containing(containing),
91 d_nlIncomplete(false),
92 d_rowTracking(),
93 d_constraintDatabase(
94 c, u, d_partialModel, d_congruenceManager, RaiseConflict(*this)),
95 d_qflraStatus(Result::SAT_UNKNOWN),
96 d_unknownsInARow(0),
97 d_hasDoneWorkSinceCut(false),
98 d_learner(u),
99 d_assertionsThatDoNotMatchTheirLiterals(c),
100 d_nextIntegerCheckVar(0),
101 d_constantIntegerVariables(c),
102 d_diseqQueue(c, false),
103 d_currentPropagationList(),
104 d_learnedBounds(c),
105 d_partialModel(c, DeltaComputeCallback(*this)),
106 d_errorSet(
107 d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(*this)),
108 d_tableau(),
109 d_linEq(d_partialModel,
110 d_tableau,
111 d_rowTracking,
112 BasicVarModelUpdateCallBack(*this)),
113 d_diosolver(c),
114 d_restartsCounter(0),
115 d_tableauSizeHasBeenModified(false),
116 d_tableauResetDensity(1.6),
117 d_tableauResetPeriod(10),
118 d_conflicts(c),
119 d_blackBoxConflict(c, Node::null()),
120 d_congruenceManager(c,
121 d_constraintDatabase,
122 SetupLiteralCallBack(*this),
123 d_partialModel,
124 RaiseEqualityEngineConflict(*this)),
125 d_cmEnabled(c, true),
126
127 d_dualSimplex(
128 d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
129 d_fcSimplex(
130 d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
131 d_soiSimplex(
132 d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
133 d_attemptSolSimplex(
134 d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
135 d_nonlinearExtension(NULL),
136 d_pass1SDP(NULL),
137 d_otherSDP(NULL),
138 d_lastContextIntegerAttempted(c, -1),
139
140 d_DELTA_ZERO(0),
141 d_approxCuts(c),
142 d_fullCheckCounter(0),
143 d_cutCount(c, 0),
144 d_cutInContext(c),
145 d_likelyIntegerInfeasible(c, false),
146 d_guessedCoeffSet(c, false),
147 d_guessedCoeffs(),
148 d_treeLog(NULL),
149 d_replayVariables(),
150 d_replayConstraints(),
151 d_lhsTmp(),
152 d_approxStats(NULL),
153 d_attemptSolveIntTurnedOff(u, 0),
154 d_dioSolveResources(0),
155 d_solveIntMaybeHelp(0u),
156 d_solveIntAttempts(0u),
157 d_statistics(),
158 d_to_int_skolem(u),
159 d_div_skolem(u),
160 d_int_div_skolem(u),
161 d_nlin_inverse_skolem(u)
162 {
163 if( options::nlExt() ){
164 d_nonlinearExtension = new NonlinearExtension(
165 containing, d_congruenceManager.getEqualityEngine());
166 }
167 }
168
~TheoryArithPrivate()169 TheoryArithPrivate::~TheoryArithPrivate(){
170 if(d_treeLog != NULL){ delete d_treeLog; }
171 if(d_approxStats != NULL) { delete d_approxStats; }
172 if(d_nonlinearExtension != NULL) { delete d_nonlinearExtension; }
173 }
174
contains(const ConstraintCPVec & v,ConstraintP con)175 static bool contains(const ConstraintCPVec& v, ConstraintP con){
176 for(unsigned i = 0, N = v.size(); i < N; ++i){
177 if(v[i] == con){
178 return true;
179 }
180 }
181 return false;
182 }
drop(ConstraintCPVec & v,ConstraintP con)183 static void drop( ConstraintCPVec& v, ConstraintP con){
184 size_t readPos, writePos, N;
185 for(readPos = 0, writePos = 0, N = v.size(); readPos < N; ++readPos){
186 ConstraintCP curr = v[readPos];
187 if(curr != con){
188 v[writePos] = curr;
189 writePos++;
190 }
191 }
192 v.resize(writePos);
193 }
194
195
resolve(ConstraintCPVec & buf,ConstraintP c,const ConstraintCPVec & pos,const ConstraintCPVec & neg)196 static void resolve(ConstraintCPVec& buf, ConstraintP c, const ConstraintCPVec& pos, const ConstraintCPVec& neg){
197 unsigned posPos CVC4_UNUSED = pos.size();
198 for(unsigned i = 0, N = pos.size(); i < N; ++i){
199 if(pos[i] == c){
200 posPos = i;
201 }else{
202 buf.push_back(pos[i]);
203 }
204 }
205 Assert(posPos < pos.size());
206 ConstraintP negc = c->getNegation();
207 unsigned negPos CVC4_UNUSED = neg.size();
208 for(unsigned i = 0, N = neg.size(); i < N; ++i){
209 if(neg[i] == negc){
210 negPos = i;
211 }else{
212 buf.push_back(neg[i]);
213 }
214 }
215 Assert(negPos < neg.size());
216
217 // Assert(dnconf.getKind() == kind::AND);
218 // Assert(upconf.getKind() == kind::AND);
219 // Assert(dnpos < dnconf.getNumChildren());
220 // Assert(uppos < upconf.getNumChildren());
221 // Assert(equalUpToNegation(dnconf[dnpos], upconf[uppos]));
222
223 // NodeBuilder<> nb(kind::AND);
224 // dropPosition(nb, dnconf, dnpos);
225 // dropPosition(nb, upconf, uppos);
226 // return safeConstructNary(nb);
227 }
228
229 // Integer division axioms:
230 // These concenrate the high level constructs needed to constrain the functions:
231 // div, mod, div_total and mod_total.
232 //
233 // The high level constraint.
234 // (for all ((m Int) (n Int))
235 // (=> (distinct n 0)
236 // (let ((q (div m n)) (r (mod m n)))
237 // (and (= m (+ (* n q) r))
238 // (<= 0 r (- (abs n) 1))))))
239 //
240 // We now add division by 0 functions.
241 // (for all ((m Int) (n Int))
242 // (let ((q (div m n)) (r (mod m n)))
243 // (ite (= n 0)
244 // (and (= q (div_0_func m)) (= r (mod_0_func m)))
245 // (and (= m (+ (* n q) r))
246 // (<= 0 r (- (abs n) 1)))))))
247 //
248 // We now express div and mod in terms of div_total and mod_total.
249 // (for all ((m Int) (n Int))
250 // (let ((q (div m n)) (r (mod m n)))
251 // (ite (= n 0)
252 // (and (= q (div_0_func m)) (= r (mod_0_func m)))
253 // (and (= q (div_total m n)) (= r (mod_total m n))))))
254 //
255 // Alternative div_total and mod_total without the abs function:
256 // (for all ((m Int) (n Int))
257 // (let ((q (div_total m n)) (r (mod_total m n)))
258 // (ite (= n 0)
259 // (and (= q 0) (= r 0))
260 // (and (r = m - n * q)
261 // (ite (> n 0)
262 // (n*q <= m < n*q + n)
263 // (n*q <= m < n*q - n))))))
264
265
266 // Returns a formula that entails that q equals the total integer division of m
267 // by n.
268 // (for all ((m Int) (n Int))
269 // (let ((q (div_total m n)))
270 // (ite (= n 0)
271 // (= q 0)
272 // (ite (> n 0)
273 // (n*q <= m < n*q + n)
274 // (n*q <= m < n*q - n)))))
mkAxiomForTotalIntDivision(Node m,Node n,Node q)275 Node mkAxiomForTotalIntDivision(Node m, Node n, Node q) {
276 NodeManager* nm = NodeManager::currentNM();
277 Node zero = mkRationalNode(0);
278 // (n*q <= m < n*q + n) is equivalent to (0 <= m - n*q < n).
279 Node diff = nm->mkNode(kind::MINUS, m, mkMult(n, q));
280 Node when_n_is_positive = mkInRange(diff, zero, n);
281 Node when_n_is_negative = mkInRange(diff, zero, nm->mkNode(kind::UMINUS, n));
282 return n.eqNode(zero).iteNode(
283 q.eqNode(zero), nm->mkNode(kind::GT, n, zero)
284 .iteNode(when_n_is_positive, when_n_is_negative));
285 }
286
287 // Returns a formula that entails that r equals the integer division total of m
288 // by n assuming q is equal to (div_total m n).
289 // (for all ((m Int) (n Int))
290 // (let ((q (div_total m n)) (r (mod_total m n)))
291 // (ite (= n 0)
292 // (= r 0)
293 // (= r (- m (n * q))))))
mkAxiomForTotalIntMod(Node m,Node n,Node q,Node r)294 Node mkAxiomForTotalIntMod(Node m, Node n, Node q, Node r) {
295 NodeManager* nm = NodeManager::currentNM();
296 Node diff = nm->mkNode(kind::MINUS, m, mkMult(n, q));
297 return mkOnZeroIte(n, r, mkRationalNode(0), diff);
298 }
299
300 // Returns an expression that constrains a term to be the result of the
301 // [total] integer division of num by den. Equivalently:
302 // (and (=> (den > 0) (den*term <= num < den*term + den))
303 // (=> (den < 0) (den*term <= num < den*term - den))
304 // (=> (den = 0) (term = 0)))
305 // static Node mkIntegerDivisionConstraint(Node term, Node num, Node den) {
306 // // We actually encode:
307 // // (and (=> (den > 0) (0 <= num - den*term < den))
308 // // (=> (den < 0) (0 <= num - den*term < -den))
309 // // (=> (den = 0) (term = 0)))
310 // NodeManager* nm = NodeManager::currentNM();
311 // Node zero = nm->mkConst(Rational(0));
312 // Node den_is_positive = nm->mkNode(kind::GT, den, zero);
313 // Node den_is_negative = nm->mkNode(kind::LT, den, zero);
314 // Node diff = nm->mkNode(kind::MINUS, num, mkMult(den, term));
315 // Node when_den_positive = den_positive.impNode(mkInRange(diff, zero, den));
316 // Node when_den_negative = den_negative.impNode(
317 // mkInRange(diff, zero, nm->mkNode(kind::UMINUS, den)));
318 // Node when_den_is_zero = (den.eqNode(zero)).impNode(term.eqNode(zero));
319 // return mk->mkNode(kind::AND, when_den_positive, when_den_negative,
320 // when_den_is_zero);
321 // }
322
setMasterEqualityEngine(eq::EqualityEngine * eq)323 void TheoryArithPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq) {
324 d_congruenceManager.setMasterEqualityEngine(eq);
325 }
326
ModelException(TNode n,const char * msg)327 TheoryArithPrivate::ModelException::ModelException(TNode n, const char* msg)
328 {
329 stringstream ss;
330 ss << "Cannot construct a model for " << n << " as " << endl << msg;
331 setMessage(ss.str());
332 }
~ModelException()333 TheoryArithPrivate::ModelException::~ModelException() {}
334
Statistics()335 TheoryArithPrivate::Statistics::Statistics()
336 : d_statAssertUpperConflicts("theory::arith::AssertUpperConflicts", 0)
337 , d_statAssertLowerConflicts("theory::arith::AssertLowerConflicts", 0)
338 , d_statUserVariables("theory::arith::UserVariables", 0)
339 , d_statAuxiliaryVariables("theory::arith::AuxiliaryVariables", 0)
340 , d_statDisequalitySplits("theory::arith::DisequalitySplits", 0)
341 , d_statDisequalityConflicts("theory::arith::DisequalityConflicts", 0)
342 , d_simplifyTimer("theory::arith::simplifyTimer")
343 , d_staticLearningTimer("theory::arith::staticLearningTimer")
344 , d_presolveTime("theory::arith::presolveTime")
345 , d_newPropTime("theory::arith::newPropTimer")
346 , d_externalBranchAndBounds("theory::arith::externalBranchAndBounds",0)
347 , d_initialTableauSize("theory::arith::initialTableauSize", 0)
348 , d_currSetToSmaller("theory::arith::currSetToSmaller", 0)
349 , d_smallerSetToCurr("theory::arith::smallerSetToCurr", 0)
350 , d_restartTimer("theory::arith::restartTimer")
351 , d_boundComputationTime("theory::arith::bound::time")
352 , d_boundComputations("theory::arith::bound::boundComputations",0)
353 , d_boundPropagations("theory::arith::bound::boundPropagations",0)
354 , d_unknownChecks("theory::arith::status::unknowns", 0)
355 , d_maxUnknownsInARow("theory::arith::status::maxUnknownsInARow", 0)
356 , d_avgUnknownsInARow("theory::arith::status::avgUnknownsInARow")
357 , d_revertsOnConflicts("theory::arith::status::revertsOnConflicts",0)
358 , d_commitsOnConflicts("theory::arith::status::commitsOnConflicts",0)
359 , d_nontrivialSatChecks("theory::arith::status::nontrivialSatChecks",0)
360 , d_replayLogRecCount("theory::arith::z::approx::replay::rec",0)
361 , d_replayLogRecConflictEscalation("theory::arith::z::approx::replay::rec::escalation",0)
362 , d_replayLogRecEarlyExit("theory::arith::z::approx::replay::rec::earlyexit",0)
363 , d_replayBranchCloseFailures("theory::arith::z::approx::replay::rec::branch::closefailures",0)
364 , d_replayLeafCloseFailures("theory::arith::z::approx::replay::rec::leaf::closefailures",0)
365 , d_replayBranchSkips("theory::arith::z::approx::replay::rec::branch::skips",0)
366 , d_mirCutsAttempted("theory::arith::z::approx::cuts::mir::attempted",0)
367 , d_gmiCutsAttempted("theory::arith::z::approx::cuts::gmi::attempted",0)
368 , d_branchCutsAttempted("theory::arith::z::approx::cuts::branch::attempted",0)
369 , d_cutsReconstructed("theory::arith::z::approx::cuts::reconstructed",0)
370 , d_cutsReconstructionFailed("theory::arith::z::approx::cuts::reconstructed::failed",0)
371 , d_cutsProven("theory::arith::z::approx::cuts::proofs",0)
372 , d_cutsProofFailed("theory::arith::z::approx::cuts::proofs::failed",0)
373 , d_mipReplayLemmaCalls("theory::arith::z::approx::external::calls",0)
374 , d_mipExternalCuts("theory::arith::z::approx::external::cuts",0)
375 , d_mipExternalBranch("theory::arith::z::approx::external::branches",0)
376 , d_inSolveInteger("theory::arith::z::approx::inSolverInteger",0)
377 , d_branchesExhausted("theory::arith::z::approx::exhausted::branches",0)
378 , d_execExhausted("theory::arith::z::approx::exhausted::exec",0)
379 , d_pivotsExhausted("theory::arith::z::approx::exhausted::pivots",0)
380 , d_panicBranches("theory::arith::z::arith::paniclemmas",0)
381 , d_relaxCalls("theory::arith::z::arith::relax::calls",0)
382 , d_relaxLinFeas("theory::arith::z::arith::relax::feasible::res",0)
383 , d_relaxLinFeasFailures("theory::arith::z::arith::relax::feasible::failures",0)
384 , d_relaxLinInfeas("theory::arith::z::arith::relax::infeasible",0)
385 , d_relaxLinInfeasFailures("theory::arith::z::arith::relax::infeasible::failures",0)
386 , d_relaxLinExhausted("theory::arith::z::arith::relax::exhausted",0)
387 , d_relaxOthers("theory::arith::z::arith::relax::other",0)
388 , d_applyRowsDeleted("theory::arith::z::arith::cuts::applyRowsDeleted",0)
389 , d_replaySimplexTimer("theory::arith::z::approx::replay::simplex::timer")
390 , d_replayLogTimer("theory::arith::z::approx::replay::log::timer")
391 , d_solveIntTimer("theory::arith::z::solveInt::timer")
392 , d_solveRealRelaxTimer("theory::arith::z::solveRealRelax::timer")
393 , d_solveIntCalls("theory::arith::z::solveInt::calls", 0)
394 , d_solveStandardEffort("theory::arith::z::solveInt::calls::standardEffort", 0)
395 , d_approxDisabled("theory::arith::z::approxDisabled", 0)
396 , d_replayAttemptFailed("theory::arith::z::replayAttemptFailed",0)
397 , d_cutsRejectedDuringReplay("theory::arith::z::approx::replay::cuts::rejected", 0)
398 , d_cutsRejectedDuringLemmas("theory::arith::z::approx::external::cuts::rejected", 0)
399 , d_satPivots("theory::arith::pivots::sat")
400 , d_unsatPivots("theory::arith::pivots::unsat")
401 , d_unknownPivots("theory::arith::pivots::unknown")
402 , d_solveIntModelsAttempts("theory::arith::z::solveInt::models::attempts", 0)
403 , d_solveIntModelsSuccessful("theory::arith::zzz::solveInt::models::successful", 0)
404 , d_mipTimer("theory::arith::z::approx::mip::timer")
405 , d_lpTimer("theory::arith::z::approx::lp::timer")
406 , d_mipProofsAttempted("theory::arith::z::mip::proofs::attempted", 0)
407 , d_mipProofsSuccessful("theory::arith::z::mip::proofs::successful", 0)
408 , d_numBranchesFailed("theory::arith::z::mip::branch::proof::failed", 0)
409 {
410 smtStatisticsRegistry()->registerStat(&d_statAssertUpperConflicts);
411 smtStatisticsRegistry()->registerStat(&d_statAssertLowerConflicts);
412
413 smtStatisticsRegistry()->registerStat(&d_statUserVariables);
414 smtStatisticsRegistry()->registerStat(&d_statAuxiliaryVariables);
415 smtStatisticsRegistry()->registerStat(&d_statDisequalitySplits);
416 smtStatisticsRegistry()->registerStat(&d_statDisequalityConflicts);
417 smtStatisticsRegistry()->registerStat(&d_simplifyTimer);
418 smtStatisticsRegistry()->registerStat(&d_staticLearningTimer);
419
420 smtStatisticsRegistry()->registerStat(&d_presolveTime);
421 smtStatisticsRegistry()->registerStat(&d_newPropTime);
422
423 smtStatisticsRegistry()->registerStat(&d_externalBranchAndBounds);
424
425 smtStatisticsRegistry()->registerStat(&d_initialTableauSize);
426 smtStatisticsRegistry()->registerStat(&d_currSetToSmaller);
427 smtStatisticsRegistry()->registerStat(&d_smallerSetToCurr);
428 smtStatisticsRegistry()->registerStat(&d_restartTimer);
429
430 smtStatisticsRegistry()->registerStat(&d_boundComputationTime);
431 smtStatisticsRegistry()->registerStat(&d_boundComputations);
432 smtStatisticsRegistry()->registerStat(&d_boundPropagations);
433
434 smtStatisticsRegistry()->registerStat(&d_unknownChecks);
435 smtStatisticsRegistry()->registerStat(&d_maxUnknownsInARow);
436 smtStatisticsRegistry()->registerStat(&d_avgUnknownsInARow);
437 smtStatisticsRegistry()->registerStat(&d_revertsOnConflicts);
438 smtStatisticsRegistry()->registerStat(&d_commitsOnConflicts);
439 smtStatisticsRegistry()->registerStat(&d_nontrivialSatChecks);
440
441
442 smtStatisticsRegistry()->registerStat(&d_satPivots);
443 smtStatisticsRegistry()->registerStat(&d_unsatPivots);
444 smtStatisticsRegistry()->registerStat(&d_unknownPivots);
445
446 smtStatisticsRegistry()->registerStat(&d_replayLogRecCount);
447 smtStatisticsRegistry()->registerStat(&d_replayLogRecConflictEscalation);
448 smtStatisticsRegistry()->registerStat(&d_replayLogRecEarlyExit);
449 smtStatisticsRegistry()->registerStat(&d_replayBranchCloseFailures);
450 smtStatisticsRegistry()->registerStat(&d_replayLeafCloseFailures);
451 smtStatisticsRegistry()->registerStat(&d_replayBranchSkips);
452 smtStatisticsRegistry()->registerStat(&d_mirCutsAttempted);
453 smtStatisticsRegistry()->registerStat(&d_gmiCutsAttempted);
454 smtStatisticsRegistry()->registerStat(&d_branchCutsAttempted);
455 smtStatisticsRegistry()->registerStat(&d_cutsReconstructed);
456 smtStatisticsRegistry()->registerStat(&d_cutsProven);
457 smtStatisticsRegistry()->registerStat(&d_cutsProofFailed);
458 smtStatisticsRegistry()->registerStat(&d_cutsReconstructionFailed);
459 smtStatisticsRegistry()->registerStat(&d_mipReplayLemmaCalls);
460 smtStatisticsRegistry()->registerStat(&d_mipExternalCuts);
461 smtStatisticsRegistry()->registerStat(&d_mipExternalBranch);
462
463 smtStatisticsRegistry()->registerStat(&d_inSolveInteger);
464 smtStatisticsRegistry()->registerStat(&d_branchesExhausted);
465 smtStatisticsRegistry()->registerStat(&d_execExhausted);
466 smtStatisticsRegistry()->registerStat(&d_pivotsExhausted);
467 smtStatisticsRegistry()->registerStat(&d_panicBranches);
468 smtStatisticsRegistry()->registerStat(&d_relaxCalls);
469 smtStatisticsRegistry()->registerStat(&d_relaxLinFeas);
470 smtStatisticsRegistry()->registerStat(&d_relaxLinFeasFailures);
471 smtStatisticsRegistry()->registerStat(&d_relaxLinInfeas);
472 smtStatisticsRegistry()->registerStat(&d_relaxLinInfeasFailures);
473 smtStatisticsRegistry()->registerStat(&d_relaxLinExhausted);
474 smtStatisticsRegistry()->registerStat(&d_relaxOthers);
475
476 smtStatisticsRegistry()->registerStat(&d_applyRowsDeleted);
477
478 smtStatisticsRegistry()->registerStat(&d_replaySimplexTimer);
479 smtStatisticsRegistry()->registerStat(&d_replayLogTimer);
480 smtStatisticsRegistry()->registerStat(&d_solveIntTimer);
481 smtStatisticsRegistry()->registerStat(&d_solveRealRelaxTimer);
482
483 smtStatisticsRegistry()->registerStat(&d_solveIntCalls);
484 smtStatisticsRegistry()->registerStat(&d_solveStandardEffort);
485
486 smtStatisticsRegistry()->registerStat(&d_approxDisabled);
487
488 smtStatisticsRegistry()->registerStat(&d_replayAttemptFailed);
489
490 smtStatisticsRegistry()->registerStat(&d_cutsRejectedDuringReplay);
491 smtStatisticsRegistry()->registerStat(&d_cutsRejectedDuringLemmas);
492
493 smtStatisticsRegistry()->registerStat(&d_solveIntModelsAttempts);
494 smtStatisticsRegistry()->registerStat(&d_solveIntModelsSuccessful);
495 smtStatisticsRegistry()->registerStat(&d_mipTimer);
496 smtStatisticsRegistry()->registerStat(&d_lpTimer);
497 smtStatisticsRegistry()->registerStat(&d_mipProofsAttempted);
498 smtStatisticsRegistry()->registerStat(&d_mipProofsSuccessful);
499 smtStatisticsRegistry()->registerStat(&d_numBranchesFailed);
500 }
501
~Statistics()502 TheoryArithPrivate::Statistics::~Statistics(){
503 smtStatisticsRegistry()->unregisterStat(&d_statAssertUpperConflicts);
504 smtStatisticsRegistry()->unregisterStat(&d_statAssertLowerConflicts);
505
506 smtStatisticsRegistry()->unregisterStat(&d_statUserVariables);
507 smtStatisticsRegistry()->unregisterStat(&d_statAuxiliaryVariables);
508 smtStatisticsRegistry()->unregisterStat(&d_statDisequalitySplits);
509 smtStatisticsRegistry()->unregisterStat(&d_statDisequalityConflicts);
510 smtStatisticsRegistry()->unregisterStat(&d_simplifyTimer);
511 smtStatisticsRegistry()->unregisterStat(&d_staticLearningTimer);
512
513 smtStatisticsRegistry()->unregisterStat(&d_presolveTime);
514 smtStatisticsRegistry()->unregisterStat(&d_newPropTime);
515
516 smtStatisticsRegistry()->unregisterStat(&d_externalBranchAndBounds);
517
518 smtStatisticsRegistry()->unregisterStat(&d_initialTableauSize);
519 smtStatisticsRegistry()->unregisterStat(&d_currSetToSmaller);
520 smtStatisticsRegistry()->unregisterStat(&d_smallerSetToCurr);
521 smtStatisticsRegistry()->unregisterStat(&d_restartTimer);
522
523 smtStatisticsRegistry()->unregisterStat(&d_boundComputationTime);
524 smtStatisticsRegistry()->unregisterStat(&d_boundComputations);
525 smtStatisticsRegistry()->unregisterStat(&d_boundPropagations);
526
527 smtStatisticsRegistry()->unregisterStat(&d_unknownChecks);
528 smtStatisticsRegistry()->unregisterStat(&d_maxUnknownsInARow);
529 smtStatisticsRegistry()->unregisterStat(&d_avgUnknownsInARow);
530 smtStatisticsRegistry()->unregisterStat(&d_revertsOnConflicts);
531 smtStatisticsRegistry()->unregisterStat(&d_commitsOnConflicts);
532 smtStatisticsRegistry()->unregisterStat(&d_nontrivialSatChecks);
533
534 smtStatisticsRegistry()->unregisterStat(&d_satPivots);
535 smtStatisticsRegistry()->unregisterStat(&d_unsatPivots);
536 smtStatisticsRegistry()->unregisterStat(&d_unknownPivots);
537
538 smtStatisticsRegistry()->unregisterStat(&d_replayLogRecCount);
539 smtStatisticsRegistry()->unregisterStat(&d_replayLogRecConflictEscalation);
540 smtStatisticsRegistry()->unregisterStat(&d_replayLogRecEarlyExit);
541 smtStatisticsRegistry()->unregisterStat(&d_replayBranchCloseFailures);
542 smtStatisticsRegistry()->unregisterStat(&d_replayLeafCloseFailures);
543 smtStatisticsRegistry()->unregisterStat(&d_replayBranchSkips);
544 smtStatisticsRegistry()->unregisterStat(&d_mirCutsAttempted);
545 smtStatisticsRegistry()->unregisterStat(&d_gmiCutsAttempted);
546 smtStatisticsRegistry()->unregisterStat(&d_branchCutsAttempted);
547 smtStatisticsRegistry()->unregisterStat(&d_cutsReconstructed);
548 smtStatisticsRegistry()->unregisterStat(&d_cutsProven);
549 smtStatisticsRegistry()->unregisterStat(&d_cutsProofFailed);
550 smtStatisticsRegistry()->unregisterStat(&d_cutsReconstructionFailed);
551 smtStatisticsRegistry()->unregisterStat(&d_mipReplayLemmaCalls);
552 smtStatisticsRegistry()->unregisterStat(&d_mipExternalCuts);
553 smtStatisticsRegistry()->unregisterStat(&d_mipExternalBranch);
554
555
556 smtStatisticsRegistry()->unregisterStat(&d_inSolveInteger);
557 smtStatisticsRegistry()->unregisterStat(&d_branchesExhausted);
558 smtStatisticsRegistry()->unregisterStat(&d_execExhausted);
559 smtStatisticsRegistry()->unregisterStat(&d_pivotsExhausted);
560 smtStatisticsRegistry()->unregisterStat(&d_panicBranches);
561 smtStatisticsRegistry()->unregisterStat(&d_relaxCalls);
562 smtStatisticsRegistry()->unregisterStat(&d_relaxLinFeas);
563 smtStatisticsRegistry()->unregisterStat(&d_relaxLinFeasFailures);
564 smtStatisticsRegistry()->unregisterStat(&d_relaxLinInfeas);
565 smtStatisticsRegistry()->unregisterStat(&d_relaxLinInfeasFailures);
566 smtStatisticsRegistry()->unregisterStat(&d_relaxLinExhausted);
567 smtStatisticsRegistry()->unregisterStat(&d_relaxOthers);
568
569 smtStatisticsRegistry()->unregisterStat(&d_applyRowsDeleted);
570
571 smtStatisticsRegistry()->unregisterStat(&d_replaySimplexTimer);
572 smtStatisticsRegistry()->unregisterStat(&d_replayLogTimer);
573 smtStatisticsRegistry()->unregisterStat(&d_solveIntTimer);
574 smtStatisticsRegistry()->unregisterStat(&d_solveRealRelaxTimer);
575
576 smtStatisticsRegistry()->unregisterStat(&d_solveIntCalls);
577 smtStatisticsRegistry()->unregisterStat(&d_solveStandardEffort);
578
579 smtStatisticsRegistry()->unregisterStat(&d_approxDisabled);
580
581 smtStatisticsRegistry()->unregisterStat(&d_replayAttemptFailed);
582
583 smtStatisticsRegistry()->unregisterStat(&d_cutsRejectedDuringReplay);
584 smtStatisticsRegistry()->unregisterStat(&d_cutsRejectedDuringLemmas);
585
586
587 smtStatisticsRegistry()->unregisterStat(&d_solveIntModelsAttempts);
588 smtStatisticsRegistry()->unregisterStat(&d_solveIntModelsSuccessful);
589 smtStatisticsRegistry()->unregisterStat(&d_mipTimer);
590 smtStatisticsRegistry()->unregisterStat(&d_lpTimer);
591 smtStatisticsRegistry()->unregisterStat(&d_mipProofsAttempted);
592 smtStatisticsRegistry()->unregisterStat(&d_mipProofsSuccessful);
593 smtStatisticsRegistry()->unregisterStat(&d_numBranchesFailed);
594 }
595
complexityBelow(const DenseMap<Rational> & row,uint32_t cap)596 bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap){
597 DenseMap<Rational>::const_iterator riter, rend;
598 for(riter=row.begin(), rend=row.end(); riter != rend; ++riter){
599 ArithVar v = *riter;
600 const Rational& q = row[v];
601 if(q.complexity() > cap){
602 return false;
603 }
604 }
605 return true;
606 }
607
raiseConflict(ConstraintCP a)608 void TheoryArithPrivate::raiseConflict(ConstraintCP a){
609 Assert(a->inConflict());
610 d_conflicts.push_back(a);
611 }
612
raiseBlackBoxConflict(Node bb)613 void TheoryArithPrivate::raiseBlackBoxConflict(Node bb){
614 if(d_blackBoxConflict.get().isNull()){
615 d_blackBoxConflict = bb;
616 }
617 }
618
revertOutOfConflict()619 void TheoryArithPrivate::revertOutOfConflict(){
620 d_partialModel.revertAssignmentChanges();
621 clearUpdates();
622 d_currentPropagationList.clear();
623 }
624
clearUpdates()625 void TheoryArithPrivate::clearUpdates(){
626 d_updatedBounds.purge();
627 }
628
629 // void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b){
630 // ConstraintCPVec v;
631 // v.push_back(a);
632 // v.push_back(b);
633 // d_conflicts.push_back(v);
634 // }
635
636 // void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c){
637 // ConstraintCPVec v;
638 // v.push_back(a);
639 // v.push_back(b);
640 // v.push_back(c);
641 // d_conflicts.push_back(v);
642 // }
643
zeroDifferenceDetected(ArithVar x)644 void TheoryArithPrivate::zeroDifferenceDetected(ArithVar x){
645 if(d_cmEnabled){
646 Assert(d_congruenceManager.isWatchedVariable(x));
647 Assert(d_partialModel.upperBoundIsZero(x));
648 Assert(d_partialModel.lowerBoundIsZero(x));
649
650 ConstraintP lb = d_partialModel.getLowerBoundConstraint(x);
651 ConstraintP ub = d_partialModel.getUpperBoundConstraint(x);
652
653 if(lb->isEquality()){
654 d_congruenceManager.watchedVariableIsZero(lb);
655 }else if(ub->isEquality()){
656 d_congruenceManager.watchedVariableIsZero(ub);
657 }else{
658 d_congruenceManager.watchedVariableIsZero(lb, ub);
659 }
660 }
661 }
662
getSolveIntegerResource()663 bool TheoryArithPrivate::getSolveIntegerResource(){
664 if(d_attemptSolveIntTurnedOff > 0){
665 d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff - 1;
666 return false;
667 }else{
668 return true;
669 }
670 }
671
getDioCuttingResource()672 bool TheoryArithPrivate::getDioCuttingResource(){
673 if(d_dioSolveResources > 0){
674 d_dioSolveResources--;
675 if(d_dioSolveResources == 0){
676 d_dioSolveResources = -options::rrTurns();
677 }
678 return true;
679 }else{
680 d_dioSolveResources++;
681 if(d_dioSolveResources >= 0){
682 d_dioSolveResources = options::dioSolverTurns();
683 }
684 return false;
685 }
686 }
687
688 /* procedure AssertLower( x_i >= c_i ) */
AssertLower(ConstraintP constraint)689 bool TheoryArithPrivate::AssertLower(ConstraintP constraint){
690 Assert(constraint != NullConstraint);
691 Assert(constraint->isLowerBound());
692 Assert(constraint->isTrue());
693 Assert(!constraint->negationHasProof());
694
695
696 ArithVar x_i = constraint->getVariable();
697 const DeltaRational& c_i = constraint->getValue();
698
699 Debug("arith") << "AssertLower(" << x_i << " " << c_i << ")"<< std::endl;
700
701 Assert(!isInteger(x_i) || c_i.isIntegral());
702
703 //TODO Relax to less than?
704 if(d_partialModel.lessThanLowerBound(x_i, c_i)){
705 return false; //sat
706 }
707
708 int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i);
709 if(cmpToUB > 0){ // c_i < \lowerbound(x_i)
710 ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i);
711 ConstraintP negation = constraint->getNegation();
712 negation->impliedByUnate(ubc, true);
713
714 raiseConflict(constraint);
715
716 ++(d_statistics.d_statAssertLowerConflicts);
717 return true;
718 }else if(cmpToUB == 0){
719 if(isInteger(x_i)){
720 d_constantIntegerVariables.push_back(x_i);
721 Debug("dio::push") << "dio::push " << x_i << endl;
722 }
723 ConstraintP ub = d_partialModel.getUpperBoundConstraint(x_i);
724
725 if(d_cmEnabled){
726 if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
727 // if it is not a watched variable report it
728 // if it is is a watched variable and c_i == 0,
729 // let zeroDifferenceDetected(x_i) catch this
730 d_congruenceManager.equalsConstant(constraint, ub);
731 }
732 }
733
734 const ValueCollection& vc = constraint->getValueCollection();
735 if(vc.hasEquality()){
736
737 Assert(vc.hasDisequality());
738 ConstraintP eq = vc.getEquality();
739 ConstraintP diseq = vc.getDisequality();
740 // x <= b, x >= b |= x = b
741 // (x > b or x < b or x = b)
742 Debug("arith::eq") << "lb == ub, propagate eq" << eq << endl;
743 bool triConflict = diseq->isTrue();
744
745 if(!eq->isTrue()){
746 eq->impliedByTrichotomy(constraint, ub, triConflict);
747 eq->tryToPropagate();
748 }
749 if(triConflict){
750 ++(d_statistics.d_statDisequalityConflicts);
751 raiseConflict(eq);
752 return true;
753 }
754 }
755 }else{
756 // l <= x <= u and l < u
757 Assert(cmpToUB < 0);
758 const ValueCollection& vc = constraint->getValueCollection();
759
760 if(vc.hasDisequality()){
761 const ConstraintP diseq = vc.getDisequality();
762 if(diseq->isTrue()){
763 const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
764 ConstraintP negUb = ub->getNegation();
765
766 // l <= x, l != x |= l < x
767 // |= not (l >= x)
768 bool ubInConflict = ub->hasProof();
769 bool learnNegUb = !(negUb->hasProof());
770 if(learnNegUb){
771 negUb->impliedByTrichotomy(constraint, diseq, ubInConflict);
772 negUb->tryToPropagate();
773 }
774 if(ubInConflict){
775 raiseConflict(ub);
776 return true;
777 }else if(learnNegUb){
778 d_learnedBounds.push_back(negUb);
779 }
780 }
781 }
782 }
783
784 d_currentPropagationList.push_back(constraint);
785 d_currentPropagationList.push_back(d_partialModel.getLowerBoundConstraint(x_i));
786
787 d_partialModel.setLowerBoundConstraint(constraint);
788
789 if(d_cmEnabled){
790 if(d_congruenceManager.isWatchedVariable(x_i)){
791 int sgn = c_i.sgn();
792 if(sgn > 0){
793 d_congruenceManager.watchedVariableCannotBeZero(constraint);
794 }else if(sgn == 0 && d_partialModel.upperBoundIsZero(x_i)){
795 zeroDifferenceDetected(x_i);
796 }
797 }
798 }
799
800 d_updatedBounds.softAdd(x_i);
801
802 if(Debug.isOn("model")) {
803 Debug("model") << "before" << endl;
804 d_partialModel.printModel(x_i);
805 d_tableau.debugPrintIsBasic(x_i);
806 }
807
808 if(!d_tableau.isBasic(x_i)){
809 if(d_partialModel.getAssignment(x_i) < c_i){
810 d_linEq.update(x_i, c_i);
811 }
812 }else{
813 d_errorSet.signalVariable(x_i);
814 }
815
816 if(Debug.isOn("model")) {
817 Debug("model") << "after" << endl;
818 d_partialModel.printModel(x_i);
819 d_tableau.debugPrintIsBasic(x_i);
820 }
821
822 return false; //sat
823 }
824
825 /* procedure AssertUpper( x_i <= c_i) */
AssertUpper(ConstraintP constraint)826 bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){
827 Assert(constraint != NullConstraint);
828 Assert(constraint->isUpperBound());
829 Assert(constraint->isTrue());
830 Assert(!constraint->negationHasProof());
831
832 ArithVar x_i = constraint->getVariable();
833 const DeltaRational& c_i = constraint->getValue();
834
835 Debug("arith") << "AssertUpper(" << x_i << " " << c_i << ")"<< std::endl;
836
837
838 //Too strong because of rounding with integers
839 //Assert(!constraint->hasLiteral() || original == constraint->getLiteral());
840 Assert(!isInteger(x_i) || c_i.isIntegral());
841
842 Debug("arith") << "AssertUpper(" << x_i << " " << c_i << ")"<< std::endl;
843
844 if(d_partialModel.greaterThanUpperBound(x_i, c_i) ){ // \upperbound(x_i) <= c_i
845 return false; //sat
846 }
847
848 // cmpToLb = \lowerbound(x_i).cmp(c_i)
849 int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i);
850 if( cmpToLB < 0 ){ // \upperbound(x_i) < \lowerbound(x_i)
851 // l_i <= x_i and c_i < l_i |= c_i < x_i
852 // or ... |= not (x_i <= c_i)
853 ConstraintP lbc = d_partialModel.getLowerBoundConstraint(x_i);
854 ConstraintP negConstraint = constraint->getNegation();
855 negConstraint->impliedByUnate(lbc, true);
856 raiseConflict(constraint);
857 ++(d_statistics.d_statAssertUpperConflicts);
858 return true;
859 }else if(cmpToLB == 0){ // \lowerBound(x_i) == \upperbound(x_i)
860 if(isInteger(x_i)){
861 d_constantIntegerVariables.push_back(x_i);
862 Debug("dio::push") << "dio::push " << x_i << endl;
863 }
864
865 const ValueCollection& vc = constraint->getValueCollection();
866 ConstraintP lb = d_partialModel.getLowerBoundConstraint(x_i);
867 if(d_cmEnabled){
868 if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
869 // if it is not a watched variable report it
870 // if it is is a watched variable and c_i == 0,
871 // let zeroDifferenceDetected(x_i) catch this
872 d_congruenceManager.equalsConstant(lb, constraint);
873 }
874 }
875
876 if(vc.hasDisequality()){
877 Assert(vc.hasDisequality());
878 ConstraintP eq = vc.getEquality();
879 ConstraintP diseq = vc.getDisequality();
880 // x <= b, x >= b |= x = b
881 // (x > b or x < b or x = b)
882 Debug("arith::eq") << "lb == ub, propagate eq" << eq << endl;
883 bool triConflict = diseq->isTrue();
884 if(!eq->isTrue()){
885 eq->impliedByTrichotomy(constraint, lb, triConflict);
886 eq->tryToPropagate();
887 }
888 if(triConflict){
889 ++(d_statistics.d_statDisequalityConflicts);
890 raiseConflict(eq);
891 return true;
892 }
893 }
894 }else if(cmpToLB > 0){
895 // l <= x <= u and l < u
896 Assert(cmpToLB > 0);
897 const ValueCollection& vc = constraint->getValueCollection();
898
899 if(vc.hasDisequality()){
900 const ConstraintP diseq = vc.getDisequality();
901 if(diseq->isTrue()){
902 const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
903 ConstraintP negLb = lb->getNegation();
904
905 // x <= u, u != x |= u < x
906 // |= not (u >= x)
907 bool lbInConflict = lb->hasProof();
908 bool learnNegLb = !(negLb->hasProof());
909 if(learnNegLb){
910 negLb->impliedByTrichotomy(constraint, diseq, lbInConflict);
911 negLb->tryToPropagate();
912 }
913 if(lbInConflict){
914 raiseConflict(lb);
915 return true;
916 }else if(learnNegLb){
917 d_learnedBounds.push_back(negLb);
918 }
919 }
920 }
921 }
922
923 d_currentPropagationList.push_back(constraint);
924 d_currentPropagationList.push_back(d_partialModel.getUpperBoundConstraint(x_i));
925 //It is fine if this is NullConstraint
926
927 d_partialModel.setUpperBoundConstraint(constraint);
928
929 if(d_cmEnabled){
930 if(d_congruenceManager.isWatchedVariable(x_i)){
931 int sgn = c_i.sgn();
932 if(sgn < 0){
933 d_congruenceManager.watchedVariableCannotBeZero(constraint);
934 }else if(sgn == 0 && d_partialModel.lowerBoundIsZero(x_i)){
935 zeroDifferenceDetected(x_i);
936 }
937 }
938 }
939
940 d_updatedBounds.softAdd(x_i);
941
942 if(Debug.isOn("model")) {
943 Debug("model") << "before" << endl;
944 d_partialModel.printModel(x_i);
945 d_tableau.debugPrintIsBasic(x_i);
946 }
947
948 if(!d_tableau.isBasic(x_i)){
949 if(d_partialModel.getAssignment(x_i) > c_i){
950 d_linEq.update(x_i, c_i);
951 }
952 }else{
953 d_errorSet.signalVariable(x_i);
954 }
955
956 if(Debug.isOn("model")) {
957 Debug("model") << "after" << endl;
958 d_partialModel.printModel(x_i);
959 d_tableau.debugPrintIsBasic(x_i);
960 }
961
962 return false; //sat
963 }
964
965
966 /* procedure AssertEquality( x_i == c_i ) */
AssertEquality(ConstraintP constraint)967 bool TheoryArithPrivate::AssertEquality(ConstraintP constraint){
968 Assert(constraint != NullConstraint);
969 Assert(constraint->isEquality());
970 Assert(constraint->isTrue());
971 Assert(!constraint->negationHasProof());
972
973 ArithVar x_i = constraint->getVariable();
974 const DeltaRational& c_i = constraint->getValue();
975
976 Debug("arith") << "AssertEquality(" << x_i << " " << c_i << ")"<< std::endl;
977
978 //Should be fine in integers
979 Assert(!isInteger(x_i) || c_i.isIntegral());
980
981 int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i);
982 int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i);
983
984 // u_i <= c_i <= l_i
985 // This can happen if both c_i <= x_i and x_i <= c_i are in the system.
986 if(cmpToUB >= 0 && cmpToLB <= 0){
987 return false; //sat
988 }
989
990 if(cmpToUB > 0 || cmpToLB < 0){
991 ConstraintP cb = (cmpToUB > 0) ? d_partialModel.getUpperBoundConstraint(x_i) :
992 d_partialModel.getLowerBoundConstraint(x_i);
993 ConstraintP diseq = constraint->getNegation();
994 Assert(!diseq->isTrue());
995 diseq->impliedByUnate(cb, true);
996 raiseConflict(constraint);
997 return true;
998 }
999
1000 Assert(cmpToUB <= 0);
1001 Assert(cmpToLB >= 0);
1002 Assert(cmpToUB < 0 || cmpToLB > 0);
1003
1004
1005 if(isInteger(x_i)){
1006 d_constantIntegerVariables.push_back(x_i);
1007 Debug("dio::push") << "dio::push " << x_i << endl;
1008 }
1009
1010 // Don't bother to check whether x_i != c_i is in d_diseq
1011 // The a and (not a) should never be on the fact queue
1012 d_currentPropagationList.push_back(constraint);
1013 d_currentPropagationList.push_back(d_partialModel.getLowerBoundConstraint(x_i));
1014 d_currentPropagationList.push_back(d_partialModel.getUpperBoundConstraint(x_i));
1015
1016 d_partialModel.setUpperBoundConstraint(constraint);
1017 d_partialModel.setLowerBoundConstraint(constraint);
1018
1019 if(d_cmEnabled){
1020 if(d_congruenceManager.isWatchedVariable(x_i)){
1021 int sgn = c_i.sgn();
1022 if(sgn == 0){
1023 zeroDifferenceDetected(x_i);
1024 }else{
1025 d_congruenceManager.watchedVariableCannotBeZero(constraint);
1026 d_congruenceManager.equalsConstant(constraint);
1027 }
1028 }else{
1029 d_congruenceManager.equalsConstant(constraint);
1030 }
1031 }
1032
1033 d_updatedBounds.softAdd(x_i);
1034
1035 if(Debug.isOn("model")) {
1036 Debug("model") << "before" << endl;
1037 d_partialModel.printModel(x_i);
1038 d_tableau.debugPrintIsBasic(x_i);
1039 }
1040
1041 if(!d_tableau.isBasic(x_i)){
1042 if(!(d_partialModel.getAssignment(x_i) == c_i)){
1043 d_linEq.update(x_i, c_i);
1044 }
1045 }else{
1046 d_errorSet.signalVariable(x_i);
1047 }
1048
1049 if(Debug.isOn("model")) {
1050 Debug("model") << "after" << endl;
1051 d_partialModel.printModel(x_i);
1052 d_tableau.debugPrintIsBasic(x_i);
1053 }
1054
1055 return false;
1056 }
1057
1058
1059 /* procedure AssertDisequality( x_i != c_i ) */
AssertDisequality(ConstraintP constraint)1060 bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){
1061 Assert(constraint != NullConstraint);
1062 Assert(constraint->isDisequality());
1063 Assert(constraint->isTrue());
1064 Assert(!constraint->negationHasProof());
1065
1066 ArithVar x_i = constraint->getVariable();
1067 const DeltaRational& c_i = constraint->getValue();
1068 Debug("arith") << "AssertDisequality(" << x_i << " " << c_i << ")"<< std::endl;
1069
1070 //Should be fine in integers
1071 Assert(!isInteger(x_i) || c_i.isIntegral());
1072
1073 if(d_cmEnabled){
1074 if(d_congruenceManager.isWatchedVariable(x_i)){
1075 int sgn = c_i.sgn();
1076 if(sgn == 0){
1077 d_congruenceManager.watchedVariableCannotBeZero(constraint);
1078 }
1079 }
1080 }
1081
1082 const ValueCollection& vc = constraint->getValueCollection();
1083 if(vc.hasLowerBound() && vc.hasUpperBound()){
1084 const ConstraintP lb = vc.getLowerBound();
1085 const ConstraintP ub = vc.getUpperBound();
1086 if(lb->isTrue() && ub->isTrue()){
1087 ConstraintP eq = constraint->getNegation();
1088 eq->impliedByTrichotomy(lb, ub, true);
1089 raiseConflict(constraint);
1090 //in conflict
1091 ++(d_statistics.d_statDisequalityConflicts);
1092 return true;
1093 }
1094 }
1095 if(vc.hasLowerBound() ){
1096 const ConstraintP lb = vc.getLowerBound();
1097 if(lb->isTrue()){
1098 const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
1099 Assert(!ub->isTrue());
1100 Debug("arith::eq") << "propagate UpperBound " << constraint << lb << ub << endl;
1101 const ConstraintP negUb = ub->getNegation();
1102 if(!negUb->isTrue()){
1103 negUb->impliedByTrichotomy(constraint, lb, false);
1104 negUb->tryToPropagate();
1105 d_learnedBounds.push_back(negUb);
1106 }
1107 }
1108 }
1109 if(vc.hasUpperBound()){
1110 const ConstraintP ub = vc.getUpperBound();
1111 if(ub->isTrue()){
1112 const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
1113 Assert(!lb->isTrue());
1114
1115 Debug("arith::eq") << "propagate LowerBound " << constraint << lb << ub << endl;
1116 const ConstraintP negLb = lb->getNegation();
1117 if(!negLb->isTrue()){
1118 negLb->impliedByTrichotomy(constraint, ub, false);
1119 negLb->tryToPropagate();
1120 d_learnedBounds.push_back(negLb);
1121 }
1122 }
1123 }
1124
1125 bool split = constraint->isSplit();
1126
1127 if(!split && c_i == d_partialModel.getAssignment(x_i)){
1128 Debug("arith::eq") << "lemma now! " << constraint << endl;
1129 outputLemma(constraint->split());
1130 return false;
1131 }else if(d_partialModel.strictlyLessThanLowerBound(x_i, c_i)){
1132 Debug("arith::eq") << "can drop as less than lb" << constraint << endl;
1133 }else if(d_partialModel.strictlyGreaterThanUpperBound(x_i, c_i)){
1134 Debug("arith::eq") << "can drop as less than ub" << constraint << endl;
1135 }else if(!split){
1136 Debug("arith::eq") << "push back" << constraint << endl;
1137 d_diseqQueue.push(constraint);
1138 d_partialModel.invalidateDelta();
1139 }else{
1140 Debug("arith::eq") << "skipping already split " << constraint << endl;
1141 }
1142 return false;
1143 }
1144
addSharedTerm(TNode n)1145 void TheoryArithPrivate::addSharedTerm(TNode n){
1146 Debug("arith::addSharedTerm") << "addSharedTerm: " << n << endl;
1147 if(n.isConst()){
1148 d_partialModel.invalidateDelta();
1149 }
1150
1151 d_congruenceManager.addSharedTerm(n);
1152 if(!n.isConst() && !isSetup(n)){
1153 Polynomial poly = Polynomial::parsePolynomial(n);
1154 Polynomial::iterator it = poly.begin();
1155 Polynomial::iterator it_end = poly.end();
1156 for (; it != it_end; ++ it) {
1157 Monomial m = *it;
1158 if (!m.isConstant() && !isSetup(m.getVarList().getNode())) {
1159 setupVariableList(m.getVarList());
1160 }
1161 }
1162 }
1163 }
1164
getModelValue(TNode term)1165 Node TheoryArithPrivate::getModelValue(TNode term) {
1166 try{
1167 const DeltaRational drv = getDeltaValue(term);
1168 const Rational& delta = d_partialModel.getDelta();
1169 const Rational qmodel = drv.substituteDelta( delta );
1170 return mkRationalNode( qmodel );
1171 } catch (DeltaRationalException& dr) {
1172 return Node::null();
1173 } catch (ModelException& me) {
1174 return Node::null();
1175 }
1176 }
1177
ppRewriteTerms(TNode n)1178 Node TheoryArithPrivate::ppRewriteTerms(TNode n) {
1179 if(Theory::theoryOf(n) != THEORY_ARITH) {
1180 return n;
1181 }
1182
1183 NodeManager* nm = NodeManager::currentNM();
1184
1185 switch(Kind k = n.getKind()) {
1186
1187 case kind::TO_INTEGER:
1188 case kind::IS_INTEGER: {
1189 Node toIntSkolem;
1190 NodeMap::const_iterator it = d_to_int_skolem.find( n[0] );
1191 if( it==d_to_int_skolem.end() ){
1192 toIntSkolem = nm->mkSkolem("toInt", nm->integerType(),
1193 "a conversion of a Real term to its Integer part");
1194 d_to_int_skolem[n[0]] = toIntSkolem;
1195 // n[0] - 1 < toIntSkolem <= n[0]
1196 // -1 < toIntSkolem - n[0] <= 0
1197 // 0 <= n[0] - toIntSkolem < 1
1198 Node one = mkRationalNode(1);
1199 Node lem = mkAxiomForTotalIntDivision(n[0], one, toIntSkolem);
1200 d_containing.d_out->lemma(lem);
1201 }else{
1202 toIntSkolem = (*it).second;
1203 }
1204 if(k == kind::IS_INTEGER) {
1205 return nm->mkNode(kind::EQUAL, n[0], toIntSkolem);
1206 }
1207 Assert(k == kind::TO_INTEGER);
1208 return toIntSkolem;
1209 }
1210 case kind::INTS_DIVISION:
1211 case kind::INTS_MODULUS:
1212 case kind::DIVISION:
1213 // these should be removed during expand definitions
1214 Assert( false );
1215 break;
1216
1217 case kind::INTS_DIVISION_TOTAL:
1218 case kind::INTS_MODULUS_TOTAL: {
1219 Node den = Rewriter::rewrite(n[1]);
1220 if(!options::rewriteDivk() && den.isConst()) {
1221 return n;
1222 }
1223 Node num = Rewriter::rewrite(n[0]);
1224 Node intVar;
1225 Node rw = nm->mkNode(k, num, den);
1226 NodeMap::const_iterator it = d_int_div_skolem.find( rw );
1227 if( it==d_int_div_skolem.end() ){
1228 intVar = nm->mkSkolem("linearIntDiv", nm->integerType(), "the result of an intdiv-by-k term");
1229 d_int_div_skolem[rw] = intVar;
1230 Node lem;
1231 if (den.isConst()) {
1232 const Rational& rat = den.getConst<Rational>();
1233 Assert(!num.isConst());
1234 if(rat != 0) {
1235 if(rat > 0) {
1236 lem = nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num),
1237 nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(1))))));
1238 } else {
1239 lem = nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num),
1240 nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(-1))))));
1241 }
1242 }
1243 }else{
1244 lem = nm->mkNode(kind::AND,
1245 nm->mkNode(kind::IMPLIES, NodeManager::currentNM()->mkNode( kind::GT, den, nm->mkConst(Rational(0)) ),
1246 nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num),
1247 nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(1))))))),
1248 nm->mkNode(kind::IMPLIES, NodeManager::currentNM()->mkNode( kind::LT, den, nm->mkConst(Rational(0)) ),
1249 nm->mkNode(kind::AND, nm->mkNode(kind::LEQ, nm->mkNode(kind::MULT, den, intVar), num),
1250 nm->mkNode(kind::LT, num, nm->mkNode(kind::MULT, den, nm->mkNode(kind::PLUS, intVar, nm->mkConst(Rational(-1))))))));
1251 }
1252 if( !lem.isNull() ){
1253 d_containing.d_out->lemma(lem);
1254 }
1255 }else{
1256 intVar = (*it).second;
1257 }
1258 if( k==kind::INTS_MODULUS_TOTAL ){
1259 Node node = nm->mkNode(kind::MINUS, num, nm->mkNode(kind::MULT, den, intVar));
1260 return node;
1261 }else{
1262 return intVar;
1263 }
1264 break;
1265 }
1266 case kind::DIVISION_TOTAL: {
1267 Node num = Rewriter::rewrite(n[0]);
1268 Node den = Rewriter::rewrite(n[1]);
1269 Assert(!den.isConst());
1270 Node var;
1271 Node rw = nm->mkNode(k, num, den);
1272 NodeMap::const_iterator it = d_div_skolem.find( rw );
1273 if( it==d_div_skolem.end() ){
1274 var = nm->mkSkolem("nonlinearDiv", nm->realType(), "the result of a non-linear div term");
1275 d_div_skolem[rw] = var;
1276 d_containing.d_out->lemma(nm->mkNode(kind::IMPLIES, den.eqNode(nm->mkConst(Rational(0))).negate(), nm->mkNode(kind::MULT, den, var).eqNode(num)));
1277 }else{
1278 var = (*it).second;
1279 }
1280 return var;
1281 break;
1282 }
1283 default:
1284 break;
1285 }
1286
1287 for(TNode::const_iterator i = n.begin(); i != n.end(); ++i) {
1288 Node rewritten = ppRewriteTerms(*i);
1289 if(rewritten != *i) {
1290 NodeBuilder<> b(n.getKind());
1291 b.append(n.begin(), i);
1292 b << rewritten;
1293 for(++i; i != n.end(); ++i) {
1294 b << ppRewriteTerms(*i);
1295 }
1296 rewritten = b;
1297 return rewritten;
1298 }
1299 }
1300
1301 return n;
1302 }
1303
ppRewrite(TNode atom)1304 Node TheoryArithPrivate::ppRewrite(TNode atom) {
1305 Debug("arith::preprocess") << "arith::preprocess() : " << atom << endl;
1306
1307 if (atom.getKind() == kind::EQUAL && options::arithRewriteEq()) {
1308 Node leq = NodeBuilder<2>(kind::LEQ) << atom[0] << atom[1];
1309 Node geq = NodeBuilder<2>(kind::GEQ) << atom[0] << atom[1];
1310 leq = ppRewriteTerms(leq);
1311 geq = ppRewriteTerms(geq);
1312 Node rewritten = Rewriter::rewrite(leq.andNode(geq));
1313 Debug("arith::preprocess") << "arith::preprocess() : returning "
1314 << rewritten << endl;
1315 return rewritten;
1316 } else {
1317 return ppRewriteTerms(atom);
1318 }
1319 }
1320
ppAssert(TNode in,SubstitutionMap & outSubstitutions)1321 Theory::PPAssertStatus TheoryArithPrivate::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
1322 TimerStat::CodeTimer codeTimer(d_statistics.d_simplifyTimer);
1323 Debug("simplify") << "TheoryArithPrivate::solve(" << in << ")" << endl;
1324
1325
1326 // Solve equalities
1327 Rational minConstant = 0;
1328 Node minMonomial;
1329 Node minVar;
1330 if (in.getKind() == kind::EQUAL &&
1331 Theory::theoryOf(in[0].getType()) == THEORY_ARITH) {
1332 Comparison cmp = Comparison::parseNormalForm(in);
1333
1334 Polynomial left = cmp.getLeft();
1335 Polynomial right = cmp.getRight();
1336
1337 Monomial m = left.getHead();
1338 if (m.getVarList().singleton()){
1339 VarList vl = m.getVarList();
1340 Node var = vl.getNode();
1341 if (var.getKind() == kind::VARIABLE){
1342 // if vl.isIntegral then m.getConstant().isOne()
1343 if(!vl.isIntegral() || m.getConstant().isOne()){
1344 minVar = var;
1345 }
1346 }
1347 }
1348
1349 // Solve for variable
1350 if (!minVar.isNull()) {
1351 Polynomial right = cmp.getRight();
1352 Node elim = right.getNode();
1353 // ax + p = c -> (ax + p) -ax - c = -ax
1354 // x = (p - ax - c) * -1/a
1355 // Add the substitution if not recursive
1356 Assert(elim == Rewriter::rewrite(elim));
1357
1358 if (right.size() > options::ppAssertMaxSubSize())
1359 {
1360 Debug("simplify")
1361 << "TheoryArithPrivate::solve(): did not substitute due to the "
1362 "right hand side containing too many terms: "
1363 << minVar << ":" << elim << endl;
1364 Debug("simplify") << right.size() << endl;
1365 }
1366 else if (expr::hasSubterm(elim, minVar))
1367 {
1368 Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute "
1369 "due to recursive pattern with sharing: "
1370 << minVar << ":" << elim << endl;
1371 }
1372 else if (!minVar.getType().isInteger() || right.isIntegral())
1373 {
1374 Assert(!expr::hasSubterm(elim, minVar));
1375 // cannot eliminate integers here unless we know the resulting
1376 // substitution is integral
1377 Debug("simplify") << "TheoryArithPrivate::solve(): substitution "
1378 << minVar << " |-> " << elim << endl;
1379
1380 outSubstitutions.addSubstitution(minVar, elim);
1381 return Theory::PP_ASSERT_STATUS_SOLVED;
1382 }
1383 else
1384 {
1385 Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute "
1386 "b/c it's integer: "
1387 << minVar << ":" << minVar.getType() << " |-> "
1388 << elim << ":" << elim.getType() << endl;
1389 }
1390 }
1391 }
1392
1393 // If a relation, remember the bound
1394 switch(in.getKind()) {
1395 case kind::LEQ:
1396 case kind::LT:
1397 case kind::GEQ:
1398 case kind::GT:
1399 if (in[0].isVar()) {
1400 d_learner.addBound(in);
1401 }
1402 break;
1403 default:
1404 // Do nothing
1405 break;
1406 }
1407
1408 return Theory::PP_ASSERT_STATUS_UNSOLVED;
1409 }
1410
ppStaticLearn(TNode n,NodeBuilder<> & learned)1411 void TheoryArithPrivate::ppStaticLearn(TNode n, NodeBuilder<>& learned) {
1412 TimerStat::CodeTimer codeTimer(d_statistics.d_staticLearningTimer);
1413
1414 d_learner.staticLearning(n, learned);
1415 }
1416
1417
1418
findShortestBasicRow(ArithVar variable)1419 ArithVar TheoryArithPrivate::findShortestBasicRow(ArithVar variable){
1420 ArithVar bestBasic = ARITHVAR_SENTINEL;
1421 uint64_t bestRowLength = std::numeric_limits<uint64_t>::max();
1422
1423 Tableau::ColIterator basicIter = d_tableau.colIterator(variable);
1424 for(; !basicIter.atEnd(); ++basicIter){
1425 const Tableau::Entry& entry = *basicIter;
1426 Assert(entry.getColVar() == variable);
1427 RowIndex ridx = entry.getRowIndex();
1428 ArithVar basic = d_tableau.rowIndexToBasic(ridx);
1429 uint32_t rowLength = d_tableau.getRowLength(ridx);
1430 if((rowLength < bestRowLength) ||
1431 (rowLength == bestRowLength && basic < bestBasic)){
1432 bestBasic = basic;
1433 bestRowLength = rowLength;
1434 }
1435 }
1436 Assert(bestBasic == ARITHVAR_SENTINEL ||
1437 bestRowLength < std::numeric_limits<uint32_t>::max());
1438 return bestBasic;
1439 }
1440
setupVariable(const Variable & x)1441 void TheoryArithPrivate::setupVariable(const Variable& x){
1442 Node n = x.getNode();
1443
1444 Assert(!isSetup(n));
1445
1446 ++(d_statistics.d_statUserVariables);
1447 requestArithVar(n, false, false);
1448 //ArithVar varN = requestArithVar(n,false);
1449 //setupInitialValue(varN);
1450
1451 markSetup(n);
1452
1453 if(x.isDivLike()){
1454 setupDivLike(x);
1455 }
1456
1457 }
1458
setupVariableList(const VarList & vl)1459 void TheoryArithPrivate::setupVariableList(const VarList& vl){
1460 Assert(!vl.empty());
1461
1462 TNode vlNode = vl.getNode();
1463 Assert(!isSetup(vlNode));
1464 Assert(!d_partialModel.hasArithVar(vlNode));
1465
1466 for(VarList::iterator i = vl.begin(), end = vl.end(); i != end; ++i){
1467 Variable var = *i;
1468
1469 if(!isSetup(var.getNode())){
1470 setupVariable(var);
1471 }
1472 }
1473
1474 if(!vl.singleton()){
1475 // vl is the product of at least 2 variables
1476 // vl : (* v1 v2 ...)
1477 if(getLogicInfo().isLinear()){
1478 throw LogicException("A non-linear fact was asserted to arithmetic in a linear logic.");
1479 }
1480
1481 if( !options::nlExt() ){
1482 d_nlIncomplete = true;
1483 }
1484
1485 ++(d_statistics.d_statUserVariables);
1486 requestArithVar(vlNode, false, false);
1487 //ArithVar av = requestArithVar(vlNode, false);
1488 //setupInitialValue(av);
1489
1490 markSetup(vlNode);
1491 }else{
1492 if( !options::nlExt() ){
1493 if( vlNode.getKind()==kind::EXPONENTIAL || vlNode.getKind()==kind::SINE ||
1494 vlNode.getKind()==kind::COSINE || vlNode.getKind()==kind::TANGENT ){
1495 d_nlIncomplete = true;
1496 }
1497 }
1498 }
1499
1500 /* Note:
1501 * Only call markSetup if the VarList is not a singleton.
1502 * See the comment in setupPolynomail for more.
1503 */
1504 }
1505
cautiousSetupPolynomial(const Polynomial & p)1506 void TheoryArithPrivate::cautiousSetupPolynomial(const Polynomial& p){
1507 if(p.containsConstant()){
1508 if(!p.isConstant()){
1509 Polynomial noConstant = p.getTail();
1510 if(!isSetup(noConstant.getNode())){
1511 setupPolynomial(noConstant);
1512 }
1513 }
1514 }else if(!isSetup(p.getNode())){
1515 setupPolynomial(p);
1516 }
1517 }
1518
setupDivLike(const Variable & v)1519 void TheoryArithPrivate::setupDivLike(const Variable& v){
1520 Assert(v.isDivLike());
1521
1522 if(getLogicInfo().isLinear()){
1523 throw LogicException(
1524 "A non-linear fact (involving div/mod/divisibility) was asserted to "
1525 "arithmetic in a linear logic;\nif you only use division (or modulus) "
1526 "by a constant value, or if you only use the divisibility-by-k "
1527 "predicate, try using the --rewrite-divk option.");
1528 }
1529
1530 Node vnode = v.getNode();
1531 Assert(isSetup(vnode)); // Otherwise there is some invariant breaking recursion
1532 Polynomial m = Polynomial::parsePolynomial(vnode[0]);
1533 Polynomial n = Polynomial::parsePolynomial(vnode[1]);
1534
1535 cautiousSetupPolynomial(m);
1536 cautiousSetupPolynomial(n);
1537
1538 Node lem;
1539 switch(vnode.getKind()){
1540 case DIVISION:
1541 case INTS_DIVISION:
1542 case INTS_MODULUS:
1543 // these should be removed during expand definitions
1544 Assert( false );
1545 break;
1546 case DIVISION_TOTAL:
1547 lem = axiomIteForTotalDivision(vnode);
1548 break;
1549 case INTS_DIVISION_TOTAL:
1550 case INTS_MODULUS_TOTAL:
1551 lem = axiomIteForTotalIntDivision(vnode);
1552 break;
1553 default:
1554 /* intentionally blank */
1555 break;
1556 }
1557
1558 if(!lem.isNull()){
1559 Debug("arith::div") << lem << endl;
1560 outputLemma(lem);
1561 }
1562 }
1563
axiomIteForTotalDivision(Node div_tot)1564 Node TheoryArithPrivate::axiomIteForTotalDivision(Node div_tot){
1565 Assert(div_tot.getKind() == DIVISION_TOTAL);
1566
1567 // Inverse of multiplication axiom:
1568 // (for all ((n Real) (d Real))
1569 // (ite (= d 0)
1570 // (= (DIVISION_TOTAL n d) 0)
1571 // (= (* d (DIVISION_TOTAL n d)) n)))
1572
1573
1574 Polynomial n = Polynomial::parsePolynomial(div_tot[0]);
1575 Polynomial d = Polynomial::parsePolynomial(div_tot[1]);
1576 Polynomial div_tot_p = Polynomial::parsePolynomial(div_tot);
1577
1578 Comparison invEq = Comparison::mkComparison(EQUAL, n, d * div_tot_p);
1579 Comparison zeroEq = Comparison::mkComparison(EQUAL, div_tot_p, Polynomial::mkZero());
1580 Node dEq0 = (d.getNode()).eqNode(mkRationalNode(0));
1581 Node ite = dEq0.iteNode(zeroEq.getNode(), invEq.getNode());
1582
1583 return ite;
1584 }
1585
axiomIteForTotalIntDivision(Node int_div_like)1586 Node TheoryArithPrivate::axiomIteForTotalIntDivision(Node int_div_like){
1587 Kind k = int_div_like.getKind();
1588 Assert(k == INTS_DIVISION_TOTAL || k == INTS_MODULUS_TOTAL);
1589
1590 // See the discussion of integer division axioms above.
1591
1592 Polynomial n = Polynomial::parsePolynomial(int_div_like[0]);
1593 Polynomial d = Polynomial::parsePolynomial(int_div_like[1]);
1594
1595 NodeManager* currNM = NodeManager::currentNM();
1596 Node zero = mkRationalNode(0);
1597
1598 Node q = (k == INTS_DIVISION_TOTAL) ? int_div_like : currNM->mkNode(INTS_DIVISION_TOTAL, n.getNode(), d.getNode());
1599 Node r = (k == INTS_MODULUS_TOTAL) ? int_div_like : currNM->mkNode(INTS_MODULUS_TOTAL, n.getNode(), d.getNode());
1600
1601 Node dEq0 = (d.getNode()).eqNode(zero);
1602 Node qEq0 = q.eqNode(zero);
1603 Node rEq0 = r.eqNode(zero);
1604
1605 Polynomial rp = Polynomial::parsePolynomial(r);
1606 Polynomial qp = Polynomial::parsePolynomial(q);
1607
1608 Node abs_d = (n.isConstant()) ?
1609 d.getHead().getConstant().abs().getNode() : mkIntSkolem("abs");
1610
1611 Node eq = Comparison::mkComparison(EQUAL, n, d * qp + rp).getNode();
1612 Node leq0 = currNM->mkNode(LEQ, zero, r);
1613 Node leq1 = currNM->mkNode(LT, r, abs_d);
1614
1615 Node andE = currNM->mkNode(AND, eq, leq0, leq1);
1616 Node defDivMode = dEq0.iteNode(qEq0.andNode(rEq0), andE);
1617 Node lem = abs_d.getMetaKind () == metakind::VARIABLE ?
1618 defDivMode.andNode(d.makeAbsCondition(Variable(abs_d))) : defDivMode;
1619
1620 return lem;
1621 }
1622
1623
setupPolynomial(const Polynomial & poly)1624 void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
1625 Assert(!poly.containsConstant());
1626 TNode polyNode = poly.getNode();
1627 Assert(!isSetup(polyNode));
1628 Assert(!d_partialModel.hasArithVar(polyNode));
1629
1630 for(Polynomial::iterator i = poly.begin(), end = poly.end(); i != end; ++i){
1631 Monomial mono = *i;
1632 const VarList& vl = mono.getVarList();
1633 if(!isSetup(vl.getNode())){
1634 setupVariableList(vl);
1635 }
1636 }
1637
1638 if(polyNode.getKind() == PLUS){
1639 d_tableauSizeHasBeenModified = true;
1640
1641 vector<ArithVar> variables;
1642 vector<Rational> coefficients;
1643 asVectors(poly, coefficients, variables);
1644
1645 ArithVar varSlack = requestArithVar(polyNode, true, false);
1646 d_tableau.addRow(varSlack, coefficients, variables);
1647 setupBasicValue(varSlack);
1648 d_linEq.trackRowIndex(d_tableau.basicToRowIndex(varSlack));
1649
1650 //Add differences to the difference manager
1651 Polynomial::iterator i = poly.begin(), end = poly.end();
1652 if(i != end){
1653 Monomial first = *i;
1654 ++i;
1655 if(i != end){
1656 Monomial second = *i;
1657 ++i;
1658 if(i == end){
1659 if(first.getConstant().isOne() && second.getConstant().getValue() == -1){
1660 VarList vl0 = first.getVarList();
1661 VarList vl1 = second.getVarList();
1662 if(vl0.singleton() && vl1.singleton()){
1663 d_congruenceManager.addWatchedPair(varSlack, vl0.getNode(), vl1.getNode());
1664 }
1665 }
1666 }
1667 }
1668 }
1669
1670 ++(d_statistics.d_statAuxiliaryVariables);
1671 markSetup(polyNode);
1672 }
1673
1674 /* Note:
1675 * It is worth documenting that polyNode should only be marked as
1676 * being setup by this function if it has kind PLUS.
1677 * Other kinds will be marked as being setup by lower levels of setup
1678 * specifically setupVariableList.
1679 */
1680 }
1681
setupAtom(TNode atom)1682 void TheoryArithPrivate::setupAtom(TNode atom) {
1683 Assert(isRelationOperator(atom.getKind()));
1684 Assert(Comparison::isNormalAtom(atom));
1685 Assert(!isSetup(atom));
1686 Assert(!d_constraintDatabase.hasLiteral(atom));
1687
1688 Comparison cmp = Comparison::parseNormalForm(atom);
1689 Polynomial nvp = cmp.normalizedVariablePart();
1690 Assert(!nvp.isZero());
1691
1692 if(!isSetup(nvp.getNode())){
1693 setupPolynomial(nvp);
1694 }
1695
1696 d_constraintDatabase.addLiteral(atom);
1697
1698 markSetup(atom);
1699 }
1700
preRegisterTerm(TNode n)1701 void TheoryArithPrivate::preRegisterTerm(TNode n) {
1702 Debug("arith::preregister") <<"begin arith::preRegisterTerm("<< n <<")"<< endl;
1703
1704 if( options::nlExt() ){
1705 d_containing.getExtTheory()->registerTermRec( n );
1706 }
1707
1708 try {
1709 if(isRelationOperator(n.getKind())){
1710 if(!isSetup(n)){
1711 setupAtom(n);
1712 }
1713 ConstraintP c = d_constraintDatabase.lookup(n);
1714 Assert(c != NullConstraint);
1715
1716 Debug("arith::preregister") << "setup constraint" << c << endl;
1717 Assert(!c->canBePropagated());
1718 c->setPreregistered();
1719 }
1720 } catch(LogicException& le) {
1721 std::stringstream ss;
1722 ss << le.getMessage() << endl << "The fact in question: " << n << endl;
1723 throw LogicException(ss.str());
1724 }
1725
1726 Debug("arith::preregister") << "end arith::preRegisterTerm("<< n <<")" << endl;
1727 }
1728
releaseArithVar(ArithVar v)1729 void TheoryArithPrivate::releaseArithVar(ArithVar v){
1730 //Assert(d_partialModel.hasNode(v));
1731
1732 d_constraintDatabase.removeVariable(v);
1733 d_partialModel.releaseArithVar(v);
1734 }
1735
requestArithVar(TNode x,bool aux,bool internal)1736 ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool aux, bool internal){
1737 //TODO : The VarList trick is good enough?
1738 Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS || internal);
1739 if(getLogicInfo().isLinear() && Variable::isDivMember(x)){
1740 stringstream ss;
1741 ss << "A non-linear fact (involving div/mod/divisibility) was asserted to arithmetic in a linear logic: " << x << endl
1742 << "if you only use division (or modulus) by a constant value, or if you only use the divisibility-by-k predicate, try using the --rewrite-divk option.";
1743 throw LogicException(ss.str());
1744 }
1745 Assert(!d_partialModel.hasArithVar(x));
1746 Assert(x.getType().isReal()); // real or integer
1747
1748 ArithVar max = d_partialModel.getNumberOfVariables();
1749 ArithVar varX = d_partialModel.allocate(x, aux);
1750
1751 bool reclaim = max >= d_partialModel.getNumberOfVariables();;
1752
1753 if(!reclaim){
1754 d_dualSimplex.increaseMax();
1755
1756 d_tableau.increaseSize();
1757 d_tableauSizeHasBeenModified = true;
1758 }
1759 d_constraintDatabase.addVariable(varX);
1760
1761 Debug("arith::arithvar") << "@" << getSatContext()->getLevel()
1762 << " " << x << " |-> " << varX
1763 << "(relaiming " << reclaim << ")" << endl;
1764
1765 Assert(!d_partialModel.hasUpperBound(varX));
1766 Assert(!d_partialModel.hasLowerBound(varX));
1767
1768 return varX;
1769 }
1770
asVectors(const Polynomial & p,std::vector<Rational> & coeffs,std::vector<ArithVar> & variables)1771 void TheoryArithPrivate::asVectors(const Polynomial& p, std::vector<Rational>& coeffs, std::vector<ArithVar>& variables) {
1772 for(Polynomial::iterator i = p.begin(), end = p.end(); i != end; ++i){
1773 const Monomial& mono = *i;
1774 const Constant& constant = mono.getConstant();
1775 const VarList& variable = mono.getVarList();
1776
1777 Node n = variable.getNode();
1778
1779 Debug("arith::asVectors") << "should be var: " << n << endl;
1780
1781 // TODO: This VarList::isMember(n) can be stronger
1782 Assert(isLeaf(n) || VarList::isMember(n));
1783 Assert(theoryOf(n) != THEORY_ARITH || d_partialModel.hasArithVar(n));
1784
1785 Assert(d_partialModel.hasArithVar(n));
1786 ArithVar av = d_partialModel.asArithVar(n);
1787
1788 coeffs.push_back(constant.getValue());
1789 variables.push_back(av);
1790 }
1791 }
1792
1793 /* Requirements:
1794 * For basic variables the row must have been added to the tableau.
1795 */
setupBasicValue(ArithVar x)1796 void TheoryArithPrivate::setupBasicValue(ArithVar x){
1797 Assert(d_tableau.isBasic(x));
1798 //If the variable is basic, assertions may have already happened and updates
1799 //may have occured before setting this variable up.
1800
1801 //This can go away if the tableau creation is done at preregister
1802 //time instead of register
1803 DeltaRational safeAssignment = d_linEq.computeRowValue(x, true);
1804 DeltaRational assignment = d_linEq.computeRowValue(x, false);
1805 d_partialModel.setAssignment(x,safeAssignment,assignment);
1806
1807 Debug("arith") << "setupVariable("<<x<<")"<<std::endl;
1808 }
1809
determineArithVar(const Polynomial & p) const1810 ArithVar TheoryArithPrivate::determineArithVar(const Polynomial& p) const{
1811 Assert(!p.containsConstant());
1812 Assert(p.getHead().constantIsPositive());
1813 TNode n = p.getNode();
1814 Debug("determineArithVar") << "determineArithVar(" << n << ")" << endl;
1815 return d_partialModel.asArithVar(n);
1816 }
1817
determineArithVar(TNode assertion) const1818 ArithVar TheoryArithPrivate::determineArithVar(TNode assertion) const{
1819 Debug("determineArithVar") << "determineArithVar " << assertion << endl;
1820 Comparison cmp = Comparison::parseNormalForm(assertion);
1821 Polynomial variablePart = cmp.normalizedVariablePart();
1822 return determineArithVar(variablePart);
1823 }
1824
1825
canSafelyAvoidEqualitySetup(TNode equality)1826 bool TheoryArithPrivate::canSafelyAvoidEqualitySetup(TNode equality){
1827 Assert(equality.getKind() == EQUAL);
1828 return d_partialModel.hasArithVar(equality[0]);
1829 }
1830
mkIntegerEqualityFromAssignment(ArithVar v)1831 Comparison TheoryArithPrivate::mkIntegerEqualityFromAssignment(ArithVar v){
1832 const DeltaRational& beta = d_partialModel.getAssignment(v);
1833
1834 Assert(beta.isIntegral());
1835 Polynomial betaAsPolynomial = Polynomial::mkPolynomial( Constant::mkConstant(beta.floor()) );
1836
1837 TNode var = d_partialModel.asNode(v);
1838 Polynomial varAsPolynomial = Polynomial::parsePolynomial(var);
1839 return Comparison::mkComparison(EQUAL, varAsPolynomial, betaAsPolynomial);
1840 }
1841
dioCutting()1842 Node TheoryArithPrivate::dioCutting(){
1843 context::Context::ScopedPush speculativePush(getSatContext());
1844 //DO NOT TOUCH THE OUTPUTSTREAM
1845
1846 for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
1847 ArithVar v = *vi;
1848 if(isInteger(v)){
1849 if(d_partialModel.cmpAssignmentUpperBound(v) == 0 ||
1850 d_partialModel.cmpAssignmentLowerBound(v) == 0){
1851 if(!d_partialModel.boundsAreEqual(v)){
1852 // If the bounds are equal this is already in the dioSolver
1853 //Add v = dr as a speculation.
1854 Comparison eq = mkIntegerEqualityFromAssignment(v);
1855 Debug("dio::push") << "dio::push " << v << " " << eq.getNode() << endl;
1856 Assert(!eq.isBoolean());
1857 d_diosolver.pushInputConstraint(eq, eq.getNode());
1858 // It does not matter what the explanation of eq is.
1859 // It cannot be used in a conflict
1860 }
1861 }
1862 }
1863 }
1864
1865 SumPair plane = d_diosolver.processEquationsForCut();
1866 if(plane.isZero()){
1867 return Node::null();
1868 }else{
1869 Polynomial p = plane.getPolynomial();
1870 Polynomial c = Polynomial::mkPolynomial(plane.getConstant() * Constant::mkConstant(-1));
1871 Integer gcd = p.gcd();
1872 Assert(p.isIntegral());
1873 Assert(c.isIntegral());
1874 Assert(gcd > 1);
1875 Assert(!gcd.divides(c.asConstant().getNumerator()));
1876 Comparison leq = Comparison::mkComparison(LEQ, p, c);
1877 Comparison geq = Comparison::mkComparison(GEQ, p, c);
1878 Node lemma = NodeManager::currentNM()->mkNode(OR, leq.getNode(), geq.getNode());
1879 Node rewrittenLemma = Rewriter::rewrite(lemma);
1880 Debug("arith::dio::ex") << "dioCutting found the plane: " << plane.getNode() << endl;
1881 Debug("arith::dio::ex") << "resulting in the cut: " << lemma << endl;
1882 Debug("arith::dio::ex") << "rewritten " << rewrittenLemma << endl;
1883 Debug("arith::dio") << "dioCutting found the plane: " << plane.getNode() << endl;
1884 Debug("arith::dio") << "resulting in the cut: " << lemma << endl;
1885 Debug("arith::dio") << "rewritten " << rewrittenLemma << endl;
1886 return rewrittenLemma;
1887 }
1888 }
1889
callDioSolver()1890 Node TheoryArithPrivate::callDioSolver(){
1891 while(!d_constantIntegerVariables.empty()){
1892 ArithVar v = d_constantIntegerVariables.front();
1893 d_constantIntegerVariables.pop();
1894
1895 Debug("arith::dio") << "callDioSolver " << v << endl;
1896
1897 Assert(isInteger(v));
1898 Assert(d_partialModel.boundsAreEqual(v));
1899
1900
1901 ConstraintP lb = d_partialModel.getLowerBoundConstraint(v);
1902 ConstraintP ub = d_partialModel.getUpperBoundConstraint(v);
1903
1904 Node orig = Node::null();
1905 if(lb->isEquality()){
1906 orig = lb->externalExplainByAssertions();
1907 }else if(ub->isEquality()){
1908 orig = ub->externalExplainByAssertions();
1909 }else {
1910 orig = Constraint::externalExplainByAssertions(ub, lb);
1911 }
1912
1913 Assert(d_partialModel.assignmentIsConsistent(v));
1914
1915 Comparison eq = mkIntegerEqualityFromAssignment(v);
1916
1917 if(eq.isBoolean()){
1918 //This can only be a conflict
1919 Assert(!eq.getNode().getConst<bool>());
1920
1921 //This should be handled by the normal form earlier in the case of equality
1922 Assert(orig.getKind() != EQUAL);
1923 return orig;
1924 }else{
1925 Debug("dio::push") << "dio::push " << v << " " << eq.getNode() << " with reason " << orig << endl;
1926 d_diosolver.pushInputConstraint(eq, orig);
1927 }
1928 }
1929
1930 return d_diosolver.processEquationsForConflict();
1931 }
1932
constraintFromFactQueue()1933 ConstraintP TheoryArithPrivate::constraintFromFactQueue(){
1934 Assert(!done());
1935 TNode assertion = get();
1936
1937 Kind simpleKind = Comparison::comparisonKind(assertion);
1938 ConstraintP constraint = d_constraintDatabase.lookup(assertion);
1939 if(constraint == NullConstraint){
1940 Assert(simpleKind == EQUAL || simpleKind == DISTINCT );
1941 bool isDistinct = simpleKind == DISTINCT;
1942 Node eq = (simpleKind == DISTINCT) ? assertion[0] : assertion;
1943 Assert(!isSetup(eq));
1944 Node reEq = Rewriter::rewrite(eq);
1945 if(reEq.getKind() == CONST_BOOLEAN){
1946 if(reEq.getConst<bool>() == isDistinct){
1947 // if is (not true), or false
1948 Assert((reEq.getConst<bool>() && isDistinct) ||
1949 (!reEq.getConst<bool>() && !isDistinct));
1950 raiseBlackBoxConflict(assertion);
1951 }
1952 return NullConstraint;
1953 }
1954 Assert(reEq.getKind() != CONST_BOOLEAN);
1955 if(!isSetup(reEq)){
1956 setupAtom(reEq);
1957 }
1958 Node reAssertion = isDistinct ? reEq.notNode() : reEq;
1959 constraint = d_constraintDatabase.lookup(reAssertion);
1960
1961 if(assertion != reAssertion){
1962 Debug("arith::nf") << "getting non-nf assertion " << assertion << " |-> " << reAssertion << endl;
1963 Assert(constraint != NullConstraint);
1964 d_assertionsThatDoNotMatchTheirLiterals.insert(assertion, constraint);
1965 }
1966 }
1967
1968 Assert(constraint != NullConstraint);
1969
1970 if(constraint->assertedToTheTheory()){
1971 //Do nothing
1972 return NullConstraint;
1973 }
1974 Assert(!constraint->assertedToTheTheory());
1975 bool inConflict = constraint->negationHasProof();
1976 constraint->setAssertedToTheTheory(assertion, inConflict);
1977
1978 if(!constraint->hasProof()){
1979 Debug("arith::constraint") << "marking as constraint as self explaining " << endl;
1980 constraint->setAssumption(inConflict);
1981 } else {
1982 Debug("arith::constraint") << "already has proof: " << constraint->externalExplainByAssertions() << endl;
1983 }
1984
1985
1986 if(Debug.isOn("arith::negatedassumption") && inConflict){
1987 ConstraintP negation = constraint->getNegation();
1988 if(Debug.isOn("arith::negatedassumption") && negation->isAssumption()){
1989 debugPrintFacts();
1990 }
1991 Debug("arith::eq") << "negation has proof" << endl;
1992 Debug("arith::eq") << constraint << endl;
1993 Debug("arith::eq") << negation << endl;
1994 }
1995
1996 if(inConflict){
1997 ConstraintP negation = constraint->getNegation();
1998 if(Debug.isOn("arith::negatedassumption") && negation->isAssumption()){
1999 debugPrintFacts();
2000 }
2001 Debug("arith::eq") << "negation has proof" << endl;
2002 Debug("arith::eq") << constraint << endl;
2003 Debug("arith::eq") << negation << endl;
2004 raiseConflict(negation);
2005 return NullConstraint;
2006 }else{
2007 return constraint;
2008 }
2009 }
2010
assertionCases(ConstraintP constraint)2011 bool TheoryArithPrivate::assertionCases(ConstraintP constraint){
2012 Assert(constraint->hasProof());
2013 Assert(!constraint->negationHasProof());
2014
2015 ArithVar x_i = constraint->getVariable();
2016
2017 switch(constraint->getType()){
2018 case UpperBound:
2019 if(isInteger(x_i) && constraint->isStrictUpperBound()){
2020 ConstraintP floorConstraint = constraint->getFloor();
2021 if(!floorConstraint->isTrue()){
2022 bool inConflict = floorConstraint->negationHasProof();
2023 floorConstraint->impliedByIntHole(constraint, inConflict);
2024 floorConstraint->tryToPropagate();
2025 if(inConflict){
2026 raiseConflict(floorConstraint);
2027 return true;
2028 }
2029 }
2030 return AssertUpper(floorConstraint);
2031 }else{
2032 return AssertUpper(constraint);
2033 }
2034 case LowerBound:
2035 if(isInteger(x_i) && constraint->isStrictLowerBound()){
2036 ConstraintP ceilingConstraint = constraint->getCeiling();
2037 if(!ceilingConstraint->isTrue()){
2038 bool inConflict = ceilingConstraint->negationHasProof();
2039 ceilingConstraint->impliedByIntHole(constraint, inConflict);
2040 ceilingConstraint->tryToPropagate();
2041 if(inConflict){
2042 raiseConflict(ceilingConstraint);
2043 return true;
2044 }
2045 }
2046 return AssertLower(ceilingConstraint);
2047 }else{
2048 return AssertLower(constraint);
2049 }
2050 case Equality:
2051 return AssertEquality(constraint);
2052 case Disequality:
2053 return AssertDisequality(constraint);
2054 default:
2055 Unreachable();
2056 return false;
2057 }
2058 }
2059 /**
2060 * Looks for through the variables starting at d_nextIntegerCheckVar
2061 * for the first integer variable that is between its upper and lower bounds
2062 * that has a non-integer assignment.
2063 *
2064 * If assumeBounds is true, skip the check that the variable is in bounds.
2065 *
2066 * If there is no such variable, returns ARITHVAR_SENTINEL;
2067 */
nextIntegerViolatation(bool assumeBounds) const2068 ArithVar TheoryArithPrivate::nextIntegerViolatation(bool assumeBounds) const {
2069 ArithVar numVars = d_partialModel.getNumberOfVariables();
2070 ArithVar v = d_nextIntegerCheckVar;
2071 if(numVars > 0){
2072 const ArithVar rrEnd = d_nextIntegerCheckVar;
2073 do {
2074 if(isIntegerInput(v)){
2075 if(!d_partialModel.integralAssignment(v)){
2076 if( assumeBounds || d_partialModel.assignmentIsConsistent(v) ){
2077 return v;
2078 }
2079 }
2080 }
2081 v= (1 + v == numVars) ? 0 : (1 + v);
2082 }while(v != rrEnd);
2083 }
2084 return ARITHVAR_SENTINEL;
2085 }
2086
2087 /**
2088 * Checks the set of integer variables I to see if each variable
2089 * in I has an integer assignment.
2090 */
hasIntegerModel()2091 bool TheoryArithPrivate::hasIntegerModel(){
2092 ArithVar next = nextIntegerViolatation(true);
2093 if(next != ARITHVAR_SENTINEL){
2094 d_nextIntegerCheckVar = next;
2095 if(Debug.isOn("arith::hasIntegerModel")){
2096 Debug("arith::hasIntegerModel") << "has int model? " << next << endl;
2097 d_partialModel.printModel(next, Debug("arith::hasIntegerModel"));
2098 }
2099 return false;
2100 }else{
2101 return true;
2102 }
2103 }
2104
2105
flattenAndSort(Node n)2106 Node flattenAndSort(Node n){
2107 Kind k = n.getKind();
2108 switch(k){
2109 case kind::OR:
2110 case kind::AND:
2111 case kind::PLUS:
2112 case kind::MULT:
2113 break;
2114 default:
2115 return n;
2116 }
2117
2118 std::vector<Node> out;
2119 std::vector<Node> process;
2120 process.push_back(n);
2121 while(!process.empty()){
2122 Node b = process.back();
2123 process.pop_back();
2124 if(b.getKind() == k){
2125 for(Node::iterator i=b.begin(), end=b.end(); i!=end; ++i){
2126 process.push_back(*i);
2127 }
2128 } else {
2129 out.push_back(b);
2130 }
2131 }
2132 Assert(out.size() >= 2);
2133 std::sort(out.begin(), out.end());
2134 return NodeManager::currentNM()->mkNode(k, out);
2135 }
2136
2137
2138
2139 /** Outputs conflicts to the output channel. */
outputConflicts()2140 void TheoryArithPrivate::outputConflicts(){
2141 Debug("arith::conflict") << "outputting conflicts" << std::endl;
2142 Assert(anyConflict());
2143 static unsigned int conflicts = 0;
2144
2145 if(!conflictQueueEmpty()){
2146 Assert(!d_conflicts.empty());
2147 for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){
2148 ConstraintCP confConstraint = d_conflicts[i];
2149 bool hasProof = confConstraint->hasProof();
2150 Assert(confConstraint->inConflict());
2151 const ConstraintRule& pf = confConstraint->getConstraintRule();
2152 if (Debug.isOn("arith::conflict"))
2153 {
2154 pf.print(std::cout);
2155 std::cout << std::endl;
2156 }
2157 Node conflict = confConstraint->externalExplainConflict();
2158
2159 ++conflicts;
2160 Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict
2161 << " has proof: " << hasProof << endl;
2162 PROOF(if (d_containing.d_proofRecorder && confConstraint->hasFarkasProof()
2163 && pf.d_farkasCoefficients->size()
2164 == conflict.getNumChildren()) {
2165 // The Farkas coefficients and the children of `conflict` seem to be in
2166 // opposite orders... There is some relevant documentation in the
2167 // comment for the d_farkasCoefficients field in "constraint.h"
2168 //
2169 // Anyways, we reverse the children in `conflict` here.
2170 NodeBuilder<> conflictInFarkasCoefficientOrder(kind::AND);
2171 for (size_t i = 0, nchildren = conflict.getNumChildren(); i < nchildren;
2172 ++i)
2173 {
2174 conflictInFarkasCoefficientOrder
2175 << conflict[conflict.getNumChildren() - i - 1];
2176 }
2177
2178 Assert(conflict.getNumChildren() == pf.d_farkasCoefficients->size());
2179 d_containing.d_proofRecorder->saveFarkasCoefficients(
2180 conflictInFarkasCoefficientOrder, pf.d_farkasCoefficients);
2181 })
2182 if(Debug.isOn("arith::normalize::external")){
2183 conflict = flattenAndSort(conflict);
2184 Debug("arith::conflict") << "(normalized to) " << conflict << endl;
2185 }
2186
2187 (d_containing.d_out)->conflict(conflict);
2188 }
2189 }
2190 if(!d_blackBoxConflict.get().isNull()){
2191 Node bb = d_blackBoxConflict.get();
2192 ++conflicts;
2193 Debug("arith::conflict") << "black box conflict" << bb
2194 //<< "("<<conflicts<<")"
2195 << endl;
2196 if(Debug.isOn("arith::normalize::external")){
2197 bb = flattenAndSort(bb);
2198 Debug("arith::conflict") << "(normalized to) " << bb << endl;
2199 }
2200
2201 (d_containing.d_out)->conflict(bb);
2202 }
2203 }
2204
outputLemma(TNode lem)2205 void TheoryArithPrivate::outputLemma(TNode lem) {
2206 Debug("arith::lemma") << "Arith Lemma: " << lem << std::endl;
2207 (d_containing.d_out)->lemma(lem);
2208 }
2209
2210 // void TheoryArithPrivate::branchVector(const std::vector<ArithVar>& lemmas){
2211 // //output the lemmas
2212 // for(vector<ArithVar>::const_iterator i = lemmas.begin(); i != lemmas.end(); ++i){
2213 // ArithVar v = *i;
2214 // Assert(!d_cutInContext.contains(v));
2215 // d_cutInContext.insert(v);
2216 // d_cutCount = d_cutCount + 1;
2217 // Node lem = branchIntegerVariable(v);
2218 // outputLemma(lem);
2219 // ++(d_statistics.d_externalBranchAndBounds);
2220 // }
2221 // }
2222
attemptSolveInteger(Theory::Effort effortLevel,bool emmmittedLemmaOrSplit)2223 bool TheoryArithPrivate::attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit){
2224 int level = getSatContext()->getLevel();
2225 Debug("approx")
2226 << "attemptSolveInteger " << d_qflraStatus
2227 << " " << emmmittedLemmaOrSplit
2228 << " " << effortLevel
2229 << " " << d_lastContextIntegerAttempted
2230 << " " << level
2231 << " " << hasIntegerModel()
2232 << endl;
2233
2234 if(d_qflraStatus == Result::UNSAT){ return false; }
2235 if(emmmittedLemmaOrSplit){ return false; }
2236 if(!options::useApprox()){ return false; }
2237 if(!ApproximateSimplex::enabled()){ return false; }
2238
2239 if(Theory::fullEffort(effortLevel)){
2240 if(hasIntegerModel()){
2241 return false;
2242 }else{
2243 return getSolveIntegerResource();
2244 }
2245 }
2246
2247 if(d_lastContextIntegerAttempted <= 0){
2248 if(hasIntegerModel()){
2249 d_lastContextIntegerAttempted = getSatContext()->getLevel();
2250 return false;
2251 }else{
2252 return getSolveIntegerResource();
2253 }
2254 }
2255
2256
2257 if(!options::trySolveIntStandardEffort()){ return false; }
2258
2259 if (d_lastContextIntegerAttempted <= (level >> 2))
2260 {
2261 double d = (double)(d_solveIntMaybeHelp + 1)
2262 / (d_solveIntAttempts + 1 + level * level);
2263 if (Random::getRandom().pickWithProb(d))
2264 {
2265 return getSolveIntegerResource();
2266 }
2267 }
2268 return false;
2269 }
2270
replayLog(ApproximateSimplex * approx)2271 bool TheoryArithPrivate::replayLog(ApproximateSimplex* approx){
2272 TimerStat::CodeTimer codeTimer(d_statistics.d_replayLogTimer);
2273
2274 ++d_statistics.d_mipProofsAttempted;
2275
2276 Assert(d_replayVariables.empty());
2277 Assert(d_replayConstraints.empty());
2278
2279 size_t enteringPropN = d_currentPropagationList.size();
2280 Assert(conflictQueueEmpty());
2281 TreeLog& tl = getTreeLog();
2282 //tl.applySelected(); /* set row ids */
2283
2284 d_replayedLemmas = false;
2285
2286 /* use the try block for the purpose of pushing the sat context */
2287 context::Context::ScopedPush speculativePush(getSatContext());
2288 d_cmEnabled = false;
2289 std::vector<ConstraintCPVec> res =
2290 replayLogRec(approx, tl.getRootId(), NullConstraint, 1);
2291
2292 if(res.empty()){
2293 ++d_statistics.d_replayAttemptFailed;
2294 }else{
2295 unsigned successes = 0;
2296 for(size_t i =0, N = res.size(); i < N; ++i){
2297 ConstraintCPVec& vec = res[i];
2298 Assert(vec.size() >= 2);
2299 for(size_t j=0, M = vec.size(); j < M; ++j){
2300 ConstraintCP at_j = vec[j];
2301 Assert(at_j->isTrue());
2302 if(!at_j->negationHasProof()){
2303 successes++;
2304 vec[j] = vec.back();
2305 vec.pop_back();
2306 ConstraintP neg_at_j = at_j->getNegation();
2307
2308 Debug("approx::replayLog") << "Setting the proof for the replayLog conflict on:" << endl
2309 << " (" << neg_at_j->isTrue() <<") " << neg_at_j << endl
2310 << " (" << at_j->isTrue() <<") " << at_j << endl;
2311 neg_at_j->impliedByIntHole(vec, true);
2312 raiseConflict(at_j);
2313 break;
2314 }
2315 }
2316 }
2317 if(successes > 0){
2318 ++d_statistics.d_mipProofsSuccessful;
2319 }
2320 }
2321
2322 if(d_currentPropagationList.size() > enteringPropN){
2323 d_currentPropagationList.resize(enteringPropN);
2324 }
2325
2326 /* It is not clear what the d_qflraStatus is at this point */
2327 d_qflraStatus = Result::SAT_UNKNOWN;
2328
2329 Assert(d_replayVariables.empty());
2330 Assert(d_replayConstraints.empty());
2331
2332 return !conflictQueueEmpty();
2333 }
2334
replayGetConstraint(const DenseMap<Rational> & lhs,Kind k,const Rational & rhs,bool branch)2335 std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const DenseMap<Rational>& lhs, Kind k, const Rational& rhs, bool branch)
2336 {
2337 ArithVar added = ARITHVAR_SENTINEL;
2338 Node sum = toSumNode(d_partialModel, lhs);
2339 if(sum.isNull()){ return make_pair(NullConstraint, added); }
2340
2341 Debug("approx::constraint") << "replayGetConstraint " << sum
2342 << " " << k
2343 << " " << rhs
2344 << endl;
2345
2346 Assert( k == kind::LEQ || k == kind::GEQ );
2347
2348 Node comparison = NodeManager::currentNM()->mkNode(k, sum, mkRationalNode(rhs));
2349 Node rewritten = Rewriter::rewrite(comparison);
2350 if(!(Comparison::isNormalAtom(rewritten))){
2351 return make_pair(NullConstraint, added);
2352 }
2353
2354 Comparison cmp = Comparison::parseNormalForm(rewritten);
2355 if(cmp.isBoolean()){ return make_pair(NullConstraint, added); }
2356
2357 Polynomial nvp = cmp.normalizedVariablePart();
2358 if(nvp.isZero()){ return make_pair(NullConstraint, added); }
2359
2360 Node norm = nvp.getNode();
2361
2362 ConstraintType t = Constraint::constraintTypeOfComparison(cmp);
2363 DeltaRational dr = cmp.normalizedDeltaRational();
2364
2365 Debug("approx::constraint") << "rewriting " << rewritten << endl
2366 << " |-> " << norm << " " << t << " " << dr << endl;
2367
2368 Assert(!branch || d_partialModel.hasArithVar(norm));
2369 ArithVar v = ARITHVAR_SENTINEL;
2370 if(d_partialModel.hasArithVar(norm)){
2371
2372 v = d_partialModel.asArithVar(norm);
2373 Debug("approx::constraint") << "replayGetConstraint found "
2374 << norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl;
2375 Assert(!branch || d_partialModel.isIntegerInput(v));
2376 }else{
2377 v = requestArithVar(norm, true, true);
2378 d_replayVariables.push_back(v);
2379
2380 added = v;
2381
2382 Debug("approx::constraint") << "replayGetConstraint adding "
2383 << norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl;
2384
2385 Polynomial poly = Polynomial::parsePolynomial(norm);
2386 vector<ArithVar> variables;
2387 vector<Rational> coefficients;
2388 asVectors(poly, coefficients, variables);
2389 d_tableau.addRow(v, coefficients, variables);
2390 setupBasicValue(v);
2391 d_linEq.trackRowIndex(d_tableau.basicToRowIndex(v));
2392 }
2393 Assert(d_partialModel.hasArithVar(norm));
2394 Assert(d_partialModel.asArithVar(norm) == v);
2395 Assert(d_constraintDatabase.variableDatabaseIsSetup(v));
2396
2397 ConstraintP imp = d_constraintDatabase.getBestImpliedBound(v, t, dr);
2398 if(imp != NullConstraint){
2399 if(imp->getValue() == dr){
2400 Assert(added == ARITHVAR_SENTINEL);
2401 return make_pair(imp, added);
2402 }
2403 }
2404
2405
2406 ConstraintP newc = d_constraintDatabase.getConstraint(v, t, dr);
2407 d_replayConstraints.push_back(newc);
2408 return make_pair(newc, added);
2409 }
2410
replayGetConstraint(ApproximateSimplex * approx,const NodeLog & nl)2411 std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(
2412 ApproximateSimplex* approx, const NodeLog& nl)
2413 {
2414 Assert(nl.isBranch());
2415 Assert(d_lhsTmp.empty());
2416
2417 ArithVar v = approx->getBranchVar(nl);
2418 if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){
2419 if(d_partialModel.hasNode(v)){
2420 d_lhsTmp.set(v, Rational(1));
2421 double dval = nl.branchValue();
2422 Maybe<Rational> maybe_value = ApproximateSimplex::estimateWithCFE(dval);
2423 if (!maybe_value)
2424 {
2425 return make_pair(NullConstraint, ARITHVAR_SENTINEL);
2426 }
2427 Rational fl(maybe_value.value().floor());
2428 pair<ConstraintP, ArithVar> p;
2429 p = replayGetConstraint(d_lhsTmp, kind::LEQ, fl, true);
2430 d_lhsTmp.purge();
2431 return p;
2432 }
2433 }
2434 return make_pair(NullConstraint, ARITHVAR_SENTINEL);
2435 }
2436
replayGetConstraint(const CutInfo & ci)2437 std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const CutInfo& ci) {
2438 Assert(ci.reconstructed());
2439 const DenseMap<Rational>& lhs = ci.getReconstruction().lhs;
2440 const Rational& rhs = ci.getReconstruction().rhs;
2441 Kind k = ci.getKind();
2442
2443 return replayGetConstraint(lhs, k, rhs, ci.getKlass() == BranchCutKlass);
2444 }
2445
2446 // Node denseVectorToLiteral(const ArithVariables& vars, const DenseVector& dv, Kind k){
2447 // NodeManager* nm = NodeManager::currentNM();
2448 // Node sumLhs = toSumNode(vars, dv.lhs);
2449 // Node ineq = nm->mkNode(k, sumLhs, mkRationalNode(dv.rhs) );
2450 // Node lit = Rewriter::rewrite(ineq);
2451 // return lit;
2452 // }
2453
toSumNode(const ArithVariables & vars,const DenseMap<Rational> & sum)2454 Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum){
2455 Debug("arith::toSumNode") << "toSumNode() begin" << endl;
2456 NodeBuilder<> nb(kind::PLUS);
2457 NodeManager* nm = NodeManager::currentNM();
2458 DenseMap<Rational>::const_iterator iter, end;
2459 iter = sum.begin(), end = sum.end();
2460 for(; iter != end; ++iter){
2461 ArithVar x = *iter;
2462 if(!vars.hasNode(x)){ return Node::null(); }
2463 Node xNode = vars.asNode(x);
2464 const Rational& q = sum[x];
2465 Node mult = nm->mkNode(kind::MULT, mkRationalNode(q), xNode);
2466 Debug("arith::toSumNode") << "toSumNode() " << x << " " << mult << endl;
2467 nb << mult;
2468 }
2469 Debug("arith::toSumNode") << "toSumNode() end" << endl;
2470 return safeConstructNary(nb);
2471 }
2472
vectorToIntHoleConflict(const ConstraintCPVec & conflict)2473 ConstraintCP TheoryArithPrivate::vectorToIntHoleConflict(const ConstraintCPVec& conflict){
2474 Assert(conflict.size() >= 2);
2475 ConstraintCPVec exp(conflict.begin(), conflict.end()-1);
2476 ConstraintCP back = conflict.back();
2477 Assert(back->hasProof());
2478 ConstraintP negBack = back->getNegation();
2479 // This can select negBack multiple times so we need to test if negBack has a proof.
2480 if(negBack->hasProof()){
2481 // back is in conflict already
2482 } else {
2483 negBack->impliedByIntHole(exp, true);
2484 }
2485
2486 return back;
2487 }
2488
intHoleConflictToVector(ConstraintCP conflicting,ConstraintCPVec & conflict)2489 void TheoryArithPrivate::intHoleConflictToVector(ConstraintCP conflicting, ConstraintCPVec& conflict){
2490 ConstraintCP negConflicting = conflicting->getNegation();
2491 Assert(conflicting->hasProof());
2492 Assert(negConflicting->hasProof());
2493
2494 conflict.push_back(conflicting);
2495 conflict.push_back(negConflicting);
2496
2497 Constraint::assertionFringe(conflict);
2498 }
2499
tryBranchCut(ApproximateSimplex * approx,int nid,BranchCutInfo & bci)2500 void TheoryArithPrivate::tryBranchCut(ApproximateSimplex* approx, int nid, BranchCutInfo& bci){
2501 Assert(conflictQueueEmpty());
2502 std::vector< ConstraintCPVec > conflicts;
2503
2504 approx->tryCut(nid, bci);
2505 Debug("approx::branch") << "tryBranchCut" << bci << endl;
2506 Assert(bci.reconstructed());
2507 Assert(!bci.proven());
2508 pair<ConstraintP, ArithVar> p = replayGetConstraint(bci);
2509 Assert(p.second == ARITHVAR_SENTINEL);
2510 ConstraintP bc = p.first;
2511 Assert(bc != NullConstraint);
2512 if(bc->hasProof()){
2513 return;
2514 }
2515
2516 ConstraintP bcneg = bc->getNegation();
2517 {
2518 context::Context::ScopedPush speculativePush(getSatContext());
2519 replayAssert(bcneg);
2520 if(conflictQueueEmpty()){
2521 TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer);
2522
2523 //test for linear feasibility
2524 d_partialModel.stopQueueingBoundCounts();
2525 UpdateTrackingCallback utcb(&d_linEq);
2526 d_partialModel.processBoundsQueue(utcb);
2527 d_linEq.startTrackingBoundCounts();
2528
2529 SimplexDecisionProcedure& simplex = selectSimplex(true);
2530 simplex.findModel(false);
2531 // Can change d_qflraStatus
2532
2533 d_linEq.stopTrackingBoundCounts();
2534 d_partialModel.startQueueingBoundCounts();
2535 }
2536 for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){
2537
2538 conflicts.push_back(ConstraintCPVec());
2539 intHoleConflictToVector(d_conflicts[i], conflicts.back());
2540 Constraint::assertionFringe(conflicts.back());
2541
2542 // ConstraintCP conflicting = d_conflicts[i];
2543 // ConstraintCP negConflicting = conflicting->getNegation();
2544 // Assert(conflicting->hasProof());
2545 // Assert(negConflicting->hasProof());
2546
2547 // conflicts.push_back(ConstraintCPVec());
2548 // ConstraintCPVec& back = conflicts.back();
2549 // back.push_back(conflicting);
2550 // back.push_back(negConflicting);
2551
2552 // // remove the floor/ceiling contraint implied by bcneg
2553 // Constraint::assertionFringe(back);
2554 }
2555
2556 if(Debug.isOn("approx::branch")){
2557 if(d_conflicts.empty()){
2558 entireStateIsConsistent("branchfailure");
2559 }
2560 }
2561 }
2562
2563 Debug("approx::branch") << "branch constraint " << bc << endl;
2564 for(size_t i = 0, N = conflicts.size(); i < N; ++i){
2565 ConstraintCPVec& conf = conflicts[i];
2566
2567 // make sure to be working on the assertion fringe!
2568 if(!contains(conf, bcneg)){
2569 Debug("approx::branch") << "reraise " << conf << endl;
2570 ConstraintCP conflicting = vectorToIntHoleConflict(conf);
2571 raiseConflict(conflicting);
2572 }else if(!bci.proven()){
2573 drop(conf, bcneg);
2574 bci.setExplanation(conf);
2575 Debug("approx::branch") << "dropped " << bci << endl;
2576 }
2577 }
2578 }
2579
replayAssert(ConstraintP c)2580 void TheoryArithPrivate::replayAssert(ConstraintP c) {
2581 if(!c->assertedToTheTheory()){
2582 bool inConflict = c->negationHasProof();
2583 if(!c->hasProof()){
2584 c->setInternalAssumption(inConflict);
2585 Debug("approx::replayAssert") << "replayAssert " << c << " set internal" << endl;
2586 }else{
2587 Debug("approx::replayAssert") << "replayAssert " << c << " has explanation" << endl;
2588 }
2589 Debug("approx::replayAssert") << "replayAssertion " << c << endl;
2590 if(inConflict){
2591 raiseConflict(c);
2592 }else{
2593 assertionCases(c);
2594 }
2595 }else{
2596 Debug("approx::replayAssert") << "replayAssert " << c << " already asserted" << endl;
2597 }
2598 }
2599
2600
resolveOutPropagated(std::vector<ConstraintCPVec> & confs,const std::set<ConstraintCP> & propagated) const2601 void TheoryArithPrivate::resolveOutPropagated(std::vector<ConstraintCPVec>& confs, const std::set<ConstraintCP>& propagated) const {
2602 Debug("arith::resolveOutPropagated")
2603 << "starting resolveOutPropagated() " << confs.size() << endl;
2604 for(size_t i =0, N = confs.size(); i < N; ++i){
2605 ConstraintCPVec& conf = confs[i];
2606 size_t orig = conf.size();
2607 Constraint::assertionFringe(conf);
2608 Debug("arith::resolveOutPropagated")
2609 << " conf["<<i<<"] " << orig << " to " << conf.size() << endl;
2610 }
2611 Debug("arith::resolveOutPropagated")
2612 << "ending resolveOutPropagated() " << confs.size() << endl;
2613 }
2614
2615 struct SizeOrd {
operator ()CVC4::theory::arith::SizeOrd2616 bool operator()(const ConstraintCPVec& a, const ConstraintCPVec& b) const{
2617 return a.size() < b.size();
2618 }
2619 };
2620
subsumption(std::vector<ConstraintCPVec> & confs) const2621 void TheoryArithPrivate::subsumption(
2622 std::vector<ConstraintCPVec> &confs) const {
2623 int checks CVC4_UNUSED = 0;
2624 int subsumed CVC4_UNUSED = 0;
2625
2626 for (size_t i = 0, N = confs.size(); i < N; ++i) {
2627 ConstraintCPVec &conf = confs[i];
2628 std::sort(conf.begin(), conf.end());
2629 }
2630
2631 std::sort(confs.begin(), confs.end(), SizeOrd());
2632 for (size_t i = 0; i < confs.size(); i++) {
2633 // i is not subsumed
2634 for (size_t j = i + 1; j < confs.size();) {
2635 ConstraintCPVec& a = confs[i];
2636 ConstraintCPVec& b = confs[j];
2637 checks++;
2638 bool subsumes = std::includes(a.begin(), a.end(), b.begin(), b.end());
2639 if (subsumes) {
2640 ConstraintCPVec& back = confs.back();
2641 b.swap(back);
2642 confs.pop_back();
2643 subsumed++;
2644 } else {
2645 j++;
2646 }
2647 }
2648 }
2649 Debug("arith::subsumption") << "subsumed " << subsumed << "/" << checks
2650 << endl;
2651 }
2652
replayLogRec(ApproximateSimplex * approx,int nid,ConstraintP bc,int depth)2653 std::vector<ConstraintCPVec> TheoryArithPrivate::replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth){
2654 ++(d_statistics.d_replayLogRecCount);
2655 Debug("approx::replayLogRec") << "replayLogRec()"
2656 << d_statistics.d_replayLogRecCount.getData() << std::endl;
2657
2658 size_t rpvars_size = d_replayVariables.size();
2659 size_t rpcons_size = d_replayConstraints.size();
2660 std::vector<ConstraintCPVec> res;
2661
2662 { /* create a block for the purpose of pushing the sat context */
2663 context::Context::ScopedPush speculativePush(getSatContext());
2664 Assert(!anyConflict());
2665 Assert(conflictQueueEmpty());
2666 set<ConstraintCP> propagated;
2667
2668 TreeLog& tl = getTreeLog();
2669
2670 if(bc != NullConstraint){
2671 replayAssert(bc);
2672 }
2673
2674 const NodeLog& nl = tl.getNode(nid);
2675 NodeLog::const_iterator iter = nl.begin(), end = nl.end();
2676 for(; conflictQueueEmpty() && iter != end; ++iter){
2677 CutInfo* ci = *iter;
2678 bool reject = false;
2679 //cout << " trying " << *ci << endl;
2680 if(ci->getKlass() == RowsDeletedKlass){
2681 RowsDeleted* rd = dynamic_cast<RowsDeleted*>(ci);
2682
2683 tl.applyRowsDeleted(nid, *rd);
2684 // The previous line modifies nl
2685
2686 ++d_statistics.d_applyRowsDeleted;
2687 }else if(ci->getKlass() == BranchCutKlass){
2688 BranchCutInfo* bci = dynamic_cast<BranchCutInfo*>(ci);
2689 Assert(bci != NULL);
2690 tryBranchCut(approx, nid, *bci);
2691
2692 ++d_statistics.d_branchCutsAttempted;
2693 if(!(conflictQueueEmpty() || ci->reconstructed())){
2694 ++d_statistics.d_numBranchesFailed;
2695 }
2696 }else{
2697 approx->tryCut(nid, *ci);
2698 if(ci->getKlass() == GmiCutKlass){
2699 ++d_statistics.d_gmiCutsAttempted;
2700 }else if(ci->getKlass() == MirCutKlass){
2701 ++d_statistics.d_mirCutsAttempted;
2702 }
2703
2704 if(ci->reconstructed() && ci->proven()){
2705 const DenseMap<Rational>& row = ci->getReconstruction().lhs;
2706 reject = !complexityBelow(row, options::replayRejectCutSize());
2707 }
2708 }
2709 if(conflictQueueEmpty()){
2710 if(reject){
2711 ++d_statistics.d_cutsRejectedDuringReplay;
2712 }else if(ci->reconstructed()){
2713 // success
2714 ++d_statistics.d_cutsReconstructed;
2715
2716 pair<ConstraintP, ArithVar> p = replayGetConstraint(*ci);
2717 if(p.second != ARITHVAR_SENTINEL){
2718 Assert(ci->getRowId() >= 1);
2719 tl.mapRowId(nl.getNodeId(), ci->getRowId(), p.second);
2720 }
2721 ConstraintP con = p.first;
2722 if(Debug.isOn("approx::replayLogRec")){
2723 Debug("approx::replayLogRec") << "cut was remade " << con << " " << *ci << endl;
2724 }
2725
2726 if(ci->proven()){
2727 ++d_statistics.d_cutsProven;
2728
2729 const ConstraintCPVec& exp = ci->getExplanation();
2730 // success
2731 if(con->isTrue()){
2732 Debug("approx::replayLogRec") << "not asserted?" << endl;
2733 }else if(!con->negationHasProof()){
2734 con->impliedByIntHole(exp, false);
2735 replayAssert(con);
2736 Debug("approx::replayLogRec") << "cut prop" << endl;
2737 }else {
2738 con->impliedByIntHole(exp, true);
2739 Debug("approx::replayLogRec") << "cut into conflict " << con << endl;
2740 raiseConflict(con);
2741 }
2742 }else{
2743 ++d_statistics.d_cutsProofFailed;
2744 Debug("approx::replayLogRec") << "failed to get proof " << *ci << endl;
2745 }
2746 }else if(ci->getKlass() != RowsDeletedKlass){
2747 ++d_statistics.d_cutsReconstructionFailed;
2748 }
2749 }
2750 }
2751
2752 /* check if the system is feasible under with the cuts */
2753 if(conflictQueueEmpty()){
2754 Assert(options::replayEarlyCloseDepths() >= 1);
2755 if(!nl.isBranch() || depth % options::replayEarlyCloseDepths() == 0 ){
2756 TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer);
2757 //test for linear feasibility
2758 d_partialModel.stopQueueingBoundCounts();
2759 UpdateTrackingCallback utcb(&d_linEq);
2760 d_partialModel.processBoundsQueue(utcb);
2761 d_linEq.startTrackingBoundCounts();
2762
2763 SimplexDecisionProcedure& simplex = selectSimplex(true);
2764 simplex.findModel(false);
2765 // can change d_qflraStatus
2766
2767 d_linEq.stopTrackingBoundCounts();
2768 d_partialModel.startQueueingBoundCounts();
2769 }
2770 }else{
2771 ++d_statistics.d_replayLogRecConflictEscalation;
2772 }
2773
2774 if(!conflictQueueEmpty()){
2775 /* if a conflict has been found stop */
2776 for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){
2777 res.push_back(ConstraintCPVec());
2778 intHoleConflictToVector(d_conflicts[i], res.back());
2779 }
2780 ++d_statistics.d_replayLogRecEarlyExit;
2781 }else if(nl.isBranch()){
2782 /* if it is a branch try the branch */
2783 pair<ConstraintP, ArithVar> p = replayGetConstraint(approx, nl);
2784 Assert(p.second == ARITHVAR_SENTINEL);
2785 ConstraintP dnc = p.first;
2786 if(dnc != NullConstraint){
2787 ConstraintP upc = dnc->getNegation();
2788
2789 int dnid = nl.getDownId();
2790 int upid = nl.getUpId();
2791
2792 NodeLog& dnlog = tl.getNode(dnid);
2793 NodeLog& uplog = tl.getNode(upid);
2794 dnlog.copyParentRowIds();
2795 uplog.copyParentRowIds();
2796
2797 std::vector<ConstraintCPVec> dnres;
2798 std::vector<ConstraintCPVec> upres;
2799 std::vector<size_t> containsdn;
2800 std::vector<size_t> containsup;
2801 if(res.empty()){
2802 dnres = replayLogRec(approx, dnid, dnc, depth+1);
2803 for(size_t i = 0, N = dnres.size(); i < N; ++i){
2804 ConstraintCPVec& conf = dnres[i];
2805 if(contains(conf, dnc)){
2806 containsdn.push_back(i);
2807 }else{
2808 res.push_back(conf);
2809 }
2810 }
2811 }else{
2812 Debug("approx::replayLogRec") << "replayLogRec() skipping" << dnlog << std::endl;
2813 ++d_statistics.d_replayBranchSkips;
2814 }
2815
2816 if(res.empty()){
2817 upres = replayLogRec(approx, upid, upc, depth+1);
2818
2819 for(size_t i = 0, N = upres.size(); i < N; ++i){
2820 ConstraintCPVec& conf = upres[i];
2821 if(contains(conf, upc)){
2822 containsup.push_back(i);
2823 }else{
2824 res.push_back(conf);
2825 }
2826 }
2827 }else{
2828 Debug("approx::replayLogRec") << "replayLogRec() skipping" << uplog << std::endl;
2829 ++d_statistics.d_replayBranchSkips;
2830 }
2831
2832 if(res.empty()){
2833 for(size_t i = 0, N = containsdn.size(); i < N; ++i){
2834 ConstraintCPVec& dnconf = dnres[containsdn[i]];
2835 for(size_t j = 0, M = containsup.size(); j < M; ++j){
2836 ConstraintCPVec& upconf = upres[containsup[j]];
2837
2838 res.push_back(ConstraintCPVec());
2839 ConstraintCPVec& back = res.back();
2840 resolve(back, dnc, dnconf, upconf);
2841 }
2842 }
2843 if(res.size() >= 2u){
2844 subsumption(res);
2845
2846 if(res.size() > 100u){
2847 res.resize(100u);
2848 }
2849 }
2850 }else{
2851 Debug("approx::replayLogRec") << "replayLogRec() skipping resolving" << nl << std::endl;
2852 }
2853 Debug("approx::replayLogRec") << "found #"<<res.size()<<" conflicts on branch " << nid << endl;
2854 if(res.empty()){
2855 ++d_statistics.d_replayBranchCloseFailures;
2856 }
2857
2858 }else{
2859 Debug("approx::replayLogRec") << "failed to make a branch " << nid << endl;
2860 }
2861 }else{
2862 ++d_statistics.d_replayLeafCloseFailures;
2863 Debug("approx::replayLogRec") << "failed on node " << nid << endl;
2864 Assert(res.empty());
2865 }
2866 resolveOutPropagated(res, propagated);
2867 Debug("approx::replayLogRec") << "replayLogRec() ending" << std::endl;
2868
2869
2870 if(options::replayFailureLemma()){
2871 // must be done inside the sat context to get things
2872 // propagated at this level
2873 if(res.empty() && nid == getTreeLog().getRootId()){
2874 Assert(!d_replayedLemmas);
2875 d_replayedLemmas = replayLemmas(approx);
2876 Assert(d_acTmp.empty());
2877 while(!d_approxCuts.empty()){
2878 Node lem = d_approxCuts.front();
2879 d_approxCuts.pop();
2880 d_acTmp.push_back(lem);
2881 }
2882 }
2883 }
2884 } /* pop the sat context */
2885
2886 /* move into the current context. */
2887 while(!d_acTmp.empty()){
2888 Node lem = d_acTmp.back();
2889 d_acTmp.pop_back();
2890 d_approxCuts.push_back(lem);
2891 }
2892 Assert(d_acTmp.empty());
2893
2894
2895 /* Garbage collect the constraints from this call */
2896 while(d_replayConstraints.size() > rpcons_size){
2897 ConstraintP c = d_replayConstraints.back();
2898 d_replayConstraints.pop_back();
2899 d_constraintDatabase.deleteConstraintAndNegation(c);
2900 }
2901
2902 /* Garbage collect the ArithVars made by this call */
2903 if(d_replayVariables.size() > rpvars_size){
2904 d_partialModel.stopQueueingBoundCounts();
2905 UpdateTrackingCallback utcb(&d_linEq);
2906 d_partialModel.processBoundsQueue(utcb);
2907 d_linEq.startTrackingBoundCounts();
2908 while(d_replayVariables.size() > rpvars_size){
2909 ArithVar v = d_replayVariables.back();
2910 d_replayVariables.pop_back();
2911 Assert(d_partialModel.canBeReleased(v));
2912 if(!d_tableau.isBasic(v)){
2913 /* if it is not basic make it basic. */
2914 ArithVar b = ARITHVAR_SENTINEL;
2915 for(Tableau::ColIterator ci = d_tableau.colIterator(v); !ci.atEnd(); ++ci){
2916 const Tableau::Entry& e = *ci;
2917 b = d_tableau.rowIndexToBasic(e.getRowIndex());
2918 break;
2919 }
2920 Assert(b != ARITHVAR_SENTINEL);
2921 DeltaRational cp = d_partialModel.getAssignment(b);
2922 if(d_partialModel.cmpAssignmentLowerBound(b) < 0){
2923 cp = d_partialModel.getLowerBound(b);
2924 }else if(d_partialModel.cmpAssignmentUpperBound(b) > 0){
2925 cp = d_partialModel.getUpperBound(b);
2926 }
2927 d_linEq.pivotAndUpdate(b, v, cp);
2928 }
2929 Assert(d_tableau.isBasic(v));
2930 d_linEq.stopTrackingRowIndex(d_tableau.basicToRowIndex(v));
2931 d_tableau.removeBasicRow(v);
2932
2933 releaseArithVar(v);
2934 Debug("approx::vars") << "releasing " << v << endl;
2935 }
2936 d_linEq.stopTrackingBoundCounts();
2937 d_partialModel.startQueueingBoundCounts();
2938 d_partialModel.attemptToReclaimReleased();
2939 }
2940 return res;
2941 }
2942
getTreeLog()2943 TreeLog& TheoryArithPrivate::getTreeLog(){
2944 if(d_treeLog == NULL){
2945 d_treeLog = new TreeLog();
2946 }
2947 return *d_treeLog;
2948 }
2949
getApproxStats()2950 ApproximateStatistics& TheoryArithPrivate::getApproxStats(){
2951 if(d_approxStats == NULL){
2952 d_approxStats = new ApproximateStatistics();
2953 }
2954 return *d_approxStats;
2955 }
2956
branchToNode(ApproximateSimplex * approx,const NodeLog & bn) const2957 Node TheoryArithPrivate::branchToNode(ApproximateSimplex* approx,
2958 const NodeLog& bn) const
2959 {
2960 Assert(bn.isBranch());
2961 ArithVar v = approx->getBranchVar(bn);
2962 if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){
2963 if(d_partialModel.hasNode(v)){
2964 Node n = d_partialModel.asNode(v);
2965 double dval = bn.branchValue();
2966 Maybe<Rational> maybe_value = ApproximateSimplex::estimateWithCFE(dval);
2967 if (!maybe_value)
2968 {
2969 return Node::null();
2970 }
2971 Rational fl(maybe_value.value().floor());
2972 NodeManager* nm = NodeManager::currentNM();
2973 Node leq = nm->mkNode(kind::LEQ, n, mkRationalNode(fl));
2974 Node norm = Rewriter::rewrite(leq);
2975 return norm;
2976 }
2977 }
2978 return Node::null();
2979 }
2980
cutToLiteral(ApproximateSimplex * approx,const CutInfo & ci) const2981 Node TheoryArithPrivate::cutToLiteral(ApproximateSimplex* approx, const CutInfo& ci) const{
2982 Assert(ci.reconstructed());
2983
2984 const DenseMap<Rational>& lhs = ci.getReconstruction().lhs;
2985 Node sum = toSumNode(d_partialModel, lhs);
2986 if(!sum.isNull()){
2987 Kind k = ci.getKind();
2988 Assert(k == kind::LEQ || k == kind::GEQ);
2989 Node rhs = mkRationalNode(ci.getReconstruction().rhs);
2990
2991 NodeManager* nm = NodeManager::currentNM();
2992 Node ineq = nm->mkNode(k, sum, rhs);
2993 return Rewriter::rewrite(ineq);
2994 }
2995 return Node::null();
2996 }
2997
replayLemmas(ApproximateSimplex * approx)2998 bool TheoryArithPrivate::replayLemmas(ApproximateSimplex* approx){
2999 ++(d_statistics.d_mipReplayLemmaCalls);
3000 bool anythingnew = false;
3001
3002 TreeLog& tl = getTreeLog();
3003 NodeLog& root = tl.getRootNode();
3004 root.applySelected(); /* set row ids */
3005
3006 vector<const CutInfo*> cuts = approx->getValidCuts(root);
3007 for(size_t i =0, N =cuts.size(); i < N; ++i){
3008 const CutInfo* cut = cuts[i];
3009 Assert(cut->reconstructed());
3010 Assert(cut->proven());
3011
3012 const DenseMap<Rational>& row = cut->getReconstruction().lhs;
3013 if(!complexityBelow(row, options::lemmaRejectCutSize())){
3014 ++(d_statistics.d_cutsRejectedDuringLemmas);
3015 continue;
3016 }
3017
3018 Node cutConstraint = cutToLiteral(approx, *cut);
3019 if(!cutConstraint.isNull()){
3020 const ConstraintCPVec& exp = cut->getExplanation();
3021 Node asLemma = Constraint::externalExplainByAssertions(exp);
3022
3023 Node implied = Rewriter::rewrite(cutConstraint);
3024 anythingnew = anythingnew || !isSatLiteral(implied);
3025
3026 Node implication = asLemma.impNode(implied);
3027 // DO NOT CALL OUTPUT LEMMA!
3028 d_approxCuts.push_back(implication);
3029 Debug("approx::lemmas") << "cut["<<i<<"] " << implication << endl;
3030 ++(d_statistics.d_mipExternalCuts);
3031 }
3032 }
3033 if(root.isBranch()){
3034 Node lit = branchToNode(approx, root);
3035 if(!lit.isNull()){
3036 anythingnew = anythingnew || !isSatLiteral(lit);
3037 Node branch = lit.orNode(lit.notNode());
3038 d_approxCuts.push_back(branch);
3039 ++(d_statistics.d_mipExternalBranch);
3040 Debug("approx::lemmas") << "branching "<< root <<" as " << branch << endl;
3041 }
3042 }
3043 return anythingnew;
3044 }
3045
turnOffApproxFor(int32_t rounds)3046 void TheoryArithPrivate::turnOffApproxFor(int32_t rounds){
3047 d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff + rounds;
3048 ++(d_statistics.d_approxDisabled);
3049 }
3050
safeToCallApprox() const3051 bool TheoryArithPrivate::safeToCallApprox() const{
3052 unsigned numRows = 0;
3053 unsigned numCols = 0;
3054 var_iterator vi = var_begin(), vi_end = var_end();
3055 // Assign each variable to a row and column variable as it appears in the input
3056 for(; vi != vi_end && !(numRows > 0 && numCols > 0); ++vi){
3057 ArithVar v = *vi;
3058
3059 if(d_partialModel.isAuxiliary(v)){
3060 ++numRows;
3061 }else{
3062 ++numCols;
3063 }
3064 }
3065 return (numRows > 0 && numCols > 0);
3066 }
3067
3068 // solve()
3069 // res = solveRealRelaxation(effortLevel);
3070 // switch(res){
3071 // case LinFeas:
3072 // case LinInfeas:
3073 // return replay()
3074 // case Unknown:
3075 // case Error
3076 // if()
solveInteger(Theory::Effort effortLevel)3077 void TheoryArithPrivate::solveInteger(Theory::Effort effortLevel){
3078 if(!safeToCallApprox()) { return; }
3079
3080 Assert(safeToCallApprox());
3081 TimerStat::CodeTimer codeTimer(d_statistics.d_solveIntTimer);
3082
3083 ++(d_statistics.d_solveIntCalls);
3084 d_statistics.d_inSolveInteger.setData(1);
3085
3086 if(!Theory::fullEffort(effortLevel)){
3087 d_solveIntAttempts++;
3088 ++(d_statistics.d_solveStandardEffort);
3089 }
3090
3091 // if integers are attempted,
3092 Assert(options::useApprox());
3093 Assert(ApproximateSimplex::enabled());
3094
3095 int level = getSatContext()->getLevel();
3096 d_lastContextIntegerAttempted = level;
3097
3098
3099 static const int32_t mipLimit = 200000;
3100
3101 TreeLog& tl = getTreeLog();
3102 ApproximateStatistics& stats = getApproxStats();
3103 ApproximateSimplex* approx =
3104 ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
3105
3106 approx->setPivotLimit(mipLimit);
3107 if(!d_guessedCoeffSet){
3108 d_guessedCoeffs = approx->heuristicOptCoeffs();
3109 d_guessedCoeffSet = true;
3110 }
3111 if(!d_guessedCoeffs.empty()){
3112 approx->setOptCoeffs(d_guessedCoeffs);
3113 }
3114 static const int32_t depthForLikelyInfeasible = 10;
3115 int maxDepthPass1 = d_likelyIntegerInfeasible ?
3116 depthForLikelyInfeasible : options::maxApproxDepth();
3117 approx->setBranchingDepth(maxDepthPass1);
3118 approx->setBranchOnVariableLimit(100);
3119 LinResult relaxRes = approx->solveRelaxation();
3120 if( relaxRes == LinFeasible ){
3121 MipResult mipRes = MipUnknown;
3122 {
3123 TimerStat::CodeTimer codeTimer(d_statistics.d_mipTimer);
3124 mipRes = approx->solveMIP(false);
3125 }
3126
3127 Debug("arith::solveInteger") << "mipRes " << mipRes << endl;
3128 switch(mipRes) {
3129 case MipBingo:
3130 // attempt the solution
3131 {
3132 ++(d_statistics.d_solveIntModelsAttempts);
3133
3134 d_partialModel.stopQueueingBoundCounts();
3135 UpdateTrackingCallback utcb(&d_linEq);
3136 d_partialModel.processBoundsQueue(utcb);
3137 d_linEq.startTrackingBoundCounts();
3138
3139 ApproximateSimplex::Solution mipSolution;
3140 mipSolution = approx->extractMIP();
3141 importSolution(mipSolution);
3142 solveRelaxationOrPanic(effortLevel);
3143
3144 if(d_qflraStatus == Result::SAT){
3145 if(!anyConflict()){
3146 if(ARITHVAR_SENTINEL == nextIntegerViolatation(false)){
3147 ++(d_statistics.d_solveIntModelsSuccessful);
3148 }
3149 }
3150 }
3151
3152 // shutdown simplex
3153 d_linEq.stopTrackingBoundCounts();
3154 d_partialModel.startQueueingBoundCounts();
3155 }
3156 break;
3157 case MipClosed:
3158 /* All integer branches closed */
3159 approx->setPivotLimit(2*mipLimit);
3160 {
3161 TimerStat::CodeTimer codeTimer(d_statistics.d_mipTimer);
3162 mipRes = approx->solveMIP(true);
3163 }
3164
3165 if(mipRes == MipClosed){
3166 d_likelyIntegerInfeasible = true;
3167 replayLog(approx);
3168 AlwaysAssert(anyConflict() || d_qflraStatus != Result::SAT);
3169
3170 if(!anyConflict()){
3171 solveRealRelaxation(effortLevel);
3172 }
3173 }
3174 if(!(anyConflict() || !d_approxCuts.empty())){
3175 turnOffApproxFor(options::replayNumericFailurePenalty());
3176 }
3177 break;
3178 case BranchesExhausted:
3179 case ExecExhausted:
3180 case PivotsExhauasted:
3181 if(mipRes == BranchesExhausted){
3182 ++d_statistics.d_branchesExhausted;
3183 }else if(mipRes == ExecExhausted){
3184 ++d_statistics.d_execExhausted;
3185 }else if(mipRes == PivotsExhauasted){
3186 ++d_statistics.d_pivotsExhausted;
3187 }
3188
3189 approx->setPivotLimit(2*mipLimit);
3190 approx->setBranchingDepth(2);
3191 {
3192 TimerStat::CodeTimer codeTimer(d_statistics.d_mipTimer);
3193 mipRes = approx->solveMIP(true);
3194 }
3195 replayLemmas(approx);
3196 break;
3197 case MipUnknown:
3198 break;
3199 }
3200 }
3201 delete approx;
3202
3203 if(!Theory::fullEffort(effortLevel)){
3204 if(anyConflict() || !d_approxCuts.empty()){
3205 d_solveIntMaybeHelp++;
3206 }
3207 }
3208
3209 d_statistics.d_inSolveInteger.setData(0);
3210 }
3211
selectSimplex(bool pass1)3212 SimplexDecisionProcedure& TheoryArithPrivate::selectSimplex(bool pass1){
3213 if(pass1){
3214 if(d_pass1SDP == NULL){
3215 if(options::useFC()){
3216 d_pass1SDP = (SimplexDecisionProcedure*)(&d_fcSimplex);
3217 }else if(options::useSOI()){
3218 d_pass1SDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
3219 }else{
3220 d_pass1SDP = (SimplexDecisionProcedure*)(&d_dualSimplex);
3221 }
3222 }
3223 Assert(d_pass1SDP != NULL);
3224 return *d_pass1SDP;
3225 }else{
3226 if(d_otherSDP == NULL){
3227 if(options::useFC()){
3228 d_otherSDP = (SimplexDecisionProcedure*)(&d_fcSimplex);
3229 }else if(options::useSOI()){
3230 d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
3231 }else{
3232 d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
3233 }
3234 }
3235 Assert(d_otherSDP != NULL);
3236 return *d_otherSDP;
3237 }
3238 }
3239
importSolution(const ApproximateSimplex::Solution & solution)3240 void TheoryArithPrivate::importSolution(const ApproximateSimplex::Solution& solution){
3241 if(Debug.isOn("arith::importSolution")){
3242 Debug("arith::importSolution") << "importSolution before " << d_qflraStatus << endl;
3243 d_partialModel.printEntireModel(Debug("arith::importSolution"));
3244 }
3245
3246 d_qflraStatus = d_attemptSolSimplex.attempt(solution);
3247
3248 if(Debug.isOn("arith::importSolution")){
3249 Debug("arith::importSolution") << "importSolution intermediate " << d_qflraStatus << endl;
3250 d_partialModel.printEntireModel(Debug("arith::importSolution"));
3251 }
3252
3253 if(d_qflraStatus != Result::UNSAT){
3254 static const int32_t pass2Limit = 20;
3255 int16_t oldCap = options::arithStandardCheckVarOrderPivots();
3256 options::arithStandardCheckVarOrderPivots.set(pass2Limit);
3257 SimplexDecisionProcedure& simplex = selectSimplex(false);
3258 d_qflraStatus = simplex.findModel(false);
3259 options::arithStandardCheckVarOrderPivots.set(oldCap);
3260 }
3261
3262 if(Debug.isOn("arith::importSolution")){
3263 Debug("arith::importSolution") << "importSolution after " << d_qflraStatus << endl;
3264 d_partialModel.printEntireModel(Debug("arith::importSolution"));
3265 }
3266 }
3267
solveRelaxationOrPanic(Theory::Effort effortLevel)3268 bool TheoryArithPrivate::solveRelaxationOrPanic(Theory::Effort effortLevel){
3269 // if at this point the linear relaxation is still unknown,
3270 // attempt to branch an integer variable as a last ditch effort on full check
3271 if(d_qflraStatus == Result::SAT_UNKNOWN){
3272 d_qflraStatus = selectSimplex(true).findModel(false);
3273 }
3274
3275 if(Theory::fullEffort(effortLevel) && d_qflraStatus == Result::SAT_UNKNOWN){
3276 ArithVar canBranch = nextIntegerViolatation(false);
3277 if(canBranch != ARITHVAR_SENTINEL){
3278 ++d_statistics.d_panicBranches;
3279 Node branch = branchIntegerVariable(canBranch);
3280 Assert(branch.getKind() == kind::OR);
3281 Node rwbranch = Rewriter::rewrite(branch[0]);
3282 if(!isSatLiteral(rwbranch)){
3283 d_approxCuts.push_back(branch);
3284 return true;
3285 }
3286 }
3287 d_qflraStatus = selectSimplex(false).findModel(true);
3288 }
3289 return false;
3290 }
3291
solveRealRelaxation(Theory::Effort effortLevel)3292 bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
3293 TimerStat::CodeTimer codeTimer(d_statistics.d_solveRealRelaxTimer);
3294 Assert(d_qflraStatus != Result::SAT);
3295
3296 d_partialModel.stopQueueingBoundCounts();
3297 UpdateTrackingCallback utcb(&d_linEq);
3298 d_partialModel.processBoundsQueue(utcb);
3299 d_linEq.startTrackingBoundCounts();
3300
3301 bool noPivotLimit = Theory::fullEffort(effortLevel) ||
3302 !options::restrictedPivots();
3303
3304 SimplexDecisionProcedure& simplex = selectSimplex(true);
3305
3306 bool useApprox = options::useApprox() && ApproximateSimplex::enabled() && getSolveIntegerResource();
3307
3308 Debug("TheoryArithPrivate::solveRealRelaxation")
3309 << "solveRealRelaxation() approx"
3310 << " " << options::useApprox()
3311 << " " << ApproximateSimplex::enabled()
3312 << " " << useApprox
3313 << " " << safeToCallApprox()
3314 << endl;
3315
3316 bool noPivotLimitPass1 = noPivotLimit && !useApprox;
3317 d_qflraStatus = simplex.findModel(noPivotLimitPass1);
3318
3319 Debug("TheoryArithPrivate::solveRealRelaxation")
3320 << "solveRealRelaxation()" << " pass1 " << d_qflraStatus << endl;
3321
3322 if(d_qflraStatus == Result::SAT_UNKNOWN && useApprox && safeToCallApprox()){
3323 // pass2: fancy-final
3324 static const int32_t relaxationLimit = 10000;
3325 Assert(ApproximateSimplex::enabled());
3326
3327 TreeLog& tl = getTreeLog();
3328 ApproximateStatistics& stats = getApproxStats();
3329 ApproximateSimplex* approxSolver =
3330 ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
3331
3332 approxSolver->setPivotLimit(relaxationLimit);
3333
3334 if(!d_guessedCoeffSet){
3335 d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
3336 d_guessedCoeffSet = true;
3337 }
3338 if(!d_guessedCoeffs.empty()){
3339 approxSolver->setOptCoeffs(d_guessedCoeffs);
3340 }
3341
3342 ++d_statistics.d_relaxCalls;
3343
3344 ApproximateSimplex::Solution relaxSolution;
3345 LinResult relaxRes = LinUnknown;
3346 {
3347 TimerStat::CodeTimer codeTimer(d_statistics.d_lpTimer);
3348 relaxRes = approxSolver->solveRelaxation();
3349 }
3350 Debug("solveRealRelaxation") << "solve relaxation? " << endl;
3351 switch(relaxRes){
3352 case LinFeasible:
3353 Debug("solveRealRelaxation") << "lin feasible? " << endl;
3354 ++d_statistics.d_relaxLinFeas;
3355 relaxSolution = approxSolver->extractRelaxation();
3356 importSolution(relaxSolution);
3357 if(d_qflraStatus != Result::SAT){
3358 ++d_statistics.d_relaxLinFeasFailures;
3359 }
3360 break;
3361 case LinInfeasible:
3362 // todo attempt to recreate approximate conflict
3363 ++d_statistics.d_relaxLinInfeas;
3364 Debug("solveRealRelaxation") << "lin infeasible " << endl;
3365 relaxSolution = approxSolver->extractRelaxation();
3366 importSolution(relaxSolution);
3367 if(d_qflraStatus != Result::UNSAT){
3368 ++d_statistics.d_relaxLinInfeasFailures;
3369 }
3370 break;
3371 case LinExhausted:
3372 ++d_statistics.d_relaxLinExhausted;
3373 Debug("solveRealRelaxation") << "exhuasted " << endl;
3374 break;
3375 case LinUnknown:
3376 default:
3377 ++d_statistics.d_relaxOthers;
3378 break;
3379 }
3380 delete approxSolver;
3381
3382 }
3383
3384 bool emmittedConflictOrSplit = solveRelaxationOrPanic(effortLevel);
3385
3386 // TODO Save zeroes with no conflicts
3387 d_linEq.stopTrackingBoundCounts();
3388 d_partialModel.startQueueingBoundCounts();
3389
3390 return emmittedConflictOrSplit;
3391 }
3392
3393 // LinUnknown, /* Unknown error */
3394 // LinFeasible, /* Relaxation is feasible */
3395 // LinInfeasible, /* Relaxation is infeasible/all integer branches closed */
3396 // LinExhausted
3397 // // Fancy final tries the following strategy
3398 // // At final check, try the preferred simplex solver with a pivot cap
3399 // // If that failed, swap the the other simplex solver
3400 // // If that failed, check if there are integer variables to cut
3401 // // If that failed, do a simplex without a pivot limit
3402
3403 // int16_t oldCap = options::arithStandardCheckVarOrderPivots();
3404
3405 // static const int32_t pass2Limit = 10;
3406 // static const int32_t relaxationLimit = 10000;
3407 // static const int32_t mipLimit = 200000;
3408
3409 // //cout << "start" << endl;
3410 // d_qflraStatus = simplex.findModel(false);
3411 // //cout << "end" << endl;
3412 // if(d_qflraStatus == Result::SAT_UNKNOWN ||
3413 // (d_qflraStatus == Result::SAT && !hasIntegerModel() && !d_likelyIntegerInfeasible)){
3414
3415 // ApproximateSimplex* approxSolver = ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, *(getTreeLog()), *(getApproxStats()));
3416 // approxSolver->setPivotLimit(relaxationLimit);
3417
3418 // if(!d_guessedCoeffSet){
3419 // d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
3420 // d_guessedCoeffSet = true;
3421 // }
3422 // if(!d_guessedCoeffs.empty()){
3423 // approxSolver->setOptCoeffs(d_guessedCoeffs);
3424 // }
3425
3426 // MipResult mipRes;
3427 // ApproximateSimplex::Solution relaxSolution, mipSolution;
3428 // LinResult relaxRes = approxSolver->solveRelaxation();
3429 // switch(relaxRes){
3430 // case LinFeasible:
3431 // {
3432 // relaxSolution = approxSolver->extractRelaxation();
3433
3434 // /* If the approximate solver known to be integer infeasible
3435 // * only redo*/
3436 // int maxDepth =
3437 // d_likelyIntegerInfeasible ? 1 : options::arithMaxBranchDepth();
3438
3439
3440 // if(d_likelyIntegerInfeasible){
3441 // d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
3442 // }else{
3443 // approxSolver->setPivotLimit(mipLimit);
3444 // mipRes = approxSolver->solveMIP(false);
3445 // if(mipRes == ApproximateSimplex::ApproxUnsat){
3446 // mipRes = approxSolver->solveMIP(true);
3447 // }
3448 // d_errorSet.reduceToSignals();
3449 // //Message() << "here" << endl;
3450 // if(mipRes == ApproximateSimplex::ApproxSat){
3451 // mipSolution = approxSolver->extractMIP();
3452 // d_qflraStatus = d_attemptSolSimplex.attempt(mipSolution);
3453 // }else{
3454 // if(mipRes == ApproximateSimplex::ApproxUnsat){
3455 // d_likelyIntegerInfeasible = true;
3456 // }
3457 // vector<Node> lemmas = approxSolver->getValidCuts();
3458 // for(size_t i = 0; i < lemmas.size(); ++i){
3459 // d_approxCuts.pushback(lemmas[i]);
3460 // }
3461 // d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
3462 // }
3463 // }
3464 // options::arithStandardCheckVarOrderPivots.set(pass2Limit);
3465 // if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
3466 // //Message() << "done" << endl;
3467 // }
3468 // break;
3469 // case ApproximateSimplex::ApproxUnsat:
3470 // {
3471 // ApproximateSimplex::Solution sol = approxSolver->extractRelaxation();
3472
3473 // d_qflraStatus = d_attemptSolSimplex.attempt(sol);
3474 // options::arithStandardCheckVarOrderPivots.set(pass2Limit);
3475
3476 // if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
3477 // }
3478 // break;
3479 // default:
3480 // break;
3481 // }
3482 // delete approxSolver;
3483 // }
3484 // }
3485
3486 // if(!useFancyFinal){
3487 // d_qflraStatus = simplex.findModel(noPivotLimit);
3488 // }else{
3489
3490
3491 // if(d_qflraStatus == Result::SAT_UNKNOWN){
3492 // //Message() << "got sat unknown" << endl;
3493 // vector<ArithVar> toCut = cutAllBounded();
3494 // if(toCut.size() > 0){
3495 // //branchVector(toCut);
3496 // emmittedConflictOrSplit = true;
3497 // }else{
3498 // //Message() << "splitting" << endl;
3499
3500 // d_qflraStatus = simplex.findModel(noPivotLimit);
3501 // }
3502 // }
3503 // options::arithStandardCheckVarOrderPivots.set(oldCap);
3504 // }
3505
3506 // // TODO Save zeroes with no conflicts
3507 // d_linEq.stopTrackingBoundCounts();
3508 // d_partialModel.startQueueingBoundCounts();
3509
3510 // return emmittedConflictOrSplit;
3511 // }
3512
hasFreshArithLiteral(Node n) const3513 bool TheoryArithPrivate::hasFreshArithLiteral(Node n) const{
3514 switch(n.getKind()){
3515 case kind::LEQ:
3516 case kind::GEQ:
3517 case kind::GT:
3518 case kind::LT:
3519 return !isSatLiteral(n);
3520 case kind::EQUAL:
3521 if(n[0].getType().isReal()){
3522 return !isSatLiteral(n);
3523 }else if(n[0].getType().isBoolean()){
3524 return hasFreshArithLiteral(n[0]) ||
3525 hasFreshArithLiteral(n[1]);
3526 }else{
3527 return false;
3528 }
3529 case kind::IMPLIES:
3530 // try the rhs first
3531 return hasFreshArithLiteral(n[1]) ||
3532 hasFreshArithLiteral(n[0]);
3533 default:
3534 if(n.getType().isBoolean()){
3535 for(Node::iterator ni=n.begin(), nend=n.end(); ni!=nend; ++ni){
3536 Node child = *ni;
3537 if(hasFreshArithLiteral(child)){
3538 return true;
3539 }
3540 }
3541 }
3542 return false;
3543 }
3544 }
3545
check(Theory::Effort effortLevel)3546 void TheoryArithPrivate::check(Theory::Effort effortLevel){
3547 Assert(d_currentPropagationList.empty());
3548
3549 if(done() && effortLevel < Theory::EFFORT_FULL && ( d_qflraStatus == Result::SAT) ){
3550 return;
3551 }
3552
3553 if(effortLevel == Theory::EFFORT_LAST_CALL){
3554 if( options::nlExt() ){
3555 d_nonlinearExtension->check( effortLevel );
3556 }
3557 return;
3558 }
3559
3560 TimerStat::CodeTimer checkTimer(d_containing.d_checkTime);
3561 //cout << "TheoryArithPrivate::check " << effortLevel << std::endl;
3562 Debug("effortlevel") << "TheoryArithPrivate::check " << effortLevel << std::endl;
3563 Debug("arith") << "TheoryArithPrivate::check begun " << effortLevel << std::endl;
3564
3565 if(Debug.isOn("arith::consistency")){
3566 Assert(unenqueuedVariablesAreConsistent());
3567 }
3568
3569 bool newFacts = !done();
3570 //If previous == SAT, then reverts on conflicts are safe
3571 //Otherwise, they are not and must be committed.
3572 Result::Sat previous = d_qflraStatus;
3573 if(newFacts){
3574 d_qflraStatus = Result::SAT_UNKNOWN;
3575 d_hasDoneWorkSinceCut = true;
3576 }
3577
3578 while(!done()){
3579 ConstraintP curr = constraintFromFactQueue();
3580 if(curr != NullConstraint){
3581 bool res CVC4_UNUSED = assertionCases(curr);
3582 Assert(!res || anyConflict());
3583 }
3584 if(anyConflict()){ break; }
3585 }
3586 if(!anyConflict()){
3587 while(!d_learnedBounds.empty()){
3588 // we may attempt some constraints twice. this is okay!
3589 ConstraintP curr = d_learnedBounds.front();
3590 d_learnedBounds.pop();
3591 Debug("arith::learned") << curr << endl;
3592
3593 bool res CVC4_UNUSED = assertionCases(curr);
3594 Assert(!res || anyConflict());
3595
3596 if(anyConflict()){ break; }
3597 }
3598 }
3599
3600 if(anyConflict()){
3601 d_qflraStatus = Result::UNSAT;
3602 if(options::revertArithModels() && previous == Result::SAT){
3603 ++d_statistics.d_revertsOnConflicts;
3604 Debug("arith::bt") << "clearing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
3605 revertOutOfConflict();
3606 d_errorSet.clear();
3607 }else{
3608 ++d_statistics.d_commitsOnConflicts;
3609 Debug("arith::bt") << "committing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
3610 d_partialModel.commitAssignmentChanges();
3611 revertOutOfConflict();
3612 }
3613 outputConflicts();
3614 //cout << "unate conflict 1 " << effortLevel << std::endl;
3615 return;
3616 }
3617
3618
3619 if(Debug.isOn("arith::print_assertions")) {
3620 debugPrintAssertions(Debug("arith::print_assertions"));
3621 }
3622
3623 bool emmittedConflictOrSplit = false;
3624 Assert(d_conflicts.empty());
3625
3626 bool useSimplex = d_qflraStatus != Result::SAT;
3627 Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3628 << "pre realRelax" << endl;
3629
3630 if(useSimplex){
3631 emmittedConflictOrSplit = solveRealRelaxation(effortLevel);
3632 }
3633 Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3634 << "post realRelax" << endl;
3635
3636
3637 Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3638 << "pre solveInteger" << endl;
3639
3640 if(attemptSolveInteger(effortLevel, emmittedConflictOrSplit)){
3641 solveInteger(effortLevel);
3642 if(anyConflict()){
3643 ++d_statistics.d_commitsOnConflicts;
3644 Debug("arith::bt") << "committing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
3645 revertOutOfConflict();
3646 d_errorSet.clear();
3647 outputConflicts();
3648 return;
3649 }
3650 }
3651
3652 Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3653 << "post solveInteger" << endl;
3654
3655 switch(d_qflraStatus){
3656 case Result::SAT:
3657 if(newFacts){
3658 ++d_statistics.d_nontrivialSatChecks;
3659 }
3660
3661 Debug("arith::bt") << "committing sap inConflit" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
3662 d_partialModel.commitAssignmentChanges();
3663 d_unknownsInARow = 0;
3664 if(Debug.isOn("arith::consistency")){
3665 Assert(entireStateIsConsistent("sat comit"));
3666 }
3667 if(useSimplex && options::collectPivots()){
3668 if(options::useFC()){
3669 d_statistics.d_satPivots << d_fcSimplex.getPivots();
3670 }else{
3671 d_statistics.d_satPivots << d_dualSimplex.getPivots();
3672 }
3673 }
3674 break;
3675 case Result::SAT_UNKNOWN:
3676 ++d_unknownsInARow;
3677 ++(d_statistics.d_unknownChecks);
3678 Assert(!Theory::fullEffort(effortLevel));
3679 Debug("arith::bt") << "committing unknown" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
3680 d_partialModel.commitAssignmentChanges();
3681 d_statistics.d_maxUnknownsInARow.maxAssign(d_unknownsInARow);
3682
3683 if(useSimplex && options::collectPivots()){
3684 if(options::useFC()){
3685 d_statistics.d_unknownPivots << d_fcSimplex.getPivots();
3686 }else{
3687 d_statistics.d_unknownPivots << d_dualSimplex.getPivots();
3688 }
3689 }
3690 break;
3691 case Result::UNSAT:
3692 d_unknownsInARow = 0;
3693
3694 ++d_statistics.d_commitsOnConflicts;
3695
3696 Debug("arith::bt") << "committing on conflict" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
3697 d_partialModel.commitAssignmentChanges();
3698 revertOutOfConflict();
3699
3700 if(Debug.isOn("arith::consistency::comitonconflict")){
3701 entireStateIsConsistent("commit on conflict");
3702 }
3703 outputConflicts();
3704 emmittedConflictOrSplit = true;
3705 Debug("arith::conflict") << "simplex conflict" << endl;
3706
3707 if(useSimplex && options::collectPivots()){
3708 if(options::useFC()){
3709 d_statistics.d_unsatPivots << d_fcSimplex.getPivots();
3710 }else{
3711 d_statistics.d_unsatPivots << d_dualSimplex.getPivots();
3712 }
3713 }
3714 break;
3715 default:
3716 Unimplemented();
3717 }
3718 d_statistics.d_avgUnknownsInARow.addEntry(d_unknownsInARow);
3719
3720 Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3721 << "pre approx cuts" << endl;
3722 if(!d_approxCuts.empty()){
3723 bool anyFresh = false;
3724 while(!d_approxCuts.empty()){
3725 Node lem = d_approxCuts.front();
3726 d_approxCuts.pop();
3727 Debug("arith::approx::cuts") << "approximate cut:" << lem << endl;
3728 anyFresh = anyFresh || hasFreshArithLiteral(lem);
3729 Debug("arith::lemma") << "approximate cut:" << lem << endl;
3730 outputLemma(lem);
3731 }
3732 if(anyFresh){
3733 emmittedConflictOrSplit = true;
3734 }
3735 }
3736
3737 Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3738 << "post approx cuts" << endl;
3739
3740 // This should be fine if sat or unknown
3741 if(!emmittedConflictOrSplit &&
3742 (options::arithPropagationMode() == UNATE_PROP ||
3743 options::arithPropagationMode() == BOTH_PROP)){
3744 TimerStat::CodeTimer codeTimer(d_statistics.d_newPropTime);
3745 Assert(d_qflraStatus != Result::UNSAT);
3746
3747 while(!d_currentPropagationList.empty() && !anyConflict()){
3748 ConstraintP curr = d_currentPropagationList.front();
3749 d_currentPropagationList.pop_front();
3750
3751 ConstraintType t = curr->getType();
3752 Assert(t != Disequality, "Disequalities are not allowed in d_currentPropagation");
3753
3754
3755 switch(t){
3756 case LowerBound:
3757 {
3758 ConstraintP prev = d_currentPropagationList.front();
3759 d_currentPropagationList.pop_front();
3760 d_constraintDatabase.unatePropLowerBound(curr, prev);
3761 break;
3762 }
3763 case UpperBound:
3764 {
3765 ConstraintP prev = d_currentPropagationList.front();
3766 d_currentPropagationList.pop_front();
3767 d_constraintDatabase.unatePropUpperBound(curr, prev);
3768 break;
3769 }
3770 case Equality:
3771 {
3772 ConstraintP prevLB = d_currentPropagationList.front();
3773 d_currentPropagationList.pop_front();
3774 ConstraintP prevUB = d_currentPropagationList.front();
3775 d_currentPropagationList.pop_front();
3776 d_constraintDatabase.unatePropEquality(curr, prevLB, prevUB);
3777 break;
3778 }
3779 default:
3780 Unhandled(curr->getType());
3781 }
3782 }
3783
3784 if(anyConflict()){
3785 Debug("arith::unate") << "unate conflict" << endl;
3786 revertOutOfConflict();
3787 d_qflraStatus = Result::UNSAT;
3788 outputConflicts();
3789 emmittedConflictOrSplit = true;
3790 //cout << "unate conflict " << endl;
3791 Debug("arith::bt") << "committing on unate conflict" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
3792
3793 Debug("arith::conflict") << "unate arith conflict" << endl;
3794 }
3795 }else{
3796 TimerStat::CodeTimer codeTimer(d_statistics.d_newPropTime);
3797 d_currentPropagationList.clear();
3798 }
3799 Assert( d_currentPropagationList.empty());
3800
3801 Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3802 << "post unate" << endl;
3803
3804 if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
3805 ++d_fullCheckCounter;
3806 }
3807 if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
3808 emmittedConflictOrSplit = splitDisequalities();
3809 }
3810 Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
3811 << "pos splitting" << endl;
3812
3813
3814 Debug("arith") << "integer? "
3815 << " conf/split " << emmittedConflictOrSplit
3816 << " fulleffort " << Theory::fullEffort(effortLevel)
3817 << " hasintmodel " << hasIntegerModel() << endl;
3818
3819 if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel) && !hasIntegerModel()){
3820 Node possibleConflict = Node::null();
3821 if(!emmittedConflictOrSplit && options::arithDioSolver()){
3822 possibleConflict = callDioSolver();
3823 if(possibleConflict != Node::null()){
3824 revertOutOfConflict();
3825 Debug("arith::conflict") << "dio conflict " << possibleConflict << endl;
3826 raiseBlackBoxConflict(possibleConflict);
3827 outputConflicts();
3828 emmittedConflictOrSplit = true;
3829 }
3830 }
3831
3832 if(!emmittedConflictOrSplit && d_hasDoneWorkSinceCut && options::arithDioSolver()){
3833 if(getDioCuttingResource()){
3834 Node possibleLemma = dioCutting();
3835 if(!possibleLemma.isNull()){
3836 emmittedConflictOrSplit = true;
3837 d_hasDoneWorkSinceCut = false;
3838 d_cutCount = d_cutCount + 1;
3839 Debug("arith::lemma") << "dio cut " << possibleLemma << endl;
3840 outputLemma(possibleLemma);
3841 }
3842 }
3843 }
3844
3845 if(!emmittedConflictOrSplit) {
3846 Node possibleLemma = roundRobinBranch();
3847 if(!possibleLemma.isNull()){
3848 ++(d_statistics.d_externalBranchAndBounds);
3849 d_cutCount = d_cutCount + 1;
3850 emmittedConflictOrSplit = true;
3851 Debug("arith::lemma") << "rrbranch lemma"
3852 << possibleLemma << endl;
3853 outputLemma(possibleLemma);
3854
3855 }
3856 }
3857
3858 if(options::maxCutsInContext() <= d_cutCount){
3859 if(d_diosolver.hasMoreDecompositionLemmas()){
3860 while(d_diosolver.hasMoreDecompositionLemmas()){
3861 Node decompositionLemma = d_diosolver.nextDecompositionLemma();
3862 Debug("arith::lemma") << "dio decomposition lemma "
3863 << decompositionLemma << endl;
3864 outputLemma(decompositionLemma);
3865 }
3866 }else{
3867 Debug("arith::restart") << "arith restart!" << endl;
3868 outputRestart();
3869 }
3870 }
3871 }//if !emmittedConflictOrSplit && fullEffort(effortLevel) && !hasIntegerModel()
3872
3873 if(!emmittedConflictOrSplit && effortLevel>=Theory::EFFORT_FULL){
3874 if( options::nlExt() ){
3875 d_nonlinearExtension->check( effortLevel );
3876 }
3877 }
3878
3879 if(Theory::fullEffort(effortLevel) && d_nlIncomplete){
3880 setIncomplete();
3881 }
3882
3883 if(Theory::fullEffort(effortLevel)){
3884 if(Debug.isOn("arith::consistency::final")){
3885 entireStateIsConsistent("arith::consistency::final");
3886 }
3887 // cout << "fulleffort" << getSatContext()->getLevel() << endl;
3888 // entireStateIsConsistent("arith::consistency::final");
3889 // cout << "emmittedConflictOrSplit" << emmittedConflictOrSplit << endl;
3890 }
3891
3892 if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
3893 if(Debug.isOn("arith::print_model")) {
3894 debugPrintModel(Debug("arith::print_model"));
3895 }
3896 Debug("arith") << "TheoryArithPrivate::check end" << std::endl;
3897 }
3898
branchIntegerVariable(ArithVar x) const3899 Node TheoryArithPrivate::branchIntegerVariable(ArithVar x) const {
3900 const DeltaRational& d = d_partialModel.getAssignment(x);
3901 Assert(!d.isIntegral());
3902 const Rational& r = d.getNoninfinitesimalPart();
3903 const Rational& i = d.getInfinitesimalPart();
3904 Trace("integers") << "integers: assignment to [[" << d_partialModel.asNode(x) << "]] is " << r << "[" << i << "]" << endl;
3905
3906 Assert(! (r.getDenominator() == 1 && i.getNumerator() == 0));
3907 Assert(!d.isIntegral());
3908 TNode var = d_partialModel.asNode(x);
3909 Integer floor_d = d.floor();
3910
3911 //Node eq = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::EQUAL, var, mkRationalNode(floor_d+1)));
3912 //Node diseq = eq.notNode();
3913
3914 Node ub = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::LEQ, var, mkRationalNode(floor_d)));
3915 Node lb = ub.notNode();
3916
3917
3918 //Node lem = NodeManager::currentNM()->mkNode(kind::OR, eq, diseq);
3919 Node lem = NodeManager::currentNM()->mkNode(kind::OR, ub, lb);
3920 Trace("integers") << "integers: branch & bound: " << lem << endl;
3921 if(isSatLiteral(lem[0])) {
3922 Debug("integers") << " " << lem[0] << " == " << getSatValue(lem[0]) << endl;
3923 } else {
3924 Debug("integers") << " " << lem[0] << " is not assigned a SAT literal" << endl;
3925 }
3926 if(isSatLiteral(lem[1])) {
3927 Debug("integers") << " " << lem[1] << " == " << getSatValue(lem[1]) << endl;
3928 } else {
3929 Debug("integers") << " " << lem[1] << " is not assigned a SAT literal" << endl;
3930 }
3931 return lem;
3932 }
3933
cutAllBounded() const3934 std::vector<ArithVar> TheoryArithPrivate::cutAllBounded() const{
3935 vector<ArithVar> lemmas;
3936 ArithVar max = d_partialModel.getNumberOfVariables();
3937
3938 if(options::doCutAllBounded() && max > 0){
3939 for(ArithVar iter = 0; iter != max; ++iter){
3940 //Do not include slack variables
3941 const DeltaRational& d = d_partialModel.getAssignment(iter);
3942 if(isIntegerInput(iter) &&
3943 !d_cutInContext.contains(iter) &&
3944 d_partialModel.hasUpperBound(iter) &&
3945 d_partialModel.hasLowerBound(iter) &&
3946 !d.isIntegral()){
3947 lemmas.push_back(iter);
3948 }
3949 }
3950 }
3951 return lemmas;
3952 }
3953
3954 /** Returns true if the roundRobinBranching() issues a lemma. */
roundRobinBranch()3955 Node TheoryArithPrivate::roundRobinBranch(){
3956 if(hasIntegerModel()){
3957 return Node::null();
3958 }else{
3959 ArithVar v = d_nextIntegerCheckVar;
3960
3961 Assert(isInteger(v));
3962 Assert(!isAuxiliaryVariable(v));
3963 return branchIntegerVariable(v);
3964 }
3965 }
3966
splitDisequalities()3967 bool TheoryArithPrivate::splitDisequalities(){
3968 bool splitSomething = false;
3969
3970 vector<ConstraintP> save;
3971
3972 while(!d_diseqQueue.empty()){
3973 ConstraintP front = d_diseqQueue.front();
3974 d_diseqQueue.pop();
3975
3976 if(front->isSplit()){
3977 Debug("arith::eq") << "split already" << endl;
3978 }else{
3979 Debug("arith::eq") << "not split already" << endl;
3980
3981 ArithVar lhsVar = front->getVariable();
3982
3983 const DeltaRational& lhsValue = d_partialModel.getAssignment(lhsVar);
3984 const DeltaRational& rhsValue = front->getValue();
3985 if(lhsValue == rhsValue){
3986 Debug("arith::lemma") << "Splitting on " << front << endl;
3987 Debug("arith::lemma") << "LHS value = " << lhsValue << endl;
3988 Debug("arith::lemma") << "RHS value = " << rhsValue << endl;
3989 Node lemma = front->split();
3990 ++(d_statistics.d_statDisequalitySplits);
3991
3992 Debug("arith::lemma") << "Now " << Rewriter::rewrite(lemma) << endl;
3993 outputLemma(lemma);
3994 //cout << "Now " << Rewriter::rewrite(lemma) << endl;
3995 splitSomething = true;
3996 }else if(d_partialModel.strictlyLessThanLowerBound(lhsVar, rhsValue)){
3997 Debug("arith::eq") << "can drop as less than lb" << front << endl;
3998 }else if(d_partialModel.strictlyGreaterThanUpperBound(lhsVar, rhsValue)){
3999 Debug("arith::eq") << "can drop as greater than ub" << front << endl;
4000 }else{
4001 Debug("arith::eq") << "save" << front << ": " <<lhsValue << " != " << rhsValue << endl;
4002 save.push_back(front);
4003 }
4004 }
4005 }
4006 vector<ConstraintP>::const_iterator i=save.begin(), i_end = save.end();
4007 for(; i != i_end; ++i){
4008 d_diseqQueue.push(*i);
4009 }
4010 return splitSomething;
4011 }
4012
4013 /**
4014 * Should be guarded by at least Debug.isOn("arith::print_assertions").
4015 * Prints to Debug("arith::print_assertions")
4016 */
debugPrintAssertions(std::ostream & out) const4017 void TheoryArithPrivate::debugPrintAssertions(std::ostream& out) const {
4018 out << "Assertions:" << endl;
4019 for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
4020 ArithVar i = *vi;
4021 if (d_partialModel.hasLowerBound(i)) {
4022 ConstraintP lConstr = d_partialModel.getLowerBoundConstraint(i);
4023 out << lConstr << endl;
4024 }
4025
4026 if (d_partialModel.hasUpperBound(i)) {
4027 ConstraintP uConstr = d_partialModel.getUpperBoundConstraint(i);
4028 out << uConstr << endl;
4029 }
4030 }
4031 context::CDQueue<ConstraintP>::const_iterator it = d_diseqQueue.begin();
4032 context::CDQueue<ConstraintP>::const_iterator it_end = d_diseqQueue.end();
4033 for(; it != it_end; ++ it) {
4034 out << *it << endl;
4035 }
4036 }
4037
debugPrintModel(std::ostream & out) const4038 void TheoryArithPrivate::debugPrintModel(std::ostream& out) const{
4039 out << "Model:" << endl;
4040 for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
4041 ArithVar i = *vi;
4042 if(d_partialModel.hasNode(i)){
4043 out << d_partialModel.asNode(i) << " : " <<
4044 d_partialModel.getAssignment(i);
4045 if(d_tableau.isBasic(i)){
4046 out << " (basic)";
4047 }
4048 out << endl;
4049 }
4050 }
4051 }
4052
needsCheckLastEffort()4053 bool TheoryArithPrivate::needsCheckLastEffort() {
4054 if( options::nlExt() ){
4055 return d_nonlinearExtension->needsCheckLastEffort();
4056 }else{
4057 return false;
4058 }
4059 }
4060
explain(TNode n)4061 Node TheoryArithPrivate::explain(TNode n) {
4062
4063 Debug("arith::explain") << "explain @" << getSatContext()->getLevel() << ": " << n << endl;
4064
4065 ConstraintP c = d_constraintDatabase.lookup(n);
4066 if(c != NullConstraint){
4067 Assert(!c->isAssumption());
4068 Node exp = c->externalExplainForPropagation();
4069 Debug("arith::explain") << "constraint explanation" << n << ":" << exp << endl;
4070 return exp;
4071 }else if(d_assertionsThatDoNotMatchTheirLiterals.find(n) != d_assertionsThatDoNotMatchTheirLiterals.end()){
4072 c = d_assertionsThatDoNotMatchTheirLiterals[n];
4073 if(!c->isAssumption()){
4074 Node exp = c->externalExplainForPropagation();
4075 Debug("arith::explain") << "assertions explanation" << n << ":" << exp << endl;
4076 return exp;
4077 }else{
4078 Debug("arith::explain") << "this is a strange mismatch" << n << endl;
4079 Assert(d_congruenceManager.canExplain(n));
4080 Debug("arith::explain") << "this is a strange mismatch" << n << endl;
4081 return d_congruenceManager.explain(n);
4082 }
4083 }else{
4084 Assert(d_congruenceManager.canExplain(n));
4085 Debug("arith::explain") << "dm explanation" << n << endl;
4086 return d_congruenceManager.explain(n);
4087 }
4088 }
4089
getCurrentSubstitution(int effort,std::vector<Node> & vars,std::vector<Node> & subs,std::map<Node,std::vector<Node>> & exp)4090 bool TheoryArithPrivate::getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
4091 if( options::nlExt() ){
4092 return d_nonlinearExtension->getCurrentSubstitution( effort, vars, subs, exp );
4093 }else{
4094 return false;
4095 }
4096 }
4097
isExtfReduced(int effort,Node n,Node on,std::vector<Node> & exp)4098 bool TheoryArithPrivate::isExtfReduced(int effort, Node n, Node on,
4099 std::vector<Node>& exp) {
4100 if (options::nlExt()) {
4101 std::pair<bool, Node> reduced =
4102 d_nonlinearExtension->isExtfReduced(effort, n, on, exp);
4103 if (!reduced.second.isNull()) {
4104 exp.clear();
4105 exp.push_back(reduced.second);
4106 }
4107 return reduced.first;
4108 } else {
4109 return false; // d_containing.isExtfReduced( effort, n, on );
4110 }
4111 }
4112
propagate(Theory::Effort e)4113 void TheoryArithPrivate::propagate(Theory::Effort e) {
4114 // This uses model values for safety. Disable for now.
4115 if(d_qflraStatus == Result::SAT &&
4116 (options::arithPropagationMode() == BOUND_INFERENCE_PROP ||
4117 options::arithPropagationMode() == BOTH_PROP)
4118 && hasAnyUpdates()){
4119 if(options::newProp()){
4120 propagateCandidatesNew();
4121 }else{
4122 propagateCandidates();
4123 }
4124 }else{
4125 clearUpdates();
4126 }
4127
4128 while(d_constraintDatabase.hasMorePropagations()){
4129 ConstraintCP c = d_constraintDatabase.nextPropagation();
4130 Debug("arith::prop") << "next prop" << getSatContext()->getLevel() << ": " << c << endl;
4131
4132 if(c->negationHasProof()){
4133 Debug("arith::prop") << "negation has proof " << c->getNegation() << endl;
4134 Debug("arith::prop") << c->getNegation()->externalExplainByAssertions()
4135 << endl;
4136 }
4137 Assert(!c->negationHasProof(), "A constraint has been propagated on the constraint propagation queue, but the negation has been set to true. Contact Tim now!");
4138
4139 if(!c->assertedToTheTheory()){
4140 Node literal = c->getLiteral();
4141 Debug("arith::prop") << "propagating @" << getSatContext()->getLevel() << " " << literal << endl;
4142
4143 outputPropagate(literal);
4144 }else{
4145 Debug("arith::prop") << "already asserted to the theory " << c->getLiteral() << endl;
4146 }
4147 }
4148
4149 while(d_congruenceManager.hasMorePropagations()){
4150 TNode toProp = d_congruenceManager.getNextPropagation();
4151
4152 //Currently if the flag is set this came from an equality detected by the
4153 //equality engine in the the difference manager.
4154 Node normalized = Rewriter::rewrite(toProp);
4155
4156 ConstraintP constraint = d_constraintDatabase.lookup(normalized);
4157 if(constraint == NullConstraint){
4158 Debug("arith::prop") << "propagating on non-constraint? " << toProp << endl;
4159
4160 outputPropagate(toProp);
4161 }else if(constraint->negationHasProof()){
4162 Node exp = d_congruenceManager.explain(toProp);
4163 Node notNormalized = normalized.getKind() == NOT ?
4164 normalized[0] : normalized.notNode();
4165 Node lp = flattenAnd(exp.andNode(notNormalized));
4166 Debug("arith::prop") << "propagate conflict" << lp << endl;
4167 raiseBlackBoxConflict(lp);
4168 outputConflicts();
4169 return;
4170 }else{
4171 Debug("arith::prop") << "propagating still?" << toProp << endl;
4172 outputPropagate(toProp);
4173 }
4174 }
4175 }
4176
getDeltaValue(TNode term) const4177 DeltaRational TheoryArithPrivate::getDeltaValue(TNode term) const
4178 {
4179 AlwaysAssert(d_qflraStatus != Result::SAT_UNKNOWN);
4180 Debug("arith::value") << term << std::endl;
4181
4182 if (d_partialModel.hasArithVar(term)) {
4183 ArithVar var = d_partialModel.asArithVar(term);
4184 return d_partialModel.getAssignment(var);
4185 }
4186
4187 switch (Kind kind = term.getKind()) {
4188 case kind::CONST_RATIONAL:
4189 return term.getConst<Rational>();
4190
4191 case kind::PLUS: { // 2+ args
4192 DeltaRational value(0);
4193 for (TNode::iterator i = term.begin(), iend = term.end(); i != iend;
4194 ++i) {
4195 value = value + getDeltaValue(*i);
4196 }
4197 return value;
4198 }
4199
4200 case kind::NONLINEAR_MULT:
4201 case kind::MULT: { // 2+ args
4202 Assert(!isSetup(term));
4203 DeltaRational value(1);
4204 for (TNode::iterator i = term.begin(), iend = term.end(); i != iend;
4205 ++i) {
4206 value = value * getDeltaValue(*i);
4207 }
4208 return value;
4209 }
4210 case kind::MINUS: { // 2 args
4211 return getDeltaValue(term[0]) - getDeltaValue(term[1]);
4212 }
4213 case kind::UMINUS: { // 1 arg
4214 return (-getDeltaValue(term[0]));
4215 }
4216
4217 case kind::DIVISION: { // 2 args
4218 Assert(!isSetup(term));
4219 return getDeltaValue(term[0]) / getDeltaValue(term[1]);
4220 }
4221 case kind::DIVISION_TOTAL:
4222 case kind::INTS_DIVISION_TOTAL:
4223 case kind::INTS_MODULUS_TOTAL: { // 2 args
4224 Assert(!isSetup(term));
4225 DeltaRational denominator = getDeltaValue(term[1]);
4226 if (denominator.isZero()) {
4227 return DeltaRational(0, 0);
4228 }
4229 DeltaRational numerator = getDeltaValue(term[0]);
4230 if (kind == kind::DIVISION_TOTAL) {
4231 return numerator / denominator;
4232 } else if (kind == kind::INTS_DIVISION_TOTAL) {
4233 return Rational(numerator.euclidianDivideQuotient(denominator));
4234 } else {
4235 Assert(kind == kind::INTS_MODULUS_TOTAL);
4236 return Rational(numerator.euclidianDivideRemainder(denominator));
4237 }
4238 }
4239
4240 default:
4241 throw ModelException(term, "No model assignment.");
4242 }
4243 }
4244
deltaValueForTotalOrder() const4245 Rational TheoryArithPrivate::deltaValueForTotalOrder() const{
4246 Rational min(2);
4247 std::set<DeltaRational> relevantDeltaValues;
4248 context::CDQueue<ConstraintP>::const_iterator qiter = d_diseqQueue.begin();
4249 context::CDQueue<ConstraintP>::const_iterator qiter_end = d_diseqQueue.end();
4250
4251 for(; qiter != qiter_end; ++qiter){
4252 ConstraintP curr = *qiter;
4253
4254 const DeltaRational& rhsValue = curr->getValue();
4255 relevantDeltaValues.insert(rhsValue);
4256 }
4257
4258 Theory::shared_terms_iterator shared_iter = d_containing.shared_terms_begin();
4259 Theory::shared_terms_iterator shared_end = d_containing.shared_terms_end();
4260 for(; shared_iter != shared_end; ++shared_iter){
4261 Node sharedCurr = *shared_iter;
4262
4263 // ModelException is fatal as this point. Don't catch!
4264 // DeltaRationalException is fatal as this point. Don't catch!
4265 DeltaRational val = getDeltaValue(sharedCurr);
4266 relevantDeltaValues.insert(val);
4267 }
4268
4269 for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
4270 ArithVar v = *vi;
4271 const DeltaRational& value = d_partialModel.getAssignment(v);
4272 relevantDeltaValues.insert(value);
4273 if( d_partialModel.hasLowerBound(v)){
4274 const DeltaRational& lb = d_partialModel.getLowerBound(v);
4275 relevantDeltaValues.insert(lb);
4276 }
4277 if( d_partialModel.hasUpperBound(v)){
4278 const DeltaRational& ub = d_partialModel.getUpperBound(v);
4279 relevantDeltaValues.insert(ub);
4280 }
4281 }
4282
4283 if(relevantDeltaValues.size() >= 2){
4284 std::set<DeltaRational>::const_iterator iter = relevantDeltaValues.begin();
4285 std::set<DeltaRational>::const_iterator iter_end = relevantDeltaValues.end();
4286 DeltaRational prev = *iter;
4287 ++iter;
4288 for(; iter != iter_end; ++iter){
4289 const DeltaRational& curr = *iter;
4290
4291 Assert(prev < curr);
4292
4293 DeltaRational::seperatingDelta(min, prev, curr);
4294 prev = curr;
4295 }
4296 }
4297
4298 Assert(min.sgn() > 0);
4299 Rational belowMin = min/Rational(2);
4300 return belowMin;
4301 }
4302
collectModelInfo(TheoryModel * m)4303 bool TheoryArithPrivate::collectModelInfo(TheoryModel* m)
4304 {
4305 AlwaysAssert(d_qflraStatus == Result::SAT);
4306 //AlwaysAssert(!d_nlIncomplete, "Arithmetic solver cannot currently produce models for input with nonlinear arithmetic constraints");
4307
4308 if(Debug.isOn("arith::collectModelInfo")){
4309 debugPrintFacts();
4310 }
4311
4312 Debug("arith::collectModelInfo") << "collectModelInfo() begin " << endl;
4313
4314 std::set<Node> termSet;
4315 d_containing.computeRelevantTerms(termSet);
4316
4317
4318 // Delta lasts at least the duration of the function call
4319 const Rational& delta = d_partialModel.getDelta();
4320 std::unordered_set<TNode, TNodeHashFunction> shared = d_containing.currentlySharedTerms();
4321
4322 // TODO:
4323 // This is not very good for user push/pop....
4324 // Revisit when implementing push/pop
4325 for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
4326 ArithVar v = *vi;
4327
4328 if(!isAuxiliaryVariable(v)){
4329 Node term = d_partialModel.asNode(v);
4330
4331 if((theoryOf(term) == THEORY_ARITH || shared.find(term) != shared.end())
4332 && termSet.find(term) != termSet.end()){
4333
4334 const DeltaRational& mod = d_partialModel.getAssignment(v);
4335 Rational qmodel = mod.substituteDelta(delta);
4336
4337 Node qNode = mkRationalNode(qmodel);
4338 Debug("arith::collectModelInfo") << "m->assertEquality(" << term << ", " << qmodel << ", true)" << endl;
4339
4340 if (!m->assertEquality(term, qNode, true))
4341 {
4342 return false;
4343 }
4344 }else{
4345 Debug("arith::collectModelInfo") << "Skipping m->assertEquality(" << term << ", true)" << endl;
4346
4347 }
4348 }
4349 }
4350
4351 // Iterate over equivalence classes in LinearEqualityModule
4352 // const eq::EqualityEngine& ee = d_congruenceManager.getEqualityEngine();
4353 // m->assertEqualityEngine(&ee);
4354
4355 Debug("arith::collectModelInfo") << "collectModelInfo() end " << endl;
4356 return true;
4357 }
4358
safeToReset() const4359 bool TheoryArithPrivate::safeToReset() const {
4360 Assert(!d_tableauSizeHasBeenModified);
4361 Assert(d_errorSet.noSignals());
4362
4363 ErrorSet::error_iterator error_iter = d_errorSet.errorBegin();
4364 ErrorSet::error_iterator error_end = d_errorSet.errorEnd();
4365 for(; error_iter != error_end; ++error_iter){
4366 ArithVar basic = *error_iter;
4367 if(!d_smallTableauCopy.isBasic(basic)){
4368 return false;
4369 }
4370 }
4371
4372 return true;
4373 }
4374
notifyRestart()4375 void TheoryArithPrivate::notifyRestart(){
4376 TimerStat::CodeTimer codeTimer(d_statistics.d_restartTimer);
4377
4378 if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
4379
4380 ++d_restartsCounter;
4381 d_solveIntMaybeHelp = 0;
4382 d_solveIntAttempts = 0;
4383 }
4384
entireStateIsConsistent(const string & s)4385 bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
4386 bool result = true;
4387 for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
4388 ArithVar var = *vi;
4389 //ArithVar var = d_partialModel.asArithVar(*i);
4390 if(!d_partialModel.assignmentIsConsistent(var)){
4391 d_partialModel.printModel(var);
4392 Warning() << s << ":" << "Assignment is not consistent for " << var << d_partialModel.asNode(var);
4393 if(d_tableau.isBasic(var)){
4394 Warning() << " (basic)";
4395 }
4396 Warning() << endl;
4397 result = false;
4398 }else if(d_partialModel.isInteger(var) && !d_partialModel.integralAssignment(var)){
4399 d_partialModel.printModel(var);
4400 Warning() << s << ":" << "Assignment is not integer for integer variable " << var << d_partialModel.asNode(var);
4401 if(d_tableau.isBasic(var)){
4402 Warning() << " (basic)";
4403 }
4404 Warning() << endl;
4405 result = false;
4406 }
4407 }
4408 return result;
4409 }
4410
unenqueuedVariablesAreConsistent()4411 bool TheoryArithPrivate::unenqueuedVariablesAreConsistent(){
4412 bool result = true;
4413 for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
4414 ArithVar var = *vi;
4415 if(!d_partialModel.assignmentIsConsistent(var)){
4416 if(!d_errorSet.inError(var)){
4417
4418 d_partialModel.printModel(var);
4419 Warning() << "Unenqueued var is not consistent for " << var << d_partialModel.asNode(var);
4420 if(d_tableau.isBasic(var)){
4421 Warning() << " (basic)";
4422 }
4423 Warning() << endl;
4424 result = false;
4425 } else if(Debug.isOn("arith::consistency::initial")){
4426 d_partialModel.printModel(var);
4427 Warning() << "Initial var is not consistent for " << var << d_partialModel.asNode(var);
4428 if(d_tableau.isBasic(var)){
4429 Warning() << " (basic)";
4430 }
4431 Warning() << endl;
4432 }
4433 }
4434 }
4435 return result;
4436 }
4437
presolve()4438 void TheoryArithPrivate::presolve(){
4439 TimerStat::CodeTimer codeTimer(d_statistics.d_presolveTime);
4440
4441 d_statistics.d_initialTableauSize.setData(d_tableau.size());
4442
4443 if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
4444
4445 static thread_local unsigned callCount = 0;
4446 if(Debug.isOn("arith::presolve")) {
4447 Debug("arith::presolve") << "TheoryArithPrivate::presolve #" << callCount << endl;
4448 callCount = callCount + 1;
4449 }
4450
4451 vector<Node> lemmas;
4452 if(!options::incrementalSolving()) {
4453 switch(options::arithUnateLemmaMode()){
4454 case NO_PRESOLVE_LEMMAS:
4455 break;
4456 case INEQUALITY_PRESOLVE_LEMMAS:
4457 d_constraintDatabase.outputUnateInequalityLemmas(lemmas);
4458 break;
4459 case EQUALITY_PRESOLVE_LEMMAS:
4460 d_constraintDatabase.outputUnateEqualityLemmas(lemmas);
4461 break;
4462 case ALL_PRESOLVE_LEMMAS:
4463 d_constraintDatabase.outputUnateInequalityLemmas(lemmas);
4464 d_constraintDatabase.outputUnateEqualityLemmas(lemmas);
4465 break;
4466 default:
4467 Unhandled(options::arithUnateLemmaMode());
4468 }
4469 }
4470
4471 vector<Node>::const_iterator i = lemmas.begin(), i_end = lemmas.end();
4472 for(; i != i_end; ++i){
4473 Node lem = *i;
4474 Debug("arith::oldprop") << " lemma lemma duck " <<lem << endl;
4475 outputLemma(lem);
4476 }
4477
4478 if (options::nlExt())
4479 {
4480 d_nonlinearExtension->presolve();
4481 }
4482 }
4483
getEqualityStatus(TNode a,TNode b)4484 EqualityStatus TheoryArithPrivate::getEqualityStatus(TNode a, TNode b) {
4485 if(d_qflraStatus == Result::SAT_UNKNOWN){
4486 return EQUALITY_UNKNOWN;
4487 }else{
4488 try {
4489 if (getDeltaValue(a) == getDeltaValue(b)) {
4490 return EQUALITY_TRUE_IN_MODEL;
4491 } else {
4492 return EQUALITY_FALSE_IN_MODEL;
4493 }
4494 } catch (DeltaRationalException& dr) {
4495 return EQUALITY_UNKNOWN;
4496 } catch (ModelException& me) {
4497 return EQUALITY_UNKNOWN;
4498 }
4499 }
4500 }
4501
propagateCandidateBound(ArithVar basic,bool upperBound)4502 bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound){
4503 ++d_statistics.d_boundComputations;
4504
4505 RowIndex ridx = d_tableau.basicToRowIndex(basic);
4506 DeltaRational bound = d_linEq.computeRowBound(ridx, upperBound, basic);
4507
4508 if((upperBound && d_partialModel.strictlyLessThanUpperBound(basic, bound)) ||
4509 (!upperBound && d_partialModel.strictlyGreaterThanLowerBound(basic, bound))){
4510
4511 // TODO: "Policy point"
4512 //We are only going to recreate the functionality for now.
4513 //In the future this can be improved to generate a temporary constraint
4514 //if none exists.
4515 //Experiment with doing this everytime or only when the new constraint
4516 //implies an unknown fact.
4517
4518 ConstraintType t = upperBound ? UpperBound : LowerBound;
4519 ConstraintP bestImplied = d_constraintDatabase.getBestImpliedBound(basic, t, bound);
4520
4521 // Node bestImplied = upperBound ?
4522 // d_apm.getBestImpliedUpperBound(basic, bound):
4523 // d_apm.getBestImpliedLowerBound(basic, bound);
4524
4525 if(bestImplied != NullConstraint){
4526 //This should be stronger
4527 Assert(!upperBound || bound <= bestImplied->getValue());
4528 Assert(!upperBound || d_partialModel.lessThanUpperBound(basic, bestImplied->getValue()));
4529
4530 Assert( upperBound || bound >= bestImplied->getValue());
4531 Assert( upperBound || d_partialModel.greaterThanLowerBound(basic, bestImplied->getValue()));
4532 //slightly changed
4533
4534 // ConstraintP c = d_constraintDatabase.lookup(bestImplied);
4535 // Assert(c != NullConstraint);
4536
4537 bool assertedToTheTheory = bestImplied->assertedToTheTheory();
4538 bool canBePropagated = bestImplied->canBePropagated();
4539 bool hasProof = bestImplied->hasProof();
4540
4541 Debug("arith::prop") << "arith::prop" << basic
4542 << " " << assertedToTheTheory
4543 << " " << canBePropagated
4544 << " " << hasProof
4545 << endl;
4546
4547 if(bestImplied->negationHasProof()){
4548 Warning() << "the negation of " << bestImplied << " : " << endl
4549 << "has proof " << bestImplied->getNegation() << endl
4550 << bestImplied->getNegation()->externalExplainByAssertions()
4551 << endl;
4552 }
4553
4554 if(!assertedToTheTheory && canBePropagated && !hasProof ){
4555 d_linEq.propagateBasicFromRow(bestImplied);
4556 // I think this can be skipped if canBePropagated is true
4557 //d_learnedBounds.push(bestImplied);
4558 if(Debug.isOn("arith::prop")){
4559 Debug("arith::prop") << "success " << bestImplied << endl;
4560 d_partialModel.printModel(basic, Debug("arith::prop"));
4561 }
4562 return true;
4563 }
4564 if(Debug.isOn("arith::prop")){
4565 Debug("arith::prop") << "failed " << basic
4566 << " " << bound
4567 << " " << assertedToTheTheory
4568 << " " << canBePropagated
4569 << " " << hasProof << endl;
4570 d_partialModel.printModel(basic, Debug("arith::prop"));
4571 }
4572 }
4573 }else if(Debug.isOn("arith::prop")){
4574 Debug("arith::prop") << "false " << bound << " ";
4575 d_partialModel.printModel(basic, Debug("arith::prop"));
4576 }
4577 return false;
4578 }
4579
propagateCandidate(ArithVar basic)4580 void TheoryArithPrivate::propagateCandidate(ArithVar basic){
4581 bool success = false;
4582 RowIndex ridx = d_tableau.basicToRowIndex(basic);
4583
4584 bool tryLowerBound =
4585 d_partialModel.strictlyAboveLowerBound(basic) &&
4586 d_linEq.rowLacksBound(ridx, false, basic) == NULL;
4587
4588 bool tryUpperBound =
4589 d_partialModel.strictlyBelowUpperBound(basic) &&
4590 d_linEq.rowLacksBound(ridx, true, basic) == NULL;
4591
4592 if(tryLowerBound){
4593 success |= propagateCandidateLowerBound(basic);
4594 }
4595 if(tryUpperBound){
4596 success |= propagateCandidateUpperBound(basic);
4597 }
4598 if(success){
4599 ++d_statistics.d_boundPropagations;
4600 }
4601 }
4602
propagateCandidates()4603 void TheoryArithPrivate::propagateCandidates(){
4604 TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
4605
4606 Debug("arith::prop") << "propagateCandidates begin" << endl;
4607
4608 Assert(d_candidateBasics.empty());
4609
4610 if(d_updatedBounds.empty()){ return; }
4611
4612 DenseSet::const_iterator i = d_updatedBounds.begin();
4613 DenseSet::const_iterator end = d_updatedBounds.end();
4614 for(; i != end; ++i){
4615 ArithVar var = *i;
4616 if(d_tableau.isBasic(var) &&
4617 d_tableau.basicRowLength(var) <= options::arithPropagateMaxLength()){
4618 d_candidateBasics.softAdd(var);
4619 }else{
4620 Tableau::ColIterator basicIter = d_tableau.colIterator(var);
4621 for(; !basicIter.atEnd(); ++basicIter){
4622 const Tableau::Entry& entry = *basicIter;
4623 RowIndex ridx = entry.getRowIndex();
4624 ArithVar rowVar = d_tableau.rowIndexToBasic(ridx);
4625 Assert(entry.getColVar() == var);
4626 Assert(d_tableau.isBasic(rowVar));
4627 if(d_tableau.getRowLength(ridx) <= options::arithPropagateMaxLength()){
4628 d_candidateBasics.softAdd(rowVar);
4629 }
4630 }
4631 }
4632 }
4633 d_updatedBounds.purge();
4634
4635 while(!d_candidateBasics.empty()){
4636 ArithVar candidate = d_candidateBasics.back();
4637 d_candidateBasics.pop_back();
4638 Assert(d_tableau.isBasic(candidate));
4639 propagateCandidate(candidate);
4640 }
4641 Debug("arith::prop") << "propagateCandidates end" << endl << endl << endl;
4642 }
4643
propagateCandidatesNew()4644 void TheoryArithPrivate::propagateCandidatesNew(){
4645 /* Four criteria must be met for progagation on a variable to happen using a row:
4646 * 0: A new bound has to have been added to the row.
4647 * 1: The hasBoundsCount for the row must be "full" or be full minus one variable
4648 * (This is O(1) to check, but requires book keeping.)
4649 * 2: The current assignment must be strictly smaller/greater than the current bound.
4650 * assign(x) < upper(x)
4651 * (This is O(1) to compute.)
4652 * 3: There is a bound that is strictly smaller/greater than the current assignment.
4653 * assign(x) < c for some x <= c literal
4654 * (This is O(log n) to compute.)
4655 * 4: The implied bound on x is strictly smaller/greater than the current bound.
4656 * (This is O(n) to compute.)
4657 */
4658
4659 TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime);
4660 Debug("arith::prop") << "propagateCandidatesNew begin" << endl;
4661
4662 Assert(d_qflraStatus == Result::SAT);
4663 if(d_updatedBounds.empty()){ return; }
4664 dumpUpdatedBoundsToRows();
4665 Assert(d_updatedBounds.empty());
4666
4667 if(!d_candidateRows.empty()){
4668 UpdateTrackingCallback utcb(&d_linEq);
4669 d_partialModel.processBoundsQueue(utcb);
4670 }
4671
4672 while(!d_candidateRows.empty()){
4673 RowIndex candidate = d_candidateRows.back();
4674 d_candidateRows.pop_back();
4675 propagateCandidateRow(candidate);
4676 }
4677 Debug("arith::prop") << "propagateCandidatesNew end" << endl << endl << endl;
4678 }
4679
propagateMightSucceed(ArithVar v,bool ub) const4680 bool TheoryArithPrivate::propagateMightSucceed(ArithVar v, bool ub) const{
4681 int cmp = ub ? d_partialModel.cmpAssignmentUpperBound(v)
4682 : d_partialModel.cmpAssignmentLowerBound(v);
4683 bool hasSlack = ub ? cmp < 0 : cmp > 0;
4684 if(hasSlack){
4685 ConstraintType t = ub ? UpperBound : LowerBound;
4686 const DeltaRational& a = d_partialModel.getAssignment(v);
4687
4688 if(isInteger(v) && !a.isIntegral()){
4689 return true;
4690 }
4691
4692 ConstraintP strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
4693 if(strongestPossible == NullConstraint){
4694 return false;
4695 }else{
4696 bool assertedToTheTheory = strongestPossible->assertedToTheTheory();
4697 bool canBePropagated = strongestPossible->canBePropagated();
4698 bool hasProof = strongestPossible->hasProof();
4699
4700 return !assertedToTheTheory && canBePropagated && !hasProof;
4701 }
4702 }else{
4703 return false;
4704 }
4705 }
4706
attemptSingleton(RowIndex ridx,bool rowUp)4707 bool TheoryArithPrivate::attemptSingleton(RowIndex ridx, bool rowUp){
4708 Debug("arith::prop") << " attemptSingleton" << ridx;
4709
4710 const Tableau::Entry* ep;
4711 ep = d_linEq.rowLacksBound(ridx, rowUp, ARITHVAR_SENTINEL);
4712 Assert(ep != NULL);
4713
4714 ArithVar v = ep->getColVar();
4715 const Rational& coeff = ep->getCoefficient();
4716
4717 // 0 = c * v + \sum rest
4718 // Suppose rowUp
4719 // - c * v = \sum rest \leq D
4720 // if c > 0, v \geq -D/c so !vUp
4721 // if c < 0, v \leq -D/c so vUp
4722 // Suppose not rowUp
4723 // - c * v = \sum rest \geq D
4724 // if c > 0, v \leq -D/c so vUp
4725 // if c < 0, v \geq -D/c so !vUp
4726 bool vUp = (rowUp == ( coeff.sgn() < 0));
4727
4728 Debug("arith::prop") << " " << rowUp << " " << v << " " << coeff << " " << vUp << endl;
4729 Debug("arith::prop") << " " << propagateMightSucceed(v, vUp) << endl;
4730
4731 if(propagateMightSucceed(v, vUp)){
4732 DeltaRational dr = d_linEq.computeRowBound(ridx, rowUp, v);
4733 DeltaRational bound = dr / (- coeff);
4734 return tryToPropagate(ridx, rowUp, v, vUp, bound);
4735 }
4736 return false;
4737 }
4738
attemptFull(RowIndex ridx,bool rowUp)4739 bool TheoryArithPrivate::attemptFull(RowIndex ridx, bool rowUp){
4740 Debug("arith::prop") << " attemptFull" << ridx << endl;
4741
4742 vector<const Tableau::Entry*> candidates;
4743
4744 for(Tableau::RowIterator i = d_tableau.ridRowIterator(ridx); !i.atEnd(); ++i){
4745 const Tableau::Entry& e =*i;
4746 const Rational& c = e.getCoefficient();
4747 ArithVar v = e.getColVar();
4748 bool vUp = (rowUp == (c.sgn() < 0));
4749 if(propagateMightSucceed(v, vUp)){
4750 candidates.push_back(&e);
4751 }
4752 }
4753 if(candidates.empty()){ return false; }
4754
4755 const DeltaRational slack =
4756 d_linEq.computeRowBound(ridx, rowUp, ARITHVAR_SENTINEL);
4757 bool any = false;
4758 vector<const Tableau::Entry*>::const_iterator i, iend;
4759 for(i = candidates.begin(), iend = candidates.end(); i != iend; ++i){
4760 const Tableau::Entry* ep = *i;
4761 const Rational& c = ep->getCoefficient();
4762 ArithVar v = ep->getColVar();
4763
4764 // See the comment for attemptSingleton()
4765 bool activeUp = (rowUp == (c.sgn() > 0));
4766 bool vUb = (rowUp == (c.sgn() < 0));
4767
4768 const DeltaRational& activeBound = activeUp ?
4769 d_partialModel.getUpperBound(v):
4770 d_partialModel.getLowerBound(v);
4771
4772 DeltaRational contribution = activeBound * c;
4773 DeltaRational impliedBound = (slack - contribution)/(-c);
4774
4775 bool success = tryToPropagate(ridx, rowUp, v, vUb, impliedBound);
4776 any |= success;
4777 }
4778 return any;
4779 }
4780
tryToPropagate(RowIndex ridx,bool rowUp,ArithVar v,bool vUb,const DeltaRational & bound)4781 bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUb, const DeltaRational& bound){
4782
4783 bool weaker = vUb ? d_partialModel.strictlyLessThanUpperBound(v, bound):
4784 d_partialModel.strictlyGreaterThanLowerBound(v, bound);
4785 if(weaker){
4786 ConstraintType t = vUb ? UpperBound : LowerBound;
4787
4788 ConstraintP implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
4789 if(implied != NullConstraint){
4790
4791 return rowImplicationCanBeApplied(ridx, rowUp, implied);
4792 }
4793 }
4794 return false;
4795 }
4796
flattenImplication(Node imp)4797 Node flattenImplication(Node imp){
4798 NodeBuilder<> nb(kind::OR);
4799 Node left = imp[0];
4800 Node right = imp[1];
4801
4802 if(left.getKind() == kind::AND){
4803 for(Node::iterator i = left.begin(), iend = left.end(); i != iend; ++i) {
4804 nb << (*i).negate();
4805 }
4806 }else{
4807 nb << left.negate();
4808 }
4809
4810 if(right.getKind() == kind::OR){
4811 for(Node::iterator i = right.begin(), iend = right.end(); i != iend; ++i) {
4812 nb << *i;
4813 }
4814 }else{
4815 nb << right;
4816 }
4817
4818 return nb;
4819 }
4820
rowImplicationCanBeApplied(RowIndex ridx,bool rowUp,ConstraintP implied)4821 bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP implied){
4822 Assert(implied != NullConstraint);
4823 ArithVar v = implied->getVariable();
4824
4825 bool assertedToTheTheory = implied->assertedToTheTheory();
4826 bool canBePropagated = implied->canBePropagated();
4827 bool hasProof = implied->hasProof();
4828
4829 Debug("arith::prop") << "arith::prop" << v
4830 << " " << assertedToTheTheory
4831 << " " << canBePropagated
4832 << " " << hasProof
4833 << endl;
4834
4835
4836 if( !assertedToTheTheory && canBePropagated && !hasProof ){
4837 ConstraintCPVec explain;
4838
4839 PROOF(d_farkasBuffer.clear());
4840 RationalVectorP coeffs = NULLPROOF(&d_farkasBuffer);
4841
4842 // After invoking `propegateRow`:
4843 // * coeffs[0] is for implied
4844 // * coeffs[i+1] is for explain[i]
4845 d_linEq.propagateRow(explain, ridx, rowUp, implied, coeffs);
4846 if(d_tableau.getRowLength(ridx) <= options::arithPropAsLemmaLength()){
4847 Node implication = implied->externalImplication(explain);
4848 Node clause = flattenImplication(implication);
4849 PROOF(if (d_containing.d_proofRecorder
4850 && coeffs != RationalVectorCPSentinel
4851 && coeffs->size() == clause.getNumChildren()) {
4852 Debug("arith::prop") << "implied : " << implied << std::endl;
4853 Debug("arith::prop") << "implication: " << implication << std::endl;
4854 Debug("arith::prop") << "coeff len: " << coeffs->size() << std::endl;
4855 Debug("arith::prop") << "exp : " << explain << std::endl;
4856 Debug("arith::prop") << "clause : " << clause << std::endl;
4857 Debug("arith::prop")
4858 << "clause len: " << clause.getNumChildren() << std::endl;
4859 Debug("arith::prop") << "exp len: " << explain.size() << std::endl;
4860 // Using the information from the above comment we assemble a conflict
4861 // AND in coefficient order
4862 NodeBuilder<> conflictInFarkasCoefficientOrder(kind::AND);
4863 conflictInFarkasCoefficientOrder << implication[1].negate();
4864 for (const Node& antecedent : implication[0])
4865 {
4866 Debug("arith::prop") << " ante: " << antecedent << std::endl;
4867 conflictInFarkasCoefficientOrder << antecedent;
4868 }
4869
4870 Assert(coeffs != RationalVectorPSentinel);
4871 Assert(conflictInFarkasCoefficientOrder.getNumChildren()
4872 == coeffs->size());
4873 d_containing.d_proofRecorder->saveFarkasCoefficients(
4874 conflictInFarkasCoefficientOrder, coeffs);
4875 })
4876 outputLemma(clause);
4877 }else{
4878 Assert(!implied->negationHasProof());
4879 implied->impliedByFarkas(explain, coeffs, false);
4880 implied->tryToPropagate();
4881 }
4882 return true;
4883 }
4884
4885 if(Debug.isOn("arith::prop")){
4886 Debug("arith::prop")
4887 << "failed " << v << " " << assertedToTheTheory << " "
4888 << canBePropagated << " " << hasProof << " " << implied << endl;
4889 d_partialModel.printModel(v, Debug("arith::prop"));
4890 }
4891 return false;
4892 }
4893
propagateCandidateRow(RowIndex ridx)4894 bool TheoryArithPrivate::propagateCandidateRow(RowIndex ridx){
4895 BoundCounts hasCount = d_linEq.hasBoundCount(ridx);
4896 uint32_t rowLength = d_tableau.getRowLength(ridx);
4897
4898 bool success = false;
4899 static int instance = 0;
4900 ++instance;
4901
4902 Debug("arith::prop")
4903 << "propagateCandidateRow " << instance << " attempt " << rowLength << " " << hasCount << endl;
4904
4905 if (rowLength >= options::arithPropagateMaxLength()
4906 && Random::getRandom().pickWithProb(
4907 1.0 - double(options::arithPropagateMaxLength()) / rowLength))
4908 {
4909 return false;
4910 }
4911
4912 if(hasCount.lowerBoundCount() == rowLength){
4913 success |= attemptFull(ridx, false);
4914 }else if(hasCount.lowerBoundCount() + 1 == rowLength){
4915 success |= attemptSingleton(ridx, false);
4916 }
4917
4918 if(hasCount.upperBoundCount() == rowLength){
4919 success |= attemptFull(ridx, true);
4920 }else if(hasCount.upperBoundCount() + 1 == rowLength){
4921 success |= attemptSingleton(ridx, true);
4922 }
4923 return success;
4924 }
4925
dumpUpdatedBoundsToRows()4926 void TheoryArithPrivate::dumpUpdatedBoundsToRows(){
4927 Assert(d_candidateRows.empty());
4928 DenseSet::const_iterator i = d_updatedBounds.begin();
4929 DenseSet::const_iterator end = d_updatedBounds.end();
4930 for(; i != end; ++i){
4931 ArithVar var = *i;
4932 if(d_tableau.isBasic(var)){
4933 RowIndex ridx = d_tableau.basicToRowIndex(var);
4934 d_candidateRows.softAdd(ridx);
4935 }else{
4936 Tableau::ColIterator basicIter = d_tableau.colIterator(var);
4937 for(; !basicIter.atEnd(); ++basicIter){
4938 const Tableau::Entry& entry = *basicIter;
4939 RowIndex ridx = entry.getRowIndex();
4940 d_candidateRows.softAdd(ridx);
4941 }
4942 }
4943 }
4944 d_updatedBounds.purge();
4945 }
4946
boundsInfo(ArithVar basic) const4947 const BoundsInfo& TheoryArithPrivate::boundsInfo(ArithVar basic) const{
4948 RowIndex ridx = d_tableau.basicToRowIndex(basic);
4949 return d_rowTracking[ridx];
4950 }
4951
4952
expandDefinition(LogicRequest & logicRequest,Node node)4953 Node TheoryArithPrivate::expandDefinition(LogicRequest &logicRequest, Node node) {
4954 NodeManager* nm = NodeManager::currentNM();
4955
4956 // eliminate here since the rewritten form of these may introduce division
4957 Kind k = node.getKind();
4958 if (k == kind::TANGENT || k == kind::COSECANT || k == kind::SECANT
4959 || k == kind::COTANGENT)
4960 {
4961 node = Rewriter::rewrite(node);
4962 k = node.getKind();
4963 }
4964
4965 switch (k)
4966 {
4967 case kind::DIVISION:
4968 {
4969 TNode num = node[0], den = node[1];
4970 Node ret = nm->mkNode(kind::DIVISION_TOTAL, num, den);
4971 if (!den.isConst() || den.getConst<Rational>().sgn() == 0)
4972 {
4973 Node divByZeroNum =
4974 getArithSkolemApp(logicRequest, num, arith_skolem_div_by_zero);
4975 Node denEq0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
4976 ret = nm->mkNode(kind::ITE, denEq0, divByZeroNum, ret);
4977 }
4978 return ret;
4979 break;
4980 }
4981
4982 case kind::INTS_DIVISION:
4983 {
4984 // partial function: integer div
4985 TNode num = node[0], den = node[1];
4986 Node ret = nm->mkNode(kind::INTS_DIVISION_TOTAL, num, den);
4987 if (!den.isConst() || den.getConst<Rational>().sgn() == 0)
4988 {
4989 Node intDivByZeroNum =
4990 getArithSkolemApp(logicRequest, num, arith_skolem_int_div_by_zero);
4991 Node denEq0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
4992 ret = nm->mkNode(kind::ITE, denEq0, intDivByZeroNum, ret);
4993 }
4994 return ret;
4995 break;
4996 }
4997
4998 case kind::INTS_MODULUS:
4999 {
5000 // partial function: mod
5001 TNode num = node[0], den = node[1];
5002 Node ret = nm->mkNode(kind::INTS_MODULUS_TOTAL, num, den);
5003 if (!den.isConst() || den.getConst<Rational>().sgn() == 0)
5004 {
5005 Node modZeroNum =
5006 getArithSkolemApp(logicRequest, num, arith_skolem_mod_by_zero);
5007 Node denEq0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
5008 ret = nm->mkNode(kind::ITE, denEq0, modZeroNum, ret);
5009 }
5010 return ret;
5011 break;
5012 }
5013
5014 case kind::ABS:
5015 {
5016 return nm->mkNode(kind::ITE,
5017 nm->mkNode(kind::LT, node[0], nm->mkConst(Rational(0))),
5018 nm->mkNode(kind::UMINUS, node[0]),
5019 node[0]);
5020 break;
5021 }
5022 case kind::SQRT:
5023 case kind::ARCSINE:
5024 case kind::ARCCOSINE:
5025 case kind::ARCTANGENT:
5026 case kind::ARCCOSECANT:
5027 case kind::ARCSECANT:
5028 case kind::ARCCOTANGENT:
5029 {
5030 // eliminate inverse functions here
5031 NodeMap::const_iterator it = d_nlin_inverse_skolem.find(node);
5032 if (it == d_nlin_inverse_skolem.end())
5033 {
5034 Node var = nm->mkBoundVar(nm->realType());
5035 Node lem;
5036 if (k == kind::SQRT)
5037 {
5038 lem = nm->mkNode(kind::MULT, var, var).eqNode(node[0]);
5039 }
5040 else
5041 {
5042 Node pi = mkPi();
5043
5044 // range of the skolem
5045 Node rlem;
5046 if (k == kind::ARCSINE || k == ARCTANGENT || k == ARCCOSECANT)
5047 {
5048 Node half = nm->mkConst(Rational(1) / Rational(2));
5049 Node pi2 = nm->mkNode(kind::MULT, half, pi);
5050 Node npi2 = nm->mkNode(kind::MULT, nm->mkConst(Rational(-1)), pi2);
5051 // -pi/2 < var <= pi/2
5052 rlem = nm->mkNode(
5053 AND, nm->mkNode(LT, npi2, var), nm->mkNode(LEQ, var, pi2));
5054 }
5055 else
5056 {
5057 // 0 <= var < pi
5058 rlem = nm->mkNode(AND,
5059 nm->mkNode(LEQ, nm->mkConst(Rational(0)), var),
5060 nm->mkNode(LT, var, pi));
5061 }
5062
5063 Kind rk = k == kind::ARCSINE
5064 ? kind::SINE
5065 : (k == kind::ARCCOSINE
5066 ? kind::COSINE
5067 : (k == kind::ARCTANGENT
5068 ? kind::TANGENT
5069 : (k == kind::ARCCOSECANT
5070 ? kind::COSECANT
5071 : (k == kind::ARCSECANT
5072 ? kind::SECANT
5073 : kind::COTANGENT))));
5074 Node invTerm = nm->mkNode(rk, var);
5075 lem = nm->mkNode(AND, rlem, invTerm.eqNode(node[0]));
5076 }
5077 Assert(!lem.isNull());
5078 Node ret = nm->mkNode(CHOICE, nm->mkNode(BOUND_VAR_LIST, var), lem);
5079 d_nlin_inverse_skolem[node] = ret;
5080 return ret;
5081 }
5082 return (*it).second;
5083 break;
5084 }
5085
5086 default: return node; break;
5087 }
5088
5089 Unreachable();
5090 }
5091
getArithSkolem(LogicRequest & logicRequest,ArithSkolemId asi)5092 Node TheoryArithPrivate::getArithSkolem(LogicRequest& logicRequest,
5093 ArithSkolemId asi)
5094 {
5095 std::map<ArithSkolemId, Node>::iterator it = d_arith_skolem.find(asi);
5096 if (it == d_arith_skolem.end())
5097 {
5098 NodeManager* nm = NodeManager::currentNM();
5099
5100 TypeNode tn;
5101 std::string name;
5102 std::string desc;
5103 if (asi == arith_skolem_div_by_zero)
5104 {
5105 tn = nm->realType();
5106 name = std::string("divByZero");
5107 desc = std::string("partial real division");
5108 }
5109 else if (asi == arith_skolem_int_div_by_zero)
5110 {
5111 tn = nm->integerType();
5112 name = std::string("intDivByZero");
5113 desc = std::string("partial int division");
5114 }
5115 else if (asi == arith_skolem_mod_by_zero)
5116 {
5117 tn = nm->integerType();
5118 name = std::string("modZero");
5119 desc = std::string("partial modulus");
5120 }
5121
5122 Node skolem;
5123 if (options::arithNoPartialFun())
5124 {
5125 // partial function: division
5126 skolem = nm->mkSkolem(name, tn, desc, NodeManager::SKOLEM_EXACT_NAME);
5127 }
5128 else
5129 {
5130 // partial function: division
5131 skolem = nm->mkSkolem(name,
5132 nm->mkFunctionType(tn, tn),
5133 desc,
5134 NodeManager::SKOLEM_EXACT_NAME);
5135 logicRequest.widenLogic(THEORY_UF);
5136 }
5137 d_arith_skolem[asi] = skolem;
5138 return skolem;
5139 }
5140 return it->second;
5141 }
5142
getArithSkolemApp(LogicRequest & logicRequest,Node n,ArithSkolemId asi)5143 Node TheoryArithPrivate::getArithSkolemApp(LogicRequest& logicRequest,
5144 Node n,
5145 ArithSkolemId asi)
5146 {
5147 Node skolem = getArithSkolem(logicRequest, asi);
5148 if (!options::arithNoPartialFun())
5149 {
5150 skolem = NodeManager::currentNM()->mkNode(APPLY_UF, skolem, n);
5151 }
5152 return skolem;
5153 }
5154
5155 // InferBoundsResult TheoryArithPrivate::inferBound(TNode term, const InferBoundsParameters& param){
5156 // Node t = Rewriter::rewrite(term);
5157 // Assert(Polynomial::isMember(t));
5158 // Polynomial p = Polynomial::parsePolynomial(t);
5159 // if(p.containsConstant()){
5160 // Constant c = p.getHead().getConstant();
5161 // if(p.isConstant()){
5162 // InferBoundsResult res(t, param.findLowerBound());
5163 // res.setBound((DeltaRational)c.getValue(), mkBoolNode(true));
5164 // return res;
5165 // }else{
5166 // Polynomial tail = p.getTail();
5167 // InferBoundsResult res = inferBound(tail.getNode(), param);
5168 // if(res.foundBound()){
5169 // DeltaRational newBound = res.getValue() + c.getValue();
5170 // if(tail.isIntegral()){
5171 // Integer asInt = (param.findLowerBound()) ? newBound.ceiling() : newBound.floor();
5172 // newBound = DeltaRational(asInt);
5173 // }
5174 // res.setBound(newBound, res.getExplanation());
5175 // }
5176 // return res;
5177 // }
5178 // }else if(param.findLowerBound()){
5179 // InferBoundsParameters find_ub = param;
5180 // find_ub.setFindUpperBound();
5181 // if(param.useThreshold()){
5182 // find_ub.setThreshold(- param.getThreshold() );
5183 // }
5184 // Polynomial negP = -p;
5185 // InferBoundsResult res = inferBound(negP.getNode(), find_ub);
5186 // res.setFindLowerBound();
5187 // if(res.foundBound()){
5188 // res.setTerm(p.getNode());
5189 // res.setBound(-res.getValue(), res.getExplanation());
5190 // }
5191 // return res;
5192 // }else{
5193 // Assert(param.findUpperBound());
5194 // // does not contain a constant
5195 // switch(param.getEffort()){
5196 // case InferBoundsParameters::Lookup:
5197 // return inferUpperBoundLookup(t, param);
5198 // case InferBoundsParameters::Simplex:
5199 // return inferUpperBoundSimplex(t, param);
5200 // case InferBoundsParameters::LookupAndSimplexOnFailure:
5201 // case InferBoundsParameters::TryBoth:
5202 // {
5203 // InferBoundsResult lookup = inferUpperBoundLookup(t, param);
5204 // if(lookup.foundBound()){
5205 // if(param.getEffort() == InferBoundsParameters::LookupAndSimplexOnFailure ||
5206 // lookup.boundIsOptimal()){
5207 // return lookup;
5208 // }
5209 // }
5210 // InferBoundsResult simplex = inferUpperBoundSimplex(t, param);
5211 // if(lookup.foundBound() && simplex.foundBound()){
5212 // return (lookup.getValue() <= simplex.getValue()) ? lookup : simplex;
5213 // }else if(lookup.foundBound()){
5214 // return lookup;
5215 // }else{
5216 // return simplex;
5217 // }
5218 // }
5219 // default:
5220 // Unreachable();
5221 // return InferBoundsResult();
5222 // }
5223 // }
5224 // }
5225
5226
entailmentCheck(TNode lit,const ArithEntailmentCheckParameters & params,ArithEntailmentCheckSideEffects & out)5227 std::pair<bool, Node> TheoryArithPrivate::entailmentCheck(TNode lit, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){
5228 using namespace inferbounds;
5229
5230 // l k r
5231 // diff : (l - r) k 0
5232 Debug("arith::entailCheck") << "TheoryArithPrivate::entailmentCheck(" << lit << ")"<< endl;
5233 Kind k;
5234 int primDir;
5235 Rational lm, rm, dm;
5236 Node lp, rp, dp;
5237 DeltaRational sep;
5238 bool successful = decomposeLiteral(lit, k, primDir, lm, lp, rm, rp, dm, dp, sep);
5239 if(!successful) { return make_pair(false, Node::null()); }
5240
5241 if(dp.getKind() == CONST_RATIONAL){
5242 Node eval = Rewriter::rewrite(lit);
5243 Assert(eval.getKind() == kind::CONST_BOOLEAN);
5244 // if true, true is an acceptable explaination
5245 // if false, the node is uninterpreted and eval can be forgotten
5246 return make_pair(eval.getConst<bool>(), eval);
5247 }
5248 Assert(dm != Rational(0));
5249 Assert(primDir == 1 || primDir == -1);
5250
5251 int negPrim = -primDir;
5252
5253 int secDir = (k == EQUAL || k == DISTINCT) ? negPrim: 0;
5254 int negSecDir = (k == EQUAL || k == DISTINCT) ? primDir: 0;
5255
5256 // primDir*[lm*( lp )] k primDir*[ [rm*( rp )] + sep ]
5257 // primDir*[lm*( lp ) - rm*( rp ) ] k primDir*sep
5258 // primDir*[dm * dp] k primDir*sep
5259
5260 std::pair<Node, DeltaRational> bestPrimLeft, bestNegPrimRight, bestPrimDiff, tmp;
5261 std::pair<Node, DeltaRational> bestSecLeft, bestNegSecRight, bestSecDiff;
5262 bestPrimLeft.first = Node::null(); bestNegPrimRight.first = Node::null(); bestPrimDiff.first = Node::null();
5263 bestSecLeft.first = Node::null(); bestNegSecRight.first = Node::null(); bestSecDiff.first = Node::null();
5264
5265
5266
5267 ArithEntailmentCheckParameters::const_iterator alg, alg_end;
5268 for( alg = params.begin(), alg_end = params.end(); alg != alg_end; ++alg ){
5269 const inferbounds::InferBoundAlgorithm& ibalg = *alg;
5270
5271 Debug("arith::entailCheck") << "entailmentCheck trying " << (inferbounds::Algorithms) ibalg.getAlgorithm() << endl;
5272 switch(ibalg.getAlgorithm()){
5273 case inferbounds::None:
5274 break;
5275 case inferbounds::Lookup:
5276 case inferbounds::RowSum:
5277 {
5278 typedef void (TheoryArithPrivate::*EntailmentCheckFunc)(std::pair<Node, DeltaRational>&, int, TNode) const;
5279
5280 EntailmentCheckFunc ecfunc =
5281 (ibalg.getAlgorithm() == inferbounds::Lookup)
5282 ? (&TheoryArithPrivate::entailmentCheckBoundLookup)
5283 : (&TheoryArithPrivate::entailmentCheckRowSum);
5284
5285 (*this.*ecfunc)(tmp, primDir * lm.sgn(), lp);
5286 setToMin(primDir * lm.sgn(), bestPrimLeft, tmp);
5287
5288 (*this.*ecfunc)(tmp, negPrim * rm.sgn(), rp);
5289 setToMin(negPrim * rm.sgn(), bestNegPrimRight, tmp);
5290
5291 (*this.*ecfunc)(tmp, secDir * lm.sgn(), lp);
5292 setToMin(secDir * lm.sgn(), bestSecLeft, tmp);
5293
5294 (*this.*ecfunc)(tmp, negSecDir * rm.sgn(), rp);
5295 setToMin(negSecDir * rm.sgn(), bestNegSecRight, tmp);
5296
5297 (*this.*ecfunc)(tmp, primDir * dm.sgn(), dp);
5298 setToMin(primDir * dm.sgn(), bestPrimDiff, tmp);
5299
5300 (*this.*ecfunc)(tmp, secDir * dm.sgn(), dp);
5301 setToMin(secDir * dm.sgn(), bestSecDiff, tmp);
5302 }
5303 break;
5304 case inferbounds::Simplex:
5305 {
5306 // primDir * diffm * diff < c or primDir * diffm * diff > c
5307 tmp = entailmentCheckSimplex(primDir * dm.sgn(), dp, ibalg, out.getSimplexSideEffects());
5308 setToMin(primDir * dm.sgn(), bestPrimDiff, tmp);
5309
5310 tmp = entailmentCheckSimplex(secDir * dm.sgn(), dp, ibalg, out.getSimplexSideEffects());
5311 setToMin(secDir * dm.sgn(), bestSecDiff, tmp);
5312 }
5313 break;
5314 default:
5315 Unhandled();
5316 }
5317
5318 // turn bounds on prim * left and -prim * right into bounds on prim * diff
5319 if(!bestPrimLeft.first.isNull() && !bestNegPrimRight.first.isNull()){
5320 // primDir*lm* lp <= primDir*lm*L
5321 // -primDir*rm* rp <= -primDir*rm*R
5322 // primDir*lm* lp -primDir*rm* rp <= primDir*lm*L - primDir*rm*R
5323 // primDir [lm* lp -rm* rp] <= primDir[lm*L - *rm*R]
5324 // primDir [dm * dp] <= primDir[lm*L - *rm*R]
5325 // primDir [dm * dp] <= primDir * dm * ([lm*L - *rm*R]/dm)
5326 tmp.second = ((bestPrimLeft.second * lm) - (bestNegPrimRight.second * rm)) / dm;
5327 tmp.first = (bestPrimLeft.first).andNode(bestNegPrimRight.first);
5328 setToMin(primDir, bestPrimDiff, tmp);
5329 }
5330
5331 // turn bounds on sec * left and sec * right into bounds on sec * diff
5332 if(secDir != 0 && !bestSecLeft.first.isNull() && !bestNegSecRight.first.isNull()){
5333 // secDir*lm* lp <= secDir*lm*L
5334 // -secDir*rm* rp <= -secDir*rm*R
5335 // secDir*lm* lp -secDir*rm* rp <= secDir*lm*L - secDir*rm*R
5336 // secDir [lm* lp -rm* rp] <= secDir[lm*L - *rm*R]
5337 // secDir [dm * dp] <= secDir[lm*L - *rm*R]
5338 // secDir [dm * dp] <= secDir * dm * ([lm*L - *rm*R]/dm)
5339 tmp.second = ((bestSecLeft.second * lm) - (bestNegSecRight.second * rm)) / dm;
5340 tmp.first = (bestSecLeft.first).andNode(bestNegSecRight.first);
5341 setToMin(secDir, bestSecDiff, tmp);
5342 }
5343
5344 switch(k){
5345 case LEQ:
5346 if(!bestPrimDiff.first.isNull()){
5347 DeltaRational d = (bestPrimDiff.second * dm);
5348 if((primDir > 0 && d <= sep) || (primDir < 0 && d >= sep) ){
5349 Debug("arith::entailCheck") << "entailmentCheck found "
5350 << primDir << "*" << dm << "*(" << dp<<")"
5351 << " <= " << primDir << "*" << dm << "*" << bestPrimDiff.second
5352 << " <= " << primDir << "*" << sep << endl
5353 << " by " << bestPrimDiff.first << endl;
5354 Assert(bestPrimDiff.second * (Rational(primDir)* dm) <= (sep * Rational(primDir)));
5355 return make_pair(true, bestPrimDiff.first);
5356 }
5357 }
5358 break;
5359 case EQUAL:
5360 if(!bestPrimDiff.first.isNull() && !bestSecDiff.first.isNull()){
5361 // Is primDir [dm * dp] == primDir * sep entailed?
5362 // Iff [dm * dp] == sep entailed?
5363 // Iff dp == sep / dm entailed?
5364 // Iff dp <= sep / dm and dp >= sep / dm entailed?
5365
5366 // primDir [dm * dp] <= primDir * dm * U
5367 // secDir [dm * dp] <= secDir * dm * L
5368
5369 // Suppose primDir * dm > 0
5370 // then secDir * dm < 0
5371 // dp >= (secDir * L) / secDir * dm
5372 // dp >= (primDir * L) / primDir * dm
5373 //
5374 // dp <= U / dm
5375 // dp >= L / dm
5376 // dp == sep / dm entailed iff U == L == sep
5377 // Suppose primDir * dm < 0
5378 // then secDir * dm > 0
5379 // dp >= U / dm
5380 // dp <= L / dm
5381 // dp == sep / dm entailed iff U == L == sep
5382 if(bestPrimDiff.second == bestSecDiff.second){
5383 if(bestPrimDiff.second == sep){
5384 return make_pair(true, (bestPrimDiff.first).andNode(bestSecDiff.first));
5385 }
5386 }
5387 }
5388 // intentionally fall through to DISTINCT case!
5389 // entailments of negations are eager exit cases for EQUAL
5390 case DISTINCT:
5391 if(!bestPrimDiff.first.isNull()){
5392 // primDir [dm * dp] <= primDir * dm * U < primDir * sep
5393 if((primDir > 0 && (bestPrimDiff.second * dm < sep)) ||
5394 (primDir < 0 && (bestPrimDiff.second * dm > sep))){
5395 // entailment of negation
5396 if(k == DISTINCT){
5397 return make_pair(true, bestPrimDiff.first);
5398 }else{
5399 Assert(k == EQUAL);
5400 return make_pair(false, Node::null());
5401 }
5402 }
5403 }
5404 if(!bestSecDiff.first.isNull()){
5405 // If primDir [dm * dp] > primDir * sep, then this is not entailed.
5406 // If primDir [dm * dp] >= primDir * dm * L > primDir * sep
5407 // -primDir * dm * L < -primDir * sep
5408 // secDir * dm * L < secDir * sep
5409 if((secDir > 0 && (bestSecDiff.second * dm < sep)) ||
5410 (secDir < 0 && (bestSecDiff.second * dm > sep))){
5411 if(k == DISTINCT){
5412 return make_pair(true, bestSecDiff.first);
5413 }else{
5414 Assert(k == EQUAL);
5415 return make_pair(false, Node::null());
5416 }
5417 }
5418 }
5419
5420 break;
5421 default:
5422 Unreachable();
5423 break;
5424 }
5425 }
5426 return make_pair(false, Node::null());
5427 }
5428
decomposeTerm(Node term,Rational & m,Node & p,Rational & c)5429 bool TheoryArithPrivate::decomposeTerm(Node term, Rational& m, Node& p, Rational& c){
5430 Node t = Rewriter::rewrite(term);
5431 if(!Polynomial::isMember(t)){
5432 return false;
5433 }
5434
5435 // TODO Speed up
5436 preprocessing::util::ContainsTermITEVisitor ctv;
5437 if(ctv.containsTermITE(t)){
5438 return false;
5439 }
5440
5441 Polynomial poly = Polynomial::parsePolynomial(t);
5442 if(poly.isConstant()){
5443 c = poly.getHead().getConstant().getValue();
5444 p = mkRationalNode(Rational(0));
5445 m = Rational(1);
5446 return true;
5447 }else if(poly.containsConstant()){
5448 c = poly.getHead().getConstant().getValue();
5449 poly = poly.getTail();
5450 }else{
5451 c = Rational(0);
5452 }
5453 Assert(!poly.isConstant());
5454 Assert(!poly.containsConstant());
5455
5456 const bool intVars = poly.allIntegralVariables();
5457
5458 if(intVars){
5459 m = Rational(1);
5460 if(!poly.isIntegral()){
5461 Integer denom = poly.denominatorLCM();
5462 m /= denom;
5463 poly = poly * denom;
5464 }
5465 Integer g = poly.gcd();
5466 m *= g;
5467 poly = poly * Rational(1,g);
5468 Assert(poly.isIntegral());
5469 Assert(poly.leadingCoefficientIsPositive());
5470 }else{
5471 Assert(!intVars);
5472 m = poly.getHead().getConstant().getValue();
5473 poly = poly * m.inverse();
5474 Assert(poly.leadingCoefficientIsAbsOne());
5475 }
5476 p = poly.getNode();
5477 return true;
5478 }
5479
setToMin(int sgn,std::pair<Node,DeltaRational> & min,const std::pair<Node,DeltaRational> & e)5480 void TheoryArithPrivate::setToMin(int sgn, std::pair<Node, DeltaRational>& min, const std::pair<Node, DeltaRational>& e){
5481 if(sgn != 0){
5482 if(min.first.isNull() && !e.first.isNull()){
5483 min = e;
5484 }else if(!min.first.isNull() && !e.first.isNull()){
5485 if(sgn > 0 && min.second > e.second){
5486 min = e;
5487 }else if(sgn < 0 && min.second < e.second){
5488 min = e;
5489 }
5490 }
5491 }
5492 }
5493
5494 // std::pair<bool, Node> TheoryArithPrivate::entailmentUpperCheck(const Rational& lm, Node lp, const Rational& rm, Node rp, const DeltaRational& sep, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){
5495
5496 // Rational negRM = -rm;
5497 // Node diff = NodeManager::currentNM()->mkNode(MULT, mkRationalConstan(lm), lp) + (negRM * rp);
5498
5499 // Rational diffm;
5500 // Node diffp;
5501 // decompose(diff, diffm, diffNode);
5502
5503
5504 // std::pair<Node, DeltaRational> bestUbLeft, bestLbRight, bestUbDiff, tmp;
5505 // bestUbLeft = bestLbRight = bestUbDiff = make_pair(Node::Null(), DeltaRational());
5506
5507 // return make_pair(false, Node::null());
5508 // }
5509
5510 /**
5511 * Decomposes a literal into the form:
5512 * dir*[lm*( lp )] k dir*[ [rm*( rp )] + sep ]
5513 * dir*[dm* dp] k dir *sep
5514 * dir is either 1 or -1
5515 */
decomposeLiteral(Node lit,Kind & k,int & dir,Rational & lm,Node & lp,Rational & rm,Node & rp,Rational & dm,Node & dp,DeltaRational & sep)5516 bool TheoryArithPrivate::decomposeLiteral(Node lit, Kind& k, int& dir, Rational& lm, Node& lp, Rational& rm, Node& rp, Rational& dm, Node& dp, DeltaRational& sep){
5517 bool negated = (lit.getKind() == kind::NOT);
5518 TNode atom = negated ? lit[0] : lit;
5519
5520 TNode left = atom[0];
5521 TNode right = atom[1];
5522
5523 // left : lm*( lp ) + lc
5524 // right: rm*( rp ) + rc
5525 Rational lc, rc;
5526 bool success = decomposeTerm(left, lm, lp, lc);
5527 if(!success){ return false; }
5528 success = decomposeTerm(right, rm, rp, rc);
5529 if(!success){ return false; }
5530
5531 Node diff = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::MINUS, left, right));
5532 Rational dc;
5533 success = decomposeTerm(diff, dm, dp, dc);
5534 Assert(success);
5535
5536 // reduce the kind of the to not include literals
5537 // GT, NOT LEQ
5538 // GEQ, NOT LT
5539 // LT, NOT GEQ
5540 // LEQ, NOT LT
5541 Kind atomKind = atom.getKind();
5542 Kind normKind = negated ? negateKind(atomKind) : atomKind;
5543
5544 if(normKind == GEQ || normKind == GT){
5545 dir = -1;
5546 normKind = (normKind == GEQ) ? LEQ : LT;
5547 }else{
5548 dir = 1;
5549 }
5550
5551 Debug("arith::decomp") << "arith::decomp "
5552 << lit << "(" << normKind << "*" << dir << ")"<< endl
5553 << " left:" << lc << " + " << lm << "*(" << lp << ") : " <<left << endl
5554 << " right:" << rc << " + " << rm << "*(" << rp << ") : " << right << endl
5555 << " diff: " << dc << " + " << dm << "*("<< dp <<"): " << diff << endl
5556 << " sep: " << sep << endl;
5557
5558
5559 // k in LT, LEQ, EQUAL, DISEQUAL
5560 // [dir*lm*( lp ) + dir*lc] k [dir*rm*( rp ) + dir*rc]
5561 Rational change = rc - lc;
5562 Assert(change == (-dc));
5563 // [dir*lm*( lp )] k [dir*rm*( rp ) + dir*(rc - lc)]
5564 if(normKind == LT){
5565 sep = DeltaRational(change, Rational(-1));
5566 k = LEQ;
5567 }else{
5568 sep = DeltaRational(change);
5569 k = normKind;
5570 }
5571 // k in LEQ, EQUAL, DISEQUAL
5572 // dir*lm*( lp ) k [dir*rm*( rp )] + dir*(sep + d * delta)
5573 return true;
5574 }
5575
5576 /**
5577 * Precondition:
5578 * tp is a polynomial not containing an ite.
5579 * either tp is constant or contains no constants.
5580 * Post:
5581 * if tmp.first is not null, then
5582 * sgn * tp <= sgn * tmp.second
5583 */
entailmentCheckBoundLookup(std::pair<Node,DeltaRational> & tmp,int sgn,TNode tp) const5584 void TheoryArithPrivate::entailmentCheckBoundLookup(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const {
5585 tmp.first = Node::null();
5586 if(sgn == 0){ return; }
5587
5588 Assert(Polynomial::isMember(tp));
5589 if(tp.getKind() == CONST_RATIONAL){
5590 tmp.first = mkBoolNode(true);
5591 tmp.second = DeltaRational(tp.getConst<Rational>());
5592 }else if(d_partialModel.hasArithVar(tp)){
5593 Assert(tp.getKind() != CONST_RATIONAL);
5594 ArithVar v = d_partialModel.asArithVar(tp);
5595 Assert(v != ARITHVAR_SENTINEL);
5596 ConstraintP c = (sgn > 0)
5597 ? d_partialModel.getUpperBoundConstraint(v)
5598 : d_partialModel.getLowerBoundConstraint(v);
5599 if(c != NullConstraint){
5600 tmp.first = c->externalExplainByAssertions();
5601 tmp.second = c->getValue();
5602 }
5603 }
5604 }
5605
entailmentCheckRowSum(std::pair<Node,DeltaRational> & tmp,int sgn,TNode tp) const5606 void TheoryArithPrivate::entailmentCheckRowSum(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const {
5607 tmp.first = Node::null();
5608 if(sgn == 0){ return; }
5609 if(tp.getKind() != PLUS){ return; }
5610 Assert(Polynomial::isMember(tp));
5611
5612 tmp.second = DeltaRational(0);
5613 NodeBuilder<> nb(kind::AND);
5614
5615 Polynomial p = Polynomial::parsePolynomial(tp);
5616 for(Polynomial::iterator i = p.begin(), iend = p.end(); i != iend; ++i) {
5617 Monomial m = *i;
5618 Node x = m.getVarList().getNode();
5619 if(d_partialModel.hasArithVar(x)){
5620 ArithVar v = d_partialModel.asArithVar(x);
5621 const Rational& coeff = m.getConstant().getValue();
5622 int dir = sgn * coeff.sgn();
5623 ConstraintP c = (dir > 0)
5624 ? d_partialModel.getUpperBoundConstraint(v)
5625 : d_partialModel.getLowerBoundConstraint(v);
5626 if(c != NullConstraint){
5627 tmp.second += c->getValue() * coeff;
5628 c->externalExplainByAssertions(nb);
5629 }else{
5630 //failed
5631 return;
5632 }
5633 }else{
5634 // failed
5635 return;
5636 }
5637 }
5638 // success
5639 tmp.first = nb;
5640 }
5641
entailmentCheckSimplex(int sgn,TNode tp,const inferbounds::InferBoundAlgorithm & param,InferBoundsResult & result)5642 std::pair<Node, DeltaRational> TheoryArithPrivate::entailmentCheckSimplex(int sgn, TNode tp, const inferbounds::InferBoundAlgorithm& param, InferBoundsResult& result){
5643
5644 if((sgn == 0) || !(d_qflraStatus == Result::SAT && d_errorSet.noSignals()) || tp.getKind() == CONST_RATIONAL){
5645 return make_pair(Node::null(), DeltaRational());
5646 }
5647
5648 Assert(d_qflraStatus == Result::SAT);
5649 Assert(d_errorSet.noSignals());
5650 Assert(param.getAlgorithm() == inferbounds::Simplex);
5651
5652 // TODO Move me into a new file
5653
5654 enum ResultState {Unset, Inferred, NoBound, ReachedThreshold, ExhaustedRounds};
5655 ResultState finalState = Unset;
5656
5657 const int maxRounds =
5658 param.getSimplexRounds().just() ? param.getSimplexRounds().value() : -1;
5659
5660 Maybe<DeltaRational> threshold;
5661 // TODO: get this from the parameters
5662
5663 // setup term
5664 Polynomial p = Polynomial::parsePolynomial(tp);
5665 vector<ArithVar> variables;
5666 vector<Rational> coefficients;
5667 asVectors(p, coefficients, variables);
5668 if(sgn < 0){
5669 for(size_t i=0, N=coefficients.size(); i < N; ++i){
5670 coefficients[i] = -coefficients[i];
5671 }
5672 }
5673 // implicitly an upperbound
5674 Node skolem = mkRealSkolem("tmpVar$$");
5675 ArithVar optVar = requestArithVar(skolem, false, true);
5676 d_tableau.addRow(optVar, coefficients, variables);
5677 RowIndex ridx = d_tableau.basicToRowIndex(optVar);
5678
5679 DeltaRational newAssignment = d_linEq.computeRowValue(optVar, false);
5680 d_partialModel.setAssignment(optVar, newAssignment);
5681 d_linEq.trackRowIndex(d_tableau.basicToRowIndex(optVar));
5682
5683 // Setup simplex
5684 d_partialModel.stopQueueingBoundCounts();
5685 UpdateTrackingCallback utcb(&d_linEq);
5686 d_partialModel.processBoundsQueue(utcb);
5687 d_linEq.startTrackingBoundCounts();
5688
5689 // maximize optVar via primal Simplex
5690 int rounds = 0;
5691 while(finalState == Unset){
5692 ++rounds;
5693 if(maxRounds >= 0 && rounds > maxRounds){
5694 finalState = ExhaustedRounds;
5695 break;
5696 }
5697
5698 // select entering by bland's rule
5699 // TODO improve upon bland's
5700 ArithVar entering = ARITHVAR_SENTINEL;
5701 const Tableau::Entry* enteringEntry = NULL;
5702 for(Tableau::RowIterator ri = d_tableau.ridRowIterator(ridx); !ri.atEnd(); ++ri){
5703 const Tableau::Entry& entry = *ri;
5704 ArithVar v = entry.getColVar();
5705 if(v != optVar){
5706 int sgn = entry.getCoefficient().sgn();
5707 Assert(sgn != 0);
5708 bool candidate = (sgn > 0)
5709 ? (d_partialModel.cmpAssignmentUpperBound(v) != 0)
5710 : (d_partialModel.cmpAssignmentLowerBound(v) != 0);
5711 if(candidate && (entering == ARITHVAR_SENTINEL || entering > v)){
5712 entering = v;
5713 enteringEntry = &entry;
5714 }
5715 }
5716 }
5717 if(entering == ARITHVAR_SENTINEL){
5718 finalState = Inferred;
5719 break;
5720 }
5721 Assert(entering != ARITHVAR_SENTINEL);
5722 Assert(enteringEntry != NULL);
5723
5724 int esgn = enteringEntry->getCoefficient().sgn();
5725 Assert(esgn != 0);
5726
5727 // select leaving and ratio
5728 ArithVar leaving = ARITHVAR_SENTINEL;
5729 DeltaRational minRatio;
5730 const Tableau::Entry* pivotEntry = NULL;
5731
5732 // Special case check the upper/lowerbound on entering
5733 ConstraintP cOnEntering = (esgn > 0)
5734 ? d_partialModel.getUpperBoundConstraint(entering)
5735 : d_partialModel.getLowerBoundConstraint(entering);
5736 if(cOnEntering != NullConstraint){
5737 leaving = entering;
5738 minRatio = d_partialModel.getAssignment(entering) - cOnEntering->getValue();
5739 }
5740 for(Tableau::ColIterator ci = d_tableau.colIterator(entering); !ci.atEnd(); ++ci){
5741 const Tableau::Entry& centry = *ci;
5742 ArithVar basic = d_tableau.rowIndexToBasic(centry.getRowIndex());
5743 int csgn = centry.getCoefficient().sgn();
5744 int basicDir = csgn * esgn;
5745
5746 ConstraintP bound = (basicDir > 0)
5747 ? d_partialModel.getUpperBoundConstraint(basic)
5748 : d_partialModel.getLowerBoundConstraint(basic);
5749 if(bound != NullConstraint){
5750 DeltaRational diff = d_partialModel.getAssignment(basic) - bound->getValue();
5751 DeltaRational ratio = diff/(centry.getCoefficient());
5752 bool selected = false;
5753 if(leaving == ARITHVAR_SENTINEL){
5754 selected = true;
5755 }else{
5756 int cmp = ratio.compare(minRatio);
5757 if((csgn > 0) ? (cmp <= 0) : (cmp >= 0)){
5758 selected = (cmp != 0) ||
5759 ((leaving != entering) && (basic < leaving));
5760 }
5761 }
5762 if(selected){
5763 leaving = basic;
5764 minRatio = ratio;
5765 pivotEntry = ¢ry;
5766 }
5767 }
5768 }
5769
5770
5771 if(leaving == ARITHVAR_SENTINEL){
5772 finalState = NoBound;
5773 break;
5774 }else if(leaving == entering){
5775 d_linEq.update(entering, minRatio);
5776 }else{
5777 DeltaRational newLeaving = minRatio * (pivotEntry->getCoefficient());
5778 d_linEq.pivotAndUpdate(leaving, entering, newLeaving);
5779 // no conflicts clear signals
5780 Assert(d_errorSet.noSignals());
5781 }
5782
5783 if(threshold.just()){
5784 if (d_partialModel.getAssignment(optVar) >= threshold.value())
5785 {
5786 finalState = ReachedThreshold;
5787 break;
5788 }
5789 }
5790 };
5791
5792 result = InferBoundsResult(tp, sgn > 0);
5793
5794 // tear down term
5795 switch(finalState){
5796 case Inferred:
5797 {
5798 NodeBuilder<> nb(kind::AND);
5799 for(Tableau::RowIterator ri = d_tableau.ridRowIterator(ridx); !ri.atEnd(); ++ri){
5800 const Tableau::Entry& e =*ri;
5801 ArithVar colVar = e.getColVar();
5802 if(colVar != optVar){
5803 const Rational& q = e.getCoefficient();
5804 Assert(q.sgn() != 0);
5805 ConstraintP c = (q.sgn() > 0)
5806 ? d_partialModel.getUpperBoundConstraint(colVar)
5807 : d_partialModel.getLowerBoundConstraint(colVar);
5808 c->externalExplainByAssertions(nb);
5809 }
5810 }
5811 Assert(nb.getNumChildren() >= 1);
5812 Node exp = (nb.getNumChildren() >= 2) ? (Node) nb : nb[0];
5813 result.setBound(d_partialModel.getAssignment(optVar), exp);
5814 result.setIsOptimal();
5815 break;
5816 }
5817 case NoBound:
5818 break;
5819 case ReachedThreshold:
5820 result.setReachedThreshold();
5821 break;
5822 case ExhaustedRounds:
5823 result.setBudgetExhausted();
5824 break;
5825 case Unset:
5826 default:
5827 Unreachable();
5828 break;
5829 };
5830
5831 d_linEq.stopTrackingRowIndex(ridx);
5832 d_tableau.removeBasicRow(optVar);
5833 releaseArithVar(optVar);
5834
5835 d_linEq.stopTrackingBoundCounts();
5836 d_partialModel.startQueueingBoundCounts();
5837
5838 if(result.foundBound()){
5839 return make_pair(result.getExplanation(), result.getValue());
5840 }else{
5841 return make_pair(Node::null(), DeltaRational());
5842 }
5843 }
5844
5845 // InferBoundsResult TheoryArithPrivate::inferUpperBoundSimplex(TNode t, const inferbounds::InferBoundAlgorithm& param){
5846 // Assert(param.findUpperBound());
5847
5848 // if(!(d_qflraStatus == Result::SAT && d_errorSet.noSignals())){
5849 // InferBoundsResult inconsistent;
5850 // inconsistent.setInconsistent();
5851 // return inconsistent;
5852 // }
5853
5854 // Assert(d_qflraStatus == Result::SAT);
5855 // Assert(d_errorSet.noSignals());
5856
5857 // // TODO Move me into a new file
5858
5859 // enum ResultState {Unset, Inferred, NoBound, ReachedThreshold, ExhaustedRounds};
5860 // ResultState finalState = Unset;
5861
5862 // int maxRounds = 0;
5863 // switch(param.getParamKind()){
5864 // case InferBoundsParameters::Unbounded:
5865 // maxRounds = -1;
5866 // break;
5867 // case InferBoundsParameters::NumVars:
5868 // maxRounds = d_partialModel.getNumberOfVariables() * param.getSimplexRoundParameter();
5869 // break;
5870 // case InferBoundsParameters::Direct:
5871 // maxRounds = param.getSimplexRoundParameter();
5872 // break;
5873 // default: maxRounds = 0; break;
5874 // }
5875
5876 // // setup term
5877 // Polynomial p = Polynomial::parsePolynomial(t);
5878 // vector<ArithVar> variables;
5879 // vector<Rational> coefficients;
5880 // asVectors(p, coefficients, variables);
5881
5882 // Node skolem = mkRealSkolem("tmpVar$$");
5883 // ArithVar optVar = requestArithVar(skolem, false, true);
5884 // d_tableau.addRow(optVar, coefficients, variables);
5885 // RowIndex ridx = d_tableau.basicToRowIndex(optVar);
5886
5887 // DeltaRational newAssignment = d_linEq.computeRowValue(optVar, false);
5888 // d_partialModel.setAssignment(optVar, newAssignment);
5889 // d_linEq.trackRowIndex(d_tableau.basicToRowIndex(optVar));
5890
5891 // // Setup simplex
5892 // d_partialModel.stopQueueingBoundCounts();
5893 // UpdateTrackingCallback utcb(&d_linEq);
5894 // d_partialModel.processBoundsQueue(utcb);
5895 // d_linEq.startTrackingBoundCounts();
5896
5897 // // maximize optVar via primal Simplex
5898 // int rounds = 0;
5899 // while(finalState == Unset){
5900 // ++rounds;
5901 // if(maxRounds >= 0 && rounds > maxRounds){
5902 // finalState = ExhaustedRounds;
5903 // break;
5904 // }
5905
5906 // // select entering by bland's rule
5907 // // TODO improve upon bland's
5908 // ArithVar entering = ARITHVAR_SENTINEL;
5909 // const Tableau::Entry* enteringEntry = NULL;
5910 // for(Tableau::RowIterator ri = d_tableau.ridRowIterator(ridx); !ri.atEnd(); ++ri){
5911 // const Tableau::Entry& entry = *ri;
5912 // ArithVar v = entry.getColVar();
5913 // if(v != optVar){
5914 // int sgn = entry.getCoefficient().sgn();
5915 // Assert(sgn != 0);
5916 // bool candidate = (sgn > 0)
5917 // ? (d_partialModel.cmpAssignmentUpperBound(v) != 0)
5918 // : (d_partialModel.cmpAssignmentLowerBound(v) != 0);
5919 // if(candidate && (entering == ARITHVAR_SENTINEL || entering > v)){
5920 // entering = v;
5921 // enteringEntry = &entry;
5922 // }
5923 // }
5924 // }
5925 // if(entering == ARITHVAR_SENTINEL){
5926 // finalState = Inferred;
5927 // break;
5928 // }
5929 // Assert(entering != ARITHVAR_SENTINEL);
5930 // Assert(enteringEntry != NULL);
5931
5932 // int esgn = enteringEntry->getCoefficient().sgn();
5933 // Assert(esgn != 0);
5934
5935 // // select leaving and ratio
5936 // ArithVar leaving = ARITHVAR_SENTINEL;
5937 // DeltaRational minRatio;
5938 // const Tableau::Entry* pivotEntry = NULL;
5939
5940 // // Special case check the upper/lowerbound on entering
5941 // ConstraintP cOnEntering = (esgn > 0)
5942 // ? d_partialModel.getUpperBoundConstraint(entering)
5943 // : d_partialModel.getLowerBoundConstraint(entering);
5944 // if(cOnEntering != NullConstraint){
5945 // leaving = entering;
5946 // minRatio = d_partialModel.getAssignment(entering) - cOnEntering->getValue();
5947 // }
5948 // for(Tableau::ColIterator ci = d_tableau.colIterator(entering); !ci.atEnd(); ++ci){
5949 // const Tableau::Entry& centry = *ci;
5950 // ArithVar basic = d_tableau.rowIndexToBasic(centry.getRowIndex());
5951 // int csgn = centry.getCoefficient().sgn();
5952 // int basicDir = csgn * esgn;
5953
5954 // ConstraintP bound = (basicDir > 0)
5955 // ? d_partialModel.getUpperBoundConstraint(basic)
5956 // : d_partialModel.getLowerBoundConstraint(basic);
5957 // if(bound != NullConstraint){
5958 // DeltaRational diff = d_partialModel.getAssignment(basic) - bound->getValue();
5959 // DeltaRational ratio = diff/(centry.getCoefficient());
5960 // bool selected = false;
5961 // if(leaving == ARITHVAR_SENTINEL){
5962 // selected = true;
5963 // }else{
5964 // int cmp = ratio.compare(minRatio);
5965 // if((csgn > 0) ? (cmp <= 0) : (cmp >= 0)){
5966 // selected = (cmp != 0) ||
5967 // ((leaving != entering) && (basic < leaving));
5968 // }
5969 // }
5970 // if(selected){
5971 // leaving = basic;
5972 // minRatio = ratio;
5973 // pivotEntry = ¢ry;
5974 // }
5975 // }
5976 // }
5977
5978
5979 // if(leaving == ARITHVAR_SENTINEL){
5980 // finalState = NoBound;
5981 // break;
5982 // }else if(leaving == entering){
5983 // d_linEq.update(entering, minRatio);
5984 // }else{
5985 // DeltaRational newLeaving = minRatio * (pivotEntry->getCoefficient());
5986 // d_linEq.pivotAndUpdate(leaving, entering, newLeaving);
5987 // // no conflicts clear signals
5988 // Assert(d_errorSet.noSignals());
5989 // }
5990
5991 // if(param.useThreshold()){
5992 // if(d_partialModel.getAssignment(optVar) >= param.getThreshold()){
5993 // finalState = ReachedThreshold;
5994 // break;
5995 // }
5996 // }
5997 // };
5998
5999 // InferBoundsResult result(t, param.findUpperBound());
6000
6001 // // tear down term
6002 // switch(finalState){
6003 // case Inferred:
6004 // {
6005 // NodeBuilder<> nb(kind::AND);
6006 // for(Tableau::RowIterator ri = d_tableau.ridRowIterator(ridx); !ri.atEnd(); ++ri){
6007 // const Tableau::Entry& e =*ri;
6008 // ArithVar colVar = e.getColVar();
6009 // if(colVar != optVar){
6010 // const Rational& q = e.getCoefficient();
6011 // Assert(q.sgn() != 0);
6012 // ConstraintP c = (q.sgn() > 0)
6013 // ? d_partialModel.getUpperBoundConstraint(colVar)
6014 // : d_partialModel.getLowerBoundConstraint(colVar);
6015 // c->externalExplainByAssertions(nb);
6016 // }
6017 // }
6018 // Assert(nb.getNumChildren() >= 1);
6019 // Node exp = (nb.getNumChildren() >= 2) ? (Node) nb : nb[0];
6020 // result.setBound(d_partialModel.getAssignment(optVar), exp);
6021 // result.setIsOptimal();
6022 // break;
6023 // }
6024 // case NoBound:
6025 // break;
6026 // case ReachedThreshold:
6027 // result.setReachedThreshold();
6028 // break;
6029 // case ExhaustedRounds:
6030 // result.setBudgetExhausted();
6031 // break;
6032 // case Unset:
6033 // default:
6034 // Unreachable();
6035 // break;
6036 // };
6037
6038 // d_linEq.stopTrackingRowIndex(ridx);
6039 // d_tableau.removeBasicRow(optVar);
6040 // releaseArithVar(optVar);
6041
6042 // d_linEq.stopTrackingBoundCounts();
6043 // d_partialModel.startQueueingBoundCounts();
6044
6045 // return result;
6046 // }
6047
6048 }/* CVC4::theory::arith namespace */
6049 }/* CVC4::theory namespace */
6050 }/* CVC4 namespace */
6051