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   	#include <assert.h>
26   	#include <iostream>
27   	
28   	#include "soplex/spxdefines.h"
29   	#include "soplex/spxsolver.h"
30   	#include "soplex/spxpricer.h"
31   	#include "soplex/spxratiotester.h"
32   	#include "soplex/exceptions.h"
33   	
34   	namespace soplex
35   	{
36   	
37   	template <class R>
38   	void SPxSolverBase<R>::addedRows(int n)
39   	{
40   	
41   	   if(n > 0)
42   	   {
43   	      SPxLPBase<R>::addedRows(n);
44   	
45   	      unInit();
46   	      reDim();
47   	
48   	      if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
49   	         SPxBasisBase<R>::addedRows(n);
50   	   }
51   	
52   	   /* we must not assert consistency here, since addedCols() might be still necessary to obtain a consistent basis */
53   	}
54   	
55   	template <class R>
56   	void SPxSolverBase<R>::addedCols(int n)
57   	{
58   	
59   	   if(n > 0)
60   	   {
61   	      SPxLPBase<R>::addedCols(n);
62   	
63   	      unInit();
64   	      reDim();
65   	
66   	      if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
67   	         SPxBasisBase<R>::addedCols(n);
68   	   }
69   	
70   	   /* we must not assert consistency here, since addedRows() might be still necessary to obtain a consistent basis */
71   	}
72   	
73   	template <class R>
74   	void SPxSolverBase<R>::doRemoveRow(int i)
75   	{
76   	
77   	   SPxLPBase<R>::doRemoveRow(i);
78   	
79   	   unInit();
80   	
81   	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
82   	   {
83   	      this->removedRow(i);
84   	
85   	      switch(SPxBasisBase<R>::status())
86   	      {
87   	      case SPxBasisBase<R>::DUAL:
88   	      case SPxBasisBase<R>::INFEASIBLE:
89   	         setBasisStatus(SPxBasisBase<R>::REGULAR);
90   	         break;
91   	
92   	      case SPxBasisBase<R>::OPTIMAL:
93   	         setBasisStatus(SPxBasisBase<R>::PRIMAL);
94   	         break;
95   	
96   	      default:
97   	         break;
98   	      }
99   	   }
100  	}
101  	
102  	template <class R>
103  	void SPxSolverBase<R>::doRemoveRows(int perm[])
104  	{
105  	
106  	   SPxLPBase<R>::doRemoveRows(perm);
107  	
108  	   unInit();
109  	
110  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
111  	   {
112  	      this->removedRows(perm);
113  	
114  	      switch(SPxBasisBase<R>::status())
115  	      {
116  	      case SPxBasisBase<R>::DUAL:
117  	      case SPxBasisBase<R>::INFEASIBLE:
118  	         setBasisStatus(SPxBasisBase<R>::REGULAR);
119  	         break;
120  	
121  	      case SPxBasisBase<R>::OPTIMAL:
122  	         setBasisStatus(SPxBasisBase<R>::PRIMAL);
123  	         break;
124  	
125  	      default:
126  	         break;
127  	      }
128  	   }
129  	}
130  	
131  	template <class R>
132  	void SPxSolverBase<R>::doRemoveCol(int i)
133  	{
134  	   forceRecompNonbasicValue();
135  	
136  	   SPxLPBase<R>::doRemoveCol(i);
137  	
138  	   unInit();
139  	
140  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
141  	   {
142  	      this->removedCol(i);
143  	
144  	      switch(SPxBasisBase<R>::status())
145  	      {
146  	      case SPxBasisBase<R>::PRIMAL:
147  	      case SPxBasisBase<R>::UNBOUNDED:
148  	         setBasisStatus(SPxBasisBase<R>::REGULAR);
149  	         break;
150  	
151  	      case SPxBasisBase<R>::OPTIMAL:
152  	         setBasisStatus(SPxBasisBase<R>::DUAL);
153  	         break;
154  	
155  	      default:
156  	         break;
157  	      }
158  	   }
159  	}
160  	
161  	template <class R>
162  	void SPxSolverBase<R>::doRemoveCols(int perm[])
163  	{
164  	   forceRecompNonbasicValue();
165  	
166  	   SPxLPBase<R>::doRemoveCols(perm);
167  	
168  	   unInit();
169  	
170  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
171  	   {
172  	      this->removedCols(perm);
173  	
174  	      switch(SPxBasisBase<R>::status())
175  	      {
176  	      case SPxBasisBase<R>::PRIMAL:
177  	      case SPxBasisBase<R>::UNBOUNDED:
178  	         setBasisStatus(SPxBasisBase<R>::REGULAR);
179  	         break;
180  	
181  	      case SPxBasisBase<R>::OPTIMAL:
182  	         setBasisStatus(SPxBasisBase<R>::DUAL);
183  	         break;
184  	
185  	      default:
186  	         break;
187  	      }
188  	   }
189  	}
190  	
191  	template <class R>
192  	void SPxSolverBase<R>::changeObj(const VectorBase<R>& newObj, bool scale)
193  	{
194  	   forceRecompNonbasicValue();
195  	
196  	   SPxLPBase<R>::changeObj(newObj, scale);
197  	
198  	   /**@todo Factorization remains valid, we do not need a reDim()
199  	    *       pricing vectors should be recomputed.
200  	    */
201  	   unInit();
202  	}
203  	
204  	template <class R>
205  	void SPxSolverBase<R>::changeObj(int i, const R& newVal, bool scale)
206  	{
207  	   forceRecompNonbasicValue();
208  	
209  	   SPxLPBase<R>::changeObj(i, newVal, scale);
210  	
211  	
212  	   /**@todo Factorization remains valid, we do not need a reDim()
213  	    *       pricing vectors should be recomputed.
214  	    */
215  	   unInit();
216  	}
217  	
218  	template <class R>
219  	void SPxSolverBase<R>::changeMaxObj(const VectorBase<R>& newObj, bool scale)
220  	{
221  	   forceRecompNonbasicValue();
222  	
223  	   SPxLPBase<R>::changeMaxObj(newObj, scale);
224  	
225  	   /**@todo Factorization remains valid, we do not need a reDim()
226  	    *       pricing vectors should be recomputed.
227  	    */
228  	   unInit();
229  	}
230  	
231  	template <class R>
232  	void SPxSolverBase<R>::changeMaxObj(int i, const R& newVal, bool scale)
233  	{
234  	   forceRecompNonbasicValue();
235  	
236  	   SPxLPBase<R>::changeMaxObj(i, newVal, scale);
237  	
238  	   /**@todo Factorization remains valid, we do not need a reDim()
239  	    *       pricing vectors should be recomputed.
240  	    */
241  	   unInit();
242  	}
243  	
244  	template <class R>
245  	void SPxSolverBase<R>::changeRowObj(const VectorBase<R>& newObj, bool scale)
246  	{
247  	   forceRecompNonbasicValue();
248  	
249  	   SPxLPBase<R>::changeRowObj(newObj, scale);
250  	
251  	   /**@todo Factorization remains valid, we do not need a reDim()
252  	    *       pricing vectors should be recomputed.
253  	    */
254  	   unInit();
255  	}
256  	
257  	template <class R>
258  	void SPxSolverBase<R>::changeRowObj(int i, const R& newVal, bool scale)
259  	{
260  	   forceRecompNonbasicValue();
261  	
262  	   SPxLPBase<R>::changeRowObj(i, newVal, scale);
263  	
264  	   /**@todo Factorization remains valid, we do not need a reDim()
265  	    *       pricing vectors should be recomputed.
266  	    */
267  	   unInit();
268  	}
269  	
270  	template <class R>
271  	void SPxSolverBase<R>::changeLowerStatus(int i, R newLower, R oldLower)
272  	{
273  	   typename SPxBasisBase<R>::Desc::Status& stat      = this->desc().colStatus(i);
274  	   R                    currUpper = this->upper(i);
275  	   R                    objChange = 0.0;
276  	
277  	   SPxOut::debug(this, "DCHANG01 changeLowerStatus(): col {} [{}:{}] {}", i, newLower, currUpper,
278  	                 stat);
279  	
280  	   switch(stat)
281  	   {
282  	   case SPxBasisBase<R>::Desc::P_ON_LOWER:
283  	      if(newLower <= R(-infinity))
284  	      {
285  	         if(currUpper >= R(infinity))
286  	         {
287  	            stat = SPxBasisBase<R>::Desc::P_FREE;
288  	
289  	            if(m_nonbasicValueUpToDate && rep() == COLUMN)
290  	               objChange = -theLCbound[i] * oldLower;
291  	         }
292  	         else
293  	         {
294  	            stat = SPxBasisBase<R>::Desc::P_ON_UPPER;
295  	
296  	            if(m_nonbasicValueUpToDate && rep() == COLUMN)
297  	               objChange = (theUCbound[i] * currUpper) - (theLCbound[i] * oldLower);
298  	         }
299  	      }
300  	      else if(EQ(newLower, currUpper, R(this->tolerances()->epsilon())))
301  	      {
302  	         stat = SPxBasisBase<R>::Desc::P_FIXED;
303  	
304  	         if(m_nonbasicValueUpToDate && rep() == COLUMN)
305  	            objChange = this->maxObj(i) * (newLower - oldLower);
306  	      }
307  	      else if(m_nonbasicValueUpToDate && rep() == COLUMN)
308  	         objChange = theLCbound[i] * (newLower - oldLower);
309  	
310  	      break;
311  	
312  	   case SPxBasisBase<R>::Desc::P_ON_UPPER:
313  	      if(EQ(newLower, currUpper, this->tolerances()->epsilon()))
314  	         stat = SPxBasisBase<R>::Desc::P_FIXED;
315  	
316  	      break;
317  	
318  	   case SPxBasisBase<R>::Desc::P_FREE:
319  	      if(newLower > R(-infinity))
320  	      {
321  	         stat = SPxBasisBase<R>::Desc::P_ON_LOWER;
322  	
323  	         if(m_nonbasicValueUpToDate && rep() == COLUMN)
324  	            objChange = theLCbound[i] * newLower;
325  	      }
326  	
327  	      break;
328  	
329  	   case SPxBasisBase<R>::Desc::P_FIXED:
330  	      if(NE(newLower, currUpper, this->tolerances()->epsilon()))
331  	      {
332  	         stat = SPxBasisBase<R>::Desc::P_ON_UPPER;
333  	
334  	         if(isInitialized())
335  	            theUCbound[i] = this->maxObj(i);
336  	      }
337  	
338  	      break;
339  	
340  	   case SPxBasisBase<R>::Desc::D_FREE:
341  	   case SPxBasisBase<R>::Desc::D_ON_UPPER:
342  	   case SPxBasisBase<R>::Desc::D_ON_LOWER:
343  	   case SPxBasisBase<R>::Desc::D_ON_BOTH:
344  	   case SPxBasisBase<R>::Desc::D_UNDEFINED:
345  	      if(rep() == ROW && theShift > 0.0)
346  	         forceRecompNonbasicValue();
347  	
348  	      stat = this->dualColStatus(i);
349  	      break;
350  	
351  	   default:
352  	      throw SPxInternalCodeException("XCHANG01 This should never happen.");
353  	   }
354  	
355  	   SPxOut::debug(this, " -> {}\n", stat);
356  	
357  	   // we only need to update the nonbasic value in column representation (see nonbasicValue() for comparison/explanation)
358  	   if(rep() == COLUMN)
359  	      updateNonbasicValue(objChange);
360  	}
361  	
362  	template <class R>
363  	void SPxSolverBase<R>::changeLower(const VectorBase<R>& newLower, bool scale)
364  	{
365  	   // we better recompute the nonbasic value when changing all lower bounds
366  	   forceRecompNonbasicValue();
367  	
368  	   SPxLPBase<R>::changeLower(newLower, scale);
369  	
370  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
371  	   {
372  	      for(int i = 0; i < newLower.dim(); ++i)
373  	         changeLowerStatus(i, this->lower(i));
374  	
375  	      unInit();
376  	   }
377  	}
378  	
379  	template <class R>
380  	void SPxSolverBase<R>::changeLower(int i, const R& newLower, bool scale)
381  	{
382  	   if(newLower != (scale ? this->lowerUnscaled(i) : this->lower(i)))
383  	   {
384  	      forceRecompNonbasicValue();
385  	
386  	      R oldLower = this->lower(i);
387  	      // This has to be done before calling changeLowerStatus() because that is calling
388  	      // basis.dualColStatus() which calls lower() and needs the changed value.
389  	      SPxLPBase<R>::changeLower(i, newLower, scale);
390  	
391  	      if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
392  	      {
393  	         changeLowerStatus(i, this->lower(i), oldLower);
394  	         unInit();
395  	      }
396  	   }
397  	}
398  	
399  	template <class R>
400  	void SPxSolverBase<R>::changeUpperStatus(int i, R newUpper, R oldUpper)
401  	{
402  	   typename SPxBasisBase<R>::Desc::Status& stat      = this->desc().colStatus(i);
403  	   R                    currLower = this->lower(i);
404  	   R                    objChange = 0.0;
405  	
406  	   SPxOut::debug(this, "DCHANG02 changeUpperStatus(): col {} [{}:{}] {}", i, currLower, newUpper,
407  	                 stat);
408  	
409  	   switch(stat)
410  	   {
411  	   case SPxBasisBase<R>::Desc::P_ON_LOWER:
412  	      if(newUpper == currLower)
413  	         stat = SPxBasisBase<R>::Desc::P_FIXED;
414  	
415  	      break;
416  	
417  	   case SPxBasisBase<R>::Desc::P_ON_UPPER:
418  	      if(newUpper >= R(infinity))
419  	      {
420  	         if(currLower <= R(-infinity))
421  	         {
422  	            stat = SPxBasisBase<R>::Desc::P_FREE;
423  	
424  	            if(m_nonbasicValueUpToDate && rep() == COLUMN)
425  	               objChange = -theUCbound[i] * oldUpper;
426  	         }
427  	         else
428  	         {
429  	            stat = SPxBasisBase<R>::Desc::P_ON_LOWER;
430  	
431  	            if(m_nonbasicValueUpToDate && rep() == COLUMN)
432  	               objChange = (theLCbound[i] * currLower) - (theUCbound[i] * oldUpper);
433  	         }
434  	      }
435  	      else if(EQ(newUpper, currLower, this->tolerances()->epsilon()))
436  	      {
437  	         stat = SPxBasisBase<R>::Desc::P_FIXED;
438  	
439  	         if(m_nonbasicValueUpToDate && rep() == COLUMN)
440  	            objChange = this->maxObj(i) * (newUpper - oldUpper);
441  	      }
442  	      else if(m_nonbasicValueUpToDate && rep() == COLUMN)
443  	         objChange = theUCbound[i] * (newUpper - oldUpper);
444  	
445  	      break;
446  	
447  	   case SPxBasisBase<R>::Desc::P_FREE:
448  	      if(newUpper < R(infinity))
449  	      {
450  	         stat = SPxBasisBase<R>::Desc::P_ON_UPPER;
451  	
452  	         if(m_nonbasicValueUpToDate && rep() == COLUMN)
453  	            objChange = theUCbound[i] * newUpper;
454  	      }
455  	
456  	      break;
457  	
458  	   case SPxBasisBase<R>::Desc::P_FIXED:
459  	      if(NE(newUpper, currLower, this->tolerances()->epsilon()))
460  	      {
461  	         stat = SPxBasisBase<R>::Desc::P_ON_LOWER;
462  	
463  	         if(isInitialized())
464  	            theLCbound[i] = this->maxObj(i);
465  	      }
466  	
467  	      break;
468  	
469  	   case SPxBasisBase<R>::Desc::D_FREE:
470  	   case SPxBasisBase<R>::Desc::D_ON_UPPER:
471  	   case SPxBasisBase<R>::Desc::D_ON_LOWER:
472  	   case SPxBasisBase<R>::Desc::D_ON_BOTH:
473  	   case SPxBasisBase<R>::Desc::D_UNDEFINED:
474  	      if(rep() == ROW && theShift > 0.0)
475  	         forceRecompNonbasicValue();
476  	
477  	      stat = this->dualColStatus(i);
478  	      break;
479  	
480  	   default:
481  	      throw SPxInternalCodeException("XCHANG02 This should never happen.");
482  	   }
483  	
484  	   SPxOut::debug(this, " -> {}\n", stat);
485  	
486  	   // we only need to update the nonbasic value in column representation (see nonbasicValue() for comparison/explanation)
487  	   if(rep() == COLUMN)
488  	      updateNonbasicValue(objChange);
489  	}
490  	
491  	template <class R>
492  	void SPxSolverBase<R>::changeUpper(const VectorBase<R>& newUpper, bool scale)
493  	{
494  	   // we better recompute the nonbasic value when changing all upper bounds
495  	   forceRecompNonbasicValue();
496  	
497  	   SPxLPBase<R>::changeUpper(newUpper, scale);
498  	
499  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
500  	   {
501  	      for(int i = 0; i < newUpper.dim(); ++i)
502  	         changeUpperStatus(i, this->upper(i));
503  	
504  	      unInit();
505  	   }
506  	}
507  	
508  	template <class R>
509  	void SPxSolverBase<R>::changeUpper(int i, const R& newUpper, bool scale)
510  	{
511  	   if(newUpper != (scale ? this->upperUnscaled(i) : this->upper(i)))
512  	   {
513  	      forceRecompNonbasicValue();
514  	
515  	      R oldUpper = this->upper(i);
516  	      SPxLPBase<R>::changeUpper(i, newUpper, scale);
517  	
518  	      if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
519  	      {
520  	         changeUpperStatus(i, this->upper(i), oldUpper);
521  	         unInit();
522  	      }
523  	   }
524  	}
525  	
526  	template <class R>
527  	void SPxSolverBase<R>::changeBounds(const VectorBase<R>& newLower, const VectorBase<R>& newUpper,
528  	                                    bool scale)
529  	{
530  	   changeLower(newLower, scale);
531  	   changeUpper(newUpper, scale);
532  	}
533  	
534  	template <class R>
535  	void SPxSolverBase<R>::changeBounds(int i, const R& newLower, const R& newUpper, bool scale)
536  	{
537  	   changeLower(i, newLower, scale);
538  	   changeUpper(i, newUpper, scale);
539  	}
540  	
541  	template <class R>
542  	void SPxSolverBase<R>::changeLhsStatus(int i, R newLhs, R oldLhs)
543  	{
544  	   typename SPxBasisBase<R>::Desc::Status& stat      = this->desc().rowStatus(i);
545  	   R                    currRhs   = this->rhs(i);
546  	   R                    objChange = 0.0;
547  	
548  	   SPxOut::debug(this, "DCHANG03 changeLhsStatus()  : row {}: {}", i, stat);
549  	
550  	   switch(stat)
551  	   {
552  	   case SPxBasisBase<R>::Desc::P_ON_LOWER:
553  	      if(newLhs <= R(-infinity))
554  	      {
555  	         if(currRhs >= R(infinity))
556  	         {
557  	            stat = SPxBasisBase<R>::Desc::P_FREE;
558  	
559  	            if(m_nonbasicValueUpToDate && rep() == COLUMN)
560  	               objChange = -theURbound[i] * oldLhs;
561  	         }
562  	         else
563  	         {
564  	            stat = SPxBasisBase<R>::Desc::P_ON_UPPER;
565  	
566  	            if(m_nonbasicValueUpToDate && rep() == COLUMN)
567  	               objChange = (theLRbound[i] * currRhs) - (theURbound[i] * oldLhs);
568  	         }
569  	      }
570  	      else if(EQ(newLhs, currRhs, this->tolerances()->epsilon()))
571  	      {
572  	         stat = SPxBasisBase<R>::Desc::P_FIXED;
573  	
574  	         if(m_nonbasicValueUpToDate && rep() == COLUMN)
575  	            objChange = this->maxRowObj(i) * (newLhs - oldLhs);
576  	      }
577  	      else if(m_nonbasicValueUpToDate && rep() == COLUMN)
578  	         objChange = theURbound[i] * (newLhs - oldLhs);
579  	
580  	      break;
581  	
582  	   case SPxBasisBase<R>::Desc::P_ON_UPPER:
583  	      if(EQ(newLhs, currRhs, this->tolerances()->epsilon()))
584  	         stat = SPxBasisBase<R>::Desc::P_FIXED;
585  	
586  	      break;
587  	
588  	   case SPxBasisBase<R>::Desc::P_FREE:
589  	      if(newLhs > R(-infinity))
590  	      {
591  	         stat = SPxBasisBase<R>::Desc::P_ON_LOWER;
592  	
593  	         if(m_nonbasicValueUpToDate && rep() == COLUMN)
594  	            objChange = theURbound[i] * newLhs;
595  	      }
596  	
597  	      break;
598  	
599  	   case SPxBasisBase<R>::Desc::P_FIXED:
600  	      if(NE(newLhs, currRhs, this->tolerances()->epsilon()))
601  	      {
602  	         stat = SPxBasisBase<R>::Desc::P_ON_UPPER;
603  	
604  	         if(isInitialized())
605  	            theLRbound[i] = this->maxRowObj(i);
606  	      }
607  	
608  	      break;
609  	
610  	   case SPxBasisBase<R>::Desc::D_FREE:
611  	   case SPxBasisBase<R>::Desc::D_ON_UPPER:
612  	   case SPxBasisBase<R>::Desc::D_ON_LOWER:
613  	   case SPxBasisBase<R>::Desc::D_ON_BOTH:
614  	   case SPxBasisBase<R>::Desc::D_UNDEFINED:
615  	      if(rep() == ROW && theShift > 0.0)
616  	         forceRecompNonbasicValue();
617  	
618  	      stat = this->dualRowStatus(i);
619  	      break;
620  	
621  	   default:
622  	      throw SPxInternalCodeException("XCHANG03 This should never happen.");
623  	   }
624  	
625  	   SPxOut::debug(this, " -> {}\n", stat);
626  	
627  	   // we only need to update the nonbasic value in column representation (see nonbasicValue() for comparison/explanation)
628  	   if(rep() == COLUMN)
629  	      updateNonbasicValue(objChange);
630  	}
631  	
632  	template <class R>
633  	void SPxSolverBase<R>::changeLhs(const VectorBase<R>& newLhs, bool scale)
634  	{
635  	   // we better recompute the nonbasic value when changing all lhs
636  	   forceRecompNonbasicValue();
637  	
638  	   SPxLPBase<R>::changeLhs(newLhs, scale);
639  	
640  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
641  	   {
642  	      for(int i = 0; i < this->nRows(); ++i)
643  	         changeLhsStatus(i, this->lhs(i));
644  	
645  	      unInit();
646  	   }
647  	}
648  	
649  	template <class R>
650  	void SPxSolverBase<R>::changeLhs(int i, const R& newLhs, bool scale)
651  	{
652  	   if(newLhs != (scale ? this->lhsUnscaled(i) : this->lhs(i)))
653  	   {
654  	      forceRecompNonbasicValue();
655  	
656  	      R oldLhs = this->lhs(i);
657  	      SPxLPBase<R>::changeLhs(i, newLhs, scale);
658  	
659  	      if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
660  	      {
661  	         changeLhsStatus(i, this->lhs(i), oldLhs);
662  	         unInit();
663  	      }
664  	   }
665  	}
666  	
667  	template <class R>
668  	void SPxSolverBase<R>::changeRhsStatus(int i, R newRhs, R oldRhs)
669  	{
670  	   typename SPxBasisBase<R>::Desc::Status& stat      = this->desc().rowStatus(i);
671  	   R                    currLhs   = this->lhs(i);
672  	   R                    objChange = 0.0;
673  	
674  	   SPxOut::debug(this, "DCHANG04 changeRhsStatus()  : row {}: {}", i, stat);
675  	
676  	   switch(stat)
677  	   {
678  	   case SPxBasisBase<R>::Desc::P_ON_UPPER:
679  	      if(newRhs >= R(infinity))
680  	      {
681  	         if(currLhs <= R(-infinity))
682  	         {
683  	            stat = SPxBasisBase<R>::Desc::P_FREE;
684  	
685  	            if(m_nonbasicValueUpToDate && rep() == COLUMN)
686  	               objChange = -theLRbound[i] * oldRhs;
687  	         }
688  	         else
689  	         {
690  	            stat = SPxBasisBase<R>::Desc::P_ON_LOWER;
691  	
692  	            if(m_nonbasicValueUpToDate && rep() == COLUMN)
693  	               objChange = (theURbound[i] * currLhs) - (theLRbound[i] * oldRhs);
694  	         }
695  	      }
696  	      else if(EQ(newRhs, currLhs, this->tolerances()->epsilon()))
697  	      {
698  	         stat = SPxBasisBase<R>::Desc::P_FIXED;
699  	
700  	         if(m_nonbasicValueUpToDate && rep() == COLUMN)
701  	            objChange = this->maxRowObj(i) * (newRhs - oldRhs);
702  	      }
703  	      else if(m_nonbasicValueUpToDate && rep() == COLUMN)
704  	         objChange = theLRbound[i] * (newRhs - oldRhs);
705  	
706  	      break;
707  	
708  	   case SPxBasisBase<R>::Desc::P_ON_LOWER:
709  	      if(EQ(newRhs, currLhs, this->tolerances()->epsilon()))
710  	         stat = SPxBasisBase<R>::Desc::P_FIXED;
711  	
712  	      break;
713  	
714  	   case SPxBasisBase<R>::Desc::P_FREE:
715  	      if(newRhs < R(infinity))
716  	      {
717  	         stat = SPxBasisBase<R>::Desc::P_ON_UPPER;
718  	
719  	         if(m_nonbasicValueUpToDate && rep() == COLUMN)
720  	            objChange = theLRbound[i] * newRhs;
721  	      }
722  	
723  	      break;
724  	
725  	   case SPxBasisBase<R>::Desc::P_FIXED:
726  	      if(NE(newRhs, currLhs, this->tolerances()->epsilon()))
727  	      {
728  	         stat = SPxBasisBase<R>::Desc::P_ON_LOWER;
729  	
730  	         if(isInitialized())
731  	            theURbound[i] = this->maxRowObj(i);
732  	      }
733  	
734  	      break;
735  	
736  	   case SPxBasisBase<R>::Desc::D_FREE:
737  	   case SPxBasisBase<R>::Desc::D_ON_UPPER:
738  	   case SPxBasisBase<R>::Desc::D_ON_LOWER:
739  	   case SPxBasisBase<R>::Desc::D_ON_BOTH:
740  	   case SPxBasisBase<R>::Desc::D_UNDEFINED:
741  	      if(rep() == ROW && theShift > 0.0)
742  	         forceRecompNonbasicValue();
743  	
744  	      stat = this->dualRowStatus(i);
745  	      break;
746  	
747  	   default:
748  	      throw SPxInternalCodeException("XCHANG04 This should never happen.");
749  	   }
750  	
751  	   SPxOut::debug(this, " -> {}\n", stat);
752  	
753  	   // we only need to update the nonbasic value in column representation (see nonbasicValue() for comparison/explanation)
754  	   if(rep() == COLUMN)
755  	      updateNonbasicValue(objChange);
756  	}
757  	
758  	
759  	template <class R>
760  	void SPxSolverBase<R>::changeRhs(const VectorBase<R>& newRhs, bool scale)
761  	{
762  	   // we better recompute the nonbasic value when changing all rhs
763  	   forceRecompNonbasicValue();
764  	
765  	   SPxLPBase<R>::changeRhs(newRhs, scale);
766  	
767  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
768  	   {
769  	      for(int i = 0; i < this->nRows(); ++i)
770  	         changeRhsStatus(i, this->rhs(i));
771  	
772  	      unInit();
773  	   }
774  	}
775  	
776  	template <class R>
777  	void SPxSolverBase<R>::changeRhs(int i, const R& newRhs, bool scale)
778  	{
779  	   if(newRhs != (scale ? this->rhsUnscaled(i) : this->rhs(i)))
780  	   {
781  	      forceRecompNonbasicValue();
782  	
783  	      R oldRhs = this->rhs(i);
784  	      SPxLPBase<R>::changeRhs(i, newRhs, scale);
785  	
786  	      if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
787  	      {
788  	         changeRhsStatus(i, this->rhs(i), oldRhs);
789  	         unInit();
790  	      }
791  	   }
792  	}
793  	
794  	template <class R>
795  	void SPxSolverBase<R>::changeRange(const VectorBase<R>& newLhs, const VectorBase<R>& newRhs,
796  	                                   bool scale)
797  	{
798  	   // we better recompute the nonbasic value when changing all ranges
799  	   forceRecompNonbasicValue();
800  	
801  	   SPxLPBase<R>::changeLhs(newLhs, scale);
802  	   SPxLPBase<R>::changeRhs(newRhs, scale);
803  	
804  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
805  	   {
806  	      for(int i = this->nRows() - 1; i >= 0; --i)
807  	      {
808  	         changeLhsStatus(i, this->lhs(i));
809  	         changeRhsStatus(i, this->rhs(i));
810  	      }
811  	
812  	      unInit();
813  	   }
814  	}
815  	
816  	template <class R>
817  	void SPxSolverBase<R>::changeRange(int i, const R& newLhs, const R& newRhs, bool scale)
818  	{
819  	   R oldLhs = this->lhs(i);
820  	   R oldRhs = this->rhs(i);
821  	
822  	   SPxLPBase<R>::changeLhs(i, newLhs, scale);
823  	
824  	   if(EQ(newLhs, newRhs, this->tolerances()->epsilon()))
825  	      SPxLPBase<R>::changeRhs(i, newLhs, scale);
826  	   else
827  	      SPxLPBase<R>::changeRhs(i, newRhs, scale);
828  	
829  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
830  	   {
831  	      changeLhsStatus(i, this->lhs(i), oldLhs);
832  	      changeRhsStatus(i, this->rhs(i), oldRhs);
833  	      unInit();
834  	   }
835  	}
836  	
837  	template <class R>
838  	void SPxSolverBase<R>::changeRow(int i, const LPRowBase<R>& newRow, bool scale)
839  	{
840  	   forceRecompNonbasicValue();
841  	
842  	   SPxLPBase<R>::changeRow(i, newRow, scale);
843  	
844  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
845  	      SPxBasisBase<R>::changedRow(i);
846  	
847  	   unInit();
848  	}
849  	
850  	template <class R>
851  	void SPxSolverBase<R>::changeCol(int i, const LPColBase<R>& newCol, bool scale)
852  	{
853  	   if(i < 0)
854  	      return;
855  	
856  	   forceRecompNonbasicValue();
857  	
858  	   SPxLPBase<R>::changeCol(i, newCol, scale);
859  	
860  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
861  	      SPxBasisBase<R>::changedCol(i);
862  	
863  	   unInit();
864  	}
865  	
866  	template <class R>
867  	void SPxSolverBase<R>::changeElement(int i, int j, const R& val, bool scale)
868  	{
869  	   if(i < 0 || j < 0)
870  	      return;
871  	
872  	   forceRecompNonbasicValue();
873  	
874  	   SPxLPBase<R>::changeElement(i, j, val, scale);
875  	
876  	   if(SPxBasisBase<R>::status() > SPxBasisBase<R>::NO_PROBLEM)
877  	      SPxBasisBase<R>::changedElement(i, j);
878  	
879  	   unInit();
880  	}
881  	
882  	template <class R>
883  	void SPxSolverBase<R>::changeSense(typename SPxLPBase<R>::SPxSense sns)
884  	{
885  	
886  	   SPxLPBase<R>::changeSense(sns);
887  	   unInit();
888  	}
889  	} // namespace soplex
890