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