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.");
46 "There might be infinite reward for some scheduler. Multi-objective model checking restricts to schedulers that yield finite reward "
47 "for all objectives. Be aware that solutions yielding infinite reward are discarded.");
48 STORM_LOG_THROW(rewardAnalysis.totalRewardLessInfinityEStates, storm::exceptions::UnexpectedException,
49 "The set of states with reward < infinity for some scheduler has not been computed during preprocessing.");
51 "At least one objective was not reduced to an expected (long run, total or cumulative) reward objective during preprocessing. This is not "
52 "supported by the considered weight vector checker.");
54 "The model has multiple initial states.");
60 rewardAnalysis.totalRewardLessInfinityEStates.get(), rewardAnalysis.totalRewardLessInfinityEStates.get());
61 std::set<std::string> relevantRewardModels;
62 for (
auto const& obj : this->objectives) {
63 obj.formula->gatherReferencedRewardModels(relevantRewardModels);
68 std::vector<std::string>(relevantRewardModels.begin(), relevantRewardModels.end()), finiteTotalRewardChoices);
69 goalStateMergerInputToReducedStateIndexMapping = std::move(mergerResult.oldToNewStateIndexMapping);
70 goalStateMergerReducedToInputChoiceMapping = mergerResult.keptChoices.getNumberOfSetBitsBeforeIndices();
72 initializeModelTypeSpecificData(*mergerResult.model);
75 transitionMatrix = std::move(mergerResult.model->getTransitionMatrix());
76 initialState = *mergerResult.model->getInitialStates().begin();
77 totalReward0EStates = rewardAnalysis.totalReward0EStates % maybeStates;
78 if (mergerResult.targetState) {
80 totalReward0EStates.
resize(totalReward0EStates.size() + 1,
true);
84 targetStateAsVector.
set(*mergerResult.targetState,
true);
85 ecChoicesHint = transitionMatrix.getRowFilter(
88 ecChoicesHint.set(transitionMatrix.getRowGroupIndices()[*mergerResult.targetState],
true);
97 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
98 auto const& formula = *this->objectives[objIndex].formula;
99 if (formula.getSubformula().isTotalRewardFormula()) {
100 objectivesWithNoUpperTimeBound.set(objIndex,
true);
103 if (formula.getSubformula().isLongRunAverageRewardFormula()) {
104 lraObjectives.set(objIndex,
true);
105 objectivesWithNoUpperTimeBound.set(objIndex,
true);
110 if (!lraObjectives.empty()) {
111 lraMecDecomposition = LraMecDecomposition();
114 actionsWithoutRewardInUnboundedPhase);
115 lraMecDecomposition->auxMecValues.resize(lraMecDecomposition->mecs.size());
119 checkHasBeenCalled =
false;
120 objectiveResults.resize(this->objectives.size());
121 offsetsToUnderApproximation.resize(this->objectives.size(), storm::utility::zero<ValueType>());
122 offsetsToOverApproximation.resize(this->objectives.size(), storm::utility::zero<ValueType>());
123 optimalChoices.resize(transitionMatrix.getRowGroupCount(), 0);
126 if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
128 STORM_PRINT_AND_LOG(
"Final preprocessed model has " << transitionMatrix.getRowGroupCount() <<
" states.\n");
129 STORM_PRINT_AND_LOG(
"Final preprocessed model has " << transitionMatrix.getRowCount() <<
" actions.\n");
130 if (lraMecDecomposition) {
131 STORM_PRINT_AND_LOG(
"Found " << lraMecDecomposition->mecs.size() <<
" end components that are relevant for LRA-analysis.\n");
132 uint64_t numLraMecStates = 0;
133 for (
auto const& mec : this->lraMecDecomposition->mecs) {
134 numLraMecStates += mec.size();
142template<
class SparseModelType>
144 checkHasBeenCalled =
true;
149 std::vector<ValueType> weightedRewardVector(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>());
150 if (!lraObjectives.empty()) {
151 boost::optional<std::vector<ValueType>> weightedStateRewardVector;
152 for (
auto objIndex : lraObjectives) {
154 storm::solver::minimize(this->objectives[objIndex].formula->getOptimalityType()) ? -weightVector[objIndex] : weightVector[objIndex];
156 if (!stateRewards.empty() && !stateRewards[objIndex].empty()) {
157 if (!weightedStateRewardVector) {
158 weightedStateRewardVector = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
163 infiniteHorizonWeightedPhase(env, weightedRewardVector, weightedStateRewardVector);
165 weightedRewardVector.assign(weightedRewardVector.size(), storm::utility::zero<ValueType>());
169 auto totalRewardObjectives = objectivesWithNoUpperTimeBound & ~lraObjectives;
170 for (
auto objIndex : totalRewardObjectives) {
177 unboundedWeightedPhase(env, weightedRewardVector, weightVector);
179 unboundedIndividualPhase(env, weightVector);
181 for (
auto const& obj : this->objectives) {
182 if (!obj.formula->getSubformula().isTotalRewardFormula() && !obj.formula->getSubformula().isLongRunAverageRewardFormula()) {
183 boundedPhase(env, weightVector, weightedRewardVector);
187 STORM_LOG_INFO(
"Weight vector check done. Lower bounds for results in initial state: "
194 STORM_LOG_THROW(resultingWeightedPrecision <= this->getWeightedPrecision(), storm::exceptions::UnexpectedException,
195 "The desired precision was not reached");
198template<
class SparseModelType>
199std::vector<typename StandardPcaaWeightVectorChecker<SparseModelType>::ValueType>
201 STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
"Tried to retrieve results but check(..) has not been called before.");
202 std::vector<ValueType> res;
203 res.reserve(this->objectives.size());
204 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
205 res.push_back(this->objectiveResults[objIndex][initialState] + this->offsetsToUnderApproximation[objIndex]);
210template<
class SparseModelType>
211std::vector<typename StandardPcaaWeightVectorChecker<SparseModelType>::ValueType>
213 STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
"Tried to retrieve results but check(..) has not been called before.");
214 std::vector<ValueType> res;
215 res.reserve(this->objectives.size());
216 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
217 res.push_back(this->objectiveResults[objIndex][initialState] + this->offsetsToOverApproximation[objIndex]);
222template<
class SparseModelType>
225 STORM_LOG_THROW(this->checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
226 "Tried to retrieve results but check(..) has not been called before.");
227 for (
auto const& obj : this->objectives) {
228 STORM_LOG_THROW(obj.formula->getSubformula().isTotalRewardFormula() || obj.formula->getSubformula().isLongRunAverageRewardFormula(),
229 storm::exceptions::NotImplementedException,
"Scheduler retrival is only implemented for objectives without time-bound.");
231 auto const numStatesOfInputModel = goalStateMergerInputToReducedStateIndexMapping.size();
233 for (uint64_t inputModelState = 0; inputModelState < numStatesOfInputModel; ++inputModelState) {
234 auto const reducedModelState = goalStateMergerInputToReducedStateIndexMapping[inputModelState];
235 if (reducedModelState >= optimalChoices.size()) {
239 auto const reducedModelChoice = optimalChoices[reducedModelState];
240 auto const inputModelChoice = goalStateMergerReducedToInputChoiceMapping[reducedModelChoice];
241 result.
setChoice(inputModelChoice, inputModelState);
247template<
typename ValueType>
251 std::vector<uint64_t> stack;
253 stack.insert(stack.end(), processedStates.
begin(), processedStates.
end());
254 uint64_t currentState = 0;
256 while (!stack.empty()) {
257 currentState = stack.back();
260 for (
auto const& predecessorEntry : backwardTransitions.
getRow(currentState)) {
261 auto predecessor = predecessorEntry.getColumn();
262 if (consideredStates.
get(predecessor) && !processedStates.
get(predecessor)) {
266 uint64_t row = allowedChoices ? allowedChoices->getNextSetIndex(groupStart) : groupStart;
267 for (; row < groupEnd; row = allowedChoices ? allowedChoices->getNextSetIndex(row + 1) : row + 1) {
268 bool hasSuccessorInProcessedStates =
false;
269 for (
auto const& successorOfPredecessor : transitionMatrix.
getRow(row)) {
270 if (processedStates.
get(successorOfPredecessor.getColumn())) {
271 hasSuccessorInProcessedStates =
true;
275 if (hasSuccessorInProcessedStates) {
276 choices[predecessor] = row - groupStart;
277 processedStates.
set(predecessor,
true);
278 stack.push_back(predecessor);
283 "Unable to find choice at a predecessor of a processed state that leads to a processed state.");
290template<
typename ValueType>
294 for (
auto state : consideredStates) {
297 bool choiceFound =
false;
300 for (
auto const& element : transitionMatrix.
getRow(row)) {
301 if (statesToAvoid.
get(element.getColumn())) {
307 choices[state] = row - groupStart;
315template<
typename ValueType>
319 auto backwardsTransitions = matrix.
transpose(
true);
321 for (uint64_t state = 0; state < result.size(); ++state) {
322 if (rowsWithSumLessOne.
getNextSetIndex(groups[state]) < groups[state + 1]) {
323 result[state] = rowsWithSumLessOne.
getNextSetIndex(groups[state]) - groups[state];
324 processedStates.
set(state,
true);
337template<
typename ValueType>
341 auto badStates = transitionMatrix.
getRowGroupFilter(finitelyOftenChoices,
true) & ~safeStates;
345 transitionMatrix, transitionMatrix.
getRowGroupIndices(), backwardTransitions, ~safeStates, badStates,
false, 0, ~finitelyOftenChoices);
348 auto avoidBadStates = ~reachBadWithProbGreater0AStates & ~safeStates;
349 computeSchedulerProb0(transitionMatrix, backwardTransitions, avoidBadStates, reachBadWithProbGreater0AStates, ~finitelyOftenChoices, choices);
354 computeSchedulerProb1(transitionMatrix, backwardTransitions, reachBadWithProbGreater0AStates, avoidBadStates | safeStates, choices);
357template<
class SparseModelType>
359 std::vector<ValueType>
const& weightedActionRewardVector,
360 boost::optional<std::vector<ValueType>>
const& weightedStateRewardVector) {
362 STORM_LOG_ASSERT(lraMecDecomposition,
"Mec decomposition for lra computations not initialized.");
367 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
368 auto const& mec = lraMecDecomposition->mecs[mecIndex];
369 auto actionValueGetter = [&weightedActionRewardVector](uint64_t
const& a) {
return weightedActionRewardVector[a]; };
371 if (weightedStateRewardVector) {
372 stateValueGetter = [&weightedStateRewardVector](uint64_t
const& s) {
return weightedStateRewardVector.get()[s]; };
374 stateValueGetter = [](uint64_t
const&) {
return storm::utility::zero<ValueType>(); };
376 lraMecDecomposition->auxMecValues[mecIndex] = helper.
computeLraForComponent(env, stateValueGetter, actionValueGetter, mec);
382template<
class SparseModelType>
384 std::vector<ValueType>
const& weightVector) {
386 if (this->objectivesWithNoUpperTimeBound.empty() ||
389 this->weightedResult.assign(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
391 if (this->lraMecDecomposition) {
392 for (
auto const& mec : this->lraMecDecomposition->mecs) {
393 for (
auto const& sc : mec) {
394 statesInLraMec.
set(sc.first,
true);
400 this->optimalChoices);
404 updateEcQuotient(weightedRewardVector);
408 std::map<uint64_t, uint64_t> ecqStateToOptimalMecMap;
409 if (!lraObjectives.empty()) {
414 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
415 auto const& mec = lraMecDecomposition->mecs[mecIndex];
416 auto const& mecValue = lraMecDecomposition->auxMecValues[mecIndex];
417 uint64_t ecqState = ecQuotient->originalToEcqStateMapping[mec.begin()->first];
418 if (ecqState >= ecQuotient->matrix.getRowGroupCount()) {
423 uint64_t ecqChoice = ecQuotient->ecqStayInEcChoices.getNextSetIndex(ecQuotient->matrix.getRowGroupIndices()[ecqState]);
424 STORM_LOG_ASSERT(ecqChoice < ecQuotient->matrix.getRowGroupIndices()[ecqState + 1],
425 "Unable to find choice that represents staying inside the (eliminated) ec.");
426 auto& ecqChoiceValue = ecQuotient->auxChoiceValues[ecqChoice];
427 auto insertionRes = ecqStateToOptimalMecMap.emplace(ecqState, mecIndex);
428 if (insertionRes.second) {
431 "Expected a total reward of zero for choices that represent staying in an EC for ever.");
432 ecqChoiceValue = mecValue;
434 if (mecValue > ecqChoiceValue) {
435 ecqChoiceValue = mecValue;
436 insertionRes.first->second = mecIndex;
443 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = solverFactory.
create(env, ecQuotient->matrix);
444 solver->setTrackScheduler(
true);
445 solver->setHasUniqueSolution(
true);
446 solver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize);
447 auto req = solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize);
448 setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), weightVector, objectivesWithNoUpperTimeBound, ecQuotient->matrix,
449 ecQuotient->rowsWithSumLessOne, ecQuotient->auxChoiceValues);
450 if (solver->hasLowerBound()) {
451 req.clearLowerBounds();
453 if (solver->hasUpperBound()) {
454 req.clearUpperBounds();
456 if (req.validInitialScheduler()) {
458 req.clearValidInitialScheduler();
460 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
461 "Solver requirements " + req.getEnabledRequirementsAsString() +
" not checked.");
462 solver->setRequirementsChecked(
true);
465 std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero<ValueType>());
467 solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues);
468 this->weightedResult = std::vector<ValueType>(transitionMatrix.getRowGroupCount());
470 transformEcqSolutionToOriginalModel(ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecqStateToOptimalMecMap, this->weightedResult,
471 this->optimalChoices);
474template<
class SparseModelType>
476 if (objectivesWithNoUpperTimeBound.getNumberOfSetBits() == 1 &&
storm::utility::isOne(weightVector[*objectivesWithNoUpperTimeBound.begin()])) {
477 uint_fast64_t objIndex = *objectivesWithNoUpperTimeBound.begin();
478 objectiveResults[objIndex] = weightedResult;
482 for (uint_fast64_t objIndex2 = 0; objIndex2 < this->objectives.size(); ++objIndex2) {
483 if (objIndex != objIndex2) {
484 objectiveResults[objIndex2] = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
490 std::vector<ValueType> deterministicStateRewards(deterministicMatrix.
getRowCount());
493 auto infiniteHorizonHelper = createDetInfiniteHorizonHelper(deterministicMatrix);
494 infiniteHorizonHelper.provideBackwardTransitions(deterministicBackwardTransitions);
498 std::vector<ValueType> weightedSumOfUncheckedObjectives = weightedResult;
502 auto const& obj = this->objectives[objIndex];
503 if (objectivesWithNoUpperTimeBound.get(objIndex)) {
504 offsetsToUnderApproximation[objIndex] = storm::utility::zero<ValueType>();
505 offsetsToOverApproximation[objIndex] = storm::utility::zero<ValueType>();
506 if (lraObjectives.get(objIndex)) {
507 auto actionValueGetter = [&](uint64_t
const& a) {
508 return actionRewards[objIndex][transitionMatrix.getRowGroupIndices()[a] + this->optimalChoices[a]];
511 if (stateRewards.empty() || stateRewards[objIndex].empty()) {
512 stateValueGetter = [](uint64_t
const&) {
return storm::utility::zero<ValueType>(); };
514 stateValueGetter = [&](uint64_t
const& s) {
return stateRewards[objIndex][s]; };
519 actionRewards[objIndex]);
527 objectiveResults[objIndex] = weightedSumOfUncheckedObjectives;
528 ValueType scalingFactor = storm::utility::one<ValueType>() / sumOfWeightsOfUncheckedObjectives;
530 scalingFactor *= -storm::utility::one<ValueType>();
536 objectiveResults[objIndex].resize(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
538 if (!maybeStates.
empty()) {
539 bool needEquationSystem =
542 deterministicMatrix.
getSubmatrix(
true, maybeStates, maybeStates, needEquationSystem);
543 if (needEquationSystem) {
554 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.
create(env, submatrix);
555 auto req = solver->getRequirements(env);
556 solver->clearBounds();
559 this->setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), objIndex, submatrix, submatrixRowsWithSumLessOne, b);
560 if (solver->hasLowerBound()) {
561 req.clearLowerBounds();
563 if (solver->hasUpperBound()) {
564 req.clearUpperBounds();
566 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
567 "Solver requirements " + req.getEnabledRequirementsAsString() +
" not checked.");
568 solver->solveEquations(env, x, b);
570 storm::utility::vector::setVectorValues<ValueType>(objectiveResults[objIndex], maybeStates, x);
572 storm::utility::vector::setVectorValues<ValueType>(objectiveResults[objIndex], ~maybeStates, storm::utility::zero<ValueType>());
577 sumOfWeightsOfUncheckedObjectives -= weightVector[objIndex];
580 objectiveResults[objIndex] = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
586template<
class SparseModelType>
591 if (lraMecDecomposition) {
592 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
595 auto const& mec = lraMecDecomposition->mecs[mecIndex];
596 for (
auto const& stateChoices : mec) {
597 for (
auto const& choice : stateChoices.second) {
598 zeroLraRewardChoices.
set(choice,
false);
605 if (!ecQuotient || ecQuotient->origReward0Choices != newReward0Choices) {
607 auto nonZeroRewardStates = transitionMatrix.getRowGroupFilter(newReward0Choices,
true);
610 transitionMatrix.transpose(
true),
storm::storage::BitVector(transitionMatrix.getRowGroupCount(),
true), nonZeroRewardStates);
615 ecChoicesHint & newTotalReward0Choices, totalReward0EStates);
618 for (uint64_t row = 0; row < rowsWithSumLessOne.
size(); ++row) {
619 if (ecElimResult.matrix.getRow(row).getNumberOfEntries() == 0) {
620 rowsWithSumLessOne.
set(row,
true);
622 for (
auto const& entry : transitionMatrix.getRow(ecElimResult.newToOldRowMapping[row])) {
623 if (!subsystemStates.
get(entry.getColumn())) {
624 rowsWithSumLessOne.
set(row,
true);
632 ecQuotient->matrix = std::move(ecElimResult.matrix);
633 ecQuotient->ecqToOriginalChoiceMapping = std::move(ecElimResult.newToOldRowMapping);
634 ecQuotient->originalToEcqStateMapping = std::move(ecElimResult.oldToNewStateMapping);
635 ecQuotient->ecqToOriginalStateMapping.resize(ecQuotient->matrix.getRowGroupCount());
636 for (uint64_t state = 0; state < ecQuotient->originalToEcqStateMapping.size(); ++state) {
637 uint64_t ecqState = ecQuotient->originalToEcqStateMapping[state];
638 if (ecqState < ecQuotient->matrix.getRowGroupCount()) {
639 ecQuotient->ecqToOriginalStateMapping[ecqState].insert(state);
642 ecQuotient->ecqStayInEcChoices = std::move(ecElimResult.sinkRows);
643 ecQuotient->origReward0Choices = std::move(newReward0Choices);
644 ecQuotient->origTotalReward0Choices = std::move(newTotalReward0Choices);
645 ecQuotient->rowsWithSumLessOne = std::move(rowsWithSumLessOne);
646 ecQuotient->auxStateValues.resize(ecQuotient->matrix.getRowGroupCount());
647 ecQuotient->auxChoiceValues.resize(ecQuotient->matrix.getRowCount());
651template<
class SparseModelType>
653 bool requiresUpper, uint64_t objIndex,
656 std::vector<ValueType>
const& rewards)
const {
658 if (this->objectives[objIndex].lowerResultBound) {
659 solver.
setLowerBound(this->objectives[objIndex].lowerResultBound.get());
661 if (this->objectives[objIndex].upperResultBound) {
662 solver.
setUpperBound(this->objectives[objIndex].upperResultBound.get());
666 computeAndSetBoundsToSolver(solver, requiresLower, requiresUpper, transitions, rowsWithSumLessOne, rewards);
670template<
class SparseModelType>
672 bool requiresUpper, std::vector<ValueType>
const& weightVector,
676 std::vector<ValueType>
const& rewards)
const {
678 boost::optional<ValueType> lowerBound = this->computeWeightedResultBound(
true, weightVector, objectiveFilter & ~lraObjectives);
680 if (!lraObjectives.empty()) {
681 auto min = std::min_element(lraMecDecomposition->auxMecValues.begin(), lraMecDecomposition->auxMecValues.end());
682 if (min != lraMecDecomposition->auxMecValues.end()) {
683 lowerBound.get() += *min;
688 boost::optional<ValueType> upperBound = this->computeWeightedResultBound(
false, weightVector, objectiveFilter);
690 if (!lraObjectives.empty()) {
691 auto max = std::max_element(lraMecDecomposition->auxMecValues.begin(), lraMecDecomposition->auxMecValues.end());
692 if (max != lraMecDecomposition->auxMecValues.end()) {
693 upperBound.get() += *max;
700 computeAndSetBoundsToSolver(solver, requiresLower, requiresUpper, transitions, rowsWithSumLessOne, rewards);
704template<
class SparseModelType>
709 std::vector<ValueType>
const& rewards)
const {
711 std::vector<ValueType> oneStepTargetProbs(transitions.
getRowCount(), storm::utility::zero<ValueType>());
712 for (
auto row : rowsWithSumLessOne) {
713 oneStepTargetProbs[row] = storm::utility::one<ValueType>() - transitions.
getRowSum(row);
718 std::vector<ValueType> negativeRewards;
719 negativeRewards.reserve(transitions.
getRowCount());
721 for (
auto const& rew : rewards) {
722 if (rew < storm::utility::zero<ValueType>()) {
723 negativeRewards.resize(row, storm::utility::zero<ValueType>());
724 negativeRewards.push_back(-rew);
728 if (!negativeRewards.empty()) {
729 negativeRewards.resize(row, storm::utility::zero<ValueType>());
730 std::vector<ValueType> lowerBounds =
742 std::vector<ValueType> positiveRewards;
743 positiveRewards.reserve(transitions.
getRowCount());
745 for (
auto const& rew : rewards) {
746 if (rew > storm::utility::zero<ValueType>()) {
747 positiveRewards.resize(row, storm::utility::zero<ValueType>());
748 positiveRewards.push_back(rew);
752 if (!positiveRewards.empty()) {
753 positiveRewards.resize(row, storm::utility::zero<ValueType>());
762template<
class SparseModelType>
764 std::vector<uint_fast64_t>
const& ecqOptimalChoices,
765 std::map<uint64_t, uint64_t>
const& ecqStateToOptimalMecMap,
766 std::vector<ValueType>& originalSolution,
767 std::vector<uint_fast64_t>& originalOptimalChoices)
const {
768 auto backwardsTransitions = transitionMatrix.transpose(
true);
779 for (uint64_t ecqState = 0; ecqState < ecqSolution.size(); ++ecqState) {
780 uint64_t ecqChoice = ecQuotient->matrix.getRowGroupIndices()[ecqState] + ecqOptimalChoices[ecqState];
781 uint_fast64_t origChoice = ecQuotient->ecqToOriginalChoiceMapping[ecqChoice];
782 auto const& origStates = ecQuotient->ecqToOriginalStateMapping[ecqState];
783 STORM_LOG_ASSERT(!origStates.empty(),
"Unexpected empty set of original states.");
784 if (ecQuotient->ecqStayInEcChoices.get(ecqChoice)) {
787 if (!ecqStateToOptimalMecMap.empty()) {
790 STORM_LOG_ASSERT(ecqStateToOptimalMecMap.count(ecqState) > 0,
"No Lra Mec associated to given eliminated EC");
791 auto const& lraMec = lraMecDecomposition->mecs[ecqStateToOptimalMecMap.at(ecqState)];
792 if (lraMec.size() == origStates.size()) {
794 for (
auto const& state : origStates) {
795 STORM_LOG_ASSERT(lraMec.containsState(state),
"Expected state to be contained in the lra mec.");
797 unprocessedStates.
set(state,
false);
798 originalSolution[state] = ecqSolution[ecqState];
802 STORM_LOG_ASSERT(lraMec.size() < origStates.size(),
"Lra Mec (" << lraMec.size()
803 <<
" states) should be a proper subset of the eliminated ec ("
804 << origStates.size() <<
" states).");
805 for (
auto const& state : origStates) {
806 if (lraMec.containsState(state)) {
807 ecStatesToReach.
set(state,
true);
810 ecStatesToProcess.
set(state,
true);
812 unprocessedStates.
set(state,
false);
813 originalSolution[state] = ecqSolution[ecqState];
815 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess, ecStatesToReach, originalOptimalChoices,
816 &ecQuotient->origTotalReward0Choices);
818 ecStatesToProcess.
clear();
819 ecStatesToReach.
clear();
825 bool needSchedulerComputation =
false;
827 "Solution for state that stays inside EC must be zero. Got " << ecqSolution[ecqState] <<
" instead.");
828 for (
auto const& state : origStates) {
829 originalSolution[state] = storm::utility::zero<ValueType>();
830 ecStatesToProcess.
set(state,
true);
832 auto validChoices = transitionMatrix.getRowFilter(ecStatesToProcess, ecStatesToProcess);
833 auto valid0RewardChoices = validChoices & actionsWithoutRewardInUnboundedPhase;
834 for (
auto const& state : origStates) {
835 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
836 auto groupEnd = transitionMatrix.getRowGroupIndices()[state + 1];
837 auto nextValidChoice = valid0RewardChoices.getNextSetIndex(groupStart);
838 if (nextValidChoice < groupEnd) {
839 originalOptimalChoices[state] = nextValidChoice - groupStart;
842 ecStatesToAvoid.
set(state,
true);
843 needSchedulerComputation =
true;
846 if (needSchedulerComputation) {
848 auto ecStatesThatCanAvoid =
850 ecStatesToProcess, ecStatesToAvoid,
false, 0, valid0RewardChoices);
851 ecStatesThatCanAvoid.complement();
853 computeSchedulerProb0(transitionMatrix, backwardsTransitions, ecStatesThatCanAvoid, ecStatesToAvoid, valid0RewardChoices,
854 originalOptimalChoices);
856 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess & ~ecStatesToAvoid, ecStatesToAvoid, originalOptimalChoices,
859 ecStatesToAvoid.
clear();
860 ecStatesToProcess.
clear();
866 if (origStates.size() > 1) {
867 for (
auto const& state : origStates) {
869 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
870 auto groupEnd = transitionMatrix.getRowGroupIndices()[state + 1];
871 if (origChoice >= groupStart && origChoice < groupEnd) {
872 originalOptimalChoices[state] = origChoice - groupStart;
873 ecStatesToReach.
set(state,
true);
875 STORM_LOG_ASSERT(origStates.size() > 1,
"Multiple original states expected.");
876 ecStatesToProcess.
set(state,
true);
878 unprocessedStates.
set(state,
false);
879 originalSolution[state] = ecqSolution[ecqState];
881 auto validChoices = transitionMatrix.getRowFilter(ecStatesToProcess, ecStatesToProcess | ecStatesToReach);
882 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess, ecStatesToReach, originalOptimalChoices, &validChoices);
884 ecStatesToProcess.
clear();
885 ecStatesToReach.
clear();
888 auto state = *origStates.begin();
889 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
891 origChoice >= groupStart && origChoice < transitionMatrix.getRowGroupIndices()[state + 1],
892 "Invalid choice: " << originalOptimalChoices[state] <<
" at a state with " << transitionMatrix.getRowGroupSize(state) <<
" choices.");
893 originalOptimalChoices[state] = origChoice - groupStart;
894 originalSolution[state] = ecqSolution[ecqState];
895 unprocessedStates.
set(state,
false);
904 if (this->lraMecDecomposition) {
906 for (
auto const& mec : this->lraMecDecomposition->mecs) {
907 for (
auto const& sc : mec) {
908 if (unprocessedStates.
get(sc.first)) {
909 ecStatesToReach.
set(sc.first,
true);
914 ecStatesToReach = unprocessedStates & totalReward0EStates;
916 computeSchedulerProb0(transitionMatrix, backwardsTransitions, ecStatesToReach, ~unprocessedStates | ~totalReward0EStates,
917 actionsWithoutRewardInUnboundedPhase, originalOptimalChoices);
919 unprocessedStates &= ~ecStatesToReach;
921 computeSchedulerProb1(transitionMatrix, backwardsTransitions, unprocessedStates, ecStatesToReach, originalOptimalChoices);
926#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.
uint64_t getNextSetIndex(uint64_t startingIndex) const
Retrieves the index of the bit that is the next bit set to true in the bit vector.
const_iterator end() const
Returns an iterator pointing at the element past the back of 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 set(uint64_t index, bool value=true)
Sets the given truth value at the given index.
const_iterator begin() const
Returns an iterator to the indices of the set bits in the bit vector.
size_t size() const
Retrieves the number of bits this bit vector can store.
void resize(uint64_t newLength, bool init=false)
Resizes the bit vector to hold the given new number of bits.
bool get(uint64_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_WARN_COND(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)
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