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 <<
").";
61 "Unable to set Gurobi Parameter Method (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
66 "Unable to set Gurobi Parameter Threads (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
70 "Unable to set Gurobi Parameter MIPFocus (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
74 "Unable to set Gurobi Parameter ConcurrentMIP (" << GRBgeterrormsg(env) <<
", error code " << error <<
").");
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;
235 gurobiConstraint.sense = GRB_LESS_EQUAL;
238 gurobiConstraint.sense = GRB_GREATER_EQUAL;
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);
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 <<
").");
474 "Illegal value for binary variable in Gurobi solution (" << value <<
").");
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->isInfeasible(), storm::exceptions::InvalidAccessException,
595 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
596 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
597 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
599 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
601 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
604 if constexpr (RawMode) {
607 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
608 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
609 varIndex = variableToIndexMap.at(variable);
613 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
615 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
616 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
618 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
620 return storm::utility::convertNumber<ValueType>(value);
623template<
typename ValueType,
bool RawMode>
625 if (!this->isOptimal()) {
626 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
627 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
628 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
629 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
631 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
633 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
636 if constexpr (RawMode) {
639 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
640 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
641 varIndex = variableToIndexMap.at(variable);
645 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
647 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
648 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
650 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
651 double roundedValue = std::round(value);
652 double diff = std::abs(roundedValue - value);
654 "Illegal value for integer variable in Gurobi solution (" << value <<
"). Difference to nearest int is " << diff);
655 return static_cast<int_fast64_t
>(roundedValue);
658template<
typename ValueType,
bool RawMode>
660 if (!this->isOptimal()) {
661 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
662 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
663 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
664 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
666 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
668 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
671 if constexpr (RawMode) {
674 STORM_LOG_THROW(variableToIndexMap.count(variable) != 0, storm::exceptions::InvalidAccessException,
675 "Accessing value of unknown variable '" << variable.getName() <<
"'.");
676 varIndex = variableToIndexMap.at(variable);
680 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
682 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
683 error = GRBgetdblattrelement(model, GRB_DBL_ATTR_Xn, varIndex, &value);
685 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
689 "Illegal value for integer variable in Gurobi solution (" << value <<
").");
693 "Illegal value for integer variable in Gurobi solution (" << value <<
").");
698template<
typename ValueType,
bool RawMode>
700 if (!this->isOptimal()) {
701 STORM_LOG_THROW(!this->isInfeasible(), storm::exceptions::InvalidAccessException,
702 "Unable to get Gurobi solution from infeasible model (" << GRBgeterrormsg(**environment) <<
").");
703 STORM_LOG_THROW(!this->isUnbounded(), storm::exceptions::InvalidAccessException,
704 "Unable to get Gurobi solution from unbounded model (" << GRBgeterrormsg(**environment) <<
").");
706 "Unable to get Gurobi solution from unoptimized model (" << GRBgeterrormsg(**environment) <<
").");
708 STORM_LOG_ASSERT(solutionIndex < getSolutionCount(),
"Invalid solution index.");
711 int error = GRBsetintparam(GRBgetenv(model), GRB_INT_PAR_SOLUTIONNUMBER, solutionIndex);
713 "Unable to set Gurobi solution index (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
714 error = GRBgetdblattr(model, GRB_DBL_ATTR_POOLOBJVAL, &value);
716 "Unable to get Gurobi solution (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
718 return storm::utility::convertNumber<ValueType>(value);
721template<
typename ValueType,
bool RawMode>
725 error = GRBsetdblparam(GRBgetenv(model), GRB_DBL_PAR_MIPGAP, storm::utility::convertNumber<double>(gap));
727 error = GRBsetdblparam(GRBgetenv(model), GRB_DBL_PAR_MIPGAPABS, storm::utility::convertNumber<double>(gap));
730 "Unable to set Gurobi MILP GAP (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
733template<
typename ValueType,
bool RawMode>
736 int error = GRBgetdblattr(model, GRB_DBL_ATTR_MIPGAP, &relativeGap);
738 "Unable to get Gurobi MILP GAP (" << GRBgeterrormsg(**environment) <<
", error code " << error <<
").");
739 auto result = storm::utility::convertNumber<ValueType>(relativeGap);
743 return storm::utility::abs<ValueType>(result * getObjectiveValue());
748template<
typename ValueType,
bool RawMode>
750 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
751 "requires this support. Please choose a version of support with Gurobi support.";
754template<
typename ValueType,
bool RawMode>
756 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
757 "requires this support. Please choose a version of support with Gurobi support.";
760template<
typename ValueType,
bool RawMode>
762 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
763 "requires this support. Please choose a version of support with Gurobi support.";
766template<
typename ValueType,
bool RawMode>
768 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
769 "requires this support. Please choose a version of support with Gurobi support.";
772template<
typename ValueType,
bool RawMode>
775template<
typename ValueType,
bool RawMode>
777 std::optional<ValueType>
const&,
778 std::optional<ValueType>
const&, ValueType) {
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>
791 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
792 "requires this support. Please choose a version of support with Gurobi support.";
795template<
typename ValueType,
bool RawMode>
797 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
798 "requires this support. Please choose a version of support with Gurobi support.";
801template<
typename ValueType,
bool RawMode>
803 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
804 "requires this support. Please choose a version of support with Gurobi support.";
807template<
typename ValueType,
bool RawMode>
809 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
810 "requires this support. Please choose a version of support with Gurobi support.";
813template<
typename ValueType,
bool RawMode>
815 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
816 "requires this support. Please choose a version of support with Gurobi support.";
819template<
typename ValueType,
bool RawMode>
821 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
822 "requires this support. Please choose a version of support with Gurobi support.";
825template<
typename ValueType,
bool RawMode>
827 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
828 "requires this support. Please choose a version of support with Gurobi support.";
831template<
typename ValueType,
bool RawMode>
833 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
834 "requires this support. Please choose a version of support with Gurobi support.";
837template<
typename ValueType,
bool RawMode>
839 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
840 "requires this support. Please choose a version of support with Gurobi support.";
843template<
typename ValueType,
bool RawMode>
845 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
846 "requires this support. Please choose a version of support with Gurobi support.";
849template<
typename ValueType,
bool RawMode>
851 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
852 "requires this support. Please choose a version of support with Gurobi support.";
855template<
typename ValueType,
bool RawMode>
857 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
858 "requires this support. Please choose a version of support with Gurobi support.";
861template<
typename ValueType,
bool RawMode>
863 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
864 "requires this support. Please choose a version of support with Gurobi support.";
867template<
typename ValueType,
bool RawMode>
869 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
870 "requires this support. Please choose a version of storm with Gurobi support.";
873template<
typename ValueType,
bool RawMode>
875 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
876 "requires this support. Please choose a version of storm with Gurobi support.";
879template<
typename ValueType,
bool RawMode>
881 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
882 "requires this support. Please choose a version of storm with Gurobi support.";
885template<
typename ValueType,
bool RawMode>
887 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
888 "requires this support. Please choose a version of storm with Gurobi support.";
891template<
typename ValueType,
bool RawMode>
893 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
894 "requires this support. Please choose a version of storm with Gurobi support.";
897template<
typename ValueType,
bool RawMode>
899 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
900 "requires this support. Please choose a version of storm with Gurobi support.";
903template<
typename ValueType,
bool RawMode>
905 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
906 "requires this support. Please choose a version of storm with Gurobi support.";
909template<
typename ValueType,
bool RawMode>
911 throw storm::exceptions::NotImplementedException() <<
"This version of storm was compiled without support for Gurobi. Yet, a method was called that "
912 "requires this support. Please choose a version of storm with Gurobi support.";
922 return "primal-simplex";
924 return "dual-simplex";
930 return "deterministic-concurrent";
932 return "deterministic-concurrent-simplex";
934 STORM_LOG_THROW(
false, storm::exceptions::InvalidArgumentException,
"Unknown solver method");
951template class GurobiLpSolver<double, true>;
952template class GurobiLpSolver<double, false>;
953template class GurobiLpSolver<storm::RationalNumber, true>;
954template 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.
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.
SettingsType const & getModule()
Get module.
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