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