Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
StandardPcaaWeightVectorChecker.cpp
Go to the documentation of this file.
2
3#include <map>
4#include <set>
5
18#include "storm/utility/graph.h"
21
27
28namespace storm {
29namespace modelchecker {
30namespace multiobjective {
31
32template<class SparseModelType>
35 : PcaaWeightVectorChecker<SparseModelType>(preprocessorResult.objectives) {
36 // Intantionally left empty
37}
38
39template<class SparseModelType>
43 STORM_LOG_THROW(rewardAnalysis.rewardFinitenessType != preprocessing::RewardFinitenessType::Infinite, storm::exceptions::NotSupportedException,
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.");
47 STORM_LOG_THROW(preprocessorResult.containsOnlyTrivialObjectives(), storm::exceptions::NotSupportedException,
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.");
50 STORM_LOG_THROW(preprocessorResult.preprocessedModel->getInitialStates().getNumberOfSetBits() == 1, storm::exceptions::NotSupportedException,
51 "The model has multiple initial states.");
53 // Build a subsystem of the preprocessor result model that discards states that yield infinite reward for all schedulers.
54 // We can also merge the states that will have reward zero anyway.
55 storm::storage::BitVector maybeStates = rewardAnalysis.totalRewardLessInfinityEStates.get() & ~rewardAnalysis.reward0AStates;
56 storm::storage::BitVector finiteTotalRewardChoices = preprocessorResult.preprocessedModel->getTransitionMatrix().getRowFilter(
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);
61 }
63 auto mergerResult =
64 merger.mergeTargetAndSinkStates(maybeStates, rewardAnalysis.reward0AStates, storm::storage::BitVector(maybeStates.size(), false),
65 std::vector<std::string>(relevantRewardModels.begin(), relevantRewardModels.end()), finiteTotalRewardChoices);
66
67 // Initialize data specific for the considered model type
68 initializeModelTypeSpecificData(*mergerResult.model);
69
70 // Initilize general data of the model
71 transitionMatrix = std::move(mergerResult.model->getTransitionMatrix());
72 initialState = *mergerResult.model->getInitialStates().begin();
73 totalReward0EStates = rewardAnalysis.totalReward0EStates % maybeStates;
74 if (mergerResult.targetState) {
75 // There is an additional state in the result
76 totalReward0EStates.resize(totalReward0EStates.size() + 1, true);
78 // The overapproximation for the possible ec choices consists of the states that can reach the target states with prob. 0 and the target state itself.
79 storm::storage::BitVector targetStateAsVector(transitionMatrix.getRowGroupCount(), false);
80 targetStateAsVector.set(*mergerResult.targetState, true);
81 ecChoicesHint = transitionMatrix.getRowFilter(
82 storm::utility::graph::performProb0E(transitionMatrix, transitionMatrix.getRowGroupIndices(), transitionMatrix.transpose(true),
83 storm::storage::BitVector(targetStateAsVector.size(), true), targetStateAsVector));
84 ecChoicesHint.set(transitionMatrix.getRowGroupIndices()[*mergerResult.targetState], true);
85 } else {
86 ecChoicesHint = storm::storage::BitVector(transitionMatrix.getRowCount(), true);
87 }
88
89 // set data for unbounded objectives
90 lraObjectives = storm::storage::BitVector(this->objectives.size(), false);
91 objectivesWithNoUpperTimeBound = storm::storage::BitVector(this->objectives.size(), false);
92 actionsWithoutRewardInUnboundedPhase = storm::storage::BitVector(transitionMatrix.getRowCount(), 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);
97 actionsWithoutRewardInUnboundedPhase &= storm::utility::vector::filterZero(actionRewards[objIndex]);
98 }
99 if (formula.getSubformula().isLongRunAverageRewardFormula()) {
100 lraObjectives.set(objIndex, true);
101 objectivesWithNoUpperTimeBound.set(objIndex, true);
102 }
103 }
105 // Set data for LRA objectives (if available)
106 if (!lraObjectives.empty()) {
107 lraMecDecomposition = LraMecDecomposition();
109 transitionMatrix, transitionMatrix.transpose(true), storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true),
110 actionsWithoutRewardInUnboundedPhase);
111 lraMecDecomposition->auxMecValues.resize(lraMecDecomposition->mecs.size());
112 }
114 // initialize data for the results
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);
121 // Print some statistics (if requested)
123 STORM_PRINT_AND_LOG("Weight Vector Checker Statistics:\n");
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();
131 }
132 STORM_PRINT_AND_LOG(numLraMecStates << " states lie on such an end component.\n");
133 }
135 }
136}
137
138template<class SparseModelType>
139void StandardPcaaWeightVectorChecker<SparseModelType>::check(Environment const& env, std::vector<ValueType> const& weightVector) {
140 checkHasBeenCalled = true;
141 STORM_LOG_INFO("Invoked WeightVectorChecker with weights \n"
142 << "\t" << storm::utility::vector::toString(storm::utility::vector::convertNumericVector<double>(weightVector)));
143
144 // Prepare and invoke weighted infinite horizon (long run average) phase
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) {
149 ValueType weight =
150 storm::solver::minimize(this->objectives[objIndex].formula->getOptimalityType()) ? -weightVector[objIndex] : weightVector[objIndex];
151 storm::utility::vector::addScaledVector(weightedRewardVector, actionRewards[objIndex], weight);
152 if (!stateRewards.empty() && !stateRewards[objIndex].empty()) {
153 if (!weightedStateRewardVector) {
154 weightedStateRewardVector = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
155 }
156 storm::utility::vector::addScaledVector(weightedStateRewardVector.get(), stateRewards[objIndex], weight);
157 }
158 }
159 infiniteHorizonWeightedPhase(env, weightedRewardVector, weightedStateRewardVector);
160 // Clear all values of the weighted reward vector
161 weightedRewardVector.assign(weightedRewardVector.size(), storm::utility::zero<ValueType>());
162 }
163
164 // Prepare and invoke weighted indefinite horizon (unbounded total reward) phase
165 auto totalRewardObjectives = objectivesWithNoUpperTimeBound & ~lraObjectives;
166 for (auto objIndex : totalRewardObjectives) {
167 if (storm::solver::minimize(this->objectives[objIndex].formula->getOptimalityType())) {
168 storm::utility::vector::addScaledVector(weightedRewardVector, actionRewards[objIndex], -weightVector[objIndex]);
169 } else {
170 storm::utility::vector::addScaledVector(weightedRewardVector, actionRewards[objIndex], weightVector[objIndex]);
171 }
172 }
173 unboundedWeightedPhase(env, weightedRewardVector, weightVector);
174
175 unboundedIndividualPhase(env, weightVector);
176 // Only invoke boundedPhase if necessarry, i.e., if there is at least one objective with a time bound
177 for (auto const& obj : this->objectives) {
178 if (!obj.formula->getSubformula().isTotalRewardFormula() && !obj.formula->getSubformula().isLongRunAverageRewardFormula()) {
179 boundedPhase(env, weightVector, weightedRewardVector);
180 break;
181 }
182 }
183 STORM_LOG_INFO("Weight vector check done. Lower bounds for results in initial state: "
184 << storm::utility::vector::toString(storm::utility::vector::convertNumericVector<double>(getUnderApproximationOfInitialStateResults())));
185 // Validate that the results are sufficiently precise
186 ValueType resultingWeightedPrecision =
187 storm::utility::abs<ValueType>(storm::utility::vector::dotProduct(getOverApproximationOfInitialStateResults(), weightVector) -
188 storm::utility::vector::dotProduct(getUnderApproximationOfInitialStateResults(), weightVector));
189 resultingWeightedPrecision /= storm::utility::sqrt(storm::utility::vector::dotProduct(weightVector, weightVector));
190 STORM_LOG_THROW(resultingWeightedPrecision <= this->getWeightedPrecision(), storm::exceptions::UnexpectedException,
191 "The desired precision was not reached");
192}
193
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]);
202 }
203 return res;
204}
205
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]);
214 }
215 return res;
216}
217
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.");
226 }
227
228 storm::storage::Scheduler<ValueType> result(this->optimalChoices.size());
229 uint_fast64_t state = 0;
230 for (auto const& choice : optimalChoices) {
231 result.setChoice(choice, state);
232 ++state;
233 }
234 return result;
235}
236
237template<typename ValueType>
239 storm::storage::BitVector const& consideredStates, storm::storage::BitVector const& statesToReach, std::vector<uint64_t>& choices,
240 storm::storage::BitVector const* allowedChoices = nullptr) {
241 std::vector<uint64_t> stack;
242 storm::storage::BitVector processedStates = statesToReach;
243 stack.insert(stack.end(), processedStates.begin(), processedStates.end());
244 uint64_t currentState = 0;
245
246 while (!stack.empty()) {
247 currentState = stack.back();
248 stack.pop_back();
249
250 for (auto const& predecessorEntry : backwardTransitions.getRow(currentState)) {
251 auto predecessor = predecessorEntry.getColumn();
252 if (consideredStates.get(predecessor) && !processedStates.get(predecessor)) {
253 // Find a choice leading to an already processed state (such a choice has to exist since this is a predecessor of the currentState)
254 auto const& groupStart = transitionMatrix.getRowGroupIndices()[predecessor];
255 auto const& groupEnd = transitionMatrix.getRowGroupIndices()[predecessor + 1];
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;
262 break;
263 }
264 }
265 if (hasSuccessorInProcessedStates) {
266 choices[predecessor] = row - groupStart;
267 processedStates.set(predecessor, true);
268 stack.push_back(predecessor);
269 break;
270 }
271 }
272 STORM_LOG_ASSERT(allowedChoices || row < groupEnd,
273 "Unable to find choice at a predecessor of a processed state that leads to a processed state.");
274 }
275 }
276 }
277 STORM_LOG_ASSERT(consideredStates.isSubsetOf(processedStates), "Not all states have been processed.");
278}
279
280template<typename ValueType>
282 storm::storage::BitVector const& consideredStates, storm::storage::BitVector const& statesToAvoid,
283 storm::storage::BitVector const& allowedChoices, std::vector<uint64_t>& choices) {
284 for (auto state : consideredStates) {
285 auto const& groupStart = transitionMatrix.getRowGroupIndices()[state];
286 auto const& groupEnd = transitionMatrix.getRowGroupIndices()[state + 1];
287 bool choiceFound = false;
288 for (uint64_t row = allowedChoices.getNextSetIndex(groupStart); row < groupEnd; row = allowedChoices.getNextSetIndex(row + 1)) {
289 choiceFound = true;
290 for (auto const& element : transitionMatrix.getRow(row)) {
291 if (statesToAvoid.get(element.getColumn())) {
292 choiceFound = false;
293 break;
294 }
295 }
296 if (choiceFound) {
297 choices[state] = row - groupStart;
298 break;
299 }
300 }
301 STORM_LOG_ASSERT(choiceFound, "Unable to find choice for a state.");
302 }
303}
304
305template<typename ValueType>
306std::vector<uint64_t> computeValidInitialScheduler(storm::storage::SparseMatrix<ValueType> const& matrix, storm::storage::BitVector const& rowsWithSumLessOne) {
307 std::vector<uint64_t> result(matrix.getRowGroupCount());
308 auto const& groups = matrix.getRowGroupIndices();
309 auto backwardsTransitions = matrix.transpose(true);
310 storm::storage::BitVector processedStates(result.size(), false);
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);
315 }
316 }
317
318 computeSchedulerProb1(matrix, backwardsTransitions, ~processedStates, processedStates, result);
319 return result;
320}
321
327template<typename ValueType>
329 storm::storage::SparseMatrix<ValueType> const& backwardTransitions, storm::storage::BitVector const& finitelyOftenChoices,
330 storm::storage::BitVector safeStates, std::vector<uint64_t>& choices) {
331 auto badStates = transitionMatrix.getRowGroupFilter(finitelyOftenChoices, true) & ~safeStates;
332 // badStates shall only be reached finitely often
333
334 auto reachBadWithProbGreater0AStates = storm::utility::graph::performProbGreater0A(
335 transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardTransitions, ~safeStates, badStates, false, 0, ~finitelyOftenChoices);
336 // States in ~reachBadWithProbGreater0AStates can avoid bad states forever by only taking ~finitelyOftenChoices.
337 // We compute a scheduler for these states achieving exactly this (but we exclude the safe states)
338 auto avoidBadStates = ~reachBadWithProbGreater0AStates & ~safeStates;
339 computeSchedulerProb0(transitionMatrix, backwardTransitions, avoidBadStates, reachBadWithProbGreater0AStates, ~finitelyOftenChoices, choices);
340
341 // We need to take care of states that will reach a bad state with prob greater 0 (including the bad states themselves).
342 // due to the precondition, we know that it has to be possible to eventually avoid the bad states for ever.
343 // Perform a backwards search from the avoid states and store choices with prob. 1
344 computeSchedulerProb1(transitionMatrix, backwardTransitions, reachBadWithProbGreater0AStates, avoidBadStates | safeStates, choices);
345}
346
347template<class SparseModelType>
349 std::vector<ValueType> const& weightedActionRewardVector,
350 boost::optional<std::vector<ValueType>> const& weightedStateRewardVector) {
351 // Compute the optimal (weighted) lra value for each mec, keeping track of the optimal choices
352 STORM_LOG_ASSERT(lraMecDecomposition, "Mec decomposition for lra computations not initialized.");
353 storm::modelchecker::helper::SparseNondeterministicInfiniteHorizonHelper<ValueType> helper = createNondetInfiniteHorizonHelper(this->transitionMatrix);
354 helper.provideLongRunComponentDecomposition(lraMecDecomposition->mecs);
355 helper.setOptimizationDirection(storm::solver::OptimizationDirection::Maximize);
356 helper.setProduceScheduler(true);
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]; };
363 } else {
364 stateValueGetter = [](uint64_t const&) { return storm::utility::zero<ValueType>(); };
365 }
366 lraMecDecomposition->auxMecValues[mecIndex] = helper.computeLraForComponent(env, stateValueGetter, actionValueGetter, mec);
367 }
368 // Extract the produced optimal choices for the MECs
369 this->optimalChoices = std::move(helper.getProducedOptimalChoices());
370}
371
372template<class SparseModelType>
373void StandardPcaaWeightVectorChecker<SparseModelType>::unboundedWeightedPhase(Environment const& env, std::vector<ValueType> const& weightedRewardVector,
374 std::vector<ValueType> const& weightVector) {
375 // Catch the case where all values on the RHS of the MinMax equation system are zero.
376 if (this->objectivesWithNoUpperTimeBound.empty() ||
377 ((this->lraObjectives.empty() || !storm::utility::vector::hasNonZeroEntry(lraMecDecomposition->auxMecValues)) &&
378 !storm::utility::vector::hasNonZeroEntry(weightedRewardVector))) {
379 this->weightedResult.assign(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
380 storm::storage::BitVector statesInLraMec(transitionMatrix.getRowGroupCount(), false);
381 if (this->lraMecDecomposition) {
382 for (auto const& mec : this->lraMecDecomposition->mecs) {
383 for (auto const& sc : mec) {
384 statesInLraMec.set(sc.first, true);
385 }
386 }
387 }
388 // Get an arbitrary scheduler that yields finite reward for all objectives
389 computeSchedulerFinitelyOften(transitionMatrix, transitionMatrix.transpose(true), ~actionsWithoutRewardInUnboundedPhase, statesInLraMec,
390 this->optimalChoices);
391 return;
392 }
393
394 updateEcQuotient(weightedRewardVector);
395
396 // Set up the choice values
397 storm::utility::vector::selectVectorValues(ecQuotient->auxChoiceValues, ecQuotient->ecqToOriginalChoiceMapping, weightedRewardVector);
398 std::map<uint64_t, uint64_t> ecqStateToOptimalMecMap;
399 if (!lraObjectives.empty()) {
400 // We also need to assign a value for each ecQuotientChoice that corresponds to "staying" in the eliminated EC. (at this point these choices should all
401 // have a value of zero). Since each of the eliminated ECs has to contain *at least* one LRA EC, we need to find the largest value among the contained
402 // LRA ECs
403 storm::storage::BitVector foundEcqChoices(ecQuotient->matrix.getRowCount(), false); // keeps track of choices we have already seen before
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()) {
409 // The mec was not part of the ecquotient. This means that it must have value 0.
410 // No further processing is needed.
411 continue;
412 }
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) {
419 // We have seen this ecqState for the first time.
421 "Expected a total reward of zero for choices that represent staying in an EC for ever.");
422 ecqChoiceValue = mecValue;
423 } else {
424 if (mecValue > ecqChoiceValue) { // found a larger value
425 ecqChoiceValue = mecValue;
426 insertionRes.first->second = mecIndex;
427 }
428 }
429 }
430 }
431
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();
442 }
443 if (solver->hasUpperBound()) {
444 req.clearUpperBounds();
445 }
446 if (req.validInitialScheduler()) {
447 solver->setInitialScheduler(computeValidInitialScheduler(ecQuotient->matrix, ecQuotient->rowsWithSumLessOne));
448 req.clearValidInitialScheduler();
449 }
450 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
451 "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
452 solver->setRequirementsChecked(true);
453
454 // Use the (0...0) vector as initial guess for the solution.
455 std::fill(ecQuotient->auxStateValues.begin(), ecQuotient->auxStateValues.end(), storm::utility::zero<ValueType>());
456
457 solver->solveEquations(env, ecQuotient->auxStateValues, ecQuotient->auxChoiceValues);
458 this->weightedResult = std::vector<ValueType>(transitionMatrix.getRowGroupCount());
459
460 transformEcqSolutionToOriginalModel(ecQuotient->auxStateValues, solver->getSchedulerChoices(), ecqStateToOptimalMecMap, this->weightedResult,
461 this->optimalChoices);
462}
463
464template<class SparseModelType>
465void StandardPcaaWeightVectorChecker<SparseModelType>::unboundedIndividualPhase(Environment const& env, std::vector<ValueType> const& weightVector) {
466 if (objectivesWithNoUpperTimeBound.getNumberOfSetBits() == 1 && storm::utility::isOne(weightVector[*objectivesWithNoUpperTimeBound.begin()])) {
467 uint_fast64_t objIndex = *objectivesWithNoUpperTimeBound.begin();
468 objectiveResults[objIndex] = weightedResult;
469 if (storm::solver::minimize(this->objectives[objIndex].formula->getOptimalityType())) {
470 storm::utility::vector::scaleVectorInPlace(objectiveResults[objIndex], -storm::utility::one<ValueType>());
471 }
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>());
475 }
476 }
477 } else {
478 storm::storage::SparseMatrix<ValueType> deterministicMatrix = transitionMatrix.selectRowsFromRowGroups(this->optimalChoices, false);
479 storm::storage::SparseMatrix<ValueType> deterministicBackwardTransitions = deterministicMatrix.transpose();
480 std::vector<ValueType> deterministicStateRewards(deterministicMatrix.getRowCount()); // allocate here
482
483 auto infiniteHorizonHelper = createDetInfiniteHorizonHelper(deterministicMatrix);
484 infiniteHorizonHelper.provideBackwardTransitions(deterministicBackwardTransitions);
485
486 // We compute an estimate for the results of the individual objectives which is obtained from the weighted result and the result of the objectives
487 // computed so far. Note that weightedResult = Sum_{i=1}^{n} w_i * objectiveResult_i.
488 std::vector<ValueType> weightedSumOfUncheckedObjectives = weightedResult;
489 ValueType sumOfWeightsOfUncheckedObjectives = storm::utility::vector::sum_if(weightVector, objectivesWithNoUpperTimeBound);
490
491 for (uint_fast64_t const& objIndex : storm::utility::vector::getSortedIndices(weightVector)) {
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]];
499 };
501 if (stateRewards.empty() || stateRewards[objIndex].empty()) {
502 stateValueGetter = [](uint64_t const&) { return storm::utility::zero<ValueType>(); };
503 } else {
504 stateValueGetter = [&](uint64_t const& s) { return stateRewards[objIndex][s]; };
505 }
506 objectiveResults[objIndex] = infiniteHorizonHelper.computeLongRunAverageValues(env, stateValueGetter, actionValueGetter);
507 } else { // i.e. a total reward objective
508 storm::utility::vector::selectVectorValues(deterministicStateRewards, this->optimalChoices, transitionMatrix.getRowGroupIndices(),
509 actionRewards[objIndex]);
510 storm::storage::BitVector statesWithRewards = ~storm::utility::vector::filterZero(deterministicStateRewards);
511 // As maybestates we pick the states from which a state with reward is reachable
513 deterministicBackwardTransitions, storm::storage::BitVector(deterministicMatrix.getRowCount(), true), statesWithRewards);
514
515 // Compute the estimate for this objective
516 if (!storm::utility::isZero(weightVector[objIndex]) && !storm::utility::isZero(sumOfWeightsOfUncheckedObjectives)) {
517 objectiveResults[objIndex] = weightedSumOfUncheckedObjectives;
518 ValueType scalingFactor = storm::utility::one<ValueType>() / sumOfWeightsOfUncheckedObjectives;
519 if (storm::solver::minimize(obj.formula->getOptimalityType())) {
520 scalingFactor *= -storm::utility::one<ValueType>();
521 }
522 storm::utility::vector::scaleVectorInPlace(objectiveResults[objIndex], scalingFactor);
523 storm::utility::vector::clip(objectiveResults[objIndex], obj.lowerResultBound, obj.upperResultBound);
524 }
525 // Make sure that the objectiveResult is initialized correctly
526 objectiveResults[objIndex].resize(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
527
528 if (!maybeStates.empty()) {
529 bool needEquationSystem =
532 deterministicMatrix.getSubmatrix(true, maybeStates, maybeStates, needEquationSystem);
533 if (needEquationSystem) {
534 // Converting the matrix from the fixpoint notation to the form needed for the equation
535 // system. That is, we go from x = A*x + b to (I-A)x = b.
536 submatrix.convertToEquationSystem();
537 }
538
539 // Prepare solution vector and rhs of the equation system.
540 std::vector<ValueType> x = storm::utility::vector::filterVector(objectiveResults[objIndex], maybeStates);
541 std::vector<ValueType> b = storm::utility::vector::filterVector(deterministicStateRewards, maybeStates);
542
543 // Now solve the resulting equation system.
544 std::unique_ptr<storm::solver::LinearEquationSolver<ValueType>> solver = linearEquationSolverFactory.create(env, submatrix);
545 auto req = solver->getRequirements(env);
546 solver->clearBounds();
547 storm::storage::BitVector submatrixRowsWithSumLessOne = deterministicMatrix.getRowFilter(maybeStates, maybeStates) % maybeStates;
548 submatrixRowsWithSumLessOne.complement();
549 this->setBoundsToSolver(*solver, req.lowerBounds(), req.upperBounds(), objIndex, submatrix, submatrixRowsWithSumLessOne, b);
550 if (solver->hasLowerBound()) {
551 req.clearLowerBounds();
552 }
553 if (solver->hasUpperBound()) {
554 req.clearUpperBounds();
555 }
556 STORM_LOG_THROW(!req.hasEnabledCriticalRequirement(), storm::exceptions::UncheckedRequirementException,
557 "Solver requirements " + req.getEnabledRequirementsAsString() + " not checked.");
558 solver->solveEquations(env, x, b);
559 // Set the result for this objective accordingly
560 storm::utility::vector::setVectorValues<ValueType>(objectiveResults[objIndex], maybeStates, x);
561 }
562 storm::utility::vector::setVectorValues<ValueType>(objectiveResults[objIndex], ~maybeStates, storm::utility::zero<ValueType>());
563 }
564 // Update the estimate for the next objectives.
565 if (!storm::utility::isZero(weightVector[objIndex])) {
566 storm::utility::vector::addScaledVector(weightedSumOfUncheckedObjectives, objectiveResults[objIndex], -weightVector[objIndex]);
567 sumOfWeightsOfUncheckedObjectives -= weightVector[objIndex];
568 }
569 } else {
570 objectiveResults[objIndex] = std::vector<ValueType>(transitionMatrix.getRowGroupCount(), storm::utility::zero<ValueType>());
571 }
572 }
573 }
574}
575
576template<class SparseModelType>
577void StandardPcaaWeightVectorChecker<SparseModelType>::updateEcQuotient(std::vector<ValueType> const& weightedRewardVector) {
578 // Check whether we need to update the currently cached ecElimResult
579 storm::storage::BitVector newTotalReward0Choices = storm::utility::vector::filterZero(weightedRewardVector);
580 storm::storage::BitVector zeroLraRewardChoices(weightedRewardVector.size(), true);
581 if (lraMecDecomposition) {
582 for (uint64_t mecIndex = 0; mecIndex < lraMecDecomposition->mecs.size(); ++mecIndex) {
583 if (!storm::utility::isZero(lraMecDecomposition->auxMecValues[mecIndex])) {
584 // The mec has a non-zero value, so flag all its choices as non-zero
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);
589 }
590 }
591 }
592 }
593 }
594 storm::storage::BitVector newReward0Choices = newTotalReward0Choices & zeroLraRewardChoices;
595 if (!ecQuotient || ecQuotient->origReward0Choices != newReward0Choices) {
596 // It is sufficient to consider the states from which a transition with non-zero reward is reachable. (The remaining states always have reward zero).
597 auto nonZeroRewardStates = transitionMatrix.getRowGroupFilter(newReward0Choices, true);
598 nonZeroRewardStates.complement();
600 transitionMatrix.transpose(true), storm::storage::BitVector(transitionMatrix.getRowGroupCount(), true), nonZeroRewardStates);
601
602 // Remove neutral end components, i.e., ECs in which no total reward is earned.
603 // Note that such ECs contain one (or maybe more) LRA ECs.
604 auto ecElimResult = storm::transformer::EndComponentEliminator<ValueType>::transform(transitionMatrix, subsystemStates,
605 ecChoicesHint & newTotalReward0Choices, totalReward0EStates);
606
607 storm::storage::BitVector rowsWithSumLessOne(ecElimResult.matrix.getRowCount(), false);
608 for (uint64_t row = 0; row < rowsWithSumLessOne.size(); ++row) {
609 if (ecElimResult.matrix.getRow(row).getNumberOfEntries() == 0) {
610 rowsWithSumLessOne.set(row, true);
611 } else {
612 for (auto const& entry : transitionMatrix.getRow(ecElimResult.newToOldRowMapping[row])) {
613 if (!subsystemStates.get(entry.getColumn())) {
614 rowsWithSumLessOne.set(row, true);
615 break;
616 }
617 }
618 }
619 }
620
621 ecQuotient = EcQuotient();
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);
630 }
631 }
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());
638 }
639}
640
641template<class SparseModelType>
643 bool requiresUpper, uint64_t objIndex,
645 storm::storage::BitVector const& rowsWithSumLessOne,
646 std::vector<ValueType> const& rewards) const {
647 // Check whether bounds are already available
648 if (this->objectives[objIndex].lowerResultBound) {
649 solver.setLowerBound(this->objectives[objIndex].lowerResultBound.get());
650 }
651 if (this->objectives[objIndex].upperResultBound) {
652 solver.setUpperBound(this->objectives[objIndex].upperResultBound.get());
653 }
654
655 if ((requiresLower && !solver.hasLowerBound()) || (requiresUpper && !solver.hasUpperBound())) {
656 computeAndSetBoundsToSolver(solver, requiresLower, requiresUpper, transitions, rowsWithSumLessOne, rewards);
657 }
658}
659
660template<class SparseModelType>
662 bool requiresUpper, std::vector<ValueType> const& weightVector,
663 storm::storage::BitVector const& objectiveFilter,
665 storm::storage::BitVector const& rowsWithSumLessOne,
666 std::vector<ValueType> const& rewards) const {
667 // Check whether bounds are already available
668 boost::optional<ValueType> lowerBound = this->computeWeightedResultBound(true, weightVector, objectiveFilter & ~lraObjectives);
669 if (lowerBound) {
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;
674 }
675 }
676 solver.setLowerBound(lowerBound.get());
677 }
678 boost::optional<ValueType> upperBound = this->computeWeightedResultBound(false, weightVector, objectiveFilter);
679 if (upperBound) {
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;
684 }
685 }
686 solver.setUpperBound(upperBound.get());
687 }
688
689 if ((requiresLower && !solver.hasLowerBound()) || (requiresUpper && !solver.hasUpperBound())) {
690 computeAndSetBoundsToSolver(solver, requiresLower, requiresUpper, transitions, rowsWithSumLessOne, rewards);
691 }
692}
693
694template<class SparseModelType>
696 bool requiresUpper,
698 storm::storage::BitVector const& rowsWithSumLessOne,
699 std::vector<ValueType> const& rewards) const {
700 // Compute the one step target probs
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);
704 }
705
706 if (requiresLower && !solver.hasLowerBound()) {
707 // Compute lower bounds
708 std::vector<ValueType> negativeRewards;
709 negativeRewards.reserve(transitions.getRowCount());
710 uint64_t row = 0;
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);
715 }
716 ++row;
717 }
718 if (!negativeRewards.empty()) {
719 negativeRewards.resize(row, storm::utility::zero<ValueType>());
720 std::vector<ValueType> lowerBounds =
721 storm::modelchecker::helper::DsMpiMdpUpperRewardBoundsComputer<ValueType>(transitions, negativeRewards, oneStepTargetProbs)
723 storm::utility::vector::scaleVectorInPlace(lowerBounds, -storm::utility::one<ValueType>());
724 solver.setLowerBounds(std::move(lowerBounds));
725 } else {
726 solver.setLowerBound(storm::utility::zero<ValueType>());
727 }
728 }
729
730 // Compute upper bounds
731 if (requiresUpper && !solver.hasUpperBound()) {
732 std::vector<ValueType> positiveRewards;
733 positiveRewards.reserve(transitions.getRowCount());
734 uint64_t row = 0;
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);
739 }
740 ++row;
741 }
742 if (!positiveRewards.empty()) {
743 positiveRewards.resize(row, storm::utility::zero<ValueType>());
744 solver.setUpperBound(
745 storm::modelchecker::helper::BaierUpperRewardBoundsComputer<ValueType>(transitions, positiveRewards, oneStepTargetProbs).computeUpperBound());
746 } else {
747 solver.setUpperBound(storm::utility::zero<ValueType>());
748 }
749 }
750}
751
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);
759
760 // Keep track of states for which no choice has been set yet.
761 storm::storage::BitVector unprocessedStates(transitionMatrix.getRowGroupCount(), true);
762
763 // For each eliminated ec, keep track of the states (within the ec) that we want to reach and the states for which a choice needs to be set
764 // (Declared already at this point to avoid expensive allocations in each loop iteration)
765 storm::storage::BitVector ecStatesToReach(transitionMatrix.getRowGroupCount(), false);
766 storm::storage::BitVector ecStatesToProcess(transitionMatrix.getRowGroupCount(), false);
767
768 // Run through each state of the ec quotient as well as the associated state(s) of the original model
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)) {
775 // We stay in the current state(s) forever (End component)
776 // We need to set choices in a way that (i) the optimal LRA Mec is reached (if there is any) and (ii) 0 total reward is collected.
777 if (!ecqStateToOptimalMecMap.empty()) {
778 // The current ecqState represents an elimnated EC and we need to stay in this EC and we need to make sure that optimal MEC decisions are
779 // performed within this EC.
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()) {
783 // LRA mec and eliminated EC coincide
784 for (auto const& state : origStates) {
785 STORM_LOG_ASSERT(lraMec.containsState(state), "Expected state to be contained in the lra mec.");
786 // Note that the optimal choice for this state has already been set in the infinite horizon phase.
787 unprocessedStates.set(state, false);
788 originalSolution[state] = ecqSolution[ecqState];
789 }
790 } else {
791 // LRA mec is proper subset of eliminated ec. There are also other states for which we have to set choices leading to the LRA MEC inside.
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);
798 // Note that the optimal choice for this state has already been set in the infinite horizon phase.
799 } else {
800 ecStatesToProcess.set(state, true);
801 }
802 unprocessedStates.set(state, false);
803 originalSolution[state] = ecqSolution[ecqState];
804 }
805 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess, ecStatesToReach, originalOptimalChoices,
806 &ecQuotient->origTotalReward0Choices);
807 // Clear bitvectors for next ecqState.
808 ecStatesToProcess.clear();
809 ecStatesToReach.clear();
810 }
811 } else {
812 // If there is no LRA Mec to reach, we just need to make sure that finite total reward is collected for all objectives
813 // In this branch our BitVectors have a slightly different meaning, so we create more readable aliases
814 storm::storage::BitVector& ecStatesToAvoid = ecStatesToReach;
815 bool needSchedulerComputation = false;
816 STORM_LOG_ASSERT(storm::utility::isZero(ecqSolution[ecqState]),
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>(); // i.e. ecqSolution[ecqState];
820 ecStatesToProcess.set(state, true);
821 }
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;
830 } else {
831 // this state should not be reached infinitely often
832 ecStatesToAvoid.set(state, true);
833 needSchedulerComputation = true;
834 }
835 }
836 if (needSchedulerComputation) {
837 // There are ec states which we should not visit infinitely often
838 auto ecStatesThatCanAvoid =
839 storm::utility::graph::performProbGreater0A(transitionMatrix, transitionMatrix.getRowGroupIndices(), backwardsTransitions,
840 ecStatesToProcess, ecStatesToAvoid, false, 0, valid0RewardChoices);
841 ecStatesThatCanAvoid.complement();
842 // Set the choice for all states that can achieve value 0
843 computeSchedulerProb0(transitionMatrix, backwardsTransitions, ecStatesThatCanAvoid, ecStatesToAvoid, valid0RewardChoices,
844 originalOptimalChoices);
845 // Set the choice for all remaining states
846 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess & ~ecStatesToAvoid, ecStatesToAvoid, originalOptimalChoices,
847 &validChoices);
848 }
849 ecStatesToAvoid.clear();
850 ecStatesToProcess.clear();
851 }
852 } else {
853 // We eventually leave the current state(s)
854 // In this case, we can safely take the origChoice at the corresponding state (say 's').
855 // For all other origStates associated with ecqState (if there are any), we make sure that the state 's' is reached almost surely.
856 if (origStates.size() > 1) {
857 for (auto const& state : origStates) {
858 // Check if the orig choice originates from this state
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);
864 } else {
865 STORM_LOG_ASSERT(origStates.size() > 1, "Multiple original states expected.");
866 ecStatesToProcess.set(state, true);
867 }
868 unprocessedStates.set(state, false);
869 originalSolution[state] = ecqSolution[ecqState];
870 }
871 auto validChoices = transitionMatrix.getRowFilter(ecStatesToProcess, ecStatesToProcess | ecStatesToReach);
872 computeSchedulerProb1(transitionMatrix, backwardsTransitions, ecStatesToProcess, ecStatesToReach, originalOptimalChoices, &validChoices);
873 // Clear bitvectors for next ecqState.
874 ecStatesToProcess.clear();
875 ecStatesToReach.clear();
876 } else {
877 // There is just one state so we take the associated choice.
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);
886 }
887 }
888 }
889
890 // The states that still not have been processed, there is no associated state of the ec quotient.
891 // This is because the value for these states will be 0 under all (lra optimal-) schedulers.
892 storm::utility::vector::setVectorValues(originalSolution, unprocessedStates, storm::utility::zero<ValueType>());
893 // Get a set of states for which we know that no reward (for all objectives) will be collected
894 if (this->lraMecDecomposition) {
895 // In this case, all unprocessed non-lra mec states should reach an (unprocessed) lra mec
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);
900 }
901 }
902 }
903 } else {
904 ecStatesToReach = unprocessedStates & totalReward0EStates;
905 // Set a scheduler for the ecStates that we want to reach
906 computeSchedulerProb0(transitionMatrix, backwardsTransitions, ecStatesToReach, ~unprocessedStates | ~totalReward0EStates,
907 actionsWithoutRewardInUnboundedPhase, originalOptimalChoices);
908 }
909 unprocessedStates &= ~ecStatesToReach;
910 // Set a scheduler for the remaining states
911 computeSchedulerProb1(transitionMatrix, backwardsTransitions, unprocessedStates, ecStatesToReach, originalOptimalChoices);
912}
913
916#ifdef STORM_HAVE_CARL
919#endif
920
921} // namespace multiobjective
922} // namespace modelchecker
923} // namespace storm
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.
virtual ValueType computeLraForComponent(Environment const &env, ValueGetter const &stateValuesGetter, ValueGetter const &actionValuesGetter, storm::storage::MaximalEndComponent const &component) override
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)
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.
Definition BitVector.h:18
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.
Definition Scheduler.h:18
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.
Definition Scheduler.cpp:37
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 ...
static EndComponentEliminatorReturnType transform(storm::storage::SparseMatrix< ValueType > const &originalMatrix, storm::storage::MaximalEndComponentDecomposition< ValueType > ecs, storm::storage::BitVector const &subsystemStates, storm::storage::BitVector const &addSinkRowStates, bool addSelfLoopAtSinkStates=false)
#define STORM_LOG_INFO(message)
Definition logging.h:29
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
#define STORM_PRINT_AND_LOG(message)
Definition macros.h:68
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...
Definition graph.cpp:322
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...
Definition graph.cpp:857
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...
Definition graph.cpp:689
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...
Definition graph.cpp:976
T dotProduct(std::vector< T > const &firstOperand, std::vector< T > const &secondOperand)
Computes the dot product (aka scalar product) and returns the result.
Definition vector.h:517
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.
Definition vector.h:83
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...
Definition vector.h:189
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...
Definition vector.h:504
std::string toString(std::vector< ValueType > const &vector)
Output vector as string.
Definition vector.h:1298
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.
Definition vector.h:1041
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.
Definition vector.h:596
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,...
Definition vector.h:149
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...
Definition vector.h:563
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...
Definition vector.h:491
bool hasNonZeroEntry(std::vector< T > const &v)
Definition vector.h:1252
std::vector< Type > filterVector(std::vector< Type > const &in, storm::storage::BitVector const &filter)
Definition vector.h:1213
bool isOne(ValueType const &a)
Definition constants.cpp:36
bool isZero(ValueType const &a)
Definition constants.cpp:41
ValueType sqrt(ValueType const &number)
LabParser.cpp.
Definition cli.cpp:18