Scippy

SoPlex

Sequential object-oriented simPlex

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