Scippy

SoPlex

Sequential object-oriented simPlex

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