1    	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2    	/*                                                                           */
3    	/*                  This file is part of the class library                   */
4    	/*       SoPlex --- the Sequential object-oriented simPlex.                  */
5    	/*                                                                           */
6    	/*  Copyright (c) 1996-2023 Zuse Institute Berlin (ZIB)                      */
7    	/*                                                                           */
8    	/*  Licensed under the Apache License, Version 2.0 (the "License");          */
9    	/*  you may not use this file except in compliance with the License.         */
10   	/*  You may obtain a copy of the License at                                  */
11   	/*                                                                           */
12   	/*      http://www.apache.org/licenses/LICENSE-2.0                           */
13   	/*                                                                           */
14   	/*  Unless required by applicable law or agreed to in writing, software      */
15   	/*  distributed under the License is distributed on an "AS IS" BASIS,        */
16   	/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
17   	/*  See the License for the specific language governing permissions and      */
18   	/*  limitations under the License.                                           */
19   	/*                                                                           */
20   	/*  You should have received a copy of the Apache-2.0 license                */
21   	/*  along with SoPlex; see the file LICENSE. If not email to soplex@zib.de.  */
22   	/*                                                                           */
23   	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24   	
25   	/**@file  spxlpbase.h
26   	 * @brief Saving LPs in a form suitable for SoPlex.
27   	 */
28   	#ifndef _SPXLPBASE_H_
29   	#define _SPXLPBASE_H_
30   	
31   	/* undefine SOPLEX_DEBUG flag from including files; if SOPLEX_DEBUG should be defined in this file, do so below */
32   	#ifdef SOPLEX_DEBUG
33   	#define SOPLEX_DEBUG_SPXLPBASE
34   	#undef SOPLEX_DEBUG
35   	#endif
36   	
37   	#include <assert.h>
38   	#include <iostream>
39   	#include <iomanip>
40   	#include <typeinfo>
41   	
42   	#include "soplex/spxdefines.h"
43   	#include "soplex/basevectors.h"
44   	#include "soplex/dataarray.h"
45   	#include "soplex/datakey.h"
46   	#include "soplex/spxid.h"
47   	#include "soplex/lprowbase.h"
48   	#include "soplex/lpcolbase.h"
49   	#include "soplex/lprowsetbase.h"
50   	#include "soplex/lpcolsetbase.h"
51   	#include "soplex/nameset.h"
52   	#include "soplex/didxset.h"
53   	#include "soplex/spxfileio.h"
54   	#include "soplex/spxscaler.h"
55   	#include "soplex/rational.h"
56   	
57   	namespace soplex
58   	{
59   	// Declarations to fix errors of the form "SPxMainSM is not a type"
60   	template <class R>
61   	class SPxSolverBase;
62   	template <class R>
63   	class SPxMainSM;
64   	template <class R>
65   	class SPxLPBase;
66   	template <class R>
67   	class SPxBasisBase;
68   	
69   	template <class R>
70   	class SPxEquiliSC;
71   	template <class R>
72   	class SPxLeastSqSC;
73   	template <class R>
74   	class SPxGeometSC;
75   	template <class R>
76   	class SPxMainSM;
77   	
78   	
79   	/**@brief   Saving LPs in a form suitable for SoPlex.
80   	 * @ingroup Algo
81   	 *
82   	 *  Class SPxLPBase provides the data structures required for saving a linear program in the form
83   	 *  \f[
84   	 *  \begin{array}{rl}
85   	 *      \hbox{max}  & c^T x              \\
86   	 *      \hbox{s.t.} & l_r \le Ax \le u_r \\
87   	 *                  & l_c \le x \le u_c
88   	 *  \end{array}
89   	 *  \f]
90   	 *  suitable for solving with SoPlex. This includes:
91   	 *  - SVSetBase%s for both columns and rows
92   	 *  - objective Vector
93   	 *  - upper and lower bound Vectors for variables (\f$l_c\f$ and \f$u_c\f$)
94   	 *  - upper and lower bound Vectors for inequalities (\f$l_r\f$ and \f$u_r\f$)
95   	 *
96   	 *  Note, that the optimization sense is not saved directly. Instead, the objective function are multiplied by -1 to
97   	 *  transform the LP to our standard form maximizing the objective function. However, the sense of the loaded LP can be
98   	 *  retrieved with method #spxSense().
99   	 *
100  	 *  Further, equality constraints are modeled by \f$l_r = u_r\f$.  Analogously, fixed variables have \f$l_c = u_c\f$.
101  	 *
102  	 *  #SPxLPBase%s are saved as an SVSet, both for columns and rows. Note that this is redundant but eases the access.
103  	 */
104  	
105  	
106  	template <class R>
107  	class SPxLPBase : protected LPRowSetBase<R>, protected LPColSetBase<R>
108  	{
109  	   template <class S> friend class SPxLPBase;
110  	   friend SPxBasisBase<R>;
111  	   friend SPxScaler<R>;
112  	   friend SPxEquiliSC<R>;
113  	   friend SPxLeastSqSC<R>;
114  	   friend SPxGeometSC<R>;
115  	   friend SPxMainSM<R>;
116  	
117  	public:
118  	
119  	   // ------------------------------------------------------------------------------------------------------------------
120  	   /**@name Types */
121  	   ///@{
122  	
123  	   /// Optimization sense.
124  	   enum SPxSense
125  	   {
126  	      MAXIMIZE = 1,
127  	      MINIMIZE = -1
128  	   };
129  	
130  	   ///@}
131  	
132  	private:
133  	
134  	   // ------------------------------------------------------------------------------------------------------------------
135  	   /**@name Data */
136  	   ///@{
137  	
138  	   SPxSense thesense;                ///< optimization sense.
139  	   R offset;                         ///< offset computed, e.g., in simplification step
140  	   bool _isScaled;                   ///< true, if scaling has been performed
141  	   SPxScaler<R>*
142  	   lp_scaler;             ///< points to the scaler if the lp has been scaled, to nullptr otherwise
143  	
144  	   ///@}
145  	
146  	public:
147  	
148  	   // message handler
149  	   SPxOut* spxout;
150  	
151  	public:
152  	
153  	   void setOutstream(SPxOut& newOutstream)
154  	   {
155  	      spxout = &newOutstream;
156  	   }
157  	
158  	   // ------------------------------------------------------------------------------------------------------------------
159  	
160  	   /// unscales the lp and clears basis
161  	   void unscaleLP();
162  	
163  	   /**@name Inquiry */
164  	   ///@{
165  	
166  	   /// returns current tolerances
167  	   const std::shared_ptr<Tolerances> tolerances() const
168  	   {
169  	      return _tolerances;
170  	   }
171  	
172  	   /// set tolerances
173  	   virtual void setTolerances(std::shared_ptr<Tolerances> tolerances)
174  	   {
175  	      this->_tolerances = tolerances;
176  	   }
177  	
178  	   /// Returns true if and only if the LP is scaled
179  	   bool isScaled() const
180  	   {
181  	      return _isScaled;
182  	   }
183  	
184  	   /// set whether the LP is scaled or not
185  	   void setScalingInfo(bool scaled)
186  	   {
187  	      _isScaled = scaled;
188  	   }
189  	
190  	   /// Returns number of rows in LP.
191  	   int nRows() const
192  	   {
193  	      return LPRowSetBase<R>::num();
194  	   }
195  	
196  	   /// Returns number of columns in LP.
197  	   int nCols() const
198  	   {
199  	      return LPColSetBase<R>::num();
200  	   }
201  	
202  	   /// Returns number of nonzeros in LP.
203  	   int nNzos() const
204  	   {
205  	
206  	      int n = 0;
207  	
208  	      for(int i = 0; i < nCols(); ++i)
209  	         n += colVector(i).size();
210  	
211  	      return n;
212  	   }
213  	
214  	   /// Absolute smallest non-zero element in (possibly scaled) LP.
215  	   virtual R minAbsNzo(bool unscaled = true) const;
216  	
217  	   /// Absolute biggest non-zero element in (in rational case possibly scaled) LP.
218  	   virtual R maxAbsNzo(bool unscaled = true) const;
219  	
220  	   /// Gets \p i 'th row.
221  	   void getRow(int i, LPRowBase<R>& row) const
222  	   {
223  	      row.setLhs(lhs(i));
224  	      row.setRhs(rhs(i));
225  	      row.setObj(rowObj(i));
226  	      row.setRowVector(DSVectorBase<R>(rowVector(i)));
227  	   }
228  	
229  	   /// Gets row with identifier \p id.
230  	   void getRow(const SPxRowId& id, LPRowBase<R>& row) const
231  	   {
232  	      getRow(number(id), row);
233  	   }
234  	
235  	   /// Gets rows \p start, ... \p end.
236  	   void getRows(int start, int end, LPRowSetBase<R>& set) const
237  	   {
238  	      set.clear();
239  	
240  	      for(int i = start; i <= end; i++)
241  	         set.add(lhs(i), rowVector(i), rhs(i), rowObj(i));
242  	   }
243  	
244  	   /// Gets row vector of row \p i.
245  	   const SVectorBase<R>& rowVector(int i) const
246  	   {
247  	      return LPRowSetBase<R>::rowVector(i);
248  	   }
249  	
250  	   /// Gets row vector of row with identifier \p id.
251  	   const SVectorBase<R>& rowVector(const SPxRowId& id) const
252  	   {
253  	      return LPRowSetBase<R>::rowVector(id);
254  	   }
255  	
256  	   /// Gets unscaled row vector of row \p i.
257  	   void getRowVectorUnscaled(int i, DSVectorBase<R>& vec) const;
258  	
259  	   /// Returns right hand side vector.
260  	   const VectorBase<R>& rhs() const
261  	   {
262  	      return LPRowSetBase<R>::rhs();
263  	   }
264  	
265  	   /// Returns right hand side of row number \p i.
266  	   const R& rhs(int i) const
267  	   {
268  	      return LPRowSetBase<R>::rhs(i);
269  	   }
270  	
271  	
272  	   /// Returns right hand side of row with identifier \p id.
273  	   const R& rhs(const SPxRowId& id) const
274  	   {
275  	      return LPRowSetBase<R>::rhs(id);
276  	   }
277  	
278  	   /// Gets (internal and possibly scaled) right hand side vector.
279  	   void getRhs(VectorBase<R>& vec) const
280  	   {
281  	      vec = LPRowSetBase<R>::rhs();
282  	   }
283  	
284  	   /// Gets unscaled right hand side vector.
285  	   void getRhsUnscaled(VectorBase<R>& vec) const;
286  	
287  	   /// Returns unscaled right hand side of row number \p i.
288  	   R rhsUnscaled(int i) const;
289  	
290  	   /// Returns unscaled right hand side of row with identifier \p id.
291  	   R rhsUnscaled(const SPxRowId& id) const;
292  	
293  	   /// Returns left hand side vector.
294  	   const VectorBase<R>& lhs() const
295  	   {
296  	      return LPRowSetBase<R>::lhs();
297  	   }
298  	
299  	   /// Returns left hand side of row number \p i.
300  	   const R& lhs(int i) const
301  	   {
302  	      return LPRowSetBase<R>::lhs(i);
303  	   }
304  	
305  	   /// Returns left hand side of row with identifier \p id.
306  	   const R& lhs(const SPxRowId& id) const
307  	   {
308  	      return LPRowSetBase<R>::lhs(id);
309  	   }
310  	
311  	   /// Gets row objective function vector.
312  	   void getRowObj(VectorBase<R>& prowobj) const
313  	   {
314  	      prowobj = LPRowSetBase<R>::obj();
315  	
316  	      if(spxSense() == MINIMIZE)
317  	         prowobj *= -1.0;
318  	   }
319  	
320  	   ///
321  	   R rowObj(int i) const
322  	   {
323  	      if(spxSense() == MINIMIZE)
324  	         return -maxRowObj(i);
325  	      else
326  	         return maxRowObj(i);
327  	   }
328  	
329  	   /// Returns row objective function value of row with identifier \p id.
330  	   R rowObj(const SPxRowId& id) const
331  	   {
332  	      if(spxSense() == MINIMIZE)
333  	         return -maxRowObj(id);
334  	      else
335  	         return maxRowObj(id);
336  	   }
337  	
338  	   ///
339  	   const VectorBase<R>& maxRowObj() const
340  	   {
341  	      return LPRowSetBase<R>::obj();
342  	   }
343  	
344  	   ///
345  	   const R& maxRowObj(int i) const
346  	   {
347  	      return LPRowSetBase<R>::obj(i);
348  	   }
349  	
350  	   /// Returns row objective function value of row with identifier \p id.
351  	   const R& maxRowObj(const SPxRowId& id) const
352  	   {
353  	      return LPRowSetBase<R>::obj(id);
354  	   }
355  	
356  	   /// Returns unscaled left hand side vector.
357  	   void getLhsUnscaled(VectorBase<R>& vec) const;
358  	
359  	   /// Returns unscaled left hand side of row number \p i.
360  	   R lhsUnscaled(int i) const;
361  	
362  	   /// Returns left hand side of row with identifier \p id.
363  	   R lhsUnscaled(const SPxRowId& id) const;
364  	
365  	   /// Returns the inequality type of the \p i'th LPRow.
366  	   typename LPRowBase<R>::Type rowType(int i) const
367  	   {
368  	      return LPRowSetBase<R>::type(i);
369  	   }
370  	
371  	   /// Returns the inequality type of the row with identifier \p key.
372  	   typename LPRowBase<R>::Type rowType(const SPxRowId& id) const
373  	   {
374  	      return LPRowSetBase<R>::type(id);
375  	   }
376  	
377  	   /// Gets \p i 'th column.
378  	   void getCol(int i, LPColBase<R>& col) const
379  	   {
380  	      col.setUpper(upper(i));
381  	      col.setLower(lower(i));
382  	      col.setObj(obj(i));
383  	      col.setColVector(colVector(i));
384  	   }
385  	
386  	   /// Gets column with identifier \p id.
387  	   void getCol(const SPxColId& id, LPColBase<R>& col) const
388  	   {
389  	      getCol(number(id), col);
390  	   }
391  	
392  	   /// Gets columns \p start, ..., \p end.
393  	   void getCols(int start, int end, LPColSetBase<R>& set) const
394  	   {
395  	      if(_isScaled)
396  	      {
397  	         LPColBase<R> lpcol;
398  	
399  	         for(int i = start; i <= end; i++)
400  	         {
401  	            getCol(i, lpcol);
402  	            set.add(lpcol);
403  	         }
404  	
405  	      }
406  	      else
407  	      {
408  	         set.clear();
409  	
410  	         for(int i = start; i <= end; i++)
411  	            set.add(obj(i), lower(i), colVector(i), upper(i));
412  	      }
413  	   }
414  	
415  	   /// Returns column vector of column \p i.
416  	   const SVectorBase<R>& colVector(int i) const
417  	   {
418  	      return LPColSetBase<R>::colVector(i);
419  	   }
420  	
421  	   /// Returns column vector of column with identifier \p id.
422  	   const SVectorBase<R>& colVector(const SPxColId& id) const
423  	   {
424  	      return LPColSetBase<R>::colVector(id);
425  	   }
426  	
427  	   /// Gets column vector of column \p i.
428  	   void getColVectorUnscaled(int i, DSVectorBase<R>& vec) const;
429  	
430  	   /// Gets column vector of column with identifier \p id.
431  	   void getColVectorUnscaled(const SPxColId& id, DSVectorBase<R>& vec) const;
432  	
433  	   /// Gets unscaled objective vector.
434  	   void getObjUnscaled(VectorBase<R>& pobj) const;
435  	
436  	   /// Gets objective vector.
437  	   void getObj(VectorBase<R>& pobj) const
438  	   {
439  	      pobj = LPColSetBase<R>::maxObj();
440  	
441  	      if(spxSense() == MINIMIZE)
442  	         pobj *= -1.0;
443  	   }
444  	
445  	   /// Returns objective value of column \p i.
446  	   R obj(int i) const
447  	   {
448  	      R res = maxObj(i);
449  	
450  	      if(spxSense() == MINIMIZE)
451  	         res *= -1;
452  	
453  	      return res;
454  	   }
455  	
456  	   /// Returns objective value of column with identifier \p id.
457  	   R obj(const SPxColId& id) const
458  	   {
459  	      return obj(number(id));
460  	   }
461  	
462  	   /// Returns unscaled objective value of column \p i.
463  	   R objUnscaled(int i) const;
464  	
465  	   /// Returns unscaled objective value of column with identifier \p id.
466  	   R objUnscaled(const SPxColId& id) const;
467  	
468  	   /// Returns objective vector for maximization problem.
469  	   /** Methods #maxObj() return the objective vector or its elements, after transformation to a maximization
470  	    *  problem. Since this is how SPxLPBase internally stores any LP these methods are generally faster. The following
471  	    *  condition holds: #obj() = #spxSense() * maxObj().
472  	    */
473  	   const VectorBase<R>& maxObj() const
474  	   {
475  	      return LPColSetBase<R>::maxObj();
476  	   }
477  	
478  	   /// Returns objective value of column \p i for maximization problem.
479  	   const R& maxObj(int i) const
480  	   {
481  	      return LPColSetBase<R>::maxObj(i);
482  	   }
483  	
484  	   /// Returns objective value of column with identifier \p id for maximization problem.
485  	   const R& maxObj(const SPxColId& id) const
486  	   {
487  	      return maxObj(number(id));
488  	   }
489  	
490  	   /// Returns unscaled objective vector for maximization problem.
491  	   void maxObjUnscaled(VectorBase<R>& vec) const;
492  	
493  	   /// Returns unscaled objective value of column \p i for maximization problem.
494  	   R maxObjUnscaled(int i) const;
495  	
496  	   /// Returns unscaled objective value of column with identifier \p id for maximization problem.
497  	   R maxObjUnscaled(const SPxColId& id) const;
498  	
499  	   /// Returns upper bound vector.
500  	   const VectorBase<R>& upper() const
501  	   {
502  	      return LPColSetBase<R>::upper();
503  	   }
504  	
505  	   /// Returns upper bound of column \p i.
506  	   const R& upper(int i) const
507  	   {
508  	      return LPColSetBase<R>::upper(i);
509  	   }
510  	
511  	   /// Returns upper bound of column with identifier \p id.
512  	   const R& upper(const SPxColId& id) const
513  	   {
514  	      return LPColSetBase<R>::upper(id);
515  	   }
516  	
517  	   /// Gets unscaled upper bound vector
518  	   void getUpperUnscaled(VectorBase<R>& vec) const;
519  	
520  	   /// Returns unscaled upper bound of column \p i.
521  	   R upperUnscaled(int i) const;
522  	
523  	   /// Returns unscaled upper bound of column with identifier \p id.
524  	   R upperUnscaled(const SPxColId& id) const;
525  	
526  	   /// Returns (internal and possibly scaled) lower bound vector.
527  	   const VectorBase<R>& lower() const
528  	   {
529  	      return LPColSetBase<R>::lower();
530  	   }
531  	
532  	   /// Returns (internal and possibly scaled) lower bound of column \p i.
533  	   const R& lower(int i) const
534  	   {
535  	      return LPColSetBase<R>::lower(i);
536  	   }
537  	
538  	   /// Returns (internal and possibly scaled) lower bound of column with identifier \p id.
539  	   const R& lower(const SPxColId& id) const
540  	   {
541  	      return LPColSetBase<R>::lower(id);
542  	   }
543  	
544  	   /// Gets unscaled lower bound vector.
545  	   void getLowerUnscaled(VectorBase<R>& vec) const;
546  	
547  	   /// Returns unscaled lower bound of column \p i.
548  	   R lowerUnscaled(int i) const;
549  	
550  	   /// Returns unscaled lower bound of column with identifier \p id.
551  	   R lowerUnscaled(const SPxColId& id) const;
552  	
553  	   /// Returns the optimization sense.
554  	   SPxSense spxSense() const
555  	   {
556  	      return thesense;
557  	   }
558  	
559  	   /// Returns the objective function value offset
560  	   const R& objOffset() const
561  	   {
562  	      return offset;
563  	   }
564  	
565  	   /// Returns the row number of the row with identifier \p id.
566  	   int number(const SPxRowId& id) const
567  	   {
568  	      return LPRowSetBase<R>::number(id);
569  	   }
570  	
571  	   /// Returns the column number of the column with identifier \p id.
572  	   int number(const SPxColId& id) const
573  	   {
574  	      return LPColSetBase<R>::number(id);
575  	   }
576  	
577  	   /// Returns the row or column number for identifier \p id.
578  	   int number(const SPxId& id) const
579  	   {
580  	      return (id.type() == SPxId::COL_ID)
581  	             ? LPColSetBase<R>::number(id)
582  	             : LPRowSetBase<R>::number(id);
583  	   }
584  	
585  	   /// Returns the row number of the row with identifier \p id.
586  	   bool has(const SPxRowId& id) const
587  	   {
588  	      return LPRowSetBase<R>::has(id);
589  	   }
590  	
591  	   /// Returns the column number of the column with identifier \p id.
592  	   bool has(const SPxColId& id) const
593  	   {
594  	      return LPColSetBase<R>::has(id);
595  	   }
596  	
597  	   /// Returns the row or column number for identifier \p id.
598  	   bool has(const SPxId& id) const
599  	   {
600  	      return (id.type() == SPxId::COL_ID)
601  	             ? LPColSetBase<R>::has(id)
602  	             : LPRowSetBase<R>::has(id);
603  	   }
604  	
605  	   /// Returns the row identifier for row \p n.
606  	   SPxRowId rId(int n) const
607  	   {
608  	      return SPxRowId(LPRowSetBase<R>::key(n));
609  	   }
610  	
611  	   /// Returns the column identifier for column \p n.
612  	   SPxColId cId(int n) const
613  	   {
614  	      return SPxColId(LPColSetBase<R>::key(n));
615  	   }
616  	
617  	   ///@}
618  	
619  	   // ------------------------------------------------------------------------------------------------------------------
620  	   /**@name Extension */
621  	   ///@{
622  	
623  	   ///
624  	   virtual void addRow(const LPRowBase<R>& row, bool scale = false)
625  	   {
626  	      doAddRow(row, scale);
627  	   }
628  	
629  	   ///
630  	   virtual void addRow(const R& lhsValue, const SVectorBase<R>& rowVec, const R& rhsValue,
631  	                       bool scale = false)
632  	   {
633  	      doAddRow(lhsValue, rowVec, rhsValue, scale);
634  	   }
635  	
636  	   ///
637  	   template < class S >
638  	   void addRow(const S* lhsValue, const S* rowValues, const int* rowIndices, int rowSize,
639  	               const S* rhsValue)
640  	   {
641  	      assert(lhsValue != 0);
642  	      assert(rowSize <= 0 || rowValues != 0);
643  	      assert(rowSize <= 0 || rowIndices != 0);
644  	      assert(rhsValue != 0);
645  	
646  	      int idx = nRows();
647  	      int oldColNumber = nCols();
648  	
649  	      LPRowSetBase<R>::add(lhsValue, rowValues, rowIndices, rowSize, rhsValue);
650  	
651  	      // now insert nonzeros to column file also
652  	      for(int j = rowSize - 1; j >= 0; --j)
653  	      {
654  	         const S& val = rowValues[j];
655  	         int i = rowIndices[j];
656  	
657  	         // create new columns if required
658  	         if(i >= nCols())
659  	         {
660  	            LPColBase<R> empty;
661  	
662  	            for(int k = nCols(); k <= i; ++k)
663  	               LPColSetBase<R>::add(empty);
664  	         }
665  	
666  	         assert(i < nCols());
667  	         LPColSetBase<R>::add2(i, 1, &idx, &val);
668  	      }
669  	
670  	      addedRows(1);
671  	      addedCols(nCols() - oldColNumber);
672  	   }
673  	
674  	   /// Adds \p row to LPRowSetBase.
675  	   virtual void addRow(SPxRowId& id, const LPRowBase<R>& row, bool scale = false)
676  	   {
677  	      addRow(row, scale);
678  	      id = rId(nRows() - 1);
679  	   }
680  	
681  	   ///
682  	   virtual void addRows(const LPRowSetBase<R>& pset, bool scale = false)
683  	   {
684  	      doAddRows(pset, scale);
685  	   }
686  	
687  	   ///
688  	   template < class S >
689  	   void addRows(const S* lhsValues, const S* rowValues, const int* rowIndices, const int* rowStarts,
690  	                const int* rowLengths, const int numRows, const int numValues, const S* rhsValues)
691  	   {
692  	      assert(lhsValues != 0);
693  	      assert(numValues <= 0 || rowValues != 0);
694  	      assert(numValues <= 0 || rowIndices != 0);
695  	      assert(numValues <= 0 || rowStarts != 0);
696  	      assert(numValues <= 0 || rowLengths != 0);
697  	      assert(rhsValues != 0);
698  	
699  	      int i, j, k, idx;
700  	      SVectorBase<R>* col;
701  	      DataArray < int > newCols(nCols());
702  	      int oldRowNumber = nRows();
703  	      int oldColNumber = nCols();
704  	
705  	      LPRowSetBase<R>::memRemax(oldRowNumber + numRows);
706  	
707  	      for(i = 0; i < numRows; i++)
708  	      {
709  	         assert(numValues <= 0 || rowStarts[i] + rowLengths[i] <= numValues);
710  	
711  	         if(numValues <= 0)
712  	            LPRowSetBase<R>::add(&(lhsValues[i]), (S*)0, (int*)0, 0, &(rhsValues[i]));
713  	         else
714  	            LPRowSetBase<R>::add(&(lhsValues[i]), &(rowValues[rowStarts[i]]), &(rowIndices[rowStarts[i]]),
715  	                                 rowLengths[i], &(rhsValues[i]));
716  	      }
717  	
718  	      assert(LPRowSetBase<R>::isConsistent());
719  	      assert(LPColSetBase<R>::isConsistent());
720  	
721  	      // count additional nonzeros per column
722  	      for(i = nCols() - 1; i >= 0; --i)
723  	         newCols[i] = 0;
724  	
725  	      if(numValues > 0)
726  	      {
727  	         for(i = 0; i < numRows; i++)
728  	         {
729  	            for(j = rowStarts[i]; j < rowStarts[i] + rowLengths[i]; j++)
730  	            {
731  	               ///@todo implement the addition of new columns as in doAddRows()
732  	               assert(rowIndices[j] >= 0);
733  	               assert(rowIndices[j] < oldColNumber);
734  	               newCols[rowIndices[j]]++;
735  	            }
736  	         }
737  	      }
738  	
739  	      // extend columns as required (backward because of memory efficiency reasons)
740  	      for(i = nCols() - 1; i >= 0; --i)
741  	      {
742  	         if(newCols[i] > 0)
743  	         {
744  	            int len = newCols[i] + colVector(i).size();
745  	            LPColSetBase<R>::xtend(i, len);
746  	
747  	            /* preset the sizes: beware that this can irritate a consistency check call from xtend(). We need to set the
748  	             * sizes here, because a possible garbage collection called from xtend might destroy the sizes again. */
749  	            colVector_w(i).set_size(len);
750  	         }
751  	      }
752  	
753  	      // insert new elements to column file
754  	      for(i = nRows() - 1; i >= oldRowNumber; --i)
755  	      {
756  	         const SVectorBase<R>& vec = rowVector(i);
757  	
758  	         for(j = vec.size() - 1; j >= 0; --j)
759  	         {
760  	            k = vec.index(j);
761  	            col = &colVector_w(k);
762  	            idx = col->size() - newCols[k];
763  	            assert(newCols[k] > 0);
764  	            assert(idx >= 0);
765  	            newCols[k]--;
766  	            col->index(idx) = i;
767  	            col->value(idx) = vec.value(j);
768  	         }
769  	      }
770  	
771  	#ifndef NDEBUG
772  	
773  	      for(i = 0; i < nCols(); ++i)
774  	         assert(newCols[i] == 0);
775  	
776  	#endif
777  	
778  	      assert(SPxLPBase<R>::isConsistent());
779  	
780  	      assert(numRows == nRows() - oldRowNumber);
781  	      addedRows(nRows() - oldRowNumber);
782  	      addedCols(nCols() - oldColNumber);
783  	   }
784  	
785  	   /// adds all LPRowBase%s of \p pset to LPRowSetBase.
786  	   virtual void addRows(SPxRowId id[], const LPRowSetBase<R>& set, bool scale = false)
787  	   {
788  	      int i = nRows();
789  	      addRows(set, scale);
790  	
791  	      for(int j = 0; i < nRows(); ++i, ++j)
792  	         id[j] = rId(i);
793  	   }
794  	
795  	   ///
796  	   virtual void addCol(const LPColBase<R>& col, bool scale = false)
797  	   {
798  	      doAddCol(col, scale);
799  	   }
800  	
801  	   ///
802  	   virtual void addCol(const R& objValue, const R& lowerValue, const SVectorBase<R>& colVec,
803  	                       const R& upperValue, bool scale = false)
804  	   {
805  	      doAddCol(objValue, lowerValue, colVec, upperValue, scale);
806  	   }
807  	
808  	   ///
809  	   template < class S >
810  	   void addCol(const S* objValue, const S* lowerValue, const S* colValues, const int* colIndices,
811  	               int colSize, const S* upperValue)
812  	   {
813  	      int idx = nCols();
814  	      int oldRowNumber = nRows();
815  	
816  	      LPColSetBase<R>::add(objValue, lowerValue, colValues, colIndices, colSize, upperValue);
817  	
818  	      if(thesense != MAXIMIZE)
819  	         LPColSetBase<R>::maxObj_w(idx) *= -1;
820  	
821  	      // now insert nonzeros to column file also
822  	      for(int j = colSize - 1; j >= 0; --j)
823  	      {
824  	         const S& val = colValues[j];
825  	         int i = colIndices[j];
826  	
827  	         // create new rows if required
828  	         if(i >= nRows())
829  	         {
830  	            LPRowBase<R> empty;
831  	
832  	            for(int k = nRows(); k <= i; ++k)
833  	               LPRowSetBase<R>::add(empty);
834  	         }
835  	
836  	         assert(i < nRows());
837  	         LPRowSetBase<R>::add2(i, 1, &idx, &val);
838  	      }
839  	
840  	      addedCols(1);
841  	      addedRows(nRows() - oldRowNumber);
842  	   }
843  	
844  	   /// Adds \p col to LPColSetVBase.
845  	   virtual void addCol(SPxColId& id, const LPColBase<R>& col, bool scale = false)
846  	   {
847  	      addCol(col, scale);
848  	      id = cId(nCols() - 1);
849  	   }
850  	
851  	   ///
852  	   virtual void addCols(const LPColSetBase<R>& pset, bool scale = false)
853  	   {
854  	      doAddCols(pset, scale);
855  	   }
856  	
857  	   ///
858  	   template < class S >
859  	   void addCols(const S* objValue, const S* lowerValues, const S* colValues, const int* colIndices,
860  	                const int* colStarts, const int* colLengths, const int numCols, const int numValues,
861  	                const S* upperValues)
862  	   {
863  	      assert(lowerValues != 0);
864  	      assert(numValues <= 0 || colValues != 0);
865  	      assert(numValues <= 0 || colIndices != 0);
866  	      assert(numValues <= 0 || colStarts != 0);
867  	      assert(numValues <= 0 || colLengths != 0);
868  	      assert(upperValues != 0);
869  	
870  	      int i, j, k, idx;
871  	      SVectorBase<R>* row;
872  	      DataArray < int > newRows(nRows());
873  	      int oldColNumber = nCols();
874  	      int oldRowNumber = nRows();
875  	      idx = nCols();
876  	
877  	      LPColSetBase<R>::memRemax(oldColNumber + numCols);
878  	
879  	      for(i = 0; i < numCols; i++)
880  	      {
881  	         assert(numValues <= 0 || colStarts[i] + colLengths[i] <= numValues);
882  	
883  	         if(numValues <= 0)
884  	            LPColSetBase<R>::add(&(objValue[i]), &(lowerValues[i]), (S*)0, (int*)0, 0, &(upperValues[i]));
885  	         else
886  	            LPColSetBase<R>::add(&(objValue[i]), &(lowerValues[i]), &(colValues[colStarts[i]]),
887  	                                 &(colIndices[colStarts[i]]), colLengths[i], &(upperValues[i]));
888  	
889  	         if(thesense != MAXIMIZE)
890  	            LPColSetBase<R>::maxObj_w(idx + i) *= -1;
891  	      }
892  	
893  	      assert(LPColSetBase<R>::isConsistent());
894  	      assert(LPRowSetBase<R>::isConsistent());
895  	
896  	      // count additional nonzeros per rows
897  	      for(i = nRows() - 1; i >= 0; --i)
898  	         newRows[i] = 0;
899  	
900  	      for(i = numValues - 1; i >= 0; --i)
901  	      {
902  	         ///@todo implement the addition of new rows as in doAddCols()
903  	         assert(colIndices[i] >= 0);
904  	         assert(colIndices[i] < oldRowNumber);
905  	         newRows[colIndices[i]]++;
906  	      }
907  	
908  	      // extend rows as required (backward because of memory efficiency reasons)
909  	      for(i = nRows() - 1; i >= 0; --i)
910  	      {
911  	         if(newRows[i] > 0)
912  	         {
913  	            int len = newRows[i] + rowVector(i).size();
914  	            LPRowSetBase<R>::xtend(i, len);
915  	
916  	            /* preset the sizes: beware that this can irritate a consistency check call from xtend(). We need to set the
917  	             * sizes here, because a possible garbage collection called from xtend might destroy the sizes again. */
918  	            rowVector_w(i).set_size(len);
919  	         }
920  	      }
921  	
922  	      // insert new elements to row file
923  	      for(i = nCols() - 1; i >= oldColNumber; --i)
924  	      {
925  	         const SVectorBase<R>& vec = colVector(i);
926  	
927  	         for(j = vec.size() - 1; j >= 0; --j)
928  	         {
929  	            k = vec.index(j);
930  	            row = &rowVector_w(k);
931  	            idx = row->size() - newRows[k];
932  	            assert(newRows[k] > 0);
933  	            assert(idx >= 0);
934  	            newRows[k]--;
935  	            row->index(idx) = i;
936  	            row->value(idx) = vec.value(j);
937  	         }
938  	      }
939  	
940  	#ifndef NDEBUG
941  	
942  	      for(i = 0; i < nRows(); ++i)
943  	         assert(newRows[i] == 0);
944  	
945  	#endif
946  	
947  	      assert(SPxLPBase<R>::isConsistent());
948  	
949  	      assert(numCols == nCols() - oldColNumber);
950  	      addedCols(nCols() - oldColNumber);
951  	      addedRows(nRows() - oldRowNumber);
952  	   }
953  	
954  	   /// Adds all LPColBase%s of \p set to LPColSetBase.
955  	   virtual void addCols(SPxColId id[], const LPColSetBase<R>& set, bool scale = false)
956  	   {
957  	
958  	      int i = nCols();
959  	      addCols(set, scale);
960  	
961  	      for(int j = 0; i < nCols(); ++i, ++j)
962  	         id[j] = cId(i);
963  	   }
964  	
965  	   ///@}
966  	
967  	   // ------------------------------------------------------------------------------------------------------------------
968  	   /**@name Shrinking */
969  	   ///@{
970  	
971  	   /// Removes \p i 'th row.
972  	   virtual void removeRow(int i)
973  	   {
974  	      if(i < 0)
975  	         return;
976  	
977  	      doRemoveRow(i);
978  	   }
979  	
980  	   /// Removes row with identifier \p id.
981  	   virtual void removeRow(SPxRowId id)
982  	   {
983  	      removeRow(number(id));
984  	   }
985  	
986  	   /// Removes multiple rows.
987  	   /** This method removes all LPRowBase%s from the SPxLPBase with an index \p i such that \p perm[i] < 0. Upon
988  	    *  completion, \p perm[i] >= 0 indicates the new index where the \p i'th LPRowBase<R> has been moved to due to this
989  	    *  removal. Note that \p perm must point to an array of at least #nRows() ints.
990  	    */
991  	   virtual void removeRows(int perm[])
992  	   {
993  	      doRemoveRows(perm);
994  	   }
995  	
996  	   ///
997  	   virtual void removeRows(SPxRowId id[], int n, int perm[] = 0)
998  	   {
999  	
1000 	      if(perm == 0)
1001 	      {
1002 	         DataArray < int > p(nRows());
1003 	         removeRows(id, n, p.get_ptr());
1004 	         return;
1005 	      }
1006 	
1007 	      for(int i = nRows() - 1; i >= 0; --i)
1008 	         perm[i] = i;
1009 	
1010 	      while(n--)
1011 	         perm[number(id[n])] = -1;
1012 	
1013 	      removeRows(perm);
1014 	   }
1015 	
1016 	   /// Removes \p n LPRowBase%s.
1017 	   /** Removing multiple rows with one method invocation is available in two flavours. An array \p perm can be passed as
1018 	    *  third argument or not. If given, \p perm must be an array at least of size #nRows(). It is used to return the
1019 	    *  permutations resulting from this removal: \p perm[i] < 0 indicates, that the element to index \p i has been
1020 	    *  removed.  Otherwise, \p perm[i] is the new index of the element with index \p i before the removal.
1021 	    */
1022 	   virtual void removeRows(int nums[], int n, int perm[] = 0)
1023 	   {
1024 	
1025 	      if(perm == 0)
1026 	      {
1027 	         DataArray < int > p(nRows());
1028 	         removeRows(nums, n, p.get_ptr());
1029 	         return;
1030 	      }
1031 	
1032 	      for(int i = nRows() - 1; i >= 0; --i)
1033 	         perm[i] = i;
1034 	
1035 	      while(n--)
1036 	         perm[nums[n]] = -1;
1037 	
1038 	      removeRows(perm);
1039 	   }
1040 	
1041 	   /// Removes rows from \p start to \p end (including both).
1042 	   virtual void removeRowRange(int start, int end, int perm[] = 0)
1043 	   {
1044 	
1045 	      if(perm == 0)
1046 	      {
1047 	         int i = end - start + 1;
1048 	         DataArray < int > p(i);
1049 	
1050 	         while(--i >= 0)
1051 	            p[i] = start + i;
1052 	
1053 	         removeRows(p.get_ptr(), end - start + 1);
1054 	         return;
1055 	      }
1056 	
1057 	      int i;
1058 	
1059 	      for(i = 0; i < start; ++i)
1060 	         perm[i] = i;
1061 	
1062 	      for(; i <= end; ++i)
1063 	         perm[i] = -1;
1064 	
1065 	      for(; i < nRows(); ++i)
1066 	         perm[i] = i;
1067 	
1068 	      removeRows(perm);
1069 	   }
1070 	
1071 	   /// Removes \p i 'th column.
1072 	   virtual void removeCol(int i)
1073 	   {
1074 	      if(i < 0)
1075 	         return;
1076 	
1077 	      doRemoveCol(i);
1078 	   }
1079 	
1080 	   /// Removes column with identifier \p id.
1081 	   virtual void removeCol(SPxColId id)
1082 	   {
1083 	      removeCol(number(id));
1084 	   }
1085 	
1086 	   /// Removes multiple columns.
1087 	   /** This method removes all LPColBase%s from the SPxLPBase with an index \p i such that \p perm[i] < 0. Upon
1088 	    *  completion, \p perm[i] >= 0 indicates the new index where the \p i 'th LPColBase has been moved to due to this
1089 	    *  removal. Note, that \p perm must point to an array of at least #nCols() ints.
1090 	    */
1091 	   virtual void removeCols(int perm[])
1092 	   {
1093 	      doRemoveCols(perm);
1094 	   }
1095 	
1096 	   ///
1097 	   virtual void removeCols(SPxColId id[], int n, int perm[] = 0)
1098 	   {
1099 	
1100 	      if(perm == 0)
1101 	      {
1102 	         DataArray < int > p(nCols());
1103 	         removeCols(id, n, p.get_ptr());
1104 	         return;
1105 	      }
1106 	
1107 	      for(int i = nCols() - 1; i >= 0; --i)
1108 	         perm[i] = i;
1109 	
1110 	      while(n--)
1111 	         perm[number(id[n])] = -1;
1112 	
1113 	      removeCols(perm);
1114 	   }
1115 	
1116 	   /// Removes \p n LPCols.
1117 	   /** Removing multiple columns with one method invocation is available in two flavours. An array \p perm can be passed
1118 	    *  as third argument or not. If given, \p perm must be an array at least of size #nCols(). It is used to return the
1119 	    *  permutations resulting from this removal: \p perm[i] < 0 indicates, that the element to index \p i has been
1120 	    *  removed.  Otherwise, \p perm[i] is the new index of the element with index \p i before the removal.
1121 	    */
1122 	   virtual void removeCols(int nums[], int n, int perm[] = 0)
1123 	   {
1124 	
1125 	      if(perm == 0)
1126 	      {
1127 	         DataArray < int > p(nCols());
1128 	         removeCols(nums, n, p.get_ptr());
1129 	         return;
1130 	      }
1131 	
1132 	      for(int i = nCols() - 1; i >= 0; --i)
1133 	         perm[i] = i;
1134 	
1135 	      while(n--)
1136 	         perm[nums[n]] = -1;
1137 	
1138 	      removeCols(perm);
1139 	   }
1140 	
1141 	   /// Removes columns from \p start to \p end (including both).
1142 	   virtual void removeColRange(int start, int end, int perm[] = 0)
1143 	   {
1144 	
1145 	      if(perm == 0)
1146 	      {
1147 	         int i = end - start + 1;
1148 	         DataArray < int > p(i);
1149 	
1150 	         while(--i >= 0)
1151 	            p[i] = start + i;
1152 	
1153 	         removeCols(p.get_ptr(), end - start + 1);
1154 	         return;
1155 	      }
1156 	
1157 	      int i;
1158 	
1159 	      for(i = 0; i < start; ++i)
1160 	         perm[i] = i;
1161 	
1162 	      for(; i <= end; ++i)
1163 	         perm[i] = -1;
1164 	
1165 	      for(; i < nCols(); ++i)
1166 	         perm[i] = i;
1167 	
1168 	      removeCols(perm);
1169 	   }
1170 	
1171 	   /// clears the LP.
1172 	   virtual void clear()
1173 	   {
1174 	
1175 	      LPRowSetBase<R>::clear();
1176 	      LPColSetBase<R>::clear();
1177 	      thesense = MAXIMIZE;
1178 	      offset = 0;
1179 	      _isScaled = false;
1180 	      lp_scaler = nullptr;
1181 	      LPColSetBase<R>::scaleExp.clear();
1182 	      LPRowSetBase<R>::scaleExp.clear();
1183 	   }
1184 	
1185 	   ///@}
1186 	
1187 	   // ------------------------------------------------------------------------------------------------------------------
1188 	   /**@name IO */
1189 	   ///@{
1190 	
1191 	   /// Reads LP in LP format from input stream \p in.
1192 	   virtual bool readLPF(std::istream& in, NameSet* rowNames = 0, NameSet* colNames = 0,
1193 	                        DIdxSet* intVars = 0);
1194 	
1195 	   /// Reads an LP in MPS format from input stream \p in.
1196 	   virtual bool readMPS(std::istream& in, NameSet* rowNames = 0, NameSet* colNames = 0,
1197 	                        DIdxSet* intVars = 0);
1198 	
1199 	   /// Reads LP in LP or MPS format from input stream \p in.
1200 	   /**@param in       input stream.
1201 	    * @param rowNames contains after the call the names of the constraints (rows) in the same order as the rows in the
1202 	    *                 LP.  Constraints without a name (only possible with LPF files) are automatically assigned a name.
1203 	    *                 Maybe 0 if the names are not needed.
1204 	    * @param colNames contains after the call the names of the variables (columns) in the same order as the columns in
1205 	    *                 the LP.  Maybe 0 if the names are not needed.
1206 	    * @param intVars contains after the call the indices of those variables that where marked as beeing integer in the
1207 	    *                 file.  Maybe 0 if the information is not needed.
1208 	    * @todo Make sure the Id's in the NameSet%s are the same as in the LP.
1209 	    */
1210 	   virtual bool read(std::istream& in, NameSet* rowNames = 0, NameSet* colNames = 0,
1211 	                     DIdxSet* intVars  = 0)
1212 	   {
1213 	      bool ok;
1214 	      char c;
1215 	
1216 	      in.get(c);
1217 	      in.putback(c);
1218 	
1219 	      /* MPS starts either with a comment mark '*' or with the keyword 'NAME' at the first column.  LPF starts either
1220 	       * with blanks, a comment mark '\' or with the keyword "MAX" or "MIN" in upper or lower case.  There is no
1221 	       * possible valid LPF file starting with a '*' or 'N'.
1222 	       */
1223 	      ok = ((c == '*') || (c == 'N'))
1224 	           ? readMPS(in, rowNames, colNames, intVars)
1225 	           : readLPF(in, rowNames, colNames, intVars);
1226 	
1227 	      return ok;
1228 	   }
1229 	
1230 	   /// Reads LP from a file.
1231 	   virtual bool readFile(const char* filename, NameSet* rowNames = 0, NameSet* colNames = 0,
1232 	                         DIdxSet* intVars = 0)
1233 	   {
1234 	
1235 	      spxifstream file(filename);
1236 	
1237 	      if(!file)
1238 	         return false;
1239 	
1240 	      return read(file, rowNames, colNames, intVars);
1241 	   }
1242 	
1243 	   /** Writes a file in LP format to \p out. If \p rowNames and \p colNames are \c NULL, default names are used for the
1244 	    *  constraints and variables. If \p intVars is not \c NULL, the variables contained in it are marked as integer in
1245 	    *  the output.
1246 	    */
1247 	   virtual void writeLPF(std::ostream&  out, const NameSet* rowNames, const NameSet* colNames,
1248 	                         const DIdxSet* p_intvars = 0) const;
1249 	
1250 	   /// Writes a file in MPS format to \p out.
1251 	   virtual void writeMPS(std::ostream&  out, const NameSet* rowNames, const NameSet* colNames,
1252 	                         const DIdxSet* p_intvars = 0) const;
1253 	
1254 	   /// Write loaded LP to \p filename.
1255 	   virtual void writeFileLPBase(const char* filename, const NameSet* rowNames = 0,
1256 	                                const NameSet* colNames = 0, const DIdxSet* p_intvars = 0) const
1257 	   {
1258 	
1259 	      std::ofstream tmp(filename);
1260 	      size_t len_f = strlen(filename);
1261 	
1262 	      if(len_f > 4 && filename[len_f - 1] == 's' && filename[len_f - 2] == 'p'
1263 	            && filename[len_f - 3] == 'm' && filename[len_f - 4] == '.')
1264 	      {
1265 	         writeMPS(tmp, rowNames, colNames, p_intvars);
1266 	      }
1267 	      else
1268 	      {
1269 	         writeLPF(tmp, rowNames, colNames, p_intvars);
1270 	      }
1271 	   }
1272 	
1273 	   /** prints problem statistics */
1274 	   void printProblemStatistics(std::ostream& os)
1275 	   {
1276 	      int countLower = 0;
1277 	      int countUpper = 0;
1278 	      int countBoxed = 0;
1279 	      int countFreeCol = 0;
1280 	
1281 	      int countEqual = 0;
1282 	      int countLhs = 0;
1283 	      int countRhs = 0;
1284 	      int countRanged = 0;
1285 	      int countFreeRow = 0;
1286 	
1287 	      for(int i = 0; i < nCols(); i++)
1288 	      {
1289 	         bool hasLower = false;
1290 	         bool hasUpper = false;
1291 	
1292 	         if(lower(i) > R(-infinity))
1293 	         {
1294 	            countLower++;
1295 	            hasLower = true;
1296 	         }
1297 	
1298 	         if(upper(i) < R(infinity))
1299 	         {
1300 	            countUpper++;
1301 	            hasUpper = true;
1302 	         }
1303 	
1304 	         if(hasUpper && hasLower)
1305 	         {
1306 	            countBoxed++;
1307 	            countLower--;
1308 	            countUpper--;
1309 	         }
1310 	
1311 	         if(!hasUpper && !hasLower)
1312 	            countFreeCol++;
1313 	      }
1314 	
1315 	      for(int i = 0; i < nRows(); i++)
1316 	      {
1317 	         bool hasRhs = false;
1318 	         bool hasLhs = false;
1319 	
1320 	         if(lhs(i) > R(-infinity))
1321 	         {
1322 	            countLhs++;
1323 	            hasLhs = true;
1324 	         }
1325 	
1326 	         if(rhs(i) < R(infinity))
1327 	         {
1328 	            countRhs++;
1329 	            hasRhs = true;
1330 	         }
1331 	
1332 	         if(hasRhs && hasLhs)
1333 	         {
1334 	            if(EQ(lhs(i), rhs(i), this->tolerances()->epsilon()))
1335 	               countEqual++;
1336 	            else
1337 	               countRanged++;
1338 	
1339 	            countLhs--;
1340 	            countRhs--;
1341 	         }
1342 	
1343 	         if(!hasRhs && !hasLhs)
1344 	            countFreeRow++;
1345 	      }
1346 	
1347 	      SPxOut::setFixed(os);
1348 	      os << "  Columns           : " << nCols() << "\n"
1349 	         << "              boxed : " << countBoxed << "\n"
1350 	         << "        lower bound : " << countLower << "\n"
1351 	         << "        upper bound : " << countUpper << "\n"
1352 	         << "               free : " << countFreeCol << "\n"
1353 	         << "  Rows              : " << nRows() << "\n"
1354 	         << "              equal : " << countEqual << "\n"
1355 	         << "             ranged : " << countRanged << "\n"
1356 	         << "                lhs : " << countLhs << "\n"
1357 	         << "                rhs : " << countRhs << "\n"
1358 	         << "               free : " << countFreeRow << "\n"
1359 	         << "  Nonzeros          : " << nNzos() << "\n"
1360 	         << "         per column : " << R(nNzos()) / R(nCols()) << "\n"
1361 	         << "            per row : " << R(nNzos()) / R(nRows()) << "\n"
1362 	         << "           sparsity : " << R(nNzos()) / R(nCols()) / R(nRows()) << "\n"
1363 	         << "    min. abs. value : " << R(minAbsNzo()) << "\n"
1364 	         << "    max. abs. value : " << R(maxAbsNzo()) << "\n";
1365 	   }
1366 	
1367 	   ///@}
1368 	
1369 	   // ------------------------------------------------------------------------------------------------------------------
1370 	   /**@name Manipulation */
1371 	   ///@{
1372 	
1373 	   /// Changes objective vector to \p newObj. \p scale determines whether the new data should be scaled
1374 	   virtual void changeObj(const VectorBase<R>& newObj, bool scale = false)
1375 	   {
1376 	      changeMaxObj(newObj, scale);
1377 	
1378 	      if(spxSense() == MINIMIZE)
1379 	         LPColSetBase<R>::maxObj_w() *= -1;
1380 	   }
1381 	
1382 	   /// changes \p i 'th objective vector element to \p newVal. \p scale determines whether the new data should be scaled
1383 	   virtual void changeObj(int i, const R& newVal, bool scale = false)
1384 	   {
1385 	      changeMaxObj(i, newVal, scale);
1386 	
1387 	      if(spxSense() == MINIMIZE)
1388 	         LPColSetBase<R>::maxObj_w(i) *= -1;
1389 	   }
1390 	
1391 	   /// changes \p i 'th objective vector element to \p newVal.
1392 	   template < class S >
1393 	   void changeObj(int i, const S* newVal)
1394 	   {
1395 	      LPColSetBase<R>::maxObj_w(i) = *newVal;
1396 	
1397 	      if(spxSense() == MINIMIZE)
1398 	         LPColSetBase<R>::maxObj_w(i) *= -1;
1399 	
1400 	      assert(isConsistent());
1401 	   }
1402 	
1403 	   /// Changes objective value of column with identifier \p id to \p newVal. \p scale determines whether the new data should be scaled
1404 	   virtual void changeObj(SPxColId id, const R& newVal, bool scale = false)
1405 	   {
1406 	      this->changeObj(number(id), newVal, scale);
1407 	   }
1408 	
1409 	   /// Changes objective vector to \p newObj. \p scale determines whether the new data should be scaled
1410 	   virtual void changeMaxObj(const VectorBase<R>& newObj, bool scale = false)
1411 	   {
1412 	      assert(maxObj().dim() == newObj.dim());
1413 	
1414 	      if(scale)
1415 	      {
1416 	         assert(_isScaled);
1417 	         assert(lp_scaler);
1418 	
1419 	         for(int i = 0; i < maxObj().dim(); i++)
1420 	            LPColSetBase<R>::maxObj_w(i) = lp_scaler->scaleObj(*this, i, newObj[i]);
1421 	      }
1422 	      else
1423 	         LPColSetBase<R>::maxObj_w() = newObj;
1424 	
1425 	      assert(isConsistent());
1426 	   }
1427 	
1428 	   /// changes \p i 'th objective vector element to \p newVal. \p scale determines whether the new data should be scaled
1429 	   virtual void changeMaxObj(int i, const R& newVal, bool scale = false)
1430 	   {
1431 	      if(scale)
1432 	      {
1433 	         assert(_isScaled);
1434 	         assert(lp_scaler);
1435 	         LPColSetBase<R>::maxObj_w(i) = lp_scaler->scaleObj(*this, i, newVal);
1436 	      }
1437 	      else
1438 	         LPColSetBase<R>::maxObj_w(i) = newVal;
1439 	
1440 	      assert(isConsistent());
1441 	   }
1442 	
1443 	   /// changes \p i 'th objective vector element to \p newVal.
1444 	   template < class S >
1445 	   void changeMaxObj(int i, const S* newVal)
1446 	   {
1447 	      LPColSetBase<R>::maxObj_w(i) = *newVal;
1448 	      assert(isConsistent());
1449 	   }
1450 	
1451 	   /// Changes objective value of column with identifier \p id to \p newVal. \p scale determines whether the new data should be scaled
1452 	   virtual void changeMaxObj(SPxColId id, const R& newVal, bool scale = false)
1453 	   {
1454 	      changeMaxObj(number(id), newVal, scale);
1455 	   }
1456 	
1457 	   /// Changes vector of lower bounds to \p newLower. \p scale determines whether the new data should be scaled
1458 	   virtual void changeLower(const VectorBase<R>& newLower, bool scale = false)
1459 	   {
1460 	      assert(lower().dim() == newLower.dim());
1461 	
1462 	      if(scale)
1463 	      {
1464 	         assert(_isScaled);
1465 	         assert(lp_scaler);
1466 	
1467 	         for(int i = 0; i < lower().dim(); i++)
1468 	            LPColSetBase<R>::lower_w(i) = lp_scaler->scaleLower(*this, i, newLower[i]);
1469 	      }
1470 	      else
1471 	         LPColSetBase<R>::lower_w() = newLower;
1472 	
1473 	      assert(isConsistent());
1474 	   }
1475 	
1476 	   /// changes \p i 'th lower bound to \p newLower. \p scale determines whether the new data should be scaled
1477 	   virtual void changeLower(int i, const R& newLower, bool scale = false)
1478 	   {
1479 	      if(scale && newLower > R(-infinity))
1480 	      {
1481 	         assert(_isScaled);
1482 	         assert(lp_scaler);
1483 	         LPColSetBase<R>::lower_w(i) = lp_scaler->scaleLower(*this, i, newLower);
1484 	      }
1485 	      else
1486 	         LPColSetBase<R>::lower_w(i) = newLower;
1487 	
1488 	      assert(isConsistent());
1489 	   }
1490 	
1491 	   /// changes \p i 'th lower bound to \p newLower.
1492 	   template < class S >
1493 	   void changeLower(int i, const S* newLower)
1494 	   {
1495 	      LPColSetBase<R>::lower_w(i) = *newLower;
1496 	      assert(isConsistent());
1497 	   }
1498 	
1499 	   /// changes lower bound of column with identifier \p id to \p newLower. \p scale determines whether the new data should be scaled
1500 	   virtual void changeLower(SPxColId id, const R& newLower, bool scale = false)
1501 	   {
1502 	      changeLower(number(id), newLower, scale);
1503 	   }
1504 	
1505 	   /// Changes vector of upper bounds to \p newUpper. \p scale determines whether the new data should be scaled
1506 	   virtual void changeUpper(const VectorBase<R>& newUpper, bool scale = false)
1507 	   {
1508 	      assert(upper().dim() == newUpper.dim());
1509 	
1510 	      if(scale)
1511 	      {
1512 	         assert(_isScaled);
1513 	         assert(lp_scaler);
1514 	
1515 	         for(int i = 0; i < upper().dim(); i++)
1516 	            LPColSetBase<R>::upper_w(i) = lp_scaler->scaleUpper(*this, i, newUpper[i]);
1517 	      }
1518 	      else
1519 	         LPColSetBase<R>::upper_w() = newUpper;
1520 	
1521 	      assert(isConsistent());
1522 	   }
1523 	
1524 	   /// Changes \p i 'th upper bound to \p newUpper. \p scale determines whether the new data should be scaled
1525 	   virtual void changeUpper(int i, const R& newUpper, bool scale = false)
1526 	   {
1527 	      if(scale && newUpper < R(infinity))
1528 	      {
1529 	         assert(_isScaled);
1530 	         assert(lp_scaler);
1531 	         LPColSetBase<R>::upper_w(i) = lp_scaler->scaleUpper(*this, i, newUpper);
1532 	      }
1533 	      else
1534 	         LPColSetBase<R>::upper_w(i) = newUpper;
1535 	
1536 	      assert(isConsistent());
1537 	   }
1538 	
1539 	   /// Changes \p i 'th upper bound to \p newUpper.
1540 	   template < class S >
1541 	   void changeUpper(int i, const S* newUpper)
1542 	   {
1543 	      LPColSetBase<R>::upper_w(i) = *newUpper;
1544 	      assert(isConsistent());
1545 	   }
1546 	
1547 	   /// Changes upper bound of column with identifier \p id to \p newLower. \p scale determines whether the new data should be scaled
1548 	   virtual void changeUpper(SPxColId id, const R& newUpper, bool scale = false)
1549 	   {
1550 	      changeUpper(number(id), newUpper, scale);
1551 	   }
1552 	
1553 	   /// Changes variable bounds to \p newLower and \p newUpper. \p scale determines whether the new data should be scaled
1554 	   virtual void changeBounds(const VectorBase<R>& newLower, const VectorBase<R>& newUpper,
1555 	                             bool scale = false)
1556 	   {
1557 	      changeLower(newLower, scale);
1558 	      changeUpper(newUpper, scale);
1559 	      assert(isConsistent());
1560 	   }
1561 	
1562 	   /// Changes bounds of column \p i to \p newLower and \p newUpper. \p scale determines whether the new data should be scaled
1563 	   virtual void changeBounds(int i, const R& newLower, const R& newUpper, bool scale = false)
1564 	   {
1565 	      changeLower(i, newLower, scale);
1566 	      changeUpper(i, newUpper, scale);
1567 	      assert(isConsistent());
1568 	   }
1569 	
1570 	   /// Changes bounds of column \p i to \p newLower and \p newUpper.
1571 	   template < class S >
1572 	   void changeBounds(int i, const S* newLower, const S* newUpper)
1573 	   {
1574 	      LPColSetBase<R>::lower_w(i) = *newLower;
1575 	      LPColSetBase<R>::upper_w(i) = *newUpper;
1576 	      assert(isConsistent());
1577 	   }
1578 	
1579 	   /// Changes bounds of column with identifier \p id. \p scale determines whether the new data should be scaled
1580 	   virtual void changeBounds(SPxColId id, const R& newLower, const R& newUpper, bool scale = false)
1581 	   {
1582 	      changeBounds(number(id), newLower, newUpper, scale);
1583 	   }
1584 	
1585 	   /// Changes left hand side vector for constraints to \p newLhs. \p scale determines whether the new data should be scaled
1586 	   virtual void changeLhs(const VectorBase<R>& newLhs, bool scale = false)
1587 	   {
1588 	      assert(lhs().dim() == newLhs.dim());
1589 	
1590 	      if(scale)
1591 	      {
1592 	         assert(_isScaled);
1593 	         assert(lp_scaler);
1594 	
1595 	         for(int i = 0; i < lhs().dim(); i++)
1596 	            LPRowSetBase<R>::lhs_w(i) = lp_scaler->scaleLhs(*this, i, newLhs[i]);
1597 	      }
1598 	      else
1599 	         LPRowSetBase<R>::lhs_w() = newLhs;
1600 	
1601 	      assert(isConsistent());
1602 	   }
1603 	
1604 	   /// Changes \p i 'th left hand side value to \p newLhs. \p scale determines whether the new data should be scaled
1605 	   virtual void changeLhs(int i, const R& newLhs, bool scale = false)
1606 	   {
1607 	      if(scale && newLhs > R(-infinity))
1608 	      {
1609 	         assert(_isScaled);
1610 	         assert(lp_scaler);
1611 	         LPRowSetBase<R>::lhs_w(i) = lp_scaler->scaleLhs(*this, i, newLhs);
1612 	      }
1613 	      else
1614 	         LPRowSetBase<R>::lhs_w(i) = newLhs;
1615 	
1616 	      assert(isConsistent());
1617 	   }
1618 	
1619 	   /// Changes \p i 'th left hand side value to \p newLhs.
1620 	   template < class S >
1621 	   void changeLhs(int i, const S* newLhs)
1622 	   {
1623 	      LPRowSetBase<R>::lhs_w(i) = *newLhs;
1624 	      assert(isConsistent());
1625 	   }
1626 	
1627 	   /// Changes left hand side value for row with identifier \p id. \p scale determines whether the new data should be scaled
1628 	   virtual void changeLhs(SPxRowId id, const R& newLhs, bool scale = false)
1629 	   {
1630 	      changeLhs(number(id), newLhs, scale);
1631 	   }
1632 	
1633 	   /// Changes right hand side vector for constraints to \p newRhs. \p scale determines whether the new data should be scaled
1634 	   virtual void changeRhs(const VectorBase<R>& newRhs, bool scale = false)
1635 	   {
1636 	      assert(rhs().dim() == newRhs.dim());
1637 	
1638 	      if(scale)
1639 	      {
1640 	         assert(_isScaled);
1641 	         assert(lp_scaler);
1642 	
1643 	         for(int i = 0; i < rhs().dim(); i++)
1644 	            LPRowSetBase<R>::rhs_w(i) = lp_scaler->scaleRhs(*this, i, newRhs[i]);
1645 	      }
1646 	      else
1647 	         LPRowSetBase<R>::rhs_w() = newRhs;
1648 	
1649 	      assert(isConsistent());
1650 	   }
1651 	
1652 	   /// Changes \p i 'th right hand side value to \p newRhs. \p scale determines whether the new data should be scaled
1653 	   virtual void changeRhs(int i, const R& newRhs, bool scale = false)
1654 	   {
1655 	      if(scale && newRhs < R(infinity))
1656 	      {
1657 	         assert(_isScaled);
1658 	         assert(lp_scaler);
1659 	         LPRowSetBase<R>::rhs_w(i) = lp_scaler->scaleRhs(*this, i, newRhs);
1660 	      }
1661 	      else
1662 	         LPRowSetBase<R>::rhs_w(i) = newRhs;
1663 	
1664 	      assert(isConsistent());
1665 	   }
1666 	
1667 	   /// Changes right hand side value for row with identifier \p id. \p scale determines whether the new data should be scaled
1668 	   virtual void changeRhs(SPxRowId id, const R& newRhs, bool scale = false)
1669 	   {
1670 	      changeRhs(number(id), newRhs, scale);
1671 	   }
1672 	
1673 	   /// Changes left and right hand side vectors. \p scale determines whether the new data should be scaled
1674 	   virtual void changeRange(const VectorBase<R>& newLhs, const VectorBase<R>& newRhs,
1675 	                            bool scale = false)
1676 	   {
1677 	      changeLhs(newLhs, scale);
1678 	      changeRhs(newRhs, scale);
1679 	      assert(isConsistent());
1680 	   }
1681 	
1682 	   /// Changes left and right hand side of row \p i. \p scale determines whether the new data should be scaled
1683 	   virtual void changeRange(int i, const R& newLhs, const R& newRhs, bool scale = false)
1684 	   {
1685 	      changeLhs(i, newLhs, scale);
1686 	      changeRhs(i, newRhs, scale);
1687 	      assert(isConsistent());
1688 	   }
1689 	
1690 	   /// Changes left and right hand side of row \p i.
1691 	   template < class S >
1692 	   void changeRange(int i, const S* newLhs, const S* newRhs)
1693 	   {
1694 	      LPRowSetBase<R>::lhs_w(i) = *newLhs;
1695 	      LPRowSetBase<R>::rhs_w(i) = *newRhs;
1696 	      assert(isConsistent());
1697 	   }
1698 	
1699 	   /// Changes left and right hand side of row with identifier \p id. \p scale determines whether the new data should be scaled
1700 	   virtual void changeRange(SPxRowId id, const R& newLhs, const R& newRhs, bool scale = false)
1701 	   {
1702 	      changeRange(number(id), newLhs, newRhs, scale);
1703 	   }
1704 	
1705 	   /// Changes row objective function vector to \p newRowObj. \p scale determines whether the new data should be scaled
1706 	   virtual void changeRowObj(const VectorBase<R>& newRowObj, bool scale = false)
1707 	   {
1708 	      assert(maxRowObj().dim() == newRowObj.dim());
1709 	      LPRowSetBase<R>::obj_w() = newRowObj;
1710 	
1711 	      if(spxSense() == MINIMIZE)
1712 	         LPRowSetBase<R>::obj_w() *= -1;
1713 	
1714 	      assert(isConsistent());
1715 	   }
1716 	
1717 	   /// Changes \p i 'th row objective function value to \p newRowObj. \p scale determines whether the new data should be scaled
1718 	   virtual void changeRowObj(int i, const R& newRowObj, bool scale = false)
1719 	   {
1720 	      LPRowSetBase<R>::obj_w(i) = newRowObj;
1721 	
1722 	      if(spxSense() == MINIMIZE)
1723 	         LPRowSetBase<R>::obj_w(i) *= -1;
1724 	
1725 	      assert(isConsistent());
1726 	   }
1727 	
1728 	   /// Changes row objective function value for row with identifier \p id. \p scale determines whether the new data should be scaled
1729 	   virtual void changeRowObj(SPxRowId id, const R& newRowObj, bool scale = false)
1730 	   {
1731 	      changeRowObj(number(id), newRowObj, scale);
1732 	   }
1733 	
1734 	   /// Clears row objective function values for all rows
1735 	   virtual void clearRowObjs()
1736 	   {
1737 	      LPRowSetBase<R>::obj_w().clear();
1738 	   }
1739 	
1740 	   /// Replaces \p i 'th row of LP with \p newRow. \p scale determines whether the new data should be scaled
1741 	   virtual void changeRow(int n, const LPRowBase<R>& newRow, bool scale = false)
1742 	   {
1743 	      if(n < 0)
1744 	         return;
1745 	
1746 	      int j;
1747 	      SVectorBase<R>& row = rowVector_w(n);
1748 	
1749 	      for(j = row.size() - 1; j >= 0; --j)
1750 	      {
1751 	         SVectorBase<R>& col = colVector_w(row.index(j));
1752 	         int position = col.pos(n);
1753 	
1754 	         assert(position != -1);
1755 	
1756 	         if(position >= 0)
1757 	            col.remove(position);
1758 	      }
1759 	
1760 	      row.clear();
1761 	
1762 	      changeLhs(n, newRow.lhs(), scale);
1763 	      changeRhs(n, newRow.rhs(), scale);
1764 	      changeRowObj(n, newRow.obj(), scale);
1765 	
1766 	      const SVectorBase<R>& newrow = newRow.rowVector();
1767 	
1768 	      for(j = newrow.size() - 1; j >= 0; --j)
1769 	      {
1770 	         int idx = newrow.index(j);
1771 	         R val = newrow.value(j);
1772 	
1773 	         if(scale)
1774 	            val = spxLdexp(val, LPRowSetBase<R>::scaleExp[n] + LPColSetBase<R>::scaleExp[idx]);
1775 	
1776 	         LPRowSetBase<R>::add2(n, 1, &idx, &val);
1777 	         LPColSetBase<R>::add2(idx, 1, &n, &val);
1778 	      }
1779 	
1780 	      assert(isConsistent());
1781 	   }
1782 	
1783 	   /// Replaces row with identifier \p id with \p newRow. \p scale determines whether the new data should be scaled
1784 	   virtual void changeRow(SPxRowId id, const LPRowBase<R>& newRow, bool scale = false)
1785 	   {
1786 	      changeRow(number(id), newRow, scale);
1787 	   }
1788 	
1789 	   /// Replaces \p i 'th column of LP with \p newCol. \p scale determines whether the new data should be scaled
1790 	   virtual void changeCol(int n, const LPColBase<R>& newCol, bool scale = false)
1791 	   {
1792 	      if(n < 0)
1793 	         return;
1794 	
1795 	      int j;
1796 	      SVectorBase<R>& col = colVector_w(n);
1797 	
1798 	      for(j = col.size() - 1; j >= 0; --j)
1799 	      {
1800 	         SVectorBase<R>& row = rowVector_w(col.index(j));
1801 	         int position = row.pos(n);
1802 	
1803 	         assert(position != -1);
1804 	
1805 	         if(position >= 0)
1806 	            row.remove(position);
1807 	      }
1808 	
1809 	      col.clear();
1810 	
1811 	      changeUpper(n, newCol.upper(), scale);
1812 	      changeLower(n, newCol.lower(), scale);
1813 	      changeObj(n, newCol.obj(), scale);
1814 	
1815 	      const SVectorBase<R>& newcol = newCol.colVector();
1816 	
1817 	      for(j = newcol.size() - 1; j >= 0; --j)
1818 	      {
1819 	         int idx = newcol.index(j);
1820 	         R val = newcol.value(j);
1821 	
1822 	         if(scale)
1823 	            val = spxLdexp(val, LPColSetBase<R>::scaleExp[n] + LPRowSetBase<R>::scaleExp[idx]);
1824 	
1825 	         LPColSetBase<R>::add2(n, 1, &idx, &val);
1826 	         LPRowSetBase<R>::add2(idx, 1, &n, &val);
1827 	      }
1828 	
1829 	      assert(isConsistent());
1830 	   }
1831 	
1832 	   /// Replaces column with identifier \p id with \p newCol. \p scale determines whether the new data should be scaled
1833 	   virtual void changeCol(SPxColId id, const LPColBase<R>& newCol, bool scale = false)
1834 	   {
1835 	      changeCol(number(id), newCol, scale);
1836 	   }
1837 	
1838 	   /// Changes LP element (\p i, \p j) to \p val. \p scale determines whether the new data should be scaled
1839 	   virtual void changeElement(int i, int j, const R& val, bool scale = false)
1840 	   {
1841 	      if(i < 0 || j < 0)
1842 	         return;
1843 	
1844 	      SVectorBase<R>& row = rowVector_w(i);
1845 	      SVectorBase<R>& col = colVector_w(j);
1846 	
1847 	      if(isNotZero(val, this->tolerances()->epsilon()))
1848 	      {
1849 	         R newVal;
1850 	
1851 	         if(scale)
1852 	         {
1853 	            assert(_isScaled);
1854 	            assert(lp_scaler);
1855 	            newVal = lp_scaler->scaleElement(*this, i, j, val);
1856 	         }
1857 	         else
1858 	            newVal = val;
1859 	
1860 	         if(row.pos(j) >= 0 && col.pos(i) >= 0)
1861 	         {
1862 	            row.value(row.pos(j)) = newVal;
1863 	            col.value(col.pos(i)) = newVal;
1864 	         }
1865 	         else
1866 	         {
1867 	            LPRowSetBase<R>::add2(i, 1, &j, &newVal);
1868 	            LPColSetBase<R>::add2(j, 1, &i, &newVal);
1869 	         }
1870 	      }
1871 	      else if(row.pos(j) >= 0 && col.pos(i) >= 0)
1872 	      {
1873 	         row.remove(row.pos(j));
1874 	         col.remove(col.pos(i));
1875 	      }
1876 	
1877 	      assert(isConsistent());
1878 	   }
1879 	
1880 	   /// Changes LP element (\p i, \p j) to \p val.
1881 	   template < class S >
1882 	   void changeElement(int i, int j, const S* val)
1883 	   {
1884 	      if(i < 0 || j < 0)
1885 	         return;
1886 	
1887 	      SVectorBase<R>& row = rowVector_w(i);
1888 	      SVectorBase<R>& col = colVector_w(j);
1889 	
1890 	      if(mpq_get_d(*val) != R(0))
1891 	      {
1892 	         if(row.pos(j) >= 0 && col.pos(i) >= 0)
1893 	         {
1894 	            row.value(row.pos(j)) = *val;
1895 	            col.value(col.pos(i)) = *val;
1896 	         }
1897 	         else
1898 	         {
1899 	            LPRowSetBase<R>::add2(i, 1, &j, val);
1900 	            LPColSetBase<R>::add2(j, 1, &i, val);
1901 	         }
1902 	      }
1903 	      else if(row.pos(j) >= 0 && col.pos(i) >= 0)
1904 	      {
1905 	         row.remove(row.pos(j));
1906 	         col.remove(col.pos(i));
1907 	      }
1908 	
1909 	      assert(isConsistent());
1910 	   }
1911 	
1912 	   /// Changes LP element identified by (\p rid, \p cid) to \p val. \p scale determines whether the new data should be scaled
1913 	   virtual void changeElement(SPxRowId rid, SPxColId cid, const R& val, bool scale = false)
1914 	   {
1915 	      changeElement(number(rid), number(cid), val, scale);
1916 	   }
1917 	
1918 	   /// Changes optimization sense to \p sns.
1919 	   virtual void changeSense(SPxSense sns)
1920 	   {
1921 	      if(sns != thesense)
1922 	      {
1923 	         LPColSetBase<R>::maxObj_w() *= -1;
1924 	         LPRowSetBase<R>::obj_w() *= -1;
1925 	      }
1926 	
1927 	      thesense = sns;
1928 	   }
1929 	
1930 	   template <typename T>
1931 	   void changeObjOffset(const T& o)
1932 	   {
1933 	      offset = o;               // Converts o into type R. Example Rational into
1934 	      // R
1935 	   }
1936 	
1937 	   /// Computes activity of the rows for a given primal vector; activity does not need to be zero
1938 	   /// @throw SPxInternalCodeException if the dimension of primal vector does not match number of columns or if the
1939 	   ///        dimension of the activity vector does not match the number of rows
1940 	   /// \p unscaled determines whether the returned data should be unscaled (if scaling was applied prior)
1941 	   virtual void computePrimalActivity(const VectorBase<R>& primal, VectorBase<R>& activity,
1942 	                                      const bool unscaled = true) const;
1943 	
1944 	   /// Updates activity of the rows for a given primal vector; activity does not need to be zero
1945 	   /// @throw SPxInternalCodeException if the dimension of primal vector does not match number of columns or if the
1946 	   ///        dimension of the activity vector does not match the number of rows
1947 	   virtual void addPrimalActivity(const SVectorBase<R>& primal, VectorBase<R>& activity) const
1948 	   {
1949 	      if(activity.dim() != nRows())
1950 	      {
1951 	         throw SPxInternalCodeException("XSPXLP03 Activity vector computing row activity has wrong dimension");
1952 	      }
1953 	
1954 	      for(int i = primal.size() - 1; i >= 0; i--)
1955 	      {
1956 	         assert(primal.index(i) >= 0);
1957 	         assert(primal.index(i) < nCols());
1958 	         activity.multAdd(primal.value(i), colVector(primal.index(i)));
1959 	      }
1960 	   }
1961 	
1962 	   /// Computes "dual" activity of the columns for a given dual vector, i.e., y^T A; activity does not need to be zero
1963 	   /// @throw SPxInternalCodeException if dimension of dual vector does not match number of rows or if the dimension of
1964 	   ///        the activity vector does not match the number of columns
1965 	   virtual void computeDualActivity(const VectorBase<R>& dual, VectorBase<R>& activity,
1966 	                                    const bool unscaled = true) const;
1967 	
1968 	   /// Updates "dual" activity of the columns for a given dual vector, i.e., y^T A; activity does not need to be zero
1969 	   /// @throw SPxInternalCodeException if dimension of dual vector does not match number of rows or if the dimension of
1970 	   ///        the activity vector does not match the number of columns
1971 	   virtual void addDualActivity(const SVectorBase<R>& dual, VectorBase<R>& activity) const
1972 	   {
1973 	      if(activity.dim() != nCols())
1974 	      {
1975 	         throw SPxInternalCodeException("XSPXLP04 Activity vector computing dual activity has wrong dimension");
1976 	      }
1977 	
1978 	      for(int i = dual.size() - 1; i >= 0; i--)
1979 	      {
1980 	         assert(dual.index(i) >= 0);
1981 	         assert(dual.index(i) < nRows());
1982 	         activity.multAdd(dual.value(i), rowVector(dual.index(i)));
1983 	      }
1984 	   }
1985 	
1986 	   /// Updates "dual" activity of the columns for a given dual vector, i.e., y^T A; activity does not need to be zero
1987 	   /// @throw SPxInternalCodeException if dimension of dual vector does not match number of rows or if the dimension of
1988 	   ///        the activity vector does not match the number of columns
1989 	   virtual void subDualActivity(const VectorBase<R>& dual, VectorBase<R>& activity) const
1990 	   {
1991 	      if(dual.dim() != nRows())
1992 	      {
1993 	         throw SPxInternalCodeException("XSPXLP02 Dual vector for computing dual activity has wrong dimension");
1994 	      }
1995 	
1996 	      if(activity.dim() != nCols())
1997 	      {
1998 	         throw SPxInternalCodeException("XSPXLP04 Activity vector computing dual activity has wrong dimension");
1999 	      }
2000 	
2001 	      for(int r = 0; r < nRows(); r++)
2002 	      {
2003 	         if(dual[r] != 0)
2004 	            activity.multSub(dual[r], rowVector(r));
2005 	      }
2006 	   }
2007 	
2008 	   ///@}
2009 	
2010 	   // ------------------------------------------------------------------------------------------------------------------
2011 	   /**@name Construction of dual problem */
2012 	   ///@{
2013 	
2014 	   /// Building the dual problem from a given LP
2015 	   /// @note primalRows must be as large as the number of unranged primal rows + 2 * the number of ranged primal rows.
2016 	   ///       dualCols must have the identical size to the primal rows.
2017 	   virtual void buildDualProblem(SPxLPBase<R>& dualLP, SPxRowId primalRowIds[] = 0,
2018 	                                 SPxColId primalColIds[] = 0,
2019 	                                 SPxRowId dualRowIds[] = 0, SPxColId dualColIds[] = 0, int* nprimalrows = 0, int* nprimalcols = 0,
2020 	                                 int* ndualrows = 0, int* ndualcols = 0);
2021 	
2022 	   ///@}
2023 	
2024 	   // ------------------------------------------------------------------------------------------------------------------
2025 	   /**@name Miscellaneous */
2026 	   ///@{
2027 	
2028 	   /// Consistency check.
2029 	   bool isConsistent() const
2030 	   {
2031 	      if(this->_tolerances == nullptr && nCols() != 0)
2032 	         return SPX_MSG_INCONSISTENT("SPxLPBase");
2033 	
2034 	#ifdef ENABLE_CONSISTENCY_CHECKS
2035 	
2036 	      for(int i = nCols() - 1; i >= 0; --i)
2037 	      {
2038 	         const SVectorBase<R>& v = colVector(i);
2039 	
2040 	         for(int j = v.size() - 1; j >= 0; --j)
2041 	         {
2042 	            const SVectorBase<R>& w = rowVector(v.index(j));
2043 	            int n = w.pos(i);
2044 	
2045 	            if(n < 0)
2046 	               return SPX_MSG_INCONSISTENT("SPxLPBase");
2047 	
2048 	            if(v.value(j) != w.value(n))
2049 	               return SPX_MSG_INCONSISTENT("SPxLPBase");
2050 	         }
2051 	      }
2052 	
2053 	      for(int i = nRows() - 1; i >= 0; --i)
2054 	      {
2055 	         const SVectorBase<R>& v = rowVector(i);
2056 	
2057 	         for(int j = v.size() - 1; j >= 0; --j)
2058 	         {
2059 	            const SVectorBase<R>& w = colVector(v.index(j));
2060 	            int n = w.pos(i);
2061 	
2062 	            if(n < 0)
2063 	               return SPX_MSG_INCONSISTENT("SPxLPBase");
2064 	
2065 	            if(v.value(j) != w.value(n))
2066 	               return SPX_MSG_INCONSISTENT("SPxLPBase");
2067 	         }
2068 	      }
2069 	
2070 	      return LPRowSetBase<R>::isConsistent() && LPColSetBase<R>::isConsistent();
2071 	#else
2072 	      return true;
2073 	#endif
2074 	   }
2075 	
2076 	   ///@}
2077 	
2078 	protected:
2079 	
2080 	   std::shared_ptr<Tolerances> _tolerances;
2081 	
2082 	   // ------------------------------------------------------------------------------------------------------------------
2083 	   /**@name Protected write access */
2084 	   ///@{
2085 	
2086 	   /// Returns right hand side of row \p i.
2087 	   R& rhs_w(int i)
2088 	   {
2089 	      return LPRowSetBase<R>::rhs_w(i);
2090 	   }
2091 	
2092 	   /// Returns left hand side of row \p i.
2093 	   R& lhs_w(int i)
2094 	   {
2095 	      return LPRowSetBase<R>::lhs_w(i);
2096 	   }
2097 	
2098 	   /// Returns objective function value of row \p i.
2099 	   R& maxRowObj_w(int i)
2100 	   {
2101 	      return LPRowSetBase<R>::obj_w(i);
2102 	   }
2103 	
2104 	   /// Returns objective value of column \p i for maximization problem.
2105 	   R& maxObj_w(int i)
2106 	   {
2107 	      return LPColSetBase<R>::maxObj_w(i);
2108 	   }
2109 	
2110 	   /// Returns upper bound of column \p i.
2111 	   R& upper_w(int i)
2112 	   {
2113 	      return LPColSetBase<R>::upper_w(i);
2114 	   }
2115 	
2116 	   /// Returns lower bound of column \p i.
2117 	   R& lower_w(int i)
2118 	   {
2119 	      return LPColSetBase<R>::lower_w(i);
2120 	   }
2121 	
2122 	   ///@}
2123 	
2124 	   // ------------------------------------------------------------------------------------------------------------------
2125 	   /**@name Protected helpers */
2126 	   ///@{
2127 	
2128 	   /// Returns the LP as an LPRowSetBase.
2129 	   const LPRowSetBase<R>* lprowset() const
2130 	   {
2131 	      return static_cast<const LPRowSetBase<R>*>(this);
2132 	   }
2133 	
2134 	   /// Returns the LP as an LPColSetBase.
2135 	   const LPColSetBase<R>* lpcolset() const
2136 	   {
2137 	      return static_cast<const LPColSetBase<R>*>(this);
2138 	   }
2139 	
2140 	   /// Internal helper method.
2141 	   virtual void doRemoveRow(int j)
2142 	   {
2143 	
2144 	      const SVectorBase<R>& vec = rowVector(j);
2145 	
2146 	      // remove row vector from column file
2147 	      for(int i = vec.size() - 1; i >= 0; --i)
2148 	      {
2149 	         SVectorBase<R>& remvec = colVector_w(vec.index(i));
2150 	         int position = remvec.pos(j);
2151 	
2152 	         if(position >= 0)
2153 	            remvec.remove(position);
2154 	      }
2155 	
2156 	      // move last row to removed position
2157 	      int idx = nRows() - 1;
2158 	
2159 	      if(j != idx)
2160 	      {
2161 	         const SVectorBase<R>& l_vec = rowVector(idx);
2162 	
2163 	         for(int i = l_vec.size() - 1; i >= 0; --i)
2164 	         {
2165 	            SVectorBase<R>& movevec = colVector_w(l_vec.index(i));
2166 	            int position = movevec.pos(idx);
2167 	
2168 	            assert(position != -1);
2169 	
2170 	            if(position >= 0)
2171 	               movevec.index(position) = j;
2172 	         }
2173 	      }
2174 	
2175 	      LPRowSetBase<R>::remove(j);
2176 	   }
2177 	
2178 	   /// Internal helper method.
2179 	   virtual void doRemoveRows(int perm[])
2180 	   {
2181 	      int j = nCols();
2182 	
2183 	      LPRowSetBase<R>::remove(perm);
2184 	
2185 	      for(int i = 0; i < j; ++i)
2186 	      {
2187 	         SVectorBase<R>& vec = colVector_w(i);
2188 	
2189 	         for(int k = vec.size() - 1; k >= 0; --k)
2190 	         {
2191 	            int idx = vec.index(k);
2192 	
2193 	            if(perm[idx] < 0)
2194 	               vec.remove(k);
2195 	            else
2196 	               vec.index(k) = perm[idx];
2197 	         }
2198 	      }
2199 	   }
2200 	
2201 	   /// Internal helper method.
2202 	   virtual void doRemoveCol(int j)
2203 	   {
2204 	
2205 	      const SVectorBase<R>& vec = colVector(j);
2206 	      int i;
2207 	
2208 	      // remove column vector from row file
2209 	      for(i = vec.size() - 1; i >= 0; --i)
2210 	      {
2211 	         SVectorBase<R>& remvec = rowVector_w(vec.index(i));
2212 	         int position = remvec.pos(j);
2213 	
2214 	         assert(position != -1);
2215 	
2216 	         if(position >= 0)
2217 	            remvec.remove(position);
2218 	      }
2219 	
2220 	      // move last column to removed position
2221 	      int idx = nCols() - 1;
2222 	
2223 	      if(j != idx)
2224 	      {
2225 	         const SVectorBase<R>& l_vec = colVector(idx);
2226 	
2227 	         for(i = l_vec.size() - 1; i >= 0; --i)
2228 	         {
2229 	            SVectorBase<R>& movevec = rowVector_w(l_vec.index(i));
2230 	            int position = movevec.pos(idx);
2231 	
2232 	            assert(position != -1);
2233 	
2234 	            if(position >= 0)
2235 	               movevec.index(position) = j;
2236 	         }
2237 	      }
2238 	
2239 	      LPColSetBase<R>::remove(j);
2240 	   }
2241 	
2242 	   /// Internal helper method.
2243 	   virtual void doRemoveCols(int perm[])
2244 	   {
2245 	      int nrows = nRows();
2246 	
2247 	      LPColSetBase<R>::remove(perm);
2248 	
2249 	      for(int i = 0; i < nrows; ++i)
2250 	      {
2251 	         SVectorBase<R>& vec = rowVector_w(i);
2252 	
2253 	         for(int k = vec.size() - 1; k >= 0; --k)
2254 	         {
2255 	            int idx = vec.index(k);
2256 	
2257 	            if(perm[idx] < 0)
2258 	               vec.remove(k);
2259 	            else
2260 	               vec.index(k) = perm[idx];
2261 	         }
2262 	      }
2263 	   }
2264 	
2265 	   /// Called after the last \p n rows have just been added.
2266 	   virtual void addedRows(int newrows)
2267 	   {}
2268 	
2269 	   /// Called after the last \p n columns have just been added.
2270 	   virtual void addedCols(int newcols)
2271 	   {}
2272 	
2273 	   ///
2274 	   void added2Set(SVSetBase<R>& set, const SVSetBase<R>& addset, int n)
2275 	   {
2276 	
2277 	      if(n == 0)
2278 	         return;
2279 	
2280 	      DataArray<int> moreArray(set.num());
2281 	      int* more = moreArray.get_ptr();
2282 	
2283 	      for(int i = set.num() - 1; i >= 0; --i)
2284 	         more[i] = 0;
2285 	
2286 	      int tot = 0;
2287 	      int end = addset.num();
2288 	
2289 	      for(int i = addset.num() - n; i < end; ++i)
2290 	      {
2291 	         const SVectorBase<R>& vec = addset[i];
2292 	
2293 	         tot += vec.size();
2294 	
2295 	         for(int j = vec.size() - 1; j >= 0; --j)
2296 	            more[vec.index(j)]++;
2297 	      }
2298 	
2299 	      if(set.memMax() < tot)
2300 	         set.memRemax(tot);
2301 	
2302 	      for(int i = set.num() - 1; i >= 0; --i)
2303 	      {
2304 	         int j = set[i].size();
2305 	         set.xtend(set[i], j + more[i]);
2306 	         set[i].set_size(j + more[i]);
2307 	         more[i] = j;
2308 	      }
2309 	
2310 	      for(int i = addset.num() - n; i < addset.num(); ++i)
2311 	      {
2312 	         const SVectorBase<R>& vec = addset[i];
2313 	
2314 	         for(int j = vec.size() - 1; j >= 0; --j)
2315 	         {
2316 	            int k = vec.index(j);
2317 	            int m = more[k]++;
2318 	            SVectorBase<R>& l_xtend = set[k];
2319 	            l_xtend.index(m) = i;
2320 	            l_xtend.value(m) = vec.value(j);
2321 	         }
2322 	      }
2323 	   }
2324 	
2325 	   ///@}
2326 	
2327 	
2328 	private:
2329 	
2330 	   // ------------------------------------------------------------------------------------------------------------------
2331 	   /**@name Private helpers */
2332 	   ///@{
2333 	
2334 	   /// Returns the LP as an LPRowBase<R>Set.
2335 	   SVectorBase<R>& colVector_w(int i)
2336 	   {
2337 	      return LPColSetBase<R>::colVector_w(i);
2338 	   }
2339 	
2340 	   ///
2341 	   SVectorBase<R>& rowVector_w(int i)
2342 	   {
2343 	      return LPRowSetBase<R>::rowVector_w(i);
2344 	   }
2345 	
2346 	   ///
2347 	   void doAddRow(const LPRowBase<R>& row, bool scale = false)
2348 	   {
2349 	      int idx = nRows();
2350 	      int oldColNumber = nCols();
2351 	      int newRowScaleExp = 0;
2352 	
2353 	      LPRowSetBase<R>::add(row);
2354 	
2355 	      SVectorBase<R>& vec = rowVector_w(idx);
2356 	
2357 	      DataArray <int>& colscaleExp = LPColSetBase<R>::scaleExp;
2358 	
2359 	      // compute new row scaling factor and apply it to the sides
2360 	      if(scale && lp_scaler)
2361 	      {
2362 	         newRowScaleExp = lp_scaler->computeScaleExp(vec, colscaleExp);
2363 	
2364 	         if(rhs(idx) < R(infinity))
2365 	            rhs_w(idx) = spxLdexp(rhs_w(idx), newRowScaleExp);
2366 	
2367 	         if(lhs(idx) > R(-infinity))
2368 	            lhs_w(idx) = spxLdexp(lhs_w(idx), newRowScaleExp);
2369 	
2370 	         maxRowObj_w(idx) = spxLdexp(maxRowObj_w(idx), newRowScaleExp);
2371 	
2372 	         LPRowSetBase<R>::scaleExp[idx] = newRowScaleExp;
2373 	      }
2374 	
2375 	      // now insert nonzeros to column file also
2376 	      for(int j = vec.size() - 1; j >= 0; --j)
2377 	      {
2378 	         int i = vec.index(j);
2379 	
2380 	         // apply new row and existing column scaling factors to new values in RowSet
2381 	         if(scale)
2382 	            vec.value(j) = spxLdexp(vec.value(j), newRowScaleExp + colscaleExp[i]);
2383 	
2384 	         R val = vec.value(j);
2385 	
2386 	         // create new columns if required
2387 	         if(i >= nCols())
2388 	         {
2389 	            LPColBase<R> empty;
2390 	
2391 	            for(int k = nCols(); k <= i; ++k)
2392 	               LPColSetBase<R>::add(empty);
2393 	         }
2394 	
2395 	         assert(i < nCols());
2396 	         LPColSetBase<R>::add2(i, 1, &idx, &val);
2397 	      }
2398 	
2399 	      addedRows(1);
2400 	      addedCols(nCols() - oldColNumber);
2401 	   }
2402 	
2403 	   ///
2404 	   void doAddRow(const R& lhsValue, const SVectorBase<R>& rowVec, const R& rhsValue,
2405 	                 bool scale = false)
2406 	   {
2407 	      int idx = nRows();
2408 	      int oldColNumber = nCols();
2409 	      int newRowScaleExp = 0;
2410 	
2411 	      LPRowSetBase<R>::add(lhsValue, rowVec, rhsValue);
2412 	
2413 	      DataArray <int>& colscaleExp = LPColSetBase<R>::scaleExp;
2414 	
2415 	      // compute new row scaling factor and apply it to the sides
2416 	      if(scale)
2417 	      {
2418 	         newRowScaleExp = lp_scaler->computeScaleExp(rowVec, colscaleExp);
2419 	
2420 	         if(rhs(idx) < R(infinity))
2421 	            rhs_w(idx) = spxLdexp(rhs_w(idx), newRowScaleExp);
2422 	
2423 	         if(lhs(idx) > R(-infinity))
2424 	            lhs_w(idx) = spxLdexp(lhs_w(idx), newRowScaleExp);
2425 	
2426 	         maxRowObj_w(idx) = spxLdexp(maxRowObj_w(idx), newRowScaleExp);
2427 	
2428 	         LPRowSetBase<R>::scaleExp[idx] = newRowScaleExp;
2429 	      }
2430 	
2431 	      SVectorBase<R>& vec = rowVector_w(idx);
2432 	
2433 	      // now insert nonzeros to column file also
2434 	      for(int j = vec.size() - 1; j >= 0; --j)
2435 	      {
2436 	         int i = vec.index(j);
2437 	
2438 	         // apply new row and existing column scaling factors to new values in RowSet
2439 	         if(scale)
2440 	            vec.value(j) = spxLdexp(vec.value(j), newRowScaleExp + colscaleExp[i]);
2441 	
2442 	         R val = vec.value(j);
2443 	
2444 	         // create new columns if required
2445 	         if(i >= nCols())
2446 	         {
2447 	            LPColBase<R> empty;
2448 	
2449 	            for(int k = nCols(); k <= i; ++k)
2450 	               LPColSetBase<R>::add(empty);
2451 	         }
2452 	
2453 	         assert(i < nCols());
2454 	         LPColSetBase<R>::add2(i, 1, &idx, &val);
2455 	      }
2456 	
2457 	      addedRows(1);
2458 	      addedCols(nCols() - oldColNumber);
2459 	   }
2460 	
2461 	   ///
2462 	   void doAddRows(const LPRowSetBase<R>& set, bool scale = false)
2463 	   {
2464 	      int i, j, k, ii, idx;
2465 	      SVectorBase<R>* col;
2466 	      DataArray < int > newCols(nCols());
2467 	      int oldRowNumber = nRows();
2468 	      int oldColNumber = nCols();
2469 	
2470 	      if(&set != this)
2471 	         LPRowSetBase<R>::add(set);
2472 	
2473 	      assert(LPRowSetBase<R>::isConsistent());
2474 	      assert(LPColSetBase<R>::isConsistent());
2475 	
2476 	      // count additional nonzeros per column
2477 	      for(i = nCols() - 1; i >= 0; --i)
2478 	         newCols[i] = 0;
2479 	
2480 	      for(i = set.num() - 1; i >= 0; --i)
2481 	      {
2482 	         const SVectorBase<R>& vec = set.rowVector(i);
2483 	
2484 	         for(j = vec.size() - 1; j >= 0; --j)
2485 	         {
2486 	            // create new columns if required
2487 	            ii = vec.index(j);
2488 	
2489 	            if(ii >= nCols())
2490 	            {
2491 	               LPColBase<R> empty;
2492 	               newCols.reSize(ii + 1);
2493 	
2494 	               for(k = nCols(); k <= ii; ++k)
2495 	               {
2496 	                  newCols[k] = 0;
2497 	                  LPColSetBase<R>::add(empty);
2498 	               }
2499 	            }
2500 	
2501 	            assert(ii < nCols());
2502 	            newCols[ii]++;
2503 	         }
2504 	      }
2505 	
2506 	      // extend columns as required (backward because of memory efficiency reasons)
2507 	      for(i = nCols() - 1; i >= 0; --i)
2508 	      {
2509 	         if(newCols[i] > 0)
2510 	         {
2511 	            int len = newCols[i] + colVector(i).size();
2512 	            LPColSetBase<R>::xtend(i, len);
2513 	
2514 	            /* preset the sizes: beware that this can irritate a consistency check call from xtend(). We need to set the
2515 	             * sizes here, because a possible garbage collection called from xtend might destroy the sizes again. */
2516 	            colVector_w(i).set_size(len);
2517 	         }
2518 	      }
2519 	
2520 	      // compute new row scaling factor and insert new elements to column file
2521 	      for(i = nRows() - 1; i >= oldRowNumber; --i)
2522 	      {
2523 	         SVectorBase<R>& vec = rowVector_w(i);
2524 	         int newRowScaleExp = 0;
2525 	
2526 	         DataArray <int>& colscaleExp = LPColSetBase<R>::scaleExp;
2527 	
2528 	         // compute new row scaling factor and apply it to the sides
2529 	         if(scale)
2530 	         {
2531 	            newRowScaleExp = lp_scaler->computeScaleExp(vec, colscaleExp);
2532 	
2533 	            if(rhs(i) < R(infinity))
2534 	               rhs_w(i) = spxLdexp(rhs_w(i), newRowScaleExp);
2535 	
2536 	            if(lhs(i) > R(-infinity))
2537 	               lhs_w(i) = spxLdexp(lhs_w(i), newRowScaleExp);
2538 	
2539 	            maxRowObj_w(i) = spxLdexp(maxRowObj_w(i), newRowScaleExp);
2540 	
2541 	            LPRowSetBase<R>::scaleExp[i] = newRowScaleExp;
2542 	         }
2543 	
2544 	         for(j = vec.size() - 1; j >= 0; --j)
2545 	         {
2546 	            k = vec.index(j);
2547 	            col = &colVector_w(k);
2548 	            idx = col->size() - newCols[k];
2549 	            assert(newCols[k] > 0);
2550 	            assert(idx >= 0);
2551 	            newCols[k]--;
2552 	            col->index(idx) = i;
2553 	
2554 	            // apply new row and existing column scaling factors to both ColSet and RowSet
2555 	            if(scale)
2556 	               vec.value(j) = spxLdexp(vec.value(j), newRowScaleExp + colscaleExp[k]);
2557 	
2558 	            col->value(idx) = vec.value(j);
2559 	         }
2560 	      }
2561 	
2562 	#ifndef NDEBUG
2563 	
2564 	      for(i = 0; i < nCols(); ++i)
2565 	         assert(newCols[i] == 0);
2566 	
2567 	#endif
2568 	
2569 	      assert(SPxLPBase<R>::isConsistent());
2570 	
2571 	      assert(set.num() == nRows() - oldRowNumber);
2572 	      addedRows(nRows() - oldRowNumber);
2573 	      addedCols(nCols() - oldColNumber);
2574 	   }
2575 	
2576 	   ///
2577 	   void doAddCol(const LPColBase<R>& col, bool scale = false)
2578 	   {
2579 	      int idx = nCols();
2580 	      int oldRowNumber = nRows();
2581 	      int newColScaleExp = 0;
2582 	
2583 	      LPColSetBase<R>::add(col);
2584 	
2585 	      if(thesense != MAXIMIZE)
2586 	         LPColSetBase<R>::maxObj_w(idx) *= -1;
2587 	
2588 	      SVectorBase<R>& vec = colVector_w(idx);
2589 	
2590 	      DataArray <int>& rowscaleExp = LPRowSetBase<R>::scaleExp;
2591 	
2592 	      // compute new column scaling factor and apply it to the bounds
2593 	      if(scale)
2594 	      {
2595 	         newColScaleExp = lp_scaler->computeScaleExp(vec, rowscaleExp);
2596 	
2597 	         if(upper(idx) < R(infinity))
2598 	            upper_w(idx) = spxLdexp(upper_w(idx), - newColScaleExp);
2599 	
2600 	         if(lower(idx) > R(-infinity))
2601 	            lower_w(idx) = spxLdexp(lower_w(idx), - newColScaleExp);
2602 	
2603 	         maxObj_w(idx) = spxLdexp(maxObj_w(idx), newColScaleExp);
2604 	
2605 	         LPColSetBase<R>::scaleExp[idx] = newColScaleExp;
2606 	      }
2607 	
2608 	      // now insert nonzeros to row file also
2609 	      for(int j = vec.size() - 1; j >= 0; --j)
2610 	      {
2611 	         int i = vec.index(j);
2612 	
2613 	         // apply new column and existing row scaling factors to new values in ColSet
2614 	         if(scale)
2615 	            vec.value(j) = spxLdexp(vec.value(j), newColScaleExp + rowscaleExp[i]);
2616 	
2617 	         R val = vec.value(j);
2618 	
2619 	         // create new rows if required
2620 	         if(i >= nRows())
2621 	         {
2622 	            LPRowBase<R> empty;
2623 	
2624 	            for(int k = nRows(); k <= i; ++k)
2625 	               LPRowSetBase<R>::add(empty);
2626 	         }
2627 	
2628 	         assert(i < nRows());
2629 	         LPRowSetBase<R>::add2(i, 1, &idx, &val);
2630 	      }
2631 	
2632 	      addedCols(1);
2633 	      addedRows(nRows() - oldRowNumber);
2634 	   }
2635 	
2636 	   ///
2637 	   void doAddCol(const R& objValue, const R& lowerValue, const SVectorBase<R>& colVec,
2638 	                 const R& upperValue, bool scale = false)
2639 	   {
2640 	      int idx = nCols();
2641 	      int oldRowNumber = nRows();
2642 	      int newColScaleExp = 0;
2643 	
2644 	      LPColSetBase<R>::add(objValue, lowerValue, colVec, upperValue);
2645 	
2646 	      if(thesense != MAXIMIZE)
2647 	         LPColSetBase<R>::maxObj_w(idx) *= -1;
2648 	
2649 	      DataArray <int>& rowscaleExp = LPRowSetBase<R>::scaleExp;
2650 	
2651 	      // compute new column scaling factor and apply it to the bounds
2652 	      if(scale)
2653 	      {
2654 	         newColScaleExp = lp_scaler->computeScaleExp(colVec, rowscaleExp);
2655 	
2656 	         if(upper(idx) < R(infinity))
2657 	            upper_w(idx) = spxLdexp(upper_w(idx), - newColScaleExp);
2658 	
2659 	         if(lower(idx) > R(-infinity))
2660 	            lower_w(idx) = spxLdexp(lower_w(idx), - newColScaleExp);
2661 	
2662 	         maxObj_w(idx) = spxLdexp(maxObj_w(idx), newColScaleExp);
2663 	
2664 	         LPColSetBase<R>::scaleExp[idx] = newColScaleExp;
2665 	      }
2666 	
2667 	      SVectorBase<R>& vec = colVector_w(idx);
2668 	
2669 	      // now insert nonzeros to row file also
2670 	      for(int j = vec.size() - 1; j >= 0; --j)
2671 	      {
2672 	         int i = vec.index(j);
2673 	
2674 	         if(scale)
2675 	            vec.value(j) = spxLdexp(vec.value(j), newColScaleExp + rowscaleExp[i]);
2676 	
2677 	         R val = vec.value(j);
2678 	
2679 	         // create new rows if required
2680 	         if(i >= nRows())
2681 	         {
2682 	            LPRowBase<R> empty;
2683 	
2684 	            for(int k = nRows(); k <= i; ++k)
2685 	               LPRowSetBase<R>::add(empty);
2686 	         }
2687 	
2688 	         assert(i < nRows());
2689 	         LPRowSetBase<R>::add2(i, 1, &idx, &val);
2690 	      }
2691 	
2692 	      addedCols(1);
2693 	      addedRows(nRows() - oldRowNumber);
2694 	   }
2695 	
2696 	   ///
2697 	   void doAddCols(const LPColSetBase<R>& set, bool scale = false)
2698 	   {
2699 	      int i, j;
2700 	      int oldColNumber = nCols();
2701 	      int oldRowNumber = nRows();
2702 	      DataArray < int > newRows(nRows());
2703 	
2704 	      if(&set != this)
2705 	         LPColSetBase<R>::add(set);
2706 	
2707 	      assert(LPColSetBase<R>::isConsistent());
2708 	      assert(LPRowSetBase<R>::isConsistent());
2709 	
2710 	      // count additional nonzeros per row
2711 	      for(i = nRows() - 1; i >= 0; --i)
2712 	         newRows[i] = 0;
2713 	
2714 	      for(i = set.num() - 1; i >= 0; --i)
2715 	      {
2716 	         const SVectorBase<R>& vec = set.colVector(i);
2717 	
2718 	         for(j = vec.size() - 1; j >= 0; --j)
2719 	         {
2720 	            // create new rows if required
2721 	            int l = vec.index(j);
2722 	
2723 	            if(l >= nRows())
2724 	            {
2725 	               LPRowBase<R> empty;
2726 	               newRows.reSize(l + 1);
2727 	
2728 	               for(int k = nRows(); k <= l; ++k)
2729 	               {
2730 	                  newRows[k] = 0;
2731 	                  LPRowSetBase<R>::add(empty);
2732 	               }
2733 	
2734 	            }
2735 	
2736 	            assert(l < nRows());
2737 	            newRows[l]++;
2738 	         }
2739 	      }
2740 	
2741 	      // extend rows as required
2742 	      for(i = 0; i < nRows(); ++i)
2743 	      {
2744 	         if(newRows[i] > 0)
2745 	         {
2746 	            int len = newRows[i] + rowVector(i).size();
2747 	            LPRowSetBase<R>::xtend(i, len);
2748 	            rowVector_w(i).set_size(len);
2749 	         }
2750 	      }
2751 	
2752 	      // insert new elements to row file
2753 	      for(i = oldColNumber; i < nCols(); ++i)
2754 	      {
2755 	         // @todo: Is there a better way to write the following if, else?
2756 	         if(thesense == MAXIMIZE)
2757 	         {
2758 	            LPColSetBase<R>::maxObj_w(i) *= 1;
2759 	         }
2760 	         else                  // thesense is MINIMIZE = -1
2761 	         {
2762 	            LPColSetBase<R>::maxObj_w(i) *= -1;
2763 	         }
2764 	
2765 	         SVectorBase<R>& vec = colVector_w(i);
2766 	         int newColScaleExp = 0;
2767 	
2768 	         DataArray <int>& rowscaleExp = LPRowSetBase<R>::scaleExp;
2769 	
2770 	         // compute new column scaling factor and apply it to the bounds
2771 	         if(scale)
2772 	         {
2773 	            newColScaleExp = lp_scaler->computeScaleExp(vec, rowscaleExp);
2774 	
2775 	            if(upper(i) < R(infinity))
2776 	               upper_w(i) = spxLdexp(upper_w(i), - newColScaleExp);
2777 	
2778 	            if(lower(i) > R(-infinity))
2779 	               lower_w(i) = spxLdexp(lower_w(i), - newColScaleExp);
2780 	
2781 	            maxObj_w(i) = spxLdexp(maxObj_w(i), newColScaleExp);
2782 	
2783 	            LPColSetBase<R>::scaleExp[i] = newColScaleExp;
2784 	         }
2785 	
2786 	         for(j = vec.size() - 1; j >= 0; --j)
2787 	         {
2788 	            int k = vec.index(j);
2789 	            SVectorBase<R>& row = rowVector_w(k);
2790 	            int idx = row.size() - newRows[k];
2791 	            assert(newRows[k] > 0);
2792 	            newRows[k]--;
2793 	            row.index(idx) = i;
2794 	
2795 	            // apply new column and existing row scaling factors to both ColSet and RowSet
2796 	            if(scale)
2797 	               vec.value(j) = spxLdexp(vec.value(j), newColScaleExp + rowscaleExp[k]);
2798 	
2799 	            row.value(idx) = vec.value(j);
2800 	         }
2801 	      }
2802 	
2803 	#ifndef NDEBUG
2804 	
2805 	      for(i = 0; i < nRows(); ++i)
2806 	         assert(newRows[i] == 0);
2807 	
2808 	#endif
2809 	
2810 	      assert(SPxLPBase<R>::isConsistent());
2811 	
2812 	      assert(set.num() == nCols() - oldColNumber);
2813 	      addedCols(nCols() - oldColNumber);
2814 	      addedRows(nRows() - oldRowNumber);
2815 	   }
2816 	
2817 	   ///@}
2818 	
2819 	public:
2820 	
2821 	   // ------------------------------------------------------------------------------------------------------------------
2822 	   /**@name Constructors / Destructors */
2823 	   ///@{
2824 	
2825 	   /// Default constructor.
2826 	   SPxLPBase()
2827 	   {
2828 	      SPxLPBase<R>::clear(); // clear is virtual.
2829 	
2830 	      assert(isConsistent());
2831 	   }
2832 	
2833 	   /// Destructor.
2834 	   virtual ~SPxLPBase()
2835 	   {}
2836 	
2837 	   /// Copy constructor.
2838 	   SPxLPBase(const SPxLPBase<R>& old)
2839 	      : LPRowSetBase<R>(old)
2840 	      , LPColSetBase<R>(old)
2841 	      , thesense(old.thesense)
2842 	      , offset(old.offset)
2843 	      , _isScaled(old._isScaled)
2844 	      , lp_scaler(old.lp_scaler)
2845 	      , spxout(old.spxout)
2846 	   {
2847 	      _tolerances = old._tolerances;
2848 	      assert(isConsistent());
2849 	   }
2850 	
2851 	   /// Copy constructor.
2852 	   template < class S >
2853 	   SPxLPBase(const SPxLPBase<S>& old)
2854 	      : LPRowSetBase<R>(old)
2855 	      , LPColSetBase<R>(old)
2856 	      , thesense(old.thesense == SPxLPBase<S>::MINIMIZE ? SPxLPBase<R>::MINIMIZE : SPxLPBase<R>::MAXIMIZE)
2857 	      , offset(old.offset)
2858 	      , _isScaled(old._isScaled)
2859 	      , spxout(old.spxout)
2860 	   {
2861 	      lp_scaler = nullptr;
2862 	      _tolerances = old._tolerances;
2863 	      assert(isConsistent());
2864 	   }
2865 	
2866 	   /// Assignment operator.
2867 	   SPxLPBase<R>& operator=(const SPxLPBase<R>& old)
2868 	   {
2869 	      if(this != &old)
2870 	      {
2871 	         LPRowSetBase<R>::operator=(old);
2872 	         LPColSetBase<R>::operator=(old);
2873 	         thesense = old.thesense;
2874 	         offset = old.offset;
2875 	         _isScaled = old._isScaled;
2876 	         lp_scaler = old.lp_scaler;
2877 	         spxout = old.spxout;
2878 	         _tolerances = old._tolerances;
2879 	
2880 	         assert(isConsistent());
2881 	      }
2882 	
2883 	      return *this;
2884 	   }
2885 	
2886 	   /// Assignment operator.
2887 	   template < class S >
2888 	   SPxLPBase<R>& operator=(const SPxLPBase<S>& old)
2889 	   {
2890 	      if(this != (const SPxLPBase<R>*)(&old))
2891 	      {
2892 	         // The value of old.lp_scaler has to be nullptr
2893 	         // Refer to issue #161 in soplex gitlab
2894 	         assert(old.lp_scaler == nullptr);
2895 	
2896 	         LPRowSetBase<R>::operator=(old);
2897 	         LPColSetBase<R>::operator=(old);
2898 	         thesense = (old.thesense) == SPxLPBase<S>::MINIMIZE ? SPxLPBase<R>::MINIMIZE :
2899 	                    SPxLPBase<R>::MAXIMIZE;
2900 	         offset = R(old.offset);
2901 	         _isScaled = old._isScaled;
2902 	         _tolerances = old._tolerances;
2903 	
2904 	         // this may have un-intended consequences in the future
2905 	         lp_scaler = nullptr;
2906 	         spxout = old.spxout;
2907 	
2908 	         assert(isConsistent());
2909 	      }
2910 	
2911 	      return *this;
2912 	   }
2913 	
2914 	   ///@}
2915 	};
2916 	
2917 	} // namespace soplex
2918 	
2919 	// For the general templated functions
2920 	#include "spxlpbase_real.hpp"
2921 	#include "spxlpbase_rational.hpp"
2922 	
2923 	/* reset the SOPLEX_DEBUG flag to its original value */
2924 	#undef SOPLEX_DEBUG
2925 	#ifdef SOPLEX_DEBUG_SPXLPBASE
2926 	#define SOPLEX_DEBUG
2927 	#undef SOPLEX_DEBUG_SPXLPBASE
2928 	#endif
2929 	
2930 	#endif // _SPXLPBASE_H_
2931