Storm 1.13.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 assert(phi.isSubsetOf(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 (auto 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, "Could not preprocess the objective " << formula << " because it is not supported");
346 }
347}
348
349template<typename SparseModelType>
350void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessProbabilityOperatorFormula(storm::logic::ProbabilityOperatorFormula const& formula,
351 storm::logic::OperatorInformation const& opInfo,
352 PreprocessorData& data) {
353 // Probabilities are between zero and one
354 data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>();
355 data.objectives.back()->upperResultBound = storm::utility::one<ValueType>();
356
357 if (formula.getSubformula().isUntilFormula()) {
358 preprocessUntilFormula(formula.getSubformula().asUntilFormula(), opInfo, data);
359 } else if (formula.getSubformula().isBoundedUntilFormula()) {
360 preprocessBoundedUntilFormula(formula.getSubformula().asBoundedUntilFormula(), opInfo, data);
361 } else if (formula.getSubformula().isGloballyFormula()) {
362 preprocessGloballyFormula(formula.getSubformula().asGloballyFormula(), opInfo, data);
363 } else if (formula.getSubformula().isEventuallyFormula()) {
364 preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data);
365 } else {
366 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported.");
367 }
368}
369
370template<typename SparseModelType>
371void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessRewardOperatorFormula(storm::logic::RewardOperatorFormula const& formula,
372 storm::logic::OperatorInformation const& opInfo,
373 PreprocessorData& data) {
374 std::string rewardModelName;
375 if (formula.hasRewardModelName()) {
376 rewardModelName = formula.getRewardModelName();
377 STORM_LOG_THROW(data.model->hasRewardModel(rewardModelName), storm::exceptions::InvalidPropertyException,
378 "The reward model specified by formula " << formula << " does not exist in the model");
379 } else {
380 // We have to assert that a unique reward model exists, and we need to find its name.
381 // However, we might have added auxiliary reward models for other objectives which we have to filter out here.
382 auto prefixOf = [](std::string const& left, std::string const& right) {
383 return std::mismatch(left.begin(), left.end(), right.begin()).first == left.end();
384 };
385 bool uniqueRewardModelFound = false;
386 for (auto const& rewModel : data.model->getRewardModels()) {
387 if (prefixOf(data.rewardModelNamePrefix, rewModel.first)) {
388 // Skip auxiliary reward model
389 continue;
390 }
391 STORM_LOG_THROW(!uniqueRewardModelFound, storm::exceptions::InvalidOperationException,
392 "The formula " << formula << " does not specify a reward model name and the reward model is not unique.");
393 uniqueRewardModelFound = true;
394 rewardModelName = rewModel.first;
395 }
396 STORM_LOG_THROW(uniqueRewardModelFound, storm::exceptions::InvalidOperationException,
397 "The formula " << formula << " refers to an unnamed reward model but no reward model has been defined.");
398 }
399
400 if (formula.getSubformula().isEventuallyFormula()) {
401 preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data, rewardModelName);
402 } else if (formula.getSubformula().isCumulativeRewardFormula()) {
403 preprocessCumulativeRewardFormula(formula.getSubformula().asCumulativeRewardFormula(), opInfo, data, rewardModelName);
404 } else if (formula.getSubformula().isTotalRewardFormula()) {
405 preprocessTotalRewardFormula(formula.getSubformula().asTotalRewardFormula(), opInfo, data, rewardModelName);
406 } else if (formula.getSubformula().isLongRunAverageRewardFormula()) {
407 preprocessLongRunAverageRewardFormula(formula.getSubformula().asLongRunAverageRewardFormula(), opInfo, data, rewardModelName);
408 } else {
409 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported.");
410 }
411}
412
413template<typename SparseModelType>
414void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessTimeOperatorFormula(storm::logic::TimeOperatorFormula const& formula,
415 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) {
416 data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>();
417
418 if (formula.getSubformula().isEventuallyFormula()) {
419 preprocessEventuallyFormula(formula.getSubformula().asEventuallyFormula(), opInfo, data);
420 } else {
421 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "The subformula of " << formula << " is not supported.");
422 }
423}
424
425template<typename SparseModelType>
426void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessLongRunAverageOperatorFormula(storm::logic::LongRunAverageOperatorFormula const& formula,
427 storm::logic::OperatorInformation const& opInfo,
428 PreprocessorData& data) {
429 data.objectives.back()->lowerResultBound = storm::utility::zero<ValueType>();
430 data.objectives.back()->upperResultBound = storm::utility::one<ValueType>();
431
432 // Convert to a long run average reward formula
433 // Create and add the new formula
434 std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
435 auto lraRewardFormula = std::make_shared<storm::logic::LongRunAverageRewardFormula>();
436 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(lraRewardFormula, rewardModelName, opInfo);
437
438 // Create and add the new reward model that only gives one reward for goal states
439 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(*data.model);
440 storm::storage::BitVector subFormulaResult =
441 mc.check(formula.getSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
442 std::vector<typename SparseModelType::ValueType> lraRewards(data.model->getNumberOfStates(), storm::utility::zero<typename SparseModelType::ValueType>());
444 data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::move(lraRewards)));
445}
446
447template<typename SparseModelType>
448void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessUntilFormula(storm::logic::UntilFormula const& formula,
449 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data,
450 std::shared_ptr<storm::logic::Formula const> subformula) {
451 // Try to transform the formula to expected total (or cumulative) rewards
452
453 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(*data.model);
454 storm::storage::BitVector rightSubformulaResult =
455 mc.check(formula.getRightSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
456 // Check if the formula is already satisfied in the initial state because then the transformation to expected rewards will fail.
457 // TODO: Handle this case more properly
458 STORM_LOG_THROW((data.model->getInitialStates() & rightSubformulaResult).empty(), storm::exceptions::NotImplementedException,
459 "The Probability for the objective "
460 << *data.objectives.back()->originalFormula
461 << " is always one as the rhs of the until formula is true in the initial state. This (trivial) case is currently not implemented.");
462
463 // 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
464 // be collected from there
465 storm::storage::BitVector notLeftOrRight =
466 mc.check(formula.getLeftSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
467 notLeftOrRight.complement();
468 notLeftOrRight |= rightSubformulaResult;
469
470 // Get the states that are reachable from a notLeftOrRight state
471 storm::storage::BitVector allStates(data.model->getNumberOfStates(), true), noStates(data.model->getNumberOfStates(), false);
472 storm::storage::BitVector reachableFromGoal =
473 storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), notLeftOrRight, allStates, noStates);
474 // Get the states that are reachable from an initial state, stopping at the states reachable from goal
475 storm::storage::BitVector reachableFromInit =
476 storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), data.model->getInitialStates(), ~notLeftOrRight, reachableFromGoal);
477 // Exclude the actual notLeftOrRight states from the states that are reachable from init
478 reachableFromInit &= ~notLeftOrRight;
479 // 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.
480 if ((reachableFromInit & reachableFromGoal).empty()) {
481 STORM_LOG_INFO("Objective " << *data.objectives.back()->originalFormula << " is transformed to an expected total/cumulative reward property.");
482 // Transform to expected total rewards:
483 // build stateAction reward vector that gives (one*transitionProbability) reward whenever a transition leads from a reachableFromInit state to a
484 // goalState
485 std::vector<typename SparseModelType::ValueType> objectiveRewards(data.model->getTransitionMatrix().getRowCount(),
487 for (auto state : reachableFromInit) {
488 for (uint_fast64_t row = data.model->getTransitionMatrix().getRowGroupIndices()[state];
489 row < data.model->getTransitionMatrix().getRowGroupIndices()[state + 1]; ++row) {
490 objectiveRewards[row] = data.model->getTransitionMatrix().getConstrainedRowSum(row, rightSubformulaResult);
491 }
492 }
493 std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
494 data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::nullopt, std::move(objectiveRewards)));
495 if (subformula == nullptr) {
496 subformula = std::make_shared<storm::logic::TotalRewardFormula>();
497 }
498 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(subformula, rewardModelName, opInfo);
499 } else {
500 STORM_LOG_INFO("Objective " << *data.objectives.back()->originalFormula << " can not be transformed to an expected total/cumulative reward property.");
501 data.objectives.back()->formula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula.asSharedPointer(), opInfo);
502 }
503}
504
505template<typename SparseModelType>
506void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessBoundedUntilFormula(storm::logic::BoundedUntilFormula const& formula,
507 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) {
508 // Check how to handle this query
509 if (formula.isMultiDimensional() || formula.getTimeBoundReference().isRewardBound()) {
510 // multidimensional and/or reward-bounded formulas are kept as they are. No preprocessing is done for them.
511 data.objectives.back()->formula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(formula.asSharedPointer(), opInfo);
512 } else if (!formula.hasLowerBound() || (!formula.isLowerBoundStrict() && storm::utility::isZero(formula.template getLowerBound<storm::RationalNumber>()))) {
513 std::shared_ptr<storm::logic::Formula const> subformula;
514 if (!formula.hasUpperBound()) {
515 // The formula is actually unbounded
516 subformula = std::make_shared<storm::logic::TotalRewardFormula>();
517 } else {
519 storm::exceptions::InvalidPropertyException,
520 "Bounded until formulas for Markov Automata are only allowed when time bounds are considered.");
521 storm::logic::TimeBound bound(formula.isUpperBoundStrict(), formula.getUpperBound());
522 subformula = std::make_shared<storm::logic::CumulativeRewardFormula>(bound, formula.getTimeBoundReference());
523 }
524 preprocessUntilFormula(storm::logic::UntilFormula(formula.getLeftSubformula().asSharedPointer(), formula.getRightSubformula().asSharedPointer()),
525 opInfo, data, subformula);
526 } else {
527 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException, "Property " << formula << "is not supported");
528 }
529}
530
531template<typename SparseModelType>
532void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessGloballyFormula(storm::logic::GloballyFormula const& formula,
533 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data) {
534 // The formula is transformed to an until formula for the complementary event.
535 auto negatedSubformula = std::make_shared<storm::logic::UnaryBooleanStateFormula>(storm::logic::UnaryBooleanStateFormula::OperatorType::Not,
536 formula.getSubformula().asSharedPointer());
537
538 preprocessUntilFormula(storm::logic::UntilFormula(storm::logic::Formula::getTrueFormula(), negatedSubformula), opInfo, data);
539}
540
541template<typename SparseModelType>
542void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessEventuallyFormula(storm::logic::EventuallyFormula const& formula,
543 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data,
544 boost::optional<std::string> const& optionalRewardModelName) {
545 if (formula.isReachabilityProbabilityFormula()) {
546 preprocessUntilFormula(
547 *std::make_shared<storm::logic::UntilFormula>(storm::logic::Formula::getTrueFormula(), formula.getSubformula().asSharedPointer()), opInfo, data);
548 return;
549 }
550
551 // Analyze the subformula
552 storm::modelchecker::SparsePropositionalModelChecker<SparseModelType> mc(*data.model);
553 storm::storage::BitVector subFormulaResult =
554 mc.check(formula.getSubformula())->template asExplicitQualitativeCheckResult<ValueType>().getTruthValuesVector();
555
556 // Get the states that are reachable from a goal state
557 storm::storage::BitVector allStates(data.model->getNumberOfStates(), true), noStates(data.model->getNumberOfStates(), false);
558 storm::storage::BitVector reachableFromGoal =
559 storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), subFormulaResult, allStates, noStates);
560 // Get the states that are reachable from an initial state, stopping at the states reachable from goal
561 storm::storage::BitVector reachableFromInit =
562 storm::utility::graph::getReachableStates(data.model->getTransitionMatrix(), data.model->getInitialStates(), allStates, reachableFromGoal);
563 // Exclude the actual goal states from the states that are reachable from an initial state
564 reachableFromInit &= ~subFormulaResult;
565 // 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
566 // possible.
567 if ((reachableFromInit & reachableFromGoal).empty()) {
568 // Transform to expected total rewards.
569 STORM_LOG_INFO("Objective " << *data.objectives.back()->originalFormula << " is transformed to an expected total reward property.");
570 std::string const rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
571 auto const totalRewardFormula = std::make_shared<storm::logic::TotalRewardFormula>();
572 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(totalRewardFormula, rewardModelName, opInfo);
573
574 if (formula.isReachabilityRewardFormula()) {
575 // The reachableFromGoal-states are those that are *only* reachable via goal.
576 // This is true because we applied the goal unfolding before, and we are in the (reachableFromInit & reachableFromGoal).empty() case).
577 // We therefore clear all the rewards collected at reachableFromGoal-states.
578 assert(optionalRewardModelName.is_initialized());
579 auto objectiveRewards =
580 storm::utility::createFilteredRewardModel(data.model->getRewardModel(optionalRewardModelName.get()), data.model->isDiscreteTimeModel(), formula)
581 .extract();
582 // Reduce potential transition branch rewards to state-action rewards.
583 objectiveRewards.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false);
584 STORM_LOG_ASSERT(!objectiveRewards.hasTransitionRewards(), "Expected no transition rewards after reducing to state-based rewards");
585 // clear state-rewards
586 if (objectiveRewards.hasStateRewards()) {
587 storm::utility::vector::setVectorValues(objectiveRewards.getStateRewardVector(), reachableFromGoal,
589 }
590 // clear state-action rewards
591 if (objectiveRewards.hasStateActionRewards()) {
592 for (auto state : reachableFromGoal) {
593 std::fill_n(objectiveRewards.getStateActionRewardVector().begin() + data.model->getTransitionMatrix().getRowGroupIndices()[state],
594 data.model->getTransitionMatrix().getRowGroupSize(state), storm::utility::zero<typename SparseModelType::ValueType>());
595 }
596 }
597 // add the new reward model
598 data.model->addRewardModel(rewardModelName, std::move(objectiveRewards));
599 } else if (formula.isReachabilityTimeFormula()) {
600 // build state reward vector that only gives reward for relevant states
601 std::vector<typename SparseModelType::ValueType> timeRewards(data.model->getNumberOfStates(),
603 if (data.model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
605 timeRewards,
606 dynamic_cast<storm::models::sparse::MarkovAutomaton<typename SparseModelType::ValueType> const&>(*data.model).getMarkovianStates() &
607 reachableFromInit,
609 } else {
611 }
612 data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::move(timeRewards)));
613 } else {
614 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException,
615 "The formula " << formula << " neither considers reachability probabilities nor reachability rewards "
616 << (data.model->isOfType(storm::models::ModelType::MarkovAutomaton) ? "nor reachability time" : "")
617 << ". This is not supported.");
618 }
619 } else {
620 STORM_LOG_INFO("Objective " << *data.objectives.back()->originalFormula << " can not be transformed to an expected total/cumulative reward property.");
621 if (formula.isReachabilityRewardFormula()) {
622 // TODO: this probably needs some better treatment regarding schedulers that do not reach the goal state allmost surely
623 assert(optionalRewardModelName.is_initialized());
624 if (data.deadlockLabel) {
625 // 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
626 // of goal states of the formula.
627 std::shared_ptr<storm::logic::Formula const> newSubSubformula =
628 std::make_shared<storm::logic::AtomicLabelFormula const>(data.deadlockLabel.get());
629 std::shared_ptr<storm::logic::Formula const> newSubformula = std::make_shared<storm::logic::BinaryBooleanStateFormula const>(
630 storm::logic::BinaryBooleanStateFormula::OperatorType::Or, formula.getSubformula().asSharedPointer(), newSubSubformula);
631 boost::optional<storm::logic::RewardAccumulation> newRewardAccumulation;
632 if (formula.hasRewardAccumulation()) {
633 newRewardAccumulation = formula.getRewardAccumulation();
634 }
635 std::shared_ptr<storm::logic::Formula const> newFormula =
636 std::make_shared<storm::logic::EventuallyFormula const>(newSubformula, formula.getContext(), newRewardAccumulation);
637 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(newFormula, optionalRewardModelName.get(), opInfo);
638 } else {
639 data.objectives.back()->formula =
640 std::make_shared<storm::logic::RewardOperatorFormula>(formula.asSharedPointer(), optionalRewardModelName.get(), opInfo);
641 }
642 } else if (formula.isReachabilityTimeFormula()) {
643 // Reduce to reachability rewards so that time formulas do not have to be treated seperately later.
644 std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
645 std::shared_ptr<storm::logic::Formula const> newSubformula = formula.getSubformula().asSharedPointer();
646 if (data.deadlockLabel) {
647 // 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
648 // of goal states of the formula.
649 std::shared_ptr<storm::logic::Formula const> newSubSubformula =
650 std::make_shared<storm::logic::AtomicLabelFormula const>(data.deadlockLabel.get());
651 newSubformula = std::make_shared<storm::logic::BinaryBooleanStateFormula const>(storm::logic::BinaryBooleanStateFormula::OperatorType::Or,
652 formula.getSubformula().asSharedPointer(), newSubSubformula);
653 }
654 auto newFormula = std::make_shared<storm::logic::EventuallyFormula>(newSubformula, storm::logic::FormulaContext::Reward);
655 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(newFormula, rewardModelName, opInfo);
656 std::vector<typename SparseModelType::ValueType> timeRewards;
657 if (data.model->isOfType(storm::models::ModelType::MarkovAutomaton)) {
658 timeRewards.assign(data.model->getNumberOfStates(), storm::utility::zero<typename SparseModelType::ValueType>());
660 timeRewards,
661 dynamic_cast<storm::models::sparse::MarkovAutomaton<typename SparseModelType::ValueType> const&>(*data.model).getMarkovianStates(),
663 } else {
664 timeRewards.assign(data.model->getNumberOfStates(), storm::utility::one<typename SparseModelType::ValueType>());
665 }
666 data.model->addRewardModel(rewardModelName, typename SparseModelType::RewardModelType(std::move(timeRewards)));
667 } else {
668 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException,
669 "The formula " << formula << " neither considers reachability probabilities nor reachability rewards "
670 << (data.model->isOfType(storm::models::ModelType::MarkovAutomaton) ? "nor reachability time" : "")
671 << ". This is not supported.");
672 }
673 }
674 data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true);
675}
676
677template<typename SparseModelType>
678void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessCumulativeRewardFormula(storm::logic::CumulativeRewardFormula const& formula,
679 storm::logic::OperatorInformation const& opInfo,
680 PreprocessorData& data,
681 boost::optional<std::string> const& optionalRewardModelName) {
682 STORM_LOG_THROW(data.model->isOfType(storm::models::ModelType::Mdp), storm::exceptions::InvalidPropertyException,
683 "Cumulative reward formulas are not supported for the given model type.");
684 std::string rewardModelName = optionalRewardModelName.get();
685 // Strip away potential RewardAccumulations in the formula itself but also in reward bounds
686 auto filteredRewards = storm::utility::createFilteredRewardModel(data.model->getRewardModel(rewardModelName), data.model->isDiscreteTimeModel(), formula);
687 if (filteredRewards.isDifferentFromUnfilteredModel()) {
688 rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
689 data.model->addRewardModel(rewardModelName, std::move(filteredRewards.extract()));
690 }
691 // Clear potential transition rewards.
692 auto& rewardModel = data.model->getRewardModel(rewardModelName);
693 rewardModel.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false);
694 STORM_LOG_ASSERT(!rewardModel.hasTransitionRewards(), "Expected no transition rewards after reducing to state-based rewards");
695
696 std::vector<storm::logic::TimeBoundReference> newTimeBoundReferences;
697 bool onlyRewardBounds = true;
698 for (uint64_t i = 0; i < formula.getDimension(); ++i) {
699 auto oldTbr = formula.getTimeBoundReference(i);
700 if (oldTbr.isRewardBound()) {
701 if (oldTbr.hasRewardAccumulation()) {
702 auto filteredBoundRewards = storm::utility::createFilteredRewardModel(data.model->getRewardModel(oldTbr.getRewardName()),
703 oldTbr.getRewardAccumulation(), data.model->isDiscreteTimeModel());
704 if (filteredBoundRewards.isDifferentFromUnfilteredModel()) {
705 std::string freshRewardModelName =
706 data.rewardModelNamePrefix + std::to_string(data.objectives.size()) + std::string("_" + std::to_string(i));
707 data.model->addRewardModel(freshRewardModelName, std::move(filteredBoundRewards.extract()));
708 newTimeBoundReferences.emplace_back(freshRewardModelName);
709 } else {
710 // Strip away the reward accumulation
711 newTimeBoundReferences.emplace_back(oldTbr.getRewardName());
712 }
713 } else {
714 newTimeBoundReferences.push_back(oldTbr);
715 }
716 } else {
717 onlyRewardBounds = false;
718 newTimeBoundReferences.push_back(oldTbr);
719 }
720 }
721
722 auto newFormula = std::make_shared<storm::logic::CumulativeRewardFormula>(formula.getBounds(), newTimeBoundReferences);
723 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(newFormula, rewardModelName, opInfo);
724
725 if (onlyRewardBounds) {
726 data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true);
727 }
728}
729
730template<typename SparseModelType>
731void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessTotalRewardFormula(storm::logic::TotalRewardFormula const& formula,
732 storm::logic::OperatorInformation const& opInfo, PreprocessorData& data,
733 boost::optional<std::string> const& optionalRewardModelName) {
734 std::string rewardModelName = optionalRewardModelName.get();
735 auto filteredRewards = storm::utility::createFilteredRewardModel(data.model->getRewardModel(rewardModelName), data.model->isDiscreteTimeModel(), formula);
736 if (filteredRewards.isDifferentFromUnfilteredModel()) {
737 rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
738 data.model->addRewardModel(rewardModelName, filteredRewards.extract());
739 }
740 // Reduce potential transition branch rewards to state-action rewards
741 auto& rewardModel = data.model->getRewardModel(rewardModelName);
742 rewardModel.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false);
743 STORM_LOG_ASSERT(!rewardModel.hasTransitionRewards(), "Expected no transition rewards after reducing to state-based rewards");
744
745 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(formula.stripRewardAccumulation(), rewardModelName, opInfo);
746 data.finiteRewardCheckObjectives.set(data.objectives.size() - 1, true);
747}
748
749template<typename SparseModelType>
750void SparseMultiObjectivePreprocessor<SparseModelType>::preprocessLongRunAverageRewardFormula(storm::logic::LongRunAverageRewardFormula const& formula,
751 storm::logic::OperatorInformation const& opInfo,
752 PreprocessorData& data,
753 boost::optional<std::string> const& optionalRewardModelName) {
754 std::string rewardModelName = optionalRewardModelName.get();
755 auto filteredRewards = storm::utility::createFilteredRewardModel(data.model->getRewardModel(rewardModelName), data.model->isDiscreteTimeModel(), formula);
756 if (filteredRewards.isDifferentFromUnfilteredModel()) {
757 std::string rewardModelName = data.rewardModelNamePrefix + std::to_string(data.objectives.size());
758 data.model->addRewardModel(rewardModelName, std::move(filteredRewards.extract()));
759 }
760 // Reduce potential transition branch rewards to state-action rewards
761 auto& rewardModel = data.model->getRewardModel(rewardModelName);
762 rewardModel.reduceToStateBasedRewards(data.model->getTransitionMatrix(), false);
763 STORM_LOG_ASSERT(!rewardModel.hasTransitionRewards(), "Expected no transition rewards after reducing to state-based rewards");
764
765 data.objectives.back()->formula = std::make_shared<storm::logic::RewardOperatorFormula>(formula.stripRewardAccumulation(), rewardModelName, opInfo);
766}
767
768template<typename SparseModelType>
769typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType SparseMultiObjectivePreprocessor<SparseModelType>::buildResult(
770 SparseModelType const& originalModel, storm::logic::MultiObjectiveFormula const& originalFormula, PreprocessorData& data) {
771 ReturnType result(originalFormula, originalModel);
772 auto backwardTransitions = data.model->getBackwardTransitions();
773 result.preprocessedModel = data.model;
774 result.memoryIncorporationReverseData = data.memoryIncorporationReverseData;
775
776 for (auto& obj : data.objectives) {
777 result.objectives.push_back(std::move(*obj));
778 }
779 result.queryType = getQueryType(result.objectives);
780 result.maybeInfiniteRewardObjectives = std::move(data.finiteRewardCheckObjectives);
781
782 return result;
783}
784
785template<typename SparseModelType>
786typename SparseMultiObjectivePreprocessor<SparseModelType>::ReturnType::QueryType SparseMultiObjectivePreprocessor<SparseModelType>::getQueryType(
787 std::vector<Objective<ValueType>> const& objectives) {
788 uint_fast64_t numOfObjectivesWithThreshold = 0;
789 for (auto& obj : objectives) {
790 if (obj.formula->hasBound()) {
791 ++numOfObjectivesWithThreshold;
792 }
793 }
794 if (numOfObjectivesWithThreshold == objectives.size()) {
795 return ReturnType::QueryType::Achievability;
796 } else if (numOfObjectivesWithThreshold + 1 == objectives.size()) {
797 // Note: We do not want to consider a Pareto query when the total number of objectives is one.
798 return ReturnType::QueryType::Quantitative;
799 } else if (numOfObjectivesWithThreshold == 0) {
800 return ReturnType::QueryType::Pareto;
801 } else {
802 STORM_LOG_THROW(false, storm::exceptions::InvalidPropertyException,
803 "Invalid Multi-objective query: The numer of qualitative objectives should be either 0 (Pareto query), 1 (quantitative query), or "
804 "#objectives (achievability query).");
805 }
806}
807
808template class SparseMultiObjectivePreprocessor<storm::models::sparse::Mdp<double>>;
809template class SparseMultiObjectivePreprocessor<storm::models::sparse::MarkovAutomaton<double>>;
810
811template class SparseMultiObjectivePreprocessor<storm::models::sparse::Mdp<storm::RationalNumber>>;
812template class SparseMultiObjectivePreprocessor<storm::models::sparse::MarkovAutomaton<storm::RationalNumber>>;
813} // namespace preprocessing
814} // namespace multiobjective
815} // namespace modelchecker
816} // 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:24
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
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:39
ValueType zero()
Definition constants.cpp:24
ValueType one()
Definition constants.cpp:19
boost::optional< Bound > bound
boost::optional< storm::solver::OptimizationDirection > optimalityType