this repo has no description
at develop 21 kB view raw
1// * -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */ 2 3/* 4 * Main authors: 5 * Gleb Belov <gleb.belov@monash.edu> 6 */ 7 8/* This Source Code Form is subject to the terms of the Mozilla Public 9 * License, v. 2.0. If a copy of the MPL was not distributed with this 10 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 11 12#ifdef _MSC_VER 13#define _CRT_SECURE_NO_WARNINGS 14#endif 15 16#include <cmath> 17#include <cstring> 18#include <fstream> 19#include <iomanip> 20#include <iostream> 21#include <sstream> 22#include <stdexcept> 23#include <string> 24 25using namespace std; 26 27#include <minizinc/solvers/MIP/MIP_scip_wrap.hh> 28#include <minizinc/utils.hh> 29 30#include "scip/scipshell.h" 31 32std::string MIP_scip_wrapper::getMznLib() { return "-Glinear_scip"; } 33 34string MIP_scip_wrapper::getDescription(MiniZinc::SolverInstanceBase::Options* opt) { 35 ostringstream oss; 36 oss << "MIP wrapper for SCIP " << getVersion(opt) << ". Compiled " __DATE__ " " __TIME__; 37 return oss.str(); 38} 39string MIP_scip_wrapper::getVersion(MiniZinc::SolverInstanceBase::Options* opt) { 40 ostringstream oss; 41 oss << SCIPmajorVersion() << '.' << SCIPminorVersion() << '.' << SCIPtechVersion() << '.' 42 << SCIPsubversion(); 43 return oss.str(); 44} 45string MIP_scip_wrapper::needDllFlag() { return ""; } 46 47string MIP_scip_wrapper::getId() { return "scip"; } 48 49string MIP_scip_wrapper::getName() { return "SCIP"; } 50 51vector<string> MIP_scip_wrapper::getTags() { return {"mip", "float", "api"}; } 52 53vector<string> MIP_scip_wrapper::getStdFlags() { return {"-a", "-p", "-s"}; } 54 55void MIP_scip_wrapper::Options::printHelp(ostream& os) { 56 os << "SCIP MIP wrapper options:" 57 << std::endl 58 // -s print statistics 59 // << " --readParam <file> read SCIP parameters from file 60 // << "--writeParam <file> write SCIP parameters to file 61 // << "--tuneParam instruct SCIP to tune parameters instead of solving 62 << "--writeModel <file> write model to <file> (.lp, .mps, ...?)" << std::endl 63 << "-a print intermediate solutions (use for optimization problems only TODO)" 64 << std::endl 65 << "-p <N> use N threads, default: 1" 66 << std::endl 67 // << "--nomippresolve disable MIP presolving NOT IMPL" << std::endl 68 << "--solver-time-limit <N> stop search after N milliseconds" << std::endl 69 << "--workmem <N> maximal amount of RAM used, MB" << std::endl 70 << "--readParam <file> read SCIP parameters from file" << std::endl 71 << "--writeParam <file> write SCIP parameters to file" 72 << std::endl 73 // << "--tuneParam instruct SCIP to tune parameters instead of solving NOT IMPL" 74 75 << "--absGap <n> absolute gap |primal-dual| to stop" << std::endl 76 << "--relGap <n> relative gap |primal-dual|/<solver-dep> to stop. Default 1e-8, set <0 " 77 "to use backend's default" 78 << std::endl 79 << "--intTol <n> integrality tolerance for a variable. Default 1e-8" 80 << std::endl 81 // << "--objDiff <n> objective function discretization. Default 1.0" << std::endl 82 83 << std::endl; 84} 85 86static inline bool beginswith(string s, string t) { return s.compare(0, t.length(), t) == 0; } 87 88bool MIP_scip_wrapper::Options::processOption(int& i, vector<string>& argv) { 89 MiniZinc::CLOParser cop(i, argv); 90 if (string(argv[i]) == "-a" || string(argv[i]) == "--all" || 91 string(argv[i]) == "--all-solutions") { 92 flag_all_solutions = true; 93 } else if (string(argv[i]) == "-f") { 94 // std::cerr << " Flag -f: ignoring fixed strategy anyway." << std::endl; 95 } else if (cop.get("--writeModel", &sExportModel)) { 96 } else if (cop.get("-p", &nThreads)) { 97 } else if (cop.get("--solver-time-limit", &nTimeout)) { 98 } else if (cop.get("--workmem", &nWorkMemLimit)) { 99 } else if (cop.get("--readParam", &sReadParams)) { 100 } else if (cop.get("--writeParam", &sWriteParams)) { 101 } else if (cop.get("--absGap", &absGap)) { 102 } else if (cop.get("--relGap", &relGap)) { 103 } else if (cop.get("--intTol", &intTol)) { 104 // } else if ( cop.get( "--objDiff", &objDiff ) ) { 105 } else 106 return false; 107 return true; 108error: 109 return false; 110} 111 112void MIP_scip_wrapper::wrap_assert(SCIP_RETCODE retcode, string msg, bool fTerm) { 113 /* evaluate return code of the SCIP process */ 114 if (retcode != SCIP_OKAY) { 115 /* write error back trace */ 116 SCIPprintError(retcode); 117 string msgAll = (" MIP_scip_wrapper runtime error, see output: " + msg); 118 cerr << msgAll << endl; 119 if (fTerm) { 120 cerr << "TERMINATING." << endl; 121 throw runtime_error(msgAll); 122 } 123 } 124} 125 126SCIP_RETCODE MIP_scip_wrapper::openSCIP() { 127 SCIP_CALL(SCIPcreate(&scip)); 128 SCIP_CALL(SCIPincludeDefaultPlugins(scip)); 129 130 /* create empty problem */ 131 SCIP_CALL(SCIPcreateProbBasic(scip, "mzn_scip")); 132 return SCIP_OKAY; 133} 134 135SCIP_RETCODE MIP_scip_wrapper::closeSCIP() { 136 SCIP_CALL(SCIPfree(&scip)); 137 /// and at last: 138 // MIP_wrapper::cleanup(); 139 return SCIP_OKAY; 140} 141 142SCIP_RETCODE MIP_scip_wrapper::doAddVars_SCIP(size_t n, double* obj, double* lb, double* ub, 143 MIP_wrapper::VarType* vt, string* names) { 144 /// Convert var types: 145 // vector<char> ctype(n); 146 // vector<char*> pcNames(n); 147 for (size_t j = 0; j < n; ++j) { 148 // pcNames[i] = (char*)names[i].c_str(); 149 SCIP_VARTYPE ctype; 150 switch (vt[j]) { 151 case REAL: 152 ctype = SCIP_VARTYPE_CONTINUOUS; 153 break; 154 case INT: 155 ctype = SCIP_VARTYPE_INTEGER; 156 break; 157 case BINARY: 158 ctype = SCIP_VARTYPE_BINARY; 159 break; 160 default: 161 throw runtime_error(" MIP_wrapper: unknown variable type"); 162 } 163 scipVars.resize(scipVars.size() + 1); 164 if (fPhase1Over) assert(scipVars.size() == colObj.size()); 165 SCIP_CALL( 166 SCIPcreateVarBasic(scip, &scipVars.back(), names[j].c_str(), lb[j], ub[j], obj[j], ctype)); 167 SCIP_CALL(SCIPaddVar(scip, scipVars.back())); 168 } 169 // retcode = SCIP_newcols (env, lp, n, obj, lb, ub, &ctype[0], &pcNames[0]); 170 // wrap_assert( !retcode, "Failed to declare variables." ); 171 return SCIP_OKAY; 172} 173 174SCIP_RETCODE MIP_scip_wrapper::delSCIPVars() { 175 for (size_t j = 0; j < scipVars.size(); ++j) SCIPreleaseVar(scip, &scipVars[j]); 176 return SCIP_OKAY; 177} 178 179SCIP_RETCODE MIP_scip_wrapper::addRow_SCIP(int nnz, int* rmatind, double* rmatval, 180 MIP_wrapper::LinConType sense, double rhs, int mask, 181 string rowName) { 182 /// Convert var types: 183 double lh = -SCIPinfinity(scip), rh = SCIPinfinity(scip); 184 switch (sense) { 185 case LQ: 186 rh = rhs; 187 break; 188 case EQ: 189 lh = rh = rhs; 190 break; 191 case GQ: 192 lh = rhs; 193 break; 194 default: 195 throw runtime_error(" MIP_wrapper: unknown constraint type"); 196 } 197 const int ccnt = 0; 198 const int rcnt = 1; 199 const int rmatbeg[] = {0}; 200 char* pRName = (char*)rowName.c_str(); 201 // ignoring mask for now. TODO 202 SCIP_CONS* cons; 203 vector<SCIP_VAR*> ab(nnz); 204 205 for (int j = 0; j < nnz; ++j) ab[j] = scipVars[rmatind[j]]; 206 207 SCIP_CALL(SCIPcreateConsBasicLinear(scip, &cons, rowName.c_str(), nnz, &ab[0], rmatval, lh, rh)); 208 SCIP_CALL(SCIPaddCons(scip, cons)); 209 SCIP_CALL(SCIPreleaseCons(scip, &cons)); 210 return SCIP_OKAY; 211 // retcode = SCIP_addrows (env, lp, ccnt, rcnt, nnz, &rhs, 212 // &ssense, rmatbeg, rmatind, rmatval, 213 // NULL, &pRName); 214 // wrap_assert( !retcode, "Failed to add constraint." ); 215} 216 217void MIP_scip_wrapper::setVarBounds(int iVar, double lb, double ub) { 218 wrap_assert(lb <= ub ? SCIP_OKAY : SCIP_ERROR, "scip interface: setVarBounds: lb>ub"); 219 setVarLB(iVar, lb); 220 setVarUB(iVar, ub); 221} 222 223void MIP_scip_wrapper::setVarLB(int iVar, double lb) { 224 auto res = SCIPchgVarLbGlobal(scip, scipVars[iVar], lb); 225 wrap_assert(res, "scip interface: failed to set var lb."); 226} 227 228void MIP_scip_wrapper::setVarUB(int iVar, double ub) { 229 auto res = SCIPchgVarUbGlobal(scip, scipVars[iVar], ub); 230 wrap_assert(res, "scip interface: failed to set var ub."); 231} 232 233void MIP_scip_wrapper::addIndicatorConstraint(int iBVar, int bVal, int nnz, int* rmatind, 234 double* rmatval, MIP_wrapper::LinConType sense, 235 double rhs, string rowName) { 236 MZN_ASSERT_HARD_MSG(0 <= bVal && 1 >= bVal, "SCIP: addIndicatorConstraint: bVal not 0/1"); 237 //// Make sure in order to notice the indices of lazy constr: also here? TODO 238 // ++ nRows; 239 240 SCIP_CONS* cons; 241 vector<SCIP_VAR*> ab(nnz); 242 SCIP_VAR* 243 indicator_var; // SCIP 6.0.1 requires that the implication is active for indicator_x == 1 244 245 for (int j = 0; j < nnz; ++j) ab[j] = scipVars[rmatind[j]]; 246 247 indicator_var = scipVars[iBVar]; 248 if (0 == bVal) { 249 wrap_assert(SCIPgetNegatedVar(scip, indicator_var, &indicator_var)); 250 } 251 252 if (LQ == sense || EQ == sense) { 253 wrap_assert(SCIPcreateConsBasicIndicator(scip, &cons, rowName.c_str(), indicator_var, nnz, 254 ab.data(), rmatval, rhs)); 255 wrap_assert(SCIPaddCons(scip, cons)); 256 wrap_assert(SCIPreleaseCons(scip, &cons)); 257 } 258 if (GQ == sense || EQ == sense) { 259 std::vector<double> rmatvalNEG(nnz); 260 for (int i = nnz; i--;) rmatvalNEG[i] = -rmatval[i]; 261 wrap_assert(SCIPcreateConsBasicIndicator(scip, &cons, rowName.c_str(), indicator_var, nnz, 262 ab.data(), rmatvalNEG.data(), -rhs)); 263 wrap_assert(SCIPaddCons(scip, cons)); 264 wrap_assert(SCIPreleaseCons(scip, &cons)); 265 } 266} 267 268void MIP_scip_wrapper::addBoundsDisj(int n, double* fUB, double* bnd, int* vars, int nF, 269 double* fUBF, double* bndF, int* varsF, string rowName) { 270 SCIP_CONS* cons; 271 std::vector<SCIP_VAR*> v(n + nF); 272 std::vector<SCIP_BOUNDTYPE> bt(n + nF); 273 std::vector<SCIP_Real> bs(n + nF); 274 275 for (int j = 0; j < n; ++j) { 276 v[j] = scipVars[vars[j]]; 277 bt[j] = fUB[j] ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER; 278 bs[j] = bnd[j]; 279 } 280 for (int j = 0; j < nF; ++j) { 281 v[n + j] = scipVars[varsF[j]]; 282 bt[n + j] = fUBF[j] ? SCIP_BOUNDTYPE_UPPER : SCIP_BOUNDTYPE_LOWER; 283 bs[n + j] = bndF[j]; 284 } 285 286 wrap_assert(SCIPcreateConsBasicBounddisjunction(scip, &cons, rowName.c_str(), v.size(), v.data(), 287 bt.data(), bs.data())); 288 wrap_assert(SCIPaddCons(scip, cons)); 289 wrap_assert(SCIPreleaseCons(scip, &cons)); 290} 291 292void MIP_scip_wrapper::addCumulative(int nnz, int* rmatind, double* d, double* r, double b, 293 string rowName) { 294 SCIP_CONS* cons; 295 vector<SCIP_VAR*> ab(nnz); 296 vector<int> nd(nnz), nr(nnz); 297 298 for (int j = 0; j < nnz; ++j) { 299 ab[j] = scipVars[rmatind[j]]; 300 nd[j] = (int)round(d[j]); 301 nr[j] = (int)round(r[j]); 302 } 303 304 wrap_assert(SCIPcreateConsBasicCumulative(scip, &cons, rowName.c_str(), nnz, ab.data(), nd.data(), 305 nr.data(), (int)round(b))); 306 307 wrap_assert(SCIPaddCons(scip, cons)); 308 wrap_assert(SCIPreleaseCons(scip, &cons)); 309} 310 311/// SolutionCallback ------------------------------------------------------------------------ 312 313/// From event_bestsol.c: 314#define EVENTHDLR_NAME "bestsol" 315#define EVENTHDLR_DESC "event handler for best solutions found" 316 317/** includes event handler for best solution found */ 318extern SCIP_RETCODE SCIPincludeEventHdlrBestsol(SCIP* scip /**< SCIP data structure */ 319); 320 321/** copy method for event handler plugins (called when SCIP copies plugins) */ 322static SCIP_DECL_EVENTCOPY(eventCopyBestsol) { /*lint --e{715}*/ 323 assert(scip != NULL); 324 assert(eventhdlr != NULL); 325 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 326 327 /* call inclusion method of event handler */ 328 SCIP_CALL(SCIPincludeEventHdlrBestsol(scip)); 329 330 return SCIP_OKAY; 331} 332 333/** initialization method of event handler (called after problem was transformed) */ 334static SCIP_DECL_EVENTINIT(eventInitBestsol) { /*lint --e{715}*/ 335 assert(scip != NULL); 336 assert(eventhdlr != NULL); 337 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 338 339 /* notify SCIP that your event handler wants to react on the event type best solution found */ 340 SCIP_CALL(SCIPcatchEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, NULL, NULL)); 341 342 return SCIP_OKAY; 343} 344 345/** deinitialization method of event handler (called before transformed problem is freed) */ 346static SCIP_DECL_EVENTEXIT(eventExitBestsol) { /*lint --e{715}*/ 347 assert(scip != NULL); 348 assert(eventhdlr != NULL); 349 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 350 351 /* notify SCIP that your event handler wants to drop the event type best solution found */ 352 SCIP_CALL(SCIPdropEvent(scip, SCIP_EVENTTYPE_BESTSOLFOUND, eventhdlr, NULL, -1)); 353 354 return SCIP_OKAY; 355} 356 357static MIP_wrapper::CBUserInfo* cbuiPtr = 0; 358static SCIP_VAR** scipVarsPtr = 0; 359 360/** execution method of event handler */ 361static SCIP_DECL_EVENTEXEC(eventExecBestsol) { /*lint --e{715}*/ 362 SCIP_SOL* bestsol; 363 SCIP_Real objVal; 364 int newincumbent = 0; 365 366 assert(eventhdlr != NULL); 367 assert(strcmp(SCIPeventhdlrGetName(eventhdlr), EVENTHDLR_NAME) == 0); 368 assert(event != NULL); 369 assert(scip != NULL); 370 assert(SCIPeventGetType(event) == SCIP_EVENTTYPE_BESTSOLFOUND); 371 372 SCIPdebugMessage("exec method of event handler for best solution found\n"); 373 374 bestsol = SCIPgetBestSol(scip); 375 assert(bestsol != NULL); 376 objVal = SCIPgetSolOrigObj(scip, bestsol); 377 378 if (!cbuiPtr) return SCIP_OKAY; 379 380 if (fabs(cbuiPtr->pOutput->objVal - objVal) > 1e-12 * (1.0 + fabs(objVal))) { 381 newincumbent = 1; 382 cbuiPtr->pOutput->objVal = objVal; 383 cbuiPtr->pOutput->status = MIP_wrapper::SAT; 384 cbuiPtr->pOutput->statusName = "feasible from a callback"; 385 } 386 387 if (newincumbent && scipVarsPtr) { 388 assert(cbuiPtr->pOutput->x); 389 SCIP_CALL(SCIPgetSolVals(scip, bestsol, cbuiPtr->pOutput->nCols, scipVarsPtr, 390 (double*)cbuiPtr->pOutput->x)); 391 // wrap_assert(!retcode, "Failed to get variable values."); 392 cbuiPtr->pOutput->nNodes = SCIPgetNNodes(scip); 393 cbuiPtr->pOutput->nOpenNodes = SCIPgetNNodesLeft(scip); 394 cbuiPtr->pOutput->bestBound = SCIPgetDualbound(scip); 395 396 cbuiPtr->pOutput->dCPUTime = -1; 397 398 /// Call the user function: 399 if (cbuiPtr->solcbfn) (*cbuiPtr->solcbfn)(*cbuiPtr->pOutput, cbuiPtr->psi); 400 } 401 402 return SCIP_OKAY; 403} 404 405/** includes event handler for best solution found */ 406SCIP_RETCODE SCIPincludeEventHdlrBestsol(SCIP* scip /**< SCIP data structure */ 407) { 408 SCIP_EVENTHDLRDATA* eventhdlrdata; 409 SCIP_EVENTHDLR* eventhdlr; 410 eventhdlrdata = NULL; 411 412 eventhdlr = NULL; 413 /* create event handler for events on watched variables */ 414 SCIP_CALL(SCIPincludeEventhdlrBasic(scip, &eventhdlr, EVENTHDLR_NAME, EVENTHDLR_DESC, 415 eventExecBestsol, eventhdlrdata)); 416 assert(eventhdlr != NULL); 417 418 /// Not for sub-SCIPs 419 // SCIP_CALL( SCIPsetEventhdlrCopy(scip, eventhdlr, eventCopyBestsol) ); 420 SCIP_CALL(SCIPsetEventhdlrInit(scip, eventhdlr, eventInitBestsol)); 421 SCIP_CALL(SCIPsetEventhdlrExit(scip, eventhdlr, eventExitBestsol)); 422 423 return SCIP_OKAY; 424} 425 426MIP_scip_wrapper::Status MIP_scip_wrapper::convertStatus(SCIP_STATUS scipStatus) { 427 Status s = Status::UNKNOWN; 428 /* Converting the status. */ 429 switch (scipStatus) { 430 case SCIP_STATUS_OPTIMAL: 431 s = Status::OPT; 432 output.statusName = "Optimal"; 433 assert(SCIPgetNSolsFound(scip)); 434 break; 435 case SCIP_STATUS_INFEASIBLE: 436 s = Status::UNSAT; 437 output.statusName = "Infeasible"; 438 break; 439 // case SCIP_MIP_OPTIMAL_INFEAS: 440 case SCIP_STATUS_INFORUNBD: 441 s = Status::UNSATorUNBND; 442 output.statusName = "Infeasible or unbounded"; 443 break; 444 // case SCIP_MIP_SOL_LIM: 445 // s = Status::SAT; 446 // wrap_assert(SCIP_getsolnpoolnumsolns(env, lp), "Feasibility reported but pool 447 // empty?", false); break; 448 case SCIP_STATUS_UNBOUNDED: 449 s = Status::UNBND; 450 output.statusName = "Unbounded"; 451 break; 452 // case SCIP_STATUSMIP_ABORT_INFEAS: 453 // case SCIP_MIP_FAIL_INFEAS: 454 // s = Status::ERROR; 455 // break; 456 default: 457 // case SCIP_MIP_OPTIMAL_TOL: 458 // case SCIP_MIP_ABORT_RELAXATION_UNBOUNDED: 459 if (SCIPgetNSols(scip)) { 460 s = Status::SAT; 461 output.statusName = "Feasible"; 462 } else { 463 s = Status::UNKNOWN; 464 output.statusName = "Unknown"; 465 } 466 } 467 return s; 468} 469 470SCIP_DECL_MESSAGEWARNING(printMsg) { cerr << msg << flush; } 471 472SCIP_RETCODE MIP_scip_wrapper::solve_SCIP() { // Move into ancestor? 473 474 /////////////// Last-minute solver options ////////////////// 475 if (options->flag_all_solutions && 0 == nProbType) 476 cerr << "WARNING. --all-solutions for SAT problems not implemented." << endl; 477 478 if (options->nThreads > 0) SCIP_CALL(SCIPsetIntParam(scip, "lp/threads", options->nThreads)); 479 480 if (options->nTimeout > 0) 481 SCIP_CALL( 482 SCIPsetRealParam(scip, "limits/time", static_cast<double>(options->nTimeout) / 1000.0)); 483 484 if (options->nWorkMemLimit > 0) 485 SCIP_CALL(SCIPsetRealParam(scip, "limits/memory", options->nWorkMemLimit)); 486 487 if (options->absGap >= 0.0) SCIP_CALL(SCIPsetRealParam(scip, "limits/absgap", options->absGap)); 488 if (options->relGap >= 0.0) SCIP_CALL(SCIPsetRealParam(scip, "limits/gap", options->relGap)); 489 if (options->intTol >= 0.0) 490 SCIP_CALL(SCIPsetRealParam(scip, "numerics/feastol", options->intTol)); 491 492 // retcode = SCIP_setintparam (env, SCIP_PARAM_ClockType, 1); // CPU time 493 // wrap_assert(!retcode, " SCIP Warning: Failure to measure CPU time.", false); 494 495 if (!options->sExportModel.empty()) { 496 // std::cerr <<" Exporting LP model to " << sExportModel << " ..." << std::endl; 497 SCIP_CALL(SCIPwriteOrigProblem(scip, options->sExportModel.c_str(), 0, 0)); 498 } 499 500 /* Turn on output to the screen - after model export */ 501 if (!fVerbose) { 502 // SCIP_CALL(SCIPsetMessagehdlr(scip, NULL)); No LP export then 503 SCIPsetMessagehdlrQuiet(scip, true); 504 } else { 505 SCIP_MESSAGEHDLR* pHndl = 0; 506 SCIP_CALL(SCIPmessagehdlrCreate(&pHndl, FALSE, NULL, FALSE, printMsg, printMsg, printMsg, NULL, 507 NULL)); 508 SCIP_CALL(SCIPsetMessagehdlr(scip, pHndl)); 509 } 510 511 // assert(scipVars.size() == colObj.size()); 512 int cur_numcols = scipVars.size(); // No, we create negated indicators: getNCols(); 513 assert(cur_numcols == colObj.size()); 514 assert(cur_numcols == scipVars.size()); 515 516 /// Solution callback 517 output.nCols = colObj.size(); 518 x.resize(output.nCols); 519 output.x = &x[0]; 520 if (options->flag_all_solutions && cbui.solcbfn && !cbuiPtr) { 521 /* include event handler for best solution found */ 522 SCIP_CALL(SCIPincludeEventHdlrBestsol(scip)); 523 cbuiPtr = &cbui; // not thread-safe... TODO 524 scipVarsPtr = &scipVars[0]; 525 // retcode = SCIP_setinfocallbackfunc (env, solcallback, &cbui); 526 // wrap_assert(!retcode, "Failed to set solution callback", false); 527 } 528 529 if (options->sReadParams.size()) { 530 SCIP_CALL(SCIPreadParams(scip, options->sReadParams.c_str())); 531 } 532 533 if (options->sWriteParams.size()) { 534 SCIP_CALL(SCIPwriteParams(scip, options->sReadParams.c_str(), TRUE, FALSE)); 535 } 536 537 cbui.pOutput->dWallTime0 = output.dWallTime0 = std::chrono::steady_clock::now(); 538 output.dCPUTime = clock(); 539 540 /* Optimize the problem and obtain solution. */ 541 SCIP_CALL(SCIPsolve(scip)); 542 // wrap_assert( !retcode, "Failed to optimize MIP." ); 543 544 output.dWallTime = 545 std::chrono::duration<double>(std::chrono::steady_clock::now() - output.dWallTime0).count(); 546 output.dCPUTime = (clock() - output.dCPUTime) / CLOCKS_PER_SEC; 547 548 cbuiPtr = 0; /// cleanup 549 scipVarsPtr = 0; 550 551 SCIP_STATUS solstat = SCIPgetStatus(scip); 552 output.status = convertStatus(solstat); 553 // output.statusName = SCIP_getstatstring (env, solstat, scip_status_buffer); 554 555 /// Continuing to fill the output object: 556 output.objVal = SCIPgetPrimalbound(scip); 557 output.bestBound = SCIPgetDualbound(scip); 558 // wrap_assert(!retcode, "Failed to get the best bound.", false); 559 if (Status::OPT == output.status || Status::SAT == output.status) { 560 // wrap_assert( !retcode, "No MIP objective value available." ); 561 562 x.resize(cur_numcols); 563 output.x = &x[0]; 564 SCIP_CALL( 565 SCIPgetSolVals(scip, SCIPgetBestSol(scip), cur_numcols, &scipVars[0], (double*)output.x)); 566 if (cbui.solcbfn && (!options->flag_all_solutions || !cbui.printed)) { 567 cbui.solcbfn(output, cbui.psi); 568 } 569 } 570 output.nNodes = SCIPgetNNodes(scip); 571 output.nOpenNodes = SCIPgetNNodesLeft(scip); // SCIP_getnodeleftcnt (env, lp); 572 573 SCIP_CALL(SCIPfreeTransform(scip)); 574 575 return SCIP_OKAY; 576} 577 578SCIP_RETCODE MIP_scip_wrapper::setObjSense_SCIP(int s) { 579 SCIP_CALL(SCIPsetObjsense(scip, s > 0 ? SCIP_OBJSENSE_MAXIMIZE : SCIP_OBJSENSE_MINIMIZE)); 580 return SCIP_OKAY; 581}