source: trunk/Cbc/examples/interrupt.cpp

Last change on this file was 2469, checked in by unxusr, 4 months ago

formatting

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