1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the class library */
4 /* SoPlex --- the Sequential object-oriented simPlex. */
5 /* */
6 /* Copyright (C) 1996-2022 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SoPlex is distributed under the terms of the ZIB Academic Licence. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SoPlex; see the file COPYING. If not email to soplex@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 #include <iostream>
17
(1) Event include_recursion: |
#include file "/sapmnt/home1/d029903/my_work/SCIPSoPlex_coverity/scipoptsuite-8.0.1/soplex/src/soplex/spxmainsm.h" includes itself: spxmainsm.h -> spxmainsm.hpp -> spxmainsm.h |
(2) Event caretline: |
^ |
18 #include "soplex/spxmainsm.h"
19 #include "soplex/array.h"
20 #include "soplex/dataarray.h"
21 #include "soplex/sorter.h"
22 #include "soplex/spxout.h"
23 #include <sstream>
24 #include <iostream>
25 #include <fstream>
26 #include <memory>
27
28
29 //rows
30 #define FREE_LHS_RHS 1
31 #define FREE_CONSTRAINT 1
32 #define EMPTY_CONSTRAINT 1
33 #define ROW_SINGLETON 1
34 #define AGGREGATE_VARS 1
35 #define FORCE_CONSTRAINT 1
36 //cols
37 #define FREE_BOUNDS 1
38 #define EMPTY_COLUMN 1
39 #define FIX_VARIABLE 1
40 #define FREE_ZERO_OBJ_VARIABLE 1
41 #define ZERO_OBJ_COL_SINGLETON 1
42 #define DOUBLETON_EQUATION 1
43 #define FREE_COL_SINGLETON 1
44 //dual
45 #define DOMINATED_COLUMN 1
46 #define WEAKLY_DOMINATED_COLUMN 1
47 #define MULTI_AGGREGATE 1
48 //other
49 #define TRIVIAL_HEURISTICS 1
50 #define PSEUDOOBJ 1
51
52
53 #define EXTREMES 1
54 #define ROWS_SPXMAINSM 1
55 #define COLS_SPXMAINSM 1
56 #define DUAL_SPXMAINSM 1
57 ///@todo check: with this simplification step, the unsimplified basis seems to be slightly suboptimal for some instances
58 #define DUPLICATE_ROWS 1
59 #define DUPLICATE_COLS 1
60
61
62 #ifndef NDEBUG
63 #define CHECK_BASIC_DIM
64 #endif // NDEBUG
65
66 namespace soplex
67 {
68
69 template <class R>
70 bool SPxMainSM<R>::PostStep::checkBasisDim(DataArray<typename SPxSolverBase<R>::VarStatus> rows,
71 DataArray<typename SPxSolverBase<R>::VarStatus> cols) const
72 {
73 int numBasis = 0;
74
75 for(int rs = 0; rs < nRows; ++rs)
76 {
77 if(rows[rs] == SPxSolverBase<R>::BASIC)
78 numBasis++;
79 }
80
81 for(int cs = 0; cs < nCols; ++cs)
82 {
83 if(cols[cs] == SPxSolverBase<R>::BASIC)
84 numBasis++;
85 }
86
87 assert(numBasis == nRows);
88 return numBasis == nRows;
89 }
90
91 template <class R>
92 void SPxMainSM<R>::RowObjPS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>& s,
93 VectorBase<R>&,
94 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
95 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
96 {
97 s[m_i] = s[m_i] - x[m_j];
98
99 assert(rStatus[m_i] != SPxSolverBase<R>::UNDEFINED);
100 assert(cStatus[m_j] != SPxSolverBase<R>::UNDEFINED);
101 assert(rStatus[m_i] != SPxSolverBase<R>::BASIC || cStatus[m_j] != SPxSolverBase<R>::BASIC);
102
103 MSG_DEBUG(std::cout << "RowObjPS: removing slack column " << m_j << " (" << cStatus[m_j] <<
104 ") for row " << m_i << " (" << rStatus[m_i] << ").\n");
105
106 if(rStatus[m_i] != SPxSolverBase<R>::BASIC)
107 {
108 switch(cStatus[m_j])
109 {
110 case SPxSolverBase<R>::ON_UPPER:
111 rStatus[m_i] = SPxSolverBase<R>::ON_LOWER;
112 break;
113
114 case SPxSolverBase<R>::ON_LOWER:
115 rStatus[m_i] = SPxSolverBase<R>::ON_UPPER;
116 break;
117
118 default:
119 rStatus[m_i] = cStatus[m_j];
120 }
121
122 // otherwise checkBasisDim() may fail
123 cStatus[m_j] = SPxSolverBase<R>::ZERO;
124 }
125
126 #ifdef CHECK_BASIC_DIM
127
128 if(!this->checkBasisDim(rStatus, cStatus))
129 {
130 assert(false);
131 throw SPxInternalCodeException("XMAISM15 Dimension doesn't match after this step.");
132 }
133
134 #endif
135 }
136
137 template <class R>
138 void SPxMainSM<R>::FreeConstraintPS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>& s,
139 VectorBase<R>&,
140 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
141 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
142 {
143 // correcting the change of idx by deletion of the row:
144 if(m_i != m_old_i)
145 {
146 s[m_old_i] = s[m_i];
147 y[m_old_i] = y[m_i];
148 rStatus[m_old_i] = rStatus[m_i];
149 }
150
151 // primal:
152 R slack = 0.0;
153
154 for(int k = 0; k < m_row.size(); ++k)
155 slack += m_row.value(k) * x[m_row.index(k)];
156
157 s[m_i] = slack;
158
159 // dual:
160 y[m_i] = m_row_obj;
161
162 // basis:
163 rStatus[m_i] = SPxSolverBase<R>::BASIC;
164
165 #ifdef CHECK_BASIC_DIM
166
167 if(!this->checkBasisDim(rStatus, cStatus))
168 {
169 throw SPxInternalCodeException("XMAISM15 Dimension doesn't match after this step.");
170 }
171
172 #endif
173 }
174
175 template <class R>
176 void SPxMainSM<R>::EmptyConstraintPS::execute(VectorBase<R>&, VectorBase<R>& y, VectorBase<R>& s,
177 VectorBase<R>&,
178 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
179 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
180 {
181 // correcting the change of idx by deletion of the row:
182 if(m_i != m_old_i)
183 {
184 s[m_old_i] = s[m_i];
185 y[m_old_i] = y[m_i];
186 rStatus[m_old_i] = rStatus[m_i];
187 }
188
189 // primal:
190 s[m_i] = 0.0;
191
192 // dual:
193 y[m_i] = m_row_obj;
194
195 // basis:
196 rStatus[m_i] = SPxSolverBase<R>::BASIC;
197
198 #ifdef CHECK_BASIC_DIM
199
200 if(!this->checkBasisDim(rStatus, cStatus))
201 {
202 throw SPxInternalCodeException("XMAISM16 Dimension doesn't match after this step.");
203 }
204
205 #endif
206 }
207
208 template <class R>
209 void SPxMainSM<R>::RowSingletonPS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>& s,
210 VectorBase<R>& r,
211 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
212 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
213 {
214 // correcting the change of idx by deletion of the row:
215 if(m_i != m_old_i)
216 {
217 y[m_old_i] = y[m_i];
218 s[m_old_i] = s[m_i];
219 rStatus[m_old_i] = rStatus[m_i];
220 }
221
222 R aij = m_col[m_i];
223 assert(aij != 0.0);
224
225 // primal:
226 s[m_i] = aij * x[m_j];
227
228 // dual & basis:
229 R val = m_obj;
230
231 for(int k = 0; k < m_col.size(); ++k)
232 {
233 if(m_col.index(k) != m_i)
234 val -= m_col.value(k) * y[m_col.index(k)];
235 }
236
237 R newLo = (aij > 0) ? m_lhs / aij : m_rhs / aij; // implicit lhs
238 R newUp = (aij > 0) ? m_rhs / aij : m_lhs / aij; // implicit rhs
239
240 switch(cStatus[m_j])
241 {
242 case SPxSolverBase<R>::FIXED:
243 if(newLo <= m_oldLo && newUp >= m_oldUp)
244 {
245 // this row is totally redundant, has not changed bound of xj
246 rStatus[m_i] = SPxSolverBase<R>::BASIC;
247 y[m_i] = m_row_obj;
248 }
249 else if(EQrel(newLo, newUp, this->eps()))
250 {
251 // row is in the type aij * xj = b
252 assert(EQrel(newLo, x[m_j], this->eps()));
253
254 if(EQrel(m_oldLo, m_oldUp, this->eps()))
255 {
256 // xj has been fixed in other row
257 rStatus[m_i] = SPxSolverBase<R>::BASIC;
258 y[m_i] = m_row_obj;
259 }
260 else if((EQrel(m_oldLo, x[m_j], this->eps()) && r[m_j] <= -this->eps())
261 || (EQrel(m_oldUp, x[m_j], this->eps()) && r[m_j] >= this->eps())
262 || (!EQrel(m_oldLo, x[m_j], this->eps()) && !(EQrel(m_oldUp, x[m_j], this->eps()))))
263 {
264 // if x_j on lower but reduced cost is negative, or x_j on upper but reduced cost is positive, or x_j not on bound: basic
265 rStatus[m_i] = (EQrel(m_lhs, x[m_j] * aij,
266 this->eps())) ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER;
267 cStatus[m_j] = SPxSolverBase<R>::BASIC;
268 y[m_i] = val / aij;
269 r[m_j] = 0.0;
270 }
271 else
272 {
273 // set x_j on one of the bound
274 assert(EQrel(m_oldLo, x[m_j], this->eps()) || EQrel(m_oldUp, x[m_j], this->eps()));
275
276 cStatus[m_j] = EQrel(m_oldLo, x[m_j],
277 this->eps()) ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER;
278 rStatus[m_i] = SPxSolverBase<R>::BASIC;
279 y[m_i] = m_row_obj;
280 r[m_j] = val;
281 }
282 }
283 else if(EQrel(newLo, m_oldUp, this->eps()))
284 {
285 // row is in the type xj >= b/aij, try to set xj on upper
286 if(r[m_j] >= this->eps())
287 {
288 // the reduced cost is positive, xj should in the basic
289 assert(EQrel(m_rhs / aij, x[m_j], this->eps()) || EQrel(m_lhs / aij, x[m_j], this->eps()));
290
291 rStatus[m_i] = (EQrel(m_lhs / aij, x[m_j],
292 this->eps())) ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER;
293 cStatus[m_j] = SPxSolverBase<R>::BASIC;
294 y[m_i] = val / aij;
295 r[m_j] = 0.0;
296 }
297 else
298 {
299 assert(EQrel(m_oldUp, x[m_j], this->eps()));
300
301 cStatus[m_j] = SPxSolverBase<R>::ON_UPPER;
302 rStatus[m_i] = SPxSolverBase<R>::BASIC;
303 y[m_i] = m_row_obj;
304 r[m_j] = val;
305 }
306 }
307 else if(EQrel(newUp, m_oldLo, this->eps()))
308 {
309 // row is in the type xj <= b/aij, try to set xj on lower
310 if(r[m_j] <= -this->eps())
311 {
312 // the reduced cost is negative, xj should in the basic
313 assert(EQrel(m_rhs / aij, x[m_j], this->eps()) || EQrel(m_lhs / aij, x[m_j], this->eps()));
314
315 rStatus[m_i] = (EQrel(m_lhs / aij, x[m_j],
316 this->eps())) ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER;
317 cStatus[m_j] = SPxSolverBase<R>::BASIC;
318 y[m_i] = val / aij;
319 r[m_j] = 0.0;
320 }
321 else
322 {
323 assert(EQrel(m_oldLo, x[m_j], this->eps()));
324
325 cStatus[m_j] = SPxSolverBase<R>::ON_LOWER;
326 rStatus[m_i] = SPxSolverBase<R>::BASIC;
327 y[m_i] = m_row_obj;
328 r[m_j] = val;
329 }
330 }
331 else
332 {
333 // the variable is set to FIXED by other constraints, i.e., this singleton row is redundant
334 rStatus[m_i] = SPxSolverBase<R>::BASIC;
335 y[m_i] = m_row_obj;
336 }
337
338 break;
339
340 case SPxSolverBase<R>::BASIC:
341 rStatus[m_i] = SPxSolverBase<R>::BASIC;
342 y[m_i] = m_row_obj;
343 r[m_j] = 0.0;
344 break;
345
346 case SPxSolverBase<R>::ON_LOWER:
347 if(EQrel(m_oldLo, x[m_j], this->eps())) // xj may stay on lower
348 {
349 rStatus[m_i] = SPxSolverBase<R>::BASIC;
350 y[m_i] = m_row_obj;
351 r[m_j] = val;
352 }
353 else // if reduced costs are negative or old lower bound not equal to xj, we need to change xj into the basis
354 {
355 assert(!isOptimal || EQrel(m_rhs / aij, x[m_j], this->eps())
356 || EQrel(m_lhs / aij, x[m_j], this->eps()));
357
358 cStatus[m_j] = SPxSolverBase<R>::BASIC;
359 rStatus[m_i] = (EQrel(m_lhs / aij, x[m_j],
360 this->eps())) ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER;
361 y[m_i] = val / aij;
362 r[m_j] = 0.0;
363 }
364
365 break;
366
367 case SPxSolverBase<R>::ON_UPPER:
368 if(EQrel(m_oldUp, x[m_j], this->eps())) // xj may stay on upper
369 {
370 rStatus[m_i] = SPxSolverBase<R>::BASIC;
371 y[m_i] = m_row_obj;
372 r[m_j] = val;
373 }
374 else // if reduced costs are positive or old upper bound not equal to xj, we need to change xj into the basis
375 {
376 assert(!isOptimal || EQrel(m_rhs / aij, x[m_j], this->eps())
377 || EQrel(m_lhs / aij, x[m_j], this->eps()));
378
379 cStatus[m_j] = SPxSolverBase<R>::BASIC;
380 rStatus[m_i] = (EQrel(m_lhs / aij, x[m_j],
381 this->eps())) ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER;
382 y[m_i] = val / aij;
383 r[m_j] = 0.0;
384 }
385
386 break;
387
388 case SPxSolverBase<R>::ZERO:
389 rStatus[m_i] = SPxSolverBase<R>::BASIC;
390 y[m_i] = m_row_obj;
391 r[m_j] = val;
392 break;
393
394 default:
395 break;
396 }
397
398 #ifdef CHECK_BASIC_DIM
399
400 if(!this->checkBasisDim(rStatus, cStatus))
401 {
402 throw SPxInternalCodeException("XMAISM17 Dimension doesn't match after this step.");
403 }
404
405 #endif
406 }
407
408 template <class R>
409 void SPxMainSM<R>::ForceConstraintPS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>& s,
410 VectorBase<R>& r,
411 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
412 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
413 {
414 // correcting the change of idx by deletion of the row:
415 if(m_i != m_old_i)
416 {
417 s[m_old_i] = s[m_i];
418 y[m_old_i] = y[m_i];
419 rStatus[m_old_i] = rStatus[m_i];
420 }
421
422 // primal:
423 s[m_i] = m_lRhs;
424
425 // basis:
426 int cBasisCandidate = -1;
427 R maxViolation = -1.0;
428 int bas_k = -1;
429
430 for(int k = 0; k < m_row.size(); ++k)
431 {
432 int cIdx = m_row.index(k);
433 R aij = m_row.value(k);
434 R oldLo = m_oldLowers[k];
435 R oldUp = m_oldUppers[k];
436
437 switch(cStatus[cIdx])
438 {
439 case SPxSolverBase<R>::FIXED:
440 if(m_fixed[k])
441 {
442 assert(EQrel(oldLo, x[cIdx], this->eps()) || EQrel(oldUp, x[cIdx], this->eps()));
443
444 R violation = spxAbs(r[cIdx] / aij);
445
446 cStatus[cIdx] = EQrel(oldLo, x[cIdx],
447 this->eps()) ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER;
448
449 if(violation > maxViolation && ((EQrel(oldLo, x[cIdx], this->eps()) && r[cIdx] < -this->eps())
450 || (EQrel(oldUp, x[cIdx], this->eps()) && r[cIdx] > this->eps())))
451 {
452 maxViolation = violation;
453 cBasisCandidate = cIdx;
454 bas_k = k;
455 }
456 } // do nothing, if the old bounds are equal, i.e. variable has been not fixed in this row
457
458 break;
459
460 case SPxSolverBase<R>::ON_LOWER:
461 case SPxSolverBase<R>::ON_UPPER:
462 case SPxSolverBase<R>::BASIC:
463 break;
464
465 default:
466 break;
467 }
468 }
469
470 // dual and basis :
471 if(cBasisCandidate >= 0) // one of the variable in the row should in the basis
472 {
473 assert(EQrel(m_lRhs, m_rhs, this->eps()) || EQrel(m_lRhs, m_lhs, this->eps()));
474 assert(bas_k >= 0);
475 assert(cBasisCandidate == m_row.index(bas_k));
476
477 cStatus[cBasisCandidate] = SPxSolverBase<R>::BASIC;
478 rStatus[m_i] = (EQrel(m_lRhs, m_lhs,
479 this->eps())) ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER;
480
481 R aij = m_row.value(bas_k);
482 R multiplier = r[cBasisCandidate] / aij;
483 r[cBasisCandidate] = 0.0;
484
485 for(int k = 0; k < m_row.size(); ++k) // update the reduced cost
486 {
487 if(k == bas_k)
488 {
489 continue;
490 }
491
492 r[m_row.index(k)] -= m_row.value(k) * multiplier;
493 }
494
495 // compute the value of new dual variable (because we have a new row)
496 R val = m_objs[bas_k];
497 DSVectorBase<R> basis_col = m_cols[bas_k];
498
499 for(int k = 0; k < basis_col.size(); ++k)
500 {
501 if(basis_col.index(k) != m_i)
502 val -= basis_col.value(k) * y[basis_col.index(k)];
503 }
504
505 y[m_i] = val / aij;
506 }
507 else // slack in the basis
508 {
509 rStatus[m_i] = SPxSolverBase<R>::BASIC;
510 y[m_i] = m_rowobj;
511 }
512
513 #ifdef CHECK_BASIC_DIM
514
515 if(!this->checkBasisDim(rStatus, cStatus))
516 {
517 throw SPxInternalCodeException("XMAISM18 Dimension doesn't match after this step.");
518 }
519
520 #endif
521 }
522
523 template <class R>
524 void SPxMainSM<R>::FixVariablePS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>& s,
525 VectorBase<R>& r,
526 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
527 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
528 {
529 // update the index mapping; if m_correctIdx is false, we assume that this has happened already
530 if(m_correctIdx)
531 {
532 x[m_old_j] = x[m_j];
533 r[m_old_j] = r[m_j];
534 cStatus[m_old_j] = cStatus[m_j];
535 }
536
537 // primal:
538 x[m_j] = m_val;
539
540 for(int k = 0; k < m_col.size(); ++k)
541 s[m_col.index(k)] += m_col.value(k) * x[m_j];
542
543 // dual:
544 R val = m_obj;
545
546 for(int k = 0; k < m_col.size(); ++k)
547 val -= m_col.value(k) * y[m_col.index(k)];
548
549 r[m_j] = val;
550
551 // basis:
552 if(m_lower == m_upper)
553 {
554 assert(EQrel(m_lower, m_val));
555
556 cStatus[m_j] = SPxSolverBase<R>::FIXED;
557 }
558 else
559 {
560 assert(EQrel(m_val, m_lower) || EQrel(m_val, m_upper) || m_val == 0.0);
561
562 cStatus[m_j] = EQrel(m_val, m_lower) ? SPxSolverBase<R>::ON_LOWER : (EQrel(m_val,
563 m_upper) ? SPxSolverBase<R>::ON_UPPER : SPxSolverBase<R>::ZERO);
564 }
565
566 #ifdef CHECK_BASIC_DIM
567
568 if(m_correctIdx)
569 {
570 if(!this->checkBasisDim(rStatus, cStatus))
571 {
572 throw SPxInternalCodeException("XMAISM19 Dimension doesn't match after this step.");
573 }
574 }
575
576 #endif
577 }
578
579 template <class R>
580 void SPxMainSM<R>::FixBoundsPS::execute(VectorBase<R>&, VectorBase<R>&, VectorBase<R>&,
581 VectorBase<R>&,
582 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
583 DataArray<typename SPxSolverBase<R>::VarStatus>&, bool isOptimal) const
584 {
585 // basis:
586 cStatus[m_j] = m_status;
587 }
588
589 template <class R>
590 void SPxMainSM<R>::FreeZeroObjVariablePS::execute(VectorBase<R>& x, VectorBase<R>& y,
591 VectorBase<R>& s, VectorBase<R>& r,
592 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
593 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
594 {
595 // correcting the change of idx by deletion of the column and corresponding rows:
596 if(m_j != m_old_j)
597 {
598 x[m_old_j] = x[m_j];
599 r[m_old_j] = r[m_j];
600 cStatus[m_old_j] = cStatus[m_j];
601 }
602
603 int rIdx = m_old_i - m_col.size() + 1;
604
605 for(int k = 0; k < m_col.size(); ++k)
606 {
607 int rIdx_new = m_col.index(k);
608 s[rIdx] = s[rIdx_new];
609 y[rIdx] = y[rIdx_new];
610 rStatus[rIdx] = rStatus[rIdx_new];
611 rIdx++;
612 }
613
614 // primal:
615 int domIdx = -1;
616 DSVectorBase<R> slack(m_col.size());
617
618 if(m_loFree)
619 {
620 R minRowUp = R(infinity);
621
622 for(int k = 0; k < m_rows.size(); ++k)
623 {
624 R val = 0.0;
625 const SVectorBase<R>& row = m_rows[k];
626
627 for(int l = 0; l < row.size(); ++l)
628 {
629 if(row.index(l) != m_j)
630 val += row.value(l) * x[row.index(l)];
631 }
632
633 R scale = maxAbs(m_lRhs[k], val);
634
635 if(scale < 1.0)
636 scale = 1.0;
637
638 R z = (m_lRhs[k] / scale) - (val / scale);
639
640 if(isZero(z))
641 z = 0.0;
642
643 R up = z * scale / row[m_j];
644 slack.add(k, val);
645
646 if(up < minRowUp)
647 {
648 minRowUp = up;
649 domIdx = k;
650 }
651 }
652
653 if(m_bnd < minRowUp)
654 {
655 x[m_j] = m_bnd;
656 domIdx = -1;
657 }
658 else
659 x[m_j] = minRowUp;
660 }
661 else
662 {
663 R maxRowLo = R(-infinity);
664
665 for(int k = 0; k < m_rows.size(); ++k)
666 {
667 R val = 0.0;
668 const SVectorBase<R>& row = m_rows[k];
669
670 for(int l = 0; l < row.size(); ++l)
671 {
672 if(row.index(l) != m_j)
673 val += row.value(l) * x[row.index(l)];
674 }
675
676 R scale = maxAbs(m_lRhs[k], val);
677
678 if(scale < 1.0)
679 scale = 1.0;
680
681 R z = (m_lRhs[k] / scale) - (val / scale);
682
683 if(isZero(z))
684 z = 0.0;
685
686 R lo = z * scale / row[m_j];
687 slack.add(k, val);
688
689 if(lo > maxRowLo)
690 {
691 maxRowLo = lo;
692 domIdx = k;
693 }
694 }
695
696 if(m_bnd > maxRowLo)
697 {
698 x[m_j] = m_bnd;
699 domIdx = -1;
700 }
701 else
702 x[m_j] = maxRowLo;
703 }
704
705 for(int k = 0; k < m_col.size(); ++k)
706 s[m_col.index(k)] = slack[k] + m_col.value(k) * x[m_j];
707
708 // dual:
709 r[m_j] = 0.0;
710
711 for(int k = 0; k < m_col.size(); ++k)
712 {
713 int idx = m_col.index(k);
714 y[idx] = m_rowObj[idx];
715 }
716
717 // basis:
718 for(int k = 0; k < m_col.size(); ++k)
719 {
720 if(k != domIdx)
721 rStatus[m_col.index(k)] = SPxSolverBase<R>::BASIC;
722
723 else
724 {
725 cStatus[m_j] = SPxSolverBase<R>::BASIC;
726
727 if(m_loFree)
728 rStatus[m_col.index(k)] = (m_col.value(k) > 0) ? SPxSolverBase<R>::ON_UPPER :
729 SPxSolverBase<R>::ON_LOWER;
730 else
731 rStatus[m_col.index(k)] = (m_col.value(k) > 0) ? SPxSolverBase<R>::ON_LOWER :
732 SPxSolverBase<R>::ON_UPPER;
733 }
734 }
735
736 if(domIdx == -1)
737 {
738 if(m_loFree)
739 cStatus[m_j] = SPxSolverBase<R>::ON_UPPER;
740 else
741 cStatus[m_j] = SPxSolverBase<R>::ON_LOWER;
742 }
743
744 #ifdef CHECK_BASIC_DIM
745
746 if(!this->checkBasisDim(rStatus, cStatus))
747 {
748 throw SPxInternalCodeException("XMAISM20 Dimension doesn't match after this step.");
749 }
750
751 #endif
752 }
753
754 template <class R>
755 void SPxMainSM<R>::ZeroObjColSingletonPS::execute(VectorBase<R>& x, VectorBase<R>& y,
756 VectorBase<R>& s, VectorBase<R>& r,
757 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
758 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
759 {
760 // correcting the change of idx by deletion of the column and corresponding rows:
761 if(m_j != m_old_j)
762 {
763 x[m_old_j] = x[m_j];
764 r[m_old_j] = r[m_j];
765 cStatus[m_old_j] = cStatus[m_j];
766 }
767
768 // primal & basis:
769 R aij = m_row[m_j];
770
771 if(isZero(s[m_i], R(1e-6)))
772 s[m_i] = 0.0;
773 else if(s[m_i] >= R(infinity))
774 // this is a fix for a highly ill conditioned instance that is "solved" in presolving (ilaser0 from MINLP, mittelmann)
775 throw SPxException("Simplifier: infinite activities - aborting unsimplification");
776
777 R scale1 = maxAbs(m_lhs, s[m_i]);
778 R scale2 = maxAbs(m_rhs, s[m_i]);
779
780 if(scale1 < 1.0)
781 scale1 = 1.0;
782
783 if(scale2 < 1.0)
784 scale2 = 1.0;
785
786 R z1 = (m_lhs / scale1) - (s[m_i] / scale1);
787 R z2 = (m_rhs / scale2) - (s[m_i] / scale2);
788
789 if(isZero(z1))
790 z1 = 0.0;
791
792 if(isZero(z2))
793 z2 = 0.0;
794
795 R lo = (aij > 0) ? z1 * scale1 / aij : z2 * scale2 / aij;
796 R up = (aij > 0) ? z2 * scale2 / aij : z1 * scale1 / aij;
797
798 if(isZero(lo, this->eps()))
799 lo = 0.0;
800
801 if(isZero(up, this->eps()))
802 up = 0.0;
803
804 assert(LErel(lo, up));
805 ASSERT_WARN("WMAISM01", isNotZero(aij, R(1.0 / R(infinity))));
806
807 if(rStatus[m_i] == SPxSolverBase<R>::ON_LOWER)
808 {
809 if(m_lower <= R(-infinity) && m_upper >= R(infinity))
810 {
811 x[m_j] = 0.0;
812 cStatus[m_j] = SPxSolverBase<R>::ZERO;
813 }
814 else if(m_lower == m_upper)
815 {
816 x[m_j] = m_lower;
817 cStatus[m_j] = SPxSolverBase<R>::FIXED;
818 }
819 else if(aij > 0)
820 {
821 x[m_j] = m_upper;
822 cStatus[m_j] = SPxSolverBase<R>::ON_UPPER;
823 }
824 else if(aij < 0)
825 {
826 x[m_j] = m_lower;
827 cStatus[m_j] = SPxSolverBase<R>::ON_LOWER;
828 }
829 else
830 throw SPxInternalCodeException("XMAISM01 This should never happen.");
831 }
832 else if(rStatus[m_i] == SPxSolverBase<R>::ON_UPPER)
833 {
834 if(m_lower <= R(-infinity) && m_upper >= R(infinity))
835 {
836 x[m_j] = 0.0;
837 cStatus[m_j] = SPxSolverBase<R>::ZERO;
838 }
839 else if(m_lower == m_upper)
840 {
841 x[m_j] = m_lower;
842 cStatus[m_j] = SPxSolverBase<R>::FIXED;
843 }
844 else if(aij > 0)
845 {
846 x[m_j] = m_lower;
847 cStatus[m_j] = SPxSolverBase<R>::ON_LOWER;
848 }
849 else if(aij < 0)
850 {
851 x[m_j] = m_upper;
852 cStatus[m_j] = SPxSolverBase<R>::ON_UPPER;
853 }
854 else
855 throw SPxInternalCodeException("XMAISM02 This should never happen.");
856 }
857 else if(rStatus[m_i] == SPxSolverBase<R>::FIXED)
858 {
859 if(m_lower <= R(-infinity) && m_upper >= R(infinity))
860 {
861 x[m_j] = 0.0;
862 cStatus[m_j] = SPxSolverBase<R>::ZERO;
863 }
864 else
865 {
866 assert(EQrel(m_lower, m_upper, this->eps()));
867
868 x[m_j] = (m_lower + m_upper) / 2.0;
869 cStatus[m_j] = SPxSolverBase<R>::FIXED;
870 }
871 }
872 else if(rStatus[m_i] == SPxSolverBase<R>::BASIC)
873 {
874 if(GErel(m_lower, lo, this->eps()) && m_lower > R(-infinity))
875 {
876 x[m_j] = m_lower;
877 cStatus[m_j] = (m_lower == m_upper) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
878 }
879 else if(LErel(m_upper, up, this->eps()) && m_upper < R(infinity))
880 {
881 x[m_j] = m_upper;
882 cStatus[m_j] = (m_lower == m_upper) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
883 }
884 else if(lo > R(-infinity))
885 {
886 // make m_i non-basic and m_j basic
887 x[m_j] = lo;
888 cStatus[m_j] = SPxSolverBase<R>::BASIC;
889 rStatus[m_i] = (aij > 0 ? SPxSolverBase<R>::ON_LOWER : SPxSolverBase<R>::ON_UPPER);
890 }
891 else if(up < R(infinity))
892 {
893 // make m_i non-basic and m_j basic
894 x[m_j] = up;
895 cStatus[m_j] = SPxSolverBase<R>::BASIC;
896 rStatus[m_i] = (aij > 0 ? SPxSolverBase<R>::ON_UPPER : SPxSolverBase<R>::ON_LOWER);
897 }
898 else
899 throw SPxInternalCodeException("XMAISM03 This should never happen.");
900 }
901 else
902 throw SPxInternalCodeException("XMAISM04 This should never happen.");
903
904 s[m_i] += aij * x[m_j];
905
906 // dual:
907 r[m_j] = -1.0 * aij * y[m_i];
908
909 assert(!isOptimal || (cStatus[m_j] != SPxSolverBase<R>::BASIC || isZero(r[m_j], this->eps())));
910
911 #ifdef CHECK_BASIC_DIM
912
913 if(!this->checkBasisDim(rStatus, cStatus))
914 {
915 throw SPxInternalCodeException("XMAISM21 Dimension doesn't match after this step.");
916 }
917
918 #endif
919 }
920
921 template <class R>
922 void SPxMainSM<R>::FreeColSingletonPS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>& s,
923 VectorBase<R>& r,
924 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
925 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
926 {
927
928 // correcting the change of idx by deletion of the row:
929 if(m_i != m_old_i)
930 {
931 s[m_old_i] = s[m_i];
932 y[m_old_i] = y[m_i];
933 rStatus[m_old_i] = rStatus[m_i];
934 }
935
936 // correcting the change of idx by deletion of the column:
937 if(m_j != m_old_j)
938 {
939 x[m_old_j] = x[m_j];
940 r[m_old_j] = r[m_j];
941 cStatus[m_old_j] = cStatus[m_j];
942 }
943
944 // primal:
945 R val = 0.0;
946 R aij = m_row[m_j];
947
948 for(int k = 0; k < m_row.size(); ++k)
949 {
950 if(m_row.index(k) != m_j)
951 val += m_row.value(k) * x[m_row.index(k)];
952 }
953
954 R scale = maxAbs(m_lRhs, val);
955
956 if(scale < 1.0)
957 scale = 1.0;
958
959 R z = (m_lRhs / scale) - (val / scale);
960
961 if(isZero(z))
962 z = 0.0;
963
964 x[m_j] = z * scale / aij;
965 s[m_i] = m_lRhs;
966
967 // dual:
968 y[m_i] = m_obj / aij;
969 r[m_j] = 0.0;
970
971 // basis:
972 cStatus[m_j] = SPxSolverBase<R>::BASIC;
973
974 if(m_eqCons)
975 rStatus[m_i] = SPxSolverBase<R>::FIXED;
976 else if(m_onLhs)
977 rStatus[m_i] = SPxSolverBase<R>::ON_LOWER;
978 else
979 rStatus[m_i] = SPxSolverBase<R>::ON_UPPER;
980
981 #ifdef CHECK_BASIC_DIM
982
983 if(!this->checkBasisDim(rStatus, cStatus))
984 {
985 throw SPxInternalCodeException("XMAISM22 Dimension doesn't match after this step.");
986 }
987
988 #endif
989 }
990
991 template <class R>
992 void SPxMainSM<R>::DoubletonEquationPS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>&,
993 VectorBase<R>& r,
994 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
995 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
996 {
997 // dual:
998 if((cStatus[m_k] != SPxSolverBase<R>::BASIC) &&
999 ((cStatus[m_k] == SPxSolverBase<R>::ON_LOWER && m_strictLo) ||
1000 (cStatus[m_k] == SPxSolverBase<R>::ON_UPPER && m_strictUp) ||
1001 (cStatus[m_k] == SPxSolverBase<R>::FIXED &&
1002 ((m_maxSense && ((r[m_j] > 0 && m_strictUp) || (r[m_j] < 0 && m_strictLo))) ||
1003 (!m_maxSense && ((r[m_j] > 0 && m_strictLo) || (r[m_j] < 0 && m_strictUp)))))))
1004 {
1005 R val = m_kObj;
1006 R aik = m_col[m_i];
1007
1008 for(int _k = 0; _k < m_col.size(); ++_k)
1009 {
1010 if(m_col.index(_k) != m_i)
1011 val -= m_col.value(_k) * y[m_col.index(_k)];
1012 }
1013
1014 y[m_i] = val / aik;
1015 r[m_k] = 0.0;
1016
1017 r[m_j] = m_jObj - val * m_aij / aik;
1018
1019 ASSERT_WARN("WMAISM73", isNotZero(m_aij * aik));
1020
1021 // basis:
1022 if(m_jFixed)
1023 cStatus[m_j] = SPxSolverBase<R>::FIXED;
1024 else
1025 {
1026 if(GT(r[m_j], (R) 0) || (isZero(r[m_j]) && EQ(x[m_j], m_Lo_j)))
1027 cStatus[m_j] = SPxSolverBase<R>::ON_LOWER;
1028 else
1029 cStatus[m_j] = SPxSolverBase<R>::ON_UPPER;
1030 }
1031
1032 cStatus[m_k] = SPxSolverBase<R>::BASIC;
1033 }
1034
1035 #ifdef CHECK_BASIC_DIM
1036
1037 if(!this->checkBasisDim(rStatus, cStatus))
1038 {
1039 throw SPxInternalCodeException("XMAISM23 Dimension doesn't match after this step.");
1040 }
1041
1042 #endif
1043 }
1044
1045 template <class R>
1046 void SPxMainSM<R>::DuplicateRowsPS::execute(VectorBase<R>&, VectorBase<R>& y, VectorBase<R>& s,
1047 VectorBase<R>&,
1048 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
1049 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
1050 {
1051 // correcting the change of idx by deletion of the duplicated rows:
1052 if(m_isLast)
1053 {
1054 for(int i = m_perm.size() - 1; i >= 0; --i)
1055 {
1056 if(m_perm[i] >= 0)
1057 {
1058 int rIdx_new = m_perm[i];
1059 int rIdx = i;
1060 s[rIdx] = s[rIdx_new];
1061 y[rIdx] = y[rIdx_new];
1062 rStatus[rIdx] = rStatus[rIdx_new];
1063 }
1064 }
1065 }
1066
1067 // primal:
1068 for(int k = 0; k < m_scale.size(); ++k)
1069 {
1070 if(m_scale.index(k) != m_i)
1071 s[m_scale.index(k)] = s[m_i] / m_scale.value(k);
1072 }
1073
1074 // dual & basis:
1075 bool haveSetBasis = false;
1076
1077 for(int k = 0; k < m_scale.size(); ++k)
1078 {
1079 int i = m_scale.index(k);
1080
1081 if(rStatus[m_i] == SPxSolverBase<R>::BASIC || (haveSetBasis && i != m_i))
1082 // if the row with tightest lower and upper bound in the basic, every duplicate row should in basic
1083 // or basis status of row m_i has been set, this row should be in basis
1084 {
1085 y[i] = m_rowObj.value(k);
1086 rStatus[i] = SPxSolverBase<R>::BASIC;
1087 continue;
1088 }
1089
1090 ASSERT_WARN("WMAISM02", isNotZero(m_scale.value(k)));
1091
1092 if(rStatus[m_i] == SPxSolverBase<R>::FIXED && (i == m_maxLhsIdx || i == m_minRhsIdx))
1093 {
1094 // this row leads to the tightest lower or upper bound, slack should not be in the basis
1095 y[i] = y[m_i] * m_scale.value(k);
1096 y[m_i] = m_i_rowObj;
1097
1098 if(m_isLhsEqualRhs[k])
1099 {
1100 rStatus[i] = SPxSolverBase<R>::FIXED;
1101 }
1102 else if(i == m_maxLhsIdx)
1103 {
1104 rStatus[i] = m_scale.value(k) * m_scale.value(0) > 0 ? SPxSolverBase<R>::ON_LOWER :
1105 SPxSolverBase<R>::ON_UPPER;
1106 }
1107 else
1108 {
1109 assert(i == m_minRhsIdx);
1110
1111 rStatus[i] = m_scale.value(k) * m_scale.value(0) > 0 ? SPxSolverBase<R>::ON_UPPER :
1112 SPxSolverBase<R>::ON_LOWER;
1113 }
1114
1115 if(i != m_i)
1116 rStatus[m_i] = SPxSolverBase<R>::BASIC;
1117
1118 haveSetBasis = true;
1119 }
1120 else if(i == m_maxLhsIdx && rStatus[m_i] == SPxSolverBase<R>::ON_LOWER)
1121 {
1122 // this row leads to the tightest lower bound, slack should not be in the basis
1123 y[i] = y[m_i] * m_scale.value(k);
1124 y[m_i] = m_i_rowObj;
1125
1126 rStatus[i] = m_scale.value(k) * m_scale.value(0) > 0 ? SPxSolverBase<R>::ON_LOWER :
1127 SPxSolverBase<R>::ON_UPPER;
1128
1129 if(i != m_i)
1130 rStatus[m_i] = SPxSolverBase<R>::BASIC;
1131
1132 haveSetBasis = true;
1133 }
1134 else if(i == m_minRhsIdx && rStatus[m_i] == SPxSolverBase<R>::ON_UPPER)
1135 {
1136 // this row leads to the tightest upper bound, slack should not be in the basis
1137 y[i] = y[m_i] * m_scale.value(k);
1138 y[m_i] = m_i_rowObj;
1139
1140 rStatus[i] = m_scale.value(k) * m_scale.value(0) > 0 ? SPxSolverBase<R>::ON_UPPER :
1141 SPxSolverBase<R>::ON_LOWER;
1142
1143 if(i != m_i)
1144 rStatus[m_i] = SPxSolverBase<R>::BASIC;
1145
1146 haveSetBasis = true;
1147 }
1148 else if(i != m_i)
1149 {
1150 // this row does not lead to the tightest lower or upper bound, slack should be in the basis
1151 y[i] = m_rowObj.value(k);
1152 rStatus[i] = SPxSolverBase<R>::BASIC;
1153 }
1154 }
1155
1156 #ifdef CHECK_BASIC_DIM
1157
1158 if(m_isFirst && !this->checkBasisDim(rStatus, cStatus))
1159 {
1160 throw SPxInternalCodeException("XMAISM24 Dimension doesn't match after this step.");
1161 }
1162
1163 #endif
1164
1165 // nothing to do for the reduced cost values
1166 }
1167
1168 template <class R>
1169 void SPxMainSM<R>::DuplicateColsPS::execute(VectorBase<R>& x,
1170 VectorBase<R>&,
1171 VectorBase<R>&,
1172 VectorBase<R>& r,
1173 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
1174 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
1175 {
1176
1177 if(m_isFirst)
1178 {
1179 #ifdef CHECK_BASIC_DIM
1180
1181 if(!this->checkBasisDim(rStatus, cStatus))
1182 {
1183 throw SPxInternalCodeException("XMAISM25 Dimension doesn't match after this step.");
1184 }
1185
1186 #endif
1187 return;
1188 }
1189
1190
1191 // correcting the change of idx by deletion of the columns:
1192 if(m_isLast)
1193 {
1194 for(int i = m_perm.size() - 1; i >= 0; --i)
1195 {
1196 if(m_perm[i] >= 0)
1197 {
1198 int cIdx_new = m_perm[i];
1199 int cIdx = i;
1200 x[cIdx] = x[cIdx_new];
1201 r[cIdx] = r[cIdx_new];
1202 cStatus[cIdx] = cStatus[cIdx_new];
1203 }
1204 }
1205
1206 return;
1207 }
1208
1209 // primal & basis:
1210 ASSERT_WARN("WMAISM03", isNotZero(m_scale));
1211
1212 if(cStatus[m_k] == SPxSolverBase<R>::ON_LOWER)
1213 {
1214 x[m_k] = m_loK;
1215
1216 if(m_scale > 0)
1217 {
1218 x[m_j] = m_loJ;
1219 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
1220 }
1221 else
1222 {
1223 x[m_j] = m_upJ;
1224 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
1225 }
1226 }
1227 else if(cStatus[m_k] == SPxSolverBase<R>::ON_UPPER)
1228 {
1229 x[m_k] = m_upK;
1230
1231 if(m_scale > 0)
1232 {
1233 x[m_j] = m_upJ;
1234 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
1235 }
1236 else
1237 {
1238 x[m_j] = m_loJ;
1239 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
1240 }
1241 }
1242 else if(cStatus[m_k] == SPxSolverBase<R>::FIXED)
1243 {
1244 // => x[m_k] and x[m_j] are also fixed before the corresponding preprocessing step
1245 x[m_j] = m_loJ;
1246 cStatus[m_j] = SPxSolverBase<R>::FIXED;
1247 }
1248 else if(cStatus[m_k] == SPxSolverBase<R>::ZERO)
1249 {
1250 /* we only aggregate duplicate columns if 0 is contained in their bounds, so we can handle this case properly */
1251 assert(isZero(x[m_k]));
1252 assert(LErel(m_loJ, R(0.0)));
1253 assert(GErel(m_upJ, R(0.0)));
1254 assert(LErel(m_loK, R(0.0)));
1255 assert(GErel(m_upK, R(0.0)));
1256
1257 if(isZero(m_loK) && isZero(m_upK) && m_loK == m_upK)
1258 cStatus[m_k] = SPxSolverBase<R>::FIXED;
1259 else if(isZero(m_loK))
1260 cStatus[m_k] = SPxSolverBase<R>::ON_LOWER;
1261 else if(isZero(m_upK))
1262 cStatus[m_k] = SPxSolverBase<R>::ON_UPPER;
1263 else if(LErel(m_loK, R(0.0)) && GErel(m_upK, R(0.0)))
1264 cStatus[m_k] = SPxSolverBase<R>::ZERO;
1265 else
1266 throw SPxInternalCodeException("XMAISM05 This should never happen.");
1267
1268 x[m_j] = 0.0;
1269
1270 if(isZero(m_loJ) && isZero(m_upJ) && m_loJ == m_upJ)
1271 cStatus[m_j] = SPxSolverBase<R>::FIXED;
1272 else if(isZero(m_loJ))
1273 cStatus[m_j] = SPxSolverBase<R>::ON_LOWER;
1274 else if(isZero(m_upJ))
1275 cStatus[m_j] = SPxSolverBase<R>::ON_UPPER;
1276 else if(LErel(m_loJ, R(0.0)) && GErel(m_upJ, R(0.0)))
1277 cStatus[m_j] = SPxSolverBase<R>::ZERO;
1278 else
1279 throw SPxInternalCodeException("XMAISM06 This should never happen.");
1280 }
1281 else if(cStatus[m_k] == SPxSolverBase<R>::BASIC)
1282 {
1283 R scale1 = maxAbs(x[m_k], m_loK);
1284 R scale2 = maxAbs(x[m_k], m_upK);
1285
1286 if(scale1 < 1.0)
1287 scale1 = 1.0;
1288
1289 if(scale2 < 1.0)
1290 scale2 = 1.0;
1291
1292 R z1 = (x[m_k] / scale1) - (m_loK / scale1);
1293 R z2 = (x[m_k] / scale2) - (m_upK / scale2);
1294
1295 if(isZero(z1))
1296 z1 = 0.0;
1297
1298 if(isZero(z2))
1299 z2 = 0.0;
1300
1301 if(m_loJ <= R(-infinity) && m_upJ >= R(infinity) && m_loK <= R(-infinity) && m_upK >= R(infinity))
1302 {
1303 cStatus[m_j] = SPxSolverBase<R>::ZERO;
1304 x[m_j] = 0.0;
1305 }
1306 else if(m_scale > 0.0)
1307 {
1308 if(GErel(x[m_k], m_upK + m_scale * m_upJ))
1309 {
1310 assert(m_upJ < R(infinity));
1311 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
1312 x[m_j] = m_upJ;
1313 x[m_k] -= m_scale * x[m_j];
1314 }
1315 else if(GErel(x[m_k], m_loK + m_scale * m_upJ) && m_upJ < R(infinity))
1316 {
1317 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
1318 x[m_j] = m_upJ;
1319 x[m_k] -= m_scale * x[m_j];
1320 }
1321 else if(GErel(x[m_k], m_upK + m_scale * m_loJ) && m_upK < R(infinity))
1322 {
1323 cStatus[m_k] = (m_loK == m_upK) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
1324 x[m_k] = m_upK;
1325 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1326 x[m_j] = z2 * scale2 / m_scale;
1327 }
1328 else if(GErel(x[m_k], m_loK + m_scale * m_loJ) && m_loJ > R(-infinity))
1329 {
1330 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
1331 x[m_j] = m_loJ;
1332 x[m_k] -= m_scale * x[m_j];
1333 }
1334 else if(GErel(x[m_k], m_loK + m_scale * m_loJ) && m_loK > R(-infinity))
1335 {
1336 cStatus[m_k] = (m_loK == m_upK) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
1337 x[m_k] = m_loK;
1338 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1339 x[m_j] = z1 * scale1 / m_scale;
1340 }
1341 else if(LTrel(x[m_k], m_loK + m_scale * m_loJ))
1342 {
1343 assert(m_loJ > R(-infinity));
1344 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
1345 x[m_j] = m_loJ;
1346 x[m_k] -= m_scale * x[m_j];
1347 }
1348 else
1349 {
1350 throw SPxInternalCodeException("XMAISM08 This should never happen.");
1351 }
1352 }
1353 else
1354 {
1355 assert(m_scale < 0.0);
1356
1357 if(GErel(x[m_k], m_upK + m_scale * m_loJ))
1358 {
1359 assert(m_loJ > R(-infinity));
1360 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
1361 x[m_j] = m_loJ;
1362 x[m_k] -= m_scale * x[m_j];
1363 }
1364 else if(GErel(x[m_k], m_loK + m_scale * m_loJ) && m_loJ > R(-infinity))
1365 {
1366 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
1367 x[m_j] = m_loJ;
1368 x[m_k] -= m_scale * x[m_j];
1369 }
1370 else if(GErel(x[m_k], m_upK + m_scale * m_upJ) && m_upK < R(infinity))
1371 {
1372 cStatus[m_k] = (m_loK == m_upK) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
1373 x[m_k] = m_upK;
1374 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1375 x[m_j] = z2 * scale2 / m_scale;
1376 }
1377 else if(GErel(x[m_k], m_loK + m_scale * m_upJ) && m_upJ < R(infinity))
1378 {
1379 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
1380 x[m_j] = m_upJ;
1381 x[m_k] -= m_scale * x[m_j];
1382 }
1383 else if(GErel(x[m_k], m_loK + m_scale * m_upJ) && m_loK > R(-infinity))
1384 {
1385 cStatus[m_k] = (m_loK == m_upK) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_LOWER;
1386 x[m_k] = m_loK;
1387 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1388 x[m_j] = z1 * scale1 / m_scale;
1389 }
1390 else if(LTrel(x[m_k], m_loK + m_scale * m_upJ))
1391 {
1392 assert(m_upJ < R(infinity));
1393 cStatus[m_j] = (m_loJ == m_upJ) ? SPxSolverBase<R>::FIXED : SPxSolverBase<R>::ON_UPPER;
1394 x[m_j] = m_upJ;
1395 x[m_k] -= m_scale * x[m_j];
1396 }
1397 else
1398 {
1399 throw SPxInternalCodeException("XMAISM09 This should never happen.");
1400 }
1401 }
1402 }
1403
1404 // dual:
1405 r[m_j] = m_scale * r[m_k];
1406 }
1407
1408 template <class R>
1409 void SPxMainSM<R>::AggregationPS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>& s,
1410 VectorBase<R>& r,
1411 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
1412 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
1413 {
1414 // correcting the change of idx by deletion of the row:
1415 if(m_i != m_old_i)
1416 {
1417 s[m_old_i] = s[m_i];
1418 y[m_old_i] = y[m_i];
1419 rStatus[m_old_i] = rStatus[m_i];
1420 }
1421
1422 // correcting the change of idx by deletion of the column:
1423 if(m_j != m_old_j)
1424 {
1425 x[m_old_j] = x[m_j];
1426 r[m_old_j] = r[m_j];
1427 cStatus[m_old_j] = cStatus[m_j];
1428 }
1429
1430 // primal:
1431 R val = 0.0;
1432 R aij = m_row[m_j];
1433 int active_idx = -1;
1434
1435 assert(m_row.size() == 2);
1436
1437 for(int k = 0; k < 2; ++k)
1438 {
1439 if(m_row.index(k) != m_j)
1440 {
1441 active_idx = m_row.index(k);
1442 val = m_row.value(k) * x[active_idx];
1443 }
1444 }
1445
1446 assert(active_idx >= 0);
1447
1448 R scale = maxAbs(m_rhs, val);
1449
1450 if(scale < 1.0)
1451 scale = 1.0;
1452
1453 R z = (m_rhs / scale) - (val / scale);
1454
1455 if(isZero(z))
1456 z = 0.0;
1457
1458 x[m_j] = z * scale / aij;
1459 s[m_i] = m_rhs;
1460
1461 if(isOptimal && (LT(x[m_j], m_lower, this->eps()) || GT(x[m_j], m_upper, this->eps())))
1462 {
1463 MSG_ERROR(std::cerr << "EMAISM: numerical violation after disaggregating variable" << std::endl;)
1464 }
1465
1466 // dual:
1467 R dualVal = 0.0;
1468
1469 for(int k = 0; k < m_col.size(); ++k)
1470 {
1471 if(m_col.index(k) != m_i)
1472 dualVal += m_col.value(k) * y[m_col.index(k)];
1473 }
1474
1475 z = m_obj - dualVal;
1476
1477 y[m_i] = z / aij;
1478 r[m_j] = 0.0;
1479
1480 // basis:
1481 if(((cStatus[active_idx] == SPxSolverBase<R>::ON_UPPER
1482 || cStatus[active_idx] == SPxSolverBase<R>::FIXED)
1483 && NE(x[active_idx], m_oldupper, this->eps())) ||
1484 ((cStatus[active_idx] == SPxSolverBase<R>::ON_LOWER
1485 || cStatus[active_idx] == SPxSolverBase<R>::FIXED)
1486 && NE(x[active_idx], m_oldlower, this->eps())))
1487 {
1488 cStatus[active_idx] = SPxSolverBase<R>::BASIC;
1489 r[active_idx] = 0.0;
1490 assert(NE(m_upper, m_lower));
1491
1492 if(EQ(x[m_j], m_upper, this->eps()))
1493 cStatus[m_j] = SPxSolverBase<R>::ON_UPPER;
1494 else if(EQ(x[m_j], m_lower, this->eps()))
1495 cStatus[m_j] = SPxSolverBase<R>::ON_LOWER;
1496 else if(m_upper >= R(infinity) && m_lower <= R(-infinity))
1497 cStatus[m_j] = SPxSolverBase<R>::ZERO;
1498 else
1499 throw SPxInternalCodeException("XMAISM unexpected basis status in aggregation unsimplifier.");
1500 }
1501 else
1502 {
1503 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1504 }
1505
1506 // sides may not be equal and we always only consider the rhs during aggregation, so set ON_UPPER
1507 // (in theory and with exact arithmetic setting it to FIXED would be correct)
1508 rStatus[m_i] = SPxSolverBase<R>::ON_UPPER;
1509
1510 #ifdef CHECK_BASIC_DIM
1511
1512 if(!this->checkBasisDim(rStatus, cStatus))
1513 {
1514 throw SPxInternalCodeException("XMAISM22 Dimension doesn't match after this step.");
1515 }
1516
1517 #endif
1518 }
1519
1520 template <class R>
1521 void SPxMainSM<R>::MultiAggregationPS::execute(VectorBase<R>& x, VectorBase<R>& y, VectorBase<R>& s,
1522 VectorBase<R>& r,
1523 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
1524 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
1525 {
1526
1527 // correcting the change of idx by deletion of the row:
1528 if(m_i != m_old_i)
1529 {
1530 s[m_old_i] = s[m_i];
1531 y[m_old_i] = y[m_i];
1532 rStatus[m_old_i] = rStatus[m_i];
1533 }
1534
1535 // correcting the change of idx by deletion of the column:
1536 if(m_j != m_old_j)
1537 {
1538 x[m_old_j] = x[m_j];
1539 r[m_old_j] = r[m_j];
1540 cStatus[m_old_j] = cStatus[m_j];
1541 }
1542
1543 // primal:
1544 R val = 0.0;
1545 R aij = m_row[m_j];
1546
1547 for(int k = 0; k < m_row.size(); ++k)
1548 {
1549 if(m_row.index(k) != m_j)
1550 val += m_row.value(k) * x[m_row.index(k)];
1551 }
1552
1553 R scale = maxAbs(m_const, val);
1554
1555 if(scale < 1.0)
1556 scale = 1.0;
1557
1558 R z = (m_const / scale) - (val / scale);
1559
1560 if(isZero(z))
1561 z = 0.0;
1562
1563 x[m_j] = z * scale / aij;
1564 s[m_i] = 0.0;
1565
1566 #ifndef NDEBUG
1567
1568 if(isOptimal && (LT(x[m_j], m_lower, this->eps()) || GT(x[m_j], m_upper, this->eps())))
1569 MSG_ERROR(std::cerr << "numerical violation in original space due to MultiAggregation\n";)
1570 #endif
1571
1572 // dual:
1573 R dualVal = 0.0;
1574
1575 for(int k = 0; k < m_col.size(); ++k)
1576 {
1577 if(m_col.index(k) != m_i)
1578 dualVal += m_col.value(k) * y[m_col.index(k)];
1579 }
1580
1581 z = m_obj - dualVal;
1582
1583 y[m_i] = z / aij;
1584 r[m_j] = 0.0;
1585
1586 // basis:
1587 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1588
1589 if(m_eqCons)
1590 rStatus[m_i] = SPxSolverBase<R>::FIXED;
1591 else if(m_onLhs)
1592 rStatus[m_i] = SPxSolverBase<R>::ON_LOWER;
1593 else
1594 rStatus[m_i] = SPxSolverBase<R>::ON_UPPER;
1595
1596 #ifdef CHECK_BASIC_DIM
1597
1598 if(!this->checkBasisDim(rStatus, cStatus))
1599 {
1600 throw SPxInternalCodeException("XMAISM22 Dimension doesn't match after this step.");
1601 }
1602
1603 #endif
1604 }
1605
1606 template <class R>
1607 void SPxMainSM<R>::TightenBoundsPS::execute(VectorBase<R>& x, VectorBase<R>&, VectorBase<R>&,
1608 VectorBase<R>&,
1609 DataArray<typename SPxSolverBase<R>::VarStatus>& cStatus,
1610 DataArray<typename SPxSolverBase<R>::VarStatus>& rStatus, bool isOptimal) const
1611 {
1612 // basis:
1613 switch(cStatus[m_j])
1614 {
1615 case SPxSolverBase<R>::FIXED:
1616 if(LT(x[m_j], m_origupper, this->eps()) && GT(x[m_j], m_origlower, this->eps()))
1617 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1618 else if(LT(x[m_j], m_origupper, this->eps()))
1619 cStatus[m_j] = SPxSolverBase<R>::ON_LOWER;
1620 else if(GT(x[m_j], m_origlower, this->eps()))
1621 cStatus[m_j] = SPxSolverBase<R>::ON_UPPER;
1622
1623 break;
1624
1625 case SPxSolverBase<R>::ON_LOWER:
1626 if(GT(x[m_j], m_origlower, this->eps()))
1627 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1628
1629 break;
1630
1631 case SPxSolverBase<R>::ON_UPPER:
1632 if(LT(x[m_j], m_origupper, this->eps()))
1633 cStatus[m_j] = SPxSolverBase<R>::BASIC;
1634
1635 break;
1636
1637 default:
1638 break;
1639 }
1640
1641 #ifdef CHECK_BASIC_DIM
1642
1643 if(!this->checkBasisDim(rStatus, cStatus))
1644 {
1645 throw SPxInternalCodeException("XMAISM22 Dimension doesn't match after this step.");
1646 }
1647
1648 #endif
1649 }
1650
1651 template <class R>
1652 void SPxMainSM<R>::handleRowObjectives(SPxLPBase<R>& lp)
1653 {
1654 for(int i = lp.nRows() - 1; i >= 0; --i)
1655 {
1656 if(lp.maxRowObj(i) != 0.0)
1657 {
1658 std::shared_ptr<PostStep> ptr(new RowObjPS(lp, i, lp.nCols()));
1659 m_hist.append(ptr);
1660 lp.addCol(lp.rowObj(i), -lp.rhs(i), UnitVectorBase<R>(i), -lp.lhs(i));
1661 lp.changeRange(i, R(0.0), R(0.0));
1662 lp.changeRowObj(i, R(0.0));
1663 m_addedcols++;
1664 }
1665 }
1666 }
1667
1668 template <class R>
1669 void SPxMainSM<R>::handleExtremes(SPxLPBase<R>& lp)
1670 {
1671
1672 // This method handles extreme value of the given LP by
1673 //
1674 // 1. setting numbers of very small absolute values to zero and
1675 // 2. setting numbers of very large absolute values to R(-infinity) or +R(infinity), respectively.
1676
1677 R maxVal = R(infinity) / 5.0;
1678 R tol = feastol() * 1e-2;
1679 tol = (tol < this->epsZero()) ? this->epsZero() : tol;
1680 int remRows = 0;
1681 int remNzos = 0;
1682 int chgBnds = 0;
1683 int chgLRhs = 0;
1684 int objCnt = 0;
1685
1686 for(int i = lp.nRows() - 1; i >= 0; --i)
1687 {
1688 // lhs
1689 R lhs = lp.lhs(i);
1690
1691 if(lhs != 0.0 && isZero(lhs, this->epsZero()))
1692 {
1693 lp.changeLhs(i, R(0.0));
1694 ++chgLRhs;
1695 }
1696 else if(lhs > R(-infinity) && lhs < -maxVal)
1697 {
1698 lp.changeLhs(i, R(-infinity));
1699 ++chgLRhs;
1700 }
1701 else if(lhs < R(infinity) && lhs > maxVal)
1702 {
1703 lp.changeLhs(i, R(infinity));
1704 ++chgLRhs;
1705 }
1706
1707 // rhs
1708 R rhs = lp.rhs(i);
1709
1710 if(rhs != 0.0 && isZero(rhs, this->epsZero()))
1711 {
1712 lp.changeRhs(i, R(0.0));
1713 ++chgLRhs;
1714 }
1715 else if(rhs > R(-infinity) && rhs < -maxVal)
1716 {
1717 lp.changeRhs(i, R(-infinity));
1718 ++chgLRhs;
1719 }
1720 else if(rhs < R(infinity) && rhs > maxVal)
1721 {
1722 lp.changeRhs(i, R(infinity));
1723 ++chgLRhs;
1724 }
1725
1726 if(lp.lhs(i) <= R(-infinity) && lp.rhs(i) >= R(infinity))
1727 {
1728 std::shared_ptr<PostStep> ptr(new FreeConstraintPS(lp, i));
1729 m_hist.append(ptr);
1730
1731 removeRow(lp, i);
1732 ++remRows;
1733
1734 ++m_stat[FREE_ROW];
1735 }
1736 }
1737
1738 for(int j = 0; j < lp.nCols(); ++j)
1739 {
1740 // lower bound
1741 R lo = lp.lower(j);
1742
1743 if(lo != 0.0 && isZero(lo, this->epsZero()))
1744 {
1745 lp.changeLower(j, R(0.0));
1746 ++chgBnds;
1747 }
1748 else if(lo > R(-infinity) && lo < -maxVal)
1749 {
1750 lp.changeLower(j, R(-infinity));
1751 ++chgBnds;
1752 }
1753 else if(lo < R(infinity) && lo > maxVal)
1754 {
1755 lp.changeLower(j, R(infinity));
1756 ++chgBnds;
1757 }
1758
1759 // upper bound
1760 R up = lp.upper(j);
1761
1762 if(up != 0.0 && isZero(up, this->epsZero()))
1763 {
1764 lp.changeUpper(j, R(0.0));
1765 ++chgBnds;
1766 }
1767 else if(up > R(-infinity) && up < -maxVal)
1768 {
1769 lp.changeUpper(j, R(-infinity));
1770 ++chgBnds;
1771 }
1772 else if(up < R(infinity) && up > maxVal)
1773 {
1774 lp.changeUpper(j, R(infinity));
1775 ++chgBnds;
1776 }
1777
1778 // fixed columns will be eliminated later
1779 if(NE(lo, up))
1780 {
1781 lo = spxAbs(lo);
1782 up = spxAbs(up);
1783
1784 R absBnd = (lo > up) ? lo : up;
1785
1786 if(absBnd < 1.0)
1787 absBnd = 1.0;
1788
1789 // non-zeros
1790 SVectorBase<R>& col = lp.colVector_w(j);
1791 int i = 0;
1792
1793 while(i < col.size())
1794 {
1795 R aij = spxAbs(col.value(i));
1796
1797 if(isZero(aij * absBnd, tol))
1798 {
1799 SVectorBase<R>& row = lp.rowVector_w(col.index(i));
1800 int row_j = row.pos(j);
1801
1802 // this changes col.size()
1803 if(row_j >= 0)
1804 row.remove(row_j);
1805
1806 col.remove(i);
1807
1808 MSG_DEBUG((*this->spxout) << "IMAISM04 aij=" << aij
1809 << " removed, absBnd=" << absBnd
1810 << std::endl;)
1811 ++remNzos;
1812 }
1813 else
1814 {
1815 if(aij > maxVal)
1816 {
1817 MSG_WARNING((*this->spxout), (*this->spxout) << "WMAISM05 Warning! Big matrix coefficient " << aij
1818 << std::endl);
1819 }
1820 else if(isZero(aij, tol))
1821 {
1822 MSG_WARNING((*this->spxout), (*this->spxout) << "WMAISM06 Warning! Tiny matrix coefficient " << aij
1823 << std::endl);
1824 }
1825
1826 ++i;
1827 }
1828 }
1829 }
1830
1831 // objective
1832 R obj = lp.obj(j);
1833
1834 if(obj != 0.0 && isZero(obj, this->epsZero()))
1835 {
1836 lp.changeObj(j, R(0.0));
1837 ++objCnt;
1838 }
1839 else if(obj > R(-infinity) && obj < -maxVal)
1840 {
1841 lp.changeObj(j, R(-infinity));
1842 ++objCnt;
1843 }
1844 else if(obj < R(infinity) && obj > maxVal)
1845 {
1846 lp.changeObj(j, R(infinity));
1847 ++objCnt;
1848 }
1849 }
1850
1851 if(remRows + remNzos + chgLRhs + chgBnds + objCnt > 0)
1852 {
1853 this->m_remRows += remRows;
1854 this->m_remNzos += remNzos;
1855 this->m_chgLRhs += chgLRhs;
1856 this->m_chgBnds += chgBnds;
1857
1858 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier (extremes) removed "
1859 << remRows << " rows, "
1860 << remNzos << " non-zeros, "
1861 << chgBnds << " col bounds, "
1862 << chgLRhs << " row bounds, "
1863 << objCnt << " objective coefficients" << std::endl;)
1864 }
1865
1866 assert(lp.isConsistent());
1867 }
1868
1869 /// computes the minimum and maximum residual activity for a given variable
1870 template <class R>
1871 void SPxMainSM<R>::computeMinMaxResidualActivity(SPxLPBase<R>& lp, int rowNumber, int colNumber,
1872 R& minAct, R& maxAct)
1873 {
1874 const SVectorBase<R>& row = lp.rowVector(rowNumber);
1875 bool minNegInfinite = false;
1876 bool maxInfinite = false;
1877
1878 minAct = 0; // this is the minimum value that the aggregation can attain
1879 maxAct = 0; // this is the maximum value that the aggregation can attain
1880
1881 for(int l = 0; l < row.size(); ++l)
1882 {
1883 if(colNumber < 0 || row.index(l) != colNumber)
1884 {
1885 // computing the minimum activity of the aggregated variables
1886 if(GT(row.value(l), R(0.0)))
1887 {
1888 if(LE(lp.lower(row.index(l)), R(-infinity)))
1889 minNegInfinite = true;
1890 else
1891 minAct += row.value(l) * lp.lower(row.index(l));
1892 }
1893 else if(LT(row.value(l), R(0.0)))
1894 {
1895 if(GE(lp.upper(row.index(l)), R(infinity)))
1896 minNegInfinite = true;
1897 else
1898 minAct += row.value(l) * lp.upper(row.index(l));
1899 }
1900
1901 // computing the maximum activity of the aggregated variables
1902 if(GT(row.value(l), R(0.0)))
1903 {
1904 if(GE(lp.upper(row.index(l)), R(infinity)))
1905 maxInfinite = true;
1906 else
1907 maxAct += row.value(l) * lp.upper(row.index(l));
1908 }
1909 else if(LT(row.value(l), R(0.0)))
1910 {
1911 if(LE(lp.lower(row.index(l)), R(-infinity)))
1912 maxInfinite = true;
1913 else
1914 maxAct += row.value(l) * lp.lower(row.index(l));
1915 }
1916 }
1917 }
1918
1919 // if an infinite value exists for the minimum activity, then that it taken
1920 if(minNegInfinite)
1921 minAct = R(-infinity);
1922
1923 // if an -infinite value exists for the maximum activity, then that value is taken
1924 if(maxInfinite)
1925 maxAct = R(infinity);
1926 }
1927
1928
1929 /// calculate min/max value for the multi aggregated variables
1930 template <class R>
1931 void SPxMainSM<R>::computeMinMaxValues(SPxLPBase<R>& lp, R side, R val, R minRes, R maxRes,
1932 R& minVal, R& maxVal)
1933 {
1934 minVal = 0;
1935 maxVal = 0;
1936
1937 if(LT(val, R(0.0)))
1938 {
1939 if(LE(minRes, R(-infinity)))
1940 minVal = R(-infinity);
1941 else
1942 minVal = (side - minRes) / val;
1943
1944 if(GE(maxRes, R(infinity)))
1945 maxVal = R(infinity);
1946 else
1947 maxVal = (side - maxRes) / val;
1948 }
1949 else if(GT(val, R(0.0)))
1950 {
1951 if(GE(maxRes, R(infinity)))
1952 minVal = R(-infinity);
1953 else
1954 minVal = (side - maxRes) / val;
1955
1956 if(LE(minRes, R(-infinity)))
1957 maxVal = R(infinity);
1958 else
1959 maxVal = (side - minRes) / val;
1960 }
1961 }
1962
1963
1964 /// tries to find good lower bound solutions by applying some trivial heuristics
1965 template <class R>
1966 void SPxMainSM<R>::trivialHeuristic(SPxLPBase<R>& lp)
1967 {
1968 VectorBase<R> zerosol(lp.nCols()); // the zero solution VectorBase<R>
1969 VectorBase<R> lowersol(lp.nCols()); // the lower bound solution VectorBase<R>
1970 VectorBase<R> uppersol(lp.nCols()); // the upper bound solution VectorBase<R>
1971 VectorBase<R> locksol(lp.nCols()); // the locks solution VectorBase<R>
1972
1973 VectorBase<R> upLocks(lp.nCols());
1974 VectorBase<R> downLocks(lp.nCols());
1975
1976 R zeroObj = this->m_objoffset;
1977 R lowerObj = this->m_objoffset;
1978 R upperObj = this->m_objoffset;
1979 R lockObj = this->m_objoffset;
1980
1981 bool zerovalid = true;
1982
1983 R largeValue = R(infinity);
1984
1985 if(LT(R(1.0 / feastol()), R(infinity)))
1986 largeValue = 1.0 / feastol();
1987
1988
1989
1990 for(int j = lp.nCols() - 1; j >= 0; --j)
1991 {
1992 upLocks[j] = 0;
1993 downLocks[j] = 0;
1994
1995 // computing the locks on the variables
1996 const SVectorBase<R>& col = lp.colVector(j);
1997
1998 for(int k = 0; k < col.size(); ++k)
1999 {
2000 R aij = col.value(k);
2001
2002 ASSERT_WARN("WMAISM45", isNotZero(aij, R(1.0 / R(infinity))));
2003
2004 if(GT(lp.lhs(col.index(k)), R(-infinity)) && LT(lp.rhs(col.index(k)), R(infinity)))
2005 {
2006 upLocks[j]++;
2007 downLocks[j]++;
2008 }
2009 else if(GT(lp.lhs(col.index(k)), R(-infinity)))
2010 {
2011 if(aij > 0)
2012 downLocks[j]++;
2013 else if(aij < 0)
2014 upLocks[j]++;
2015 }
2016 else if(LT(lp.rhs(col.index(k)), R(infinity)))
2017 {
2018 if(aij > 0)
2019 upLocks[j]++;
2020 else if(aij < 0)
2021 downLocks[j]++;
2022 }
2023 }
2024
2025 R lower = lp.lower(j);
2026 R upper = lp.upper(j);
2027
2028 if(LE(lower, R(-infinity)))
2029 lower = MINIMUM(-largeValue, upper);
2030
2031 if(GE(upper, R(infinity)))
2032 upper = MAXIMUM(lp.lower(j), largeValue);
2033
2034 if(zerovalid)
2035 {
2036 if(LE(lower, R(0.0), feastol()) && GE(upper, R(0.0), feastol()))
2037 zerosol[j] = 0.0;
2038 else
2039 zerovalid = false;
2040 }
2041
2042 lowersol[j] = lower;
2043 uppersol[j] = upper;
2044
2045 if(downLocks[j] > upLocks[j])
2046 locksol[j] = upper;
2047 else if(downLocks[j] < upLocks[j])
2048 locksol[j] = lower;
2049 else
2050 locksol[j] = (lower + upper) / 2.0;
2051
2052 lowerObj += lp.maxObj(j) * lowersol[j];
2053 upperObj += lp.maxObj(j) * uppersol[j];
2054 lockObj += lp.maxObj(j) * locksol[j];
2055 }
2056
2057 // trying the lower bound solution
2058 if(checkSolution(lp, lowersol))
2059 {
2060 if(lowerObj > m_cutoffbound)
2061 m_cutoffbound = lowerObj;
2062 }
2063
2064 // trying the upper bound solution
2065 if(checkSolution(lp, uppersol))
2066 {
2067 if(upperObj > m_cutoffbound)
2068 m_cutoffbound = upperObj;
2069 }
2070
2071 // trying the zero solution
2072 if(zerovalid && checkSolution(lp, zerosol))
2073 {
2074 if(zeroObj > m_cutoffbound)
2075 m_cutoffbound = zeroObj;
2076 }
2077
2078 // trying the lock solution
2079 if(checkSolution(lp, locksol))
2080 {
2081 if(lockObj > m_cutoffbound)
2082 m_cutoffbound = lockObj;
2083 }
2084 }
2085
2086
2087
2088 /// checks a solution for feasibility
2089 template <class R>
2090 bool SPxMainSM<R>::checkSolution(SPxLPBase<R>& lp, VectorBase<R> sol)
2091 {
2092 for(int i = lp.nRows() - 1; i >= 0; --i)
2093 {
2094 const SVectorBase<R>& row = lp.rowVector(i);
2095 R activity = 0;
2096
2097 for(int k = 0; k < row.size(); k++)
2098 activity += row.value(k) * sol[row.index(k)];
2099
2100 if(!GE(activity, lp.lhs(i), feastol()) || !LE(activity, lp.rhs(i), feastol()))
2101 return false;
2102 }
2103
2104 return true;
2105 }
2106
2107
2108 /// tightens variable bounds by propagating the pseudo objective function value.
2109 template <class R>
2110 void SPxMainSM<R>::propagatePseudoobj(SPxLPBase<R>& lp)
2111 {
2112 R pseudoObj = this->m_objoffset;
2113
2114 for(int j = lp.nCols() - 1; j >= 0; --j)
2115 {
2116 R val = lp.maxObj(j);
2117
2118 if(val < 0)
2119 {
2120 if(lp.lower(j) <= R(-infinity))
2121 return;
2122
2123 pseudoObj += val * lp.lower(j);
2124 }
2125 else if(val > 0)
2126 {
2127 if(lp.upper(j) >= R(-infinity))
2128 return;
2129
2130 pseudoObj += val * lp.upper(j);
2131 }
2132 }
2133
2134 if(GT(m_cutoffbound, R(-infinity)) && LT(m_cutoffbound, R(infinity)))
2135 {
2136 if(pseudoObj > m_pseudoobj)
2137 m_pseudoobj = pseudoObj;
2138
2139 for(int j = lp.nCols() - 1; j >= 0; --j)
2140 {
2141 R objval = lp.maxObj(j);
2142
2143 if(EQ(objval, R(0.0)))
2144 continue;
2145
2146 if(objval < 0.0)
2147 {
2148 R newbound = lp.lower(j) + (m_cutoffbound - m_pseudoobj) / objval;
2149
2150 if(LT(newbound, lp.upper(j)))
2151 {
2152 std::shared_ptr<PostStep> ptr(new TightenBoundsPS(lp, j, lp.upper(j), lp.lower(j)));
2153 m_hist.append(ptr);
2154 lp.changeUpper(j, newbound);
2155 }
2156 }
2157 else if(objval > 0.0)
2158 {
2159 R newbound = lp.upper(j) + (m_cutoffbound - m_pseudoobj) / objval;
2160
2161 if(GT(newbound, lp.lower(j)))
2162 {
2163 std::shared_ptr<PostStep> ptr(new TightenBoundsPS(lp, j, lp.upper(j), lp.lower(j)));
2164 m_hist.append(ptr);
2165 lp.changeLower(j, newbound);
2166 }
2167 }
2168 }
2169 }
2170 }
2171
2172
2173
2174 template <class R>
2175 typename SPxSimplifier<R>::Result SPxMainSM<R>::removeEmpty(SPxLPBase<R>& lp)
2176 {
2177
2178 // This method removes empty rows and columns from the LP.
2179
2180 int remRows = 0;
2181 int remCols = 0;
2182
2183 for(int i = lp.nRows() - 1; i >= 0; --i)
2184 {
2185 const SVectorBase<R>& row = lp.rowVector(i);
2186
2187 if(row.size() == 0)
2188 {
2189 MSG_DEBUG((*this->spxout) << "IMAISM07 row " << i
2190 << ": empty ->";)
2191
2192 if(LT(lp.rhs(i), R(0.0), feastol()) || GT(lp.lhs(i), R(0.0), feastol()))
2193 {
2194 MSG_DEBUG((*this->spxout) << " infeasible lhs=" << lp.lhs(i)
2195 << " rhs=" << lp.rhs(i) << std::endl;)
2196 return this->INFEASIBLE;
2197 }
2198
2199 MSG_DEBUG((*this->spxout) << " removed" << std::endl;)
2200
2201 std::shared_ptr<PostStep> ptr(new EmptyConstraintPS(lp, i));
2202 m_hist.append(ptr);
2203
2204 ++remRows;
2205 removeRow(lp, i);
2206
2207 ++m_stat[EMPTY_ROW];
2208 }
2209 }
2210
2211 for(int j = lp.nCols() - 1; j >= 0; --j)
2212 {
2213 const SVectorBase<R>& col = lp.colVector(j);
2214
2215 if(col.size() == 0)
2216 {
2217 MSG_DEBUG((*this->spxout) << "IMAISM08 col " << j
2218 << ": empty -> maxObj=" << lp.maxObj(j)
2219 << " lower=" << lp.lower(j)
2220 << " upper=" << lp.upper(j);)
2221
2222 R val;
2223
2224 if(GT(lp.maxObj(j), R(0.0), this->epsZero()))
2225 {
2226 if(lp.upper(j) >= R(infinity))
2227 {
2228 MSG_DEBUG((*this->spxout) << " unbounded" << std::endl;)
2229 return this->UNBOUNDED;
2230 }
2231
2232 val = lp.upper(j);
2233 }
2234 else if(LT(lp.maxObj(j), R(0.0), this->epsZero()))
2235 {
2236 if(lp.lower(j) <= R(-infinity))
2237 {
2238 MSG_DEBUG((*this->spxout) << " unbounded" << std::endl;)
2239 return this->UNBOUNDED;
2240 }
2241
2242 val = lp.lower(j);
2243 }
2244 else
2245 {
2246 ASSERT_WARN("WMAISM09", isZero(lp.maxObj(j), this->epsZero()));
2247
2248 // any value within the bounds is ok
2249 if(lp.lower(j) > R(-infinity))
2250 val = lp.lower(j);
2251 else if(lp.upper(j) < R(infinity))
2252 val = lp.upper(j);
2253 else
2254 val = 0.0;
2255 }
2256
2257 MSG_DEBUG((*this->spxout) << " removed" << std::endl;)
2258
2259 std::shared_ptr<PostStep> ptr1(new FixBoundsPS(lp, j, val));
2260 std::shared_ptr<PostStep> ptr2(new FixVariablePS(lp, *this, j, val));
2261 m_hist.append(ptr1);
2262 m_hist.append(ptr2);
2263
2264 ++remCols;
2265 removeCol(lp, j);
2266
2267 ++m_stat[EMPTY_COL];
2268 }
2269 }
2270
2271 if(remRows + remCols > 0)
2272 {
2273 this->m_remRows += remRows;
2274 this->m_remCols += remCols;
2275
2276 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier (empty rows/colums) removed "
2277 << remRows << " rows, "
2278 << remCols << " cols"
2279 << std::endl;)
2280
2281 }
2282
2283 return this->OKAY;
2284 }
2285
2286 template <class R>
2287 typename SPxSimplifier<R>::Result SPxMainSM<R>::removeRowSingleton(SPxLPBase<R>& lp,
2288 const SVectorBase<R>& row, int& i)
2289 {
2290 assert(row.size() == 1);
2291
2292 R aij = row.value(0);
2293 int j = row.index(0);
2294 R lo = R(-infinity);
2295 R up = R(infinity);
2296
2297 MSG_DEBUG((*this->spxout) << "IMAISM22 row " << i
2298 << ": singleton -> val=" << aij
2299 << " lhs=" << lp.lhs(i)
2300 << " rhs=" << lp.rhs(i);)
2301
2302 if(GT(aij, R(0.0), this->epsZero())) // aij > 0
2303 {
2304 lo = (lp.lhs(i) <= R(-infinity)) ? R(-infinity) : lp.lhs(i) / aij;
2305 up = (lp.rhs(i) >= R(infinity)) ? R(infinity) : lp.rhs(i) / aij;
2306 }
2307 else if(LT(aij, R(0.0), this->epsZero())) // aij < 0
2308 {
2309 lo = (lp.rhs(i) >= R(infinity)) ? R(-infinity) : lp.rhs(i) / aij;
2310 up = (lp.lhs(i) <= R(-infinity)) ? R(infinity) : lp.lhs(i) / aij;
2311 }
2312 else if(LT(lp.rhs(i), R(0.0), feastol()) || GT(lp.lhs(i), R(0.0), feastol()))
2313 {
2314 // aij == 0, rhs < 0 or lhs > 0
2315 MSG_DEBUG((*this->spxout) << " infeasible" << std::endl;)
2316 return this->INFEASIBLE;
2317 }
2318
2319 if(isZero(lo, this->epsZero()))
2320 lo = 0.0;
2321
2322 if(isZero(up, this->epsZero()))
2323 up = 0.0;
2324
2325 MSG_DEBUG((*this->spxout) << " removed, lower=" << lo
2326 << " (" << lp.lower(j)
2327 << ") upper=" << up
2328 << " (" << lp.upper(j)
2329 << ")" << std::endl;)
2330
2331 bool stricterUp = false;
2332 bool stricterLo = false;
2333
2334 R oldLo = lp.lower(j);
2335 R oldUp = lp.upper(j);
2336
2337 if(LTrel(up, lp.upper(j), feastol()))
2338 {
2339 lp.changeUpper(j, up);
2340 stricterUp = true;
2341 }
2342
2343 if(GTrel(lo, lp.lower(j), feastol()))
2344 {
2345 lp.changeLower(j, lo);
2346 stricterLo = true;
2347 }
2348
2349 std::shared_ptr<PostStep> ptr(new RowSingletonPS(lp, i, j, stricterLo, stricterUp, lp.lower(j),
2350 lp.upper(j), oldLo, oldUp));
2351 m_hist.append(ptr);
2352
2353 removeRow(lp, i);
2354
2355 this->m_remRows++;
2356 this->m_remNzos++;
2357 ++m_stat[SINGLETON_ROW];
2358
2359 return this->OKAY;
2360 }
2361
2362 /// aggregate variable x_j to x_j = (rhs - aik * x_k) / aij from row i: aij * x_j + aik * x_k = rhs
2363 template <class R>
2364 typename SPxSimplifier<R>::Result SPxMainSM<R>::aggregateVars(SPxLPBase<R>& lp,
2365 const SVectorBase<R>& row, int& i)
2366 {
2367 assert(row.size() == 2);
2368 assert(EQrel(lp.lhs(i), lp.rhs(i), feastol()));
2369
2370 R rhs = lp.rhs(i);
2371 assert(rhs < R(infinity) && rhs > R(-infinity));
2372
2373 int j = row.index(0);
2374 int k = row.index(1);
2375 R aij = row.value(0);
2376 R aik = row.value(1);
2377 R lower_j = lp.lower(j);
2378 R upper_j = lp.upper(j);
2379 R lower_k = lp.lower(k);
2380 R upper_k = lp.upper(k);
2381
2382 // fixed variables should be removed by simplifyCols()
2383 if(EQrel(lower_j, upper_j, feastol()) || EQrel(lower_k, upper_k, feastol()))
2384 return this->OKAY;
2385
2386 assert(isNotZero(aij, this->epsZero()) && isNotZero(aik, this->epsZero()));
2387
2388 MSG_DEBUG((*this->spxout) << "IMAISM22 row " << i << ": doubleton equation -> "
2389 << aij << " x_" << j << " + " << aik << " x_" << k << " = " << rhs;)
2390
2391 // determine which variable can be aggregated without requiring bound tightening of the other variable
2392 R new_lo_j;
2393 R new_up_j;
2394 R new_lo_k;
2395 R new_up_k;
2396
2397 if(aij * aik < 0.0)
2398 {
2399 // orientation persists
2400 new_lo_j = (upper_k >= R(infinity)) ? R(-infinity) : (rhs - aik * upper_k) / aij;
2401 new_up_j = (lower_k <= R(-infinity)) ? R(infinity) : (rhs - aik * lower_k) / aij;
2402 new_lo_k = (upper_j >= R(infinity)) ? R(-infinity) : (rhs - aij * upper_j) / aik;
2403 new_up_k = (lower_j <= R(-infinity)) ? R(infinity) : (rhs - aij * lower_j) / aik;
2404 }
2405 else if(aij * aik > 0.0)
2406 {
2407 // orientation is reversed
2408 new_lo_j = (lower_k <= R(-infinity)) ? R(-infinity) : (rhs - aik * lower_k) / aij;
2409 new_up_j = (upper_k >= R(infinity)) ? R(infinity) : (rhs - aik * upper_k) / aij;
2410 new_lo_k = (lower_j <= R(-infinity)) ? R(-infinity) : (rhs - aij * lower_j) / aik;
2411 new_up_k = (upper_j >= R(infinity)) ? R(infinity) : (rhs - aij * upper_j) / aik;
2412 }
2413 else
2414 throw SPxInternalCodeException("XMAISM12 This should never happen.");
2415
2416 bool flip_jk = false;
2417
2418 if(new_lo_j <= R(-infinity) && new_up_j >= R(infinity))
2419 {
2420 // no bound tightening on x_j when x_k is aggregated
2421 flip_jk = true;
2422 }
2423 else if(new_lo_k <= R(-infinity) && new_up_k >= R(infinity))
2424 {
2425 // no bound tightening on x_k when x_j is aggregated
2426 flip_jk = false;
2427 }
2428 else if(LE(new_lo_j, lower_j) && GE(new_up_j, upper_j))
2429 {
2430 if(LE(new_lo_k, lower_k) && GE(new_up_k, upper_k))
2431 {
2432 // both variables' bounds are not affected by aggregation; choose the better aggregation coeff (aik/aij)
2433 if(spxAbs(aij) > spxAbs(aik))
2434 flip_jk = false;
2435 else
2436 flip_jk = true;
2437 }
2438 else
2439 flip_jk = false;
2440 }
2441 else if(LE(new_lo_k, lower_k) && GE(new_up_k, upper_k))
2442 {
2443 flip_jk = true;
2444 }
2445 else
2446 {
2447 if(spxAbs(aij) > spxAbs(aik))
2448 flip_jk = false;
2449 else
2450 flip_jk = true;
2451 }
2452
2453 if(flip_jk)
2454 {
2455 int _j = j;
2456 R _aij = aij;
2457 R _lower_j = lower_j;
2458 R _upper_j = upper_j;
2459 j = k;
2460 k = _j;
2461 aij = aik;
2462 aik = _aij;
2463 lower_j = lower_k;
2464 lower_k = _lower_j;
2465 upper_j = upper_k;
2466 upper_k = _upper_j;
2467 }
2468
2469 const SVectorBase<R>& col_j = lp.colVector(j);
2470 const SVectorBase<R>& col_k = lp.colVector(k);
2471
2472 // aggregation coefficients (x_j = aggr_coef * x_k + aggr_const)
2473 R aggr_coef = - (aik / aij);
2474 R aggr_const = rhs / aij;
2475
2476 MSG_DEBUG((*this->spxout) << " removed, replacing x_" << j << " with "
2477 << aggr_const << " + " << aggr_coef << " * x_" << k << std::endl;)
2478
2479 // replace all occurrences of x_j
2480 for(int r = 0; r < col_j.size(); ++r)
2481 {
2482 int row_r = col_j.index(r);
2483 R arj = col_j.value(r);
2484
2485 // skip row i
2486 if(row_r == i)
2487 continue;
2488
2489 // adapt sides of row r
2490 R lhs_r = lp.lhs(row_r);
2491 R rhs_r = lp.rhs(row_r);
2492
2493 if(lhs_r > R(-infinity))
2494 {
2495 lp.changeLhs(row_r, lhs_r - aggr_const * arj);
2496 this->m_chgLRhs++;
2497 }
2498
2499 if(rhs_r < R(infinity))
2500 {
2501 lp.changeRhs(row_r, rhs_r - aggr_const * arj);
2502 this->m_chgLRhs++;
2503 }
2504
2505 R newcoef = aggr_coef * arj;
2506 int pos_rk = col_k.pos(row_r);
2507
2508 // check whether x_k is also present in row r and get its coefficient
2509 if(pos_rk >= 0)
2510 {
2511 R ark = col_k.value(pos_rk);
2512 newcoef += ark;
2513 this->m_remNzos++;
2514 }
2515
2516 // add new column k to row r or adapt the coefficient a_rk
2517 lp.changeElement(row_r, k, newcoef);
2518 }
2519
2520 // adapt objective function
2521 R obj_j = lp.obj(j);
2522
2523 if(isNotZero(obj_j, this->epsZero()))
2524 {
2525 this->addObjoffset(aggr_const * obj_j);
2526 R obj_k = lp.obj(k);
2527 lp.changeObj(k, obj_k + aggr_coef * obj_j);
2528 }
2529
2530 // adapt bounds of x_k
2531 R scale1 = maxAbs(rhs, aij * upper_j);
2532 R scale2 = maxAbs(rhs, aij * lower_j);
2533
2534 if(scale1 < 1.0)
2535 scale1 = 1.0;
2536
2537 if(scale2 < 1.0)
2538 scale2 = 1.0;
2539
2540 R z1 = (rhs / scale1) - (aij * upper_j / scale1);
2541 R z2 = (rhs / scale2) - (aij * lower_j / scale2);
2542
2543 // just some rounding
2544 if(isZero(z1, this->epsZero()))
2545 z1 = 0.0;
2546
2547 if(isZero(z2, this->epsZero()))
2548 z2 = 0.0;
2549
2550 // determine which side has to be used for the bounds comparison below
2551 if(aik * aij > 0.0)
2552 {
2553 new_lo_k = (upper_j >= R(infinity)) ? R(-infinity) : z1 * scale1 / aik;
2554 new_up_k = (lower_j <= R(-infinity)) ? R(infinity) : z2 * scale2 / aik;
2555 }
2556 else if(aik * aij < 0.0)
2557 {
2558 new_lo_k = (lower_j <= R(-infinity)) ? R(-infinity) : z2 * scale2 / aik;
2559 new_up_k = (upper_j >= R(infinity)) ? R(infinity) : z1 * scale1 / aik;
2560 }
2561 else
2562 throw SPxInternalCodeException("XMAISM12 This should never happen.");
2563
2564 // change bounds of x_k if the new ones are tighter
2565 R oldlower_k = lower_k;
2566 R oldupper_k = upper_k;
2567
2568 if(GT(new_lo_k, lower_k, this->epsZero()))
2569 {
2570 lp.changeLower(k, new_lo_k);
2571 this->m_chgBnds++;
2572 }
2573
2574 if(LT(new_up_k, upper_k, this->epsZero()))
2575 {
2576 lp.changeUpper(k, new_up_k);
2577 this->m_chgBnds++;
2578 }
2579
2580 std::shared_ptr<PostStep> ptr(new AggregationPS(lp, i, j, rhs, oldupper_k, oldlower_k));
2581 m_hist.append(ptr);
2582
2583 removeRow(lp, i);
2584 removeCol(lp, j);
2585
2586 this->m_remRows++;
2587 this->m_remCols++;
2588 this->m_remNzos += 2;
2589
2590 ++m_stat[AGGREGATION];
2591
2592 return this->OKAY;
2593 }
2594
2595 template <class R>
2596 typename SPxSimplifier<R>::Result SPxMainSM<R>::simplifyRows(SPxLPBase<R>& lp, bool& again)
2597 {
2598
2599 // This method simplifies the rows of the LP.
2600 //
2601 // The following operations are done:
2602 // 1. detect implied free variables
2603 // 2. detect implied free constraints
2604 // 3. detect infeasible constraints
2605 // 4. remove unconstrained constraints
2606 // 5. remove empty constraints
2607 // 6. remove row singletons and tighten the corresponding variable bounds if necessary
2608 // 7. remove doubleton equation, aka aggregation
2609 // 8. detect forcing rows and fix the corresponding variables
2610
2611 int remRows = 0;
2612 int remNzos = 0;
2613 int chgLRhs = 0;
2614 int chgBnds = 0;
2615 int keptBnds = 0;
2616 int keptLRhs = 0;
2617
2618 int oldRows = lp.nRows();
2619
2620 bool redundantLower;
2621 bool redundantUpper;
2622 bool redundantLhs;
2623 bool redundantRhs;
2624
2625 for(int i = lp.nRows() - 1; i >= 0; --i)
2626 {
2627 const SVectorBase<R>& row = lp.rowVector(i);
2628
2629
2630 // compute bounds on constraint value
2631 R lhsBnd = 0.0; // minimal activity (finite summands)
2632 R rhsBnd = 0.0; // maximal activity (finite summands)
2633 int lhsCnt = 0; // number of R(-infinity) summands in minimal activity
2634 int rhsCnt = 0; // number of +R(infinity) summands in maximal activity
2635
2636 for(int k = 0; k < row.size(); ++k)
2637 {
2638 R aij = row.value(k);
2639 int j = row.index(k);
2640
2641 if(!isNotZero(aij, R(1.0 / R(infinity))))
2642 {
2643 MSG_WARNING((*this->spxout), (*this->spxout) << "Warning: tiny nonzero coefficient " << aij <<
2644 " in row " << i << "\n");
2645 }
2646
2647 if(aij > 0.0)
2648 {
2649 if(lp.lower(j) <= R(-infinity))
2650 ++lhsCnt;
2651 else
2652 lhsBnd += aij * lp.lower(j);
2653
2654 if(lp.upper(j) >= R(infinity))
2655 ++rhsCnt;
2656 else
2657 rhsBnd += aij * lp.upper(j);
2658 }
2659 else if(aij < 0.0)
2660 {
2661 if(lp.lower(j) <= R(-infinity))
2662 ++rhsCnt;
2663 else
2664 rhsBnd += aij * lp.lower(j);
2665
2666 if(lp.upper(j) >= R(infinity))
2667 ++lhsCnt;
2668 else
2669 lhsBnd += aij * lp.upper(j);
2670 }
2671 }
2672
2673 #if FREE_BOUNDS
2674
2675 // 1. detect implied free variables
2676 if(rhsCnt <= 1 || lhsCnt <= 1)
2677 {
2678 for(int k = 0; k < row.size(); ++k)
2679 {
2680 R aij = row.value(k);
2681 int j = row.index(k);
2682
2683 redundantLower = false;
2684 redundantUpper = false;
2685
2686 ASSERT_WARN("WMAISM12", isNotZero(aij, R(1.0 / R(infinity))));
2687
2688 if(aij > 0.0)
2689 {
2690 if(lp.lhs(i) > R(-infinity) && lp.lower(j) > R(-infinity) && rhsCnt <= 1
2691 && NErel(lp.lhs(i), rhsBnd, feastol())
2692 // do not perform if strongly different orders of magnitude occur
2693 && spxAbs(lp.lhs(i) / maxAbs(rhsBnd, R(1.0))) > Param::epsilon())
2694 {
2695 R lo = R(-infinity);
2696 R scale = maxAbs(lp.lhs(i), rhsBnd);
2697
2698 if(scale < 1.0)
2699 scale = 1.0;
2700
2701 R z = (lp.lhs(i) / scale) - (rhsBnd / scale);
2702
2703 if(isZero(z, this->epsZero()))
2704 z = 0.0;
2705
2706 assert(rhsCnt > 0 || lp.upper(j) < R(infinity));
2707
2708 if(rhsCnt == 0)
2709 lo = lp.upper(j) + z * scale / aij;
2710 else if(lp.upper(j) >= R(infinity))
2711 lo = z * scale / aij;
2712
2713 if(isZero(lo, this->epsZero()))
2714 lo = 0.0;
2715
2716 if(GErel(lo, lp.lower(j), feastol()))
2717 {
2718 MSG_DEBUG((*this->spxout) << "IMAISM13 row " << i
2719 << ": redundant lower bound on x" << j
2720 << " -> lower=" << lo
2721 << " (" << lp.lower(j)
2722 << ")" << std::endl;)
2723
2724 redundantLower = true;
2725 }
2726
2727 }
2728
2729 if(lp.rhs(i) < R(infinity) && lp.upper(j) < R(infinity) && lhsCnt <= 1
2730 && NErel(lp.rhs(i), lhsBnd, feastol())
2731 // do not perform if strongly different orders of magnitude occur
2732 && spxAbs(lp.rhs(i) / maxAbs(lhsBnd, R(1.0))) > Param::epsilon())
2733 {
2734 R up = R(infinity);
2735 R scale = maxAbs(lp.rhs(i), lhsBnd);
2736
2737 if(scale < 1.0)
2738 scale = 1.0;
2739
2740 R z = (lp.rhs(i) / scale) - (lhsBnd / scale);
2741
2742 if(isZero(z, this->epsZero()))
2743 z = 0.0;
2744
2745 assert(lhsCnt > 0 || lp.lower(j) > R(-infinity));
2746
2747 if(lhsCnt == 0)
2748 up = lp.lower(j) + z * scale / aij;
2749 else if(lp.lower(j) <= R(-infinity))
2750 up = z * scale / aij;
2751
2752 if(isZero(up, this->epsZero()))
2753 up = 0.0;
2754
2755 if(LErel(up, lp.upper(j), feastol()))
2756 {
2757 MSG_DEBUG((*this->spxout) << "IMAISM14 row " << i
2758 << ": redundant upper bound on x" << j
2759 << " -> upper=" << up
2760 << " (" << lp.upper(j)
2761 << ")" << std::endl;)
2762
2763 redundantUpper = true;
2764 }
2765 }
2766
2767 if(redundantLower)
2768 {
2769 // no upper bound on x_j OR redundant upper bound
2770 if((lp.upper(j) >= R(infinity)) || redundantUpper || (!m_keepbounds))
2771 {
2772 ++lhsCnt;
2773 lhsBnd -= aij * lp.lower(j);
2774
2775 lp.changeLower(j, R(-infinity));
2776 ++chgBnds;
2777 }
2778 else
2779 ++keptBnds;
2780 }
2781
2782 if(redundantUpper)
2783 {
2784 // no lower bound on x_j OR redundant lower bound
2785 if((lp.lower(j) <= R(-infinity)) || redundantLower || (!m_keepbounds))
2786 {
2787 ++rhsCnt;
2788 rhsBnd -= aij * lp.upper(j);
2789
2790 lp.changeUpper(j, R(infinity));
2791 ++chgBnds;
2792 }
2793 else
2794 ++keptBnds;
2795 }
2796 }
2797 else if(aij < 0.0)
2798 {
2799 if(lp.lhs(i) > R(-infinity) && lp.upper(j) < R(infinity) && rhsCnt <= 1
2800 && NErel(lp.lhs(i), rhsBnd, feastol())
2801 // do not perform if strongly different orders of magnitude occur
2802 && spxAbs(lp.lhs(i) / maxAbs(rhsBnd, R(1.0))) > Param::epsilon())
2803 {
2804 R up = R(infinity);
2805 R scale = maxAbs(lp.lhs(i), rhsBnd);
2806
2807 if(scale < 1.0)
2808 scale = 1.0;
2809
2810 R z = (lp.lhs(i) / scale) - (rhsBnd / scale);
2811
2812 if(isZero(z, this->epsZero()))
2813 z = 0.0;
2814
2815 assert(rhsCnt > 0 || lp.lower(j) > R(-infinity));
2816
2817 if(rhsCnt == 0)
2818 up = lp.lower(j) + z * scale / aij;
2819 else if(lp.lower(j) <= R(-infinity))
2820 up = z * scale / aij;
2821
2822 if(isZero(up, this->epsZero()))
2823 up = 0.0;
2824
2825 if(LErel(up, lp.upper(j), feastol()))
2826 {
2827 MSG_DEBUG((*this->spxout) << "IMAISM15 row " << i
2828 << ": redundant upper bound on x" << j
2829 << " -> upper=" << up
2830 << " (" << lp.upper(j)
2831 << ")" << std::endl;)
2832
2833 redundantUpper = true;
2834 }
2835 }
2836
2837 if(lp.rhs(i) < R(infinity) && lp.lower(j) > R(-infinity) && lhsCnt <= 1
2838 && NErel(lp.rhs(i), lhsBnd, feastol())
2839 // do not perform if strongly different orders of magnitude occur
2840 && spxAbs(lp.rhs(i) / maxAbs(lhsBnd, R(1.0))) > Param::epsilon())
2841 {
2842 R lo = R(-infinity);
2843 R scale = maxAbs(lp.rhs(i), lhsBnd);
2844
2845 if(scale < 1.0)
2846 scale = 1.0;
2847
2848 R z = (lp.rhs(i) / scale) - (lhsBnd / scale);
2849
2850 if(isZero(z, this->epsZero()))
2851 z = 0.0;
2852
2853 assert(lhsCnt > 0 || lp.upper(j) < R(infinity));
2854
2855 if(lhsCnt == 0)
2856 lo = lp.upper(j) + z * scale / aij;
2857 else if(lp.upper(j) >= R(infinity))
2858 lo = z * scale / aij;
2859
2860 if(isZero(lo, this->epsZero()))
2861 lo = 0.0;
2862
2863 if(GErel(lo, lp.lower(j)))
2864 {
2865 MSG_DEBUG((*this->spxout) << "IMAISM16 row " << i
2866 << ": redundant lower bound on x" << j
2867 << " -> lower=" << lo
2868 << " (" << lp.lower(j)
2869 << ")" << std::endl;)
2870
2871 redundantLower = true;
2872 }
2873 }
2874
2875 if(redundantUpper)
2876 {
2877 // no lower bound on x_j OR redundant lower bound
2878 if((lp.lower(j) <= R(-infinity)) || redundantLower || (!m_keepbounds))
2879 {
2880 ++lhsCnt;
2881 lhsBnd -= aij * lp.upper(j);
2882
2883 lp.changeUpper(j, R(infinity));
2884 ++chgBnds;
2885 }
2886 else
2887 ++keptBnds;
2888 }
2889
2890 if(redundantLower)
2891 {
2892 // no upper bound on x_j OR redundant upper bound
2893 if((lp.upper(j) >= R(infinity)) || redundantUpper || (!m_keepbounds))
2894 {
2895 ++rhsCnt;
2896 rhsBnd -= aij * lp.lower(j);
2897
2898 lp.changeLower(j, R(-infinity));
2899 ++chgBnds;
2900 }
2901 else
2902 ++keptBnds;
2903 }
2904 }
2905 }
2906 }
2907
2908 #endif
2909
2910 #if FREE_LHS_RHS
2911
2912 redundantLhs = false;
2913 redundantRhs = false;
2914
2915 // 2. detect implied free constraints
2916 if(lp.lhs(i) > R(-infinity) && lhsCnt == 0 && GErel(lhsBnd, lp.lhs(i), feastol()))
2917 {
2918 MSG_DEBUG((*this->spxout) << "IMAISM17 row " << i
2919 << ": redundant lhs -> lhsBnd=" << lhsBnd
2920 << " lhs=" << lp.lhs(i)
2921 << std::endl;)
2922
2923 redundantLhs = true;
2924 }
2925
2926 if(lp.rhs(i) < R(infinity) && rhsCnt == 0 && LErel(rhsBnd, lp.rhs(i), feastol()))
2927 {
2928 MSG_DEBUG((*this->spxout) << "IMAISM18 row " << i
2929 << ": redundant rhs -> rhsBnd=" << rhsBnd
2930 << " rhs=" << lp.rhs(i)
2931 << std::endl;)
2932
2933 redundantRhs = true;
2934 }
2935
2936 if(redundantLhs)
2937 {
2938 // no rhs for constraint i OR redundant rhs
2939 if((lp.rhs(i) >= R(infinity)) || redundantRhs || (!m_keepbounds))
2940 {
2941 lp.changeLhs(i, R(-infinity));
2942 ++chgLRhs;
2943 }
2944 else
2945 ++keptLRhs;
2946 }
2947
2948 if(redundantRhs)
2949 {
2950 // no lhs for constraint i OR redundant lhs
2951 if((lp.lhs(i) <= R(-infinity)) || redundantLhs || (!m_keepbounds))
2952 {
2953 lp.changeRhs(i, R(infinity));
2954 ++chgLRhs;
2955 }
2956 else
2957 ++keptLRhs;
2958 }
2959
2960 #endif
2961
2962 // 3. infeasible constraint
2963 if(LTrel(lp.rhs(i), lp.lhs(i), feastol()) ||
2964 (LTrel(rhsBnd, lp.lhs(i), feastol()) && rhsCnt == 0) ||
2965 (GTrel(lhsBnd, lp.rhs(i), feastol()) && lhsCnt == 0))
2966 {
2967 MSG_DEBUG((*this->spxout) << "IMAISM19 row " << std::setprecision(20) << i
2968 << ": infeasible -> lhs=" << lp.lhs(i)
2969 << " rhs=" << lp.rhs(i)
2970 << " lhsBnd=" << lhsBnd
2971 << " rhsBnd=" << rhsBnd
2972 << std::endl;)
2973 return this->INFEASIBLE;
2974 }
2975
2976 #if FREE_CONSTRAINT
2977
2978 // 4. unconstrained constraint
2979 if(lp.lhs(i) <= R(-infinity) && lp.rhs(i) >= R(infinity))
2980 {
2981 MSG_DEBUG((*this->spxout) << "IMAISM20 row " << i
2982 << ": unconstrained -> removed" << std::endl;)
2983
2984 std::shared_ptr<PostStep> ptr(new FreeConstraintPS(lp, i));
2985 m_hist.append(ptr);
2986
2987 ++remRows;
2988 remNzos += row.size();
2989 removeRow(lp, i);
2990
2991 ++m_stat[FREE_ROW];
2992
2993 continue;
2994 }
2995
2996 #endif
2997
2998 #if EMPTY_CONSTRAINT
2999
3000 // 5. empty constraint
3001 if(row.size() == 0)
3002 {
3003 MSG_DEBUG((*this->spxout) << "IMAISM21 row " << i
3004 << ": empty ->";)
3005
3006 if(LT(lp.rhs(i), R(0.0), feastol()) || GT(lp.lhs(i), R(0.0), feastol()))
3007 {
3008 MSG_DEBUG((*this->spxout) << " infeasible lhs=" << lp.lhs(i)
3009 << " rhs=" << lp.rhs(i) << std::endl;)
3010 return this->INFEASIBLE;
3011 }
3012
3013 MSG_DEBUG((*this->spxout) << " removed" << std::endl;)
3014
3015 std::shared_ptr<PostStep> ptr(new EmptyConstraintPS(lp, i));
3016 m_hist.append(ptr);
3017
3018 ++remRows;
3019 removeRow(lp, i);
3020
3021 ++m_stat[EMPTY_ROW];
3022
3023 continue;
3024 }
3025
3026 #endif
3027
3028 #if ROW_SINGLETON
3029
3030 // 6. row singleton
3031 if(row.size() == 1)
3032 {
3033 removeRowSingleton(lp, row, i);
3034 continue;
3035 }
3036
3037 #endif
3038
3039 #if AGGREGATE_VARS
3040
3041 // 7. row doubleton, aka. simple aggregation of two variables in an equation
3042 if(row.size() == 2 && EQrel(lp.lhs(i), lp.rhs(i), feastol()))
3043 {
3044 aggregateVars(lp, row, i);
3045 continue;
3046 }
3047
3048 #endif
3049
3050 #if FORCE_CONSTRAINT
3051
3052 // 8. forcing constraint (postsolving)
3053 // fix variables to obtain the upper bound on constraint value
3054 if(rhsCnt == 0 && EQrel(rhsBnd, lp.lhs(i), feastol()))
3055 {
3056 MSG_DEBUG((*this->spxout) << "IMAISM24 row " << i
3057 << ": forcing constraint fix on lhs ->"
3058 << " lhs=" << lp.lhs(i)
3059 << " rhsBnd=" << rhsBnd
3060 << std::endl;)
3061
3062 DataArray<bool> fixedCol(row.size());
3063 Array<R> lowers(row.size());
3064 Array<R> uppers(row.size());
3065
3066 for(int k = 0; k < row.size(); ++k)
3067 {
3068 R aij = row.value(k);
3069 int j = row.index(k);
3070
3071 fixedCol[k] = !(EQrel(lp.upper(j), lp.lower(j), m_epsilon));
3072
3073 lowers[k] = lp.lower(j);
3074 uppers[k] = lp.upper(j);
3075
3076 ASSERT_WARN("WMAISM25", isNotZero(aij, R(1.0 / R(infinity))));
3077
3078 if(aij > 0.0)
3079 lp.changeLower(j, lp.upper(j));
3080 else
3081 lp.changeUpper(j, lp.lower(j));
3082 }
3083
3084 std::shared_ptr<PostStep> ptr(new ForceConstraintPS(lp, i, true, fixedCol, lowers, uppers));
3085 m_hist.append(ptr);
3086
3087 ++remRows;
3088 remNzos += row.size();
3089 removeRow(lp, i);
3090
3091 ++m_stat[FORCE_ROW];
3092
3093 continue;
3094 }
3095
3096 // fix variables to obtain the lower bound on constraint value
3097 if(lhsCnt == 0 && EQrel(lhsBnd, lp.rhs(i), feastol()))
3098 {
3099 MSG_DEBUG((*this->spxout) << "IMAISM26 row " << i
3100 << ": forcing constraint fix on rhs ->"
3101 << " rhs=" << lp.rhs(i)
3102 << " lhsBnd=" << lhsBnd
3103 << std::endl;)
3104
3105 DataArray<bool> fixedCol(row.size());
3106 Array<R> lowers(row.size());
3107 Array<R> uppers(row.size());
3108
3109 for(int k = 0; k < row.size(); ++k)
3110 {
3111 R aij = row.value(k);
3112 int j = row.index(k);
3113
3114 fixedCol[k] = !(EQrel(lp.upper(j), lp.lower(j), m_epsilon));
3115
3116 lowers[k] = lp.lower(j);
3117 uppers[k] = lp.upper(j);
3118
3119 ASSERT_WARN("WMAISM27", isNotZero(aij, R(1.0 / R(infinity))));
3120
3121 if(aij > 0.0)
3122 lp.changeUpper(j, lp.lower(j));
3123 else
3124 lp.changeLower(j, lp.upper(j));
3125 }
3126
3127 std::shared_ptr<PostStep> ptr(new ForceConstraintPS(lp, i, false, fixedCol, lowers, uppers));
3128 m_hist.append(ptr);
3129
3130 ++remRows;
3131 remNzos += row.size();
3132 removeRow(lp, i);
3133
3134 ++m_stat[FORCE_ROW];
3135
3136 continue;
3137 }
3138
3139 #endif
3140 }
3141
3142 assert(remRows > 0 || remNzos == 0);
3143
3144 if(remRows + chgLRhs + chgBnds > 0)
3145 {
3146 this->m_remRows += remRows;
3147 this->m_remNzos += remNzos;
3148 this->m_chgLRhs += chgLRhs;
3149 this->m_chgBnds += chgBnds;
3150 this->m_keptBnds += keptBnds;
3151 this->m_keptLRhs += keptLRhs;
3152
3153 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier (rows) removed "
3154 << remRows << " rows, "
3155 << remNzos << " non-zeros, "
3156 << chgBnds << " col bounds, "
3157 << chgLRhs << " row bounds; kept "
3158 << keptBnds << " column bounds, "
3159 << keptLRhs << " row bounds"
3160 << std::endl;)
3161
3162 if(remRows > this->m_minReduction * oldRows)
3163 again = true;
3164 }
3165
3166 return this->OKAY;
3167 }
3168
3169 template <class R>
3170 typename SPxSimplifier<R>::Result SPxMainSM<R>::simplifyCols(SPxLPBase<R>& lp, bool& again)
3171 {
3172
3173 // This method simplifies the columns of the LP.
3174 //
3175 // The following operations are done:
3176 // 1. detect empty columns and fix corresponding variables
3177 // 2. detect variables that are unconstrained from below or above
3178 // and fix corresponding variables or remove involved constraints
3179 // 3. fix variables
3180 // 4. use column singleton variables with zero objective to adjust constraint bounds
3181 // 5. (not free) column singleton combined with doubleton equation are
3182 // used to make the column singleton variable free
3183 // 6. substitute (implied) free column singletons
3184
3185 int remRows = 0;
3186 int remCols = 0;
3187 int remNzos = 0;
3188 int chgBnds = 0;
3189
3190 int oldCols = lp.nCols();
3191 int oldRows = lp.nRows();
3192
3193 for(int j = lp.nCols() - 1; j >= 0; --j)
3194 {
3195 const SVectorBase<R>& col = lp.colVector(j);
3196
3197 // infeasible bounds
3198 if(GTrel(lp.lower(j), lp.upper(j), feastol()))
3199 {
3200 MSG_DEBUG((*this->spxout) << "IMAISM29 col " << j
3201 << ": infeasible bounds on x" << j
3202 << " -> lower=" << lp.lower(j)
3203 << " upper=" << lp.upper(j)
3204 << std::endl;)
3205 return this->INFEASIBLE;
3206 }
3207
3208 // 1. empty column
3209 if(col.size() == 0)
3210 {
3211 #if EMPTY_COLUMN
3212 MSG_DEBUG((*this->spxout) << "IMAISM30 col " << j
3213 << ": empty -> maxObj=" << lp.maxObj(j)
3214 << " lower=" << lp.lower(j)
3215 << " upper=" << lp.upper(j);)
3216
3217 R val;
3218
3219 if(GT(lp.maxObj(j), R(0.0), this->epsZero()))
3220 {
3221 if(lp.upper(j) >= R(infinity))
3222 {
3223 MSG_DEBUG((*this->spxout) << " unbounded" << std::endl;)
3224 return this->UNBOUNDED;
3225 }
3226
3227 val = lp.upper(j);
3228 }
3229 else if(LT(lp.maxObj(j), R(0.0), this->epsZero()))
3230 {
3231 if(lp.lower(j) <= R(-infinity))
3232 {
3233 MSG_DEBUG((*this->spxout) << " unbounded" << std::endl;)
3234 return this->UNBOUNDED;
3235 }
3236
3237 val = lp.lower(j);
3238 }
3239 else
3240 {
3241 assert(isZero(lp.maxObj(j), this->epsZero()));
3242
3243 // any value within the bounds is ok
3244 if(lp.lower(j) > R(-infinity))
3245 val = lp.lower(j);
3246 else if(lp.upper(j) < R(infinity))
3247 val = lp.upper(j);
3248 else
3249 val = 0.0;
3250 }
3251
3252 MSG_DEBUG((*this->spxout) << " removed" << std::endl;)
3253
3254 std::shared_ptr<PostStep> ptr1(new FixBoundsPS(lp, j, val));
3255 std::shared_ptr<PostStep> ptr2(new FixVariablePS(lp, *this, j, val));
3256 m_hist.append(ptr1);
3257 m_hist.append(ptr2);
3258
3259 ++remCols;
3260 removeCol(lp, j);
3261
3262 ++m_stat[EMPTY_COL];
3263
3264 continue;
3265 #endif
3266 }
3267
3268 if(NErel(lp.lower(j), lp.upper(j), feastol()))
3269 {
3270 // will be set to false if any constraint implies a bound on the variable
3271 bool loFree = true;
3272 bool upFree = true;
3273
3274 // 1. fix and remove variables
3275 for(int k = 0; k < col.size(); ++k)
3276 {
3277 if(!loFree && !upFree)
3278 break;
3279
3280 int i = col.index(k);
3281
3282 // warn since this unhandled case may slip through unnoticed otherwise
3283 ASSERT_WARN("WMAISM31", isNotZero(col.value(k), R(1.0 / R(infinity))));
3284
3285 if(col.value(k) > 0.0)
3286 {
3287 if(lp.rhs(i) < R(infinity))
3288 upFree = false;
3289
3290 if(lp.lhs(i) > R(-infinity))
3291 loFree = false;
3292 }
3293 else if(col.value(k) < 0.0)
3294 {
3295 if(lp.rhs(i) < R(infinity))
3296 loFree = false;
3297
3298 if(lp.lhs(i) > R(-infinity))
3299 upFree = false;
3300 }
3301 }
3302
3303 // 2. detect variables that are unconstrained from below or above
3304 // max 3 x
3305 // s.t. 5 x >= 8
3306 if(GT(lp.maxObj(j), R(0.0), this->epsZero()) && upFree)
3307 {
3308 #if FIX_VARIABLE
3309 MSG_DEBUG((*this->spxout) << "IMAISM32 col " << j
3310 << ": x" << j
3311 << " unconstrained above ->";)
3312
3313 if(lp.upper(j) >= R(infinity))
3314 {
3315 MSG_DEBUG((*this->spxout) << " unbounded" << std::endl;)
3316
3317 return this->UNBOUNDED;
3318 }
3319
3320 MSG_DEBUG((*this->spxout) << " fixed at upper=" << lp.upper(j) << std::endl;)
3321
3322 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j, lp.upper(j)));
3323 m_hist.append(ptr);
3324 lp.changeLower(j, lp.upper(j));
3325 }
3326 // max -3 x
3327 // s.t. 5 x <= 8
3328 else if(LT(lp.maxObj(j), R(0.0), this->epsZero()) && loFree)
3329 {
3330 MSG_DEBUG((*this->spxout) << "IMAISM33 col " << j
3331 << ": x" << j
3332 << " unconstrained below ->";)
3333
3334 if(lp.lower(j) <= R(-infinity))
3335 {
3336 MSG_DEBUG((*this->spxout) << " unbounded" << std::endl;)
3337
3338 return this->UNBOUNDED;
3339 }
3340
3341 MSG_DEBUG((*this->spxout) << " fixed at lower=" << lp.lower(j) << std::endl;)
3342
3343 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j, lp.lower(j)));
3344 m_hist.append(ptr);
3345 lp.changeUpper(j, lp.lower(j));
3346 #endif
3347 }
3348 else if(isZero(lp.maxObj(j), this->epsZero()))
3349 {
3350 #if FREE_ZERO_OBJ_VARIABLE
3351 bool unconstrained_below = loFree && lp.lower(j) <= R(-infinity);
3352 bool unconstrained_above = upFree && lp.upper(j) >= R(infinity);
3353
3354 if(unconstrained_below || unconstrained_above)
3355 {
3356 MSG_DEBUG((*this->spxout) << "IMAISM34 col " << j
3357 << ": x" << j
3358 << " unconstrained "
3359 << (unconstrained_below ? "below" : "above")
3360 << " with zero objective (" << lp.maxObj(j)
3361 << ")" << std::endl;)
3362
3363 DSVectorBase<R> col_idx_sorted(col);
3364
3365 // sort col elements by increasing idx
3366 IdxCompare compare;
3367 SPxQuicksort(col_idx_sorted.mem(), col_idx_sorted.size(), compare);
3368
3369 std::shared_ptr<PostStep> ptr(new FreeZeroObjVariablePS(lp, j, unconstrained_below,
3370 col_idx_sorted));
3371 m_hist.append(ptr);
3372
3373 // we have to remove the rows with larger idx first, because otherwise the rows are reorder and indices
3374 // are out-of-date
3375 remRows += col.size();
3376
3377 for(int k = col_idx_sorted.size() - 1; k >= 0; --k)
3378 removeRow(lp, col_idx_sorted.index(k));
3379
3380 // remove column
3381 removeCol(lp, j);
3382
3383 // statistics
3384 for(int k = 0; k < col.size(); ++k)
3385 {
3386 int l = col.index(k);
3387 remNzos += lp.rowVector(l).size();
3388 }
3389
3390 ++m_stat[FREE_ZOBJ_COL];
3391 ++remCols;
3392
3393 continue;
3394 }
3395
3396 #endif
3397 }
3398 }
3399
3400 #if FIX_VARIABLE
3401
3402 // 3. fix variable
3403 if(EQrel(lp.lower(j), lp.upper(j), feastol()))
3404 {
3405 MSG_DEBUG((*this->spxout) << "IMAISM36 col " << j
3406 << ": x" << j
3407 << " fixed -> lower=" << lp.lower(j)
3408 << " upper=" << lp.upper(j) << std::endl;)
3409
3410 fixColumn(lp, j);
3411
3412 ++remCols;
3413 remNzos += col.size();
3414 removeCol(lp, j);
3415
3416 ++m_stat[FIX_COL];
3417
3418 continue;
3419 }
3420
3421 #endif
3422
3423 // handle column singletons
3424 if(col.size() == 1)
3425 {
3426 R aij = col.value(0);
3427 int i = col.index(0);
3428
3429 // 4. column singleton with zero objective
3430 if(isZero(lp.maxObj(j), this->epsZero()))
3431 {
3432 #if ZERO_OBJ_COL_SINGLETON
3433 MSG_DEBUG((*this->spxout) << "IMAISM37 col " << j
3434 << ": singleton in row " << i
3435 << " with zero objective";)
3436
3437 R lhs = R(-infinity);
3438 R rhs = +R(infinity);
3439
3440 if(GT(aij, R(0.0), this->epsZero()))
3441 {
3442 if(lp.lhs(i) > R(-infinity) && lp.upper(j) < R(infinity))
3443 lhs = lp.lhs(i) - aij * lp.upper(j);
3444
3445 if(lp.rhs(i) < R(infinity) && lp.lower(j) > R(-infinity))
3446 rhs = lp.rhs(i) - aij * lp.lower(j);
3447 }
3448 else if(LT(aij, R(0.0), this->epsZero()))
3449 {
3450 if(lp.lhs(i) > R(-infinity) && lp.lower(j) > R(-infinity))
3451 lhs = lp.lhs(i) - aij * lp.lower(j);
3452
3453 if(lp.rhs(i) < R(infinity) && lp.upper(j) < R(infinity))
3454 rhs = lp.rhs(i) - aij * lp.upper(j);
3455 }
3456 else
3457 {
3458 lhs = lp.lhs(i);
3459 rhs = lp.rhs(i);
3460 }
3461
3462 if(isZero(lhs, this->epsZero()))
3463 lhs = 0.0;
3464
3465 if(isZero(rhs, this->epsZero()))
3466 rhs = 0.0;
3467
3468 MSG_DEBUG((*this->spxout) << " removed -> lhs=" << lhs
3469 << " (" << lp.lhs(i)
3470 << ") rhs=" << rhs
3471 << " (" << lp.rhs(i)
3472 << ")" << std::endl;)
3473
3474 std::shared_ptr<PostStep> ptr(new ZeroObjColSingletonPS(lp, *this, j, i));
3475 m_hist.append(ptr);
3476
3477 lp.changeRange(i, lhs, rhs);
3478
3479 ++remCols;
3480 ++remNzos;
3481 removeCol(lp, j);
3482
3483 ++m_stat[ZOBJ_SINGLETON_COL];
3484
3485 if(lp.lhs(i) <= R(-infinity) && lp.rhs(i) >= R(infinity))
3486 {
3487 std::shared_ptr<PostStep> ptr2(new FreeConstraintPS(lp, i));
3488 m_hist.append(ptr2);
3489
3490 ++remRows;
3491 removeRow(lp, i);
3492
3493 ++m_stat[FREE_ROW];
3494 }
3495
3496 continue;
3497 #endif
3498 }
3499
3500 // 5. not free column singleton combined with doubleton equation
3501 else if(EQrel(lp.lhs(i), lp.rhs(i), feastol()) &&
3502 lp.rowVector(i).size() == 2 &&
3503 (lp.lower(j) > R(-infinity) || lp.upper(j) < R(infinity)))
3504 {
3505 #if DOUBLETON_EQUATION
3506 MSG_DEBUG((*this->spxout) << "IMAISM38 col " << j
3507 << ": singleton in row " << i
3508 << " with doubleton equation ->";)
3509
3510 R lhs = lp.lhs(i);
3511
3512 const SVectorBase<R>& row = lp.rowVector(i);
3513
3514 R aik;
3515 int k;
3516
3517 if(row.index(0) == j)
3518 {
3519 aik = row.value(1);
3520 k = row.index(1);
3521 }
3522 else if(row.index(1) == j)
3523 {
3524 aik = row.value(0);
3525 k = row.index(0);
3526 }
3527 else
3528 throw SPxInternalCodeException("XMAISM11 This should never happen.");
3529
3530 ASSERT_WARN("WMAISM39", isNotZero(aik, R(1.0 / R(infinity))));
3531
3532 R lo, up;
3533 R oldLower = lp.lower(k);
3534 R oldUpper = lp.upper(k);
3535
3536 R scale1 = maxAbs(lhs, aij * lp.upper(j));
3537 R scale2 = maxAbs(lhs, aij * lp.lower(j));
3538
3539 if(scale1 < 1.0)
3540 scale1 = 1.0;
3541
3542 if(scale2 < 1.0)
3543 scale2 = 1.0;
3544
3545 R z1 = (lhs / scale1) - (aij * lp.upper(j) / scale1);
3546 R z2 = (lhs / scale2) - (aij * lp.lower(j) / scale2);
3547
3548 if(isZero(z1, this->epsZero()))
3549 z1 = 0.0;
3550
3551 if(isZero(z2, this->epsZero()))
3552 z2 = 0.0;
3553
3554 if(aij * aik > 0.0)
3555 {
3556 lo = (lp.upper(j) >= R(infinity)) ? R(-infinity) : z1 * scale1 / aik;
3557 up = (lp.lower(j) <= R(-infinity)) ? R(infinity) : z2 * scale2 / aik;
3558 }
3559 else if(aij * aik < 0.0)
3560 {
3561 lo = (lp.lower(j) <= R(-infinity)) ? R(-infinity) : z2 * scale2 / aik;
3562 up = (lp.upper(j) >= R(infinity)) ? R(infinity) : z1 * scale1 / aik;
3563 }
3564 else
3565 throw SPxInternalCodeException("XMAISM12 This should never happen.");
3566
3567 if(GTrel(lo, lp.lower(k), this->epsZero()))
3568 lp.changeLower(k, lo);
3569
3570 if(LTrel(up, lp.upper(k), this->epsZero()))
3571 lp.changeUpper(k, up);
3572
3573 MSG_DEBUG((*this->spxout) << " made free, bounds on x" << k
3574 << ": lower=" << lp.lower(k)
3575 << " (" << oldLower
3576 << ") upper=" << lp.upper(k)
3577 << " (" << oldUpper
3578 << ")" << std::endl;)
3579
3580 // infeasible bounds
3581 if(GTrel(lp.lower(k), lp.upper(k), feastol()))
3582 {
3583 MSG_DEBUG((*this->spxout) << "new bounds are infeasible"
3584 << std::endl;)
3585 return this->INFEASIBLE;
3586 }
3587
3588 std::shared_ptr<PostStep> ptr(new DoubletonEquationPS(lp, j, k, i, oldLower, oldUpper));
3589 m_hist.append(ptr);
3590
3591 if(lp.lower(j) > R(-infinity) && lp.upper(j) < R(infinity))
3592 chgBnds += 2;
3593 else
3594 ++chgBnds;
3595
3596 lp.changeBounds(j, R(-infinity), R(infinity));
3597
3598 ++m_stat[DOUBLETON_ROW];
3599 #endif
3600 }
3601
3602 // 6. (implied) free column singleton
3603 if(lp.lower(j) <= R(-infinity) && lp.upper(j) >= R(infinity))
3604 {
3605 #if FREE_COL_SINGLETON
3606 R slackVal = lp.lhs(i);
3607
3608 // constraint i is an inequality constraint -> transform into equation type
3609 if(NErel(lp.lhs(i), lp.rhs(i), feastol()))
3610 {
3611 MSG_DEBUG((*this->spxout) << "IMAISM40 col " << j
3612 << ": free singleton in inequality constraint" << std::endl;)
3613
3614 // do nothing if constraint i is unconstrained
3615 if(lp.lhs(i) <= R(-infinity) && lp.rhs(i) >= R(infinity))
3616 continue;
3617
3618 // introduce slack variable to obtain equality constraint
3619 R sMaxObj = lp.maxObj(j) / aij; // after substituting variable j in objective
3620 R sLo = lp.lhs(i);
3621 R sUp = lp.rhs(i);
3622
3623 if(GT(sMaxObj, R(0.0), this->epsZero()))
3624 {
3625 if(sUp >= R(infinity))
3626 {
3627 MSG_DEBUG((*this->spxout) << " -> problem unbounded" << std::endl;)
3628 return this->UNBOUNDED;
3629 }
3630
3631 slackVal = sUp;
3632 }
3633 else if(LT(sMaxObj, R(0.0), this->epsZero()))
3634 {
3635 if(sLo <= R(-infinity))
3636 {
3637 MSG_DEBUG((*this->spxout) << " -> problem unbounded" << std::endl;)
3638 return this->UNBOUNDED;
3639 }
3640
3641 slackVal = sLo;
3642 }
3643 else
3644 {
3645 assert(isZero(sMaxObj, this->epsZero()));
3646
3647 // any value within the bounds is ok
3648 if(sLo > R(-infinity))
3649 slackVal = sLo;
3650 else if(sUp < R(infinity))
3651 slackVal = sUp;
3652 else
3653 throw SPxInternalCodeException("XMAISM13 This should never happen.");
3654 }
3655 }
3656
3657 std::shared_ptr<PostStep> ptr(new FreeColSingletonPS(lp, *this, j, i, slackVal));
3658 m_hist.append(ptr);
3659
3660 MSG_DEBUG((*this->spxout) << "IMAISM41 col " << j
3661 << ": free singleton removed" << std::endl;)
3662
3663 const SVectorBase<R>& row = lp.rowVector(i);
3664
3665 for(int h = 0; h < row.size(); ++h)
3666 {
3667 int k = row.index(h);
3668
3669 if(k != j)
3670 {
3671 R new_obj = lp.obj(k) - (lp.obj(j) * row.value(h) / aij);
3672 lp.changeObj(k, new_obj);
3673 }
3674 }
3675
3676 ++remRows;
3677 ++remCols;
3678 remNzos += row.size();
3679 removeRow(lp, i);
3680 removeCol(lp, j);
3681
3682 ++m_stat[FREE_SINGLETON_COL];
3683
3684 continue;
3685 #endif
3686 }
3687 }
3688 }
3689
3690 if(remCols + remRows > 0)
3691 {
3692 this->m_remRows += remRows;
3693 this->m_remCols += remCols;
3694 this->m_remNzos += remNzos;
3695 this->m_chgBnds += chgBnds;
3696
3697 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier (columns) removed "
3698 << remRows << " rows, "
3699 << remCols << " cols, "
3700 << remNzos << " non-zeros, "
3701 << chgBnds << " col bounds"
3702 << std::endl;)
3703
3704 if(remCols + remRows > this->m_minReduction * (oldCols + oldRows))
3705 again = true;
3706 }
3707
3708 return this->OKAY;
3709 }
3710
3711 template <class R>
3712 typename SPxSimplifier<R>::Result SPxMainSM<R>::simplifyDual(SPxLPBase<R>& lp, bool& again)
3713 {
3714
3715 // This method simplifies LP using the following dual structures:
3716 //
3717 // 1. dominated columns
3718 // 2. weakly dominated columns
3719 //
3720 // For constructing the dual variables, it is assumed that the objective sense is max
3721
3722 int remRows = 0;
3723 int remCols = 0;
3724 int remNzos = 0;
3725
3726 int oldRows = lp.nRows();
3727 int oldCols = lp.nCols();
3728
3729 DataArray<bool> colSingleton(lp.nCols());
3730 VectorBase<R> dualVarLo(lp.nRows());
3731 VectorBase<R> dualVarUp(lp.nRows());
3732 VectorBase<R> dualConsLo(lp.nCols());
3733 VectorBase<R> dualConsUp(lp.nCols());
3734
3735 // init
3736 for(int i = lp.nRows() - 1; i >= 0; --i)
3737 {
3738 // check for unconstrained constraints
3739 if(lp.lhs(i) <= R(-infinity) && lp.rhs(i) >= R(infinity))
3740 {
3741 MSG_DEBUG((*this->spxout) << "IMAISM43 row " << i
3742 << ": unconstrained" << std::endl;)
3743
3744 std::shared_ptr<PostStep> ptr(new FreeConstraintPS(lp, i));
3745 m_hist.append(ptr);
3746
3747 ++remRows;
3748 remNzos += lp.rowVector(i).size();
3749 removeRow(lp, i);
3750
3751 ++m_stat[FREE_ROW];
3752
3753 continue;
3754 }
3755
3756 // corresponds to maximization sense
3757 dualVarLo[i] = (lp.lhs(i) <= R(-infinity)) ? 0.0 : R(-infinity);
3758 dualVarUp[i] = (lp.rhs(i) >= R(infinity)) ? 0.0 : R(infinity);
3759 }
3760
3761 // compute bounds on the dual variables using column singletons
3762 for(int j = 0; j < lp.nCols(); ++j)
3763 {
3764 if(lp.colVector(j).size() == 1)
3765 {
3766 int i = lp.colVector(j).index(0);
3767 R aij = lp.colVector(j).value(0);
3768
3769 ASSERT_WARN("WMAISM44", isNotZero(aij, R(1.0 / R(infinity))));
3770
3771 R bound = lp.maxObj(j) / aij;
3772
3773 if(aij > 0)
3774 {
3775 if(lp.lower(j) <= R(-infinity) && bound < dualVarUp[i])
3776 dualVarUp[i] = bound;
3777
3778 if(lp.upper(j) >= R(infinity) && bound > dualVarLo[i])
3779 dualVarLo[i] = bound;
3780 }
3781 else if(aij < 0)
3782 {
3783 if(lp.lower(j) <= R(-infinity) && bound > dualVarLo[i])
3784 dualVarLo[i] = bound;
3785
3786 if(lp.upper(j) >= R(infinity) && bound < dualVarUp[i])
3787 dualVarUp[i] = bound;
3788 }
3789 }
3790
3791 }
3792
3793 // compute bounds on the dual constraints
3794 for(int j = 0; j < lp.nCols(); ++j)
3795 {
3796 dualConsLo[j] = dualConsUp[j] = 0.0;
3797
3798 const SVectorBase<R>& col = lp.colVector(j);
3799
3800 for(int k = 0; k < col.size(); ++k)
3801 {
3802 if(dualConsLo[j] <= R(-infinity) && dualConsUp[j] >= R(infinity))
3803 break;
3804
3805 R aij = col.value(k);
3806 int i = col.index(k);
3807
3808 ASSERT_WARN("WMAISM45", isNotZero(aij, R(1.0 / R(infinity))));
3809
3810 if(aij > 0)
3811 {
3812 if(dualVarLo[i] <= R(-infinity))
3813 dualConsLo[j] = R(-infinity);
3814 else
3815 dualConsLo[j] += aij * dualVarLo[i];
3816
3817 if(dualVarUp[i] >= R(infinity))
3818 dualConsUp[j] = R(infinity);
3819 else
3820 dualConsUp[j] += aij * dualVarUp[i];
3821 }
3822 else if(aij < 0)
3823 {
3824 if(dualVarLo[i] <= R(-infinity))
3825 dualConsUp[j] = R(infinity);
3826 else
3827 dualConsUp[j] += aij * dualVarLo[i];
3828
3829 if(dualVarUp[i] >= R(infinity))
3830 dualConsLo[j] = R(-infinity);
3831 else
3832 dualConsLo[j] += aij * dualVarUp[i];
3833 }
3834 }
3835 }
3836
3837 for(int j = lp.nCols() - 1; j >= 0; --j)
3838 {
3839 if(lp.colVector(j).size() <= 1)
3840 continue;
3841
3842 // dual infeasibility checks
3843 if(LTrel(dualConsUp[j], dualConsLo[j], opttol()))
3844 {
3845 MSG_DEBUG((*this->spxout) << "IMAISM46 col " << j
3846 << ": dual infeasible -> dual lhs bound=" << dualConsLo[j]
3847 << " dual rhs bound=" << dualConsUp[j] << std::endl;)
3848 return this->DUAL_INFEASIBLE;
3849 }
3850
3851 R obj = lp.maxObj(j);
3852
3853 // 1. dominated column
3854 // Is the problem really unbounded in the cases below ??? Or is only dual infeasibility be shown
3855 if(GTrel(obj, dualConsUp[j], opttol()))
3856 {
3857 #if DOMINATED_COLUMN
3858 MSG_DEBUG((*this->spxout) << "IMAISM47 col " << j
3859 << ": dominated -> maxObj=" << obj
3860 << " dual rhs bound=" << dualConsUp[j] << std::endl;)
3861
3862 if(lp.upper(j) >= R(infinity))
3863 {
3864 MSG_INFO2((*this->spxout), (*this->spxout) << " unbounded" << std::endl;)
3865 return this->UNBOUNDED;
3866 }
3867
3868 MSG_DEBUG((*this->spxout) << " fixed at upper=" << lp.upper(j) << std::endl;)
3869
3870 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j, lp.upper(j)));
3871 m_hist.append(ptr);
3872 lp.changeLower(j, lp.upper(j));
3873
3874 ++m_stat[DOMINATED_COL];
3875 #endif
3876 }
3877 else if(LTrel(obj, dualConsLo[j], opttol()))
3878 {
3879 #if DOMINATED_COLUMN
3880 MSG_DEBUG((*this->spxout) << "IMAISM48 col " << j
3881 << ": dominated -> maxObj=" << obj
3882 << " dual lhs bound=" << dualConsLo[j] << std::endl;)
3883
3884 if(lp.lower(j) <= R(-infinity))
3885 {
3886 MSG_INFO2((*this->spxout), (*this->spxout) << " unbounded" << std::endl;)
3887 return this->UNBOUNDED;
3888 }
3889
3890 MSG_DEBUG((*this->spxout) << " fixed at lower=" << lp.lower(j) << std::endl;)
3891
3892 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j, lp.lower(j)));
3893 m_hist.append(ptr);
3894 lp.changeUpper(j, lp.lower(j));
3895
3896 ++m_stat[DOMINATED_COL];
3897 #endif
3898 }
3899
3900 // 2. weakly dominated column (no postsolving)
3901 else if(lp.upper(j) < R(infinity) && EQrel(obj, dualConsUp[j], opttol()))
3902 {
3903 #if WEAKLY_DOMINATED_COLUMN
3904 MSG_DEBUG((*this->spxout) << "IMAISM49 col " << j
3905 << ": weakly dominated -> maxObj=" << obj
3906 << " dual rhs bound=" << dualConsUp[j] << std::endl;)
3907
3908 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j, lp.upper(j)));
3909 m_hist.append(ptr);
3910 lp.changeLower(j, lp.upper(j));
3911
3912 ++m_stat[WEAKLY_DOMINATED_COL];
3913 #endif
3914 }
3915 else if(lp.lower(j) > R(-infinity) && EQrel(obj, dualConsLo[j], opttol()))
3916 {
3917 #if WEAKLY_DOMINATED_COLUMN
3918 MSG_DEBUG((*this->spxout) << "IMAISM50 col " << j
3919 << ": weakly dominated -> maxObj=" << obj
3920 << " dual lhs bound=" << dualConsLo[j] << std::endl;)
3921
3922 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j, lp.lower(j)));
3923 m_hist.append(ptr);
3924 lp.changeUpper(j, lp.lower(j));
3925
3926 ++m_stat[WEAKLY_DOMINATED_COL];
3927 #endif
3928 }
3929
3930 // fix column
3931 if(EQrel(lp.lower(j), lp.upper(j), feastol()))
3932 {
3933 #if FIX_VARIABLE
3934 fixColumn(lp, j);
3935
3936 ++remCols;
3937 remNzos += lp.colVector(j).size();
3938 removeCol(lp, j);
3939
3940 ++m_stat[FIX_COL];
3941 #endif
3942 }
3943 }
3944
3945
3946 assert(remRows > 0 || remCols > 0 || remNzos == 0);
3947
3948 if(remCols + remRows > 0)
3949 {
3950 this->m_remRows += remRows;
3951 this->m_remCols += remCols;
3952 this->m_remNzos += remNzos;
3953
3954 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier (dual) removed "
3955 << remRows << " rows, "
3956 << remCols << " cols, "
3957 << remNzos << " non-zeros"
3958 << std::endl;)
3959
3960 if(remCols + remRows > this->m_minReduction * (oldCols + oldRows))
3961 again = true;
3962 }
3963
3964 return this->OKAY;
3965 }
3966
3967
3968
3969 template <class R>
3970 typename SPxSimplifier<R>::Result SPxMainSM<R>::multiaggregation(SPxLPBase<R>& lp, bool& again)
3971 {
3972 // this simplifier eliminates rows and columns by performing multi aggregations as identified by the constraint
3973 // activities.
3974 int remRows = 0;
3975 int remCols = 0;
3976 int remNzos = 0;
3977
3978 int oldRows = lp.nRows();
3979 int oldCols = lp.nCols();
3980
3981 VectorBase<R> upLocks(lp.nCols());
3982 VectorBase<R> downLocks(lp.nCols());
3983
3984 for(int j = lp.nCols() - 1; j >= 0; --j)
3985 {
3986 // setting the locks on the variables
3987 upLocks[j] = 0;
3988 downLocks[j] = 0;
3989
3990 if(lp.colVector(j).size() <= 1)
3991 continue;
3992
3993 const SVectorBase<R>& col = lp.colVector(j);
3994
3995 for(int k = 0; k < col.size(); ++k)
3996 {
3997 R aij = col.value(k);
3998
3999 ASSERT_WARN("WMAISM45", isNotZero(aij, R(1.0 / R(infinity))));
4000
4001 if(GT(lp.lhs(col.index(k)), R(-infinity)) && LT(lp.rhs(col.index(k)), R(infinity)))
4002 {
4003 upLocks[j]++;
4004 downLocks[j]++;
4005 }
4006 else if(GT(lp.lhs(col.index(k)), R(-infinity)))
4007 {
4008 if(aij > 0)
4009 downLocks[j]++;
4010 else if(aij < 0)
4011 upLocks[j]++;
4012 }
4013 else if(LT(lp.rhs(col.index(k)), R(infinity)))
4014 {
4015 if(aij > 0)
4016 upLocks[j]++;
4017 else if(aij < 0)
4018 downLocks[j]++;
4019 }
4020 }
4021
4022 // multi-aggregate column
4023 if(upLocks[j] == 1 || downLocks[j] == 1)
4024 {
4025 R lower = lp.lower(j);
4026 R upper = lp.upper(j);
4027 int maxOtherLocks;
4028 int bestpos = -1;
4029 bool bestislhs = true;
4030
4031 for(int k = 0; k < col.size(); ++k)
4032 {
4033 int rowNumber;
4034 R lhs;
4035 R rhs;
4036 bool lhsExists;
4037 bool rhsExists;
4038 bool aggLhs;
4039 bool aggRhs;
4040
4041 R val = col.value(k);
4042
4043 rowNumber = col.index(k);
4044 lhs = lp.lhs(rowNumber);
4045 rhs = lp.rhs(rowNumber);
4046
4047 if(EQ(lhs, rhs, feastol()))
4048 continue;
4049
4050 lhsExists = GT(lhs, R(-infinity));
4051 rhsExists = LT(rhs, R(infinity));
4052
4053 if(lp.rowVector(rowNumber).size() <= 2)
4054 maxOtherLocks = INT_MAX;
4055 else if(lp.rowVector(rowNumber).size() == 3)
4056 maxOtherLocks = 3;
4057 else if(lp.rowVector(rowNumber).size() == 4)
4058 maxOtherLocks = 2;
4059 else
4060 maxOtherLocks = 1;
4061
4062 aggLhs = lhsExists
4063 && ((col.value(k) > 0.0 && lp.maxObj(j) <= 0.0 && downLocks[j] == 1 && upLocks[j] <= maxOtherLocks)
4064 || (col.value(k) < 0.0 && lp.maxObj(j) >= 0.0 && upLocks[j] == 1 && downLocks[j] <= maxOtherLocks));
4065 aggRhs = rhsExists
4066 && ((col.value(k) > 0.0 && lp.maxObj(j) >= 0.0 && upLocks[j] == 1 && downLocks[j] <= maxOtherLocks)
4067 || (col.value(k) < 0.0 && lp.maxObj(j) <= 0.0 && downLocks[j] == 1 && upLocks[j] <= maxOtherLocks));
4068
4069 if(aggLhs || aggRhs)
4070 {
4071 R minRes = 0; // this is the minimum value that the aggregation can attain
4072 R maxRes = 0; // this is the maximum value that the aggregation can attain
4073
4074 // computing the minimum and maximum residuals if variable j is set to zero.
4075 computeMinMaxResidualActivity(lp, rowNumber, j, minRes, maxRes);
4076
4077 // we will try to aggregate to the lhs
4078 if(aggLhs)
4079 {
4080 R minVal;
4081 R maxVal;
4082
4083 // computing the values of the upper and lower bounds for the aggregated variables
4084 computeMinMaxValues(lp, lhs, val, minRes, maxRes, minVal, maxVal);
4085
4086 assert(LE(minVal, maxVal));
4087
4088 // if the bounds of the aggregation and the original variable are equivalent, then we can reduce
4089 if((minVal > R(-infinity) && GT(minVal, lower, feastol()))
4090 && (maxVal < R(infinity) && LT(maxVal, upper, feastol())))
4091 {
4092 bestpos = col.index(k);
4093 bestislhs = true;
4094 break;
4095 }
4096 }
4097
4098 // we will try to aggregate to the rhs
4099 if(aggRhs)
4100 {
4101 R minVal;
4102 R maxVal;
4103
4104 // computing the values of the upper and lower bounds for the aggregated variables
4105 computeMinMaxValues(lp, rhs, val, minRes, maxRes, minVal, maxVal);
4106
4107 assert(LE(minVal, maxVal));
4108
4109 if((minVal > R(-infinity) && GT(minVal, lower, feastol()))
4110 && (maxVal < R(infinity) && LT(maxVal, upper, feastol())))
4111 {
4112 bestpos = col.index(k);
4113 bestislhs = false;
4114 break;
4115 }
4116 }
4117 }
4118 }
4119
4120 // it is only possible to aggregate if a best position has been found
4121 if(bestpos >= 0)
4122 {
4123 const SVectorBase<R>& bestRow = lp.rowVector(bestpos);
4124 // aggregating the variable and applying the fixings to the all other constraints
4125 R aggConstant = (bestislhs ? lp.lhs(bestpos) : lp.rhs(
4126 bestpos)); // this is the lhs or rhs of the aggregated row
4127 R aggAij =
4128 bestRow[j]; // this is the coefficient of the deleted col
4129
4130 MSG_DEBUG(
4131 (*this->spxout) << "IMAISM51 col " << j
4132 << ": Aggregating row: " << bestpos
4133 << " Aggregation Constant=" << aggConstant
4134 << " Coefficient of aggregated col=" << aggAij << std::endl;
4135 )
4136
4137 std::shared_ptr<PostStep> ptr(new MultiAggregationPS(lp, *this, bestpos, j, aggConstant));
4138 m_hist.append(ptr);
4139
4140 for(int k = 0; k < col.size(); ++k)
4141 {
4142 if(col.index(k) != bestpos)
4143 {
4144 int rowNumber = col.index(k);
4145 VectorBase<R> updateRow(lp.nCols());
4146 R updateRhs = lp.rhs(col.index(k));
4147 R updateLhs = lp.lhs(col.index(k));
4148
4149 updateRow = lp.rowVector(col.index(k));
4150
4151 // updating the row with the best row
4152 for(int l = 0; l < bestRow.size(); l++)
4153 {
4154 if(bestRow.index(l) != j)
4155 {
4156 if(lp.rowVector(rowNumber).pos(bestRow.index(l)) >= 0)
4157 lp.changeElement(rowNumber, bestRow.index(l), updateRow[bestRow.index(l)]
4158 - updateRow[j]*bestRow.value(l) / aggAij);
4159 else
4160 lp.changeElement(rowNumber, bestRow.index(l), -1.0 * updateRow[j]*bestRow.value(l) / aggAij);
4161 }
4162 }
4163
4164 // NOTE: I don't know whether we should change the LHS and RHS if they are currently at R(infinity)
4165 if(LT(lp.rhs(rowNumber), R(infinity)))
4166 lp.changeRhs(rowNumber, updateRhs - updateRow[j]*aggConstant / aggAij);
4167
4168 if(GT(lp.lhs(rowNumber), R(-infinity)))
4169 lp.changeLhs(rowNumber, updateLhs - updateRow[j]*aggConstant / aggAij);
4170
4171 assert(LE(lp.lhs(rowNumber), lp.rhs(rowNumber)));
4172 }
4173 }
4174
4175 for(int l = 0; l < bestRow.size(); l++)
4176 {
4177 if(bestRow.index(l) != j)
4178 lp.changeMaxObj(bestRow.index(l),
4179 lp.maxObj(bestRow.index(l)) - lp.maxObj(j)*bestRow.value(l) / aggAij);
4180 }
4181
4182 ++remCols;
4183 remNzos += lp.colVector(j).size();
4184 removeCol(lp, j);
4185 ++remRows;
4186 remNzos += lp.rowVector(bestpos).size();
4187 removeRow(lp, bestpos);
4188
4189 ++m_stat[MULTI_AGG];
4190 }
4191 }
4192 }
4193
4194
4195 assert(remRows > 0 || remCols > 0 || remNzos == 0);
4196
4197 if(remCols + remRows > 0)
4198 {
4199 this->m_remRows += remRows;
4200 this->m_remCols += remCols;
4201 this->m_remNzos += remNzos;
4202
4203 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier (multi-aggregation) removed "
4204 << remRows << " rows, "
4205 << remCols << " cols, "
4206 << remNzos << " non-zeros"
4207 << std::endl;)
4208
4209 if(remCols + remRows > this->m_minReduction * (oldCols + oldRows))
4210 again = true;
4211 }
4212
4213 return this->OKAY;
4214 }
4215
4216
4217
4218 template <class R>
4219 typename SPxSimplifier<R>::Result SPxMainSM<R>::duplicateRows(SPxLPBase<R>& lp, bool& again)
4220 {
4221
4222 // This method simplifies the LP by removing duplicate rows
4223 // Duplicates are detected using the algorithm of Bixby and Wagner [1987]
4224
4225 // Possible extension: use generalized definition of duplicate rows according to Andersen and Andersen
4226 // However: the resulting sparsification is often very small since the involved rows are usually very sparse
4227
4228 int remRows = 0;
4229 int remNzos = 0;
4230
4231 int oldRows = lp.nRows();
4232
4233 // remove empty rows and columns
4234 typename SPxSimplifier<R>::Result ret = removeEmpty(lp);
4235
4236 if(ret != this->OKAY)
4237 return ret;
4238
4239 #if ROW_SINGLETON
4240 int rs_remRows = 0;
4241
4242 for(int i = 0; i < lp.nRows(); ++i)
4243 {
4244 const SVectorBase<R>& row = lp.rowVector(i);
4245
4246 if(row.size() == 1)
4247 {
4248 removeRowSingleton(lp, row, i);
4249 rs_remRows++;
4250 }
4251 }
4252
4253 if(rs_remRows > 0)
4254 {
4255 MSG_INFO2((*this->spxout), (*this->spxout) <<
4256 "Simplifier duplicate rows (row singleton stage) removed "
4257 << rs_remRows << " rows, "
4258 << rs_remRows << " non-zeros"
4259 << std::endl;)
4260 }
4261
4262 #endif
4263
4264 if(lp.nRows() < 2)
4265 return this->OKAY;
4266
4267 DataArray<int> pClass(lp.nRows()); // class of parallel rows
4268 DataArray<int> classSize(lp.nRows()); // size of each class
4269 Array<R> scale(lp.nRows()); // scaling factor for each row
4270 int* idxMem = 0;
4271
4272 try
4273 {
4274 spx_alloc(idxMem, lp.nRows());
4275 }
4276 catch(const SPxMemoryException& x)
4277 {
4278 spx_free(idxMem);
4279 throw x;
4280 }
4281
4282 IdxSet idxSet(lp.nRows(), idxMem); // set of feasible indices for new pClass
4283
4284 // init
4285 pClass[0] = 0;
4286 scale[0] = 0.0;
4287 classSize[0] = lp.nRows();
4288
4289 for(int i = 1; i < lp.nRows(); ++i)
4290 {
4291 pClass[i] = 0;
4292 scale[i] = 0.0;
4293 classSize[i] = 0;
4294 idxSet.addIdx(i);
4295 }
4296
4297 R oldVal = 0.0;
4298
4299 // main loop
4300 for(int j = 0; j < lp.nCols(); ++j)
4301 {
4302 const SVectorBase<R>& col = lp.colVector(j);
4303
4304 for(int k = 0; k < col.size(); ++k)
4305 {
4306 R aij = col.value(k);
4307 int i = col.index(k);
4308
4309 if(scale[i] == 0.0)
4310 scale[i] = aij;
4311
4312 m_classSetRows[pClass[i]].add(i, aij / scale[i]);
4313
4314 if(--classSize[pClass[i]] == 0)
4315 idxSet.addIdx(pClass[i]);
4316 }
4317
4318 // update each parallel class with non-zero column entry
4319 for(int m = 0; m < col.size(); ++m)
4320 {
4321 int k = pClass[col.index(m)];
4322
4323 if(m_classSetRows[k].size() > 0)
4324 {
4325 // sort classSet[k] w.r.t. scaled column values
4326 ElementCompare compare;
4327
4328 if(m_classSetRows[k].size() > 1)
4329 SPxQuicksort(m_classSetRows[k].mem(), m_classSetRows[k].size(), compare);
4330
4331 // use new index first
4332 int classIdx = idxSet.index(0);
4333 idxSet.remove(0);
4334
4335 for(int l = 0; l < m_classSetRows[k].size(); ++l)
4336 {
4337 if(l != 0 && NErel(m_classSetRows[k].value(l), oldVal, this->epsZero()))
4338 {
4339 classIdx = idxSet.index(0);
4340 idxSet.remove(0);
4341 }
4342
4343 pClass[m_classSetRows[k].index(l)] = classIdx;
4344 ++classSize[classIdx];
4345
4346 oldVal = m_classSetRows[k].value(l);
4347 }
4348
4349 m_classSetRows[k].clear();
4350 }
4351 }
4352 }
4353
4354 spx_free(idxMem);
4355
4356 DataArray<bool> remRow(lp.nRows());
4357
4358 for(int k = 0; k < lp.nRows(); ++k)
4359 m_dupRows[k].clear();
4360
4361 for(int k = 0; k < lp.nRows(); ++k)
4362 {
4363 remRow[k] = false;
4364 m_dupRows[pClass[k]].add(k, 0.0);
4365 }
4366
4367 const int nRowsOld_tmp = lp.nRows();
4368 int* perm_tmp = 0;
4369 spx_alloc(perm_tmp, nRowsOld_tmp);
4370
4371 for(int j = 0; j < nRowsOld_tmp; ++j)
4372 {
4373 perm_tmp[j] = 0;
4374 }
4375
4376 int idxFirstDupRows = -1;
4377 int idxLastDupRows = -1;
4378 int numDelRows = 0;
4379
4380 for(int k = 0; k < lp.nRows(); ++k)
4381 {
4382 if(m_dupRows[k].size() > 1 && !(lp.rowVector(m_dupRows[k].index(0)).size() == 1))
4383 {
4384 idxLastDupRows = k;
4385
4386 if(idxFirstDupRows < 0)
4387 {
4388 idxFirstDupRows = k;
4389 }
4390
4391 for(int l = 1; l < m_dupRows[k].size(); ++l)
4392 {
4393 int i = m_dupRows[k].index(l);
4394 perm_tmp[i] = -1;
4395 }
4396
4397 numDelRows += (m_dupRows[k].size() - 1);
4398 }
4399 }
4400
4401 {
4402 int k_tmp, j_tmp = -1;
4403
4404 for(k_tmp = j_tmp = 0; k_tmp < nRowsOld_tmp; ++k_tmp)
4405 {
4406 if(perm_tmp[k_tmp] >= 0)
4407 perm_tmp[k_tmp] = j_tmp++;
4408 }
4409 }
4410
4411 // store rhs and lhs changes for combined update
4412 bool doChangeRanges = false;
4413 VectorBase<R> newLhsVec(lp.lhs());
4414 VectorBase<R> newRhsVec(lp.rhs());
4415
4416 for(int k = 0; k < lp.nRows(); ++k)
4417 {
4418 if(m_dupRows[k].size() > 1 && !(lp.rowVector(m_dupRows[k].index(0)).size() == 1))
4419 {
4420 MSG_DEBUG((*this->spxout) << "IMAISM53 " << m_dupRows[k].size()
4421 << " duplicate rows found" << std::endl;)
4422
4423 m_stat[DUPLICATE_ROW] += m_dupRows[k].size() - 1;
4424
4425 // index of one non-column singleton row in dupRows[k]
4426 int rowIdx = -1;
4427 int maxLhsIdx = -1;
4428 int minRhsIdx = -1;
4429 R maxLhs = R(-infinity);
4430 R minRhs = +R(infinity);
4431
4432 DataArray<bool> isLhsEqualRhs(m_dupRows[k].size());
4433
4434 // determine strictest bounds on constraint
4435 for(int l = 0; l < m_dupRows[k].size(); ++l)
4436 {
4437 int i = m_dupRows[k].index(l);
4438 isLhsEqualRhs[l] = (lp.lhs(i) == lp.rhs(i));
4439
4440 ASSERT_WARN("WMAISM54", isNotZero(scale[i], R(1.0 / R(infinity))));
4441
4442 if(rowIdx == -1)
4443 {
4444 rowIdx = i;
4445 maxLhs = lp.lhs(rowIdx);
4446 minRhs = lp.rhs(rowIdx);
4447 }
4448 else
4449 {
4450 R scaledLhs, scaledRhs;
4451 R factor = scale[rowIdx] / scale[i];
4452
4453 if(factor > 0)
4454 {
4455 scaledLhs = (lp.lhs(i) <= R(-infinity)) ? R(-infinity) : lp.lhs(i) * factor;
4456 scaledRhs = (lp.rhs(i) >= R(infinity)) ? R(infinity) : lp.rhs(i) * factor;
4457 }
4458 else
4459 {
4460 scaledLhs = (lp.rhs(i) >= R(infinity)) ? R(-infinity) : lp.rhs(i) * factor;
4461 scaledRhs = (lp.lhs(i) <= R(-infinity)) ? R(infinity) : lp.lhs(i) * factor;
4462 }
4463
4464 if(scaledLhs > maxLhs)
4465 {
4466 maxLhs = scaledLhs;
4467 maxLhsIdx = i;
4468 }
4469
4470 if(scaledRhs < minRhs)
4471 {
4472 minRhs = scaledRhs;
4473 minRhsIdx = i;
4474 }
4475
4476 remRow[i] = true;
4477 }
4478 }
4479
4480 if(rowIdx != -1)
4481 {
4482 R newLhs = (maxLhs > lp.lhs(rowIdx)) ? maxLhs : lp.lhs(rowIdx);
4483 R newRhs = (minRhs < lp.rhs(rowIdx)) ? minRhs : lp.rhs(rowIdx);
4484
4485 if(k == idxLastDupRows)
4486 {
4487 DataArray<int> da_perm(nRowsOld_tmp);
4488
4489 for(int j = 0; j < nRowsOld_tmp; ++j)
4490 {
4491 da_perm[j] = perm_tmp[j];
4492 }
4493
4494 std::shared_ptr<PostStep> ptr(new DuplicateRowsPS(lp, rowIdx, maxLhsIdx, minRhsIdx,
4495 m_dupRows[k], scale, da_perm, isLhsEqualRhs, true,
4496 EQrel(newLhs, newRhs), k == idxFirstDupRows));
4497 m_hist.append(ptr);
4498 }
4499 else
4500 {
4501 DataArray<int> da_perm_empty(0);
4502 std::shared_ptr<PostStep> ptr(new DuplicateRowsPS(lp, rowIdx, maxLhsIdx, minRhsIdx,
4503 m_dupRows[k], scale, da_perm_empty, isLhsEqualRhs, false, EQrel(newLhs, newRhs),
4504 k == idxFirstDupRows));
4505 m_hist.append(ptr);
4506 }
4507
4508 if(maxLhs > lp.lhs(rowIdx) || minRhs < lp.rhs(rowIdx))
4509 {
4510 // modify lhs and rhs of constraint rowIdx
4511 doChangeRanges = true;
4512
4513 if(LTrel(newRhs, newLhs, feastol()))
4514 {
4515 MSG_DEBUG((*this->spxout) << "IMAISM55 duplicate rows yield infeasible bounds:"
4516 << " lhs=" << newLhs
4517 << " rhs=" << newRhs << std::endl;)
4518 spx_free(perm_tmp);
4519 return this->INFEASIBLE;
4520 }
4521
4522 // if we accept the infeasibility we should clean up the values to avoid problems later
4523 if(newRhs < newLhs)
4524 newRhs = newLhs;
4525
4526 newLhsVec[rowIdx] = newLhs;
4527 newRhsVec[rowIdx] = newRhs;
4528 }
4529 }
4530 }
4531 }
4532
4533 // change ranges for all modified constraints by one single call (more efficient)
4534 if(doChangeRanges)
4535 {
4536 lp.changeRange(newLhsVec, newRhsVec);
4537 }
4538
4539 // remove all rows by one single method call (more efficient)
4540 const int nRowsOld = lp.nRows();
4541 int* perm = 0;
4542 spx_alloc(perm, nRowsOld);
4543
4544 for(int i = 0; i < nRowsOld; ++i)
4545 {
4546 if(remRow[i])
4547 {
4548 perm[i] = -1;
4549 ++remRows;
4550 remNzos += lp.rowVector(i).size();
4551 }
4552 else
4553 perm[i] = 0;
4554 }
4555
4556 lp.removeRows(perm);
4557
4558 for(int i = 0; i < nRowsOld; ++i)
4559 {
4560 // assert that the pre-computed permutation was correct
4561 assert(perm[i] == perm_tmp[i]);
4562
4563 // update the global index mapping
4564 if(perm[i] >= 0)
4565 m_rIdx[perm[i]] = m_rIdx[i];
4566 }
4567
4568 spx_free(perm);
4569 spx_free(perm_tmp);
4570
4571 if(remRows + remNzos > 0)
4572 {
4573 this->m_remRows += remRows;
4574 this->m_remNzos += remNzos;
4575
4576 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier (duplicate rows) removed "
4577 << remRows << " rows, "
4578 << remNzos << " non-zeros"
4579 << std::endl;)
4580
4581 if(remRows > this->m_minReduction * oldRows)
4582 again = true;
4583
4584 }
4585
4586 return this->OKAY;
4587 }
4588
4589 template <class R>
4590 typename SPxSimplifier<R>::Result SPxMainSM<R>::duplicateCols(SPxLPBase<R>& lp, bool& again)
4591 {
4592
4593 // This method simplifies the LP by removing duplicate columns
4594 // Duplicates are detected using the algorithm of Bixby and Wagner [1987]
4595
4596 int remCols = 0;
4597 int remNzos = 0;
4598
4599 // remove empty rows and columns
4600 typename SPxSimplifier<R>::Result ret = removeEmpty(lp);
4601
4602 if(ret != this->OKAY)
4603 return ret;
4604
4605 if(lp.nCols() < 2)
4606 return this->OKAY;
4607
4608 DataArray<int> pClass(lp.nCols()); // class of parallel columns
4609 DataArray<int> classSize(lp.nCols()); // size of each class
4610 Array<R> scale(lp.nCols()); // scaling factor for each column
4611 int* idxMem = 0;
4612
4613 try
4614 {
4615 spx_alloc(idxMem, lp.nCols());
4616 }
4617 catch(const SPxMemoryException& x)
4618 {
4619 spx_free(idxMem);
4620 throw x;
4621 }
4622
4623 IdxSet idxSet(lp.nCols(), idxMem); // set of feasible indices for new pClass
4624
4625 // init
4626 pClass[0] = 0;
4627 scale[0] = 0.0;
4628 classSize[0] = lp.nCols();
4629
4630 for(int j = 1; j < lp.nCols(); ++j)
4631 {
4632 pClass[j] = 0;
4633 scale[j] = 0.0;
4634 classSize[j] = 0;
4635 idxSet.addIdx(j);
4636 }
4637
4638 R oldVal = 0.0;
4639
4640 // main loop
4641 for(int i = 0; i < lp.nRows(); ++i)
4642 {
4643 const SVectorBase<R>& row = lp.rowVector(i);
4644
4645 for(int k = 0; k < row.size(); ++k)
4646 {
4647 R aij = row.value(k);
4648 int j = row.index(k);
4649
4650 if(scale[j] == 0.0)
4651 scale[j] = aij;
4652
4653 m_classSetCols[pClass[j]].add(j, aij / scale[j]);
4654
4655 if(--classSize[pClass[j]] == 0)
4656 idxSet.addIdx(pClass[j]);
4657 }
4658
4659 // update each parallel class with non-zero row entry
4660 for(int m = 0; m < row.size(); ++m)
4661 {
4662 int k = pClass[row.index(m)];
4663
4664 if(m_classSetCols[k].size() > 0)
4665 {
4666 // sort classSet[k] w.r.t. scaled row values
4667 ElementCompare compare;
4668
4669 if(m_classSetCols[k].size() > 1)
4670 SPxQuicksort(m_classSetCols[k].mem(), m_classSetCols[k].size(), compare);
4671
4672 // use new index first
4673 int classIdx = idxSet.index(0);
4674 idxSet.remove(0);
4675
4676 for(int l = 0; l < m_classSetCols[k].size(); ++l)
4677 {
4678 if(l != 0 && NErel(m_classSetCols[k].value(l), oldVal, this->epsZero()))
4679 {
4680 // start new parallel class
4681 classIdx = idxSet.index(0);
4682 idxSet.remove(0);
4683 }
4684
4685 pClass[m_classSetCols[k].index(l)] = classIdx;
4686 ++classSize[classIdx];
4687
4688 oldVal = m_classSetCols[k].value(l);
4689 }
4690
4691 m_classSetCols[k].clear();
4692 }
4693 }
4694 }
4695
4696 spx_free(idxMem);
4697
4698 DataArray<bool> remCol(lp.nCols());
4699 DataArray<bool> fixAndRemCol(lp.nCols());
4700
4701 for(int k = 0; k < lp.nCols(); ++k)
4702 m_dupCols[k].clear();
4703
4704 for(int k = 0; k < lp.nCols(); ++k)
4705 {
4706 remCol[k] = false;
4707 fixAndRemCol[k] = false;
4708 m_dupCols[pClass[k]].add(k, 0.0);
4709 }
4710
4711 bool hasDuplicateCol = false;
4712 DataArray<int> m_perm_empty(0);
4713
4714 for(int k = 0; k < lp.nCols(); ++k)
4715 {
4716 if(m_dupCols[k].size() > 1 && !(lp.colVector(m_dupCols[k].index(0)).size() == 1))
4717 {
4718 MSG_DEBUG((*this->spxout) << "IMAISM58 " << m_dupCols[k].size()
4719 << " duplicate columns found" << std::endl;)
4720
4721 if(!hasDuplicateCol)
4722 {
4723 std::shared_ptr<PostStep> ptr(new DuplicateColsPS(lp, 0, 0, 1.0, m_perm_empty, true));
4724 m_hist.append(ptr);
4725 hasDuplicateCol = true;
4726 }
4727
4728 for(int l = 0; l < m_dupCols[k].size(); ++l)
4729 {
4730 for(int m = 0; m < m_dupCols[k].size(); ++m)
4731 {
4732 int j1 = m_dupCols[k].index(l);
4733 int j2 = m_dupCols[k].index(m);
4734
4735 if(l != m && !remCol[j1] && !remCol[j2])
4736 {
4737 R cj1 = lp.maxObj(j1);
4738 R cj2 = lp.maxObj(j2);
4739
4740 // A.j1 = factor * A.j2
4741 R factor = scale[j1] / scale[j2];
4742 R objDif = cj1 - cj2 * scale[j1] / scale[j2];
4743
4744 ASSERT_WARN("WMAISM59", isNotZero(factor, this->epsZero()));
4745
4746 if(isZero(objDif, this->epsZero()))
4747 {
4748 // case 1: objectives also duplicate
4749
4750 // if 0 is not within the column bounds, we are not able to postsolve if the aggregated column has
4751 // status ZERO, hence we skip this case
4752 if(LErel(lp.lower(j1), R(0.0)) && GErel(lp.upper(j1), R(0.0))
4753 && LErel(lp.lower(j2), R(0.0)) && GErel(lp.upper(j2), R(0.0)))
4754 {
4755 std::shared_ptr<PostStep> ptr(new DuplicateColsPS(lp, j1, j2, factor, m_perm_empty));
4756 // variable substitution xj2' := xj2 + factor * xj1 <=> xj2 = -factor * xj1 + xj2'
4757 m_hist.append(ptr);
4758
4759 // update bounds of remaining column j2 (new column j2')
4760 if(factor > 0)
4761 {
4762 if(lp.lower(j2) <= R(-infinity) || lp.lower(j1) <= R(-infinity))
4763 lp.changeLower(j2, R(-infinity));
4764 else
4765 lp.changeLower(j2, lp.lower(j2) + factor * lp.lower(j1));
4766
4767 if(lp.upper(j2) >= R(infinity) || lp.upper(j1) >= R(infinity))
4768 lp.changeUpper(j2, R(infinity));
4769 else
4770 lp.changeUpper(j2, lp.upper(j2) + factor * lp.upper(j1));
4771 }
4772 else if(factor < 0)
4773 {
4774 if(lp.lower(j2) <= R(-infinity) || lp.upper(j1) >= R(infinity))
4775 lp.changeLower(j2, R(-infinity));
4776 else
4777 lp.changeLower(j2, lp.lower(j2) + factor * lp.upper(j1));
4778
4779 if(lp.upper(j2) >= R(infinity) || lp.lower(j1) <= R(-infinity))
4780 lp.changeUpper(j2, R(infinity));
4781 else
4782 lp.changeUpper(j2, lp.upper(j2) + factor * lp.lower(j1));
4783 }
4784
4785 MSG_DEBUG((*this->spxout) << "IMAISM60 two duplicate columns " << j1
4786 << ", " << j2
4787 << " replaced by one" << std::endl;)
4788
4789 remCol[j1] = true;
4790
4791 ++m_stat[SUB_DUPLICATE_COL];
4792 }
4793 else
4794 {
4795 MSG_DEBUG((*this->spxout) << "IMAISM80 not removing two duplicate columns " << j1
4796 << ", " << j2
4797 << " because zero not contained in their bounds" << std::endl;)
4798 }
4799 }
4800 else
4801 {
4802 // case 2: objectives not duplicate
4803 // considered for maximization sense
4804 if(lp.lower(j2) <= R(-infinity))
4805 {
4806 if(factor > 0 && objDif > 0)
4807 {
4808 if(lp.upper(j1) >= R(infinity))
4809 {
4810 MSG_DEBUG((*this->spxout) << "IMAISM75 LP unbounded" << std::endl;)
4811 return this->UNBOUNDED;
4812 }
4813
4814 // fix j1 at upper bound
4815 MSG_DEBUG((*this->spxout) << "IMAISM61 two duplicate columns " << j1
4816 << ", " << j2
4817 << " first one fixed at upper bound=" << lp.upper(j1) << std::endl;)
4818
4819 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j1, lp.upper(j1)));
4820 m_hist.append(ptr);
4821 lp.changeLower(j1, lp.upper(j1));
4822 }
4823 else if(factor < 0 && objDif < 0)
4824 {
4825 if(lp.lower(j1) <= R(-infinity))
4826 {
4827 MSG_DEBUG((*this->spxout) << "IMAISM76 LP unbounded" << std::endl;)
4828 return this->UNBOUNDED;
4829 }
4830
4831 // fix j1 at lower bound
4832 MSG_DEBUG((*this->spxout) << "IMAISM62 two duplicate columns " << j1
4833 << ", " << j2
4834 << " first one fixed at lower bound=" << lp.lower(j1) << std::endl;)
4835
4836 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j1, lp.lower(j1)));
4837 m_hist.append(ptr);
4838 lp.changeUpper(j1, lp.lower(j1));
4839 }
4840 }
4841 else if(lp.upper(j2) >= R(infinity))
4842 {
4843 // fix j1 at upper bound
4844 if(factor < 0 && objDif > 0)
4845 {
4846 if(lp.upper(j1) >= R(infinity))
4847 {
4848 MSG_DEBUG((*this->spxout) << "IMAISM77 LP unbounded" << std::endl;)
4849 return this->UNBOUNDED;
4850 }
4851
4852 // fix j1 at upper bound
4853 MSG_DEBUG((*this->spxout) << "IMAISM63 two duplicate columns " << j1
4854 << ", " << j2
4855 << " first one fixed at upper bound=" << lp.upper(j1) << std::endl;)
4856
4857 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j1, lp.upper(j1)));
4858 m_hist.append(ptr);
4859 lp.changeLower(j1, lp.upper(j1));
4860 }
4861
4862 // fix j1 at lower bound
4863 else if(factor > 0 && objDif < 0)
4864 {
4865 if(lp.lower(j1) <= R(-infinity))
4866 {
4867 MSG_DEBUG((*this->spxout) << "IMAISM78 LP unbounded" << std::endl;)
4868 return this->UNBOUNDED;
4869 }
4870
4871 // fix j1 at lower bound
4872 MSG_DEBUG((*this->spxout) << "IMAISM64 two duplicate columns " << j1
4873 << ", " << j2
4874 << " first one fixed at lower bound=" << lp.lower(j1) << std::endl;)
4875
4876 std::shared_ptr<PostStep> ptr(new FixBoundsPS(lp, j1, lp.lower(j1)));
4877 m_hist.append(ptr);
4878 lp.changeUpper(j1, lp.lower(j1));
4879 }
4880 }
4881
4882 if(EQrel(lp.lower(j1), lp.upper(j1), feastol()))
4883 {
4884 remCol[j1] = true;
4885 fixAndRemCol[j1] = true;
4886
4887 ++m_stat[FIX_DUPLICATE_COL];
4888 }
4889 }
4890 }
4891 }
4892 }
4893 }
4894 }
4895
4896 for(int j = 0; j < lp.nCols(); ++j)
4897 {
4898 if(fixAndRemCol[j])
4899 {
4900 assert(remCol[j]);
4901
4902 // correctIdx == false, because the index mapping will be handled by the postsolving in DuplicateColsPS
4903 fixColumn(lp, j, false);
4904 }
4905 }
4906
4907 // remove all columns by one single method call (more efficient)
4908 const int nColsOld = lp.nCols();
4909 int* perm = 0;
4910 spx_alloc(perm, nColsOld);
4911
4912 for(int j = 0; j < nColsOld; ++j)
4913 {
4914 if(remCol[j])
4915 {
4916 perm[j] = -1;
4917 ++remCols;
4918 remNzos += lp.colVector(j).size();
4919 }
4920 else
4921 perm[j] = 0;
4922 }
4923
4924 lp.removeCols(perm);
4925
4926 for(int j = 0; j < nColsOld; ++j)
4927 {
4928 if(perm[j] >= 0)
4929 m_cIdx[perm[j]] = m_cIdx[j];
4930 }
4931
4932 DataArray<int> da_perm(nColsOld);
4933
4934 for(int j = 0; j < nColsOld; ++j)
4935 {
4936 da_perm[j] = perm[j];
4937 }
4938
4939 if(hasDuplicateCol)
4940 {
4941 std::shared_ptr<PostStep> ptr(new DuplicateColsPS(lp, 0, 0, 1.0, da_perm, false, true));
4942 m_hist.append(ptr);
4943 }
4944
4945 spx_free(perm);
4946
4947 assert(remCols > 0 || remNzos == 0);
4948
4949 if(remCols > 0)
4950 {
4951 this->m_remCols += remCols;
4952 this->m_remNzos += remNzos;
4953
4954 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier (duplicate columns) removed "
4955 << remCols << " cols, "
4956 << remNzos << " non-zeros"
4957 << std::endl;)
4958
4959 if(remCols > this->m_minReduction * nColsOld)
4960 again = true;
4961 }
4962
4963 return this->OKAY;
4964 }
4965
4966 template <class R>
4967 void SPxMainSM<R>::fixColumn(SPxLPBase<R>& lp, int j, bool correctIdx)
4968 {
4969
4970 assert(EQrel(lp.lower(j), lp.upper(j), feastol()));
4971
4972 R lo = lp.lower(j);
4973 R up = lp.upper(j);
4974 const SVectorBase<R>& col = lp.colVector(j);
4975 R mid = lo;
4976
4977 // use the center value between slightly different bounds to improve numerics
4978 if(NE(lo, up))
4979 mid = (up + lo) / 2.0;
4980
4981 assert(LT(lo, R(infinity)) && GT(lo, R(-infinity)));
4982 assert(LT(up, R(infinity)) && GT(up, R(-infinity)));
4983
4984 MSG_DEBUG((*this->spxout) << "IMAISM66 fix variable x" << j
4985 << ": lower=" << lo
4986 << " upper=" << up
4987 << "to new value: " << mid
4988 << std::endl;)
4989
4990 if(isNotZero(lo, this->epsZero()))
4991 {
4992 for(int k = 0; k < col.size(); ++k)
4993 {
4994 int i = col.index(k);
4995
4996 if(lp.rhs(i) < R(infinity))
4997 {
4998 R y = mid * col.value(k);
4999 R scale = maxAbs(lp.rhs(i), y);
5000
5001 if(scale < 1.0)
5002 scale = 1.0;
5003
5004 R rhs = (lp.rhs(i) / scale) - (y / scale);
5005
5006 if(isZero(rhs, this->epsZero()))
5007 rhs = 0.0;
5008 else
5009 rhs *= scale;
5010
5011 MSG_DEBUG((*this->spxout) << "IMAISM67 row " << i
5012 << ": rhs=" << rhs
5013 << " (" << lp.rhs(i)
5014 << ") aij=" << col.value(k)
5015 << std::endl;)
5016
5017 lp.changeRhs(i, rhs);
5018 }
5019
5020 if(lp.lhs(i) > R(-infinity))
5021 {
5022 R y = mid * col.value(k);
5023 R scale = maxAbs(lp.lhs(i), y);
5024
5025 if(scale < 1.0)
5026 scale = 1.0;
5027
5028 R lhs = (lp.lhs(i) / scale) - (y / scale);
5029
5030 if(isZero(lhs, this->epsZero()))
5031 lhs = 0.0;
5032 else
5033 lhs *= scale;
5034
5035 MSG_DEBUG((*this->spxout) << "IMAISM68 row " << i
5036 << ": lhs=" << lhs
5037 << " (" << lp.lhs(i)
5038 << ") aij=" << col.value(k)
5039 << std::endl;)
5040
5041 lp.changeLhs(i, lhs);
5042 }
5043
5044 assert(lp.lhs(i) <= lp.rhs(i) + feastol());
5045 }
5046 }
5047
5048 std::shared_ptr<PostStep> ptr(new FixVariablePS(lp, *this, j, lp.lower(j), correctIdx));
5049 m_hist.append(ptr);
5050 }
5051
5052 template <class R>
5053 typename SPxSimplifier<R>::Result SPxMainSM<R>::simplify(SPxLPBase<R>& lp, R eps, R ftol, R otol,
5054 Real remainingTime,
5055 bool keepbounds, uint32_t seed)
5056 {
5057 // transfer message handler
5058 this->spxout = lp.spxout;
5059 assert(this->spxout != 0);
5060
5061 m_thesense = lp.spxSense();
5062 this->m_timeUsed->reset();
5063 this->m_timeUsed->start();
5064
5065 this->m_objoffset = 0.0;
5066 m_cutoffbound = R(-infinity);
5067 m_pseudoobj = R(-infinity);
5068
5069 this->m_remRows = 0;
5070 this->m_remCols = 0;
5071 this->m_remNzos = 0;
5072 this->m_chgBnds = 0;
5073 this->m_chgLRhs = 0;
5074 this->m_keptBnds = 0;
5075 this->m_keptLRhs = 0;
5076
5077 m_result = this->OKAY;
5078 bool again = true;
5079 int nrounds = 0;
5080
5081 if(m_hist.size() > 0)
5082 {
5083 m_hist.clear();
5084 }
5085
5086 m_hist.reSize(0);
5087 m_postsolved = false;
5088
5089 if(eps < 0.0)
5090 throw SPxInterfaceException("XMAISM30 Cannot use negative this->epsilon in simplify().");
5091
5092 if(ftol < 0.0)
5093 throw SPxInterfaceException("XMAISM31 Cannot use negative feastol in simplify().");
5094
5095 if(otol < 0.0)
5096 throw SPxInterfaceException("XMAISM32 Cannot use negative opttol in simplify().");
5097
5098 m_epsilon = eps;
5099 m_feastol = ftol;
5100 m_opttol = otol;
5101
5102
5103 MSG_INFO2((*this->spxout),
5104 int numRangedRows = 0;
5105 int numBoxedCols = 0;
5106 int numEqualities = 0;
5107
5108 for(int i = 0; i < lp.nRows(); ++i)
5109 {
5110 if(lp.lhs(i) > R(-infinity) && lp.rhs(i) < R(infinity))
5111 {
5112 if(EQ(lp.lhs(i), lp.rhs(i)))
5113 ++numEqualities;
5114 else
5115 ++numRangedRows;
5116 }
5117 }
5118 for(int j = 0; j < lp.nCols(); ++j)
5119 if(lp.lower(j) > R(-infinity) && lp.upper(j) < R(infinity))
5120 ++numBoxedCols;
5121
5122 (*this->spxout) << "LP has "
5123 << numEqualities << " equations, "
5124 << numRangedRows << " ranged rows, "
5125 << numBoxedCols << " boxed columns"
5126 << std::endl;
5127 )
5128
5129 m_stat.reSize(17);
5130
5131 for(int k = 0; k < m_stat.size(); ++k)
5132 m_stat[k] = 0;
5133
5134 m_addedcols = 0;
5135 handleRowObjectives(lp);
5136
5137 m_prim.reDim(lp.nCols());
5138 m_slack.reDim(lp.nRows());
5139 m_dual.reDim(lp.nRows());
5140 m_redCost.reDim(lp.nCols());
5141 m_cBasisStat.reSize(lp.nCols());
5142 m_rBasisStat.reSize(lp.nRows());
5143 m_cIdx.reSize(lp.nCols());
5144 m_rIdx.reSize(lp.nRows());
5145
5146 m_classSetRows.reSize(lp.nRows());
5147 m_classSetCols.reSize(lp.nCols());
5148 m_dupRows.reSize(lp.nRows());
5149 m_dupCols.reSize(lp.nCols());
5150
5151 m_keepbounds = keepbounds;
5152
5153 for(int i = 0; i < lp.nRows(); ++i)
5154 m_rIdx[i] = i;
5155
5156 for(int j = 0; j < lp.nCols(); ++j)
5157 m_cIdx[j] = j;
5158
5159 // round extreme values (set all values smaller than this->eps to zero and all values bigger than R(infinity)/5 to R(infinity))
5160 #if EXTREMES
5161 handleExtremes(lp);
5162 #endif
5163
5164 // main presolving loop
5165 while(again && m_result == this->OKAY)
5166 {
5167 nrounds++;
5168 MSG_INFO3((*this->spxout), (*this->spxout) << "Round " << nrounds << ":" << std::endl;)
5169 again = false;
5170
5171 #if ROWS_SPXMAINSM
5172
5173 if(m_result == this->OKAY)
5174 m_result = simplifyRows(lp, again);
5175
5176 #endif
5177
5178 #if COLS_SPXMAINSM
5179
5180 if(m_result == this->OKAY)
5181 m_result = simplifyCols(lp, again);
5182
5183 #endif
5184
5185 #if DUAL_SPXMAINSM
5186
5187 if(m_result == this->OKAY)
5188 m_result = simplifyDual(lp, again);
5189
5190 #endif
5191
5192 #if DUPLICATE_ROWS
5193
5194 if(m_result == this->OKAY)
5195 m_result = duplicateRows(lp, again);
5196
5197 #endif
5198
5199 #if DUPLICATE_COLS
5200
5201 if(m_result == this->OKAY)
5202 m_result = duplicateCols(lp, again);
5203
5204 #endif
5205
5206 if(!again)
5207 {
5208 #if TRIVIAL_HEURISTICS
5209 trivialHeuristic(lp);
5210 #endif
5211
5212 #if PSEUDOOBJ
5213 propagatePseudoobj(lp);
5214 #endif
5215
5216 #if MULTI_AGGREGATE
5217
5218 if(m_result == this->OKAY)
5219 m_result = multiaggregation(lp, again);
5220
5221 #endif
5222 }
5223
5224 }
5225
5226 // preprocessing detected infeasibility or unboundedness
5227 if(m_result != this->OKAY)
5228 {
5229 MSG_INFO1((*this->spxout), (*this->spxout) << "Simplifier result: " << static_cast<int>
5230 (m_result) << std::endl;)
5231 return m_result;
5232 }
5233
5234 this->m_remCols -= m_addedcols;
5235 this->m_remNzos -= m_addedcols;
5236 MSG_INFO1((*this->spxout), (*this->spxout) << "Simplifier removed "
5237 << this->m_remRows << " rows, "
5238 << this->m_remCols << " columns, "
5239 << this->m_remNzos << " nonzeros, "
5240 << this->m_chgBnds << " col bounds, "
5241 << this->m_chgLRhs << " row bounds"
5242 << std::endl;)
5243
5244 if(keepbounds)
5245 MSG_INFO2((*this->spxout), (*this->spxout) << "Simplifier kept "
5246 << this->m_keptBnds << " column bounds, "
5247 << this->m_keptLRhs << " row bounds"
5248 << std::endl;)
5249
5250 MSG_INFO1((*this->spxout), (*this->spxout) << "Reduced LP has "
5251 << lp.nRows() << " rows "
5252 << lp.nCols() << " columns "
5253 << lp.nNzos() << " nonzeros"
5254 << std::endl;)
5255
5256 MSG_INFO2((*this->spxout),
5257 int numRangedRows = 0;
5258 int numBoxedCols = 0;
5259 int numEqualities = 0;
5260
5261 for(int i = 0; i < lp.nRows(); ++i)
5262 {
5263 if(lp.lhs(i) > R(-infinity) && lp.rhs(i) < R(infinity))
5264 {
5265 if(EQ(lp.lhs(i), lp.rhs(i)))
5266 ++numEqualities;
5267 else
5268 ++numRangedRows;
5269 }
5270 }
5271 for(int j = 0; j < lp.nCols(); ++j)
5272 if(lp.lower(j) > R(-infinity) && lp.upper(j) < R(infinity))
5273 ++numBoxedCols;
5274
5275 (*this->spxout) << "Reduced LP has "
5276 << numEqualities << " equations, "
5277 << numRangedRows << " ranged rows, "
5278 << numBoxedCols << " boxed columns"
5279 << std::endl;
5280 )
5281
5282 if(lp.nCols() == 0 && lp.nRows() == 0)
5283 {
5284 MSG_INFO1((*this->spxout), (*this->spxout) << "Simplifier removed all rows and columns" <<
5285 std::endl;)
5286 m_result = this->VANISHED;
5287 }
5288
5289 MSG_INFO2((*this->spxout), (*this->spxout) << "\nSimplifier performed:\n"
5290 << m_stat[EMPTY_ROW] << " empty rows\n"
5291 << m_stat[FREE_ROW] << " free rows\n"
5292 << m_stat[SINGLETON_ROW] << " singleton rows\n"
5293 << m_stat[FORCE_ROW] << " forcing rows\n"
5294 << m_stat[EMPTY_COL] << " empty columns\n"
5295 << m_stat[FIX_COL] << " fixed columns\n"
5296 << m_stat[FREE_ZOBJ_COL] << " free columns with zero objective\n"
5297 << m_stat[ZOBJ_SINGLETON_COL] << " singleton columns with zero objective\n"
5298 << m_stat[DOUBLETON_ROW] << " singleton columns combined with a doubleton equation\n"
5299 << m_stat[FREE_SINGLETON_COL] << " free singleton columns\n"
5300 << m_stat[DOMINATED_COL] << " dominated columns\n"
5301 << m_stat[WEAKLY_DOMINATED_COL] << " weakly dominated columns\n"
5302 << m_stat[DUPLICATE_ROW] << " duplicate rows\n"
5303 << m_stat[FIX_DUPLICATE_COL] << " duplicate columns (fixed)\n"
5304 << m_stat[SUB_DUPLICATE_COL] << " duplicate columns (substituted)\n"
5305 << m_stat[AGGREGATION] << " variable aggregations\n"
5306 << m_stat[MULTI_AGG] << " multi aggregations\n"
5307 << std::endl;);
5308
5309 this->m_timeUsed->stop();
5310
5311 return m_result;
5312 }
5313
5314 template <class R>
5315 void SPxMainSM<R>::unsimplify(const VectorBase<R>& x, const VectorBase<R>& y,
5316 const VectorBase<R>& s, const VectorBase<R>& r,
5317 const typename SPxSolverBase<R>::VarStatus rows[],
5318 const typename SPxSolverBase<R>::VarStatus cols[], bool isOptimal)
5319 {
5320 MSG_INFO1((*this->spxout), (*this->spxout) << " --- unsimplifying solution and basis" << std::endl;)
5321 assert(x.dim() <= m_prim.dim());
5322 assert(y.dim() <= m_dual.dim());
5323 assert(x.dim() == r.dim());
5324 assert(y.dim() == s.dim());
5325
5326 // assign values of variables in reduced LP
5327 // NOTE: for maximization problems, we have to switch signs of dual and reduced cost values,
5328 // since simplifier assumes minimization problem
5329 for(int j = 0; j < x.dim(); ++j)
5330 {
5331 m_prim[j] = isZero(x[j], this->epsZero()) ? 0.0 : x[j];
5332 m_redCost[j] = isZero(r[j], this->epsZero()) ? 0.0 : (m_thesense == SPxLPBase<R>::MAXIMIZE ? -r[j] :
5333 r[j]);
5334 m_cBasisStat[j] = cols[j];
5335 }
5336
5337 for(int i = 0; i < y.dim(); ++i)
5338 {
5339 m_dual[i] = isZero(y[i], this->epsZero()) ? 0.0 : (m_thesense == SPxLPBase<R>::MAXIMIZE ? -y[i] :
5340 y[i]);
5341 m_slack[i] = isZero(s[i], this->epsZero()) ? 0.0 : s[i];
5342 m_rBasisStat[i] = rows[i];
5343 }
5344
5345 // undo preprocessing
5346 for(int k = m_hist.size() - 1; k >= 0; --k)
5347 {
5348 MSG_DEBUG(std::cout << "unsimplifying " << m_hist[k]->getName() << "\n");
5349
5350 try
5351 {
5352 m_hist[k]->execute(m_prim, m_dual, m_slack, m_redCost, m_cBasisStat, m_rBasisStat, isOptimal);
5353 }
5354 catch(const SPxException& ex)
5355 {
5356 MSG_INFO1((*this->spxout), (*this->spxout) << "Exception thrown while unsimplifying " <<
5357 m_hist[k]->getName() << ":\n" << ex.what() << "\n");
5358 throw SPxInternalCodeException("XMAISM00 Exception thrown during unsimply().");
5359 }
5360
5361 m_hist.reSize(k);
5362 }
5363
5364 // for maximization problems, we have to switch signs of dual and reduced cost values back
5365 if(m_thesense == SPxLPBase<R>::MAXIMIZE)
5366 {
5367 for(int j = 0; j < m_redCost.dim(); ++j)
5368 m_redCost[j] = -m_redCost[j];
5369
5370 for(int i = 0; i < m_dual.dim(); ++i)
5371 m_dual[i] = -m_dual[i];
5372 }
5373
5374 if(m_addedcols > 0)
5375 {
5376 assert(m_prim.dim() >= m_addedcols);
5377 m_prim.reDim(m_prim.dim() - m_addedcols);
5378 m_redCost.reDim(m_redCost.dim() - m_addedcols);
5379 m_cBasisStat.reSize(m_cBasisStat.size() - m_addedcols);
5380 m_cIdx.reSize(m_cIdx.size() - m_addedcols);
5381 }
5382
5383 #ifdef CHECK_BASIC_DIM
5384 int numBasis = 0;
5385
5386 for(int rs = 0; rs < m_rBasisStat.size(); ++rs)
5387 {
5388 if(m_rBasisStat[rs] == SPxSolverBase<R>::BASIC)
5389 numBasis ++;
5390 }
5391
5392 for(int cs = 0; cs < m_cBasisStat.size(); ++cs)
5393 {
5394 if(m_cBasisStat[cs] == SPxSolverBase<R>::BASIC)
5395 numBasis ++;
5396 }
5397
5398 if(numBasis != m_rBasisStat.size())
5399 {
5400 throw SPxInternalCodeException("XMAISM26 Dimension doesn't match after this step.");
5401 }
5402
5403 #endif
5404
5405 m_hist.clear();
5406 m_postsolved = true;
5407 }
5408
5409 // Pretty-printing of solver status.
5410 template <class R>
5411 std::ostream& operator<<(std::ostream& os, const typename SPxSimplifier<R>::Result& status)
5412 {
5413 switch(status)
5414 {
5415 case SPxSimplifier<R>::OKAY:
5416 os << "SUCCESS";
5417 break;
5418
5419 case SPxSimplifier<R>::INFEASIBLE:
5420 os << "INFEASIBLE";
5421 break;
5422
5423 case SPxSimplifier<R>::DUAL_INFEASIBLE:
5424 os << "DUAL_INFEASIBLE";
5425 break;
5426
5427 case SPxSimplifier<R>::UNBOUNDED:
5428 os << "UNBOUNDED";
5429 break;
5430
5431 case SPxSimplifier<R>::VANISHED:
5432 os << "VANISHED";
5433 break;
5434
5435 default:
5436 os << "UNKNOWN";
5437 break;
5438 }
5439
5440 return os;
5441 }
5442
5443 } //namespace soplex
5444