Scippy

SoPlex

Sequential object-oriented simPlex

soplexlegacy.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 #include <iostream>
17 
18 #include "soplexlegacy.h"
19 #include "exceptions.h"
20 
21 namespace soplex
22 {
24  : m_solver(p_type, p_rep)
25  , m_preScaler(0)
26  , m_postScaler(0)
27  , m_simplifier(0)
28  , m_vanished(false)
29  , m_freePreScaler(false)
30  , m_freePostScaler(false)
31  , m_freeSimplifier(false)
32 {
33  m_solver.setOutstream(outstream);
36  m_solver.setPricer(new SPxSteepPR(), true);
38 
40 }
41 
43 {
44  assert(!m_freePreScaler || m_preScaler != 0);
45  assert(!m_freePostScaler || m_postScaler != 0);
46  assert(!m_freeSimplifier || m_simplifier != 0);
47 
48  if(m_freePreScaler)
49  {
50  delete m_preScaler;
51  m_preScaler = 0;
52  }
53 
55  {
56  delete m_postScaler;
57  m_postScaler = 0;
58  }
59 
61  {
62  delete m_simplifier;
63  m_simplifier = 0;
64  }
65 }
66 
68 {
69  assert(!m_freePreScaler || m_preScaler != 0);
70  assert(!m_freePostScaler || m_postScaler != 0);
71  assert(!m_freeSimplifier || m_simplifier != 0);
72 
73  if(this != &base)
74  {
75  SPxLP::operator=(base);
76  m_slu = base.m_slu; // call of SLinSolver::clone() SPxBasis assignment operator not necessary (done by m_solver.setSolver(&m_slu) below)
77  m_solver = base.m_solver;
78  m_vanished = base.m_vanished;
80 
81  // m_preScaler
82  if(m_freePreScaler)
83  {
84  delete m_preScaler;
85  m_preScaler = 0;
86  }
87  if(base.m_preScaler == 0)
88  {
89  m_preScaler = 0;
90  m_freePreScaler = false;
91  }
92  else
93  {
94  m_preScaler = base.m_preScaler->clone();
95  m_freePreScaler = true;
96  }
97 
98  // m_postScaler
100  {
101  delete m_postScaler;
102  m_postScaler = 0;
103  }
104  if(base.m_postScaler == 0)
105  {
106  m_postScaler = 0;
107  m_freePostScaler = false;
108  }
109  else
110  {
111  m_postScaler = base.m_postScaler->clone();
112  m_freePostScaler = true;
113  }
114 
115  // m_simplifier
116  if(m_freeSimplifier)
117  {
118  delete m_simplifier;
119  m_simplifier = 0;
120  }
121  if(base.m_simplifier == 0)
122  {
123  m_simplifier = 0;
124  m_freeSimplifier = false;
125  }
126  else
127  {
128  m_simplifier = base.m_simplifier->clone();
129  m_freeSimplifier = true;
130  }
131 
132 
133  }
134 
135  return *this;
136 }
137 
138 
140  : SPxLP(old)
141  , m_slu(old.m_slu) // call of SLinSolver::clone() SPxBasis copy constructor not necessary (done by m_solver.setSolver(&m_slu) below)
142  , m_solver(old.m_solver)
143  , m_vanished(old.m_vanished)
144 {
146 
147  // m_preScaler
148  if(old.m_preScaler == 0)
149  {
150  m_preScaler = 0;
151  m_freePreScaler = false;
152  }
153  else
154  {
155  m_preScaler = old.m_preScaler->clone();
156  m_freePreScaler = true;
157  }
158 
159  // m_postScaler
160  if(old.m_postScaler == 0)
161  {
162  m_postScaler = 0;
163  m_freePostScaler = false;
164  }
165  else
166  {
168  m_freePostScaler = true;
169  }
170 
171  // m_simplifier
172  if(old.m_simplifier == 0)
173  {
174  m_simplifier = 0;
175  m_freeSimplifier = false;
176  }
177  else
178  {
180  m_freeSimplifier = true;
181  }
182 }
183 
184 
185 
186 void SoPlexLegacy::setPreScaler(SPxScaler* x, const bool destroy)
187 {
188 
189  assert(!m_freePreScaler || m_preScaler != 0);
190 
191  if(m_freePreScaler)
192  {
193  delete m_preScaler;
194  m_preScaler = 0;
195  }
196  m_preScaler = x;
197  if( m_preScaler )
199  m_freePreScaler = destroy;
200 }
201 
202 void SoPlexLegacy::setPostScaler(SPxScaler* x, const bool destroy)
203 {
204 
205  assert(!m_freePostScaler || m_postScaler != 0);
206 
207  if(m_freePostScaler)
208  {
209  delete m_postScaler;
210  m_postScaler = 0;
211  }
212  m_postScaler = x;
213  if( m_postScaler )
215  m_freePostScaler = destroy;
216 }
217 
218 void SoPlexLegacy::setSimplifier(SPxSimplifier* x, const bool destroy)
219 {
220 
221  assert(!m_freeSimplifier || m_simplifier != 0);
222 
223  if(m_freeSimplifier)
224  {
225  delete m_simplifier;
226  m_simplifier = 0;
227  }
228  m_simplifier = x;
229  m_freeSimplifier = destroy;
230 }
231 
233 {
234 
235  DVector x(nCols());
236 
237  getPrimal(x);
238 
239  return x * maxObj() * Real(spxSense());
240 }
241 
243 {
244 
245  if (nRows() <= 0 && nCols() <= 0) // no problem loaded
246  throw SPxStatusException("XSOLVR01 No Problem loaded");
247 
248  // assume presolver did NOT solve problem
249  m_vanished = false;
250 
251  // working LP
252  SPxLP work(*this);
253  work.setOutstream(*spxout);
254 
255  // keep useful bounds for bfrt
256  bool keepbounds = (!strcmp(m_solver.ratiotester()->getName(), "Bound Flipping"));
257 
258  // should the LP be scaled
259  if (m_preScaler != 0)
260  m_preScaler->scale(work);
261 
262  // should the LP be simplified ?
263  if (m_simplifier != 0)
264  {
265  switch(m_simplifier->simplify(work, m_solver.epsilon(), m_solver.feastol(), m_solver.opttol(), keepbounds))
266  {
269  return SPxSolver::UNBOUNDED;
272  return SPxSolver::INFEASIBLE;
274  m_vanished = true;
275  return SPxSolver::OPTIMAL;
276  case SPxSimplifier::OKAY:
277  break;
278  default:
279  throw SPxInternalCodeException("XRSOLVR01 This should never happen.");
280  }
281  }
282 
283  // should the LP be scaled after simplifing?
284  if (m_postScaler != 0)
285  m_postScaler->scale(work);
286 
287  /* if a basis of correct size was set externally, try to load it into the transformed LP */
288  if ( m_colsbasisstatus.size() == work.nCols() && m_rowsbasisstatus.size() == work.nRows() )
289  {
290  m_solver.loadLP(work);
292  {
293  m_solver.setBasis(m_rowsbasisstatus.get_const_ptr(), m_colsbasisstatus.get_const_ptr());
294  }
295  m_colsbasisstatus.clear();
296  m_rowsbasisstatus.clear();
297  }
298  /* if a basis with status at least REGULAR exists (loaded via readBasisFile()
299  * or available from previous simplex run), we check whether it can be (re)used
300  * for the newly loaded LP.
301  */
302  else if ( m_solver.basis().status() <= SPxBasis::SINGULAR )
303  {
304  m_solver.loadLP(work);
305  }
306  else
307  {
308  SPxBasis::Desc oldbasisdesc(m_solver.basis().desc());
309  m_solver.loadLP(work);
310  if(m_solver.basis().isDescValid(oldbasisdesc))
311  m_solver.loadBasis(oldbasisdesc);
312  }
313 
314  return m_solver.solve();
315 }
316 
318 {
319 
320  if (has_simplifier())
321  {
323  unsimplify();
324 
326 
327  // unscale prescaling
328  if (m_preScaler != 0)
330 
331  if (m_vanished)
332  return SPxSolver::OPTIMAL;
333  else
334  return m_solver.status();
335  }
336 
337  // else
339 
340  // unscale postscaling
341  if (m_postScaler != 0)
343 
344  // unscale prescaling
345  if (m_preScaler != 0)
347 
348  return stat;
349 }
350 
352 {
353 
354  if (has_simplifier())
355  {
357  unsimplify();
358 
360 
361  // unscale prescaling
362  if (m_preScaler != 0)
364 
365  if (m_vanished)
366  return SPxSolver::OPTIMAL;
367  else
368  return m_solver.status();
369  }
370 
371  // else
373 
374  // unscale postscaling
375  if (m_postScaler != 0)
377 
378  // unscale prescaling
379  if (m_preScaler != 0)
381 
382  return stat;
383 }
384 
386 {
387 
388  if (has_simplifier())
389  {
391  unsimplify();
392 
394 
395  // unscale prescaling
396  if (m_preScaler != 0)
398 
399  if (m_vanished)
400  return SPxSolver::OPTIMAL;
401  else
402  return m_solver.status();
403  }
404 
405  // else
407 
408  // unscale postscaling
409  if (m_postScaler != 0)
411 
412  // unscale prescaling
413  if (m_preScaler != 0)
415 
416  return stat;
417 }
418 
420 {
421 
422  if (has_simplifier())
423  {
425  unsimplify();
426 
427  rdcost = m_simplifier->unsimplifiedRedCost();
428 
429  // unscale prescaling
430  if (m_preScaler != 0)
431  m_preScaler->unscaleRedCost(rdcost);
432 
433  if (m_vanished)
434  return SPxSolver::OPTIMAL;
435  else
436  return m_solver.status();
437  }
438 
439  // else
440  SPxSolver::Status stat = m_solver.getRedCost(rdcost);
441 
442  // unscale postscaling
443  if (m_postScaler != 0)
444  m_postScaler->unscaleRedCost(rdcost);
445 
446  // unscale prescaling
447  if (m_preScaler != 0)
448  m_preScaler->unscaleRedCost(rdcost);
449 
450  return stat;
451 }
452 
454 {
456  if((b_status == SPxBasis::NO_PROBLEM || (has_simplifier() && b_status == SPxBasis::SINGULAR)) && !m_vanished)
457  return SPxSolver::UNDEFINED;
458 
459  if (has_simplifier())
460  {
462  unsimplify();
463 
464  return m_simplifier->getBasisRowStatus(i);
465  }
466  else
467  return m_solver.getBasisRowStatus(i);
468 }
469 
471 {
473  if((b_status == SPxBasis::NO_PROBLEM || (has_simplifier() && b_status == SPxBasis::SINGULAR)) && !m_vanished)
474  return SPxSolver::UNDEFINED;
475 
476  if (has_simplifier())
477  {
479  unsimplify();
480 
481  return m_simplifier->getBasisColStatus(j);
482  }
483  else
484  return m_solver.getBasisColStatus(j);
485 }
486 
488 {
490  if((b_status == SPxBasis::NO_PROBLEM || (has_simplifier() && b_status == SPxBasis::SINGULAR)) && !m_vanished)
491  {
492  int i;
493 
494  if (cols)
495  for (i = nCols() - 1; i >= 0; --i)
496  cols[i] = SPxSolver::UNDEFINED;
497 
498  if (rows)
499  for (i = nRows() - 1; i >= 0; --i)
500  rows[i] = SPxSolver::UNDEFINED;
501 
502  return m_solver.status();
503  }
504 
505  if (has_simplifier())
506  {
508  unsimplify();
509 
510  m_simplifier->getBasis(rows, cols);
511  return m_solver.status();
512  }
513 
514  else
515  return m_solver.getBasis(rows, cols);
516 }
517 
519 {
520  /// Does not work yet with presolve
521  if (has_simplifier())
522  {
523  MSG_ERROR( std::cerr << "ESOLVR02 Primal ray with presolving not yet implemented" << std::endl; )
524  throw SPxStatusException("XSOLVR02 Primal ray with presolving not yet implemented");
525  }
526  SPxSolver::Status stat = m_solver.getPrimalray(primalray);
527 
528  if (m_postScaler != 0)
529  m_postScaler->unscalePrimal(primalray);
530 
531  if (m_preScaler != 0)
532  m_preScaler->unscalePrimal(primalray);
533 
534  return stat;
535 }
536 
538 {
539  /// Does not work yet with presolve
540  if (has_simplifier())
541  {
542  MSG_ERROR( std::cerr << "ESOLVR02 Dual farkas with presolving not yet implemented" << std::endl; )
543  throw SPxStatusException("XSOLVR03 Dual farkas with presolving not yet implemented");
544  // return SPxSolver::ERROR;
545  }
546  SPxSolver::Status stat = m_solver.getDualfarkas(dualfarkas);
547 
548  if (m_postScaler != 0)
549  m_postScaler->unscaleDual(dualfarkas);
550 
551  if (m_preScaler != 0)
552  m_preScaler->unscaleDual(dualfarkas);
553 
554  return stat;
555 }
556 
558  Real& maxviol,
559  Real& sumviol) const
560 {
561  maxviol = 0.0;
562  sumviol = 0.0;
563 
564  DVector solu( nCols() );
565 
566  getPrimal( solu );
567 
568  for( int row = 0; row < nRows(); ++row )
569  {
570  const SVector& rowvec = rowVector( row );
571 
572  Real val = 0.0;
573 
574  for( int col = 0; col < rowvec.size(); ++col )
575  val += rowvec.value( col ) * solu[rowvec.index( col )];
576 
577  Real viol = 0.0;
578 
579  assert(lhs( row ) <= rhs( row ));
580 
581  if (val < lhs( row ))
582  viol = spxAbs(val - lhs( row ));
583  else
584  if (val > rhs( row ))
585  viol = spxAbs(val - rhs( row ));
586 
587  if (viol > maxviol)
588  maxviol = viol;
589 
590  sumviol += viol;
591  }
592 }
593 
595  Real& maxviol,
596  Real& sumviol) const
597 {
598  maxviol = 0.0;
599  sumviol = 0.0;
600 
601  DVector solu( nCols() );
602 
603  getPrimal( solu );
604 
605  for( int col = 0; col < nCols(); ++col )
606  {
607  assert( lower( col ) <= upper( col ));
608 
609  Real viol = 0.0;
610 
611  if (solu[col] < lower( col ))
612  viol = spxAbs( solu[col] - lower( col ));
613  else
614  if (solu[col] > upper( col ))
615  viol = spxAbs( solu[col] - upper( col ));
616 
617  if (viol > maxviol)
618  maxviol = viol;
619 
620  sumviol += viol;
621  }
622 }
623 
625  const char* filename,
626  const NameSet* rowNames,
627  const NameSet* colNames
628  )
629 {
630  // init solver using original LP
631  m_solver.loadLP(*this);
632  return m_solver.readBasisFile(filename, rowNames, colNames);
633 }
634 
636  const char* filename,
637  const NameSet* rowNames,
638  const NameSet* colNames
639  )
640 {
641  assert(rep() == SPxSolver::COLUMN);
642 
643  /* make sure the basis of the original problem is written */
644  unsimplify();
645 
646  std::ofstream file(filename);
647  std::ostream& os = file;
648 
649  os.setf(std::ios::left);
650  os << "NAME soplex.bas\n";
651 
652  /* do not write basis if there is none */
653  if( status() == SPxSolver::NO_PROBLEM )
654  {
655  os << "ENDATA" << std::endl;
656  return true;
657  }
658 
659  /* start writing */
660  char buf[255];
661  int row = 0;
662  for( int col = 0; col < nCols(); col++ )
663  {
664  if( getBasisColStatus(col) == SPxSolver::BASIC )
665  {
666  /* Find non basic row */
667  for( ; row < nRows(); row++ )
668  {
669  if( getBasisRowStatus(row) != SPxSolver::BASIC )
670  break;
671  }
672 
673  assert(row != nRows());
674 
675  os << ( getBasisRowStatus(row) == SPxSolver::ON_UPPER ? " XU " : " XL " )
676  << std::setw(8) << getColName(col, colNames, buf);
677 
678  /* break in two parts since buf is reused */
679  os << " "
680  << getRowName(row, rowNames, buf)
681  << std::endl;
682 
683  row++;
684  }
685  else
686  {
688  {
689  os << " UL "
690  << getColName(col, colNames, buf)
691  << std::endl;
692  }
693  }
694  }
695 
696  #ifndef NDEBUG
697  // Check that we covered all nonbasic rows - the remaining should be basic.
698  for( ; row < nRows(); row++ )
699  {
700  if( getBasisRowStatus(row) != SPxSolver::BASIC )
701  break;
702  }
703  assert(row == nRows());
704  #endif // NDEBUG
705 
706  os << "ENDATA" << std::endl;
707  return true;
708 }
709 
711  const char* filename,
712  const NameSet* rowNames,
713  const NameSet* colNames ) const
714 {
715 
716  return m_solver.writeState(filename, rowNames, colNames);
717 }
718 
720 {
722  return;
723 
724  DVector psp_x(m_solver.nCols()); // primal solution (prescaled simplified postscaled)
725  DVector psp_y(m_solver.nRows()); // dual solution (prescaled simplified postscaled)
726  DVector psp_s(m_solver.nRows()); // slacks (prescaled simplified postscaled)
727  DVector psp_r(m_solver.nCols()); // reduced costs (prescaled simplified postscaled)
728 
729  if (! m_vanished) {
730  // If solver status is not regular or optimal, do nothing.
731  const SPxSolver::Status stat = status();
732  if( stat != SPxSolver::OPTIMAL && stat != SPxSolver::REGULAR )
733  return;
734 
735  m_solver.getPrimal(psp_x);
736  m_solver.getDual(psp_y);
737  m_solver.getSlacks(psp_s);
738  m_solver.getRedCost(psp_r);
739 
740  // unscale postscaling
741  if (m_postScaler != 0)
742  {
743  m_postScaler->unscalePrimal(psp_x);
744  m_postScaler->unscaleDual(psp_y);
745  m_postScaler->unscaleSlacks(psp_s);
747  }
748  }
749  else {
750  // If there is no sensible solution, do nothing.
751  const SPxSolver::Status stat = status();
752  if (stat != SPxSolver::OPTIMAL)
753  return;
754 
755  psp_x.reDim(0);
756  psp_y.reDim(0);
757  psp_s.reDim(0);
758  psp_r.reDim(0);
759  }
760 
761  // unsimplify
762  if(m_vanished)
763  {
764  m_simplifier->unsimplify(psp_x, psp_y, psp_s, psp_r, NULL, NULL);
765  }
766  else
767  {
768  SPxSolver::VarStatus *rows, *cols;
769  rows = NULL;
770  cols = NULL;
771  try
772  {
773  spx_alloc(rows, m_solver.nRows());
774  spx_alloc(cols, m_solver.nCols());
775 
776  m_solver.getBasis(rows, cols, m_solver.nRows(), m_solver.nCols());
777  m_simplifier->unsimplify(psp_x, psp_y, psp_s, psp_r, rows, cols);
778  }
779  catch( const SPxMemoryException& x)
780  {
781  spx_free(rows);
782  spx_free(cols);
783  throw x;
784  }
785 
786  spx_free(rows);
787  spx_free(cols);
788  }
789 }
790 } // namespace soplex