00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "CouenneProblem.hpp"
00011 #include "CouenneFeasPump.hpp"
00012 #include "CouenneExprVar.hpp"
00013
00014 #include "cons_rowcuts.h"
00015
00016 using namespace Couenne;
00017
00018 #ifdef COIN_HAS_SCIP
00019
00020
00021 #include "scip/scip.h"
00022 #include "scip/cons_linear.h"
00023 #include "scip/scipdefplugins.h"
00024 #include "scip/cons_bounddisjunction.h"
00025
00026 SCIP_RETCODE CouenneFeasPump::ScipSolve (const double *nSol, double* &sol, int niter, int* nsuciter, CouNumber &obj) {
00027
00028 static int currentmilpmethod = 0;
00029
00030 int depth = (model_ -> currentNode ()) ? model_ -> currentNode () -> depth () : 0;
00031
00032 SCIP* scip;
00033
00034 SCIP_VAR** vars;
00035 SCIP_Real* lbs;
00036 SCIP_Real* ubs;
00037 const SCIP_Real* objs;
00038 const char* vartypes;
00039 const CoinPackedMatrix * matrix;
00040 const CoinBigIndex* rowstarts;
00041 const int* rowlengths;
00042 const SCIP_Real* coeffs;
00043 const SCIP_Real* lhss;
00044 const SCIP_Real* rhss;
00045 const int* indices;
00046
00047 SCIP_Real timelimit;
00048
00049 SCIP_VAR **tabuvars;
00050 SCIP_Real *tabubounds;
00051 SCIP_BOUNDTYPE *tabuboundtypes;
00052
00053 double infinity;
00054 int nvars;
00055 int nconss;
00056 int nscipsols;
00057
00058 bool solveagain;
00059
00060
00061
00062
00063 nvars = milp_ -> getNumCols ();
00064 nconss = milp_ -> getNumRows ();
00065 infinity = milp_ -> getInfinity ();
00066
00067
00068 lbs = CoinCopyOfArray (milp_ -> getColLower (), milp_ -> getNumCols ());
00069 ubs = CoinCopyOfArray (milp_ -> getColUpper (), milp_ -> getNumCols ());
00070
00071 objs = milp_ -> getObjCoefficients ();
00072 vartypes = milp_ -> getColType ();
00073
00074
00075
00076 for (int i = 0; i < problem_->nVars(); ++i)
00077 if (problem_ -> Var (i) -> Multiplicity () > 0) {
00078 if (problem_ -> Lb (i) > lbs [i]) lbs [i] = problem_ -> Lb (i);
00079 if (problem_ -> Ub (i) < ubs [i]) ubs [i] = problem_ -> Ub (i);
00080 }
00081
00082
00083 lhss = milp_ -> getRowLower ();
00084 rhss = milp_ -> getRowUpper ();
00085
00086
00087 matrix = milp_ -> getMatrixByRow();
00088 rowstarts = matrix -> getVectorStarts();
00089 rowlengths = matrix -> getVectorLengths();
00090 coeffs = matrix -> getElements();
00091 indices = matrix -> getIndices();
00092
00093
00094
00095 if (problem_ -> Jnlst () -> ProduceOutput (Ipopt::J_ERROR, J_NLPHEURISTIC)) {
00096 SCIPdebugMessage("create SCIP problem instance with %d variables and %d constraints.\n", nvars, nconss);
00097 }
00098
00099
00100 SCIP_CALL( SCIPcreate (&scip) );
00101 assert(scip != NULL);
00102
00103
00104 SCIP_CALL( SCIPincludeDefaultPlugins(scip) );
00105
00106
00107 if( milpCuttingPlane_ == FP_CUT_INTEGRATED )
00108 {
00109 SCIP_CALL( SCIPincludeConshdlrRowcuts(scip, couenneCG_, milp_) );
00110 }
00111
00112
00113 SCIP_CALL( SCIPcreateProb(scip, "auxiliary FeasPump MILP", NULL, NULL, NULL, NULL, NULL, NULL, NULL) );
00114
00115
00116 SCIP_CALL( SCIPallocMemoryArray(scip, &vars, nvars) );
00117
00118
00119
00120 SCIP_CALL( SCIPallocMemoryArray(scip, &tabuvars , 2*nvars) );
00121 SCIP_CALL( SCIPallocMemoryArray(scip, &tabubounds , 2*nvars) );
00122 SCIP_CALL( SCIPallocMemoryArray(scip, &tabuboundtypes, 2*nvars) );
00123
00124
00125
00126
00127 for (int i=0; i<nvars; i++) {
00128
00129 char varname[SCIP_MAXSTRLEN];
00130
00131 bool neglect =
00132 (i < problem_ -> nVars ()) &&
00133 (problem_ -> Var (i) -> Multiplicity () <= 0);
00134
00135
00136 assert( 0 <= vartypes[i] && vartypes[i] <= 2);
00137
00138 if (!neglect) {
00139
00140 checkInfinity(scip, lbs[i], infinity);
00141 checkInfinity(scip, ubs[i], infinity);
00142 }
00143
00144
00145 (void) SCIPsnprintf(varname, SCIP_MAXSTRLEN, "x_%d", i);
00146 SCIP_CALL( SCIPcreateVar(scip, &vars[i], varname,
00147 CoinMin (lbs [i], ubs [i]),
00148 CoinMax (lbs [i], ubs [i]),
00149 objs [i],
00150 vartypes[i] == 0 ? SCIP_VARTYPE_CONTINUOUS : (vartypes[i] == 1 ? SCIP_VARTYPE_BINARY : SCIP_VARTYPE_INTEGER),
00151 TRUE, FALSE, NULL, NULL, NULL, NULL, NULL) );
00152
00153
00154 SCIP_CALL( SCIPaddVar(scip, vars[i]) );
00155 }
00156
00157 for (std::set <CouenneFPsolution, compareSol>:: iterator i = tabuPool_ . begin ();
00158 i != tabuPool_ . end (); ++i) {
00159
00160 const double *x = i -> x ();
00161
00162 int nEntries = 0;
00163
00164 SCIP_CONS *tabucons = NULL;
00165
00166 for (int j = 0; j < i -> n (); ++j) {
00167
00168 if (problem_ -> Var (j) -> isInteger () &&
00169 (problem_ -> Var (j) -> Multiplicity () > 0) &&
00170 (fabs (ubs [j] - lbs [j]) > .5)) {
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 assert (fabs (x [j] - floor (x [j] + .5)) < SCIPfeastol (scip) * 1.e3);
00181
00182 assert (nEntries <= 2*nvars - 2);
00183
00184 double x_rounded = floor (x [j] + .5);
00185
00186 if (x [j] >= ubs [j] - COUENNE_EPS) {
00187
00188 tabuvars [nEntries] = vars [j];
00189 tabubounds [nEntries] = x_rounded - 1.;
00190 tabuboundtypes [nEntries++] = SCIP_BOUNDTYPE_UPPER;
00191
00192 } else if (x [j] <= lbs [j] + COUENNE_EPS) {
00193
00194 tabuvars [nEntries] = vars [j];
00195 tabubounds [nEntries] = x_rounded + 1.;
00196 tabuboundtypes [nEntries++] = SCIP_BOUNDTYPE_LOWER;
00197
00198 } else {
00199
00200 tabuvars [nEntries] = vars [j];
00201 tabubounds [nEntries] = x_rounded - 1.;
00202 tabuboundtypes [nEntries++] = SCIP_BOUNDTYPE_UPPER;
00203
00204 tabuvars [nEntries] = vars [j];
00205 tabubounds [nEntries] = x_rounded + 1.;
00206 tabuboundtypes [nEntries++] = SCIP_BOUNDTYPE_LOWER;
00207 }
00208 }
00209 }
00210
00211 if (nEntries != 0) {
00212
00213 SCIP_CALL (SCIPcreateConsBounddisjunction (scip, &tabucons, "Tabu Solution", nEntries,
00214 tabuvars, tabuboundtypes, tabubounds,
00215 TRUE, TRUE, TRUE, TRUE, TRUE,
00216 FALSE, FALSE, FALSE, FALSE, FALSE));
00217
00218 SCIP_CALL( SCIPaddCons(scip, tabucons) );
00219
00220 SCIP_CALL (SCIPreleaseCons (scip, &tabucons));
00221 }
00222 }
00223
00224
00225 for (int i=0; i<nconss; i++) {
00226
00227 SCIP_CONS* cons;
00228
00229 char consname[SCIP_MAXSTRLEN];
00230 (void) SCIPsnprintf(consname, SCIP_MAXSTRLEN, "row_%d", i);
00231
00232
00233 checkInfinity(scip, lhss[i], infinity);
00234 checkInfinity(scip, rhss[i], infinity);
00235
00236
00237 SCIP_CALL( SCIPcreateConsLinear(scip, &cons, consname, 0, NULL, NULL, lhss[i], rhss[i],
00238 TRUE, TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE) );
00239
00240
00241 for(int j=rowstarts[i]; j<rowstarts[i]+rowlengths[i]; j++)
00242 {
00243 checkInfinity(scip, coeffs[j], infinity);
00244 SCIP_CALL( SCIPaddCoefLinear(scip, cons, vars[indices[j]], coeffs[j]) );
00245 }
00246
00247
00248 SCIP_CALL( SCIPaddCons(scip, cons) );
00249 SCIP_CALL( SCIPreleaseCons(scip, &cons) );
00250 }
00251
00252
00253 if (milpMethod_ == 0 && niter == 0)
00254 {
00255
00256
00257 if( depth == 0 )
00258 currentmilpmethod = 2;
00259 else
00260 currentmilpmethod = 4;
00261 }
00262 else if (milpMethod_ != 0)
00263 currentmilpmethod = milpMethod_;
00264
00265
00266 do {
00267 solveagain = false;
00268
00269
00270 SCIP_CALL( SCIPresetParams(scip) );
00271
00272
00273 if (!(problem_ -> Jnlst () -> ProduceOutput (Ipopt::J_WARNING, J_NLPHEURISTIC))) {
00274 SCIP_CALL( SCIPsetIntParam(scip, "display/verblevel", 0) );
00275 }
00276
00277
00278 SCIP_CALL( SCIPsetBoolParam(scip, "misc/catchctrlc", FALSE) );
00279
00280
00281 timelimit = problem_ -> getMaxCpuTime () - CoinCpuTime ();
00282
00283 if (timelimit < 0)
00284 break;
00285
00286 SCIP_CALL( SCIPsetRealParam(scip, "limits/time", timelimit) );
00287
00288 if (problem_ -> Jnlst () -> ProduceOutput (Ipopt::J_WARNING, J_NLPHEURISTIC)) {
00289 SCIPinfoMessage(scip, NULL, "using MILP method: %d\n",currentmilpmethod);
00290 }
00291
00292
00299 switch(currentmilpmethod)
00300 {
00301 case -1:
00302 if( milpCuttingPlane_ == FP_CUT_INTEGRATED )
00303 {
00304 SCIP_CALL( SCIPsetLongintParam(scip, "constraints/rowcuts/maxcuttingrounds", 0) );
00305 }
00306
00307
00308
00309 SCIP_CALL( SCIPsetIntParam(scip, "limits/bestsol", 1) );
00310 break;
00311
00312 case 1:
00313
00314 SCIP_CALL( SCIPsetLongintParam(scip, "limits/stallnodes", 1000) );
00315 SCIP_CALL( SCIPsetLongintParam(scip, "limits/nodes", 10000) );
00316 SCIP_CALL( SCIPsetRealParam (scip, "limits/gap", .001) );
00317
00318
00319
00320
00321
00322
00323
00324
00325 SCIP_CALL( SCIPsetHeuristics(scip, SCIP_PARAMSETTING_AGGRESSIVE, TRUE) );
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352 break;
00353
00354 case 2:
00355 SCIP_CALL( SCIPsetLongintParam(scip, "limits/stallnodes", 500) );
00356 SCIP_CALL( SCIPsetLongintParam(scip, "limits/nodes", 5000) );
00357 SCIP_CALL( SCIPsetRealParam (scip, "limits/gap", .005) );
00358
00359
00360
00361 SCIP_CALL( SCIPsetSeparating(scip, SCIP_PARAMSETTING_FAST, TRUE) );
00362 SCIP_CALL( SCIPsetPresolving(scip, SCIP_PARAMSETTING_FAST, TRUE) );
00363 SCIP_CALL( SCIPsetIntParam(scip, "branching/pscost/priority", INT_MAX/4) );
00364
00365 break;
00366 case 3:
00367 SCIP_CALL( SCIPsetLongintParam(scip, "limits/nodes", 1) );
00368
00369
00370 SCIP_CALL( SCIPsetSeparating(scip, SCIP_PARAMSETTING_OFF, TRUE) );
00371
00372
00373 SCIP_CALL( SCIPsetPresolving(scip, SCIP_PARAMSETTING_FAST, TRUE) );
00374
00375
00376 SCIP_CALL( SCIPsetHeuristics(scip, SCIP_PARAMSETTING_FAST, TRUE) );
00377
00378
00379 if( SCIPfindBranchrule(scip, "inference") != NULL )
00380 {
00381 SCIP_CALL( SCIPsetIntParam(scip, "branching/inference/priority", INT_MAX/4) );
00382 }
00383
00384
00385 if( SCIPfindHeur(scip, "rens") != NULL )
00386 {
00387 SCIP_CALL( SCIPsetIntParam(scip, "heuristics/rens/freq", 0) );
00388 SCIP_CALL( SCIPsetRealParam(scip, "heuristics/rens/minfixingrate", 0.0) );
00389 }
00390 if( milpCuttingPlane_ == FP_CUT_INTEGRATED )
00391 {
00392 SCIP_CALL( SCIPsetLongintParam(scip, "constraints/rowcuts/maxcuttingrounds", 0) );
00393 }
00394 break;
00395
00396 case 4:
00397 SCIP_CALL( SCIPsetLongintParam(scip, "limits/nodes", 1) );
00398
00399
00400 SCIP_CALL( SCIPsetSeparating(scip, SCIP_PARAMSETTING_OFF, TRUE) );
00401
00402
00403 SCIP_CALL( SCIPsetPresolving(scip, SCIP_PARAMSETTING_FAST, TRUE) );
00404
00405
00406 SCIP_CALL( SCIPsetHeuristics(scip, SCIP_PARAMSETTING_FAST, TRUE) );
00407
00408
00409 if( SCIPfindBranchrule(scip, "inference") != NULL )
00410 {
00411 SCIP_CALL( SCIPsetIntParam(scip, "branching/inference/priority", INT_MAX/4) );
00412 }
00413
00414
00415 if( SCIPfindHeur(scip, "feaspump") != NULL )
00416 {
00417 SCIP_CALL( SCIPsetIntParam(scip, "heuristics/feaspump/freq", 0) );
00418 SCIP_CALL( SCIPsetIntParam(scip, "heuristics/feaspump/maxsols", -1) );
00419
00420
00421
00422
00423 if( SCIPversion() <= 2.01 )
00424 {
00425 SCIP_CALL( SCIPsetBoolParam(scip, "heuristics/feaspump2/stage3", TRUE) );
00426 }
00427 else
00428 {
00429 SCIP_CALL( SCIPsetBoolParam(scip, "heuristics/feaspump/stage3", TRUE) );
00430 }
00431 }
00432 if( milpCuttingPlane_ == FP_CUT_INTEGRATED )
00433 {
00434 SCIP_CALL( SCIPsetLongintParam(scip, "constraints/rowcuts/maxcuttingrounds", 0) );
00435 }
00436 break;
00437
00438 case 5:
00439
00440 SCIP_CALL( SCIPsetLongintParam(scip, "limits/stallnodes", 500) );
00441 SCIP_CALL( SCIPsetLongintParam(scip, "limits/nodes", 5000) );
00442 SCIP_CALL( SCIPsetRealParam (scip, "limits/gap", .05) );
00443
00444 {
00445 if (!sol)
00446 sol = new CouNumber [problem_ -> nVars ()];
00447
00448 if (!nSol)
00449 nSol = milp_ -> getColSolution ();
00450
00451
00452
00453 problem_ -> getIntegerCandidate (nSol, sol, problem_ -> Lb (), problem_ -> Ub ());
00454
00455 SCIP_SOL* scipSol;
00456 SCIP_CALL( SCIPcreateSol(scip, &scipSol, NULL ));
00457 SCIP_CALL(SCIPsetSolVals(scip, scipSol, nvars, vars,(double*) sol));
00458 }
00459
00460 break;
00461
00462 case 6:
00463
00464 SCIP_CALL( SCIPsetLongintParam(scip, "limits/stallnodes", 500) );
00465 SCIP_CALL( SCIPsetLongintParam(scip, "limits/nodes", 5000) );
00466 SCIP_CALL( SCIPsetRealParam (scip, "limits/gap", .05) );
00467
00468 if (!sol)
00469 sol = new CouNumber [problem_ -> nVars ()];
00470
00471 if (!nSol)
00472 nSol = milp_ -> getColSolution ();
00473
00474 for (int j = 0; j < problem_ -> nVars (); ++j)
00475 sol [j] =
00476 (problem_ -> Var (j) -> Multiplicity () <= 0) ? 0. :
00477 (problem_ -> Var (j) -> isInteger ()) ? COUENNE_round (nSol [j]) : nSol [j];
00478
00479 SCIP_SOL* scipSol;
00480 SCIP_CALL( SCIPcreateSol(scip, &scipSol, NULL ));
00481 SCIP_CALL(SCIPsetSolVals(scip, scipSol, nvars, vars, (double*) sol));
00482
00483 break;
00484
00485
00486 default:
00487 printf("Invalid MILP method in feasibility pump: %d\n", currentmilpmethod);
00488 assert(false);
00489 break;
00490 }
00491
00493
00494 SCIP_CALL(SCIPtransformProb(scip));
00495
00496 {
00497 SCIP_CONSHDLR* conshdlr_bounddisjunction = SCIPfindConshdlr(scip, "bounddisjunction");
00498 int nbdconss= SCIPconshdlrGetNConss(conshdlr_bounddisjunction);
00499 SCIP_CONS** bdconss = SCIPconshdlrGetConss(conshdlr_bounddisjunction);
00500
00501 for(int i=0; i < nbdconss; i++)
00502 {
00503 SCIP_CONS* checkcons = bdconss[i];
00504 SCIP_VAR** checkvars = SCIPgetVarsBounddisjunction(scip, checkcons);
00505 SCIP_Real* checkbounds = SCIPgetBoundsBounddisjunction(scip,checkcons);
00506 SCIP_BOUNDTYPE* checkboundtypes =SCIPgetBoundtypesBounddisjunction(scip, checkcons);
00507 int checknvars = SCIPgetNVarsBounddisjunction(scip, checkcons);
00508
00509 for(int j=i+1; j < nbdconss; j++)
00510 {
00511 SCIP_CONS* tmpcons =SCIPconshdlrGetConss(conshdlr_bounddisjunction)[j];
00512 SCIP_VAR **tmpvars = SCIPgetVarsBounddisjunction(scip,tmpcons);
00513 SCIP_Real *tmpbounds =SCIPgetBoundsBounddisjunction(scip, tmpcons);
00514 SCIP_BOUNDTYPE *tmpboundtypes =SCIPgetBoundtypesBounddisjunction(scip, tmpcons);
00515 int tmpnvars = SCIPgetNVarsBounddisjunction(scip, tmpcons);
00516 int k;
00517
00518 if( checknvars != tmpnvars )
00519 continue;
00520
00521 for(k=0; k < tmpnvars; k++)
00522 if(tmpvars[k] != checkvars[k] || tmpbounds[k] !=checkbounds[k] || tmpboundtypes[k] != checkboundtypes[k])
00523 break;
00524
00525 if (k == tmpnvars)
00526 problem_ -> Jnlst () -> Printf (Ipopt::J_WARNING, J_NLPHEURISTIC, "ZZZ identical bounddisjunction constraints\n");
00527 }
00528 }
00529 }
00530
00532
00533 #if 0
00534
00535 SCIP_CALL( SCIPwriteOrigProblem(scip, "debug.lp", NULL, FALSE) );
00536 SCIP_CALL( SCIPwriteParams(scip, "debug.set", FALSE,TRUE) );
00537 #endif
00538
00539
00540
00541
00542 SCIP_RETCODE retcode = SCIPsolve (scip);
00543
00544
00545 #if 0
00546 if (SCIPgetStatus (scip) == SCIP_STATUS_INFEASIBLE) {
00547
00548
00549 SCIP_CALL( SCIPwriteOrigProblem(scip, "debug.lp", NULL, FALSE) );
00550 SCIP_CALL( SCIPwriteParams(scip, "debug.set", FALSE, TRUE));
00551
00552 printf ("SCIP found that the problem is infeasible, exiting\n");
00553
00554 exit (-1);
00555 }
00556 #endif
00557
00558 if (problem_ -> Jnlst () -> ProduceOutput (Ipopt::J_WARNING, J_NLPHEURISTIC))
00559 SCIP_CALL( SCIPprintStatistics(scip, NULL) );
00560
00561
00562
00563 problem_ -> Jnlst () -> Printf (Ipopt::J_ERROR, J_NLPHEURISTIC, "[FeasPump-SCIP] %5d %5d %7.2f\n", SCIPgetNVars(scip), SCIPgetNConss(scip), SCIPgetSolvingTime(scip));
00564
00565 if (retcode != SCIP_OKAY) {
00566 problem_ -> Jnlst () -> Printf (Ipopt::J_WARNING, J_NLPHEURISTIC, "Couenne FP: SCIPsolve did not succeed\n");
00567 goto TERMINATION;
00568 }
00569
00570 nscipsols = SCIPgetNSols(scip);
00571
00572
00573 if( nscipsols)
00574 {
00575 SCIP_SOL** scipsols;
00576 SCIP_SOL* bestsol;
00577 SCIP_Real cutoffbound;
00578
00579 int nstoredsols;
00580
00581 double objval = 0;
00582
00583
00584 bestsol = SCIPgetBestSol(scip);
00585 assert(bestsol != NULL);
00586
00587
00588 scipsols = SCIPgetSols(scip);
00589 assert(scipsols != NULL);
00590
00591 if (!sol)
00592 sol = new CouNumber [problem_ -> nVars ()];
00593
00594
00595 SCIP_CALL( SCIPgetSolVals(scip, bestsol, problem_ -> nVars (), vars, sol) );
00596 obj = SCIPgetSolOrigObj(scip, bestsol);
00597
00598 nstoredsols = 0;
00599
00600
00601 cutoffbound = obj > 0 ? 2*obj : obj / 2.0;
00602
00603
00604
00605 for(int i=1; i<nscipsols && nstoredsols < 10 &&
00606 (objval = SCIPgetSolOrigObj(scip,scipsols[i])) <= cutoffbound; i++){
00607
00608 double* tmpsol = new CouNumber [nvars];
00609
00610
00611 SCIP_CALL( SCIPgetSolVals(scip, scipsols[i], problem_ -> nVars (), vars, tmpsol) );
00612 CouenneFPsolution couennesol = CouenneFPsolution (problem_, tmpsol);
00613
00614 delete [] tmpsol;
00615
00616
00617 if ( tabuPool_ . find (couennesol) == tabuPool_ . end ()
00618 && pool_ -> Set (). find (couennesol) == pool_ -> Set() . end ()
00619 ){
00620
00621 pool_ -> Set (). insert (couennesol);
00622
00623 ++nstoredsols;
00624 }
00625 }
00626
00627 ++(*nsuciter);
00628
00629
00630
00631 if( milpMethod_ == 0 && *nsuciter >= 3 && currentmilpmethod < 4 )
00632 {
00633 ++currentmilpmethod;
00634 *nsuciter = 0;
00635 }
00636 }
00637
00638 else if( milpMethod_ == 0 && currentmilpmethod > 1 )
00639 {
00640 --currentmilpmethod;
00641 solveagain = true;
00642 *nsuciter = 0;
00643
00644
00645 SCIP_CALL( SCIPfreeTransform(scip) );
00646 }
00647 else {
00648
00649 obj = COIN_DBL_MAX;
00650 }
00651
00652 } while (solveagain);
00653
00655
00656 TERMINATION:
00657
00658
00659 for (int i=0; i<nvars; i++) {
00660 SCIP_CALL( SCIPreleaseVar(scip, &vars[i]) );
00661 }
00662
00663
00664 SCIPfreeMemoryArray(scip, &vars);
00665
00666
00667 SCIPfreeMemoryArray(scip, &tabuvars );
00668 SCIPfreeMemoryArray(scip, &tabubounds );
00669 SCIPfreeMemoryArray(scip, &tabuboundtypes);
00670
00671 delete [] lbs;
00672 delete [] ubs;
00673
00674 SCIP_CALL( SCIPfree(&scip) );
00675
00676 BMScheckEmptyMemory();
00677
00678 return SCIP_OKAY;
00679 }
00680
00681 #endif