SoPlex Doxygen Documentation
soplex.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-2012 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 "soplex.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 {
34  m_solver.setTester(new SPxFastRT(), true);
35  m_solver.setPricer(new SPxSteepPR(), true);
37 
38  assert(SoPlex::isConsistent());
39 }
40 
42 {
43  assert(!m_freePreScaler || m_preScaler != 0);
44  assert(!m_freePostScaler || m_postScaler != 0);
45  assert(!m_freeSimplifier || m_simplifier != 0);
46 
47  if(m_freePreScaler)
48  {
49  delete m_preScaler;
50  m_preScaler = 0;
51  }
52 
54  {
55  delete m_postScaler;
56  m_postScaler = 0;
57  }
58 
60  {
61  delete m_simplifier;
62  m_simplifier = 0;
63  }
64 }
65 
67 {
68  assert(!m_freePreScaler || m_preScaler != 0);
69  assert(!m_freePostScaler || m_postScaler != 0);
70  assert(!m_freeSimplifier || m_simplifier != 0);
71 
72  if(this != &base)
73  {
74  SPxLP::operator=(base);
75  m_slu = base.m_slu; // call of SLinSolver::clone() SPxBasis assignment operator not necessary (done by m_solver.setSolver(&m_slu) below)
76  m_solver = base.m_solver;
77  m_vanished = base.m_vanished;
79 
80  // m_preScaler
81  if(m_freePreScaler)
82  {
83  delete m_preScaler;
84  m_preScaler = 0;
85  }
86  if(base.m_preScaler == 0)
87  {
88  m_preScaler = 0;
89  m_freePreScaler = false;
90  }
91  else
92  {
93  m_preScaler = base.m_preScaler->clone();
94  m_freePreScaler = true;
95  }
96 
97  // m_postScaler
99  {
100  delete m_postScaler;
101  m_postScaler = 0;
102  }
103  if(base.m_postScaler == 0)
104  {
105  m_postScaler = 0;
106  m_freePostScaler = false;
107  }
108  else
109  {
110  m_postScaler = base.m_postScaler->clone();
111  m_freePostScaler = true;
112  }
113 
114  // m_simplifier
115  if(m_freeSimplifier)
116  {
117  delete m_simplifier;
118  m_simplifier = 0;
119  }
120  if(base.m_simplifier == 0)
121  {
122  m_simplifier = 0;
123  m_freeSimplifier = false;
124  }
125  else
126  {
127  m_simplifier = base.m_simplifier->clone();
128  m_freeSimplifier = true;
129  }
130 
131 
132  }
133 
134  return *this;
135 }
136 
137 
139  : SPxLP(old)
140  , m_slu(old.m_slu) // call of SLinSolver::clone() SPxBasis copy constructor not necessary (done by m_solver.setSolver(&m_slu) below)
141  , m_solver(old.m_solver)
142  , m_vanished(old.m_vanished)
143 {
145 
146  // m_preScaler
147  if(old.m_preScaler == 0)
148  {
149  m_preScaler = 0;
150  m_freePreScaler = false;
151  }
152  else
153  {
154  m_preScaler = old.m_preScaler->clone();
155  m_freePreScaler = true;
156  }
157 
158  // m_postScaler
159  if(old.m_postScaler == 0)
160  {
161  m_postScaler = 0;
162  m_freePostScaler = false;
163  }
164  else
165  {
167  m_freePostScaler = true;
168  }
169 
170  // m_simplifier
171  if(old.m_simplifier == 0)
172  {
173  m_simplifier = 0;
174  m_freeSimplifier = false;
175  }
176  else
177  {
179  m_freeSimplifier = true;
180  }
181 }
182 
183 
184 
185 void SoPlex::setPreScaler(SPxScaler* x, const bool destroy)
186 {
187  METHOD( "SoPlex::setPreScaler()" );
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  m_freePreScaler = destroy;
198 }
199 
200 void SoPlex::setPostScaler(SPxScaler* x, const bool destroy)
201 {
202  METHOD( "SoPlex::setPostScaler()" );
203 
204  assert(!m_freePostScaler || m_postScaler != 0);
205 
206  if(m_freePostScaler)
207  {
208  delete m_postScaler;
209  m_postScaler = 0;
210  }
211  m_postScaler = x;
212  m_freePostScaler = destroy;
213 }
214 
215 void SoPlex::setSimplifier(SPxSimplifier* x, const bool destroy)
216 {
217  METHOD( "SoPlex::setSimplifier()" );
218 
219  assert(!m_freeSimplifier || m_simplifier != 0);
220 
221  if(m_freeSimplifier)
222  {
223  delete m_simplifier;
224  m_simplifier = 0;
225  }
226  m_simplifier = x;
227  m_freeSimplifier = destroy;
228 }
229 
231 {
232  METHOD( "SoPlex::value()" );
233 
234  DVector x(nCols());
235 
236  getPrimal(x);
237 
238  return x * maxObj() * Real(spxSense());
239 }
240 
242 {
243  METHOD( "SoPlex::solve()" );
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 
254  // should the LP be scaled
255  if (m_preScaler != 0)
256  m_preScaler->scale(work);
257 
258  // should the LP be simplified ?
259  if (m_simplifier != 0)
260  {
262  {
265  return SPxSolver::UNBOUNDED;
268  return SPxSolver::INFEASIBLE;
270  m_vanished = true;
271  return SPxSolver::OPTIMAL;
272  case SPxSimplifier::OKAY:
273  break;
274  default:
275  throw SPxInternalCodeException("XRSOLVR01 This should never happen.");
276  }
277  }
278 
279  // should the LP be scaled after simplifing?
280  if (m_postScaler != 0)
281  m_postScaler->scale(work);
282 
283  /* if a basis of correct size was set externally, try to load it into the transformed LP */
284  if ( m_colsbasisstatus.size() == work.nCols() && m_rowsbasisstatus.size() == work.nRows() )
285  {
286  m_solver.loadLP(work);
288  {
289  m_solver.setBasis(m_rowsbasisstatus.get_const_ptr(), m_colsbasisstatus.get_const_ptr());
290  }
291  m_colsbasisstatus.clear();
292  m_rowsbasisstatus.clear();
293  }
294  /* if a basis with status at least REGULAR exists (loaded via readBasisFile()
295  * or available from previous simplex run), we check whether it can be (re)used
296  * for the newly loaded LP.
297  */
298  else if ( m_solver.basis().status() <= SPxBasis::SINGULAR )
299  {
300  m_solver.loadLP(work);
301  }
302  else
303  {
304  SPxBasis::Desc oldbasisdesc(m_solver.basis().desc());
305  m_solver.loadLP(work);
306  if(m_solver.basis().isDescValid(oldbasisdesc))
307  m_solver.loadBasis(oldbasisdesc);
308  }
309 
310  return m_solver.solve();
311 }
312 
314 {
315  METHOD( "SoPlex::getPrimal()" );
316 
317  if (has_simplifier())
318  {
320  unsimplify();
321 
323 
324  // unscale prescaling
325  if (m_preScaler != 0)
327 
328  if (m_vanished)
329  return SPxSolver::OPTIMAL;
330  else
331  return m_solver.status();
332  }
333 
334  // else
336 
337  // unscale postscaling
338  if (m_postScaler != 0)
340 
341  // unscale prescaling
342  if (m_preScaler != 0)
344 
345  return stat;
346 }
347 
349 {
350  METHOD( "SoPlex::getSlacks()" );
351 
352  if (has_simplifier())
353  {
355  unsimplify();
356 
358 
359  // unscale prescaling
360  if (m_preScaler != 0)
362 
363  if (m_vanished)
364  return SPxSolver::OPTIMAL;
365  else
366  return m_solver.status();
367  }
368 
369  // else
371 
372  // unscale postscaling
373  if (m_postScaler != 0)
375 
376  // unscale prescaling
377  if (m_preScaler != 0)
379 
380  return stat;
381 }
382 
384 {
385  METHOD( "SoPlex::getDual()" );
386 
387  if (has_simplifier())
388  {
390  unsimplify();
391 
393 
394  // unscale prescaling
395  if (m_preScaler != 0)
397 
398  if (m_vanished)
399  return SPxSolver::OPTIMAL;
400  else
401  return m_solver.status();
402  }
403 
404  // else
406 
407  // unscale postscaling
408  if (m_postScaler != 0)
410 
411  // unscale prescaling
412  if (m_preScaler != 0)
414 
415  return stat;
416 }
417 
419 {
420  METHOD( "SoPlex::getRedCost()" );
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( spxout << "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( spxout << "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 = fabs(val - lhs( row ));
583  else
584  if (val > rhs( row ))
585  viol = fabs(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 = fabs( solu[col] - lower( col ));
613  else
614  if (solu[col] > upper( col ))
615  viol = fabs( 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  MSG_DEBUG( thedesc.dump() );
698 
699  // Check that we covered all nonbasic rows - the remaining should be basic.
700  for( ; row < nRows(); row++ )
701  {
702  if( getBasisRowStatus(row) != SPxSolver::BASIC )
703  break;
704  }
705  assert(row == nRows());
706 
707  #endif // NDEBUG
708 
709  os << "ENDATA" << std::endl;
710  return true;
711 }
712 
714  const char* filename,
715  const NameSet* rowNames,
716  const NameSet* colNames ) const
717 {
718  METHOD( "SoPlex::writeState()" );
719 
720  return m_solver.writeState(filename, rowNames, colNames);
721 }
722 
723 void SoPlex::unsimplify() const
724 {
726  return;
727 
728  DVector psp_x(m_solver.nCols()); // primal solution (prescaled simplified postscaled)
729  DVector psp_y(m_solver.nRows()); // dual solution (prescaled simplified postscaled)
730  DVector psp_s(m_solver.nRows()); // slacks (prescaled simplified postscaled)
731  DVector psp_r(m_solver.nCols()); // reduced costs (prescaled simplified postscaled)
732 
733  if (! m_vanished) {
734  // If solver status is not regular or optimal, do nothing.
735  const SPxSolver::Status stat = status();
736  if( stat != SPxSolver::OPTIMAL && stat != SPxSolver::REGULAR )
737  return;
738 
739  m_solver.getPrimal(psp_x);
740  m_solver.getDual(psp_y);
741  m_solver.getSlacks(psp_s);
742  m_solver.getRedCost(psp_r);
743 
744  // unscale postscaling
745  if (m_postScaler != 0)
746  {
747  m_postScaler->unscalePrimal(psp_x);
748  m_postScaler->unscaleDual(psp_y);
749  m_postScaler->unscaleSlacks(psp_s);
751  }
752  }
753  else {
754  // If there is no sensible solution, do nothing.
755  const SPxSolver::Status stat = status();
756  if (stat != SPxSolver::OPTIMAL)
757  return;
758 
759  psp_x.reDim(0);
760  psp_y.reDim(0);
761  psp_s.reDim(0);
762  psp_r.reDim(0);
763  }
764 
765  // unsimplify
766  if(m_vanished)
767  {
768  m_simplifier->unsimplify(psp_x, psp_y, psp_s, psp_r, NULL, NULL);
769  }
770  else
771  {
772  SPxSolver::VarStatus *rows, *cols;
773  rows = NULL;
774  cols = NULL;
775  try
776  {
777  rows = new SPxSolver::VarStatus[m_solver.nRows()];
778  cols = new SPxSolver::VarStatus[m_solver.nCols()];
779 
780  m_solver.getBasis(rows, cols);
781  m_simplifier->unsimplify(psp_x, psp_y, psp_s, psp_r, rows, cols);
782  }
783  catch(std::bad_alloc& x)
784  {
785  delete[] rows;
786  delete[] cols;
787  throw x;
788  }
789 
790  delete[] rows;
791  delete[] cols;
792  }
793 }
794 } // namespace soplex
795 
796 //-----------------------------------------------------------------------------
797 //Emacs Local Variables:
798 //Emacs mode:c++
799 //Emacs c-basic-offset:3
800 //Emacs tab-width:8
801 //Emacs indent-tabs-mode:nil
802 //Emacs End:
803 //-----------------------------------------------------------------------------
804 
805 
806 
807 
808 
809 
810