Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
GlpkLpSolver.cpp
Go to the documentation of this file.
2
3#include <cmath>
4
18
19namespace storm {
20namespace solver {
21
22#ifdef STORM_HAVE_GLPK
23template<typename ValueType, bool RawMode>
24GlpkLpSolver<ValueType, RawMode>::GlpkLpSolver(storm::GlpkSolverEnvironment const& glpkSettings, bool debug, std::string const& name,
25 OptimizationDirection const& optDir)
26 : LpSolver<ValueType, RawMode>(optDir),
27 lp(nullptr),
28 variableToIndexMap(),
29 modelContainsIntegerVariables(false),
30 integerTolerance(glpkSettings.getIntegerTolerance()),
31 milpPresolverEnabled(glpkSettings.isMILPPresolverEnabled()),
32 isInfeasibleFlag(false),
33 isUnboundedFlag(false) {
34 // Create the LP problem for glpk.
35 lp = glp_create_prob();
36
37 // Set its name and model sense.
38 glp_set_prob_name(lp, name.c_str());
39
40 // Set whether the glpk output shall be printed to the command line.
41 glp_term_out(debug || glpkSettings.isOutputSet() ? GLP_ON : GLP_OFF);
42
43 // Set the maximal allowed MILP gap to its default value
44 glp_iocp* defaultParameters = new glp_iocp();
45 glp_init_iocp(defaultParameters);
46 this->maxMILPGap = defaultParameters->mip_gap;
47 this->maxMILPGapRelative = true;
48}
49
50#else
51
52template<typename ValueType, bool RawMode>
54 // Throw nothing in a constructor.
55}
56#endif
57
58template<typename ValueType, bool RawMode>
59GlpkLpSolver<ValueType, RawMode>::GlpkLpSolver(storm::GlpkSolverEnvironment const& glpkSettings, bool debug, std::string const& name)
60 : GlpkLpSolver(glpkSettings, debug, name, OptimizationDirection::Minimize) {
61 // Intentionally left empty.
62}
63
64template<typename ValueType, bool RawMode>
66 : GlpkLpSolver(glpkSettings, debug, "", OptimizationDirection::Minimize) {
67 // Intentionally left empty.
68}
69
70template<typename ValueType, bool RawMode>
72 : GlpkLpSolver(glpkSettings, debug, "", optDir) {
73 // Intentionally left empty.
74}
75
76template<typename ValueType, bool RawMode>
78#ifdef STORM_HAVE_GLPK
79 // Dispose of all objects allocated dynamically by glpk.
80 glp_delete_prob(this->lp);
81 glp_free_env();
82#endif
83}
84
85template<typename ValueType, bool RawMode>
87#ifdef STORM_HAVE_GLPK
88 switch (type) {
90 return GLP_CV;
92 return GLP_IV;
94 return GLP_BV;
95 }
96 STORM_LOG_ASSERT(false, "Unexpected variable type.");
97 return -1;
98#else
99 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
100 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
101 "version with GLPK support.");
102#endif
103}
104
105template<typename ValueType, bool RawMode>
107 std::optional<ValueType> const& lowerBound,
108 std::optional<ValueType> const& upperBound,
109 ValueType objectiveFunctionCoefficient) {
110#ifdef STORM_HAVE_GLPK
111 Variable resultVar;
112 if constexpr (RawMode) {
113 resultVar = variableToIndexMap.size();
114 } else {
115 resultVar = this->declareOrGetExpressionVariable(name, type);
116 // Assert whether the variable does not exist yet.
117 // Due to incremental usage (push(), pop()), a variable might be declared in the manager but not in the lp model.
118 STORM_LOG_ASSERT(variableToIndexMap.count(resultVar) == 0, "Variable " << resultVar.getName() << " exists already in the model.");
119 }
120
121 int boundType;
122 if (lowerBound.has_value()) {
123 boundType = upperBound.has_value() ? GLP_DB : GLP_LO;
124 } else {
125 boundType = upperBound.has_value() ? GLP_UP : GLP_FR;
126 }
127
128 if (type == VariableType::Integer || type == VariableType::Binary) {
129 this->modelContainsIntegerVariables = true;
130 }
131
132 // Create the variable in glpk.
133 int variableIndex = glp_add_cols(this->lp, 1);
134 glp_set_col_name(this->lp, variableIndex, name.c_str());
135 glp_set_col_bnds(lp, variableIndex, boundType, lowerBound.has_value() ? storm::utility::convertNumber<double>(*lowerBound) : 0.0,
136 upperBound.has_value() ? storm::utility::convertNumber<double>(*upperBound) : 0.0);
137 glp_set_col_kind(this->lp, variableIndex, getGlpkType<ValueType, RawMode>(type));
138 glp_set_obj_coef(this->lp, variableIndex, storm::utility::convertNumber<double>(objectiveFunctionCoefficient));
139
140 if constexpr (RawMode) {
141 this->variableToIndexMap.push_back(variableIndex);
142 } else {
143 this->variableToIndexMap.emplace(resultVar, variableIndex);
144 if (!incrementalData.empty()) {
145 incrementalData.back().variables.push_back(resultVar);
146 }
147 }
148
149 return resultVar;
150#else
151 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
152 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
153 "version with GLPK support.");
154#endif
155}
156
157template<typename ValueType, bool RawMode>
159 // Intentionally left empty.
160}
161
162template<typename ValueType, bool RawMode>
163void GlpkLpSolver<ValueType, RawMode>::addConstraint(std::string const& name, Constraint const& constraint) {
164#ifdef STORM_HAVE_GLPK
165 // Add the row that will represent this constraint.
166 int constraintIndex = glp_add_rows(this->lp, 1);
167 glp_set_row_name(this->lp, constraintIndex, name.c_str());
168
169 // Extract constraint data
170 double rhs;
172 // glpk uses 1-based indexing (wtf!?)...
173 std::vector<int> variableIndices(1, -1);
174 std::vector<double> coefficients(1, 0.0);
175 if constexpr (RawMode) {
176 rhs = storm::utility::convertNumber<double>(constraint.rhs);
177 relationType = constraint.relationType;
178 variableIndices.reserve(constraint.lhsVariableIndices.size() + 1);
179 for (auto const& var : constraint.lhsVariableIndices) {
180 variableIndices.push_back(this->variableToIndexMap.at(var));
181 }
182 coefficients.reserve(constraint.lhsCoefficients.size() + 1);
183 for (auto const& coef : constraint.lhsCoefficients) {
184 coefficients.push_back(storm::utility::convertNumber<double>(coef));
185 }
186 } else {
187 STORM_LOG_THROW(constraint.getManager() == this->getManager(), storm::exceptions::InvalidArgumentException,
188 "Constraint was not built over the proper variables.");
189 STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException, "Illegal constraint is not a relational expression.");
190
195 leftCoefficients.separateVariablesFromConstantPart(rightCoefficients);
196 rhs = rightCoefficients.getConstantPart();
197 relationType = constraint.getBaseExpression().asBinaryRelationExpression().getRelationType();
198 int len = std::distance(leftCoefficients.begin(), leftCoefficients.end());
199 variableIndices.reserve(len + 1);
200 coefficients.reserve(len + 1);
201 for (auto const& variableCoefficientPair : leftCoefficients) {
202 auto variableIndexPair = this->variableToIndexMap.find(variableCoefficientPair.first);
203 variableIndices.push_back(variableIndexPair->second);
204 coefficients.push_back(variableCoefficientPair.second);
205 }
206 }
207
208 // Determine the type of the constraint and add it properly.
209 switch (relationType) {
211 glp_set_row_bnds(this->lp, constraintIndex, GLP_UP, 0, rhs - this->integerTolerance);
212 break;
214 glp_set_row_bnds(this->lp, constraintIndex, GLP_UP, 0, rhs);
215 break;
217 glp_set_row_bnds(this->lp, constraintIndex, GLP_LO, rhs + this->integerTolerance, 0);
218 break;
220 glp_set_row_bnds(this->lp, constraintIndex, GLP_LO, rhs, 0);
221 break;
223 glp_set_row_bnds(this->lp, constraintIndex, GLP_FX, rhs, rhs);
224 break;
225 default:
226 STORM_LOG_ASSERT(false, "Illegal operator in LP solver constraint.");
227 }
228
229 // Add the constraints
230 glp_set_mat_row(this->lp, constraintIndex, variableIndices.size() - 1, variableIndices.data(), coefficients.data());
231
232 this->currentModelHasBeenOptimized = false;
233#else
234 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
235 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
236 "version with GLPK support.");
237#endif
238}
239
240template<typename ValueType, bool RawMode>
242 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Indicator constraints are not supported for GLPK.");
243}
244
245#ifdef STORM_HAVE_GLPK
246// Method used within the MIP solver to terminate early
247void callback(glp_tree* t, void* info) {
248 auto& mipgap = *static_cast<std::pair<double, bool>*>(info);
249 double actualRelativeGap = glp_ios_mip_gap(t);
250 double factor = storm::utility::one<double>();
251 if (!mipgap.second) {
252 // Compute absolute gap
253 factor = storm::utility::abs(glp_mip_obj_val(glp_ios_get_prob(t))) + DBL_EPSILON;
254 STORM_LOG_ASSERT(factor >= 0.0, "Expected non-negative factor.");
255 }
256 if (actualRelativeGap * factor <= mipgap.first) {
257 // Terminate early
258 mipgap.first = actualRelativeGap;
259 mipgap.second = true; // The gap is relative.
260 glp_ios_terminate(t);
261 }
262}
263#endif
264
265template<typename ValueType, bool RawMode>
267#ifdef STORM_HAVE_GLPK
268 // First, reset the flags.
269 this->isInfeasibleFlag = false;
270 this->isUnboundedFlag = false;
271
272 // Start by setting the model sense.
273 glp_set_obj_dir(this->lp, this->getOptimizationDirection() == OptimizationDirection::Minimize ? GLP_MIN : GLP_MAX);
274
275 int error = 0;
276 if (this->modelContainsIntegerVariables) {
277 glp_iocp* parameters = new glp_iocp();
278 glp_init_iocp(parameters);
279 parameters->tol_int = this->integerTolerance;
280 this->isInfeasibleFlag = false;
281 if (this->milpPresolverEnabled) {
282 parameters->presolve = GLP_ON;
283 } else {
284 // Without presolving, we solve the relaxed model first. This is required because
285 // glp_intopt requires that either presolving is enabled or an optimal initial basis is provided.
286 error = glp_simplex(this->lp, nullptr);
287 STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to optimize relaxed glpk model (" << error << ").");
288 // If the relaxed model is already not feasible, we don't have to solve the actual model.
289 if (glp_get_status(this->lp) == GLP_INFEAS || glp_get_status(this->lp) == GLP_NOFEAS) {
290 this->isInfeasibleFlag = true;
291 }
292 // If the relaxed model is unbounded, there could still be no feasible integer solution.
293 // However, since we can not provide an optimal initial basis, we will need to enable presolving
294 if (glp_get_status(this->lp) == GLP_UNBND) {
295 parameters->presolve = GLP_ON;
296 } else {
297 parameters->presolve = GLP_OFF;
298 }
299 }
300 if (!this->isInfeasibleFlag) {
301 // Check whether we allow sub-optimal solutions via a non-zero MIP gap.
302 // parameters->mip_gap = this->maxMILPGap; (only works for relative values. Also, we need to obtain the actual gap anyway.
303 std::pair<double, bool> mipgap(this->maxMILPGap, this->maxMILPGapRelative);
304 if (!storm::utility::isZero(this->maxMILPGap)) {
305 parameters->cb_func = &callback;
306 parameters->cb_info = &mipgap;
307 }
308
309 // Invoke mip solving
310 error = glp_intopt(this->lp, parameters);
311 int status = glp_mip_status(this->lp);
312 delete parameters;
313
314 // mipgap.first has been set to the achieved mipgap (either within the callback function or because it has been set to this->maxMILPGap)
315 this->actualRelativeMILPGap = mipgap.first;
316
317 // In case the error is caused by an infeasible problem, we do not want to view this as an error and
318 // reset the error code.
319 if (error == GLP_ENOPFS || status == GLP_NOFEAS) {
320 this->isInfeasibleFlag = true;
321 error = 0;
322 } else if (error == GLP_ENODFS) {
323 this->isUnboundedFlag = true;
324 error = 0;
325 } else if (error == GLP_ESTOP) {
326 // Early termination due to achieved MIP Gap. That's fine.
327 error = 0;
328 } else if (error == GLP_EBOUND) {
329 STORM_LOG_THROW(false, storm::exceptions::InvalidStateException,
330 "The bounds of some variables are illegal. Note that glpk only accepts integer bounds for integer variables.");
331 }
332 }
333 } else {
334 error = glp_simplex(this->lp, nullptr);
335 }
336
337 STORM_LOG_THROW(error == 0, storm::exceptions::InvalidStateException, "Unable to optimize glpk model (" << error << ").");
338 this->currentModelHasBeenOptimized = true;
339#else
340 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
341 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
342 "version with GLPK support.");
343#endif
344}
345
346template<typename ValueType, bool RawMode>
348#ifdef STORM_HAVE_GLPK
349 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
350 "Illegal call to GlpkLpSolver::isInfeasible: model has not been optimized.");
351
352 if (this->modelContainsIntegerVariables) {
353 return isInfeasibleFlag;
354 } else {
355 return glp_get_status(this->lp) == GLP_INFEAS || glp_get_status(this->lp) == GLP_NOFEAS;
356 }
357#else
358 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
359 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
360 "version with GLPK support.");
361#endif
362}
363
364template<typename ValueType, bool RawMode>
366#ifdef STORM_HAVE_GLPK
367 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
368 "Illegal call to GlpkLpSolver::isUnbounded: model has not been optimized.");
369
370 if (this->modelContainsIntegerVariables) {
371 return isUnboundedFlag;
372 } else {
373 return glp_get_status(this->lp) == GLP_UNBND;
374 }
375#else
376 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
377 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
378 "version with GLPK support.");
379#endif
380}
381
382template<typename ValueType, bool RawMode>
384 if (!this->currentModelHasBeenOptimized) {
385 return false;
386 }
387
388 return !isInfeasible() && !isUnbounded();
389}
390
391template<typename ValueType, bool RawMode>
393#ifdef STORM_HAVE_GLPK
394 if (!this->isOptimal()) {
395 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
396 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
397 STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
398 }
399
400 int variableIndex = variableToIndexMap.at(variable);
401
402 double value = 0;
403 if (this->modelContainsIntegerVariables) {
404 value = glp_mip_col_val(this->lp, static_cast<int>(variableIndex));
405 } else {
406 value = glp_get_col_prim(this->lp, static_cast<int>(variableIndex));
407 }
409#else
410 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
411 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
412 "version with GLPK support.");
413#endif
414}
415
416template<typename ValueType, bool RawMode>
418#ifdef STORM_HAVE_GLPK
419 if (!this->isOptimal()) {
420 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
421 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
422 STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
423 }
424
425 int variableIndex = variableToIndexMap.at(variable);
426
427 double value = 0;
428 if (this->modelContainsIntegerVariables) {
429 value = glp_mip_col_val(this->lp, variableIndex);
430 } else {
431 value = glp_get_col_prim(this->lp, variableIndex);
432 }
433
434 double roundedValue = std::round(value);
435 double diff = std::abs(roundedValue - value);
436 STORM_LOG_ERROR_COND(diff <= this->integerTolerance,
437 "Illegal value for integer variable in GLPK solution (" << value << "). Difference to nearest int is " << diff);
438 return static_cast<int_fast64_t>(roundedValue);
439#else
440 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
441 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
442 "version with GLPK support.");
443#endif
444}
445
446template<typename ValueType, bool RawMode>
448#ifdef STORM_HAVE_GLPK
449 if (!this->isOptimal()) {
450 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
451 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
452 STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
453 }
454
455 int variableIndex = variableToIndexMap.at(variable);
456
457 double value = 0;
458 if (this->modelContainsIntegerVariables) {
459 value = glp_mip_col_val(this->lp, variableIndex);
460 } else {
461 value = glp_get_col_prim(this->lp, variableIndex);
462 }
463
464 if (value > 0.5) {
465 STORM_LOG_ERROR_COND(std::abs(value - 1.0) <= this->integerTolerance, "Illegal value for binary variable in GLPK solution (" << value << ").");
466 return true;
467 } else {
468 STORM_LOG_ERROR_COND(std::abs(value) <= this->integerTolerance, "Illegal value for binary variable in GLPK solution (" << value << ").");
469 return false;
470 }
471
472 return static_cast<bool>(value);
473#else
474 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
475 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
476 "version with GLPK support.");
477#endif
478}
479
480template<typename ValueType, bool RawMode>
482#ifdef STORM_HAVE_GLPK
483 if (!this->isOptimal()) {
484 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from infeasible model.");
485 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unbounded model.");
486 STORM_LOG_THROW(false, storm::exceptions::InvalidAccessException, "Unable to get glpk solution from unoptimized model.");
487 }
488
489 double value = 0;
490 if (this->modelContainsIntegerVariables) {
491 value = glp_mip_obj_val(this->lp);
492 } else {
493 value = glp_get_obj_val(this->lp);
494 }
495
497#else
498 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
499 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
500 "version with GLPK support.");
501#endif
502}
503
504template<typename ValueType, bool RawMode>
505void GlpkLpSolver<ValueType, RawMode>::writeModelToFile(std::string const& filename) const {
506#ifdef STORM_HAVE_GLPK
507 glp_write_lp(this->lp, nullptr, filename.c_str());
508#else
509 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
510 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
511 "version with GLPK support.");
512#endif
513}
514
515template<typename ValueType, bool RawMode>
517#ifdef STORM_HAVE_GLPK
518 if constexpr (RawMode) {
519 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Incremental LP solving not supported in raw mode.");
520 } else {
521 IncrementalLevel lvl;
522 lvl.firstConstraintIndex = glp_get_num_rows(this->lp) + 1;
523 incrementalData.push_back(lvl);
524 }
525#else
526 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
527 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
528 "version with GLPK support.");
529#endif
530}
531
532template<typename ValueType, bool RawMode>
534#ifdef STORM_HAVE_GLPK
535 if constexpr (RawMode) {
536 STORM_LOG_THROW(false, storm::exceptions::InvalidOperationException, "Incremental LP solving not supported in raw mode.");
537 } else {
538 if (incrementalData.empty()) {
539 STORM_LOG_ERROR("Tried to pop from a solver without pushing before.");
540 } else {
541 IncrementalLevel const& lvl = incrementalData.back();
542 // Since glpk uses 1-based indexing, we need to prepend an additional index
543 std::vector<int> indicesToBeRemoved = storm::utility::vector::buildVectorForRange(lvl.firstConstraintIndex - 1, glp_get_num_rows(this->lp) + 1);
544 if (indicesToBeRemoved.size() > 1) {
545 glp_del_rows(this->lp, indicesToBeRemoved.size() - 1, indicesToBeRemoved.data());
546 }
547 indicesToBeRemoved.clear();
548
549 if (!lvl.variables.empty()) {
550 int firstIndex = -1;
551 bool first = true;
552 for (auto const& var : lvl.variables) {
553 if (first) {
554 auto it = variableToIndexMap.find(var);
555 firstIndex = it->second;
556 variableToIndexMap.erase(it);
557 first = false;
558 } else {
559 variableToIndexMap.erase(var);
560 }
561 }
562 // Since glpk uses 1-based indexing, we need to prepend an additional index
563 std::vector<int> indicesToBeRemoved = storm::utility::vector::buildVectorForRange(firstIndex - 1, glp_get_num_cols(this->lp) + 1);
564 glp_del_cols(this->lp, indicesToBeRemoved.size() - 1, indicesToBeRemoved.data());
565 }
566 incrementalData.pop_back();
567 update();
568 // Check whether we need to adapt the current basis (i.e. the number of basic variables does not equal the number of constraints)
569 int n = glp_get_num_rows(lp);
570 int m = glp_get_num_cols(lp);
571 int nb(0), mb(0);
572 for (int i = 1; i <= n; ++i) {
573 if (glp_get_row_stat(lp, i) == GLP_BS) {
574 ++nb;
575 }
576 }
577 for (int j = 1; j <= m; ++j) {
578 if (glp_get_col_stat(lp, j) == GLP_BS) {
579 ++mb;
580 }
581 }
582 if (n != (nb + mb)) {
583 glp_std_basis(this->lp);
584 }
585 }
586 }
587#else
588 STORM_LOG_THROW(false, storm::exceptions::MissingLibraryException,
589 "This version of storm was compiled without support for GLPK. Yet, a method was called that requires this support. Please choose a "
590 "version with GLPK support.");
591#endif
592}
593
594template<typename ValueType, bool RawMode>
595void GlpkLpSolver<ValueType, RawMode>::setMaximalMILPGap(ValueType const& gap, bool relative) {
596 this->maxMILPGap = storm::utility::convertNumber<double>(gap);
597 this->maxMILPGapRelative = relative;
598}
599
600template<typename ValueType, bool RawMode>
601ValueType GlpkLpSolver<ValueType, RawMode>::getMILPGap(bool relative) const {
602 STORM_LOG_ASSERT(this->isOptimal(), "Asked for the MILP gap although there is no (bounded) solution.");
603 if (relative) {
604 return storm::utility::convertNumber<ValueType>(this->actualRelativeMILPGap);
605 } else {
607 }
608}
609
610template class GlpkLpSolver<double, true>;
611template class GlpkLpSolver<double, false>;
614
615} // namespace solver
616} // namespace storm
VariableCoefficients getLinearCoefficients(Expression const &expression)
Computes the (double) coefficients of all identifiers appearing in the expression if the expression w...
A class that implements the LpSolver interface using glpk as the background solver.
virtual bool getBinaryValue(Variable const &name) const override
Retrieves the value of the binary variable with the given name.
virtual void setMaximalMILPGap(ValueType const &gap, bool relative) override
Specifies the maximum difference between lower- and upper objective bounds that triggers termination.
virtual void push() override
Pushes a backtracking point on the solver's stack.
virtual ValueType getContinuousValue(Variable const &name) const override
Retrieves the value of the continuous variable with the given name.
virtual int_fast64_t getIntegerValue(Variable const &name) const override
Retrieves the value of the integer variable with the given name.
virtual Variable addVariable(std::string const &name, VariableType const &type, std::optional< ValueType > const &lowerBound=std::nullopt, std::optional< ValueType > const &upperBound=std::nullopt, ValueType objectiveFunctionCoefficient=0) override
virtual bool isOptimal() const override
Retrieves whether the model was found to be optimal, i.e.
virtual void writeModelToFile(std::string const &filename) const override
Writes the current LP problem to the given file.
virtual bool isInfeasible() const override
Retrieves whether the model was found to be infeasible.
virtual void pop() override
Pops a backtracking point from the solver's stack.
typename LpSolver< ValueType, RawMode >::Constraint Constraint
virtual ValueType getObjectiveValue() const override
Retrieves the value of the objective function.
virtual void addIndicatorConstraint(std::string const &name, Variable indicatorVariable, bool indicatorValue, Constraint const &constraint) override
Adds the given indicator constraint to the LP problem: "If indicatorVariable == indicatorValue,...
virtual void addConstraint(std::string const &name, Constraint const &constraint) override
Adds a the given constraint to the LP problem.
virtual void update() const override
Updates the model to make the variables that have been declared since the last call to update usable.
virtual ValueType getMILPGap(bool relative) const override
Returns the obtained gap after a call to optimize().
virtual ~GlpkLpSolver()
Destructs a solver by freeing the pointers to glpk's structures.
typename LpSolver< ValueType, RawMode >::VariableType VariableType
virtual bool isUnbounded() const override
Retrieves whether the model was found to be infeasible.
virtual void optimize() const override
Optimizes the LP problem previously constructed.
GlpkLpSolver(storm::GlpkSolverEnvironment const &glpkSettings, bool debug, std::string const &name, OptimizationDirection const &optDir)
Constructs a solver with the given name and model sense.
typename LpSolver< ValueType, RawMode >::Variable Variable
An interface that captures the functionality of an LP solver.
Definition LpSolver.h:50
OptimizationDirection getOptimizationDirection() const
Definition LpSolver.cpp:125
storm::expressions::Variable declareOrGetExpressionVariable(std::string const &name, VariableType const &type)
Definition LpSolver.cpp:136
#define STORM_LOG_ERROR(message)
Definition logging.h:29
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_ERROR_COND(cond, message)
Definition macros.h:50
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
SFTBDDChecker::ValueType ValueType
RelationType
An enum type specifying the different relations applicable.
int getGlpkType(typename GlpkLpSolver< ValueType, RawMode >::VariableType const &type)
std::vector< T > buildVectorForRange(T min, T max)
Constructs a vector [min, min+1, ...., max-1].
Definition vector.h:129
bool isZero(ValueType const &a)
Definition constants.cpp:42
ValueType abs(ValueType const &number)
ValueType one()
Definition constants.cpp:19
TargetType convertNumber(SourceType const &number)
std::map< storm::expressions::Variable, double >::const_iterator end() const
void separateVariablesFromConstantPart(VariableCoefficients &rhs)
Brings all variables of the right-hand side coefficients to the left-hand side by negating them and m...
std::map< storm::expressions::Variable, double >::const_iterator begin() const