1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Tim King, Alex Ozdemir, Andrew Reynolds |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* [[ Add one-line brief description here ]] |
14 |
|
* |
15 |
|
* [[ Add lengthier description here ]] |
16 |
|
* \todo document this file |
17 |
|
*/ |
18 |
|
|
19 |
|
#include "theory/arith/theory_arith_private.h" |
20 |
|
|
21 |
|
#include <map> |
22 |
|
#include <queue> |
23 |
|
#include <vector> |
24 |
|
|
25 |
|
#include "base/output.h" |
26 |
|
#include "context/cdhashset.h" |
27 |
|
#include "context/cdinsert_hashmap.h" |
28 |
|
#include "context/cdlist.h" |
29 |
|
#include "context/cdqueue.h" |
30 |
|
#include "context/context.h" |
31 |
|
#include "expr/kind.h" |
32 |
|
#include "expr/metakind.h" |
33 |
|
#include "expr/node.h" |
34 |
|
#include "expr/node_algorithm.h" |
35 |
|
#include "expr/node_builder.h" |
36 |
|
#include "expr/skolem_manager.h" |
37 |
|
#include "options/arith_options.h" |
38 |
|
#include "options/base_options.h" |
39 |
|
#include "preprocessing/util/ite_utilities.h" |
40 |
|
#include "proof/proof_generator.h" |
41 |
|
#include "proof/proof_node_manager.h" |
42 |
|
#include "proof/proof_rule.h" |
43 |
|
#include "smt/logic_exception.h" |
44 |
|
#include "smt/smt_statistics_registry.h" |
45 |
|
#include "smt_util/boolean_simplification.h" |
46 |
|
#include "theory/arith/approx_simplex.h" |
47 |
|
#include "theory/arith/arith_ite_utils.h" |
48 |
|
#include "theory/arith/arith_rewriter.h" |
49 |
|
#include "theory/arith/arith_static_learner.h" |
50 |
|
#include "theory/arith/arith_utilities.h" |
51 |
|
#include "theory/arith/arithvar.h" |
52 |
|
#include "theory/arith/congruence_manager.h" |
53 |
|
#include "theory/arith/constraint.h" |
54 |
|
#include "theory/arith/cut_log.h" |
55 |
|
#include "theory/arith/delta_rational.h" |
56 |
|
#include "theory/arith/dio_solver.h" |
57 |
|
#include "theory/arith/linear_equality.h" |
58 |
|
#include "theory/arith/matrix.h" |
59 |
|
#include "theory/arith/nl/nonlinear_extension.h" |
60 |
|
#include "theory/arith/normal_form.h" |
61 |
|
#include "theory/arith/partial_model.h" |
62 |
|
#include "theory/arith/simplex.h" |
63 |
|
#include "theory/arith/theory_arith.h" |
64 |
|
#include "theory/ext_theory.h" |
65 |
|
#include "theory/quantifiers/fmf/bounded_integers.h" |
66 |
|
#include "theory/rewriter.h" |
67 |
|
#include "theory/theory_model.h" |
68 |
|
#include "theory/trust_substitutions.h" |
69 |
|
#include "theory/valuation.h" |
70 |
|
#include "util/dense_map.h" |
71 |
|
#include "util/integer.h" |
72 |
|
#include "util/random.h" |
73 |
|
#include "util/rational.h" |
74 |
|
#include "util/result.h" |
75 |
|
#include "util/statistics_stats.h" |
76 |
|
|
77 |
|
using namespace std; |
78 |
|
using namespace cvc5::kind; |
79 |
|
|
80 |
|
namespace cvc5 { |
81 |
|
namespace theory { |
82 |
|
namespace arith { |
83 |
|
|
84 |
|
static Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum); |
85 |
|
static bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap); |
86 |
|
|
87 |
9853 |
TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, |
88 |
|
context::Context* c, |
89 |
|
context::UserContext* u, |
90 |
|
BranchAndBound& bab, |
91 |
9853 |
ProofNodeManager* pnm) |
92 |
|
: d_containing(containing), |
93 |
|
d_foundNl(false), |
94 |
|
d_rowTracking(), |
95 |
|
d_bab(bab), |
96 |
|
d_pnm(pnm), |
97 |
|
d_checker(), |
98 |
9853 |
d_pfGen(new EagerProofGenerator(d_pnm, u)), |
99 |
|
d_constraintDatabase(c, |
100 |
|
u, |
101 |
|
d_partialModel, |
102 |
|
d_congruenceManager, |
103 |
|
RaiseConflict(*this), |
104 |
|
d_pfGen.get(), |
105 |
|
d_pnm), |
106 |
|
d_qflraStatus(Result::SAT_UNKNOWN), |
107 |
|
d_unknownsInARow(0), |
108 |
|
d_hasDoneWorkSinceCut(false), |
109 |
|
d_learner(u), |
110 |
|
d_assertionsThatDoNotMatchTheirLiterals(c), |
111 |
|
d_nextIntegerCheckVar(0), |
112 |
|
d_constantIntegerVariables(c), |
113 |
|
d_diseqQueue(c, false), |
114 |
|
d_currentPropagationList(), |
115 |
|
d_learnedBounds(c), |
116 |
|
d_preregisteredNodes(u), |
117 |
19706 |
d_partialModel(c, DeltaComputeCallback(*this)), |
118 |
|
d_errorSet( |
119 |
9853 |
d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(*this)), |
120 |
|
d_tableau(), |
121 |
|
d_linEq(d_partialModel, |
122 |
|
d_tableau, |
123 |
|
d_rowTracking, |
124 |
19706 |
BasicVarModelUpdateCallBack(*this)), |
125 |
|
d_diosolver(c), |
126 |
|
d_restartsCounter(0), |
127 |
|
d_tableauSizeHasBeenModified(false), |
128 |
|
d_tableauResetDensity(1.6), |
129 |
|
d_tableauResetPeriod(10), |
130 |
|
d_conflicts(c), |
131 |
19706 |
d_blackBoxConflict(c, Node::null()), |
132 |
19706 |
d_blackBoxConflictPf(c, std::shared_ptr<ProofNode>(nullptr)), |
133 |
|
d_congruenceManager(c, |
134 |
|
u, |
135 |
|
d_constraintDatabase, |
136 |
19706 |
SetupLiteralCallBack(*this), |
137 |
|
d_partialModel, |
138 |
|
RaiseEqualityEngineConflict(*this), |
139 |
|
d_pnm), |
140 |
19706 |
d_cmEnabled(c, options::arithCongMan()), |
141 |
|
|
142 |
|
d_dualSimplex( |
143 |
19706 |
d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)), |
144 |
|
d_fcSimplex( |
145 |
19706 |
d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)), |
146 |
|
d_soiSimplex( |
147 |
19706 |
d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)), |
148 |
|
d_attemptSolSimplex( |
149 |
19706 |
d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)), |
150 |
|
d_pass1SDP(NULL), |
151 |
|
d_otherSDP(NULL), |
152 |
|
d_lastContextIntegerAttempted(c, -1), |
153 |
|
|
154 |
|
d_DELTA_ZERO(0), |
155 |
|
d_approxCuts(c), |
156 |
|
d_fullCheckCounter(0), |
157 |
|
d_cutCount(c, 0), |
158 |
|
d_cutInContext(c), |
159 |
|
d_likelyIntegerInfeasible(c, false), |
160 |
|
d_guessedCoeffSet(c, false), |
161 |
|
d_guessedCoeffs(), |
162 |
|
d_treeLog(NULL), |
163 |
|
d_replayVariables(), |
164 |
|
d_replayConstraints(), |
165 |
|
d_lhsTmp(), |
166 |
|
d_approxStats(NULL), |
167 |
|
d_attemptSolveIntTurnedOff(u, 0), |
168 |
|
d_dioSolveResources(0), |
169 |
|
d_solveIntMaybeHelp(0u), |
170 |
|
d_solveIntAttempts(0u), |
171 |
|
d_newFacts(false), |
172 |
|
d_previousStatus(Result::SAT_UNKNOWN), |
173 |
226619 |
d_statistics("theory::arith::") |
174 |
|
{ |
175 |
9853 |
} |
176 |
|
|
177 |
19706 |
TheoryArithPrivate::~TheoryArithPrivate(){ |
178 |
9853 |
if(d_treeLog != NULL){ delete d_treeLog; } |
179 |
9853 |
if(d_approxStats != NULL) { delete d_approxStats; } |
180 |
9853 |
} |
181 |
|
|
182 |
9814 |
bool TheoryArithPrivate::needsEqualityEngine(EeSetupInfo& esi) |
183 |
|
{ |
184 |
9814 |
if (!d_cmEnabled) |
185 |
|
{ |
186 |
|
return false; |
187 |
|
} |
188 |
9814 |
return d_congruenceManager.needsEqualityEngine(esi); |
189 |
|
} |
190 |
9853 |
void TheoryArithPrivate::finishInit() |
191 |
|
{ |
192 |
9853 |
if (d_cmEnabled) |
193 |
|
{ |
194 |
9814 |
eq::EqualityEngine* ee = d_containing.getEqualityEngine(); |
195 |
9814 |
Assert(ee != nullptr); |
196 |
9814 |
d_congruenceManager.finishInit(ee); |
197 |
|
} |
198 |
9853 |
} |
199 |
|
|
200 |
|
static bool contains(const ConstraintCPVec& v, ConstraintP con){ |
201 |
|
for(unsigned i = 0, N = v.size(); i < N; ++i){ |
202 |
|
if(v[i] == con){ |
203 |
|
return true; |
204 |
|
} |
205 |
|
} |
206 |
|
return false; |
207 |
|
} |
208 |
|
static void drop( ConstraintCPVec& v, ConstraintP con){ |
209 |
|
size_t readPos, writePos, N; |
210 |
|
for(readPos = 0, writePos = 0, N = v.size(); readPos < N; ++readPos){ |
211 |
|
ConstraintCP curr = v[readPos]; |
212 |
|
if(curr != con){ |
213 |
|
v[writePos] = curr; |
214 |
|
writePos++; |
215 |
|
} |
216 |
|
} |
217 |
|
v.resize(writePos); |
218 |
|
} |
219 |
|
|
220 |
|
|
221 |
|
static void resolve(ConstraintCPVec& buf, ConstraintP c, const ConstraintCPVec& pos, const ConstraintCPVec& neg){ |
222 |
|
unsigned posPos CVC5_UNUSED = pos.size(); |
223 |
|
for(unsigned i = 0, N = pos.size(); i < N; ++i){ |
224 |
|
if(pos[i] == c){ |
225 |
|
posPos = i; |
226 |
|
}else{ |
227 |
|
buf.push_back(pos[i]); |
228 |
|
} |
229 |
|
} |
230 |
|
Assert(posPos < pos.size()); |
231 |
|
ConstraintP negc = c->getNegation(); |
232 |
|
unsigned negPos CVC5_UNUSED = neg.size(); |
233 |
|
for(unsigned i = 0, N = neg.size(); i < N; ++i){ |
234 |
|
if(neg[i] == negc){ |
235 |
|
negPos = i; |
236 |
|
}else{ |
237 |
|
buf.push_back(neg[i]); |
238 |
|
} |
239 |
|
} |
240 |
|
Assert(negPos < neg.size()); |
241 |
|
|
242 |
|
// Assert(dnconf.getKind() == kind::AND); |
243 |
|
// Assert(upconf.getKind() == kind::AND); |
244 |
|
// Assert(dnpos < dnconf.getNumChildren()); |
245 |
|
// Assert(uppos < upconf.getNumChildren()); |
246 |
|
// Assert(equalUpToNegation(dnconf[dnpos], upconf[uppos])); |
247 |
|
|
248 |
|
// NodeBuilder nb(kind::AND); |
249 |
|
// dropPosition(nb, dnconf, dnpos); |
250 |
|
// dropPosition(nb, upconf, uppos); |
251 |
|
// return safeConstructNary(nb); |
252 |
|
} |
253 |
|
|
254 |
|
TheoryArithPrivate::ModelException::ModelException(TNode n, const char* msg) |
255 |
|
{ |
256 |
|
stringstream ss; |
257 |
|
ss << "Cannot construct a model for " << n << " as " << endl << msg; |
258 |
|
setMessage(ss.str()); |
259 |
|
} |
260 |
|
TheoryArithPrivate::ModelException::~ModelException() {} |
261 |
|
|
262 |
9853 |
TheoryArithPrivate::Statistics::Statistics(const std::string& name) |
263 |
|
: d_statAssertUpperConflicts( |
264 |
19706 |
smtStatisticsRegistry().registerInt(name + "AssertUpperConflicts")), |
265 |
|
d_statAssertLowerConflicts( |
266 |
19706 |
smtStatisticsRegistry().registerInt(name + "AssertLowerConflicts")), |
267 |
|
d_statUserVariables( |
268 |
19706 |
smtStatisticsRegistry().registerInt(name + "UserVariables")), |
269 |
|
d_statAuxiliaryVariables( |
270 |
19706 |
smtStatisticsRegistry().registerInt(name + "AuxiliaryVariables")), |
271 |
|
d_statDisequalitySplits( |
272 |
19706 |
smtStatisticsRegistry().registerInt(name + "DisequalitySplits")), |
273 |
|
d_statDisequalityConflicts( |
274 |
19706 |
smtStatisticsRegistry().registerInt(name + "DisequalityConflicts")), |
275 |
|
d_simplifyTimer( |
276 |
19706 |
smtStatisticsRegistry().registerTimer(name + "simplifyTimer")), |
277 |
|
d_staticLearningTimer( |
278 |
19706 |
smtStatisticsRegistry().registerTimer(name + "staticLearningTimer")), |
279 |
|
d_presolveTime( |
280 |
19706 |
smtStatisticsRegistry().registerTimer(name + "presolveTime")), |
281 |
|
d_newPropTime( |
282 |
19706 |
smtStatisticsRegistry().registerTimer(name + "newPropTimer")), |
283 |
9853 |
d_externalBranchAndBounds(smtStatisticsRegistry().registerInt( |
284 |
19706 |
name + "externalBranchAndBounds")), |
285 |
|
d_initialTableauSize( |
286 |
19706 |
smtStatisticsRegistry().registerInt(name + "initialTableauSize")), |
287 |
|
d_currSetToSmaller( |
288 |
19706 |
smtStatisticsRegistry().registerInt(name + "currSetToSmaller")), |
289 |
|
d_smallerSetToCurr( |
290 |
19706 |
smtStatisticsRegistry().registerInt(name + "smallerSetToCurr")), |
291 |
|
d_restartTimer( |
292 |
19706 |
smtStatisticsRegistry().registerTimer(name + "restartTimer")), |
293 |
|
d_boundComputationTime( |
294 |
19706 |
smtStatisticsRegistry().registerTimer(name + "bound::time")), |
295 |
9853 |
d_boundComputations(smtStatisticsRegistry().registerInt( |
296 |
19706 |
name + "bound::boundComputations")), |
297 |
9853 |
d_boundPropagations(smtStatisticsRegistry().registerInt( |
298 |
19706 |
name + "bound::boundPropagations")), |
299 |
|
d_unknownChecks( |
300 |
19706 |
smtStatisticsRegistry().registerInt(name + "status::unknowns")), |
301 |
9853 |
d_maxUnknownsInARow(smtStatisticsRegistry().registerInt( |
302 |
19706 |
name + "status::maxUnknownsInARow")), |
303 |
9853 |
d_avgUnknownsInARow(smtStatisticsRegistry().registerAverage( |
304 |
19706 |
name + "status::avgUnknownsInARow")), |
305 |
9853 |
d_revertsOnConflicts(smtStatisticsRegistry().registerInt( |
306 |
19706 |
name + "status::revertsOnConflicts")), |
307 |
9853 |
d_commitsOnConflicts(smtStatisticsRegistry().registerInt( |
308 |
19706 |
name + "status::commitsOnConflicts")), |
309 |
9853 |
d_nontrivialSatChecks(smtStatisticsRegistry().registerInt( |
310 |
19706 |
name + "status::nontrivialSatChecks")), |
311 |
|
d_replayLogRecCount( |
312 |
19706 |
smtStatisticsRegistry().registerInt(name + "z::approx::replay::rec")), |
313 |
9853 |
d_replayLogRecConflictEscalation(smtStatisticsRegistry().registerInt( |
314 |
19706 |
name + "z::approx::replay::rec::escalation")), |
315 |
9853 |
d_replayLogRecEarlyExit(smtStatisticsRegistry().registerInt( |
316 |
19706 |
name + "z::approx::replay::rec::earlyexit")), |
317 |
9853 |
d_replayBranchCloseFailures(smtStatisticsRegistry().registerInt( |
318 |
19706 |
name + "z::approx::replay::rec::branch::closefailures")), |
319 |
9853 |
d_replayLeafCloseFailures(smtStatisticsRegistry().registerInt( |
320 |
19706 |
name + "z::approx::replay::rec::leaf::closefailures")), |
321 |
9853 |
d_replayBranchSkips(smtStatisticsRegistry().registerInt( |
322 |
19706 |
name + "z::approx::replay::rec::branch::skips")), |
323 |
9853 |
d_mirCutsAttempted(smtStatisticsRegistry().registerInt( |
324 |
19706 |
name + "z::approx::cuts::mir::attempted")), |
325 |
9853 |
d_gmiCutsAttempted(smtStatisticsRegistry().registerInt( |
326 |
19706 |
name + "z::approx::cuts::gmi::attempted")), |
327 |
9853 |
d_branchCutsAttempted(smtStatisticsRegistry().registerInt( |
328 |
19706 |
name + "z::approx::cuts::branch::attempted")), |
329 |
9853 |
d_cutsReconstructed(smtStatisticsRegistry().registerInt( |
330 |
19706 |
name + "z::approx::cuts::reconstructed")), |
331 |
9853 |
d_cutsReconstructionFailed(smtStatisticsRegistry().registerInt( |
332 |
19706 |
name + "z::approx::cuts::reconstructed::failed")), |
333 |
9853 |
d_cutsProven(smtStatisticsRegistry().registerInt( |
334 |
19706 |
name + "z::approx::cuts::proofs")), |
335 |
9853 |
d_cutsProofFailed(smtStatisticsRegistry().registerInt( |
336 |
19706 |
name + "z::approx::cuts::proofs::failed")), |
337 |
9853 |
d_mipReplayLemmaCalls(smtStatisticsRegistry().registerInt( |
338 |
19706 |
name + "z::approx::external::calls")), |
339 |
9853 |
d_mipExternalCuts(smtStatisticsRegistry().registerInt( |
340 |
19706 |
name + "z::approx::external::cuts")), |
341 |
9853 |
d_mipExternalBranch(smtStatisticsRegistry().registerInt( |
342 |
19706 |
name + "z::approx::external::branches")), |
343 |
9853 |
d_inSolveInteger(smtStatisticsRegistry().registerInt( |
344 |
19706 |
name + "z::approx::inSolverInteger")), |
345 |
9853 |
d_branchesExhausted(smtStatisticsRegistry().registerInt( |
346 |
19706 |
name + "z::approx::exhausted::branches")), |
347 |
9853 |
d_execExhausted(smtStatisticsRegistry().registerInt( |
348 |
19706 |
name + "z::approx::exhausted::exec")), |
349 |
9853 |
d_pivotsExhausted(smtStatisticsRegistry().registerInt( |
350 |
19706 |
name + "z::approx::exhausted::pivots")), |
351 |
|
d_panicBranches( |
352 |
19706 |
smtStatisticsRegistry().registerInt(name + "z::arith::paniclemmas")), |
353 |
|
d_relaxCalls( |
354 |
19706 |
smtStatisticsRegistry().registerInt(name + "z::arith::relax::calls")), |
355 |
9853 |
d_relaxLinFeas(smtStatisticsRegistry().registerInt( |
356 |
19706 |
name + "z::arith::relax::feasible::res")), |
357 |
9853 |
d_relaxLinFeasFailures(smtStatisticsRegistry().registerInt( |
358 |
19706 |
name + "z::arith::relax::feasible::failures")), |
359 |
9853 |
d_relaxLinInfeas(smtStatisticsRegistry().registerInt( |
360 |
19706 |
name + "z::arith::relax::infeasible")), |
361 |
9853 |
d_relaxLinInfeasFailures(smtStatisticsRegistry().registerInt( |
362 |
19706 |
name + "z::arith::relax::infeasible::failures")), |
363 |
9853 |
d_relaxLinExhausted(smtStatisticsRegistry().registerInt( |
364 |
19706 |
name + "z::arith::relax::exhausted")), |
365 |
|
d_relaxOthers( |
366 |
19706 |
smtStatisticsRegistry().registerInt(name + "z::arith::relax::other")), |
367 |
9853 |
d_applyRowsDeleted(smtStatisticsRegistry().registerInt( |
368 |
19706 |
name + "z::arith::cuts::applyRowsDeleted")), |
369 |
9853 |
d_replaySimplexTimer(smtStatisticsRegistry().registerTimer( |
370 |
19706 |
name + "z::approx::replay::simplex::timer")), |
371 |
9853 |
d_replayLogTimer(smtStatisticsRegistry().registerTimer( |
372 |
19706 |
name + "z::approx::replay::log::timer")), |
373 |
|
d_solveIntTimer( |
374 |
19706 |
smtStatisticsRegistry().registerTimer(name + "z::solveInt::timer")), |
375 |
9853 |
d_solveRealRelaxTimer(smtStatisticsRegistry().registerTimer( |
376 |
19706 |
name + "z::solveRealRelax::timer")), |
377 |
|
d_solveIntCalls( |
378 |
19706 |
smtStatisticsRegistry().registerInt(name + "z::solveInt::calls")), |
379 |
9853 |
d_solveStandardEffort(smtStatisticsRegistry().registerInt( |
380 |
19706 |
name + "z::solveInt::calls::standardEffort")), |
381 |
|
d_approxDisabled( |
382 |
19706 |
smtStatisticsRegistry().registerInt(name + "z::approxDisabled")), |
383 |
|
d_replayAttemptFailed( |
384 |
19706 |
smtStatisticsRegistry().registerInt(name + "z::replayAttemptFailed")), |
385 |
9853 |
d_cutsRejectedDuringReplay(smtStatisticsRegistry().registerInt( |
386 |
19706 |
name + "z::approx::replay::cuts::rejected")), |
387 |
9853 |
d_cutsRejectedDuringLemmas(smtStatisticsRegistry().registerInt( |
388 |
19706 |
name + "z::approx::external::cuts::rejected")), |
389 |
9853 |
d_satPivots(smtStatisticsRegistry().registerHistogram<uint32_t>( |
390 |
19706 |
name + "pivots::sat")), |
391 |
9853 |
d_unsatPivots(smtStatisticsRegistry().registerHistogram<uint32_t>( |
392 |
19706 |
name + "pivots::unsat")), |
393 |
9853 |
d_unknownPivots(smtStatisticsRegistry().registerHistogram<uint32_t>( |
394 |
19706 |
name + "pivots::unknown")), |
395 |
9853 |
d_solveIntModelsAttempts(smtStatisticsRegistry().registerInt( |
396 |
19706 |
name + "z::solveInt::models::attempts")), |
397 |
9853 |
d_solveIntModelsSuccessful(smtStatisticsRegistry().registerInt( |
398 |
19706 |
name + "zzz::solveInt::models::successful")), |
399 |
9853 |
d_mipTimer(smtStatisticsRegistry().registerTimer( |
400 |
19706 |
name + "z::approx::mip::timer")), |
401 |
|
d_lpTimer( |
402 |
19706 |
smtStatisticsRegistry().registerTimer(name + "z::approx::lp::timer")), |
403 |
9853 |
d_mipProofsAttempted(smtStatisticsRegistry().registerInt( |
404 |
19706 |
name + "z::mip::proofs::attempted")), |
405 |
9853 |
d_mipProofsSuccessful(smtStatisticsRegistry().registerInt( |
406 |
19706 |
name + "z::mip::proofs::successful")), |
407 |
9853 |
d_numBranchesFailed(smtStatisticsRegistry().registerInt( |
408 |
719269 |
name + "z::mip::branch::proof::failed")) |
409 |
|
{ |
410 |
9853 |
} |
411 |
|
|
412 |
|
bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap){ |
413 |
|
DenseMap<Rational>::const_iterator riter, rend; |
414 |
|
for(riter=row.begin(), rend=row.end(); riter != rend; ++riter){ |
415 |
|
ArithVar v = *riter; |
416 |
|
const Rational& q = row[v]; |
417 |
|
if(q.complexity() > cap){ |
418 |
|
return false; |
419 |
|
} |
420 |
|
} |
421 |
|
return true; |
422 |
|
} |
423 |
|
|
424 |
175499 |
bool TheoryArithPrivate::isProofEnabled() const |
425 |
|
{ |
426 |
175499 |
return d_pnm != nullptr; |
427 |
|
} |
428 |
|
|
429 |
72908 |
void TheoryArithPrivate::raiseConflict(ConstraintCP a, InferenceId id){ |
430 |
72908 |
Assert(a->inConflict()); |
431 |
145816 |
d_conflicts.push_back(std::make_pair(a, id)); |
432 |
72908 |
} |
433 |
|
|
434 |
2389 |
void TheoryArithPrivate::raiseBlackBoxConflict(Node bb, |
435 |
|
std::shared_ptr<ProofNode> pf) |
436 |
|
{ |
437 |
2389 |
Debug("arith::bb") << "raiseBlackBoxConflict: " << bb << std::endl; |
438 |
2389 |
if (d_blackBoxConflict.get().isNull()) |
439 |
|
{ |
440 |
2389 |
if (isProofEnabled()) |
441 |
|
{ |
442 |
415 |
Debug("arith::bb") << " with proof " << pf << std::endl; |
443 |
415 |
d_blackBoxConflictPf.set(pf); |
444 |
|
} |
445 |
2389 |
d_blackBoxConflict = bb; |
446 |
|
} |
447 |
2389 |
} |
448 |
|
|
449 |
15732534 |
bool TheoryArithPrivate::anyConflict() const |
450 |
|
{ |
451 |
15732534 |
return !conflictQueueEmpty() || !d_blackBoxConflict.get().isNull(); |
452 |
|
} |
453 |
|
|
454 |
54533 |
void TheoryArithPrivate::revertOutOfConflict(){ |
455 |
54533 |
d_partialModel.revertAssignmentChanges(); |
456 |
54533 |
clearUpdates(); |
457 |
54533 |
d_currentPropagationList.clear(); |
458 |
54533 |
} |
459 |
|
|
460 |
1725106 |
void TheoryArithPrivate::clearUpdates(){ |
461 |
1725106 |
d_updatedBounds.purge(); |
462 |
1725106 |
} |
463 |
|
|
464 |
|
// void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b){ |
465 |
|
// ConstraintCPVec v; |
466 |
|
// v.push_back(a); |
467 |
|
// v.push_back(b); |
468 |
|
// d_conflicts.push_back(v); |
469 |
|
// } |
470 |
|
|
471 |
|
// void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c){ |
472 |
|
// ConstraintCPVec v; |
473 |
|
// v.push_back(a); |
474 |
|
// v.push_back(b); |
475 |
|
// v.push_back(c); |
476 |
|
// d_conflicts.push_back(v); |
477 |
|
// } |
478 |
|
|
479 |
544755 |
void TheoryArithPrivate::zeroDifferenceDetected(ArithVar x){ |
480 |
544755 |
if(d_cmEnabled){ |
481 |
544755 |
Assert(d_congruenceManager.isWatchedVariable(x)); |
482 |
544755 |
Assert(d_partialModel.upperBoundIsZero(x)); |
483 |
544755 |
Assert(d_partialModel.lowerBoundIsZero(x)); |
484 |
|
|
485 |
544755 |
ConstraintP lb = d_partialModel.getLowerBoundConstraint(x); |
486 |
544755 |
ConstraintP ub = d_partialModel.getUpperBoundConstraint(x); |
487 |
|
|
488 |
544755 |
if(lb->isEquality()){ |
489 |
224720 |
d_congruenceManager.watchedVariableIsZero(lb); |
490 |
320035 |
}else if(ub->isEquality()){ |
491 |
|
d_congruenceManager.watchedVariableIsZero(ub); |
492 |
|
}else{ |
493 |
320035 |
d_congruenceManager.watchedVariableIsZero(lb, ub); |
494 |
|
} |
495 |
|
} |
496 |
544755 |
} |
497 |
|
|
498 |
|
bool TheoryArithPrivate::getSolveIntegerResource(){ |
499 |
|
if(d_attemptSolveIntTurnedOff > 0){ |
500 |
|
d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff - 1; |
501 |
|
return false; |
502 |
|
}else{ |
503 |
|
return true; |
504 |
|
} |
505 |
|
} |
506 |
|
|
507 |
2537 |
bool TheoryArithPrivate::getDioCuttingResource(){ |
508 |
2537 |
if(d_dioSolveResources > 0){ |
509 |
1883 |
d_dioSolveResources--; |
510 |
1883 |
if(d_dioSolveResources == 0){ |
511 |
131 |
d_dioSolveResources = -options::rrTurns(); |
512 |
|
} |
513 |
1883 |
return true; |
514 |
|
}else{ |
515 |
654 |
d_dioSolveResources++; |
516 |
654 |
if(d_dioSolveResources >= 0){ |
517 |
402 |
d_dioSolveResources = options::dioSolverTurns(); |
518 |
|
} |
519 |
654 |
return false; |
520 |
|
} |
521 |
|
} |
522 |
|
|
523 |
|
/* procedure AssertLower( x_i >= c_i ) */ |
524 |
2064524 |
bool TheoryArithPrivate::AssertLower(ConstraintP constraint){ |
525 |
2064524 |
Assert(constraint != NullConstraint); |
526 |
2064524 |
Assert(constraint->isLowerBound()); |
527 |
2064524 |
Assert(constraint->isTrue()); |
528 |
2064524 |
Assert(!constraint->negationHasProof()); |
529 |
|
|
530 |
2064524 |
ArithVar x_i = constraint->getVariable(); |
531 |
2064524 |
const DeltaRational& c_i = constraint->getValue(); |
532 |
|
|
533 |
2064524 |
Debug("arith") << "AssertLower(" << x_i << " " << c_i << ")"<< std::endl; |
534 |
|
|
535 |
2064524 |
Assert(!isInteger(x_i) || c_i.isIntegral()); |
536 |
|
|
537 |
|
//TODO Relax to less than? |
538 |
2064524 |
if(d_partialModel.lessThanLowerBound(x_i, c_i)){ |
539 |
861229 |
return false; //sat |
540 |
|
} |
541 |
|
|
542 |
1203295 |
int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i); |
543 |
1203295 |
if(cmpToUB > 0){ // c_i < \lowerbound(x_i) |
544 |
768 |
ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i); |
545 |
768 |
ConstraintP negation = constraint->getNegation(); |
546 |
768 |
negation->impliedByUnate(ubc, true); |
547 |
|
|
548 |
768 |
raiseConflict(constraint, InferenceId::ARITH_CONF_LOWER); |
549 |
|
|
550 |
768 |
++(d_statistics.d_statAssertLowerConflicts); |
551 |
768 |
return true; |
552 |
1202527 |
}else if(cmpToUB == 0){ |
553 |
364796 |
if(isInteger(x_i)){ |
554 |
166999 |
d_constantIntegerVariables.push_back(x_i); |
555 |
166999 |
Debug("dio::push") << "dio::push " << x_i << endl; |
556 |
|
} |
557 |
364796 |
ConstraintP ub = d_partialModel.getUpperBoundConstraint(x_i); |
558 |
|
|
559 |
364796 |
if(d_cmEnabled){ |
560 |
364796 |
if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){ |
561 |
|
// if it is not a watched variable report it |
562 |
|
// if it is is a watched variable and c_i == 0, |
563 |
|
// let zeroDifferenceDetected(x_i) catch this |
564 |
117152 |
d_congruenceManager.equalsConstant(constraint, ub); |
565 |
|
} |
566 |
|
} |
567 |
|
|
568 |
364796 |
const ValueCollection& vc = constraint->getValueCollection(); |
569 |
364796 |
if(vc.hasEquality()){ |
570 |
258560 |
Assert(vc.hasDisequality()); |
571 |
258560 |
ConstraintP eq = vc.getEquality(); |
572 |
258560 |
ConstraintP diseq = vc.getDisequality(); |
573 |
|
// x <= b, x >= b |= x = b |
574 |
|
// (x > b or x < b or x = b) |
575 |
258560 |
Debug("arith::eq") << "lb == ub, propagate eq" << eq << endl; |
576 |
258560 |
bool triConflict = diseq->isTrue(); |
577 |
|
|
578 |
258560 |
if(!eq->isTrue()){ |
579 |
253535 |
eq->impliedByTrichotomy(constraint, ub, triConflict); |
580 |
253535 |
eq->tryToPropagate(); |
581 |
|
} |
582 |
258560 |
if(triConflict){ |
583 |
|
++(d_statistics.d_statDisequalityConflicts); |
584 |
|
raiseConflict(eq, InferenceId::ARITH_CONF_TRICHOTOMY); |
585 |
|
return true; |
586 |
|
} |
587 |
|
} |
588 |
|
}else{ |
589 |
|
// l <= x <= u and l < u |
590 |
837731 |
Assert(cmpToUB < 0); |
591 |
837731 |
const ValueCollection& vc = constraint->getValueCollection(); |
592 |
|
|
593 |
837731 |
if(vc.hasDisequality()){ |
594 |
235015 |
const ConstraintP diseq = vc.getDisequality(); |
595 |
235015 |
if(diseq->isTrue()){ |
596 |
12276 |
const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound); |
597 |
12276 |
ConstraintP negUb = ub->getNegation(); |
598 |
|
|
599 |
|
// l <= x, l != x |= l < x |
600 |
|
// |= not (l >= x) |
601 |
12276 |
bool ubInConflict = ub->hasProof(); |
602 |
12276 |
bool learnNegUb = !(negUb->hasProof()); |
603 |
12276 |
if(learnNegUb){ |
604 |
12276 |
negUb->impliedByTrichotomy(constraint, diseq, ubInConflict); |
605 |
12276 |
negUb->tryToPropagate(); |
606 |
|
} |
607 |
12276 |
if(ubInConflict){ |
608 |
|
raiseConflict(ub, InferenceId::ARITH_CONF_TRICHOTOMY); |
609 |
|
return true; |
610 |
12276 |
}else if(learnNegUb){ |
611 |
12276 |
d_learnedBounds.push_back(negUb); |
612 |
|
} |
613 |
|
} |
614 |
|
} |
615 |
|
} |
616 |
|
|
617 |
1202527 |
d_currentPropagationList.push_back(constraint); |
618 |
1202527 |
d_currentPropagationList.push_back(d_partialModel.getLowerBoundConstraint(x_i)); |
619 |
|
|
620 |
1202527 |
d_partialModel.setLowerBoundConstraint(constraint); |
621 |
|
|
622 |
1202527 |
if(d_cmEnabled){ |
623 |
1201962 |
if(d_congruenceManager.isWatchedVariable(x_i)){ |
624 |
795409 |
int sgn = c_i.sgn(); |
625 |
795409 |
if(sgn > 0){ |
626 |
177853 |
d_congruenceManager.watchedVariableCannotBeZero(constraint); |
627 |
617556 |
}else if(sgn == 0 && d_partialModel.upperBoundIsZero(x_i)){ |
628 |
247644 |
zeroDifferenceDetected(x_i); |
629 |
|
} |
630 |
|
} |
631 |
|
} |
632 |
|
|
633 |
1202527 |
d_updatedBounds.softAdd(x_i); |
634 |
|
|
635 |
1202527 |
if(Debug.isOn("model")) { |
636 |
|
Debug("model") << "before" << endl; |
637 |
|
d_partialModel.printModel(x_i); |
638 |
|
d_tableau.debugPrintIsBasic(x_i); |
639 |
|
} |
640 |
|
|
641 |
1202527 |
if(!d_tableau.isBasic(x_i)){ |
642 |
428206 |
if(d_partialModel.getAssignment(x_i) < c_i){ |
643 |
59699 |
d_linEq.update(x_i, c_i); |
644 |
|
} |
645 |
|
}else{ |
646 |
774321 |
d_errorSet.signalVariable(x_i); |
647 |
|
} |
648 |
|
|
649 |
1202527 |
if(Debug.isOn("model")) { |
650 |
|
Debug("model") << "after" << endl; |
651 |
|
d_partialModel.printModel(x_i); |
652 |
|
d_tableau.debugPrintIsBasic(x_i); |
653 |
|
} |
654 |
|
|
655 |
1202527 |
return false; //sat |
656 |
|
} |
657 |
|
|
658 |
|
/* procedure AssertUpper( x_i <= c_i) */ |
659 |
1968281 |
bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){ |
660 |
1968281 |
Assert(constraint != NullConstraint); |
661 |
1968281 |
Assert(constraint->isUpperBound()); |
662 |
1968281 |
Assert(constraint->isTrue()); |
663 |
1968281 |
Assert(!constraint->negationHasProof()); |
664 |
|
|
665 |
1968281 |
ArithVar x_i = constraint->getVariable(); |
666 |
1968281 |
const DeltaRational& c_i = constraint->getValue(); |
667 |
|
|
668 |
1968281 |
Debug("arith") << "AssertUpper(" << x_i << " " << c_i << ")"<< std::endl; |
669 |
|
|
670 |
|
|
671 |
|
//Too strong because of rounding with integers |
672 |
|
//Assert(!constraint->hasLiteral() || original == constraint->getLiteral()); |
673 |
1968281 |
Assert(!isInteger(x_i) || c_i.isIntegral()); |
674 |
|
|
675 |
1968281 |
Debug("arith") << "AssertUpper(" << x_i << " " << c_i << ")"<< std::endl; |
676 |
|
|
677 |
1968281 |
if(d_partialModel.greaterThanUpperBound(x_i, c_i) ){ // \upperbound(x_i) <= c_i |
678 |
908915 |
return false; //sat |
679 |
|
} |
680 |
|
|
681 |
|
// cmpToLb = \lowerbound(x_i).cmp(c_i) |
682 |
1059366 |
int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i); |
683 |
1059366 |
if( cmpToLB < 0 ){ // \upperbound(x_i) < \lowerbound(x_i) |
684 |
|
// l_i <= x_i and c_i < l_i |= c_i < x_i |
685 |
|
// or ... |= not (x_i <= c_i) |
686 |
2065 |
ConstraintP lbc = d_partialModel.getLowerBoundConstraint(x_i); |
687 |
2065 |
ConstraintP negConstraint = constraint->getNegation(); |
688 |
2065 |
negConstraint->impliedByUnate(lbc, true); |
689 |
2065 |
raiseConflict(constraint, InferenceId::ARITH_CONF_UPPER); |
690 |
2065 |
++(d_statistics.d_statAssertUpperConflicts); |
691 |
2065 |
return true; |
692 |
1057301 |
}else if(cmpToLB == 0){ // \lowerBound(x_i) == \upperbound(x_i) |
693 |
151443 |
if(isInteger(x_i)){ |
694 |
101505 |
d_constantIntegerVariables.push_back(x_i); |
695 |
101505 |
Debug("dio::push") << "dio::push " << x_i << endl; |
696 |
|
} |
697 |
|
|
698 |
151443 |
const ValueCollection& vc = constraint->getValueCollection(); |
699 |
151443 |
ConstraintP lb = d_partialModel.getLowerBoundConstraint(x_i); |
700 |
151443 |
if(d_cmEnabled){ |
701 |
151443 |
if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){ |
702 |
|
// if it is not a watched variable report it |
703 |
|
// if it is is a watched variable and c_i == 0, |
704 |
|
// let zeroDifferenceDetected(x_i) catch this |
705 |
79052 |
d_congruenceManager.equalsConstant(lb, constraint); |
706 |
|
} |
707 |
|
} |
708 |
|
|
709 |
151443 |
if(vc.hasDisequality()){ |
710 |
117105 |
Assert(vc.hasDisequality()); |
711 |
117105 |
ConstraintP eq = vc.getEquality(); |
712 |
117105 |
ConstraintP diseq = vc.getDisequality(); |
713 |
|
// x <= b, x >= b |= x = b |
714 |
|
// (x > b or x < b or x = b) |
715 |
117105 |
Debug("arith::eq") << "lb == ub, propagate eq" << eq << endl; |
716 |
117105 |
bool triConflict = diseq->isTrue(); |
717 |
117105 |
if(!eq->isTrue()){ |
718 |
87199 |
eq->impliedByTrichotomy(constraint, lb, triConflict); |
719 |
87199 |
eq->tryToPropagate(); |
720 |
|
} |
721 |
117105 |
if(triConflict){ |
722 |
2 |
++(d_statistics.d_statDisequalityConflicts); |
723 |
2 |
raiseConflict(eq, InferenceId::ARITH_CONF_TRICHOTOMY); |
724 |
2 |
return true; |
725 |
|
} |
726 |
|
} |
727 |
905858 |
}else if(cmpToLB > 0){ |
728 |
|
// l <= x <= u and l < u |
729 |
905858 |
Assert(cmpToLB > 0); |
730 |
905858 |
const ValueCollection& vc = constraint->getValueCollection(); |
731 |
|
|
732 |
905858 |
if(vc.hasDisequality()){ |
733 |
371758 |
const ConstraintP diseq = vc.getDisequality(); |
734 |
371758 |
if(diseq->isTrue()){ |
735 |
36225 |
const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound); |
736 |
36225 |
ConstraintP negLb = lb->getNegation(); |
737 |
|
|
738 |
|
// x <= u, u != x |= u < x |
739 |
|
// |= not (u >= x) |
740 |
36225 |
bool lbInConflict = lb->hasProof(); |
741 |
36225 |
bool learnNegLb = !(negLb->hasProof()); |
742 |
36225 |
if(learnNegLb){ |
743 |
36224 |
negLb->impliedByTrichotomy(constraint, diseq, lbInConflict); |
744 |
36224 |
negLb->tryToPropagate(); |
745 |
|
} |
746 |
36225 |
if(lbInConflict){ |
747 |
|
raiseConflict(lb, InferenceId::ARITH_CONF_TRICHOTOMY); |
748 |
|
return true; |
749 |
36225 |
}else if(learnNegLb){ |
750 |
36224 |
d_learnedBounds.push_back(negLb); |
751 |
|
} |
752 |
|
} |
753 |
|
} |
754 |
|
} |
755 |
|
|
756 |
1057299 |
d_currentPropagationList.push_back(constraint); |
757 |
1057299 |
d_currentPropagationList.push_back(d_partialModel.getUpperBoundConstraint(x_i)); |
758 |
|
//It is fine if this is NullConstraint |
759 |
|
|
760 |
1057299 |
d_partialModel.setUpperBoundConstraint(constraint); |
761 |
|
|
762 |
1057299 |
if(d_cmEnabled){ |
763 |
1056468 |
if(d_congruenceManager.isWatchedVariable(x_i)){ |
764 |
742745 |
int sgn = c_i.sgn(); |
765 |
742745 |
if(sgn < 0){ |
766 |
330133 |
d_congruenceManager.watchedVariableCannotBeZero(constraint); |
767 |
412612 |
}else if(sgn == 0 && d_partialModel.lowerBoundIsZero(x_i)){ |
768 |
72391 |
zeroDifferenceDetected(x_i); |
769 |
|
} |
770 |
|
} |
771 |
|
} |
772 |
|
|
773 |
1057299 |
d_updatedBounds.softAdd(x_i); |
774 |
|
|
775 |
1057299 |
if(Debug.isOn("model")) { |
776 |
|
Debug("model") << "before" << endl; |
777 |
|
d_partialModel.printModel(x_i); |
778 |
|
d_tableau.debugPrintIsBasic(x_i); |
779 |
|
} |
780 |
|
|
781 |
1057299 |
if(!d_tableau.isBasic(x_i)){ |
782 |
420733 |
if(d_partialModel.getAssignment(x_i) > c_i){ |
783 |
47695 |
d_linEq.update(x_i, c_i); |
784 |
|
} |
785 |
|
}else{ |
786 |
636566 |
d_errorSet.signalVariable(x_i); |
787 |
|
} |
788 |
|
|
789 |
1057299 |
if(Debug.isOn("model")) { |
790 |
|
Debug("model") << "after" << endl; |
791 |
|
d_partialModel.printModel(x_i); |
792 |
|
d_tableau.debugPrintIsBasic(x_i); |
793 |
|
} |
794 |
|
|
795 |
1057299 |
return false; //sat |
796 |
|
} |
797 |
|
|
798 |
|
|
799 |
|
/* procedure AssertEquality( x_i == c_i ) */ |
800 |
1025054 |
bool TheoryArithPrivate::AssertEquality(ConstraintP constraint){ |
801 |
1025054 |
Assert(constraint != NullConstraint); |
802 |
1025054 |
Assert(constraint->isEquality()); |
803 |
1025054 |
Assert(constraint->isTrue()); |
804 |
1025054 |
Assert(!constraint->negationHasProof()); |
805 |
|
|
806 |
1025054 |
ArithVar x_i = constraint->getVariable(); |
807 |
1025054 |
const DeltaRational& c_i = constraint->getValue(); |
808 |
|
|
809 |
1025054 |
Debug("arith") << "AssertEquality(" << x_i << " " << c_i << ")"<< std::endl; |
810 |
|
|
811 |
|
//Should be fine in integers |
812 |
1025054 |
Assert(!isInteger(x_i) || c_i.isIntegral()); |
813 |
|
|
814 |
1025054 |
int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i); |
815 |
1025054 |
int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i); |
816 |
|
|
817 |
|
// u_i <= c_i <= l_i |
818 |
|
// This can happen if both c_i <= x_i and x_i <= c_i are in the system. |
819 |
1025054 |
if(cmpToUB >= 0 && cmpToLB <= 0){ |
820 |
45310 |
return false; //sat |
821 |
|
} |
822 |
|
|
823 |
979744 |
if(cmpToUB > 0 || cmpToLB < 0){ |
824 |
3050 |
ConstraintP cb = (cmpToUB > 0) ? d_partialModel.getUpperBoundConstraint(x_i) : |
825 |
3050 |
d_partialModel.getLowerBoundConstraint(x_i); |
826 |
2002 |
ConstraintP diseq = constraint->getNegation(); |
827 |
2002 |
Assert(!diseq->isTrue()); |
828 |
2002 |
diseq->impliedByUnate(cb, true); |
829 |
2002 |
raiseConflict(constraint, InferenceId::ARITH_CONF_EQ); |
830 |
2002 |
return true; |
831 |
|
} |
832 |
|
|
833 |
977742 |
Assert(cmpToUB <= 0); |
834 |
977742 |
Assert(cmpToLB >= 0); |
835 |
977742 |
Assert(cmpToUB < 0 || cmpToLB > 0); |
836 |
|
|
837 |
977742 |
if(isInteger(x_i)){ |
838 |
932194 |
d_constantIntegerVariables.push_back(x_i); |
839 |
932194 |
Debug("dio::push") << "dio::push " << x_i << endl; |
840 |
|
} |
841 |
|
|
842 |
|
// Don't bother to check whether x_i != c_i is in d_diseq |
843 |
|
// The a and (not a) should never be on the fact queue |
844 |
977742 |
d_currentPropagationList.push_back(constraint); |
845 |
977742 |
d_currentPropagationList.push_back(d_partialModel.getLowerBoundConstraint(x_i)); |
846 |
977742 |
d_currentPropagationList.push_back(d_partialModel.getUpperBoundConstraint(x_i)); |
847 |
|
|
848 |
977742 |
d_partialModel.setUpperBoundConstraint(constraint); |
849 |
977742 |
d_partialModel.setLowerBoundConstraint(constraint); |
850 |
|
|
851 |
977742 |
if(d_cmEnabled){ |
852 |
976129 |
if(d_congruenceManager.isWatchedVariable(x_i)){ |
853 |
260406 |
int sgn = c_i.sgn(); |
854 |
260406 |
if(sgn == 0){ |
855 |
224720 |
zeroDifferenceDetected(x_i); |
856 |
|
}else{ |
857 |
35686 |
d_congruenceManager.watchedVariableCannotBeZero(constraint); |
858 |
35686 |
d_congruenceManager.equalsConstant(constraint); |
859 |
|
} |
860 |
|
}else{ |
861 |
715723 |
d_congruenceManager.equalsConstant(constraint); |
862 |
|
} |
863 |
|
} |
864 |
|
|
865 |
977742 |
d_updatedBounds.softAdd(x_i); |
866 |
|
|
867 |
977742 |
if(Debug.isOn("model")) { |
868 |
|
Debug("model") << "before" << endl; |
869 |
|
d_partialModel.printModel(x_i); |
870 |
|
d_tableau.debugPrintIsBasic(x_i); |
871 |
|
} |
872 |
|
|
873 |
977742 |
if(!d_tableau.isBasic(x_i)){ |
874 |
530039 |
if(!(d_partialModel.getAssignment(x_i) == c_i)){ |
875 |
59189 |
d_linEq.update(x_i, c_i); |
876 |
|
} |
877 |
|
}else{ |
878 |
447703 |
d_errorSet.signalVariable(x_i); |
879 |
|
} |
880 |
|
|
881 |
977742 |
if(Debug.isOn("model")) { |
882 |
|
Debug("model") << "after" << endl; |
883 |
|
d_partialModel.printModel(x_i); |
884 |
|
d_tableau.debugPrintIsBasic(x_i); |
885 |
|
} |
886 |
|
|
887 |
977742 |
return false; |
888 |
|
} |
889 |
|
|
890 |
|
|
891 |
|
/* procedure AssertDisequality( x_i != c_i ) */ |
892 |
762456 |
bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){ |
893 |
762456 |
Assert(constraint != NullConstraint); |
894 |
762456 |
Assert(constraint->isDisequality()); |
895 |
762456 |
Assert(constraint->isTrue()); |
896 |
762456 |
Assert(!constraint->negationHasProof()); |
897 |
|
|
898 |
762456 |
ArithVar x_i = constraint->getVariable(); |
899 |
762456 |
const DeltaRational& c_i = constraint->getValue(); |
900 |
762456 |
Debug("arith") << "AssertDisequality(" << x_i << " " << c_i << ")"<< std::endl; |
901 |
|
|
902 |
|
//Should be fine in integers |
903 |
762456 |
Assert(!isInteger(x_i) || c_i.isIntegral()); |
904 |
|
|
905 |
762456 |
if(d_cmEnabled){ |
906 |
761865 |
if(d_congruenceManager.isWatchedVariable(x_i)){ |
907 |
175137 |
int sgn = c_i.sgn(); |
908 |
175137 |
if(sgn == 0){ |
909 |
151459 |
d_congruenceManager.watchedVariableCannotBeZero(constraint); |
910 |
|
} |
911 |
|
} |
912 |
|
} |
913 |
|
|
914 |
762456 |
const ValueCollection& vc = constraint->getValueCollection(); |
915 |
762456 |
if(vc.hasLowerBound() && vc.hasUpperBound()){ |
916 |
334578 |
const ConstraintP lb = vc.getLowerBound(); |
917 |
334578 |
const ConstraintP ub = vc.getUpperBound(); |
918 |
334578 |
if(lb->isTrue() && ub->isTrue()){ |
919 |
82 |
ConstraintP eq = constraint->getNegation(); |
920 |
82 |
eq->impliedByTrichotomy(lb, ub, true); |
921 |
82 |
raiseConflict(constraint, InferenceId::ARITH_CONF_TRICHOTOMY); |
922 |
|
//in conflict |
923 |
82 |
++(d_statistics.d_statDisequalityConflicts); |
924 |
82 |
return true; |
925 |
|
} |
926 |
|
} |
927 |
762374 |
if(vc.hasLowerBound() ){ |
928 |
381179 |
const ConstraintP lb = vc.getLowerBound(); |
929 |
381179 |
if(lb->isTrue()){ |
930 |
118262 |
const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound); |
931 |
118262 |
Assert(!ub->isTrue()); |
932 |
118262 |
Debug("arith::eq") << "propagate UpperBound " << constraint << lb << ub << endl; |
933 |
118262 |
const ConstraintP negUb = ub->getNegation(); |
934 |
118262 |
if(!negUb->isTrue()){ |
935 |
60926 |
negUb->impliedByTrichotomy(constraint, lb, false); |
936 |
60926 |
negUb->tryToPropagate(); |
937 |
60926 |
d_learnedBounds.push_back(negUb); |
938 |
|
} |
939 |
|
} |
940 |
|
} |
941 |
762374 |
if(vc.hasUpperBound()){ |
942 |
388801 |
const ConstraintP ub = vc.getUpperBound(); |
943 |
388801 |
if(ub->isTrue()){ |
944 |
81839 |
const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound); |
945 |
81839 |
Assert(!lb->isTrue()); |
946 |
|
|
947 |
81839 |
Debug("arith::eq") << "propagate LowerBound " << constraint << lb << ub << endl; |
948 |
81839 |
const ConstraintP negLb = lb->getNegation(); |
949 |
81839 |
if(!negLb->isTrue()){ |
950 |
12478 |
negLb->impliedByTrichotomy(constraint, ub, false); |
951 |
12478 |
negLb->tryToPropagate(); |
952 |
12478 |
d_learnedBounds.push_back(negLb); |
953 |
|
} |
954 |
|
} |
955 |
|
} |
956 |
|
|
957 |
762374 |
bool split = constraint->isSplit(); |
958 |
|
|
959 |
762374 |
if(!split && c_i == d_partialModel.getAssignment(x_i)){ |
960 |
14725 |
Debug("arith::eq") << "lemma now! " << constraint << endl; |
961 |
14725 |
outputTrustedLemma(constraint->split(), InferenceId::ARITH_SPLIT_DEQ); |
962 |
14725 |
return false; |
963 |
747649 |
}else if(d_partialModel.strictlyLessThanLowerBound(x_i, c_i)){ |
964 |
224929 |
Debug("arith::eq") << "can drop as less than lb" << constraint << endl; |
965 |
522720 |
}else if(d_partialModel.strictlyGreaterThanUpperBound(x_i, c_i)){ |
966 |
201137 |
Debug("arith::eq") << "can drop as less than ub" << constraint << endl; |
967 |
321583 |
}else if(!split){ |
968 |
191607 |
Debug("arith::eq") << "push back" << constraint << endl; |
969 |
191607 |
d_diseqQueue.push(constraint); |
970 |
191607 |
d_partialModel.invalidateDelta(); |
971 |
|
}else{ |
972 |
129976 |
Debug("arith::eq") << "skipping already split " << constraint << endl; |
973 |
|
} |
974 |
747649 |
return false; |
975 |
|
} |
976 |
|
|
977 |
678817 |
void TheoryArithPrivate::notifySharedTerm(TNode n) |
978 |
|
{ |
979 |
678817 |
Debug("arith::notifySharedTerm") << "notifySharedTerm: " << n << endl; |
980 |
678817 |
if(n.isConst()){ |
981 |
82133 |
d_partialModel.invalidateDelta(); |
982 |
|
} |
983 |
678817 |
if(!n.isConst() && !isSetup(n)){ |
984 |
555440 |
Polynomial poly = Polynomial::parsePolynomial(n); |
985 |
555440 |
Polynomial::iterator it = poly.begin(); |
986 |
555440 |
Polynomial::iterator it_end = poly.end(); |
987 |
1499156 |
for (; it != it_end; ++ it) { |
988 |
1221436 |
Monomial m = *it; |
989 |
610718 |
if (!m.isConstant() && !isSetup(m.getVarList().getNode())) { |
990 |
5613 |
setupVariableList(m.getVarList()); |
991 |
|
} |
992 |
|
} |
993 |
|
} |
994 |
678817 |
} |
995 |
|
|
996 |
2852 |
Node TheoryArithPrivate::getModelValue(TNode term) { |
997 |
|
try{ |
998 |
5704 |
const DeltaRational drv = getDeltaValue(term); |
999 |
2852 |
const Rational& delta = d_partialModel.getDelta(); |
1000 |
5704 |
const Rational qmodel = drv.substituteDelta( delta ); |
1001 |
2852 |
return mkRationalNode( qmodel ); |
1002 |
|
} catch (DeltaRationalException& dr) { |
1003 |
|
return Node::null(); |
1004 |
|
} catch (ModelException& me) { |
1005 |
|
return Node::null(); |
1006 |
|
} |
1007 |
|
} |
1008 |
|
|
1009 |
11667 |
Theory::PPAssertStatus TheoryArithPrivate::ppAssert( |
1010 |
|
TrustNode tin, TrustSubstitutionMap& outSubstitutions) |
1011 |
|
{ |
1012 |
23334 |
TimerStat::CodeTimer codeTimer(d_statistics.d_simplifyTimer); |
1013 |
23334 |
TNode in = tin.getNode(); |
1014 |
11667 |
Debug("simplify") << "TheoryArithPrivate::solve(" << in << ")" << endl; |
1015 |
|
|
1016 |
|
|
1017 |
|
// Solve equalities |
1018 |
23334 |
Rational minConstant = 0; |
1019 |
23334 |
Node minMonomial; |
1020 |
23334 |
Node minVar; |
1021 |
28682 |
if (in.getKind() == kind::EQUAL && |
1022 |
17015 |
Theory::theoryOf(in[0].getType()) == THEORY_ARITH) { |
1023 |
4149 |
Comparison cmp = Comparison::parseNormalForm(in); |
1024 |
|
|
1025 |
4149 |
Polynomial left = cmp.getLeft(); |
1026 |
|
|
1027 |
4149 |
Monomial m = left.getHead(); |
1028 |
2674 |
if (m.getVarList().singleton()){ |
1029 |
5232 |
VarList vl = m.getVarList(); |
1030 |
5232 |
Node var = vl.getNode(); |
1031 |
2616 |
if (var.isVar()) |
1032 |
|
{ |
1033 |
|
// if vl.isIntegral then m.getConstant().isOne() |
1034 |
1411 |
if(!vl.isIntegral() || m.getConstant().isOne()){ |
1035 |
1399 |
minVar = var; |
1036 |
|
} |
1037 |
|
} |
1038 |
|
} |
1039 |
|
|
1040 |
|
// Solve for variable |
1041 |
2674 |
if (!minVar.isNull()) { |
1042 |
1599 |
Polynomial right = cmp.getRight(); |
1043 |
1599 |
Node elim = right.getNode(); |
1044 |
|
// ax + p = c -> (ax + p) -ax - c = -ax |
1045 |
|
// x = (p - ax - c) * -1/a |
1046 |
|
// Add the substitution if not recursive |
1047 |
1399 |
Assert(elim == Rewriter::rewrite(elim)); |
1048 |
|
|
1049 |
1399 |
if (right.size() > options::ppAssertMaxSubSize()) |
1050 |
|
{ |
1051 |
218 |
Debug("simplify") |
1052 |
|
<< "TheoryArithPrivate::solve(): did not substitute due to the " |
1053 |
109 |
"right hand side containing too many terms: " |
1054 |
109 |
<< minVar << ":" << elim << endl; |
1055 |
109 |
Debug("simplify") << right.size() << endl; |
1056 |
|
} |
1057 |
1290 |
else if (d_containing.isLegalElimination(minVar, elim)) |
1058 |
|
{ |
1059 |
|
// cannot eliminate integers here unless we know the resulting |
1060 |
|
// substitution is integral |
1061 |
2398 |
Debug("simplify") << "TheoryArithPrivate::solve(): substitution " |
1062 |
1199 |
<< minVar << " |-> " << elim << endl; |
1063 |
|
|
1064 |
1199 |
outSubstitutions.addSubstitutionSolved(minVar, elim, tin); |
1065 |
1199 |
return Theory::PP_ASSERT_STATUS_SOLVED; |
1066 |
|
} |
1067 |
|
else |
1068 |
|
{ |
1069 |
182 |
Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute " |
1070 |
182 |
<< minVar << ":" << minVar.getType() << " |-> " |
1071 |
91 |
<< elim << ":" << elim.getType() << endl; |
1072 |
|
} |
1073 |
|
} |
1074 |
|
} |
1075 |
|
|
1076 |
|
// If a relation, remember the bound |
1077 |
10468 |
switch(in.getKind()) { |
1078 |
5795 |
case kind::LEQ: |
1079 |
|
case kind::LT: |
1080 |
|
case kind::GEQ: |
1081 |
|
case kind::GT: |
1082 |
5795 |
if (in[0].isVar()) { |
1083 |
2503 |
d_learner.addBound(in); |
1084 |
|
} |
1085 |
5795 |
break; |
1086 |
4673 |
default: |
1087 |
|
// Do nothing |
1088 |
4673 |
break; |
1089 |
|
} |
1090 |
|
|
1091 |
10468 |
return Theory::PP_ASSERT_STATUS_UNSOLVED; |
1092 |
|
} |
1093 |
|
|
1094 |
105238 |
void TheoryArithPrivate::ppStaticLearn(TNode n, NodeBuilder& learned) |
1095 |
|
{ |
1096 |
210476 |
TimerStat::CodeTimer codeTimer(d_statistics.d_staticLearningTimer); |
1097 |
|
|
1098 |
105238 |
d_learner.staticLearning(n, learned); |
1099 |
105238 |
} |
1100 |
|
|
1101 |
|
ArithVar TheoryArithPrivate::findShortestBasicRow(ArithVar variable){ |
1102 |
|
ArithVar bestBasic = ARITHVAR_SENTINEL; |
1103 |
|
uint64_t bestRowLength = std::numeric_limits<uint64_t>::max(); |
1104 |
|
|
1105 |
|
Tableau::ColIterator basicIter = d_tableau.colIterator(variable); |
1106 |
|
for(; !basicIter.atEnd(); ++basicIter){ |
1107 |
|
const Tableau::Entry& entry = *basicIter; |
1108 |
|
Assert(entry.getColVar() == variable); |
1109 |
|
RowIndex ridx = entry.getRowIndex(); |
1110 |
|
ArithVar basic = d_tableau.rowIndexToBasic(ridx); |
1111 |
|
uint32_t rowLength = d_tableau.getRowLength(ridx); |
1112 |
|
if((rowLength < bestRowLength) || |
1113 |
|
(rowLength == bestRowLength && basic < bestBasic)){ |
1114 |
|
bestBasic = basic; |
1115 |
|
bestRowLength = rowLength; |
1116 |
|
} |
1117 |
|
} |
1118 |
|
Assert(bestBasic == ARITHVAR_SENTINEL |
1119 |
|
|| bestRowLength < std::numeric_limits<uint32_t>::max()); |
1120 |
|
return bestBasic; |
1121 |
|
} |
1122 |
|
|
1123 |
66685 |
void TheoryArithPrivate::setupVariable(const Variable& x){ |
1124 |
133370 |
Node n = x.getNode(); |
1125 |
|
|
1126 |
66685 |
Assert(!isSetup(n)); |
1127 |
|
|
1128 |
66685 |
++(d_statistics.d_statUserVariables); |
1129 |
66685 |
requestArithVar(n, false, false); |
1130 |
|
//ArithVar varN = requestArithVar(n,false); |
1131 |
|
//setupInitialValue(varN); |
1132 |
|
|
1133 |
66685 |
markSetup(n); |
1134 |
66685 |
} |
1135 |
|
|
1136 |
68153 |
void TheoryArithPrivate::setupVariableList(const VarList& vl){ |
1137 |
68153 |
Assert(!vl.empty()); |
1138 |
|
|
1139 |
136306 |
TNode vlNode = vl.getNode(); |
1140 |
68153 |
Assert(!isSetup(vlNode)); |
1141 |
68153 |
Assert(!d_partialModel.hasArithVar(vlNode)); |
1142 |
|
|
1143 |
142503 |
for(VarList::iterator i = vl.begin(), end = vl.end(); i != end; ++i){ |
1144 |
148700 |
Variable var = *i; |
1145 |
|
|
1146 |
74350 |
if(!isSetup(var.getNode())){ |
1147 |
66685 |
setupVariable(var); |
1148 |
|
} |
1149 |
|
} |
1150 |
|
|
1151 |
68153 |
if(!vl.singleton()){ |
1152 |
|
// vl is the product of at least 2 variables |
1153 |
|
// vl : (* v1 v2 ...) |
1154 |
2441 |
if(getLogicInfo().isLinear()){ |
1155 |
1 |
throw LogicException("A non-linear fact was asserted to arithmetic in a linear logic."); |
1156 |
|
} |
1157 |
2440 |
d_foundNl = true; |
1158 |
|
|
1159 |
2440 |
++(d_statistics.d_statUserVariables); |
1160 |
2440 |
requestArithVar(vlNode, false, false); |
1161 |
|
//ArithVar av = requestArithVar(vlNode, false); |
1162 |
|
//setupInitialValue(av); |
1163 |
|
|
1164 |
2440 |
markSetup(vlNode); |
1165 |
|
} |
1166 |
131424 |
else if (vlNode.getKind() == kind::EXPONENTIAL |
1167 |
65664 |
|| vlNode.getKind() == kind::SINE || vlNode.getKind() == kind::COSINE |
1168 |
130927 |
|| vlNode.getKind() == kind::TANGENT) |
1169 |
|
{ |
1170 |
497 |
d_foundNl = true; |
1171 |
|
} |
1172 |
|
|
1173 |
|
/* Note: |
1174 |
|
* Only call markSetup if the VarList is not a singleton. |
1175 |
|
* See the comment in setupPolynomail for more. |
1176 |
|
*/ |
1177 |
68152 |
} |
1178 |
|
|
1179 |
|
void TheoryArithPrivate::cautiousSetupPolynomial(const Polynomial& p){ |
1180 |
|
if(p.containsConstant()){ |
1181 |
|
if(!p.isConstant()){ |
1182 |
|
Polynomial noConstant = p.getTail(); |
1183 |
|
if(!isSetup(noConstant.getNode())){ |
1184 |
|
setupPolynomial(noConstant); |
1185 |
|
} |
1186 |
|
} |
1187 |
|
}else if(!isSetup(p.getNode())){ |
1188 |
|
setupPolynomial(p); |
1189 |
|
} |
1190 |
|
} |
1191 |
|
|
1192 |
|
|
1193 |
120525 |
void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) { |
1194 |
120525 |
Assert(!poly.containsConstant()); |
1195 |
241050 |
TNode polyNode = poly.getNode(); |
1196 |
120525 |
Assert(!isSetup(polyNode)); |
1197 |
120525 |
Assert(!d_partialModel.hasArithVar(polyNode)); |
1198 |
|
|
1199 |
362290 |
for(Polynomial::iterator i = poly.begin(), end = poly.end(); i != end; ++i){ |
1200 |
483530 |
Monomial mono = *i; |
1201 |
241765 |
const VarList& vl = mono.getVarList(); |
1202 |
241765 |
if(!isSetup(vl.getNode())){ |
1203 |
62540 |
setupVariableList(vl); |
1204 |
|
} |
1205 |
|
} |
1206 |
|
|
1207 |
120524 |
if(polyNode.getKind() == PLUS){ |
1208 |
92722 |
d_tableauSizeHasBeenModified = true; |
1209 |
|
|
1210 |
185444 |
vector<ArithVar> variables; |
1211 |
185444 |
vector<Rational> coefficients; |
1212 |
92722 |
asVectors(poly, coefficients, variables); |
1213 |
|
|
1214 |
92722 |
ArithVar varSlack = requestArithVar(polyNode, true, false); |
1215 |
92722 |
d_tableau.addRow(varSlack, coefficients, variables); |
1216 |
92722 |
setupBasicValue(varSlack); |
1217 |
92722 |
d_linEq.trackRowIndex(d_tableau.basicToRowIndex(varSlack)); |
1218 |
|
|
1219 |
|
//Add differences to the difference manager |
1220 |
185444 |
Polynomial::iterator i = poly.begin(), end = poly.end(); |
1221 |
92722 |
if(i != end){ |
1222 |
185444 |
Monomial first = *i; |
1223 |
92722 |
++i; |
1224 |
92722 |
if(i != end){ |
1225 |
185444 |
Monomial second = *i; |
1226 |
92722 |
++i; |
1227 |
92722 |
if(i == end){ |
1228 |
74436 |
if(first.getConstant().isOne() && second.getConstant().getValue() == -1){ |
1229 |
128556 |
VarList vl0 = first.getVarList(); |
1230 |
128556 |
VarList vl1 = second.getVarList(); |
1231 |
64278 |
if(vl0.singleton() && vl1.singleton()){ |
1232 |
62090 |
d_congruenceManager.addWatchedPair(varSlack, vl0.getNode(), vl1.getNode()); |
1233 |
|
} |
1234 |
|
} |
1235 |
|
} |
1236 |
|
} |
1237 |
|
} |
1238 |
|
|
1239 |
92722 |
++(d_statistics.d_statAuxiliaryVariables); |
1240 |
92722 |
markSetup(polyNode); |
1241 |
|
} |
1242 |
|
|
1243 |
|
/* Note: |
1244 |
|
* It is worth documenting that polyNode should only be marked as |
1245 |
|
* being setup by this function if it has kind PLUS. |
1246 |
|
* Other kinds will be marked as being setup by lower levels of setup |
1247 |
|
* specifically setupVariableList. |
1248 |
|
*/ |
1249 |
120524 |
} |
1250 |
|
|
1251 |
266196 |
void TheoryArithPrivate::setupAtom(TNode atom) { |
1252 |
266196 |
Assert(isRelationOperator(atom.getKind())) << atom; |
1253 |
266196 |
Assert(Comparison::isNormalAtom(atom)); |
1254 |
266196 |
Assert(!isSetup(atom)); |
1255 |
266196 |
Assert(!d_constraintDatabase.hasLiteral(atom)); |
1256 |
|
|
1257 |
532392 |
Comparison cmp = Comparison::parseNormalForm(atom); |
1258 |
532392 |
Polynomial nvp = cmp.normalizedVariablePart(); |
1259 |
266196 |
Assert(!nvp.isZero()); |
1260 |
|
|
1261 |
266196 |
if(!isSetup(nvp.getNode())){ |
1262 |
120525 |
setupPolynomial(nvp); |
1263 |
|
} |
1264 |
|
|
1265 |
266195 |
d_constraintDatabase.addLiteral(atom); |
1266 |
|
|
1267 |
266195 |
markSetup(atom); |
1268 |
266195 |
} |
1269 |
|
|
1270 |
790255 |
void TheoryArithPrivate::preRegisterTerm(TNode n) { |
1271 |
790255 |
Debug("arith::preregister") <<"begin arith::preRegisterTerm("<< n <<")"<< endl; |
1272 |
|
|
1273 |
790255 |
d_preregisteredNodes.insert(n); |
1274 |
|
|
1275 |
|
try { |
1276 |
790255 |
if(isRelationOperator(n.getKind())){ |
1277 |
407533 |
if(!isSetup(n)){ |
1278 |
210036 |
setupAtom(n); |
1279 |
|
} |
1280 |
407532 |
ConstraintP c = d_constraintDatabase.lookup(n); |
1281 |
407532 |
Assert(c != NullConstraint); |
1282 |
|
|
1283 |
407532 |
Debug("arith::preregister") << "setup constraint" << c << endl; |
1284 |
407532 |
Assert(!c->canBePropagated()); |
1285 |
407532 |
c->setPreregistered(); |
1286 |
|
} |
1287 |
2 |
} catch(LogicException& le) { |
1288 |
2 |
std::stringstream ss; |
1289 |
1 |
ss << le.getMessage() << endl << "The fact in question: " << n << endl; |
1290 |
1 |
throw LogicException(ss.str()); |
1291 |
|
} |
1292 |
|
|
1293 |
790254 |
Debug("arith::preregister") << "end arith::preRegisterTerm("<< n <<")" << endl; |
1294 |
790254 |
} |
1295 |
|
|
1296 |
|
void TheoryArithPrivate::releaseArithVar(ArithVar v){ |
1297 |
|
//Assert(d_partialModel.hasNode(v)); |
1298 |
|
|
1299 |
|
d_constraintDatabase.removeVariable(v); |
1300 |
|
d_partialModel.releaseArithVar(v); |
1301 |
|
} |
1302 |
|
|
1303 |
161847 |
ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool aux, bool internal){ |
1304 |
|
//TODO : The VarList trick is good enough? |
1305 |
161847 |
Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS || internal); |
1306 |
161847 |
if(getLogicInfo().isLinear() && Variable::isDivMember(x)){ |
1307 |
|
stringstream ss; |
1308 |
|
ss << "A non-linear fact (involving div/mod/divisibility) was asserted to " |
1309 |
|
"arithmetic in a linear logic: " |
1310 |
|
<< x << std::endl; |
1311 |
|
throw LogicException(ss.str()); |
1312 |
|
} |
1313 |
161847 |
Assert(!d_partialModel.hasArithVar(x)); |
1314 |
161847 |
Assert(x.getType().isReal()); // real or integer |
1315 |
|
|
1316 |
161847 |
ArithVar max = d_partialModel.getNumberOfVariables(); |
1317 |
161847 |
ArithVar varX = d_partialModel.allocate(x, aux); |
1318 |
|
|
1319 |
161847 |
bool reclaim = max >= d_partialModel.getNumberOfVariables();; |
1320 |
|
|
1321 |
161847 |
if(!reclaim){ |
1322 |
161847 |
d_dualSimplex.increaseMax(); |
1323 |
|
|
1324 |
161847 |
d_tableau.increaseSize(); |
1325 |
161847 |
d_tableauSizeHasBeenModified = true; |
1326 |
|
} |
1327 |
161847 |
d_constraintDatabase.addVariable(varX); |
1328 |
|
|
1329 |
323694 |
Debug("arith::arithvar") << "@" << getSatContext()->getLevel() |
1330 |
161847 |
<< " " << x << " |-> " << varX |
1331 |
161847 |
<< "(relaiming " << reclaim << ")" << endl; |
1332 |
|
|
1333 |
161847 |
Assert(!d_partialModel.hasUpperBound(varX)); |
1334 |
161847 |
Assert(!d_partialModel.hasLowerBound(varX)); |
1335 |
|
|
1336 |
161847 |
return varX; |
1337 |
|
} |
1338 |
|
|
1339 |
92722 |
void TheoryArithPrivate::asVectors(const Polynomial& p, std::vector<Rational>& coeffs, std::vector<ArithVar>& variables) { |
1340 |
306684 |
for(Polynomial::iterator i = p.begin(), end = p.end(); i != end; ++i){ |
1341 |
427924 |
const Monomial& mono = *i; |
1342 |
213962 |
const Constant& constant = mono.getConstant(); |
1343 |
213962 |
const VarList& variable = mono.getVarList(); |
1344 |
|
|
1345 |
427924 |
Node n = variable.getNode(); |
1346 |
|
|
1347 |
213962 |
Debug("arith::asVectors") << "should be var: " << n << endl; |
1348 |
|
|
1349 |
|
// TODO: This VarList::isMember(n) can be stronger |
1350 |
213962 |
Assert(isLeaf(n) || VarList::isMember(n)); |
1351 |
213962 |
Assert(theoryOf(n) != THEORY_ARITH || d_partialModel.hasArithVar(n)); |
1352 |
|
|
1353 |
213962 |
Assert(d_partialModel.hasArithVar(n)); |
1354 |
213962 |
ArithVar av = d_partialModel.asArithVar(n); |
1355 |
|
|
1356 |
213962 |
coeffs.push_back(constant.getValue()); |
1357 |
213962 |
variables.push_back(av); |
1358 |
|
} |
1359 |
92722 |
} |
1360 |
|
|
1361 |
|
/* Requirements: |
1362 |
|
* For basic variables the row must have been added to the tableau. |
1363 |
|
*/ |
1364 |
92722 |
void TheoryArithPrivate::setupBasicValue(ArithVar x){ |
1365 |
92722 |
Assert(d_tableau.isBasic(x)); |
1366 |
|
//If the variable is basic, assertions may have already happened and updates |
1367 |
|
//may have occured before setting this variable up. |
1368 |
|
|
1369 |
|
//This can go away if the tableau creation is done at preregister |
1370 |
|
//time instead of register |
1371 |
185444 |
DeltaRational safeAssignment = d_linEq.computeRowValue(x, true); |
1372 |
185444 |
DeltaRational assignment = d_linEq.computeRowValue(x, false); |
1373 |
92722 |
d_partialModel.setAssignment(x,safeAssignment,assignment); |
1374 |
|
|
1375 |
92722 |
Debug("arith") << "setupVariable("<<x<<")"<<std::endl; |
1376 |
92722 |
} |
1377 |
|
|
1378 |
|
ArithVar TheoryArithPrivate::determineArithVar(const Polynomial& p) const{ |
1379 |
|
Assert(!p.containsConstant()); |
1380 |
|
Assert(p.getHead().constantIsPositive()); |
1381 |
|
TNode n = p.getNode(); |
1382 |
|
Debug("determineArithVar") << "determineArithVar(" << n << ")" << endl; |
1383 |
|
return d_partialModel.asArithVar(n); |
1384 |
|
} |
1385 |
|
|
1386 |
|
ArithVar TheoryArithPrivate::determineArithVar(TNode assertion) const{ |
1387 |
|
Debug("determineArithVar") << "determineArithVar " << assertion << endl; |
1388 |
|
Comparison cmp = Comparison::parseNormalForm(assertion); |
1389 |
|
Polynomial variablePart = cmp.normalizedVariablePart(); |
1390 |
|
return determineArithVar(variablePart); |
1391 |
|
} |
1392 |
|
|
1393 |
|
|
1394 |
|
bool TheoryArithPrivate::canSafelyAvoidEqualitySetup(TNode equality){ |
1395 |
|
Assert(equality.getKind() == EQUAL); |
1396 |
|
return d_partialModel.hasArithVar(equality[0]); |
1397 |
|
} |
1398 |
|
|
1399 |
37619 |
Comparison TheoryArithPrivate::mkIntegerEqualityFromAssignment(ArithVar v){ |
1400 |
37619 |
const DeltaRational& beta = d_partialModel.getAssignment(v); |
1401 |
|
|
1402 |
37619 |
Assert(beta.isIntegral()); |
1403 |
75238 |
Polynomial betaAsPolynomial = Polynomial::mkPolynomial( Constant::mkConstant(beta.floor()) ); |
1404 |
|
|
1405 |
75238 |
TNode var = d_partialModel.asNode(v); |
1406 |
75238 |
Polynomial varAsPolynomial = Polynomial::parsePolynomial(var); |
1407 |
75238 |
return Comparison::mkComparison(EQUAL, varAsPolynomial, betaAsPolynomial); |
1408 |
|
} |
1409 |
|
|
1410 |
1883 |
TrustNode TheoryArithPrivate::dioCutting() |
1411 |
|
{ |
1412 |
3766 |
context::Context::ScopedPush speculativePush(getSatContext()); |
1413 |
|
//DO NOT TOUCH THE OUTPUTSTREAM |
1414 |
|
|
1415 |
81985 |
for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ |
1416 |
80102 |
ArithVar v = *vi; |
1417 |
80102 |
if(isInteger(v)){ |
1418 |
128962 |
if(d_partialModel.cmpAssignmentUpperBound(v) == 0 || |
1419 |
50374 |
d_partialModel.cmpAssignmentLowerBound(v) == 0){ |
1420 |
36113 |
if(!d_partialModel.boundsAreEqual(v)){ |
1421 |
|
// If the bounds are equal this is already in the dioSolver |
1422 |
|
//Add v = dr as a speculation. |
1423 |
31936 |
Comparison eq = mkIntegerEqualityFromAssignment(v); |
1424 |
15968 |
Debug("dio::push") << "dio::push " << v << " " << eq.getNode() << endl; |
1425 |
15968 |
Assert(!eq.isBoolean()); |
1426 |
15968 |
d_diosolver.pushInputConstraint(eq, eq.getNode()); |
1427 |
|
// It does not matter what the explanation of eq is. |
1428 |
|
// It cannot be used in a conflict |
1429 |
|
} |
1430 |
|
} |
1431 |
|
} |
1432 |
|
} |
1433 |
|
|
1434 |
3766 |
SumPair plane = d_diosolver.processEquationsForCut(); |
1435 |
1883 |
if(plane.isZero()){ |
1436 |
445 |
return TrustNode::null(); |
1437 |
|
}else{ |
1438 |
2876 |
Polynomial p = plane.getPolynomial(); |
1439 |
2876 |
Polynomial c = Polynomial::mkPolynomial(plane.getConstant() * Constant::mkConstant(-1)); |
1440 |
2876 |
Integer gcd = p.gcd(); |
1441 |
1438 |
Assert(p.isIntegral()); |
1442 |
1438 |
Assert(c.isIntegral()); |
1443 |
1438 |
Assert(gcd > 1); |
1444 |
1438 |
Assert(!gcd.divides(c.asConstant().getNumerator())); |
1445 |
2876 |
Comparison leq = Comparison::mkComparison(LEQ, p, c); |
1446 |
2876 |
Comparison geq = Comparison::mkComparison(GEQ, p, c); |
1447 |
2876 |
Node lemma = NodeManager::currentNM()->mkNode(OR, leq.getNode(), geq.getNode()); |
1448 |
2876 |
Node rewrittenLemma = Rewriter::rewrite(lemma); |
1449 |
1438 |
Debug("arith::dio::ex") << "dioCutting found the plane: " << plane.getNode() << endl; |
1450 |
1438 |
Debug("arith::dio::ex") << "resulting in the cut: " << lemma << endl; |
1451 |
1438 |
Debug("arith::dio::ex") << "rewritten " << rewrittenLemma << endl; |
1452 |
1438 |
Debug("arith::dio") << "dioCutting found the plane: " << plane.getNode() << endl; |
1453 |
1438 |
Debug("arith::dio") << "resulting in the cut: " << lemma << endl; |
1454 |
1438 |
Debug("arith::dio") << "rewritten " << rewrittenLemma << endl; |
1455 |
1438 |
if (proofsEnabled()) |
1456 |
|
{ |
1457 |
205 |
NodeManager* nm = NodeManager::currentNM(); |
1458 |
410 |
Node gt = nm->mkNode(kind::GT, p.getNode(), c.getNode()); |
1459 |
410 |
Node lt = nm->mkNode(kind::LT, p.getNode(), c.getNode()); |
1460 |
|
|
1461 |
410 |
Pf pfNotLeq = d_pnm->mkAssume(leq.getNode().negate()); |
1462 |
|
Pf pfGt = |
1463 |
410 |
d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, {pfNotLeq}, {gt}); |
1464 |
410 |
Pf pfNotGeq = d_pnm->mkAssume(geq.getNode().negate()); |
1465 |
|
Pf pfLt = |
1466 |
410 |
d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, {pfNotGeq}, {lt}); |
1467 |
|
Pf pfSum = |
1468 |
205 |
d_pnm->mkNode(PfRule::MACRO_ARITH_SCALE_SUM_UB, |
1469 |
|
{pfGt, pfLt}, |
1470 |
410 |
{nm->mkConst<Rational>(-1), nm->mkConst<Rational>(1)}); |
1471 |
205 |
Pf pfBot = d_pnm->mkNode( |
1472 |
410 |
PfRule::MACRO_SR_PRED_TRANSFORM, {pfSum}, {nm->mkConst<bool>(false)}); |
1473 |
205 |
std::vector<Node> assumptions = {leq.getNode().negate(), |
1474 |
410 |
geq.getNode().negate()}; |
1475 |
410 |
Pf pfNotAndNot = d_pnm->mkScope(pfBot, assumptions); |
1476 |
410 |
Pf pfOr = d_pnm->mkNode(PfRule::NOT_AND, {pfNotAndNot}, {}); |
1477 |
205 |
Pf pfRewritten = d_pnm->mkNode( |
1478 |
410 |
PfRule::MACRO_SR_PRED_TRANSFORM, {pfOr}, {rewrittenLemma}); |
1479 |
205 |
return d_pfGen->mkTrustNode(rewrittenLemma, pfRewritten); |
1480 |
|
} |
1481 |
|
else |
1482 |
|
{ |
1483 |
1233 |
return TrustNode::mkTrustLemma(rewrittenLemma, nullptr); |
1484 |
|
} |
1485 |
|
} |
1486 |
|
} |
1487 |
|
|
1488 |
24362 |
Node TheoryArithPrivate::callDioSolver(){ |
1489 |
46013 |
while(!d_constantIntegerVariables.empty()){ |
1490 |
21651 |
ArithVar v = d_constantIntegerVariables.front(); |
1491 |
21651 |
d_constantIntegerVariables.pop(); |
1492 |
|
|
1493 |
21651 |
Debug("arith::dio") << "callDioSolver " << v << endl; |
1494 |
|
|
1495 |
21651 |
Assert(isInteger(v)); |
1496 |
21651 |
Assert(d_partialModel.boundsAreEqual(v)); |
1497 |
|
|
1498 |
21651 |
ConstraintP lb = d_partialModel.getLowerBoundConstraint(v); |
1499 |
21651 |
ConstraintP ub = d_partialModel.getUpperBoundConstraint(v); |
1500 |
|
|
1501 |
43302 |
Node orig = Node::null(); |
1502 |
21651 |
if(lb->isEquality()){ |
1503 |
20091 |
orig = Constraint::externalExplainByAssertions({lb}); |
1504 |
1560 |
}else if(ub->isEquality()){ |
1505 |
|
orig = Constraint::externalExplainByAssertions({ub}); |
1506 |
|
}else { |
1507 |
1560 |
orig = Constraint::externalExplainByAssertions(ub, lb); |
1508 |
|
} |
1509 |
|
|
1510 |
21651 |
Assert(d_partialModel.assignmentIsConsistent(v)); |
1511 |
|
|
1512 |
43302 |
Comparison eq = mkIntegerEqualityFromAssignment(v); |
1513 |
|
|
1514 |
21651 |
if(eq.isBoolean()){ |
1515 |
|
//This can only be a conflict |
1516 |
|
Assert(!eq.getNode().getConst<bool>()); |
1517 |
|
|
1518 |
|
//This should be handled by the normal form earlier in the case of equality |
1519 |
|
Assert(orig.getKind() != EQUAL); |
1520 |
|
return orig; |
1521 |
|
}else{ |
1522 |
21651 |
Debug("dio::push") << "dio::push " << v << " " << eq.getNode() << " with reason " << orig << endl; |
1523 |
21651 |
d_diosolver.pushInputConstraint(eq, orig); |
1524 |
|
} |
1525 |
|
} |
1526 |
|
|
1527 |
2711 |
return d_diosolver.processEquationsForConflict(); |
1528 |
|
} |
1529 |
|
|
1530 |
5992642 |
ConstraintP TheoryArithPrivate::constraintFromFactQueue(TNode assertion) |
1531 |
|
{ |
1532 |
5992642 |
Kind simpleKind = Comparison::comparisonKind(assertion); |
1533 |
5992642 |
ConstraintP constraint = d_constraintDatabase.lookup(assertion); |
1534 |
5992642 |
if(constraint == NullConstraint){ |
1535 |
794246 |
Assert(simpleKind == EQUAL || simpleKind == DISTINCT); |
1536 |
794246 |
bool isDistinct = simpleKind == DISTINCT; |
1537 |
1578267 |
Node eq = (simpleKind == DISTINCT) ? assertion[0] : assertion; |
1538 |
794246 |
Assert(!isSetup(eq)); |
1539 |
1578267 |
Node reEq = Rewriter::rewrite(eq); |
1540 |
794246 |
Debug("arith::distinct::const") << "Assertion: " << assertion << std::endl; |
1541 |
794246 |
Debug("arith::distinct::const") << "Eq : " << eq << std::endl; |
1542 |
794246 |
Debug("arith::distinct::const") << "reEq : " << reEq << std::endl; |
1543 |
794246 |
if(reEq.getKind() == CONST_BOOLEAN){ |
1544 |
10225 |
if(reEq.getConst<bool>() == isDistinct){ |
1545 |
|
// if is (not true), or false |
1546 |
|
Assert((reEq.getConst<bool>() && isDistinct) |
1547 |
|
|| (!reEq.getConst<bool>() && !isDistinct)); |
1548 |
|
if (proofsEnabled()) |
1549 |
|
{ |
1550 |
|
Pf assume = d_pnm->mkAssume(assertion); |
1551 |
|
std::vector<Node> assumptions = {assertion}; |
1552 |
|
Pf pf = d_pnm->mkScope(d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, |
1553 |
|
{d_pnm->mkAssume(assertion)}, |
1554 |
|
{}), |
1555 |
|
assumptions); |
1556 |
|
raiseBlackBoxConflict(assertion, pf); |
1557 |
|
} |
1558 |
|
else |
1559 |
|
{ |
1560 |
|
raiseBlackBoxConflict(assertion); |
1561 |
|
} |
1562 |
|
} |
1563 |
10225 |
return NullConstraint; |
1564 |
|
} |
1565 |
784021 |
Assert(reEq.getKind() != CONST_BOOLEAN); |
1566 |
784021 |
if(!isSetup(reEq)){ |
1567 |
36619 |
setupAtom(reEq); |
1568 |
|
} |
1569 |
1568042 |
Node reAssertion = isDistinct ? reEq.notNode() : reEq; |
1570 |
784021 |
constraint = d_constraintDatabase.lookup(reAssertion); |
1571 |
|
|
1572 |
784021 |
if(assertion != reAssertion){ |
1573 |
765463 |
Debug("arith::nf") << "getting non-nf assertion " << assertion << " |-> " << reAssertion << endl; |
1574 |
765463 |
Assert(constraint != NullConstraint); |
1575 |
765463 |
d_assertionsThatDoNotMatchTheirLiterals.insert(assertion, constraint); |
1576 |
|
} |
1577 |
|
} |
1578 |
|
|
1579 |
5982417 |
Assert(constraint != NullConstraint); |
1580 |
|
|
1581 |
5982417 |
if(constraint->assertedToTheTheory()){ |
1582 |
|
//Do nothing |
1583 |
276654 |
return NullConstraint; |
1584 |
|
} |
1585 |
5705763 |
Assert(!constraint->assertedToTheTheory()); |
1586 |
5705763 |
bool inConflict = constraint->negationHasProof(); |
1587 |
5705763 |
constraint->setAssertedToTheTheory(assertion, inConflict); |
1588 |
|
|
1589 |
5705763 |
if(!constraint->hasProof()){ |
1590 |
4770967 |
Debug("arith::constraint") << "marking as constraint as self explaining " << endl; |
1591 |
4770967 |
constraint->setAssumption(inConflict); |
1592 |
|
} else { |
1593 |
1869592 |
Debug("arith::constraint") |
1594 |
934796 |
<< "already has proof: " |
1595 |
934796 |
<< Constraint::externalExplainByAssertions({constraint}); |
1596 |
|
} |
1597 |
|
|
1598 |
5705763 |
if(Debug.isOn("arith::negatedassumption") && inConflict){ |
1599 |
|
ConstraintP negation = constraint->getNegation(); |
1600 |
|
if(Debug.isOn("arith::negatedassumption") && negation->isAssumption()){ |
1601 |
|
debugPrintFacts(); |
1602 |
|
} |
1603 |
|
Debug("arith::eq") << "negation has proof" << endl; |
1604 |
|
Debug("arith::eq") << constraint << endl; |
1605 |
|
Debug("arith::eq") << negation << endl; |
1606 |
|
} |
1607 |
|
|
1608 |
5705763 |
if(inConflict){ |
1609 |
3492 |
ConstraintP negation = constraint->getNegation(); |
1610 |
3492 |
if(Debug.isOn("arith::negatedassumption") && negation->isAssumption()){ |
1611 |
|
debugPrintFacts(); |
1612 |
|
} |
1613 |
3492 |
Debug("arith::eq") << "negation has proof" << endl; |
1614 |
3492 |
Debug("arith::eq") << constraint << endl; |
1615 |
3492 |
Debug("arith::eq") << negation << endl; |
1616 |
3492 |
raiseConflict(negation, InferenceId::ARITH_CONF_FACT_QUEUE); |
1617 |
3492 |
return NullConstraint; |
1618 |
|
}else{ |
1619 |
5702271 |
return constraint; |
1620 |
|
} |
1621 |
|
} |
1622 |
|
|
1623 |
5823116 |
bool TheoryArithPrivate::assertionCases(ConstraintP constraint){ |
1624 |
5823116 |
Assert(constraint->hasProof()); |
1625 |
5823116 |
Assert(!constraint->negationHasProof()); |
1626 |
|
|
1627 |
5823116 |
ArithVar x_i = constraint->getVariable(); |
1628 |
|
|
1629 |
5823116 |
switch(constraint->getType()){ |
1630 |
1971048 |
case UpperBound: |
1631 |
1971048 |
if(isInteger(x_i) && constraint->isStrictUpperBound()){ |
1632 |
1248073 |
ConstraintP floorConstraint = constraint->getFloor(); |
1633 |
1248073 |
if(!floorConstraint->isTrue()){ |
1634 |
1064365 |
bool inConflict = floorConstraint->negationHasProof(); |
1635 |
1064365 |
if (Debug.isOn("arith::intbound")) { |
1636 |
|
Debug("arith::intbound") << "literal, before: " << constraint->getLiteral() << std::endl; |
1637 |
|
Debug("arith::intbound") << "constraint, after: " << floorConstraint << std::endl; |
1638 |
|
} |
1639 |
1064365 |
floorConstraint->impliedByIntTighten(constraint, inConflict); |
1640 |
1064365 |
floorConstraint->tryToPropagate(); |
1641 |
1064365 |
if(inConflict){ |
1642 |
2767 |
raiseConflict(floorConstraint, InferenceId::ARITH_TIGHTEN_FLOOR); |
1643 |
2767 |
return true; |
1644 |
|
} |
1645 |
|
} |
1646 |
1245306 |
return AssertUpper(floorConstraint); |
1647 |
|
}else{ |
1648 |
722975 |
return AssertUpper(constraint); |
1649 |
|
} |
1650 |
2064558 |
case LowerBound: |
1651 |
2064558 |
if(isInteger(x_i) && constraint->isStrictLowerBound()){ |
1652 |
69672 |
ConstraintP ceilingConstraint = constraint->getCeiling(); |
1653 |
69672 |
if(!ceilingConstraint->isTrue()){ |
1654 |
37291 |
bool inConflict = ceilingConstraint->negationHasProof(); |
1655 |
37291 |
if (Debug.isOn("arith::intbound")) { |
1656 |
|
Debug("arith::intbound") << "literal, before: " << constraint->getLiteral() << std::endl; |
1657 |
|
Debug("arith::intbound") << "constraint, after: " << ceilingConstraint << std::endl; |
1658 |
|
} |
1659 |
37291 |
ceilingConstraint->impliedByIntTighten(constraint, inConflict); |
1660 |
37291 |
ceilingConstraint->tryToPropagate(); |
1661 |
37291 |
if(inConflict){ |
1662 |
34 |
raiseConflict(ceilingConstraint, InferenceId::ARITH_TIGHTEN_CEIL); |
1663 |
34 |
return true; |
1664 |
|
} |
1665 |
|
} |
1666 |
69638 |
return AssertLower(ceilingConstraint); |
1667 |
|
}else{ |
1668 |
1994886 |
return AssertLower(constraint); |
1669 |
|
} |
1670 |
1025054 |
case Equality: |
1671 |
1025054 |
return AssertEquality(constraint); |
1672 |
762456 |
case Disequality: |
1673 |
762456 |
return AssertDisequality(constraint); |
1674 |
|
default: |
1675 |
|
Unreachable(); |
1676 |
|
return false; |
1677 |
|
} |
1678 |
|
} |
1679 |
|
/** |
1680 |
|
* Looks for through the variables starting at d_nextIntegerCheckVar |
1681 |
|
* for the first integer variable that is between its upper and lower bounds |
1682 |
|
* that has a non-integer assignment. |
1683 |
|
* |
1684 |
|
* If assumeBounds is true, skip the check that the variable is in bounds. |
1685 |
|
* |
1686 |
|
* If there is no such variable, returns ARITHVAR_SENTINEL; |
1687 |
|
*/ |
1688 |
3456521 |
ArithVar TheoryArithPrivate::nextIntegerViolation(bool assumeBounds) const |
1689 |
|
{ |
1690 |
3456521 |
ArithVar numVars = d_partialModel.getNumberOfVariables(); |
1691 |
3456521 |
ArithVar v = d_nextIntegerCheckVar; |
1692 |
3456521 |
if (numVars > 0) |
1693 |
|
{ |
1694 |
3415658 |
const ArithVar rrEnd = d_nextIntegerCheckVar; |
1695 |
615546251 |
do |
1696 |
|
{ |
1697 |
618961909 |
if (isIntegerInput(v)) |
1698 |
|
{ |
1699 |
170181321 |
if (!d_partialModel.integralAssignment(v)) |
1700 |
|
{ |
1701 |
111782 |
if (assumeBounds || d_partialModel.assignmentIsConsistent(v)) |
1702 |
|
{ |
1703 |
111782 |
return v; |
1704 |
|
} |
1705 |
|
} |
1706 |
|
} |
1707 |
618850127 |
v = (1 + v == numVars) ? 0 : (1 + v); |
1708 |
618850127 |
} while (v != rrEnd); |
1709 |
|
} |
1710 |
3344739 |
return ARITHVAR_SENTINEL; |
1711 |
|
} |
1712 |
|
|
1713 |
|
/** |
1714 |
|
* Checks the set of integer variables I to see if each variable |
1715 |
|
* in I has an integer assignment. |
1716 |
|
*/ |
1717 |
3456521 |
bool TheoryArithPrivate::hasIntegerModel() |
1718 |
|
{ |
1719 |
3456521 |
ArithVar next = nextIntegerViolation(true); |
1720 |
3456521 |
if (next != ARITHVAR_SENTINEL) |
1721 |
|
{ |
1722 |
111782 |
d_nextIntegerCheckVar = next; |
1723 |
111782 |
if (Debug.isOn("arith::hasIntegerModel")) |
1724 |
|
{ |
1725 |
|
Debug("arith::hasIntegerModel") << "has int model? " << next << endl; |
1726 |
|
d_partialModel.printModel(next, Debug("arith::hasIntegerModel")); |
1727 |
|
} |
1728 |
111782 |
return false; |
1729 |
|
} |
1730 |
|
else |
1731 |
|
{ |
1732 |
3344739 |
return true; |
1733 |
|
} |
1734 |
|
} |
1735 |
|
|
1736 |
|
Node flattenAndSort(Node n){ |
1737 |
|
Kind k = n.getKind(); |
1738 |
|
switch(k){ |
1739 |
|
case kind::OR: |
1740 |
|
case kind::AND: |
1741 |
|
case kind::PLUS: |
1742 |
|
case kind::MULT: |
1743 |
|
break; |
1744 |
|
default: |
1745 |
|
return n; |
1746 |
|
} |
1747 |
|
|
1748 |
|
std::vector<Node> out; |
1749 |
|
std::vector<Node> process; |
1750 |
|
process.push_back(n); |
1751 |
|
while(!process.empty()){ |
1752 |
|
Node b = process.back(); |
1753 |
|
process.pop_back(); |
1754 |
|
if(b.getKind() == k){ |
1755 |
|
for(Node::iterator i=b.begin(), end=b.end(); i!=end; ++i){ |
1756 |
|
process.push_back(*i); |
1757 |
|
} |
1758 |
|
} else { |
1759 |
|
out.push_back(b); |
1760 |
|
} |
1761 |
|
} |
1762 |
|
Assert(out.size() >= 2); |
1763 |
|
std::sort(out.begin(), out.end()); |
1764 |
|
return NodeManager::currentNM()->mkNode(k, out); |
1765 |
|
} |
1766 |
|
|
1767 |
|
|
1768 |
|
|
1769 |
|
/** Outputs conflicts to the output channel. */ |
1770 |
54533 |
void TheoryArithPrivate::outputConflicts(){ |
1771 |
54533 |
Debug("arith::conflict") << "outputting conflicts" << std::endl; |
1772 |
54533 |
Assert(anyConflict()); |
1773 |
|
static unsigned int conflicts = 0; |
1774 |
|
|
1775 |
54533 |
if(!conflictQueueEmpty()){ |
1776 |
52149 |
Assert(!d_conflicts.empty()); |
1777 |
125057 |
for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){ |
1778 |
72908 |
const std::pair<ConstraintCP, InferenceId>& conf = d_conflicts[i]; |
1779 |
72908 |
const ConstraintCP& confConstraint = conf.first; |
1780 |
72908 |
bool hasProof = confConstraint->hasProof(); |
1781 |
72908 |
Assert(confConstraint->inConflict()); |
1782 |
72908 |
const ConstraintRule& pf = confConstraint->getConstraintRule(); |
1783 |
72908 |
if (Debug.isOn("arith::conflict")) |
1784 |
|
{ |
1785 |
|
pf.print(std::cout); |
1786 |
|
std::cout << std::endl; |
1787 |
|
} |
1788 |
72908 |
if (Debug.isOn("arith::pf::tree")) |
1789 |
|
{ |
1790 |
|
Debug("arith::pf::tree") << "\n\nTree:\n"; |
1791 |
|
confConstraint->printProofTree(Debug("arith::pf::tree")); |
1792 |
|
confConstraint->getNegation()->printProofTree(Debug("arith::pf::tree")); |
1793 |
|
} |
1794 |
|
|
1795 |
145816 |
TrustNode trustedConflict = confConstraint->externalExplainConflict(); |
1796 |
145816 |
Node conflict = trustedConflict.getNode(); |
1797 |
|
|
1798 |
72908 |
++conflicts; |
1799 |
145816 |
Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict |
1800 |
72908 |
<< " has proof: " << hasProof << endl; |
1801 |
72908 |
if(Debug.isOn("arith::normalize::external")){ |
1802 |
|
conflict = flattenAndSort(conflict); |
1803 |
|
Debug("arith::conflict") << "(normalized to) " << conflict << endl; |
1804 |
|
} |
1805 |
|
|
1806 |
72908 |
if (isProofEnabled()) |
1807 |
|
{ |
1808 |
11632 |
outputTrustedConflict(trustedConflict, conf.second); |
1809 |
|
} |
1810 |
|
else |
1811 |
|
{ |
1812 |
61276 |
outputConflict(conflict, conf.second); |
1813 |
|
} |
1814 |
|
} |
1815 |
|
} |
1816 |
54533 |
if(!d_blackBoxConflict.get().isNull()){ |
1817 |
4778 |
Node bb = d_blackBoxConflict.get(); |
1818 |
2389 |
++conflicts; |
1819 |
4778 |
Debug("arith::conflict") << "black box conflict" << bb |
1820 |
|
//<< "("<<conflicts<<")" |
1821 |
2389 |
<< endl; |
1822 |
2389 |
if(Debug.isOn("arith::normalize::external")){ |
1823 |
|
bb = flattenAndSort(bb); |
1824 |
|
Debug("arith::conflict") << "(normalized to) " << bb << endl; |
1825 |
|
} |
1826 |
2389 |
if (isProofEnabled() && d_blackBoxConflictPf.get()) |
1827 |
|
{ |
1828 |
758 |
auto confPf = d_blackBoxConflictPf.get(); |
1829 |
379 |
outputTrustedConflict(d_pfGen->mkTrustNode(bb, confPf, true), InferenceId::ARITH_BLACK_BOX); |
1830 |
|
} |
1831 |
|
else |
1832 |
|
{ |
1833 |
2010 |
outputConflict(bb, InferenceId::ARITH_BLACK_BOX); |
1834 |
|
} |
1835 |
|
} |
1836 |
54533 |
} |
1837 |
|
|
1838 |
72103 |
bool TheoryArithPrivate::outputTrustedLemma(TrustNode lemma, InferenceId id) |
1839 |
|
{ |
1840 |
72103 |
Debug("arith::channel") << "Arith trusted lemma: " << lemma << std::endl; |
1841 |
72103 |
return d_containing.d_im.trustedLemma(lemma, id); |
1842 |
|
} |
1843 |
|
|
1844 |
83428 |
bool TheoryArithPrivate::outputLemma(TNode lem, InferenceId id) { |
1845 |
83428 |
Debug("arith::channel") << "Arith lemma: " << lem << std::endl; |
1846 |
83428 |
return d_containing.d_im.lemma(lem, id); |
1847 |
|
} |
1848 |
|
|
1849 |
12011 |
void TheoryArithPrivate::outputTrustedConflict(TrustNode conf, InferenceId id) |
1850 |
|
{ |
1851 |
12011 |
Debug("arith::channel") << "Arith trusted conflict: " << conf << std::endl; |
1852 |
12011 |
d_containing.d_im.trustedConflict(conf, id); |
1853 |
12011 |
} |
1854 |
|
|
1855 |
63286 |
void TheoryArithPrivate::outputConflict(TNode lit, InferenceId id) { |
1856 |
63286 |
Debug("arith::channel") << "Arith conflict: " << lit << std::endl; |
1857 |
63286 |
d_containing.d_im.conflict(lit, id); |
1858 |
63286 |
} |
1859 |
|
|
1860 |
1418901 |
void TheoryArithPrivate::outputPropagate(TNode lit) { |
1861 |
1418901 |
Debug("arith::channel") << "Arith propagation: " << lit << std::endl; |
1862 |
|
// call the propagate lit method of the |
1863 |
1418901 |
d_containing.d_im.propagateLit(lit); |
1864 |
1418901 |
} |
1865 |
|
|
1866 |
|
void TheoryArithPrivate::outputRestart() { |
1867 |
|
Debug("arith::channel") << "Arith restart!" << std::endl; |
1868 |
|
(d_containing.d_out)->demandRestart(); |
1869 |
|
} |
1870 |
|
|
1871 |
1695036 |
bool TheoryArithPrivate::attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit){ |
1872 |
1695036 |
int level = getSatContext()->getLevel(); |
1873 |
3390072 |
Debug("approx") |
1874 |
1695036 |
<< "attemptSolveInteger " << d_qflraStatus |
1875 |
1695036 |
<< " " << emmmittedLemmaOrSplit |
1876 |
1695036 |
<< " " << effortLevel |
1877 |
1695036 |
<< " " << d_lastContextIntegerAttempted |
1878 |
1695036 |
<< " " << level |
1879 |
3390072 |
<< " " << hasIntegerModel() |
1880 |
1695036 |
<< endl; |
1881 |
|
|
1882 |
1695036 |
if(d_qflraStatus == Result::UNSAT){ return false; } |
1883 |
1654099 |
if(emmmittedLemmaOrSplit){ return false; } |
1884 |
1654099 |
if(!options::useApprox()){ return false; } |
1885 |
|
if(!ApproximateSimplex::enabled()){ return false; } |
1886 |
|
|
1887 |
|
if(Theory::fullEffort(effortLevel)){ |
1888 |
|
if(hasIntegerModel()){ |
1889 |
|
return false; |
1890 |
|
}else{ |
1891 |
|
return getSolveIntegerResource(); |
1892 |
|
} |
1893 |
|
} |
1894 |
|
|
1895 |
|
if(d_lastContextIntegerAttempted <= 0){ |
1896 |
|
if(hasIntegerModel()){ |
1897 |
|
d_lastContextIntegerAttempted = getSatContext()->getLevel(); |
1898 |
|
return false; |
1899 |
|
}else{ |
1900 |
|
return getSolveIntegerResource(); |
1901 |
|
} |
1902 |
|
} |
1903 |
|
|
1904 |
|
|
1905 |
|
if(!options::trySolveIntStandardEffort()){ return false; } |
1906 |
|
|
1907 |
|
if (d_lastContextIntegerAttempted <= (level >> 2)) |
1908 |
|
{ |
1909 |
|
double d = (double)(d_solveIntMaybeHelp + 1) |
1910 |
|
/ (d_solveIntAttempts + 1 + level * level); |
1911 |
|
if (Random::getRandom().pickWithProb(d)) |
1912 |
|
{ |
1913 |
|
return getSolveIntegerResource(); |
1914 |
|
} |
1915 |
|
} |
1916 |
|
return false; |
1917 |
|
} |
1918 |
|
|
1919 |
|
bool TheoryArithPrivate::replayLog(ApproximateSimplex* approx){ |
1920 |
|
TimerStat::CodeTimer codeTimer(d_statistics.d_replayLogTimer); |
1921 |
|
|
1922 |
|
++d_statistics.d_mipProofsAttempted; |
1923 |
|
|
1924 |
|
Assert(d_replayVariables.empty()); |
1925 |
|
Assert(d_replayConstraints.empty()); |
1926 |
|
|
1927 |
|
size_t enteringPropN = d_currentPropagationList.size(); |
1928 |
|
Assert(conflictQueueEmpty()); |
1929 |
|
TreeLog& tl = getTreeLog(); |
1930 |
|
//tl.applySelected(); /* set row ids */ |
1931 |
|
|
1932 |
|
d_replayedLemmas = false; |
1933 |
|
|
1934 |
|
/* use the try block for the purpose of pushing the sat context */ |
1935 |
|
context::Context::ScopedPush speculativePush(getSatContext()); |
1936 |
|
d_cmEnabled = false; |
1937 |
|
std::vector<ConstraintCPVec> res = |
1938 |
|
replayLogRec(approx, tl.getRootId(), NullConstraint, 1); |
1939 |
|
|
1940 |
|
if(res.empty()){ |
1941 |
|
++d_statistics.d_replayAttemptFailed; |
1942 |
|
}else{ |
1943 |
|
unsigned successes = 0; |
1944 |
|
for(size_t i =0, N = res.size(); i < N; ++i){ |
1945 |
|
ConstraintCPVec& vec = res[i]; |
1946 |
|
Assert(vec.size() >= 2); |
1947 |
|
for(size_t j=0, M = vec.size(); j < M; ++j){ |
1948 |
|
ConstraintCP at_j = vec[j]; |
1949 |
|
Assert(at_j->isTrue()); |
1950 |
|
if(!at_j->negationHasProof()){ |
1951 |
|
successes++; |
1952 |
|
vec[j] = vec.back(); |
1953 |
|
vec.pop_back(); |
1954 |
|
ConstraintP neg_at_j = at_j->getNegation(); |
1955 |
|
|
1956 |
|
Debug("approx::replayLog") << "Setting the proof for the replayLog conflict on:" << endl |
1957 |
|
<< " (" << neg_at_j->isTrue() <<") " << neg_at_j << endl |
1958 |
|
<< " (" << at_j->isTrue() <<") " << at_j << endl; |
1959 |
|
neg_at_j->impliedByIntHole(vec, true); |
1960 |
|
raiseConflict(at_j, InferenceId::UNKNOWN); |
1961 |
|
break; |
1962 |
|
} |
1963 |
|
} |
1964 |
|
} |
1965 |
|
if(successes > 0){ |
1966 |
|
++d_statistics.d_mipProofsSuccessful; |
1967 |
|
} |
1968 |
|
} |
1969 |
|
|
1970 |
|
if(d_currentPropagationList.size() > enteringPropN){ |
1971 |
|
d_currentPropagationList.resize(enteringPropN); |
1972 |
|
} |
1973 |
|
|
1974 |
|
/* It is not clear what the d_qflraStatus is at this point */ |
1975 |
|
d_qflraStatus = Result::SAT_UNKNOWN; |
1976 |
|
|
1977 |
|
Assert(d_replayVariables.empty()); |
1978 |
|
Assert(d_replayConstraints.empty()); |
1979 |
|
|
1980 |
|
return !conflictQueueEmpty(); |
1981 |
|
} |
1982 |
|
|
1983 |
|
std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const DenseMap<Rational>& lhs, Kind k, const Rational& rhs, bool branch) |
1984 |
|
{ |
1985 |
|
ArithVar added = ARITHVAR_SENTINEL; |
1986 |
|
Node sum = toSumNode(d_partialModel, lhs); |
1987 |
|
if(sum.isNull()){ return make_pair(NullConstraint, added); } |
1988 |
|
|
1989 |
|
Debug("approx::constraint") << "replayGetConstraint " << sum |
1990 |
|
<< " " << k |
1991 |
|
<< " " << rhs |
1992 |
|
<< endl; |
1993 |
|
|
1994 |
|
Assert(k == kind::LEQ || k == kind::GEQ); |
1995 |
|
|
1996 |
|
Node comparison = NodeManager::currentNM()->mkNode(k, sum, mkRationalNode(rhs)); |
1997 |
|
Node rewritten = Rewriter::rewrite(comparison); |
1998 |
|
if(!(Comparison::isNormalAtom(rewritten))){ |
1999 |
|
return make_pair(NullConstraint, added); |
2000 |
|
} |
2001 |
|
|
2002 |
|
Comparison cmp = Comparison::parseNormalForm(rewritten); |
2003 |
|
if(cmp.isBoolean()){ return make_pair(NullConstraint, added); } |
2004 |
|
|
2005 |
|
Polynomial nvp = cmp.normalizedVariablePart(); |
2006 |
|
if(nvp.isZero()){ return make_pair(NullConstraint, added); } |
2007 |
|
|
2008 |
|
Node norm = nvp.getNode(); |
2009 |
|
|
2010 |
|
ConstraintType t = Constraint::constraintTypeOfComparison(cmp); |
2011 |
|
DeltaRational dr = cmp.normalizedDeltaRational(); |
2012 |
|
|
2013 |
|
Debug("approx::constraint") << "rewriting " << rewritten << endl |
2014 |
|
<< " |-> " << norm << " " << t << " " << dr << endl; |
2015 |
|
|
2016 |
|
Assert(!branch || d_partialModel.hasArithVar(norm)); |
2017 |
|
ArithVar v = ARITHVAR_SENTINEL; |
2018 |
|
if(d_partialModel.hasArithVar(norm)){ |
2019 |
|
|
2020 |
|
v = d_partialModel.asArithVar(norm); |
2021 |
|
Debug("approx::constraint") << "replayGetConstraint found " |
2022 |
|
<< norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl; |
2023 |
|
Assert(!branch || d_partialModel.isIntegerInput(v)); |
2024 |
|
}else{ |
2025 |
|
v = requestArithVar(norm, true, true); |
2026 |
|
d_replayVariables.push_back(v); |
2027 |
|
|
2028 |
|
added = v; |
2029 |
|
|
2030 |
|
Debug("approx::constraint") << "replayGetConstraint adding " |
2031 |
|
<< norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl; |
2032 |
|
|
2033 |
|
Polynomial poly = Polynomial::parsePolynomial(norm); |
2034 |
|
vector<ArithVar> variables; |
2035 |
|
vector<Rational> coefficients; |
2036 |
|
asVectors(poly, coefficients, variables); |
2037 |
|
d_tableau.addRow(v, coefficients, variables); |
2038 |
|
setupBasicValue(v); |
2039 |
|
d_linEq.trackRowIndex(d_tableau.basicToRowIndex(v)); |
2040 |
|
} |
2041 |
|
Assert(d_partialModel.hasArithVar(norm)); |
2042 |
|
Assert(d_partialModel.asArithVar(norm) == v); |
2043 |
|
Assert(d_constraintDatabase.variableDatabaseIsSetup(v)); |
2044 |
|
|
2045 |
|
ConstraintP imp = d_constraintDatabase.getBestImpliedBound(v, t, dr); |
2046 |
|
if(imp != NullConstraint){ |
2047 |
|
if(imp->getValue() == dr){ |
2048 |
|
Assert(added == ARITHVAR_SENTINEL); |
2049 |
|
return make_pair(imp, added); |
2050 |
|
} |
2051 |
|
} |
2052 |
|
|
2053 |
|
ConstraintP newc = d_constraintDatabase.getConstraint(v, t, dr); |
2054 |
|
d_replayConstraints.push_back(newc); |
2055 |
|
return make_pair(newc, added); |
2056 |
|
} |
2057 |
|
|
2058 |
|
std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint( |
2059 |
|
ApproximateSimplex* approx, const NodeLog& nl) |
2060 |
|
{ |
2061 |
|
Assert(nl.isBranch()); |
2062 |
|
Assert(d_lhsTmp.empty()); |
2063 |
|
|
2064 |
|
ArithVar v = approx->getBranchVar(nl); |
2065 |
|
if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){ |
2066 |
|
if(d_partialModel.hasNode(v)){ |
2067 |
|
d_lhsTmp.set(v, Rational(1)); |
2068 |
|
double dval = nl.branchValue(); |
2069 |
|
Maybe<Rational> maybe_value = ApproximateSimplex::estimateWithCFE(dval); |
2070 |
|
if (!maybe_value) |
2071 |
|
{ |
2072 |
|
return make_pair(NullConstraint, ARITHVAR_SENTINEL); |
2073 |
|
} |
2074 |
|
Rational fl(maybe_value.value().floor()); |
2075 |
|
pair<ConstraintP, ArithVar> p; |
2076 |
|
p = replayGetConstraint(d_lhsTmp, kind::LEQ, fl, true); |
2077 |
|
d_lhsTmp.purge(); |
2078 |
|
return p; |
2079 |
|
} |
2080 |
|
} |
2081 |
|
return make_pair(NullConstraint, ARITHVAR_SENTINEL); |
2082 |
|
} |
2083 |
|
|
2084 |
|
std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const CutInfo& ci) { |
2085 |
|
Assert(ci.reconstructed()); |
2086 |
|
const DenseMap<Rational>& lhs = ci.getReconstruction().lhs; |
2087 |
|
const Rational& rhs = ci.getReconstruction().rhs; |
2088 |
|
Kind k = ci.getKind(); |
2089 |
|
|
2090 |
|
return replayGetConstraint(lhs, k, rhs, ci.getKlass() == BranchCutKlass); |
2091 |
|
} |
2092 |
|
|
2093 |
|
// Node denseVectorToLiteral(const ArithVariables& vars, const DenseVector& dv, Kind k){ |
2094 |
|
// NodeManager* nm = NodeManager::currentNM(); |
2095 |
|
// Node sumLhs = toSumNode(vars, dv.lhs); |
2096 |
|
// Node ineq = nm->mkNode(k, sumLhs, mkRationalNode(dv.rhs) ); |
2097 |
|
// Node lit = Rewriter::rewrite(ineq); |
2098 |
|
// return lit; |
2099 |
|
// } |
2100 |
|
|
2101 |
|
Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum){ |
2102 |
|
Debug("arith::toSumNode") << "toSumNode() begin" << endl; |
2103 |
|
NodeBuilder nb(kind::PLUS); |
2104 |
|
NodeManager* nm = NodeManager::currentNM(); |
2105 |
|
DenseMap<Rational>::const_iterator iter, end; |
2106 |
|
iter = sum.begin(), end = sum.end(); |
2107 |
|
for(; iter != end; ++iter){ |
2108 |
|
ArithVar x = *iter; |
2109 |
|
if(!vars.hasNode(x)){ return Node::null(); } |
2110 |
|
Node xNode = vars.asNode(x); |
2111 |
|
const Rational& q = sum[x]; |
2112 |
|
Node mult = nm->mkNode(kind::MULT, mkRationalNode(q), xNode); |
2113 |
|
Debug("arith::toSumNode") << "toSumNode() " << x << " " << mult << endl; |
2114 |
|
nb << mult; |
2115 |
|
} |
2116 |
|
Debug("arith::toSumNode") << "toSumNode() end" << endl; |
2117 |
|
return safeConstructNary(nb); |
2118 |
|
} |
2119 |
|
|
2120 |
|
ConstraintCP TheoryArithPrivate::vectorToIntHoleConflict(const ConstraintCPVec& conflict){ |
2121 |
|
Assert(conflict.size() >= 2); |
2122 |
|
ConstraintCPVec exp(conflict.begin(), conflict.end()-1); |
2123 |
|
ConstraintCP back = conflict.back(); |
2124 |
|
Assert(back->hasProof()); |
2125 |
|
ConstraintP negBack = back->getNegation(); |
2126 |
|
// This can select negBack multiple times so we need to test if negBack has a proof. |
2127 |
|
if(negBack->hasProof()){ |
2128 |
|
// back is in conflict already |
2129 |
|
} else { |
2130 |
|
negBack->impliedByIntHole(exp, true); |
2131 |
|
} |
2132 |
|
|
2133 |
|
return back; |
2134 |
|
} |
2135 |
|
|
2136 |
|
void TheoryArithPrivate::intHoleConflictToVector(ConstraintCP conflicting, ConstraintCPVec& conflict){ |
2137 |
|
ConstraintCP negConflicting = conflicting->getNegation(); |
2138 |
|
Assert(conflicting->hasProof()); |
2139 |
|
Assert(negConflicting->hasProof()); |
2140 |
|
|
2141 |
|
conflict.push_back(conflicting); |
2142 |
|
conflict.push_back(negConflicting); |
2143 |
|
|
2144 |
|
Constraint::assertionFringe(conflict); |
2145 |
|
} |
2146 |
|
|
2147 |
|
void TheoryArithPrivate::tryBranchCut(ApproximateSimplex* approx, int nid, BranchCutInfo& bci){ |
2148 |
|
Assert(conflictQueueEmpty()); |
2149 |
|
std::vector< ConstraintCPVec > conflicts; |
2150 |
|
|
2151 |
|
approx->tryCut(nid, bci); |
2152 |
|
Debug("approx::branch") << "tryBranchCut" << bci << endl; |
2153 |
|
Assert(bci.reconstructed()); |
2154 |
|
Assert(!bci.proven()); |
2155 |
|
pair<ConstraintP, ArithVar> p = replayGetConstraint(bci); |
2156 |
|
Assert(p.second == ARITHVAR_SENTINEL); |
2157 |
|
ConstraintP bc = p.first; |
2158 |
|
Assert(bc != NullConstraint); |
2159 |
|
if(bc->hasProof()){ |
2160 |
|
return; |
2161 |
|
} |
2162 |
|
|
2163 |
|
ConstraintP bcneg = bc->getNegation(); |
2164 |
|
{ |
2165 |
|
context::Context::ScopedPush speculativePush(getSatContext()); |
2166 |
|
replayAssert(bcneg); |
2167 |
|
if(conflictQueueEmpty()){ |
2168 |
|
TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer); |
2169 |
|
|
2170 |
|
//test for linear feasibility |
2171 |
|
d_partialModel.stopQueueingBoundCounts(); |
2172 |
|
UpdateTrackingCallback utcb(&d_linEq); |
2173 |
|
d_partialModel.processBoundsQueue(utcb); |
2174 |
|
d_linEq.startTrackingBoundCounts(); |
2175 |
|
|
2176 |
|
SimplexDecisionProcedure& simplex = selectSimplex(true); |
2177 |
|
simplex.findModel(false); |
2178 |
|
// Can change d_qflraStatus |
2179 |
|
|
2180 |
|
d_linEq.stopTrackingBoundCounts(); |
2181 |
|
d_partialModel.startQueueingBoundCounts(); |
2182 |
|
} |
2183 |
|
for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){ |
2184 |
|
|
2185 |
|
conflicts.push_back(ConstraintCPVec()); |
2186 |
|
intHoleConflictToVector(d_conflicts[i].first, conflicts.back()); |
2187 |
|
Constraint::assertionFringe(conflicts.back()); |
2188 |
|
|
2189 |
|
// ConstraintCP conflicting = d_conflicts[i]; |
2190 |
|
// ConstraintCP negConflicting = conflicting->getNegation(); |
2191 |
|
// Assert(conflicting->hasProof()); |
2192 |
|
// Assert(negConflicting->hasProof()); |
2193 |
|
|
2194 |
|
// conflicts.push_back(ConstraintCPVec()); |
2195 |
|
// ConstraintCPVec& back = conflicts.back(); |
2196 |
|
// back.push_back(conflicting); |
2197 |
|
// back.push_back(negConflicting); |
2198 |
|
|
2199 |
|
// // remove the floor/ceiling contraint implied by bcneg |
2200 |
|
// Constraint::assertionFringe(back); |
2201 |
|
} |
2202 |
|
|
2203 |
|
if(Debug.isOn("approx::branch")){ |
2204 |
|
if(d_conflicts.empty()){ |
2205 |
|
entireStateIsConsistent("branchfailure"); |
2206 |
|
} |
2207 |
|
} |
2208 |
|
} |
2209 |
|
|
2210 |
|
Debug("approx::branch") << "branch constraint " << bc << endl; |
2211 |
|
for(size_t i = 0, N = conflicts.size(); i < N; ++i){ |
2212 |
|
ConstraintCPVec& conf = conflicts[i]; |
2213 |
|
|
2214 |
|
// make sure to be working on the assertion fringe! |
2215 |
|
if(!contains(conf, bcneg)){ |
2216 |
|
Debug("approx::branch") << "reraise " << conf << endl; |
2217 |
|
ConstraintCP conflicting = vectorToIntHoleConflict(conf); |
2218 |
|
raiseConflict(conflicting, InferenceId::UNKNOWN); |
2219 |
|
}else if(!bci.proven()){ |
2220 |
|
drop(conf, bcneg); |
2221 |
|
bci.setExplanation(conf); |
2222 |
|
Debug("approx::branch") << "dropped " << bci << endl; |
2223 |
|
} |
2224 |
|
} |
2225 |
|
} |
2226 |
|
|
2227 |
|
void TheoryArithPrivate::replayAssert(ConstraintP c) { |
2228 |
|
if(!c->assertedToTheTheory()){ |
2229 |
|
bool inConflict = c->negationHasProof(); |
2230 |
|
if(!c->hasProof()){ |
2231 |
|
c->setInternalAssumption(inConflict); |
2232 |
|
Debug("approx::replayAssert") << "replayAssert " << c << " set internal" << endl; |
2233 |
|
}else{ |
2234 |
|
Debug("approx::replayAssert") << "replayAssert " << c << " has explanation" << endl; |
2235 |
|
} |
2236 |
|
Debug("approx::replayAssert") << "replayAssertion " << c << endl; |
2237 |
|
if(inConflict){ |
2238 |
|
raiseConflict(c, InferenceId::UNKNOWN); |
2239 |
|
}else{ |
2240 |
|
assertionCases(c); |
2241 |
|
} |
2242 |
|
}else{ |
2243 |
|
Debug("approx::replayAssert") |
2244 |
|
<< "replayAssert " << c << " already asserted" << endl; |
2245 |
|
} |
2246 |
|
} |
2247 |
|
|
2248 |
|
|
2249 |
|
void TheoryArithPrivate::resolveOutPropagated(std::vector<ConstraintCPVec>& confs, const std::set<ConstraintCP>& propagated) const { |
2250 |
|
Debug("arith::resolveOutPropagated") |
2251 |
|
<< "starting resolveOutPropagated() " << confs.size() << endl; |
2252 |
|
for(size_t i =0, N = confs.size(); i < N; ++i){ |
2253 |
|
ConstraintCPVec& conf = confs[i]; |
2254 |
|
size_t orig = conf.size(); |
2255 |
|
Constraint::assertionFringe(conf); |
2256 |
|
Debug("arith::resolveOutPropagated") |
2257 |
|
<< " conf["<<i<<"] " << orig << " to " << conf.size() << endl; |
2258 |
|
} |
2259 |
|
Debug("arith::resolveOutPropagated") |
2260 |
|
<< "ending resolveOutPropagated() " << confs.size() << endl; |
2261 |
|
} |
2262 |
|
|
2263 |
|
struct SizeOrd { |
2264 |
|
bool operator()(const ConstraintCPVec& a, const ConstraintCPVec& b) const{ |
2265 |
|
return a.size() < b.size(); |
2266 |
|
} |
2267 |
|
}; |
2268 |
|
|
2269 |
|
void TheoryArithPrivate::subsumption( |
2270 |
|
std::vector<ConstraintCPVec> &confs) const { |
2271 |
|
int checks CVC5_UNUSED = 0; |
2272 |
|
int subsumed CVC5_UNUSED = 0; |
2273 |
|
|
2274 |
|
for (size_t i = 0, N = confs.size(); i < N; ++i) { |
2275 |
|
ConstraintCPVec &conf = confs[i]; |
2276 |
|
std::sort(conf.begin(), conf.end()); |
2277 |
|
} |
2278 |
|
|
2279 |
|
std::sort(confs.begin(), confs.end(), SizeOrd()); |
2280 |
|
for (size_t i = 0; i < confs.size(); i++) { |
2281 |
|
// i is not subsumed |
2282 |
|
for (size_t j = i + 1; j < confs.size();) { |
2283 |
|
ConstraintCPVec& a = confs[i]; |
2284 |
|
ConstraintCPVec& b = confs[j]; |
2285 |
|
checks++; |
2286 |
|
bool subsumes = std::includes(a.begin(), a.end(), b.begin(), b.end()); |
2287 |
|
if (subsumes) { |
2288 |
|
ConstraintCPVec& back = confs.back(); |
2289 |
|
b.swap(back); |
2290 |
|
confs.pop_back(); |
2291 |
|
subsumed++; |
2292 |
|
} else { |
2293 |
|
j++; |
2294 |
|
} |
2295 |
|
} |
2296 |
|
} |
2297 |
|
Debug("arith::subsumption") << "subsumed " << subsumed << "/" << checks |
2298 |
|
<< endl; |
2299 |
|
} |
2300 |
|
|
2301 |
|
std::vector<ConstraintCPVec> TheoryArithPrivate::replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth){ |
2302 |
|
++(d_statistics.d_replayLogRecCount); |
2303 |
|
Debug("approx::replayLogRec") << "replayLogRec()" << std::endl; |
2304 |
|
|
2305 |
|
size_t rpvars_size = d_replayVariables.size(); |
2306 |
|
size_t rpcons_size = d_replayConstraints.size(); |
2307 |
|
std::vector<ConstraintCPVec> res; |
2308 |
|
|
2309 |
|
{ /* create a block for the purpose of pushing the sat context */ |
2310 |
|
context::Context::ScopedPush speculativePush(getSatContext()); |
2311 |
|
Assert(!anyConflict()); |
2312 |
|
Assert(conflictQueueEmpty()); |
2313 |
|
set<ConstraintCP> propagated; |
2314 |
|
|
2315 |
|
TreeLog& tl = getTreeLog(); |
2316 |
|
|
2317 |
|
if(bc != NullConstraint){ |
2318 |
|
replayAssert(bc); |
2319 |
|
} |
2320 |
|
|
2321 |
|
const NodeLog& nl = tl.getNode(nid); |
2322 |
|
NodeLog::const_iterator iter = nl.begin(), end = nl.end(); |
2323 |
|
for(; conflictQueueEmpty() && iter != end; ++iter){ |
2324 |
|
CutInfo* ci = *iter; |
2325 |
|
bool reject = false; |
2326 |
|
//cout << " trying " << *ci << endl; |
2327 |
|
if(ci->getKlass() == RowsDeletedKlass){ |
2328 |
|
RowsDeleted* rd = dynamic_cast<RowsDeleted*>(ci); |
2329 |
|
|
2330 |
|
tl.applyRowsDeleted(nid, *rd); |
2331 |
|
// The previous line modifies nl |
2332 |
|
|
2333 |
|
++d_statistics.d_applyRowsDeleted; |
2334 |
|
}else if(ci->getKlass() == BranchCutKlass){ |
2335 |
|
BranchCutInfo* bci = dynamic_cast<BranchCutInfo*>(ci); |
2336 |
|
Assert(bci != NULL); |
2337 |
|
tryBranchCut(approx, nid, *bci); |
2338 |
|
|
2339 |
|
++d_statistics.d_branchCutsAttempted; |
2340 |
|
if(!(conflictQueueEmpty() || ci->reconstructed())){ |
2341 |
|
++d_statistics.d_numBranchesFailed; |
2342 |
|
} |
2343 |
|
}else{ |
2344 |
|
approx->tryCut(nid, *ci); |
2345 |
|
if(ci->getKlass() == GmiCutKlass){ |
2346 |
|
++d_statistics.d_gmiCutsAttempted; |
2347 |
|
}else if(ci->getKlass() == MirCutKlass){ |
2348 |
|
++d_statistics.d_mirCutsAttempted; |
2349 |
|
} |
2350 |
|
|
2351 |
|
if(ci->reconstructed() && ci->proven()){ |
2352 |
|
const DenseMap<Rational>& row = ci->getReconstruction().lhs; |
2353 |
|
reject = !complexityBelow(row, options::replayRejectCutSize()); |
2354 |
|
} |
2355 |
|
} |
2356 |
|
if(conflictQueueEmpty()){ |
2357 |
|
if(reject){ |
2358 |
|
++d_statistics.d_cutsRejectedDuringReplay; |
2359 |
|
}else if(ci->reconstructed()){ |
2360 |
|
// success |
2361 |
|
++d_statistics.d_cutsReconstructed; |
2362 |
|
|
2363 |
|
pair<ConstraintP, ArithVar> p = replayGetConstraint(*ci); |
2364 |
|
if(p.second != ARITHVAR_SENTINEL){ |
2365 |
|
Assert(ci->getRowId() >= 1); |
2366 |
|
tl.mapRowId(nl.getNodeId(), ci->getRowId(), p.second); |
2367 |
|
} |
2368 |
|
ConstraintP con = p.first; |
2369 |
|
if(Debug.isOn("approx::replayLogRec")){ |
2370 |
|
Debug("approx::replayLogRec") << "cut was remade " << con << " " << *ci << endl; |
2371 |
|
} |
2372 |
|
|
2373 |
|
if(ci->proven()){ |
2374 |
|
++d_statistics.d_cutsProven; |
2375 |
|
|
2376 |
|
const ConstraintCPVec& exp = ci->getExplanation(); |
2377 |
|
// success |
2378 |
|
if(con->isTrue()){ |
2379 |
|
Debug("approx::replayLogRec") << "not asserted?" << endl; |
2380 |
|
}else if(!con->negationHasProof()){ |
2381 |
|
con->impliedByIntHole(exp, false); |
2382 |
|
replayAssert(con); |
2383 |
|
Debug("approx::replayLogRec") << "cut prop" << endl; |
2384 |
|
}else { |
2385 |
|
con->impliedByIntHole(exp, true); |
2386 |
|
Debug("approx::replayLogRec") << "cut into conflict " << con << endl; |
2387 |
|
raiseConflict(con, InferenceId::UNKNOWN); |
2388 |
|
} |
2389 |
|
}else{ |
2390 |
|
++d_statistics.d_cutsProofFailed; |
2391 |
|
Debug("approx::replayLogRec") << "failed to get proof " << *ci << endl; |
2392 |
|
} |
2393 |
|
}else if(ci->getKlass() != RowsDeletedKlass){ |
2394 |
|
++d_statistics.d_cutsReconstructionFailed; |
2395 |
|
} |
2396 |
|
} |
2397 |
|
} |
2398 |
|
|
2399 |
|
/* check if the system is feasible under with the cuts */ |
2400 |
|
if(conflictQueueEmpty()){ |
2401 |
|
Assert(options::replayEarlyCloseDepths() >= 1); |
2402 |
|
if(!nl.isBranch() || depth % options::replayEarlyCloseDepths() == 0 ){ |
2403 |
|
TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer); |
2404 |
|
//test for linear feasibility |
2405 |
|
d_partialModel.stopQueueingBoundCounts(); |
2406 |
|
UpdateTrackingCallback utcb(&d_linEq); |
2407 |
|
d_partialModel.processBoundsQueue(utcb); |
2408 |
|
d_linEq.startTrackingBoundCounts(); |
2409 |
|
|
2410 |
|
SimplexDecisionProcedure& simplex = selectSimplex(true); |
2411 |
|
simplex.findModel(false); |
2412 |
|
// can change d_qflraStatus |
2413 |
|
|
2414 |
|
d_linEq.stopTrackingBoundCounts(); |
2415 |
|
d_partialModel.startQueueingBoundCounts(); |
2416 |
|
} |
2417 |
|
}else{ |
2418 |
|
++d_statistics.d_replayLogRecConflictEscalation; |
2419 |
|
} |
2420 |
|
|
2421 |
|
if(!conflictQueueEmpty()){ |
2422 |
|
/* if a conflict has been found stop */ |
2423 |
|
for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){ |
2424 |
|
res.push_back(ConstraintCPVec()); |
2425 |
|
intHoleConflictToVector(d_conflicts[i].first, res.back()); |
2426 |
|
} |
2427 |
|
++d_statistics.d_replayLogRecEarlyExit; |
2428 |
|
}else if(nl.isBranch()){ |
2429 |
|
/* if it is a branch try the branch */ |
2430 |
|
pair<ConstraintP, ArithVar> p = replayGetConstraint(approx, nl); |
2431 |
|
Assert(p.second == ARITHVAR_SENTINEL); |
2432 |
|
ConstraintP dnc = p.first; |
2433 |
|
if(dnc != NullConstraint){ |
2434 |
|
ConstraintP upc = dnc->getNegation(); |
2435 |
|
|
2436 |
|
int dnid = nl.getDownId(); |
2437 |
|
int upid = nl.getUpId(); |
2438 |
|
|
2439 |
|
NodeLog& dnlog = tl.getNode(dnid); |
2440 |
|
NodeLog& uplog = tl.getNode(upid); |
2441 |
|
dnlog.copyParentRowIds(); |
2442 |
|
uplog.copyParentRowIds(); |
2443 |
|
|
2444 |
|
std::vector<ConstraintCPVec> dnres; |
2445 |
|
std::vector<ConstraintCPVec> upres; |
2446 |
|
std::vector<size_t> containsdn; |
2447 |
|
std::vector<size_t> containsup; |
2448 |
|
if(res.empty()){ |
2449 |
|
dnres = replayLogRec(approx, dnid, dnc, depth+1); |
2450 |
|
for(size_t i = 0, N = dnres.size(); i < N; ++i){ |
2451 |
|
ConstraintCPVec& conf = dnres[i]; |
2452 |
|
if(contains(conf, dnc)){ |
2453 |
|
containsdn.push_back(i); |
2454 |
|
}else{ |
2455 |
|
res.push_back(conf); |
2456 |
|
} |
2457 |
|
} |
2458 |
|
}else{ |
2459 |
|
Debug("approx::replayLogRec") << "replayLogRec() skipping" << dnlog << std::endl; |
2460 |
|
++d_statistics.d_replayBranchSkips; |
2461 |
|
} |
2462 |
|
|
2463 |
|
if(res.empty()){ |
2464 |
|
upres = replayLogRec(approx, upid, upc, depth+1); |
2465 |
|
|
2466 |
|
for(size_t i = 0, N = upres.size(); i < N; ++i){ |
2467 |
|
ConstraintCPVec& conf = upres[i]; |
2468 |
|
if(contains(conf, upc)){ |
2469 |
|
containsup.push_back(i); |
2470 |
|
}else{ |
2471 |
|
res.push_back(conf); |
2472 |
|
} |
2473 |
|
} |
2474 |
|
}else{ |
2475 |
|
Debug("approx::replayLogRec") << "replayLogRec() skipping" << uplog << std::endl; |
2476 |
|
++d_statistics.d_replayBranchSkips; |
2477 |
|
} |
2478 |
|
|
2479 |
|
if(res.empty()){ |
2480 |
|
for(size_t i = 0, N = containsdn.size(); i < N; ++i){ |
2481 |
|
ConstraintCPVec& dnconf = dnres[containsdn[i]]; |
2482 |
|
for(size_t j = 0, M = containsup.size(); j < M; ++j){ |
2483 |
|
ConstraintCPVec& upconf = upres[containsup[j]]; |
2484 |
|
|
2485 |
|
res.push_back(ConstraintCPVec()); |
2486 |
|
ConstraintCPVec& back = res.back(); |
2487 |
|
resolve(back, dnc, dnconf, upconf); |
2488 |
|
} |
2489 |
|
} |
2490 |
|
if(res.size() >= 2u){ |
2491 |
|
subsumption(res); |
2492 |
|
|
2493 |
|
if(res.size() > 100u){ |
2494 |
|
res.resize(100u); |
2495 |
|
} |
2496 |
|
} |
2497 |
|
}else{ |
2498 |
|
Debug("approx::replayLogRec") << "replayLogRec() skipping resolving" << nl << std::endl; |
2499 |
|
} |
2500 |
|
Debug("approx::replayLogRec") << "found #"<<res.size()<<" conflicts on branch " << nid << endl; |
2501 |
|
if(res.empty()){ |
2502 |
|
++d_statistics.d_replayBranchCloseFailures; |
2503 |
|
} |
2504 |
|
|
2505 |
|
}else{ |
2506 |
|
Debug("approx::replayLogRec") << "failed to make a branch " << nid << endl; |
2507 |
|
} |
2508 |
|
}else{ |
2509 |
|
++d_statistics.d_replayLeafCloseFailures; |
2510 |
|
Debug("approx::replayLogRec") << "failed on node " << nid << endl; |
2511 |
|
Assert(res.empty()); |
2512 |
|
} |
2513 |
|
resolveOutPropagated(res, propagated); |
2514 |
|
Debug("approx::replayLogRec") << "replayLogRec() ending" << std::endl; |
2515 |
|
|
2516 |
|
|
2517 |
|
if(options::replayFailureLemma()){ |
2518 |
|
// must be done inside the sat context to get things |
2519 |
|
// propagated at this level |
2520 |
|
if(res.empty() && nid == getTreeLog().getRootId()){ |
2521 |
|
Assert(!d_replayedLemmas); |
2522 |
|
d_replayedLemmas = replayLemmas(approx); |
2523 |
|
Assert(d_acTmp.empty()); |
2524 |
|
while(!d_approxCuts.empty()){ |
2525 |
|
TrustNode lem = d_approxCuts.front(); |
2526 |
|
d_approxCuts.pop(); |
2527 |
|
d_acTmp.push_back(lem); |
2528 |
|
} |
2529 |
|
} |
2530 |
|
} |
2531 |
|
} /* pop the sat context */ |
2532 |
|
|
2533 |
|
/* move into the current context. */ |
2534 |
|
while(!d_acTmp.empty()){ |
2535 |
|
TrustNode lem = d_acTmp.back(); |
2536 |
|
d_acTmp.pop_back(); |
2537 |
|
d_approxCuts.push_back(lem); |
2538 |
|
} |
2539 |
|
Assert(d_acTmp.empty()); |
2540 |
|
|
2541 |
|
/* Garbage collect the constraints from this call */ |
2542 |
|
while(d_replayConstraints.size() > rpcons_size){ |
2543 |
|
ConstraintP c = d_replayConstraints.back(); |
2544 |
|
d_replayConstraints.pop_back(); |
2545 |
|
d_constraintDatabase.deleteConstraintAndNegation(c); |
2546 |
|
} |
2547 |
|
|
2548 |
|
/* Garbage collect the ArithVars made by this call */ |
2549 |
|
if(d_replayVariables.size() > rpvars_size){ |
2550 |
|
d_partialModel.stopQueueingBoundCounts(); |
2551 |
|
UpdateTrackingCallback utcb(&d_linEq); |
2552 |
|
d_partialModel.processBoundsQueue(utcb); |
2553 |
|
d_linEq.startTrackingBoundCounts(); |
2554 |
|
while(d_replayVariables.size() > rpvars_size){ |
2555 |
|
ArithVar v = d_replayVariables.back(); |
2556 |
|
d_replayVariables.pop_back(); |
2557 |
|
Assert(d_partialModel.canBeReleased(v)); |
2558 |
|
if(!d_tableau.isBasic(v)){ |
2559 |
|
/* if it is not basic make it basic. */ |
2560 |
|
ArithVar b = ARITHVAR_SENTINEL; |
2561 |
|
for(Tableau::ColIterator ci = d_tableau.colIterator(v); !ci.atEnd(); ++ci){ |
2562 |
|
const Tableau::Entry& e = *ci; |
2563 |
|
b = d_tableau.rowIndexToBasic(e.getRowIndex()); |
2564 |
|
break; |
2565 |
|
} |
2566 |
|
Assert(b != ARITHVAR_SENTINEL); |
2567 |
|
DeltaRational cp = d_partialModel.getAssignment(b); |
2568 |
|
if(d_partialModel.cmpAssignmentLowerBound(b) < 0){ |
2569 |
|
cp = d_partialModel.getLowerBound(b); |
2570 |
|
}else if(d_partialModel.cmpAssignmentUpperBound(b) > 0){ |
2571 |
|
cp = d_partialModel.getUpperBound(b); |
2572 |
|
} |
2573 |
|
d_linEq.pivotAndUpdate(b, v, cp); |
2574 |
|
} |
2575 |
|
Assert(d_tableau.isBasic(v)); |
2576 |
|
d_linEq.stopTrackingRowIndex(d_tableau.basicToRowIndex(v)); |
2577 |
|
d_tableau.removeBasicRow(v); |
2578 |
|
|
2579 |
|
releaseArithVar(v); |
2580 |
|
Debug("approx::vars") << "releasing " << v << endl; |
2581 |
|
} |
2582 |
|
d_linEq.stopTrackingBoundCounts(); |
2583 |
|
d_partialModel.startQueueingBoundCounts(); |
2584 |
|
d_partialModel.attemptToReclaimReleased(); |
2585 |
|
} |
2586 |
|
return res; |
2587 |
|
} |
2588 |
|
|
2589 |
|
TreeLog& TheoryArithPrivate::getTreeLog(){ |
2590 |
|
if(d_treeLog == NULL){ |
2591 |
|
d_treeLog = new TreeLog(); |
2592 |
|
} |
2593 |
|
return *d_treeLog; |
2594 |
|
} |
2595 |
|
|
2596 |
|
ApproximateStatistics& TheoryArithPrivate::getApproxStats(){ |
2597 |
|
if(d_approxStats == NULL){ |
2598 |
|
d_approxStats = new ApproximateStatistics(); |
2599 |
|
} |
2600 |
|
return *d_approxStats; |
2601 |
|
} |
2602 |
|
|
2603 |
|
Node TheoryArithPrivate::branchToNode(ApproximateSimplex* approx, |
2604 |
|
const NodeLog& bn) const |
2605 |
|
{ |
2606 |
|
Assert(bn.isBranch()); |
2607 |
|
ArithVar v = approx->getBranchVar(bn); |
2608 |
|
if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){ |
2609 |
|
if(d_partialModel.hasNode(v)){ |
2610 |
|
Node n = d_partialModel.asNode(v); |
2611 |
|
double dval = bn.branchValue(); |
2612 |
|
Maybe<Rational> maybe_value = ApproximateSimplex::estimateWithCFE(dval); |
2613 |
|
if (!maybe_value) |
2614 |
|
{ |
2615 |
|
return Node::null(); |
2616 |
|
} |
2617 |
|
Rational fl(maybe_value.value().floor()); |
2618 |
|
NodeManager* nm = NodeManager::currentNM(); |
2619 |
|
Node leq = nm->mkNode(kind::LEQ, n, mkRationalNode(fl)); |
2620 |
|
Node norm = Rewriter::rewrite(leq); |
2621 |
|
return norm; |
2622 |
|
} |
2623 |
|
} |
2624 |
|
return Node::null(); |
2625 |
|
} |
2626 |
|
|
2627 |
|
Node TheoryArithPrivate::cutToLiteral(ApproximateSimplex* approx, const CutInfo& ci) const{ |
2628 |
|
Assert(ci.reconstructed()); |
2629 |
|
|
2630 |
|
const DenseMap<Rational>& lhs = ci.getReconstruction().lhs; |
2631 |
|
Node sum = toSumNode(d_partialModel, lhs); |
2632 |
|
if(!sum.isNull()){ |
2633 |
|
Kind k = ci.getKind(); |
2634 |
|
Assert(k == kind::LEQ || k == kind::GEQ); |
2635 |
|
Node rhs = mkRationalNode(ci.getReconstruction().rhs); |
2636 |
|
|
2637 |
|
NodeManager* nm = NodeManager::currentNM(); |
2638 |
|
Node ineq = nm->mkNode(k, sum, rhs); |
2639 |
|
return Rewriter::rewrite(ineq); |
2640 |
|
} |
2641 |
|
return Node::null(); |
2642 |
|
} |
2643 |
|
|
2644 |
|
bool TheoryArithPrivate::replayLemmas(ApproximateSimplex* approx){ |
2645 |
|
++(d_statistics.d_mipReplayLemmaCalls); |
2646 |
|
bool anythingnew = false; |
2647 |
|
|
2648 |
|
TreeLog& tl = getTreeLog(); |
2649 |
|
NodeLog& root = tl.getRootNode(); |
2650 |
|
root.applySelected(); /* set row ids */ |
2651 |
|
|
2652 |
|
vector<const CutInfo*> cuts = approx->getValidCuts(root); |
2653 |
|
for(size_t i =0, N =cuts.size(); i < N; ++i){ |
2654 |
|
const CutInfo* cut = cuts[i]; |
2655 |
|
Assert(cut->reconstructed()); |
2656 |
|
Assert(cut->proven()); |
2657 |
|
|
2658 |
|
const DenseMap<Rational>& row = cut->getReconstruction().lhs; |
2659 |
|
if(!complexityBelow(row, options::lemmaRejectCutSize())){ |
2660 |
|
++(d_statistics.d_cutsRejectedDuringLemmas); |
2661 |
|
continue; |
2662 |
|
} |
2663 |
|
|
2664 |
|
Node cutConstraint = cutToLiteral(approx, *cut); |
2665 |
|
if(!cutConstraint.isNull()){ |
2666 |
|
const ConstraintCPVec& exp = cut->getExplanation(); |
2667 |
|
Node asLemma = Constraint::externalExplainByAssertions(exp); |
2668 |
|
|
2669 |
|
Node implied = Rewriter::rewrite(cutConstraint); |
2670 |
|
anythingnew = anythingnew || !isSatLiteral(implied); |
2671 |
|
|
2672 |
|
Node implication = asLemma.impNode(implied); |
2673 |
|
// DO NOT CALL OUTPUT LEMMA! |
2674 |
|
// TODO (project #37): justify |
2675 |
|
d_approxCuts.push_back(TrustNode::mkTrustLemma(implication, nullptr)); |
2676 |
|
Debug("approx::lemmas") << "cut["<<i<<"] " << implication << endl; |
2677 |
|
++(d_statistics.d_mipExternalCuts); |
2678 |
|
} |
2679 |
|
} |
2680 |
|
if(root.isBranch()){ |
2681 |
|
Node lit = branchToNode(approx, root); |
2682 |
|
if(!lit.isNull()){ |
2683 |
|
anythingnew = anythingnew || !isSatLiteral(lit); |
2684 |
|
Node branch = lit.orNode(lit.notNode()); |
2685 |
|
if (proofsEnabled()) |
2686 |
|
{ |
2687 |
|
d_pfGen->mkTrustNode(branch, PfRule::SPLIT, {}, {lit}); |
2688 |
|
} |
2689 |
|
else |
2690 |
|
{ |
2691 |
|
d_approxCuts.push_back(TrustNode::mkTrustLemma(branch, nullptr)); |
2692 |
|
} |
2693 |
|
++(d_statistics.d_mipExternalBranch); |
2694 |
|
Debug("approx::lemmas") << "branching "<< root <<" as " << branch << endl; |
2695 |
|
} |
2696 |
|
} |
2697 |
|
return anythingnew; |
2698 |
|
} |
2699 |
|
|
2700 |
|
void TheoryArithPrivate::turnOffApproxFor(int32_t rounds){ |
2701 |
|
d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff + rounds; |
2702 |
|
++(d_statistics.d_approxDisabled); |
2703 |
|
} |
2704 |
|
|
2705 |
1635646 |
bool TheoryArithPrivate::safeToCallApprox() const{ |
2706 |
1635646 |
unsigned numRows = 0; |
2707 |
1635646 |
unsigned numCols = 0; |
2708 |
1635646 |
var_iterator vi = var_begin(), vi_end = var_end(); |
2709 |
|
// Assign each variable to a row and column variable as it appears in the input |
2710 |
25447686 |
for(; vi != vi_end && !(numRows > 0 && numCols > 0); ++vi){ |
2711 |
11906020 |
ArithVar v = *vi; |
2712 |
|
|
2713 |
11906020 |
if(d_partialModel.isAuxiliary(v)){ |
2714 |
1618513 |
++numRows; |
2715 |
|
}else{ |
2716 |
10287507 |
++numCols; |
2717 |
|
} |
2718 |
|
} |
2719 |
1635646 |
return (numRows > 0 && numCols > 0); |
2720 |
|
} |
2721 |
|
|
2722 |
|
// solve() |
2723 |
|
// res = solveRealRelaxation(effortLevel); |
2724 |
|
// switch(res){ |
2725 |
|
// case LinFeas: |
2726 |
|
// case LinInfeas: |
2727 |
|
// return replay() |
2728 |
|
// case Unknown: |
2729 |
|
// case Error |
2730 |
|
// if() |
2731 |
|
void TheoryArithPrivate::solveInteger(Theory::Effort effortLevel){ |
2732 |
|
if(!safeToCallApprox()) { return; } |
2733 |
|
|
2734 |
|
Assert(safeToCallApprox()); |
2735 |
|
TimerStat::CodeTimer codeTimer0(d_statistics.d_solveIntTimer); |
2736 |
|
|
2737 |
|
++(d_statistics.d_solveIntCalls); |
2738 |
|
d_statistics.d_inSolveInteger = 1; |
2739 |
|
|
2740 |
|
if(!Theory::fullEffort(effortLevel)){ |
2741 |
|
d_solveIntAttempts++; |
2742 |
|
++(d_statistics.d_solveStandardEffort); |
2743 |
|
} |
2744 |
|
|
2745 |
|
// if integers are attempted, |
2746 |
|
Assert(options::useApprox()); |
2747 |
|
Assert(ApproximateSimplex::enabled()); |
2748 |
|
|
2749 |
|
int level = getSatContext()->getLevel(); |
2750 |
|
d_lastContextIntegerAttempted = level; |
2751 |
|
|
2752 |
|
|
2753 |
|
static const int32_t mipLimit = 200000; |
2754 |
|
|
2755 |
|
TreeLog& tl = getTreeLog(); |
2756 |
|
ApproximateStatistics& stats = getApproxStats(); |
2757 |
|
ApproximateSimplex* approx = |
2758 |
|
ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats); |
2759 |
|
|
2760 |
|
approx->setPivotLimit(mipLimit); |
2761 |
|
if(!d_guessedCoeffSet){ |
2762 |
|
d_guessedCoeffs = approx->heuristicOptCoeffs(); |
2763 |
|
d_guessedCoeffSet = true; |
2764 |
|
} |
2765 |
|
if(!d_guessedCoeffs.empty()){ |
2766 |
|
approx->setOptCoeffs(d_guessedCoeffs); |
2767 |
|
} |
2768 |
|
static const int32_t depthForLikelyInfeasible = 10; |
2769 |
|
int maxDepthPass1 = d_likelyIntegerInfeasible ? |
2770 |
|
depthForLikelyInfeasible : options::maxApproxDepth(); |
2771 |
|
approx->setBranchingDepth(maxDepthPass1); |
2772 |
|
approx->setBranchOnVariableLimit(100); |
2773 |
|
LinResult relaxRes = approx->solveRelaxation(); |
2774 |
|
if( relaxRes == LinFeasible ){ |
2775 |
|
MipResult mipRes = MipUnknown; |
2776 |
|
{ |
2777 |
|
TimerStat::CodeTimer codeTimer1(d_statistics.d_mipTimer); |
2778 |
|
mipRes = approx->solveMIP(false); |
2779 |
|
} |
2780 |
|
|
2781 |
|
Debug("arith::solveInteger") << "mipRes " << mipRes << endl; |
2782 |
|
switch(mipRes) { |
2783 |
|
case MipBingo: |
2784 |
|
// attempt the solution |
2785 |
|
{ |
2786 |
|
++(d_statistics.d_solveIntModelsAttempts); |
2787 |
|
|
2788 |
|
d_partialModel.stopQueueingBoundCounts(); |
2789 |
|
UpdateTrackingCallback utcb(&d_linEq); |
2790 |
|
d_partialModel.processBoundsQueue(utcb); |
2791 |
|
d_linEq.startTrackingBoundCounts(); |
2792 |
|
|
2793 |
|
ApproximateSimplex::Solution mipSolution; |
2794 |
|
mipSolution = approx->extractMIP(); |
2795 |
|
importSolution(mipSolution); |
2796 |
|
solveRelaxationOrPanic(effortLevel); |
2797 |
|
|
2798 |
|
if (d_qflraStatus == Result::SAT) |
2799 |
|
{ |
2800 |
|
if (!anyConflict()) |
2801 |
|
{ |
2802 |
|
if (ARITHVAR_SENTINEL == nextIntegerViolation(false)) |
2803 |
|
{ |
2804 |
|
++(d_statistics.d_solveIntModelsSuccessful); |
2805 |
|
} |
2806 |
|
} |
2807 |
|
} |
2808 |
|
|
2809 |
|
// shutdown simplex |
2810 |
|
d_linEq.stopTrackingBoundCounts(); |
2811 |
|
d_partialModel.startQueueingBoundCounts(); |
2812 |
|
} |
2813 |
|
break; |
2814 |
|
case MipClosed: |
2815 |
|
/* All integer branches closed */ |
2816 |
|
approx->setPivotLimit(2*mipLimit); |
2817 |
|
{ |
2818 |
|
TimerStat::CodeTimer codeTimer2(d_statistics.d_mipTimer); |
2819 |
|
mipRes = approx->solveMIP(true); |
2820 |
|
} |
2821 |
|
|
2822 |
|
if(mipRes == MipClosed){ |
2823 |
|
d_likelyIntegerInfeasible = true; |
2824 |
|
replayLog(approx); |
2825 |
|
AlwaysAssert(anyConflict() || d_qflraStatus != Result::SAT); |
2826 |
|
|
2827 |
|
if (!anyConflict()) |
2828 |
|
{ |
2829 |
|
solveRealRelaxation(effortLevel); |
2830 |
|
} |
2831 |
|
} |
2832 |
|
if(!(anyConflict() || !d_approxCuts.empty())){ |
2833 |
|
turnOffApproxFor(options::replayNumericFailurePenalty()); |
2834 |
|
} |
2835 |
|
break; |
2836 |
|
case BranchesExhausted: |
2837 |
|
case ExecExhausted: |
2838 |
|
case PivotsExhauasted: |
2839 |
|
if(mipRes == BranchesExhausted){ |
2840 |
|
++d_statistics.d_branchesExhausted; |
2841 |
|
}else if(mipRes == ExecExhausted){ |
2842 |
|
++d_statistics.d_execExhausted; |
2843 |
|
}else if(mipRes == PivotsExhauasted){ |
2844 |
|
++d_statistics.d_pivotsExhausted; |
2845 |
|
} |
2846 |
|
|
2847 |
|
approx->setPivotLimit(2*mipLimit); |
2848 |
|
approx->setBranchingDepth(2); |
2849 |
|
{ |
2850 |
|
TimerStat::CodeTimer codeTimer3(d_statistics.d_mipTimer); |
2851 |
|
mipRes = approx->solveMIP(true); |
2852 |
|
} |
2853 |
|
replayLemmas(approx); |
2854 |
|
break; |
2855 |
|
case MipUnknown: |
2856 |
|
break; |
2857 |
|
} |
2858 |
|
} |
2859 |
|
delete approx; |
2860 |
|
|
2861 |
|
if(!Theory::fullEffort(effortLevel)){ |
2862 |
|
if(anyConflict() || !d_approxCuts.empty()){ |
2863 |
|
d_solveIntMaybeHelp++; |
2864 |
|
} |
2865 |
|
} |
2866 |
|
|
2867 |
|
d_statistics.d_inSolveInteger = 0; |
2868 |
|
} |
2869 |
|
|
2870 |
1635646 |
SimplexDecisionProcedure& TheoryArithPrivate::selectSimplex(bool pass1){ |
2871 |
1635646 |
if(pass1){ |
2872 |
1635646 |
if(d_pass1SDP == NULL){ |
2873 |
6344 |
if(options::useFC()){ |
2874 |
|
d_pass1SDP = (SimplexDecisionProcedure*)(&d_fcSimplex); |
2875 |
6344 |
}else if(options::useSOI()){ |
2876 |
|
d_pass1SDP = (SimplexDecisionProcedure*)(&d_soiSimplex); |
2877 |
|
}else{ |
2878 |
6344 |
d_pass1SDP = (SimplexDecisionProcedure*)(&d_dualSimplex); |
2879 |
|
} |
2880 |
|
} |
2881 |
1635646 |
Assert(d_pass1SDP != NULL); |
2882 |
1635646 |
return *d_pass1SDP; |
2883 |
|
}else{ |
2884 |
|
if(d_otherSDP == NULL){ |
2885 |
|
if(options::useFC()){ |
2886 |
|
d_otherSDP = (SimplexDecisionProcedure*)(&d_fcSimplex); |
2887 |
|
}else if(options::useSOI()){ |
2888 |
|
d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex); |
2889 |
|
}else{ |
2890 |
|
d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex); |
2891 |
|
} |
2892 |
|
} |
2893 |
|
Assert(d_otherSDP != NULL); |
2894 |
|
return *d_otherSDP; |
2895 |
|
} |
2896 |
|
} |
2897 |
|
|
2898 |
|
void TheoryArithPrivate::importSolution(const ApproximateSimplex::Solution& solution){ |
2899 |
|
if(Debug.isOn("arith::importSolution")){ |
2900 |
|
Debug("arith::importSolution") << "importSolution before " << d_qflraStatus << endl; |
2901 |
|
d_partialModel.printEntireModel(Debug("arith::importSolution")); |
2902 |
|
} |
2903 |
|
|
2904 |
|
d_qflraStatus = d_attemptSolSimplex.attempt(solution); |
2905 |
|
|
2906 |
|
if(Debug.isOn("arith::importSolution")){ |
2907 |
|
Debug("arith::importSolution") << "importSolution intermediate " << d_qflraStatus << endl; |
2908 |
|
d_partialModel.printEntireModel(Debug("arith::importSolution")); |
2909 |
|
} |
2910 |
|
|
2911 |
|
if(d_qflraStatus != Result::UNSAT){ |
2912 |
|
static const int32_t pass2Limit = 20; |
2913 |
|
int16_t oldCap = options::arithStandardCheckVarOrderPivots(); |
2914 |
|
Options::current().arith.arithStandardCheckVarOrderPivots = pass2Limit; |
2915 |
|
SimplexDecisionProcedure& simplex = selectSimplex(false); |
2916 |
|
d_qflraStatus = simplex.findModel(false); |
2917 |
|
Options::current().arith.arithStandardCheckVarOrderPivots = oldCap; |
2918 |
|
} |
2919 |
|
|
2920 |
|
if(Debug.isOn("arith::importSolution")){ |
2921 |
|
Debug("arith::importSolution") << "importSolution after " << d_qflraStatus << endl; |
2922 |
|
d_partialModel.printEntireModel(Debug("arith::importSolution")); |
2923 |
|
} |
2924 |
|
} |
2925 |
|
|
2926 |
1635646 |
bool TheoryArithPrivate::solveRelaxationOrPanic(Theory::Effort effortLevel) |
2927 |
|
{ |
2928 |
|
// if at this point the linear relaxation is still unknown, |
2929 |
|
// attempt to branch an integer variable as a last ditch effort on full check |
2930 |
1635646 |
if (d_qflraStatus == Result::SAT_UNKNOWN) |
2931 |
|
{ |
2932 |
|
d_qflraStatus = selectSimplex(true).findModel(false); |
2933 |
|
} |
2934 |
|
|
2935 |
1635646 |
if (Theory::fullEffort(effortLevel) && d_qflraStatus == Result::SAT_UNKNOWN) |
2936 |
|
{ |
2937 |
|
ArithVar canBranch = nextIntegerViolation(false); |
2938 |
|
if (canBranch != ARITHVAR_SENTINEL) |
2939 |
|
{ |
2940 |
|
++d_statistics.d_panicBranches; |
2941 |
|
TrustNode branch = branchIntegerVariable(canBranch); |
2942 |
|
Assert(branch.getNode().getKind() == kind::OR); |
2943 |
|
Node rwbranch = Rewriter::rewrite(branch.getNode()[0]); |
2944 |
|
if (!isSatLiteral(rwbranch)) |
2945 |
|
{ |
2946 |
|
d_approxCuts.push_back(branch); |
2947 |
|
return true; |
2948 |
|
} |
2949 |
|
} |
2950 |
|
d_qflraStatus = selectSimplex(false).findModel(true); |
2951 |
|
} |
2952 |
1635646 |
return false; |
2953 |
|
} |
2954 |
|
|
2955 |
1635646 |
bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){ |
2956 |
3271292 |
TimerStat::CodeTimer codeTimer0(d_statistics.d_solveRealRelaxTimer); |
2957 |
1635646 |
Assert(d_qflraStatus != Result::SAT); |
2958 |
|
|
2959 |
1635646 |
d_partialModel.stopQueueingBoundCounts(); |
2960 |
3271292 |
UpdateTrackingCallback utcb(&d_linEq); |
2961 |
1635646 |
d_partialModel.processBoundsQueue(utcb); |
2962 |
1635646 |
d_linEq.startTrackingBoundCounts(); |
2963 |
|
|
2964 |
3258194 |
bool noPivotLimit = Theory::fullEffort(effortLevel) || |
2965 |
3258194 |
!options::restrictedPivots(); |
2966 |
|
|
2967 |
1635646 |
SimplexDecisionProcedure& simplex = selectSimplex(true); |
2968 |
|
|
2969 |
1635646 |
bool useApprox = options::useApprox() && ApproximateSimplex::enabled() && getSolveIntegerResource(); |
2970 |
|
|
2971 |
3271292 |
Debug("TheoryArithPrivate::solveRealRelaxation") |
2972 |
1635646 |
<< "solveRealRelaxation() approx" |
2973 |
3271292 |
<< " " << options::useApprox() |
2974 |
3271292 |
<< " " << ApproximateSimplex::enabled() |
2975 |
1635646 |
<< " " << useApprox |
2976 |
3271292 |
<< " " << safeToCallApprox() |
2977 |
1635646 |
<< endl; |
2978 |
|
|
2979 |
1635646 |
bool noPivotLimitPass1 = noPivotLimit && !useApprox; |
2980 |
1635646 |
d_qflraStatus = simplex.findModel(noPivotLimitPass1); |
2981 |
|
|
2982 |
3271292 |
Debug("TheoryArithPrivate::solveRealRelaxation") |
2983 |
1635646 |
<< "solveRealRelaxation()" << " pass1 " << d_qflraStatus << endl; |
2984 |
|
|
2985 |
1635646 |
if(d_qflraStatus == Result::SAT_UNKNOWN && useApprox && safeToCallApprox()){ |
2986 |
|
// pass2: fancy-final |
2987 |
|
static const int32_t relaxationLimit = 10000; |
2988 |
|
Assert(ApproximateSimplex::enabled()); |
2989 |
|
|
2990 |
|
TreeLog& tl = getTreeLog(); |
2991 |
|
ApproximateStatistics& stats = getApproxStats(); |
2992 |
|
ApproximateSimplex* approxSolver = |
2993 |
|
ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats); |
2994 |
|
|
2995 |
|
approxSolver->setPivotLimit(relaxationLimit); |
2996 |
|
|
2997 |
|
if(!d_guessedCoeffSet){ |
2998 |
|
d_guessedCoeffs = approxSolver->heuristicOptCoeffs(); |
2999 |
|
d_guessedCoeffSet = true; |
3000 |
|
} |
3001 |
|
if(!d_guessedCoeffs.empty()){ |
3002 |
|
approxSolver->setOptCoeffs(d_guessedCoeffs); |
3003 |
|
} |
3004 |
|
|
3005 |
|
++d_statistics.d_relaxCalls; |
3006 |
|
|
3007 |
|
ApproximateSimplex::Solution relaxSolution; |
3008 |
|
LinResult relaxRes = LinUnknown; |
3009 |
|
{ |
3010 |
|
TimerStat::CodeTimer codeTimer1(d_statistics.d_lpTimer); |
3011 |
|
relaxRes = approxSolver->solveRelaxation(); |
3012 |
|
} |
3013 |
|
Debug("solveRealRelaxation") << "solve relaxation? " << endl; |
3014 |
|
switch(relaxRes){ |
3015 |
|
case LinFeasible: |
3016 |
|
Debug("solveRealRelaxation") << "lin feasible? " << endl; |
3017 |
|
++d_statistics.d_relaxLinFeas; |
3018 |
|
relaxSolution = approxSolver->extractRelaxation(); |
3019 |
|
importSolution(relaxSolution); |
3020 |
|
if(d_qflraStatus != Result::SAT){ |
3021 |
|
++d_statistics.d_relaxLinFeasFailures; |
3022 |
|
} |
3023 |
|
break; |
3024 |
|
case LinInfeasible: |
3025 |
|
// todo attempt to recreate approximate conflict |
3026 |
|
++d_statistics.d_relaxLinInfeas; |
3027 |
|
Debug("solveRealRelaxation") << "lin infeasible " << endl; |
3028 |
|
relaxSolution = approxSolver->extractRelaxation(); |
3029 |
|
importSolution(relaxSolution); |
3030 |
|
if(d_qflraStatus != Result::UNSAT){ |
3031 |
|
++d_statistics.d_relaxLinInfeasFailures; |
3032 |
|
} |
3033 |
|
break; |
3034 |
|
case LinExhausted: |
3035 |
|
++d_statistics.d_relaxLinExhausted; |
3036 |
|
Debug("solveRealRelaxation") << "exhuasted " << endl; |
3037 |
|
break; |
3038 |
|
case LinUnknown: |
3039 |
|
default: |
3040 |
|
++d_statistics.d_relaxOthers; |
3041 |
|
break; |
3042 |
|
} |
3043 |
|
delete approxSolver; |
3044 |
|
|
3045 |
|
} |
3046 |
|
|
3047 |
1635646 |
bool emmittedConflictOrSplit = solveRelaxationOrPanic(effortLevel); |
3048 |
|
|
3049 |
|
// TODO Save zeroes with no conflicts |
3050 |
1635646 |
d_linEq.stopTrackingBoundCounts(); |
3051 |
1635646 |
d_partialModel.startQueueingBoundCounts(); |
3052 |
|
|
3053 |
3271292 |
return emmittedConflictOrSplit; |
3054 |
|
} |
3055 |
|
|
3056 |
|
bool TheoryArithPrivate::hasFreshArithLiteral(Node n) const{ |
3057 |
|
switch(n.getKind()){ |
3058 |
|
case kind::LEQ: |
3059 |
|
case kind::GEQ: |
3060 |
|
case kind::GT: |
3061 |
|
case kind::LT: |
3062 |
|
return !isSatLiteral(n); |
3063 |
|
case kind::EQUAL: |
3064 |
|
if(n[0].getType().isReal()){ |
3065 |
|
return !isSatLiteral(n); |
3066 |
|
}else if(n[0].getType().isBoolean()){ |
3067 |
|
return hasFreshArithLiteral(n[0]) || |
3068 |
|
hasFreshArithLiteral(n[1]); |
3069 |
|
}else{ |
3070 |
|
return false; |
3071 |
|
} |
3072 |
|
case kind::IMPLIES: |
3073 |
|
// try the rhs first |
3074 |
|
return hasFreshArithLiteral(n[1]) || |
3075 |
|
hasFreshArithLiteral(n[0]); |
3076 |
|
default: |
3077 |
|
if(n.getType().isBoolean()){ |
3078 |
|
for(Node::iterator ni=n.begin(), nend=n.end(); ni!=nend; ++ni){ |
3079 |
|
Node child = *ni; |
3080 |
|
if(hasFreshArithLiteral(child)){ |
3081 |
|
return true; |
3082 |
|
} |
3083 |
|
} |
3084 |
|
} |
3085 |
|
return false; |
3086 |
|
} |
3087 |
|
} |
3088 |
|
|
3089 |
1711471 |
bool TheoryArithPrivate::preCheck(Theory::Effort level) |
3090 |
|
{ |
3091 |
1711471 |
Assert(d_currentPropagationList.empty()); |
3092 |
1711471 |
if(Debug.isOn("arith::consistency")){ |
3093 |
|
Assert(unenqueuedVariablesAreConsistent()); |
3094 |
|
} |
3095 |
|
|
3096 |
1711471 |
d_newFacts = !done(); |
3097 |
|
// If d_previousStatus == SAT, then reverts on conflicts are safe |
3098 |
|
// Otherwise, they are not and must be committed. |
3099 |
1711471 |
d_previousStatus = d_qflraStatus; |
3100 |
1711471 |
if (d_newFacts) |
3101 |
|
{ |
3102 |
1646099 |
d_qflraStatus = Result::SAT_UNKNOWN; |
3103 |
1646099 |
d_hasDoneWorkSinceCut = true; |
3104 |
|
} |
3105 |
1711471 |
return false; |
3106 |
|
} |
3107 |
|
|
3108 |
5992642 |
void TheoryArithPrivate::preNotifyFact(TNode atom, bool pol, TNode fact) |
3109 |
|
{ |
3110 |
5992642 |
ConstraintP curr = constraintFromFactQueue(fact); |
3111 |
5992642 |
if (curr != NullConstraint) |
3112 |
|
{ |
3113 |
5702271 |
bool res CVC5_UNUSED = assertionCases(curr); |
3114 |
5702271 |
Assert(!res || anyConflict()); |
3115 |
|
} |
3116 |
5992642 |
} |
3117 |
|
|
3118 |
1708458 |
bool TheoryArithPrivate::postCheck(Theory::Effort effortLevel) |
3119 |
|
{ |
3120 |
1708458 |
if(!anyConflict()){ |
3121 |
1936662 |
while(!d_learnedBounds.empty()){ |
3122 |
|
// we may attempt some constraints twice. this is okay! |
3123 |
120845 |
ConstraintP curr = d_learnedBounds.front(); |
3124 |
120845 |
d_learnedBounds.pop(); |
3125 |
120845 |
Debug("arith::learned") << curr << endl; |
3126 |
|
|
3127 |
120845 |
bool res CVC5_UNUSED = assertionCases(curr); |
3128 |
120845 |
Assert(!res || anyConflict()); |
3129 |
|
|
3130 |
120845 |
if(anyConflict()){ break; } |
3131 |
|
} |
3132 |
|
} |
3133 |
|
|
3134 |
1708458 |
if(anyConflict()){ |
3135 |
13422 |
d_qflraStatus = Result::UNSAT; |
3136 |
13422 |
if (options::revertArithModels() && d_previousStatus == Result::SAT) |
3137 |
|
{ |
3138 |
|
++d_statistics.d_revertsOnConflicts; |
3139 |
|
Debug("arith::bt") << "clearing here " |
3140 |
|
<< " " << d_newFacts << " " << d_previousStatus << " " |
3141 |
|
<< d_qflraStatus << endl; |
3142 |
|
revertOutOfConflict(); |
3143 |
|
d_errorSet.clear(); |
3144 |
|
}else{ |
3145 |
13422 |
++d_statistics.d_commitsOnConflicts; |
3146 |
26844 |
Debug("arith::bt") << "committing here " |
3147 |
13422 |
<< " " << d_newFacts << " " << d_previousStatus << " " |
3148 |
13422 |
<< d_qflraStatus << endl; |
3149 |
13422 |
d_partialModel.commitAssignmentChanges(); |
3150 |
13422 |
revertOutOfConflict(); |
3151 |
|
} |
3152 |
13422 |
outputConflicts(); |
3153 |
|
//cout << "unate conflict 1 " << effortLevel << std::endl; |
3154 |
13422 |
return true; |
3155 |
|
} |
3156 |
|
|
3157 |
|
|
3158 |
1695036 |
if(Debug.isOn("arith::print_assertions")) { |
3159 |
|
debugPrintAssertions(Debug("arith::print_assertions")); |
3160 |
|
} |
3161 |
|
|
3162 |
1695036 |
bool emmittedConflictOrSplit = false; |
3163 |
1695036 |
Assert(d_conflicts.empty()); |
3164 |
|
|
3165 |
1695036 |
bool useSimplex = d_qflraStatus != Result::SAT; |
3166 |
3390072 |
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit |
3167 |
1695036 |
<< "pre realRelax" << endl; |
3168 |
|
|
3169 |
1695036 |
if(useSimplex){ |
3170 |
1635646 |
emmittedConflictOrSplit = solveRealRelaxation(effortLevel); |
3171 |
|
} |
3172 |
3390072 |
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit |
3173 |
1695036 |
<< "post realRelax" << endl; |
3174 |
|
|
3175 |
|
|
3176 |
3390072 |
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit |
3177 |
1695036 |
<< "pre solveInteger" << endl; |
3178 |
|
|
3179 |
1695036 |
if(attemptSolveInteger(effortLevel, emmittedConflictOrSplit)){ |
3180 |
|
solveInteger(effortLevel); |
3181 |
|
if(anyConflict()){ |
3182 |
|
++d_statistics.d_commitsOnConflicts; |
3183 |
|
Debug("arith::bt") << "committing here " |
3184 |
|
<< " " << d_newFacts << " " << d_previousStatus << " " |
3185 |
|
<< d_qflraStatus << endl; |
3186 |
|
revertOutOfConflict(); |
3187 |
|
d_errorSet.clear(); |
3188 |
|
outputConflicts(); |
3189 |
|
return true; |
3190 |
|
} |
3191 |
|
} |
3192 |
|
|
3193 |
3390072 |
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit |
3194 |
1695036 |
<< "post solveInteger" << endl; |
3195 |
|
|
3196 |
1695036 |
switch(d_qflraStatus){ |
3197 |
1654099 |
case Result::SAT: |
3198 |
1654099 |
if (d_newFacts) |
3199 |
|
{ |
3200 |
1591740 |
++d_statistics.d_nontrivialSatChecks; |
3201 |
|
} |
3202 |
|
|
3203 |
3308198 |
Debug("arith::bt") << "committing sap inConflit" |
3204 |
1654099 |
<< " " << d_newFacts << " " << d_previousStatus << " " |
3205 |
1654099 |
<< d_qflraStatus << endl; |
3206 |
1654099 |
d_partialModel.commitAssignmentChanges(); |
3207 |
1654099 |
d_unknownsInARow = 0; |
3208 |
1654099 |
if(Debug.isOn("arith::consistency")){ |
3209 |
|
Assert(entireStateIsConsistent("sat comit")); |
3210 |
|
} |
3211 |
1654099 |
if(useSimplex && options::collectPivots()){ |
3212 |
|
if(options::useFC()){ |
3213 |
|
d_statistics.d_satPivots << d_fcSimplex.getPivots(); |
3214 |
|
}else{ |
3215 |
|
d_statistics.d_satPivots << d_dualSimplex.getPivots(); |
3216 |
|
} |
3217 |
|
} |
3218 |
1654099 |
break; |
3219 |
|
case Result::SAT_UNKNOWN: |
3220 |
|
++d_unknownsInARow; |
3221 |
|
++(d_statistics.d_unknownChecks); |
3222 |
|
Assert(!Theory::fullEffort(effortLevel)); |
3223 |
|
Debug("arith::bt") << "committing unknown" |
3224 |
|
<< " " << d_newFacts << " " << d_previousStatus << " " |
3225 |
|
<< d_qflraStatus << endl; |
3226 |
|
d_partialModel.commitAssignmentChanges(); |
3227 |
|
d_statistics.d_maxUnknownsInARow.maxAssign(d_unknownsInARow); |
3228 |
|
|
3229 |
|
if(useSimplex && options::collectPivots()){ |
3230 |
|
if(options::useFC()){ |
3231 |
|
d_statistics.d_unknownPivots << d_fcSimplex.getPivots(); |
3232 |
|
}else{ |
3233 |
|
d_statistics.d_unknownPivots << d_dualSimplex.getPivots(); |
3234 |
|
} |
3235 |
|
} |
3236 |
|
break; |
3237 |
40937 |
case Result::UNSAT: |
3238 |
40937 |
d_unknownsInARow = 0; |
3239 |
|
|
3240 |
40937 |
++d_statistics.d_commitsOnConflicts; |
3241 |
|
|
3242 |
81874 |
Debug("arith::bt") << "committing on conflict" |
3243 |
40937 |
<< " " << d_newFacts << " " << d_previousStatus << " " |
3244 |
40937 |
<< d_qflraStatus << endl; |
3245 |
40937 |
d_partialModel.commitAssignmentChanges(); |
3246 |
40937 |
revertOutOfConflict(); |
3247 |
|
|
3248 |
40937 |
if(Debug.isOn("arith::consistency::comitonconflict")){ |
3249 |
|
entireStateIsConsistent("commit on conflict"); |
3250 |
|
} |
3251 |
40937 |
outputConflicts(); |
3252 |
40937 |
emmittedConflictOrSplit = true; |
3253 |
40937 |
Debug("arith::conflict") << "simplex conflict" << endl; |
3254 |
|
|
3255 |
40937 |
if(useSimplex && options::collectPivots()){ |
3256 |
|
if(options::useFC()){ |
3257 |
|
d_statistics.d_unsatPivots << d_fcSimplex.getPivots(); |
3258 |
|
}else{ |
3259 |
|
d_statistics.d_unsatPivots << d_dualSimplex.getPivots(); |
3260 |
|
} |
3261 |
|
} |
3262 |
40937 |
break; |
3263 |
|
default: |
3264 |
|
Unimplemented(); |
3265 |
|
} |
3266 |
1695036 |
d_statistics.d_avgUnknownsInARow << d_unknownsInARow; |
3267 |
|
|
3268 |
|
size_t nPivots = |
3269 |
1695036 |
options::useFC() ? d_fcSimplex.getPivots() : d_dualSimplex.getPivots(); |
3270 |
1896794 |
for (std::size_t i = 0; i < nPivots; ++i) |
3271 |
|
{ |
3272 |
403516 |
d_containing.d_out->spendResource( |
3273 |
201758 |
Resource::ArithPivotStep); |
3274 |
|
} |
3275 |
|
|
3276 |
3390072 |
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit |
3277 |
1695036 |
<< "pre approx cuts" << endl; |
3278 |
1695036 |
if(!d_approxCuts.empty()){ |
3279 |
|
bool anyFresh = false; |
3280 |
|
while(!d_approxCuts.empty()){ |
3281 |
|
TrustNode lem = d_approxCuts.front(); |
3282 |
|
d_approxCuts.pop(); |
3283 |
|
Debug("arith::approx::cuts") << "approximate cut:" << lem << endl; |
3284 |
|
anyFresh = anyFresh || hasFreshArithLiteral(lem.getNode()); |
3285 |
|
Debug("arith::lemma") << "approximate cut:" << lem << endl; |
3286 |
|
outputTrustedLemma(lem, InferenceId::ARITH_APPROX_CUT); |
3287 |
|
} |
3288 |
|
if(anyFresh){ |
3289 |
|
emmittedConflictOrSplit = true; |
3290 |
|
} |
3291 |
|
} |
3292 |
|
|
3293 |
3390072 |
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit |
3294 |
1695036 |
<< "post approx cuts" << endl; |
3295 |
|
|
3296 |
|
// This should be fine if sat or unknown |
3297 |
3390072 |
if (!emmittedConflictOrSplit |
3298 |
3349135 |
&& (options::arithPropagationMode() |
3299 |
|
== options::ArithPropagationMode::UNATE_PROP |
3300 |
1654099 |
|| options::arithPropagationMode() |
3301 |
|
== options::ArithPropagationMode::BOTH_PROP)) |
3302 |
|
{ |
3303 |
3308198 |
TimerStat::CodeTimer codeTimer0(d_statistics.d_newPropTime); |
3304 |
1654099 |
Assert(d_qflraStatus != Result::UNSAT); |
3305 |
|
|
3306 |
7769223 |
while(!d_currentPropagationList.empty() && !anyConflict()){ |
3307 |
3057562 |
ConstraintP curr = d_currentPropagationList.front(); |
3308 |
3057562 |
d_currentPropagationList.pop_front(); |
3309 |
|
|
3310 |
3057562 |
ConstraintType t = curr->getType(); |
3311 |
3057562 |
Assert(t != Disequality) |
3312 |
|
<< "Disequalities are not allowed in d_currentPropagation"; |
3313 |
|
|
3314 |
3057562 |
switch(t){ |
3315 |
1131546 |
case LowerBound: |
3316 |
|
{ |
3317 |
1131546 |
ConstraintP prev = d_currentPropagationList.front(); |
3318 |
1131546 |
d_currentPropagationList.pop_front(); |
3319 |
1131546 |
d_constraintDatabase.unatePropLowerBound(curr, prev); |
3320 |
1131546 |
break; |
3321 |
|
} |
3322 |
1001772 |
case UpperBound: |
3323 |
|
{ |
3324 |
1001772 |
ConstraintP prev = d_currentPropagationList.front(); |
3325 |
1001772 |
d_currentPropagationList.pop_front(); |
3326 |
1001772 |
d_constraintDatabase.unatePropUpperBound(curr, prev); |
3327 |
1001772 |
break; |
3328 |
|
} |
3329 |
924244 |
case Equality: |
3330 |
|
{ |
3331 |
924244 |
ConstraintP prevLB = d_currentPropagationList.front(); |
3332 |
924244 |
d_currentPropagationList.pop_front(); |
3333 |
924244 |
ConstraintP prevUB = d_currentPropagationList.front(); |
3334 |
924244 |
d_currentPropagationList.pop_front(); |
3335 |
924244 |
d_constraintDatabase.unatePropEquality(curr, prevLB, prevUB); |
3336 |
924244 |
break; |
3337 |
|
} |
3338 |
|
default: Unhandled() << curr->getType(); |
3339 |
|
} |
3340 |
|
} |
3341 |
|
|
3342 |
1654099 |
if(anyConflict()){ |
3343 |
|
Debug("arith::unate") << "unate conflict" << endl; |
3344 |
|
revertOutOfConflict(); |
3345 |
|
d_qflraStatus = Result::UNSAT; |
3346 |
|
outputConflicts(); |
3347 |
|
emmittedConflictOrSplit = true; |
3348 |
|
//cout << "unate conflict " << endl; |
3349 |
|
Debug("arith::bt") << "committing on unate conflict" |
3350 |
|
<< " " << d_newFacts << " " << d_previousStatus << " " |
3351 |
|
<< d_qflraStatus << endl; |
3352 |
|
|
3353 |
|
Debug("arith::conflict") << "unate arith conflict" << endl; |
3354 |
|
} |
3355 |
|
} |
3356 |
|
else |
3357 |
|
{ |
3358 |
81874 |
TimerStat::CodeTimer codeTimer1(d_statistics.d_newPropTime); |
3359 |
40937 |
d_currentPropagationList.clear(); |
3360 |
|
} |
3361 |
1695036 |
Assert(d_currentPropagationList.empty()); |
3362 |
|
|
3363 |
3390072 |
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit |
3364 |
1695036 |
<< "post unate" << endl; |
3365 |
|
|
3366 |
1695036 |
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){ |
3367 |
65507 |
++d_fullCheckCounter; |
3368 |
|
} |
3369 |
1695036 |
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){ |
3370 |
65507 |
emmittedConflictOrSplit = splitDisequalities(); |
3371 |
|
} |
3372 |
3390072 |
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit |
3373 |
1695036 |
<< "pos splitting" << endl; |
3374 |
|
|
3375 |
|
|
3376 |
3390072 |
Debug("arith") << "integer? " |
3377 |
1695036 |
<< " conf/split " << emmittedConflictOrSplit |
3378 |
3390072 |
<< " fulleffort " << Theory::fullEffort(effortLevel) |
3379 |
1695036 |
<< " hasintmodel " << hasIntegerModel() << endl; |
3380 |
|
|
3381 |
1695036 |
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel) && !hasIntegerModel()){ |
3382 |
5422 |
Node possibleConflict = Node::null(); |
3383 |
2711 |
if(!emmittedConflictOrSplit && options::arithDioSolver()){ |
3384 |
2711 |
possibleConflict = callDioSolver(); |
3385 |
2711 |
if(possibleConflict != Node::null()){ |
3386 |
174 |
revertOutOfConflict(); |
3387 |
174 |
Debug("arith::conflict") << "dio conflict " << possibleConflict << endl; |
3388 |
|
// TODO (project #37): justify (proofs in the DIO solver) |
3389 |
174 |
raiseBlackBoxConflict(possibleConflict); |
3390 |
174 |
outputConflicts(); |
3391 |
174 |
emmittedConflictOrSplit = true; |
3392 |
|
} |
3393 |
|
} |
3394 |
|
|
3395 |
2711 |
if(!emmittedConflictOrSplit && d_hasDoneWorkSinceCut && options::arithDioSolver()){ |
3396 |
2537 |
if(getDioCuttingResource()){ |
3397 |
3766 |
TrustNode possibleLemma = dioCutting(); |
3398 |
1883 |
if(!possibleLemma.isNull()){ |
3399 |
1438 |
d_hasDoneWorkSinceCut = false; |
3400 |
1438 |
d_cutCount = d_cutCount + 1; |
3401 |
1438 |
Debug("arith::lemma") << "dio cut " << possibleLemma << endl; |
3402 |
1438 |
if (outputTrustedLemma(possibleLemma, InferenceId::ARITH_DIO_CUT)) |
3403 |
|
{ |
3404 |
1438 |
emmittedConflictOrSplit = true; |
3405 |
|
} |
3406 |
|
} |
3407 |
|
} |
3408 |
|
} |
3409 |
|
|
3410 |
2711 |
if(!emmittedConflictOrSplit) { |
3411 |
2198 |
TrustNode possibleLemma = roundRobinBranch(); |
3412 |
1099 |
if (!possibleLemma.getNode().isNull()) |
3413 |
|
{ |
3414 |
1099 |
++(d_statistics.d_externalBranchAndBounds); |
3415 |
1099 |
d_cutCount = d_cutCount + 1; |
3416 |
2198 |
Debug("arith::lemma") << "rrbranch lemma" |
3417 |
1099 |
<< possibleLemma << endl; |
3418 |
1099 |
if (outputTrustedLemma(possibleLemma, InferenceId::ARITH_BB_LEMMA)) |
3419 |
|
{ |
3420 |
1097 |
emmittedConflictOrSplit = true; |
3421 |
|
} |
3422 |
|
} |
3423 |
|
} |
3424 |
|
|
3425 |
2711 |
if(options::maxCutsInContext() <= d_cutCount){ |
3426 |
|
if(d_diosolver.hasMoreDecompositionLemmas()){ |
3427 |
|
while(d_diosolver.hasMoreDecompositionLemmas()){ |
3428 |
|
Node decompositionLemma = d_diosolver.nextDecompositionLemma(); |
3429 |
|
Debug("arith::lemma") << "dio decomposition lemma " |
3430 |
|
<< decompositionLemma << endl; |
3431 |
|
outputLemma(decompositionLemma, InferenceId::ARITH_DIO_DECOMPOSITION); |
3432 |
|
} |
3433 |
|
}else{ |
3434 |
|
Debug("arith::restart") << "arith restart!" << endl; |
3435 |
|
outputRestart(); |
3436 |
|
} |
3437 |
|
} |
3438 |
|
}//if !emmittedConflictOrSplit && fullEffort(effortLevel) && !hasIntegerModel() |
3439 |
|
|
3440 |
1695036 |
if(Theory::fullEffort(effortLevel)){ |
3441 |
72488 |
if(Debug.isOn("arith::consistency::final")){ |
3442 |
|
entireStateIsConsistent("arith::consistency::final"); |
3443 |
|
} |
3444 |
|
} |
3445 |
|
|
3446 |
1695036 |
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); } |
3447 |
1695036 |
if(Debug.isOn("arith::print_model")) { |
3448 |
|
debugPrintModel(Debug("arith::print_model")); |
3449 |
|
} |
3450 |
1695036 |
Debug("arith") << "TheoryArithPrivate::check end" << std::endl; |
3451 |
1695036 |
return emmittedConflictOrSplit; |
3452 |
|
} |
3453 |
|
|
3454 |
28534 |
bool TheoryArithPrivate::foundNonlinear() const { return d_foundNl; } |
3455 |
|
|
3456 |
1099 |
TrustNode TheoryArithPrivate::branchIntegerVariable(ArithVar x) const |
3457 |
|
{ |
3458 |
1099 |
const DeltaRational& d = d_partialModel.getAssignment(x); |
3459 |
1099 |
Assert(!d.isIntegral()); |
3460 |
1099 |
const Rational& r = d.getNoninfinitesimalPart(); |
3461 |
1099 |
const Rational& i = d.getInfinitesimalPart(); |
3462 |
1099 |
Trace("integers") << "integers: assignment to [[" << d_partialModel.asNode(x) << "]] is " << r << "[" << i << "]" << endl; |
3463 |
1099 |
Assert(!(r.getDenominator() == 1 && i.getNumerator() == 0)); |
3464 |
2198 |
TNode var = d_partialModel.asNode(x); |
3465 |
1099 |
TrustNode lem = d_bab.branchIntegerVariable(var, r); |
3466 |
1099 |
if (Debug.isOn("integers")) |
3467 |
|
{ |
3468 |
|
Node l = lem.getNode(); |
3469 |
|
if (isSatLiteral(l[0])) |
3470 |
|
{ |
3471 |
|
Debug("integers") << " " << l[0] << " == " << getSatValue(l[0]) |
3472 |
|
<< endl; |
3473 |
|
} |
3474 |
|
else |
3475 |
|
{ |
3476 |
|
Debug("integers") << " " << l[0] << " is not assigned a SAT literal" |
3477 |
|
<< endl; |
3478 |
|
} |
3479 |
|
if (isSatLiteral(l[1])) |
3480 |
|
{ |
3481 |
|
Debug("integers") << " " << l[1] << " == " << getSatValue(l[1]) |
3482 |
|
<< endl; |
3483 |
|
} |
3484 |
|
else |
3485 |
|
{ |
3486 |
|
Debug("integers") << " " << l[1] << " is not assigned a SAT literal" |
3487 |
|
<< endl; |
3488 |
|
} |
3489 |
|
} |
3490 |
2198 |
return lem; |
3491 |
|
} |
3492 |
|
|
3493 |
|
std::vector<ArithVar> TheoryArithPrivate::cutAllBounded() const{ |
3494 |
|
vector<ArithVar> lemmas; |
3495 |
|
ArithVar max = d_partialModel.getNumberOfVariables(); |
3496 |
|
|
3497 |
|
if(options::doCutAllBounded() && max > 0){ |
3498 |
|
for(ArithVar iter = 0; iter != max; ++iter){ |
3499 |
|
//Do not include slack variables |
3500 |
|
const DeltaRational& d = d_partialModel.getAssignment(iter); |
3501 |
|
if(isIntegerInput(iter) && |
3502 |
|
!d_cutInContext.contains(iter) && |
3503 |
|
d_partialModel.hasUpperBound(iter) && |
3504 |
|
d_partialModel.hasLowerBound(iter) && |
3505 |
|
!d.isIntegral()){ |
3506 |
|
lemmas.push_back(iter); |
3507 |
|
} |
3508 |
|
} |
3509 |
|
} |
3510 |
|
return lemmas; |
3511 |
|
} |
3512 |
|
|
3513 |
|
/** Returns true if the roundRobinBranching() issues a lemma. */ |
3514 |
1099 |
TrustNode TheoryArithPrivate::roundRobinBranch() |
3515 |
|
{ |
3516 |
1099 |
if(hasIntegerModel()){ |
3517 |
|
return TrustNode::null(); |
3518 |
|
}else{ |
3519 |
1099 |
ArithVar v = d_nextIntegerCheckVar; |
3520 |
|
|
3521 |
1099 |
Assert(isInteger(v)); |
3522 |
1099 |
Assert(!isAuxiliaryVariable(v)); |
3523 |
1099 |
return branchIntegerVariable(v); |
3524 |
|
} |
3525 |
|
} |
3526 |
|
|
3527 |
65507 |
bool TheoryArithPrivate::splitDisequalities(){ |
3528 |
65507 |
bool splitSomething = false; |
3529 |
|
|
3530 |
131014 |
vector<ConstraintP> save; |
3531 |
|
|
3532 |
565303 |
while(!d_diseqQueue.empty()){ |
3533 |
249898 |
ConstraintP front = d_diseqQueue.front(); |
3534 |
249898 |
d_diseqQueue.pop(); |
3535 |
|
|
3536 |
249898 |
if(front->isSplit()){ |
3537 |
205 |
Debug("arith::eq") << "split already" << endl; |
3538 |
|
}else{ |
3539 |
249693 |
Debug("arith::eq") << "not split already" << endl; |
3540 |
|
|
3541 |
249693 |
ArithVar lhsVar = front->getVariable(); |
3542 |
|
|
3543 |
249693 |
const DeltaRational& lhsValue = d_partialModel.getAssignment(lhsVar); |
3544 |
249693 |
const DeltaRational& rhsValue = front->getValue(); |
3545 |
249693 |
if(lhsValue == rhsValue){ |
3546 |
215 |
Debug("arith::lemma") << "Splitting on " << front << endl; |
3547 |
215 |
Debug("arith::lemma") << "LHS value = " << lhsValue << endl; |
3548 |
215 |
Debug("arith::lemma") << "RHS value = " << rhsValue << endl; |
3549 |
430 |
TrustNode lemma = front->split(); |
3550 |
215 |
++(d_statistics.d_statDisequalitySplits); |
3551 |
|
|
3552 |
430 |
Debug("arith::lemma") |
3553 |
215 |
<< "Now " << Rewriter::rewrite(lemma.getNode()) << endl; |
3554 |
215 |
outputTrustedLemma(lemma, InferenceId::ARITH_SPLIT_DEQ); |
3555 |
|
//cout << "Now " << Rewriter::rewrite(lemma) << endl; |
3556 |
215 |
splitSomething = true; |
3557 |
249478 |
}else if(d_partialModel.strictlyLessThanLowerBound(lhsVar, rhsValue)){ |
3558 |
45840 |
Debug("arith::eq") << "can drop as less than lb" << front << endl; |
3559 |
203638 |
}else if(d_partialModel.strictlyGreaterThanUpperBound(lhsVar, rhsValue)){ |
3560 |
21572 |
Debug("arith::eq") << "can drop as greater than ub" << front << endl; |
3561 |
|
}else{ |
3562 |
182066 |
Debug("arith::eq") << "save" << front << ": " <<lhsValue << " != " << rhsValue << endl; |
3563 |
182066 |
save.push_back(front); |
3564 |
|
} |
3565 |
|
} |
3566 |
|
} |
3567 |
65507 |
vector<ConstraintP>::const_iterator i=save.begin(), i_end = save.end(); |
3568 |
429639 |
for(; i != i_end; ++i){ |
3569 |
182066 |
d_diseqQueue.push(*i); |
3570 |
|
} |
3571 |
131014 |
return splitSomething; |
3572 |
|
} |
3573 |
|
|
3574 |
|
/** |
3575 |
|
* Should be guarded by at least Debug.isOn("arith::print_assertions"). |
3576 |
|
* Prints to Debug("arith::print_assertions") |
3577 |
|
*/ |
3578 |
|
void TheoryArithPrivate::debugPrintAssertions(std::ostream& out) const { |
3579 |
|
out << "Assertions:" << endl; |
3580 |
|
for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ |
3581 |
|
ArithVar i = *vi; |
3582 |
|
if (d_partialModel.hasLowerBound(i)) { |
3583 |
|
ConstraintP lConstr = d_partialModel.getLowerBoundConstraint(i); |
3584 |
|
out << lConstr << endl; |
3585 |
|
} |
3586 |
|
|
3587 |
|
if (d_partialModel.hasUpperBound(i)) { |
3588 |
|
ConstraintP uConstr = d_partialModel.getUpperBoundConstraint(i); |
3589 |
|
out << uConstr << endl; |
3590 |
|
} |
3591 |
|
} |
3592 |
|
context::CDQueue<ConstraintP>::const_iterator it = d_diseqQueue.begin(); |
3593 |
|
context::CDQueue<ConstraintP>::const_iterator it_end = d_diseqQueue.end(); |
3594 |
|
for(; it != it_end; ++ it) { |
3595 |
|
out << *it << endl; |
3596 |
|
} |
3597 |
|
} |
3598 |
|
|
3599 |
|
void TheoryArithPrivate::debugPrintModel(std::ostream& out) const{ |
3600 |
|
out << "Model:" << endl; |
3601 |
|
for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ |
3602 |
|
ArithVar i = *vi; |
3603 |
|
if(d_partialModel.hasNode(i)){ |
3604 |
|
out << d_partialModel.asNode(i) << " : " << |
3605 |
|
d_partialModel.getAssignment(i); |
3606 |
|
if(d_tableau.isBasic(i)){ |
3607 |
|
out << " (basic)"; |
3608 |
|
} |
3609 |
|
out << endl; |
3610 |
|
} |
3611 |
|
} |
3612 |
|
} |
3613 |
|
|
3614 |
28310 |
TrustNode TheoryArithPrivate::explain(TNode n) |
3615 |
|
{ |
3616 |
28310 |
Debug("arith::explain") << "explain @" << getSatContext()->getLevel() << ": " << n << endl; |
3617 |
|
|
3618 |
28310 |
ConstraintP c = d_constraintDatabase.lookup(n); |
3619 |
28310 |
TrustNode exp; |
3620 |
28310 |
if(c != NullConstraint){ |
3621 |
9991 |
Assert(!c->isAssumption()); |
3622 |
9991 |
exp = c->externalExplainForPropagation(n); |
3623 |
9991 |
Debug("arith::explain") << "constraint explanation" << n << ":" << exp << endl; |
3624 |
18319 |
}else if(d_assertionsThatDoNotMatchTheirLiterals.find(n) != d_assertionsThatDoNotMatchTheirLiterals.end()){ |
3625 |
14821 |
c = d_assertionsThatDoNotMatchTheirLiterals[n]; |
3626 |
14821 |
if(!c->isAssumption()){ |
3627 |
4551 |
exp = c->externalExplainForPropagation(n); |
3628 |
4551 |
Debug("arith::explain") << "assertions explanation" << n << ":" << exp << endl; |
3629 |
|
}else{ |
3630 |
10270 |
Debug("arith::explain") << "this is a strange mismatch" << n << endl; |
3631 |
10270 |
Assert(d_congruenceManager.canExplain(n)); |
3632 |
10270 |
exp = d_congruenceManager.explain(n); |
3633 |
|
} |
3634 |
|
}else{ |
3635 |
3498 |
Assert(d_congruenceManager.canExplain(n)); |
3636 |
3498 |
Debug("arith::explain") << "dm explanation" << n << endl; |
3637 |
3498 |
exp = d_congruenceManager.explain(n); |
3638 |
|
} |
3639 |
28310 |
return exp; |
3640 |
|
} |
3641 |
|
|
3642 |
2721464 |
void TheoryArithPrivate::propagate(Theory::Effort e) { |
3643 |
|
// This uses model values for safety. Disable for now. |
3644 |
5442928 |
if (d_qflraStatus == Result::SAT |
3645 |
2694712 |
&& (options::arithPropagationMode() |
3646 |
|
== options::ArithPropagationMode::BOUND_INFERENCE_PROP |
3647 |
2694712 |
|| options::arithPropagationMode() |
3648 |
|
== options::ArithPropagationMode::BOTH_PROP) |
3649 |
5416176 |
&& hasAnyUpdates()) |
3650 |
|
{ |
3651 |
1050891 |
if(options::newProp()){ |
3652 |
1048339 |
propagateCandidatesNew(); |
3653 |
|
}else{ |
3654 |
2552 |
propagateCandidates(); |
3655 |
|
} |
3656 |
|
} |
3657 |
|
else |
3658 |
|
{ |
3659 |
1670573 |
clearUpdates(); |
3660 |
|
} |
3661 |
|
|
3662 |
4195756 |
while(d_constraintDatabase.hasMorePropagations()){ |
3663 |
737146 |
ConstraintCP c = d_constraintDatabase.nextPropagation(); |
3664 |
737146 |
Debug("arith::prop") << "next prop" << getSatContext()->getLevel() << ": " << c << endl; |
3665 |
|
|
3666 |
737146 |
if(c->negationHasProof()){ |
3667 |
|
Debug("arith::prop") << "negation has proof " << c->getNegation() << endl; |
3668 |
|
Debug("arith::prop") << c->getNegation()->externalExplainByAssertions() |
3669 |
|
<< endl; |
3670 |
|
} |
3671 |
737146 |
Assert(!c->negationHasProof()) |
3672 |
|
<< "A constraint has been propagated on the constraint propagation " |
3673 |
|
"queue, but the negation has been set to true. Contact Tim now!"; |
3674 |
|
|
3675 |
737146 |
if(!c->assertedToTheTheory()){ |
3676 |
1434226 |
Node literal = c->getLiteral(); |
3677 |
717113 |
Debug("arith::prop") << "propagating @" << getSatContext()->getLevel() << " " << literal << endl; |
3678 |
|
|
3679 |
717113 |
outputPropagate(literal); |
3680 |
|
}else{ |
3681 |
20033 |
Debug("arith::prop") << "already asserted to the theory " << c->getLiteral() << endl; |
3682 |
|
} |
3683 |
|
} |
3684 |
|
|
3685 |
4125040 |
while(d_congruenceManager.hasMorePropagations()){ |
3686 |
1403576 |
TNode toProp = d_congruenceManager.getNextPropagation(); |
3687 |
|
|
3688 |
|
//Currently if the flag is set this came from an equality detected by the |
3689 |
|
//equality engine in the the difference manager. |
3690 |
1403576 |
Node normalized = Rewriter::rewrite(toProp); |
3691 |
|
|
3692 |
701788 |
ConstraintP constraint = d_constraintDatabase.lookup(normalized); |
3693 |
701788 |
if(constraint == NullConstraint){ |
3694 |
147 |
Debug("arith::prop") << "propagating on non-constraint? " << toProp << endl; |
3695 |
|
|
3696 |
147 |
outputPropagate(toProp); |
3697 |
701641 |
}else if(constraint->negationHasProof()){ |
3698 |
|
// The congruence manager can prove: antecedents => toProp, |
3699 |
|
// ergo. antecedents ^ ~toProp is a conflict. |
3700 |
|
TrustNode exp = d_congruenceManager.explain(toProp); |
3701 |
|
Node notNormalized = normalized.negate(); |
3702 |
|
std::vector<Node> ants(exp.getNode().begin(), exp.getNode().end()); |
3703 |
|
ants.push_back(notNormalized); |
3704 |
|
Node lp = safeConstructNary(kind::AND, ants); |
3705 |
|
Debug("arith::prop") << "propagate conflict" << lp << endl; |
3706 |
|
if (proofsEnabled()) |
3707 |
|
{ |
3708 |
|
// Assume all of antecedents and ~toProp (rewritten) |
3709 |
|
std::vector<Pf> pfAntList; |
3710 |
|
for (size_t i = 0; i < ants.size(); ++i) |
3711 |
|
{ |
3712 |
|
pfAntList.push_back(d_pnm->mkAssume(ants[i])); |
3713 |
|
} |
3714 |
|
Pf pfAnt = pfAntList.size() > 1 |
3715 |
|
? d_pnm->mkNode(PfRule::AND_INTRO, pfAntList, {}) |
3716 |
|
: pfAntList[0]; |
3717 |
|
// Use modus ponens to get toProp (un rewritten) |
3718 |
|
Pf pfConc = d_pnm->mkNode( |
3719 |
|
PfRule::MODUS_PONENS, |
3720 |
|
{pfAnt, exp.getGenerator()->getProofFor(exp.getProven())}, |
3721 |
|
{}); |
3722 |
|
// prove toProp (rewritten) |
3723 |
|
Pf pfConcRewritten = d_pnm->mkNode( |
3724 |
|
PfRule::MACRO_SR_PRED_TRANSFORM, {pfConc}, {normalized}); |
3725 |
|
Pf pfNotNormalized = d_pnm->mkAssume(notNormalized); |
3726 |
|
// prove bottom from toProp and ~toProp |
3727 |
|
Pf pfBot; |
3728 |
|
if (normalized.getKind() == kind::NOT) |
3729 |
|
{ |
3730 |
|
pfBot = d_pnm->mkNode( |
3731 |
|
PfRule::CONTRA, {pfNotNormalized, pfConcRewritten}, {}); |
3732 |
|
} |
3733 |
|
else |
3734 |
|
{ |
3735 |
|
pfBot = d_pnm->mkNode( |
3736 |
|
PfRule::CONTRA, {pfConcRewritten, pfNotNormalized}, {}); |
3737 |
|
} |
3738 |
|
// close scope |
3739 |
|
Pf pfNotAnd = d_pnm->mkScope(pfBot, ants); |
3740 |
|
raiseBlackBoxConflict(lp, pfNotAnd); |
3741 |
|
} |
3742 |
|
else |
3743 |
|
{ |
3744 |
|
raiseBlackBoxConflict(lp); |
3745 |
|
} |
3746 |
|
outputConflicts(); |
3747 |
|
return; |
3748 |
|
}else{ |
3749 |
701641 |
Debug("arith::prop") << "propagating still?" << toProp << endl; |
3750 |
701641 |
outputPropagate(toProp); |
3751 |
|
} |
3752 |
|
} |
3753 |
|
} |
3754 |
|
|
3755 |
6145412 |
DeltaRational TheoryArithPrivate::getDeltaValue(TNode term) const |
3756 |
|
{ |
3757 |
6145412 |
AlwaysAssert(d_qflraStatus != Result::SAT_UNKNOWN); |
3758 |
6145412 |
Debug("arith::value") << term << std::endl; |
3759 |
|
|
3760 |
6145412 |
if (d_partialModel.hasArithVar(term)) { |
3761 |
1899509 |
ArithVar var = d_partialModel.asArithVar(term); |
3762 |
1899509 |
return d_partialModel.getAssignment(var); |
3763 |
|
} |
3764 |
|
|
3765 |
4245903 |
switch (Kind kind = term.getKind()) { |
3766 |
2405733 |
case kind::CONST_RATIONAL: |
3767 |
2405733 |
return term.getConst<Rational>(); |
3768 |
|
|
3769 |
1340184 |
case kind::PLUS: { // 2+ args |
3770 |
2680368 |
DeltaRational value(0); |
3771 |
4337224 |
for (TNode::iterator i = term.begin(), iend = term.end(); i != iend; |
3772 |
|
++i) { |
3773 |
2997040 |
value = value + getDeltaValue(*i); |
3774 |
|
} |
3775 |
1340184 |
return value; |
3776 |
|
} |
3777 |
|
|
3778 |
499986 |
case kind::NONLINEAR_MULT: |
3779 |
|
case kind::MULT: { // 2+ args |
3780 |
499986 |
Assert(!isSetup(term)); |
3781 |
999972 |
DeltaRational value(1); |
3782 |
1499958 |
for (TNode::iterator i = term.begin(), iend = term.end(); i != iend; |
3783 |
|
++i) { |
3784 |
999972 |
value = value * getDeltaValue(*i); |
3785 |
|
} |
3786 |
499986 |
return value; |
3787 |
|
} |
3788 |
|
case kind::MINUS: { // 2 args |
3789 |
|
return getDeltaValue(term[0]) - getDeltaValue(term[1]); |
3790 |
|
} |
3791 |
|
case kind::UMINUS: { // 1 arg |
3792 |
|
return (-getDeltaValue(term[0])); |
3793 |
|
} |
3794 |
|
|
3795 |
|
case kind::DIVISION: { // 2 args |
3796 |
|
Assert(!isSetup(term)); |
3797 |
|
return getDeltaValue(term[0]) / getDeltaValue(term[1]); |
3798 |
|
} |
3799 |
|
case kind::DIVISION_TOTAL: |
3800 |
|
case kind::INTS_DIVISION_TOTAL: |
3801 |
|
case kind::INTS_MODULUS_TOTAL: { // 2 args |
3802 |
|
Assert(!isSetup(term)); |
3803 |
|
DeltaRational denominator = getDeltaValue(term[1]); |
3804 |
|
if (denominator.isZero()) { |
3805 |
|
return DeltaRational(0, 0); |
3806 |
|
} |
3807 |
|
DeltaRational numerator = getDeltaValue(term[0]); |
3808 |
|
if (kind == kind::DIVISION_TOTAL) { |
3809 |
|
return numerator / denominator; |
3810 |
|
} else if (kind == kind::INTS_DIVISION_TOTAL) { |
3811 |
|
return Rational(numerator.euclidianDivideQuotient(denominator)); |
3812 |
|
} else { |
3813 |
|
Assert(kind == kind::INTS_MODULUS_TOTAL); |
3814 |
|
return Rational(numerator.euclidianDivideRemainder(denominator)); |
3815 |
|
} |
3816 |
|
} |
3817 |
|
|
3818 |
|
default: |
3819 |
|
throw ModelException(term, "No model assignment."); |
3820 |
|
} |
3821 |
|
} |
3822 |
|
|
3823 |
12708 |
Rational TheoryArithPrivate::deltaValueForTotalOrder() const{ |
3824 |
25416 |
Rational min(2); |
3825 |
25416 |
std::set<DeltaRational> relevantDeltaValues; |
3826 |
12708 |
context::CDQueue<ConstraintP>::const_iterator qiter = d_diseqQueue.begin(); |
3827 |
12708 |
context::CDQueue<ConstraintP>::const_iterator qiter_end = d_diseqQueue.end(); |
3828 |
|
|
3829 |
64208 |
for(; qiter != qiter_end; ++qiter){ |
3830 |
25750 |
ConstraintP curr = *qiter; |
3831 |
|
|
3832 |
25750 |
const DeltaRational& rhsValue = curr->getValue(); |
3833 |
25750 |
relevantDeltaValues.insert(rhsValue); |
3834 |
|
} |
3835 |
|
|
3836 |
12708 |
Theory::shared_terms_iterator shared_iter = d_containing.shared_terms_begin(); |
3837 |
12708 |
Theory::shared_terms_iterator shared_end = d_containing.shared_terms_end(); |
3838 |
529300 |
for(; shared_iter != shared_end; ++shared_iter){ |
3839 |
516592 |
Node sharedCurr = *shared_iter; |
3840 |
|
|
3841 |
|
// ModelException is fatal as this point. Don't catch! |
3842 |
|
// DeltaRationalException is fatal as this point. Don't catch! |
3843 |
516592 |
DeltaRational val = getDeltaValue(sharedCurr); |
3844 |
258296 |
relevantDeltaValues.insert(val); |
3845 |
|
} |
3846 |
|
|
3847 |
595947 |
for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ |
3848 |
583239 |
ArithVar v = *vi; |
3849 |
583239 |
const DeltaRational& value = d_partialModel.getAssignment(v); |
3850 |
583239 |
relevantDeltaValues.insert(value); |
3851 |
583239 |
if( d_partialModel.hasLowerBound(v)){ |
3852 |
349895 |
const DeltaRational& lb = d_partialModel.getLowerBound(v); |
3853 |
349895 |
relevantDeltaValues.insert(lb); |
3854 |
|
} |
3855 |
583239 |
if( d_partialModel.hasUpperBound(v)){ |
3856 |
282765 |
const DeltaRational& ub = d_partialModel.getUpperBound(v); |
3857 |
282765 |
relevantDeltaValues.insert(ub); |
3858 |
|
} |
3859 |
|
} |
3860 |
|
|
3861 |
12708 |
if(relevantDeltaValues.size() >= 2){ |
3862 |
10823 |
std::set<DeltaRational>::const_iterator iter = relevantDeltaValues.begin(); |
3863 |
10823 |
std::set<DeltaRational>::const_iterator iter_end = relevantDeltaValues.end(); |
3864 |
21646 |
DeltaRational prev = *iter; |
3865 |
10823 |
++iter; |
3866 |
277517 |
for(; iter != iter_end; ++iter){ |
3867 |
133347 |
const DeltaRational& curr = *iter; |
3868 |
|
|
3869 |
133347 |
Assert(prev < curr); |
3870 |
|
|
3871 |
133347 |
DeltaRational::seperatingDelta(min, prev, curr); |
3872 |
133347 |
prev = curr; |
3873 |
|
} |
3874 |
|
} |
3875 |
|
|
3876 |
12708 |
Assert(min.sgn() > 0); |
3877 |
12708 |
Rational belowMin = min/Rational(2); |
3878 |
25416 |
return belowMin; |
3879 |
|
} |
3880 |
|
|
3881 |
14565 |
void TheoryArithPrivate::collectModelValues(const std::set<Node>& termSet, |
3882 |
|
std::map<Node, Node>& arithModel) |
3883 |
|
{ |
3884 |
14565 |
AlwaysAssert(d_qflraStatus == Result::SAT); |
3885 |
|
|
3886 |
14565 |
if(Debug.isOn("arith::collectModelInfo")){ |
3887 |
|
debugPrintFacts(); |
3888 |
|
} |
3889 |
|
|
3890 |
14565 |
Debug("arith::collectModelInfo") << "collectModelInfo() begin " << endl; |
3891 |
|
|
3892 |
|
// Delta lasts at least the duration of the function call |
3893 |
14565 |
const Rational& delta = d_partialModel.getDelta(); |
3894 |
29130 |
std::unordered_set<TNode> shared = d_containing.currentlySharedTerms(); |
3895 |
|
|
3896 |
|
// TODO: |
3897 |
|
// This is not very good for user push/pop.... |
3898 |
|
// Revisit when implementing push/pop |
3899 |
593113 |
for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ |
3900 |
578548 |
ArithVar v = *vi; |
3901 |
|
|
3902 |
578548 |
if(!isAuxiliaryVariable(v)){ |
3903 |
505008 |
Node term = d_partialModel.asNode(v); |
3904 |
|
|
3905 |
929342 |
if((theoryOf(term) == THEORY_ARITH || shared.find(term) != shared.end()) |
3906 |
1004892 |
&& termSet.find(term) != termSet.end()){ |
3907 |
|
|
3908 |
241436 |
const DeltaRational& mod = d_partialModel.getAssignment(v); |
3909 |
482872 |
Rational qmodel = mod.substituteDelta(delta); |
3910 |
|
|
3911 |
482872 |
Node qNode = mkRationalNode(qmodel); |
3912 |
241436 |
Debug("arith::collectModelInfo") << "m->assertEquality(" << term << ", " << qmodel << ", true)" << endl; |
3913 |
|
// Add to the map |
3914 |
241436 |
arithModel[term] = qNode; |
3915 |
|
}else{ |
3916 |
11068 |
Debug("arith::collectModelInfo") << "Skipping m->assertEquality(" << term << ", true)" << endl; |
3917 |
|
|
3918 |
|
} |
3919 |
|
} |
3920 |
|
} |
3921 |
|
|
3922 |
|
// Iterate over equivalence classes in LinearEqualityModule |
3923 |
|
// const eq::EqualityEngine& ee = d_congruenceManager.getEqualityEngine(); |
3924 |
|
// m->assertEqualityEngine(&ee); |
3925 |
|
|
3926 |
14565 |
Debug("arith::collectModelInfo") << "collectModelInfo() end " << endl; |
3927 |
14565 |
} |
3928 |
|
|
3929 |
|
bool TheoryArithPrivate::safeToReset() const { |
3930 |
|
Assert(!d_tableauSizeHasBeenModified); |
3931 |
|
Assert(d_errorSet.noSignals()); |
3932 |
|
|
3933 |
|
ErrorSet::error_iterator error_iter = d_errorSet.errorBegin(); |
3934 |
|
ErrorSet::error_iterator error_end = d_errorSet.errorEnd(); |
3935 |
|
for(; error_iter != error_end; ++error_iter){ |
3936 |
|
ArithVar basic = *error_iter; |
3937 |
|
if(!d_smallTableauCopy.isBasic(basic)){ |
3938 |
|
return false; |
3939 |
|
} |
3940 |
|
} |
3941 |
|
|
3942 |
|
return true; |
3943 |
|
} |
3944 |
|
|
3945 |
1724 |
void TheoryArithPrivate::notifyRestart(){ |
3946 |
3448 |
TimerStat::CodeTimer codeTimer(d_statistics.d_restartTimer); |
3947 |
|
|
3948 |
1724 |
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); } |
3949 |
|
|
3950 |
1724 |
++d_restartsCounter; |
3951 |
1724 |
d_solveIntMaybeHelp = 0; |
3952 |
1724 |
d_solveIntAttempts = 0; |
3953 |
1724 |
} |
3954 |
|
|
3955 |
|
bool TheoryArithPrivate::entireStateIsConsistent(const string& s){ |
3956 |
|
bool result = true; |
3957 |
|
for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ |
3958 |
|
ArithVar var = *vi; |
3959 |
|
//ArithVar var = d_partialModel.asArithVar(*i); |
3960 |
|
if(!d_partialModel.assignmentIsConsistent(var)){ |
3961 |
|
d_partialModel.printModel(var); |
3962 |
|
Warning() << s << ":" << "Assignment is not consistent for " << var << d_partialModel.asNode(var); |
3963 |
|
if(d_tableau.isBasic(var)){ |
3964 |
|
Warning() << " (basic)"; |
3965 |
|
} |
3966 |
|
Warning() << endl; |
3967 |
|
result = false; |
3968 |
|
}else if(d_partialModel.isInteger(var) && !d_partialModel.integralAssignment(var)){ |
3969 |
|
d_partialModel.printModel(var); |
3970 |
|
Warning() << s << ":" << "Assignment is not integer for integer variable " << var << d_partialModel.asNode(var); |
3971 |
|
if(d_tableau.isBasic(var)){ |
3972 |
|
Warning() << " (basic)"; |
3973 |
|
} |
3974 |
|
Warning() << endl; |
3975 |
|
result = false; |
3976 |
|
} |
3977 |
|
} |
3978 |
|
return result; |
3979 |
|
} |
3980 |
|
|
3981 |
|
bool TheoryArithPrivate::unenqueuedVariablesAreConsistent(){ |
3982 |
|
bool result = true; |
3983 |
|
for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){ |
3984 |
|
ArithVar var = *vi; |
3985 |
|
if(!d_partialModel.assignmentIsConsistent(var)){ |
3986 |
|
if(!d_errorSet.inError(var)){ |
3987 |
|
|
3988 |
|
d_partialModel.printModel(var); |
3989 |
|
Warning() << "Unenqueued var is not consistent for " << var << d_partialModel.asNode(var); |
3990 |
|
if(d_tableau.isBasic(var)){ |
3991 |
|
Warning() << " (basic)"; |
3992 |
|
} |
3993 |
|
Warning() << endl; |
3994 |
|
result = false; |
3995 |
|
} else if(Debug.isOn("arith::consistency::initial")){ |
3996 |
|
d_partialModel.printModel(var); |
3997 |
|
Warning() << "Initial var is not consistent for " << var << d_partialModel.asNode(var); |
3998 |
|
if(d_tableau.isBasic(var)){ |
3999 |
|
Warning() << " (basic)"; |
4000 |
|
} |
4001 |
|
Warning() << endl; |
4002 |
|
} |
4003 |
|
} |
4004 |
|
} |
4005 |
|
return result; |
4006 |
|
} |
4007 |
|
|
4008 |
15204 |
void TheoryArithPrivate::presolve(){ |
4009 |
30408 |
TimerStat::CodeTimer codeTimer(d_statistics.d_presolveTime); |
4010 |
|
|
4011 |
15204 |
d_statistics.d_initialTableauSize = d_tableau.size(); |
4012 |
|
|
4013 |
15204 |
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); } |
4014 |
|
|
4015 |
|
static thread_local unsigned callCount = 0; |
4016 |
15204 |
if(Debug.isOn("arith::presolve")) { |
4017 |
|
Debug("arith::presolve") << "TheoryArithPrivate::presolve #" << callCount << endl; |
4018 |
|
callCount = callCount + 1; |
4019 |
|
} |
4020 |
|
|
4021 |
30408 |
vector<TrustNode> lemmas; |
4022 |
15204 |
if(!options::incrementalSolving()) { |
4023 |
7634 |
switch(options::arithUnateLemmaMode()){ |
4024 |
|
case options::ArithUnateLemmaMode::NO: break; |
4025 |
|
case options::ArithUnateLemmaMode::INEQUALITY: |
4026 |
|
d_constraintDatabase.outputUnateInequalityLemmas(lemmas); |
4027 |
|
break; |
4028 |
|
case options::ArithUnateLemmaMode::EQUALITY: |
4029 |
|
d_constraintDatabase.outputUnateEqualityLemmas(lemmas); |
4030 |
|
break; |
4031 |
7634 |
case options::ArithUnateLemmaMode::ALL: |
4032 |
7634 |
d_constraintDatabase.outputUnateInequalityLemmas(lemmas); |
4033 |
7634 |
d_constraintDatabase.outputUnateEqualityLemmas(lemmas); |
4034 |
7634 |
break; |
4035 |
|
default: Unhandled() << options::arithUnateLemmaMode(); |
4036 |
|
} |
4037 |
|
} |
4038 |
|
|
4039 |
15204 |
vector<TrustNode>::const_iterator i = lemmas.begin(), i_end = lemmas.end(); |
4040 |
95686 |
for(; i != i_end; ++i){ |
4041 |
80482 |
TrustNode lem = *i; |
4042 |
40241 |
Debug("arith::oldprop") << " lemma lemma duck " <<lem << endl; |
4043 |
40241 |
outputTrustedLemma(lem, InferenceId::ARITH_UNATE); |
4044 |
|
} |
4045 |
15204 |
} |
4046 |
|
|
4047 |
943626 |
EqualityStatus TheoryArithPrivate::getEqualityStatus(TNode a, TNode b) { |
4048 |
943626 |
if(d_qflraStatus == Result::SAT_UNKNOWN){ |
4049 |
|
return EQUALITY_UNKNOWN; |
4050 |
|
}else{ |
4051 |
|
try { |
4052 |
943626 |
if (getDeltaValue(a) == getDeltaValue(b)) { |
4053 |
97425 |
return EQUALITY_TRUE_IN_MODEL; |
4054 |
|
} else { |
4055 |
846201 |
return EQUALITY_FALSE_IN_MODEL; |
4056 |
|
} |
4057 |
|
} catch (DeltaRationalException& dr) { |
4058 |
|
return EQUALITY_UNKNOWN; |
4059 |
|
} catch (ModelException& me) { |
4060 |
|
return EQUALITY_UNKNOWN; |
4061 |
|
} |
4062 |
|
} |
4063 |
|
} |
4064 |
|
|
4065 |
1746 |
bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound){ |
4066 |
1746 |
++d_statistics.d_boundComputations; |
4067 |
|
|
4068 |
1746 |
RowIndex ridx = d_tableau.basicToRowIndex(basic); |
4069 |
3492 |
DeltaRational bound = d_linEq.computeRowBound(ridx, upperBound, basic); |
4070 |
|
|
4071 |
4504 |
if((upperBound && d_partialModel.strictlyLessThanUpperBound(basic, bound)) || |
4072 |
2048 |
(!upperBound && d_partialModel.strictlyGreaterThanLowerBound(basic, bound))){ |
4073 |
|
|
4074 |
|
// TODO: "Policy point" |
4075 |
|
//We are only going to recreate the functionality for now. |
4076 |
|
//In the future this can be improved to generate a temporary constraint |
4077 |
|
//if none exists. |
4078 |
|
//Experiment with doing this every time or only when the new constraint |
4079 |
|
//implies an unknown fact. |
4080 |
|
|
4081 |
1730 |
ConstraintType t = upperBound ? UpperBound : LowerBound; |
4082 |
1730 |
ConstraintP bestImplied = d_constraintDatabase.getBestImpliedBound(basic, t, bound); |
4083 |
|
|
4084 |
|
// Node bestImplied = upperBound ? |
4085 |
|
// d_apm.getBestImpliedUpperBound(basic, bound): |
4086 |
|
// d_apm.getBestImpliedLowerBound(basic, bound); |
4087 |
|
|
4088 |
1730 |
if(bestImplied != NullConstraint){ |
4089 |
|
//This should be stronger |
4090 |
1272 |
Assert(!upperBound || bound <= bestImplied->getValue()); |
4091 |
1272 |
Assert( |
4092 |
|
!upperBound |
4093 |
|
|| d_partialModel.lessThanUpperBound(basic, bestImplied->getValue())); |
4094 |
|
|
4095 |
1272 |
Assert(upperBound || bound >= bestImplied->getValue()); |
4096 |
1272 |
Assert(upperBound |
4097 |
|
|| d_partialModel.greaterThanLowerBound(basic, |
4098 |
|
bestImplied->getValue())); |
4099 |
|
//slightly changed |
4100 |
|
|
4101 |
|
// ConstraintP c = d_constraintDatabase.lookup(bestImplied); |
4102 |
|
// Assert(c != NullConstraint); |
4103 |
|
|
4104 |
1272 |
bool assertedToTheTheory = bestImplied->assertedToTheTheory(); |
4105 |
1272 |
bool canBePropagated = bestImplied->canBePropagated(); |
4106 |
1272 |
bool hasProof = bestImplied->hasProof(); |
4107 |
|
|
4108 |
2544 |
Debug("arith::prop") << "arith::prop" << basic |
4109 |
1272 |
<< " " << assertedToTheTheory |
4110 |
1272 |
<< " " << canBePropagated |
4111 |
1272 |
<< " " << hasProof |
4112 |
1272 |
<< endl; |
4113 |
|
|
4114 |
1272 |
if(bestImplied->negationHasProof()){ |
4115 |
|
Warning() << "the negation of " << bestImplied << " : " << endl |
4116 |
|
<< "has proof " << bestImplied->getNegation() << endl |
4117 |
|
<< bestImplied->getNegation()->externalExplainByAssertions() |
4118 |
|
<< endl; |
4119 |
|
} |
4120 |
|
|
4121 |
1272 |
if(!assertedToTheTheory && canBePropagated && !hasProof ){ |
4122 |
232 |
d_linEq.propagateBasicFromRow(bestImplied); |
4123 |
|
// I think this can be skipped if canBePropagated is true |
4124 |
|
//d_learnedBounds.push(bestImplied); |
4125 |
232 |
if(Debug.isOn("arith::prop")){ |
4126 |
|
Debug("arith::prop") << "success " << bestImplied << endl; |
4127 |
|
d_partialModel.printModel(basic, Debug("arith::prop")); |
4128 |
|
} |
4129 |
232 |
return true; |
4130 |
|
} |
4131 |
1040 |
if(Debug.isOn("arith::prop")){ |
4132 |
|
Debug("arith::prop") << "failed " << basic |
4133 |
|
<< " " << bound |
4134 |
|
<< " " << assertedToTheTheory |
4135 |
|
<< " " << canBePropagated |
4136 |
|
<< " " << hasProof << endl; |
4137 |
|
d_partialModel.printModel(basic, Debug("arith::prop")); |
4138 |
|
} |
4139 |
|
} |
4140 |
16 |
}else if(Debug.isOn("arith::prop")){ |
4141 |
|
Debug("arith::prop") << "false " << bound << " "; |
4142 |
|
d_partialModel.printModel(basic, Debug("arith::prop")); |
4143 |
|
} |
4144 |
1514 |
return false; |
4145 |
|
} |
4146 |
|
|
4147 |
4434 |
void TheoryArithPrivate::propagateCandidate(ArithVar basic){ |
4148 |
4434 |
bool success = false; |
4149 |
4434 |
RowIndex ridx = d_tableau.basicToRowIndex(basic); |
4150 |
|
|
4151 |
|
bool tryLowerBound = |
4152 |
8480 |
d_partialModel.strictlyAboveLowerBound(basic) && |
4153 |
8480 |
d_linEq.rowLacksBound(ridx, false, basic) == NULL; |
4154 |
|
|
4155 |
|
bool tryUpperBound = |
4156 |
8446 |
d_partialModel.strictlyBelowUpperBound(basic) && |
4157 |
8446 |
d_linEq.rowLacksBound(ridx, true, basic) == NULL; |
4158 |
|
|
4159 |
4434 |
if(tryLowerBound){ |
4160 |
1020 |
success |= propagateCandidateLowerBound(basic); |
4161 |
|
} |
4162 |
4434 |
if(tryUpperBound){ |
4163 |
726 |
success |= propagateCandidateUpperBound(basic); |
4164 |
|
} |
4165 |
4434 |
if(success){ |
4166 |
226 |
++d_statistics.d_boundPropagations; |
4167 |
|
} |
4168 |
4434 |
} |
4169 |
|
|
4170 |
2552 |
void TheoryArithPrivate::propagateCandidates(){ |
4171 |
5104 |
TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime); |
4172 |
|
|
4173 |
2552 |
Debug("arith::prop") << "propagateCandidates begin" << endl; |
4174 |
|
|
4175 |
2552 |
Assert(d_candidateBasics.empty()); |
4176 |
|
|
4177 |
2552 |
if(d_updatedBounds.empty()){ return; } |
4178 |
|
|
4179 |
2552 |
DenseSet::const_iterator i = d_updatedBounds.begin(); |
4180 |
2552 |
DenseSet::const_iterator end = d_updatedBounds.end(); |
4181 |
9200 |
for(; i != end; ++i){ |
4182 |
3324 |
ArithVar var = *i; |
4183 |
4098 |
if(d_tableau.isBasic(var) && |
4184 |
774 |
d_tableau.basicRowLength(var) <= options::arithPropagateMaxLength()){ |
4185 |
702 |
d_candidateBasics.softAdd(var); |
4186 |
|
}else{ |
4187 |
2622 |
Tableau::ColIterator basicIter = d_tableau.colIterator(var); |
4188 |
15002 |
for(; !basicIter.atEnd(); ++basicIter){ |
4189 |
6190 |
const Tableau::Entry& entry = *basicIter; |
4190 |
6190 |
RowIndex ridx = entry.getRowIndex(); |
4191 |
6190 |
ArithVar rowVar = d_tableau.rowIndexToBasic(ridx); |
4192 |
6190 |
Assert(entry.getColVar() == var); |
4193 |
6190 |
Assert(d_tableau.isBasic(rowVar)); |
4194 |
6190 |
if(d_tableau.getRowLength(ridx) <= options::arithPropagateMaxLength()){ |
4195 |
4576 |
d_candidateBasics.softAdd(rowVar); |
4196 |
|
} |
4197 |
|
} |
4198 |
|
} |
4199 |
|
} |
4200 |
2552 |
d_updatedBounds.purge(); |
4201 |
|
|
4202 |
11420 |
while(!d_candidateBasics.empty()){ |
4203 |
4434 |
ArithVar candidate = d_candidateBasics.back(); |
4204 |
4434 |
d_candidateBasics.pop_back(); |
4205 |
4434 |
Assert(d_tableau.isBasic(candidate)); |
4206 |
4434 |
propagateCandidate(candidate); |
4207 |
|
} |
4208 |
2552 |
Debug("arith::prop") << "propagateCandidates end" << endl << endl << endl; |
4209 |
|
} |
4210 |
|
|
4211 |
1048339 |
void TheoryArithPrivate::propagateCandidatesNew(){ |
4212 |
|
/* Four criteria must be met for progagation on a variable to happen using a row: |
4213 |
|
* 0: A new bound has to have been added to the row. |
4214 |
|
* 1: The hasBoundsCount for the row must be "full" or be full minus one variable |
4215 |
|
* (This is O(1) to check, but requires book keeping.) |
4216 |
|
* 2: The current assignment must be strictly smaller/greater than the current bound. |
4217 |
|
* assign(x) < upper(x) |
4218 |
|
* (This is O(1) to compute.) |
4219 |
|
* 3: There is a bound that is strictly smaller/greater than the current assignment. |
4220 |
|
* assign(x) < c for some x <= c literal |
4221 |
|
* (This is O(log n) to compute.) |
4222 |
|
* 4: The implied bound on x is strictly smaller/greater than the current bound. |
4223 |
|
* (This is O(n) to compute.) |
4224 |
|
*/ |
4225 |
|
|
4226 |
2096678 |
TimerStat::CodeTimer codeTimer(d_statistics.d_boundComputationTime); |
4227 |
1048339 |
Debug("arith::prop") << "propagateCandidatesNew begin" << endl; |
4228 |
|
|
4229 |
1048339 |
Assert(d_qflraStatus == Result::SAT); |
4230 |
1048339 |
if(d_updatedBounds.empty()){ return; } |
4231 |
1048339 |
dumpUpdatedBoundsToRows(); |
4232 |
1048339 |
Assert(d_updatedBounds.empty()); |
4233 |
|
|
4234 |
1048339 |
if(!d_candidateRows.empty()){ |
4235 |
1984104 |
UpdateTrackingCallback utcb(&d_linEq); |
4236 |
992052 |
d_partialModel.processBoundsQueue(utcb); |
4237 |
|
} |
4238 |
|
|
4239 |
19631489 |
while(!d_candidateRows.empty()){ |
4240 |
9291575 |
RowIndex candidate = d_candidateRows.back(); |
4241 |
9291575 |
d_candidateRows.pop_back(); |
4242 |
9291575 |
propagateCandidateRow(candidate); |
4243 |
|
} |
4244 |
1048339 |
Debug("arith::prop") << "propagateCandidatesNew end" << endl << endl << endl; |
4245 |
|
} |
4246 |
|
|
4247 |
16142137 |
bool TheoryArithPrivate::propagateMightSucceed(ArithVar v, bool ub) const{ |
4248 |
24458809 |
int cmp = ub ? d_partialModel.cmpAssignmentUpperBound(v) |
4249 |
24458809 |
: d_partialModel.cmpAssignmentLowerBound(v); |
4250 |
16142137 |
bool hasSlack = ub ? cmp < 0 : cmp > 0; |
4251 |
16142137 |
if(hasSlack){ |
4252 |
7876241 |
ConstraintType t = ub ? UpperBound : LowerBound; |
4253 |
7876241 |
const DeltaRational& a = d_partialModel.getAssignment(v); |
4254 |
|
|
4255 |
7876241 |
if(isInteger(v) && !a.isIntegral()){ |
4256 |
61117 |
return true; |
4257 |
|
} |
4258 |
|
|
4259 |
7815124 |
ConstraintP strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a); |
4260 |
7815124 |
if(strongestPossible == NullConstraint){ |
4261 |
4989973 |
return false; |
4262 |
|
}else{ |
4263 |
2825151 |
bool assertedToTheTheory = strongestPossible->assertedToTheTheory(); |
4264 |
2825151 |
bool canBePropagated = strongestPossible->canBePropagated(); |
4265 |
2825151 |
bool hasProof = strongestPossible->hasProof(); |
4266 |
|
|
4267 |
2825151 |
return !assertedToTheTheory && canBePropagated && !hasProof; |
4268 |
|
} |
4269 |
|
}else{ |
4270 |
8265896 |
return false; |
4271 |
|
} |
4272 |
|
} |
4273 |
|
|
4274 |
4098183 |
bool TheoryArithPrivate::attemptSingleton(RowIndex ridx, bool rowUp){ |
4275 |
4098183 |
Debug("arith::prop") << " attemptSingleton" << ridx; |
4276 |
|
|
4277 |
|
const Tableau::Entry* ep; |
4278 |
4098183 |
ep = d_linEq.rowLacksBound(ridx, rowUp, ARITHVAR_SENTINEL); |
4279 |
4098183 |
Assert(ep != NULL); |
4280 |
|
|
4281 |
4098183 |
ArithVar v = ep->getColVar(); |
4282 |
4098183 |
const Rational& coeff = ep->getCoefficient(); |
4283 |
|
|
4284 |
|
// 0 = c * v + \sum rest |
4285 |
|
// Suppose rowUp |
4286 |
|
// - c * v = \sum rest \leq D |
4287 |
|
// if c > 0, v \geq -D/c so !vUp |
4288 |
|
// if c < 0, v \leq -D/c so vUp |
4289 |
|
// Suppose not rowUp |
4290 |
|
// - c * v = \sum rest \geq D |
4291 |
|
// if c > 0, v \leq -D/c so vUp |
4292 |
|
// if c < 0, v \geq -D/c so !vUp |
4293 |
4098183 |
bool vUp = (rowUp == ( coeff.sgn() < 0)); |
4294 |
|
|
4295 |
4098183 |
Debug("arith::prop") << " " << rowUp << " " << v << " " << coeff << " " << vUp << endl; |
4296 |
4098183 |
Debug("arith::prop") << " " << propagateMightSucceed(v, vUp) << endl; |
4297 |
|
|
4298 |
4098183 |
if(propagateMightSucceed(v, vUp)){ |
4299 |
605258 |
DeltaRational dr = d_linEq.computeRowBound(ridx, rowUp, v); |
4300 |
605258 |
DeltaRational bound = dr / (- coeff); |
4301 |
302629 |
return tryToPropagate(ridx, rowUp, v, vUp, bound); |
4302 |
|
} |
4303 |
3795554 |
return false; |
4304 |
|
} |
4305 |
|
|
4306 |
1573655 |
bool TheoryArithPrivate::attemptFull(RowIndex ridx, bool rowUp){ |
4307 |
1573655 |
Debug("arith::prop") << " attemptFull" << ridx << endl; |
4308 |
|
|
4309 |
3147310 |
vector<const Tableau::Entry*> candidates; |
4310 |
|
|
4311 |
9519426 |
for(Tableau::RowIterator i = d_tableau.ridRowIterator(ridx); !i.atEnd(); ++i){ |
4312 |
7945771 |
const Tableau::Entry& e =*i; |
4313 |
7945771 |
const Rational& c = e.getCoefficient(); |
4314 |
7945771 |
ArithVar v = e.getColVar(); |
4315 |
7945771 |
bool vUp = (rowUp == (c.sgn() < 0)); |
4316 |
7945771 |
if(propagateMightSucceed(v, vUp)){ |
4317 |
159813 |
candidates.push_back(&e); |
4318 |
|
} |
4319 |
|
} |
4320 |
1573655 |
if(candidates.empty()){ return false; } |
4321 |
|
|
4322 |
|
const DeltaRational slack = |
4323 |
286162 |
d_linEq.computeRowBound(ridx, rowUp, ARITHVAR_SENTINEL); |
4324 |
143081 |
bool any = false; |
4325 |
143081 |
vector<const Tableau::Entry*>::const_iterator i, iend; |
4326 |
302894 |
for(i = candidates.begin(), iend = candidates.end(); i != iend; ++i){ |
4327 |
159813 |
const Tableau::Entry* ep = *i; |
4328 |
159813 |
const Rational& c = ep->getCoefficient(); |
4329 |
159813 |
ArithVar v = ep->getColVar(); |
4330 |
|
|
4331 |
|
// See the comment for attemptSingleton() |
4332 |
159813 |
bool activeUp = (rowUp == (c.sgn() > 0)); |
4333 |
159813 |
bool vUb = (rowUp == (c.sgn() < 0)); |
4334 |
|
|
4335 |
319626 |
const DeltaRational& activeBound = activeUp ? |
4336 |
126057 |
d_partialModel.getUpperBound(v): |
4337 |
193569 |
d_partialModel.getLowerBound(v); |
4338 |
|
|
4339 |
319626 |
DeltaRational contribution = activeBound * c; |
4340 |
319626 |
DeltaRational impliedBound = (slack - contribution)/(-c); |
4341 |
|
|
4342 |
159813 |
bool success = tryToPropagate(ridx, rowUp, v, vUb, impliedBound); |
4343 |
159813 |
any |= success; |
4344 |
|
} |
4345 |
143081 |
return any; |
4346 |
|
} |
4347 |
|
|
4348 |
462442 |
bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUb, const DeltaRational& bound){ |
4349 |
|
|
4350 |
800467 |
bool weaker = vUb ? d_partialModel.strictlyLessThanUpperBound(v, bound): |
4351 |
800467 |
d_partialModel.strictlyGreaterThanLowerBound(v, bound); |
4352 |
462442 |
if(weaker){ |
4353 |
301111 |
ConstraintType t = vUb ? UpperBound : LowerBound; |
4354 |
|
|
4355 |
301111 |
ConstraintP implied = d_constraintDatabase.getBestImpliedBound(v, t, bound); |
4356 |
301111 |
if(implied != NullConstraint){ |
4357 |
153890 |
return rowImplicationCanBeApplied(ridx, rowUp, implied); |
4358 |
|
} |
4359 |
|
} |
4360 |
308552 |
return false; |
4361 |
|
} |
4362 |
|
|
4363 |
97813 |
Node flattenImplication(Node imp){ |
4364 |
195626 |
NodeBuilder nb(kind::OR); |
4365 |
195626 |
std::unordered_set<Node> included; |
4366 |
195626 |
Node left = imp[0]; |
4367 |
195626 |
Node right = imp[1]; |
4368 |
|
|
4369 |
97813 |
if(left.getKind() == kind::AND){ |
4370 |
439919 |
for(Node::iterator i = left.begin(), iend = left.end(); i != iend; ++i) { |
4371 |
342106 |
if (!included.count((*i).negate())) |
4372 |
|
{ |
4373 |
342106 |
nb << (*i).negate(); |
4374 |
342106 |
included.insert((*i).negate()); |
4375 |
|
} |
4376 |
|
} |
4377 |
|
}else{ |
4378 |
|
if (!included.count(left.negate())) |
4379 |
|
{ |
4380 |
|
nb << left.negate(); |
4381 |
|
included.insert(left.negate()); |
4382 |
|
} |
4383 |
|
} |
4384 |
|
|
4385 |
97813 |
if(right.getKind() == kind::OR){ |
4386 |
|
for(Node::iterator i = right.begin(), iend = right.end(); i != iend; ++i) { |
4387 |
|
if (!included.count(*i)) |
4388 |
|
{ |
4389 |
|
nb << *i; |
4390 |
|
included.insert(*i); |
4391 |
|
} |
4392 |
|
} |
4393 |
|
}else{ |
4394 |
97813 |
if (!included.count(right)) |
4395 |
|
{ |
4396 |
97813 |
nb << right; |
4397 |
97813 |
included.insert(right); |
4398 |
|
} |
4399 |
|
} |
4400 |
|
|
4401 |
195626 |
return nb; |
4402 |
|
} |
4403 |
|
|
4404 |
153890 |
bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP implied){ |
4405 |
153890 |
Assert(implied != NullConstraint); |
4406 |
153890 |
ArithVar v = implied->getVariable(); |
4407 |
|
|
4408 |
153890 |
bool assertedToTheTheory = implied->assertedToTheTheory(); |
4409 |
153890 |
bool canBePropagated = implied->canBePropagated(); |
4410 |
153890 |
bool hasProof = implied->hasProof(); |
4411 |
|
|
4412 |
307780 |
Debug("arith::prop") << "arith::prop" << v |
4413 |
153890 |
<< " " << assertedToTheTheory |
4414 |
153890 |
<< " " << canBePropagated |
4415 |
153890 |
<< " " << hasProof |
4416 |
153890 |
<< endl; |
4417 |
|
|
4418 |
|
|
4419 |
153890 |
if( !assertedToTheTheory && canBePropagated && !hasProof ){ |
4420 |
260402 |
ConstraintCPVec explain; |
4421 |
130201 |
ARITH_PROOF(d_farkasBuffer.clear()); |
4422 |
130201 |
RationalVectorP coeffs = ARITH_NULLPROOF(&d_farkasBuffer); |
4423 |
|
|
4424 |
|
// After invoking `propegateRow`: |
4425 |
|
// * coeffs[0] is for implied |
4426 |
|
// * coeffs[i+1] is for explain[i] |
4427 |
130201 |
d_linEq.propagateRow(explain, ridx, rowUp, implied, coeffs); |
4428 |
130201 |
if(d_tableau.getRowLength(ridx) <= options::arithPropAsLemmaLength()){ |
4429 |
97813 |
if (Debug.isOn("arith::prop::pf")) { |
4430 |
|
for (const auto & constraint : explain) { |
4431 |
|
Assert(constraint->hasProof()); |
4432 |
|
constraint->printProofTree(Debug("arith::prop::pf")); |
4433 |
|
} |
4434 |
|
} |
4435 |
195626 |
Node implication = implied->externalImplication(explain); |
4436 |
195626 |
Node clause = flattenImplication(implication); |
4437 |
195626 |
std::shared_ptr<ProofNode> clausePf{nullptr}; |
4438 |
|
|
4439 |
97813 |
if (isProofEnabled()) |
4440 |
|
{ |
4441 |
|
// We can prove this lemma from Farkas... |
4442 |
28770 |
std::vector<std::shared_ptr<ProofNode>> conflictPfs; |
4443 |
|
// Assume the negated getLiteral version of the implied constaint |
4444 |
|
// then rewrite it into proof normal form. |
4445 |
14385 |
conflictPfs.push_back( |
4446 |
86310 |
d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, |
4447 |
28770 |
{d_pnm->mkAssume(implied->getLiteral().negate())}, |
4448 |
28770 |
{implied->getNegation()->getProofLiteral()})); |
4449 |
|
// Add the explaination proofs. |
4450 |
63355 |
for (const auto constraint : explain) |
4451 |
|
{ |
4452 |
97940 |
NodeBuilder nb; |
4453 |
48970 |
conflictPfs.push_back(constraint->externalExplainByAssertions(nb)); |
4454 |
|
} |
4455 |
|
// Collect the farkas coefficients, as nodes. |
4456 |
28770 |
std::vector<Node> farkasCoefficients; |
4457 |
14385 |
farkasCoefficients.reserve(coeffs->size()); |
4458 |
14385 |
auto nm = NodeManager::currentNM(); |
4459 |
14385 |
std::transform( |
4460 |
|
coeffs->begin(), |
4461 |
|
coeffs->end(), |
4462 |
|
std::back_inserter(farkasCoefficients), |
4463 |
77740 |
[nm](const Rational& r) { return nm->mkConst<Rational>(r); }); |
4464 |
|
|
4465 |
|
// Prove bottom. |
4466 |
14385 |
auto sumPf = d_pnm->mkNode( |
4467 |
28770 |
PfRule::MACRO_ARITH_SCALE_SUM_UB, conflictPfs, farkasCoefficients); |
4468 |
14385 |
auto botPf = d_pnm->mkNode( |
4469 |
28770 |
PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)}); |
4470 |
|
|
4471 |
|
// Prove the conflict |
4472 |
28770 |
std::vector<Node> assumptions; |
4473 |
14385 |
assumptions.reserve(clause.getNumChildren()); |
4474 |
14385 |
std::transform(clause.begin(), |
4475 |
|
clause.end(), |
4476 |
|
std::back_inserter(assumptions), |
4477 |
78373 |
[](TNode r) { return r.negate(); }); |
4478 |
28770 |
auto notAndNotPf = d_pnm->mkScope(botPf, assumptions); |
4479 |
|
|
4480 |
|
// Convert it to a clause |
4481 |
28770 |
auto orNotNotPf = d_pnm->mkNode(PfRule::NOT_AND, {notAndNotPf}, {}); |
4482 |
43155 |
clausePf = d_pnm->mkNode( |
4483 |
28770 |
PfRule::MACRO_SR_PRED_TRANSFORM, {orNotNotPf}, {clause}); |
4484 |
|
|
4485 |
|
// Output it |
4486 |
28770 |
TrustNode trustedClause = d_pfGen->mkTrustNode(clause, clausePf); |
4487 |
14385 |
outputTrustedLemma(trustedClause, InferenceId::ARITH_ROW_IMPL); |
4488 |
|
} |
4489 |
|
else |
4490 |
|
{ |
4491 |
83428 |
outputLemma(clause, InferenceId::ARITH_ROW_IMPL); |
4492 |
|
} |
4493 |
|
}else{ |
4494 |
32388 |
Assert(!implied->negationHasProof()); |
4495 |
32388 |
implied->impliedByFarkas(explain, coeffs, false); |
4496 |
32388 |
implied->tryToPropagate(); |
4497 |
|
} |
4498 |
130201 |
return true; |
4499 |
|
} |
4500 |
|
|
4501 |
23689 |
if(Debug.isOn("arith::prop")){ |
4502 |
|
Debug("arith::prop") |
4503 |
|
<< "failed " << v << " " << assertedToTheTheory << " " |
4504 |
|
<< canBePropagated << " " << hasProof << " " << implied << endl; |
4505 |
|
d_partialModel.printModel(v, Debug("arith::prop")); |
4506 |
|
} |
4507 |
23689 |
return false; |
4508 |
|
} |
4509 |
|
|
4510 |
9291575 |
bool TheoryArithPrivate::propagateCandidateRow(RowIndex ridx){ |
4511 |
9291575 |
BoundCounts hasCount = d_linEq.hasBoundCount(ridx); |
4512 |
9291575 |
uint32_t rowLength = d_tableau.getRowLength(ridx); |
4513 |
|
|
4514 |
9291575 |
bool success = false; |
4515 |
|
static int instance = 0; |
4516 |
9291575 |
++instance; |
4517 |
|
|
4518 |
18583150 |
Debug("arith::prop") |
4519 |
9291575 |
<< "propagateCandidateRow " << instance << " attempt " << rowLength << " " << hasCount << endl; |
4520 |
|
|
4521 |
18583150 |
if (rowLength >= options::arithPropagateMaxLength() |
4522 |
10869706 |
&& Random::getRandom().pickWithProb( |
4523 |
1578131 |
1.0 - double(options::arithPropagateMaxLength()) / rowLength)) |
4524 |
|
{ |
4525 |
333544 |
return false; |
4526 |
|
} |
4527 |
|
|
4528 |
8958031 |
if(hasCount.lowerBoundCount() == rowLength){ |
4529 |
677203 |
success |= attemptFull(ridx, false); |
4530 |
8280828 |
}else if(hasCount.lowerBoundCount() + 1 == rowLength){ |
4531 |
2148369 |
success |= attemptSingleton(ridx, false); |
4532 |
|
} |
4533 |
|
|
4534 |
8958031 |
if(hasCount.upperBoundCount() == rowLength){ |
4535 |
896452 |
success |= attemptFull(ridx, true); |
4536 |
8061579 |
}else if(hasCount.upperBoundCount() + 1 == rowLength){ |
4537 |
1949814 |
success |= attemptSingleton(ridx, true); |
4538 |
|
} |
4539 |
8958031 |
return success; |
4540 |
|
} |
4541 |
|
|
4542 |
1048339 |
void TheoryArithPrivate::dumpUpdatedBoundsToRows(){ |
4543 |
1048339 |
Assert(d_candidateRows.empty()); |
4544 |
1048339 |
DenseSet::const_iterator i = d_updatedBounds.begin(); |
4545 |
1048339 |
DenseSet::const_iterator end = d_updatedBounds.end(); |
4546 |
6170819 |
for(; i != end; ++i){ |
4547 |
2561240 |
ArithVar var = *i; |
4548 |
2561240 |
if(d_tableau.isBasic(var)){ |
4549 |
1437724 |
RowIndex ridx = d_tableau.basicToRowIndex(var); |
4550 |
1437724 |
d_candidateRows.softAdd(ridx); |
4551 |
|
}else{ |
4552 |
1123516 |
Tableau::ColIterator basicIter = d_tableau.colIterator(var); |
4553 |
25119676 |
for(; !basicIter.atEnd(); ++basicIter){ |
4554 |
11998080 |
const Tableau::Entry& entry = *basicIter; |
4555 |
11998080 |
RowIndex ridx = entry.getRowIndex(); |
4556 |
11998080 |
d_candidateRows.softAdd(ridx); |
4557 |
|
} |
4558 |
|
} |
4559 |
|
} |
4560 |
1048339 |
d_updatedBounds.purge(); |
4561 |
1048339 |
} |
4562 |
|
|
4563 |
|
const BoundsInfo& TheoryArithPrivate::boundsInfo(ArithVar basic) const{ |
4564 |
|
RowIndex ridx = d_tableau.basicToRowIndex(basic); |
4565 |
|
return d_rowTracking[ridx]; |
4566 |
|
} |
4567 |
|
|
4568 |
6591 |
std::pair<bool, Node> TheoryArithPrivate::entailmentCheck(TNode lit, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){ |
4569 |
|
using namespace inferbounds; |
4570 |
|
|
4571 |
|
// l k r |
4572 |
|
// diff : (l - r) k 0 |
4573 |
6591 |
Debug("arith::entailCheck") << "TheoryArithPrivate::entailmentCheck(" << lit << ")"<< endl; |
4574 |
|
Kind k; |
4575 |
|
int primDir; |
4576 |
13182 |
Rational lm, rm, dm; |
4577 |
13182 |
Node lp, rp, dp; |
4578 |
13182 |
DeltaRational sep; |
4579 |
6591 |
bool successful = decomposeLiteral(lit, k, primDir, lm, lp, rm, rp, dm, dp, sep); |
4580 |
6591 |
if(!successful) { return make_pair(false, Node::null()); } |
4581 |
|
|
4582 |
6591 |
if(dp.getKind() == CONST_RATIONAL){ |
4583 |
|
Node eval = Rewriter::rewrite(lit); |
4584 |
|
Assert(eval.getKind() == kind::CONST_BOOLEAN); |
4585 |
|
// if true, true is an acceptable explaination |
4586 |
|
// if false, the node is uninterpreted and eval can be forgotten |
4587 |
|
return make_pair(eval.getConst<bool>(), eval); |
4588 |
|
} |
4589 |
6591 |
Assert(dm != Rational(0)); |
4590 |
6591 |
Assert(primDir == 1 || primDir == -1); |
4591 |
|
|
4592 |
6591 |
int negPrim = -primDir; |
4593 |
|
|
4594 |
6591 |
int secDir = (k == EQUAL || k == DISTINCT) ? negPrim: 0; |
4595 |
6591 |
int negSecDir = (k == EQUAL || k == DISTINCT) ? primDir: 0; |
4596 |
|
|
4597 |
|
// primDir*[lm*( lp )] k primDir*[ [rm*( rp )] + sep ] |
4598 |
|
// primDir*[lm*( lp ) - rm*( rp ) ] k primDir*sep |
4599 |
|
// primDir*[dm * dp] k primDir*sep |
4600 |
|
|
4601 |
13182 |
std::pair<Node, DeltaRational> bestPrimLeft, bestNegPrimRight, bestPrimDiff, tmp; |
4602 |
13182 |
std::pair<Node, DeltaRational> bestSecLeft, bestNegSecRight, bestSecDiff; |
4603 |
6591 |
bestPrimLeft.first = Node::null(); bestNegPrimRight.first = Node::null(); bestPrimDiff.first = Node::null(); |
4604 |
6591 |
bestSecLeft.first = Node::null(); bestNegSecRight.first = Node::null(); bestSecDiff.first = Node::null(); |
4605 |
|
|
4606 |
|
|
4607 |
|
|
4608 |
6591 |
ArithEntailmentCheckParameters::const_iterator alg, alg_end; |
4609 |
18154 |
for( alg = params.begin(), alg_end = params.end(); alg != alg_end; ++alg ){ |
4610 |
12871 |
const inferbounds::InferBoundAlgorithm& ibalg = *alg; |
4611 |
|
|
4612 |
12871 |
Debug("arith::entailCheck") << "entailmentCheck trying " << (inferbounds::Algorithms) ibalg.getAlgorithm() << endl; |
4613 |
12871 |
switch(ibalg.getAlgorithm()){ |
4614 |
|
case inferbounds::None: |
4615 |
|
break; |
4616 |
12871 |
case inferbounds::Lookup: |
4617 |
|
case inferbounds::RowSum: |
4618 |
|
{ |
4619 |
|
typedef void (TheoryArithPrivate::*EntailmentCheckFunc)(std::pair<Node, DeltaRational>&, int, TNode) const; |
4620 |
|
|
4621 |
|
EntailmentCheckFunc ecfunc = |
4622 |
12871 |
(ibalg.getAlgorithm() == inferbounds::Lookup) |
4623 |
|
? (&TheoryArithPrivate::entailmentCheckBoundLookup) |
4624 |
12871 |
: (&TheoryArithPrivate::entailmentCheckRowSum); |
4625 |
|
|
4626 |
12871 |
(*this.*ecfunc)(tmp, primDir * lm.sgn(), lp); |
4627 |
12871 |
setToMin(primDir * lm.sgn(), bestPrimLeft, tmp); |
4628 |
|
|
4629 |
12871 |
(*this.*ecfunc)(tmp, negPrim * rm.sgn(), rp); |
4630 |
12871 |
setToMin(negPrim * rm.sgn(), bestNegPrimRight, tmp); |
4631 |
|
|
4632 |
12871 |
(*this.*ecfunc)(tmp, secDir * lm.sgn(), lp); |
4633 |
12871 |
setToMin(secDir * lm.sgn(), bestSecLeft, tmp); |
4634 |
|
|
4635 |
12871 |
(*this.*ecfunc)(tmp, negSecDir * rm.sgn(), rp); |
4636 |
12871 |
setToMin(negSecDir * rm.sgn(), bestNegSecRight, tmp); |
4637 |
|
|
4638 |
12871 |
(*this.*ecfunc)(tmp, primDir * dm.sgn(), dp); |
4639 |
12871 |
setToMin(primDir * dm.sgn(), bestPrimDiff, tmp); |
4640 |
|
|
4641 |
12871 |
(*this.*ecfunc)(tmp, secDir * dm.sgn(), dp); |
4642 |
12871 |
setToMin(secDir * dm.sgn(), bestSecDiff, tmp); |
4643 |
|
} |
4644 |
12871 |
break; |
4645 |
|
default: |
4646 |
|
Unhandled(); |
4647 |
|
} |
4648 |
|
|
4649 |
|
// turn bounds on prim * left and -prim * right into bounds on prim * diff |
4650 |
12871 |
if(!bestPrimLeft.first.isNull() && !bestNegPrimRight.first.isNull()){ |
4651 |
|
// primDir*lm* lp <= primDir*lm*L |
4652 |
|
// -primDir*rm* rp <= -primDir*rm*R |
4653 |
|
// primDir*lm* lp -primDir*rm* rp <= primDir*lm*L - primDir*rm*R |
4654 |
|
// primDir [lm* lp -rm* rp] <= primDir[lm*L - *rm*R] |
4655 |
|
// primDir [dm * dp] <= primDir[lm*L - *rm*R] |
4656 |
|
// primDir [dm * dp] <= primDir * dm * ([lm*L - *rm*R]/dm) |
4657 |
2084 |
tmp.second = ((bestPrimLeft.second * lm) - (bestNegPrimRight.second * rm)) / dm; |
4658 |
2084 |
tmp.first = (bestPrimLeft.first).andNode(bestNegPrimRight.first); |
4659 |
2084 |
setToMin(primDir, bestPrimDiff, tmp); |
4660 |
|
} |
4661 |
|
|
4662 |
|
// turn bounds on sec * left and sec * right into bounds on sec * diff |
4663 |
12871 |
if(secDir != 0 && !bestSecLeft.first.isNull() && !bestNegSecRight.first.isNull()){ |
4664 |
|
// secDir*lm* lp <= secDir*lm*L |
4665 |
|
// -secDir*rm* rp <= -secDir*rm*R |
4666 |
|
// secDir*lm* lp -secDir*rm* rp <= secDir*lm*L - secDir*rm*R |
4667 |
|
// secDir [lm* lp -rm* rp] <= secDir[lm*L - *rm*R] |
4668 |
|
// secDir [dm * dp] <= secDir[lm*L - *rm*R] |
4669 |
|
// secDir [dm * dp] <= secDir * dm * ([lm*L - *rm*R]/dm) |
4670 |
|
tmp.second = ((bestSecLeft.second * lm) - (bestNegSecRight.second * rm)) / dm; |
4671 |
|
tmp.first = (bestSecLeft.first).andNode(bestNegSecRight.first); |
4672 |
|
setToMin(secDir, bestSecDiff, tmp); |
4673 |
|
} |
4674 |
|
|
4675 |
12871 |
switch(k){ |
4676 |
12827 |
case LEQ: |
4677 |
12827 |
if(!bestPrimDiff.first.isNull()){ |
4678 |
2860 |
DeltaRational d = (bestPrimDiff.second * dm); |
4679 |
2084 |
if((primDir > 0 && d <= sep) || (primDir < 0 && d >= sep) ){ |
4680 |
2616 |
Debug("arith::entailCheck") << "entailmentCheck found " |
4681 |
1308 |
<< primDir << "*" << dm << "*(" << dp<<")" |
4682 |
1308 |
<< " <= " << primDir << "*" << dm << "*" << bestPrimDiff.second |
4683 |
1308 |
<< " <= " << primDir << "*" << sep << endl |
4684 |
1308 |
<< " by " << bestPrimDiff.first << endl; |
4685 |
1308 |
Assert(bestPrimDiff.second * (Rational(primDir) * dm) |
4686 |
|
<= (sep * Rational(primDir))); |
4687 |
1308 |
return make_pair(true, bestPrimDiff.first); |
4688 |
|
} |
4689 |
|
} |
4690 |
11519 |
break; |
4691 |
22 |
case EQUAL: |
4692 |
22 |
if(!bestPrimDiff.first.isNull() && !bestSecDiff.first.isNull()){ |
4693 |
|
// Is primDir [dm * dp] == primDir * sep entailed? |
4694 |
|
// Iff [dm * dp] == sep entailed? |
4695 |
|
// Iff dp == sep / dm entailed? |
4696 |
|
// Iff dp <= sep / dm and dp >= sep / dm entailed? |
4697 |
|
|
4698 |
|
// primDir [dm * dp] <= primDir * dm * U |
4699 |
|
// secDir [dm * dp] <= secDir * dm * L |
4700 |
|
|
4701 |
|
// Suppose primDir * dm > 0 |
4702 |
|
// then secDir * dm < 0 |
4703 |
|
// dp >= (secDir * L) / secDir * dm |
4704 |
|
// dp >= (primDir * L) / primDir * dm |
4705 |
|
// |
4706 |
|
// dp <= U / dm |
4707 |
|
// dp >= L / dm |
4708 |
|
// dp == sep / dm entailed iff U == L == sep |
4709 |
|
// Suppose primDir * dm < 0 |
4710 |
|
// then secDir * dm > 0 |
4711 |
|
// dp >= U / dm |
4712 |
|
// dp <= L / dm |
4713 |
|
// dp == sep / dm entailed iff U == L == sep |
4714 |
|
if(bestPrimDiff.second == bestSecDiff.second){ |
4715 |
|
if(bestPrimDiff.second == sep){ |
4716 |
|
return make_pair(true, (bestPrimDiff.first).andNode(bestSecDiff.first)); |
4717 |
|
} |
4718 |
|
} |
4719 |
|
} |
4720 |
|
// intentionally fall through to DISTINCT case! |
4721 |
|
// entailments of negations are eager exit cases for EQUAL |
4722 |
|
CVC5_FALLTHROUGH; |
4723 |
|
case DISTINCT: |
4724 |
44 |
if(!bestPrimDiff.first.isNull()){ |
4725 |
|
// primDir [dm * dp] <= primDir * dm * U < primDir * sep |
4726 |
|
if((primDir > 0 && (bestPrimDiff.second * dm < sep)) || |
4727 |
|
(primDir < 0 && (bestPrimDiff.second * dm > sep))){ |
4728 |
|
// entailment of negation |
4729 |
|
if(k == DISTINCT){ |
4730 |
|
return make_pair(true, bestPrimDiff.first); |
4731 |
|
}else{ |
4732 |
|
Assert(k == EQUAL); |
4733 |
|
return make_pair(false, Node::null()); |
4734 |
|
} |
4735 |
|
} |
4736 |
|
} |
4737 |
44 |
if(!bestSecDiff.first.isNull()){ |
4738 |
|
// If primDir [dm * dp] > primDir * sep, then this is not entailed. |
4739 |
|
// If primDir [dm * dp] >= primDir * dm * L > primDir * sep |
4740 |
|
// -primDir * dm * L < -primDir * sep |
4741 |
|
// secDir * dm * L < secDir * sep |
4742 |
|
if((secDir > 0 && (bestSecDiff.second * dm < sep)) || |
4743 |
|
(secDir < 0 && (bestSecDiff.second * dm > sep))){ |
4744 |
|
if(k == DISTINCT){ |
4745 |
|
return make_pair(true, bestSecDiff.first); |
4746 |
|
}else{ |
4747 |
|
Assert(k == EQUAL); |
4748 |
|
return make_pair(false, Node::null()); |
4749 |
|
} |
4750 |
|
} |
4751 |
|
} |
4752 |
|
|
4753 |
44 |
break; |
4754 |
|
default: |
4755 |
|
Unreachable(); |
4756 |
|
break; |
4757 |
|
} |
4758 |
|
} |
4759 |
5283 |
return make_pair(false, Node::null()); |
4760 |
|
} |
4761 |
|
|
4762 |
19773 |
bool TheoryArithPrivate::decomposeTerm(Node term, Rational& m, Node& p, Rational& c){ |
4763 |
39546 |
Node t = Rewriter::rewrite(term); |
4764 |
19773 |
if(!Polynomial::isMember(t)){ |
4765 |
|
return false; |
4766 |
|
} |
4767 |
|
|
4768 |
|
// TODO Speed up |
4769 |
39546 |
preprocessing::util::ContainsTermITEVisitor ctv; |
4770 |
19773 |
if(ctv.containsTermITE(t)){ |
4771 |
|
return false; |
4772 |
|
} |
4773 |
|
|
4774 |
39546 |
Polynomial poly = Polynomial::parsePolynomial(t); |
4775 |
19773 |
if(poly.isConstant()){ |
4776 |
6569 |
c = poly.getHead().getConstant().getValue(); |
4777 |
6569 |
p = mkRationalNode(Rational(0)); |
4778 |
6569 |
m = Rational(1); |
4779 |
6569 |
return true; |
4780 |
13204 |
}else if(poly.containsConstant()){ |
4781 |
3187 |
c = poly.getHead().getConstant().getValue(); |
4782 |
3187 |
poly = poly.getTail(); |
4783 |
|
}else{ |
4784 |
10017 |
c = Rational(0); |
4785 |
|
} |
4786 |
13204 |
Assert(!poly.isConstant()); |
4787 |
13204 |
Assert(!poly.containsConstant()); |
4788 |
|
|
4789 |
13204 |
const bool intVars = poly.allIntegralVariables(); |
4790 |
|
|
4791 |
13204 |
if(intVars){ |
4792 |
13204 |
m = Rational(1); |
4793 |
13204 |
if(!poly.isIntegral()){ |
4794 |
|
Integer denom = poly.denominatorLCM(); |
4795 |
|
m /= denom; |
4796 |
|
poly = poly * denom; |
4797 |
|
} |
4798 |
26408 |
Integer g = poly.gcd(); |
4799 |
13204 |
m *= g; |
4800 |
13204 |
poly = poly * Rational(1,g); |
4801 |
13204 |
Assert(poly.isIntegral()); |
4802 |
13204 |
Assert(poly.leadingCoefficientIsPositive()); |
4803 |
|
}else{ |
4804 |
|
Assert(!intVars); |
4805 |
|
m = poly.getHead().getConstant().getValue(); |
4806 |
|
poly = poly * m.inverse(); |
4807 |
|
Assert(poly.leadingCoefficientIsAbsOne()); |
4808 |
|
} |
4809 |
13204 |
p = poly.getNode(); |
4810 |
13204 |
return true; |
4811 |
|
} |
4812 |
|
|
4813 |
79310 |
void TheoryArithPrivate::setToMin(int sgn, std::pair<Node, DeltaRational>& min, const std::pair<Node, DeltaRational>& e){ |
4814 |
79310 |
if(sgn != 0){ |
4815 |
40829 |
if(min.first.isNull() && !e.first.isNull()){ |
4816 |
10729 |
min = e; |
4817 |
30100 |
}else if(!min.first.isNull() && !e.first.isNull()){ |
4818 |
2084 |
if(sgn > 0 && min.second > e.second){ |
4819 |
|
min = e; |
4820 |
2084 |
}else if(sgn < 0 && min.second < e.second){ |
4821 |
|
min = e; |
4822 |
|
} |
4823 |
|
} |
4824 |
|
} |
4825 |
79310 |
} |
4826 |
|
|
4827 |
|
// std::pair<bool, Node> TheoryArithPrivate::entailmentUpperCheck(const Rational& lm, Node lp, const Rational& rm, Node rp, const DeltaRational& sep, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){ |
4828 |
|
|
4829 |
|
// Rational negRM = -rm; |
4830 |
|
// Node diff = NodeManager::currentNM()->mkNode(MULT, mkRationalConstan(lm), lp) + (negRM * rp); |
4831 |
|
|
4832 |
|
// Rational diffm; |
4833 |
|
// Node diffp; |
4834 |
|
// decompose(diff, diffm, diffNode); |
4835 |
|
|
4836 |
|
|
4837 |
|
// std::pair<Node, DeltaRational> bestUbLeft, bestLbRight, bestUbDiff, tmp; |
4838 |
|
// bestUbLeft = bestLbRight = bestUbDiff = make_pair(Node::Null(), DeltaRational()); |
4839 |
|
|
4840 |
|
// return make_pair(false, Node::null()); |
4841 |
|
// } |
4842 |
|
|
4843 |
|
/** |
4844 |
|
* Decomposes a literal into the form: |
4845 |
|
* dir*[lm*( lp )] k dir*[ [rm*( rp )] + sep ] |
4846 |
|
* dir*[dm* dp] k dir *sep |
4847 |
|
* dir is either 1 or -1 |
4848 |
|
*/ |
4849 |
6591 |
bool TheoryArithPrivate::decomposeLiteral(Node lit, Kind& k, int& dir, Rational& lm, Node& lp, Rational& rm, Node& rp, Rational& dm, Node& dp, DeltaRational& sep){ |
4850 |
6591 |
bool negated = (lit.getKind() == kind::NOT); |
4851 |
13182 |
TNode atom = negated ? lit[0] : lit; |
4852 |
|
|
4853 |
13182 |
TNode left = atom[0]; |
4854 |
13182 |
TNode right = atom[1]; |
4855 |
|
|
4856 |
|
// left : lm*( lp ) + lc |
4857 |
|
// right: rm*( rp ) + rc |
4858 |
13182 |
Rational lc, rc; |
4859 |
6591 |
bool success = decomposeTerm(left, lm, lp, lc); |
4860 |
6591 |
if(!success){ return false; } |
4861 |
6591 |
success = decomposeTerm(right, rm, rp, rc); |
4862 |
6591 |
if(!success){ return false; } |
4863 |
|
|
4864 |
13182 |
Node diff = Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::MINUS, left, right)); |
4865 |
13182 |
Rational dc; |
4866 |
6591 |
success = decomposeTerm(diff, dm, dp, dc); |
4867 |
6591 |
Assert(success); |
4868 |
|
|
4869 |
|
// reduce the kind of the to not include literals |
4870 |
|
// GT, NOT LEQ |
4871 |
|
// GEQ, NOT LT |
4872 |
|
// LT, NOT GEQ |
4873 |
|
// LEQ, NOT LT |
4874 |
6591 |
Kind atomKind = atom.getKind(); |
4875 |
6591 |
Kind normKind = negated ? negateKind(atomKind) : atomKind; |
4876 |
|
|
4877 |
6591 |
if(normKind == GEQ || normKind == GT){ |
4878 |
3187 |
dir = -1; |
4879 |
3187 |
normKind = (normKind == GEQ) ? LEQ : LT; |
4880 |
|
}else{ |
4881 |
3404 |
dir = 1; |
4882 |
|
} |
4883 |
|
|
4884 |
13182 |
Debug("arith::decomp") << "arith::decomp " |
4885 |
6591 |
<< lit << "(" << normKind << "*" << dir << ")"<< endl |
4886 |
6591 |
<< " left:" << lc << " + " << lm << "*(" << lp << ") : " <<left << endl |
4887 |
6591 |
<< " right:" << rc << " + " << rm << "*(" << rp << ") : " << right << endl |
4888 |
6591 |
<< " diff: " << dc << " + " << dm << "*("<< dp <<"): " << diff << endl |
4889 |
6591 |
<< " sep: " << sep << endl; |
4890 |
|
|
4891 |
|
|
4892 |
|
// k in LT, LEQ, EQUAL, DISEQUAL |
4893 |
|
// [dir*lm*( lp ) + dir*lc] k [dir*rm*( rp ) + dir*rc] |
4894 |
13182 |
Rational change = rc - lc; |
4895 |
6591 |
Assert(change == (-dc)); |
4896 |
|
// [dir*lm*( lp )] k [dir*rm*( rp ) + dir*(rc - lc)] |
4897 |
6591 |
if(normKind == LT){ |
4898 |
3382 |
sep = DeltaRational(change, Rational(-1)); |
4899 |
3382 |
k = LEQ; |
4900 |
|
}else{ |
4901 |
3209 |
sep = DeltaRational(change); |
4902 |
3209 |
k = normKind; |
4903 |
|
} |
4904 |
|
// k in LEQ, EQUAL, DISEQUAL |
4905 |
|
// dir*lm*( lp ) k [dir*rm*( rp )] + dir*(sep + d * delta) |
4906 |
6591 |
return true; |
4907 |
|
} |
4908 |
|
|
4909 |
|
/** |
4910 |
|
* Precondition: |
4911 |
|
* tp is a polynomial not containing an ite. |
4912 |
|
* either tp is constant or contains no constants. |
4913 |
|
* Post: |
4914 |
|
* if tmp.first is not null, then |
4915 |
|
* sgn * tp <= sgn * tmp.second |
4916 |
|
*/ |
4917 |
39546 |
void TheoryArithPrivate::entailmentCheckBoundLookup(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const { |
4918 |
39546 |
tmp.first = Node::null(); |
4919 |
39546 |
if(sgn == 0){ return; } |
4920 |
|
|
4921 |
19839 |
Assert(Polynomial::isMember(tp)); |
4922 |
19839 |
if(tp.getKind() == CONST_RATIONAL){ |
4923 |
6569 |
tmp.first = mkBoolNode(true); |
4924 |
6569 |
tmp.second = DeltaRational(tp.getConst<Rational>()); |
4925 |
13270 |
}else if(d_partialModel.hasArithVar(tp)){ |
4926 |
10532 |
Assert(tp.getKind() != CONST_RATIONAL); |
4927 |
10532 |
ArithVar v = d_partialModel.asArithVar(tp); |
4928 |
10532 |
Assert(v != ARITHVAR_SENTINEL); |
4929 |
|
ConstraintP c = (sgn > 0) |
4930 |
15682 |
? d_partialModel.getUpperBoundConstraint(v) |
4931 |
15682 |
: d_partialModel.getLowerBoundConstraint(v); |
4932 |
10532 |
if(c != NullConstraint){ |
4933 |
630 |
tmp.first = Constraint::externalExplainByAssertions({c}); |
4934 |
630 |
tmp.second = c->getValue(); |
4935 |
|
} |
4936 |
|
} |
4937 |
|
} |
4938 |
|
|
4939 |
37680 |
void TheoryArithPrivate::entailmentCheckRowSum(std::pair<Node, DeltaRational>& tmp, int sgn, TNode tp) const { |
4940 |
37680 |
tmp.first = Node::null(); |
4941 |
71830 |
if(sgn == 0){ return; } |
4942 |
18906 |
if(tp.getKind() != PLUS){ return; } |
4943 |
12528 |
Assert(Polynomial::isMember(tp)); |
4944 |
|
|
4945 |
12528 |
tmp.second = DeltaRational(0); |
4946 |
16058 |
NodeBuilder nb(kind::AND); |
4947 |
|
|
4948 |
16058 |
Polynomial p = Polynomial::parsePolynomial(tp); |
4949 |
24348 |
for(Polynomial::iterator i = p.begin(), iend = p.end(); i != iend; ++i) { |
4950 |
32638 |
Monomial m = *i; |
4951 |
32638 |
Node x = m.getVarList().getNode(); |
4952 |
20818 |
if(d_partialModel.hasArithVar(x)){ |
4953 |
20774 |
ArithVar v = d_partialModel.asArithVar(x); |
4954 |
20774 |
const Rational& coeff = m.getConstant().getValue(); |
4955 |
20774 |
int dir = sgn * coeff.sgn(); |
4956 |
|
ConstraintP c = (dir > 0) |
4957 |
29064 |
? d_partialModel.getUpperBoundConstraint(v) |
4958 |
29064 |
: d_partialModel.getLowerBoundConstraint(v); |
4959 |
20774 |
if(c != NullConstraint){ |
4960 |
11820 |
tmp.second += c->getValue() * coeff; |
4961 |
11820 |
c->externalExplainByAssertions(nb); |
4962 |
|
}else{ |
4963 |
|
//failed |
4964 |
8954 |
return; |
4965 |
|
} |
4966 |
|
}else{ |
4967 |
|
// failed |
4968 |
44 |
return; |
4969 |
|
} |
4970 |
|
} |
4971 |
|
// success |
4972 |
3530 |
tmp.first = nb; |
4973 |
|
} |
4974 |
|
|
4975 |
3768 |
ArithProofRuleChecker* TheoryArithPrivate::getProofChecker() |
4976 |
|
{ |
4977 |
3768 |
return &d_checker; |
4978 |
|
} |
4979 |
|
|
4980 |
|
} // namespace arith |
4981 |
|
} // namespace theory |
4982 |
29340 |
} // namespace cvc5 |