24#ifdef STORM_HAVE_GUROBI
31#ifdef STORM_HAVE_GUROBI
32GRBenv* GurobiEnvironment::operator*() {
33 STORM_LOG_ASSERT(initialized,
"Gurobi Environment has not been initialized");
39#ifdef STORM_HAVE_GUROBI
41 int error = GRBloadenv(&env,
"");
42 if (error || env ==
nullptr) {
44 STORM_LOG_ERROR(
"Gurobi License Issue. " << GRBgeterrormsg(env) <<
", error code " << error <<
").");
45 throw storm::exceptions::GurobiLicenseException()
46 <<
"Could not initialize Gurobi environment (" << GRBgeterrormsg(env) <<
", error code " << error <<
").";
48 STORM_LOG_ERROR(
"Could not initialize Gurobi (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
49 throw storm::exceptions::InvalidStateException()
50 <<
"Could not initialize Gurobi environment (" << GRBgeterrormsg(env) <<
", error code " << error <<
").";
52 setOutput(storm::settings::getModule<storm::settings::modules::DebugSettings>().isDebugSet() ||
53 storm::settings::getModule<storm::settings::modules::GurobiSettings>().isOutputSet());
55 error = GRBsetintparam(env,
"Method",
static_cast<int>(storm::settings::getModule<storm::settings::modules::GurobiSettings>().getMethod()));
57 "Unable to set Gurobi Parameter Method (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
60 error = GRBsetintparam(env,
"Threads", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getNumberOfThreads());
62 "Unable to set Gurobi Parameter Threads (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
64 error = GRBsetintparam(env,
"MIPFocus", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getMIPFocus());
66 "Unable to set Gurobi Parameter MIPFocus (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
68 error = GRBsetintparam(env,
"ConcurrentMIP", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getNumberOfConcurrentMipThreads());
70 "Unable to set Gurobi Parameter ConcurrentMIP (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
73 error = GRBsetdblparam(env,
"IntFeasTol", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance());
75 "Unable to set Gurobi Parameter IntFeasTol (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
81#ifdef STORM_HAVE_GUROBI
82 int error = GRBsetintparam(env,
"OutputFlag", set);
84 "Unable to set Gurobi Parameter OutputFlag (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
90#ifdef STORM_HAVE_GUROBI
92template<
typename ValueType,
bool RawMode>
95 :
LpSolver<ValueType, RawMode>(optDir), model(nullptr), environment(environment), nextVariableIndex(0) {
98 error = GRBnewmodel(**environment, &model, name.c_str(), 0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
100 STORM_LOG_ERROR(
"Could not initialize Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
101 throw storm::exceptions::InvalidStateException()
102 <<
"Could not initialize Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").";
106template<
typename ValueType,
bool RawMode>
112template<
typename ValueType,
bool RawMode>
114 : GurobiLpSolver(environment,
"", optDir) {
118template<
typename ValueType,
bool RawMode>
124template<
typename ValueType,
bool RawMode>
130template<
typename ValueType,
bool RawMode>
132 int error = GRBupdatemodel(model);
134 "Unable to update Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
137 this->currentModelHasBeenOptimized =
false;
140template<
typename ValueType,
bool RawMode>
143 case GurobiLpSolver<ValueType, RawMode>::VariableType::Continuous:
144 return GRB_CONTINUOUS;
145 case GurobiLpSolver<ValueType, RawMode>::VariableType::Integer:
147 case GurobiLpSolver<ValueType, RawMode>::VariableType::Binary:
154template<
typename ValueType,
bool RawMode>
156 std::optional<ValueType>
const& lowerBound,
157 std::optional<ValueType>
const& upperBound,
158 ValueType objectiveFunctionCoefficient) {
160 if constexpr (RawMode) {
161 resultVar = nextVariableIndex;
163 resultVar = this->declareOrGetExpressionVariable(name, type);
166 STORM_LOG_ASSERT(variableToIndexMap.count(resultVar) == 0,
"Variable " << resultVar.getName() <<
" exists already in the model.");
167 this->variableToIndexMap.emplace(resultVar, nextVariableIndex);
168 if (!incrementalData.empty()) {
169 incrementalData.back().variables.push_back(resultVar);
176 error = GRBaddvar(model, 0,
nullptr,
nullptr, storm::utility::convertNumber<double>(objectiveFunctionCoefficient),
177 lowerBound.has_value() ? storm::utility::convertNumber<double>(*lowerBound) : -GRB_INFINITY,
178 upperBound.has_value() ?
storm::utility::
convertNumber<double>(*upperBound) : GRB_INFINITY, getGurobiType<
ValueType, RawMode>(type),
181 "Could not create binary Gurobi variable (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
185struct GurobiConstraint {
186 std::vector<int> variableIndices;
187 std::vector<double> coefficients;
192template<
typename ValueType,
bool RawMode>
194 std::map<storm::expressions::Variable, int>
const& variableToIndexMap) {
195 GurobiConstraint gurobiConstraint;
197 if constexpr (RawMode) {
198 gurobiConstraint.rhs = storm::utility::convertNumber<double>(constraint.rhs);
199 relationType = constraint.relationType;
200 gurobiConstraint.variableIndices.insert(gurobiConstraint.variableIndices.end(), constraint.lhsVariableIndices.begin(),
201 constraint.lhsVariableIndices.end());
202 gurobiConstraint.coefficients.reserve(constraint.lhsCoefficients.size());
203 for (
auto const& coef : constraint.lhsCoefficients) {
204 gurobiConstraint.coefficients.push_back(storm::utility::convertNumber<double>(coef));
207 STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException,
"Illegal constraint is not a relational expression.");
214 relationType = constraint.getBaseExpression().asBinaryRelationExpression().getRelationType();
215 int len = std::distance(leftCoefficients.
begin(), leftCoefficients.
end());
216 gurobiConstraint.variableIndices.reserve(len);
217 gurobiConstraint.coefficients.reserve(len);
218 for (
auto const& variableCoefficientPair : leftCoefficients) {
219 auto variableIndexPair = variableToIndexMap.find(variableCoefficientPair.first);
220 gurobiConstraint.variableIndices.push_back(variableIndexPair->second);
221 gurobiConstraint.coefficients.push_back(variableCoefficientPair.second);
225 switch (relationType) {
227 gurobiConstraint.sense = GRB_LESS_EQUAL;
228 gurobiConstraint.rhs -= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance();
231 gurobiConstraint.sense = GRB_LESS_EQUAL;
234 gurobiConstraint.sense = GRB_GREATER_EQUAL;
235 gurobiConstraint.rhs += storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance();
238 gurobiConstraint.sense = GRB_GREATER_EQUAL;
241 gurobiConstraint.sense = GRB_EQUAL;
246 return gurobiConstraint;
249template<
typename ValueType,
bool RawMode>
251 if constexpr (!RawMode) {
252 STORM_LOG_TRACE(
"Adding constraint " << name <<
" to GurobiLpSolver:\n"
253 <<
"\t" << constraint);
254 STORM_LOG_ASSERT(constraint.getManager() == this->getManager(),
"Constraint was not built over the proper variables.");
258 auto grbConstr = createConstraint<ValueType, RawMode>(constraint, this->variableToIndexMap);
259 int error = GRBaddconstr(model, grbConstr.variableIndices.size(), grbConstr.variableIndices.data(), grbConstr.coefficients.data(), grbConstr.sense,
260 grbConstr.rhs, name ==
"" ?
nullptr : name.c_str());
262 "Could not assert constraint (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
265template<
typename ValueType,
bool RawMode>
267 Constraint
const& constraint) {
270 if constexpr (RawMode) {
271 indVar = indicatorVariable;
273 STORM_LOG_ASSERT(this->variableToIndexMap.count(indicatorVariable) > 0,
"Indicator Variable " << indicatorVariable.getName() <<
" unknown to solver.");
274 STORM_LOG_ASSERT(indicatorVariable.hasIntegerType(),
"Indicator Variable " << indicatorVariable.getName() <<
" has unexpected type.");
275 STORM_LOG_ASSERT(constraint.getManager() == this->getManager(),
"Constraint was not built over the proper variables.");
276 STORM_LOG_TRACE(
"Adding Indicator constraint " << name <<
" to GurobiLpSolver:\n"
277 <<
"\t(" << indicatorVariable.getName() <<
"==" << indicatorValue <<
") implies " << constraint);
278 indVar = this->variableToIndexMap.at(indicatorVariable);
280 int indVal = indicatorValue ? 1 : 0;
281 auto grbConstr = createConstraint<ValueType, RawMode>(constraint, this->variableToIndexMap);
283 int error = GRBaddgenconstrIndicator(model, name ==
"" ?
nullptr : name.c_str(), indVar, indVal, grbConstr.variableIndices.size(),
284 grbConstr.variableIndices.data(), grbConstr.coefficients.data(), grbConstr.sense, grbConstr.rhs);
286 "Could not assert constraint (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
289template<
typename ValueType,
bool RawMode>
295 int error = GRBsetintattr(model,
"ModelSense", this->getOptimizationDirection() == OptimizationDirection::Minimize ? 1 : -1);
297 "Unable to set Gurobi model sense (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
300 error = GRBoptimize(model);
302 "Unable to optimize Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
304 this->currentModelHasBeenOptimized =
true;
307template<
typename ValueType,
bool RawMode>
309 if (!this->currentModelHasBeenOptimized) {
310 throw storm::exceptions::InvalidStateException() <<
"Illegal call to GurobiLpSolver<ValueType, RawMode>::isInfeasible: model has not been optimized.";
313 int optimalityStatus = 0;
315 int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
317 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
321 if (optimalityStatus == GRB_INF_OR_UNBD) {
322 error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0);
324 "Unable to set Gurobi parameter (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
328 error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
330 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
332 error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 1);
334 "Unable to set Gurobi parameter (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
337 return optimalityStatus == GRB_INFEASIBLE;
340template<
typename ValueType,
bool RawMode>
342 if (!this->currentModelHasBeenOptimized) {
343 throw storm::exceptions::InvalidStateException() <<
"Illegal call to GurobiLpSolver<ValueType, RawMode>::isUnbounded: model has not been optimized.";
346 int optimalityStatus = 0;
348 int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
350 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
354 if (optimalityStatus == GRB_INF_OR_UNBD) {
355 error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0);
357 "Unable to set Gurobi parameter (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
361 error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
363 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
365 error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 1);
367 "Unable to set Gurobi parameter (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
370 return optimalityStatus == GRB_UNBOUNDED;
373template<
typename ValueType,
bool RawMode>
375 if (!this->currentModelHasBeenOptimized) {
378 int optimalityStatus = 0;
380 int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
382 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
384 return optimalityStatus == GRB_OPTIMAL;
387template<
typename ValueType,
bool RawMode>
389 if (!this->isOptimal()) {
390 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
391 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
392 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
393 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
395 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
399 if constexpr (RawMode) {
402 STORM_LOG_ASSERT(variableToIndexMap.count(variable) != 0,
"Accessing value of unknown variable '" << variable.getName() <<
"'.");
403 varIndex = variableToIndexMap.at(variable);
407 int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, varIndex, &value);
409 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
411 return storm::utility::convertNumber<ValueType>(value);
414template<
typename ValueType,
bool RawMode>
416 if (!this->isOptimal()) {
417 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
418 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
419 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
420 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
422 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
426 if constexpr (RawMode) {
429 STORM_LOG_ASSERT(variableToIndexMap.count(variable) != 0,
"Accessing value of unknown variable '" << variable.getName() <<
"'.");
430 varIndex = variableToIndexMap.at(variable);
434 int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, varIndex, &value);
436 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
437 double roundedValue = std::round(value);
438 double diff = std::abs(roundedValue - value);
439 STORM_LOG_ERROR_COND(diff <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
440 "Illegal value for integer variable in Gurobi solution (" << value <<
"). Difference to nearest int is " << diff);
441 return static_cast<int_fast64_t
>(roundedValue);
444template<
typename ValueType,
bool RawMode>
446 if (!this->isOptimal()) {
447 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
448 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
449 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
450 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
452 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
456 if constexpr (RawMode) {
459 STORM_LOG_ASSERT(variableToIndexMap.count(variable) != 0,
"Accessing value of unknown variable '" << variable.getName() <<
"'.");
460 varIndex = variableToIndexMap.at(variable);
464 int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, varIndex, &value);
466 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
469 STORM_LOG_ERROR_COND(std::abs(value - 1.0) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
470 "Illegal value for binary variable in Gurobi solution (" << value <<
").");
473 STORM_LOG_ERROR_COND(std::abs(value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
474 "Illegal value for binary variable in Gurobi solution (" << value <<
").");
479template<
typename ValueType,
bool RawMode>
481 if (!this->isOptimal()) {
482 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
483 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
484 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
485 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
487 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
491 int error = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &value);
493 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
495 return storm::utility::convertNumber<ValueType>(value);
498template<
typename ValueType,
bool RawMode>
500 int error = GRBwrite(model, filename.c_str());
502 STORM_LOG_ERROR(
"Unable to write Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
") to file.");
503 throw storm::exceptions::InvalidStateException()
504 <<
"Unable to write Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
") to file.";
508template<
typename ValueType,
bool RawMode>
510 IncrementalLevel lvl;
512 GRBgetintattr(model, GRB_INT_ATTR_NUMCONSTRS, &num);
513 lvl.firstConstraintIndex = num;
514 GRBgetintattr(model, GRB_INT_ATTR_NUMGENCONSTRS, &num);
515 lvl.firstGenConstraintIndex = num;
516 incrementalData.push_back(lvl);
519template<
typename ValueType,
bool RawMode>
521 if (incrementalData.empty()) {
524 IncrementalLevel
const& lvl = incrementalData.back();
526 GRBgetintattr(model, GRB_INT_ATTR_NUMCONSTRS, &num);
528 int error = GRBdelconstrs(model, indicesToBeRemoved.size(), indicesToBeRemoved.data());
530 "Unable to delete constraints (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
531 GRBgetintattr(model, GRB_INT_ATTR_NUMGENCONSTRS, &num);
534 "Unable to delete general constraints (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
535 indicesToBeRemoved.clear();
537 if (!lvl.variables.empty()) {
540 for (
auto const& var : lvl.variables) {
542 auto it = variableToIndexMap.find(var);
543 firstIndex = it->second;
544 variableToIndexMap.erase(it);
547 variableToIndexMap.erase(var);
551 error = GRBdelvars(model, indicesToBeRemoved.size(), indicesToBeRemoved.data());
553 "Unable to delete variables (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
554 nextVariableIndex = firstIndex;
558 GRBgetintattr(model, GRB_INT_ATTR_NUMCONSTRS, &num);
559 STORM_LOG_THROW(lvl.firstConstraintIndex == num, storm::exceptions::InvalidStateException,
"Unexpected number of constraints after deletion.");
560 GRBgetintattr(model, GRB_INT_ATTR_NUMGENCONSTRS, &num);
561 STORM_LOG_THROW(lvl.firstGenConstraintIndex == num, storm::exceptions::InvalidStateException,
562 "Unexpected number of general constraints after deletion.");
563 GRBgetintattr(model, GRB_INT_ATTR_NUMVARS, &num);
564 STORM_LOG_THROW(nextVariableIndex == num, storm::exceptions::InvalidStateException,
"Unexpected number ofvariables after deletion.");
566 incrementalData.pop_back();
570template<
typename ValueType,
bool RawMode>
572 int error = GRBsetintparam(GRBgetenv(model),
"PoolSolutions", value);
574 "Unable to set Gurobi Parameter PoolSolutions (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
577template<
typename ValueType,
bool RawMode>
579 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
580 "Illegal call to GurobiLpSolver<ValueType, RawMode>::getSolutionCount: model has not been optimized.");
582 int error = GRBgetintattr(model,
"SolCount", &result);
583 STORM_LOG_THROW(error == 0 && result >= 0, storm::exceptions::InvalidStateException,
"Unable to get solution count or invalid number of solutions.");
587template<
typename ValueType,
bool RawMode>
589 if (!this->isOptimal()) {
590 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidAccessException,
591 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
593 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
596 if constexpr (RawMode) {
599 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
600 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
601 varIndex = variableToIndexMap.at(variable);
605 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
607 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
608 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
610 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
612 return storm::utility::convertNumber<ValueType>(value);
615template<
typename ValueType,
bool RawMode>
617 if (!this->isOptimal()) {
618 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidAccessException,
619 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
621 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
624 if constexpr (RawMode) {
627 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
628 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
629 varIndex = variableToIndexMap.at(variable);
633 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
635 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
636 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
638 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
639 double roundedValue = std::round(value);
640 double diff = std::abs(roundedValue - value);
641 STORM_LOG_ERROR_COND(diff <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
642 "Illegal value for integer variable in Gurobi solution (" << value <<
"). Difference to nearest int is " << diff);
643 return static_cast<int_fast64_t
>(roundedValue);
646template<
typename ValueType,
bool RawMode>
648 if (!this->isOptimal()) {
649 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidAccessException,
650 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
652 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
655 if constexpr (RawMode) {
658 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
659 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
660 varIndex = variableToIndexMap.at(variable);
664 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
666 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
667 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
669 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
672 STORM_LOG_ERROR_COND(std::abs(value - 1) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
673 "Illegal value for integer variable in Gurobi solution (" << value <<
").");
676 STORM_LOG_ERROR_COND(std::abs(value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
677 "Illegal value for integer variable in Gurobi solution (" << value <<
").");
682template<
typename ValueType,
bool RawMode>
684 if (!this->isOptimal()) {
685 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidAccessException,
686 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
688 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
691 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
693 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
694 error = GRBgetdblattr(model, GRB_DBL_ATTR_POOLOBJVAL, &value);
696 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
698 return storm::utility::convertNumber<ValueType>(value);
701template<
typename ValueType,
bool RawMode>
705 error = GRBsetdblparam(GRBgetenv(model), GRB_DBL_PAR_MIPGAP, storm::utility::convertNumber<double>(gap));
707 error = GRBsetdblparam(GRBgetenv(model), GRB_DBL_PAR_MIPGAPABS, storm::utility::convertNumber<double>(gap));
710 "Unable to set Gurobi MILP GAP (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
713template<
typename ValueType,
bool RawMode>
716 int error = GRBgetdblattr(model, GRB_DBL_ATTR_MIPGAP, &relativeGap);
718 "Unable to get Gurobi MILP GAP (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
719 auto result = storm::utility::convertNumber<ValueType>(relativeGap);
723 return storm::utility::abs<ValueType>(result * getObjectiveValue());
727template<
typename ValueType,
bool RawMode>
729 int error = GRBsetdblparam(GRBgetenv(model), GRB_DBL_PAR_TIMELIMIT, seconds);
730 timeLimit.emplace(seconds);
732 "Unable to set Gurobi time limit (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
735template<
typename ValueType,
bool RawMode>
737 STORM_LOG_THROW(timeLimit.has_value(), storm::exceptions::InvalidAccessException,
"Unable to get Gurobi time limit because none was specified.");
738 return timeLimit.value();
741template<
typename ValueType,
bool RawMode>
743 return timeLimit.has_value();
746template<
typename ValueType,
bool RawMode>
748 if (!this->currentModelHasBeenOptimized) {
753 int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &status);
755 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
757 return status == GRB_TIME_LIMIT;
761template<
typename ValueType,
bool RawMode>
763 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
764 "requires this support. Please choose a version of support with Gurobi support.";
767template<
typename ValueType,
bool RawMode>
769 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
770 "requires this support. Please choose a version of support with Gurobi support.";
773template<
typename ValueType,
bool RawMode>
775 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
776 "requires this support. Please choose a version of support with Gurobi support.";
779template<
typename ValueType,
bool RawMode>
781 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
782 "requires this support. Please choose a version of support with Gurobi support.";
785template<
typename ValueType,
bool RawMode>
788template<
typename ValueType,
bool RawMode>
790 std::optional<ValueType>
const&,
791 std::optional<ValueType>
const&, ValueType) {
792 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
793 "requires this support. Please choose a version of support with Gurobi support.";
796template<
typename ValueType,
bool RawMode>
798 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
799 "requires this support. Please choose a version of support with Gurobi support.";
802template<
typename ValueType,
bool RawMode>
804 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
805 "requires this support. Please choose a version of support with Gurobi support.";
808template<
typename ValueType,
bool RawMode>
810 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
811 "requires this support. Please choose a version of support with Gurobi support.";
814template<
typename ValueType,
bool RawMode>
816 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
817 "requires this support. Please choose a version of support with Gurobi support.";
820template<
typename ValueType,
bool RawMode>
822 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
823 "requires this support. Please choose a version of support with Gurobi support.";
826template<
typename ValueType,
bool RawMode>
828 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
829 "requires this support. Please choose a version of support with Gurobi support.";
832template<
typename ValueType,
bool RawMode>
834 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
835 "requires this support. Please choose a version of support with Gurobi support.";
838template<
typename ValueType,
bool RawMode>
840 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
841 "requires this support. Please choose a version of support with Gurobi support.";
844template<
typename ValueType,
bool RawMode>
846 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
847 "requires this support. Please choose a version of support with Gurobi support.";
850template<
typename ValueType,
bool RawMode>
852 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
853 "requires this support. Please choose a version of support with Gurobi support.";
856template<
typename ValueType,
bool RawMode>
858 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
859 "requires this support. Please choose a version of support with Gurobi support.";
862template<
typename ValueType,
bool RawMode>
864 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
865 "requires this support. Please choose a version of support with Gurobi support.";
868template<
typename ValueType,
bool RawMode>
870 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
871 "requires this support. Please choose a version of support with Gurobi support.";
874template<
typename ValueType,
bool RawMode>
876 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
877 "requires this support. Please choose a version of support with Gurobi support.";
880template<
typename ValueType,
bool RawMode>
882 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
883 "requires this support. Please choose a version of storm with Gurobi support.";
886template<
typename ValueType,
bool RawMode>
888 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
889 "requires this support. Please choose a version of storm with Gurobi support.";
892template<
typename ValueType,
bool RawMode>
894 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
895 "requires this support. Please choose a version of storm with Gurobi support.";
898template<
typename ValueType,
bool RawMode>
900 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
901 "requires this support. Please choose a version of storm with Gurobi support.";
904template<
typename ValueType,
bool RawMode>
906 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
907 "requires this support. Please choose a version of storm with Gurobi support.";
910template<
typename ValueType,
bool RawMode>
912 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
913 "requires this support. Please choose a version of storm with Gurobi support.";
916template<
typename ValueType,
bool RawMode>
918 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
919 "requires this support. Please choose a version of storm with Gurobi support.";
922template<
typename ValueType,
bool RawMode>
924 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
925 "requires this support. Please choose a version of storm with Gurobi support.";
928template<
typename ValueType,
bool RawMode>
930 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
931 "requires this support. Please choose a version of storm with Gurobi support.";
934template<
typename ValueType,
bool RawMode>
936 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
937 "requires this support. Please choose a version of storm with Gurobi support.";
940template<
typename ValueType,
bool RawMode>
942 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
943 "requires this support. Please choose a version of storm with Gurobi support.";
946template<
typename ValueType,
bool RawMode>
948 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
949 "requires this support. Please choose a version of storm with Gurobi support.";
959 return "primal-simplex";
961 return "dual-simplex";
967 return "deterministic-concurrent";
969 return "deterministic-concurrent-simplex";
971 STORM_LOG_THROW(
false, storm::exceptions::InvalidArgumentException,
"Unknown solver method");
988template class GurobiLpSolver<double, true>;
989template class GurobiLpSolver<double, false>;
990template class GurobiLpSolver<storm::RationalNumber, true>;
991template class GurobiLpSolver<storm::RationalNumber, false>;
VariableCoefficients getLinearCoefficients(Expression const &expression)
Computes the (double) coefficients of all identifiers appearing in the expression if the expression w...
void setOutput(bool set=false)
void initialize()
Sets some properties of the Gurobi environment according to parameters given by the options.
virtual ~GurobiEnvironment()
virtual ~GurobiLpSolver()
Destructs a solver by freeing the pointers to Gurobi's structures.
virtual bool isInfeasible() const override
Retrieves whether the model was found to be infeasible.
virtual int_fast64_t getIntegerValue(Variable const &name) const override
Retrieves the value of the integer variable with the given name.
virtual bool isUnbounded() const override
Retrieves whether the model was found to be infeasible.
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.
void setMaximalSolutionCount(uint64_t value)
typename LpSolver< ValueType, RawMode >::VariableType VariableType
GurobiLpSolver(std::shared_ptr< GurobiEnvironment > const &environment, std::string const &name, OptimizationDirection const &optDir)
Constructs a solver with the given name and model sense.
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 ValueType getContinuousValue(Variable const &name) const override
Retrieves the value of the continuous variable with the given name.
virtual bool getBinaryValue(Variable const &name) const override
Retrieves the value of the binary variable with the given name.
virtual ValueType getObjectiveValue() const override
Retrieves the value of the objective function.
void setTimeLimit(uint64_t seconds)
virtual void pop() override
Pops a backtracking point from the solver's stack.
virtual void writeModelToFile(std::string const &filename) const override
Writes the current LP problem to the given file.
typename LpSolver< ValueType, RawMode >::Variable Variable
virtual void optimize() const override
Optimizes the LP problem previously constructed.
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.
uint64_t getSolutionCount() const
typename LpSolver< ValueType, RawMode >::Constraint Constraint
virtual ValueType getMILPGap(bool relative) const override
Returns the obtained gap after a call to optimize()
virtual bool isOptimal() const override
Retrieves whether the model was found to be optimal, i.e.
virtual void update() const override
Updates the model to make the variables that have been declared since the last call to update usable.
An interface that captures the functionality of an LP solver.
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ERROR(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_ERROR_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
SFTBDDChecker::ValueType ValueType
RelationType
An enum type specifying the different relations applicable.
std::string toString(GurobiSolverMethod const &method)
Yields a string representation of the GurobiSolverMethod.
std::optional< GurobiSolverMethod > gurobiSolverMethodFromString(std::string const &method)
std::vector< GurobiSolverMethod > getGurobiSolverMethods()
std::vector< T > buildVectorForRange(T min, T max)
Constructs a vector [min, min+1, ...., max-1].
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
double getConstantPart() const