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