20template<
typename ModelType,
typename GeometryValueType>
23 : model(model), objectiveHelper(objectiveHelper), numLpQueries(0) {
27template<
typename ModelType,
typename GeometryValueType>
31 initializeLpModel(env);
36template<
typename ModelType,
typename GeometryValueType>
38 std::stringstream out;
39 out << prefix << swAll <<
" seconds for LP Checker including... \n";
40 out << prefix <<
" " << swInit <<
" seconds for LP initialization\n";
41 out << prefix <<
" " << swCheckWeightVectors <<
" seconds for checking weight vectors\n";
42 out << prefix <<
" " << swCheckAreas <<
" seconds for checking areas\n";
43 out << prefix <<
" " << swValidate <<
" seconds for validating LP solutions\n";
44 out << prefix <<
" " << numLpQueries <<
" calls to LP optimization\n";
48template<
typename ModelType,
typename GeometryValueType>
50 std::vector<GeometryValueType>
const& weightVector) {
53 STORM_LOG_ASSERT(weightVector.size() == objectiveHelper.size(),
"Setting a weight vector with invalid number of entries.");
54 if (!currentWeightVector.empty()) {
58 currentObjectiveVariables.clear();
61 currentWeightVector = weightVector;
65 for (uint64_t objIndex = 0; objIndex < initialStateResults.size(); ++objIndex) {
66 currentObjectiveVariables.push_back(
67 lpModel->addUnboundedContinuousVariable(
"w_" + std::to_string(objIndex), storm::utility::convertNumber<ValueType>(weightVector[objIndex])));
68 lpModel->addConstraint(
"", currentObjectiveVariables.back().getExpression() == initialStateResults[objIndex]);
74template<
typename ModelType,
typename GeometryValueType>
79 STORM_LOG_ASSERT(!currentWeightVector.empty(),
"Checking invoked before specifying a weight vector.");
82 auto areaConstraints = overapproximation->getConstraints(lpModel->getManager(), currentObjectiveVariables);
83 for (
auto const& c : areaConstraints) {
84 lpModel->addConstraint(
"", c);
88 STORM_LOG_ASSERT(currentWeightVector.size() == eps.size(),
"Eps vector has unexpected size.");
91 lpModel->setMaximalMILPGap(storm::utility::convertNumber<ValueType>(milpGap),
false);
94 swCheckWeightVectors.start();
96 swCheckWeightVectors.stop();
100 std::optional<std::pair<Point, GeometryValueType>> result;
101 if (!lpModel->isInfeasible()) {
104 auto resultPoint = validateCurrentModel(env);
108 resultValue += storm::utility::convertNumber<GeometryValueType>(lpModel->getMILPGap(
false));
110 result = std::make_pair(resultPoint, resultValue);
118template<
typename ModelType,
typename GeometryValueType>
119std::pair<std::vector<std::vector<GeometryValueType>>, std::vector<std::shared_ptr<storm::storage::geometry::Polytope<GeometryValueType>>>>
125 STORM_LOG_ASSERT(!currentWeightVector.empty(),
"Checking invoked before specifying a weight vector.");
134 lpModel->setMaximalMILPGap(storm::utility::convertNumber<ValueType>(milpGap),
false);
137 std::vector<Point> foundPoints;
138 std::vector<Polytope> infeasableAreas;
139 checkRecursive(env, polytopeTree, eps, foundPoints, infeasableAreas, 0);
141 return {foundPoints, infeasableAreas};
144template<
typename ValueType>
146 std::vector<storm::expressions::Expression> choiceVariables;
150 if (choices.size() == 1) {
151 choiceVariables.push_back(lpModel.
getConstant(storm::utility::one<ValueType>()));
153 std::vector<storm::expressions::Expression> localChoices;
154 for (
auto const choice : choices) {
156 choiceVariables.push_back(localChoices.back());
162 return choiceVariables;
165template<
typename ValueType,
typename HelperType>
168 HelperType
const& objectiveHelper,
169 std::vector<storm::expressions::Expression>
const& choiceVariables) {
171 std::vector<storm::expressions::Expression> objectiveValueVariables(matrix.
getRowGroupCount());
172 for (
auto const& state : objectiveHelper.getMaybeStates()) {
173 if (indicatorConstraints) {
174 objectiveValueVariables[state] = lpModel.
addContinuousVariable(
"x_" + std::to_string(objIndex) +
"_" + std::to_string(state));
176 objectiveValueVariables[state] =
178 objectiveHelper.getLowerValueBoundAtState(state), objectiveHelper.getUpperValueBoundAtState(state));
181 std::vector<storm::expressions::Expression> reachVars;
182 if (objectiveHelper.getInfinityCase() == HelperType::InfinityCase::HasNegativeInfinite) {
184 for (
auto const& state : objectiveHelper.getRewMinusInfEStates()) {
185 reachVars[state] = lpModel.
addBinaryVariable(
"c_" + std::to_string(objIndex) +
"_" + std::to_string(state));
187 STORM_LOG_ASSERT(objectiveHelper.getRewMinusInfEStates().get(initialState),
"");
192 for (
auto const& state : objectiveHelper.getMaybeStates()) {
193 bool const requireReachConstraints =
194 objectiveHelper.getInfinityCase() == HelperType::InfinityCase::HasNegativeInfinite && objectiveHelper.getRewMinusInfEStates().get(state);
196 auto const& choiceVarAsExpression = choiceVariables.at(choice);
198 (!choiceVarAsExpression.containsVariables() &&
storm::utility::isOne(choiceVarAsExpression.evaluateAsRational())),
199 "Unexpected kind of choice variable: " << choiceVarAsExpression);
200 std::vector<storm::expressions::Expression> summands;
201 if (!indicatorConstraints && choiceVarAsExpression.isVariable()) {
202 summands.push_back((lpModel.
getConstant(storm::utility::one<ValueType>()) - choiceVarAsExpression) *
203 lpModel.
getConstant(objectiveHelper.getUpperValueBoundAtState(state) - objectiveHelper.getLowerValueBoundAtState(state)));
205 if (
auto findRes = objectiveHelper.getChoiceRewards().find(choice); findRes != objectiveHelper.getChoiceRewards().end()) {
206 auto rewExpr = lpModel.
getConstant(findRes->second);
207 if (requireReachConstraints) {
208 summands.push_back(reachVars[state] * rewExpr);
210 summands.push_back(rewExpr);
213 for (
auto const& succ : matrix.
getRow(choice)) {
214 if (objectiveHelper.getMaybeStates().get(succ.getColumn())) {
215 summands.push_back(lpModel.
getConstant(succ.getValue()) * objectiveValueVariables.at(succ.getColumn()));
217 if (requireReachConstraints && objectiveHelper.getRewMinusInfEStates().get(succ.getColumn())) {
219 "", reachVars[state] <= reachVars[succ.getColumn()] + lpModel.
getConstant(storm::utility::one<ValueType>()) - choiceVarAsExpression);
222 if (summands.empty()) {
223 summands.push_back(lpModel.
getConstant(storm::utility::zero<ValueType>()));
225 if (indicatorConstraints && choiceVarAsExpression.isVariable()) {
226 auto choiceVar = choiceVarAsExpression.getBaseExpression().asVariableExpression().getVariable();
233 return objectiveValueVariables;
238template<
typename ValueType,
typename ObjHelperType>
240 std::vector<ObjHelperType>
const& objectiveHelper) {
241 std::vector<std::pair<storm::storage::MaximalEndComponent, std::vector<uint64_t>>> problMecs;
242 for (uint64_t objIndex = 0; objIndex < objectiveHelper.size(); ++objIndex) {
243 auto const& obj = objectiveHelper[objIndex];
245 obj.getRelevantZeroRewardChoices());
246 for (
auto& newMec : objMecs) {
248 for (
auto& problMec : problMecs) {
249 if (problMec.first == newMec) {
250 problMec.second.push_back(objIndex);
256 problMecs.emplace_back(std::move(newMec), std::vector<uint64_t>({objIndex}));
260 STORM_LOG_DEBUG(
"Found " << problMecs.size() <<
" problematic ECs." << std::endl);
264template<
typename ValueType,
typename UpperBoundsGetterType>
268 std::vector<uint64_t>
const& relevantObjectiveIndices,
269 std::vector<std::vector<storm::expressions::Expression>>
const& objectiveValueVariables,
270 std::vector<storm::expressions::Expression>
const& choiceVariables,
271 UpperBoundsGetterType
const& objectiveStateUpperBoundGetter) {
273 if (!indicatorConstraints) {
279 std::map<uint64_t, storm::expressions::Expression> expVisitsVars;
280 std::map<uint64_t, storm::expressions::Expression> botVars;
281 std::map<uint64_t, storm::expressions::Expression> bsccIndicatorVariables;
282 for (
auto const& stateChoices : problematicMec) {
283 auto const state = stateChoices.first;
284 auto bsccIndicatorVar = lpModel.
addBinaryVariable(
"b_" + std::to_string(mecIndex) +
"_" + std::to_string(state));
285 bsccIndicatorVariables.emplace(state, bsccIndicatorVar.getExpression());
286 std::string visitsVarPref =
"z_" + std::to_string(mecIndex) +
"_";
287 auto stateBotVisitsVar =
289 botVars.emplace(state, stateBotVisitsVar);
291 if (indicatorConstraints) {
294 lpModel.
addConstraint(
"", stateBotVisitsVar <= bsccIndicatorVar.getExpression() * visitsUpperBound);
297 auto stateActionVisitsVar =
300 if (indicatorConstraints) {
301 if (
auto const& a = choiceVariables[choice]; a.isVariable()) {
302 auto aVar = a.getBaseExpression().asVariableExpression().getVariable();
306 lpModel.
addConstraint(
"", stateActionVisitsVar <= choiceVariables[choice] * visitsUpperBound);
308 expVisitsVars.emplace(choice, stateActionVisitsVar);
310 for (
auto const& ecChoice : stateChoices.second) {
311 mecChoices.
set(ecChoice,
true);
313 for (
auto const& objIndex : relevantObjectiveIndices) {
314 if (indicatorConstraints) {
316 objectiveValueVariables[objIndex][state] <= lpModel.
getConstant(storm::utility::zero<ValueType>()));
318 auto const upperBnd = lpModel.
getConstant(objectiveStateUpperBoundGetter(objIndex, state));
319 lpModel.
addConstraint(
"", objectiveValueVariables[objIndex][state] <= upperBnd - upperBnd * bsccIndicatorVar.getExpression());
325 auto const initProb = lpModel.
getConstant(storm::utility::one<ValueType>() / storm::utility::convertNumber<ValueType, uint64_t>(problematicMec.
size()));
326 std::vector<storm::expressions::Expression> outVisitsSummands;
327 for (
auto const& stateChoices : problematicMec) {
328 auto const state = stateChoices.first;
329 auto const& choices = stateChoices.second;
330 auto const& stateBotVar = botVars.at(state);
331 outVisitsSummands.push_back(stateBotVar);
332 std::vector<storm::expressions::Expression> stateVisitsSummands;
333 stateVisitsSummands.push_back(stateBotVar);
335 auto const& choiceVisitsVar = expVisitsVars.at(choice);
336 stateVisitsSummands.push_back(choiceVisitsVar);
337 if (choices.count(choice) != 0) {
338 if (redundantConstraints) {
339 for (
auto const& postElem : matrix.
getRow(choice)) {
343 auto succ = postElem.getColumn();
344 lpModel.
addConstraint(
"", bsccIndicatorVariables.at(state) + choiceVariables.at(choice) <=
345 lpModel.
getConstant(storm::utility::one<ValueType>()) + bsccIndicatorVariables.at(succ));
349 outVisitsSummands.push_back(choiceVisitsVar);
352 for (
auto const& preEntry : backwardChoices.
getRow(state)) {
353 uint64_t
const preChoice = preEntry.getColumn();
354 if (mecChoices.
get(preChoice)) {
356 storm::utility::one<ValueType>() / storm::utility::convertNumber<ValueType, uint64_t>(matrix.
getRow(preChoice).
getNumberOfEntries());
357 stateVisitsSummands.push_back(lpModel.
getConstant(-preProb) * expVisitsVars.at(preChoice));
365template<
typename ValueType,
typename UpperBoundsGetterType>
369 std::vector<storm::expressions::Expression>
const& choiceVariables,
370 std::vector<std::vector<storm::expressions::Expression>>
const& objectiveValueVariables,
371 UpperBoundsGetterType
const& objectiveStateUpperBoundGetter) {
374 std::map<uint64_t, storm::expressions::Expression> bsccIndicatorVariables;
375 std::map<uint64_t, storm::expressions::Expression> orderVariables;
376 for (
auto const& stateChoices : problematicMec) {
377 auto const state = stateChoices.first;
378 auto bsccIndicatorVar = lpModel.
addBinaryVariable(
"b_" + std::to_string(mecIndex) +
"_" + std::to_string(state));
379 bsccIndicatorVariables.emplace(state, bsccIndicatorVar.getExpression());
380 auto orderVar = lpModel
382 storm::utility::one<ValueType>())
385 orderVariables.emplace(state, orderVar);
386 for (
auto const& ecChoice : stateChoices.second) {
387 mecChoices.
set(ecChoice,
true);
389 for (
auto const& objIndex : relevantObjectiveIndices) {
390 if (indicatorConstraints) {
392 objectiveValueVariables[objIndex][state] <= lpModel.
getConstant(storm::utility::zero<ValueType>()));
394 auto const upperBnd = lpModel.
getConstant(objectiveStateUpperBoundGetter(objIndex, state));
395 lpModel.
addConstraint(
"", objectiveValueVariables[objIndex][state] <= upperBnd - upperBnd * bsccIndicatorVar.getExpression());
401 auto const minDiff = lpModel.
getConstant(-storm::utility::one<ValueType>() / storm::utility::convertNumber<ValueType, uint64_t>(problematicMec.
size()));
402 for (
auto const& stateChoices : problematicMec) {
403 auto const state = stateChoices.first;
404 auto const& choices = stateChoices.second;
405 auto const& bsccIndicatorVar = bsccIndicatorVariables.at(state);
406 auto const& orderVar = orderVariables.at(state);
407 for (
auto choice : choices) {
408 auto const& choiceVariable = choiceVariables.at(choice);
409 std::vector<storm::expressions::Expression> choiceConstraint;
410 choiceConstraint.push_back(bsccIndicatorVar);
411 std::string
const transSelectPrefix =
"d_" + std::to_string(mecIndex) +
"_" + std::to_string(choice) +
"_";
412 for (
auto const& postElem : matrix.
getRow(choice)) {
416 auto succ = postElem.getColumn();
417 if (redundantConstraints) {
419 "", bsccIndicatorVar + choiceVariable <= lpModel.
getConstant(storm::utility::one<ValueType>()) + bsccIndicatorVariables.at(succ));
421 auto transVar = lpModel.
addBinaryVariable(transSelectPrefix + std::to_string(succ)).getExpression();
423 choiceConstraint.push_back(transVar);
425 lpModel.
addConstraint(
"", orderVar <= minDiff + orderVariables.at(succ) + lpModel.
getConstant(storm::utility::one<ValueType>()) - transVar);
432template<
typename ValueType,
typename HelperType>
437 std::vector<HelperType>
const& objectiveHelper,
438 std::vector<storm::expressions::Expression>
const& choiceVariables) {
439 auto objHelpIt = objectiveHelper.begin();
441 for (++objHelpIt; objHelpIt != objectiveHelper.end(); ++objHelpIt) {
442 anyMaybeStates |= objHelpIt->getMaybeStates();
445 for (
auto const& oh : objectiveHelper) {
446 for (
auto const& rew : oh.getChoiceRewards()) {
448 allZeroRewardChoices.
set(rew.first,
false);
453 for (
auto const& mec : mecs) {
454 for (
auto const& sc : mec) {
455 mecStates.
set(sc.first,
true);
458 std::vector<ValueType> maxVisits;
459 if (!indicatorConstraints) {
466 for (
auto state : anyMaybeStates) {
467 assert(indicatorConstraints || maxVisits[state] >= storm::utility::zero<ValueType>());
469 choiceVisitsVars[choice] =
472 if (indicatorConstraints) {
473 if (
auto const& a = choiceVariables[choice]; a.isVariable()) {
474 auto aVar = a.getBaseExpression().asVariableExpression().getVariable();
478 lpModel.
addConstraint(
"", choiceVisitsVars[choice] <= choiceVariables.at(choice) * lpModel.
getConstant(maxVisits[state]));
481 if (mecStates.
get(state)) {
482 bsccVars[state] = lpModel.
addBinaryVariable(
"b_" + std::to_string(state)).getExpression();
483 botVisitsVars[state] =
486 if (indicatorConstraints) {
487 lpModel.
addIndicatorConstraint(
"", bsccVars[state].getBaseExpression().asVariableExpression().getVariable(),
false,
488 botVisitsVars[state] <= lpModel.
getConstant(storm::utility::zero<ValueType>()));
496 auto notMaybe = ~anyMaybeStates;
497 std::vector<storm::expressions::Expression> outSummands;
498 for (
auto state : anyMaybeStates) {
499 std::vector<storm::expressions::Expression> visitsSummands;
500 if (mecStates.
get(state)) {
501 visitsSummands.push_back(-botVisitsVars[state]);
502 outSummands.push_back(botVisitsVars[state]);
505 visitsSummands.push_back(-choiceVisitsVars[choice]);
507 outSummands.push_back(lpModel.
getConstant(outProb) * choiceVisitsVars[choice]);
510 if (state == initialState) {
511 visitsSummands.push_back(lpModel.
getConstant(storm::utility::one<ValueType>()));
513 for (
auto const& preEntry : backwardChoices.
getRow(state)) {
514 assert(choiceVisitsVars[preEntry.getColumn()].isInitialized());
515 visitsSummands.push_back(lpModel.
getConstant(preEntry.getValue()) * choiceVisitsVars[preEntry.getColumn()]);
522 for (
auto const& mec : mecs) {
523 for (
auto const& stateChoices : mec) {
524 auto const& state = stateChoices.first;
526 if (stateChoices.second.count(choice) != 0) {
527 for (
auto const& succ : matrix.
getRow(choice)) {
531 assert(mecStates.
get(succ.getColumn()));
532 lpModel.
addConstraint(
"", bsccVars[state] <= bsccVars[succ.getColumn()] + lpModel.
getConstant(storm::utility::one<ValueType>()) -
533 choiceVariables[choice]);
536 lpModel.
addConstraint(
"", bsccVars[state] <= lpModel.
getConstant(storm::utility::one<ValueType>()) - choiceVariables[choice]);
543 std::vector<storm::expressions::Expression> objectiveValueVariables;
544 for (uint64_t objIndex = 0; objIndex < objectiveHelper.size(); ++objIndex) {
545 if (objectiveHelper[objIndex].getMaybeStates().get(initialState)) {
548 std::vector<storm::expressions::Expression> summands;
549 for (
auto const& objRew : objectiveHelper[objIndex].getChoiceRewards()) {
550 assert(choiceVisitsVars[objRew.first].isInitialized());
551 summands.push_back(choiceVisitsVars[objRew.first] * lpModel.
getConstant(objRew.second));
555 objectiveValueVariables.push_back(lpModel.
getConstant(objectiveHelper[objIndex].getConstantInitialStateValue()));
558 return objectiveValueVariables;
561template<
typename HelperType>
563 bool supportsFlowEncoding = std::all_of(objectiveHelper.begin(), objectiveHelper.end(), [](
auto const& h) { return h.isTotalRewardObjective(); });
566 return supportsFlowEncoding;
568 STORM_LOG_THROW(supportsFlowEncoding, storm::exceptions::InvalidOperationException,
569 "Flow encoding only applicable if all objectives are (transformable to) total reward objectives.");
576template<
typename ModelType,
typename GeometryValueType>
577void DeterministicSchedsLpChecker<ModelType, GeometryValueType>::initializeLpModel(
Environment const& env) {
578 STORM_LOG_INFO(
"Initializing LP model with " << model.getNumberOfStates() <<
" states.");
580 STORM_LOG_INFO(
"Using " << (flowEncoding ?
"flow" :
"classical") <<
" encoding.\n");
581 uint64_t initialState = *model.getInitialStates().begin();
582 auto backwardTransitions = model.getBackwardTransitions();
583 auto backwardChoices = model.getTransitionMatrix().transpose();
586 "The selected MILP solver might not perform well. Consider installing / using Gurobi.");
587 lpModel = storm::utility::solver::getLpSolver<ValueType>(
"model");
589 lpModel->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize);
590 initialStateResults.clear();
596 backwardTransitions, backwardChoices, initialState, objectiveHelper, choiceVariables);
598 std::vector<std::vector<storm::expressions::Expression>> objectiveValueVariables;
599 initialStateResults.clear();
600 for (uint64_t objIndex = 0; objIndex < objectiveHelper.size(); ++objIndex) {
601 if (objectiveHelper[objIndex].getMaybeStates().get(initialState)) {
603 model.getTransitionMatrix(), initialState, objIndex, objectiveHelper[objIndex],
605 initialStateResults.push_back(objectiveValueVariables.back()[initialState]);
607 initialStateResults.push_back(lpModel->getConstant(objectiveHelper[objIndex].getConstantInitialStateValue()));
610 auto problematicMecs =
computeProblematicMecs(model.getTransitionMatrix(), backwardTransitions, objectiveHelper);
611 uint64_t mecIndex = 0;
612 auto upperBoundsGetter = [&](uint64_t objIndex, uint64_t state) -> ValueType {
return objectiveHelper[objIndex].getUpperValueBoundAtState(state); };
613 for (
auto const& mecObj : problematicMecs) {
617 mecObj.second, choiceVariables, objectiveValueVariables, upperBoundsGetter);
621 mecIndex, mecObj.first, mecObj.second, objectiveValueVariables, choiceVariables, upperBoundsGetter);
630template<
typename ModelType,
typename GeometryValueType>
631void DeterministicSchedsLpChecker<ModelType, GeometryValueType>::checkRecursive(Environment
const& env,
633 Point
const& eps, std::vector<Point>& foundPoints,
634 std::vector<Polytope>& infeasableAreas, uint64_t
const& depth) {
641 auto nodeConstraints = polytopeTree.
getPolytope()->getConstraints(lpModel->getManager(), currentObjectiveVariables);
642 for (
auto const& constr : nodeConstraints) {
643 lpModel->addConstraint(
"", constr);
655 uint64_t num_sharpen = 0;
656 auto halfspaces = polytopeTree.
getPolytope()->getHalfspaces();
659 swCheckAreas.start();
668 if (lpModel->isInfeasible()) {
669 infeasableAreas.push_back(polytopeTree.
getPolytope());
670 polytopeTree.
clear();
675 Point newPoint = validateCurrentModel(env);
680 Point newPointPlusEps = newPoint;
682 if (polytopeTree.
getPolytope()->contains(newPoint) ||
686 GeometryValueType offset = storm::utility::convertNumber<GeometryValueType>(lpModel->getObjectiveValue());
688 offset += storm::utility::convertNumber<GeometryValueType>(lpModel->getMILPGap(
false));
692 infeasableAreas.push_back(polytopeTree.
getPolytope()->intersection(halfspace));
693 if (infeasableAreas.back()->isEmpty()) {
694 infeasableAreas.pop_back();
697 foundPoints.push_back(newPoint);
700 checkRecursive(env, polytopeTree, eps, foundPoints, infeasableAreas, depth);
705 for (
auto& h : halfspaces) {
706 GeometryValueType distance = h.distance(newPoint);
711 bool normalVectorContainsNegative =
false;
712 for (
auto const& hi : h.normalVector()) {
713 if (hi < storm::utility::zero<GeometryValueType>()) {
714 normalVectorContainsNegative =
true;
718 if (normalVectorContainsNegative) {
719 h.offset() -= distance / storm::utility::convertNumber<GeometryValueType, uint64_t>(2);
720 if (num_sharpen == 0) {
723 lpModel->addConstraint(
"", h.toExpression(lpModel->getManager(), currentObjectiveVariables));
733 if (num_sharpen > 0) {
735 "Numerical instabilities detected: LP Solver found an achievable point outside of the search area. The search area had to be sharpened "
736 << num_sharpen <<
" times.");
743 for (uint64_t childId = 0; childId < polytopeTree.
getChildren().size(); ++childId) {
744 if (polytopeTree.
getChildren()[childId].isEmpty()) {
747 uint64_t newPointIndex = foundPoints.size();
748 checkRecursive(env, polytopeTree.
getChildren()[childId], eps, foundPoints, infeasableAreas, depth + 1);
751 for (; newPointIndex < foundPoints.size(); ++newPointIndex) {
752 for (uint64_t siblingId = childId + 1; siblingId < polytopeTree.
getChildren().size(); ++siblingId) {
753 polytopeTree.
getChildren()[siblingId].substractDownwardClosure(foundPoints[newPointIndex], eps);
758 polytopeTree.
clear();
766template<
typename ModelType,
typename GeometryValueType>
768 Environment
const& env)
const {
770 for (uint64_t state = 0; state < model.getNumberOfStates(); ++state) {
771 auto choices = model.getTransitionMatrix().getRowGroupIndices(state);
772 if (choices.size() == 1) {
773 selectedChoices.set(*choices.begin());
775 bool choiceFound =
false;
776 for (
auto choice : choices) {
777 assert(choiceVariables[choice].isVariable());
778 if (lpModel->getBinaryValue(choiceVariables[choice].getBaseExpression().asVariableExpression().getVariable())) {
779 STORM_LOG_THROW(!choiceFound, storm::exceptions::UnexpectedException,
"Multiple choices selected at state " << state);
780 selectedChoices.set(choice,
true);
788 for (uint64_t objIndex = 0; objIndex < objectiveHelper.size(); ++objIndex) {
789 ValueType inducedValue = objectiveHelper[objIndex].evaluateScheduler(env, selectedChoices);
790 inducedPoint.push_back(storm::utility::convertNumber<GeometryValueType>(inducedValue));
793 ValueType lpValue = lpModel->getContinuousValue(currentObjectiveVariables[objIndex]);
794 double diff = storm::utility::convertNumber<double>(storm::utility::abs<ValueType>(inducedValue - lpValue));
795 STORM_LOG_WARN_COND(diff <= 1e-4 * std::abs(storm::utility::convertNumber<double>(inducedValue)),
796 "Imprecise value for objective " << objIndex <<
": LP says " << lpValue <<
" but scheduler induces " << inducedValue
797 <<
" (difference is " << diff <<
")");
803template class DeterministicSchedsLpChecker<storm::models::sparse::Mdp<double>, storm::RationalNumber>;
804template class DeterministicSchedsLpChecker<storm::models::sparse::Mdp<storm::RationalNumber>, storm::RationalNumber>;
805template class DeterministicSchedsLpChecker<storm::models::sparse::MarkovAutomaton<double>, storm::RationalNumber>;
806template class DeterministicSchedsLpChecker<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>, storm::RationalNumber>;
ModelCheckerEnvironment & modelchecker()
MultiObjectiveModelCheckerEnvironment & multi()
bool getUseIndicatorConstraints() const
EncodingType const & getEncodingType() const
@ Flow
The classic backwards encoding.
bool getUseBsccOrderEncoding() const
bool getUseRedundantBsccConstraints() const
Represents the LP Encoding for achievability under simple strategies.
void setCurrentWeightVector(Environment const &env, std::vector< GeometryValueType > const &weightVector)
Specifies the current direction.
std::string getStatistics(std::string const &prefix="") const
Returns usage statistics in a human readable format.
DeterministicSchedsLpChecker(ModelType const &model, std::vector< DeterministicSchedsObjectiveHelper< ModelType > > const &objectiveHelper)
std::optional< std::pair< Point, GeometryValueType > > check(storm::Environment const &env, Polytope overapproximation, Point const &eps={})
Optimizes in the currently given direction.
std::vector< GeometryValueType > Point
std::shared_ptr< storm::storage::geometry::Polytope< GeometryValueType > > Polytope
Provides helper functions for computing bounds on the expected visiting times.
static std::vector< ValueType > computeUpperBoundsOnExpectedVisitingTimes(storm::storage::BitVector const &subsystem, storm::storage::SparseMatrix< ValueType > const &transitions, storm::storage::SparseMatrix< ValueType > const &backwardTransitions)
Computes for each state in the given subsystem an upper bound for the maximal finite expected number ...
An interface that captures the functionality of an LP solver.
Variable addContinuousVariable(std::string const &name, std::optional< ValueType > const &lowerBound=std::nullopt, std::optional< ValueType > const &upperBound=std::nullopt, ValueType objectiveFunctionCoefficient=0)
Registers a continuous variable, i.e.
virtual void update() const =0
Updates the model to make the variables that have been declared since the last call to update usable.
virtual void addConstraint(std::string const &name, Constraint const &constraint)=0
Adds a the given constraint to the LP problem.
Variable addLowerBoundedContinuousVariable(std::string const &name, ValueType lowerBound, ValueType objectiveFunctionCoefficient=0)
Registers a lower-bounded continuous variable, i.e.
Constant getConstant(ValueType value) const
Retrieves an expression that characterizes the given constant value.
virtual void addIndicatorConstraint(std::string const &name, Variable indicatorVariable, bool indicatorValue, Constraint const &constraint)=0
Adds the given indicator constraint to the LP problem: "If indicatorVariable == indicatorValue,...
Variable addBoundedContinuousVariable(std::string const &name, ValueType lowerBound, ValueType upperBound, ValueType objectiveFunctionCoefficient=0)
Registers an upper- and lower-bounded continuous variable, i.e.
Variable addUnboundedContinuousVariable(std::string const &name, ValueType objectiveFunctionCoefficient=0)
Registers a unbounded continuous variable, i.e.
Variable addBinaryVariable(std::string const &name, ValueType objectiveFunctionCoefficient=0)
Registers a boolean variable, i.e.
A bit vector that is internally represented as a vector of 64-bit values.
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
bool get(uint_fast64_t index) const
Retrieves the truth value of the bit at the given index and performs a bound check.
This class represents the decomposition of a nondeterministic model into its maximal end components.
This class represents a maximal end-component of a nondeterministic model.
index_type getNumberOfEntries() const
Retrieves the number of entries in the rows.
A class that holds a possibly non-square matrix in the compressed row storage format.
const_rows getRow(index_type row) const
Returns an object representing the given row.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
value_type getConstrainedRowSum(index_type row, storm::storage::BitVector const &columns) const
Sums the entries in the given row and columns.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
index_type getRowCount() const
Returns the number of rows of the matrix.
Halfspace< ValueType > invert() const
Represents a set of points in Euclidean space.
std::shared_ptr< Polytope< ValueType > > & getPolytope()
Gets the polytope at this node.
void substractDownwardClosure(std::vector< ValueType > const &point)
Substracts the downward closure of the given point from this set.
void setMinus(std::shared_ptr< Polytope< ValueType > > const &rhs)
Substracts the given rhs from this polytope.
bool isEmpty() const
Returns true if this is the empty set.
std::vector< PolytopeTree > & getChildren()
Gets the children at this node.
std::string toString()
Returns a string representation of this node (for debugging purposes)
void clear()
Clears all contents of this set, making it the empty set.
#define STORM_LOG_INFO(message)
#define STORM_LOG_WARN(message)
#define STORM_LOG_DEBUG(message)
#define STORM_LOG_TRACE(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_WARN_COND(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
SFTBDDChecker::ValueType ValueType
Expression sum(std::vector< storm::expressions::Expression > const &expressions)
std::vector< storm::expressions::Expression > expVisitsConstraints(storm::solver::LpSolver< ValueType > &lpModel, bool const &indicatorConstraints, storm::storage::SparseMatrix< ValueType > const &matrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::SparseMatrix< ValueType > const &backwardChoices, uint64_t initialState, std::vector< HelperType > const &objectiveHelper, std::vector< storm::expressions::Expression > const &choiceVariables)
auto createChoiceVariables(storm::solver::LpSolver< ValueType > &lpModel, storm::storage::SparseMatrix< ValueType > const &matrix)
auto computeProblematicMecs(storm::storage::SparseMatrix< ValueType > const &matrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, std::vector< ObjHelperType > const &objectiveHelper)
Computes the set of problematic MECS with the objective indices that induced them An EC is problemati...
auto problematicMecConstraintsExpVisits(storm::solver::LpSolver< ValueType > &lpModel, bool const &indicatorConstraints, bool const &redundantConstraints, storm::storage::SparseMatrix< ValueType > const &matrix, storm::storage::SparseMatrix< ValueType > const &backwardChoices, uint64_t mecIndex, storm::storage::MaximalEndComponent const &problematicMec, std::vector< uint64_t > const &relevantObjectiveIndices, std::vector< std::vector< storm::expressions::Expression > > const &objectiveValueVariables, std::vector< storm::expressions::Expression > const &choiceVariables, UpperBoundsGetterType const &objectiveStateUpperBoundGetter)
std::vector< storm::expressions::Expression > classicConstraints(storm::solver::LpSolver< ValueType > &lpModel, bool const &indicatorConstraints, storm::storage::SparseMatrix< ValueType > const &matrix, uint64_t initialState, uint64_t objIndex, HelperType const &objectiveHelper, std::vector< storm::expressions::Expression > const &choiceVariables)
bool useFlowEncoding(storm::Environment const &env, std::vector< HelperType > const &objectiveHelper)
auto problematicMecConstraintsOrder(storm::solver::LpSolver< ValueType > &lpModel, bool const &indicatorConstraints, bool const &redundantConstraints, storm::storage::SparseMatrix< ValueType > const &matrix, uint64_t mecIndex, storm::storage::MaximalEndComponent const &problematicMec, std::vector< uint64_t > const &relevantObjectiveIndices, std::vector< storm::expressions::Expression > const &choiceVariables, std::vector< std::vector< storm::expressions::Expression > > const &objectiveValueVariables, UpperBoundsGetterType const &objectiveStateUpperBoundGetter)
SettingsType const & getModule()
Get module.
T dotProduct(std::vector< T > const &firstOperand, std::vector< T > const &secondOperand)
Computes the dot product (aka scalar product) and returns the result.
void addScaledVector(std::vector< InValueType1 > &firstOperand, std::vector< InValueType2 > const &secondOperand, InValueType3 const &factor)
Computes x:= x + a*y, i.e., adds each element of the first vector and (the corresponding element of t...
bool isOne(ValueType const &a)
bool isZero(ValueType const &a)