source: stable/2.8/Cbc/examples/interrupt.cpp @ 1873

Last change on this file since 1873 was 1873, checked in by stefan, 6 years ago

sync with trunk rev 1872

File size: 12.3 KB
Line 
1// $Id: interrupt.cpp 1854 2013-01-28 00:02:55Z stefan $
2// Copyright (C) 2007, International Business Machines
3// Corporation and others.  All Rights Reserved.
4// This code is licensed under the terms of the Eclipse Public License (EPL).
5
6#if defined(_MSC_VER)
7// Turn off compiler warning about long names
8#  pragma warning(disable:4786)
9#endif
10
11#include <cassert>
12#include <iomanip>
13
14
15#include "CbcModel.hpp"
16#include "OsiClpSolverInterface.hpp"
17#include "CbcSolver.hpp"
18
19#include  "CoinTime.hpp"
20
21//#############################################################################
22
23
24/************************************************************************
25
26This main program shows how to take advantage of the standalone cbc in your program,
27while still making major modifications.
28This is very like driver4 but allows interrupts in clp for faster stopping
29It would be up to user to clean up output as stopping in Clp seems to
30give correct results but can think it is stopping in an odd way.
31To make cleaner would need more events defined (in Cbc AND Clp)
32First it reads in an integer model from an mps file
33Then it initializes the integer model with cbc defaults
34Then it calls CbcMain1 passing all parameters apart from first but with callBack to modify stuff
35Finally it prints solution
36
37************************************************************************/
38/* Meaning of whereFrom:
39   1 after initial solve by dualsimplex etc
40   2 after preprocessing
41   3 just before branchAndBound (so user can override)
42   4 just after branchAndBound (before postprocessing)
43   5 after postprocessing
44*/
45/* Meaning of model status is as normal
46   status
47      -1 before branchAndBound
48      0 finished - check isProvenOptimal or isProvenInfeasible to see if solution found
49      (or check value of best solution)
50      1 stopped - on maxnodes, maxsols, maxtime
51      2 difficulties so run was abandoned
52      (5 event user programmed event occurred)
53
54      cbc secondary status of problem
55        -1 unset (status_ will also be -1)
56        0 search completed with solution
57        1 linear relaxation not feasible (or worse than cutoff)
58        2 stopped on gap
59        3 stopped on nodes
60        4 stopped on time
61        5 stopped on user event
62        6 stopped on solutions
63        7 linear relaxation unbounded
64
65   but initially check if status is 0 and secondary status is 1 -> infeasible
66   or you can check solver status.
67*/
68/* Return non-zero to return quickly */   
69static int callBack(CbcModel * model, int whereFrom)
70{
71  int returnCode=0;
72  switch (whereFrom) {
73  case 1:
74  case 2:
75    if (!model->status()&&model->secondaryStatus())
76      returnCode=1;
77    break;
78  case 3:
79    {
80      //CbcCompareUser compare;
81      //model->setNodeComparison(compare);
82    }
83    break;
84  case 4:
85    // If not good enough could skip postprocessing
86    break;
87  case 5:
88    break;
89  default:
90    abort();
91  }
92  return returnCode;
93}
94#include "CbcEventHandler.hpp"
95static int cancelAsap=0;
96/*
97  0 - not yet in Cbc
98  1 - in Cbc with new signal handler
99  2 - ending Cbc
100*/
101static int statusOfCbc=0;
102#include "CoinSignal.hpp"
103static CoinSighandler_t saveSignal = static_cast<CoinSighandler_t> (0);
104
105extern "C" {
106     static void
107#if defined(_MSC_VER)
108     __cdecl
109#endif // _MSC_VER
110     signal_handler(int /*whichSignal*/)
111     {
112       cancelAsap=3;
113       return;
114     }
115}
116/** This is so user can trap events and do useful stuff. 
117
118    CbcModel model_ is available as well as anything else you care
119    to pass in
120*/
121
122class MyEventHandler3 : public CbcEventHandler {
123 
124public:
125  /**@name Overrides */
126  //@{
127  virtual CbcAction event(CbcEvent whichEvent);
128  //@}
129
130  /**@name Constructors, destructor etc*/
131  //@{
132  /** Default constructor. */
133  MyEventHandler3();
134  /// Constructor with pointer to model (redundant as setEventHandler does)
135  MyEventHandler3(CbcModel * model);
136  /** Destructor */
137  virtual ~MyEventHandler3();
138  /** The copy constructor. */
139  MyEventHandler3(const MyEventHandler3 & rhs);
140  /// Assignment
141  MyEventHandler3& operator=(const MyEventHandler3 & rhs);
142  /// Clone
143  virtual CbcEventHandler * clone() const ;
144  //@}
145   
146   
147protected:
148  // data goes here
149};
150//-------------------------------------------------------------------
151// Default Constructor
152//-------------------------------------------------------------------
153MyEventHandler3::MyEventHandler3 () 
154  : CbcEventHandler()
155{
156}
157
158//-------------------------------------------------------------------
159// Copy constructor
160//-------------------------------------------------------------------
161MyEventHandler3::MyEventHandler3 (const MyEventHandler3 & rhs) 
162: CbcEventHandler(rhs)
163{ 
164}
165
166// Constructor with pointer to model
167MyEventHandler3::MyEventHandler3(CbcModel * model)
168  : CbcEventHandler(model)
169{
170}
171
172//-------------------------------------------------------------------
173// Destructor
174//-------------------------------------------------------------------
175MyEventHandler3::~MyEventHandler3 ()
176{
177}
178
179//----------------------------------------------------------------
180// Assignment operator
181//-------------------------------------------------------------------
182MyEventHandler3 &
183MyEventHandler3::operator=(const MyEventHandler3& rhs)
184{
185  if (this != &rhs) {
186    CbcEventHandler::operator=(rhs);
187  }
188  return *this;
189}
190//-------------------------------------------------------------------
191// Clone
192//-------------------------------------------------------------------
193CbcEventHandler * MyEventHandler3::clone() const
194{
195  return new MyEventHandler3(*this);
196}
197
198CbcEventHandler::CbcAction
199MyEventHandler3::event(CbcEvent whichEvent)
200{
201  if(!statusOfCbc) {
202    // override signal handler
203    // register signal handler
204    saveSignal = signal(SIGINT, signal_handler);
205    statusOfCbc=1;
206  }
207  if ( (cancelAsap&2)!=0 ) {
208    printf("Cbc got cancel\n");
209    // switch off Clp cancel
210    cancelAsap &= 2;
211    return stop;
212  }
213  // If in sub tree carry on
214  if (!model_->parentModel()) {
215    if (whichEvent==endSearch&&statusOfCbc==1) {
216      // switch off cancel
217      cancelAsap=0;
218      // restore signal handler
219      signal(SIGINT, saveSignal);
220      statusOfCbc=2;
221    }
222    if (whichEvent==solution||whichEvent==heuristicSolution) {
223#ifdef STOP_EARLY
224      return stop; // say finished
225#else
226#ifdef WANT_SOLUTION
227      // If preprocessing was done solution will be to processed model
228      int numberColumns = model_->getNumCols();
229      const double * bestSolution = model_->bestSolution();
230      assert (bestSolution);
231      printf("value of solution is %g\n",model_->getObjValue());
232      for (int i=0;i<numberColumns;i++) {
233        if (fabs(bestSolution[i])>1.0e-8)
234          printf("%d %g\n",i,bestSolution[i]);
235      }
236#endif
237      return noAction; // carry on
238#endif
239    } else {
240      return noAction; // carry on
241    }
242  } else {
243      return noAction; // carry on
244  }
245}
246/** This is so user can trap events and do useful stuff. 
247
248    ClpSimplex model_ is available as well as anything else you care
249    to pass in
250*/
251
252class MyEventHandler4 : public ClpEventHandler {
253 
254public:
255  /**@name Overrides */
256  //@{
257  virtual int event(Event whichEvent);
258  //@}
259
260  /**@name Constructors, destructor etc*/
261  //@{
262  /** Default constructor. */
263  MyEventHandler4();
264  /// Constructor with pointer to model (redundant as setEventHandler does)
265  MyEventHandler4(ClpSimplex * model);
266  /** Destructor */
267  virtual ~MyEventHandler4();
268  /** The copy constructor. */
269  MyEventHandler4(const MyEventHandler4 & rhs);
270  /// Assignment
271  MyEventHandler4& operator=(const MyEventHandler4 & rhs);
272  /// Clone
273  virtual ClpEventHandler * clone() const ;
274  //@}
275   
276   
277protected:
278  // data goes here
279};
280//-------------------------------------------------------------------
281// Default Constructor
282//-------------------------------------------------------------------
283MyEventHandler4::MyEventHandler4 () 
284  : ClpEventHandler()
285{
286}
287
288//-------------------------------------------------------------------
289// Copy constructor
290//-------------------------------------------------------------------
291MyEventHandler4::MyEventHandler4 (const MyEventHandler4 & rhs) 
292: ClpEventHandler(rhs)
293{ 
294}
295
296// Constructor with pointer to model
297MyEventHandler4::MyEventHandler4(ClpSimplex * model)
298  : ClpEventHandler(model)
299{
300}
301
302//-------------------------------------------------------------------
303// Destructor
304//-------------------------------------------------------------------
305MyEventHandler4::~MyEventHandler4 ()
306{
307}
308
309//----------------------------------------------------------------
310// Assignment operator
311//-------------------------------------------------------------------
312MyEventHandler4 &
313MyEventHandler4::operator=(const MyEventHandler4& rhs)
314{
315  if (this != &rhs) {
316    ClpEventHandler::operator=(rhs);
317  }
318  return *this;
319}
320//-------------------------------------------------------------------
321// Clone
322//-------------------------------------------------------------------
323ClpEventHandler * MyEventHandler4::clone() const
324{
325  return new MyEventHandler4(*this);
326}
327
328int
329MyEventHandler4::event(Event whichEvent)
330{
331  if ( (cancelAsap&1)!=0 ) {
332    printf("Clp got cancel\n");
333    return 5;
334  } else {
335    return -1;
336  }
337}
338
339int main (int argc, const char *argv[])
340{
341
342  OsiClpSolverInterface solver1;
343  //#define USE_OSI_NAMES
344#ifdef USE_OSI_NAMES
345  // Say we are keeping names (a bit slower this way)
346  solver1.setIntParam(OsiNameDiscipline,1);
347#endif
348  // Read in model using argv[1]
349  // and assert that it is a clean model
350  std::string mpsFileName;
351#if defined(SAMPLEDIR)
352  mpsFileName = SAMPLEDIR "/p0033.mps";
353#else
354  if (argc < 2) {
355    fprintf(stderr, "Do not know where to find sample MPS files.\n");
356    exit(1);
357  }
358#endif
359  if (argc>=2) mpsFileName = argv[1];
360  int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),"");
361  assert(numMpsReadErrors==0);
362  // Tell solver to return fast if presolve or initial solve infeasible
363  solver1.getModelPtr()->setMoreSpecialOptions(3);
364  // allow Clp to handle interrupts
365  MyEventHandler4 clpEventHandler;
366  solver1.getModelPtr()->passInEventHandler(&clpEventHandler);
367
368  /* Two ways of doing this depending on whether NEW_STYLE_SOLVER defined.
369     So we need pointer to model.  Old way could use modelA. rather than model->
370   */
371  // Messy code below copied from CbcSolver.cpp
372#if NEW_STYLE_SOLVER==0
373  // Pass to Cbc initialize defaults
374  CbcModel modelA(solver1);
375  CbcModel * model = &modelA;
376  CbcMain0(modelA);
377  // Event handler
378  MyEventHandler3 eventHandler;
379  model->passInEventHandler(&eventHandler);
380  /* Now go into code for standalone solver
381     Could copy arguments and add -quit at end to be safe
382     but this will do
383  */
384  if (argc>2) {
385    CbcMain1(argc-1,argv+1,modelA,callBack);
386  } else {
387    const char * argv2[]={"driver4","-solve","-quit"};
388    CbcMain1(3,argv2,modelA,callBack);
389  }
390#else
391  CbcSolver control(solver1);
392  // initialize
393  control.fillValuesInSolver();
394  // Event handler
395  MyEventHandler3 eventHandler;
396  CbcModel * model = control.model();
397  model->passInEventHandler(&eventHandler);
398  control.solve (argc-1, argv+1, 1);
399#endif
400  // Solver was cloned so get current copy
401  OsiSolverInterface * solver = model->solver();
402  // Print solution if finished (could get from model->bestSolution() as well
403
404  if (model->bestSolution()) {
405   
406    const double * solution = solver->getColSolution();
407   
408    int iColumn;
409    int numberColumns = solver->getNumCols();
410    std::cout<<std::setiosflags(std::ios::fixed|std::ios::showpoint)<<std::setw(14);
411   
412    std::cout<<"--------------------------------------"<<std::endl;
413#ifdef USE_OSI_NAMES
414   
415    for (iColumn=0;iColumn<numberColumns;iColumn++) {
416      double value=solution[iColumn];
417      if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) 
418        std::cout<<std::setw(6)<<iColumn<<" "<<std::setw(8)<<setiosflags(std::ios::left)<<solver->getColName(iColumn)
419                 <<resetiosflags(std::ios::adjustfield)<<std::setw(14)<<" "<<value<<std::endl;
420    }
421#else
422    // names may not be in current solver - use original
423   
424    for (iColumn=0;iColumn<numberColumns;iColumn++) {
425      double value=solution[iColumn];
426      if (fabs(value)>1.0e-7&&solver->isInteger(iColumn)) 
427        std::cout<<std::setw(6)<<iColumn<<" "<<std::setw(8)<<setiosflags(std::ios::left)<<solver1.getModelPtr()->columnName(iColumn)
428                 <<resetiosflags(std::ios::adjustfield)<<std::setw(14)<<" "<<value<<std::endl;
429    }
430#endif
431    std::cout<<"--------------------------------------"<<std::endl;
432 
433    std::cout<<std::resetiosflags(std::ios::fixed|std::ios::showpoint|std::ios::scientific);
434  } else {
435    std::cout<<" No solution!"<<std::endl;
436  }
437  return 0;
438}   
Note: See TracBrowser for help on using the repository browser.