00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "OsiSolverInterface.hpp"
00013
00014 #include "CouenneProblem.hpp"
00015 #include "CouenneProblemElem.hpp"
00016 #include "CouenneCutGenerator.hpp"
00017
00018 #include "CouenneRecordBestSol.hpp"
00019
00020
00021
00022 namespace Couenne {
00023
00025 template <class T>
00026 CouenneSolverInterface<T>::CouenneSolverInterface
00027 (CouenneCutGenerator *cg ):
00028
00029 T (),
00030 cutgen_ (cg),
00031 knowInfeasible_(false),
00032 knowOptimal_(false),
00033 knowDualInfeasible_(false) {}
00034
00035
00036
00038 template <class T>
00039 CouenneSolverInterface<T>::CouenneSolverInterface
00040 (const CouenneSolverInterface &src):
00041
00042 OsiSolverInterface (src),
00043 T (src),
00044 cutgen_ (src.cutgen_),
00045 knowInfeasible_ (src.knowInfeasible_),
00046 knowOptimal_ (src.knowOptimal_),
00047 knowDualInfeasible_ (src.knowDualInfeasible_) {}
00048
00049
00051 template <class T>
00052 CouenneSolverInterface<T>::~CouenneSolverInterface () {
00053
00054
00055 }
00056
00057
00059 template <class T>
00060 void CouenneSolverInterface<T>::initialSolve () {
00061
00062 knowInfeasible_ =
00063 knowOptimal_ =
00064 knowDualInfeasible_ = false;
00065
00066 T::initialSolve ();
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 if (T::getObjValue () <= - Couenne_large_bound)
00077 knowDualInfeasible_ = true;
00078
00079
00080
00081 if (cutgen_ -> Problem () -> nUnusedOriginals () > 0) {
00082 CouNumber *x = new CouNumber [T::getNumCols ()];
00083 CoinCopyN (T::getColSolution (), T::getNumCols (), x);
00084 cutgen_ -> Problem () -> restoreUnusedOriginals (x);
00085 T::setColSolution (x);
00086 delete [] x;
00087 }
00088 }
00089
00090 template <class T>
00091 bool CouenneSolverInterface<T>::isProvenPrimalInfeasible() const {
00092 return knowInfeasible_ || T::isProvenPrimalInfeasible();
00093 }
00094
00095 template <class T>
00096 bool CouenneSolverInterface<T>::isProvenOptimal() const {
00097 return knowOptimal_ || T::isProvenOptimal();
00098 }
00099
00100 template <class T>
00101 bool CouenneSolverInterface<T>::isProvenDualInfeasible() const {
00102 return knowDualInfeasible_ || T::isProvenDualInfeasible();
00103 }
00104
00106 void sparse2dense (int, t_chg_bounds *, int *&, int &);
00107
00108
00110 template <class T>
00111 void CouenneSolverInterface<T>::resolve () {
00112
00113 static int count = -1;
00114 char filename [30];
00115
00116
00117 if (cutgen_ && (cutgen_ -> check_lp ())) {
00118 count++;
00119 sprintf (filename, "resolve_%d", count);
00120 T::writeMps (filename);
00121 }
00122
00123 knowInfeasible_ =
00124 knowOptimal_ =
00125 knowDualInfeasible_ = false;
00126
00127 const CoinWarmStart *ws = NULL;
00128
00129 if (cutgen_ && (cutgen_ -> check_lp ()))
00130 ws = T::getWarmStart ();
00131
00132
00133
00134
00135 T::resolve ();
00136
00137
00138
00139
00140
00141
00142 if (T::getObjValue () <= - Couenne_large_bound)
00143 knowDualInfeasible_ = true;
00144
00145 CouNumber
00146
00147 curCutoff = cutgen_ -> Problem () -> getCutOff (),
00148 objvalGlob = T::getColSolution () [cutgen_ -> Problem () -> Obj (0) -> Body () -> Index ()];
00149
00150
00151 bool isChecked = false;
00152 #ifdef FM_CHECKNLP2
00153 double curBestVal = 1e50;
00154 if(cutgen_->Problem()->getRecordBestSol()->getHasSol()) {
00155 curBestVal = cutgen_->Problem()->getRecordBestSol()->getVal();
00156 }
00157 curBestVal = (curBestVal < curCutoff ? curBestVal : curCutoff);
00158 if(isProvenOptimal()) {
00159 isChecked = cutgen_->Problem()->checkNLP2(T::getColSolution(),
00160 curBestVal, false,
00161 true,
00162 true,
00163 cutgen_->Problem()->getFeasTol());
00164 if(isChecked) {
00165 objvalGlob = cutgen_->Problem()->getRecordBestSol()->getModSolVal();
00166 if(!(objvalGlob < curBestVal - COUENNE_EPS)) {
00167 isChecked = false;
00168 }
00169 }
00170 }
00171
00172 #ifdef FM_CHECK
00173 bool ckIsChecked = false;
00174 double ckObj = objvalGlob;
00175 if(isProvenOptimal () &&
00176 (objvalGlob < curCutoff - COUENNE_EPS)) {
00177 ckIsChecked = cutgen_->Problem()->checkNLP(T::getColSolution (),
00178 ckObj, true);
00179 }
00180 if(!isChecked && ckIsChecked) {
00181 printf("CouenneSolverInterface::resolve(): ### ERROR: isChecked: false ckIsChecked: true\n");
00182 exit(1);
00183 }
00184 else {
00185 printf("CouenneSolverInterface::resolve(): isChecked == ckIsChecked\n");
00186 }
00187 #endif
00188
00189 #else
00190 if(isProvenOptimal () &&
00191 (objvalGlob < curCutoff - COUENNE_EPS)) {
00192 isChecked = cutgen_->Problem()->checkNLP(T::getColSolution (),
00193 objvalGlob, true);
00194 }
00195 #endif
00196
00197 if (
00198 isChecked &&
00199 (objvalGlob > -COUENNE_INFINITY/2)) {
00200
00201
00202
00203
00204 cutgen_ -> Problem () -> setCutOff (objvalGlob);
00205
00206 #ifdef FM_TRACE_OPTSOL
00207 #ifdef FM_CHECKNLP2
00208 cutgen_->Problem()->getRecordBestSol()->update();
00209 #else
00210
00211
00212
00213 if (cutgen_ -> Problem () -> nUnusedOriginals () > 0) {
00214 CouNumber *x = new CouNumber [T::getNumCols ()];
00215 CoinCopyN (T::getColSolution (), T::getNumCols (), x);
00216 cutgen_ -> Problem () -> restoreUnusedOriginals (x);
00217 T::setColSolution (x);
00218 delete [] x;
00219 }
00220
00221 cutgen_->Problem()->getRecordBestSol()->update(T::getColSolution(),
00222 cutgen_->Problem()->nVars(),
00223 objvalGlob,
00224 cutgen_->Problem()->getFeasTol());
00225 #endif
00226 #endif
00227
00228 }
00229
00230
00231 if (cutgen_ && (cutgen_ -> check_lp ())) {
00232
00233 OsiSolverInterface
00234 *nsi = new T,
00235 *csi = clone ();
00236
00237 sprintf (filename, "resolve_%d.mps", count);
00238 nsi -> readMps (filename);
00239
00240 nsi -> messageHandler () -> setLogLevel (0);
00241 nsi -> setWarmStart (ws);
00242
00243 nsi -> initialSolve ();
00244
00245 if ((nsi -> isProvenOptimal () && isProvenOptimal ()) ||
00246 (!(nsi -> isProvenOptimal ()) && !isProvenOptimal ())) {
00247
00248 if (nsi -> isProvenOptimal () &&
00249 (fabs (nsi -> getObjValue () - T::getObjValue ()) /
00250 (1. + fabs (nsi -> getObjValue ()) + fabs (T::getObjValue ())) > 1e-2))
00251
00252 printf ("Warning: discrepancy between saved %g and current %g [%g], file %s\n",
00253 nsi -> getObjValue (), T::getObjValue (),
00254 nsi -> getObjValue () - T::getObjValue (),
00255 filename);
00256 }
00257
00258 csi -> messageHandler () -> setLogLevel (0);
00259 csi -> setWarmStart (ws);
00260
00261 csi -> initialSolve ();
00262
00263 if ((csi -> isProvenOptimal () && isProvenOptimal ()) ||
00264 (!(csi -> isProvenOptimal ()) && !isProvenOptimal ())) {
00265
00266 if (csi -> isProvenOptimal () &&
00267 (fabs (csi -> getObjValue () - T::getObjValue ()) /
00268 (1. + fabs (csi -> getObjValue ()) + fabs (T::getObjValue ())) > 1e-2))
00269
00270 printf ("Warning: discrepancy between cloned %g and current %g [%g]\n",
00271 csi -> getObjValue (), T::getObjValue (),
00272 csi -> getObjValue () - T::getObjValue ());
00273 }
00274
00275 delete nsi;
00276 delete csi;
00277
00278 delete ws;
00279
00280
00281
00282 }
00283 }
00284
00285
00287 template <class T>
00288 void CouenneSolverInterface<T>::markHotStart ()
00289 {OsiSolverInterface::markHotStart ();}
00290
00291
00293 template <class T>
00294 void CouenneSolverInterface<T>::unmarkHotStart ()
00295 {OsiSolverInterface::unmarkHotStart();}
00296
00297
00299 template <class T>
00300 void CouenneSolverInterface<T>::solveFromHotStart () {
00301
00302 knowInfeasible_ =
00303 knowOptimal_ =
00304 knowDualInfeasible_ = false;
00305
00306 resolve();
00307
00308 if (T::getObjValue () <= - Couenne_large_bound)
00309 knowDualInfeasible_ = true;
00310
00311
00312
00313 if (cutgen_ -> Problem () -> nUnusedOriginals () > 0) {
00314 CouNumber *x = new CouNumber [T::getNumCols ()];
00315 CoinCopyN (T::getColSolution (), T::getNumCols (), x);
00316 cutgen_ -> Problem () -> restoreUnusedOriginals (x);
00317 T::setColSolution (x);
00318 delete [] x;
00319 }
00320
00321 if (isProvenPrimalInfeasible ()) knowInfeasible_ = true;
00322 if (isProvenOptimal ()) knowOptimal_ = true;
00323 if (isProvenDualInfeasible ()) knowDualInfeasible_ = true;
00324 }
00325
00326 }