CouenneSolverInterface.cpp
Go to the documentation of this file.
1 /* $Id: CouenneSolverInterface.cpp 833 2012-02-11 14:09:50Z pbelotti $
2  *
3  * Name: CouenneSolverInterface.cpp
4  * Authors: Pietro Belotti, Carnegie Mellon University
5  * Andreas Waechter, IBM Corp.
6  * Purpose: Implementation of the OsiSolverInterface::resolve () method
7  *
8  * (C) Carnegie-Mellon University, 2006-09.
9  * This file is licensed under the Eclipse Public License (EPL)
10  */
11 
12 #include "OsiSolverInterface.hpp"
13 
14 #include "CouenneProblem.hpp"
15 #include "CouenneProblemElem.hpp"
16 #include "CouenneCutGenerator.hpp"
17 
18 #include "CouenneRecordBestSol.hpp"
19 
20 //#define FM_CHECK
21 
22 namespace Couenne {
23 
25 template <class T>
27 (CouenneCutGenerator *cg /*= NULL*/):
28 
29  T (),
30  cutgen_ (cg),
31  knowInfeasible_(false),
32  knowOptimal_(false),
33  knowDualInfeasible_(false)
34  // ,beforeFirstRootLP_ (true)
35  // ,rootLB_ (-COIN_DBL_MAX)
36 {}
37 
38 
40 template <class T>
43 
44  OsiSolverInterface (src),
45  T (src),
46  cutgen_ (src.cutgen_),
47  knowInfeasible_ (src.knowInfeasible_),
48  knowOptimal_ (src.knowOptimal_),
49  knowDualInfeasible_ (src.knowDualInfeasible_)
50  // ,beforeFirstRootLP_ (src.beforeFirstRootLP_)
51  // ,rootLB_ (src.rootLB_)
52 {}
53 
54 
56 template <class T>
58  // if (cutgen_)
59  // delete cutgen_;
60 }
61 
62 
64 template <class T>
66 
67  knowInfeasible_ =
68  knowOptimal_ =
69  knowDualInfeasible_ = false;
70 
71  T::initialSolve ();
72 
73  // if (beforeFirstRootLP_ && T::isProvenOptimal ()) {
74  // printf ("\n\nGot first LP: %g\n\n", getObjValue ());
75  // beforeFirstRootLP_ = false;
76  // rootLB_ = getObjValue ();
77  // }
78 
79  // printf ("init solution: (");
80  // for (int i=0; i< T::getNumCols (); i++)
81  // printf ("%g [%g,%g] ",
82  // T::getColSolution () [i],
83  // T::getColLower () [i],
84  // T::getColUpper () [i]);
85  // printf (")\n");
86 
87  if (getObjValue () <= - Couenne_large_bound)
88  knowDualInfeasible_ = true;
89 
90  // some originals may be unused due to their zero multiplicity (that
91  // happens when they are duplicates), restore their value
92  if (cutgen_ -> Problem () -> nUnusedOriginals () > 0) {
93  CouNumber *x = new CouNumber [T::getNumCols ()];
94  CoinCopyN (T::getColSolution (), T::getNumCols (), x);
95  cutgen_ -> Problem () -> restoreUnusedOriginals (x);
96  T::setColSolution (x);
97  delete [] x;
98  }
99 }
100 
101 template <class T>
103  return knowInfeasible_ || T::isProvenPrimalInfeasible();
104 }
105 
106 template <class T>
108  return knowOptimal_ || T::isProvenOptimal();
109 }
110 
111 template <class T>
113  return knowDualInfeasible_ || T::isProvenDualInfeasible();
114 }
115 
117 void sparse2dense (int, t_chg_bounds *, int *&, int &);
118 
119 
121 template <class T>
123 
124  static int count = -1;
125  char filename [30];
126 
127  // save problem to be loaded later
128  if (cutgen_ && (cutgen_ -> check_lp ())) {
129  count++;
130  sprintf (filename, "resolve_%d", count);
131  T::writeMps (filename);
132  }
133 
134  knowInfeasible_ =
135  knowOptimal_ =
136  knowDualInfeasible_ = false;
137 
138  const CoinWarmStart *ws = NULL;
139 
140  if (cutgen_ && (cutgen_ -> check_lp ()))
141  ws = T::getWarmStart ();
142 
143  //deleteScaleFactors ();
144 
145  // re-solve problem
146  T::resolve ();
147 
148  // printf ("solution: (");
149  // for (int i=0; i< T::getNumCols (); i++)
150  // printf ("%g ", T::getColSolution () [i]);
151  // printf (")\n");
152 
153  if (getObjValue () <= - Couenne_large_bound)
154  knowDualInfeasible_ = true;
155 
156  int objind = cutgen_ -> Problem () -> Obj (0) -> Body () -> Index ();
157 
158  CouNumber
159  //objval = T::getObjValue (),
160  curCutoff = cutgen_ -> Problem () -> getCutOff (),
161  objvalGlob = objind >= 0 ? T::getColSolution () [objind] : cutgen_ -> Problem () -> Obj (0) -> Body () -> Value ();
162 
163  // check if resolve found new integer solution
164  bool isChecked = false;
165 #ifdef FM_CHECKNLP2
166  double curBestVal = 1.e50;
167  if(cutgen_->Problem()->getRecordBestSol()->getHasSol()) {
168  curBestVal = cutgen_->Problem()->getRecordBestSol()->getVal();
169  }
170  curBestVal = (curBestVal < curCutoff ? curBestVal : curCutoff);
171  if(isProvenOptimal()) {
172  isChecked = cutgen_->Problem()->checkNLP2(T::getColSolution(),
173  curBestVal, false,
174  true, // stopAtFirstViol
175  true, // checkALL
176  cutgen_->Problem()->getFeasTol());
177  if(isChecked) {
178  objvalGlob = cutgen_->Problem()->getRecordBestSol()->getModSolVal();
179  if(!(objvalGlob < curBestVal - COUENNE_EPS)) {
180  isChecked = false;
181  }
182  }
183  }
184 
185 #ifdef FM_CHECK
186  bool ckIsChecked = false;
187  double ckObj = objvalGlob;
188  if(isProvenOptimal () &&
189  (objvalGlob < curCutoff - COUENNE_EPS)) {
190  ckIsChecked = cutgen_->Problem()->checkNLP(T::getColSolution (),
191  ckObj, true);
192  }
193  if(!isChecked && ckIsChecked) {
194  printf("CouenneSolverInterface::resolve(): ### ERROR: isChecked: false ckIsChecked: true\n");
195  exit(1);
196  }
197  else {
198  printf("CouenneSolverInterface::resolve(): isChecked == ckIsChecked\n");
199  }
200 #endif
201 
202 #else /* not FM_CHECKNLP2 */
203  if(isProvenOptimal () &&
204  (objvalGlob < curCutoff - COUENNE_EPS)) {
205  isChecked = cutgen_->Problem()->checkNLP(T::getColSolution (),
206  objvalGlob, true);
207  }
208 #endif /* not FM_CHECKNLP2 */
209 
210  if (//doingResolve () && // this is not called from strong branching
211  isChecked &&
212  (objvalGlob > -COUENNE_INFINITY/2)) { // check if it makes sense
213 
214  // also save the solution so that cbcModel::setBestSolution saves it too
215 
216  //printf ("new cutoff from CSI: %g\n", objval);
217  cutgen_ -> Problem () -> setCutOff (objvalGlob);
218 
219 #ifdef FM_TRACE_OPTSOL
220 #ifdef FM_CHECKNLP2
221  cutgen_->Problem()->getRecordBestSol()->update();
222 #else /* not FM_CHECKNLP2 */
223 
224  // some originals may be unused due to their zero multiplicity (that
225  // happens when they are duplicates), restore their value
226  if (cutgen_ -> Problem () -> nUnusedOriginals () > 0) {
227  CouNumber *x = new CouNumber [T::getNumCols ()];
228  CoinCopyN (T::getColSolution (), T::getNumCols (), x);
229  cutgen_ -> Problem () -> restoreUnusedOriginals (x);
230  T::setColSolution (x);
231  delete [] x;
232  }
233 
234  cutgen_->Problem()->getRecordBestSol()->update(T::getColSolution(),
235  cutgen_->Problem()->nVars(),
236  objvalGlob,
237  cutgen_->Problem()->getFeasTol());
238 #endif /* not FM_CHECKNLP2 */
239 #endif /* FM_TRACE_OPTSOL */
240 
241  }
242 
243  // check LP independently
244  if (cutgen_ && (cutgen_ -> check_lp ())) {
245 
246  OsiSolverInterface
247  *nsi = new T,
248  *csi = clone ();
249 
250  sprintf (filename, "resolve_%d.mps", count);
251  nsi -> readMps (filename);
252 
253  nsi -> messageHandler () -> setLogLevel (0);
254  nsi -> setWarmStart (ws);
255 
256  nsi -> initialSolve ();
257 
258  if ((nsi -> isProvenOptimal () && isProvenOptimal ()) ||
259  (!(nsi -> isProvenOptimal ()) && !isProvenOptimal ())) {
260 
261  if (nsi -> isProvenOptimal () &&
262  (fabs (nsi -> getObjValue () - T::getObjValue ()) /
263  (1. + fabs (nsi -> getObjValue ()) + fabs (T::getObjValue ())) > 1e-2))
264 
265  printf ("Warning: discrepancy between saved %g and current %g [%g], file %s\n",
266  nsi -> getObjValue (), T::getObjValue (),
267  nsi -> getObjValue () - T::getObjValue (),
268  filename);
269  }
270 
271  csi -> messageHandler () -> setLogLevel (0);
272  csi -> setWarmStart (ws);
273 
274  csi -> initialSolve ();
275 
276  if ((csi -> isProvenOptimal () && isProvenOptimal ()) ||
277  (!(csi -> isProvenOptimal ()) && !isProvenOptimal ())) {
278 
279  if (csi -> isProvenOptimal () &&
280  (fabs (csi -> getObjValue () - getObjValue ()) /
281  (1. + fabs (csi -> getObjValue ()) + fabs (getObjValue ())) > 1e-2))
282 
283  printf ("Warning: discrepancy between cloned %g and current %g [%g]\n",
284  csi -> getObjValue (), getObjValue (),
285  csi -> getObjValue () - getObjValue ());
286  }
287 
288  delete nsi;
289  delete csi;
290 
291  delete ws;
292 
293  //else printf ("Warning: discrepancy between statuses %s -- %s feasible\n",
294  //filename, isProvenOptimal () ? "current" : "saved");
295  }
296 }
297 
298 
300 template <class T>
302 {OsiSolverInterface::markHotStart ();} // OsiClpSolverInterface::markHotStart() seems not to work
303 
304 
306 template <class T>
308 {OsiSolverInterface::unmarkHotStart();}
309 
310 
312 template <class T>
314 
315  knowInfeasible_ =
316  knowOptimal_ =
317  knowDualInfeasible_ = false;
318 
319  resolve();
320 
321  if (getObjValue () <= - Couenne_large_bound)
322  knowDualInfeasible_ = true;
323 
324  // some originals may be unused due to their zero multiplicity (that
325  // happens when they are duplicates), restore their value
326  if (cutgen_ -> Problem () -> nUnusedOriginals () > 0) {
327  CouNumber *x = new CouNumber [T::getNumCols ()];
328  CoinCopyN (T::getColSolution (), T::getNumCols (), x);
329  cutgen_ -> Problem () -> restoreUnusedOriginals (x);
330  T::setColSolution (x);
331  delete [] x;
332  }
333 
334  if (isProvenPrimalInfeasible ()) knowInfeasible_ = true;
335  if (isProvenOptimal ()) knowOptimal_ = true;
336  if (isProvenDualInfeasible ()) knowDualInfeasible_ = true;
337 }
338 
341 template <class T>
343  return cutgen_ -> Problem () -> constObjVal () + T::getObjValue();
344 }
345 
346 }
Cut Generator for linear convexifications.
CouenneCutGenerator * cutgen_
The pointer to the Couenne cut generator.
virtual void unmarkHotStart()
Delete the hot start snapshot.
status of lower/upper bound of a variable, to be checked/modified in bound tightening ...
virtual void solveFromHotStart()
Optimize starting from the hot start snapshot.
const double Couenne_large_bound
used to declare LP unbounded
bool isProvenDualInfeasible() const
set doingResolve_
bool knowOptimal_
Flag indicating that optimality was detected during solveFromHotStart.
virtual double getObjValue() const
Get the objective function value.
virtual bool isProvenOptimal() const
we need to overwrite this since we might have internal knowledge
void sparse2dense(int ncols, t_chg_bounds *chg_bds, int *&changed, int &nchanged)
translate sparse to dense vector (should be replaced)
void fint fint fint real fint real real real real real real real real real * e
Solver interface class with a pointer to a Couenne cut generator.
#define COUENNE_EPS
void fint fint fint real fint real real real real real real real real real fint real fint fint fint real * ws
virtual void initialSolve()
Solve initial LP relaxation.
double CouNumber
main number type in Couenne
bool knowDualInfeasible_
Flag indicating this problem&#39;s continuous relaxation is unbounded.
#define COUENNE_INFINITY
CouenneSolverInterface(CouenneCutGenerator *cg=NULL)
Constructor.
virtual void resolve()
Resolve an LP relaxation after problem modification.
bool knowInfeasible_
Flag indicating that infeasibility was detected during solveFromHotStart.
virtual void markHotStart()
Create a hot start snapshot of the optimization process.
void fint fint fint real fint real * x
virtual bool isProvenPrimalInfeasible() const
we need to overwrite this since we might have internal knowledge