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