Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SparseMultiObjectivePreprocessor.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <set>
5
17#include "storm/utility/graph.h"
20
23
24namespace storm {
25namespace modelchecker {
26namespace multiobjective {
27namespace preprocessing {
28
29template<typename SparseModelType>
31 Environment const& env, SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula, bool produceScheduler) {
32 std::shared_ptr<SparseModelType> model;
33 std::optional<storm::storage::SparseModelMemoryProductReverseData> memoryIncorporationReverseData;
34
35 // Incorporate the necessary memory
37 auto const& schedRestr = env.modelchecker().multi().getSchedulerRestriction();
38 if (schedRestr.getMemoryPattern() == storm::storage::SchedulerClass::MemoryPattern::GoalMemory) {
39 if (produceScheduler) {
40 std::tie(model, memoryIncorporationReverseData) =
42 originalFormula.getSubformulas());
43 } else {
45 }
46 } else if (schedRestr.getMemoryPattern() == storm::storage::SchedulerClass::MemoryPattern::Arbitrary && schedRestr.getMemoryStates() > 1) {
47 STORM_LOG_THROW(!produceScheduler, storm::exceptions::NotImplementedException, "Cannot produce schedulers for the provided memory pattern.");
48 model = storm::transformer::MemoryIncorporation<SparseModelType>::incorporateFullMemory(originalModel, schedRestr.getMemoryStates());
49 } else if (schedRestr.getMemoryPattern() == storm::storage::SchedulerClass::MemoryPattern::Counter && schedRestr.getMemoryStates() > 1) {
50 STORM_LOG_THROW(!produceScheduler, storm::exceptions::NotImplementedException, "Cannot produce schedulers for the provided memory pattern.");
51 model = storm::transformer::MemoryIncorporation<SparseModelType>::incorporateCountingMemory(originalModel, schedRestr.getMemoryStates());
52 } else if (schedRestr.isPositional()) {
53 model = std::make_shared<SparseModelType>(originalModel);
54 } else {
55 STORM_LOG_THROW(false, storm::exceptions::NotImplementedException, "The given scheduler restriction has not been implemented.");
56 }
57 } else {
58 if (produceScheduler) {
59 std::tie(model, memoryIncorporationReverseData) =
61 } else {
63 }
64 }
65
66 // Remove states that are irrelevant for all properties (e.g. because they are only reachable via goal states
67 boost::optional<std::string> deadlockLabel;
68 if (!produceScheduler) {
69 // When producing schedulers, removing irrelevant states requires additional bookkeeping.
70 removeIrrelevantStates(model, deadlockLabel, originalFormula);
71 }
72
73 PreprocessorData data(model);
74 data.deadlockLabel = deadlockLabel;
75 data.memoryIncorporationReverseData = std::move(memoryIncorporationReverseData);
76
77 // Invoke preprocessing on the individual objectives
78 for (auto const& subFormula : originalFormula.getSubformulas()) {
79 STORM_LOG_INFO("Preprocessing objective " << *subFormula << ".");
80 data.objectives.push_back(std::make_shared<Objective<ValueType>>());
81 data.objectives.back()->originalFormula = subFormula;
82 data.finiteRewardCheckObjectives.resize(data.objectives.size(), false);
83 STORM_LOG_THROW(data.objectives.back()->originalFormula->isOperatorFormula(), storm::exceptions::InvalidPropertyException,
84 "Could not preprocess the subformula " << *subFormula << " of " << originalFormula << " because it is not supported.");
85 preprocessOperatorFormula(data.objectives.back()->originalFormula->asOperatorFormula(), data);
86 }
87
88 // Remove reward models that are not needed anymore
89 std::set<std::string> relevantRewardModels;
90 for (auto const& obj : data.objectives) {
91 obj->formula->gatherReferencedRewardModels(relevantRewardModels);
92 }
93 data.model->restrictRewardModels(relevantRewardModels);
94
95 // Build the actual result
96 return buildResult(originalModel, originalFormula, data);
97}
98
99template<typename SparseModelType>
101 // Get the complement of the states that are reachable without visiting phi
102 auto result =
103 storm::utility::graph::getReachableStates(model.getTransitionMatrix(), model.getInitialStates(), ~phi, storm::storage::BitVector(phi.size(), false));
104 result.complement();
105 STORM_LOG_ASSERT(phi.isSubsetOf(result), "Phi is not a subset of result.");
106 return result;
107}
108
109template<typename SparseModelType>
110void SparseMultiObjectivePreprocessor<SparseModelType>::removeIrrelevantStates(std::shared_ptr<SparseModelType>& model,
111 boost::optional<std::string>& deadlockLabel,
112 storm::logic::MultiObjectiveFormula const& originalFormula) {
113 storm::storage::BitVector absorbingStates(model->getNumberOfStates(), true);
114
116 storm::storage::SparseMatrix<ValueType> backwardTransitions = model->getBackwardTransitions();
117
118 for (auto const& opFormula : originalFormula.getSubformulas()) {
119 // Compute a set of states from which we can make any subset absorbing without affecting this subformula
120 storm::storage::BitVector absorbingStatesForSubformula;
121 STORM_LOG_THROW(opFormula->isOperatorFormula(), storm::exceptions::InvalidPropertyException,
122 "Could not preprocess the subformula " << *opFormula << " of " << originalFormula << " because it is not supported.");
123 auto const& pathFormula = opFormula->asOperatorFormula().getSubformula();
124 if (opFormula->isProbabilityOperatorFormula()) {
125 if (pathFormula.isUntilFormula()) {
126 auto lhs =
127 mc.check(pathFormula.asUntilFormula().getLeftSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
128 auto rhs =
129 mc.check(pathFormula.asUntilFormula().getRightSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
130 absorbingStatesForSubformula = storm::utility::graph::performProb0A(backwardTransitions, lhs, rhs);
131 absorbingStatesForSubformula |= getOnlyReachableViaPhi(*model, ~lhs | rhs);
132 } else if (pathFormula.isBoundedUntilFormula()) {
133 if (pathFormula.asBoundedUntilFormula().hasMultiDimensionalSubformulas()) {
134 absorbingStatesForSubformula = storm::storage::BitVector(model->getNumberOfStates(), true);
135 storm::storage::BitVector absorbingStatesForSubSubformula;
136 for (uint64_t i = 0; i < pathFormula.asBoundedUntilFormula().getDimension(); ++i) {
137 auto subPathFormula = pathFormula.asBoundedUntilFormula().restrictToDimension(i);
138 auto lhs = mc.check(pathFormula.asBoundedUntilFormula().getLeftSubformula(i))
139 ->template asExplicitQualitativeCheckResult<ValueType>()
140 .getTruthValuesVector();
141 auto rhs = mc.check(pathFormula.asBoundedUntilFormula().getRightSubformula(i))
142 ->template asExplicitQualitativeCheckResult<ValueType>()
143 .getTruthValuesVector();
144 absorbingStatesForSubSubformula = storm::utility::graph::performProb0A(backwardTransitions, lhs, rhs);
145 if (pathFormula.asBoundedUntilFormula().hasLowerBound(i)) {
146 absorbingStatesForSubSubformula |= getOnlyReachableViaPhi(*model, ~lhs);
147 } else {
148 absorbingStatesForSubSubformula |= getOnlyReachableViaPhi(*model, ~lhs | rhs);
149 }
150 absorbingStatesForSubformula &= absorbingStatesForSubSubformula;
151 }
152 } else {
153 auto lhs = mc.check(pathFormula.asBoundedUntilFormula().getLeftSubformula())
154 ->template asExplicitQualitativeCheckResult<ValueType>()
155 .getTruthValuesVector();
156 auto rhs = mc.check(pathFormula.asBoundedUntilFormula().getRightSubformula())
157 ->template asExplicitQualitativeCheckResult<ValueType>()
158 .getTruthValuesVector();
159 absorbingStatesForSubformula = storm::utility::graph::performProb0A(backwardTransitions, lhs, rhs);
160 if (pathFormula.asBoundedUntilFormula().hasLowerBound()) {
161 absorbingStatesForSubformula |= getOnlyReachableViaPhi(*model, ~lhs);
162 } else {
163 absorbingStatesForSubformula |= getOnlyReachableViaPhi(*model, ~lhs | rhs);
164 }
165 }
166 } else if (pathFormula.isGloballyFormula()) {
167 auto phi =
168 mc.check(pathFormula.asGloballyFormula().getSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
169 auto notPhi = ~phi;
170 absorbingStatesForSubformula = storm::utility::graph::performProb0A(backwardTransitions, phi, notPhi);
171 absorbingStatesForSubformula |= getOnlyReachableViaPhi(*model, notPhi);
172 } else if (pathFormula.isEventuallyFormula()) {
173 auto phi =
174 mc.check(pathFormula.asEventuallyFormula().getSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
175 absorbingStatesForSubformula = storm::utility::graph::performProb0A(backwardTransitions, ~phi, phi);
176 absorbingStatesForSubformula |= getOnlyReachableViaPhi(*model, phi);
177 } else {
178 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << pathFormula << " is not supported.");
179 }
180 } else if (opFormula->isRewardOperatorFormula()) {
181 auto const& baseRewardModel = opFormula->asRewardOperatorFormula().hasRewardModelName()
182 ? model->getRewardModel(opFormula->asRewardOperatorFormula().getRewardModelName())
183 : model->getUniqueRewardModel();
184 if (pathFormula.isEventuallyFormula()) {
185 auto rewardModel = storm::utility::createFilteredRewardModel(baseRewardModel, model->isDiscreteTimeModel(), pathFormula.asEventuallyFormula());
186 storm::storage::BitVector statesWithoutReward = rewardModel.get().getStatesWithZeroReward(model->getTransitionMatrix());
187 // Make states that can not reach a state with non-zero reward absorbing
188 absorbingStatesForSubformula = storm::utility::graph::performProb0A(backwardTransitions, statesWithoutReward, ~statesWithoutReward);
189 auto phi =
190 mc.check(pathFormula.asEventuallyFormula().getSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
191 // Make states that reach phi with prob 1 while only visiting states with reward 0 absorbing
192 absorbingStatesForSubformula |= storm::utility::graph::performProb1A(
193 model->getTransitionMatrix(), model->getTransitionMatrix().getRowGroupIndices(), backwardTransitions, statesWithoutReward, phi);
194 // Make states that are only reachable via phi absorbing
195 absorbingStatesForSubformula |= getOnlyReachableViaPhi(*model, phi);
196 } else if (pathFormula.isCumulativeRewardFormula()) {
197 auto rewardModel =
198 storm::utility::createFilteredRewardModel(baseRewardModel, model->isDiscreteTimeModel(), pathFormula.asCumulativeRewardFormula());
199 storm::storage::BitVector statesWithoutReward = rewardModel.get().getStatesWithZeroReward(model->getTransitionMatrix());
200 absorbingStatesForSubformula = storm::utility::graph::performProb0A(backwardTransitions, statesWithoutReward, ~statesWithoutReward);
201 } else if (pathFormula.isTotalRewardFormula()) {
202 auto rewardModel = storm::utility::createFilteredRewardModel(baseRewardModel, model->isDiscreteTimeModel(), pathFormula.asTotalRewardFormula());
203 storm::storage::BitVector statesWithoutReward = rewardModel.get().getStatesWithZeroReward(model->getTransitionMatrix());
204 absorbingStatesForSubformula = storm::utility::graph::performProb0A(backwardTransitions, statesWithoutReward, ~statesWithoutReward);
205 } else if (pathFormula.isLongRunAverageRewardFormula()) {
206 auto rewardModel =
207 storm::utility::createFilteredRewardModel(baseRewardModel, model->isDiscreteTimeModel(), pathFormula.asLongRunAverageRewardFormula());
208 storm::storage::BitVector statesWithoutReward = rewardModel.get().getStatesWithZeroReward(model->getTransitionMatrix());
209 // Compute Sat(Forall F (Forall G "statesWithoutReward"))
210 auto forallGloballyStatesWithoutReward = storm::utility::graph::performProb0A(backwardTransitions, statesWithoutReward, ~statesWithoutReward);
211 absorbingStatesForSubformula =
212 storm::utility::graph::performProb1A(model->getTransitionMatrix(), model->getNondeterministicChoiceIndices(), backwardTransitions,
213 storm::storage::BitVector(model->getNumberOfStates(), true), forallGloballyStatesWithoutReward);
214 } else {
215 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << pathFormula << " is not supported.");
216 }
217 } else if (opFormula->isTimeOperatorFormula()) {
218 if (pathFormula.isEventuallyFormula()) {
219 auto phi =
220 mc.check(pathFormula.asEventuallyFormula().getSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
221 absorbingStatesForSubformula = getOnlyReachableViaPhi(*model, phi);
222 } else {
223 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << pathFormula << " is not supported.");
224 }
225 } else if (opFormula->isLongRunAverageOperatorFormula()) {
226 auto lraStates = mc.check(pathFormula)->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
227 // Compute Sat(Forall F (Forall G not "lraStates"))
228 auto forallGloballyNotLraStates = storm::utility::graph::performProb0A(backwardTransitions, ~lraStates, lraStates);
229 absorbingStatesForSubformula = storm::utility::graph::performProb1A(model->getTransitionMatrix(), model->getNondeterministicChoiceIndices(),
230 backwardTransitions, ~lraStates, forallGloballyNotLraStates);
231 } else {
232 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException,
233 "Could not preprocess the subformula " << *opFormula << " of " << originalFormula << " because it is not supported.");
234 }
235 absorbingStates &= absorbingStatesForSubformula;
236 if (absorbingStates.empty()) {
237 break;
238 }
239 }
240
241 if (!absorbingStates.empty()) {
242 // We can make the states absorbing and delete unreachable states.
243 storm::storage::BitVector subsystemActions(model->getNumberOfChoices(), true);
244 for (uint64_t absorbingState : absorbingStates) {
245 for (uint64_t action = model->getTransitionMatrix().getRowGroupIndices()[absorbingState];
246 action < model->getTransitionMatrix().getRowGroupIndices()[absorbingState + 1]; ++action) {
247 subsystemActions.set(action, false);
248 }
249 }
250 storm::transformer::SubsystemBuilderOptions options;
251 options.fixDeadlocks = true;
252 auto const& submodel =
253 storm::transformer::buildSubsystem(*model, storm::storage::BitVector(model->getNumberOfStates(), true), subsystemActions, false, options);
254 STORM_LOG_INFO("Making states absorbing reduced the state space from " << model->getNumberOfStates() << " to " << submodel.model->getNumberOfStates()
255 << ".");
256 model = submodel.model->template as<SparseModelType>();
257 deadlockLabel = submodel.deadlockLabel;
258 }
259}
260
261template<typename SparseModelType>
262SparseMultiObjectivePreprocessor<SparseModelType>::PreprocessorData::PreprocessorData(std::shared_ptr<SparseModelType> model) : model(model) {
263 // The rewardModelNamePrefix should not be a prefix of a reward model name of the given model to ensure uniqueness of new reward model names
264 rewardModelNamePrefix = "obj";
265 while (true) {
266 bool prefixIsUnique = true;
267 for (auto const& rewardModels : model->getRewardModels()) {
268 if (rewardModelNamePrefix.size() <= rewardModels.first.size()) {
269 if (std::mismatch(rewardModelNamePrefix.begin(), rewardModelNamePrefix.end(), rewardModels.first.begin()).first ==
270 rewardModelNamePrefix.end()) {
271 prefixIsUnique = false;
272 rewardModelNamePrefix = "_" + rewardModelNamePrefix;
273 break;
274 }
275 }
276 }
277 if (prefixIsUnique) {
278 break;
279 }
280 }
281}
282
285 if (formula.hasBound()) {
286 opInfo.bound = formula.getBound();
287 // Invert the bound (if necessary)
288 if (considerComplementaryEvent) {
289 opInfo.bound->threshold = opInfo.bound->threshold.getManager().rational(storm::utility::one<storm::RationalNumber>()) - opInfo.bound->threshold;
290 switch (opInfo.bound->comparisonType) {
292 opInfo.bound->comparisonType = storm::logic::ComparisonType::Less;
293 break;
295 opInfo.bound->comparisonType = storm::logic::ComparisonType::LessEqual;
296 break;
298 opInfo.bound->comparisonType = storm::logic::ComparisonType::Greater;
299 break;
301 opInfo.bound->comparisonType = storm::logic::ComparisonType::GreaterEqual;
302 break;
303 default:
304 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Current objective " << formula << " has unexpected comparison type.");
305 }
306 }
307 if (storm::logic::isLowerBound(opInfo.bound->comparisonType)) {
308 opInfo.optimalityType = storm::solver::OptimizationDirection::Maximize;
309 } else {
310 opInfo.optimalityType = storm::solver::OptimizationDirection::Minimize;
311 }
313 "Optimization direction of formula " << formula << " ignored as the formula also specifies a threshold.");
314 } else if (formula.hasOptimalityType()) {
315 opInfo.optimalityType = formula.getOptimalityType();
316 // Invert the optimality type (if necessary)
317 if (considerComplementaryEvent) {
319 }
320 } else {
321 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Objective " << formula << " does not specify whether to minimize or maximize.");
322 }
323 return opInfo;
324}
325
326template<typename SparseModelType>
327void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessOperatorFormula(storm::logic::OperatorFormula const& formula, PreprocessorData& data) {
328 Objective<ValueType>& objective = *data.objectives.back();
329
330 // Check whether the complementary event is considered
332
333 // Extract the operator information from the formula and potentially invert it for the complementary event
334 storm::logic::OperatorInformation opInfo = getOperatorInformation(formula, objective.considersComplementaryEvent);
335
336 if (formula.isProbabilityOperatorFormula()) {
337 preprocessProbabilityOperatorFormula(formula.asProbabilityOperatorFormula(), opInfo, data);
338 } else if (formula.isRewardOperatorFormula()) {
339 preprocessRewardOperatorFormula(formula.asRewardOperatorFormula(), opInfo, data);
340 } else if (formula.isTimeOperatorFormula()) {
341 preprocessTimeOperatorFormula(formula.asTimeOperatorFormula(), opInfo, data);
342 } else if (formula.isLongRunAverageOperatorFormula()) {
343 preprocessLongRunAverageOperatorFormula(formula.asLongRunAverageOperatorFormula(), opInfo, data);
344 } else {
345 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException,
346 "Could not preprocess the objective " << formula << " because it is not supported.");
347 }
348}
349
350template<typename SparseModelType>
351void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessProbabilityOperatorFormula(storm::logic::ProbabilityOperatorFormula const& formula,
352 storm::logic::OperatorInformation const& opInfo,
353 PreprocessorData& data) {
354 // Probabilities are between zero and one
355 data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>();
356 data.objectives.back()->upperResultBound = storm::utility::one<ValueType>();
357
358 if (formula.getSubformula().isUntilFormula()) {
359 preprocessUntilFormula(formula.getSubformula().asUntilFormula(), opInfo, data);
360 } else if (formula.getSubformula().isBoundedUntilFormula()) {
361 preprocessBoundedUntilFormula(formula.getSubformula().asBoundedUntilFormula(), opInfo, data);
362 } else if (formula.getSubformula().isGloballyFormula()) {
363 preprocessGloballyFormula(formula.getSubformula().asGloballyFormula(), opInfo, data);
364 } else if (formula.getSubformula().isEventuallyFormula()) {
365 preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data);
366 } else {
367 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported.");
368 }
369}
370
371template<typename SparseModelType>
372void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessRewardOperatorFormula(storm::logic::RewardOperatorFormula const& formula,
373 storm::logic::OperatorInformation const& opInfo,
374 PreprocessorData& data) {
375 std::string rewardModelName;
376 if (formula.hasRewardModelName()) {
377 rewardModelName = formula.getRewardModelName();
378 STORM_LOG_THROW(data.model->hasRewardModel(rewardModelName), storm::exceptions::InvalidPropertyException,
379 "The reward model specified by formula " << formula << " does not exist in the model.");
380 } else {
381 // We have to assert that a unique reward model exists, and we need to find its name.
382 // However, we might have added auxiliary reward models for other objectives which we have to filter out here.
383 auto prefixOf = [](std::string const& left, std::string const& right) {
384 return std::mismatch(left.begin(), left.end(), right.begin()).first == left.end();
385 };
386 bool uniqueRewardModelFound = false;
387 for (auto const& rewModel : data.model->getRewardModels()) {
388 if (prefixOf(data.rewardModelNamePrefix, rewModel.first)) {
389 // Skip auxiliary reward model
390 continue;
391 }
392 STORM_LOG_THROW(!uniqueRewardModelFound, storm::exceptions::InvalidOperationException,
393 "The formula " << formula << " does not specify a reward model name and the reward model is not unique.");
394 uniqueRewardModelFound = true;
395 rewardModelName = rewModel.first;
396 }
397 STORM_LOG_THROW(uniqueRewardModelFound, storm::exceptions::InvalidOperationException,
398 "The formula " << formula << " refers to an unnamed reward model but no reward model has been defined.");
399 }
400
401 if (formula.getSubformula().isEventuallyFormula()) {
402 preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data, rewardModelName);
403 } else if (formula.getSubformula().isCumulativeRewardFormula()) {
404 preprocessCumulativeRewardFormula(formula.getSubformula().asCumulativeRewardFormula(), opInfo, data, rewardModelName);
405 } else if (formula.getSubformula().isTotalRewardFormula()) {
406 preprocessTotalRewardFormula(formula.getSubformula().asTotalRewardFormula(), opInfo, data, rewardModelName);
407 } else if (formula.getSubformula().isLongRunAverageRewardFormula()) {
408 preprocessLongRunAverageRewardFormula(formula.getSubformula().asLongRunAverageRewardFormula(), opInfo, data, rewardModelName);
409 } else {
410 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported.");
411 }
412}
413
414template<typename SparseModelType>
415void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessTimeOperatorFormula(storm::logic::TimeOperatorFormula const& formula,
416 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) {
417 data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>();
418
419 if (formula.getSubformula().isEventuallyFormula()) {
420 preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data);
421 } else {
422 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported.");
423 }
424}
425
426template<typename SparseModelType>
427void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessLongRunAverageOperatorFormula(storm::logic::LongRunAverageOperatorFormula const& formula,
428 storm::logic::OperatorInformation const& opInfo,
429 PreprocessorData& data) {
430 data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>();
431 data.objectives.back()->upperResultBound = storm::utility::one<ValueType>();
432
433 // Convert to a long run average reward formula
434 // Create and add the new formula
435 std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
436 auto lraRewardFormula = std::make_shared<storm::logic::LongRunAverageRewardFormula>();
437 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(lraRewardFormula, rewardModelName, opInfo);
438
439 // Create and add the new reward model that only gives one reward for goal states
440 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(*data.model);
441 storm::storage::BitVector subFormulaResult =
442 mc.check(formula.getSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
443 std::vector<typename SparseModelType::ValueType> lraRewards(data.model->getNumberOfStates(), storm::utility::zero<typename SparseModelType::ValueType>());
445 data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::move(lraRewards)));
446}
447
448template<typename SparseModelType>
449void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessUntilFormula(storm::logic::UntilFormula const& formula,
450 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data,
451 std::shared_ptr<storm::logic::Formula const> subformula) {
452 // Try to transform the formula to expected total (or cumulative) rewards
453
454 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(*data.model);
455 storm::storage::BitVector rightSubformulaResult =
456 mc.check(formula.getRightSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
457 // Check if the formula is already satisfied in the initial state because then the transformation to expected rewards will fail.
458 // TODO: Handle this case more properly
459 STORM_LOG_THROW((data.model->getInitialStates() & rightSubformulaResult).empty(), storm::exceptions::NotImplementedException,
460 "The Probability for the objective "
461 << *data.objectives.back()->originalFormula
462 << " is always one as the rhs of the until formula is true in the initial state. This (trivial) case is currently not implemented.");
463
464 // Whenever a state that violates the left subformula or satisfies the right subformula is reached, the objective is 'decided', i.e., no more reward should
465 // be collected from there
466 storm::storage::BitVector notLeftOrRight =
467 mc.check(formula.getLeftSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
468 notLeftOrRight.complement();
469 notLeftOrRight |= rightSubformulaResult;
470
471 // Get the states that are reachable from a notLeftOrRight state
472 storm::storage::BitVector allStates(data.model->getNumberOfStates(), true), noStates(data.model->getNumberOfStates(), false);
473 storm::storage::BitVector reachableFromGoal =
474 storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), notLeftOrRight, allStates, noStates);
475 // Get the states that are reachable from an initial state, stopping at the states reachable from goal
476 storm::storage::BitVector reachableFromInit =
477 storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), data.model->getInitialStates(), ~notLeftOrRight, reachableFromGoal);
478 // Exclude the actual notLeftOrRight states from the states that are reachable from init
479 reachableFromInit &= ~notLeftOrRight;
480 // If we can reach a state that is reachable from goal, but which is not a goal state, it means that the transformation to expected rewards is not possible.
481 if ((reachableFromInit & reachableFromGoal).empty()) {
482 STORM_LOG_INFO("Objective " << *data.objectives.back()->originalFormula << " is transformed to an expected total/cumulative reward property.");
483 // Transform to expected total rewards:
484 // build stateAction reward vector that gives (one*transitionProbability) reward whenever a transition leads from a reachableFromInit state to a
485 // goalState
486 std::vector<typename SparseModelType::ValueType> objectiveRewards(data.model->getTransitionMatrix().getRowCount(),
488 for (uint64_t state : reachableFromInit) {
489 for (uint_fast64_t row = data.model->getTransitionMatrix().getRowGroupIndices()[state];
490 row < data.model->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++row) {
491 objectiveRewards[row] = data.model->getTransitionMatrix().getConstrainedRowSum(row, rightSubformulaResult);
492 }
493 }
494 std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
495 data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::nullopt, std::move(objectiveRewards)));
496 if (subformula == nullptr) {
497 subformula = std::make_shared<storm::logic::TotalRewardFormula>();
498 }
499 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(subformula, rewardModelName, opInfo);
500 } else {
501 STORM_LOG_INFO("Objective " << *data.objectives.back()->originalFormula << " can not be transformed to an expected total/cumulative reward property.");
502 data.objectives.back()->formula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula.asSharedPointer(), opInfo);
503 }
504}
505
506template<typename SparseModelType>
507void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessBoundedUntilFormula(storm::logic::BoundedUntilFormula const& formula,
508 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) {
509 // Check how to handle this query
510 if (formula.isMultiDimensional() || formula.getTimeBoundReference().isRewardBound()) {
511 // multidimensional and/or reward-bounded formulas are kept as they are. No preprocessing is done for them.
512 data.objectives.back()->formula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula.asSharedPointer(), opInfo);
513 } else if (!formula.hasLowerBound() || (!formula.isLowerBoundStrict() && storm::utility::isZero(formula.template getLowerBound<storm::RationalNumber>()))) {
514 std::shared_ptr<storm::logic::Formula const> subformula;
515 if (!formula.hasUpperBound()) {
516 // The formula is actually unbounded
517 subformula = std::make_shared<storm::logic::TotalRewardFormula>();
518 } else {
520 storm::exceptions::InvalidPropertyException,
521 "Bounded until formulas for Markov Automata are only allowed when time bounds are considered.");
522 storm::logic::TimeBound bound(formula.isUpperBoundStrict(), formula.getUpperBound());
523 subformula = std::make_shared<storm::logic::CumulativeRewardFormula>(bound, formula.getTimeBoundReference());
524 }
525 preprocessUntilFormula(storm::logic::UntilFormula(formula.getLeftSubformula().asSharedPointer(), formula.getRightSubformula().asSharedPointer()),
526 opInfo, data, subformula);
527 } else {
528 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Property " << formula << "is not supported.");
529 }
530}
531
532template<typename SparseModelType>
533void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessGloballyFormula(storm::logic::GloballyFormula const& formula,
534 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) {
535 // The formula is transformed to an until formula for the complementary event.
536 auto negatedSubformula = std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not,
537 formula.getSubformula().asSharedPointer());
538
539 preprocessUntilFormula(storm::logic::UntilFormula(storm::logic::Formula::getTrueFormula(), negatedSubformula), opInfo, data);
540}
541
542template<typename SparseModelType>
543void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessEventuallyFormula(storm::logic::EventuallyFormula const& formula,
544 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data,
545 boost::optional<std::string> const& optionalRewardModelName) {
546 if (formula.isReachabilityProbabilityFormula()) {
547 preprocessUntilFormula(
548 *std::make_shared<storm::logic::UntilFormula>(storm::logic::Formula::getTrueFormula(), formula.getSubformula().asSharedPointer()), opInfo, data);
549 return;
550 }
551
552 // Analyze the subformula
553 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(*data.model);
554 storm::storage::BitVector subFormulaResult =
555 mc.check(formula.getSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
556
557 // Get the states that are reachable from a goal state
558 storm::storage::BitVector allStates(data.model->getNumberOfStates(), true), noStates(data.model->getNumberOfStates(), false);
559 storm::storage::BitVector reachableFromGoal =
560 storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), subFormulaResult, allStates, noStates);
561 // Get the states that are reachable from an initial state, stopping at the states reachable from goal
562 storm::storage::BitVector reachableFromInit =
563 storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), data.model->getInitialStates(), allStates, reachableFromGoal);
564 // Exclude the actual goal states from the states that are reachable from an initial state
565 reachableFromInit &= ~subFormulaResult;
566 // If we can reach a state that is reachable from goal but which is not a goal state, it means that the transformation to expected total rewards is not
567 // possible.
568 if ((reachableFromInit & reachableFromGoal).empty()) {
569 // Transform to expected total rewards.
570 STORM_LOG_INFO("Objective " << *data.objectives.back()->originalFormula << " is transformed to an expected total reward property.");
571 std::string const rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
572 auto const totalRewardFormula = std::make_shared<storm::logic::TotalRewardFormula>();
573 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(totalRewardFormula, rewardModelName, opInfo);
574
575 if (formula.isReachabilityRewardFormula()) {
576 // The reachableFromGoal-states are those that are *only* reachable via goal.
577 // This is true because we applied the goal unfolding before, and we are in the (reachableFromInit & reachableFromGoal).empty() case).
578 // We therefore clear all the rewards collected at reachableFromGoal-states.
579 STORM_LOG_ASSERT(optionalRewardModelName.is_initialized(), "Optional reward model name not initialized.");
580 auto objectiveRewards =
581 storm::utility::createFilteredRewardModel(data.model->getRewardModel(optionalRewardModelName.get()), data.model->isDiscreteTimeModel(), formula)
582 .extract();
583 // Reduce potential transition branch rewards to state-action rewards.
584 objectiveRewards.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false);
585 STORM_LOG_ASSERT(!objectiveRewards.hasTransitionRewards(), "Expected no transition rewards after reducing to state-based rewards.");
586 // clear state-rewards
587 if (objectiveRewards.hasStateRewards()) {
588 storm::utility::vector::setVectorValues(objectiveRewards.getStateRewardVector(), reachableFromGoal,
590 }
591 // clear state-action rewards
592 if (objectiveRewards.hasStateActionRewards()) {
593 for (uint64_t state : reachableFromGoal) {
594 std::fill_n(objectiveRewards.getStateActionRewardVector().begin() + data.model->getTransitionMatrix().getRowGroupIndices()[state],
595 data.model->getTransitionMatrix().getRowGroupSize(state), storm::utility::zero<typename SparseModelType::ValueType>());
596 }
597 }
598 // add the new reward model
599 data.model->addRewardModel(rewardModelName, std::move(objectiveRewards));
600 } else if (formula.isReachabilityTimeFormula()) {
601 // build state reward vector that only gives reward for relevant states
602 std::vector<typename SparseModelType::ValueType> timeRewards(data.model->getNumberOfStates(),
604 if (data.model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
606 timeRewards,
607 dynamic_cast<storm::models::sparse::MarkovAutomaton<typename SparseModelType::ValueType> const&>(*data.model).getMarkovianStates() &
608 reachableFromInit,
610 } else {
612 }
613 data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::move(timeRewards)));
614 } else {
615 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException,
616 "The formula " << formula << " neither considers reachability probabilities nor reachability rewards "
617 << (data.model->isOfType(storm::models::ModelType::MarkovAutomaton) ? "nor reachability time" : "")
618 << ". This is not supported.");
619 }
620 } else {
621 STORM_LOG_INFO("Objective " << *data.objectives.back()->originalFormula << " can not be transformed to an expected total/cumulative reward property.");
622 if (formula.isReachabilityRewardFormula()) {
623 // TODO: this probably needs some better treatment regarding schedulers that do not reach the goal state allmost surely
624 STORM_LOG_ASSERT(optionalRewardModelName.is_initialized(), "Optional reward model name not initialized.");
625 if (data.deadlockLabel) {
626 // We made some states absorbing and created a new deadlock state. To make sure that this deadlock state gets value zero, we add it to the set
627 // of goal states of the formula.
628 std::shared_ptr<storm::logic::Formula const> newSubSubformula =
629 std::make_shared<storm::logic::AtomicLabelFormula const>(data.deadlockLabel.get());
630 std::shared_ptr<storm::logic::Formula const> newSubformula = std::make_shared<storm::logic::BinaryBooleanStateFormula const>(
631 storm::logic::BinaryBooleanStateFormula::OperatorType::Or, formula.getSubformula().asSharedPointer(), newSubSubformula);
632 boost::optional<storm::logic::RewardAccumulation> newRewardAccumulation;
633 if (formula.hasRewardAccumulation()) {
634 newRewardAccumulation = formula.getRewardAccumulation();
635 }
636 std::shared_ptr<storm::logic::Formula const> newFormula =
637 std::make_shared<storm::logic::EventuallyFormula const>(newSubformula, formula.getContext(), newRewardAccumulation);
638 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(newFormula, optionalRewardModelName.get(), opInfo);
639 } else {
640 data.objectives.back()->formula =
641 std::make_shared<storm::logic::RewardOperatorFormula>(formula.asSharedPointer(), optionalRewardModelName.get(), opInfo);
642 }
643 } else if (formula.isReachabilityTimeFormula()) {
644 // Reduce to reachability rewards so that time formulas do not have to be treated seperately later.
645 std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
646 std::shared_ptr<storm::logic::Formula const> newSubformula = formula.getSubformula().asSharedPointer();
647 if (data.deadlockLabel) {
648 // We made some states absorbing and created a new deadlock state. To make sure that this deadlock state gets value zero, we add it to the set
649 // of goal states of the formula.
650 std::shared_ptr<storm::logic::Formula const> newSubSubformula =
651 std::make_shared<storm::logic::AtomicLabelFormula const>(data.deadlockLabel.get());
652 newSubformula = std::make_shared<storm::logic::BinaryBooleanStateFormula const>(storm::logic::BinaryBooleanStateFormula::OperatorType::Or,
653 formula.getSubformula().asSharedPointer(), newSubSubformula);
654 }
655 auto newFormula = std::make_shared<storm::logic::EventuallyFormula>(newSubformula, storm::logic::FormulaContext::Reward);
656 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(newFormula, rewardModelName, opInfo);
657 std::vector<typename SparseModelType::ValueType> timeRewards;
658 if (data.model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
659 timeRewards.assign(data.model->getNumberOfStates(), storm::utility::zero<typename SparseModelType::ValueType>());
661 timeRewards,
662 dynamic_cast<storm::models::sparse::MarkovAutomaton<typename SparseModelType::ValueType> const&>(*data.model).getMarkovianStates(),
664 } else {
665 timeRewards.assign(data.model->getNumberOfStates(), storm::utility::one<typename SparseModelType::ValueType>());
666 }
667 data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::move(timeRewards)));
668 } else {
669 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException,
670 "The formula " << formula << " neither considers reachability probabilities nor reachability rewards "
671 << (data.model->isOfType(storm::models::ModelType::MarkovAutomaton) ? "nor reachability time" : "")
672 << ". This is not supported.");
673 }
674 }
675 data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true);
676}
677
678template<typename SparseModelType>
679void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessCumulativeRewardFormula(storm::logic::CumulativeRewardFormula const& formula,
680 storm::logic::OperatorInformation const& opInfo,
681 PreprocessorData& data,
682 boost::optional<std::string> const& optionalRewardModelName) {
683 STORM_LOG_THROW(data.model->isOfType(storm::models::ModelType::Mdp), storm::exceptions::InvalidPropertyException,
684 "Cumulative reward formulas are not supported for the given model type.");
685 std::string rewardModelName = optionalRewardModelName.get();
686 // Strip away potential RewardAccumulations in the formula itself but also in reward bounds
687 auto filteredRewards = storm::utility::createFilteredRewardModel(data.model->getRewardModel(rewardModelName), data.model->isDiscreteTimeModel(), formula);
688 if (filteredRewards.isDifferentFromUnfilteredModel()) {
689 rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
690 data.model->addRewardModel(rewardModelName, std::move(filteredRewards.extract()));
691 }
692 // Clear potential transition rewards.
693 auto& rewardModel = data.model->getRewardModel(rewardModelName);
694 rewardModel.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false);
695 STORM_LOG_ASSERT(!rewardModel.hasTransitionRewards(), "Expected no transition rewards after reducing to state-based rewards.");
696
697 std::vector<storm::logic::TimeBoundReference> newTimeBoundReferences;
698 bool onlyRewardBounds = true;
699 for (uint64_t i = 0; i < formula.getDimension(); ++i) {
700 auto oldTbr = formula.getTimeBoundReference(i);
701 if (oldTbr.isRewardBound()) {
702 if (oldTbr.hasRewardAccumulation()) {
703 auto filteredBoundRewards = storm::utility::createFilteredRewardModel(data.model->getRewardModel(oldTbr.getRewardName()),
704 oldTbr.getRewardAccumulation(), data.model->isDiscreteTimeModel());
705 if (filteredBoundRewards.isDifferentFromUnfilteredModel()) {
706 std::string freshRewardModelName =
707 data.rewardModelNamePrefix + std::to_string(data.objectives.size()) + std::string("_" + std::to_string(i));
708 data.model->addRewardModel(freshRewardModelName, std::move(filteredBoundRewards.extract()));
709 newTimeBoundReferences.emplace_back(freshRewardModelName);
710 } else {
711 // Strip away the reward accumulation
712 newTimeBoundReferences.emplace_back(oldTbr.getRewardName());
713 }
714 } else {
715 newTimeBoundReferences.push_back(oldTbr);
716 }
717 } else {
718 onlyRewardBounds = false;
719 newTimeBoundReferences.push_back(oldTbr);
720 }
721 }
722
723 auto newFormula = std::make_shared<storm::logic::CumulativeRewardFormula>(formula.getBounds(), newTimeBoundReferences);
724 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(newFormula, rewardModelName, opInfo);
725
726 if (onlyRewardBounds) {
727 data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true);
728 }
729}
730
731template<typename SparseModelType>
732void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessTotalRewardFormula(storm::logic::TotalRewardFormula const& formula,
733 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data,
734 boost::optional<std::string> const& optionalRewardModelName) {
735 std::string rewardModelName = optionalRewardModelName.get();
736 auto filteredRewards = storm::utility::createFilteredRewardModel(data.model->getRewardModel(rewardModelName), data.model->isDiscreteTimeModel(), formula);
737 if (filteredRewards.isDifferentFromUnfilteredModel()) {
738 rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
739 data.model->addRewardModel(rewardModelName, filteredRewards.extract());
740 }
741 // Reduce potential transition branch rewards to state-action rewards
742 auto& rewardModel = data.model->getRewardModel(rewardModelName);
743 rewardModel.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false);
744 STORM_LOG_ASSERT(!rewardModel.hasTransitionRewards(), "Expected no transition rewards after reducing to state-based rewards.");
745
746 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(formula.stripRewardAccumulation(), rewardModelName, opInfo);
747 data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true);
748}
749
750template<typename SparseModelType>
751void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessLongRunAverageRewardFormula(storm::logic::LongRunAverageRewardFormula const& formula,
752 storm::logic::OperatorInformation const& opInfo,
753 PreprocessorData& data,
754 boost::optional<std::string> const& optionalRewardModelName) {
755 std::string rewardModelName = optionalRewardModelName.get();
756 auto filteredRewards = storm::utility::createFilteredRewardModel(data.model->getRewardModel(rewardModelName), data.model->isDiscreteTimeModel(), formula);
757 if (filteredRewards.isDifferentFromUnfilteredModel()) {
758 std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
759 data.model->addRewardModel(rewardModelName, std::move(filteredRewards.extract()));
760 }
761 // Reduce potential transition branch rewards to state-action rewards
762 auto& rewardModel = data.model->getRewardModel(rewardModelName);
763 rewardModel.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false);
764 STORM_LOG_ASSERT(!rewardModel.hasTransitionRewards(), "Expected no transition rewards after reducing to state-based rewards.");
765
766 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(formula.stripRewardAccumulation(), rewardModelName, opInfo);
767}
768
769template<typename SparseModelType>
770typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType SparseMultiObjectivePreprocessor<SparseModelType>::buildResult(
771 SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula, PreprocessorData& data) {
772 ReturnType result(originalFormula, originalModel);
773 auto backwardTransitions = data.model->getBackwardTransitions();
774 result.preprocessedModel = data.model;
775 result.memoryIncorporationReverseData = data.memoryIncorporationReverseData;
776
777 for (auto& obj : data.objectives) {
778 result.objectives.push_back(std::move(*obj));
779 }
780 result.queryType = getQueryType(result.objectives);
781 result.maybeInfiniteRewardObjectives = std::move(data.finiteRewardCheckObjectives);
782
783 return result;
784}
785
786template<typename SparseModelType>
787typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType::QueryType SparseMultiObjectivePreprocessor<SparseModelType>::getQueryType(
788 std::vector<Objective<ValueType>> const& objectives) {
789 uint_fast64_t numOfObjectivesWithThreshold = 0;
790 for (auto& obj : objectives) {
791 if (obj.formula->hasBound()) {
792 ++numOfObjectivesWithThreshold;
793 }
794 }
795 if (numOfObjectivesWithThreshold == objectives.size()) {
796 return ReturnType::QueryType::Achievability;
797 } else if (numOfObjectivesWithThreshold + 1 == objectives.size()) {
798 // Note: We do not want to consider a Pareto query when the total number of objectives is one.
799 return ReturnType::QueryType::Quantitative;
800 } else if (numOfObjectivesWithThreshold == 0) {
801 return ReturnType::QueryType::Pareto;
802 } else {
803 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException,
804 "Invalid Multi-objective query: The numer of qualitative objectives should be either 0 (Pareto query), 1 (quantitative query), or "
805 "#objectives (achievability query).");
806 }
807}
808
809template class SparseMultiObjectivePreprocessor<storm::models::sparse::Mdp<double>>;
810template class SparseMultiObjectivePreprocessor<storm::models::sparse::MarkovAutomaton<double>>;
811
812template class SparseMultiObjectivePreprocessor<storm::models::sparse::Mdp<storm::RationalNumber>>;
813template class SparseMultiObjectivePreprocessor<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
814} // namespace preprocessing
815} // namespace multiobjective
816} // namespace modelchecker
817} // namespace storm
ModelCheckerEnvironment & modelchecker()
MultiObjectiveModelCheckerEnvironment & multi()
storm::storage::SchedulerClass const & getSchedulerRestriction() const
Formula const & getRightSubformula() const
Formula const & getLeftSubformula() const
TimeBoundReference const & getTimeBoundReference(unsigned i=0) const
bool isLowerBoundStrict(unsigned i=0) const
storm::expressions::Expression const & getUpperBound(unsigned i=0) const
bool isUpperBoundStrict(unsigned i=0) const
TimeBoundReference const & getTimeBoundReference() const
std::vector< TimeBound > const & getBounds() const
virtual bool isReachabilityRewardFormula() const override
FormulaContext const & getContext() const
virtual bool isReachabilityProbabilityFormula() const override
RewardAccumulation const & getRewardAccumulation() const
virtual bool isReachabilityTimeFormula() const override
TotalRewardFormula & asTotalRewardFormula()
Definition Formula.cpp:437
RewardOperatorFormula & asRewardOperatorFormula()
Definition Formula.cpp:484
virtual bool isGloballyFormula() const
Definition Formula.cpp:96
UntilFormula & asUntilFormula()
Definition Formula.cpp:325
BoundedUntilFormula & asBoundedUntilFormula()
Definition Formula.cpp:333
static std::shared_ptr< Formula const > getTrueFormula()
Definition Formula.cpp:213
LongRunAverageOperatorFormula & asLongRunAverageOperatorFormula()
Definition Formula.cpp:413
LongRunAverageRewardFormula & asLongRunAverageRewardFormula()
Definition Formula.cpp:468
virtual bool isProbabilityOperatorFormula() const
Definition Formula.cpp:180
virtual bool isCumulativeRewardFormula() const
Definition Formula.cpp:144
ProbabilityOperatorFormula & asProbabilityOperatorFormula()
Definition Formula.cpp:476
GloballyFormula & asGloballyFormula()
Definition Formula.cpp:381
virtual bool isUntilFormula() const
Definition Formula.cpp:80
virtual bool isRewardOperatorFormula() const
Definition Formula.cpp:184
virtual bool isLongRunAverageRewardFormula() const
Definition Formula.cpp:160
EventuallyFormula & asEventuallyFormula()
Definition Formula.cpp:341
TimeOperatorFormula & asTimeOperatorFormula()
Definition Formula.cpp:421
virtual bool isLongRunAverageOperatorFormula() const
Definition Formula.cpp:136
virtual bool isBoundedUntilFormula() const
Definition Formula.cpp:84
virtual bool isEventuallyFormula() const
Definition Formula.cpp:88
virtual bool isTimeOperatorFormula() const
Definition Formula.cpp:140
virtual bool isTotalRewardFormula() const
Definition Formula.cpp:164
CumulativeRewardFormula & asCumulativeRewardFormula()
Definition Formula.cpp:429
std::shared_ptr< Formula const > asSharedPointer()
Definition Formula.cpp:571
std::shared_ptr< LongRunAverageRewardFormula const > stripRewardAccumulation() const
std::vector< std::shared_ptr< Formula const > > const & getSubformulas() const
Bound const & getBound() const
storm::solver::OptimizationDirection const & getOptimalityType() const
std::string const & getRewardModelName() const
Retrieves the name of the reward model this property refers to (if any).
bool hasRewardModelName() const
Retrieves whether the reward model refers to a specific reward model.
std::shared_ptr< TotalRewardFormula const > stripRewardAccumulation() const
Formula const & getSubformula() const
Formula const & getSubformula() const
static ReturnType preprocess(Environment const &env, SparseModelType const &originalModel, storm::logic::MultiObjectiveFormula const &originalFormula, bool produceScheduler)
Preprocesses the given model w.r.t.
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
void complement()
Negates all bits in 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.
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.
A class that holds a possibly non-square matrix in the compressed row storage format.
static std::shared_ptr< SparseModelType > incorporateFullMemory(SparseModelType const &model, uint64_t memoryStates)
Incorporates a memory structure where the nondeterminism of the model decides which successor state t...
static std::pair< std::shared_ptr< SparseModelType >, storm::storage::SparseModelMemoryProductReverseData > incorporateGoalMemoryWithReverseData(SparseModelType const &model, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas)
Like incorporateGoalMemory, but also returns data necessary to translate results (in particular sched...
static std::shared_ptr< SparseModelType > incorporateGoalMemory(SparseModelType const &model, std::vector< std::shared_ptr< storm::logic::Formula const > > const &formulas)
Incorporates memory that stores whether a 'goal' state has already been reached.
static std::shared_ptr< SparseModelType > incorporateCountingMemory(SparseModelType const &model, uint64_t memoryStates)
Incorporates a memory structure where the nondeterminism of the model can increment a counter.
#define STORM_LOG_INFO(message)
Definition logging.h:27
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:36
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
bool isLowerBound(ComparisonType t)
storm::storage::BitVector getOnlyReachableViaPhi(SparseModelType const &model, storm::storage::BitVector const &phi)
storm::logic::OperatorInformation getOperatorInformation(storm::logic::OperatorFormula const &formula, bool considerComplementaryEvent)
OptimizationDirection constexpr invert(OptimizationDirection d)
SubsystemBuilderReturnType< ValueType, RewardModelType > buildSubsystem(storm::models::sparse::Model< ValueType, RewardModelType > const &originalModel, storm::storage::BitVector const &subsystemStates, storm::storage::BitVector const &subsystemActions, bool keepUnreachableStates, SubsystemBuilderOptions options)
storm::storage::BitVector getReachableStates(storm::storage::SparseMatrix< T > const &transitionMatrix, storm::storage::BitVector const &initialStates, storm::storage::BitVector const &constraintStates, storm::storage::BitVector const &targetStates, bool useStepBound, uint_fast64_t maximalSteps, boost::optional< storm::storage::BitVector > const &choiceFilter)
Performs a forward depth-first search through the underlying graph structure to identify the states t...
Definition graph.cpp:41
storm::storage::BitVector performProb1A(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 1 of satisfying phi until psi under all possible re...
Definition graph.cpp:981
storm::storage::BitVector performProb0A(storm::storage::SparseMatrix< T > const &backwardTransitions, storm::storage::BitVector const &phiStates, storm::storage::BitVector const &psiStates)
Definition graph.cpp:733
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:78
FilteredRewardModel< RewardModelType > createFilteredRewardModel(RewardModelType const &baseRewardModel, storm::logic::RewardAccumulation const &acc, bool isDiscreteTimeModel)
bool isZero(ValueType const &a)
Definition constants.cpp:42
ValueType zero()
Definition constants.cpp:24
ValueType one()
Definition constants.cpp:19
boost::optional< Bound > bound
boost::optional< storm::solver::OptimizationDirection > optimalityType