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