Scippy

SoPlex

Sequential object-oriented simPlex

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