00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include "BonCouenneInterface.hpp"
00014 #include "CoinHelperFunctions.hpp"
00015
00016 #include "CouenneProblem.hpp"
00017 #include "CouenneProblemElem.hpp"
00018 #include "CouenneExprVar.hpp"
00019 #include "CouenneRecordBestSol.hpp"
00020
00021 using namespace Couenne;
00022
00024 CouenneInterface::CouenneInterface():
00025 AmplInterface(),
00026 have_nlp_solution_ (false)
00027 {}
00028
00030 CouenneInterface::CouenneInterface(const CouenneInterface &other):
00031 AmplInterface(other),
00032 have_nlp_solution_ (false)
00033 {}
00034
00036 CouenneInterface * CouenneInterface::clone(bool CopyData){
00037 return new CouenneInterface(*this);
00038 }
00039
00041 CouenneInterface::~CouenneInterface(){
00042 }
00043
00044 #ifdef COUENNEINTERFACE_FROM_ASL
00045 void
00046 CouenneInterface::readAmplNlFile(char **& argv, Ipopt::SmartPtr<Bonmin::RegisteredOptions> roptions,
00047 Ipopt::SmartPtr<Ipopt::OptionsList> options,
00048 Ipopt::SmartPtr<Ipopt::Journalist> journalist){
00049
00050
00051 AmplInterface::readAmplNlFile(argv, roptions, options, journalist);
00052 }
00053 #endif
00054
00067 void
00068 CouenneInterface::extractLinearRelaxation
00069 (OsiSolverInterface &si, CouenneCutGenerator & couenneCg, bool getObj, bool solveNlp) {
00070
00071 {
00072 int nlpLogLevel;
00073 options () -> GetIntegerValue ("nlp_log_level", nlpLogLevel, "couenne.");
00074 messageHandler () -> setLogLevel (nlpLogLevel);
00075 }
00076
00077 CouenneProblem *p = couenneCg.Problem ();
00078 bool is_feasible = true;
00079
00080 if (solveNlp) {
00081
00082 int nvars = p -> nVars();
00083
00084 if (p -> doFBBT ()) {
00085
00086
00087
00088
00089 for (int i=0; i < p -> nCons (); i++) {
00090
00091
00092 CouenneConstraint *con = p -> Con (i);
00093
00094
00095 int index = con -> Body () -> Index ();
00096
00097 if ((index >= 0) && (con -> Body () -> Type () == AUX)) {
00098
00099
00100 CouNumber
00101 l = con -> Lb () -> Value (),
00102 u = con -> Ub () -> Value ();
00103
00104
00105 p -> Lb (index) = CoinMax (l, p -> Lb (index));
00106 p -> Ub (index) = CoinMin (u, p -> Ub (index));
00107 }
00108 }
00109
00110 t_chg_bounds *chg_bds = new t_chg_bounds [nvars];
00111
00112 for (int i=0; i<nvars; i++) {
00113 chg_bds [i].setLower(t_chg_bounds::CHANGED);
00114 chg_bds [i].setUpper(t_chg_bounds::CHANGED);
00115 }
00116
00117 if (!(p -> boundTightening (chg_bds, CglTreeInfo (), NULL))) {
00118 is_feasible = false;
00119
00120 }
00121
00122 delete [] chg_bds;
00123
00124 const double
00125 *nlb = getColLower (),
00126 *nub = getColUpper ();
00127
00128 for (int i=0; i < p -> nOrigVars () - p -> nDefVars (); i++)
00129 if (p -> Var (i) -> Multiplicity () > 0) {
00130
00131
00132
00133
00134 double
00135 lower = nlb [i],
00136 upper = nub [i];
00137
00138 if (lower > upper) CoinSwap (lower, upper);
00139 if (p -> Lb (i) > p -> Ub (i)) CoinSwap (p -> Lb (i), p -> Ub (i));
00140
00141 if (lower < p -> Lb (i) - COUENNE_EPS) setColLower (i, CoinMin (nub[i], p -> Lb (i)));
00142 if (upper > p -> Ub (i) + COUENNE_EPS) setColUpper (i, CoinMax (nlb[i], p -> Ub (i)));
00143
00144 } else {
00145
00146 setColLower (i, -COIN_DBL_MAX);
00147 setColUpper (i, COIN_DBL_MAX);
00148 }
00149 }
00150
00151 if (is_feasible) {
00152 try {
00153 options () -> SetNumericValue ("max_cpu_time", CoinMax (0.1, (p -> getMaxCpuTime () - CoinCpuTime ()) / 2));
00154
00155 initialSolve ();
00156
00157 if (isDualObjectiveLimitReached() &&
00158 (getNumIntegers () == 0))
00159 *messageHandler () << "Couenne: Warning, NLP is unbounded" << CoinMessageEol;
00160 }
00161 catch (Bonmin::TNLPSolver::UnsolvedError *E) {
00162
00163
00164 }
00165 }
00166
00167 if (!is_feasible) {
00168 OsiAuxInfo * auxInfo = si.getAuxiliaryInfo ();
00169 Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (auxInfo);
00170
00171 if (babInfo)
00172 babInfo -> setInfeasibleNode ();
00173 }
00174
00175 if (is_feasible && isProvenOptimal ()) {
00176
00177 CouNumber obj = getObjValue ();
00178 const CouNumber *solution = getColSolution ();
00179
00180 if (getNumIntegers () > 0) {
00181
00182 int
00183 norig = p -> nOrigVars () - p -> nDefVars (),
00184 nvars = p -> nVars ();
00185
00186 bool fractional = false;
00187
00188
00189
00190
00191 for (int i=0; i<norig; i++)
00192 if ((p -> Var (i) -> Multiplicity () > 0) &&
00193 p -> Var (i) -> isDefinedInteger () &&
00194 (!::isInteger (solution [i]))) {
00195 fractional = true;
00196 break;
00197 }
00198
00199 if (fractional) {
00200
00201 double
00202 *lbSave = new double [norig],
00203 *ubSave = new double [norig],
00204
00205 *lbCur = new double [nvars],
00206 *ubCur = new double [nvars],
00207
00208 *Y = new double [nvars];
00209
00210 CoinCopyN (getColLower (), norig, lbSave);
00211 CoinCopyN (getColUpper (), norig, ubSave);
00212
00213 CoinFillN (Y, nvars, 0.);
00214 CoinFillN (lbCur, nvars, -COUENNE_INFINITY);
00215 CoinFillN (ubCur, nvars, COUENNE_INFINITY);
00216
00217 CoinCopyN (getColLower (), norig, lbCur);
00218 CoinCopyN (getColUpper (), norig, ubCur);
00219
00220 if (p -> getIntegerCandidate (solution, Y, lbCur, ubCur) >= 0) {
00221
00222 for (int i = getNumCols (); i--;) {
00223
00224 if (lbCur [i] > ubCur [i])
00225 CoinSwap (lbCur [i], ubCur [i]);
00226
00227 if (Y [i] < lbCur [i]) Y [i] = lbCur [i];
00228 else if (Y [i] > ubCur [i]) Y [i] = ubCur [i];
00229 }
00230
00231 for (int i=0; i<norig; i++)
00232 if ((p -> Var (i) -> Multiplicity () > 0) &&
00233 p -> Var (i) -> isDefinedInteger ()) {
00234
00235 setColLower (i, lbCur [i]);
00236 setColUpper (i, ubCur [i]);
00237 }
00238
00239 setColSolution (Y);
00240
00241 try {
00242 options () -> SetNumericValue ("max_cpu_time", CoinMax (0.1, p -> getMaxCpuTime () - CoinCpuTime ()));
00243
00244 resolve ();
00245
00246 if (isDualObjectiveLimitReached() &&
00247 (getNumIntegers () == 0))
00248 *messageHandler () << "Couenne: Warning, NLP is is unbounded" << CoinMessageEol;
00249 }
00250 catch (Bonmin::TNLPSolver::UnsolvedError *E) {
00251 }
00252
00253
00254
00255 obj = getObjValue ();
00256 solution = getColSolution ();
00257
00258
00259 for (int i=0; i<norig; i++)
00260 if ((p -> Var (i) -> Multiplicity () > 0) &&
00261 p -> Var (i) -> isDefinedInteger ()) {
00262
00263 if (lbSave [i] > ubSave [i])
00264 CoinSwap (lbSave [i], ubSave [i]);
00265
00266 setColLower (i, lbSave [i]);
00267 setColUpper (i, ubSave [i]);
00268 }
00269 }
00270
00271 delete [] Y;
00272 delete [] lbSave;
00273 delete [] ubSave;
00274 delete [] lbCur;
00275 delete [] ubCur;
00276 }
00277 }
00278
00279
00280 if (isProvenOptimal () &&
00281
00282
00283 #ifdef FM_CHECKNLP2
00284 (p->checkNLP2(solution, 0, false, true, false, p->getFeasTol())) &&
00285 (p->getRecordBestSol()->getModSolVal() < p->getCutOff())
00286 #else
00287 p -> checkNLP (solution, obj, true) &&
00288 (obj < p -> getCutOff ())
00289 #endif
00290 ) {
00291
00292
00293 have_nlp_solution_ = true;
00294
00295
00296
00297 #ifdef FM_CHECKNLP2
00298 obj = p->getRecordBestSol()->getModSolVal();
00299 #endif
00300
00301 p -> setCutOff (obj, solution);
00302
00303 OsiAuxInfo * auxInfo = si.getAuxiliaryInfo ();
00304 Bonmin::BabInfo * babInfo = dynamic_cast <Bonmin::BabInfo *> (auxInfo);
00305
00306 if (babInfo) {
00307
00308 #ifdef FM_CHECKNLP2
00309 babInfo -> setNlpSolution (p->getRecordBestSol()->modSol,
00310 getNumCols(), obj);
00311 #else
00312 babInfo -> setNlpSolution (solution, getNumCols (), obj);
00313 #endif
00314 babInfo -> setHasNlpSolution (true);
00315 }
00316
00317 #ifdef FM_TRACE_OPTSOL
00318 #ifdef FM_CHECKNLP2
00319 p->getRecordBestSol()->update();
00320 #else
00321 p->getRecordBestSol()->update(solution, getNumCols(),
00322 obj, p->getFeasTol());
00323 #endif
00324 #endif
00325
00326 }
00327 } else {
00328
00329
00330 }
00331 }
00332
00333 if (!is_feasible)
00334 return;
00335
00336 int
00337 numcols = p -> nOrigVars (),
00338 numcolsconv = p -> nVars ();
00339
00340 const double
00341 *lb = p -> Lb (),
00342 *ub = p -> Ub ();
00343
00344
00345 for (int i=0; i<numcols; i++)
00346 if (p -> Var (i) -> Multiplicity () > 0) si.addCol (0, NULL,NULL, lb [i], ub [i], 0);
00347 else si.addCol (0, NULL,NULL, -COIN_DBL_MAX,COIN_DBL_MAX,0);
00348 for (int i=numcols; i<numcolsconv; i++) si.addCol (0, NULL,NULL, -COIN_DBL_MAX,COIN_DBL_MAX,0);
00349
00350
00351 OsiCuts cs;
00352 couenneCg.generateCuts (si, cs);
00353
00354
00355 CouNumber * colLower = new CouNumber [numcolsconv];
00356 CouNumber * colUpper = new CouNumber [numcolsconv];
00357
00358 CouNumber *ll = p -> Lb ();
00359 CouNumber *uu = p -> Ub ();
00360
00361
00362 for (int i = numcolsconv; i--;)
00363 if (p -> Var (i) -> Multiplicity () > 0) {
00364 colLower [i] = (ll [i] > - COUENNE_INFINITY) ? ll [i] : -COIN_DBL_MAX;
00365 colUpper [i] = (uu [i] < COUENNE_INFINITY) ? uu [i] : COIN_DBL_MAX;
00366 } else {
00367 colLower [i] = -COIN_DBL_MAX;
00368 colUpper [i] = COIN_DBL_MAX;
00369 }
00370
00371 int numrowsconv = cs.sizeRowCuts ();
00372
00373
00374 CoinBigIndex * start = new CoinBigIndex [numrowsconv + 1];
00375
00376 int * length = new int [numrowsconv];
00377 double * rowLower = new double [numrowsconv];
00378 double * rowUpper = new double [numrowsconv];
00379
00380 start[0] = 0;
00381 int nnz = 0;
00382
00383 for(int i = 0 ; i < numrowsconv ; i++)
00384 {
00385 OsiRowCut * cut = cs.rowCutPtr (i);
00386
00387 const CoinPackedVector &v = cut->row();
00388 start[i+1] = start[i] + v.getNumElements();
00389 nnz += v.getNumElements();
00390 length[i] = v.getNumElements();
00391
00392 rowLower[i] = cut->lb();
00393 rowUpper[i] = cut->ub();
00394 }
00395
00396 assert (nnz == start [numrowsconv]);
00397
00398 int * ind = new int[start[numrowsconv]];
00399 double * elem = new double[start[numrowsconv]];
00400 for(int i = 0 ; i < numrowsconv ; i++) {
00401
00402 OsiRowCut * cut = cs.rowCutPtr (i);
00403
00404 const CoinPackedVector &v = cut->row();
00405
00406 if(v.getNumElements() != length[i])
00407 std::cout<<"Empty row"<<std::endl;
00408
00409 CoinCopyN (v.getIndices(), length[i], ind + start[i]);
00410 CoinCopyN (v.getElements(), length[i], elem + start[i]);
00411 }
00412
00413
00414 CoinPackedMatrix A;
00415 A.assignMatrix(false, numcolsconv, numrowsconv,
00416 start[numrowsconv], elem, ind,
00417 start, length);
00418 if(A.getNumCols() != numcolsconv || A.getNumRows() != numrowsconv){
00419 std::cout<<"Error in row number"<<std::endl;
00420 }
00421 assert(A.getNumElements() == nnz);
00422
00423 double * obj = new double[numcolsconv];
00424 CoinFillN(obj,numcolsconv,0.);
00425
00426
00427 if (p -> nObjs () > 0)
00428 p -> fillObjCoeff (obj);
00429
00430
00431 si.loadProblem (A, colLower, colUpper, obj, rowLower, rowUpper);
00432
00433 delete [] rowLower;
00434 delete [] rowUpper;
00435 delete [] colLower;
00436 delete [] colUpper;
00437 delete [] obj;
00438
00439 for (int i=0; i<numcolsconv; i++)
00440 if ((p -> Var (i) -> Multiplicity () > 0) &&
00441 (p -> Var (i) -> isDefinedInteger ()))
00442 si.setInteger (i);
00443
00444
00445
00446 app_ -> enableWarmStart();
00447
00448
00449 if (problem () -> x_sol ()) {
00450 setColSolution (problem () -> x_sol ());
00451 setRowPrice (problem () -> duals_sol ());
00452 }
00453 }
00454
00455
00457 void CouenneInterface::setAppDefaultOptions(Ipopt::SmartPtr<Ipopt::OptionsList> Options){
00458 Options->SetStringValue("bonmin.algorithm", "B-Couenne", true, true);
00459 Options->SetIntegerValue("bonmin.filmint_ecp_cuts", 1, true, true);
00460 }
00461