1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2 /* */
3 /* This file is part of the class library */
4 /* SoPlex --- the Sequential object-oriented simPlex. */
5 /* */
6 /* Copyright (C) 1996-2021 Konrad-Zuse-Zentrum */
7 /* fuer Informationstechnik Berlin */
8 /* */
9 /* SoPlex is distributed under the terms of the ZIB Academic Licence. */
10 /* */
11 /* You should have received a copy of the ZIB Academic License */
12 /* along with SoPlex; see the file COPYING. If not email to soplex@zib.de. */
13 /* */
14 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15
16 #include <iostream>
17 #include <assert.h>
18
19 #include "soplex.h"
20 #include "soplex/statistics.h"
21 #include "soplex/slufactor_rational.h"
22 #include "soplex/ratrecon.h"
23
24 namespace soplex
25 {
26
27 /// solves rational LP
28 template <class R>
29 void SoPlexBase<R>::_optimizeRational(volatile bool* interrupt)
30 {
31 bool hasUnboundedRay = false;
32 bool infeasibilityNotCertified = false;
33 bool unboundednessNotCertified = false;
34
35 // start timing
36 _statistics->solvingTime->start();
37 _statistics->preprocessingTime->start();
38
39 // remember that last solve was rational
40 _lastSolveMode = SOLVEMODE_RATIONAL;
41
42 // ensure that the solver has the original problemo
43 if(!_isRealLPLoaded)
44 {
45 assert(_realLP != &_solver);
46
47 _solver.loadLP(*_realLP);
48 spx_free(_realLP);
49 _realLP = &_solver;
50 _isRealLPLoaded = true;
51 }
52 // during the rational solve, we always store basis information in the basis arrays
53 else if(_hasBasis)
54 {
55 _basisStatusRows.reSize(numRows());
56 _basisStatusCols.reSize(numCols());
57 _solver.getBasis(_basisStatusRows.get_ptr(), _basisStatusCols.get_ptr(), _basisStatusRows.size(),
58 _basisStatusCols.size());
59 }
60
61 // store objective, bounds, and sides of Real LP in case they will be modified during iterative refinement
62 _storeLPReal();
63
64 // deactivate objective limit in floating-point solver
65 if(realParam(SoPlexBase<R>::OBJLIMIT_LOWER) > -realParam(SoPlexBase<R>::INFTY)
66 || realParam(SoPlexBase<R>::OBJLIMIT_UPPER) < realParam(SoPlexBase<R>::INFTY))
67 {
68 MSG_INFO2(spxout, spxout << "Deactivating objective limit.\n");
69 }
70
71 _solver.setTerminationValue(realParam(SoPlexBase<R>::INFTY));
72
73 _statistics->preprocessingTime->stop();
74
75 // apply lifting to reduce range of nonzero matrix coefficients
76 if(boolParam(SoPlexBase<R>::LIFTING))
77 _lift();
78
79 // force column representation
80 ///@todo implement row objectives with row representation
81 int oldRepresentation = intParam(SoPlexBase<R>::REPRESENTATION);
82 setIntParam(SoPlexBase<R>::REPRESENTATION, SoPlexBase<R>::REPRESENTATION_COLUMN);
83
84 // force ratio test (avoid bound flipping)
85 int oldRatiotester = intParam(SoPlexBase<R>::RATIOTESTER);
86 setIntParam(SoPlexBase<R>::RATIOTESTER, SoPlexBase<R>::RATIOTESTER_FAST);
87
88 ///@todo implement handling of row objectives in Cplex interface
89 #ifdef SOPLEX_WITH_CPX
90 int oldEqtrans = boolParam(SoPlexBase<R>::EQTRANS);
91 setBoolParam(SoPlexBase<R>::EQTRANS, true);
92 #endif
93
94 // introduce slack variables to transform inequality constraints into equations
95 if(boolParam(SoPlexBase<R>::EQTRANS))
96 _transformEquality();
97
98 _storedBasis = false;
99
100 bool stoppedTime;
101 bool stoppedIter;
102
103 do
104 {
105 bool primalFeasible = false;
106 bool dualFeasible = false;
107 bool infeasible = false;
108 bool unbounded = false;
109 bool error = false;
110 stoppedTime = false;
111 stoppedIter = false;
112
113 // solve problem with iterative refinement and recovery mechanism
|
(4) Event template_instantiation_context: |
instantiation of "void soplex::SoPlexBase<R>::_performOptIRStable(soplex::SolRational &, bool, bool, int, bool &, bool &, bool &, bool &, bool &, bool &, bool &) [with R=soplex::Real]" at line 114 |
| Also see events: |
[switch_selector_expr_is_constant][caretline][template_instantiation_context][template_instantiation_context][template_instantiation_context][template_instantiation_context] |
114 _performOptIRStable(_solRational, !unboundednessNotCertified, !infeasibilityNotCertified, 0,
115 primalFeasible, dualFeasible, infeasible, unbounded, stoppedTime, stoppedIter, error);
116
117 // case: an unrecoverable error occured
118 if(error)
119 {
120 _status = SPxSolverBase<R>::ERROR;
121 break;
122 }
123 // case: stopped due to some limit
124 else if(stoppedTime)
125 {
126 _status = SPxSolverBase<R>::ABORT_TIME;
127 break;
128 }
129 else if(stoppedIter)
130 {
131 _status = SPxSolverBase<R>::ABORT_ITER;
132 break;
133 }
134 // case: unboundedness detected for the first time
135 else if(unbounded && !unboundednessNotCertified)
136 {
137 SolRational solUnbounded;
138
139 _performUnboundedIRStable(solUnbounded, hasUnboundedRay, stoppedTime, stoppedIter, error);
140
141 assert(!hasUnboundedRay || solUnbounded.hasPrimalRay());
142 assert(!solUnbounded.hasPrimalRay() || hasUnboundedRay);
143
144 if(error)
145 {
146 MSG_INFO1(spxout, spxout << "Error while testing for unboundedness.\n");
147 _status = SPxSolverBase<R>::ERROR;
148 break;
149 }
150
151 if(hasUnboundedRay)
152 {
153 MSG_INFO1(spxout, spxout << "Dual infeasible. Primal unbounded ray available.\n");
154 }
155 else
156 {
157 MSG_INFO1(spxout, spxout << "Dual feasible. Rejecting primal unboundedness.\n");
158 }
159
160 unboundednessNotCertified = !hasUnboundedRay;
161
162 if(stoppedTime)
163 {
164 _status = SPxSolverBase<R>::ABORT_TIME;
165 break;
166 }
167 else if(stoppedIter)
168 {
169 _status = SPxSolverBase<R>::ABORT_ITER;
170 break;
171 }
172
173 _performFeasIRStable(_solRational, infeasible, stoppedTime, stoppedIter, error);
174
175 ///@todo this should be stored already earlier, possible switch use solRational above and solFeas here
176 if(hasUnboundedRay)
177 {
178 _solRational._primalRay = solUnbounded._primalRay;
179 _solRational._hasPrimalRay = true;
180 }
181
182 if(error)
183 {
184 MSG_INFO1(spxout, spxout << "Error while testing for feasibility.\n");
185 _status = SPxSolverBase<R>::ERROR;
186 break;
187 }
188 else if(stoppedTime)
189 {
190 _status = SPxSolverBase<R>::ABORT_TIME;
191 break;
192 }
193 else if(stoppedIter)
194 {
195 _status = SPxSolverBase<R>::ABORT_ITER;
196 break;
197 }
198 else if(infeasible)
199 {
200 MSG_INFO1(spxout, spxout << "Primal infeasible. Dual Farkas ray available.\n");
201 _status = SPxSolverBase<R>::INFEASIBLE;
202 break;
203 }
204 else if(hasUnboundedRay)
205 {
206 MSG_INFO1(spxout, spxout << "Primal feasible and unbounded.\n");
207 _status = SPxSolverBase<R>::UNBOUNDED;
208 break;
209 }
210 else
211 {
212 MSG_INFO1(spxout, spxout << "Primal feasible and bounded.\n");
213 continue;
214 }
215 }
216 // case: infeasibility detected
217 else if(infeasible && !infeasibilityNotCertified)
218 {
219 _storeBasis();
220
221 _performFeasIRStable(_solRational, infeasible, stoppedTime, stoppedIter, error);
222
223 if(error)
224 {
225 MSG_INFO1(spxout, spxout << "Error while testing for infeasibility.\n");
226 _status = SPxSolverBase<R>::ERROR;
227 _restoreBasis();
228 break;
229 }
230
231 infeasibilityNotCertified = !infeasible;
232
233 if(stoppedTime)
234 {
235 _status = SPxSolverBase<R>::ABORT_TIME;
236 _restoreBasis();
237 break;
238 }
239 else if(stoppedIter)
240 {
241 _status = SPxSolverBase<R>::ABORT_ITER;
242 _restoreBasis();
243 break;
244 }
245
246 if(infeasible && boolParam(SoPlexBase<R>::TESTDUALINF))
247 {
248 SolRational solUnbounded;
249
250 _performUnboundedIRStable(solUnbounded, hasUnboundedRay, stoppedTime, stoppedIter, error);
251
252 assert(!hasUnboundedRay || solUnbounded.hasPrimalRay());
253 assert(!solUnbounded.hasPrimalRay() || hasUnboundedRay);
254
255 if(error)
256 {
257 MSG_INFO1(spxout, spxout << "Error while testing for dual infeasibility.\n");
258 _status = SPxSolverBase<R>::ERROR;
259 _restoreBasis();
260 break;
261 }
262
263 if(hasUnboundedRay)
264 {
265 MSG_INFO1(spxout, spxout << "Dual infeasible. Primal unbounded ray available.\n");
266 _solRational._primalRay = solUnbounded._primalRay;
267 _solRational._hasPrimalRay = true;
268 }
269 else if(solUnbounded._isDualFeasible)
270 {
271 MSG_INFO1(spxout, spxout << "Dual feasible. Storing dual multipliers.\n");
272 _solRational._dual = solUnbounded._dual;
273 _solRational._redCost = solUnbounded._redCost;
274 _solRational._isDualFeasible = true;
275 }
276 else
277 {
278 assert(false);
279 MSG_INFO1(spxout, spxout << "Not dual infeasible.\n");
280 }
281 }
282
283 _restoreBasis();
284
285 if(infeasible)
286 {
287 MSG_INFO1(spxout, spxout << "Primal infeasible. Dual Farkas ray available.\n");
288 _status = SPxSolverBase<R>::INFEASIBLE;
289 break;
290 }
291 else if(hasUnboundedRay)
292 {
293 MSG_INFO1(spxout, spxout << "Primal feasible and unbounded.\n");
294 _status = SPxSolverBase<R>::UNBOUNDED;
295 break;
296 }
297 else
298 {
299 MSG_INFO1(spxout, spxout << "Primal feasible. Optimizing again.\n");
300 continue;
301 }
302 }
303 else if(primalFeasible && dualFeasible)
304 {
305 MSG_INFO1(spxout, spxout << "Solved to optimality.\n");
306 _status = SPxSolverBase<R>::OPTIMAL;
307 break;
308 }
309 else
310 {
311 MSG_INFO1(spxout, spxout << "Terminating without success.\n");
312 break;
313 }
314 }
315 while(!_isSolveStopped(stoppedTime, stoppedIter));
316
317 ///@todo set status to ABORT_VALUE if optimal solution exceeds objective limit
318
319 if(_status == SPxSolverBase<R>::OPTIMAL || _status == SPxSolverBase<R>::INFEASIBLE
320 || _status == SPxSolverBase<R>::UNBOUNDED)
321 _hasSolRational = true;
322
323 // restore original problem
324 if(boolParam(SoPlexBase<R>::EQTRANS))
325 _untransformEquality(_solRational);
326
327 #ifdef SOPLEX_WITH_CPX
328 setBoolParam(SoPlexBase<R>::EQTRANS, oldEqtrans);
329 #endif
330
331 // reset representation and ratio test
332 setIntParam(SoPlexBase<R>::REPRESENTATION, oldRepresentation);
333 setIntParam(SoPlexBase<R>::RATIOTESTER, oldRatiotester);
334
335 // undo lifting
336 if(boolParam(SoPlexBase<R>::LIFTING))
337 _project(_solRational);
338
339 // restore objective, bounds, and sides of Real LP in case they have been modified during iterative refinement
340 _restoreLPReal();
341
342 // since the Real LP is loaded in the solver, we need to also pass the basis information to the solver if
343 // available
344 if(_hasBasis)
345 {
346 assert(_isRealLPLoaded);
347 _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
348 _hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
349
350 // since setBasis always sets the basis status to regular, we need to set it manually here
351 switch(_status)
352 {
353 case SPxSolverBase<R>::OPTIMAL:
354 _solver.setBasisStatus(SPxBasisBase<R>::OPTIMAL);
355 break;
356
357 case SPxSolverBase<R>::INFEASIBLE:
358 _solver.setBasisStatus(SPxBasisBase<R>::INFEASIBLE);
359 break;
360
361 case SPxSolverBase<R>::UNBOUNDED:
362 _solver.setBasisStatus(SPxBasisBase<R>::UNBOUNDED);
363 break;
364
365 default:
366 break;
367 }
368
369 }
370
371 // stop timing
372 _statistics->solvingTime->stop();
373 }
374
375
376
377 /// solves current problem with iterative refinement and recovery mechanism
378 template <class R>
379 void SoPlexBase<R>::_performOptIRStable(
380 SolRational& sol,
381 bool acceptUnbounded,
382 bool acceptInfeasible,
383 int minRounds,
384 bool& primalFeasible,
385 bool& dualFeasible,
386 bool& infeasible,
387 bool& unbounded,
388 bool& stoppedTime,
389 bool& stoppedIter,
390 bool& error)
391 {
392 // start rational solving timing
393 _statistics->rationalTime->start();
394
395 primalFeasible = false;
396 dualFeasible = false;
397 infeasible = false;
398 unbounded = false;
399 stoppedTime = false;
400 stoppedIter = false;
401 error = false;
402
403 // set working tolerances in floating-point solver
404 _solver.setFeastol(realParam(SoPlexBase<R>::FPFEASTOL));
405 _solver.setOpttol(realParam(SoPlexBase<R>::FPOPTTOL));
406
407 // declare vectors and variables
408 typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
409
410 _modLower.reDim(numColsRational(), false);
411 _modUpper.reDim(numColsRational(), false);
412 _modLhs.reDim(numRowsRational(), false);
413 _modRhs.reDim(numRowsRational(), false);
414 _modObj.reDim(numColsRational(), false);
415
416 VectorBase<R> primalReal(numColsRational());
417 VectorBase<R> dualReal(numRowsRational());
418
419 Rational boundsViolation;
420 Rational sideViolation;
421 Rational redCostViolation;
422 Rational dualViolation;
423 Rational primalScale;
424 Rational dualScale;
425 Rational maxScale;
426
427 // solve original LP
428 MSG_INFO1(spxout, spxout << "Initial floating-point solve . . .\n");
429
430 if(_hasBasis)
431 {
432 assert(_basisStatusRows.size() == numRowsRational());
433 assert(_basisStatusCols.size() == numColsRational());
434 _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
435 _hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
436 }
437
438 for(int r = numRowsRational() - 1; r >= 0; r--)
439 {
440 assert(_solver.maxRowObj(r) == 0.0);
441 }
442
443 _statistics->rationalTime->stop();
444 result = _solveRealStable(acceptUnbounded, acceptInfeasible, primalReal, dualReal, _basisStatusRows,
445 _basisStatusCols);
446
447 // evaluate result
448 switch(result)
449 {
450 case SPxSolverBase<R>::OPTIMAL:
451 MSG_INFO1(spxout, spxout << "Floating-point optimal.\n");
452 break;
453
454 case SPxSolverBase<R>::INFEASIBLE:
455 MSG_INFO1(spxout, spxout << "Floating-point infeasible.\n");
456
457 // the floating-point solve returns a Farkas ray if and only if the simplifier was not used, which is exactly
458 // the case when a basis could be returned
459 if(_hasBasis)
460 {
461 sol._dualFarkas = dualReal;
462 sol._hasDualFarkas = true;
463 }
464 else
465 sol._hasDualFarkas = false;
466
467 infeasible = true;
468 return;
469
470 case SPxSolverBase<R>::UNBOUNDED:
471 MSG_INFO1(spxout, spxout << "Floating-point unbounded.\n");
472 unbounded = true;
473 return;
474
475 case SPxSolverBase<R>::ABORT_TIME:
476 stoppedTime = true;
477 return;
478
479 case SPxSolverBase<R>::ABORT_ITER:
480 stoppedIter = true;
481 return;
482
483 default:
484 error = true;
485 return;
486 }
487
488 _statistics->rationalTime->start();
489
490 // store floating-point solution of original LP as current rational solution and ensure that solution vectors have
491 // right dimension; ensure that solution is aligned with basis
492 sol._primal.reDim(numColsRational(), false);
493 sol._slacks.reDim(numRowsRational(), false);
494 sol._dual.reDim(numRowsRational(), false);
495 sol._redCost.reDim(numColsRational(), false);
496 sol._isPrimalFeasible = true;
497 sol._isDualFeasible = true;
498
499 for(int c = numColsRational() - 1; c >= 0; c--)
500 {
501 typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
502
503 if(basisStatusCol == SPxSolverBase<R>::ON_LOWER)
504 sol._primal[c] = lowerRational(c);
505 else if(basisStatusCol == SPxSolverBase<R>::ON_UPPER)
506 sol._primal[c] = upperRational(c);
507 else if(basisStatusCol == SPxSolverBase<R>::FIXED)
508 {
509 // it may happen that lower and upper are only equal in the Real LP but different in the rational LP; we do
510 // not check this to avoid rational comparisons, but simply switch the basis status to the lower bound; this
511 // is necessary, because for fixed variables any reduced cost is feasible
512 sol._primal[c] = lowerRational(c);
513 basisStatusCol = SPxSolverBase<R>::ON_LOWER;
514 }
515 else if(basisStatusCol == SPxSolverBase<R>::ZERO)
516 sol._primal[c] = 0;
517 else
518 sol._primal[c].assign(primalReal[c]);
519 }
520
521 _rationalLP->computePrimalActivity(sol._primal, sol._slacks);
522
523 int dualSize = 0;
524
525 for(int r = numRowsRational() - 1; r >= 0; r--)
526 {
527 typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
528
529 // it may happen that left-hand and right-hand side are different in the rational, but equal in the Real LP,
530 // leading to a fixed basis status; this is critical because rows with fixed basis status are ignored in the
531 // computation of the dual violation; to avoid rational comparisons we do not check this but simply switch to
532 // the left-hand side status
533 if(basisStatusRow == SPxSolverBase<R>::FIXED)
534 basisStatusRow = SPxSolverBase<R>::ON_LOWER;
535
536 {
537 sol._dual[r].assign(dualReal[r]);
538
539 if(dualReal[r] != 0.0)
540 dualSize++;
541 }
542 }
543
544 // we assume that the objective function vector has less nonzeros than the reduced cost vector, and so multiplying
545 // with -1 first and subtracting the dual activity should be faster than adding the dual activity and negating
546 // afterwards
547 _rationalLP->getObj(sol._redCost);
548 _rationalLP->subDualActivity(sol._dual, sol._redCost);
549
550 // initial scaling factors are one
551 primalScale = _rationalPosone;
552 dualScale = _rationalPosone;
553
554 // control progress
555 Rational maxViolation;
556 Rational bestViolation = _rationalPosInfty;
557 const Rational violationImprovementFactor = 16;
558 const Rational errorCorrectionFactor = 1.1;
559 Rational errorCorrection = 2;
560 int numFailedRefinements = 0;
561
562 // store basis status in case solving modified problem failed
563 DataArray< typename SPxSolverBase<R>::VarStatus > basisStatusRowsFirst;
564 DataArray< typename SPxSolverBase<R>::VarStatus > basisStatusColsFirst;
565
566 // refinement loop
567 const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
568 const int maxDimRational = numColsRational() > numRowsRational() ? numColsRational() :
569 numRowsRational();
570 SolRational factorSol;
571 bool factorSolNewBasis = true;
572 int lastStallRefinements = 0;
573 int nextRatrecRefinement = 0;
574
575 do
576 {
577 // decrement minRounds counter
578 minRounds--;
579
580 MSG_DEBUG(std::cout << "Computing primal violations.\n");
581
582 // compute violation of bounds
583 boundsViolation = 0;
584
585 for(int c = numColsRational() - 1; c >= 0; c--)
586 {
587 // lower bound
588 assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
589
590 if(_lowerFinite(_colTypes[c]))
591 {
592 if(lowerRational(c) == 0)
593 {
594 _modLower[c] = sol._primal[c];
595 _modLower[c] *= -1;
596
597 if(_modLower[c] > boundsViolation)
598 boundsViolation = _modLower[c];
599 }
600 else
601 {
602 _modLower[c] = lowerRational(c);
603 _modLower[c] -= sol._primal[c];
604
605 if(_modLower[c] > boundsViolation)
606 boundsViolation = _modLower[c];
607 }
608 }
609
610 // upper bound
611 assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
612
613 if(_upperFinite(_colTypes[c]))
614 {
615 if(upperRational(c) == 0)
616 {
617 _modUpper[c] = sol._primal[c];
618 _modUpper[c] *= -1;
619
620 if(_modUpper[c] < -boundsViolation)
621 boundsViolation = -_modUpper[c];
622 }
623 else
624 {
625 _modUpper[c] = upperRational(c);
626 _modUpper[c] -= sol._primal[c];
627
628 if(_modUpper[c] < -boundsViolation)
629 boundsViolation = -_modUpper[c];
630 }
631 }
632 }
633
634 // compute violation of sides
635 sideViolation = 0;
636
637 for(int r = numRowsRational() - 1; r >= 0; r--)
638 {
639 const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
640
641 // left-hand side
642 assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
643
644 if(_lowerFinite(_rowTypes[r]))
645 {
646 if(lhsRational(r) == 0)
647 {
648 _modLhs[r] = sol._slacks[r];
649 _modLhs[r] *= -1;
650 }
651 else
652 {
653 _modLhs[r] = lhsRational(r);
654 _modLhs[r] -= sol._slacks[r];
655 }
656
657 if(_modLhs[r] > sideViolation)
658 sideViolation = _modLhs[r];
659 // if the activity is feasible, but too far from the bound, this violates complementary slackness; we
660 // count it as side violation here
661 else if(basisStatusRow == SPxSolverBase<R>::ON_LOWER && _modLhs[r] < -sideViolation)
662 sideViolation = -_modLhs[r];
663 }
664
665 // right-hand side
666 assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
667
668 if(_upperFinite(_rowTypes[r]))
669 {
670 if(rhsRational(r) == 0)
671 {
672 _modRhs[r] = sol._slacks[r];
673 _modRhs[r] *= -1;
674 }
675 else
676 {
677 _modRhs[r] = rhsRational(r);
678 _modRhs[r] -= sol._slacks[r];
679 }
680
681 if(_modRhs[r] < -sideViolation)
682 sideViolation = -_modRhs[r];
683 // if the activity is feasible, but too far from the bound, this violates complementary slackness; we
684 // count it as side violation here
685 else if(basisStatusRow == SPxSolverBase<R>::ON_UPPER && _modRhs[r] > sideViolation)
686 sideViolation = _modRhs[r];
687 }
688 }
689
690 MSG_DEBUG(std::cout << "Computing dual violations.\n");
691
692 // compute reduced cost violation
693 redCostViolation = 0;
694
695 for(int c = numColsRational() - 1; c >= 0; c--)
696 {
697 if(_colTypes[c] == RANGETYPE_FIXED)
698 continue;
699
700 const typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
701 assert(basisStatusCol != SPxSolverBase<R>::FIXED);
702
703 if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_LOWER) || (!maximizing
704 && basisStatusCol != SPxSolverBase<R>::ON_UPPER))
705 && sol._redCost[c] < -redCostViolation)
706 {
707 MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
708 << ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
709 << ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
710 << ", sol._redCost[c] = " << sol._redCost[c].str()
711 << "\n");
712 redCostViolation = -sol._redCost[c];
713 }
714
715 if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_UPPER) || (!maximizing
716 && basisStatusCol != SPxSolverBase<R>::ON_LOWER))
717 && sol._redCost[c] > redCostViolation)
718 {
719 MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
720 << ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
721 << ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
722 << ", sol._redCost[c] = " << sol._redCost[c].str()
723 << "\n");
724 redCostViolation = sol._redCost[c];
725 }
726 }
727
728 // compute dual violation
729 dualViolation = 0;
730
731 for(int r = numRowsRational() - 1; r >= 0; r--)
732 {
733 if(_rowTypes[r] == RANGETYPE_FIXED)
734 continue;
735
736 const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
737 assert(basisStatusRow != SPxSolverBase<R>::FIXED);
738
739 if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_LOWER) || (!maximizing
740 && basisStatusRow != SPxSolverBase<R>::ON_UPPER))
741 && sol._dual[r] < -dualViolation)
742 {
743 MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
744 << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
745 << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
746 << ", sol._dual[r] = " << sol._dual[r].str()
747 << "\n");
748 dualViolation = -sol._dual[r];
749 }
750
751 if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_UPPER) || (!maximizing
752 && basisStatusRow != SPxSolverBase<R>::ON_LOWER))
753 && sol._dual[r] > dualViolation)
754 {
755 MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
756 << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
757 << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
758 << ", sol._dual[r] = " << sol._dual[r].str()
759 << "\n");
760 dualViolation = sol._dual[r];
761 }
762 }
763
764 _modObj = sol._redCost;
765
766 // output violations; the reduced cost violations for artificially introduced slack columns are actually violations of the dual multipliers
767 MSG_INFO1(spxout, spxout
768 << "Max. bound violation = " << boundsViolation.str() << "\n"
769 << "Max. row violation = " << sideViolation.str() << "\n"
770 << "Max. reduced cost violation = " << redCostViolation.str() << "\n"
771 << "Max. dual violation = " << dualViolation.str() << "\n");
772
773 MSG_DEBUG(spxout
774 << std::fixed << std::setprecision(2) << std::setw(10)
775 << "Progress table: "
776 << std::setw(10) << _statistics->refinements << " & "
777 << std::setw(10) << _statistics->iterations << " & "
778 << std::setw(10) << _statistics->solvingTime->time() << " & "
779 << std::setw(10) << _statistics->rationalTime->time() << " & "
780 << std::setw(10) << boundsViolation > sideViolation ? boundsViolation :
781 sideViolation << " & "
782 << std::setw(10) << redCostViolation > dualViolation ? redCostViolation :
783 dualViolation << "\n");
784
785 // terminate if tolerances are satisfied
786 primalFeasible = (boundsViolation <= _rationalFeastol && sideViolation <= _rationalFeastol);
787 dualFeasible = (redCostViolation <= _rationalOpttol && dualViolation <= _rationalOpttol);
788
789 if(primalFeasible && dualFeasible)
790 {
791 if(minRounds < 0)
792 {
793 MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
794 break;
795 }
796 else
797 {
798 MSG_INFO1(spxout, spxout <<
799 "Tolerances reached but minRounds forcing additional refinement rounds.\n");
800 }
801 }
802
803 // terminate if some limit is reached
804 if(_isSolveStopped(stoppedTime, stoppedIter) || numFailedRefinements > 2)
805 break;
806
807 // check progress
808 maxViolation = boundsViolation;
809
810 if(sideViolation > maxViolation)
811 maxViolation = sideViolation;
812
813 if(redCostViolation > maxViolation)
814 maxViolation = redCostViolation;
815
816 if(dualViolation > maxViolation)
817 maxViolation = dualViolation;
818
819 bestViolation /= violationImprovementFactor;
820
821 if(maxViolation > bestViolation)
822 {
823 MSG_INFO2(spxout, spxout << "Failed to reduce violation significantly.\n");
824 bestViolation *= violationImprovementFactor;
825 numFailedRefinements++;
826 }
827 else
828 bestViolation = maxViolation;
829
830 // decide whether to perform rational reconstruction and/or factorization
831 bool forcebasic = boolParam(SoPlexBase<R>::FORCEBASIC);
832 bool performRatfac = boolParam(SoPlexBase<R>::RATFAC)
833 && lastStallRefinements >= intParam(SoPlexBase<R>::RATFAC_MINSTALLS) && _hasBasis
834 && factorSolNewBasis;
835 bool performRatrec = boolParam(SoPlexBase<R>::RATREC)
836 && (_statistics->refinements >= nextRatrecRefinement || performRatfac);
837
838 // if we want to force the solution to be basic we need to turn rational factorization on
839 performRatfac = performRatfac || forcebasic;
840
841 // attempt rational reconstruction
842 errorCorrection *= errorCorrectionFactor;
843
844 if(performRatrec && maxViolation > 0)
845 {
846 MSG_INFO1(spxout, spxout << "Performing rational reconstruction . . .\n");
847
848 maxViolation *= errorCorrection; // only used for sign check later
849 invert(maxViolation);
850
851 if(_reconstructSolutionRational(sol, _basisStatusRows, _basisStatusCols, maxViolation))
852 {
853 MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
854 primalFeasible = true;
855 dualFeasible = true;
856
857 if(_hasBasis || !forcebasic)
858 break;
859 }
860
861 nextRatrecRefinement = int(_statistics->refinements * realParam(SoPlexBase<R>::RATREC_FREQ)) + 1;
862 MSG_DEBUG(spxout << "Next rational reconstruction after refinement " << nextRatrecRefinement <<
863 ".\n");
864 }
865
866 // solve basis systems exactly
867 if((performRatfac && maxViolation > 0) || (!_hasBasis && forcebasic))
868 {
869 MSG_INFO1(spxout, spxout << "Performing rational factorization . . .\n");
870
871 bool optimal;
872 _factorizeColumnRational(sol, _basisStatusRows, _basisStatusCols, stoppedTime, stoppedIter, error,
873 optimal);
874 factorSolNewBasis = false;
875
876 if(stoppedTime)
877 {
878 MSG_INFO1(spxout, spxout << "Stopped rational factorization.\n");
879 }
880 else if(error)
881 {
882 // message was already printed; reset error flag and continue without factorization
883 error = false;
884 }
885 else if(optimal)
886 {
887 MSG_INFO1(spxout, spxout << "Tolerances reached.\n");
888 primalFeasible = true;
889 dualFeasible = true;
890 break;
891 }
892 else if(boolParam(SoPlexBase<R>::RATFACJUMP))
893 {
894 MSG_INFO1(spxout, spxout << "Jumping to exact basic solution.\n");
895 minRounds++;
896 continue;
897 }
898 }
899
900 // start refinement
901
902 // compute primal scaling factor; limit increase in scaling by tolerance used in floating point solve
903 maxScale = primalScale;
904 maxScale *= _rationalMaxscaleincr;
905
906 primalScale = boundsViolation > sideViolation ? boundsViolation : sideViolation;
907
908 if(primalScale < redCostViolation)
909 primalScale = redCostViolation;
910
911 assert(primalScale >= 0);
912
913 if(primalScale > 0)
914 {
915 invert(primalScale);
916
917 if(primalScale > maxScale)
918 primalScale = maxScale;
919 }
920 else
921 primalScale = maxScale;
922
923 if(boolParam(SoPlexBase<R>::POWERSCALING))
924 powRound(primalScale);
925
926 // apply scaled bounds
927 if(primalScale <= 1)
928 {
929 if(primalScale < 1)
930 primalScale = 1;
931
932 for(int c = numColsRational() - 1; c >= 0; c--)
933 {
934 if(_lowerFinite(_colTypes[c]))
935 {
936 if(_modLower[c] <= _rationalNegInfty)
937 _solver.changeLower(c, -realParam(SoPlexBase<R>::INFTY));
938 else
939 _solver.changeLower(c, static_cast<R>(_modLower[c]));
940 }
941
942 if(_upperFinite(_colTypes[c]))
943 {
944 if(_modUpper[c] >= _rationalPosInfty)
945 _solver.changeUpper(c, realParam(SoPlexBase<R>::INFTY));
946 else
947 _solver.changeUpper(c, R(_modUpper[c]));
948 }
949 }
950 }
951 else
952 {
953 MSG_INFO2(spxout, spxout << "Scaling primal by " << primalScale.str() << ".\n");
954
955 for(int c = numColsRational() - 1; c >= 0; c--)
956 {
957 if(_lowerFinite(_colTypes[c]))
958 {
959 _modLower[c] *= primalScale;
960
961 if(_modLower[c] <= _rationalNegInfty)
962 _solver.changeLower(c, -realParam(SoPlexBase<R>::INFTY));
963 else
964 _solver.changeLower(c, R(_modLower[c]));
965 }
966
967 if(_upperFinite(_colTypes[c]))
968 {
969 _modUpper[c] *= primalScale;
970
971 if(_modUpper[c] >= _rationalPosInfty)
972 _solver.changeUpper(c, realParam(SoPlexBase<R>::INFTY));
973 else
974 _solver.changeUpper(c, R(_modUpper[c]));
975 }
976 }
977 }
978
979 // apply scaled sides
980 assert(primalScale >= 1);
981
982 if(primalScale == 1)
983 {
984 for(int r = numRowsRational() - 1; r >= 0; r--)
985 {
986 if(_lowerFinite(_rowTypes[r]))
987 {
988 if(_modLhs[r] <= _rationalNegInfty)
989 _solver.changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
990 else
991 _solver.changeLhs(r, R(_modLhs[r]));
992 }
993
994 if(_upperFinite(_rowTypes[r]))
995 {
996 if(_modRhs[r] >= _rationalPosInfty)
997 _solver.changeRhs(r, realParam(SoPlexBase<R>::INFTY));
998 else
999 _solver.changeRhs(r, R(_modRhs[r]));
1000 }
1001 }
1002 }
1003 else
1004 {
1005 for(int r = numRowsRational() - 1; r >= 0; r--)
1006 {
1007 if(_lowerFinite(_rowTypes[r]))
1008 {
1009 _modLhs[r] *= primalScale;
1010
1011 if(_modLhs[r] <= _rationalNegInfty)
1012 _solver.changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
1013 else
1014 _solver.changeLhs(r, R(_modLhs[r]));
1015 }
1016
1017 if(_upperFinite(_rowTypes[r]))
1018 {
1019 _modRhs[r] *= primalScale;
1020
1021 if(_modRhs[r] >= _rationalPosInfty)
1022 _solver.changeRhs(r, realParam(SoPlexBase<R>::INFTY));
1023 else
1024 _solver.changeRhs(r, R(_modRhs[r]));
1025 }
1026 }
1027 }
1028
1029 // compute dual scaling factor; limit increase in scaling by tolerance used in floating point solve
1030 maxScale = dualScale;
1031 maxScale *= _rationalMaxscaleincr;
1032
1033 dualScale = redCostViolation > dualViolation ? redCostViolation : dualViolation;
1034 assert(dualScale >= 0);
1035
1036 if(dualScale > 0)
1037 {
1038 invert(dualScale);
1039
1040 if(dualScale > maxScale)
1041 dualScale = maxScale;
1042 }
1043 else
1044 dualScale = maxScale;
1045
1046 if(boolParam(SoPlexBase<R>::POWERSCALING))
1047 powRound(dualScale);
1048
1049 if(dualScale > primalScale)
1050 dualScale = primalScale;
1051
1052 if(dualScale < 1)
1053 dualScale = 1;
1054 else
1055 {
1056 MSG_INFO2(spxout, spxout << "Scaling dual by " << dualScale.str() << ".\n");
1057
1058 // perform dual scaling
1059 ///@todo remove _modObj and use dualScale * sol._redCost directly
1060 _modObj *= dualScale;
1061 }
1062
1063 // apply scaled objective function
1064 for(int c = numColsRational() - 1; c >= 0; c--)
1065 {
1066 if(_modObj[c] >= _rationalPosInfty)
1067 _solver.changeObj(c, realParam(SoPlexBase<R>::INFTY));
1068 else if(_modObj[c] <= _rationalNegInfty)
1069 _solver.changeObj(c, -realParam(SoPlexBase<R>::INFTY));
1070 else
1071 _solver.changeObj(c, R(_modObj[c]));
1072 }
1073
1074 for(int r = numRowsRational() - 1; r >= 0; r--)
1075 {
1076 Rational newRowObj;
1077
1078 if(_rowTypes[r] == RANGETYPE_FIXED)
1079 _solver.changeRowObj(r, R(0.0));
1080 else
1081 {
1082 newRowObj = sol._dual[r];
1083 newRowObj *= dualScale;
1084
1085 if(newRowObj >= _rationalPosInfty)
1086 _solver.changeRowObj(r, -realParam(SoPlexBase<R>::INFTY));
1087 else if(newRowObj <= _rationalNegInfty)
1088 _solver.changeRowObj(r, realParam(SoPlexBase<R>::INFTY));
1089 else
1090 _solver.changeRowObj(r, -R(newRowObj));
1091 }
1092 }
1093
1094 MSG_INFO1(spxout, spxout << "Refined floating-point solve . . .\n");
1095
1096 // ensure that artificial slack columns are basic and inequality constraints are nonbasic; otherwise we may end
1097 // up with dual violation on inequality constraints after removing the slack columns; do not change this in the
1098 // floating-point solver, though, because the solver may require its original basis to detect optimality
1099 if(_slackCols.num() > 0 && _hasBasis)
1100 {
1101 int numOrigCols = numColsRational() - _slackCols.num();
1102 assert(_slackCols.num() <= 0 || boolParam(SoPlexBase<R>::EQTRANS));
1103
1104 for(int i = 0; i < _slackCols.num(); i++)
1105 {
1106 int row = _slackCols.colVector(i).index(0);
1107 int col = numOrigCols + i;
1108
1109 assert(row >= 0);
1110 assert(row < numRowsRational());
1111
1112 if(_basisStatusRows[row] == SPxSolverBase<R>::BASIC
1113 && _basisStatusCols[col] != SPxSolverBase<R>::BASIC)
1114 {
1115 _basisStatusRows[row] = _basisStatusCols[col];
1116 _basisStatusCols[col] = SPxSolverBase<R>::BASIC;
1117 _rationalLUSolver.clear();
1118 }
1119 }
1120 }
1121
1122 // load basis
1123 if(_hasBasis && _solver.basis().status() < SPxBasisBase<R>::REGULAR)
1124 {
1125 MSG_DEBUG(spxout << "basis (status = " << _solver.basis().status() << ") desc before set:\n";
1126 _solver.basis().desc().dump());
1127 _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
1128 MSG_DEBUG(spxout << "basis (status = " << _solver.basis().status() << ") desc after set:\n";
1129 _solver.basis().desc().dump());
1130
1131 _hasBasis = _solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM;
1132 MSG_DEBUG(spxout << "setting basis in solver " << (_hasBasis ? "successful" : "failed") <<
1133 " (3)\n");
1134 }
1135
1136 // solve modified problem
1137 int prevIterations = _statistics->iterations;
1138 _statistics->rationalTime->stop();
1139 result = _solveRealStable(acceptUnbounded, acceptInfeasible, primalReal, dualReal, _basisStatusRows,
1140 _basisStatusCols, primalScale > 1e20 || dualScale > 1e20);
1141
1142 // count refinements and remember whether we moved to a new basis
1143 _statistics->refinements++;
1144
1145 if(_statistics->iterations <= prevIterations)
1146 {
1147 lastStallRefinements++;
1148 _statistics->stallRefinements++;
1149 }
1150 else
1151 {
1152 factorSolNewBasis = true;
1153 lastStallRefinements = 0;
1154 _statistics->pivotRefinements = _statistics->refinements;
1155 }
1156
1157 // evaluate result; if modified problem was not solved to optimality, stop refinement
1158 switch(result)
1159 {
1160 case SPxSolverBase<R>::OPTIMAL:
1161 MSG_INFO1(spxout, spxout << "Floating-point optimal.\n");
1162 break;
1163
1164 case SPxSolverBase<R>::INFEASIBLE:
1165 MSG_INFO1(spxout, spxout << "Floating-point infeasible.\n");
1166 sol._dualFarkas = dualReal;
1167 sol._hasDualFarkas = true;
1168 infeasible = true;
1169 _solver.clearRowObjs();
1170 return;
1171
1172 case SPxSolverBase<R>::UNBOUNDED:
1173 MSG_INFO1(spxout, spxout << "Floating-point unbounded.\n");
1174 unbounded = true;
1175 _solver.clearRowObjs();
1176 return;
1177
1178 case SPxSolverBase<R>::ABORT_TIME:
1179 stoppedTime = true;
1180 return;
1181
1182 case SPxSolverBase<R>::ABORT_ITER:
1183 stoppedIter = true;
1184 _solver.clearRowObjs();
1185 return;
1186
1187 default:
1188 error = true;
1189 _solver.clearRowObjs();
1190 return;
1191 }
1192
1193 _statistics->rationalTime->start();
1194
1195 // correct primal solution and align with basis
1196 MSG_DEBUG(std::cout << "Correcting primal solution.\n");
1197
1198 int primalSize = 0;
1199 Rational primalScaleInverse = primalScale;
1200 invert(primalScaleInverse);
1201 _primalDualDiff.clear();
1202
1203 for(int c = numColsRational() - 1; c >= 0; c--)
1204 {
1205 // force values of nonbasic variables to bounds
1206 typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
1207
1208 if(basisStatusCol == SPxSolverBase<R>::ON_LOWER)
1209 {
1210 if(sol._primal[c] != lowerRational(c))
1211 {
1212 int i = _primalDualDiff.size();
1213 _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1214 _primalDualDiff.add(c);
1215 _primalDualDiff.value(i) = lowerRational(c);
1216 _primalDualDiff.value(i) -= sol._primal[c];
1217 sol._primal[c] = lowerRational(c);
1218 }
1219 }
1220 else if(basisStatusCol == SPxSolverBase<R>::ON_UPPER)
1221 {
1222 if(sol._primal[c] != upperRational(c))
1223 {
1224 int i = _primalDualDiff.size();
1225 _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1226 _primalDualDiff.add(c);
1227 _primalDualDiff.value(i) = upperRational(c);
1228 _primalDualDiff.value(i) -= sol._primal[c];
1229 sol._primal[c] = upperRational(c);
1230 }
1231 }
1232 else if(basisStatusCol == SPxSolverBase<R>::FIXED)
1233 {
1234 // it may happen that lower and upper are only equal in the Real LP but different in the rational LP; we
1235 // do not check this to avoid rational comparisons, but simply switch the basis status to the lower
1236 // bound; this is necessary, because for fixed variables any reduced cost is feasible
1237 basisStatusCol = SPxSolverBase<R>::ON_LOWER;
1238
1239 if(sol._primal[c] != lowerRational(c))
1240 {
1241 int i = _primalDualDiff.size();
1242 _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1243 _primalDualDiff.add(c);
1244 _primalDualDiff.value(i) = lowerRational(c);
1245 _primalDualDiff.value(i) -= sol._primal[c];
1246 sol._primal[c] = lowerRational(c);
1247 }
1248 }
1249 else if(basisStatusCol == SPxSolverBase<R>::ZERO)
1250 {
1251 if(sol._primal[c] != 0)
1252 {
1253 int i = _primalDualDiff.size();
1254 _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1255 _primalDualDiff.add(c);
1256 _primalDualDiff.value(i) = sol._primal[c];
1257 _primalDualDiff.value(i) *= -1;
1258 sol._primal[c] = 0;
1259 }
1260 }
1261 else
1262 {
1263 if(primalReal[c] == 1.0)
1264 {
1265 int i = _primalDualDiff.size();
1266 _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1267 _primalDualDiff.add(c);
1268 _primalDualDiff.value(i) = primalScaleInverse;
1269 sol._primal[c] += _primalDualDiff.value(i);
1270 }
1271 else if(primalReal[c] == -1.0)
1272 {
1273 int i = _primalDualDiff.size();
1274 _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1275 _primalDualDiff.add(c);
1276 _primalDualDiff.value(i) = primalScaleInverse;
1277 _primalDualDiff.value(i) *= -1;
1278 sol._primal[c] += _primalDualDiff.value(i);
1279 }
1280 else if(primalReal[c] != 0.0)
1281 {
1282 int i = _primalDualDiff.size();
1283 _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1284 _primalDualDiff.add(c);
1285 _primalDualDiff.value(i).assign(primalReal[c]);
1286 _primalDualDiff.value(i) *= primalScaleInverse;
1287 sol._primal[c] += _primalDualDiff.value(i);
1288 }
1289 }
1290
1291 if(sol._primal[c] != 0)
1292 primalSize++;
1293 }
1294
1295 // update or recompute slacks depending on which looks faster
1296 if(_primalDualDiff.size() < primalSize)
1297 {
1298 _rationalLP->addPrimalActivity(_primalDualDiff, sol._slacks);
1299 #ifndef NDEBUG
1300 {
1301 VectorRational activity(numRowsRational());
1302 _rationalLP->computePrimalActivity(sol._primal, activity);
1303 assert(sol._slacks == activity);
1304 }
1305 #endif
1306 }
1307 else
1308 _rationalLP->computePrimalActivity(sol._primal, sol._slacks);
1309
1310 const int numCorrectedPrimals = _primalDualDiff.size();
1311
1312 // correct dual solution and align with basis
1313 MSG_DEBUG(std::cout << "Correcting dual solution.\n");
1314
1315 #ifndef NDEBUG
1316 {
1317 // compute reduced cost violation
1318 VectorRational debugRedCost(numColsRational());
1319 debugRedCost = VectorRational(_realLP->maxObj());
1320 debugRedCost *= -1;
1321 _rationalLP->subDualActivity(VectorRational(dualReal), debugRedCost);
1322
1323 Rational debugRedCostViolation = 0;
1324
1325 for(int c = numColsRational() - 1; c >= 0; c--)
1326 {
1327 if(_colTypes[c] == RANGETYPE_FIXED)
1328 continue;
1329
1330 const typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
1331 assert(basisStatusCol != SPxSolverBase<R>::FIXED);
1332
1333 if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_LOWER) || (!maximizing
1334 && basisStatusCol != SPxSolverBase<R>::ON_UPPER))
1335 && debugRedCost[c] < -debugRedCostViolation)
1336 {
1337 MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
1338 << ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
1339 << ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
1340 << ", obj[c] = " << _realLP->obj(c)
1341 << ", debugRedCost[c] = " << debugRedCost[c].str()
1342 << "\n");
1343 debugRedCostViolation = -debugRedCost[c];
1344 }
1345
1346 if(((maximizing && basisStatusCol != SPxSolverBase<R>::ON_UPPER) || (!maximizing
1347 && basisStatusCol != SPxSolverBase<R>::ON_LOWER))
1348 && debugRedCost[c] > debugRedCostViolation)
1349 {
1350 MSG_DEBUG(std::cout << "basisStatusCol = " << basisStatusCol
1351 << ", lower tight = " << bool(sol._primal[c] <= lowerRational(c))
1352 << ", upper tight = " << bool(sol._primal[c] >= upperRational(c))
1353 << ", obj[c] = " << _realLP->obj(c)
1354 << ", debugRedCost[c] = " << debugRedCost[c].str()
1355 << "\n");
1356 debugRedCostViolation = debugRedCost[c];
1357 }
1358 }
1359
1360 // compute dual violation
1361 Rational debugDualViolation = 0;
1362 Rational debugBasicDualViolation = 0;
1363
1364 for(int r = numRowsRational() - 1; r >= 0; r--)
1365 {
1366 if(_rowTypes[r] == RANGETYPE_FIXED)
1367 continue;
1368
1369 const typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
1370 assert(basisStatusRow != SPxSolverBase<R>::FIXED);
1371
1372 Rational val = (-dualScale * sol._dual[r]) - Rational(dualReal[r]);
1373
1374 if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_LOWER) || (!maximizing
1375 && basisStatusRow != SPxSolverBase<R>::ON_UPPER))
1376 && val > debugDualViolation)
1377 {
1378 MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
1379 << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
1380 << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
1381 << ", dualReal[r] = " << val.str()
1382 << ", dualReal[r] = " << dualReal[r]
1383 << "\n");
1384 debugDualViolation = val;
1385 }
1386
1387 if(((maximizing && basisStatusRow != SPxSolverBase<R>::ON_UPPER) || (!maximizing
1388 && basisStatusRow != SPxSolverBase<R>::ON_LOWER))
1389 && val < -debugDualViolation)
1390 {
1391 MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
1392 << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
1393 << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
1394 << ", dualReal[r] = " << val.str()
1395 << ", dualReal[r] = " << dualReal[r]
1396 << "\n");
1397 debugDualViolation = -val;
1398 }
1399
1400 if(basisStatusRow == SPxSolverBase<R>::BASIC && spxAbs(val) > debugBasicDualViolation)
1401 {
1402 MSG_DEBUG(std::cout << "basisStatusRow = " << basisStatusRow
1403 << ", lower tight = " << bool(sol._slacks[r] <= lhsRational(r))
1404 << ", upper tight = " << bool(sol._slacks[r] >= rhsRational(r))
1405 << ", dualReal[r] = " << val.str()
1406 << ", dualReal[r] = " << dualReal[r]
1407 << "\n");
1408 debugBasicDualViolation = spxAbs(val);
1409 }
1410 }
1411
1412 if(R(debugRedCostViolation) > _solver.opttol() || R(debugDualViolation) > _solver.opttol()
1413 || debugBasicDualViolation > 1e-9)
1414 {
1415 MSG_WARNING(spxout, spxout << "Warning: floating-point dual solution with violation "
1416 << debugRedCostViolation.str() << " / "
1417 << debugDualViolation.str() << " / "
1418 << debugBasicDualViolation.str()
1419 << " (red. cost, dual, basic).\n");
1420 }
1421 }
1422 #endif
1423
1424 Rational dualScaleInverseNeg = dualScale;
1425 invert(dualScaleInverseNeg);
1426 dualScaleInverseNeg *= -1;
1427 _primalDualDiff.clear();
1428 dualSize = 0;
1429
1430 for(int r = numRowsRational() - 1; r >= 0; r--)
1431 {
1432 typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
1433
1434 // it may happen that left-hand and right-hand side are different in the rational, but equal in the Real LP,
1435 // leading to a fixed basis status; this is critical because rows with fixed basis status are ignored in the
1436 // computation of the dual violation; to avoid rational comparisons we do not check this but simply switch
1437 // to the left-hand side status
1438 if(basisStatusRow == SPxSolverBase<R>::FIXED)
1439 basisStatusRow = SPxSolverBase<R>::ON_LOWER;
1440
1441 {
1442 if(dualReal[r] != 0)
1443 {
1444 int i = _primalDualDiff.size();
1445 _ensureDSVectorRationalMemory(_primalDualDiff, maxDimRational);
1446 _primalDualDiff.add(r);
1447 _primalDualDiff.value(i).assign(dualReal[r]);
1448 _primalDualDiff.value(i) *= dualScaleInverseNeg;
1449 sol._dual[r] -= _primalDualDiff.value(i);
1450
1451 dualSize++;
1452 }
1453 else
1454 {
1455 // we do not check whether the dual value is nonzero, because it probably is; this gives us an
1456 // overestimation of the number of nonzeros in the dual solution
1457 dualSize++;
1458 }
1459 }
1460 }
1461
1462 // update or recompute reduced cost values depending on which looks faster; adding one to the length of the
1463 // dual vector accounts for the objective function vector
1464 if(_primalDualDiff.size() < dualSize + 1)
1465 {
1466 _rationalLP->addDualActivity(_primalDualDiff, sol._redCost);
1467 #ifndef NDEBUG
1468 {
1469 VectorRational activity(_rationalLP->maxObj());
1470 activity *= -1;
1471 _rationalLP->subDualActivity(sol._dual, activity);
1472 }
1473 #endif
1474 }
1475 else
1476 {
1477 // we assume that the objective function vector has less nonzeros than the reduced cost vector, and so multiplying
1478 // with -1 first and subtracting the dual activity should be faster than adding the dual activity and negating
1479 // afterwards
1480 _rationalLP->getObj(sol._redCost);
1481 _rationalLP->subDualActivity(sol._dual, sol._redCost);
1482 }
1483
1484 const int numCorrectedDuals = _primalDualDiff.size();
1485
1486 if(numCorrectedPrimals + numCorrectedDuals > 0)
1487 {
1488 MSG_INFO2(spxout, spxout << "Corrected " << numCorrectedPrimals << " primal variables and " <<
1489 numCorrectedDuals << " dual values.\n");
1490 }
1491 }
1492 while(true);
1493
1494 // correct basis status for restricted inequalities
1495 if(_hasBasis)
1496 {
1497 for(int r = numRowsRational() - 1; r >= 0; r--)
1498 {
1499 assert((lhsRational(r) == rhsRational(r)) == (_rowTypes[r] == RANGETYPE_FIXED));
1500
1501 if(_rowTypes[r] != RANGETYPE_FIXED && _basisStatusRows[r] == SPxSolverBase<R>::FIXED)
1502 _basisStatusRows[r] = (maximizing == (sol._dual[r] < 0))
1503 ? SPxSolverBase<R>::ON_LOWER
1504 : SPxSolverBase<R>::ON_UPPER;
1505 }
1506 }
1507
1508 // compute objective function values
1509 assert(sol._isPrimalFeasible == sol._isDualFeasible);
1510
1511 if(sol._isPrimalFeasible)
1512 {
1513 sol._objVal = sol._primal * _rationalLP->maxObj();
1514
1515 if(intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MINIMIZE)
1516 sol._objVal *= -1;
1517 }
1518
1519 // set objective coefficients for all rows to zero
1520 _solver.clearRowObjs();
1521
1522 // stop rational solving time
1523 _statistics->rationalTime->stop();
1524 }
1525
1526
1527 /// performs iterative refinement on the auxiliary problem for testing unboundedness
1528 template <class R>
1529 void SoPlexBase<R>::_performUnboundedIRStable(
1530 SolRational& sol,
1531 bool& hasUnboundedRay,
1532 bool& stoppedTime,
1533 bool& stoppedIter,
1534 bool& error)
1535 {
1536 bool primalFeasible;
1537 bool dualFeasible;
1538 bool infeasible;
1539 bool unbounded;
1540
1541 // move objective function to constraints and adjust sides and bounds
1542 _transformUnbounded();
1543
1544 // invalidate solution
1545 sol.invalidate();
1546
1547 // remember current number of refinements
1548 int oldRefinements = _statistics->refinements;
1549
1550 // perform iterative refinement
1551 _performOptIRStable(sol, false, false, 0, primalFeasible, dualFeasible, infeasible, unbounded,
1552 stoppedTime, stoppedIter, error);
1553
1554 // update unbounded refinement counter
1555 _statistics->unbdRefinements += _statistics->refinements - oldRefinements;
1556
1557 // stopped due to some limit
1558 if(stoppedTime || stoppedIter)
1559 {
1560 sol.invalidate();
1561 hasUnboundedRay = false;
1562 error = false;
1563 }
1564 // the unbounded problem should always be solved to optimality
1565 else if(error || unbounded || infeasible || !primalFeasible || !dualFeasible)
1566 {
1567 sol.invalidate();
1568 hasUnboundedRay = false;
1569 error = true;
1570 }
1571 else
1572 {
1573 const Rational& tau = sol._primal[numColsRational() - 1];
1574
1575 MSG_DEBUG(std::cout << "tau = " << tau << " (roughly " << tau.str() << ")\n");
1576
1577 assert(tau <= 1.0 + 2.0 * realParam(SoPlexBase<R>::FEASTOL));
1578 assert(tau >= -realParam(SoPlexBase<R>::FEASTOL));
1579
1580 // because the right-hand side and all bounds (but tau's upper bound) are zero, tau should be approximately
1581 // zero if basic; otherwise at its upper bound 1
1582 error = !(tau >= _rationalPosone || tau <= _rationalFeastol);
1583 assert(!error);
1584
1585 hasUnboundedRay = (tau >= 1);
1586 }
1587
1588 // restore problem
1589 _untransformUnbounded(sol, hasUnboundedRay);
1590 }
1591
1592
1593
1594 /// performs iterative refinement on the auxiliary problem for testing feasibility
1595 template <class R>
1596 void SoPlexBase<R>::_performFeasIRStable(
1597 SolRational& sol,
1598 bool& withDualFarkas,
1599 bool& stoppedTime,
1600 bool& stoppedIter,
1601 bool& error)
1602 {
1603 bool primalFeasible;
1604 bool dualFeasible;
1605 bool infeasible;
1606 bool unbounded;
1607 bool success = false;
1608 error = false;
1609
1610 #if 0
1611 // if the problem has been found to be infeasible and an approximate Farkas proof is available, we compute a
1612 // scaled unit box around the origin that provably contains no feasible solution; this currently only works for
1613 // equality form
1614 ///@todo check whether approximate Farkas proof can be used
1615 _computeInfeasBox(_solRational, false);
1616 ///@todo if approx Farkas proof is good enough then exit without doing any transformation
1617 #endif
1618
1619 // remove objective function, shift, homogenize
1620 _transformFeasibility();
1621
1622 // invalidate solution
1623 sol.invalidate();
1624
1625 do
1626 {
1627 // remember current number of refinements
1628 int oldRefinements = _statistics->refinements;
1629
1630 // perform iterative refinement
1631 _performOptIRStable(sol, false, false, 0, primalFeasible, dualFeasible, infeasible, unbounded,
1632 stoppedTime, stoppedIter, error);
1633
1634 // update feasible refinement counter
1635 _statistics->feasRefinements += _statistics->refinements - oldRefinements;
1636
1637 // stopped due to some limit
1638 if(stoppedTime || stoppedIter)
1639 {
1640 sol.invalidate();
1641 withDualFarkas = false;
1642 error = false;
1643 }
1644 // the feasibility problem should always be solved to optimality
1645 else if(error || unbounded || infeasible || !primalFeasible || !dualFeasible)
1646 {
1647 sol.invalidate();
1648 withDualFarkas = false;
1649 error = true;
1650 }
1651 // else we should have either a refined Farkas proof or an approximate feasible solution to the original
1652 else
1653 {
1654 const Rational& tau = sol._primal[numColsRational() - 1];
1655
1656 MSG_DEBUG(std::cout << "tau = " << tau << " (roughly " << tau.str() << ")\n");
1657
1658 assert(tau >= -realParam(SoPlexBase<R>::FEASTOL));
1659 assert(tau <= 1.0 + realParam(SoPlexBase<R>::FEASTOL));
1660
1661 error = (tau < -_rationalFeastol || tau > _rationalPosone + _rationalFeastol);
1662 withDualFarkas = (tau < _rationalPosone);
1663
1664 if(withDualFarkas)
1665 {
1666 _solRational._hasDualFarkas = true;
1667 _solRational._dualFarkas = _solRational._dual;
1668
1669 #if 0
1670 // check if we can compute sufficiently large Farkas box
1671 _computeInfeasBox(_solRational, true);
1672 #endif
1673
1674 if(true) //@todo check if computeInfeasBox found a sufficient box
1675 {
1676
1677 success = true;
1678 sol._isPrimalFeasible = false;
1679 }
1680 }
1681 else
1682 {
1683 sol._isDualFeasible = false;
1684 success = true; //successfully found approximate feasible solution
1685 }
1686 }
1687 }
1688 while(!error && !success && !(stoppedTime || stoppedIter));
1689
1690 // restore problem
1691 _untransformFeasibility(sol, withDualFarkas);
1692 }
1693
1694
1695
1696 /// reduces matrix coefficient in absolute value by the lifting procedure of Thiele et al. 2013
1697 template <class R>
1698 void SoPlexBase<R>::_lift()
1699 {
1700 MSG_DEBUG(std::cout << "Reducing matrix coefficients by lifting.\n");
1701
1702 // start timing
1703 _statistics->transformTime->start();
1704
1705 MSG_DEBUG(_realLP->writeFileLPBase("beforeLift.lp", 0, 0, 0));
1706
1707 // remember unlifted state
1708 _beforeLiftCols = numColsRational();
1709 _beforeLiftRows = numRowsRational();
1710
1711 // allocate vector memory
1712 DSVectorRational colVector;
1713 SVectorRational::Element liftingRowMem[2];
1714 SVectorRational liftingRowVector(2, liftingRowMem);
1715
1716 // search each column for large nonzeros entries
1717 // @todo: rethink about the static_cast TODO
1718 const Rational maxValue = static_cast<Rational>(realParam(SoPlexBase<R>::LIFTMAXVAL));
1719
1720 for(int i = 0; i < numColsRational(); i++)
1721 {
1722 MSG_DEBUG(std::cout << "in lifting: examining column " << i << "\n");
1723
1724 // get column vector
1725 colVector = colVectorRational(i);
1726
1727 bool addedLiftingRow = false;
1728 int liftingColumnIndex = -1;
1729
1730 // go through nonzero entries of the column
1731 for(int k = colVector.size() - 1; k >= 0; k--)
1732 {
1733 const Rational& value = colVector.value(k);
1734
1735 if(spxAbs(value) > maxValue)
1736 {
1737 MSG_DEBUG(std::cout << " --> nonzero " << k << " has value " << value.str() << " in row " <<
1738 colVector.index(k) << "\n");
1739
1740 // add new column equal to maxValue times original column
1741 if(!addedLiftingRow)
1742 {
1743 MSG_DEBUG(std::cout << " --> adding lifting row\n");
1744
1745 assert(liftingRowVector.size() == 0);
1746
1747 liftingColumnIndex = numColsRational();
1748 liftingRowVector.add(i, maxValue);
1749 liftingRowVector.add(liftingColumnIndex, -1);
1750
1751 _rationalLP->addRow(LPRowRational(0, liftingRowVector, 0));
1752 _realLP->addRow(LPRowBase<R>(0.0, DSVectorBase<R>(liftingRowVector), 0.0));
1753
1754 assert(liftingColumnIndex == numColsRational() - 1);
1755 assert(liftingColumnIndex == numCols() - 1);
1756
1757 _rationalLP->changeBounds(liftingColumnIndex, _rationalNegInfty, _rationalPosInfty);
1758 _realLP->changeBounds(liftingColumnIndex, -realParam(SoPlexBase<R>::INFTY),
1759 realParam(SoPlexBase<R>::INFTY));
1760
1761 liftingRowVector.clear();
1762 addedLiftingRow = true;
1763 }
1764
1765 // get row index
1766 int rowIndex = colVector.index(k);
1767 assert(rowIndex >= 0);
1768 assert(rowIndex < _beforeLiftRows);
1769 assert(liftingColumnIndex == numColsRational() - 1);
1770
1771 MSG_DEBUG(std::cout << " --> changing matrix\n");
1772
1773 // remove nonzero from original column
1774 _rationalLP->changeElement(rowIndex, i, 0);
1775 _realLP->changeElement(rowIndex, i, 0.0);
1776
1777 // add nonzero divided by maxValue to new column
1778 Rational newValue(value);
1779 newValue /= maxValue;
1780 _rationalLP->changeElement(rowIndex, liftingColumnIndex, newValue);
1781 _realLP->changeElement(rowIndex, liftingColumnIndex, R(newValue));
1782 }
1783 }
1784 }
1785
1786 // search each column for small nonzeros entries
1787 const Rational minValue = Rational(realParam(SoPlexBase<R>::LIFTMINVAL));
1788
1789 for(int i = 0; i < numColsRational(); i++)
1790 {
1791 MSG_DEBUG(std::cout << "in lifting: examining column " << i << "\n");
1792
1793 // get column vector
1794 colVector = colVectorRational(i);
1795
1796 bool addedLiftingRow = false;
1797 int liftingColumnIndex = -1;
1798
1799 // go through nonzero entries of the column
1800 for(int k = colVector.size() - 1; k >= 0; k--)
1801 {
1802 const Rational& value = colVector.value(k);
1803
1804 if(spxAbs(value) < minValue)
1805 {
1806 MSG_DEBUG(std::cout << " --> nonzero " << k << " has value " << value.str() << " in row " <<
1807 colVector.index(k) << "\n");
1808
1809 // add new column equal to maxValue times original column
1810 if(!addedLiftingRow)
1811 {
1812 MSG_DEBUG(std::cout << " --> adding lifting row\n");
1813
1814 assert(liftingRowVector.size() == 0);
1815
1816 liftingColumnIndex = numColsRational();
1817 liftingRowVector.add(i, minValue);
1818 liftingRowVector.add(liftingColumnIndex, -1);
1819
1820 _rationalLP->addRow(LPRowRational(0, liftingRowVector, 0));
1821 _realLP->addRow(LPRowBase<R>(0.0, DSVectorBase<R>(liftingRowVector), 0.0));
1822
1823 assert(liftingColumnIndex == numColsRational() - 1);
1824 assert(liftingColumnIndex == numCols() - 1);
1825
1826 _rationalLP->changeBounds(liftingColumnIndex, _rationalNegInfty, _rationalPosInfty);
1827 _realLP->changeBounds(liftingColumnIndex, -realParam(SoPlexBase<R>::INFTY),
1828 realParam(SoPlexBase<R>::INFTY));
1829
1830 liftingRowVector.clear();
1831 addedLiftingRow = true;
1832 }
1833
1834 // get row index
1835 int rowIndex = colVector.index(k);
1836 assert(rowIndex >= 0);
1837 assert(rowIndex < _beforeLiftRows);
1838 assert(liftingColumnIndex == numColsRational() - 1);
1839
1840 MSG_DEBUG(std::cout << " --> changing matrix\n");
1841
1842 // remove nonzero from original column
1843 _rationalLP->changeElement(rowIndex, i, 0);
1844 _realLP->changeElement(rowIndex, i, 0.0);
1845
1846 // add nonzero divided by maxValue to new column
1847 Rational newValue(value);
1848 newValue /= minValue;
1849 _rationalLP->changeElement(rowIndex, liftingColumnIndex, newValue);
1850 _realLP->changeElement(rowIndex, liftingColumnIndex, R(newValue));
1851 }
1852 }
1853 }
1854
1855 // adjust basis
1856 if(_hasBasis)
1857 {
1858 assert(numColsRational() >= _beforeLiftCols);
1859 assert(numRowsRational() >= _beforeLiftRows);
1860
1861 _basisStatusCols.append(numColsRational() - _beforeLiftCols, SPxSolverBase<R>::BASIC);
1862 _basisStatusRows.append(numRowsRational() - _beforeLiftRows, SPxSolverBase<R>::FIXED);
1863 _rationalLUSolver.clear();
1864 }
1865
1866 MSG_DEBUG(_realLP->writeFileLPBase("afterLift.lp", 0, 0, 0));
1867
1868 // stop timing
1869 _statistics->transformTime->stop();
1870
1871 if(numColsRational() > _beforeLiftCols || numRowsRational() > _beforeLiftRows)
1872 {
1873 MSG_INFO1(spxout, spxout << "Added " << numColsRational() - _beforeLiftCols << " columns and "
1874 << numRowsRational() - _beforeLiftRows << " rows to reduce large matrix coefficients\n.");
1875 }
1876 }
1877
1878
1879
1880 /// undoes lifting
1881 template <class R>
1882 void SoPlexBase<R>::_project(SolRational& sol)
1883 {
1884 // start timing
1885 _statistics->transformTime->start();
1886
1887 // print LP if in debug mode
1888 MSG_DEBUG(_realLP->writeFileLPBase("beforeProject.lp", 0, 0, 0));
1889
1890 assert(numColsRational() >= _beforeLiftCols);
1891 assert(numRowsRational() >= _beforeLiftRows);
1892
1893 // shrink rational LP to original size
1894 _rationalLP->removeColRange(_beforeLiftCols, numColsRational() - 1);
1895 _rationalLP->removeRowRange(_beforeLiftRows, numRowsRational() - 1);
1896
1897 // shrink real LP to original size
1898 _realLP->removeColRange(_beforeLiftCols, numColsReal() - 1);
1899 _realLP->removeRowRange(_beforeLiftRows, numRowsReal() - 1);
1900
1901 // adjust solution
1902 if(sol.isPrimalFeasible())
1903 {
1904 sol._primal.reDim(_beforeLiftCols);
1905 sol._slacks.reDim(_beforeLiftRows);
1906 }
1907
1908 if(sol.hasPrimalRay())
1909 {
1910 sol._primalRay.reDim(_beforeLiftCols);
1911 }
1912
1913 ///@todo if we know the mapping between original and lifting columns, we simply need to add the reduced cost of
1914 /// the lifting column to the reduced cost of the original column; this is not implemented now, because for
1915 /// optimal solutions the reduced costs of the lifting columns are zero
1916 const Rational maxValue = Rational(realParam(SoPlexBase<R>::LIFTMAXVAL));
1917
1918 for(int i = _beforeLiftCols; i < numColsRational() && sol._isDualFeasible; i++)
1919 {
1920 if(spxAbs(Rational(maxValue * sol._redCost[i])) > _rationalOpttol)
1921 {
1922 MSG_INFO1(spxout, spxout << "Warning: lost dual solution during project phase.\n");
1923 sol._isDualFeasible = false;
1924 }
1925 }
1926
1927 if(sol.isDualFeasible())
1928 {
1929 sol._redCost.reDim(_beforeLiftCols);
1930 sol._dual.reDim(_beforeLiftRows);
1931 }
1932
1933 if(sol.hasDualFarkas())
1934 {
1935 sol._dualFarkas.reDim(_beforeLiftRows);
1936 }
1937
1938 // adjust basis
1939 for(int i = _beforeLiftCols; i < numColsRational() && _hasBasis; i++)
1940 {
1941 if(_basisStatusCols[i] != SPxSolverBase<R>::BASIC)
1942 {
1943 MSG_INFO1(spxout, spxout <<
1944 "Warning: lost basis during project phase because of nonbasic lifting column.\n");
1945 _hasBasis = false;
1946 _rationalLUSolver.clear();
1947 }
1948 }
1949
1950 for(int i = _beforeLiftRows; i < numRowsRational() && _hasBasis; i++)
1951 {
1952 if(_basisStatusRows[i] == SPxSolverBase<R>::BASIC)
1953 {
1954 MSG_INFO1(spxout, spxout <<
1955 "Warning: lost basis during project phase because of basic lifting row.\n");
1956 _hasBasis = false;
1957 _rationalLUSolver.clear();
1958 }
1959 }
1960
1961 if(_hasBasis)
1962 {
1963 _basisStatusCols.reSize(_beforeLiftCols);
1964 _basisStatusRows.reSize(_beforeLiftRows);
1965 _rationalLUSolver.clear();
1966 }
1967
1968 // print LP if in debug mode
1969 MSG_DEBUG(_realLP->writeFileLPBase("afterProject.lp", 0, 0, 0));
1970
1971 // stop timing
1972 _statistics->transformTime->stop();
1973 }
1974
1975
1976
1977 /// stores objective, bounds, and sides of real LP
1978 template <class R>
1979 void SoPlexBase<R>::_storeLPReal()
1980 {
1981 #ifndef SOPLEX_MANUAL_ALT
1982
1983 if(intParam(SoPlexBase<R>::SYNCMODE) == SYNCMODE_MANUAL)
1984 {
1985 _manualRealLP = *_realLP;
1986 return;
1987 }
1988
1989 #endif
1990
1991 _manualLower = _realLP->lower();
1992 _manualUpper = _realLP->upper();
1993 _manualLhs = _realLP->lhs();
1994 _manualRhs = _realLP->rhs();
1995 _manualObj.reDim(_realLP->nCols());
1996 _realLP->getObj(_manualObj);
1997 }
1998
1999
2000
2001 /// restores objective, bounds, and sides of real LP
2002 template <class R>
2003 void SoPlexBase<R>::_restoreLPReal()
2004 {
2005 if(intParam(SoPlexBase<R>::SYNCMODE) == SYNCMODE_MANUAL)
2006 {
2007 #ifndef SOPLEX_MANUAL_ALT
2008 _solver.loadLP(_manualRealLP);
2009 #else
2010 _realLP->changeLower(_manualLower);
2011 _realLP->changeUpper(_manualUpper);
2012 _realLP->changeLhs(_manualLhs);
2013 _realLP->changeRhs(_manualRhs);
2014 _realLP->changeObj(_manualObj);
2015 #endif
2016
2017 if(_hasBasis)
2018 {
2019 // in manual sync mode, if the right-hand side of an equality constraint is not floating-point
2020 // representable, the user might have constructed the constraint in the real LP by rounding down the
2021 // left-hand side and rounding up the right-hand side; if the basis status is fixed, we need to adjust it
2022 for(int i = 0; i < _solver.nRows(); i++)
2023 {
2024 if(_basisStatusRows[i] == SPxSolverBase<R>::FIXED && _solver.lhs(i) != _solver.rhs(i))
2025 {
2026 assert(_solver.rhs(i) == spxNextafter(_solver.lhs(i), R(infinity)));
2027
2028 if(_hasSolRational && _solRational.isDualFeasible()
2029 && ((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE
2030 && _solRational._dual[i] > 0)
2031 || (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MINIMIZE
2032 && _solRational._dual[i] < 0)))
2033 {
2034 _basisStatusRows[i] = SPxSolverBase<R>::ON_UPPER;
2035 }
2036 else
2037 {
2038 _basisStatusRows[i] = SPxSolverBase<R>::ON_LOWER;
2039 }
2040 }
2041 }
2042
2043 _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
2044 _hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
2045 }
2046 }
2047 else
2048 {
2049 _realLP->changeLower(_manualLower);
2050 _realLP->changeUpper(_manualUpper);
2051 _realLP->changeLhs(_manualLhs);
2052 _realLP->changeRhs(_manualRhs);
2053 _realLP->changeObj(_manualObj);
2054 }
2055 }
2056
2057
2058
2059 /// introduces slack variables to transform inequality constraints into equations for both rational and real LP,
2060 /// which should be in sync
2061 template <class R>
2062 void SoPlexBase<R>::_transformEquality()
2063 {
2064 MSG_DEBUG(std::cout << "Transforming rows to equation form.\n");
2065
2066 // start timing
2067 _statistics->transformTime->start();
2068
2069 MSG_DEBUG(_realLP->writeFileLPBase("beforeTransEqu.lp", 0, 0, 0));
2070
2071 // clear array of slack columns
2072 _slackCols.clear();
2073
2074 // add artificial slack variables to convert inequality to equality constraints
2075 for(int i = 0; i < numRowsRational(); i++)
2076 {
2077 assert((lhsRational(i) == rhsRational(i)) == (_rowTypes[i] == RANGETYPE_FIXED));
2078
2079 if(_rowTypes[i] != RANGETYPE_FIXED)
2080 {
2081 _slackCols.add(_rationalZero, -rhsRational(i), *_unitVectorRational(i), -lhsRational(i));
2082
2083 if(_rationalLP->lhs(i) != 0)
2084 _rationalLP->changeLhs(i, _rationalZero);
2085
2086 if(_rationalLP->rhs(i) != 0)
2087 _rationalLP->changeRhs(i, _rationalZero);
2088
2089 assert(_rationalLP->lhs(i) == 0);
2090 assert(_rationalLP->rhs(i) == 0);
2091 _realLP->changeRange(i, R(0.0), R(0.0));
2092 _colTypes.append(_switchRangeType(_rowTypes[i]));
2093 _rowTypes[i] = RANGETYPE_FIXED;
2094 }
2095 }
2096
2097 _rationalLP->addCols(_slackCols);
2098 _realLP->addCols(_slackCols);
2099
2100 // adjust basis
2101 if(_hasBasis)
2102 {
2103 for(int i = 0; i < _slackCols.num(); i++)
2104 {
2105 int row = _slackCols.colVector(i).index(0);
2106
2107 assert(row >= 0);
2108 assert(row < numRowsRational());
2109
2110 switch(_basisStatusRows[row])
2111 {
2112 case SPxSolverBase<R>::ON_LOWER:
2113 _basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
2114 break;
2115
2116 case SPxSolverBase<R>::ON_UPPER:
2117 _basisStatusCols.append(SPxSolverBase<R>::ON_LOWER);
2118 break;
2119
2120 case SPxSolverBase<R>::BASIC:
2121 case SPxSolverBase<R>::FIXED:
2122 default:
2123 _basisStatusCols.append(_basisStatusRows[row]);
2124 break;
2125 }
2126
2127 _basisStatusRows[row] = SPxSolverBase<R>::FIXED;
2128 }
2129
2130 _rationalLUSolver.clear();
2131 }
2132
2133 MSG_DEBUG(_realLP->writeFileLPBase("afterTransEqu.lp", 0, 0, 0));
2134
2135 // stop timing
2136 _statistics->transformTime->stop();
2137
2138 if(_slackCols.num() > 0)
2139 {
2140 MSG_INFO1(spxout, spxout << "Added " << _slackCols.num() <<
2141 " slack columns to transform rows to equality form.\n");
2142 }
2143 }
2144
2145
2146
2147 /// restores original problem
2148 template <class R>
2149 void SoPlexBase<R>::_untransformEquality(SolRational& sol)
2150 {
2151 // start timing
2152 _statistics->transformTime->start();
2153
2154 // print LP if in debug mode
2155 MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransEqu.lp", 0, 0, 0));
2156
2157 int numCols = numColsRational();
2158 int numOrigCols = numColsRational() - _slackCols.num();
2159
2160 // adjust solution
2161 if(sol.isPrimalFeasible())
2162 {
2163 for(int i = 0; i < _slackCols.num(); i++)
2164 {
2165 int col = numOrigCols + i;
2166 int row = _slackCols.colVector(i).index(0);
2167
2168 assert(row >= 0);
2169 assert(row < numRowsRational());
2170
2171 sol._slacks[row] -= sol._primal[col];
2172 }
2173
2174 sol._primal.reDim(numOrigCols);
2175 }
2176
2177 if(sol.hasPrimalRay())
2178 {
2179 sol._primalRay.reDim(numOrigCols);
2180 }
2181
2182 // adjust basis
2183 if(_hasBasis)
2184 {
2185 for(int i = 0; i < _slackCols.num(); i++)
2186 {
2187 int col = numOrigCols + i;
2188 int row = _slackCols.colVector(i).index(0);
2189
2190 assert(row >= 0);
2191 assert(row < numRowsRational());
2192 assert(_basisStatusRows[row] != SPxSolverBase<R>::UNDEFINED);
2193 assert(_basisStatusRows[row] != SPxSolverBase<R>::ZERO || lhsRational(row) == 0);
2194 assert(_basisStatusRows[row] != SPxSolverBase<R>::ZERO || rhsRational(row) == 0);
2195 assert(_basisStatusRows[row] != SPxSolverBase<R>::BASIC
2196 || _basisStatusCols[col] != SPxSolverBase<R>::BASIC);
2197
2198 MSG_DEBUG(std::cout << "slack column " << col << " for row " << row
2199 << ": col status=" << _basisStatusCols[col]
2200 << ", row status=" << _basisStatusRows[row]
2201 << ", redcost=" << sol._redCost[col].str()
2202 << ", dual=" << sol._dual[row].str() << "\n");
2203
2204 if(_basisStatusRows[row] != SPxSolverBase<R>::BASIC)
2205 {
2206 switch(_basisStatusCols[col])
2207 {
2208 case SPxSolverBase<R>::ON_LOWER:
2209 _basisStatusRows[row] = SPxSolverBase<R>::ON_UPPER;
2210 break;
2211
2212 case SPxSolverBase<R>::ON_UPPER:
2213 _basisStatusRows[row] = SPxSolverBase<R>::ON_LOWER;
2214 break;
2215
2216 case SPxSolverBase<R>::BASIC:
2217 case SPxSolverBase<R>::FIXED:
2218 default:
2219 _basisStatusRows[row] = _basisStatusCols[col];
2220 break;
2221 }
2222 }
2223 }
2224
2225 _basisStatusCols.reSize(numOrigCols);
2226
2227 if(_slackCols.num() > 0)
2228 _rationalLUSolver.clear();
2229 }
2230
2231 // not earlier because of debug message
2232 if(sol.isDualFeasible())
2233 {
2234 sol._redCost.reDim(numOrigCols);
2235 }
2236
2237 // restore sides and remove slack columns
2238 for(int i = 0; i < _slackCols.num(); i++)
2239 {
2240 int col = numOrigCols + i;
2241 int row = _slackCols.colVector(i).index(0);
2242
2243 if(upperRational(col) != 0)
2244 _rationalLP->changeLhs(row, -upperRational(col));
2245
2246 if(lowerRational(col) != 0)
2247 _rationalLP->changeRhs(row, -lowerRational(col));
2248
2249 assert(_rationalLP->lhs(row) == -upperRational(col));
2250 assert(_rationalLP->rhs(row) == -lowerRational(col));
2251 _rowTypes[row] = _switchRangeType(_colTypes[col]);
2252 }
2253
2254 _rationalLP->removeColRange(numOrigCols, numCols - 1);
2255 _realLP->removeColRange(numOrigCols, numCols - 1);
2256 _colTypes.reSize(numOrigCols);
2257
2258 // objective, bounds, and sides of real LP are restored only after _solveRational()
2259
2260 // print LP if in debug mode
2261 MSG_DEBUG(_realLP->writeFileLPBase("afterUntransEqu.lp", 0, 0, 0));
2262
2263 // stop timing
2264 _statistics->transformTime->stop();
2265 }
2266
2267
2268
2269 /// transforms LP to unboundedness problem by moving the objective function to the constraints, changing right-hand
2270 /// side and bounds to zero, and adding an auxiliary variable for the decrease in the objective function
2271 template <class R>
2272 void SoPlexBase<R>::_transformUnbounded()
2273 {
2274 MSG_INFO1(spxout, spxout << "Setting up LP to compute primal unbounded ray.\n");
2275
2276 // start timing
2277 _statistics->transformTime->start();
2278
2279 // print LP if in debug mode
2280 MSG_DEBUG(_realLP->writeFileLPBase("beforeTransUnbounded.lp", 0, 0, 0));
2281
2282 // store bounds
2283 _unboundedLower.reDim(numColsRational());
2284 _unboundedUpper.reDim(numColsRational());
2285
2286 for(int c = numColsRational() - 1; c >= 0; c--)
2287 {
2288 if(_lowerFinite(_colTypes[c]))
2289 _unboundedLower[c] = lowerRational(c);
2290
2291 if(_upperFinite(_colTypes[c]))
2292 _unboundedUpper[c] = upperRational(c);
2293 }
2294
2295 // store sides
2296 _unboundedLhs.reDim(numRowsRational());
2297 _unboundedRhs.reDim(numRowsRational());
2298
2299 for(int r = numRowsRational() - 1; r >= 0; r--)
2300 {
2301 if(_lowerFinite(_rowTypes[r]))
2302 _unboundedLhs[r] = lhsRational(r);
2303
2304 if(_upperFinite(_rowTypes[r]))
2305 _unboundedRhs[r] = rhsRational(r);
2306 }
2307
2308 // make right-hand side zero
2309 for(int r = numRowsRational() - 1; r >= 0; r--)
2310 {
2311 assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2312
2313 if(_lowerFinite(_rowTypes[r]))
2314 {
2315 _rationalLP->changeLhs(r, Rational(0));
2316 _realLP->changeLhs(r, R(0.0));
2317 }
2318 else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
2319 _realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
2320
2321 assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2322
2323 if(_upperFinite(_rowTypes[r]))
2324 {
2325 _rationalLP->changeRhs(r, Rational(0));
2326 _realLP->changeRhs(r, R(0.0));
2327 }
2328 else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
2329 _realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
2330 }
2331
2332 // transform objective function to constraint and add auxiliary variable
2333 int numOrigCols = numColsRational();
2334 DSVectorRational obj(numOrigCols + 1);
2335 ///@todo implement this without copying the objective function
2336 obj = _rationalLP->maxObj();
2337 obj.add(numOrigCols, -1);
2338 _rationalLP->addRow(LPRowRational(0, obj, 0));
2339 _realLP->addRow(LPRowBase<R>(0, DSVectorBase<R>(obj), 0));
2340 _rowTypes.append(RANGETYPE_FIXED);
2341
2342 assert(numColsRational() == numOrigCols + 1);
2343
2344 // set objective coefficient and bounds for auxiliary variable
2345 _rationalLP->changeMaxObj(numOrigCols, Rational(1));
2346 _realLP->changeMaxObj(numOrigCols, R(1.0));
2347
2348 _rationalLP->changeBounds(numOrigCols, _rationalNegInfty, 1);
2349 _realLP->changeBounds(numOrigCols, -realParam(SoPlexBase<R>::INFTY), 1.0);
2350 _colTypes.append(RANGETYPE_UPPER);
2351
2352 // set objective coefficients to zero and adjust bounds for problem variables
2353 for(int c = numColsRational() - 2; c >= 0; c--)
2354 {
2355 _rationalLP->changeObj(c, Rational(0));
2356 _realLP->changeObj(c, R(0.0));
2357
2358 assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
2359
2360 if(_lowerFinite(_colTypes[c]))
2361 {
2362 _rationalLP->changeLower(c, Rational(0));
2363 _realLP->changeLower(c, R(0.0));
2364 }
2365 else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
2366 _realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
2367
2368 assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
2369
2370 if(_upperFinite(_colTypes[c]))
2371 {
2372 _rationalLP->changeUpper(c, Rational(0));
2373 _realLP->changeUpper(c, R(0.0));
2374 }
2375 else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
2376 _realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
2377 }
2378
2379 // adjust basis
2380 if(_hasBasis)
2381 {
2382 _basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
2383 _basisStatusRows.append(SPxSolverBase<R>::BASIC);
2384 _rationalLUSolver.clear();
2385 }
2386
2387 // print LP if in debug mode
2388 MSG_DEBUG(_realLP->writeFileLPBase("afterTransUnbounded.lp", 0, 0, 0));
2389
2390 // stop timing
2391 _statistics->transformTime->stop();
2392 }
2393
2394
2395
2396 /// undoes transformation to unboundedness problem
2397 template <class R>
2398 void SoPlexBase<R>::_untransformUnbounded(SolRational& sol, bool unbounded)
2399 {
2400 // start timing
2401 _statistics->transformTime->start();
2402
2403 // print LP if in debug mode
2404 MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransUnbounded.lp", 0, 0, 0));
2405
2406 int numOrigCols = numColsRational() - 1;
2407 int numOrigRows = numRowsRational() - 1;
2408 const Rational& tau = sol._primal[numOrigCols];
2409
2410 // adjust solution and basis
2411 if(unbounded)
2412 {
2413 assert(tau >= _rationalPosone);
2414
2415 sol._isPrimalFeasible = false;
2416 sol._hasPrimalRay = true;
2417 sol._isDualFeasible = false;
2418 sol._hasDualFarkas = false;
2419
2420 if(tau != 1)
2421 sol._primal /= tau;
2422
2423 sol._primalRay = sol._primal;
2424 sol._primalRay.reDim(numOrigCols);
2425
2426 _hasBasis = (_basisStatusCols[numOrigCols] != SPxSolverBase<R>::BASIC
2427 && _basisStatusRows[numOrigRows] == SPxSolverBase<R>::BASIC);
2428 _basisStatusCols.reSize(numOrigCols);
2429 _basisStatusRows.reSize(numOrigRows);
2430 }
2431 else if(boolParam(SoPlexBase<R>::TESTDUALINF) && tau < _rationalFeastol)
2432 {
2433 const Rational& alpha = sol._dual[numOrigRows];
2434
2435 assert(sol._isDualFeasible);
2436 assert(alpha <= _rationalFeastol - _rationalPosone);
2437
2438 sol._isPrimalFeasible = false;
2439 sol._hasPrimalRay = false;
2440 sol._hasDualFarkas = false;
2441
2442 if(alpha != -1)
2443 {
2444 sol._dual /= -alpha;
2445 sol._redCost /= -alpha;
2446 }
2447
2448 sol._dual.reDim(numOrigRows);
2449 sol._redCost.reDim(numOrigCols);
2450 }
2451 else
2452 {
2453 sol.invalidate();
2454 _hasBasis = false;
2455 _basisStatusCols.reSize(numOrigCols);
2456 _basisStatusCols.reSize(numOrigRows);
2457 }
2458
2459 // recover objective function
2460 const SVectorRational& objRowVector = _rationalLP->rowVector(numOrigRows);
2461
2462 for(int i = objRowVector.size() - 1; i >= 0; i--)
2463 {
2464 _rationalLP->changeMaxObj(objRowVector.index(i), objRowVector.value(i));
2465 _realLP->changeMaxObj(objRowVector.index(i), R(objRowVector.value(i)));
2466 }
2467
2468 // remove objective function constraint and auxiliary variable
2469 _rationalLP->removeRow(numOrigRows);
2470 _realLP->removeRow(numOrigRows);
2471 _rowTypes.reSize(numOrigRows);
2472
2473 _rationalLP->removeCol(numOrigCols);
2474 _realLP->removeCol(numOrigCols);
2475 _colTypes.reSize(numOrigCols);
2476
2477 // restore objective, sides and bounds
2478 for(int r = numRowsRational() - 1; r >= 0; r--)
2479 {
2480 if(_lowerFinite(_rowTypes[r]))
2481 {
2482 _rationalLP->changeLhs(r, _unboundedLhs[r]);
2483 _realLP->changeLhs(r, R(_unboundedLhs[r]));
2484 }
2485
2486 if(_upperFinite(_rowTypes[r]))
2487 {
2488 _rationalLP->changeRhs(r, _unboundedRhs[r]);
2489 _realLP->changeRhs(r, R(_unboundedRhs[r]));
2490 }
2491
2492 assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2493 assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2494 assert((lhsReal(r) > -realParam(SoPlexBase<R>::INFTY)) == _lowerFinite(_rowTypes[r]));
2495 assert((rhsReal(r) < realParam(SoPlexBase<R>::INFTY)) == _upperFinite(_rowTypes[r]));
2496 }
2497
2498 for(int c = numColsRational() - 1; c >= 0; c--)
2499 {
2500 if(_lowerFinite(_colTypes[c]))
2501 {
2502 _rationalLP->changeLower(c, _unboundedLower[c]);
2503 _realLP->changeLower(c, R(_unboundedLower[c]));
2504 }
2505
2506 if(_upperFinite(_colTypes[c]))
2507 {
2508 _rationalLP->changeUpper(c, _unboundedUpper[c]);
2509 _realLP->changeUpper(c, R(_unboundedUpper[c]));
2510 }
2511
2512 assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
2513 assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
2514 assert((lowerReal(c) > -realParam(SoPlexBase<R>::INFTY)) == _lowerFinite(_colTypes[c]));
2515 assert((upperReal(c) < realParam(SoPlexBase<R>::INFTY)) == _upperFinite(_colTypes[c]));
2516 }
2517
2518 // invalidate rational basis factorization
2519 _rationalLUSolver.clear();
2520
2521 // print LP if in debug mode
2522 MSG_DEBUG(_realLP->writeFileLPBase("afterUntransUnbounded.lp", 0, 0, 0));
2523
2524 // stop timing
2525 _statistics->transformTime->stop();
2526 }
2527
2528
2529
2530 /// store basis
2531 template <class R>
2532 void SoPlexBase<R>::_storeBasis()
2533 {
2534 assert(!_storedBasis);
2535
2536 if(_hasBasis)
2537 {
2538 _storedBasis = true;
2539 _storedBasisStatusCols = _basisStatusCols;
2540 _storedBasisStatusRows = _basisStatusRows;
2541 }
2542 else
2543 _storedBasis = false;
2544 }
2545
2546
2547
2548 /// restore basis
2549 template <class R>
2550 void SoPlexBase<R>::_restoreBasis()
2551 {
2552 if(_storedBasis)
2553 {
2554 _hasBasis = true;
2555 _basisStatusCols = _storedBasisStatusCols;
2556 _basisStatusRows = _storedBasisStatusRows;
2557 _storedBasis = false;
2558 }
2559 }
2560
2561
2562
2563 /// transforms LP to feasibility problem by removing the objective function, shifting variables, and homogenizing the
2564 /// right-hand side
2565 template <class R>
2566 void SoPlexBase<R>::_transformFeasibility()
2567 {
2568 MSG_INFO1(spxout, spxout << "Setting up LP to test for feasibility.\n");
2569
2570 // start timing
2571 _statistics->transformTime->start();
2572
2573 // print LP if in debug mode
2574 MSG_DEBUG(_realLP->writeFileLPBase("beforeTransFeas.lp", 0, 0, 0));
2575
2576 // store objective function
2577 _feasObj.reDim(numColsRational());
2578
2579 for(int c = numColsRational() - 1; c >= 0; c--)
2580 _feasObj[c] = _rationalLP->maxObj(c);
2581
2582 // store bounds
2583 _feasLower.reDim(numColsRational());
2584 _feasUpper.reDim(numColsRational());
2585
2586 for(int c = numColsRational() - 1; c >= 0; c--)
2587 {
2588 if(_lowerFinite(_colTypes[c]))
2589 _feasLower[c] = lowerRational(c);
2590
2591 if(_upperFinite(_colTypes[c]))
2592 _feasUpper[c] = upperRational(c);
2593 }
2594
2595 // store sides
2596 _feasLhs.reDim(numRowsRational());
2597 _feasRhs.reDim(numRowsRational());
2598
2599 for(int r = numRowsRational() - 1; r >= 0; r--)
2600 {
2601 if(_lowerFinite(_rowTypes[r]))
2602 _feasLhs[r] = lhsRational(r);
2603
2604 if(_upperFinite(_rowTypes[r]))
2605 _feasRhs[r] = rhsRational(r);
2606 }
2607
2608 // set objective coefficients to zero; shift primal space such as to guarantee that the zero solution is within
2609 // the bounds
2610 Rational shiftValue;
2611 Rational shiftValue2;
2612
2613 for(int c = numColsRational() - 1; c >= 0; c--)
2614 {
2615 _rationalLP->changeMaxObj(c, Rational(0));
2616 _realLP->changeMaxObj(c, R(0.0));
2617
2618 if(lowerRational(c) > 0)
2619 {
2620 const SVectorRational& colVector = colVectorRational(c);
2621
2622 for(int i = 0; i < colVector.size(); i++)
2623 {
2624 shiftValue = colVector.value(i);
2625 shiftValue *= lowerRational(c);
2626 int r = colVector.index(i);
2627
2628 assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2629 assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2630
2631 if(_lowerFinite(_rowTypes[r]) && _upperFinite(_rowTypes[r]))
2632 {
2633 shiftValue2 = lhsRational(r);
2634 shiftValue2 -= shiftValue;
2635 _rationalLP->changeLhs(r, shiftValue2);
2636 _realLP->changeLhs(r, R(shiftValue2));
2637
2638 shiftValue -= rhsRational(r);
2639 shiftValue *= -1;
2640 _rationalLP->changeRhs(r, shiftValue);
2641 _realLP->changeRhs(r, R(shiftValue));
2642 }
2643 else if(_lowerFinite(_rowTypes[r]))
2644 {
2645 shiftValue -= lhsRational(r);
2646 shiftValue *= -1;
2647 _rationalLP->changeLhs(r, shiftValue);
2648 _realLP->changeLhs(r, R(shiftValue));
2649 }
2650 else if(_upperFinite(_rowTypes[r]))
2651 {
2652 shiftValue -= rhsRational(r);
2653 shiftValue *= -1;
2654 _rationalLP->changeRhs(r, shiftValue);
2655 _realLP->changeRhs(r, R(shiftValue));
2656 }
2657 }
2658
2659 assert((upperRational(c) < _rationalPosInfty) == _upperFinite(_colTypes[c]));
2660
2661 if(_upperFinite(_colTypes[c]))
2662 {
2663 _rationalLP->changeBounds(c, 0, upperRational(c) - lowerRational(c));
2664 _realLP->changeBounds(c, 0.0, R(upperRational(c)));
2665 }
2666 else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
2667 {
2668 _rationalLP->changeLower(c, Rational(0));
2669 _realLP->changeBounds(c, 0.0, realParam(SoPlexBase<R>::INFTY));
2670 }
2671 else
2672 {
2673 _rationalLP->changeLower(c, Rational(0));
2674 _realLP->changeLower(c, R(0.0));
2675 }
2676 }
2677 else if(upperRational(c) < 0)
2678 {
2679 const SVectorRational& colVector = colVectorRational(c);
2680
2681 for(int i = 0; i < colVector.size(); i++)
2682 {
2683 shiftValue = colVector.value(i);
2684 shiftValue *= upperRational(c);
2685 int r = colVector.index(i);
2686
2687 assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2688 assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2689
2690 if(_lowerFinite(_rowTypes[r]) && _upperFinite(_rowTypes[r]))
2691 {
2692 shiftValue2 = lhsRational(r);
2693 shiftValue2 -= shiftValue;
2694 _rationalLP->changeLhs(r, shiftValue2);
2695 _realLP->changeLhs(r, R(shiftValue2));
2696
2697 shiftValue -= rhsRational(r);
2698 shiftValue *= -1;
2699 _rationalLP->changeRhs(r, shiftValue);
2700 _realLP->changeRhs(r, R(shiftValue));
2701 }
2702 else if(_lowerFinite(_rowTypes[r]))
2703 {
2704 shiftValue -= lhsRational(r);
2705 shiftValue *= -1;
2706 _rationalLP->changeLhs(r, shiftValue);
2707 _realLP->changeLhs(r, R(shiftValue));
2708 }
2709 else if(_upperFinite(_rowTypes[r]))
2710 {
2711 shiftValue -= rhsRational(r);
2712 shiftValue *= -1;
2713 _rationalLP->changeRhs(r, shiftValue);
2714 _realLP->changeRhs(r, R(shiftValue));
2715 }
2716 }
2717
2718 assert((lowerRational(c) > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
2719
2720 if(_lowerFinite(_colTypes[c]))
2721 {
2722 _rationalLP->changeBounds(c, lowerRational(c) - upperRational(c), 0);
2723 _realLP->changeBounds(c, R(lowerRational(c)), 0.0);
2724 }
2725 else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
2726 {
2727 _rationalLP->changeUpper(c, Rational(0));
2728 _realLP->changeBounds(c, -realParam(SoPlexBase<R>::INFTY), 0.0);
2729 }
2730 else
2731 {
2732 _rationalLP->changeUpper(c, Rational(0));
2733 _realLP->changeUpper(c, R(0.0));
2734 }
2735 }
2736 else
2737 {
2738 if(_lowerFinite(_colTypes[c]))
2739 _realLP->changeLower(c, R(lowerRational(c)));
2740 else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
2741 _realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
2742
2743 if(_upperFinite(_colTypes[c]))
2744 _realLP->changeUpper(c, R(upperRational(c)));
2745 else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
2746 _realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
2747 }
2748
2749 assert(lowerReal(c) <= upperReal(c));
2750 }
2751
2752 // homogenize sides
2753 _tauColVector.clear();
2754
2755 for(int r = numRowsRational() - 1; r >= 0; r--)
2756 {
2757 if(lhsRational(r) > 0)
2758 {
2759 _tauColVector.add(r, lhsRational(r));
2760 assert((rhsRational(r) < _rationalPosInfty) == _upperFinite(_rowTypes[r]));
2761
2762 if(_upperFinite(_rowTypes[r]))
2763 {
2764 _rationalLP->changeRange(r, 0, rhsRational(r) - lhsRational(r));
2765 _realLP->changeRange(r, 0.0, R(rhsRational(r)));
2766 }
2767 else
2768 {
2769 _rationalLP->changeLhs(r, Rational(0));
2770 _realLP->changeLhs(r, R(0.0));
2771
2772 if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
2773 _realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
2774 }
2775 }
2776 else if(rhsRational(r) < 0)
2777 {
2778 _tauColVector.add(r, rhsRational(r));
2779 assert((lhsRational(r) > _rationalNegInfty) == _lowerFinite(_rowTypes[r]));
2780
2781 if(_lowerFinite(_rowTypes[r]))
2782 {
2783 _rationalLP->changeRange(r, lhsRational(r) - rhsRational(r), 0);
2784 _realLP->changeRange(r, R(lhsRational(r)), 0.0);
2785 }
2786 else
2787 {
2788 _rationalLP->changeRhs(r, Rational(0));
2789 _realLP->changeRhs(r, R(0.0));
2790
2791 if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
2792 _realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
2793 }
2794 }
2795 else
2796 {
2797 if(_lowerFinite(_rowTypes[r]))
2798 _realLP->changeLhs(r, R(lhsRational(r)));
2799 else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
2800 _realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
2801
2802 if(_upperFinite(_rowTypes[r]))
2803 _realLP->changeRhs(r, R(rhsRational(r)));
2804 else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
2805 _realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
2806 }
2807
2808 assert(rhsReal(r) <= rhsReal(r));
2809 }
2810
2811 ///@todo exploit this case by returning without LP solving
2812 if(_tauColVector.size() == 0)
2813 {
2814 MSG_INFO3(spxout, spxout << "LP is trivially feasible.\n");
2815 }
2816
2817 // add artificial column
2818 SPxColId id;
2819 _tauColVector *= -1;
2820 _rationalLP->addCol(id,
2821 LPColRational((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE ?
2822 _rationalPosone : _rationalNegone),
2823 _tauColVector, 1, 0));
2824 _realLP->addCol(id,
2825 LPColBase<R>((intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE ? 1.0 : -1.0),
2826 DSVectorBase<R>(_tauColVector), 1.0, 0.0));
2827 _colTypes.append(RANGETYPE_BOXED);
2828
2829 // adjust basis
2830 if(_hasBasis)
2831 {
2832 _basisStatusCols.append(SPxSolverBase<R>::ON_UPPER);
2833 }
2834
2835 // invalidate rational basis factorization
2836 _rationalLUSolver.clear();
2837
2838 // print LP if in debug mode
2839 MSG_DEBUG(_realLP->writeFileLPBase("afterTransFeas.lp", 0, 0, 0));
2840
2841 // stop timing
2842 _statistics->transformTime->stop();
2843 }
2844
2845
2846
2847 /// undoes transformation to feasibility problem
2848 template <class R>
2849 void SoPlexBase<R>::_untransformFeasibility(SolRational& sol, bool infeasible)
2850 {
2851 // start timing
2852 _statistics->transformTime->start();
2853
2854 // print LP if in debug mode
2855 MSG_DEBUG(_realLP->writeFileLPBase("beforeUntransFeas.lp", 0, 0, 0));
2856
2857 int numOrigCols = numColsRational() - 1;
2858
2859 // adjust solution and basis
2860 if(infeasible)
2861 {
2862 assert(sol._isDualFeasible);
2863 assert(sol._primal[numOrigCols] < 1);
2864
2865 sol._isPrimalFeasible = false;
2866 sol._hasPrimalRay = false;
2867 sol._isDualFeasible = false;
2868 sol._hasDualFarkas = true;
2869
2870 sol._dualFarkas = sol._dual;
2871
2872 _hasBasis = false;
2873 _basisStatusCols.reSize(numOrigCols);
2874 }
2875 else if(sol._isPrimalFeasible)
2876 {
2877 assert(sol._primal[numOrigCols] >= 1);
2878
2879 sol._hasPrimalRay = false;
2880 sol._isDualFeasible = false;
2881 sol._hasDualFarkas = false;
2882
2883 if(sol._primal[numOrigCols] != 1)
2884 {
2885 sol._slacks /= sol._primal[numOrigCols];
2886
2887 for(int i = 0; i < numOrigCols; i++)
2888 sol._primal[i] /= sol._primal[numOrigCols];
2889
2890 sol._primal[numOrigCols] = 1;
2891 }
2892
2893 sol._primal.reDim(numOrigCols);
2894 sol._slacks -= _rationalLP->colVector(numOrigCols);
2895
2896 _hasBasis = (_basisStatusCols[numOrigCols] != SPxSolverBase<R>::BASIC);
2897 _basisStatusCols.reSize(numOrigCols);
2898 }
2899 else
2900 {
2901 _hasBasis = false;
2902 _basisStatusCols.reSize(numOrigCols);
2903 }
2904
2905 // restore right-hand side
2906 for(int r = numRowsRational() - 1; r >= 0; r--)
2907 {
2908 assert(rhsRational(r) >= _rationalPosInfty || lhsRational(r) <= _rationalNegInfty
2909 || _feasLhs[r] - lhsRational(r) == _feasRhs[r] - rhsRational(r));
2910
2911 if(_lowerFinite(_rowTypes[r]))
2912 {
2913 _rationalLP->changeLhs(r, _feasLhs[r]);
2914 _realLP->changeLhs(r, R(_feasLhs[r]));
2915 }
2916 else if(_realLP->lhs(r) > -realParam(SoPlexBase<R>::INFTY))
2917 _realLP->changeLhs(r, -realParam(SoPlexBase<R>::INFTY));
2918
2919 assert(_lowerFinite(_rowTypes[r]) == (lhsRational(r) > _rationalNegInfty));
2920 assert(_lowerFinite(_rowTypes[r]) == (lhsReal(r) > -realParam(SoPlexBase<R>::INFTY)));
2921
2922 if(_upperFinite(_rowTypes[r]))
2923 {
2924 _rationalLP->changeRhs(r, _feasRhs[r]);
2925 _realLP->changeRhs(r, R(_feasRhs[r]));
2926 }
2927 else if(_realLP->rhs(r) < realParam(SoPlexBase<R>::INFTY))
2928 _realLP->changeRhs(r, realParam(SoPlexBase<R>::INFTY));
2929
2930 assert(_upperFinite(_rowTypes[r]) == (rhsRational(r) < _rationalPosInfty));
2931 assert(_upperFinite(_rowTypes[r]) == (rhsReal(r) < realParam(SoPlexBase<R>::INFTY)));
2932
2933 assert(lhsReal(r) <= rhsReal(r));
2934 }
2935
2936 // unshift primal space and restore objective coefficients
2937 Rational shiftValue;
2938
2939 for(int c = numOrigCols - 1; c >= 0; c--)
2940 {
2941 bool shifted = (_lowerFinite(_colTypes[c]) && _feasLower[c] > 0) || (_upperFinite(_colTypes[c])
2942 && _feasUpper[c] < 0);
2943 assert(shifted || !_lowerFinite(_colTypes[c]) || _feasLower[c] == lowerRational(c));
2944 assert(shifted || !_upperFinite(_colTypes[c]) || _feasUpper[c] == upperRational(c));
2945 assert(upperRational(c) >= _rationalPosInfty || lowerRational(c) <= _rationalNegInfty
2946 || _feasLower[c] - lowerRational(c) == _feasUpper[c] - upperRational(c));
2947
2948 if(shifted)
2949 {
2950 if(_lowerFinite(_colTypes[c]))
2951 {
2952 shiftValue = _feasLower[c];
2953 shiftValue -= lowerRational(c);
2954 }
2955 else if(_upperFinite(_colTypes[c]))
2956 {
2957 shiftValue = _feasUpper[c];
2958 shiftValue -= upperRational(c);
2959 }
2960
2961 if(sol._isPrimalFeasible)
2962 {
2963 sol._primal[c] += shiftValue;
2964 sol._slacks.multAdd(shiftValue, _rationalLP->colVector(c));
2965 }
2966 }
2967
2968 if(_lowerFinite(_colTypes[c]))
2969 {
2970 if(shifted)
2971 _rationalLP->changeLower(c, _feasLower[c]);
2972
2973 _realLP->changeLower(c, R(_feasLower[c]));
2974 }
2975 else if(_realLP->lower(c) > -realParam(SoPlexBase<R>::INFTY))
2976 _realLP->changeLower(c, -realParam(SoPlexBase<R>::INFTY));
2977
2978 assert(_lowerFinite(_colTypes[c]) == (lowerRational(c) > -_rationalPosInfty));
2979 assert(_lowerFinite(_colTypes[c]) == (lowerReal(c) > -realParam(SoPlexBase<R>::INFTY)));
2980
2981 if(_upperFinite(_colTypes[c]))
2982 {
2983 if(shifted)
2984 _rationalLP->changeUpper(c, _feasUpper[c]);
2985
2986 _realLP->changeUpper(c, R(upperRational(c)));
2987 }
2988 else if(_realLP->upper(c) < realParam(SoPlexBase<R>::INFTY))
2989 _realLP->changeUpper(c, realParam(SoPlexBase<R>::INFTY));
2990
2991 assert(_upperFinite(_colTypes[c]) == (upperRational(c) < _rationalPosInfty));
2992 assert(_upperFinite(_colTypes[c]) == (upperReal(c) < realParam(SoPlexBase<R>::INFTY)));
2993
2994 _rationalLP->changeMaxObj(c, _feasObj[c]);
2995 _realLP->changeMaxObj(c, R(_feasObj[c]));
2996
2997 assert(lowerReal(c) <= upperReal(c));
2998 }
2999
3000 // remove last column
3001 _rationalLP->removeCol(numOrigCols);
3002 _realLP->removeCol(numOrigCols);
3003 _colTypes.reSize(numOrigCols);
3004
3005 // invalidate rational basis factorization
3006 _rationalLUSolver.clear();
3007
3008 // print LP if in debug mode
3009 MSG_DEBUG(_realLP->writeFileLPBase("afterUntransFeas.lp", 0, 0, 0));
3010
3011 // stop timing
3012 _statistics->transformTime->stop();
3013
3014 #ifndef NDEBUG
3015
3016 if(sol._isPrimalFeasible)
3017 {
3018 VectorRational activity(numRowsRational());
3019 _rationalLP->computePrimalActivity(sol._primal, activity);
3020 assert(sol._slacks == activity);
3021 }
3022
3023 #endif
3024 }
3025
3026 /** computes radius of infeasibility box implied by an approximate Farkas' proof
3027
3028 Given constraints of the form \f$ lhs <= Ax <= rhs \f$, a farkas proof y should satisfy \f$ y^T A = 0 \f$ and
3029 \f$ y_+^T lhs - y_-^T rhs > 0 \f$, where \f$ y_+, y_- \f$ denote the positive and negative parts of \f$ y \f$.
3030 If \f$ y \f$ is approximate, it may not satisfy \f$ y^T A = 0 \f$ exactly, but the proof is still valid as long
3031 as the following holds for all potentially feasible \f$ x \f$:
3032
3033 \f[
3034 y^T Ax < (y_+^T lhs - y_-^T rhs) (*)
3035 \f]
3036
3037 we may therefore calculate \f$ y^T A \f$ and \f$ y_+^T lhs - y_-^T rhs \f$ exactly and check if the upper and lower
3038 bounds on \f$ x \f$ imply that all feasible \f$ x \f$ satisfy (*), and if not then compute bounds on \f$ x \f$ to
3039 guarantee (*). The simplest way to do this is to compute
3040
3041 \f[
3042 B = (y_+^T lhs - y_-^T rhs) / \sum_i(|(y^T A)_i|)
3043 \f]
3044
3045 noting that if every component of \f$ x \f$ has \f$ |x_i| < B \f$, then (*) holds.
3046
3047 \f$ B \f$ can be increased by iteratively including variable bounds smaller than \f$ B \f$. The speed of this
3048 method can be further improved by using interval arithmetic for all computations. For related information see
3049 Sec. 4 of Neumaier and Shcherbina, Mathematical Programming A, 2004.
3050
3051 Set transformed to true if this method is called after _transformFeasibility().
3052 */
3053 template <class R>
3054 void SoPlexBase<R>::_computeInfeasBox(SolRational& sol, bool transformed)
3055 {
3056 assert(sol.hasDualFarkas());
3057
3058 const VectorRational& lower = transformed ? _feasLower : lowerRational();
3059 const VectorRational& upper = transformed ? _feasUpper : upperRational();
3060 const VectorRational& lhs = transformed ? _feasLhs : lhsRational();
3061 const VectorRational& rhs = transformed ? _feasRhs : rhsRational();
3062 const VectorRational& y = sol._dualFarkas;
3063
3064 const int numRows = numRowsRational();
3065 const int numCols = transformed ? numColsRational() - 1 : numColsRational();
3066
3067 SSVectorRational ytransA(numColsRational());
3068 Rational ytransb;
3069 Rational temp;
3070
3071 // prepare ytransA and ytransb; since we want exact arithmetic, we set the zero threshold of the semi-sparse
3072 // vector to zero
3073 ytransA.setEpsilon(0);
3074 ytransA.clear();
3075 ytransb = 0;
3076
3077 ///@todo this currently works only if all constraints are equations aggregate rows and sides using the multipliers of the Farkas ray
3078 for(int r = 0; r < numRows; r++)
3079 {
3080 ytransA += y[r] * _rationalLP->rowVector(r);
3081 ytransb += y[r] * (y[r] > 0 ? lhs[r] : rhs[r]);
3082 }
3083
3084 // if we work on the feasibility problem, we ignore the last column
3085 if(transformed)
3086 ytransA.reDim(numCols);
3087
3088 MSG_DEBUG(std::cout << "ytransb = " << ytransb.str() << "\n");
3089
3090 // if we choose minus ytransb as vector of multipliers for the bound constraints on the variables, we obtain an
3091 // exactly feasible dual solution for the LP with zero objective function; we aggregate the bounds of the
3092 // variables accordingly and store its negation in temp
3093 temp = 0;
3094 bool isTempFinite = true;
3095
3096 for(int c = 0; c < numCols && isTempFinite; c++)
3097 {
3098 const Rational& minusRedCost = ytransA[c];
3099
3100 if(minusRedCost > 0)
3101 {
3102 assert((upper[c] < _rationalPosInfty) == _upperFinite(_colTypes[c]));
3103
3104 if(_upperFinite(_colTypes[c]))
3105 temp += minusRedCost * upper[c];
3106 else
3107 isTempFinite = false;
3108 }
3109 else if(minusRedCost < 0)
3110 {
3111 assert((lower[c] > _rationalNegInfty) == _lowerFinite(_colTypes[c]));
3112
3113 if(_lowerFinite(_colTypes[c]))
3114 temp += minusRedCost * lower[c];
3115 else
3116 isTempFinite = false;
3117 }
3118 }
3119
3120 MSG_DEBUG(std::cout << "max ytransA*[x_l,x_u] = " << (isTempFinite ? temp.str() : "infinite") <<
3121 "\n");
3122
3123 // ytransb - temp is the increase in the dual objective along the Farkas ray; if this is positive, the dual is
3124 // unbounded and certifies primal infeasibility
3125 if(isTempFinite && temp < ytransb)
3126 {
3127 MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (1)\n");
3128 return;
3129 }
3130
3131 // ensure that array of nonzero elements in ytransA is available
3132 assert(ytransA.isSetup());
3133 ytransA.setup();
3134
3135 // if ytransb is negative, try to make it zero by including a positive lower bound or a negative upper bound
3136 if(ytransb < 0)
3137 {
3138 for(int c = 0; c < numCols; c++)
3139 {
3140 if(lower[c] > 0)
3141 {
3142 ytransA.setValue(c, ytransA[c] - ytransb / lower[c]);
3143 ytransb = 0;
3144 break;
3145 }
3146 else if(upper[c] < 0)
3147 {
3148 ytransA.setValue(c, ytransA[c] - ytransb / upper[c]);
3149 ytransb = 0;
3150 break;
3151 }
3152 }
3153 }
3154
3155 // if ytransb is still zero then the zero solution is inside the bounds and cannot be cut off by the Farkas
3156 // constraint; in this case, we cannot compute a Farkas box
3157 if(ytransb < 0)
3158 {
3159 MSG_INFO1(spxout, spxout <<
3160 "Approximate Farkas proof to weak. Could not compute Farkas box. (1)\n");
3161 return;
3162 }
3163
3164 // compute the one norm of ytransA
3165 temp = 0;
3166 const int size = ytransA.size();
3167
3168 for(int n = 0; n < size; n++)
3169 temp += spxAbs(ytransA.value(n));
3170
3171 // if the one norm is zero then ytransA is zero the Farkas proof should have been verified above
3172 assert(temp != 0);
3173
3174 // initialize variables in loop: size of Farkas box B, flag whether B has been increased, and number of current
3175 // nonzero in ytransA
3176 Rational B = ytransb / temp;
3177 bool success = false;
3178 int n = 0;
3179
3180 // loop through nonzeros of ytransA
3181 MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
3182 assert(ytransb >= 0);
3183
3184 while(true)
3185 {
3186 // if all nonzeros have been inspected once without increasing B, we abort; otherwise, we start another round
3187 if(n >= ytransA.size())
3188 {
3189 if(!success)
3190 break;
3191
3192 success = false;
3193 n = 0;
3194 }
3195
3196 // get Farkas multiplier of the bound constraint as minus the value in ytransA
3197 const Rational& minusRedCost = ytransA.value(n);
3198 int colIdx = ytransA.index(n);
3199
3200 // if the multiplier is positive we inspect the lower bound: if it is finite and within the Farkas box, we can
3201 // increase B by including it in the Farkas proof
3202 assert((upper[colIdx] < _rationalPosInfty) == _upperFinite(_colTypes[colIdx]));
3203 assert((lower[colIdx] > _rationalNegInfty) == _lowerFinite(_colTypes[colIdx]));
3204
3205 if(minusRedCost < 0 && lower[colIdx] > -B && _lowerFinite(_colTypes[colIdx]))
3206 {
3207 ytransA.clearNum(n);
3208 ytransb -= minusRedCost * lower[colIdx];
3209 temp += minusRedCost;
3210
3211 assert(ytransb >= 0);
3212 assert(temp >= 0);
3213 assert(temp == 0 || ytransb / temp > B);
3214
3215 // if ytransA and ytransb are zero, we have 0^T x >= 0 and cannot compute a Farkas box
3216 if(temp == 0 && ytransb == 0)
3217 {
3218 MSG_INFO1(spxout, spxout <<
3219 "Approximate Farkas proof to weak. Could not compute Farkas box. (2)\n");
3220 return;
3221 }
3222 // if ytransb is positive and ytransA is zero, we have 0^T x > 0, proving infeasibility
3223 else if(temp == 0)
3224 {
3225 assert(ytransb > 0);
3226 MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (2)\n");
3227 return;
3228 }
3229 else
3230 {
3231 B = ytransb / temp;
3232 MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
3233 }
3234
3235 success = true;
3236 }
3237 // if the multiplier is negative we inspect the upper bound: if it is finite and within the Farkas box, we can
3238 // increase B by including it in the Farkas proof
3239 else if(minusRedCost > 0 && upper[colIdx] < B && _upperFinite(_colTypes[colIdx]))
3240 {
3241 ytransA.clearNum(n);
3242 ytransb -= minusRedCost * upper[colIdx];
3243 temp -= minusRedCost;
3244
3245 assert(ytransb >= 0);
3246 assert(temp >= 0);
3247 assert(temp == 0 || ytransb / temp > B);
3248
3249 // if ytransA and ytransb are zero, we have 0^T x >= 0 and cannot compute a Farkas box
3250 if(temp == 0 && ytransb == 0)
3251 {
3252 MSG_INFO1(spxout, spxout <<
3253 "Approximate Farkas proof to weak. Could not compute Farkas box. (2)\n");
3254 return;
3255 }
3256 // if ytransb is positive and ytransA is zero, we have 0^T x > 0, proving infeasibility
3257 else if(temp == 0)
3258 {
3259 assert(ytransb > 0);
3260 MSG_INFO1(spxout, spxout << "Farkas infeasibility proof verified exactly. (2)\n");
3261 return;
3262 }
3263 else
3264 {
3265 B = ytransb / temp;
3266 MSG_DEBUG(std::cout << "B = " << B.str() << "\n");
3267 }
3268
3269 success = true;
3270 }
3271 // the multiplier is zero, we can ignore the bound constraints on this variable
3272 else if(minusRedCost == 0)
3273 ytransA.clearNum(n);
3274 // currently this bound cannot be used to increase B; we will check it again in the next round, because B might
3275 // have increased by then
3276 else
3277 n++;
3278 }
3279
3280 if(B > 0)
3281 {
3282 MSG_INFO1(spxout, spxout <<
3283 "Computed Farkas box: provably no feasible solutions with components less than "
3284 << B.str() << " in absolute value.\n");
3285 }
3286 }
3287
3288
3289
3290
3291 // General specializations
3292 /// solves real LP during iterative refinement
3293 template <class R>
3294 typename SPxSolverBase<R>::Status SoPlexBase<R>::_solveRealForRational(bool fromscratch,
3295 VectorBase<R>& primal, VectorBase<R>& dual,
3296 DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
3297 DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols)
3298 {
3299 assert(_isConsistent());
3300
3301 assert(_solver.nRows() == numRowsRational());
3302 assert(_solver.nCols() == numColsRational());
3303 assert(primal.dim() == numColsRational());
3304 assert(dual.dim() == numRowsRational());
3305
3306 typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
3307
3308 #ifndef SOPLEX_MANUAL_ALT
3309
3310 if(fromscratch || !_hasBasis)
3311 _enableSimplifierAndScaler();
3312 else
3313 _disableSimplifierAndScaler();
3314
3315 #else
3316 _disableSimplifierAndScaler();
3317 #endif
3318
3319 // reset basis to slack basis when solving from scratch
3320 if(fromscratch)
3321 _solver.reLoad();
3322
3323 // start timing
3324 _statistics->syncTime->start();
3325
3326 // if preprocessing is applied, we need to restore the original LP at the end
3327 SPxLPRational* rationalLP = 0;
3328
3329 if(_simplifier != 0 || _scaler != nullptr)
3330 {
3331 spx_alloc(rationalLP);
3332 rationalLP = new(rationalLP) SPxLPRational(_solver);
3333 }
3334
3335 // with preprocessing or solving from scratch, the basis may change, hence invalidate the
3336 // rational basis factorization
3337 if(_simplifier != nullptr || _scaler != nullptr || fromscratch)
3338 _rationalLUSolver.clear();
3339
3340 // stop timing
3341 _statistics->syncTime->stop();
3342
3343 try
3344 {
3345 // apply problem simplification
3346 typename SPxSimplifier<R>::Result simplificationStatus = SPxSimplifier<R>::OKAY;
3347
3348 if(_simplifier != 0)
3349 {
3350 // do not remove bounds of boxed variables or sides of ranged rows if bound flipping is used
3351 bool keepbounds = intParam(SoPlexBase<R>::RATIOTESTER) == SoPlexBase<R>::RATIOTESTER_BOUNDFLIPPING;
3352 Real remainingTime = _solver.getMaxTime() - _solver.time();
3353 simplificationStatus = _simplifier->simplify(_solver, realParam(SoPlexBase<R>::EPSILON_ZERO),
3354 realParam(SoPlexBase<R>::FPFEASTOL), realParam(SoPlexBase<R>::FPOPTTOL), remainingTime, keepbounds,
3355 _solver.random.getSeed());
3356 }
3357
3358 // apply scaling after the simplification
3359 if(_scaler != nullptr && simplificationStatus == SPxSimplifier<R>::OKAY)
3360 _scaler->scale(_solver, false);
3361
3362 // run the simplex method if problem has not been solved by the simplifier
3363 if(simplificationStatus == SPxSimplifier<R>::OKAY)
3364 {
3365 MSG_INFO1(spxout, spxout << std::endl);
3366
3367 _solveRealLPAndRecordStatistics();
3368
3369 MSG_INFO1(spxout, spxout << std::endl);
3370 }
3371
3372 ///@todo move to private helper methods
3373 // evaluate status flag
3374 if(simplificationStatus == SPxSimplifier<R>::INFEASIBLE)
3375 result = SPxSolverBase<R>::INFEASIBLE;
3376 else if(simplificationStatus == SPxSimplifier<R>::DUAL_INFEASIBLE)
3377 result = SPxSolverBase<R>::INForUNBD;
3378 else if(simplificationStatus == SPxSimplifier<R>::UNBOUNDED)
3379 result = SPxSolverBase<R>::UNBOUNDED;
3380 else if(simplificationStatus == SPxSimplifier<R>::VANISHED
3381 || simplificationStatus == SPxSimplifier<R>::OKAY)
3382 {
3383 result = simplificationStatus == SPxSimplifier<R>::VANISHED ? SPxSolverBase<R>::OPTIMAL :
3384 _solver.status();
3385
3386 ///@todo move to private helper methods
3387 // process result
3388 switch(result)
3389 {
3390 case SPxSolverBase<R>::OPTIMAL:
3391
3392 // unsimplify if simplifier is active and LP is solved to optimality; this must be done here and not at solution
3393 // query, because we want to have the basis for the original problem
3394 if(_simplifier != 0)
3395 {
3396 assert(!_simplifier->isUnsimplified());
3397 assert(simplificationStatus == SPxSimplifier<R>::VANISHED
3398 || simplificationStatus == SPxSimplifier<R>::OKAY);
3399
3400 bool vanished = simplificationStatus == SPxSimplifier<R>::VANISHED;
3401
3402 // get solution vectors for transformed problem
3403 VectorBase<R> tmpPrimal(vanished ? 0 : _solver.nCols());
3404 VectorBase<R> tmpSlacks(vanished ? 0 : _solver.nRows());
3405 VectorBase<R> tmpDual(vanished ? 0 : _solver.nRows());
3406 VectorBase<R> tmpRedCost(vanished ? 0 : _solver.nCols());
3407
3408 if(!vanished)
3409 {
3410 assert(_solver.status() == SPxSolverBase<R>::OPTIMAL);
3411
3412 _solver.getPrimalSol(tmpPrimal);
3413 _solver.getSlacks(tmpSlacks);
3414 _solver.getDualSol(tmpDual);
3415 _solver.getRedCostSol(tmpRedCost);
3416
3417 // unscale vectors
3418 if(_scaler != nullptr)
3419 {
3420 _scaler->unscalePrimal(_solver, tmpPrimal);
3421 _scaler->unscaleSlacks(_solver, tmpSlacks);
3422 _scaler->unscaleDual(_solver, tmpDual);
3423 _scaler->unscaleRedCost(_solver, tmpRedCost);
3424 }
3425
3426 // get basis of transformed problem
3427 basisStatusRows.reSize(_solver.nRows());
3428 basisStatusCols.reSize(_solver.nCols());
3429 _solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3430 basisStatusCols.size());
3431 }
3432
3433 ///@todo catch exception
3434 _simplifier->unsimplify(tmpPrimal, tmpDual, tmpSlacks, tmpRedCost, basisStatusRows.get_ptr(),
3435 basisStatusCols.get_ptr());
3436
3437 // store basis for original problem
3438 basisStatusRows.reSize(numRowsRational());
3439 basisStatusCols.reSize(numColsRational());
3440 _simplifier->getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3441 basisStatusCols.size());
3442 _hasBasis = true;
3443
3444 primal = _simplifier->unsimplifiedPrimal();
3445 dual = _simplifier->unsimplifiedDual();
3446 }
3447 else
3448 {
3449 _solver.getPrimalSol(primal);
3450 _solver.getDualSol(dual);
3451
3452 // unscale vectors
3453 if(_scaler != nullptr)
3454 {
3455 _scaler->unscalePrimal(_solver, primal);
3456 _scaler->unscaleDual(_solver, dual);
3457 }
3458
3459 // get basis of transformed problem
3460 basisStatusRows.reSize(_solver.nRows());
3461 basisStatusCols.reSize(_solver.nCols());
3462 _solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3463 basisStatusCols.size());
3464 _hasBasis = true;
3465 }
3466
3467 break;
3468
3469 case SPxSolverBase<R>::ABORT_CYCLING:
3470 if(_simplifier == 0 && boolParam(SoPlexBase<R>::ACCEPTCYCLING))
3471 {
3472 _solver.getPrimalSol(primal);
3473 _solver.getDualSol(dual);
3474
3475 // unscale vectors
3476 if(_scaler != nullptr)
3477 {
3478 _scaler->unscalePrimal(_solver, primal);
3479 _scaler->unscaleDual(_solver, dual);
3480 }
3481 }
3482
3483 // intentional fallthrough
3484 case SPxSolverBase<R>::ABORT_TIME:
3485 case SPxSolverBase<R>::ABORT_ITER:
3486 case SPxSolverBase<R>::ABORT_VALUE:
3487 case SPxSolverBase<R>::REGULAR:
3488 case SPxSolverBase<R>::RUNNING:
3489 case SPxSolverBase<R>::UNBOUNDED:
3490 _hasBasis = (_solver.basis().status() > SPxBasisBase<R>::NO_PROBLEM);
3491
3492 if(_hasBasis && _simplifier == 0)
3493 {
3494 basisStatusRows.reSize(_solver.nRows());
3495 basisStatusCols.reSize(_solver.nCols());
3496 _solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3497 basisStatusCols.size());
3498 }
3499 else
3500 {
3501 _hasBasis = false;
3502 _rationalLUSolver.clear();
3503 }
3504
3505 break;
3506
3507 case SPxSolverBase<R>::INFEASIBLE:
3508
3509 // if simplifier is active we can currently not return a Farkas ray or basis
3510 if(_simplifier != 0)
3511 {
3512 _hasBasis = false;
3513 _rationalLUSolver.clear();
3514 break;
3515 }
3516
3517 // return Farkas ray as dual solution
3518 _solver.getDualfarkas(dual);
3519
3520 // unscale vectors
3521 if(_scaler != nullptr)
3522 _scaler->unscaleDual(_solver, dual);
3523
3524 // get basis of transformed problem
3525 basisStatusRows.reSize(_solver.nRows());
3526 basisStatusCols.reSize(_solver.nCols());
3527 _solver.getBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr(), basisStatusRows.size(),
3528 basisStatusCols.size());
3529 _hasBasis = true;
3530 break;
3531
3532 case SPxSolverBase<R>::INForUNBD:
3533 case SPxSolverBase<R>::SINGULAR:
3534 default:
3535 _hasBasis = false;
3536 _rationalLUSolver.clear();
3537 break;
3538 }
3539 }
3540 }
3541 catch(...)
3542 {
3543 MSG_INFO1(spxout, spxout << "Exception thrown during floating-point solve.\n");
3544 result = SPxSolverBase<R>::ERROR;
3545 _hasBasis = false;
3546 _rationalLUSolver.clear();
3547
3548 }
3549
3550 // restore original LP if necessary
3551 if(_simplifier != 0 || _scaler != nullptr)
3552 {
3553 assert(rationalLP != 0);
3554 _solver.loadLP((SPxLPBase<R>)(*rationalLP));
3555 rationalLP->~SPxLPRational();
3556 spx_free(rationalLP);
3557
3558 if(_hasBasis)
3559 _solver.setBasis(basisStatusRows.get_ptr(), basisStatusCols.get_ptr());
3560 }
3561
3562 return result;
3563 }
3564
3565 /// solves real LP with recovery mechanism
3566 template <class R>
3567 typename SPxSolverBase<R>::Status SoPlexBase<R>::_solveRealStable(bool acceptUnbounded,
3568 bool acceptInfeasible, VectorBase<R>& primal, VectorBase<R>& dual,
3569 DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
3570 DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols,
3571 const bool forceNoSimplifier)
3572 {
3573 typename SPxSolverBase<R>::Status result = SPxSolverBase<R>::UNKNOWN;
3574
3575 bool fromScratch = false;
3576 bool solved = false;
3577 bool solvedFromScratch = false;
3578 bool initialSolve = true;
3579 bool increasedMarkowitz = false;
3580 bool relaxedTolerances = false;
3581 bool tightenedTolerances = false;
3582 bool switchedScaler = false;
3583 bool switchedSimplifier = false;
3584 bool switchedRatiotester = false;
3585 bool switchedPricer = false;
3586 bool turnedoffPre = false;
3587
3588 R markowitz = _slufactor.markowitz();
3589 int ratiotester = intParam(SoPlexBase<R>::RATIOTESTER);
3590 int pricer = intParam(SoPlexBase<R>::PRICER);
3591 int simplifier = intParam(SoPlexBase<R>::SIMPLIFIER);
3592 int scaler = intParam(SoPlexBase<R>::SCALER);
3593 int type = intParam(SoPlexBase<R>::ALGORITHM);
3594
3595 if(forceNoSimplifier)
3596 setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
3597
3598 while(true)
3599 {
3600 assert(!increasedMarkowitz || GE(_slufactor.markowitz(), R(0.9)));
3601
3602 result = _solveRealForRational(fromScratch, primal, dual, basisStatusRows, basisStatusCols);
3603
3604 solved = (result == SPxSolverBase<R>::OPTIMAL)
3605 || (result == SPxSolverBase<R>::INFEASIBLE && acceptInfeasible)
3606 || (result == SPxSolverBase<R>::UNBOUNDED && acceptUnbounded);
3607
3608 if(solved || result == SPxSolverBase<R>::ABORT_TIME || result == SPxSolverBase<R>::ABORT_ITER)
3609 break;
3610
3611 if(initialSolve)
3612 {
3613 MSG_INFO1(spxout, spxout << "Numerical troubles during floating-point solve." << std::endl);
3614 initialSolve = false;
3615 }
3616
3617 if(!turnedoffPre
3618 && (intParam(SoPlexBase<R>::SIMPLIFIER) != SoPlexBase<R>::SIMPLIFIER_OFF
3619 || intParam(SoPlexBase<R>::SCALER) != SoPlexBase<R>::SCALER_OFF))
3620 {
3621 MSG_INFO1(spxout, spxout << "Turning off preprocessing." << std::endl);
3622
3623 turnedoffPre = true;
3624
3625 setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_OFF);
3626 setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
3627
3628 fromScratch = true;
3629 solvedFromScratch = true;
3630 continue;
3631 }
3632
3633 setIntParam(SoPlexBase<R>::SCALER, scaler);
3634 setIntParam(SoPlexBase<R>::SIMPLIFIER, simplifier);
3635
3636 if(!increasedMarkowitz)
3637 {
3638 MSG_INFO1(spxout, spxout << "Increasing Markowitz threshold." << std::endl);
3639
3640 _slufactor.setMarkowitz(0.9);
3641 increasedMarkowitz = true;
3642
3643 try
3644 {
3645 _solver.factorize();
3646 continue;
3647 }
3648 catch(...)
3649 {
3650 MSG_DEBUG(std::cout << std::endl << "Factorization failed." << std::endl);
3651 }
3652 }
3653
3654 if(!solvedFromScratch)
3655 {
3656 MSG_INFO1(spxout, spxout << "Solving from scratch." << std::endl);
3657
3658 fromScratch = true;
3659 solvedFromScratch = true;
3660 continue;
3661 }
3662
3663 setIntParam(SoPlexBase<R>::RATIOTESTER, ratiotester);
3664 setIntParam(SoPlexBase<R>::PRICER, pricer);
3665
3666 if(!switchedScaler)
3667 {
3668 MSG_INFO1(spxout, spxout << "Switching scaling." << std::endl);
3669
3670 if(scaler == int(SoPlexBase<R>::SCALER_OFF))
3671 setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_BIEQUI);
3672 else
3673 setIntParam(SoPlexBase<R>::SCALER, SoPlexBase<R>::SCALER_OFF);
3674
3675 fromScratch = true;
3676 solvedFromScratch = true;
3677 switchedScaler = true;
3678 continue;
3679 }
3680
3681 if(!switchedSimplifier && !forceNoSimplifier)
3682 {
3683 MSG_INFO1(spxout, spxout << "Switching simplification." << std::endl);
3684
3685 if(simplifier == int(SoPlexBase<R>::SIMPLIFIER_OFF))
3686 setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_INTERNAL);
3687 else
3688 setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
3689
3690 fromScratch = true;
3691 solvedFromScratch = true;
3692 switchedSimplifier = true;
3693 continue;
3694 }
3695
3696 setIntParam(SoPlexBase<R>::SIMPLIFIER, SoPlexBase<R>::SIMPLIFIER_OFF);
3697
3698 if(!relaxedTolerances)
3699 {
3700 MSG_INFO1(spxout, spxout << "Relaxing tolerances." << std::endl);
3701
3702 setIntParam(SoPlexBase<R>::ALGORITHM, SoPlexBase<R>::ALGORITHM_PRIMAL);
3703 _solver.setDelta((_solver.feastol() * 1e3 > 1e-3) ? 1e-3 : (_solver.feastol() * 1e3));
3704 relaxedTolerances = _solver.feastol() >= 1e-3;
3705 solvedFromScratch = false;
3706 continue;
3707 }
3708
3709 if(!tightenedTolerances && result != SPxSolverBase<R>::INFEASIBLE)
3710 {
3711 MSG_INFO1(spxout, spxout << "Tightening tolerances." << std::endl);
3712
3713 setIntParam(SoPlexBase<R>::ALGORITHM, SoPlexBase<R>::ALGORITHM_DUAL);
3714 _solver.setDelta(_solver.feastol() * 1e-3 < 1e-9 ? 1e-9 : _solver.feastol() * 1e-3);
3715 tightenedTolerances = _solver.feastol() <= 1e-9;
3716 solvedFromScratch = false;
3717 continue;
3718 }
3719
3720 setIntParam(SoPlexBase<R>::ALGORITHM, type);
3721
3722 if(!switchedRatiotester)
3723 {
3724 MSG_INFO1(spxout, spxout << "Switching ratio test." << std::endl);
3725
3726 _solver.setType(_solver.type() == SPxSolverBase<R>::LEAVE ? SPxSolverBase<R>::ENTER :
3727 SPxSolverBase<R>::LEAVE);
3728
3729 if(_solver.ratiotester() != (SPxRatioTester<R>*)&_ratiotesterTextbook)
3730 setIntParam(SoPlexBase<R>::RATIOTESTER, RATIOTESTER_TEXTBOOK);
3731 else
3732 setIntParam(SoPlexBase<R>::RATIOTESTER, RATIOTESTER_FAST);
3733
3734 switchedRatiotester = true;
3735 solvedFromScratch = false;
3736 continue;
3737 }
3738
3739 if(!switchedPricer)
3740 {
3741 MSG_INFO1(spxout, spxout << "Switching pricer." << std::endl);
3742
3743 _solver.setType(_solver.type() == SPxSolverBase<R>::LEAVE ? SPxSolverBase<R>::ENTER :
3744 SPxSolverBase<R>::LEAVE);
3745
3746 if(_solver.pricer() != (SPxPricer<R>*)&_pricerDevex)
3747 setIntParam(SoPlexBase<R>::PRICER, PRICER_DEVEX);
3748 else
3749 setIntParam(SoPlexBase<R>::PRICER, PRICER_STEEP);
3750
3751 switchedPricer = true;
3752 solvedFromScratch = false;
3753 continue;
3754 }
3755
3756 MSG_INFO1(spxout, spxout << "Giving up." << std::endl);
3757
3758 break;
3759 }
3760
3761 _solver.setFeastol(realParam(SoPlexBase<R>::FPFEASTOL));
3762 _solver.setOpttol(realParam(SoPlexBase<R>::FPOPTTOL));
3763 _slufactor.setMarkowitz(markowitz);
3764
3765 setIntParam(SoPlexBase<R>::RATIOTESTER, ratiotester);
3766 setIntParam(SoPlexBase<R>::PRICER, pricer);
3767 setIntParam(SoPlexBase<R>::SIMPLIFIER, simplifier);
3768 setIntParam(SoPlexBase<R>::SCALER, scaler);
3769 setIntParam(SoPlexBase<R>::ALGORITHM, type);
3770
3771 return result;
3772 }
3773
3774 /// computes rational inverse of basis matrix as defined by _rationalLUSolverBind
3775 template <class R>
3776 void SoPlexBase<R>::_computeBasisInverseRational()
3777 {
3778 assert(_rationalLUSolver.status() == SLinSolverRational::UNLOADED
3779 || _rationalLUSolver.status() == SLinSolverRational::TIME);
3780
3781 const int matrixdim = numRowsRational();
3782 assert(_rationalLUSolverBind.size() == matrixdim);
3783
3784 Array< const SVectorRational* > matrix(matrixdim);
3785 _rationalLUSolverBind.reSize(matrixdim);
3786
3787 for(int i = 0; i < matrixdim; i++)
3788 {
3789 if(_rationalLUSolverBind[i] >= 0)
3790 {
3791 assert(_rationalLUSolverBind[i] < numColsRational());
3792 matrix[i] = &colVectorRational(_rationalLUSolverBind[i]);
3793 }
3794 else
3795 {
3796 assert(-1 - _rationalLUSolverBind[i] >= 0);
3797 assert(-1 - _rationalLUSolverBind[i] < numRowsRational());
3798 matrix[i] = _unitVectorRational(-1 - _rationalLUSolverBind[i]);
3799 }
3800 }
3801
3802 // load and factorize rational basis matrix
3803 if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
3804 _rationalLUSolver.setTimeLimit((double)realParam(SoPlexBase<R>::TIMELIMIT) -
3805 _statistics->solvingTime->time());
3806 else
3807 _rationalLUSolver.setTimeLimit(-1.0);
3808
3809 _rationalLUSolver.load(matrix.get_ptr(), matrixdim);
3810
3811 // record statistics
3812 _statistics->luFactorizationTimeRational += _rationalLUSolver.getFactorTime();
3813 _statistics->luFactorizationsRational += _rationalLUSolver.getFactorCount();
3814 _rationalLUSolver.resetCounters();
3815
3816 if(_rationalLUSolver.status() == SLinSolverRational::TIME)
3817 {
3818 MSG_INFO2(spxout, spxout << "Rational factorization hit time limit.\n");
3819 }
3820 else if(_rationalLUSolver.status() != SLinSolverRational::OK)
3821 {
3822 MSG_INFO1(spxout, spxout << "Error performing rational LU factorization.\n");
3823 }
3824
3825 return;
3826 }
3827
3828
3829
3830 /// factorizes rational basis matrix in column representation
3831 template <class R>
3832 void SoPlexBase<R>::_factorizeColumnRational(SolRational& sol,
3833 DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
3834 DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols, bool& stoppedTime,
3835 bool& stoppedIter, bool& error, bool& optimal)
3836 {
3837 // start rational solving time
3838 _statistics->rationalTime->start();
3839
3840 stoppedTime = false;
3841 stoppedIter = false;
3842 error = false;
3843 optimal = false;
3844
3845 const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
3846 const int matrixdim = numRowsRational();
3847 bool loadMatrix = (_rationalLUSolver.status() == SLinSolverRational::UNLOADED
3848 || _rationalLUSolver.status() == SLinSolverRational::TIME);
3849 int numBasicRows;
3850
3851 assert(loadMatrix || matrixdim == _rationalLUSolver.dim());
3852 assert(loadMatrix || matrixdim == _rationalLUSolverBind.size());
3853
3854 if(!loadMatrix && (matrixdim != _rationalLUSolver.dim()
3855 || matrixdim != _rationalLUSolverBind.size()))
3856 {
3857 MSG_WARNING(spxout, spxout <<
3858 "Warning: dimensioning error in rational matrix factorization (recovered).\n");
3859 loadMatrix = true;
3860 }
3861
3862 _workSol._primal.reDim(matrixdim);
3863 _workSol._slacks.reDim(matrixdim);
3864 _workSol._dual.reDim(matrixdim);
3865 _workSol._redCost.reDim(numColsRational() > matrixdim ? numColsRational() : matrixdim);
3866
3867 if(loadMatrix)
3868 _rationalLUSolverBind.reSize(matrixdim);
3869
3870 VectorRational& basicPrimalRhs = _workSol._slacks;
3871 VectorRational& basicDualRhs = _workSol._redCost;
3872 VectorRational& basicPrimal = _workSol._primal;
3873 VectorRational& basicDual = _workSol._dual;
3874
3875 Rational violation;
3876 Rational primalViolation;
3877 Rational dualViolation;
3878 bool primalFeasible = false;
3879 bool dualFeasible = false;
3880
3881 assert(basisStatusCols.size() == numColsRational());
3882 assert(basisStatusRows.size() == numRowsRational());
3883
3884 int j = 0;
3885
3886 for(int i = 0; i < basisStatusRows.size(); i++)
3887 {
3888 if(basisStatusRows[i] == SPxSolverBase<R>::BASIC && j < matrixdim)
3889 {
3890 basicPrimalRhs[i] = 0;
3891 basicDualRhs[j] = 0;
3892
3893 if(loadMatrix)
3894 _rationalLUSolverBind[j] = -1 - i;
3895
3896 j++;
3897 }
3898 else if(basisStatusRows[i] == SPxSolverBase<R>::ON_LOWER)
3899 basicPrimalRhs[i] = lhsRational(i);
3900 else if(basisStatusRows[i] == SPxSolverBase<R>::ON_UPPER)
3901 basicPrimalRhs[i] = rhsRational(i);
3902 else if(basisStatusRows[i] == SPxSolverBase<R>::ZERO)
3903 basicPrimalRhs[i] = 0;
3904 else if(basisStatusRows[i] == SPxSolverBase<R>::FIXED)
3905 {
3906 assert(lhsRational(i) == rhsRational(i));
3907 basicPrimalRhs[i] = lhsRational(i);
3908 }
3909 else if(basisStatusRows[i] == SPxSolverBase<R>::UNDEFINED)
3910 {
3911 MSG_INFO1(spxout, spxout << "Undefined basis status of row in rational factorization.\n");
3912 error = true;
3913 goto TERMINATE;
3914 }
3915 else
3916 {
3917 assert(basisStatusRows[i] == SPxSolverBase<R>::BASIC);
3918 MSG_INFO1(spxout, spxout << "Too many basic rows in rational factorization.\n");
3919 error = true;
3920 goto TERMINATE;
3921 }
3922 }
3923
3924 numBasicRows = j;
3925
3926 for(int i = 0; i < basisStatusCols.size(); i++)
3927 {
3928 if(basisStatusCols[i] == SPxSolverBase<R>::BASIC && j < matrixdim)
3929 {
3930 basicDualRhs[j] = objRational(i);
3931
3932 if(loadMatrix)
3933 _rationalLUSolverBind[j] = i;
3934
3935 j++;
3936 }
3937 else if(basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER)
3938 basicPrimalRhs.multAdd(-lowerRational(i), colVectorRational(i));
3939 else if(basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER)
3940 basicPrimalRhs.multAdd(-upperRational(i), colVectorRational(i));
3941 else if(basisStatusCols[i] == SPxSolverBase<R>::ZERO)
3942 {}
3943 else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
3944 {
3945 assert(lowerRational(i) == upperRational(i));
3946 basicPrimalRhs.multAdd(-lowerRational(i), colVectorRational(i));
3947 }
3948 else if(basisStatusCols[i] == SPxSolverBase<R>::UNDEFINED)
3949 {
3950 MSG_INFO1(spxout, spxout << "Undefined basis status of column in rational factorization.\n");
3951 error = true;
3952 goto TERMINATE;
3953 }
3954 else
3955 {
3956 assert(basisStatusCols[i] == SPxSolverBase<R>::BASIC);
3957 MSG_INFO1(spxout, spxout << "Too many basic columns in rational factorization.\n");
3958 error = true;
3959 goto TERMINATE;
3960 }
3961 }
3962
3963 if(j != matrixdim)
3964 {
3965 MSG_INFO1(spxout, spxout << "Too few basic entries in rational factorization.\n");
3966 error = true;
3967 goto TERMINATE;
3968 }
3969
3970 // load and factorize rational basis matrix
3971 if(loadMatrix)
3972 _computeBasisInverseRational();
3973
3974 if(_rationalLUSolver.status() == SLinSolverRational::TIME)
3975 {
3976 stoppedTime = true;
3977 return;
3978 }
3979 else if(_rationalLUSolver.status() != SLinSolverRational::OK)
3980 {
3981 error = true;
3982 return;
3983 }
3984
3985 assert(_rationalLUSolver.status() == SLinSolverRational::OK);
3986
3987 // solve for primal solution
3988 if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
3989 _rationalLUSolver.setTimeLimit(Real(realParam(SoPlexBase<R>::TIMELIMIT)) -
3990 _statistics->solvingTime->time());
3991 else
3992 _rationalLUSolver.setTimeLimit(-1.0);
3993
3994 _rationalLUSolver.solveRight(basicPrimal, basicPrimalRhs);
3995
3996 // record statistics
3997 _statistics->luSolveTimeRational += _rationalLUSolver.getSolveTime();
3998 _rationalLUSolver.resetCounters();
3999
4000 if(_isSolveStopped(stoppedTime, stoppedIter))
4001 {
4002 MSG_INFO2(spxout, spxout << "Rational factorization hit time limit while solving for primal.\n");
4003 return;
4004 }
4005
4006 // check bound violation on basic rows and columns
4007 j = 0;
4008 primalViolation = 0;
4009 primalFeasible = true;
4010
4011 for(int i = 0; i < basisStatusRows.size(); i++)
4012 {
4013 if(basisStatusRows[i] == SPxSolverBase<R>::BASIC)
4014 {
4015 assert(j < matrixdim);
4016 assert(_rationalLUSolverBind[j] == -1 - i);
4017 violation = lhsRational(i);
4018 violation += basicPrimal[j];
4019
4020 if(violation > primalViolation)
4021 {
4022 primalFeasible = false;
4023 primalViolation = violation;
4024 }
4025
4026 violation = rhsRational(i);
4027 violation += basicPrimal[j];
4028 violation *= -1;
4029
4030 if(violation > primalViolation)
4031 {
4032 primalFeasible = false;
4033 primalViolation = violation;
4034 }
4035
4036 j++;
4037 }
4038 }
4039
4040 for(int i = 0; i < basisStatusCols.size(); i++)
4041 {
4042 if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
4043 {
4044 assert(j < matrixdim);
4045 assert(_rationalLUSolverBind[j] == i);
4046
4047 if(basicPrimal[j] < lowerRational(i))
4048 {
4049 violation = lowerRational(i);
4050 violation -= basicPrimal[j];
4051
4052 if(violation > primalViolation)
4053 {
4054 primalFeasible = false;
4055 primalViolation = violation;
4056 }
4057 }
4058
4059 if(basicPrimal[j] > upperRational(i))
4060 {
4061 violation = basicPrimal[j];
4062 violation -= upperRational(i);
4063
4064 if(violation > primalViolation)
4065 {
4066 primalFeasible = false;
4067 primalViolation = violation;
4068 }
4069 }
4070
4071 j++;
4072 }
4073 }
4074
4075 if(!primalFeasible)
4076 {
4077 MSG_INFO1(spxout, spxout << "Rational solution primal infeasible.\n");
4078 }
4079
4080 // solve for dual solution
4081 if(realParam(SoPlexBase<R>::TIMELIMIT) < realParam(SoPlexBase<R>::INFTY))
4082 _rationalLUSolver.setTimeLimit(Real(realParam(SoPlexBase<R>::TIMELIMIT)) -
4083 _statistics->solvingTime->time());
4084 else
4085 _rationalLUSolver.setTimeLimit(-1.0);
4086
4087 _rationalLUSolver.solveLeft(basicDual, basicDualRhs);
4088
4089 // record statistics
4090 _statistics->luSolveTimeRational += _rationalLUSolver.getSolveTime();
4091 _rationalLUSolver.resetCounters();
4092
4093 if(_isSolveStopped(stoppedTime, stoppedIter))
4094 {
4095 MSG_INFO2(spxout, spxout << "Rational factorization hit time limit while solving for dual.\n");
4096 return;
4097 }
4098
4099 // check dual violation on nonbasic rows
4100 dualViolation = 0;
4101 dualFeasible = true;
4102
4103 for(int i = 0; i < basisStatusRows.size(); i++)
4104 {
4105 if(_rowTypes[i] == RANGETYPE_FIXED
4106 && (basisStatusRows[i] == SPxSolverBase<R>::ON_LOWER
4107 || basisStatusRows[i] == SPxSolverBase<R>::ON_UPPER))
4108 {
4109 assert(lhsRational(i) == rhsRational(i));
4110 basisStatusRows[i] = SPxSolverBase<R>::FIXED;
4111 }
4112
4113 assert(basisStatusRows[i] != SPxSolverBase<R>::BASIC || basicDual[i] == 0);
4114
4115 if(basisStatusRows[i] == SPxSolverBase<R>::BASIC || basisStatusRows[i] == SPxSolverBase<R>::FIXED)
4116 continue;
4117 else if(basicDual[i] < 0)
4118 {
4119 if(((maximizing && basisStatusRows[i] != SPxSolverBase<R>::ON_LOWER) || (!maximizing
4120 && basisStatusRows[i] != SPxSolverBase<R>::ON_UPPER))
4121 && (basisStatusRows[i] != SPxSolverBase<R>::ZERO || rhsRational(i) != 0))
4122 {
4123 dualFeasible = false;
4124 violation = -basicDual[i];
4125
4126 if(violation > dualViolation)
4127 dualViolation = violation;
4128
4129 MSG_DEBUG(spxout << "negative dual multliplier for row " << i
4130 << " with dual " << basicDual[i].str()
4131 << " and status " << basisStatusRows[i]
4132 << " and [lhs,rhs] = [" << lhsRational(i).str() << "," << rhsRational(i).str() << "]"
4133 << "\n");
4134 }
4135 }
4136 else if(basicDual[i] > 0)
4137 {
4138 if(((maximizing && basisStatusRows[i] != SPxSolverBase<R>::ON_UPPER) || (!maximizing
4139 && basisStatusRows[i] != SPxSolverBase<R>::ON_LOWER))
4140 && (basisStatusRows[i] != SPxSolverBase<R>::ZERO || lhsRational(i) == 0))
4141 {
4142 dualFeasible = false;
4143
4144 if(basicDual[i] > dualViolation)
4145 dualViolation = basicDual[i];
4146
4147 MSG_DEBUG(spxout << "positive dual multliplier for row " << i
4148 << " with dual " << basicDual[i].str()
4149 << " and status " << basisStatusRows[i]
4150 << " and [lhs,rhs] = [" << lhsRational(i).str() << "," << rhsRational(i).str() << "]"
4151 << "\n");
4152 }
4153 }
4154 }
4155
4156 // check reduced cost violation on nonbasic columns
4157 for(int i = 0; i < basisStatusCols.size(); i++)
4158 {
4159 if(_colTypes[i] == RANGETYPE_FIXED
4160 && (basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER
4161 || basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER))
4162 {
4163 assert(lowerRational(i) == upperRational(i));
4164 basisStatusCols[i] = SPxSolverBase<R>::FIXED;
4165 }
4166
4167 assert(basisStatusCols[i] != SPxSolverBase<R>::BASIC
4168 || basicDual * colVectorRational(i) == objRational(i));
4169
4170 if(basisStatusCols[i] == SPxSolverBase<R>::BASIC || basisStatusCols[i] == SPxSolverBase<R>::FIXED)
4171 continue;
4172 else
4173 {
4174 _workSol._redCost[i] = basicDual * colVectorRational(i);
4175 _workSol._redCost[i] -= objRational(i);
4176
4177 if(_workSol._redCost[i] > 0)
4178 {
4179 if(((maximizing && basisStatusCols[i] != SPxSolverBase<R>::ON_LOWER) || (!maximizing
4180 && basisStatusCols[i] != SPxSolverBase<R>::ON_UPPER))
4181 && (basisStatusCols[i] != SPxSolverBase<R>::ZERO || upperRational(i) != 0))
4182 {
4183 dualFeasible = false;
4184
4185 if(_workSol._redCost[i] > dualViolation)
4186 dualViolation = _workSol._redCost[i];
4187 }
4188
4189 _workSol._redCost[i] *= -1;
4190 }
4191 else if(_workSol._redCost[i] < 0)
4192 {
4193 _workSol._redCost[i] *= -1;
4194
4195 if(((maximizing && basisStatusCols[i] != SPxSolverBase<R>::ON_UPPER) || (!maximizing
4196 && basisStatusCols[i] != SPxSolverBase<R>::ON_LOWER))
4197 && (basisStatusCols[i] != SPxSolverBase<R>::ZERO || lowerRational(i) != 0))
4198 {
4199 dualFeasible = false;
4200
4201 if(_workSol._redCost[i] > dualViolation)
4202 dualViolation = _workSol._redCost[i];
4203 }
4204 }
4205 else
4206 _workSol._redCost[i] *= -1;
4207 }
4208 }
4209
4210 if(!dualFeasible)
4211 {
4212 MSG_INFO1(spxout, spxout << "Rational solution dual infeasible.\n");
4213 }
4214
4215 // store solution
4216 optimal = primalFeasible && dualFeasible;
4217
4218 if(optimal || boolParam(SoPlexBase<R>::RATFACJUMP))
4219 {
4220 _hasBasis = true;
4221
4222 if(&basisStatusRows != &_basisStatusRows)
4223 _basisStatusRows = basisStatusRows;
4224
4225 if(&basisStatusCols != &_basisStatusCols)
4226 _basisStatusCols = basisStatusCols;
4227
4228 sol._primal.reDim(numColsRational());
4229 j = numBasicRows;
4230
4231 for(int i = 0; i < basisStatusCols.size(); i++)
4232 {
4233 if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
4234 {
4235 assert(j < matrixdim);
4236 assert(_rationalLUSolverBind[j] == i);
4237 sol._primal[i] = basicPrimal[j];
4238 j++;
4239 }
4240 else if(basisStatusCols[i] == SPxSolverBase<R>::ON_LOWER)
4241 sol._primal[i] = lowerRational(i);
4242 else if(basisStatusCols[i] == SPxSolverBase<R>::ON_UPPER)
4243 sol._primal[i] = upperRational(i);
4244 else if(basisStatusCols[i] == SPxSolverBase<R>::ZERO)
4245 sol._primal[i] = 0;
4246 else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
4247 {
4248 assert(lowerRational(i) == upperRational(i));
4249 sol._primal[i] = lowerRational(i);
4250 }
4251 else
4252 {
4253 assert(basisStatusCols[i] == SPxSolverBase<R>::UNDEFINED);
4254 MSG_INFO1(spxout, spxout << "Undefined basis status of column in rational factorization.\n");
4255 error = true;
4256 goto TERMINATE;
4257 }
4258 }
4259
4260 sol._slacks.reDim(numRowsRational());
4261 _rationalLP->computePrimalActivity(sol._primal, sol._slacks);
4262 sol._isPrimalFeasible = true;
4263
4264 sol._dual = basicDual;
4265
4266 for(int i = 0; i < numColsRational(); i++)
4267 {
4268 if(basisStatusCols[i] == SPxSolverBase<R>::BASIC)
4269 sol._redCost[i] = 0;
4270 else if(basisStatusCols[i] == SPxSolverBase<R>::FIXED)
4271 {
4272 sol._redCost[i] = basicDual * colVectorRational(i);
4273 sol._redCost[i] -= objRational(i);
4274 sol._redCost[i] *= -1;
4275 }
4276 else
4277 sol._redCost[i] = _workSol._redCost[i];
4278 }
4279
4280 sol._isDualFeasible = true;
4281 }
4282 else
4283 {
4284 _rationalLUSolver.clear();
4285 }
4286
4287
4288 TERMINATE:
4289 // stop rational solving time
4290 _statistics->rationalTime->stop();
4291 return;
4292 }
4293
4294 /// attempts rational reconstruction of primal-dual solution
4295 template <class R>
4296 bool SoPlexBase<R>::_reconstructSolutionRational(SolRational& sol,
4297 DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusRows,
4298 DataArray< typename SPxSolverBase<R>::VarStatus >& basisStatusCols,
4299 const Rational& denomBoundSquared)
4300 {
4301 bool success;
4302 bool isSolBasic;
4303 DIdxSet basicIndices(numColsRational());
4304
4305 success = false;
4306 isSolBasic = true;
4307
4308 if(!sol.isPrimalFeasible() || !sol.isDualFeasible())
4309 return success;
4310
4311 // start timing and increment statistics counter
4312 _statistics->reconstructionTime->start();
4313 _statistics->rationalReconstructions++;
4314
4315 // reconstruct primal vector
4316 _workSol._primal = sol._primal;
4317
4318 for(int j = 0; j < numColsRational(); ++j)
4319 {
4320 if(basisStatusCols[j] == SPxSolverBase<R>::BASIC)
4321 basicIndices.addIdx(j);
4322 }
4323
4324 success = reconstructVector(_workSol._primal, denomBoundSquared, &basicIndices);
4325
4326 if(!success)
4327 {
4328 MSG_INFO1(spxout, spxout << "Rational reconstruction of primal solution failed.\n");
4329 _statistics->reconstructionTime->stop();
4330 return success;
4331 }
4332
4333 MSG_DEBUG(spxout << "Rational reconstruction of primal solution successful.\n");
4334
4335 // check violation of bounds
4336 for(int c = numColsRational() - 1; c >= 0; c--)
4337 {
4338 // we want to notify the user whether the reconstructed solution is basic; otherwise, this would be redundant
4339 typename SPxSolverBase<R>::VarStatus& basisStatusCol = _basisStatusCols[c];
4340
4341 if((basisStatusCol == SPxSolverBase<R>::FIXED && _workSol._primal[c] != lowerRational(c))
4342 || (basisStatusCol == SPxSolverBase<R>::ON_LOWER && _workSol._primal[c] != lowerRational(c))
4343 || (basisStatusCol == SPxSolverBase<R>::ON_UPPER && _workSol._primal[c] != upperRational(c))
4344 || (basisStatusCol == SPxSolverBase<R>::ZERO && _workSol._primal[c] != 0)
4345 || (basisStatusCol == SPxSolverBase<R>::UNDEFINED))
4346 {
4347 isSolBasic = false;
4348 }
4349
4350 if(_lowerFinite(_colTypes[c]) && _workSol._primal[c] < lowerRational(c))
4351 {
4352 MSG_DEBUG(std::cout << "Lower bound of variable " << c << " violated by " <<
4353 (lowerRational(c) - _workSol._primal[c]).str() << "\n");
4354 MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (1).\n");
4355 _statistics->reconstructionTime->stop();
4356 return false;
4357 }
4358
4359 if(_upperFinite(_colTypes[c]) && _workSol._primal[c] > upperRational(c))
4360 {
4361 MSG_DEBUG(std::cout << "Upper bound of variable " << c << " violated by " <<
4362 (_workSol._primal[c] - upperRational(c)).str() << "\n");
4363 MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (2).\n");
4364 _statistics->reconstructionTime->stop();
4365 return false;
4366 }
4367 }
4368
4369 // compute slacks
4370 ///@todo we should compute them one by one so we can abort when encountering an infeasibility
4371 _workSol._slacks.reDim(numRowsRational());
4372 _rationalLP->computePrimalActivity(_workSol._primal, _workSol._slacks);
4373
4374 // check violation of sides
4375 for(int r = numRowsRational() - 1; r >= 0; r--)
4376 {
4377 // we want to notify the user whether the reconstructed solution is basic; otherwise, this would be redundant
4378 typename SPxSolverBase<R>::VarStatus& basisStatusRow = _basisStatusRows[r];
4379
4380 if((basisStatusRow == SPxSolverBase<R>::FIXED && _workSol._slacks[r] != lhsRational(r))
4381 || (basisStatusRow == SPxSolverBase<R>::ON_LOWER && _workSol._slacks[r] != lhsRational(r))
4382 || (basisStatusRow == SPxSolverBase<R>::ON_UPPER && _workSol._slacks[r] != rhsRational(r))
4383 || (basisStatusRow == SPxSolverBase<R>::ZERO && _workSol._slacks[r] != 0)
4384 || (basisStatusRow == SPxSolverBase<R>::UNDEFINED))
4385 {
4386 isSolBasic = false;
4387 }
4388
4389 if(_lowerFinite(_rowTypes[r]) && _workSol._slacks[r] < lhsRational(r))
4390 {
4391 MSG_DEBUG(std::cout << "Lhs of row " << r << " violated by " <<
4392 (lhsRational(r) - _workSol._slacks[r]).str() << "\n");
4393 MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (3).\n");
4394 _statistics->reconstructionTime->stop();
4395 return false;
4396 }
4397
4398 if(_upperFinite(_rowTypes[r]) && _workSol._slacks[r] > rhsRational(r))
4399 {
4400 MSG_DEBUG(std::cout << "Rhs of row " << r << " violated by " <<
4401 (_workSol._slacks[r] - rhsRational(r)) << "\n");
4402 MSG_INFO1(spxout, spxout << "Reconstructed solution primal infeasible (4).\n");
4403 _statistics->reconstructionTime->stop();
4404 return false;
4405 }
4406 }
4407
4408 // reconstruct dual vector
4409 _workSol._dual = sol._dual;
4410
4411 success = reconstructVector(_workSol._dual, denomBoundSquared);
4412
4413 if(!success)
4414 {
4415 MSG_INFO1(spxout, spxout << "Rational reconstruction of dual solution failed.\n");
4416 _statistics->reconstructionTime->stop();
4417 return success;
4418 }
4419
4420 MSG_DEBUG(spxout << "Rational reconstruction of dual vector successful.\n");
4421
4422 // check dual multipliers before reduced costs because this check is faster since it does not require the
4423 // computation of reduced costs
4424 const bool maximizing = (intParam(SoPlexBase<R>::OBJSENSE) == SoPlexBase<R>::OBJSENSE_MAXIMIZE);
4425
4426 for(int r = numRowsRational() - 1; r >= 0; r--)
4427 {
4428 int sig = sign(_workSol._dual[r]);
4429
4430 if((!maximizing && sig > 0) || (maximizing && sig < 0))
4431 {
4432 if(!_lowerFinite(_rowTypes[r]) || _workSol._slacks[r] > lhsRational(r))
4433 {
4434 MSG_DEBUG(std::cout << "complementary slackness violated by row " << r
4435 << " with dual " << _workSol._dual[r].str()
4436 << " and slack " << _workSol._slacks[r].str()
4437 << " not at lhs " << lhsRational(r).str()
4438 << "\n");
4439 MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (1).\n");
4440 _statistics->reconstructionTime->stop();
4441 return false;
4442 }
4443
4444 if(_basisStatusRows[r] != SPxSolverBase<R>::ON_LOWER
4445 && _basisStatusRows[r] != SPxSolverBase<R>::FIXED)
4446 {
4447 if(_basisStatusRows[r] == SPxSolverBase<R>::BASIC
4448 || _basisStatusRows[r] == SPxSolverBase<R>::UNDEFINED)
4449 isSolBasic = false;
4450 else
4451 _basisStatusRows[r] = SPxSolverBase<R>::ON_LOWER;
4452 }
4453 }
4454 else if((!maximizing && sig < 0) || (maximizing && sig > 0))
4455 {
4456 if(!_upperFinite(_rowTypes[r]) || _workSol._slacks[r] < rhsRational(r))
4457 {
4458 MSG_DEBUG(std::cout << "complementary slackness violated by row " << r
4459 << " with dual " << _workSol._dual[r].str()
4460 << " and slack " << _workSol._slacks[r].str()
4461 << " not at rhs " << rhsRational(r).str()
4462 << "\n");
4463 MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (2).\n");
4464 _statistics->reconstructionTime->stop();
4465 return false;
4466 }
4467
4468 if(_basisStatusRows[r] != SPxSolverBase<R>::ON_UPPER
4469 && _basisStatusRows[r] != SPxSolverBase<R>::FIXED)
4470 {
4471 if(_basisStatusRows[r] == SPxSolverBase<R>::BASIC
4472 || _basisStatusRows[r] == SPxSolverBase<R>::UNDEFINED)
4473 isSolBasic = false;
4474 else
4475 _basisStatusRows[r] = SPxSolverBase<R>::ON_UPPER;
4476 }
4477 }
4478 }
4479
4480 // compute reduced cost vector; we assume that the objective function vector has less nonzeros than the reduced
4481 // cost vector, and so multiplying with -1 first and subtracting the dual activity should be faster than adding
4482 // the dual activity and negating afterwards
4483 ///@todo we should compute them one by one so we can abort when encountering an infeasibility
4484 _workSol._redCost.reDim(numColsRational());
4485 _rationalLP->getObj(_workSol._redCost);
4486 _rationalLP->subDualActivity(_workSol._dual, _workSol._redCost);
4487
4488 // check reduced cost violation
4489 for(int c = numColsRational() - 1; c >= 0; c--)
4490 {
4491 int sig = sign(_workSol._redCost[c]);
4492
4493 if((!maximizing && sig > 0) || (maximizing && sig < 0))
4494 {
4495 if(!_lowerFinite(_colTypes[c]) || _workSol._primal[c] > lowerRational(c))
4496 {
4497 MSG_DEBUG(std::cout << "complementary slackness violated by column " << c
4498 << " with reduced cost " << _workSol._redCost[c].str()
4499 << " and value " << _workSol._primal[c].str()
4500 << " not at lower bound " << lowerRational(c).str()
4501 << "\n");
4502 MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (3).\n");
4503 _statistics->reconstructionTime->stop();
4504 return false;
4505 }
4506
4507 if(_basisStatusCols[c] != SPxSolverBase<R>::ON_LOWER
4508 && _basisStatusCols[c] != SPxSolverBase<R>::FIXED)
4509 {
4510 if(_basisStatusCols[c] == SPxSolverBase<R>::BASIC
4511 || _basisStatusCols[c] == SPxSolverBase<R>::UNDEFINED)
4512 isSolBasic = false;
4513 else
4514 _basisStatusCols[c] = SPxSolverBase<R>::ON_LOWER;
4515 }
4516 }
4517 else if((!maximizing && sig < 0) || (maximizing && sig > 0))
4518 {
4519 if(!_upperFinite(_colTypes[c]) || _workSol._primal[c] < upperRational(c))
4520 {
4521 MSG_DEBUG(std::cout << "complementary slackness violated by column " << c
4522 << " with reduced cost " << _workSol._redCost[c].str()
4523 << " and value " << _workSol._primal[c].str()
4524 << " not at upper bound " << upperRational(c).str()
4525 << "\n");
4526 MSG_INFO1(spxout, spxout << "Reconstructed solution dual infeasible (4).\n");
4527 _statistics->reconstructionTime->stop();
4528 return false;
4529 }
4530
4531 if(_basisStatusCols[c] != SPxSolverBase<R>::ON_UPPER
4532 && _basisStatusCols[c] != SPxSolverBase<R>::FIXED)
4533 {
4534 if(_basisStatusCols[c] == SPxSolverBase<R>::BASIC
4535 || _basisStatusCols[c] == SPxSolverBase<R>::UNDEFINED)
4536 isSolBasic = false;
4537 else
4538 _basisStatusCols[c] = SPxSolverBase<R>::ON_UPPER;
4539 }
4540 }
4541 }
4542
4543 // update solution
4544 sol._primal = _workSol._primal;
4545 sol._slacks = _workSol._slacks;
4546 sol._dual = _workSol._dual;
4547 sol._redCost = _workSol._redCost;
4548
4549 if(!isSolBasic)
4550 {
4551 MSG_WARNING(spxout, spxout << "Warning: Reconstructed solution not basic.\n");
4552 _hasBasis = false;
4553 }
4554
4555 // stop timing
4556 _statistics->reconstructionTime->stop();
4557
4558 return success;
4559 }
4560 } // namespace soplex
4561