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 = &centry;
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 = &centry;
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