1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2 /* */ 3 /* This file is part of the HiGHS linear optimization suite */ 4 /* */ 5 /* Written and engineered 2008-2021 at the University of Edinburgh */ 6 /* */ 7 /* Available as open-source under the MIT License */ 8 /* */ 9 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 10 /**@file simplex/HFactor.h 11 * @brief Basis matrix factorization, update and solves for HiGHS 12 * @author Julian Hall, Ivet Galabova, Qi Huangfu and Michael Feldmeier 13 */ 14 #ifndef HFACTOR_H_ 15 #define HFACTOR_H_ 16 17 #include <algorithm> 18 #include <cmath> 19 #include <vector> 20 21 #include "HConfig.h" 22 #include "io/HighsIO.h" 23 #include "lp_data/HConst.h" 24 #include "lp_data/HighsAnalysis.h" 25 26 using std::max; 27 using std::min; 28 using std::vector; 29 30 class HVector; 31 32 enum UPDATE_METHOD { 33 UPDATE_METHOD_FT = 1, 34 UPDATE_METHOD_PF = 2, 35 UPDATE_METHOD_MPF = 3, 36 UPDATE_METHOD_APF = 4 37 }; 38 /** 39 * Limits and default value of pivoting threshold 40 */ 41 const double min_pivot_threshold = 8e-4; 42 const double default_pivot_threshold = 0.1; 43 const double pivot_threshold_change_factor = 5.0; 44 const double max_pivot_threshold = 0.5; 45 /** 46 * Limits and default value of minimum absolute pivot 47 */ 48 const double min_pivot_tolerance = 0; 49 const double default_pivot_tolerance = 1e-10; 50 const double max_pivot_tolerance = 1.0; 51 /** 52 * Necessary thresholds for historical density to trigger 53 * hyper-sparse TRANs, 54 */ 55 const double hyperFTRANL = 0.15; 56 const double hyperFTRANU = 0.10; 57 const double hyperBTRANL = 0.10; 58 const double hyperBTRANU = 0.15; 59 /** 60 * Necessary threshold for RHS density to trigger hyper-sparse TRANs, 61 */ 62 const double hyperCANCEL = 0.05; 63 /** 64 * Threshold for result density for it to be considered as 65 * hyper-sparse - only for reporting 66 */ 67 const double hyperRESULT = 0.10; 68 /** 69 * @brief Basis matrix factorization, update and solves for HiGHS 70 * 71 * Class for the following 72 * 73 * Basis matrix factorization \f$PBQ=LU\f$ 74 * 75 * Update according to \f$B'=B+(\mathbf{a}_q-B\mathbf{e}_p)\mathbf{e}_p^T\f$ 76 * 77 * Solves \f$B\mathbf{x}=\mathbf{b}\f$ (FTRAN) and 78 * \f$B^T\mathbf{x}=\mathbf{b}\f$ (BTRAN) 79 * 80 * HFactor is initialised using HFactor::setup, which takes copies of 81 * the pointers to the constraint matrix starts, indices, values and 82 * basic column indices. 83 * 84 * Forming \f$PBQ=LU\f$ (INVERT) is performed using HFactor::build 85 * 86 * Solving \f$B\mathbf{x}=\mathbf{b}\f$ (FTRAN) is performed using 87 * HFactor::ftran 88 * 89 * Solving \f$B^T\mathbf{x}=\mathbf{b}\f$ (BTRAN) is performed using 90 * HFactor::btran 91 * 92 * Updating the invertible representation of the basis matrix 93 * according to \f$B'=B+(\mathbf{a}_q-B\mathbf{e}_p)\mathbf{e}_p^T\f$ 94 * is performed by HFactor::update. UPDATE requires vectors 95 * \f$B^{-1}\mathbf{a}_q\f$ and \f$B^{-T}\mathbf{e}_q\f$, together 96 * with the index of the pivotal row. 97 * 98 * HFactor assumes that the basic column indices are kept up-to-date 99 * externally as basis changes take place. INVERT permutes the basic 100 * column indices, since these define the order of the solution values 101 * after FTRAN, and the assumed order of the RHS before BTRAN 102 * 103 */ 104 class HFactor { 105 public: 106 /** 107 * @brief Copy problem size and pointers of constraint matrix, and set 108 * up space for INVERT 109 * 110 * Copy problem size and pointers to coefficient matrix, allocate 111 * working buffer for INVERT, allocate space for basis matrix, L, U 112 * factor and Update buffer, allocated space for Markowitz matrices, 113 * count-link-list, L factor and U factor 114 */ 115 void setup( 116 int numCol, //!< Number of columns 117 int numRow, //!< Number of rows 118 const int* Astart, //!< Column starts of constraint matrix 119 const int* Aindex, //!< Row indices of constraint matrix 120 const double* Avalue, //!< Row values of constraint matrix 121 int* baseIndex, //!< Indices of basic variables 122 int highs_debug_level = HIGHS_DEBUG_LEVEL_MIN, FILE* logfile = NULL, 123 FILE* output = NULL, int message_level = ML_NONE, 124 double pivot_threshold = default_pivot_threshold, //!< Pivoting threshold 125 double pivot_tolerance = default_pivot_tolerance, //!< Min absolute pivot 126 const bool use_original_HFactor_logic = true, 127 int updateMethod = 128 UPDATE_METHOD_FT //!< Default update method is Forrest Tomlin 129 ); 130 131 /** 132 * @brief Form \f$PBQ=LU\f$ for basis matrix \f$B\f$ or report degree of rank 133 * deficiency. 134 * 135 * @return 0 if successful, otherwise rank_deficiency>0 136 * 137 */ 138 int build(HighsTimerClock* factor_timer_clock_pointer = NULL); 139 140 /** 141 * @brief Solve \f$B\mathbf{x}=\mathbf{b}\f$ (FTRAN) 142 */ 143 void ftran(HVector& vector, //!< RHS vector \f$\mathbf{b}\f$ 144 double historical_density, //!< Historical density of the result 145 HighsTimerClock* factor_timer_clock_pointer = NULL) const; 146 147 /** 148 * @brief Solve \f$B^T\mathbf{x}=\mathbf{b}\f$ (BTRAN) 149 */ 150 void btran(HVector& vector, //!< RHS vector \f$\mathbf{b}\f$ 151 double historical_density, //!< Historical density of the result 152 HighsTimerClock* factor_timer_clock_pointer = NULL) const; 153 154 /** 155 * @brief Update according to 156 * \f$B'=B+(\mathbf{a}_q-B\mathbf{e}_p)\mathbf{e}_p^T\f$ 157 */ 158 void update(HVector* aq, //!< Vector \f$B^{-1}\mathbf{a}_q\f$ 159 HVector* ep, //!< Vector \f$B^{-T}\mathbf{e}_p\f$ 160 int* iRow, //!< Index of pivotal row 161 int* hint //!< Reinversion status 162 ); 163 164 /** 165 * @brief Sets pivoting threshold 166 */ 167 bool setPivotThreshold( 168 const double new_pivot_threshold = default_pivot_threshold); 169 /** 170 * @brief Sets minimum absolute pivot 171 */ 172 bool setMinAbsPivot( 173 const double new_pivot_tolerance = default_pivot_tolerance); 174 175 /** 176 * @brief Wall clock time for INVERT 177 */ 178 double build_realTick; 179 180 /** 181 * @brief The synthetic clock for INVERT 182 */ 183 double build_syntheticTick; 184 185 // Rank deficiency information 186 187 /** 188 * @brief Degree of rank deficiency in \f$B\f$ 189 */ 190 int rank_deficiency; 191 192 /** 193 * @brief Rows not pivoted on 194 */ 195 vector<int> noPvR; 196 197 /** 198 * @brief Columns not pivoted on 199 */ 200 vector<int> noPvC; 201 202 /** 203 * @brief Gets baseIndex since it is private 204 */ getBaseIndex()205 const int* getBaseIndex() const { return baseIndex; } 206 207 /** 208 * @brief Gets Astart since it is private 209 */ getAstart()210 const int* getAstart() const { return Astart; } 211 212 /** 213 * @brief Gets Aindex since it is private 214 */ getAindex()215 const int* getAindex() const { return Aindex; } 216 217 /** 218 * @brief Gets Avalue since it is private 219 */ getAvalue()220 const double* getAvalue() const { return Avalue; } 221 222 // Properties of data held in HFactor.h. To "have" them means that 223 // they are assigned. 224 int haveArrays; 225 // The representation of B^{-1} corresponds to the current basis 226 int haveInvert; 227 // The representation of B^{-1} corresponds to the current basis and is fresh 228 int haveFreshInvert; 229 int basis_matrix_num_el = 0; 230 int invert_num_el = 0; 231 int kernel_dim = 0; 232 int kernel_num_el = 0; 233 234 /** 235 * Data of the factor 236 */ 237 238 // private: 239 // Problem size, coefficient matrix and update method 240 int numRow; 241 int numCol; 242 243 private: 244 const int* Astart; 245 const int* Aindex; 246 const double* Avalue; 247 int* baseIndex; 248 int updateMethod; 249 bool use_original_HFactor_logic; 250 int highs_debug_level; 251 FILE* logfile; 252 FILE* output; 253 int message_level; 254 double pivot_threshold; 255 double pivot_tolerance; 256 257 // Working buffer 258 int nwork; 259 vector<int> iwork; 260 vector<double> dwork; 261 262 // Basis matrix 263 vector<int> Bstart; 264 vector<int> Bindex; 265 vector<double> Bvalue; 266 267 // Permutation 268 vector<int> permute; 269 270 // Kernel matrix 271 vector<int> MCstart; 272 vector<int> MCcountA; 273 vector<int> MCcountN; 274 vector<int> MCspace; 275 vector<int> MCindex; 276 vector<double> MCvalue; 277 vector<double> MCminpivot; 278 279 // Row wise kernel matrix 280 vector<int> MRstart; 281 vector<int> MRcount; 282 vector<int> MRspace; 283 vector<int> MRcountb4; 284 vector<int> MRindex; 285 286 // Kernel column buffer 287 vector<int> McolumnIndex; 288 vector<char> McolumnMark; 289 vector<double> McolumnArray; 290 291 // Count link list 292 vector<int> clinkFirst; 293 vector<int> clinkNext; 294 vector<int> clinkLast; 295 296 vector<int> rlinkFirst; 297 vector<int> rlinkNext; 298 vector<int> rlinkLast; 299 300 // Factor L 301 vector<int> LpivotLookup; 302 vector<int> LpivotIndex; 303 304 vector<int> Lstart; 305 vector<int> Lindex; 306 vector<double> Lvalue; 307 vector<int> LRstart; 308 vector<int> LRindex; 309 vector<double> LRvalue; 310 311 // Factor U 312 vector<int> UpivotLookup; 313 vector<int> UpivotIndex; 314 vector<double> UpivotValue; 315 316 int UmeritX; 317 int UtotalX; 318 vector<int> Ustart; 319 vector<int> Ulastp; 320 vector<int> Uindex; 321 vector<double> Uvalue; 322 vector<int> URstart; 323 vector<int> URlastp; 324 vector<int> URspace; 325 vector<int> URindex; 326 vector<double> URvalue; 327 328 // Update buffer 329 vector<double> PFpivotValue; 330 vector<int> PFpivotIndex; 331 vector<int> PFstart; 332 vector<int> PFindex; 333 vector<double> PFvalue; 334 335 // Implementation 336 void buildSimple(); 337 // void buildKernel(); 338 int buildKernel(); 339 void buildHandleRankDeficiency(); 340 void buildReportRankDeficiency(); 341 void buildMarkSingC(); 342 void buildFinish(); 343 344 void ftranL(HVector& vector, double historical_density, 345 HighsTimerClock* factor_timer_clock_pointer = NULL) const; 346 void btranL(HVector& vector, double historical_density, 347 HighsTimerClock* factor_timer_clock_pointer = NULL) const; 348 void ftranU(HVector& vector, double historical_density, 349 HighsTimerClock* factor_timer_clock_pointer = NULL) const; 350 void btranU(HVector& vector, double historical_density, 351 HighsTimerClock* factor_timer_clock_pointer = NULL) const; 352 353 void ftranFT(HVector& vector) const; 354 void btranFT(HVector& vector) const; 355 void ftranPF(HVector& vector) const; 356 void btranPF(HVector& vector) const; 357 void ftranMPF(HVector& vector) const; 358 void btranMPF(HVector& vector) const; 359 void ftranAPF(HVector& vector) const; 360 void btranAPF(HVector& vector) const; 361 362 void updateCFT(HVector* aq, HVector* ep, int* iRow); 363 void updateFT(HVector* aq, HVector* ep, int iRow); 364 void updatePF(HVector* aq, int iRow, int* hint); 365 void updateMPF(HVector* aq, HVector* ep, int iRow, int* hint); 366 void updateAPF(HVector* aq, HVector* ep, int iRow); 367 368 /** 369 * Local in-line functions 370 */ colInsert(const int iCol,const int iRow,const double value)371 void colInsert(const int iCol, const int iRow, const double value) { 372 const int iput = MCstart[iCol] + MCcountA[iCol]++; 373 MCindex[iput] = iRow; 374 MCvalue[iput] = value; 375 } colStoreN(const int iCol,const int iRow,const double value)376 void colStoreN(const int iCol, const int iRow, const double value) { 377 const int iput = MCstart[iCol] + MCspace[iCol] - (++MCcountN[iCol]); 378 MCindex[iput] = iRow; 379 MCvalue[iput] = value; 380 } colFixMax(const int iCol)381 void colFixMax(const int iCol) { 382 double maxValue = 0; 383 for (int k = MCstart[iCol]; k < MCstart[iCol] + MCcountA[iCol]; k++) 384 maxValue = max(maxValue, fabs(MCvalue[k])); 385 MCminpivot[iCol] = maxValue * pivot_threshold; 386 } 387 colDelete(const int iCol,const int iRow)388 double colDelete(const int iCol, const int iRow) { 389 int idel = MCstart[iCol]; 390 int imov = idel + (--MCcountA[iCol]); 391 while (MCindex[idel] != iRow) idel++; 392 double pivotX = MCvalue[idel]; 393 MCindex[idel] = MCindex[imov]; 394 MCvalue[idel] = MCvalue[imov]; 395 return pivotX; 396 } 397 rowInsert(const int iCol,const int iRow)398 void rowInsert(const int iCol, const int iRow) { 399 int iput = MRstart[iRow] + MRcount[iRow]++; 400 MRindex[iput] = iCol; 401 } 402 rowDelete(const int iCol,const int iRow)403 void rowDelete(const int iCol, const int iRow) { 404 int idel = MRstart[iRow]; 405 int imov = idel + (--MRcount[iRow]); 406 while (MRindex[idel] != iCol) idel++; 407 MRindex[idel] = MRindex[imov]; 408 } 409 clinkAdd(const int index,const int count)410 void clinkAdd(const int index, const int count) { 411 const int mover = clinkFirst[count]; 412 clinkLast[index] = -2 - count; 413 clinkNext[index] = mover; 414 clinkFirst[count] = index; 415 if (mover >= 0) clinkLast[mover] = index; 416 } 417 clinkDel(const int index)418 void clinkDel(const int index) { 419 const int xlast = clinkLast[index]; 420 const int xnext = clinkNext[index]; 421 if (xlast >= 0) 422 clinkNext[xlast] = xnext; 423 else 424 clinkFirst[-xlast - 2] = xnext; 425 if (xnext >= 0) clinkLast[xnext] = xlast; 426 } 427 rlinkAdd(const int index,const int count)428 void rlinkAdd(const int index, const int count) { 429 const int mover = rlinkFirst[count]; 430 rlinkLast[index] = -2 - count; 431 rlinkNext[index] = mover; 432 rlinkFirst[count] = index; 433 if (mover >= 0) rlinkLast[mover] = index; 434 } 435 rlinkDel(const int index)436 void rlinkDel(const int index) { 437 const int xlast = rlinkLast[index]; 438 const int xnext = rlinkNext[index]; 439 if (xlast >= 0) 440 rlinkNext[xlast] = xnext; 441 else 442 rlinkFirst[-xlast - 2] = xnext; 443 if (xnext >= 0) rlinkLast[xnext] = xlast; 444 } 445 }; 446 447 #endif /* HFACTOR_H_ */ 448