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