this repo has no description
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}