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