28#ifdef STORM_HAVE_GUROBI
35#ifdef STORM_HAVE_GUROBI
36GRBenv* GurobiEnvironment::operator*() {
37 STORM_LOG_ASSERT(initialized,
"Gurobi Environment has not been initialized");
43#ifdef STORM_HAVE_GUROBI
45 int error = GRBloadenv(&env,
"");
46 if (error || env ==
nullptr) {
48 STORM_LOG_ERROR(
"Gurobi License Issue. " << GRBgeterrormsg(env) <<
", error code " << error <<
").");
49 throw storm::exceptions::GurobiLicenseException()
50 <<
"Could not initialize Gurobi environment (" << GRBgeterrormsg(env) <<
", error code " << error <<
").";
52 STORM_LOG_ERROR(
"Could not initialize Gurobi (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
53 throw storm::exceptions::InvalidStateException()
54 <<
"Could not initialize Gurobi environment (" << GRBgeterrormsg(env) <<
", error code " << error <<
").";
56 setOutput(storm::settings::getModule<storm::settings::modules::DebugSettings>().isDebugSet() ||
57 storm::settings::getModule<storm::settings::modules::GurobiSettings>().isOutputSet());
59 error = GRBsetintparam(env,
"Method",
static_cast<int>(storm::settings::getModule<storm::settings::modules::GurobiSettings>().getMethod()));
61 "Unable to set Gurobi Parameter Method (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
64 error = GRBsetintparam(env,
"Threads", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getNumberOfThreads());
66 "Unable to set Gurobi Parameter Threads (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
68 error = GRBsetintparam(env,
"MIPFocus", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getMIPFocus());
70 "Unable to set Gurobi Parameter MIPFocus (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
72 error = GRBsetintparam(env,
"ConcurrentMIP", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getNumberOfConcurrentMipThreads());
74 "Unable to set Gurobi Parameter ConcurrentMIP (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
77 error = GRBsetdblparam(env,
"IntFeasTol", storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance());
79 "Unable to set Gurobi Parameter IntFeasTol (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
85#ifdef STORM_HAVE_GUROBI
86 int error = GRBsetintparam(env,
"OutputFlag", set);
88 "Unable to set Gurobi Parameter OutputFlag (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
94#ifdef STORM_HAVE_GUROBI
96template<
typename ValueType,
bool RawMode>
99 :
LpSolver<ValueType, RawMode>(optDir), model(nullptr), environment(environment), nextVariableIndex(0) {
102 error = GRBnewmodel(**environment, &model, name.c_str(), 0,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr);
104 STORM_LOG_ERROR(
"Could not initialize Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
105 throw storm::exceptions::InvalidStateException()
106 <<
"Could not initialize Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").";
110template<
typename ValueType,
bool RawMode>
116template<
typename ValueType,
bool RawMode>
118 : GurobiLpSolver(environment,
"", optDir) {
122template<
typename ValueType,
bool RawMode>
128template<
typename ValueType,
bool RawMode>
134template<
typename ValueType,
bool RawMode>
136 int error = GRBupdatemodel(model);
138 "Unable to update Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
141 this->currentModelHasBeenOptimized =
false;
144template<
typename ValueType,
bool RawMode>
147 case GurobiLpSolver<ValueType, RawMode>::VariableType::Continuous:
148 return GRB_CONTINUOUS;
149 case GurobiLpSolver<ValueType, RawMode>::VariableType::Integer:
151 case GurobiLpSolver<ValueType, RawMode>::VariableType::Binary:
158template<
typename ValueType,
bool RawMode>
160 std::optional<ValueType>
const& lowerBound,
161 std::optional<ValueType>
const& upperBound,
162 ValueType objectiveFunctionCoefficient) {
164 if constexpr (RawMode) {
165 resultVar = nextVariableIndex;
167 resultVar = this->declareOrGetExpressionVariable(name, type);
170 STORM_LOG_ASSERT(variableToIndexMap.count(resultVar) == 0,
"Variable " << resultVar.getName() <<
" exists already in the model.");
171 this->variableToIndexMap.emplace(resultVar, nextVariableIndex);
172 if (!incrementalData.empty()) {
173 incrementalData.back().variables.push_back(resultVar);
180 error = GRBaddvar(model, 0,
nullptr,
nullptr, storm::utility::convertNumber<double>(objectiveFunctionCoefficient),
181 lowerBound.has_value() ? storm::utility::convertNumber<double>(*lowerBound) : -GRB_INFINITY,
182 upperBound.has_value() ?
storm::utility::
convertNumber<double>(*upperBound) : GRB_INFINITY, getGurobiType<
ValueType, RawMode>(type),
185 "Could not create binary Gurobi variable (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
189struct GurobiConstraint {
190 std::vector<int> variableIndices;
191 std::vector<double> coefficients;
196template<
typename ValueType,
bool RawMode>
198 std::map<storm::expressions::Variable, int>
const& variableToIndexMap) {
199 GurobiConstraint gurobiConstraint;
201 if constexpr (RawMode) {
202 gurobiConstraint.rhs = storm::utility::convertNumber<double>(constraint.rhs);
203 relationType = constraint.relationType;
204 gurobiConstraint.variableIndices.insert(gurobiConstraint.variableIndices.end(), constraint.lhsVariableIndices.begin(),
205 constraint.lhsVariableIndices.end());
206 gurobiConstraint.coefficients.reserve(constraint.lhsCoefficients.size());
207 for (
auto const& coef : constraint.lhsCoefficients) {
208 gurobiConstraint.coefficients.push_back(storm::utility::convertNumber<double>(coef));
211 STORM_LOG_THROW(constraint.isRelationalExpression(), storm::exceptions::InvalidArgumentException,
"Illegal constraint is not a relational expression.");
218 relationType = constraint.getBaseExpression().asBinaryRelationExpression().getRelationType();
219 int len = std::distance(leftCoefficients.
begin(), leftCoefficients.
end());
220 gurobiConstraint.variableIndices.reserve(len);
221 gurobiConstraint.coefficients.reserve(len);
222 for (
auto const& variableCoefficientPair : leftCoefficients) {
223 auto variableIndexPair = variableToIndexMap.find(variableCoefficientPair.first);
224 gurobiConstraint.variableIndices.push_back(variableIndexPair->second);
225 gurobiConstraint.coefficients.push_back(variableCoefficientPair.second);
229 switch (relationType) {
231 gurobiConstraint.sense = GRB_LESS_EQUAL;
232 gurobiConstraint.rhs -= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance();
235 gurobiConstraint.sense = GRB_LESS_EQUAL;
238 gurobiConstraint.sense = GRB_GREATER_EQUAL;
239 gurobiConstraint.rhs += storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance();
242 gurobiConstraint.sense = GRB_GREATER_EQUAL;
245 gurobiConstraint.sense = GRB_EQUAL;
250 return gurobiConstraint;
253template<
typename ValueType,
bool RawMode>
255 if constexpr (!RawMode) {
256 STORM_LOG_TRACE(
"Adding constraint " << name <<
" to GurobiLpSolver:\n"
257 <<
"\t" << constraint);
258 STORM_LOG_ASSERT(constraint.getManager() == this->getManager(),
"Constraint was not built over the proper variables.");
262 auto grbConstr = createConstraint<ValueType, RawMode>(constraint, this->variableToIndexMap);
263 int error = GRBaddconstr(model, grbConstr.variableIndices.size(), grbConstr.variableIndices.data(), grbConstr.coefficients.data(), grbConstr.sense,
264 grbConstr.rhs, name ==
"" ?
nullptr : name.c_str());
266 "Could not assert constraint (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
269template<
typename ValueType,
bool RawMode>
271 Constraint
const& constraint) {
274 if constexpr (RawMode) {
275 indVar = indicatorVariable;
277 STORM_LOG_ASSERT(this->variableToIndexMap.count(indicatorVariable) > 0,
"Indicator Variable " << indicatorVariable.getName() <<
" unknown to solver.");
278 STORM_LOG_ASSERT(indicatorVariable.hasIntegerType(),
"Indicator Variable " << indicatorVariable.getName() <<
" has unexpected type.");
279 STORM_LOG_ASSERT(constraint.getManager() == this->getManager(),
"Constraint was not built over the proper variables.");
280 STORM_LOG_TRACE(
"Adding Indicator constraint " << name <<
" to GurobiLpSolver:\n"
281 <<
"\t(" << indicatorVariable.getName() <<
"==" << indicatorValue <<
") implies " << constraint);
282 indVar = this->variableToIndexMap.at(indicatorVariable);
284 int indVal = indicatorValue ? 1 : 0;
285 auto grbConstr = createConstraint<ValueType, RawMode>(constraint, this->variableToIndexMap);
287 int error = GRBaddgenconstrIndicator(model, name ==
"" ?
nullptr : name.c_str(), indVar, indVal, grbConstr.variableIndices.size(),
288 grbConstr.variableIndices.data(), grbConstr.coefficients.data(), grbConstr.sense, grbConstr.rhs);
290 "Could not assert constraint (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
293template<
typename ValueType,
bool RawMode>
299 int error = GRBsetintattr(model,
"ModelSense", this->getOptimizationDirection() == OptimizationDirection::Minimize ? 1 : -1);
301 "Unable to set Gurobi model sense (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
304 error = GRBoptimize(model);
306 "Unable to optimize Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
308 this->currentModelHasBeenOptimized =
true;
311template<
typename ValueType,
bool RawMode>
313 if (!this->currentModelHasBeenOptimized) {
314 throw storm::exceptions::InvalidStateException() <<
"Illegal call to GurobiLpSolver<ValueType, RawMode>::isInfeasible: model has not been optimized.";
317 int optimalityStatus = 0;
319 int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
321 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
325 if (optimalityStatus == GRB_INF_OR_UNBD) {
326 error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0);
328 "Unable to set Gurobi parameter (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
332 error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
334 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
336 error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 1);
338 "Unable to set Gurobi parameter (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
341 return optimalityStatus == GRB_INFEASIBLE;
344template<
typename ValueType,
bool RawMode>
346 if (!this->currentModelHasBeenOptimized) {
347 throw storm::exceptions::InvalidStateException() <<
"Illegal call to GurobiLpSolver<ValueType, RawMode>::isUnbounded: model has not been optimized.";
350 int optimalityStatus = 0;
352 int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
354 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
358 if (optimalityStatus == GRB_INF_OR_UNBD) {
359 error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 0);
361 "Unable to set Gurobi parameter (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
365 error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
367 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
369 error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_DUALREDUCTIONS, 1);
371 "Unable to set Gurobi parameter (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
374 return optimalityStatus == GRB_UNBOUNDED;
377template<
typename ValueType,
bool RawMode>
379 if (!this->currentModelHasBeenOptimized) {
382 int optimalityStatus = 0;
384 int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &optimalityStatus);
386 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
388 return optimalityStatus == GRB_OPTIMAL;
391template<
typename ValueType,
bool RawMode>
393 if (!this->isOptimal()) {
394 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
395 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
396 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
397 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
399 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
403 if constexpr (RawMode) {
406 STORM_LOG_ASSERT(variableToIndexMap.count(variable) != 0,
"Accessing value of unknown variable '" << variable.getName() <<
"'.");
407 varIndex = variableToIndexMap.at(variable);
411 int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, varIndex, &value);
413 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
415 return storm::utility::convertNumber<ValueType>(value);
418template<
typename ValueType,
bool RawMode>
420 if (!this->isOptimal()) {
421 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
422 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
423 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
424 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
426 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
430 if constexpr (RawMode) {
433 STORM_LOG_ASSERT(variableToIndexMap.count(variable) != 0,
"Accessing value of unknown variable '" << variable.getName() <<
"'.");
434 varIndex = variableToIndexMap.at(variable);
438 int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, varIndex, &value);
440 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
441 double roundedValue = std::round(value);
442 double diff = std::abs(roundedValue - value);
443 STORM_LOG_ERROR_COND(diff <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
444 "Illegal value for integer variable in Gurobi solution (" << value <<
"). Difference to nearest int is " << diff);
445 return static_cast<int_fast64_t
>(roundedValue);
448template<
typename ValueType,
bool RawMode>
450 if (!this->isOptimal()) {
451 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
452 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
453 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
454 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
456 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
460 if constexpr (RawMode) {
463 STORM_LOG_ASSERT(variableToIndexMap.count(variable) != 0,
"Accessing value of unknown variable '" << variable.getName() <<
"'.");
464 varIndex = variableToIndexMap.at(variable);
468 int error = GRBgetdblattrelement(model, GRB_DBL_ATTR_X, varIndex, &value);
470 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
473 STORM_LOG_ERROR_COND(std::abs(value - 1.0) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
474 "Illegal value for binary variable in Gurobi solution (" << value <<
").");
477 STORM_LOG_ERROR_COND(std::abs(value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
478 "Illegal value for binary variable in Gurobi solution (" << value <<
").");
483template<
typename ValueType,
bool RawMode>
485 if (!this->isOptimal()) {
486 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
487 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
488 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
489 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
491 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
495 int error = GRBgetdblattr(model, GRB_DBL_ATTR_OBJVAL, &value);
497 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
499 return storm::utility::convertNumber<ValueType>(value);
502template<
typename ValueType,
bool RawMode>
504 int error = GRBwrite(model, filename.c_str());
506 STORM_LOG_ERROR(
"Unable to write Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
") to file.");
507 throw storm::exceptions::InvalidStateException()
508 <<
"Unable to write Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
") to file.";
512template<
typename ValueType,
bool RawMode>
514 IncrementalLevel lvl;
516 GRBgetintattr(model, GRB_INT_ATTR_NUMCONSTRS, &num);
517 lvl.firstConstraintIndex = num;
518 GRBgetintattr(model, GRB_INT_ATTR_NUMGENCONSTRS, &num);
519 lvl.firstGenConstraintIndex = num;
520 incrementalData.push_back(lvl);
523template<
typename ValueType,
bool RawMode>
525 if (incrementalData.empty()) {
528 IncrementalLevel
const& lvl = incrementalData.back();
530 GRBgetintattr(model, GRB_INT_ATTR_NUMCONSTRS, &num);
532 int error = GRBdelconstrs(model, indicesToBeRemoved.size(), indicesToBeRemoved.data());
534 "Unable to delete constraints (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
535 GRBgetintattr(model, GRB_INT_ATTR_NUMGENCONSTRS, &num);
538 "Unable to delete general constraints (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
539 indicesToBeRemoved.clear();
541 if (!lvl.variables.empty()) {
544 for (
auto const& var : lvl.variables) {
546 auto it = variableToIndexMap.find(var);
547 firstIndex = it->second;
548 variableToIndexMap.erase(it);
551 variableToIndexMap.erase(var);
555 error = GRBdelvars(model, indicesToBeRemoved.size(), indicesToBeRemoved.data());
557 "Unable to delete variables (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
558 nextVariableIndex = firstIndex;
562 GRBgetintattr(model, GRB_INT_ATTR_NUMCONSTRS, &num);
563 STORM_LOG_THROW(lvl.firstConstraintIndex == num, storm::exceptions::InvalidStateException,
"Unexpected number of constraints after deletion.");
564 GRBgetintattr(model, GRB_INT_ATTR_NUMGENCONSTRS, &num);
565 STORM_LOG_THROW(lvl.firstGenConstraintIndex == num, storm::exceptions::InvalidStateException,
566 "Unexpected number of general constraints after deletion.");
567 GRBgetintattr(model, GRB_INT_ATTR_NUMVARS, &num);
568 STORM_LOG_THROW(nextVariableIndex == num, storm::exceptions::InvalidStateException,
"Unexpected number ofvariables after deletion.");
570 incrementalData.pop_back();
574template<
typename ValueType,
bool RawMode>
576 int error = GRBsetintparam(GRBgetenv(model),
"PoolSolutions", value);
578 "Unable to set Gurobi Parameter PoolSolutions (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
581template<
typename ValueType,
bool RawMode>
583 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidStateException,
584 "Illegal call to GurobiLpSolver<ValueType, RawMode>::getSolutionCount: model has not been optimized.");
586 int error = GRBgetintattr(model,
"SolCount", &result);
587 STORM_LOG_THROW(error == 0 && result >= 0, storm::exceptions::InvalidStateException,
"Unable to get solution count or invalid number of solutions.");
591template<
typename ValueType,
bool RawMode>
593 if (!this->isOptimal()) {
594 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidAccessException,
595 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
597 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
600 if constexpr (RawMode) {
603 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
604 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
605 varIndex = variableToIndexMap.at(variable);
609 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
611 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
612 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
614 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
616 return storm::utility::convertNumber<ValueType>(value);
619template<
typename ValueType,
bool RawMode>
621 if (!this->isOptimal()) {
622 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidAccessException,
623 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
625 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
628 if constexpr (RawMode) {
631 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
632 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
633 varIndex = variableToIndexMap.at(variable);
637 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
639 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
640 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
642 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
643 double roundedValue = std::round(value);
644 double diff = std::abs(roundedValue - value);
645 STORM_LOG_ERROR_COND(diff <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
646 "Illegal value for integer variable in Gurobi solution (" << value <<
"). Difference to nearest int is " << diff);
647 return static_cast<int_fast64_t
>(roundedValue);
650template<
typename ValueType,
bool RawMode>
652 if (!this->isOptimal()) {
653 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidAccessException,
654 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
656 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
659 if constexpr (RawMode) {
662 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
663 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
664 varIndex = variableToIndexMap.at(variable);
668 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
670 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
671 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
673 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
676 STORM_LOG_ERROR_COND(std::abs(value - 1) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
677 "Illegal value for integer variable in Gurobi solution (" << value <<
").");
680 STORM_LOG_ERROR_COND(std::abs(value) <= storm::settings::getModule<storm::settings::modules::GurobiSettings>().getIntegerTolerance(),
681 "Illegal value for integer variable in Gurobi solution (" << value <<
").");
686template<
typename ValueType,
bool RawMode>
688 if (!this->isOptimal()) {
689 STORM_LOG_THROW(this->currentModelHasBeenOptimized, storm::exceptions::InvalidAccessException,
690 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
692 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
695 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
697 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
698 error = GRBgetdblattr(model, GRB_DBL_ATTR_POOLOBJVAL, &value);
700 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
702 return storm::utility::convertNumber<ValueType>(value);
705template<
typename ValueType,
bool RawMode>
709 error = GRBsetdblparam(GRBgetenv(model), GRB_DBL_PAR_MIPGAP, storm::utility::convertNumber<double>(gap));
711 error = GRBsetdblparam(GRBgetenv(model), GRB_DBL_PAR_MIPGAPABS, storm::utility::convertNumber<double>(gap));
714 "Unable to set Gurobi MILP GAP (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
717template<
typename ValueType,
bool RawMode>
720 int error = GRBgetdblattr(model, GRB_DBL_ATTR_MIPGAP, &relativeGap);
722 "Unable to get Gurobi MILP GAP (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
723 auto result = storm::utility::convertNumber<ValueType>(relativeGap);
727 return storm::utility::abs<ValueType>(result * getObjectiveValue());
731template<
typename ValueType,
bool RawMode>
733 int error = GRBsetdblparam(GRBgetenv(model), GRB_DBL_PAR_TIMELIMIT, seconds);
734 timeLimit.emplace(seconds);
736 "Unable to set Gurobi time limit (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
739template<
typename ValueType,
bool RawMode>
741 STORM_LOG_THROW(timeLimit.has_value(), storm::exceptions::InvalidAccessException,
"Unable to get Gurobi time limit because none was specified.");
742 return timeLimit.value();
745template<
typename ValueType,
bool RawMode>
747 return timeLimit.has_value();
750template<
typename ValueType,
bool RawMode>
752 if (!this->currentModelHasBeenOptimized) {
757 int error = GRBgetintattr(model, GRB_INT_ATTR_STATUS, &status);
759 "Unable to retrieve optimization status of Gurobi model (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
761 return status == GRB_TIME_LIMIT;
765template<
typename ValueType,
bool RawMode>
767 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
768 "requires this support. Please choose a version of support with Gurobi support.";
771template<
typename ValueType,
bool RawMode>
773 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
774 "requires this support. Please choose a version of support with Gurobi support.";
777template<
typename ValueType,
bool RawMode>
779 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
780 "requires this support. Please choose a version of support with Gurobi support.";
783template<
typename ValueType,
bool RawMode>
785 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
786 "requires this support. Please choose a version of support with Gurobi support.";
789template<
typename ValueType,
bool RawMode>
792template<
typename ValueType,
bool RawMode>
794 std::optional<ValueType>
const&,
795 std::optional<ValueType>
const&, ValueType) {
796 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
797 "requires this support. Please choose a version of support with Gurobi support.";
800template<
typename ValueType,
bool RawMode>
802 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
803 "requires this support. Please choose a version of support with Gurobi support.";
806template<
typename ValueType,
bool RawMode>
808 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
809 "requires this support. Please choose a version of support with Gurobi support.";
812template<
typename ValueType,
bool RawMode>
814 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
815 "requires this support. Please choose a version of support with Gurobi support.";
818template<
typename ValueType,
bool RawMode>
820 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
821 "requires this support. Please choose a version of support with Gurobi support.";
824template<
typename ValueType,
bool RawMode>
826 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
827 "requires this support. Please choose a version of support with Gurobi support.";
830template<
typename ValueType,
bool RawMode>
832 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
833 "requires this support. Please choose a version of support with Gurobi support.";
836template<
typename ValueType,
bool RawMode>
838 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
839 "requires this support. Please choose a version of support with Gurobi support.";
842template<
typename ValueType,
bool RawMode>
844 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
845 "requires this support. Please choose a version of support with Gurobi support.";
848template<
typename ValueType,
bool RawMode>
850 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
851 "requires this support. Please choose a version of support with Gurobi support.";
854template<
typename ValueType,
bool RawMode>
856 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
857 "requires this support. Please choose a version of support with Gurobi support.";
860template<
typename ValueType,
bool RawMode>
862 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
863 "requires this support. Please choose a version of support with Gurobi support.";
866template<
typename ValueType,
bool RawMode>
868 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
869 "requires this support. Please choose a version of support with Gurobi support.";
872template<
typename ValueType,
bool RawMode>
874 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
875 "requires this support. Please choose a version of support with Gurobi support.";
878template<
typename ValueType,
bool RawMode>
880 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
881 "requires this support. Please choose a version of support with Gurobi support.";
884template<
typename ValueType,
bool RawMode>
886 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
887 "requires this support. Please choose a version of storm with Gurobi support.";
890template<
typename ValueType,
bool RawMode>
892 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
893 "requires this support. Please choose a version of storm with Gurobi support.";
896template<
typename ValueType,
bool RawMode>
898 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
899 "requires this support. Please choose a version of storm with Gurobi support.";
902template<
typename ValueType,
bool RawMode>
904 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
905 "requires this support. Please choose a version of storm with Gurobi support.";
908template<
typename ValueType,
bool RawMode>
910 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
911 "requires this support. Please choose a version of storm with Gurobi support.";
914template<
typename ValueType,
bool RawMode>
916 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
917 "requires this support. Please choose a version of storm with Gurobi support.";
920template<
typename ValueType,
bool RawMode>
922 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
923 "requires this support. Please choose a version of storm with Gurobi support.";
926template<
typename ValueType,
bool RawMode>
928 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
929 "requires this support. Please choose a version of storm with Gurobi support.";
932template<
typename ValueType,
bool RawMode>
934 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
935 "requires this support. Please choose a version of storm with Gurobi support.";
938template<
typename ValueType,
bool RawMode>
940 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
941 "requires this support. Please choose a version of storm with Gurobi support.";
944template<
typename ValueType,
bool RawMode>
946 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
947 "requires this support. Please choose a version of storm with Gurobi support.";
950template<
typename ValueType,
bool RawMode>
952 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
953 "requires this support. Please choose a version of storm with Gurobi support.";
963 return "primal-simplex";
965 return "dual-simplex";
971 return "deterministic-concurrent";
973 return "deterministic-concurrent-simplex";
975 STORM_LOG_THROW(
false, storm::exceptions::InvalidArgumentException,
"Unknown solver method");
992template class GurobiLpSolver<double, true>;
993template class GurobiLpSolver<double, false>;
994template class GurobiLpSolver<storm::RationalNumber, true>;
995template 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