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