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