Scippy

SoPlex

Sequential object-oriented simPlex

solvereal.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 
23 namespace soplex
24 {
25  /// solves real LP
27  {
28  // start timing
30 
31  // remember that last solve was in floating-point
33 
34  // solve and store solution; if we have a starting basis, do not apply preprocessing; if we are solving from
35  // scratch, apply preprocessing according to parameter settings
38 
39  // stop timing
41  }
42 
43 
44 
45  /// checks result of the solving process and solves again without preprocessing if necessary
47  {
48  if( simplificationStatus == SPxSimplifier::INFEASIBLE )
50  else if( simplificationStatus == SPxSimplifier::DUAL_INFEASIBLE )
52  else if( simplificationStatus == SPxSimplifier::UNBOUNDED )
54  else if( simplificationStatus == SPxSimplifier::VANISHED )
56  else if( simplificationStatus == SPxSimplifier::OKAY )
58 
59  // process result
60  switch( _status )
61  {
62  case SPxSolver::OPTIMAL:
63  if( !_isRealLPLoaded )
64  {
65  MSG_INFO1( spxout, spxout << " --- transforming basis into original space" << std::endl; )
67  _resolveWithoutPreprocessing(simplificationStatus);
68  return;
69  }
70  else
71  _hasBasis = true;
72  break;
73 
77  // in case of infeasibility or unboundedness, we currently can not unsimplify, but have to solve the original LP again
78  if( !_isRealLPLoaded )
79  {
82  return;
83  }
84  else
86  break;
87 
89  // if preprocessing was applied, try to run again without to avoid singularity
90  if( !_isRealLPLoaded )
91  {
94  return;
95  }
96  break;
97 
99  // if preprocessing was applied, try to run again without to avoid cycling
100  if( !_isRealLPLoaded )
101  {
104  return;
105  }
106  // else fallthrough
110  case SPxSolver::REGULAR:
111  case SPxSolver::RUNNING:
112  if( _isRealLPLoaded )
114  // store regular basis if there is no simplifier and the original problem is not in the solver because of
115  // scaling; non-optimal bases should currently not be unsimplified
116  else if( _simplifier == 0 && _solver.basis().status() > SPxBasis::NO_PROBLEM )
117  {
118  _basisStatusRows.reSize(numRowsReal());
119  _basisStatusCols.reSize(numColsReal());
120  assert(_basisStatusRows.size() == _solver.nRows());
121  assert(_basisStatusCols.size() == _solver.nCols());
122 
124  _hasBasis = true;
125  }
126  else
127  _hasBasis = false;
128  break;
129 
130  default:
131  _hasBasis = false;
132  break;
133  }
134  }
135 
136 
137 
138  /// solves real LP with/without preprocessing
139  void SoPlex::_preprocessAndSolveReal(bool applyPreprocessing)
140  {
142 
143  if( applyPreprocessing )
144  {
147  }
148  else
149  {
151  ///@todo implement for both objective senses
154  }
155 
156  applyPreprocessing = (_simplifier != 0 || _scaler != 0);
157 
158  if( _isRealLPLoaded )
159  {
160  assert(_realLP == &_solver);
161 
162  // preprocessing is always applied to the LP in the solver; hence we have to create a copy of the original LP
163  // if preprocessing is turned on
164  if( applyPreprocessing )
165  {
166  _realLP = 0;
168  _realLP = new (_realLP) SPxLPReal(_solver);
169  _isRealLPLoaded = false;
170  }
171  }
172  else
173  {
174  assert(_realLP != &_solver);
175 
176  // ensure that the solver has the original problem
178 
179  // load basis if available
180  if( _hasBasis )
181  {
182  assert(_basisStatusRows.size() == numRowsReal());
183  assert(_basisStatusCols.size() == numColsReal());
184 
185  ///@todo this should not fail even if the basis is invalid (wrong dimension or wrong number of basic
186  /// entries); fix either in SPxSolver or in SPxBasis
187  _solver.setBasis(_basisStatusRows.get_const_ptr(), _basisStatusCols.get_const_ptr());
188  }
189 
190  // if there is no preprocessing, then the original and the transformed problem are identical and it is more
191  // memory-efficient to keep only the problem in the solver
192  if( !applyPreprocessing )
193  {
194  _realLP->~SPxLPReal();
195  spx_free(_realLP);
196  _realLP = &_solver;
197  _isRealLPLoaded = true;
198  }
199  }
200 
201  // assert that we have two problems if and only if we apply preprocessing
202  assert(_realLP == &_solver || applyPreprocessing);
203  assert(_realLP != &_solver || !applyPreprocessing);
204 
205  // apply problem simplification
206  SPxSimplifier::Result simplificationStatus = SPxSimplifier::OKAY;
207  if( _simplifier != 0 )
208  {
209  // do not remove bounds of boxed variables or sides of ranged rows if bound flipping is used
213  }
214 
216 
217  // run the simplex method if problem has not been solved by the simplifier
218  if( simplificationStatus == SPxSimplifier::OKAY )
219  {
220  if( _scaler != 0 )
222 
224  }
225 
226  // check the result and run again without preprocessing if necessary
227  _evaluateSolutionReal(simplificationStatus);
228  }
229 
230 
231 
232  /// loads original problem into solver and solves again after it has been solved to optimality with preprocessing
234  {
235  assert(!_isRealLPLoaded);
236  assert(_simplifier != 0 || _scaler != 0);
237  assert(simplificationStatus == SPxSimplifier::VANISHED
238  || (simplificationStatus == SPxSimplifier::OKAY && _solver.status() == SPxSolver::OPTIMAL));
239 
240  // if simplifier is active and LP is solved in presolving or to optimality, then we unsimplify to get the basis
241  if( _simplifier != 0 )
242  {
243  assert(!_simplifier->isUnsimplified());
244 
245  bool vanished = simplificationStatus == SPxSimplifier::VANISHED;
246 
247  // get solution vectors for transformed problem
248  DVectorReal primal(vanished ? 0 : _solver.nCols());
249  DVectorReal slacks(vanished ? 0 : _solver.nRows());
250  DVectorReal dual(vanished ? 0 : _solver.nRows());
251  DVectorReal redCost(vanished ? 0 : _solver.nCols());
252 
253  _basisStatusRows.reSize(numRowsReal());
254  _basisStatusCols.reSize(numColsReal());
255  assert(vanished || _basisStatusRows.size() >= _solver.nRows());
256  assert(vanished || _basisStatusCols.size() >= _solver.nCols());
257 
258  if( !vanished )
259  {
260  assert(_solver.status() == SPxSolver::OPTIMAL);
261 
262  _solver.getPrimal(primal);
263  _solver.getSlacks(slacks);
264  _solver.getDual(dual);
265  _solver.getRedCost(redCost);
266 
267  // unscale vectors
268  if( _scaler != 0 )
269  {
270  _scaler->unscalePrimal(primal);
271  _scaler->unscaleSlacks(slacks);
272  _scaler->unscaleDual(dual);
273  _scaler->unscaleRedCost(redCost);
274  }
275 
276  // get basis of transformed problem
278  }
279 
280  try
281  {
282  _simplifier->unsimplify(primal, dual, slacks, redCost, _basisStatusRows.get_ptr(), _basisStatusCols.get_ptr());
284  _hasBasis = true;
285  }
286  catch( const SPxException& E )
287  {
288  MSG_ERROR( std::cerr << "Caught exception <" << E.what() << "> during unsimplification. Resolving without simplifier and scaler.\n" );
289  }
290  catch( ... )
291  {
292  MSG_ERROR( std::cerr << "Caught unknown exception during unsimplification. Resolving without simplifier and scaler.\n" );
294  }
295  }
296  // if the original problem is not in the solver because of scaling, we also need to store the basis
297  else if( _scaler != 0 )
298  {
299  _basisStatusRows.reSize(numRowsReal());
300  _basisStatusCols.reSize(numColsReal());
301  assert(_basisStatusRows.size() == _solver.nRows());
302  assert(_basisStatusCols.size() == _solver.nCols());
303 
305  _hasBasis = true;
306  }
307 
308  // resolve the original problem
310  return;
311  }
312 
313 
314 
315  /// stores solution of the real LP; before calling this, the real LP must be loaded in the solver and solved (again)
317  {
318  assert(status() != SPxSolver::OPTIMAL || _isRealLPLoaded);
319 
331 
336  if( _solReal._hasPrimal )
337  {
343  }
344 
346  if( _solReal._hasPrimalRay )
347  {
350  }
351 
352  assert(_solver.basis().status() != SPxBasis::DUAL || status() != SPxSolver::ERROR);
363 
367  if( _solReal._hasDual )
368  {
374  }
375 
378  {
381  }
382 
383  _hasSolReal = true;
384  }
385 } // namespace soplex
386 #endif