1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Tim King, Morgan Deters, Mathias Preiner |
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 is an implementation of the Simplex Module for the Simplex for |
14 |
|
* DPLL(T)decision procedure. |
15 |
|
* |
16 |
|
* This implements the Simplex module for the Simpelx for DPLL(T) decision |
17 |
|
* procedure. |
18 |
|
* See the Simplex for DPLL(T) technical report for more background.(citation?) |
19 |
|
* This shares with the theory a Tableau, and a PartialModel that: |
20 |
|
* - satisfies the equalities in the Tableau, and |
21 |
|
* - the assignment for the non-basic variables satisfies their bounds. |
22 |
|
* This is required to either produce a conflict or satisifying PartialModel. |
23 |
|
* Further, we require being told when a basic variable updates its value. |
24 |
|
* |
25 |
|
* During the Simplex search we maintain a queue of variables. |
26 |
|
* The queue is required to contain all of the basic variables that voilate |
27 |
|
* their bounds. |
28 |
|
* As elimination from the queue is more efficient to be done lazily, |
29 |
|
* we do not maintain that the queue of variables needs to be only basic |
30 |
|
* variables or only variables that satisfy their bounds. |
31 |
|
* |
32 |
|
* The simplex procedure roughly follows Alberto's thesis. (citation?) |
33 |
|
* There is one round of selecting using a heuristic pivoting rule. |
34 |
|
* (See PreferenceFunction Documentation for the available options.) |
35 |
|
* The non-basic variable is the one that appears in the fewest pivots. |
36 |
|
* (Bruno says that Leonardo invented this first.) |
37 |
|
* After this, Bland's pivot rule is invoked. |
38 |
|
* |
39 |
|
* During this proccess, we periodically inspect the queue of variables to |
40 |
|
* 1) remove now extraneous extries, |
41 |
|
* 2) detect conflicts that are "waiting" on the queue but may not be detected |
42 |
|
* by the current queue heuristics, and |
43 |
|
* 3) detect multiple conflicts. |
44 |
|
* |
45 |
|
* Conflicts are greedily slackened to use the weakest bounds that still |
46 |
|
* produce the conflict. |
47 |
|
* |
48 |
|
* Extra things tracked atm: (Subject to change at Tim's whims) |
49 |
|
* - A superset of all of the newly pivoted variables. |
50 |
|
* - A queue of additional conflicts that were discovered by Simplex. |
51 |
|
* These are theory valid and are currently turned into lemmas |
52 |
|
*/ |
53 |
|
|
54 |
|
#include "cvc5_private.h" |
55 |
|
|
56 |
|
#pragma once |
57 |
|
|
58 |
|
#include "theory/arith/error_set.h" |
59 |
|
#include "theory/arith/linear_equality.h" |
60 |
|
#include "theory/arith/simplex.h" |
61 |
|
#include "theory/arith/simplex_update.h" |
62 |
|
#include "util/dense_map.h" |
63 |
|
#include "util/statistics_stats.h" |
64 |
|
|
65 |
|
namespace cvc5 { |
66 |
|
namespace theory { |
67 |
|
namespace arith { |
68 |
|
|
69 |
9853 |
class FCSimplexDecisionProcedure : public SimplexDecisionProcedure{ |
70 |
|
public: |
71 |
|
FCSimplexDecisionProcedure(LinearEqualityModule& linEq, ErrorSet& errors, RaiseConflict conflictChannel, TempVarMalloc tvmalloc); |
72 |
|
|
73 |
|
Result::Sat findModel(bool exactResult) override; |
74 |
|
|
75 |
|
// other error variables are dropping |
76 |
|
WitnessImprovement dualLikeImproveError(ArithVar evar); |
77 |
|
WitnessImprovement primalImproveError(ArithVar evar); |
78 |
|
|
79 |
|
// dual like |
80 |
|
// - found conflict |
81 |
|
// - satisfied error set |
82 |
|
Result::Sat dualLike(); |
83 |
|
|
84 |
|
private: |
85 |
|
static const uint32_t PENALTY = 4; |
86 |
|
DenseMultiset d_scores; |
87 |
|
void decreasePenalties(){ d_scores.removeOneOfEverything(); } |
88 |
|
uint32_t penalty(ArithVar x) const { return d_scores.count(x); } |
89 |
|
void setPenalty(ArithVar x, WitnessImprovement w){ |
90 |
|
if(improvement(w)){ |
91 |
|
if(d_scores.count(x) > 0){ |
92 |
|
d_scores.removeAll(x); |
93 |
|
} |
94 |
|
}else{ |
95 |
|
d_scores.setCount(x, PENALTY); |
96 |
|
} |
97 |
|
} |
98 |
|
|
99 |
|
/** The size of the focus set. */ |
100 |
|
uint32_t d_focusSize; |
101 |
|
|
102 |
|
/** The current error focus variable. */ |
103 |
|
ArithVar d_focusErrorVar; |
104 |
|
|
105 |
|
/** |
106 |
|
* The signs of the coefficients in the focus set. |
107 |
|
* This is empty until this has been loaded. |
108 |
|
*/ |
109 |
|
DenseMap<const Rational*> d_focusCoefficients; |
110 |
|
|
111 |
|
/** |
112 |
|
* Loads the signs of the coefficients of the variables on the row d_focusErrorVar |
113 |
|
* into d_focusSgns. |
114 |
|
*/ |
115 |
|
void loadFocusSigns(); |
116 |
|
|
117 |
|
/** Unloads the information from d_focusSgns. */ |
118 |
|
void unloadFocusSigns(); |
119 |
|
|
120 |
|
/** |
121 |
|
* The signs of a variable in the row of d_focusErrorVar. |
122 |
|
* d_focusSgns must be loaded. |
123 |
|
*/ |
124 |
|
const Rational& focusCoefficient(ArithVar nb) const; |
125 |
|
|
126 |
|
int32_t d_pivotBudget; |
127 |
|
// enum PivotImprovement { |
128 |
|
// ErrorDropped, |
129 |
|
// NonDegenerate, |
130 |
|
// HeuristicDegenerate, |
131 |
|
// BlandsDegenerate |
132 |
|
// }; |
133 |
|
|
134 |
|
WitnessImprovement d_prevWitnessImprovement; |
135 |
|
uint32_t d_witnessImprovementInARow; |
136 |
|
|
137 |
|
uint32_t degeneratePivotsInARow() const; |
138 |
|
|
139 |
|
static const uint32_t s_focusThreshold = 6; |
140 |
|
static const uint32_t s_maxDegeneratePivotsBeforeBlandsOnLeaving = 100; |
141 |
|
static const uint32_t s_maxDegeneratePivotsBeforeBlandsOnEntering = 10; |
142 |
|
|
143 |
|
DenseMap<uint32_t> d_leavingCountSinceImprovement; |
144 |
|
void increaseLeavingCount(ArithVar x){ |
145 |
|
if(!d_leavingCountSinceImprovement.isKey(x)){ |
146 |
|
d_leavingCountSinceImprovement.set(x,1); |
147 |
|
}else{ |
148 |
|
(d_leavingCountSinceImprovement.get(x))++; |
149 |
|
} |
150 |
|
} |
151 |
|
LinearEqualityModule::UpdatePreferenceFunction selectLeavingFunction(ArithVar x){ |
152 |
|
bool useBlands = d_leavingCountSinceImprovement.isKey(x) && |
153 |
|
d_leavingCountSinceImprovement[x] >= s_maxDegeneratePivotsBeforeBlandsOnEntering; |
154 |
|
if(useBlands) { |
155 |
|
return &LinearEqualityModule::preferWitness<false>; |
156 |
|
} else { |
157 |
|
return &LinearEqualityModule::preferWitness<true>; |
158 |
|
} |
159 |
|
} |
160 |
|
|
161 |
|
bool debugDualLike(WitnessImprovement w, std::ostream& out, |
162 |
|
int instance, |
163 |
|
uint32_t prevFocusSize, uint32_t prevErrorSize) const; |
164 |
|
|
165 |
|
void debugPrintSignal(ArithVar updated) const; |
166 |
|
|
167 |
|
ArithVarVec d_sgnDisagreements; |
168 |
|
|
169 |
|
//static PivotImprovement pivotImprovement(const UpdateInfo& selected, bool useBlands = false); |
170 |
|
|
171 |
|
void logPivot(WitnessImprovement w); |
172 |
|
|
173 |
|
void updateAndSignal(const UpdateInfo& selected, WitnessImprovement w); |
174 |
|
|
175 |
|
UpdateInfo selectPrimalUpdate(ArithVar error, |
176 |
|
LinearEqualityModule::UpdatePreferenceFunction upf, |
177 |
|
LinearEqualityModule::VarPreferenceFunction bpf); |
178 |
|
|
179 |
|
|
180 |
|
UpdateInfo selectUpdateForDualLike(ArithVar basic){ |
181 |
|
TimerStat::CodeTimer codeTimer(d_statistics.d_selectUpdateForDualLike); |
182 |
|
|
183 |
|
LinearEqualityModule::UpdatePreferenceFunction upf = |
184 |
|
&LinearEqualityModule::preferWitness<true>; |
185 |
|
LinearEqualityModule::VarPreferenceFunction bpf = |
186 |
|
&LinearEqualityModule::minVarOrder; |
187 |
|
return selectPrimalUpdate(basic, upf, bpf); |
188 |
|
} |
189 |
|
|
190 |
|
UpdateInfo selectUpdateForPrimal(ArithVar basic, bool useBlands){ |
191 |
|
TimerStat::CodeTimer codeTimer(d_statistics.d_selectUpdateForPrimal); |
192 |
|
|
193 |
|
LinearEqualityModule::UpdatePreferenceFunction upf; |
194 |
|
if(useBlands) { |
195 |
|
upf = &LinearEqualityModule::preferWitness<false>; |
196 |
|
} else { |
197 |
|
upf = &LinearEqualityModule::preferWitness<true>; |
198 |
|
} |
199 |
|
|
200 |
|
LinearEqualityModule::VarPreferenceFunction bpf = useBlands ? |
201 |
|
&LinearEqualityModule::minVarOrder : |
202 |
|
&LinearEqualityModule::minRowLength; |
203 |
|
|
204 |
|
return selectPrimalUpdate(basic, upf, bpf); |
205 |
|
} |
206 |
|
WitnessImprovement selectFocusImproving() ; |
207 |
|
|
208 |
|
WitnessImprovement focusUsingSignDisagreements(ArithVar basic); |
209 |
|
WitnessImprovement focusDownToLastHalf(); |
210 |
|
WitnessImprovement adjustFocusShrank(const ArithVarVec& drop); |
211 |
|
WitnessImprovement focusDownToJust(ArithVar v); |
212 |
|
|
213 |
|
|
214 |
|
void adjustFocusAndError(const UpdateInfo& up, const AVIntPairVec& focusChanges); |
215 |
|
|
216 |
|
/** |
217 |
|
* This is the main simplex for DPLL(T) loop. |
218 |
|
* It runs for at most maxIterations. |
219 |
|
* |
220 |
|
* Returns true iff it has found a conflict. |
221 |
|
* d_conflictVariable will be set and the conflict for this row is reported. |
222 |
|
*/ |
223 |
|
bool searchForFeasibleSolution(uint32_t maxIterations); |
224 |
|
|
225 |
|
bool initialProcessSignals(){ |
226 |
|
TimerStat &timer = d_statistics.d_initialSignalsTime; |
227 |
|
IntStat& conflictStat = d_statistics.d_initialConflicts; |
228 |
|
bool res = standardProcessSignals(timer, conflictStat); |
229 |
|
d_focusSize = d_errorSet.focusSize(); |
230 |
|
return res; |
231 |
|
} |
232 |
|
|
233 |
|
static bool debugCheckWitness(const UpdateInfo& inf, WitnessImprovement w, bool useBlands); |
234 |
|
|
235 |
|
/** These fields are designed to be accessible to TheoryArith methods. */ |
236 |
9853 |
class Statistics { |
237 |
|
public: |
238 |
|
TimerStat d_initialSignalsTime; |
239 |
|
IntStat d_initialConflicts; |
240 |
|
|
241 |
|
IntStat d_fcFoundUnsat; |
242 |
|
IntStat d_fcFoundSat; |
243 |
|
IntStat d_fcMissed; |
244 |
|
|
245 |
|
TimerStat d_fcTimer; |
246 |
|
TimerStat d_fcFocusConstructionTimer; |
247 |
|
|
248 |
|
TimerStat d_selectUpdateForDualLike; |
249 |
|
TimerStat d_selectUpdateForPrimal; |
250 |
|
|
251 |
|
ReferenceStat<uint32_t> d_finalCheckPivotCounter; |
252 |
|
|
253 |
|
Statistics(const std::string& name, uint32_t& pivots); |
254 |
|
} d_statistics; |
255 |
|
};/* class FCSimplexDecisionProcedure */ |
256 |
|
|
257 |
|
} // namespace arith |
258 |
|
} // namespace theory |
259 |
|
} // namespace cvc5 |