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