1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Tim King, Mathias Preiner, Morgan Deters |
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 |
|
* This module maintains the relationship between a Tableau and |
14 |
|
* PartialModel. |
15 |
|
* |
16 |
|
* This shares with the theory a Tableau, and a PartialModel that: |
17 |
|
* - satisfies the equalities in the Tableau, and |
18 |
|
* - the assignment for the non-basic variables satisfies their bounds. |
19 |
|
* This maintains the relationship needed by the SimplexDecisionProcedure. |
20 |
|
* |
21 |
|
* In the language of Simplex for DPLL(T), this provides: |
22 |
|
* - update() |
23 |
|
* - pivotAndUpdate() |
24 |
|
* |
25 |
|
* This class also provides utility functions that require |
26 |
|
* using both the Tableau and PartialModel. |
27 |
|
*/ |
28 |
|
|
29 |
|
#include "cvc5_private.h" |
30 |
|
|
31 |
|
#pragma once |
32 |
|
|
33 |
|
#include "options/arith_options.h" |
34 |
|
#include "theory/arith/arithvar.h" |
35 |
|
#include "theory/arith/constraint_forward.h" |
36 |
|
#include "theory/arith/delta_rational.h" |
37 |
|
#include "theory/arith/partial_model.h" |
38 |
|
#include "theory/arith/simplex_update.h" |
39 |
|
#include "theory/arith/tableau.h" |
40 |
|
#include "util/statistics_stats.h" |
41 |
|
|
42 |
|
namespace cvc5 { |
43 |
|
namespace theory { |
44 |
|
namespace arith { |
45 |
|
|
46 |
|
struct Border{ |
47 |
|
// The constraint for the border |
48 |
|
ConstraintP d_bound; |
49 |
|
|
50 |
|
// The change to the nonbasic to reach the border |
51 |
|
DeltaRational d_diff; |
52 |
|
|
53 |
|
// Is reach this value fixing the constraint |
54 |
|
// or is going past this value hurting the constraint |
55 |
|
bool d_areFixing; |
56 |
|
|
57 |
|
// Entry into the tableau |
58 |
|
const Tableau::Entry* d_entry; |
59 |
|
|
60 |
|
// Was this an upper bound or a lower bound? |
61 |
|
bool d_upperbound; |
62 |
|
|
63 |
|
Border(): |
64 |
|
d_bound(NullConstraint) // ignore the other values |
65 |
|
{} |
66 |
|
|
67 |
|
Border(ConstraintP l, const DeltaRational& diff, bool areFixing, const Tableau::Entry* en, bool ub): |
68 |
|
d_bound(l), d_diff(diff), d_areFixing(areFixing), d_entry(en), d_upperbound(ub) |
69 |
|
{} |
70 |
|
|
71 |
|
Border(ConstraintP l, const DeltaRational& diff, bool areFixing, bool ub): |
72 |
|
d_bound(l), d_diff(diff), d_areFixing(areFixing), d_entry(NULL), d_upperbound(ub) |
73 |
|
{} |
74 |
|
bool operator<(const Border& other) const{ |
75 |
|
return d_diff < other.d_diff; |
76 |
|
} |
77 |
|
|
78 |
|
/** d_lim is the nonbasic variable's own bound. */ |
79 |
|
bool ownBorder() const { return d_entry == NULL; } |
80 |
|
|
81 |
|
bool isZero() const { return d_diff.sgn() == 0; } |
82 |
|
static bool nonZero(const Border& b) { return !b.isZero(); } |
83 |
|
|
84 |
|
const Rational& getCoefficient() const { |
85 |
|
Assert(!ownBorder()); |
86 |
|
return d_entry->getCoefficient(); |
87 |
|
} |
88 |
|
void output(std::ostream& out) const; |
89 |
|
}; |
90 |
|
|
91 |
|
inline std::ostream& operator<<(std::ostream& out, const Border& b){ |
92 |
|
b.output(out); |
93 |
|
return out; |
94 |
|
} |
95 |
|
|
96 |
|
typedef std::vector<Border> BorderVec; |
97 |
|
|
98 |
19878 |
class BorderHeap { |
99 |
|
const int d_dir; |
100 |
|
|
101 |
|
class BorderHeapCmp { |
102 |
|
private: |
103 |
|
int d_nbDirection; |
104 |
|
public: |
105 |
19884 |
BorderHeapCmp(int dir): d_nbDirection(dir){} |
106 |
|
bool operator()(const Border& a, const Border& b) const{ |
107 |
|
if(d_nbDirection > 0){ |
108 |
|
// if nb is increasing, |
109 |
|
// this needs to act like a max |
110 |
|
// in order to have a min heap |
111 |
|
return b < a; |
112 |
|
}else{ |
113 |
|
// if nb is decreasing, |
114 |
|
// this needs to act like a min |
115 |
|
// in order to have a max heap |
116 |
|
return a < b; |
117 |
|
} |
118 |
|
} |
119 |
|
}; |
120 |
|
const BorderHeapCmp d_cmp; |
121 |
|
|
122 |
|
BorderVec d_vec; |
123 |
|
|
124 |
|
BorderVec::iterator d_begin; |
125 |
|
|
126 |
|
/** |
127 |
|
* Once this is initialized the top of the heap will always |
128 |
|
* be at d_end - 1 |
129 |
|
*/ |
130 |
|
BorderVec::iterator d_end; |
131 |
|
|
132 |
|
int d_possibleFixes; |
133 |
|
int d_numZeroes; |
134 |
|
|
135 |
|
public: |
136 |
19884 |
BorderHeap(int dir) |
137 |
19884 |
: d_dir(dir), d_cmp(dir), d_possibleFixes(0), d_numZeroes(0) |
138 |
19884 |
{} |
139 |
|
|
140 |
|
void push_back(const Border& b){ |
141 |
|
d_vec.push_back(b); |
142 |
|
if(b.d_areFixing){ |
143 |
|
d_possibleFixes++; |
144 |
|
} |
145 |
|
if(b.d_diff.sgn() == 0){ |
146 |
|
d_numZeroes++; |
147 |
|
} |
148 |
|
} |
149 |
|
|
150 |
|
int numZeroes() const { return d_numZeroes; } |
151 |
|
int possibleFixes() const { return d_possibleFixes; } |
152 |
|
int direction() const { return d_dir; } |
153 |
|
|
154 |
|
void make_heap(){ |
155 |
|
d_begin = d_vec.begin(); |
156 |
|
d_end = d_vec.end(); |
157 |
|
std::make_heap(d_begin, d_end, d_cmp); |
158 |
|
} |
159 |
|
|
160 |
|
void dropNonZeroes(){ |
161 |
|
d_vec.erase(std::remove_if(d_vec.begin(), d_vec.end(), &Border::nonZero), |
162 |
|
d_vec.end()); |
163 |
|
} |
164 |
|
|
165 |
|
const Border& top() const { |
166 |
|
Assert(more()); |
167 |
|
return *d_begin; |
168 |
|
} |
169 |
|
void pop_heap(){ |
170 |
|
Assert(more()); |
171 |
|
|
172 |
|
std::pop_heap(d_begin, d_end, d_cmp); |
173 |
|
--d_end; |
174 |
|
} |
175 |
|
|
176 |
|
BorderVec::const_iterator end() const{ |
177 |
|
return BorderVec::const_iterator(d_end); |
178 |
|
} |
179 |
|
BorderVec::const_iterator begin() const{ |
180 |
|
return BorderVec::const_iterator(d_begin); |
181 |
|
} |
182 |
|
|
183 |
|
inline bool more() const{ return d_begin != d_end; } |
184 |
|
|
185 |
|
inline bool empty() const{ return d_vec.empty(); } |
186 |
|
|
187 |
|
void clear(){ |
188 |
|
d_possibleFixes = 0; |
189 |
|
d_numZeroes = 0; |
190 |
|
d_vec.clear(); |
191 |
|
} |
192 |
|
}; |
193 |
|
|
194 |
|
|
195 |
9939 |
class LinearEqualityModule { |
196 |
|
public: |
197 |
|
typedef ArithVar (LinearEqualityModule::*VarPreferenceFunction)(ArithVar, ArithVar) const; |
198 |
|
|
199 |
|
|
200 |
|
typedef bool (LinearEqualityModule::*UpdatePreferenceFunction)(const UpdateInfo&, const UpdateInfo&) const; |
201 |
|
|
202 |
|
|
203 |
|
private: |
204 |
|
/** |
205 |
|
* Manages information about the assignment and upper and lower bounds on the |
206 |
|
* variables. |
207 |
|
*/ |
208 |
|
ArithVariables& d_variables; |
209 |
|
|
210 |
|
/** Reference to the Tableau to operate upon. */ |
211 |
|
Tableau& d_tableau; |
212 |
|
|
213 |
|
/** Called whenever the value of a basic variable is updated. */ |
214 |
|
BasicVarModelUpdateCallBack d_basicVariableUpdates; |
215 |
|
|
216 |
|
BorderHeap d_increasing; |
217 |
|
BorderHeap d_decreasing; |
218 |
|
std::optional<DeltaRational> d_upperBoundDifference; |
219 |
|
std::optional<DeltaRational> d_lowerBoundDifference; |
220 |
|
|
221 |
|
Rational d_one; |
222 |
|
Rational d_negOne; |
223 |
|
public: |
224 |
|
|
225 |
|
/** |
226 |
|
* Initializes a LinearEqualityModule with a partial model, a tableau, |
227 |
|
* and a callback function for when basic variables update their values. |
228 |
|
*/ |
229 |
|
LinearEqualityModule(ArithVariables& vars, Tableau& t, BoundInfoMap& boundTracking, BasicVarModelUpdateCallBack f); |
230 |
|
|
231 |
|
/** |
232 |
|
* Updates the assignment of a nonbasic variable x_i to v. |
233 |
|
* Also updates the assignment of basic variables accordingly. |
234 |
|
*/ |
235 |
166072 |
void update(ArithVar x_i, const DeltaRational& v){ |
236 |
166072 |
if(d_areTracking){ |
237 |
|
updateTracked(x_i,v); |
238 |
|
}else{ |
239 |
166072 |
updateUntracked(x_i,v); |
240 |
|
} |
241 |
166072 |
} |
242 |
|
|
243 |
|
/** Specialization of update if the module is not tracking yet (for Assert*). */ |
244 |
|
void updateUntracked(ArithVar x_i, const DeltaRational& v); |
245 |
|
|
246 |
|
/** Specialization of update if the module is not tracking yet (for Simplex). */ |
247 |
|
void updateTracked(ArithVar x_i, const DeltaRational& v); |
248 |
|
|
249 |
|
|
250 |
|
/** |
251 |
|
* Updates the value of a basic variable x_i to v, |
252 |
|
* and then pivots x_i with the nonbasic variable in its row x_j. |
253 |
|
* Updates the assignment of the other basic variables accordingly. |
254 |
|
*/ |
255 |
|
void pivotAndUpdate(ArithVar x_i, ArithVar x_j, const DeltaRational& v); |
256 |
|
|
257 |
39768 |
ArithVariables& getVariables() const{ return d_variables; } |
258 |
4196118 |
Tableau& getTableau() const{ return d_tableau; } |
259 |
|
|
260 |
|
/** |
261 |
|
* Updates every non-basic to reflect the assignment in many. |
262 |
|
* For use with ApproximateSimplex. |
263 |
|
*/ |
264 |
|
void updateMany(const DenseMap<DeltaRational>& many); |
265 |
|
void forceNewBasis(const DenseSet& newBasis); |
266 |
|
void applySolution(const DenseSet& newBasis, const DenseMap<DeltaRational>& newValues); |
267 |
|
|
268 |
|
|
269 |
|
/** |
270 |
|
* Returns a pointer to the first Tableau entry on the row ridx that does not |
271 |
|
* have an either a lower bound/upper bound for proving a bound on skip. |
272 |
|
* The variable skip is always excluded. Returns NULL if there is no such element. |
273 |
|
* |
274 |
|
* If skip == ARITHVAR_SENTINEL, this is equivalent to considering the whole row. |
275 |
|
*/ |
276 |
|
const Tableau::Entry* rowLacksBound(RowIndex ridx, bool upperBound, ArithVar skip); |
277 |
|
|
278 |
|
|
279 |
|
void startTrackingBoundCounts(); |
280 |
|
void stopTrackingBoundCounts(); |
281 |
|
|
282 |
|
|
283 |
|
void includeBoundUpdate(ArithVar nb, const BoundsInfo& prev); |
284 |
|
|
285 |
|
|
286 |
|
uint32_t updateProduct(const UpdateInfo& inf) const; |
287 |
|
|
288 |
|
inline bool minNonBasicVarOrder(const UpdateInfo& a, const UpdateInfo& b) const{ |
289 |
|
return a.nonbasic() >= b.nonbasic(); |
290 |
|
} |
291 |
|
|
292 |
|
/** |
293 |
|
* Prefer the update that touch the fewest entries in the matrix. |
294 |
|
* |
295 |
|
* The intuition is that this operation will be cheaper. |
296 |
|
* This strongly biases the system towards updates instead of pivots. |
297 |
|
*/ |
298 |
|
inline bool minProduct(const UpdateInfo& a, const UpdateInfo& b) const{ |
299 |
|
uint32_t aprod = updateProduct(a); |
300 |
|
uint32_t bprod = updateProduct(b); |
301 |
|
|
302 |
|
if(aprod == bprod){ |
303 |
|
return minNonBasicVarOrder(a,b); |
304 |
|
}else{ |
305 |
|
return aprod > bprod; |
306 |
|
} |
307 |
|
} |
308 |
|
inline bool constrainedMin(const UpdateInfo& a, const UpdateInfo& b) const{ |
309 |
|
if(a.describesPivot() && b.describesPivot()){ |
310 |
|
bool aAtBounds = basicsAtBounds(a); |
311 |
|
bool bAtBounds = basicsAtBounds(b); |
312 |
|
if(aAtBounds != bAtBounds){ |
313 |
|
return bAtBounds; |
314 |
|
} |
315 |
|
} |
316 |
|
return minProduct(a,b); |
317 |
|
} |
318 |
|
|
319 |
|
/** |
320 |
|
* If both a and b are pivots, prefer the pivot with the leaving variables that has equal bounds. |
321 |
|
* The intuition is that such variables will be less likely to lead to future problems. |
322 |
|
*/ |
323 |
|
inline bool preferFrozen(const UpdateInfo& a, const UpdateInfo& b) const { |
324 |
|
if(a.describesPivot() && b.describesPivot()){ |
325 |
|
bool aFrozen = d_variables.boundsAreEqual(a.leaving()); |
326 |
|
bool bFrozen = d_variables.boundsAreEqual(b.leaving()); |
327 |
|
|
328 |
|
if(aFrozen != bFrozen){ |
329 |
|
return bFrozen; |
330 |
|
} |
331 |
|
} |
332 |
|
return constrainedMin(a,b); |
333 |
|
} |
334 |
|
|
335 |
|
/** |
336 |
|
* Prefer pivots with entering variables that do not have bounds. |
337 |
|
* The intuition is that such variables will be less likely to lead to future problems. |
338 |
|
*/ |
339 |
|
bool preferNeitherBound(const UpdateInfo& a, const UpdateInfo& b) const { |
340 |
|
if(d_variables.hasEitherBound(a.nonbasic()) == d_variables.hasEitherBound(b.nonbasic())){ |
341 |
|
return preferFrozen(a,b); |
342 |
|
}else{ |
343 |
|
return d_variables.hasEitherBound(a.nonbasic()); |
344 |
|
} |
345 |
|
} |
346 |
|
|
347 |
|
bool modifiedBlands(const UpdateInfo& a, const UpdateInfo& b) const { |
348 |
|
Assert(a.focusDirection() == 0 && b.focusDirection() == 0); |
349 |
|
Assert(a.describesPivot()); |
350 |
|
Assert(b.describesPivot()); |
351 |
|
if(a.nonbasic() == b.nonbasic()){ |
352 |
|
bool aIsZero = a.nonbasicDelta().sgn() == 0; |
353 |
|
bool bIsZero = b.nonbasicDelta().sgn() == 0; |
354 |
|
|
355 |
|
if((aIsZero || bIsZero) && (!aIsZero || !bIsZero)){ |
356 |
|
return bIsZero; |
357 |
|
}else{ |
358 |
|
return a.leaving() >= b.leaving(); |
359 |
|
} |
360 |
|
}else{ |
361 |
|
return a.nonbasic() > b.nonbasic(); |
362 |
|
} |
363 |
|
} |
364 |
|
|
365 |
|
template <bool heuristic> |
366 |
|
bool preferWitness(const UpdateInfo& a, const UpdateInfo& b) const{ |
367 |
|
WitnessImprovement aImp = a.getWitness(!heuristic); |
368 |
|
WitnessImprovement bImp = b.getWitness(!heuristic); |
369 |
|
|
370 |
|
if(aImp == bImp){ |
371 |
|
switch(aImp){ |
372 |
|
case ConflictFound: |
373 |
|
return preferNeitherBound(a,b); |
374 |
|
case ErrorDropped: |
375 |
|
if(a.errorsChange() == b.errorsChange()){ |
376 |
|
return preferNeitherBound(a,b); |
377 |
|
}else{ |
378 |
|
return a.errorsChange() > b.errorsChange(); |
379 |
|
} |
380 |
|
case FocusImproved: |
381 |
|
return preferNeitherBound(a,b); |
382 |
|
case BlandsDegenerate: |
383 |
|
Assert(a.describesPivot()); |
384 |
|
Assert(b.describesPivot()); |
385 |
|
Assert(a.focusDirection() == 0 && b.focusDirection() == 0); |
386 |
|
return modifiedBlands(a,b); |
387 |
|
case HeuristicDegenerate: |
388 |
|
Assert(a.describesPivot()); |
389 |
|
Assert(b.describesPivot()); |
390 |
|
Assert(a.focusDirection() == 0 && b.focusDirection() == 0); |
391 |
|
return preferNeitherBound(a,b); |
392 |
|
case AntiProductive: |
393 |
|
return minNonBasicVarOrder(a, b); |
394 |
|
// Not valid responses |
395 |
|
case Degenerate: |
396 |
|
case FocusShrank: |
397 |
|
Unreachable(); |
398 |
|
} |
399 |
|
Unreachable(); |
400 |
|
}else{ |
401 |
|
return aImp > bImp; |
402 |
|
} |
403 |
|
} |
404 |
|
|
405 |
|
private: |
406 |
|
|
407 |
|
/** |
408 |
|
* This maps each row index to its relevant bounds info. |
409 |
|
* This tracks the count for how many variables on a row have bounds |
410 |
|
* and how many are assigned at their bounds. |
411 |
|
*/ |
412 |
|
BoundInfoMap& d_btracking; |
413 |
|
bool d_areTracking; |
414 |
|
|
415 |
|
public: |
416 |
|
/** |
417 |
|
* The constraint on a basic variable b is implied by the constraints |
418 |
|
* on its row. This is a wrapper for propagateRow(). |
419 |
|
*/ |
420 |
|
void propagateBasicFromRow(ConstraintP c); |
421 |
|
|
422 |
|
/** |
423 |
|
* Let v be the variable for the constraint c. |
424 |
|
* Exports either the explanation of an upperbound or a lower bound |
425 |
|
* of v using the other variables in the row. |
426 |
|
* |
427 |
|
* If farkas != RationalVectorPSentinel, this function additionally |
428 |
|
* stores the farkas coefficients of the constraints stored in into. |
429 |
|
* Position 0 is the coefficient of v. |
430 |
|
* Position i > 0, corresponds to the order of the other constraints. |
431 |
|
*/ |
432 |
|
void propagateRow(ConstraintCPVec& into |
433 |
|
, RowIndex ridx |
434 |
|
, bool rowUp |
435 |
|
, ConstraintP c |
436 |
|
, RationalVectorP farkas); |
437 |
|
|
438 |
|
/** |
439 |
|
* Computes the value of a basic variable using the assignments |
440 |
|
* of the values of the variables in the basic variable's row tableau. |
441 |
|
* This can compute the value using either: |
442 |
|
* - the the current assignment (useSafe=false) or |
443 |
|
* - the safe assignment (useSafe = true). |
444 |
|
*/ |
445 |
|
DeltaRational computeRowValue(ArithVar x, bool useSafe) const; |
446 |
|
|
447 |
|
/** |
448 |
|
* A PreferenceFunction takes a const ref to the SimplexDecisionProcedure, |
449 |
|
* and 2 ArithVar variables and returns one of the ArithVar variables |
450 |
|
* potentially using the internals of the SimplexDecisionProcedure. |
451 |
|
*/ |
452 |
|
|
453 |
|
ArithVar noPreference(ArithVar x, ArithVar y) const{ |
454 |
|
return x; |
455 |
|
} |
456 |
|
|
457 |
|
/** |
458 |
|
* minVarOrder is a PreferenceFunction for selecting the smaller of the 2 |
459 |
|
* ArithVars. This PreferenceFunction is used during the VarOrder stage of |
460 |
|
* findModel. |
461 |
|
*/ |
462 |
|
ArithVar minVarOrder(ArithVar x, ArithVar y) const; |
463 |
|
|
464 |
|
/** |
465 |
|
* minColLength is a PreferenceFunction for selecting the variable with the |
466 |
|
* smaller row count in the tableau. |
467 |
|
* |
468 |
|
* This is a heuristic rule and should not be used during the VarOrder |
469 |
|
* stage of findModel. |
470 |
|
*/ |
471 |
|
ArithVar minColLength(ArithVar x, ArithVar y) const; |
472 |
|
|
473 |
|
/** |
474 |
|
* minRowLength is a PreferenceFunction for selecting the variable with the |
475 |
|
* smaller row count in the tableau. |
476 |
|
* |
477 |
|
* This is a heuristic rule and should not be used during the VarOrder |
478 |
|
* stage of findModel. |
479 |
|
*/ |
480 |
|
ArithVar minRowLength(ArithVar x, ArithVar y) const; |
481 |
|
|
482 |
|
/** |
483 |
|
* minBoundAndRowCount is a PreferenceFunction for preferring a variable |
484 |
|
* without an asserted bound over variables with an asserted bound. |
485 |
|
* If both have bounds or both do not have bounds, |
486 |
|
* the rule falls back to minRowCount(...). |
487 |
|
* |
488 |
|
* This is a heuristic rule and should not be used during the VarOrder |
489 |
|
* stage of findModel. |
490 |
|
*/ |
491 |
|
ArithVar minBoundAndColLength(ArithVar x, ArithVar y) const; |
492 |
|
|
493 |
|
|
494 |
|
template <bool above> |
495 |
4752474 |
inline bool isAcceptableSlack(int sgn, ArithVar nonbasic) const { |
496 |
|
return |
497 |
550334 |
( above && sgn < 0 && d_variables.strictlyBelowUpperBound(nonbasic)) || |
498 |
682893 |
( above && sgn > 0 && d_variables.strictlyAboveLowerBound(nonbasic)) || |
499 |
5826015 |
(!above && sgn > 0 && d_variables.strictlyBelowUpperBound(nonbasic)) || |
500 |
7163253 |
(!above && sgn < 0 && d_variables.strictlyAboveLowerBound(nonbasic)); |
501 |
|
} |
502 |
|
|
503 |
|
/** |
504 |
|
* Given the basic variable x_i, |
505 |
|
* this function finds the smallest nonbasic variable x_j in the row of x_i |
506 |
|
* in the tableau that can "take up the slack" to let x_i satisfy its bounds. |
507 |
|
* This returns ARITHVAR_SENTINEL if none exists. |
508 |
|
* |
509 |
|
* More formally one of the following conditions must be satisfied: |
510 |
|
* - lowerBound && a_ij < 0 && assignment(x_j) < upperbound(x_j) |
511 |
|
* - lowerBound && a_ij > 0 && assignment(x_j) > lowerbound(x_j) |
512 |
|
* - !lowerBound && a_ij > 0 && assignment(x_j) < upperbound(x_j) |
513 |
|
* - !lowerBound && a_ij < 0 && assignment(x_j) > lowerbound(x_j) |
514 |
|
* |
515 |
|
*/ |
516 |
|
template <bool lowerBound> ArithVar selectSlack(ArithVar x_i, VarPreferenceFunction pf) const; |
517 |
98715 |
ArithVar selectSlackLowerBound(ArithVar x_i, VarPreferenceFunction pf) const { |
518 |
98715 |
return selectSlack<true>(x_i, pf); |
519 |
|
} |
520 |
112509 |
ArithVar selectSlackUpperBound(ArithVar x_i, VarPreferenceFunction pf) const { |
521 |
112509 |
return selectSlack<false>(x_i, pf); |
522 |
|
} |
523 |
|
|
524 |
|
const Tableau::Entry* selectSlackEntry(ArithVar x_i, bool above) const; |
525 |
|
|
526 |
68238470 |
inline bool rowIndexIsTracked(RowIndex ridx) const { |
527 |
68238470 |
return d_btracking.isKey(ridx); |
528 |
|
} |
529 |
6713571 |
inline bool basicIsTracked(ArithVar v) const { |
530 |
6713571 |
return rowIndexIsTracked(d_tableau.basicToRowIndex(v)); |
531 |
|
} |
532 |
|
void trackRowIndex(RowIndex ridx); |
533 |
|
void stopTrackingRowIndex(RowIndex ridx){ |
534 |
|
Assert(rowIndexIsTracked(ridx)); |
535 |
|
d_btracking.remove(ridx); |
536 |
|
} |
537 |
|
|
538 |
|
/** |
539 |
|
* If the pivot described in u were performed, |
540 |
|
* then the row would qualify as being either at the minimum/maximum |
541 |
|
* to the non-basics being at their bounds. |
542 |
|
* The minimum/maximum is determined by the direction the non-basic is changing. |
543 |
|
*/ |
544 |
|
bool basicsAtBounds(const UpdateInfo& u) const; |
545 |
|
|
546 |
|
private: |
547 |
|
|
548 |
|
/** |
549 |
|
* Recomputes the bound info for a row using either the information |
550 |
|
* in the bounds queue or the current information. |
551 |
|
* O(row length of ridx) |
552 |
|
*/ |
553 |
|
BoundsInfo computeRowBoundInfo(RowIndex ridx, bool inQueue) const; |
554 |
|
|
555 |
|
public: |
556 |
|
/** Debug only routine. */ |
557 |
|
BoundCounts debugBasicAtBoundCount(ArithVar x_i) const; |
558 |
|
|
559 |
|
/** Track the effect of the change of coefficient for bound counting. */ |
560 |
|
void trackingCoefficientChange(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn); |
561 |
|
|
562 |
|
/** Track the effect of multiplying a row by a sign for bound counting. */ |
563 |
|
void trackingMultiplyRow(RowIndex ridx, int sgn); |
564 |
|
|
565 |
|
/** Count for how many on a row have *an* upper/lower bounds. */ |
566 |
10005778 |
BoundCounts hasBoundCount(RowIndex ri) const { |
567 |
10005778 |
Assert(d_variables.boundsQueueEmpty()); |
568 |
10005778 |
return d_btracking[ri].hasBounds(); |
569 |
|
} |
570 |
|
|
571 |
|
/** |
572 |
|
* Are there any non-basics on x_i's row that are not at |
573 |
|
* their respective lower bounds (mod sgns). |
574 |
|
* O(1) time due to the atBound() count. |
575 |
|
*/ |
576 |
|
bool nonbasicsAtLowerBounds(ArithVar x_i) const; |
577 |
|
|
578 |
|
/** |
579 |
|
* Are there any non-basics on x_i's row that are not at |
580 |
|
* their respective upper bounds (mod sgns). |
581 |
|
* O(1) time due to the atBound() count. |
582 |
|
*/ |
583 |
|
bool nonbasicsAtUpperBounds(ArithVar x_i) const; |
584 |
|
|
585 |
|
private: |
586 |
9939 |
class TrackingCallback : public CoefficientChangeCallback { |
587 |
|
private: |
588 |
|
LinearEqualityModule* d_linEq; |
589 |
|
public: |
590 |
9942 |
TrackingCallback(LinearEqualityModule* le) : d_linEq(le) {} |
591 |
56851112 |
void update(RowIndex ridx, ArithVar nb, int oldSgn, int currSgn) override |
592 |
|
{ |
593 |
56851112 |
d_linEq->trackingCoefficientChange(ridx, nb, oldSgn, currSgn); |
594 |
56851112 |
} |
595 |
211224 |
void multiplyRow(RowIndex ridx, int sgn) override |
596 |
|
{ |
597 |
211224 |
d_linEq->trackingMultiplyRow(ridx, sgn); |
598 |
211224 |
} |
599 |
4156350 |
bool canUseRow(RowIndex ridx) const override |
600 |
|
{ |
601 |
4156350 |
ArithVar basic = d_linEq->getTableau().rowIndexToBasic(ridx); |
602 |
4156350 |
return d_linEq->basicIsTracked(basic); |
603 |
|
} |
604 |
|
} d_trackCallback; |
605 |
|
|
606 |
|
/** |
607 |
|
* Selects the constraint for the variable v on the row for basic |
608 |
|
* with the weakest possible constraint that is consistent with the surplus |
609 |
|
* surplus. |
610 |
|
*/ |
611 |
|
ConstraintP weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, |
612 |
|
const Rational& coeff, bool& anyWeakening, ArithVar basic) const; |
613 |
|
|
614 |
|
public: |
615 |
|
/** |
616 |
|
* Constructs a minimally weak conflict for the basic variable basicVar. |
617 |
|
* |
618 |
|
* Returns a constraint that is now in conflict. |
619 |
|
*/ |
620 |
|
ConstraintCP minimallyWeakConflict(bool aboveUpper, ArithVar basicVar, FarkasConflictBuilder& rc) const; |
621 |
|
|
622 |
|
/** |
623 |
|
* Given a basic variable that is know to have a conflict on it, |
624 |
|
* construct and return a conflict. |
625 |
|
* Follows section 4.2 in the CAV06 paper. |
626 |
|
*/ |
627 |
31501 |
inline ConstraintCP generateConflictAboveUpperBound(ArithVar conflictVar, FarkasConflictBuilder& rc) const { |
628 |
31501 |
return minimallyWeakConflict(true, conflictVar, rc); |
629 |
|
} |
630 |
|
|
631 |
39677 |
inline ConstraintCP generateConflictBelowLowerBound(ArithVar conflictVar, FarkasConflictBuilder& rc) const { |
632 |
39677 |
return minimallyWeakConflict(false, conflictVar, rc); |
633 |
|
} |
634 |
|
|
635 |
|
/** |
636 |
|
* Computes the sum of the upper/lower bound of row. |
637 |
|
* The variable skip is not included in the sum. |
638 |
|
*/ |
639 |
|
DeltaRational computeRowBound(RowIndex ridx, bool rowUb, ArithVar skip) const; |
640 |
|
|
641 |
|
public: |
642 |
|
void substitutePlusTimesConstant(ArithVar to, ArithVar from, const Rational& mult); |
643 |
|
void directlyAddToCoefficient(ArithVar row, ArithVar col, const Rational& mult); |
644 |
|
|
645 |
|
|
646 |
|
/** |
647 |
|
* Checks to make sure the assignment is consistent with the tableau. |
648 |
|
* This code is for debugging. |
649 |
|
*/ |
650 |
|
void debugCheckTableau(); |
651 |
|
|
652 |
|
void debugCheckTracking(); |
653 |
|
|
654 |
|
/** Debugging information for a pivot. */ |
655 |
|
void debugPivot(ArithVar x_i, ArithVar x_j); |
656 |
|
|
657 |
|
/** Checks the tableau + partial model for consistency. */ |
658 |
|
bool debugEntireLinEqIsConsistent(const std::string& s); |
659 |
|
|
660 |
|
|
661 |
|
ArithVar minBy(const ArithVarVec& vec, VarPreferenceFunction pf) const; |
662 |
|
|
663 |
|
/** |
664 |
|
* Returns true if there would be a conflict on this row after a pivot |
665 |
|
* and update using its basic variable and one of the non-basic variables on |
666 |
|
* the row. |
667 |
|
*/ |
668 |
|
bool willBeInConflictAfterPivot(const Tableau::Entry& entry, const DeltaRational& nbDiff, bool bToUB) const; |
669 |
|
UpdateInfo mkConflictUpdate(const Tableau::Entry& entry, bool ub) const; |
670 |
|
|
671 |
|
/** |
672 |
|
* Looks more an update for fcSimplex on the nonbasic variable nb with the focus coefficient. |
673 |
|
*/ |
674 |
|
UpdateInfo speculativeUpdate(ArithVar nb, const Rational& focusCoeff, UpdatePreferenceFunction pref); |
675 |
|
|
676 |
|
private: |
677 |
|
|
678 |
|
/** |
679 |
|
* Examines the effects of pivoting the entries column variable |
680 |
|
* with the row's basic variable and setting the variable s.t. |
681 |
|
* the basic variable is equal to one of its bounds. |
682 |
|
* |
683 |
|
* If ub, then the basic variable will be equal its upper bound. |
684 |
|
* If not ub,then the basic variable will be equal its lower bound. |
685 |
|
* |
686 |
|
* Returns iff this row will be in conflict after the pivot. |
687 |
|
* |
688 |
|
* If this is false, add the bound to the relevant heap. |
689 |
|
* If the bound is +/-infinity, this is ignored. |
690 |
|
|
691 |
|
* |
692 |
|
* Returns true if this would be a conflict. |
693 |
|
* If it returns false, this |
694 |
|
*/ |
695 |
|
bool accumulateBorder(const Tableau::Entry& entry, bool ub); |
696 |
|
|
697 |
|
void handleBorders(UpdateInfo& selected, ArithVar nb, const Rational& focusCoeff, BorderHeap& heap, int minimumFixes, UpdatePreferenceFunction pref); |
698 |
|
void pop_block(BorderHeap& heap, int& brokenInBlock, int& fixesRemaining, int& negErrorChange); |
699 |
|
void clearSpeculative(); |
700 |
|
Rational updateCoefficient(BorderVec::const_iterator startBlock, BorderVec::const_iterator endBlock); |
701 |
|
|
702 |
|
private: |
703 |
|
/** These fields are designed to be accessible to TheoryArith methods. */ |
704 |
|
class Statistics { |
705 |
|
public: |
706 |
|
IntStat d_statPivots, d_statUpdates; |
707 |
|
TimerStat d_pivotTime; |
708 |
|
TimerStat d_adjTime; |
709 |
|
|
710 |
|
IntStat d_weakeningAttempts, d_weakeningSuccesses, d_weakenings; |
711 |
|
TimerStat d_weakenTime; |
712 |
|
TimerStat d_forceTime; |
713 |
|
|
714 |
|
Statistics(); |
715 |
|
}; |
716 |
|
mutable Statistics d_statistics; |
717 |
|
|
718 |
|
};/* class LinearEqualityModule */ |
719 |
|
|
720 |
|
struct Cand { |
721 |
|
ArithVar d_nb; |
722 |
|
uint32_t d_penalty; |
723 |
|
int d_sgn; |
724 |
|
const Rational* d_coeff; |
725 |
|
|
726 |
|
Cand(ArithVar nb, uint32_t penalty, int s, const Rational* c) : |
727 |
|
d_nb(nb), d_penalty(penalty), d_sgn(s), d_coeff(c){} |
728 |
|
}; |
729 |
|
|
730 |
|
|
731 |
|
class CompPenaltyColLength { |
732 |
|
private: |
733 |
|
LinearEqualityModule* d_mod; |
734 |
|
public: |
735 |
|
CompPenaltyColLength(LinearEqualityModule* mod): d_mod(mod){} |
736 |
|
|
737 |
|
bool operator()(const Cand& x, const Cand& y) const { |
738 |
|
if(x.d_penalty == y.d_penalty || !options::havePenalties()){ |
739 |
|
return x.d_nb == d_mod->minBoundAndColLength(x.d_nb,y.d_nb); |
740 |
|
}else{ |
741 |
|
return x.d_penalty < y.d_penalty; |
742 |
|
} |
743 |
|
} |
744 |
|
}; |
745 |
|
|
746 |
2934328 |
class UpdateTrackingCallback : public BoundUpdateCallback { |
747 |
|
private: |
748 |
|
LinearEqualityModule* d_mod; |
749 |
|
public: |
750 |
2934328 |
UpdateTrackingCallback(LinearEqualityModule* mod): d_mod(mod){} |
751 |
4883208 |
void operator()(ArithVar v, const BoundsInfo& bi) override |
752 |
|
{ |
753 |
4883208 |
d_mod->includeBoundUpdate(v, bi); |
754 |
4883208 |
} |
755 |
|
}; |
756 |
|
|
757 |
|
} // namespace arith |
758 |
|
} // namespace theory |
759 |
|
} // namespace cvc5 |