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  pseudoObj += val*lp.lower(j);
1822  else if(val > 0)
1823  pseudoObj += val*lp.upper(j);
1824  }
1825 
1826  if(LT(pseudoObj, infinity) && GT(pseudoObj, -infinity) && GT(m_cutoffbound, -infinity) && LT(m_cutoffbound, infinity))
1827  {
1828  if(pseudoObj > m_pseudoobj)
1829  m_pseudoobj = pseudoObj;
1830 
1831  for(int j = lp.nCols()-1; j >= 0; --j)
1832  {
1833  Real objval = lp.maxObj(j);
1834 
1835  if(EQ(objval, 0.0))
1836  continue;
1837 
1838  if(objval < 0.0)
1839  {
1840  Real newbound = lp.lower(j) + (m_cutoffbound - m_pseudoobj) / objval;
1841 
1842  if(LT(newbound, lp.upper(j)))
1843  {
1844  TightenBoundsPS* TightenBoundsPSptr = 0;
1845  spx_alloc(TightenBoundsPSptr);
1846  m_hist.append(new (TightenBoundsPSptr) TightenBoundsPS(lp, j, lp.upper(j), lp.lower(j)));
1847  lp.changeUpper(j, newbound);
1848  }
1849  }
1850  else if(objval > 0.0)
1851  {
1852  Real newbound = lp.upper(j) + (m_cutoffbound - m_pseudoobj) / objval;
1853  if(GT(newbound, lp.lower(j)))
1854  {
1855  TightenBoundsPS* TightenBoundsPSptr = 0;
1856  spx_alloc(TightenBoundsPSptr);
1857  m_hist.append(new (TightenBoundsPSptr) TightenBoundsPS(lp, j, lp.upper(j), lp.lower(j)));
1858  lp.changeLower(j, newbound);
1859  }
1860  }
1861  }
1862  }
1863 }
1864 
1865 
1866 
1868 {
1869 
1870  // This method removes empty rows and columns from the LP.
1871 
1872  int remRows = 0;
1873  int remCols = 0;
1874 
1875  for(int i = lp.nRows()-1; i >= 0; --i)
1876  {
1877  const SVector& row = lp.rowVector(i);
1878 
1879  if (row.size() == 0)
1880  {
1881  MSG_DEBUG( (*spxout) << "IMAISM07 row " << i
1882  << ": empty ->"; )
1883 
1884  if (LT(lp.rhs(i), 0.0, feastol()) || GT(lp.lhs(i), 0.0, feastol()))
1885  {
1886  MSG_DEBUG( (*spxout) << " infeasible lhs=" << lp.lhs(i)
1887  << " rhs=" << lp.rhs(i) << std::endl; )
1888  return INFEASIBLE;
1889  }
1890  MSG_DEBUG( (*spxout) << " removed" << std::endl; )
1891 
1892  EmptyConstraintPS* EmptyConstraintPSptr = 0;
1893  spx_alloc(EmptyConstraintPSptr);
1894  m_hist.append(new (EmptyConstraintPSptr) EmptyConstraintPS(lp, i));
1895 
1896  ++remRows;
1897  removeRow(lp, i);
1898 
1899  ++m_stat[EMPTY_ROW];
1900  }
1901  }
1902 
1903  for(int j = lp.nCols()-1; j >= 0; --j)
1904  {
1905  const SVector& col = lp.colVector(j);
1906 
1907  if (col.size() == 0)
1908  {
1909  MSG_DEBUG( (*spxout) << "IMAISM08 col " << j
1910  << ": empty -> maxObj=" << lp.maxObj(j)
1911  << " lower=" << lp.lower(j)
1912  << " upper=" << lp.upper(j); )
1913 
1914  Real val;
1915 
1916  if (GT(lp.maxObj(j), 0.0, epsZero()))
1917  {
1918  if (lp.upper(j) >= infinity)
1919  {
1920  MSG_DEBUG( (*spxout) << " unbounded" << std::endl; )
1921  return UNBOUNDED;
1922  }
1923  val = lp.upper(j);
1924  }
1925  else if (LT(lp.maxObj(j), 0.0, epsZero()))
1926  {
1927  if (lp.lower(j) <= -infinity)
1928  {
1929  MSG_DEBUG( (*spxout) << " unbounded" << std::endl; )
1930  return UNBOUNDED;
1931  }
1932  val = lp.lower(j);
1933  }
1934  else
1935  {
1936  ASSERT_WARN( "WMAISM09", isZero(lp.maxObj(j), epsZero()) );
1937  // any value within the bounds is ok
1938  if (lp.lower(j) > -infinity)
1939  val = lp.lower(j);
1940  else if (lp.upper(j) < infinity)
1941  val = lp.upper(j);
1942  else
1943  val = 0.0;
1944  }
1945  MSG_DEBUG( (*spxout) << " removed" << std::endl; )
1946 
1947  FixBoundsPS* FixBoundsPSptr = 0;
1948  FixVariablePS* FixVariablePSptr = 0;
1949  spx_alloc(FixBoundsPSptr);
1950  spx_alloc(FixVariablePSptr);
1951  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j, val));
1952  m_hist.append(new (FixVariablePSptr) FixVariablePS(lp, *this, j, val));
1953 
1954  ++remCols;
1955  removeCol(lp, j);
1956 
1957  ++m_stat[EMPTY_COL];
1958  }
1959  }
1960 
1961  if (remRows + remCols > 0)
1962  {
1963  m_remRows += remRows;
1964  m_remCols += remCols;
1965 
1966  MSG_INFO2( (*spxout), (*spxout) << "Simplifier (empty rows/colums) removed "
1967  << remRows << " rows, "
1968  << remCols << " cols"
1969  << std::endl; )
1970 
1971  }
1972  return OKAY;
1973 }
1974 
1976 {
1977  assert(row.size() == 1);
1978 
1979  Real aij = row.value(0);
1980  int j = row.index(0);
1981  Real lo = -infinity;
1982  Real up = infinity;
1983 
1984  MSG_DEBUG( (*spxout) << "IMAISM22 row " << i
1985  << ": singleton -> val=" << aij
1986  << " lhs=" << lp.lhs(i)
1987  << " rhs=" << lp.rhs(i); )
1988 
1989  if (GT(aij, 0.0, epsZero())) // aij > 0
1990  {
1991  lo = (lp.lhs(i) <= -infinity) ? -infinity : lp.lhs(i) / aij;
1992  up = (lp.rhs(i) >= infinity) ? infinity : lp.rhs(i) / aij;
1993  }
1994  else if (LT(aij, 0.0, epsZero())) // aij < 0
1995  {
1996  lo = (lp.rhs(i) >= infinity) ? -infinity : lp.rhs(i) / aij;
1997  up = (lp.lhs(i) <= -infinity) ? infinity : lp.lhs(i) / aij;
1998  }
1999  else if (LT(lp.rhs(i), 0.0, feastol()) || GT(lp.lhs(i), 0.0, feastol()))
2000  {
2001  // aij == 0, rhs < 0 or lhs > 0
2002  MSG_DEBUG( (*spxout) << " infeasible" << std::endl; )
2003  return INFEASIBLE;
2004  }
2005 
2006  if (isZero(lo, epsZero()))
2007  lo = 0.0;
2008 
2009  if (isZero(up, epsZero()))
2010  up = 0.0;
2011 
2012  MSG_DEBUG( (*spxout) << " removed, lower=" << lo
2013  << " (" << lp.lower(j)
2014  << ") upper=" << up
2015  << " (" << lp.upper(j)
2016  << ")" << std::endl; )
2017 
2018  bool stricterUp = false;
2019  bool stricterLo = false;
2020 
2021  Real oldLo = lp.lower(j);
2022  Real oldUp = lp.upper(j);
2023 
2024  if (LTrel(up, lp.upper(j), feastol()))
2025  {
2026  lp.changeUpper(j, up);
2027  stricterUp = true;
2028  }
2029  if (GTrel(lo, lp.lower(j), feastol()))
2030  {
2031  lp.changeLower(j, lo);
2032  stricterLo = true;
2033  }
2034 
2035  RowSingletonPS* RowSingletonPSptr = 0;
2036  spx_alloc(RowSingletonPSptr);
2037  m_hist.append(new (RowSingletonPSptr) RowSingletonPS(lp, i, j, stricterLo, stricterUp, lp.lower(j), lp.upper(j), oldLo, oldUp));
2038 
2039  removeRow(lp, i);
2040 
2041  m_remRows++;
2042  m_remNzos++;
2043  ++m_stat[SINGLETON_ROW];
2044 
2045  return OKAY;
2046 }
2047 
2049 {
2050 
2051  // This method simplifies the rows of the LP.
2052  //
2053  // The following operations are done:
2054  // 1. detect implied free variables
2055  // 2. detect implied free constraints
2056  // 3. detect infeasible constraints
2057  // 4. remove unconstrained constraints
2058  // 5. remove empty constraints
2059  // 6. remove row singletons and tighten the corresponding variable bounds if necessary
2060  // 7. detect forcing rows and fix the corresponding variables
2061 
2062  int remRows = 0;
2063  int remNzos = 0;
2064  int chgLRhs = 0;
2065  int chgBnds = 0;
2066  int keptBnds = 0;
2067  int keptLRhs = 0;
2068 
2069  int oldRows = lp.nRows();
2070 
2071  bool redundantLower;
2072  bool redundantUpper;
2073  bool redundantLhs;
2074  bool redundantRhs;
2075 
2076  for(int i = lp.nRows()-1; i >= 0; --i)
2077  {
2078  const SVector& row = lp.rowVector(i);
2079 
2080 
2081  // compute bounds on constraint value
2082  Real lhsBnd = 0.0; // minimal activity (finite summands)
2083  Real rhsBnd = 0.0; // maximal activity (finite summands)
2084  int lhsCnt = 0; // number of -infinity summands in minimal activity
2085  int rhsCnt = 0; // number of +infinity summands in maximal activity
2086 
2087  for(int k = 0; k < row.size(); ++k)
2088  {
2089  Real aij = row.value(k);
2090  int j = row.index(k);
2091 
2092  if( !isNotZero(aij, 1.0 / infinity) )
2093  {
2094  MSG_WARNING( (*spxout), (*spxout) << "Warning: tiny nonzero coefficient " << aij << " in row " << i << "\n" );
2095  }
2096 
2097  if (aij > 0.0)
2098  {
2099  if (lp.lower(j) <= -infinity)
2100  ++lhsCnt;
2101  else
2102  lhsBnd += aij * lp.lower(j);
2103 
2104  if (lp.upper(j) >= infinity)
2105  ++rhsCnt;
2106  else
2107  rhsBnd += aij * lp.upper(j);
2108  }
2109  else if (aij < 0.0)
2110  {
2111  if (lp.lower(j) <= -infinity)
2112  ++rhsCnt;
2113  else
2114  rhsBnd += aij * lp.lower(j);
2115 
2116  if (lp.upper(j) >= infinity)
2117  ++lhsCnt;
2118  else
2119  lhsBnd += aij * lp.upper(j);
2120  }
2121  }
2122 
2123 #if FREE_BOUNDS
2124  // 1. detect implied free variables
2125  if (rhsCnt <= 1 || lhsCnt <= 1)
2126  {
2127  for(int k = 0; k < row.size(); ++k)
2128  {
2129  Real aij = row.value(k);
2130  int j = row.index(k);
2131 
2132  redundantLower = false;
2133  redundantUpper = false;
2134 
2135  ASSERT_WARN( "WMAISM12", isNotZero(aij, 1.0 / infinity) );
2136 
2137  if (aij > 0.0)
2138  {
2139  if (lp.lhs(i) > -infinity && lp.lower(j) > -infinity && rhsCnt <= 1 && NErel(lp.lhs(i), rhsBnd, feastol())
2140  // do not perform if strongly different orders of magnitude occur
2141  && spxAbs(lp.lhs(i) / maxAbs(rhsBnd, 1.0)) > Param::epsilon())
2142  {
2143  Real lo = -infinity;
2144  Real scale = maxAbs(lp.lhs(i), rhsBnd);
2145 
2146  if (scale < 1.0)
2147  scale = 1.0;
2148 
2149  Real z = (lp.lhs(i) / scale) - (rhsBnd / scale);
2150 
2151  if (isZero(z, epsZero()))
2152  z = 0.0;
2153 
2154  assert(rhsCnt > 0 || lp.upper(j) < infinity);
2155 
2156  if (rhsCnt == 0)
2157  lo = lp.upper(j) + z * scale / aij;
2158  else if (lp.upper(j) >= infinity)
2159  lo = z * scale / aij;
2160 
2161  if (isZero(lo, epsZero()))
2162  lo = 0.0;
2163 
2164  if (GErel(lo, lp.lower(j), feastol()))
2165  {
2166  MSG_DEBUG( (*spxout) << "IMAISM13 row " << i
2167  << ": redundant lower bound on x" << j
2168  << " -> lower=" << lo
2169  << " (" << lp.lower(j)
2170  << ")" << std::endl; )
2171 
2172  redundantLower = true;
2173  }
2174 
2175  }
2176  if (lp.rhs(i) < infinity && lp.upper(j) < infinity && lhsCnt <= 1 && NErel(lp.rhs(i), lhsBnd, feastol())
2177  // do not perform if strongly different orders of magnitude occur
2178  && spxAbs(lp.rhs(i) / maxAbs(lhsBnd, 1.0)) > Param::epsilon())
2179  {
2180  Real up = infinity;
2181  Real scale = maxAbs(lp.rhs(i), lhsBnd);
2182 
2183  if (scale < 1.0)
2184  scale = 1.0;
2185 
2186  Real z = (lp.rhs(i) / scale) - (lhsBnd / scale);
2187 
2188  if (isZero(z, epsZero()))
2189  z = 0.0;
2190 
2191  assert(lhsCnt > 0 || lp.lower(j) > -infinity);
2192 
2193  if (lhsCnt == 0)
2194  up = lp.lower(j) + z * scale / aij;
2195  else if (lp.lower(j) <= -infinity)
2196  up = z * scale / aij;
2197 
2198  if (isZero(up, epsZero()))
2199  up = 0.0;
2200 
2201  if (LErel(up, lp.upper(j), feastol()))
2202  {
2203  MSG_DEBUG( (*spxout) << "IMAISM14 row " << i
2204  << ": redundant upper bound on x" << j
2205  << " -> upper=" << up
2206  << " (" << lp.upper(j)
2207  << ")" << std::endl; )
2208 
2209  redundantUpper = true;
2210  }
2211  }
2212  if (redundantLower)
2213  {
2214  // no upper bound on x_j OR redundant upper bound
2215  if ((lp.upper(j) >= infinity) || redundantUpper || (!m_keepbounds))
2216  {
2217  ++lhsCnt;
2218  lhsBnd -= aij * lp.lower(j);
2219 
2220  lp.changeLower(j, -infinity);
2221  ++chgBnds;
2222  }
2223  else
2224  ++keptBnds;
2225  }
2226  if (redundantUpper)
2227  {
2228  // no lower bound on x_j OR redundant lower bound
2229  if ((lp.lower(j) <= -infinity) || redundantLower || (!m_keepbounds))
2230  {
2231  ++rhsCnt;
2232  rhsBnd -= aij * lp.upper(j);
2233 
2234  lp.changeUpper(j, infinity);
2235  ++chgBnds;
2236  }
2237  else
2238  ++keptBnds;
2239  }
2240  }
2241  else if (aij < 0.0)
2242  {
2243  if (lp.lhs(i) > -infinity && lp.upper(j) < infinity && rhsCnt <= 1 && NErel(lp.lhs(i), rhsBnd, feastol())
2244  // do not perform if strongly different orders of magnitude occur
2245  && spxAbs(lp.lhs(i) / maxAbs(rhsBnd, 1.0)) > Param::epsilon())
2246  {
2247  Real up = infinity;
2248  Real scale = maxAbs(lp.lhs(i), rhsBnd);
2249 
2250  if (scale < 1.0)
2251  scale = 1.0;
2252 
2253  Real z = (lp.lhs(i) / scale) - (rhsBnd / scale);
2254 
2255  if (isZero(z, epsZero()))
2256  z = 0.0;
2257 
2258  assert(rhsCnt > 0 || lp.lower(j) > -infinity);
2259 
2260  if (rhsCnt == 0)
2261  up = lp.lower(j) + z * scale / aij;
2262  else if (lp.lower(j) <= -infinity)
2263  up = z * scale / aij;
2264 
2265  if (isZero(up, epsZero()))
2266  up = 0.0;
2267 
2268  if (LErel(up, lp.upper(j), feastol()))
2269  {
2270  MSG_DEBUG( (*spxout) << "IMAISM15 row " << i
2271  << ": redundant upper bound on x" << j
2272  << " -> upper=" << up
2273  << " (" << lp.upper(j)
2274  << ")" << std::endl; )
2275 
2276  redundantUpper = true;
2277  }
2278  }
2279  if (lp.rhs(i) < infinity && lp.lower(j) > -infinity && lhsCnt <= 1 && NErel(lp.rhs(i), lhsBnd, feastol())
2280  // do not perform if strongly different orders of magnitude occur
2281  && spxAbs(lp.rhs(i) / maxAbs(lhsBnd, 1.0)) > Param::epsilon())
2282  {
2283  Real lo = -infinity;
2284  Real scale = maxAbs(lp.rhs(i), lhsBnd);
2285 
2286  if (scale < 1.0)
2287  scale = 1.0;
2288 
2289  Real z = (lp.rhs(i) / scale) - (lhsBnd / scale);
2290 
2291  if (isZero(z, epsZero()))
2292  z = 0.0;
2293 
2294  assert(lhsCnt > 0 || lp.upper(j) < infinity);
2295 
2296  if (lhsCnt == 0)
2297  lo = lp.upper(j) + z * scale / aij;
2298  else if (lp.upper(j) >= infinity)
2299  lo = z * scale / aij;
2300 
2301  if (isZero(lo, epsZero()))
2302  lo = 0.0;
2303 
2304  if (GErel(lo, lp.lower(j)))
2305  {
2306  MSG_DEBUG( (*spxout) << "IMAISM16 row " << i
2307  << ": redundant lower bound on x" << j
2308  << " -> lower=" << lo
2309  << " (" << lp.lower(j)
2310  << ")" << std::endl; )
2311 
2312  redundantLower = true;
2313  }
2314  }
2315  if (redundantUpper)
2316  {
2317  // no lower bound on x_j OR redundant lower bound
2318  if ((lp.lower(j) <= -infinity) || redundantLower || (!m_keepbounds))
2319  {
2320  ++lhsCnt;
2321  lhsBnd -= aij * lp.upper(j);
2322 
2323  lp.changeUpper(j, infinity);
2324  ++chgBnds;
2325  }
2326  else
2327  ++keptBnds;
2328  }
2329  if (redundantLower)
2330  {
2331  // no upper bound on x_j OR redundant upper bound
2332  if ((lp.upper(j) >= infinity) || redundantUpper || (!m_keepbounds))
2333  {
2334  ++rhsCnt;
2335  rhsBnd -= aij * lp.lower(j);
2336 
2337  lp.changeLower(j, -infinity);
2338  ++chgBnds;
2339  }
2340  else
2341  ++keptBnds;
2342  }
2343  }
2344  }
2345  }
2346 #endif
2347 
2348 #if FREE_LHS_RHS
2349 
2350  redundantLhs = false;
2351  redundantRhs = false;
2352 
2353  // 2. detect implied free constraints
2354  if (lp.lhs(i) > -infinity && lhsCnt == 0 && GErel(lhsBnd, lp.lhs(i), feastol()))
2355  {
2356  MSG_DEBUG( (*spxout) << "IMAISM17 row " << i
2357  << ": redundant lhs -> lhsBnd=" << lhsBnd
2358  << " lhs=" << lp.lhs(i)
2359  << std::endl; )
2360 
2361  redundantLhs = true;
2362  }
2363  if (lp.rhs(i) < infinity && rhsCnt == 0 && LErel(rhsBnd, lp.rhs(i), feastol()))
2364  {
2365  MSG_DEBUG( (*spxout) << "IMAISM18 row " << i
2366  << ": redundant rhs -> rhsBnd=" << rhsBnd
2367  << " rhs=" << lp.rhs(i)
2368  << std::endl; )
2369 
2370  redundantRhs = true;
2371  }
2372  if (redundantLhs)
2373  {
2374  // no rhs for constraint i OR redundant rhs
2375  if ((lp.rhs(i) >= infinity) || redundantRhs || (!m_keepbounds))
2376  {
2377  lp.changeLhs(i, -infinity);
2378  ++chgLRhs;
2379  }
2380  else
2381  ++keptLRhs;
2382  }
2383  if (redundantRhs)
2384  {
2385  // no lhs for constraint i OR redundant lhs
2386  if ((lp.lhs(i) <= -infinity) || redundantLhs || (!m_keepbounds))
2387  {
2388  lp.changeRhs(i, infinity);
2389  ++chgLRhs;
2390  }
2391  else
2392  ++keptLRhs;
2393  }
2394 #endif
2395 
2396  // 3. infeasible constraint
2397  if (LTrel(lp.rhs(i), lp.lhs(i), feastol()) ||
2398  (LTrel(rhsBnd, lp.lhs(i), feastol()) && rhsCnt == 0) ||
2399  (GTrel(lhsBnd, lp.rhs(i), feastol()) && lhsCnt == 0))
2400  {
2401  MSG_DEBUG( (*spxout) << "IMAISM19 row " << std::setprecision(20) << i
2402  << ": infeasible -> lhs=" << lp.lhs(i)
2403  << " rhs=" << lp.rhs(i)
2404  << " lhsBnd=" << lhsBnd
2405  << " rhsBnd=" << rhsBnd
2406  << std::endl; )
2407  return INFEASIBLE;
2408  }
2409 
2410 #if FREE_CONSTRAINT
2411  // 4. unconstrained constraint
2412  if (lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
2413  {
2414  MSG_DEBUG( (*spxout) << "IMAISM20 row " << i
2415  << ": unconstrained -> removed" << std::endl; )
2416 
2417  FreeConstraintPS* FreeConstraintPSptr = 0;
2418  spx_alloc(FreeConstraintPSptr);
2419  m_hist.append(new (FreeConstraintPSptr) FreeConstraintPS(lp, i));
2420 
2421  ++remRows;
2422  remNzos += row.size();
2423  removeRow(lp, i);
2424 
2425  ++m_stat[FREE_ROW];
2426 
2427  continue;
2428  }
2429 #endif
2430 
2431 #if EMPTY_CONSTRAINT
2432  // 5. empty constraint
2433  if (row.size() == 0)
2434  {
2435  MSG_DEBUG( (*spxout) << "IMAISM21 row " << i
2436  << ": empty ->"; )
2437 
2438  if (LT(lp.rhs(i), 0.0, feastol()) || GT(lp.lhs(i), 0.0, feastol()))
2439  {
2440  MSG_DEBUG( (*spxout) << " infeasible lhs=" << lp.lhs(i)
2441  << " rhs=" << lp.rhs(i) << std::endl; )
2442  return INFEASIBLE;
2443  }
2444  MSG_DEBUG( (*spxout) << " removed" << std::endl; )
2445 
2446  EmptyConstraintPS* EmptyConstraintPSptr = 0;
2447  spx_alloc(EmptyConstraintPSptr);
2448  m_hist.append(new (EmptyConstraintPSptr) EmptyConstraintPS(lp, i));
2449 
2450  ++remRows;
2451  removeRow(lp, i);
2452 
2453  ++m_stat[EMPTY_ROW];
2454 
2455  continue;
2456  }
2457 #endif
2458 
2459 #if ROW_SINGLETON
2460  // 6. row singleton
2461  if (row.size() == 1)
2462  {
2463  removeRowSingleton(lp, row, i);
2464  continue;
2465  }
2466 #endif
2467 
2468 #if FORCE_CONSTRAINT
2469  // 7. forcing constraint (postsolving)
2470  // fix variables to obtain the upper bound on constraint value
2471  if (rhsCnt == 0 && EQrel(rhsBnd, lp.lhs(i), feastol()))
2472  {
2473  MSG_DEBUG( (*spxout) << "IMAISM24 row " << i
2474  << ": forcing constraint fix on lhs ->"
2475  << " lhs=" << lp.lhs(i)
2476  << " rhsBnd=" << rhsBnd
2477  << std::endl; )
2478 
2479  DataArray<bool> fixedCol(row.size());
2480  DataArray<Real> lowers(row.size());
2481  DataArray<Real> uppers(row.size());
2482 
2483  for(int k = 0; k < row.size(); ++k)
2484  {
2485  Real aij = row.value(k);
2486  int j = row.index(k);
2487 
2488  fixedCol[k] = !(EQrel(lp.upper(j), lp.lower(j), m_epsilon));
2489 
2490  lowers[k] = lp.lower(j);
2491  uppers[k] = lp.upper(j);
2492 
2493  ASSERT_WARN( "WMAISM25", isNotZero(aij, 1.0 /infinity) );
2494 
2495  if (aij > 0.0)
2496  lp.changeLower(j, lp.upper(j));
2497  else
2498  lp.changeUpper(j, lp.lower(j));
2499  }
2500 
2501  ForceConstraintPS* ForceConstraintPSptr = 0;
2502  spx_alloc(ForceConstraintPSptr);
2503  m_hist.append(new (ForceConstraintPSptr) ForceConstraintPS(lp, i, true, fixedCol, lowers, uppers));
2504 
2505  ++remRows;
2506  remNzos += row.size();
2507  removeRow(lp, i);
2508 
2509  ++m_stat[FORCE_ROW];
2510 
2511  continue;
2512  }
2513  // fix variables to obtain the lower bound on constraint value
2514  if (lhsCnt == 0 && EQrel(lhsBnd, lp.rhs(i), feastol()))
2515  {
2516  MSG_DEBUG( (*spxout) << "IMAISM26 row " << i
2517  << ": forcing constraint fix on rhs ->"
2518  << " rhs=" << lp.rhs(i)
2519  << " lhsBnd=" << lhsBnd
2520  << std::endl; )
2521 
2522  DataArray<bool> fixedCol(row.size());
2523  DataArray<Real> lowers(row.size());
2524  DataArray<Real> uppers(row.size());
2525 
2526  for(int k = 0; k < row.size(); ++k)
2527  {
2528  Real aij = row.value(k);
2529  int j = row.index(k);
2530 
2531  fixedCol[k] = !(EQrel(lp.upper(j), lp.lower(j), m_epsilon));
2532 
2533  lowers[k] = lp.lower(j);
2534  uppers[k] = lp.upper(j);
2535 
2536  ASSERT_WARN( "WMAISM27", isNotZero(aij, 1.0 / infinity) );
2537 
2538  if (aij > 0.0)
2539  lp.changeUpper(j, lp.lower(j));
2540  else
2541  lp.changeLower(j, lp.upper(j));
2542  }
2543 
2544  ForceConstraintPS* ForceConstraintPSptr = 0;
2545  spx_alloc(ForceConstraintPSptr);
2546  m_hist.append(new (ForceConstraintPSptr) ForceConstraintPS(lp, i, false, fixedCol, lowers, uppers));
2547 
2548  ++remRows;
2549  remNzos += row.size();
2550  removeRow(lp, i);
2551 
2552  ++m_stat[FORCE_ROW];
2553 
2554  continue;
2555  }
2556 #endif
2557  }
2558 
2559  assert(remRows > 0 || remNzos == 0);
2560 
2561  if (remRows + chgLRhs + chgBnds > 0)
2562  {
2563  m_remRows += remRows;
2564  m_remNzos += remNzos;
2565  m_chgLRhs += chgLRhs;
2566  m_chgBnds += chgBnds;
2567  m_keptBnds += keptBnds;
2568  m_keptLRhs += keptLRhs;
2569 
2570  MSG_INFO2( (*spxout), (*spxout) << "Simplifier (rows) removed "
2571  << remRows << " rows, "
2572  << remNzos << " non-zeros, "
2573  << chgBnds << " col bounds, "
2574  << chgLRhs << " row bounds; kept "
2575  << keptBnds << " column bounds, "
2576  << keptLRhs << " row bounds"
2577  << std::endl; )
2578  if( remRows > m_minReduction * oldRows )
2579  again = true;
2580  }
2581  return OKAY;
2582 }
2583 
2585 {
2586 
2587  // This method simplifies the columns of the LP.
2588  //
2589  // The following operations are done:
2590  // 1. detect empty columns and fix corresponding variables
2591  // 2. detect variables that are unconstrained from below or above
2592  // and fix corresponding variables or remove involved constraints
2593  // 3. fix variables
2594  // 4. use column singleton variables with zero objective to adjust constraint bounds
2595  // 5. free column singleton combined with doubleton equation are
2596  // used to make the column singleton variable free
2597  // 6. substitute (implied) free column singletons
2598 
2599  int remRows = 0;
2600  int remCols = 0;
2601  int remNzos = 0;
2602  int chgBnds = 0;
2603 
2604  int oldCols = lp.nCols();
2605  int oldRows = lp.nRows();
2606 
2607  for(int j = lp.nCols()-1; j >= 0; --j)
2608  {
2609  const SVector& col = lp.colVector(j);
2610 
2611  // infeasible bounds
2612  if (GTrel(lp.lower(j), lp.upper(j), feastol()))
2613  {
2614  MSG_DEBUG( (*spxout) << "IMAISM29 col " << j
2615  << ": infeasible bounds on x" << j
2616  << " -> lower=" << lp.lower(j)
2617  << " upper=" << lp.upper(j)
2618  << std::endl; )
2619  return INFEASIBLE;
2620  }
2621 
2622  // 1. empty column
2623  if (col.size() == 0)
2624  {
2625 #if EMPTY_COLUMN
2626  MSG_DEBUG( (*spxout) << "IMAISM30 col " << j
2627  << ": empty -> maxObj=" << lp.maxObj(j)
2628  << " lower=" << lp.lower(j)
2629  << " upper=" << lp.upper(j); )
2630 
2631  Real val;
2632 
2633  if (GT(lp.maxObj(j), 0.0, epsZero()))
2634  {
2635  if (lp.upper(j) >= infinity)
2636  {
2637  MSG_DEBUG( (*spxout) << " unbounded" << std::endl; )
2638  return UNBOUNDED;
2639  }
2640  val = lp.upper(j);
2641  }
2642  else if (LT(lp.maxObj(j), 0.0, epsZero()))
2643  {
2644  if (lp.lower(j) <= -infinity)
2645  {
2646  MSG_DEBUG( (*spxout) << " unbounded" << std::endl; )
2647  return UNBOUNDED;
2648  }
2649  val = lp.lower(j);
2650  }
2651  else
2652  {
2653  assert(isZero(lp.maxObj(j), epsZero()));
2654  // any value within the bounds is ok
2655  if (lp.lower(j) > -infinity)
2656  val = lp.lower(j);
2657  else if (lp.upper(j) < infinity)
2658  val = lp.upper(j);
2659  else
2660  val = 0.0;
2661  }
2662  MSG_DEBUG( (*spxout) << " removed" << std::endl; )
2663 
2664  FixBoundsPS* FixBoundsPSptr = 0;
2665  FixVariablePS* FixVariablePSptr = 0;
2666  spx_alloc(FixBoundsPSptr);
2667  spx_alloc(FixVariablePSptr);
2668  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j, val));
2669  m_hist.append(new (FixVariablePSptr) FixVariablePS(lp, *this, j, val));
2670 
2671  ++remCols;
2672  removeCol(lp, j);
2673 
2674  ++m_stat[EMPTY_COL];
2675 
2676  continue;
2677 #endif
2678  }
2679 
2680  if (NErel(lp.lower(j), lp.upper(j), feastol()))
2681  {
2682  // will be set to false if any constraint implies a bound on the variable
2683  bool loFree = true;
2684  bool upFree = true;
2685 
2686  // 1. fix and remove variables
2687  for(int k = 0; k < col.size(); ++k)
2688  {
2689  if (!loFree && !upFree)
2690  break;
2691 
2692  int i = col.index(k);
2693 
2694  // warn since this unhandled case may slip through unnoticed otherwise
2695  ASSERT_WARN( "WMAISM31", isNotZero(col.value(k), 1.0 / infinity) );
2696 
2697  if (col.value(k) > 0.0)
2698  {
2699  if (lp.rhs(i) < infinity)
2700  upFree = false;
2701 
2702  if (lp.lhs(i) > -infinity)
2703  loFree = false;
2704  }
2705  else if (col.value(k) < 0.0)
2706  {
2707  if (lp.rhs(i) < infinity)
2708  loFree = false;
2709 
2710  if (lp.lhs(i) > -infinity)
2711  upFree = false;
2712  }
2713  }
2714 
2715  // 2. detect variables that are unconstrained from below or above
2716  // max 3 x
2717  // s.t. 5 x >= 8
2718  if (GT(lp.maxObj(j), 0.0, epsZero()) && upFree)
2719  {
2720 #if FIX_VARIABLE
2721  MSG_DEBUG( (*spxout) << "IMAISM32 col " << j
2722  << ": x" << j
2723  << " unconstrained above ->"; )
2724 
2725  if (lp.upper(j) >= infinity)
2726  {
2727  MSG_DEBUG( (*spxout) << " unbounded" << std::endl; )
2728 
2729  return UNBOUNDED;
2730  }
2731  MSG_DEBUG( (*spxout) << " fixed at upper=" << lp.upper(j) << std::endl; )
2732 
2733  FixBoundsPS* FixBoundsPSptr = 0;
2734  spx_alloc(FixBoundsPSptr);
2735  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j, lp.upper(j)));
2736  lp.changeLower(j, lp.upper(j));
2737  }
2738  // max -3 x
2739  // s.t. 5 x <= 8
2740  else if (LT(lp.maxObj(j), 0.0, epsZero()) && loFree)
2741  {
2742  MSG_DEBUG( (*spxout) << "IMAISM33 col " << j
2743  << ": x" << j
2744  << " unconstrained below ->"; )
2745 
2746  if (lp.lower(j) <= -infinity)
2747  {
2748  MSG_DEBUG( (*spxout) << " unbounded" << std::endl; )
2749 
2750  return UNBOUNDED;
2751  }
2752  MSG_DEBUG( (*spxout) << " fixed at lower=" << lp.lower(j) << std::endl; )
2753 
2754  FixBoundsPS* FixBoundsPSptr = 0;
2755  spx_alloc(FixBoundsPSptr);
2756  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j, lp.lower(j)));
2757  lp.changeUpper(j, lp.lower(j));
2758 #endif
2759  }
2760  else if (isZero(lp.maxObj(j), epsZero()))
2761  {
2762 #if FREE_ZERO_OBJ_VARIABLE
2763  bool unconstrained_below = loFree && lp.lower(j) <= -infinity;
2764  bool unconstrained_above = upFree && lp.upper(j) >= infinity;
2765 
2766  if (unconstrained_below || unconstrained_above)
2767  {
2768  MSG_DEBUG( (*spxout) << "IMAISM34 col " << j
2769  << ": x" << j
2770  << " unconstrained "
2771  << (unconstrained_below ? "below" : "above")
2772  << " with zero objective (" << lp.maxObj(j)
2773  << ")" << std::endl; )
2774 
2775  SVector col_idx_sorted(col);
2776 
2777  // sort col elements by increasing idx
2778  IdxCompare compare;
2779  SPxQuicksort(col_idx_sorted.mem(), col_idx_sorted.size(), compare);
2780 
2781  FreeZeroObjVariablePS* FreeZeroObjVariablePSptr = 0;
2782  spx_alloc(FreeZeroObjVariablePSptr);
2783  m_hist.append(new (FreeZeroObjVariablePSptr) FreeZeroObjVariablePS(lp, j, unconstrained_below, col_idx_sorted));
2784 
2785  // we have to remove the rows with larger idx first, because otherwise the rows are reorder and indices
2786  // are out-of-date
2787  remRows += col.size();
2788  for(int k = col_idx_sorted.size()-1; k >= 0; --k)
2789  removeRow(lp, col_idx_sorted.index(k));
2790 
2791  // remove column
2792  removeCol(lp, j);
2793 
2794  // statistics
2795  for(int k = 0; k < col.size(); ++k)
2796  {
2797  int l = col.index(k);
2798  remNzos += lp.rowVector(l).size();
2799  }
2800 
2801  ++m_stat[FREE_ZOBJ_COL];
2802  ++remCols;
2803 
2804  continue;
2805  }
2806 #endif
2807  }
2808  }
2809 
2810 #if FIX_VARIABLE
2811  // 3. fix variable
2812  if (EQrel(lp.lower(j), lp.upper(j), feastol()))
2813  {
2814  MSG_DEBUG( (*spxout) << "IMAISM36 col " << j
2815  << ": x" << j
2816  << " fixed -> lower=" << lp.lower(j)
2817  << " upper=" << lp.upper(j) << std::endl; )
2818 
2819  fixColumn(lp, j);
2820 
2821  ++remCols;
2822  remNzos += col.size();
2823  removeCol(lp, j);
2824 
2825  ++m_stat[FIX_COL];
2826 
2827  continue;
2828  }
2829 #endif
2830 
2831  // handle column singletons
2832  if (col.size() == 1)
2833  {
2834  Real aij = col.value(0);
2835  int i = col.index(0);
2836 
2837  // 4. column singleton with zero objective
2838  if (isZero(lp.maxObj(j), epsZero()))
2839  {
2840 #if ZERO_OBJ_COL_SINGLETON
2841  MSG_DEBUG( (*spxout) << "IMAISM37 col " << j
2842  << ": singleton in row " << i
2843  << " with zero objective"; )
2844 
2845  Real lhs = -infinity;
2846  Real rhs = +infinity;
2847 
2848  if (GT(aij, 0.0, epsZero()))
2849  {
2850  if (lp.lhs(i) > -infinity && lp.upper(j) < infinity)
2851  lhs = lp.lhs(i) - aij * lp.upper(j);
2852  if (lp.rhs(i) < infinity && lp.lower(j) > -infinity)
2853  rhs = lp.rhs(i) - aij * lp.lower(j);
2854  }
2855  else if (LT(aij, 0.0, epsZero()))
2856  {
2857  if (lp.lhs(i) > -infinity && lp.lower(j) > -infinity)
2858  lhs = lp.lhs(i) - aij * lp.lower(j);
2859  if (lp.rhs(i) < infinity && lp.upper(j) < infinity)
2860  rhs = lp.rhs(i) - aij * lp.upper(j);
2861  }
2862  else
2863  {
2864  lhs = lp.lhs(i);
2865  rhs = lp.rhs(i);
2866  }
2867 
2868  if (isZero(lhs, epsZero()))
2869  lhs = 0.0;
2870  if (isZero(rhs, epsZero()))
2871  rhs = 0.0;
2872 
2873  MSG_DEBUG( (*spxout) << " removed -> lhs=" << lhs
2874  << " (" << lp.lhs(i)
2875  << ") rhs=" << rhs
2876  << " (" << lp.rhs(i)
2877  << ")" << std::endl; )
2878 
2879  ZeroObjColSingletonPS* ZeroObjColSingletonPSptr = 0;
2880  spx_alloc(ZeroObjColSingletonPSptr);
2881  m_hist.append(new (ZeroObjColSingletonPSptr) ZeroObjColSingletonPS(lp, *this, j, i));
2882 
2883  lp.changeRange(i, lhs, rhs);
2884 
2885  ++remCols;
2886  ++remNzos;
2887  removeCol(lp, j);
2888 
2890 
2891  if (lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
2892  {
2893  FreeConstraintPS* FreeConstraintPSptr = 0;
2894  spx_alloc(FreeConstraintPSptr);
2895  m_hist.append(new (FreeConstraintPSptr) FreeConstraintPS(lp, i));
2896 
2897  ++remRows;
2898  removeRow(lp, i);
2899 
2900  ++m_stat[FREE_ROW];
2901  }
2902 
2903  continue;
2904 #endif
2905  }
2906 
2907  // 5. not free column singleton combined with doubleton equation
2908  else if (EQrel(lp.lhs(i), lp.rhs(i), feastol()) &&
2909  lp.rowVector(i).size() == 2 &&
2910  (lp.lower(j) > -infinity || lp.upper(j) < infinity))
2911  {
2912 #if DOUBLETON_EQUATION
2913  MSG_DEBUG( (*spxout) << "IMAISM38 col " << j
2914  << ": singleton in row " << i
2915  << " with doubleton equation ->"; )
2916 
2917  Real lhs = lp.lhs(i);
2918 
2919  const SVector& row = lp.rowVector(i);
2920 
2921  Real aik;
2922  int k;
2923 
2924  if (row.index(0) == j)
2925  {
2926  aik = row.value(1);
2927  k = row.index(1);
2928  }
2929  else if (row.index(1) == j)
2930  {
2931  aik = row.value(0);
2932  k = row.index(0);
2933  }
2934  else
2935  throw SPxInternalCodeException("XMAISM11 This should never happen.");
2936 
2937  ASSERT_WARN( "WMAISM39", isNotZero(aik, 1.0 / infinity) );
2938 
2939  Real lo, up;
2940  Real oldLower = lp.lower(k);
2941  Real oldUpper = lp.upper(k);
2942 
2943  Real scale1 = maxAbs(lhs, aij * lp.upper(j));
2944  Real scale2 = maxAbs(lhs, aij * lp.lower(j));
2945 
2946  if (scale1 < 1.0)
2947  scale1 = 1.0;
2948  if (scale2 < 1.0)
2949  scale2 = 1.0;
2950 
2951  Real z1 = (lhs / scale1) - (aij * lp.upper(j) / scale1);
2952  Real z2 = (lhs / scale2) - (aij * lp.lower(j) / scale2);
2953 
2954  if (isZero(z1, epsZero()))
2955  z1 = 0.0;
2956  if (isZero(z2, epsZero()))
2957  z2 = 0.0;
2958 
2959  if (GT(aij * aik, 0.0, epsZero()))
2960  {
2961  lo = (lp.upper(j) >= infinity) ? -infinity : z1 * scale1 / aik;
2962  up = (lp.lower(j) <= -infinity) ? infinity : z2 * scale2 / aik;
2963  }
2964  else if (LT(aij * aik, 0.0, epsZero()))
2965  {
2966  lo = (lp.lower(j) <= -infinity) ? -infinity : z2 * scale2 / aik;
2967  up = (lp.upper(j) >= infinity) ? infinity : z1 * scale1 / aik;
2968  }
2969  else
2970  throw SPxInternalCodeException("XMAISM12 This should never happen.");
2971 
2972  if (GTrel(lo, lp.lower(k), epsZero()))
2973  lp.changeLower(k, lo);
2974 
2975  if (LTrel(up, lp.upper(k), epsZero()))
2976  lp.changeUpper(k, up);
2977 
2978  MSG_DEBUG( (*spxout) << " made free, bounds on x" << k
2979  << ": lower=" << lp.lower(k)
2980  << " (" << oldLower
2981  << ") upper=" << lp.upper(k)
2982  << " (" << oldUpper
2983  << ")" << std::endl; )
2984 
2985  // infeasible bounds
2986  if (GTrel(lp.lower(k), lp.upper(k), feastol()))
2987  {
2988  MSG_DEBUG( (*spxout) << "new bounds are infeasible"
2989  << std::endl; )
2990  return INFEASIBLE;
2991  }
2992 
2993  DoubletonEquationPS* DoubletonEquationPSptr = 0;
2994  spx_alloc(DoubletonEquationPSptr);
2995  m_hist.append(new (DoubletonEquationPSptr) DoubletonEquationPS(lp, j, k, i, oldLower, oldUpper));
2996 
2997  if (lp.lower(j) > -infinity && lp.upper(j) < infinity)
2998  chgBnds += 2;
2999  else
3000  ++chgBnds;
3001 
3002  lp.changeBounds(j, -infinity, infinity);
3003 
3004  ++m_stat[DOUBLETON_ROW];
3005 #endif
3006  }
3007 
3008  // 6. (implied) free column singleton
3009  if (lp.lower(j) <= -infinity && lp.upper(j) >= infinity)
3010  {
3011 #if FREE_COL_SINGLETON
3012  Real slackVal = lp.lhs(i);
3013 
3014  // constraint i is an inequality constraint -> transform into equation type
3015  if (NErel(lp.lhs(i), lp.rhs(i), feastol()))
3016  {
3017  MSG_DEBUG( (*spxout) << "IMAISM40 col " << j
3018  << ": free singleton in inequality constraint" << std::endl; )
3019 
3020  // do nothing if constraint i is unconstrained
3021  if (lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
3022  continue;
3023 
3024  // introduce slack variable to obtain equality constraint
3025  Real sMaxObj = lp.maxObj(j) / aij; // after substituting variable j in objective
3026  Real sLo = lp.lhs(i);
3027  Real sUp = lp.rhs(i);
3028 
3029  if (GT(sMaxObj, 0.0, epsZero()))
3030  {
3031  if (sUp >= infinity)
3032  {
3033  MSG_DEBUG( (*spxout) << " -> problem unbounded" << std::endl; )
3034  return UNBOUNDED;
3035  }
3036  slackVal = sUp;
3037  }
3038  else if (LT(sMaxObj, 0.0, epsZero()))
3039  {
3040  if (sLo <= -infinity)
3041  {
3042  MSG_DEBUG( (*spxout) << " -> problem unbounded" << std::endl; )
3043  return UNBOUNDED;
3044  }
3045  slackVal = sLo;
3046  }
3047  else
3048  {
3049  assert(isZero(sMaxObj, epsZero()));
3050  // any value within the bounds is ok
3051  if (sLo > -infinity)
3052  slackVal = sLo;
3053  else if (sUp < infinity)
3054  slackVal = sUp;
3055  else
3056  throw SPxInternalCodeException("XMAISM13 This should never happen.");
3057  }
3058  }
3059 
3060  FreeColSingletonPS* FreeColSingletonPSptr = 0;
3061  spx_alloc(FreeColSingletonPSptr);
3062  m_hist.append(new (FreeColSingletonPSptr) FreeColSingletonPS(lp, *this, j, i, slackVal));
3063 
3064  MSG_DEBUG( (*spxout) << "IMAISM41 col " << j
3065  << ": free singleton removed" << std::endl; )
3066 
3067  const SVector& row = lp.rowVector(i);
3068 
3069  for (int h = 0; h < row.size(); ++h)
3070  {
3071  int k = row.index(h);
3072 
3073  if (k != j)
3074  {
3075  Real new_obj = lp.obj(k) - (lp.obj(j) * row.value(h) / aij);
3076  lp.changeObj(k, new_obj);
3077  }
3078  }
3079 
3080  ++remRows;
3081  ++remCols;
3082  remNzos += row.size();
3083  removeRow(lp, i);
3084  removeCol(lp, j);
3085 
3087 
3088  continue;
3089 #endif
3090  }
3091  }
3092  }
3093 
3094  if (remCols + remRows > 0)
3095  {
3096  m_remRows += remRows;
3097  m_remCols += remCols;
3098  m_remNzos += remNzos;
3099  m_chgBnds += chgBnds;
3100 
3101  MSG_INFO2( (*spxout), (*spxout) << "Simplifier (columns) removed "
3102  << remRows << " rows, "
3103  << remCols << " cols, "
3104  << remNzos << " non-zeros, "
3105  << chgBnds << " col bounds"
3106  << std::endl; )
3107  if( remCols + remRows > m_minReduction * (oldCols + oldRows) )
3108  again = true;
3109  }
3110  return OKAY;
3111 }
3112 
3114 {
3115 
3116  // This method simplifies LP using the following dual structures:
3117  //
3118  // 1. dominated columns
3119  // 2. weakly dominated columns
3120  //
3121  // For constructing the dual variables, it is assumed that the objective sense is max
3122 
3123  int remRows = 0;
3124  int remCols = 0;
3125  int remNzos = 0;
3126 
3127  int oldRows = lp.nRows();
3128  int oldCols = lp.nCols();
3129 
3130  DataArray<bool> colSingleton(lp.nCols());
3131  DVector dualVarLo(lp.nRows());
3132  DVector dualVarUp(lp.nRows());
3133  DVector dualConsLo(lp.nCols());
3134  DVector dualConsUp(lp.nCols());
3135 
3136  // init
3137  for(int i = lp.nRows()-1; i >= 0; --i)
3138  {
3139  // check for unconstrained constraints
3140  if (lp.lhs(i) <= -infinity && lp.rhs(i) >= infinity)
3141  {
3142  MSG_DEBUG( (*spxout) << "IMAISM43 row " << i
3143  << ": unconstrained" << std::endl; )
3144 
3145  FreeConstraintPS* FreeConstraintPSptr = 0;
3146  spx_alloc(FreeConstraintPSptr);
3147  m_hist.append(new (FreeConstraintPSptr) FreeConstraintPS(lp, i));
3148 
3149  ++remRows;
3150  remNzos += lp.rowVector(i).size();
3151  removeRow(lp, i);
3152 
3153  ++m_stat[FREE_ROW];
3154 
3155  continue;
3156  }
3157 
3158  // corresponds to maximization sense
3159  dualVarLo[i] = (lp.lhs(i) <= -infinity) ? 0.0 : -infinity;
3160  dualVarUp[i] = (lp.rhs(i) >= infinity) ? 0.0 : infinity;
3161  }
3162 
3163  // compute bounds on the dual variables using column singletons
3164  for(int j = 0; j < lp.nCols(); ++j)
3165  {
3166  if (lp.colVector(j).size() == 1)
3167  {
3168  int i = lp.colVector(j).index(0);
3169  Real aij = lp.colVector(j).value(0);
3170 
3171  ASSERT_WARN( "WMAISM44", isNotZero(aij, 1.0 / infinity) );
3172 
3173  Real bound = lp.maxObj(j) / aij;
3174 
3175  if (aij > 0)
3176  {
3177  if (lp.lower(j) <= -infinity && bound < dualVarUp[i])
3178  dualVarUp[i] = bound;
3179  if (lp.upper(j) >= infinity && bound > dualVarLo[i])
3180  dualVarLo[i] = bound;
3181  }
3182  else if (aij < 0)
3183  {
3184  if (lp.lower(j) <= -infinity && bound > dualVarLo[i])
3185  dualVarLo[i] = bound;
3186  if (lp.upper(j) >= infinity && bound < dualVarUp[i])
3187  dualVarUp[i] = bound;
3188  }
3189  }
3190 
3191  }
3192 
3193  // compute bounds on the dual constraints
3194  for(int j = 0; j < lp.nCols(); ++j)
3195  {
3196  dualConsLo[j] = dualConsUp[j] = 0.0;
3197 
3198  const SVector& col = lp.colVector(j);
3199 
3200  for(int k = 0; k < col.size(); ++k)
3201  {
3202  if (dualConsLo[j] <= -infinity && dualConsUp[j] >= infinity)
3203  break;
3204 
3205  Real aij = col.value(k);
3206  int i = col.index(k);
3207 
3208  ASSERT_WARN( "WMAISM45", isNotZero(aij, 1.0 / infinity) );
3209 
3210  if (aij > 0)
3211  {
3212  if (dualVarLo[i] <= -infinity)
3213  dualConsLo[j] = -infinity;
3214  else
3215  dualConsLo[j] += aij * dualVarLo[i];
3216 
3217  if (dualVarUp[i] >= infinity)
3218  dualConsUp[j] = infinity;
3219  else
3220  dualConsUp[j] += aij * dualVarUp[i];
3221  }
3222  else if (aij < 0)
3223  {
3224  if (dualVarLo[i] <= -infinity)
3225  dualConsUp[j] = infinity;
3226  else
3227  dualConsUp[j] += aij * dualVarLo[i];
3228 
3229  if (dualVarUp[i] >= infinity)
3230  dualConsLo[j] = -infinity;
3231  else
3232  dualConsLo[j] += aij * dualVarUp[i];
3233  }
3234  }
3235  }
3236 
3237  for(int j = lp.nCols()-1; j >= 0; --j)
3238  {
3239  if (lp.colVector(j).size() <= 1)
3240  continue;
3241 
3242  // dual infeasibility checks
3243  if (LTrel(dualConsUp[j], dualConsLo[j], opttol()))
3244  {
3245  MSG_DEBUG( (*spxout) << "IMAISM46 col " << j
3246  << ": dual infeasible -> dual lhs bound=" << dualConsLo[j]
3247  << " dual rhs bound=" << dualConsUp[j] << std::endl; )
3248  return DUAL_INFEASIBLE;
3249  }
3250 
3251  Real obj = lp.maxObj(j);
3252 
3253  // 1. dominated column
3254  // Is the problem really unbounded in the cases below ??? Or is only dual infeasibility be shown
3255  if (GTrel(obj, dualConsUp[j], opttol()))
3256  {
3257 #if DOMINATED_COLUMN
3258  MSG_DEBUG( (*spxout) << "IMAISM47 col " << j
3259  << ": dominated -> maxObj=" << obj
3260  << " dual rhs bound=" << dualConsUp[j] << std::endl; )
3261 
3262  if (lp.upper(j) >= infinity)
3263  {
3264  MSG_INFO2( (*spxout), (*spxout) << " unbounded" << std::endl; )
3265  return UNBOUNDED;
3266  }
3267 
3268  MSG_DEBUG( (*spxout) << " fixed at upper=" << lp.upper(j) << std::endl; )
3269 
3270  FixBoundsPS* FixBoundsPSptr = 0;
3271  spx_alloc(FixBoundsPSptr);
3272  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j, lp.upper(j)));
3273  lp.changeLower(j, lp.upper(j));
3274 
3275  ++m_stat[DOMINATED_COL];
3276 #endif
3277  }
3278  else if (LTrel(obj, dualConsLo[j], opttol()))
3279  {
3280 #if DOMINATED_COLUMN
3281  MSG_DEBUG( (*spxout) << "IMAISM48 col " << j
3282  << ": dominated -> maxObj=" << obj
3283  << " dual lhs bound=" << dualConsLo[j] << std::endl; )
3284 
3285  if (lp.lower(j) <= -infinity)
3286  {
3287  MSG_INFO2( (*spxout), (*spxout) << " unbounded" << std::endl; )
3288  return UNBOUNDED;
3289  }
3290 
3291  MSG_DEBUG( (*spxout) << " fixed at lower=" << lp.lower(j) << std::endl; )
3292 
3293  FixBoundsPS* FixBoundsPSptr = 0;
3294  spx_alloc(FixBoundsPSptr);
3295  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j, lp.lower(j)));
3296  lp.changeUpper(j, lp.lower(j));
3297 
3298  ++m_stat[DOMINATED_COL];
3299 #endif
3300  }
3301 
3302  // 2. weakly dominated column (no postsolving)
3303  else if (lp.upper(j) < infinity && EQrel(obj, dualConsUp[j], opttol()))
3304  {
3305 #if WEAKLY_DOMINATED_COLUMN
3306  MSG_DEBUG( (*spxout) << "IMAISM49 col " << j
3307  << ": weakly dominated -> maxObj=" << obj
3308  << " dual rhs bound=" << dualConsUp[j] << std::endl; )
3309 
3310  FixBoundsPS* FixBoundsPSptr = 0;
3311  spx_alloc(FixBoundsPSptr);
3312  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j, lp.upper(j)));
3313  lp.changeLower(j, lp.upper(j));
3314 
3316 #endif
3317  }
3318  else if (lp.lower(j) > -infinity && EQrel(obj, dualConsLo[j], opttol()))
3319  {
3320 #if WEAKLY_DOMINATED_COLUMN
3321  MSG_DEBUG( (*spxout) << "IMAISM50 col " << j
3322  << ": weakly dominated -> maxObj=" << obj
3323  << " dual lhs bound=" << dualConsLo[j] << std::endl; )
3324 
3325  FixBoundsPS* FixBoundsPSptr = 0;
3326  spx_alloc(FixBoundsPSptr);
3327  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j, lp.lower(j)));
3328  lp.changeUpper(j, lp.lower(j));
3329 
3331 #endif
3332  }
3333 
3334  // fix column
3335  if (EQrel(lp.lower(j), lp.upper(j), feastol()))
3336  {
3337 #if FIX_VARIABLE
3338  fixColumn(lp, j);
3339 
3340  ++remCols;
3341  remNzos += lp.colVector(j).size();
3342  removeCol(lp, j);
3343 
3344  ++m_stat[FIX_COL];
3345 #endif
3346  }
3347  }
3348 
3349 
3350  assert(remRows > 0 || remCols > 0 || remNzos == 0);
3351 
3352  if (remCols + remRows > 0)
3353  {
3354  m_remRows += remRows;
3355  m_remCols += remCols;
3356  m_remNzos += remNzos;
3357 
3358  MSG_INFO2( (*spxout), (*spxout) << "Simplifier (dual) removed "
3359  << remRows << " rows, "
3360  << remCols << " cols, "
3361  << remNzos << " non-zeros"
3362  << std::endl; )
3363  if( remCols + remRows > m_minReduction * (oldCols + oldRows) )
3364  again = true;
3365  }
3366  return OKAY;
3367 }
3368 
3369 
3370 
3372 {
3373  // this simplifier eliminates rows and columns by performing multi aggregations as identified by the constraint
3374  // activities.
3375  int remRows = 0;
3376  int remCols = 0;
3377  int remNzos = 0;
3378 
3379  int oldRows = lp.nRows();
3380  int oldCols = lp.nCols();
3381 
3382  DVector upLocks(lp.nCols());
3383  DVector downLocks(lp.nCols());
3384 
3385  for(int j = lp.nCols()-1; j >= 0; --j)
3386  {
3387  // setting the locks on the variables
3388  upLocks[j] = 0;
3389  downLocks[j] = 0;
3390 
3391  if (lp.colVector(j).size() <= 1)
3392  continue;
3393 
3394  const SVector& col = lp.colVector(j);
3395  for(int k = 0; k < col.size(); ++k)
3396  {
3397  Real aij = col.value(k);
3398 
3399  ASSERT_WARN( "WMAISM45", isNotZero(aij, 1.0 / infinity) );
3400 
3401  if(GT(lp.lhs(col.index(k)), -infinity) && LT(lp.rhs(col.index(k)), infinity))
3402  {
3403  upLocks[j]++;
3404  downLocks[j]++;
3405  }
3406  else if (GT(lp.lhs(col.index(k)), -infinity))
3407  {
3408  if(aij > 0)
3409  downLocks[j]++;
3410  else if (aij < 0)
3411  upLocks[j]++;
3412  }
3413  else if (LT(lp.rhs(col.index(k)), infinity))
3414  {
3415  if(aij > 0)
3416  upLocks[j]++;
3417  else if (aij < 0)
3418  downLocks[j]++;
3419  }
3420  }
3421 
3422  // multi-aggregate column
3423  if (upLocks[j] == 1 || downLocks[j] == 1)
3424  {
3425  Real lower = lp.lower(j);
3426  Real upper = lp.upper(j);
3427  int maxOtherLocks;
3428  int bestpos = -1;
3429  bool bestislhs = true;
3430 
3431 
3432 
3433  for(int k = 0; k < col.size(); ++k)
3434  {
3435  int rowNumber;
3436  Real lhs;
3437  Real rhs;
3438  bool lhsExists;
3439  bool rhsExists;
3440  bool aggLhs;
3441  bool aggRhs;
3442 
3443  Real val = col.value(k);
3444 
3445  rowNumber = col.index(k);
3446  lhs = lp.lhs(rowNumber);
3447  rhs = lp.rhs(rowNumber);
3448 
3449  if( EQ(lhs, rhs, feastol()) )
3450  continue;
3451 
3452  lhsExists = GT(lhs, -infinity);
3453  rhsExists = LT(rhs, infinity);
3454 
3455  if (lp.rowVector(rowNumber).size() <= 2)
3456  maxOtherLocks = INT_MAX;
3457  else if (lp.rowVector(rowNumber).size() == 3)
3458  maxOtherLocks = 3;
3459  else if (lp.rowVector(rowNumber).size() == 4)
3460  maxOtherLocks = 2;
3461  else
3462  maxOtherLocks = 1;
3463 
3464  aggLhs = lhsExists
3465  && ((col.value(k) > 0.0 && lp.maxObj(j) <= 0.0 && downLocks[j] == 1 && upLocks[j] <= maxOtherLocks)
3466  || (col.value(k) < 0.0 && lp.maxObj(j) >= 0.0 && upLocks[j] == 1 && downLocks[j] <= maxOtherLocks));
3467  aggRhs = rhsExists
3468  && ((col.value(k) > 0.0 && lp.maxObj(j) >= 0.0 && upLocks[j] == 1 && downLocks[j] <= maxOtherLocks)
3469  || (col.value(k) < 0.0 && lp.maxObj(j) <= 0.0 && downLocks[j] == 1 && upLocks[j] <= maxOtherLocks));
3470 
3471  if (aggLhs || aggRhs)
3472  {
3473  Real minRes = 0; // this is the minimum value that the aggregation can attain
3474  Real maxRes = 0; // this is the maximum value that the aggregation can attain
3475 
3476  // computing the minimum and maximum residuals if variable j is set to zero.
3477  computeMinMaxResidualActivity(lp, rowNumber, j, minRes, maxRes);
3478 
3479  // we will try to aggregate to the lhs
3480  if (aggLhs)
3481  {
3482  Real minVal;
3483  Real maxVal;
3484 
3485  // computing the values of the upper and lower bounds for the aggregated variables
3486  computeMinMaxValues(lp, lhs, val, minRes, maxRes, minVal, maxVal);
3487 
3488  assert(LE(minVal, maxVal));
3489 
3490  // if the bounds of the aggregation and the original variable are equivalent, then we can reduce
3491  if ((minVal > -infinity && GT(minVal, lower, feastol()))
3492  && (maxVal < infinity && LT(maxVal, upper, feastol())))
3493  {
3494  bestpos = col.index(k);
3495  bestislhs = true;
3496  break;
3497  }
3498  }
3499 
3500  // we will try to aggregate to the rhs
3501  if (aggRhs)
3502  {
3503  Real minVal;
3504  Real maxVal;
3505 
3506  // computing the values of the upper and lower bounds for the aggregated variables
3507  computeMinMaxValues(lp, rhs, val, minRes, maxRes, minVal, maxVal);
3508 
3509  assert(LE(minVal, maxVal));
3510 
3511  if ((minVal > -infinity && GT(minVal, lower, feastol()))
3512  && (maxVal < infinity && LT(maxVal, upper, feastol())))
3513  {
3514  bestpos = col.index(k);
3515  bestislhs = false;
3516  break;
3517  }
3518  }
3519  }
3520  }
3521 
3522  // it is only possible to aggregate if a best position has been found
3523  if( bestpos >= 0 )
3524  {
3525  const SVector& bestRow = lp.rowVector(bestpos);
3526  // aggregating the variable and applying the fixings to the all other constraints
3527  Real aggConstant = (bestislhs ? lp.lhs(bestpos) : lp.rhs(bestpos)); // this is the lhs or rhs of the aggregated row
3528  Real aggAij = bestRow[j]; // this is the coefficient of the deleted col
3529 
3530  MSG_DEBUG(
3531  (*spxout) << "IMAISM51 col " << j
3532  << ": Aggregating row: " << bestpos
3533  << " Aggregation Constant=" << aggConstant
3534  << " Coefficient of aggregated col=" << aggAij << std::endl;
3535  )
3536 
3537  MultiAggregationPS* MultiAggregationPSptr = 0;
3538  spx_alloc(MultiAggregationPSptr);
3539  m_hist.append(new (MultiAggregationPSptr) MultiAggregationPS(lp, *this, bestpos, j, aggConstant));
3540 
3541  for(int k = 0; k < col.size(); ++k)
3542  {
3543  if(col.index(k) != bestpos)
3544  {
3545  int rowNumber = col.index(k);
3546  DVector updateRow(lp.nCols());
3547  Real updateRhs = lp.rhs(col.index(k));
3548  Real updateLhs = lp.lhs(col.index(k));
3549 
3550  updateRow = lp.rowVector(col.index(k));
3551 
3552  // updating the row with the best row
3553  for(int l = 0; l < bestRow.size(); l++)
3554  {
3555  if(bestRow.index(l) != j)
3556  {
3557  if(lp.rowVector(rowNumber).pos(bestRow.index(l)) >= 0)
3558  lp.changeElement(rowNumber, bestRow.index(l), updateRow[bestRow.index(l)]
3559  - updateRow[j]*bestRow.value(l)/aggAij);
3560  else
3561  lp.changeElement(rowNumber, bestRow.index(l), -1.0*updateRow[j]*bestRow.value(l)/aggAij);
3562  }
3563  }
3564 
3565  // NOTE: I don't know whether we should change the LHS and RHS if they are currently at infinity
3566  if(LT(lp.rhs(rowNumber), infinity))
3567  lp.changeRhs(rowNumber, updateRhs - updateRow[j]*aggConstant/aggAij);
3568  if(GT(lp.lhs(rowNumber), -infinity))
3569  lp.changeLhs(rowNumber, updateLhs - updateRow[j]*aggConstant/aggAij);
3570 
3571  assert(LE(lp.lhs(rowNumber), lp.rhs(rowNumber)));
3572  }
3573  }
3574 
3575  for(int l = 0; l < bestRow.size(); l++)
3576  {
3577  if(bestRow.index(l) != j)
3578  lp.changeMaxObj(bestRow.index(l), lp.maxObj(bestRow.index(l)) - lp.maxObj(j)*bestRow.value(l)/aggAij);
3579  }
3580 
3581  ++remCols;
3582  remNzos += lp.colVector(j).size();
3583  removeCol(lp, j);
3584  ++remRows;
3585  remNzos += lp.rowVector(bestpos).size();
3586  removeRow(lp, bestpos);
3587 
3588  ++m_stat[MULTI_AGG];
3589  }
3590  }
3591  }
3592 
3593 
3594  assert(remRows > 0 || remCols > 0 || remNzos == 0);
3595 
3596  if (remCols + remRows > 0)
3597  {
3598  m_remRows += remRows;
3599  m_remCols += remCols;
3600  m_remNzos += remNzos;
3601 
3602  MSG_INFO2( (*spxout), (*spxout) << "Simplifier (multi-aggregation) removed "
3603  << remRows << " rows, "
3604  << remCols << " cols, "
3605  << remNzos << " non-zeros"
3606  << std::endl; )
3607  if( remCols + remRows > m_minReduction * (oldCols + oldRows) )
3608  again = true;
3609  }
3610  return OKAY;
3611 }
3612 
3613 
3614 
3616 {
3617 
3618  // This method simplifies the LP by removing duplicate rows
3619  // Duplicates are detected using the algorithm of Bixby and Wagner [1987]
3620 
3621  // Possible extension: use generalized definition of duplicate rows according to Andersen and Andersen
3622  // However: the resulting sparsification is often very small since the involved rows are usually very sparse
3623 
3624  int remRows = 0;
3625  int remNzos = 0;
3626 
3627  int oldRows = lp.nRows();
3628 
3629  // remove empty rows and columns
3631  if (ret != OKAY)
3632  return ret;
3633 
3634 #if ROW_SINGLETON
3635  int rs_remRows = 0;
3636  for (int i = 0; i < lp.nRows(); ++i)
3637  {
3638  const SVector& row = lp.rowVector(i);
3639 
3640  if (row.size() == 1)
3641  {
3642  removeRowSingleton(lp, row, i);
3643  rs_remRows++;
3644  }
3645  }
3646 
3647  if (rs_remRows > 0)
3648  {
3649  MSG_INFO2( (*spxout), (*spxout) << "Simplifier duplicate rows (row singleton stage) removed "
3650  << rs_remRows << " rows, "
3651  << rs_remRows << " non-zeros"
3652  << std::endl; )
3653  }
3654 #endif
3655 
3656  if (lp.nRows() < 2)
3657  return OKAY;
3658 
3659  DataArray<int> pClass(lp.nRows()); // class of parallel rows
3660  DataArray<int> classSize(lp.nRows()); // size of each class
3661  DataArray<Real> scale(lp.nRows()); // scaling factor for each row
3662  int* idxMem = 0;
3663 
3664  try
3665  {
3666  spx_alloc(idxMem, lp.nRows());
3667  }
3668  catch( const SPxMemoryException& x )
3669  {
3670  spx_free(idxMem);
3671  throw x;
3672  }
3673 
3674  IdxSet idxSet(lp.nRows(), idxMem); // set of feasible indices for new pClass
3675 
3676  // init
3677  pClass[0] = 0;
3678  scale[0] = 0.0;
3679  classSize[0] = lp.nRows();
3680 
3681  for(int i = 1; i < lp.nRows(); ++i)
3682  {
3683  pClass[i] = 0;
3684  scale[i] = 0.0;
3685  classSize[i] = 0;
3686  idxSet.addIdx(i);
3687  }
3688 
3689  Real oldVal = 0.0;
3690 
3691  // main loop
3692  for(int j = 0; j < lp.nCols(); ++j)
3693  {
3694  const SVector& col = lp.colVector(j);
3695 
3696  for(int k = 0; k < col.size(); ++k)
3697  {
3698  Real aij = col.value(k);
3699  int i = col.index(k);
3700 
3701  if (scale[i] == 0.0)
3702  scale[i] = aij;
3703 
3704  m_classSetRows[pClass[i]].add(i, aij / scale[i]);
3705  if (--classSize[pClass[i]] == 0)
3706  idxSet.addIdx(pClass[i]);
3707  }
3708 
3709  // update each parallel class with non-zero column entry
3710  for(int m = 0; m < col.size(); ++m)
3711  {
3712  int k = pClass[col.index(m)];
3713 
3714  if (m_classSetRows[k].size() > 0)
3715  {
3716  // sort classSet[k] w.r.t. scaled column values
3717  ElementCompare compare;
3718 
3719  if (m_classSetRows[k].size() > 1)
3720  SPxQuicksort(m_classSetRows[k].mem(), m_classSetRows[k].size(), compare);
3721 
3722  // use new index first
3723  int classIdx = idxSet.index(0);
3724  idxSet.remove(0);
3725 
3726  for(int l = 0; l < m_classSetRows[k].size(); ++l)
3727  {
3728  if (l != 0 && NErel(m_classSetRows[k].value(l), oldVal, epsZero()))
3729  {
3730  classIdx = idxSet.index(0);
3731  idxSet.remove(0);
3732  }
3733 
3734  pClass[m_classSetRows[k].index(l)] = classIdx;
3735  ++classSize[classIdx];
3736 
3737  oldVal = m_classSetRows[k].value(l);
3738  }
3739 
3740  m_classSetRows[k].clear();
3741  }
3742  }
3743  }
3744 
3745  spx_free(idxMem);
3746 
3747  DataArray<bool> remRow(lp.nRows());
3748 
3749  for(int k = 0; k < lp.nRows(); ++k )
3750  m_dupRows[k].clear();
3751 
3752  for(int k = 0; k < lp.nRows(); ++k)
3753  {
3754  remRow[k] = false;
3755  m_dupRows[pClass[k]].add(k, 0.0);
3756  }
3757 
3758  const int nRowsOld_tmp = lp.nRows();
3759  int* perm_tmp = 0;
3760  spx_alloc(perm_tmp, nRowsOld_tmp);
3761 
3762  for(int j = 0; j < nRowsOld_tmp; ++j)
3763  {
3764  perm_tmp[j] = 0;
3765  }
3766 
3767  int idxFirstDupRows = -1;
3768  int idxLastDupRows = -1;
3769  int numDelRows = 0;
3770 
3771  for(int k = 0; k < lp.nRows(); ++k)
3772  {
3773  if (m_dupRows[k].size() > 1 && !(lp.rowVector(m_dupRows[k].index(0)).size() == 1))
3774  {
3775  idxLastDupRows = k;
3776 
3777  if(idxFirstDupRows < 0)
3778  {
3779  idxFirstDupRows = k;
3780  }
3781 
3782  for(int l = 1; l < m_dupRows[k].size(); ++l)
3783  {
3784  int i = m_dupRows[k].index(l);
3785  perm_tmp[i] = -1;
3786  }
3787 
3788  numDelRows += (m_dupRows[k].size()-1);
3789  }
3790  }
3791 
3792  {
3793  int k_tmp, j_tmp = -1;
3794  for (k_tmp = j_tmp = 0; k_tmp < nRowsOld_tmp; ++k_tmp)
3795  {
3796  if (perm_tmp[k_tmp] >= 0)
3797  perm_tmp[k_tmp] = j_tmp++;
3798  }
3799  }
3800 
3801  // store rhs and lhs changes for combined update
3802  bool doChangeRanges = false;
3803  DVector newLhsVec(lp.lhs());
3804  DVector newRhsVec(lp.rhs());
3805 
3806  for(int k = 0; k < lp.nRows(); ++k)
3807  {
3808  if (m_dupRows[k].size() > 1 && !(lp.rowVector(m_dupRows[k].index(0)).size() == 1))
3809  {
3810  MSG_DEBUG( (*spxout) << "IMAISM53 " << m_dupRows[k].size()
3811  << " duplicate rows found" << std::endl; )
3812 
3813  m_stat[DUPLICATE_ROW] += m_dupRows[k].size()-1;
3814 
3815  // index of one non-column singleton row in dupRows[k]
3816  int rowIdx = -1;
3817  int maxLhsIdx = -1;
3818  int minRhsIdx = -1;
3819  Real maxLhs = -infinity;
3820  Real minRhs = +infinity;
3821 
3822  DataArray<bool> isLhsEqualRhs(m_dupRows[k].size());
3823 
3824  // determine strictest bounds on constraint
3825  for(int l = 0; l < m_dupRows[k].size(); ++l)
3826  {
3827  int i = m_dupRows[k].index(l);
3828  isLhsEqualRhs[l] = (lp.lhs(i) == lp.rhs(i));
3829 
3830  ASSERT_WARN( "WMAISM54", isNotZero(scale[i], 1.0 / infinity) );
3831 
3832  if (rowIdx == -1)
3833  {
3834  rowIdx = i;
3835  maxLhs = lp.lhs(rowIdx);
3836  minRhs = lp.rhs(rowIdx);
3837  }
3838  else
3839  {
3840  Real scaledLhs, scaledRhs;
3841  Real factor = scale[rowIdx] / scale[i];
3842 
3843  if (factor > 0)
3844  {
3845  scaledLhs = (lp.lhs(i) <= -infinity) ? -infinity : lp.lhs(i) * factor;
3846  scaledRhs = (lp.rhs(i) >= infinity) ? infinity : lp.rhs(i) * factor;
3847  }
3848  else
3849  {
3850  scaledLhs = (lp.rhs(i) >= infinity) ? -infinity : lp.rhs(i) * factor;
3851  scaledRhs = (lp.lhs(i) <= -infinity) ? infinity : lp.lhs(i) * factor;
3852  }
3853  if (scaledLhs > maxLhs)
3854  {
3855  maxLhs = scaledLhs;
3856  maxLhsIdx = i;
3857  }
3858  if (scaledRhs < minRhs)
3859  {
3860  minRhs = scaledRhs;
3861  minRhsIdx = i;
3862  }
3863 
3864  remRow[i] = true;
3865  }
3866  }
3867 
3868  if (rowIdx != -1)
3869  {
3870  Real newLhs = (maxLhs > lp.lhs(rowIdx)) ? maxLhs : lp.lhs(rowIdx);
3871  Real newRhs = (minRhs < lp.rhs(rowIdx)) ? minRhs : lp.rhs(rowIdx);
3872 
3873  if(k == idxLastDupRows)
3874  {
3875  DataArray<int> da_perm(nRowsOld_tmp);
3876  for(int j = 0; j < nRowsOld_tmp; ++j)
3877  {
3878  da_perm[j] = perm_tmp[j];
3879  }
3880  DuplicateRowsPS* DuplicateRowsPSptr = 0;
3881  spx_alloc(DuplicateRowsPSptr);
3882  m_hist.append(new (DuplicateRowsPSptr) DuplicateRowsPS(lp, rowIdx, maxLhsIdx, minRhsIdx, m_dupRows[k], scale, da_perm, isLhsEqualRhs, true, EQrel(newLhs, newRhs), k==idxFirstDupRows));
3883  }
3884  else
3885  {
3886  DataArray<int> da_perm_empty(0);
3887  DuplicateRowsPS* DuplicateRowsPSptr = 0;
3888  spx_alloc(DuplicateRowsPSptr);
3889  m_hist.append(new (DuplicateRowsPSptr) DuplicateRowsPS(lp, rowIdx, maxLhsIdx, minRhsIdx, m_dupRows[k], scale, da_perm_empty, isLhsEqualRhs, false, EQrel(newLhs, newRhs), k == idxFirstDupRows));
3890  }
3891 
3892  if (maxLhs > lp.lhs(rowIdx) || minRhs < lp.rhs(rowIdx))
3893  {
3894  // modify lhs and rhs of constraint rowIdx
3895  doChangeRanges = true;
3896 
3897  if (LTrel(newRhs, newLhs, feastol()))
3898  {
3899  MSG_DEBUG( (*spxout) << "IMAISM55 duplicate rows yield infeasible bounds:"
3900  << " lhs=" << newLhs
3901  << " rhs=" << newRhs << std::endl; )
3902  spx_free(perm_tmp);
3903  return INFEASIBLE;
3904  }
3905  // if we accept the infeasibility we should clean up the values to avoid problems later
3906  if( newRhs < newLhs )
3907  newRhs = newLhs;
3908 
3909  newLhsVec[rowIdx] = newLhs;
3910  newRhsVec[rowIdx] = newRhs;
3911  }
3912  }
3913  }
3914  }
3915 
3916  // change ranges for all modified constraints by one single call (more efficient)
3917  if (doChangeRanges)
3918  {
3919  lp.changeRange(newLhsVec, newRhsVec);
3920  }
3921 
3922  // remove all rows by one single method call (more efficient)
3923  const int nRowsOld = lp.nRows();
3924  int* perm = 0;
3925  spx_alloc(perm, nRowsOld);
3926 
3927  for(int i = 0; i < nRowsOld; ++i)
3928  {
3929  if (remRow[i])
3930  {
3931  perm[i] = -1;
3932  ++remRows;
3933  remNzos += lp.rowVector(i).size();
3934  }
3935  else
3936  perm[i] = 0;
3937  }
3938  lp.removeRows(perm);
3939 
3940  for(int i = 0; i < nRowsOld; ++i)
3941  {
3942  // assert that the pre-computed permutation was correct
3943  assert(perm[i] == perm_tmp[i]);
3944 
3945  // update the global index mapping
3946  if (perm[i] >= 0)
3947  m_rIdx[perm[i]] = m_rIdx[i];
3948  }
3949 
3950  spx_free(perm);
3951  spx_free(perm_tmp);
3952 
3953  if (remRows + remNzos > 0)
3954  {
3955  m_remRows += remRows;
3956  m_remNzos += remNzos;
3957 
3958  MSG_INFO2( (*spxout), (*spxout) << "Simplifier (duplicate rows) removed "
3959  << remRows << " rows, "
3960  << remNzos << " non-zeros"
3961  << std::endl; )
3962  if( remRows > m_minReduction * oldRows )
3963  again = true;
3964 
3965  }
3966  return OKAY;
3967 }
3968 
3970 {
3971 
3972  // This method simplifies the LP by removing duplicate columns
3973  // Duplicates are detected using the algorithm of Bixby and Wagner [1987]
3974 
3975  int remCols = 0;
3976  int remNzos = 0;
3977 
3978  // remove empty rows and columns
3980  if (ret != OKAY)
3981  return ret;
3982 
3983  if (lp.nCols() < 2)
3984  return OKAY;
3985 
3986  DataArray<int> pClass(lp.nCols()); // class of parallel columns
3987  DataArray<int> classSize(lp.nCols()); // size of each class
3988  DataArray<Real> scale(lp.nCols()); // scaling factor for each column
3989  int* idxMem = 0;
3990 
3991  try
3992  {
3993  spx_alloc(idxMem, lp.nCols());
3994  }
3995  catch( const SPxMemoryException& x )
3996  {
3997  spx_free(idxMem);
3998  throw x;
3999  }
4000 
4001  IdxSet idxSet(lp.nCols(), idxMem); // set of feasible indices for new pClass
4002 
4003  // init
4004  pClass[0] = 0;
4005  scale[0] = 0.0;
4006  classSize[0] = lp.nCols();
4007 
4008  for(int j = 1; j < lp.nCols(); ++j)
4009  {
4010  pClass[j] = 0;
4011  scale[j] = 0.0;
4012  classSize[j] = 0;
4013  idxSet.addIdx(j);
4014  }
4015 
4016  Real oldVal = 0.0;
4017 
4018  // main loop
4019  for(int i = 0; i < lp.nRows(); ++i)
4020  {
4021  const SVector& row = lp.rowVector(i);
4022 
4023  for(int k = 0; k < row.size(); ++k)
4024  {
4025  Real aij = row.value(k);
4026  int j = row.index(k);
4027 
4028  if (scale[j] == 0.0)
4029  scale[j] = aij;
4030 
4031  m_classSetCols[pClass[j]].add(j, aij / scale[j]);
4032  if (--classSize[pClass[j]] == 0)
4033  idxSet.addIdx(pClass[j]);
4034  }
4035 
4036  // update each parallel class with non-zero row entry
4037  for(int m = 0; m < row.size(); ++m)
4038  {
4039  int k = pClass[row.index(m)];
4040 
4041  if (m_classSetCols[k].size() > 0)
4042  {
4043  // sort classSet[k] w.r.t. scaled row values
4044  ElementCompare compare;
4045 
4046  if (m_classSetCols[k].size() > 1)
4047  SPxQuicksort(m_classSetCols[k].mem(), m_classSetCols[k].size(), compare);
4048 
4049  // use new index first
4050  int classIdx = idxSet.index(0);
4051  idxSet.remove(0);
4052 
4053  for(int l = 0; l < m_classSetCols[k].size(); ++l)
4054  {
4055  if (l != 0 && NErel(m_classSetCols[k].value(l), oldVal, epsZero()))
4056  {
4057  // start new parallel class
4058  classIdx = idxSet.index(0);
4059  idxSet.remove(0);
4060  }
4061 
4062  pClass[m_classSetCols[k].index(l)] = classIdx;
4063  ++classSize[classIdx];
4064 
4065  oldVal = m_classSetCols[k].value(l);
4066  }
4067 
4068  m_classSetCols[k].clear();
4069  }
4070  }
4071  }
4072 
4073  spx_free(idxMem);
4074 
4075  DataArray<bool> remCol(lp.nCols());
4076  DataArray<bool> fixAndRemCol(lp.nCols());
4077 
4078  for( int k = 0; k < lp.nCols(); ++k )
4079  m_dupCols[k].clear();
4080 
4081  for(int k = 0; k < lp.nCols(); ++k)
4082  {
4083  remCol[k] = false;
4084  fixAndRemCol[k] = false;
4085  m_dupCols[pClass[k]].add(k, 0.0);
4086  }
4087 
4088  bool hasDuplicateCol = false;
4089  DataArray<int> m_perm_empty(0);
4090 
4091  for(int k = 0; k < lp.nCols(); ++k)
4092  {
4093  if (m_dupCols[k].size() > 1 && !(lp.colVector(m_dupCols[k].index(0)).size() == 1))
4094  {
4095  MSG_DEBUG( (*spxout) << "IMAISM58 " << m_dupCols[k].size()
4096  << " duplicate columns found" << std::endl; )
4097 
4098  if (!hasDuplicateCol)
4099  {
4100  DuplicateColsPS* DuplicateColsPSptr = 0;
4101  spx_alloc(DuplicateColsPSptr);
4102  m_hist.append(new (DuplicateColsPSptr) DuplicateColsPS(lp, 0, 0, 1.0, m_perm_empty, true));
4103  hasDuplicateCol = true;
4104  }
4105 
4106  for(int l = 0; l < m_dupCols[k].size(); ++l)
4107  {
4108  for(int m = 0; m < m_dupCols[k].size(); ++m)
4109  {
4110  int j1 = m_dupCols[k].index(l);
4111  int j2 = m_dupCols[k].index(m);
4112 
4113  if (l != m && !remCol[j1] && !remCol[j2])
4114  {
4115  Real cj1 = lp.maxObj(j1);
4116  Real cj2 = lp.maxObj(j2);
4117 
4118  // A.j1 = factor * A.j2
4119  Real factor = scale[j1] / scale[j2];
4120  Real objDif = cj1 - cj2 * scale[j1] / scale[j2];
4121 
4122  ASSERT_WARN( "WMAISM59", isNotZero(factor, epsZero()) );
4123 
4124  if (isZero(objDif, epsZero()))
4125  {
4126  // case 1: objectives also duplicate
4127 
4128  // if 0 is not within the column bounds, we are not able to postsolve if the aggregated column has
4129  // status ZERO, hence we skip this case
4130  if (LErel(lp.lower(j1), 0.0) && GErel(lp.upper(j1), 0.0)
4131  && LErel(lp.lower(j2), 0.0) && GErel(lp.upper(j2), 0.0))
4132  {
4133  DuplicateColsPS* DuplicateColsPSptr = 0;
4134  spx_alloc(DuplicateColsPSptr);
4135  // variable substitution xj2' := xj2 + factor * xj1 <=> xj2 = -factor * xj1 + xj2'
4136  m_hist.append(new (DuplicateColsPSptr) DuplicateColsPS(lp, j1, j2, factor, m_perm_empty));
4137 
4138  // update bounds of remaining column j2 (new column j2')
4139  if (factor > 0)
4140  {
4141  if (lp.lower(j2) <= -infinity || lp.lower(j1) <= -infinity)
4142  lp.changeLower(j2, -infinity);
4143  else
4144  lp.changeLower(j2, lp.lower(j2) + factor * lp.lower(j1));
4145 
4146  if (lp.upper(j2) >= infinity || lp.upper(j1) >= infinity)
4147  lp.changeUpper(j2, infinity);
4148  else
4149  lp.changeUpper(j2, lp.upper(j2) + factor * lp.upper(j1));
4150  }
4151  else if (factor < 0)
4152  {
4153  if (lp.lower(j2) <= -infinity || lp.upper(j1) >= infinity)
4154  lp.changeLower(j2, -infinity);
4155  else
4156  lp.changeLower(j2, lp.lower(j2) + factor * lp.upper(j1));
4157 
4158  if (lp.upper(j2) >= infinity || lp.lower(j1) <= -infinity)
4159  lp.changeUpper(j2, infinity);
4160  else
4161  lp.changeUpper(j2, lp.upper(j2) + factor * lp.lower(j1));
4162  }
4163 
4164  MSG_DEBUG( (*spxout) << "IMAISM60 two duplicate columns " << j1
4165  << ", " << j2
4166  << " replaced by one" << std::endl; )
4167 
4168  remCol[j1] = true;
4169 
4171  }
4172  else
4173  {
4174  MSG_DEBUG( (*spxout) << "IMAISM80 not removing two duplicate columns " << j1
4175  << ", " << j2
4176  << " because zero not contained in their bounds" << std::endl; )
4177  }
4178  }
4179  else
4180  {
4181  // case 2: objectives not duplicate
4182  // considered for maximization sense
4183  if (lp.lower(j2) <= -infinity)
4184  {
4185  if (factor > 0 && objDif > 0)
4186  {
4187  if (lp.upper(j1) >= infinity)
4188  {
4189  MSG_DEBUG( (*spxout) << "IMAISM75 LP unbounded" << std::endl; )
4190  return UNBOUNDED;
4191  }
4192 
4193  // fix j1 at upper bound
4194  MSG_DEBUG( (*spxout) << "IMAISM61 two duplicate columns " << j1
4195  << ", " << j2
4196  << " first one fixed at upper bound=" << lp.upper(j1) << std::endl; )
4197 
4198  FixBoundsPS* FixBoundsPSptr = 0;
4199  spx_alloc(FixBoundsPSptr);
4200  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j1, lp.upper(j1)));
4201  lp.changeLower(j1, lp.upper(j1));
4202  }
4203  else if (factor < 0 && objDif < 0)
4204  {
4205  if (lp.lower(j1) <= -infinity)
4206  {
4207  MSG_DEBUG( (*spxout) << "IMAISM76 LP unbounded" << std::endl; )
4208  return UNBOUNDED;
4209  }
4210 
4211  // fix j1 at lower bound
4212  MSG_DEBUG( (*spxout) << "IMAISM62 two duplicate columns " << j1
4213  << ", " << j2
4214  << " first one fixed at lower bound=" << lp.lower(j1) << std::endl; )
4215 
4216  FixBoundsPS* FixBoundsPSptr = 0;
4217  spx_alloc(FixBoundsPSptr);
4218  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j1, lp.lower(j1)));
4219  lp.changeUpper(j1, lp.lower(j1));
4220  }
4221  }
4222  else if (lp.upper(j2) >= infinity)
4223  {
4224  // fix j1 at upper bound
4225  if (factor < 0 && objDif > 0)
4226  {
4227  if (lp.upper(j1) >= infinity)
4228  {
4229  MSG_DEBUG( (*spxout) << "IMAISM77 LP unbounded" << std::endl; )
4230  return UNBOUNDED;
4231  }
4232 
4233  // fix j1 at upper bound
4234  MSG_DEBUG( (*spxout) << "IMAISM63 two duplicate columns " << j1
4235  << ", " << j2
4236  << " first one fixed at upper bound=" << lp.upper(j1) << std::endl; )
4237 
4238  FixBoundsPS* FixBoundsPSptr = 0;
4239  spx_alloc(FixBoundsPSptr);
4240  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j1, lp.upper(j1)));
4241  lp.changeLower(j1, lp.upper(j1));
4242  }
4243 
4244  // fix j1 at lower bound
4245  else if (factor > 0 && objDif < 0)
4246  {
4247  if (lp.lower(j1) <= -infinity)
4248  {
4249  MSG_DEBUG( (*spxout) << "IMAISM78 LP unbounded" << std::endl; )
4250  return UNBOUNDED;
4251  }
4252 
4253  // fix j1 at lower bound
4254  MSG_DEBUG( (*spxout) << "IMAISM64 two duplicate columns " << j1
4255  << ", " << j2
4256  << " first one fixed at lower bound=" << lp.lower(j1) << std::endl; )
4257 
4258  FixBoundsPS* FixBoundsPSptr = 0;
4259  spx_alloc(FixBoundsPSptr);
4260  m_hist.append(new (FixBoundsPSptr) FixBoundsPS(lp, j1, lp.lower(j1)));
4261  lp.changeUpper(j1, lp.lower(j1));
4262  }
4263  }
4264  if (EQrel(lp.lower(j1), lp.upper(j1), feastol()))
4265  {
4266  remCol[j1] = true;
4267  fixAndRemCol[j1] = true;
4268 
4270  }
4271  }
4272  }
4273  }
4274  }
4275  }
4276  }
4277 
4278  for(int j = 0; j < lp.nCols(); ++j)
4279  {
4280  if(fixAndRemCol[j])
4281  {
4282  assert(remCol[j]);
4283 
4284  // correctIdx == false, because the index mapping will be handled by the postsolving in DuplicateColsPS
4285  fixColumn(lp, j, false);
4286  }
4287  }
4288 
4289  // remove all columns by one single method call (more efficient)
4290  const int nColsOld = lp.nCols();
4291  int* perm = 0;
4292  spx_alloc(perm, nColsOld);
4293 
4294  for(int j = 0; j < nColsOld; ++j)
4295  {
4296  if (remCol[j])
4297  {
4298  perm[j] = -1;
4299  ++remCols;
4300  remNzos += lp.colVector(j).size();
4301  }
4302  else
4303  perm[j] = 0;
4304  }
4305  lp.removeCols(perm);
4306 
4307  for(int j = 0; j < nColsOld; ++j)
4308  {
4309  if (perm[j] >= 0)
4310  m_cIdx[perm[j]] = m_cIdx[j];
4311  }
4312 
4313  DataArray<int> da_perm(nColsOld);
4314  for(int j = 0; j < nColsOld; ++j)
4315  {
4316  da_perm[j] = perm[j];
4317  }
4318 
4319  if (hasDuplicateCol)
4320  {
4321  DuplicateColsPS* DuplicateColsPSptr = 0;
4322  spx_alloc(DuplicateColsPSptr);
4323  m_hist.append(new (DuplicateColsPSptr) DuplicateColsPS(lp, 0, 0, 1.0, da_perm, false, true));
4324  }
4325 
4326  spx_free(perm);
4327 
4328  assert(remCols > 0 || remNzos == 0);
4329 
4330  if (remCols > 0)
4331  {
4332  m_remCols += remCols;
4333  m_remNzos += remNzos;
4334 
4335  MSG_INFO2( (*spxout), (*spxout) << "Simplifier (duplicate columns) removed "
4336  << remCols << " cols, "
4337  << remNzos << " non-zeros"
4338  << std::endl; )
4339  if( remCols > m_minReduction * nColsOld )
4340  again = true;
4341  }
4342  return OKAY;
4343 }
4344 
4345 void SPxMainSM::fixColumn(SPxLP& lp, int j, bool correctIdx)
4346 {
4347 
4348  assert(EQrel(lp.lower(j), lp.upper(j), feastol()));
4349 
4350  Real lo = lp.lower(j);
4351  const SVector& col = lp.colVector(j);
4352 
4353  assert(NE(lo, infinity) && NE(lo, -infinity));
4354 
4355  MSG_DEBUG( (*spxout) << "IMAISM66 fix variable x" << j
4356  << ": lower=" << lp.lower(j)
4357  << " upper=" << lp.upper(j)
4358  << std::endl; )
4359 
4360  if (isNotZero(lo, epsZero()))
4361  {
4362  for(int k = 0; k < col.size(); ++k)
4363  {
4364  int i = col.index(k);
4365 
4366  if (lp.rhs(i) < infinity)
4367  {
4368  Real y = lo * col.value(k);
4369  Real scale = maxAbs(lp.rhs(i), y);
4370 
4371  if (scale < 1.0)
4372  scale = 1.0;
4373 
4374  Real rhs = (lp.rhs(i) / scale) - (y / scale);
4375 
4376  if (isZero(rhs, epsZero()))
4377  rhs = 0.0;
4378  else
4379  rhs *= scale;
4380 
4381  MSG_DEBUG( (*spxout) << "IMAISM67 row " << i
4382  << ": rhs=" << rhs
4383  << " (" << lp.rhs(i)
4384  << ") aij=" << col.value(k)
4385  << std::endl; )
4386 
4387  lp.changeRhs(i, rhs);
4388  }
4389  if (lp.lhs(i) > -infinity)
4390  {
4391  Real y = lo * col.value(k);
4392  Real scale = maxAbs(lp.lhs(i), y);
4393 
4394  if (scale < 1.0)
4395  scale = 1.0;
4396 
4397  Real lhs = (lp.lhs(i) / scale) - (y / scale);
4398 
4399  if (isZero(lhs, epsZero()))
4400  lhs = 0.0;
4401  else
4402  lhs *= scale;
4403 
4404  MSG_DEBUG( (*spxout) << "IMAISM68 row " << i
4405  << ": lhs=" << lhs
4406  << " (" << lp.lhs(i)
4407  << ") aij=" << col.value(k)
4408  << std::endl; )
4409 
4410  lp.changeLhs(i, lhs);
4411  }
4412  assert(lp.lhs(i) <= lp.rhs(i));
4413  }
4414  }
4415 
4416  FixVariablePS* FixVariablePSptr = 0;
4417  spx_alloc(FixVariablePSptr);
4418  m_hist.append(new (FixVariablePSptr) FixVariablePS(lp, *this, j, lp.lower(j), correctIdx));
4419 }
4420 
4422 {
4423  // transfer message handler
4424  spxout = lp.spxout;
4425  assert(spxout != 0);
4426 
4427  m_thesense = lp.spxSense();
4428  m_timeUsed->reset();
4429  m_timeUsed->start();
4430 
4431  m_objoffset = 0.0;
4433  m_pseudoobj = -infinity;
4434 
4435  m_remRows = 0;
4436  m_remCols = 0;
4437  m_remNzos = 0;
4438  m_chgBnds = 0;
4439  m_chgLRhs = 0;
4440  m_keptBnds = 0;
4441  m_keptLRhs = 0;
4442 
4443  m_result = OKAY;
4444  bool again = true;
4445 
4446  if(m_hist.size() > 0)
4447  {
4448  // delete pointers in old m_hist
4449  for(int k = 0; k < m_hist.size(); ++k)
4450  {
4451  m_hist[k]->~PostStep();
4452  spx_free(m_hist[k]);
4453  }
4454  m_hist.clear();
4455  }
4456 
4457  m_hist.reSize(0);
4458  m_postsolved = false;
4459 
4460  if( eps < 0.0 )
4461  throw SPxInterfaceException("XMAISM30 Cannot use negative epsilon in simplify().");
4462 
4463  if( ftol < 0.0 )
4464  throw SPxInterfaceException("XMAISM31 Cannot use negative feastol in simplify().");
4465 
4466  if( otol < 0.0 )
4467  throw SPxInterfaceException("XMAISM32 Cannot use negative opttol in simplify().");
4468 
4469  m_epsilon = eps;
4470  m_feastol = ftol;
4471  m_opttol = otol;
4472 
4473 
4474  MSG_INFO2( (*spxout),
4475  int numRangedRows = 0;
4476  int numBoxedCols = 0;
4477 
4478  for(int i = 0; i < lp.nRows(); ++i)
4479  if (lp.lhs(i) > -infinity && lp.rhs(i) < infinity)
4480  ++numRangedRows;
4481  for(int j = 0; j < lp.nCols(); ++j)
4482  if (lp.lower(j) > -infinity && lp.upper(j) < infinity)
4483  ++numBoxedCols;
4484 
4485  (*spxout) << "LP has "
4486  << numRangedRows << " ranged rows, "
4487  << numBoxedCols << " boxed columns"
4488  << std::endl;
4489  )
4490 
4491  m_stat.reSize(16);
4492 
4493  for(int k = 0; k < m_stat.size(); ++k)
4494  m_stat[k] = 0;
4495 
4496  m_addedcols = 0;
4497  handleRowObjectives(lp);
4498 
4499  m_prim.reDim(lp.nCols());
4500  m_slack.reDim(lp.nRows());
4501  m_dual.reDim(lp.nRows());
4502  m_redCost.reDim(lp.nCols());
4503  m_cBasisStat.reSize(lp.nCols());
4504  m_rBasisStat.reSize(lp.nRows());
4505  m_cIdx.reSize(lp.nCols());
4506  m_rIdx.reSize(lp.nRows());
4507 
4508  m_classSetRows.reSize(lp.nRows());
4509  m_classSetCols.reSize(lp.nCols());
4510  m_dupRows.reSize(lp.nRows());
4511  m_dupCols.reSize(lp.nCols());
4512 
4513  m_keepbounds = keepbounds;
4514 
4515  for(int i = 0; i < lp.nRows(); ++i)
4516  m_rIdx[i] = i;
4517 
4518  for(int j = 0; j < lp.nCols(); ++j)
4519  m_cIdx[j] = j;
4520 
4521  // round extreme values (set all values smaller than eps to zero and all values bigger than infinity/5 to infinity)
4522 #if EXTREMES
4523  handleExtremes(lp);
4524 #endif
4525 
4526  // main presolving loop
4527  while(again && m_result == OKAY)
4528  {
4529  again = false;
4530 
4531 #if ROWS
4532  if (m_result == OKAY)
4533  m_result = simplifyRows(lp, again);
4534 #endif
4535 
4536 #if COLS
4537  if (m_result == OKAY)
4538  m_result = simplifyCols(lp, again);
4539 #endif
4540 
4541 #if DUAL
4542  if (m_result == OKAY)
4543  m_result = simplifyDual(lp, again);
4544 #endif
4545 
4546 #if DUPLICATE_ROWS
4547  if (m_result == OKAY)
4548  m_result = duplicateRows(lp, again);
4549 #endif
4550 
4551 #if DUPLICATE_COLS
4552  if (m_result == OKAY)
4553  m_result = duplicateCols(lp, again);
4554 #endif
4555 
4556  if( !again )
4557  {
4558 #if TRIVIAL_HEURISTICS
4559  trivialHeuristic(lp);
4560 #endif
4561 
4562 #if PSEUDOOBJ
4563  propagatePseudoobj(lp);
4564 #endif
4565 
4566 #if MULTI_AGGREGATE
4567  if (m_result == OKAY)
4568  m_result = multiaggregation(lp, again);
4569 #endif
4570  }
4571 
4572  }
4573 
4574  // preprocessing detected infeasibility or unboundedness
4575  if (m_result != OKAY)
4576  {
4577  MSG_INFO1( (*spxout), (*spxout) << "Simplifier result: " << m_result << std::endl; )
4578  return m_result;
4579  }
4580 
4583  MSG_INFO1( (*spxout), (*spxout) << "Simplifier removed "
4584  << m_remRows << " rows, "
4585  << m_remCols << " columns, "
4586  << m_remNzos << " nonzeros, "
4587  << m_chgBnds << " col bounds, "
4588  << m_chgLRhs << " row bounds"
4589  << std::endl; )
4590 
4591  if (keepbounds)
4592  MSG_INFO2( (*spxout), (*spxout) << "Simplifier kept "
4593  << m_keptBnds << " column bounds, "
4594  << m_keptLRhs << " row bounds"
4595  << std::endl; )
4596 
4597  MSG_INFO1( (*spxout), (*spxout) << "Reduced LP has "
4598  << lp.nRows() << " rows "
4599  << lp.nCols() << " columns "
4600  << lp.nNzos() << " nonzeros"
4601  << std::endl; )
4602 
4603  MSG_INFO2( (*spxout),
4604  int numRangedRows = 0;
4605  int numBoxedCols = 0;
4606 
4607  for(int i = 0; i < lp.nRows(); ++i)
4608  if (lp.lhs(i) > -infinity && lp.rhs(i) < infinity)
4609  ++numRangedRows;
4610 
4611  for(int j = 0; j < lp.nCols(); ++j)
4612  if (lp.lower(j) > -infinity && lp.upper(j) < infinity)
4613  ++numBoxedCols;
4614 
4615  (*spxout) << "Reduced LP has "
4616  << numRangedRows << " ranged rows, "
4617  << numBoxedCols << " boxed columns"
4618  << std::endl;
4619  )
4620 
4621  if (lp.nCols() == 0 && lp.nRows() == 0)
4622  {
4623  MSG_INFO1( (*spxout), (*spxout) << "Simplifier removed all rows and columns" << std::endl; )
4624  m_result = VANISHED;
4625  }
4626 
4627  MSG_INFO2( (*spxout), (*spxout) << "\nSimplifier performed:\n"
4628  << m_stat[EMPTY_ROW] << " empty rows\n"
4629  << m_stat[FREE_ROW] << " free rows\n"
4630  << m_stat[SINGLETON_ROW] << " singleton rows\n"
4631  << m_stat[FORCE_ROW] << " forcing rows\n"
4632  << m_stat[EMPTY_COL] << " empty columns\n"
4633  << m_stat[FIX_COL] << " fixed columns\n"
4634  << m_stat[FREE_ZOBJ_COL] << " free columns with zero objective\n"
4635  << m_stat[ZOBJ_SINGLETON_COL] << " singleton columns with zero objective\n"
4636  << m_stat[DOUBLETON_ROW] << " singleton columns combined with a doubleton equation\n"
4637  << m_stat[FREE_SINGLETON_COL] << " free singleton columns\n"
4638  << m_stat[DOMINATED_COL] << " dominated columns\n"
4639  << m_stat[WEAKLY_DOMINATED_COL] << " weakly dominated columns\n"
4640  << m_stat[DUPLICATE_ROW] << " duplicate rows\n"
4641  << m_stat[FIX_DUPLICATE_COL] << " duplicate columns (fixed)\n"
4642  << m_stat[SUB_DUPLICATE_COL] << " duplicate columns (substituted)\n"
4643  << m_stat[MULTI_AGG] << " multi aggregation of variables\n"
4644  << std::endl; );
4645 
4646  m_timeUsed->stop();
4647 
4648  return m_result;
4649 }
4650 
4651 void SPxMainSM::unsimplify(const Vector& x, const Vector& y, const Vector& s, const Vector& r,
4652  const SPxSolver::VarStatus rows[], const SPxSolver::VarStatus cols[], bool isOptimal)
4653 {
4654  MSG_INFO1( (*spxout), (*spxout) << " --- unsimplifying solution and basis" << std::endl; )
4655  assert(x.dim() <= m_prim.dim());
4656  assert(y.dim() <= m_dual.dim());
4657  assert(x.dim() == r.dim());
4658  assert(y.dim() == s.dim());
4659 
4660  // assign values of variables in reduced LP
4661  // NOTE: for maximization problems, we have to switch signs of dual and reduced cost values,
4662  // since simplifier assumes minimization problem
4663  for(int j = 0; j < x.dim(); ++j)
4664  {
4665  m_prim[j] = isZero(x[j], epsZero()) ? 0.0 : x[j];
4666  m_redCost[j] = isZero(r[j], epsZero()) ? 0.0 : (m_thesense == SPxLP::MAXIMIZE ? -r[j] : r[j]);
4667  m_cBasisStat[j] = cols[j];
4668  }
4669  for(int i = 0; i < y.dim(); ++i)
4670  {
4671  m_dual[i] = isZero(y[i], epsZero()) ? 0.0 : (m_thesense == SPxLP::MAXIMIZE ? -y[i] : y[i]);
4672  m_slack[i] = isZero(s[i], epsZero()) ? 0.0 : s[i];
4673  m_rBasisStat[i] = rows[i];
4674  }
4675 
4676  // undo preprocessing
4677  for(int k = m_hist.size()-1; k >= 0; --k)
4678  {
4679  MSG_DEBUG( std::cout << "unsimplifying " << m_hist[k]->getName() << "\n" );
4680 
4681  try
4682  {
4683  m_hist[k]->execute(m_prim, m_dual, m_slack, m_redCost, m_cBasisStat, m_rBasisStat, isOptimal);
4684  }
4685  catch( const SPxException& ex )
4686  {
4687  MSG_INFO1( (*spxout), (*spxout) << "Exception thrown while unsimplifying " << m_hist[k]->getName() << ":\n" << ex.what() << "\n" );
4688  throw SPxInternalCodeException("XMAISM00 Exception thrown during unsimply().");
4689  }
4690 
4691  m_hist[k]->~PostStep();
4692  spx_free(m_hist[k]);
4693  m_hist.reSize(k);
4694  }
4695 
4696  // for maximization problems, we have to switch signs of dual and reduced cost values back
4698  {
4699  for(int j = 0; j < m_redCost.dim(); ++j)
4700  m_redCost[j] = -m_redCost[j];
4701 
4702  for(int i = 0; i < m_dual.dim(); ++i)
4703  m_dual[i] = -m_dual[i];
4704  }
4705 
4706  if( m_addedcols > 0 )
4707  {
4708  assert(m_prim.dim() >= m_addedcols);
4713  }
4714 
4715 #ifdef CHECK_BASIC_DIM
4716  int numBasis = 0;
4717  for(int rs = 0; rs < m_rBasisStat.size(); ++rs)
4718  {
4719  if(m_rBasisStat[rs] == SPxSolver::BASIC)
4720  numBasis ++;
4721  }
4722 
4723  for(int cs = 0; cs < m_cBasisStat.size(); ++cs)
4724  {
4725  if(m_cBasisStat[cs] == SPxSolver::BASIC)
4726  numBasis ++;
4727  }
4728 
4729  if( numBasis != m_rBasisStat.size())
4730  {
4731  throw SPxInternalCodeException("XMAISM26 Dimension doesn't match after this step.");
4732  }
4733 #endif
4734 
4735  m_hist.clear();
4736  m_postsolved = true;
4737 }
4738 
4739 // Pretty-printing of solver status.
4740 std::ostream& operator<<(std::ostream& os, const SPxSimplifier::Result& status)
4741 {
4742  switch( status )
4743  {
4744  case SPxSimplifier::OKAY:
4745  os << "SUCCESS";
4746  break;
4748  os << "INFEASIBLE";
4749  break;
4751  os << "DUAL_INFEASIBLE";
4752  break;
4754  os << "UNBOUNDED";
4755  break;
4757  os << "VANISHED";
4758  break;
4759  default:
4760  os << "UNKNOWN";
4761  break;
4762  }
4763  return os;
4764 }
4765 
4766 } //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:428
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:446
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:1975
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:416
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:371
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:404
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:398
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:392
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:73
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:4651
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:4345
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:214
Array< DSVector > m_classSetCols
stores parallel classes with non-zero row entry
Definition: spxmainsm.h:1208
#define MAXIMUM(x, y)
Definition: spxdefines.h:242
Result duplicateCols(SPxLP &lp, bool &again)
removes duplicate columns
Definition: spxmainsm.cpp:3969
void removeCol(SPxLP &lp, int j)
removes a column in the LP.
Definition: spxmainsm.h:1284
#define MSG_DEBUG(x)
Definition: spxdefines.h:128
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:410
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:2048
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:116
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:243
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:458
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:464
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
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:386
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:434
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:112
Result duplicateRows(SPxLP &lp, bool &again)
removes duplicate rows.
Definition: spxmainsm.cpp:3615
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:3371
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:440
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:1867
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:3113
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:114
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:452
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:422
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:2584
Array< DSVector > m_dupRows
arrange duplicate rows using bucket sort w.r.t. their pClass values
Definition: spxmainsm.h:1209
static Real epsilon()
Definition: spxdefines.h:270
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