28namespace modelchecker {
29namespace multiobjective {
31template<
class SparseModelType>
38template<
class SparseModelType>
43 "There is no Pareto optimal scheduler that yields finite reward for all objectives. This is not supported.");
45 "There might be infinite reward for some scheduler. Multi-objective model checking restricts to schedulers that yield finite reward "
46 "for all objectives. Be aware that solutions yielding infinite reward are discarded.");
47 STORM_LOG_THROW(rewardAnalysis.totalRewardLessInfinityEStates, storm::exceptions::UnexpectedException,
48 "The set of states with reward < infinity for some scheduler has not been computed during preprocessing.");
49 STORM_LOG_THROW(preprocessorResult.containsOnlyTrivialObjectives(), storm::exceptions::NotSupportedException,
50 "At least one objective was not reduced to an expected (long run, total or cumulative) reward objective during preprocessing. This is not "
51 "supported by the considered weight vector checker.");
52 STORM_LOG_THROW(preprocessorResult.preprocessedModel->getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException,
53 "The model has multiple initial states.");
58 storm::storage::BitVector finiteTotalRewardChoices = preprocessorResult.preprocessedModel->getTransitionMatrix().getRowFilter(
59 rewardAnalysis.totalRewardLessInfinityEStates.get(), rewardAnalysis.totalRewardLessInfinityEStates.get());
60 std::set<std::string> relevantRewardModels;
61 for (
auto const& obj : this->objectives) {
62 obj.formula->gatherReferencedRewardModels(relevantRewardModels);
67 std::vector<std::string>(relevantRewardModels.begin(), relevantRewardModels.end()), finiteTotalRewardChoices);
68 goalStateMergerInputToReducedStateIndexMapping = std::move(mergerResult.oldToNewStateIndexMapping);
69 goalStateMergerReducedToInputChoiceMapping = mergerResult.keptChoices.getNumberOfSetBitsBeforeIndices();
71 initializeModelTypeSpecificData(*mergerResult.model);
74 transitionMatrix = std::move(mergerResult.model->getTransitionMatrix());
75 initialState = *mergerResult.model->getInitialStates().begin();
76 totalReward0EStates = rewardAnalysis.totalReward0EStates % maybeStates;
77 if (mergerResult.targetState) {
79 totalReward0EStates.
resize(totalReward0EStates.size() + 1,
true);
83 targetStateAsVector.
set(*mergerResult.targetState,
true);
84 ecChoicesHint = transitionMatrix.getRowFilter(
87 ecChoicesHint.set(transitionMatrix.getRowGroupIndices()[*mergerResult.targetState],
true);
96 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
97 auto const& formula = *this->objectives[objIndex].formula;
98 if (formula.getSubformula().isTotalRewardFormula()) {
99 objectivesWithNoUpperTimeBound.set(objIndex,
true);
102 if (formula.getSubformula().isLongRunAverageRewardFormula()) {
103 lraObjectives.set(objIndex,
true);
104 objectivesWithNoUpperTimeBound.set(objIndex,
true);
109 if (!lraObjectives.empty()) {
110 lraMecDecomposition = LraMecDecomposition();
112 transitionMatrix, transitionMatrix.transpose(
true),
storm::storage::BitVector(transitionMatrix.getRowGroupCount(),
true),
113 actionsWithoutRewardInUnboundedPhase);
114 lraMecDecomposition->auxMecValues.resize(lraMecDecomposition->mecs.size());
118 checkHasBeenCalled =
false;
119 objectiveResults.resize(this->objectives.size());
120 offsetsToUnderApproximation.resize(this->objectives.size(), storm::utility::zero<ValueType>());
121 offsetsToOverApproximation.resize(this->objectives.size(), storm::utility::zero<ValueType>());
122 optimalChoices.resize(transitionMatrix.getRowGroupCount(), 0);
125 if (storm::settings::getModule<storm::settings::modules::CoreSettings>().isShowStatisticsSet()) {
127 STORM_PRINT_AND_LOG(
"Final preprocessed model has " << transitionMatrix.getRowGroupCount() <<
" states.\n");
128 STORM_PRINT_AND_LOG(
"Final preprocessed model has " << transitionMatrix.getRowCount() <<
" actions.\n");
129 if (lraMecDecomposition) {
130 STORM_PRINT_AND_LOG(
"Found " << lraMecDecomposition->mecs.size() <<
" end components that are relevant for LRA-analysis.\n");
131 uint64_t numLraMecStates = 0;
132 for (
auto const& mec : this->lraMecDecomposition->mecs) {
133 numLraMecStates += mec.size();
141template<
class SparseModelType>
143 checkHasBeenCalled =
true;
148 std::vector<ValueType> weightedRewardVector(transitionMatrix.getRowCount(), storm::utility::zero<ValueType>());
149 if (!lraObjectives.empty()) {
150 boost::optional<std::vector<ValueType>> weightedStateRewardVector;
151 for (
auto objIndex : lraObjectives) {
153 storm::solver::minimize(this->objectives[objIndex].formula->getOptimalityType()) ? -weightVector[objIndex] : weightVector[objIndex];
155 if (!stateRewards.empty() && !stateRewards[objIndex].empty()) {
156 if (!weightedStateRewardVector) {
157 weightedStateRewardVector = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
162 infiniteHorizonWeightedPhase(env, weightedRewardVector, weightedStateRewardVector);
164 weightedRewardVector.assign(weightedRewardVector.size(), storm::utility::zero<ValueType>());
168 auto totalRewardObjectives = objectivesWithNoUpperTimeBound & ~lraObjectives;
169 for (
auto objIndex : totalRewardObjectives) {
176 unboundedWeightedPhase(env, weightedRewardVector, weightVector);
178 unboundedIndividualPhase(env, weightVector);
180 for (
auto const& obj : this->objectives) {
181 if (!obj.formula->getSubformula().isTotalRewardFormula() && !obj.formula->getSubformula().isLongRunAverageRewardFormula()) {
182 boundedPhase(env, weightVector, weightedRewardVector);
186 STORM_LOG_INFO(
"Weight vector check done. Lower bounds for results in initial state: "
193 STORM_LOG_THROW(resultingWeightedPrecision <= this->getWeightedPrecision(), storm::exceptions::UnexpectedException,
194 "The desired precision was not reached");
197template<
class SparseModelType>
198std::vector<typename StandardPcaaWeightVectorChecker<SparseModelType>::ValueType>
200 STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
"Tried to retrieve results but check(..) has not been called before.");
201 std::vector<ValueType> res;
202 res.reserve(this->objectives.size());
203 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
204 res.push_back(this->objectiveResults[objIndex][initialState] + this->offsetsToUnderApproximation[objIndex]);
209template<
class SparseModelType>
210std::vector<typename StandardPcaaWeightVectorChecker<SparseModelType>::ValueType>
212 STORM_LOG_THROW(checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
"Tried to retrieve results but check(..) has not been called before.");
213 std::vector<ValueType> res;
214 res.reserve(this->objectives.size());
215 for (uint_fast64_t objIndex = 0; objIndex < this->objectives.size(); ++objIndex) {
216 res.push_back(this->objectiveResults[objIndex][initialState] + this->offsetsToOverApproximation[objIndex]);
221template<
class SparseModelType>
224 STORM_LOG_THROW(this->checkHasBeenCalled, storm::exceptions::IllegalFunctionCallException,
225 "Tried to retrieve results but check(..) has not been called before.");
226 for (
auto const& obj : this->objectives) {
227 STORM_LOG_THROW(obj.formula->getSubformula().isTotalRewardFormula() || obj.formula->getSubformula().isLongRunAverageRewardFormula(),
228 storm::exceptions::NotImplementedException,
"Scheduler retrival is only implemented for objectives without time-bound.");
230 auto const numStatesOfInputModel = goalStateMergerInputToReducedStateIndexMapping.size();
232 for (uint64_t inputModelState = 0; inputModelState < numStatesOfInputModel; ++inputModelState) {
233 auto const reducedModelState = goalStateMergerInputToReducedStateIndexMapping[inputModelState];
234 if (reducedModelState >= optimalChoices.size()) {
238 auto const reducedModelChoice = optimalChoices[reducedModelState];
239 auto const inputModelChoice = goalStateMergerReducedToInputChoiceMapping[reducedModelChoice];
240 result.
setChoice(inputModelChoice, inputModelState);
246template<
typename ValueType>
250 std::vector<uint64_t> stack;
252 stack.insert(stack.end(), processedStates.
begin(), processedStates.
end());
253 uint64_t currentState = 0;
255 while (!stack.empty()) {
256 currentState = stack.back();
259 for (
auto const& predecessorEntry : backwardTransitions.
getRow(currentState)) {
260 auto predecessor = predecessorEntry.getColumn();
261 if (consideredStates.
get(predecessor) && !processedStates.
get(predecessor)) {
265 uint64_t row = allowedChoices ? allowedChoices->getNextSetIndex(groupStart) : groupStart;
266 for (; row < groupEnd; row = allowedChoices ? allowedChoices->getNextSetIndex(row + 1) : row + 1) {
267 bool hasSuccessorInProcessedStates =
false;
268 for (
auto const& successorOfPredecessor : transitionMatrix.
getRow(row)) {
269 if (processedStates.
get(successorOfPredecessor.getColumn())) {
270 hasSuccessorInProcessedStates =
true;
274 if (hasSuccessorInProcessedStates) {
275 choices[predecessor] = row - groupStart;
276 processedStates.
set(predecessor,
true);
277 stack.push_back(predecessor);
282 "Unable to find choice at a predecessor of a processed state that leads to a processed state.");
289template<
typename ValueType>
293 for (
auto state : consideredStates) {
296 bool choiceFound =
false;
299 for (
auto const& element : transitionMatrix.
getRow(row)) {
300 if (statesToAvoid.
get(element.getColumn())) {
306 choices[state] = row - groupStart;
314template<
typename ValueType>
318 auto backwardsTransitions = matrix.
transpose(
true);
320 for (uint64_t state = 0; state < result.size(); ++state) {
321 if (rowsWithSumLessOne.
getNextSetIndex(groups[state]) < groups[state + 1]) {
322 result[state] = rowsWithSumLessOne.
getNextSetIndex(groups[state]) - groups[state];
323 processedStates.
set(state,
true);
336template<
typename ValueType>
340 auto badStates = transitionMatrix.
getRowGroupFilter(finitelyOftenChoices,
true) & ~safeStates;
344 transitionMatrix, transitionMatrix.
getRowGroupIndices(), backwardTransitions, ~safeStates, badStates,
false, 0, ~finitelyOftenChoices);
347 auto avoidBadStates = ~reachBadWithProbGreater0AStates & ~safeStates;
348 computeSchedulerProb0(transitionMatrix, backwardTransitions, avoidBadStates, reachBadWithProbGreater0AStates, ~finitelyOftenChoices, choices);
353 computeSchedulerProb1(transitionMatrix, backwardTransitions, reachBadWithProbGreater0AStates, avoidBadStates | safeStates, choices);
356template<
class SparseModelType>
358 std::vector<ValueType>
const& weightedActionRewardVector,
359 boost::optional<std::vector<ValueType>>
const& weightedStateRewardVector) {
361 STORM_LOG_ASSERT(lraMecDecomposition,
"Mec decomposition for lra computations not initialized.");
366 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
367 auto const& mec = lraMecDecomposition->mecs[mecIndex];
368 auto actionValueGetter = [&weightedActionRewardVector](uint64_t
const& a) {
return weightedActionRewardVector[a]; };
370 if (weightedStateRewardVector) {
371 stateValueGetter = [&weightedStateRewardVector](uint64_t
const& s) {
return weightedStateRewardVector.get()[s]; };
373 stateValueGetter = [](uint64_t
const&) {
return storm::utility::zero<ValueType>(); };
375 lraMecDecomposition->auxMecValues[mecIndex] = helper.
computeLraForComponent(env, stateValueGetter, actionValueGetter, mec);
381template<
class SparseModelType>
383 std::vector<ValueType>
const& weightVector) {
385 if (this->objectivesWithNoUpperTimeBound.empty() ||
388 this->weightedResult.assign(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
390 if (this->lraMecDecomposition) {
391 for (
auto const& mec : this->lraMecDecomposition->mecs) {
392 for (
auto const& sc : mec) {
393 statesInLraMec.
set(sc.first,
true);
399 this->optimalChoices);
403 updateEcQuotient(weightedRewardVector);
407 std::map<uint64_t, uint64_t> ecqStateToOptimalMecMap;
408 if (!lraObjectives.empty()) {
413 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
414 auto const& mec = lraMecDecomposition->mecs[mecIndex];
415 auto const& mecValue = lraMecDecomposition->auxMecValues[mecIndex];
416 uint64_t ecqState = ecQuotient->originalToEcqStateMapping[mec.begin()->first];
417 if (ecqState >= ecQuotient->matrix.getRowGroupCount()) {
422 uint64_t ecqChoice = ecQuotient->ecqStayInEcChoices.getNextSetIndex(ecQuotient->matrix.getRowGroupIndices()[ecqState]);
423 STORM_LOG_ASSERT(ecqChoice < ecQuotient->matrix.getRowGroupIndices()[ecqState + 1],
424 "Unable to find choice that represents staying inside the (eliminated) ec.");
425 auto& ecqChoiceValue = ecQuotient->auxChoiceValues[ecqChoice];
426 auto insertionRes = ecqStateToOptimalMecMap.emplace(ecqState, mecIndex);
427 if (insertionRes.second) {
430 "Expected a total reward of zero for choices that represent staying in an EC for ever.");
431 ecqChoiceValue = mecValue;
433 if (mecValue > ecqChoiceValue) {
434 ecqChoiceValue = mecValue;
435 insertionRes.first->second = mecIndex;
442 std::unique_ptr<storm::solver::MinMaxLinearEquationSolver<ValueType>> solver = solverFactory.
create(env, ecQuotient->matrix);
443 solver->setTrackScheduler(
true);
444 solver->setHasUniqueSolution(
true);
445 solver->setOptimizationDirection(storm::solver::OptimizationDirection::Maximize);
446 auto req = solver->getRequirements(env, storm::solver::OptimizationDirection::Maximize);
447 setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), weightVector, objectivesWithNoUpperTimeBound, ecQuotient->matrix,
448 ecQuotient->rowsWithSumLessOne, ecQuotient->auxChoiceValues);
449 if (solver->hasLowerBound()) {
450 req.clearLowerBounds();
452 if (solver->hasUpperBound()) {
453 req.clearUpperBounds();
455 if (req.validInitialScheduler()) {
457 req.clearValidInitialScheduler();
459 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
460 "Solver requirements " + req.getEnabledRequirementsAsString() +
" not checked.");
461 solver->setRequirementsChecked(
true);
464 std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero<ValueType>());
466 solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues);
467 this->weightedResult = std::vector<ValueType>(transitionMatrix.getRowGroupCount());
469 transformEcqSolutionToOriginalModel(ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecqStateToOptimalMecMap, this->weightedResult,
470 this->optimalChoices);
473template<
class SparseModelType>
475 if (objectivesWithNoUpperTimeBound.getNumberOfSetBits() == 1 &&
storm::utility::isOne(weightVector[*objectivesWithNoUpperTimeBound.begin()])) {
476 uint_fast64_t objIndex = *objectivesWithNoUpperTimeBound.begin();
477 objectiveResults[objIndex] = weightedResult;
481 for (uint_fast64_t objIndex2 = 0; objIndex2 < this->objectives.size(); ++objIndex2) {
482 if (objIndex != objIndex2) {
483 objectiveResults[objIndex2] = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
489 std::vector<ValueType> deterministicStateRewards(deterministicMatrix.
getRowCount());
492 auto infiniteHorizonHelper = createDetInfiniteHorizonHelper(deterministicMatrix);
493 infiniteHorizonHelper.provideBackwardTransitions(deterministicBackwardTransitions);
497 std::vector<ValueType> weightedSumOfUncheckedObjectives = weightedResult;
501 auto const& obj = this->objectives[objIndex];
502 if (objectivesWithNoUpperTimeBound.get(objIndex)) {
503 offsetsToUnderApproximation[objIndex] = storm::utility::zero<ValueType>();
504 offsetsToOverApproximation[objIndex] = storm::utility::zero<ValueType>();
505 if (lraObjectives.get(objIndex)) {
506 auto actionValueGetter = [&](uint64_t
const& a) {
507 return actionRewards[objIndex][transitionMatrix.getRowGroupIndices()[a] + this->optimalChoices[a]];
510 if (stateRewards.empty() || stateRewards[objIndex].empty()) {
511 stateValueGetter = [](uint64_t
const&) {
return storm::utility::zero<ValueType>(); };
513 stateValueGetter = [&](uint64_t
const& s) {
return stateRewards[objIndex][s]; };
518 actionRewards[objIndex]);
526 objectiveResults[objIndex] = weightedSumOfUncheckedObjectives;
527 ValueType scalingFactor = storm::utility::one<ValueType>() / sumOfWeightsOfUncheckedObjectives;
529 scalingFactor *= -storm::utility::one<ValueType>();
535 objectiveResults[objIndex].resize(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
537 if (!maybeStates.
empty()) {
538 bool needEquationSystem =
541 deterministicMatrix.
getSubmatrix(
true, maybeStates, maybeStates, needEquationSystem);
542 if (needEquationSystem) {
553 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.
create(env, submatrix);
554 auto req = solver->getRequirements(env);
555 solver->clearBounds();
558 this->setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), objIndex, submatrix, submatrixRowsWithSumLessOne, b);
559 if (solver->hasLowerBound()) {
560 req.clearLowerBounds();
562 if (solver->hasUpperBound()) {
563 req.clearUpperBounds();
565 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
566 "Solver requirements " + req.getEnabledRequirementsAsString() +
" not checked.");
567 solver->solveEquations(env, x, b);
569 storm::utility::vector::setVectorValues<ValueType>(objectiveResults[objIndex], maybeStates, x);
571 storm::utility::vector::setVectorValues<ValueType>(objectiveResults[objIndex], ~maybeStates, storm::utility::zero<ValueType>());
576 sumOfWeightsOfUncheckedObjectives -= weightVector[objIndex];
579 objectiveResults[objIndex] = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
585template<
class SparseModelType>
590 if (lraMecDecomposition) {
591 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
594 auto const& mec = lraMecDecomposition->mecs[mecIndex];
595 for (
auto const& stateChoices : mec) {
596 for (
auto const& choice : stateChoices.second) {
597 zeroLraRewardChoices.
set(choice,
false);
604 if (!ecQuotient || ecQuotient->origReward0Choices != newReward0Choices) {
606 auto nonZeroRewardStates = transitionMatrix.getRowGroupFilter(newReward0Choices,
true);
609 transitionMatrix.transpose(
true),
storm::storage::BitVector(transitionMatrix.getRowGroupCount(),
true), nonZeroRewardStates);
614 ecChoicesHint & newTotalReward0Choices, totalReward0EStates);
617 for (uint64_t row = 0; row < rowsWithSumLessOne.
size(); ++row) {
618 if (ecElimResult.matrix.getRow(row).getNumberOfEntries() == 0) {
619 rowsWithSumLessOne.
set(row,
true);
621 for (
auto const& entry : transitionMatrix.getRow(ecElimResult.newToOldRowMapping[row])) {
622 if (!subsystemStates.
get(entry.getColumn())) {
623 rowsWithSumLessOne.
set(row,
true);
631 ecQuotient->matrix = std::move(ecElimResult.matrix);
632 ecQuotient->ecqToOriginalChoiceMapping = std::move(ecElimResult.newToOldRowMapping);
633 ecQuotient->originalToEcqStateMapping = std::move(ecElimResult.oldToNewStateMapping);
634 ecQuotient->ecqToOriginalStateMapping.resize(ecQuotient->matrix.getRowGroupCount());
635 for (uint64_t state = 0; state < ecQuotient->originalToEcqStateMapping.size(); ++state) {
636 uint64_t ecqState = ecQuotient->originalToEcqStateMapping[state];
637 if (ecqState < ecQuotient->matrix.getRowGroupCount()) {
638 ecQuotient->ecqToOriginalStateMapping[ecqState].insert(state);
641 ecQuotient->ecqStayInEcChoices = std::move(ecElimResult.sinkRows);
642 ecQuotient->origReward0Choices = std::move(newReward0Choices);
643 ecQuotient->origTotalReward0Choices = std::move(newTotalReward0Choices);
644 ecQuotient->rowsWithSumLessOne = std::move(rowsWithSumLessOne);
645 ecQuotient->auxStateValues.resize(ecQuotient->matrix.getRowGroupCount());
646 ecQuotient->auxChoiceValues.resize(ecQuotient->matrix.getRowCount());
650template<
class SparseModelType>
652 bool requiresUpper, uint64_t objIndex,
655 std::vector<ValueType>
const& rewards)
const {
657 if (this->objectives[objIndex].lowerResultBound) {
658 solver.
setLowerBound(this->objectives[objIndex].lowerResultBound.get());
660 if (this->objectives[objIndex].upperResultBound) {
661 solver.
setUpperBound(this->objectives[objIndex].upperResultBound.get());
665 computeAndSetBoundsToSolver(solver, requiresLower, requiresUpper, transitions, rowsWithSumLessOne, rewards);
669template<
class SparseModelType>
671 bool requiresUpper, std::vector<ValueType>
const& weightVector,
675 std::vector<ValueType>
const& rewards)
const {
677 boost::optional<ValueType> lowerBound = this->computeWeightedResultBound(
true, weightVector, objectiveFilter & ~lraObjectives);
679 if (!lraObjectives.empty()) {
680 auto min = std::min_element(lraMecDecomposition->auxMecValues.begin(), lraMecDecomposition->auxMecValues.end());
681 if (min != lraMecDecomposition->auxMecValues.end()) {
682 lowerBound.get() += *min;
687 boost::optional<ValueType> upperBound = this->computeWeightedResultBound(
false, weightVector, objectiveFilter);
689 if (!lraObjectives.empty()) {
690 auto max = std::max_element(lraMecDecomposition->auxMecValues.begin(), lraMecDecomposition->auxMecValues.end());
691 if (max != lraMecDecomposition->auxMecValues.end()) {
692 upperBound.get() += *max;
699 computeAndSetBoundsToSolver(solver, requiresLower, requiresUpper, transitions, rowsWithSumLessOne, rewards);
703template<
class SparseModelType>
708 std::vector<ValueType>
const& rewards)
const {
710 std::vector<ValueType> oneStepTargetProbs(transitions.
getRowCount(), storm::utility::zero<ValueType>());
711 for (
auto row : rowsWithSumLessOne) {
712 oneStepTargetProbs[row] = storm::utility::one<ValueType>() - transitions.
getRowSum(row);
717 std::vector<ValueType> negativeRewards;
718 negativeRewards.reserve(transitions.
getRowCount());
720 for (
auto const& rew : rewards) {
721 if (rew < storm::utility::zero<ValueType>()) {
722 negativeRewards.resize(row, storm::utility::zero<ValueType>());
723 negativeRewards.push_back(-rew);
727 if (!negativeRewards.empty()) {
728 negativeRewards.resize(row, storm::utility::zero<ValueType>());
729 std::vector<ValueType> lowerBounds =
741 std::vector<ValueType> positiveRewards;
742 positiveRewards.reserve(transitions.
getRowCount());
744 for (
auto const& rew : rewards) {
745 if (rew > storm::utility::zero<ValueType>()) {
746 positiveRewards.resize(row, storm::utility::zero<ValueType>());
747 positiveRewards.push_back(rew);
751 if (!positiveRewards.empty()) {
752 positiveRewards.resize(row, storm::utility::zero<ValueType>());
761template<
class SparseModelType>
763 std::vector<uint_fast64_t>
const& ecqOptimalChoices,
764 std::map<uint64_t, uint64_t>
const& ecqStateToOptimalMecMap,
765 std::vector<ValueType>& originalSolution,
766 std::vector<uint_fast64_t>& originalOptimalChoices)
const {
767 auto backwardsTransitions = transitionMatrix.transpose(
true);
778 for (uint64_t ecqState = 0; ecqState < ecqSolution.size(); ++ecqState) {
779 uint64_t ecqChoice = ecQuotient->matrix.getRowGroupIndices()[ecqState] + ecqOptimalChoices[ecqState];
780 uint_fast64_t origChoice = ecQuotient->ecqToOriginalChoiceMapping[ecqChoice];
781 auto const& origStates = ecQuotient->ecqToOriginalStateMapping[ecqState];
782 STORM_LOG_ASSERT(!origStates.empty(),
"Unexpected empty set of original states.");
783 if (ecQuotient->ecqStayInEcChoices.get(ecqChoice)) {
786 if (!ecqStateToOptimalMecMap.empty()) {
789 STORM_LOG_ASSERT(ecqStateToOptimalMecMap.count(ecqState) > 0,
"No Lra Mec associated to given eliminated EC");
790 auto const& lraMec = lraMecDecomposition->mecs[ecqStateToOptimalMecMap.at(ecqState)];
791 if (lraMec.size() == origStates.size()) {
793 for (
auto const& state : origStates) {
794 STORM_LOG_ASSERT(lraMec.containsState(state),
"Expected state to be contained in the lra mec.");
796 unprocessedStates.
set(state,
false);
797 originalSolution[state] = ecqSolution[ecqState];
801 STORM_LOG_ASSERT(lraMec.size() < origStates.size(),
"Lra Mec (" << lraMec.size()
802 <<
" states) should be a proper subset of the eliminated ec ("
803 << origStates.size() <<
" states).");
804 for (
auto const& state : origStates) {
805 if (lraMec.containsState(state)) {
806 ecStatesToReach.
set(state,
true);
809 ecStatesToProcess.
set(state,
true);
811 unprocessedStates.
set(state,
false);
812 originalSolution[state] = ecqSolution[ecqState];
814 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess, ecStatesToReach, originalOptimalChoices,
815 &ecQuotient->origTotalReward0Choices);
817 ecStatesToProcess.
clear();
818 ecStatesToReach.
clear();
824 bool needSchedulerComputation =
false;
826 "Solution for state that stays inside EC must be zero. Got " << ecqSolution[ecqState] <<
" instead.");
827 for (
auto const& state : origStates) {
828 originalSolution[state] = storm::utility::zero<ValueType>();
829 ecStatesToProcess.
set(state,
true);
831 auto validChoices = transitionMatrix.getRowFilter(ecStatesToProcess, ecStatesToProcess);
832 auto valid0RewardChoices = validChoices & actionsWithoutRewardInUnboundedPhase;
833 for (
auto const& state : origStates) {
834 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
835 auto groupEnd = transitionMatrix.getRowGroupIndices()[state + 1];
836 auto nextValidChoice = valid0RewardChoices.getNextSetIndex(groupStart);
837 if (nextValidChoice < groupEnd) {
838 originalOptimalChoices[state] = nextValidChoice - groupStart;
841 ecStatesToAvoid.
set(state,
true);
842 needSchedulerComputation =
true;
845 if (needSchedulerComputation) {
847 auto ecStatesThatCanAvoid =
849 ecStatesToProcess, ecStatesToAvoid,
false, 0, valid0RewardChoices);
850 ecStatesThatCanAvoid.complement();
852 computeSchedulerProb0(transitionMatrix, backwardsTransitions, ecStatesThatCanAvoid, ecStatesToAvoid, valid0RewardChoices,
853 originalOptimalChoices);
855 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess & ~ecStatesToAvoid, ecStatesToAvoid, originalOptimalChoices,
858 ecStatesToAvoid.
clear();
859 ecStatesToProcess.
clear();
865 if (origStates.size() > 1) {
866 for (
auto const& state : origStates) {
868 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
869 auto groupEnd = transitionMatrix.getRowGroupIndices()[state + 1];
870 if (origChoice >= groupStart && origChoice < groupEnd) {
871 originalOptimalChoices[state] = origChoice - groupStart;
872 ecStatesToReach.
set(state,
true);
874 STORM_LOG_ASSERT(origStates.size() > 1,
"Multiple original states expected.");
875 ecStatesToProcess.
set(state,
true);
877 unprocessedStates.
set(state,
false);
878 originalSolution[state] = ecqSolution[ecqState];
880 auto validChoices = transitionMatrix.getRowFilter(ecStatesToProcess, ecStatesToProcess | ecStatesToReach);
881 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess, ecStatesToReach, originalOptimalChoices, &validChoices);
883 ecStatesToProcess.
clear();
884 ecStatesToReach.
clear();
887 auto state = *origStates.begin();
888 auto groupStart = transitionMatrix.getRowGroupIndices()[state];
890 origChoice >= groupStart && origChoice < transitionMatrix.getRowGroupIndices()[state + 1],
891 "Invalid choice: " << originalOptimalChoices[state] <<
" at a state with " << transitionMatrix.getRowGroupSize(state) <<
" choices.");
892 originalOptimalChoices[state] = origChoice - groupStart;
893 originalSolution[state] = ecqSolution[ecqState];
894 unprocessedStates.
set(state,
false);
903 if (this->lraMecDecomposition) {
905 for (
auto const& mec : this->lraMecDecomposition->mecs) {
906 for (
auto const& sc : mec) {
907 if (unprocessedStates.
get(sc.first)) {
908 ecStatesToReach.
set(sc.first,
true);
913 ecStatesToReach = unprocessedStates & totalReward0EStates;
915 computeSchedulerProb0(transitionMatrix, backwardsTransitions, ecStatesToReach, ~unprocessedStates | ~totalReward0EStates,
916 actionsWithoutRewardInUnboundedPhase, originalOptimalChoices);
918 unprocessedStates &= ~ecStatesToReach;
920 computeSchedulerProb1(transitionMatrix, backwardsTransitions, unprocessedStates, ecStatesToReach, originalOptimalChoices);
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)