29namespace modelchecker {
30namespace multiobjective {
32template<
class SparseModelType>
39template<
class SparseModelType>
44 "There is no Pareto optimal scheduler that yields finite reward for all objectives. This is not supported.");
45 STORM_LOG_THROW(rewardAnalysis.totalRewardLessInfinityEStates, storm::exceptions::UnexpectedException,
46 "The set of states with reward < infinity for some scheduler has not been computed during preprocessing.");
48 "At least one objective was not reduced to an expected (long run, total or cumulative) reward objective during preprocessing. This is not "
49 "supported by the considered weight vector checker.");
51 "The model has multiple initial states.");
57 rewardAnalysis.totalRewardLessInfinityEStates.get(), rewardAnalysis.totalRewardLessInfinityEStates.get());
58 std::set<std::string> relevantRewardModels;
59 for (
auto const& obj : this->objectives) {
60 obj.formula->gatherReferencedRewardModels(relevantRewardModels);
65 std::vector<std::string>(relevantRewardModels.begin(), relevantRewardModels.end()), finiteTotalRewardChoices);
68 initializeModelTypeSpecificData(*mergerResult.model);
71 transitionMatrix = std::move(mergerResult.model->getTransitionMatrix());
72 initialState = *mergerResult.model->getInitialStates().begin();
73 totalReward0EStates = rewardAnalysis.totalReward0EStates % maybeStates;
74 if (mergerResult.targetState) {
76 totalReward0EStates.
resize(totalReward0EStates.size() + 1,
true);
80 targetStateAsVector.set(*mergerResult.targetState,
true);
81 ecChoicesHint = transitionMatrix.getRowFilter(
84 ecChoicesHint.set(transitionMatrix.getRowGroupIndices()[*mergerResult.targetState],
true);
93 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
94 auto const& formula = *this->objectives[objIndex].formula;
95 if (formula.getSubformula().isTotalRewardFormula()) {
96 objectivesWithNoUpperTimeBound.set(objIndex,
true);
99 if (formula.getSubformula().isLongRunAverageRewardFormula()) {
100 lraObjectives.set(objIndex,
true);
101 objectivesWithNoUpperTimeBound.set(objIndex,
true);
106 if (!lraObjectives.empty()) {
107 lraMecDecomposition = LraMecDecomposition();
110 actionsWithoutRewardInUnboundedPhase);
111 lraMecDecomposition->auxMecValues.resize(lraMecDecomposition->mecs.size());
115 checkHasBeenCalled =
false;
116 objectiveResults.resize(this->objectives.size());
117 offsetsToUnderApproximation.resize(this->objectives.size(), storm::utility::zero<ValueType>());
118 offsetsToOverApproximation.resize(this->objectives.size(), storm::utility::zero<ValueType>());
119 optimalChoices.resize(transitionMatrix.getRowGroupCount(), 0);
124 STORM_PRINT_AND_LOG(
"Final preprocessed model has " << transitionMatrix.getRowGroupCount() <<
" states.\n");
125 STORM_PRINT_AND_LOG(
"Final preprocessed model has " << transitionMatrix.getRowCount() <<
" actions.\n");
126 if (lraMecDecomposition) {
127 STORM_PRINT_AND_LOG(
"Found " << lraMecDecomposition->mecs.size() <<
" end components that are relevant for LRA-analysis.\n");
128 uint64_t numLraMecStates = 0;
129 for (
auto const& mec : this->lraMecDecomposition->mecs) {
130 numLraMecStates += mec.size();
138template<
class SparseModelType>
140 checkHasBeenCalled =
true;
145 std::vector<ValueType> weightedRewardVector(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>());
146 if (!lraObjectives.empty()) {
147 boost::optional<std::vector<ValueType>> weightedStateRewardVector;
148 for (
auto objIndex : lraObjectives) {
150 storm::solver::minimize(this->objectives[objIndex].formula->getOptimalityType()) ? -weightVector[objIndex] : weightVector[objIndex];
152 if (!stateRewards.empty() && !stateRewards[objIndex].empty()) {
153 if (!weightedStateRewardVector) {
154 weightedStateRewardVector = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
159 infiniteHorizonWeightedPhase(env, weightedRewardVector, weightedStateRewardVector);
161 weightedRewardVector.assign(weightedRewardVector.size(), storm::utility::zero<ValueType>());
165 auto totalRewardObjectives = objectivesWithNoUpperTimeBound & ~lraObjectives;
166 for (
auto objIndex : totalRewardObjectives) {
173 unboundedWeightedPhase(env, weightedRewardVector, weightVector);
175 unboundedIndividualPhase(env, weightVector);
177 for (
auto const& obj : this->objectives) {
178 if (!obj.formula->getSubformula().isTotalRewardFormula() && !obj.formula->getSubformula().isLongRunAverageRewardFormula()) {
179 boundedPhase(env, weightVector, weightedRewardVector);
183 STORM_LOG_INFO(
"Weight vector check done. Lower bounds for results in initial state: "
190 STORM_LOG_THROW(resultingWeightedPrecision <= this->getWeightedPrecision(), storm::exceptions::UnexpectedException,
191 "The desired precision was not reached");
194template<
class SparseModelType>
195std::vector<typename StandardPcaaWeightVectorChecker<SparseModelType>::ValueType>
197 STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
"Tried to retrieve results but check(..) has not been called before.");
198 std::vector<ValueType> res;
199 res.reserve(this->objectives.size());
200 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
201 res.push_back(this->objectiveResults[objIndex][initialState] + this->offsetsToUnderApproximation[objIndex]);
206template<
class SparseModelType>
207std::vector<typename StandardPcaaWeightVectorChecker<SparseModelType>::ValueType>
209 STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
"Tried to retrieve results but check(..) has not been called before.");
210 std::vector<ValueType> res;
211 res.reserve(this->objectives.size());
212 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
213 res.push_back(this->objectiveResults[objIndex][initialState] + this->offsetsToOverApproximation[objIndex]);
218template<
class SparseModelType>
221 STORM_LOG_THROW(this->checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
222 "Tried to retrieve results but check(..) has not been called before.");
223 for (
auto const& obj : this->objectives) {
224 STORM_LOG_THROW(obj.formula->getSubformula().isTotalRewardFormula() || obj.formula->getSubformula().isLongRunAverageRewardFormula(),
225 storm::exceptions::NotImplementedException,
"Scheduler retrival is only implemented for objectives without time-bound.");
229 uint_fast64_t state = 0;
230 for (
auto const& choice : optimalChoices) {
237template<
typename ValueType>
241 std::vector<uint64_t> stack;
243 stack.insert(stack.end(), processedStates.
begin(), processedStates.
end());
244 uint64_t currentState = 0;
246 while (!stack.empty()) {
247 currentState = stack.back();
250 for (
auto const& predecessorEntry : backwardTransitions.
getRow(currentState)) {
251 auto predecessor = predecessorEntry.getColumn();
252 if (consideredStates.
get(predecessor) && !processedStates.
get(predecessor)) {
256 uint64_t row = allowedChoices ? allowedChoices->getNextSetIndex(groupStart) : groupStart;
257 for (; row < groupEnd; row = allowedChoices ? allowedChoices->getNextSetIndex(row + 1) : row + 1) {
258 bool hasSuccessorInProcessedStates =
false;
259 for (
auto const& successorOfPredecessor : transitionMatrix.
getRow(row)) {
260 if (processedStates.
get(successorOfPredecessor.getColumn())) {
261 hasSuccessorInProcessedStates =
true;
265 if (hasSuccessorInProcessedStates) {
266 choices[predecessor] = row - groupStart;
267 processedStates.
set(predecessor,
true);
268 stack.push_back(predecessor);
273 "Unable to find choice at a predecessor of a processed state that leads to a processed state.");
280template<
typename ValueType>
284 for (
auto state : consideredStates) {
287 bool choiceFound =
false;
290 for (
auto const& element : transitionMatrix.
getRow(row)) {
291 if (statesToAvoid.
get(element.getColumn())) {
297 choices[state] = row - groupStart;
305template<
typename ValueType>
309 auto backwardsTransitions = matrix.
transpose(
true);
311 for (uint64_t state = 0; state < result.size(); ++state) {
312 if (rowsWithSumLessOne.
getNextSetIndex(groups[state]) < groups[state + 1]) {
313 result[state] = rowsWithSumLessOne.
getNextSetIndex(groups[state]) - groups[state];
314 processedStates.
set(state,
true);
327template<
typename ValueType>
331 auto badStates = transitionMatrix.
getRowGroupFilter(finitelyOftenChoices,
true) & ~safeStates;
335 transitionMatrix, transitionMatrix.
getRowGroupIndices(), backwardTransitions, ~safeStates, badStates,
false, 0, ~finitelyOftenChoices);
338 auto avoidBadStates = ~reachBadWithProbGreater0AStates & ~safeStates;
339 computeSchedulerProb0(transitionMatrix, backwardTransitions, avoidBadStates, reachBadWithProbGreater0AStates, ~finitelyOftenChoices, choices);
344 computeSchedulerProb1(transitionMatrix, backwardTransitions, reachBadWithProbGreater0AStates, avoidBadStates | safeStates, choices);
347template<
class SparseModelType>
349 std::vector<ValueType>
const& weightedActionRewardVector,
350 boost::optional<std::vector<ValueType>>
const& weightedStateRewardVector) {
352 STORM_LOG_ASSERT(lraMecDecomposition,
"Mec decomposition for lra computations not initialized.");
357 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
358 auto const& mec = lraMecDecomposition->mecs[mecIndex];
359 auto actionValueGetter = [&weightedActionRewardVector](uint64_t
const& a) {
return weightedActionRewardVector[a]; };
361 if (weightedStateRewardVector) {
362 stateValueGetter = [&weightedStateRewardVector](uint64_t
const& s) {
return weightedStateRewardVector.get()[s]; };
364 stateValueGetter = [](uint64_t
const&) {
return storm::utility::zero<ValueType>(); };
366 lraMecDecomposition->auxMecValues[mecIndex] = helper.
computeLraForComponent(env, stateValueGetter, actionValueGetter, mec);
372template<
class SparseModelType>
374 std::vector<ValueType>
const& weightVector) {
376 if (this->objectivesWithNoUpperTimeBound.empty() ||
379 this->weightedResult.assign(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
381 if (this->lraMecDecomposition) {
382 for (
auto const& mec : this->lraMecDecomposition->mecs) {
383 for (
auto const& sc : mec) {
384 statesInLraMec.
set(sc.first,
true);
390 this->optimalChoices);
394 updateEcQuotient(weightedRewardVector);
398 std::map<uint64_t, uint64_t> ecqStateToOptimalMecMap;
399 if (!lraObjectives.empty()) {
404 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
405 auto const& mec = lraMecDecomposition->mecs[mecIndex];
406 auto const& mecValue = lraMecDecomposition->auxMecValues[mecIndex];
407 uint64_t ecqState = ecQuotient->originalToEcqStateMapping[mec.begin()->first];
408 if (ecqState >= ecQuotient->matrix.getRowGroupCount()) {
413 uint64_t ecqChoice = ecQuotient->ecqStayInEcChoices.getNextSetIndex(ecQuotient->matrix.getRowGroupIndices()[ecqState]);
414 STORM_LOG_ASSERT(ecqChoice < ecQuotient->matrix.getRowGroupIndices()[ecqState + 1],
415 "Unable to find choice that represents staying inside the (eliminated) ec.");
416 auto& ecqChoiceValue = ecQuotient->auxChoiceValues[ecqChoice];
417 auto insertionRes = ecqStateToOptimalMecMap.emplace(ecqState, mecIndex);
418 if (insertionRes.second) {
421 "Expected a total reward of zero for choices that represent staying in an EC for ever.");
422 ecqChoiceValue = mecValue;
424 if (mecValue > ecqChoiceValue) {
425 ecqChoiceValue = mecValue;
426 insertionRes.first->second = mecIndex;
433 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = solverFactory.
create(env, ecQuotient->matrix);
434 solver->setTrackScheduler(
true);
435 solver->setHasUniqueSolution(
true);
436 solver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize);
437 auto req = solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize);
438 setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), weightVector, objectivesWithNoUpperTimeBound, ecQuotient->matrix,
439 ecQuotient->rowsWithSumLessOne, ecQuotient->auxChoiceValues);
440 if (solver->hasLowerBound()) {
441 req.clearLowerBounds();
443 if (solver->hasUpperBound()) {
444 req.clearUpperBounds();
446 if (req.validInitialScheduler()) {
448 req.clearValidInitialScheduler();
450 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
451 "Solver requirements " + req.getEnabledRequirementsAsString() +
" not checked.");
452 solver->setRequirementsChecked(
true);
455 std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero<ValueType>());
457 solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues);
458 this->weightedResult = std::vector<ValueType>(transitionMatrix.getRowGroupCount());
460 transformEcqSolutionToOriginalModel(ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecqStateToOptimalMecMap, this->weightedResult,
461 this->optimalChoices);
464template<
class SparseModelType>
466 if (objectivesWithNoUpperTimeBound.getNumberOfSetBits() == 1 &&
storm::utility::isOne(weightVector[*objectivesWithNoUpperTimeBound.begin()])) {
467 uint_fast64_t objIndex = *objectivesWithNoUpperTimeBound.begin();
468 objectiveResults[objIndex] = weightedResult;
472 for (uint_fast64_t objIndex2 = 0; objIndex2 < this->objectives.size(); ++objIndex2) {
473 if (objIndex != objIndex2) {
474 objectiveResults[objIndex2] = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
480 std::vector<ValueType> deterministicStateRewards(deterministicMatrix.
getRowCount());
483 auto infiniteHorizonHelper = createDetInfiniteHorizonHelper(deterministicMatrix);
484 infiniteHorizonHelper.provideBackwardTransitions(deterministicBackwardTransitions);
488 std::vector<ValueType> weightedSumOfUncheckedObjectives = weightedResult;
492 auto const& obj = this->objectives[objIndex];
493 if (objectivesWithNoUpperTimeBound.get(objIndex)) {
494 offsetsToUnderApproximation[objIndex] = storm::utility::zero<ValueType>();
495 offsetsToOverApproximation[objIndex] = storm::utility::zero<ValueType>();
496 if (lraObjectives.get(objIndex)) {
497 auto actionValueGetter = [&](uint64_t
const& a) {
498 return actionRewards[objIndex][transitionMatrix.getRowGroupIndices()[a] + this->optimalChoices[a]];
501 if (stateRewards.empty() || stateRewards[objIndex].empty()) {
502 stateValueGetter = [](uint64_t
const&) {
return storm::utility::zero<ValueType>(); };
504 stateValueGetter = [&](uint64_t
const& s) {
return stateRewards[objIndex][s]; };
509 actionRewards[objIndex]);
517 objectiveResults[objIndex] = weightedSumOfUncheckedObjectives;
518 ValueType scalingFactor = storm::utility::one<ValueType>() / sumOfWeightsOfUncheckedObjectives;
520 scalingFactor *= -storm::utility::one<ValueType>();
526 objectiveResults[objIndex].resize(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
528 if (!maybeStates.
empty()) {
529 bool needEquationSystem =
532 deterministicMatrix.
getSubmatrix(
true, maybeStates, maybeStates, needEquationSystem);
533 if (needEquationSystem) {
544 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.
create(env, submatrix);
545 auto req = solver->getRequirements(env);
546 solver->clearBounds();
549 this->setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), objIndex, submatrix, submatrixRowsWithSumLessOne, b);
550 if (solver->hasLowerBound()) {
551 req.clearLowerBounds();
553 if (solver->hasUpperBound()) {
554 req.clearUpperBounds();
556 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
557 "Solver requirements " + req.getEnabledRequirementsAsString() +
" not checked.");
558 solver->solveEquations(env, x, b);
560 storm::utility::vector::setVectorValues<ValueType>(objectiveResults[objIndex], maybeStates, x);
562 storm::utility::vector::setVectorValues<ValueType>(objectiveResults[objIndex], ~maybeStates, storm::utility::zero<ValueType>());
567 sumOfWeightsOfUncheckedObjectives -= weightVector[objIndex];
570 objectiveResults[objIndex] = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
576template<
class SparseModelType>
581 if (lraMecDecomposition) {
582 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
585 auto const& mec = lraMecDecomposition->mecs[mecIndex];
586 for (
auto const& stateChoices : mec) {
587 for (
auto const& choice : stateChoices.second) {
588 zeroLraRewardChoices.
set(choice,
false);
595 if (!ecQuotient || ecQuotient->origReward0Choices != newReward0Choices) {
597 auto nonZeroRewardStates = transitionMatrix.getRowGroupFilter(newReward0Choices,
true);
600 transitionMatrix.transpose(
true),
storm::storage::BitVector(transitionMatrix.getRowGroupCount(),
true), nonZeroRewardStates);
605 ecChoicesHint & newTotalReward0Choices, totalReward0EStates);
608 for (uint64_t row = 0; row < rowsWithSumLessOne.
size(); ++row) {
609 if (ecElimResult.matrix.getRow(row).getNumberOfEntries() == 0) {
610 rowsWithSumLessOne.
set(row,
true);
612 for (
auto const& entry : transitionMatrix.getRow(ecElimResult.newToOldRowMapping[row])) {
613 if (!subsystemStates.
get(entry.getColumn())) {
614 rowsWithSumLessOne.
set(row,
true);
622 ecQuotient->matrix = std::move(ecElimResult.matrix);
623 ecQuotient->ecqToOriginalChoiceMapping = std::move(ecElimResult.newToOldRowMapping);
624 ecQuotient->originalToEcqStateMapping = std::move(ecElimResult.oldToNewStateMapping);
625 ecQuotient->ecqToOriginalStateMapping.resize(ecQuotient->matrix.getRowGroupCount());
626 for (uint64_t state = 0; state < ecQuotient->originalToEcqStateMapping.size(); ++state) {
627 uint64_t ecqState = ecQuotient->originalToEcqStateMapping[state];
628 if (ecqState < ecQuotient->matrix.getRowGroupCount()) {
629 ecQuotient->ecqToOriginalStateMapping[ecqState].insert(state);
632 ecQuotient->ecqStayInEcChoices = std::move(ecElimResult.sinkRows);
633 ecQuotient->origReward0Choices = std::move(newReward0Choices);
634 ecQuotient->origTotalReward0Choices = std::move(newTotalReward0Choices);
635 ecQuotient->rowsWithSumLessOne = std::move(rowsWithSumLessOne);
636 ecQuotient->auxStateValues.resize(ecQuotient->matrix.getRowGroupCount());
637 ecQuotient->auxChoiceValues.resize(ecQuotient->matrix.getRowCount());
641template<
class SparseModelType>
643 bool requiresUpper, uint64_t objIndex,
646 std::vector<ValueType>
const& rewards)
const {
648 if (this->objectives[objIndex].lowerResultBound) {
649 solver.
setLowerBound(this->objectives[objIndex].lowerResultBound.get());
651 if (this->objectives[objIndex].upperResultBound) {
652 solver.
setUpperBound(this->objectives[objIndex].upperResultBound.get());
656 computeAndSetBoundsToSolver(solver, requiresLower, requiresUpper, transitions, rowsWithSumLessOne, rewards);
660template<
class SparseModelType>
662 bool requiresUpper, std::vector<ValueType>
const& weightVector,
666 std::vector<ValueType>
const& rewards)
const {
668 boost::optional<ValueType> lowerBound = this->computeWeightedResultBound(
true, weightVector, objectiveFilter & ~lraObjectives);
670 if (!lraObjectives.empty()) {
671 auto min = std::min_element(lraMecDecomposition->auxMecValues.begin(), lraMecDecomposition->auxMecValues.end());
672 if (min != lraMecDecomposition->auxMecValues.end()) {
673 lowerBound.get() += *min;
678 boost::optional<ValueType> upperBound = this->computeWeightedResultBound(
false, weightVector, objectiveFilter);
680 if (!lraObjectives.empty()) {
681 auto max = std::max_element(lraMecDecomposition->auxMecValues.begin(), lraMecDecomposition->auxMecValues.end());
682 if (max != lraMecDecomposition->auxMecValues.end()) {
683 upperBound.get() += *max;
690 computeAndSetBoundsToSolver(solver, requiresLower, requiresUpper, transitions, rowsWithSumLessOne, rewards);
694template<
class SparseModelType>
699 std::vector<ValueType>
const& rewards)
const {
701 std::vector<ValueType> oneStepTargetProbs(transitions.
getRowCount(), storm::utility::zero<ValueType>());
702 for (
auto row : rowsWithSumLessOne) {
703 oneStepTargetProbs[row] = storm::utility::one<ValueType>() - transitions.
getRowSum(row);
708 std::vector<ValueType> negativeRewards;
709 negativeRewards.reserve(transitions.
getRowCount());
711 for (
auto const& rew : rewards) {
712 if (rew < storm::utility::zero<ValueType>()) {
713 negativeRewards.resize(row, storm::utility::zero<ValueType>());
714 negativeRewards.push_back(-rew);
718 if (!negativeRewards.empty()) {
719 negativeRewards.resize(row, storm::utility::zero<ValueType>());
720 std::vector<ValueType> lowerBounds =
732 std::vector<ValueType> positiveRewards;
733 positiveRewards.reserve(transitions.
getRowCount());
735 for (
auto const& rew : rewards) {
736 if (rew > storm::utility::zero<ValueType>()) {
737 positiveRewards.resize(row, storm::utility::zero<ValueType>());
738 positiveRewards.push_back(rew);
742 if (!positiveRewards.empty()) {
743 positiveRewards.resize(row, storm::utility::zero<ValueType>());
752template<
class SparseModelType>
754 std::vector<uint_fast64_t>
const& ecqOptimalChoices,
755 std::map<uint64_t, uint64_t>
const& ecqStateToOptimalMecMap,
756 std::vector<ValueType>& originalSolution,
757 std::vector<uint_fast64_t>& originalOptimalChoices)
const {
758 auto backwardsTransitions = transitionMatrix.transpose(
true);
769 for (uint64_t ecqState = 0; ecqState < ecqSolution.size(); ++ecqState) {
770 uint64_t ecqChoice = ecQuotient->matrix.getRowGroupIndices()[ecqState] + ecqOptimalChoices[ecqState];
771 uint_fast64_t origChoice = ecQuotient->ecqToOriginalChoiceMapping[ecqChoice];
772 auto const& origStates = ecQuotient->ecqToOriginalStateMapping[ecqState];
773 STORM_LOG_ASSERT(!origStates.empty(),
"Unexpected empty set of original states.");
774 if (ecQuotient->ecqStayInEcChoices.get(ecqChoice)) {
777 if (!ecqStateToOptimalMecMap.empty()) {
780 STORM_LOG_ASSERT(ecqStateToOptimalMecMap.count(ecqState) > 0,
"No Lra Mec associated to given eliminated EC");
781 auto const& lraMec = lraMecDecomposition->mecs[ecqStateToOptimalMecMap.at(ecqState)];
782 if (lraMec.size() == origStates.size()) {
784 for (
auto const& state : origStates) {
785 STORM_LOG_ASSERT(lraMec.containsState(state),
"Expected state to be contained in the lra mec.");
787 unprocessedStates.
set(state,
false);
788 originalSolution[state] = ecqSolution[ecqState];
792 STORM_LOG_ASSERT(lraMec.size() < origStates.size(),
"Lra Mec (" << lraMec.size()
793 <<
" states) should be a proper subset of the eliminated ec ("
794 << origStates.size() <<
" states).");
795 for (
auto const& state : origStates) {
796 if (lraMec.containsState(state)) {
797 ecStatesToReach.
set(state,
true);
800 ecStatesToProcess.
set(state,
true);
802 unprocessedStates.
set(state,
false);
803 originalSolution[state] = ecqSolution[ecqState];
805 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess, ecStatesToReach, originalOptimalChoices,
806 &ecQuotient->origTotalReward0Choices);
808 ecStatesToProcess.
clear();
809 ecStatesToReach.
clear();
815 bool needSchedulerComputation =
false;
817 "Solution for state that stays inside EC must be zero. Got " << ecqSolution[ecqState] <<
" instead.");
818 for (
auto const& state : origStates) {
819 originalSolution[state] = storm::utility::zero<ValueType>();
820 ecStatesToProcess.
set(state,
true);
822 auto validChoices = transitionMatrix.getRowFilter(ecStatesToProcess, ecStatesToProcess);
823 auto valid0RewardChoices = validChoices & actionsWithoutRewardInUnboundedPhase;
824 for (
auto const& state : origStates) {
825 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
826 auto groupEnd = transitionMatrix.getRowGroupIndices()[state + 1];
827 auto nextValidChoice = valid0RewardChoices.getNextSetIndex(groupStart);
828 if (nextValidChoice < groupEnd) {
829 originalOptimalChoices[state] = nextValidChoice - groupStart;
832 ecStatesToAvoid.
set(state,
true);
833 needSchedulerComputation =
true;
836 if (needSchedulerComputation) {
838 auto ecStatesThatCanAvoid =
840 ecStatesToProcess, ecStatesToAvoid,
false, 0, valid0RewardChoices);
841 ecStatesThatCanAvoid.complement();
843 computeSchedulerProb0(transitionMatrix, backwardsTransitions, ecStatesThatCanAvoid, ecStatesToAvoid, valid0RewardChoices,
844 originalOptimalChoices);
846 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess & ~ecStatesToAvoid, ecStatesToAvoid, originalOptimalChoices,
849 ecStatesToAvoid.
clear();
850 ecStatesToProcess.
clear();
856 if (origStates.size() > 1) {
857 for (
auto const& state : origStates) {
859 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
860 auto groupEnd = transitionMatrix.getRowGroupIndices()[state + 1];
861 if (origChoice >= groupStart && origChoice < groupEnd) {
862 originalOptimalChoices[state] = origChoice - groupStart;
863 ecStatesToReach.
set(state,
true);
865 STORM_LOG_ASSERT(origStates.size() > 1,
"Multiple original states expected.");
866 ecStatesToProcess.
set(state,
true);
868 unprocessedStates.
set(state,
false);
869 originalSolution[state] = ecqSolution[ecqState];
871 auto validChoices = transitionMatrix.getRowFilter(ecStatesToProcess, ecStatesToProcess | ecStatesToReach);
872 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess, ecStatesToReach, originalOptimalChoices, &validChoices);
874 ecStatesToProcess.
clear();
875 ecStatesToReach.
clear();
878 auto state = *origStates.begin();
879 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
881 origChoice >= groupStart && origChoice < transitionMatrix.getRowGroupIndices()[state + 1],
882 "Invalid choice: " << originalOptimalChoices[state] <<
" at a state with " << transitionMatrix.getRowGroupSize(state) <<
" choices.");
883 originalOptimalChoices[state] = origChoice - groupStart;
884 originalSolution[state] = ecqSolution[ecqState];
885 unprocessedStates.
set(state,
false);
894 if (this->lraMecDecomposition) {
896 for (
auto const& mec : this->lraMecDecomposition->mecs) {
897 for (
auto const& sc : mec) {
898 if (unprocessedStates.
get(sc.first)) {
899 ecStatesToReach.
set(sc.first,
true);
904 ecStatesToReach = unprocessedStates & totalReward0EStates;
906 computeSchedulerProb0(transitionMatrix, backwardsTransitions, ecStatesToReach, ~unprocessedStates | ~totalReward0EStates,
907 actionsWithoutRewardInUnboundedPhase, originalOptimalChoices);
909 unprocessedStates &= ~ecStatesToReach;
911 computeSchedulerProb1(transitionMatrix, backwardsTransitions, unprocessedStates, ecStatesToReach, originalOptimalChoices);
916#ifdef STORM_HAVE_CARL
ValueType computeUpperBound()
Computes an upper bound on the expected rewards.
std::vector< ValueType > computeUpperBounds()
Computes upper bounds on the expected rewards.
void setProduceScheduler(bool value)
Sets whether an optimal scheduler shall be constructed during the computation.
void setOptimizationDirection(storm::solver::OptimizationDirection const &direction)
Sets the optimization direction, i.e., whether we want to minimize or maximize the value for each sta...
void provideLongRunComponentDecomposition(storm::storage::Decomposition< LongRunComponentType > const &decomposition)
Provides the decomposition into long run components (BSCCs/MECs) that can be used during the computat...
std::vector< ValueType > computeLongRunAverageValues(Environment const &env, std::vector< ValueType > const *stateValues=nullptr, std::vector< ValueType > const *actionValues=nullptr)
Computes the long run average value given the provided state and action-based rewards.
Helper class for model checking queries that depend on the long run behavior of the (nondeterministic...
SparseInfiniteHorizonHelper< ValueType, true >::ValueGetter ValueGetter
Function mapping from indices to values.
std::vector< uint64_t > const & getProducedOptimalChoices() const
virtual ValueType computeLraForComponent(Environment const &env, ValueGetter const &stateValuesGetter, ValueGetter const &actionValuesGetter, storm::storage::MaximalEndComponent const &component) override
Helper Class that takes a weight vector and ...
Helper Class that takes preprocessed Pcaa data and a weight vector and ...
void unboundedWeightedPhase(Environment const &env, std::vector< ValueType > const &weightedRewardVector, std::vector< ValueType > const &weightVector)
Determines the scheduler that optimizes the weighted reward vector of the unbounded objectives.
virtual std::vector< ValueType > getOverApproximationOfInitialStateResults() const override
void computeAndSetBoundsToSolver(storm::solver::AbstractEquationSolver< ValueType > &solver, bool requiresLower, bool requiresUpper, storm::storage::SparseMatrix< ValueType > const &transitions, storm::storage::BitVector const &rowsWithSumLessOne, std::vector< ValueType > const &rewards) const
StandardPcaaWeightVectorChecker(preprocessing::SparseMultiObjectivePreprocessorResult< SparseModelType > const &preprocessorResult)
SparseModelType::ValueType ValueType
virtual std::vector< ValueType > getUnderApproximationOfInitialStateResults() const override
Retrieves the results of the individual objectives at the initial state of the given model.
void transformEcqSolutionToOriginalModel(std::vector< ValueType > const &ecqSolution, std::vector< uint_fast64_t > const &ecqOptimalChoices, std::map< uint64_t, uint64_t > const &ecqStateToOptimalMecMap, std::vector< ValueType > &originalSolution, std::vector< uint_fast64_t > &originalOptimalChoices) const
Transforms the results of a min-max-solver that considers a reduced model (without end components) to...
void infiniteHorizonWeightedPhase(Environment const &env, std::vector< ValueType > const &weightedActionRewardVector, boost::optional< std::vector< ValueType > > const &weightedStateRewardVector)
virtual storm::storage::Scheduler< ValueType > computeScheduler() const override
Retrieves a scheduler that induces the current values Note that check(..) has to be called before ret...
virtual void check(Environment const &env, std::vector< ValueType > const &weightVector) override
void updateEcQuotient(std::vector< ValueType > const &weightedRewardVector)
void initialize(preprocessing::SparseMultiObjectivePreprocessorResult< SparseModelType > const &preprocessorResult)
void unboundedIndividualPhase(Environment const &env, std::vector< ValueType > const &weightVector)
Computes the values of the objectives that do not have a stepBound w.r.t.
void setBoundsToSolver(storm::solver::AbstractEquationSolver< ValueType > &solver, bool requiresLower, bool requiresUpper, uint64_t objIndex, storm::storage::SparseMatrix< ValueType > const &transitions, storm::storage::BitVector const &rowsWithSumLessOne, std::vector< ValueType > const &rewards) const
static ReturnType analyze(storm::modelchecker::multiobjective::preprocessing::SparseMultiObjectivePreprocessorResult< SparseModelType > const &preprocessorResult)
Analyzes the reward objectives of the multi objective query.
void setUpperBound(ValueType const &value)
Sets an upper bound for the solution that can potentially be used by the solver.
bool hasUpperBound(BoundType const &type=BoundType::Any) const
Retrieves whether this solver has an upper bound.
bool hasLowerBound(BoundType const &type=BoundType::Any) const
Retrieves whether this solver has a lower bound.
void setLowerBound(ValueType const &value)
Sets a lower bound for the solution that can potentially be used by the solver.
void setLowerBounds(std::vector< ValueType > const &values)
Sets lower bounds for the solution that can potentially be used by the solver.
virtual std::unique_ptr< LinearEquationSolver< ValueType > > create(Environment const &env) const override
Creates an equation solver with the current settings, but without a matrix.
virtual std::unique_ptr< MinMaxLinearEquationSolver< ValueType, SolutionType > > create(Environment const &env) const override
virtual LinearEquationSolverProblemFormat getEquationProblemFormat(Environment const &env) const
Retrieves the problem format that the solver expects if it was created with the current settings.
A bit vector that is internally represented as a vector of 64-bit values.
void complement()
Negates all bits in the bit vector.
const_iterator end() const
Returns an iterator pointing at the element past the back of the bit vector.
uint_fast64_t getNextSetIndex(uint_fast64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to true in the bit vector.
bool empty() const
Retrieves whether no bits are set to true in this bit vector.
void clear()
Removes all set bits from the bit vector.
bool isSubsetOf(BitVector const &other) const
Checks whether all bits that are set in the current bit vector are also set in the given bit vector.
void resize(uint_fast64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
const_iterator begin() const
Returns an iterator to the indices of the set bits in the bit vector.
void set(uint_fast64_t index, bool value=true)
Sets the given truth value at the given index.
size_t size() const
Retrieves the number of bits this bit vector can store.
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 defines which action is chosen in a particular state of a non-deterministic model.
void setChoice(SchedulerChoice< ValueType > const &choice, uint_fast64_t modelState, uint_fast64_t memoryState=0)
Sets the choice defined by the scheduler for the given state.
A class that holds a possibly non-square matrix in the compressed row storage format.
void convertToEquationSystem()
Transforms the matrix into an equation system.
const_rows getRow(index_type row) const
Returns an object representing the given row.
SparseMatrix selectRowsFromRowGroups(std::vector< index_type > const &rowGroupToRowIndexMapping, bool insertDiagonalEntries=true) const
Selects exactly one row from each row group of this matrix and returns the resulting matrix.
SparseMatrix getSubmatrix(bool useGroups, storm::storage::BitVector const &rowConstraint, storm::storage::BitVector const &columnConstraint, bool insertDiagonalEntries=false, storm::storage::BitVector const &makeZeroColumns=storm::storage::BitVector()) const
Creates a submatrix of the current matrix by dropping all rows and columns whose bits are not set to ...
value_type getRowSum(index_type row) const
Computes the sum of the entries in a given row.
index_type getRowGroupCount() const
Returns the number of row groups in the matrix.
storm::storage::BitVector getRowGroupFilter(storm::storage::BitVector const &rowConstraint, bool setIfForAllRowsInGroup) const
Returns the indices of all row groups selected by the row constraints.
std::vector< index_type > const & getRowGroupIndices() const
Returns the grouping of rows of this matrix.
storm::storage::SparseMatrix< value_type > transpose(bool joinGroups=false, bool keepZeros=false) const
Transposes the matrix.
index_type getRowCount() const
Returns the number of rows of the matrix.
storm::storage::BitVector getRowFilter(storm::storage::BitVector const &groupConstraint) const
Returns a bitvector representing the set of rows, with all indices set that correspond to one of the ...
#define STORM_LOG_INFO(message)
#define STORM_LOG_ASSERT(cond, message)
#define STORM_LOG_THROW(cond, exception, message)
#define STORM_PRINT_AND_LOG(message)
std::vector< uint64_t > computeValidInitialScheduler(storm::storage::SparseMatrix< ValueType > const &matrix, storm::storage::BitVector const &rowsWithSumLessOne)
void computeSchedulerFinitelyOften(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &finitelyOftenChoices, storm::storage::BitVector safeStates, std::vector< uint64_t > &choices)
Computes a scheduler taking the choices from the given set only finitely often.
void computeSchedulerProb1(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &consideredStates, storm::storage::BitVector const &statesToReach, std::vector< uint64_t > &choices, storm::storage::BitVector const *allowedChoices=nullptr)
void computeSchedulerProb0(storm::storage::SparseMatrix< ValueType > const &transitionMatrix, storm::storage::SparseMatrix< ValueType > const &backwardTransitions, storm::storage::BitVector const &consideredStates, storm::storage::BitVector const &statesToAvoid, storm::storage::BitVector const &allowedChoices, std::vector< uint64_t > &choices)
SettingsType const & getModule()
Get module.
bool constexpr minimize(OptimizationDirection d)
storm::storage::BitVector performProbGreater0(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Performs a backward depth-first search trough the underlying graph structure of the given model to de...
storm::storage::BitVector performProbGreater0A(storm::storage::SparseMatrix< T > const &transitionMatrix, std::vector< uint_fast64_t > const &nondeterministicChoiceIndices, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceConstraint)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under any pos...
storm::storage::BitVector performProbGreater0E(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates, bool useStepBound, uint_fast64_t maximalSteps)
Computes the sets of states that have probability greater 0 of satisfying phi until psi under at leas...
storm::storage::BitVector performProb0E(storm::models::sparse::NondeterministicModel< T, RM > const &model, storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Computes the sets of states that have probability 0 of satisfying phi until psi under at least one po...
T dotProduct(std::vector< T > const &firstOperand, std::vector< T > const &secondOperand)
Computes the dot product (aka scalar product) and returns the result.
void setVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Sets the provided values at the provided positions in the given vector.
void selectVectorValues(std::vector< T > &vector, storm::storage::BitVector const &positions, std::vector< T > const &values)
Selects the elements from a vector at the specified positions and writes them consecutively into anot...
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...
std::string toString(std::vector< ValueType > const &vector)
Output vector as string.
void clip(std::vector< ValueType > &x, boost::optional< ValueType > const &lowerBound, boost::optional< ValueType > const &upperBound)
Takes the input vector and ensures that all entries conform to the bounds.
VT sum_if(std::vector< VT > const &values, storm::storage::BitVector const &filter)
Sum the entries from values that are set to one in the filter vector.
std::vector< uint_fast64_t > getSortedIndices(std::vector< T > const &v)
Returns a list of indices such that the first index refers to the highest entry of the given vector,...
storm::storage::BitVector filterZero(std::vector< T > const &values)
Retrieves a bit vector containing all the indices for which the value at this position is equal to ze...
void scaleVectorInPlace(std::vector< ValueType1 > &target, ValueType2 const &factor)
Multiplies each element of the given vector with the given factor and writes the result into the vect...
bool hasNonZeroEntry(std::vector< T > const &v)
std::vector< Type > filterVector(std::vector< Type > const &in, storm::storage::BitVector const &filter)
bool isOne(ValueType const &a)
bool isZero(ValueType const &a)
ValueType sqrt(ValueType const &number)
bool containsOnlyTrivialObjectives() const
std::shared_ptr< SparseModelType > preprocessedModel