source: trunk/Cbc/examples/interrupt.cpp

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

fixup svn properties

  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1// $Id: interrupt.cpp 1899 2013-04-09 18:12:08Z forrest $
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#include <cassert>
7#include <iomanip>
8
9
10#include "CoinPragma.hpp"
11#include "CbcModel.hpp"
12#include "OsiClpSolverInterface.hpp"
13#include "CbcSolver.hpp"
14
15#include "CoinTime.hpp"
16
17//#############################################################################
18
19
20/************************************************************************
21
22This main program shows how to take advantage of the standalone cbc in your program,
23while still making major modifications.
24This is very like driver4 but allows interrupts in clp for faster stopping
25It would be up to user to clean up output as stopping in Clp seems to
26give correct results but can think it is stopping in an odd way.
27To make cleaner would need more events defined (in Cbc AND Clp)
28First it reads in an integer model from an mps file
29Then it initializes the integer model with cbc defaults
30Then it calls CbcMain1 passing all parameters apart from first but with callBack to modify stuff
31Finally it prints solution
32
33************************************************************************/
34/* Meaning of whereFrom:
35   1 after initial solve by dualsimplex etc
36   2 after preprocessing
37   3 just before branchAndBound (so user can override)
38   4 just after branchAndBound (before postprocessing)
39   5 after postprocessing
40*/
41/* Meaning of model status is as normal
42   status
43      -1 before branchAndBound
44      0 finished - check isProvenOptimal or isProvenInfeasible to see if solution found
45      (or check value of best solution)
46      1 stopped - on maxnodes, maxsols, maxtime
47      2 difficulties so run was abandoned
48      (5 event user programmed event occurred)
49
50      cbc secondary status of problem
51        -1 unset (status_ will also be -1)
52        0 search completed with solution
53        1 linear relaxation not feasible (or worse than cutoff)
54        2 stopped on gap
55        3 stopped on nodes
56        4 stopped on time
57        5 stopped on user event
58        6 stopped on solutions
59        7 linear relaxation unbounded
60
61   but initially check if status is 0 and secondary status is 1 -> infeasible
62   or you can check solver status.
63*/
64/* Return non-zero to return quickly */   
65static int callBack(CbcModel * model, int whereFrom)
66{
67  int returnCode=0;
68  switch (whereFrom) {
69  case 1:
70  case 2:
71    if (!model->status()&&model->secondaryStatus())
72      returnCode=1;
73    break;
74  case 3:
75    {
76      //CbcCompareUser compare;
77      //model->setNodeComparison(compare);
78    }
79    break;
80  case 4:
81    // If not good enough could skip postprocessing
82    break;
83  case 5:
84    break;
85  default:
86    abort();
87  }
88  return returnCode;
89}
90#include "CbcEventHandler.hpp"
91static int cancelAsap=0;
92/*
93  0 - not yet in Cbc
94  1 - in Cbc with new signal handler
95  2 - ending Cbc
96*/
97static int statusOfCbc=0;
98#include "CoinSignal.hpp"
99static CoinSighandler_t saveSignal = static_cast<CoinSighandler_t> (0);
100
101extern "C" {
102     static void
103#if defined(_MSC_VER)
104     __cdecl
105#endif // _MSC_VER
106     signal_handler(int /*whichSignal*/)
107     {
108       cancelAsap=3;
109       return;
110     }
111}
112/** This is so user can trap events and do useful stuff. 
113
114    CbcModel model_ is available as well as anything else you care
115    to pass in
116*/
117
118class MyEventHandler3 : public CbcEventHandler {
119 
120public:
121  /**@name Overrides */
122  //@{
123  virtual CbcAction event(CbcEvent whichEvent);
124  //@}
125
126  /**@name Constructors, destructor etc*/
127  //@{
128  /** Default constructor. */
129  MyEventHandler3();
130  /// Constructor with pointer to model (redundant as setEventHandler does)
131  MyEventHandler3(CbcModel * model);
132  /** Destructor */
133  virtual ~MyEventHandler3();
134  /** The copy constructor. */
135  MyEventHandler3(const MyEventHandler3 & rhs);
136  /// Assignment
137  MyEventHandler3& operator=(const MyEventHandler3 & rhs);
138  /// Clone
139  virtual CbcEventHandler * clone() const ;
140  //@}
141   
142   
143protected:
144  // data goes here
145};
146//-------------------------------------------------------------------
147// Default Constructor
148//-------------------------------------------------------------------
149MyEventHandler3::MyEventHandler3 () 
150  : CbcEventHandler()
151{
152}
153
154//-------------------------------------------------------------------
155// Copy constructor
156//-------------------------------------------------------------------
157MyEventHandler3::MyEventHandler3 (const MyEventHandler3 & rhs) 
158: CbcEventHandler(rhs)
159{ 
160}
161
162// Constructor with pointer to model
163MyEventHandler3::MyEventHandler3(CbcModel * model)
164  : CbcEventHandler(model)
165{
166}
167
168//-------------------------------------------------------------------
169// Destructor
170//-------------------------------------------------------------------
171MyEventHandler3::~MyEventHandler3 ()
172{
173}
174
175//----------------------------------------------------------------
176// Assignment operator
177//-------------------------------------------------------------------
178MyEventHandler3 &
179MyEventHandler3::operator=(const MyEventHandler3& rhs)
180{
181  if (this != &rhs) {
182    CbcEventHandler::operator=(rhs);
183  }
184  return *this;
185}
186//-------------------------------------------------------------------
187// Clone
188//-------------------------------------------------------------------
189CbcEventHandler * MyEventHandler3::clone() const
190{
191  return new MyEventHandler3(*this);
192}
193
194CbcEventHandler::CbcAction
195MyEventHandler3::event(CbcEvent whichEvent)
196{
197  if(!statusOfCbc) {
198    // override signal handler
199    // register signal handler
200    saveSignal = signal(SIGINT, signal_handler);
201    statusOfCbc=1;
202  }
203  if ( (cancelAsap&2)!=0 ) {
204    printf("Cbc got cancel\n");
205    // switch off Clp cancel
206    cancelAsap &= 2;
207    return stop;
208  }
209  // If in sub tree carry on
210  if (!model_->parentModel()) {
211    if (whichEvent==endSearch&&statusOfCbc==1) {
212      // switch off cancel
213      cancelAsap=0;
214      // restore signal handler
215      signal(SIGINT, saveSignal);
216      statusOfCbc=2;
217    }
218    if (whichEvent==solution||whichEvent==heuristicSolution) {
219#ifdef STOP_EARLY
220      return stop; // say finished
221#else
222#ifdef WANT_SOLUTION
223      // If preprocessing was done solution will be to processed model
224      int numberColumns = model_->getNumCols();
225      const double * bestSolution = model_->bestSolution();
226      assert (bestSolution);
227      printf("value of solution is %g\n",model_->getObjValue());
228      for (int i=0;i<numberColumns;i++) {
229        if (fabs(bestSolution[i])>1.0e-8)
230          printf("%d %g\n",i,bestSolution[i]);
231      }
232#endif
233      return noAction; // carry on
234#endif
235    } else {
236      return noAction; // carry on
237    }
238  } else {
239      return noAction; // carry on
240  }
241}
242/** This is so user can trap events and do useful stuff. 
243
244    ClpSimplex model_ is available as well as anything else you care
245    to pass in
246*/
247
248class MyEventHandler4 : public ClpEventHandler {
249 
250public:
251  /**@name Overrides */
252  //@{
253  virtual int event(Event whichEvent);
254  //@}
255
256  /**@name Constructors, destructor etc*/
257  //@{
258  /** Default constructor. */
259  MyEventHandler4();
260  /// Constructor with pointer to model (redundant as setEventHandler does)
261  MyEventHandler4(ClpSimplex * model);
262  /** Destructor */
263  virtual ~MyEventHandler4();
264  /** The copy constructor. */
265  MyEventHandler4(const MyEventHandler4 & rhs);
266  /// Assignment
267  MyEventHandler4& operator=(const MyEventHandler4 & rhs);
268  /// Clone
269  virtual ClpEventHandler * clone() const ;
270  //@}
271   
272   
273protected:
274  // data goes here
275};
276//-------------------------------------------------------------------
277// Default Constructor
278//-------------------------------------------------------------------
279MyEventHandler4::MyEventHandler4 () 
280  : ClpEventHandler()
281{
282}
283
284//-------------------------------------------------------------------
285// Copy constructor
286//-------------------------------------------------------------------
287MyEventHandler4::MyEventHandler4 (const MyEventHandler4 & rhs) 
288: ClpEventHandler(rhs)
289{ 
290}
291
292// Constructor with pointer to model
293MyEventHandler4::MyEventHandler4(ClpSimplex * model)
294  : ClpEventHandler(model)
295{
296}
297
298//-------------------------------------------------------------------
299// Destructor
300//-------------------------------------------------------------------
301MyEventHandler4::~MyEventHandler4 ()
302{
303}
304
305//----------------------------------------------------------------
306// Assignment operator
307//-------------------------------------------------------------------
308MyEventHandler4 &
309MyEventHandler4::operator=(const MyEventHandler4& rhs)
310{
311  if (this != &rhs) {
312    ClpEventHandler::operator=(rhs);
313  }
314  return *this;
315}
316//-------------------------------------------------------------------
317// Clone
318//-------------------------------------------------------------------
319ClpEventHandler * MyEventHandler4::clone() const
320{
321  return new MyEventHandler4(*this);
322}
323
324int
325MyEventHandler4::event(Event whichEvent)
326{
327  if ( (cancelAsap&1)!=0 ) {
328    printf("Clp got cancel\n");
329    return 5;
330  } else {
331    return -1;
332  }
333}
334
335int main (int argc, const char *argv[])
336{
337
338  OsiClpSolverInterface solver1;
339  //#define USE_OSI_NAMES
340#ifdef USE_OSI_NAMES
341  // Say we are keeping names (a bit slower this way)
342  solver1.setIntParam(OsiNameDiscipline,1);
343#endif
344  // Read in model using argv[1]
345  // and assert that it is a clean model
346  std::string mpsFileName;
347#if defined(SAMPLEDIR)
348  mpsFileName = SAMPLEDIR "/p0033.mps";
349#else
350  if (argc < 2) {
351    fprintf(stderr, "Do not know where to find sample MPS files.\n");
352    exit(1);
353  }
354#endif
355  if (argc>=2) mpsFileName = argv[1];
356  int numMpsReadErrors = solver1.readMps(mpsFileName.c_str(),"");
357  if( numMpsReadErrors != 0 )
358  {
359     printf("%d errors reading MPS file\n", numMpsReadErrors);
360     return numMpsReadErrors;
361  }
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.