Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
DdPrismModelBuilder.cpp
Go to the documentation of this file.
2
3#include <boost/algorithm/string/join.hpp>
4
9
11
15
16#include "storm/utility/dd.h"
17#include "storm/utility/math.h"
18#include "storm/utility/prism.h"
19
21
28
30
32
33namespace storm {
34namespace builder {
35
36template<storm::dd::DdType Type, typename ValueType>
37class ParameterCreator {
38 public:
39 void create(storm::prism::Program const& /*program*/, storm::adapters::AddExpressionAdapter<Type, ValueType>& /*rowExpressionAdapter*/) {
40 // Intentionally left empty: no support for parameters for this data type.
41 }
42
43 std::set<storm::RationalFunctionVariable> const& getParameters() const {
44 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Creating parameters for non-parametric model is not supported.");
45 }
46
47 private:
48};
49
50template<storm::dd::DdType Type>
52 public:
53 ParameterCreator() : cache(std::make_shared<storm::RawPolynomialCache>()) {
54 // Intentionally left empty.
55 }
56
58 for (auto const& constant : program.getConstants()) {
59 if (!constant.isDefined()) {
60 storm::RationalFunctionVariable carlVariable = storm::createRFVariable(constant.getExpressionVariable().getName());
61 parameters.insert(carlVariable);
62 auto rf = convertVariableToPolynomial(carlVariable);
63 rowExpressionAdapter.setValue(constant.getExpressionVariable(), rf);
64 }
65 }
66 }
68 template<typename RationalFunctionType = storm::RationalFunction, typename TP = typename RationalFunctionType::PolyType,
69 carl::EnableIf<carl::needs_cache<TP>> = carl::dummy>
70 RationalFunctionType convertVariableToPolynomial(storm::RationalFunctionVariable const& variable) {
71 return RationalFunctionType(typename RationalFunctionType::PolyType(typename RationalFunctionType::PolyType::PolyType(variable), cache));
72 }
73
74 template<typename RationalFunctionType = storm::RationalFunction, typename TP = typename RationalFunctionType::PolyType,
75 carl::DisableIf<carl::needs_cache<TP>> = carl::dummy>
76 RationalFunctionType convertVariableToPolynomial(storm::RationalFunctionVariable const& variable) {
77 return RationalFunctionType(variable);
78 }
79
80 std::set<storm::RationalFunctionVariable> const& getParameters() const {
81 return parameters;
82 }
83
84 private:
85 // A mapping from our variables to carl's.
86 std::unordered_map<storm::expressions::Variable, storm::RationalFunctionVariable> variableToVariableMap;
87
88 // The cache that is used in case the underlying type needs a cache.
89 std::shared_ptr<storm::RawPolynomialCache> cache;
90
91 // All created parameters.
92 std::set<storm::RationalFunctionVariable> parameters;
93};
94
95template<storm::dd::DdType Type, typename ValueType>
97 public:
98 GenerationInformation(storm::prism::Program const& program, std::shared_ptr<storm::dd::DdManager<Type>> const& manager)
99 : program(program),
100 manager(manager),
101 rowMetaVariables(),
102 variableToRowMetaVariableMap(std::make_shared<std::map<storm::expressions::Variable, storm::expressions::Variable>>()),
103 rowExpressionAdapter(std::make_shared<storm::adapters::AddExpressionAdapter<Type, ValueType>>(manager, variableToRowMetaVariableMap)),
104 columnMetaVariables(),
105 variableToColumnMetaVariableMap((std::make_shared<std::map<storm::expressions::Variable, storm::expressions::Variable>>())),
106 rowColumnMetaVariablePairs(),
107 nondeterminismMetaVariables(),
108 variableToIdentityMap(),
109 allGlobalVariables(),
110 moduleToIdentityMap(),
111 parameters() {
112 // Initializes variables and identity DDs.
113 createMetaVariablesAndIdentities();
114
115 // Initialize the parameters (if any).
116 ParameterCreator<Type, ValueType> parameterCreator;
117 parameterCreator.create(this->program, *this->rowExpressionAdapter);
118 if (std::is_same<ValueType, storm::RationalFunction>::value) {
119 this->parameters = parameterCreator.getParameters();
120 }
121 }
122
123 // The program that is currently translated.
125
126 // The manager used to build the decision diagrams.
127 std::shared_ptr<storm::dd::DdManager<Type>> manager;
128
129 // The meta variables for the row encoding.
130 std::set<storm::expressions::Variable> rowMetaVariables;
131 std::shared_ptr<std::map<storm::expressions::Variable, storm::expressions::Variable>> variableToRowMetaVariableMap;
132 std::shared_ptr<storm::adapters::AddExpressionAdapter<Type, ValueType>> rowExpressionAdapter;
133
134 // The meta variables for the column encoding.
135 std::set<storm::expressions::Variable> columnMetaVariables;
136 std::shared_ptr<std::map<storm::expressions::Variable, storm::expressions::Variable>> variableToColumnMetaVariableMap;
137
138 // All pairs of row/column meta variables.
139 std::vector<std::pair<storm::expressions::Variable, storm::expressions::Variable>> rowColumnMetaVariablePairs;
140
141 // The meta variables used to encode the nondeterminism.
142 std::vector<storm::expressions::Variable> nondeterminismMetaVariables;
143
144 // The meta variables used to encode the synchronization.
145 std::vector<storm::expressions::Variable> synchronizationMetaVariables;
146
147 // A set of all variables used for encoding the nondeterminism (i.e. nondetermism + synchronization
148 // variables). This is handy to abstract from this variable set.
149 std::set<storm::expressions::Variable> allNondeterminismVariables;
150
151 // As set of all variables used for encoding the synchronization.
152 std::set<storm::expressions::Variable> allSynchronizationMetaVariables;
153
154 // DDs representing the identity for each variable.
155 std::map<storm::expressions::Variable, storm::dd::Add<Type, ValueType>> variableToIdentityMap;
156
157 // A set of all meta variables that correspond to global variables.
158 std::set<storm::expressions::Variable> allGlobalVariables;
159
160 // DDs representing the identity for each module.
161 std::map<std::string, storm::dd::Add<Type, ValueType>> moduleToIdentityMap;
162
163 // DDs representing the valid ranges of the variables of each module.
164 std::map<std::string, storm::dd::Add<Type, ValueType>> moduleToRangeMap;
165
166 // The parameters appearing in the model.
167 std::set<storm::RationalFunctionVariable> parameters;
168
169 private:
173 void createMetaVariablesAndIdentities() {
174 // Add synchronization variables.
175 for (auto const& actionIndex : program.getSynchronizingActionIndices()) {
176 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(program.getActionName(actionIndex));
177 synchronizationMetaVariables.push_back(variablePair.first);
178 allSynchronizationMetaVariables.insert(variablePair.first);
179 allNondeterminismVariables.insert(variablePair.first);
180 }
181
182 // Add nondeterminism variables (number of modules + number of commands).
183 uint_fast64_t numberOfNondeterminismVariables = program.getModules().size();
184 for (auto const& module : program.getModules()) {
185 numberOfNondeterminismVariables += module.getNumberOfCommands();
186 }
187 for (uint_fast64_t i = 0; i < numberOfNondeterminismVariables; ++i) {
188 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable("nondet" + std::to_string(i));
189 nondeterminismMetaVariables.push_back(variablePair.first);
190 allNondeterminismVariables.insert(variablePair.first);
191 }
192
193 // Create meta variables for global program variables.
194 for (storm::prism::IntegerVariable const& integerVariable : program.getGlobalIntegerVariables()) {
195 int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
196 int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
197 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(integerVariable.getName(), low, high);
198
199 STORM_LOG_TRACE("Created meta variables for global integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex()
200 << "] and " << variablePair.second.getName() << "["
201 << variablePair.second.getIndex() << "]");
202
203 rowMetaVariables.insert(variablePair.first);
204 variableToRowMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.first);
205
206 columnMetaVariables.insert(variablePair.second);
207 variableToColumnMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.second);
208
209 storm::dd::Bdd<Type> variableIdentity = manager->getIdentity(variablePair.first, variablePair.second);
210 variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
211 rowColumnMetaVariablePairs.push_back(variablePair);
212
213 allGlobalVariables.insert(integerVariable.getExpressionVariable());
214 }
215 for (storm::prism::BooleanVariable const& booleanVariable : program.getGlobalBooleanVariables()) {
216 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(booleanVariable.getName());
217
218 STORM_LOG_TRACE("Created meta variables for global boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex()
219 << "] and " << variablePair.second.getName() << "["
220 << variablePair.second.getIndex() << "]");
221
222 rowMetaVariables.insert(variablePair.first);
223 variableToRowMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.first);
224
225 columnMetaVariables.insert(variablePair.second);
226 variableToColumnMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.second);
227
228 storm::dd::Bdd<Type> variableIdentity = manager->getIdentity(variablePair.first, variablePair.second);
229 variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
230
231 rowColumnMetaVariablePairs.push_back(variablePair);
232 allGlobalVariables.insert(booleanVariable.getExpressionVariable());
233 }
234
235 // Create meta variables for each of the modules' variables.
236 for (storm::prism::Module const& module : program.getModules()) {
237 storm::dd::Bdd<Type> moduleIdentity = manager->getBddOne();
238 storm::dd::Bdd<Type> moduleRange = manager->getBddOne();
239
240 for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) {
241 int_fast64_t low = integerVariable.getLowerBoundExpression().evaluateAsInt();
242 int_fast64_t high = integerVariable.getUpperBoundExpression().evaluateAsInt();
243 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair =
244 manager->addMetaVariable(integerVariable.getName(), low, high);
245 STORM_LOG_TRACE("Created meta variables for integer variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex()
246 << "] and " << variablePair.second.getName() << "["
247 << variablePair.second.getIndex() << "]");
248
249 rowMetaVariables.insert(variablePair.first);
250 variableToRowMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.first);
251
252 columnMetaVariables.insert(variablePair.second);
253 variableToColumnMetaVariableMap->emplace(integerVariable.getExpressionVariable(), variablePair.second);
254
255 storm::dd::Bdd<Type> variableIdentity = manager->getIdentity(variablePair.first, variablePair.second);
256 variableToIdentityMap.emplace(integerVariable.getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
257 moduleIdentity &= variableIdentity;
258 moduleRange &= manager->getRange(variablePair.first);
259
260 rowColumnMetaVariablePairs.push_back(variablePair);
261 }
262 for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) {
263 std::pair<storm::expressions::Variable, storm::expressions::Variable> variablePair = manager->addMetaVariable(booleanVariable.getName());
264 STORM_LOG_TRACE("Created meta variables for boolean variable: " << variablePair.first.getName() << "[" << variablePair.first.getIndex()
265 << "] and " << variablePair.second.getName() << "["
266 << variablePair.second.getIndex() << "]");
267
268 rowMetaVariables.insert(variablePair.first);
269 variableToRowMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.first);
270
271 columnMetaVariables.insert(variablePair.second);
272 variableToColumnMetaVariableMap->emplace(booleanVariable.getExpressionVariable(), variablePair.second);
273
274 storm::dd::Bdd<Type> variableIdentity = manager->getIdentity(variablePair.first, variablePair.second);
275 variableToIdentityMap.emplace(booleanVariable.getExpressionVariable(), variableIdentity.template toAdd<ValueType>());
276 moduleIdentity &= variableIdentity;
277 moduleRange &= manager->getRange(variablePair.first);
278
279 rowColumnMetaVariablePairs.push_back(variablePair);
280 }
281 moduleToIdentityMap[module.getName()] = moduleIdentity.template toAdd<ValueType>();
282 moduleToRangeMap[module.getName()] = moduleRange.template toAdd<ValueType>();
283 }
284 }
285};
286
287template<storm::dd::DdType Type, typename ValueType>
289 public:
290 ModuleComposer(typename DdPrismModelBuilder<Type, ValueType>::GenerationInformation& generationInfo) : generationInfo(generationInfo) {
291 // Intentionally left empty.
292 }
293
295 return boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(
296 composition.accept(*this, newSynchronizingActionToOffsetMap()));
297 }
298
299 std::map<uint_fast64_t, uint_fast64_t> newSynchronizingActionToOffsetMap() const {
300 std::map<uint_fast64_t, uint_fast64_t> result;
301 for (auto const& actionIndex : generationInfo.program.getSynchronizingActionIndices()) {
302 result[actionIndex] = 0;
303 }
304 return result;
305 }
306
308 std::map<uint_fast64_t, uint_fast64_t> const& oldMapping) const {
309 std::map<uint_fast64_t, uint_fast64_t> result = oldMapping;
310 for (auto const& action : sub.synchronizingActionToDecisionDiagramMap) {
311 result[action.first] = action.second.numberOfUsedNondeterminismVariables;
312 }
313 return result;
314 }
315
316 virtual boost::any visit(storm::prism::ModuleComposition const& composition, boost::any const& data) override {
317 STORM_LOG_TRACE("Translating module '" << composition.getModuleName() << "'.");
318 std::map<uint_fast64_t, uint_fast64_t> const& synchronizingActionToOffsetMap = boost::any_cast<std::map<uint_fast64_t, uint_fast64_t> const&>(data);
319
321 generationInfo, generationInfo.program.getModule(composition.getModuleName()), synchronizingActionToOffsetMap);
322
323 return result;
324 }
325
326 virtual boost::any visit(storm::prism::RenamingComposition const& composition, boost::any const& data) override {
327 // Create the mapping from action indices to action indices.
328 std::map<uint_fast64_t, uint_fast64_t> renaming;
329 for (auto const& namePair : composition.getActionRenaming()) {
330 STORM_LOG_THROW(generationInfo.program.hasAction(namePair.first), storm::exceptions::InvalidArgumentException,
331 "Composition refers to unknown action '" << namePair.first << "'.");
332 STORM_LOG_THROW(generationInfo.program.hasAction(namePair.second), storm::exceptions::InvalidArgumentException,
333 "Composition refers to unknown action '" << namePair.second << "'.");
334 renaming.emplace(generationInfo.program.getActionIndex(namePair.first), generationInfo.program.getActionIndex(namePair.second));
335 }
336
337 // Prepare the new offset mapping.
338 std::map<uint_fast64_t, uint_fast64_t> const& synchronizingActionToOffsetMap = boost::any_cast<std::map<uint_fast64_t, uint_fast64_t> const&>(data);
339 std::map<uint_fast64_t, uint_fast64_t> newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap;
340 for (auto const& indexPair : renaming) {
341 auto it = synchronizingActionToOffsetMap.find(indexPair.second);
342 STORM_LOG_THROW(it != synchronizingActionToOffsetMap.end(), storm::exceptions::InvalidArgumentException,
343 "Invalid action index " << indexPair.second << ".");
344 newSynchronizingActionToOffsetMap[indexPair.first] = it->second;
345 }
346
347 // Then, we translate the subcomposition.
349 boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(
350 composition.getSubcomposition().accept(*this, newSynchronizingActionToOffsetMap));
351
352 // Perform the renaming and return result.
353 return rename(sub, renaming);
354 }
355
356 virtual boost::any visit(storm::prism::HidingComposition const& composition, boost::any const& data) override {
357 // Create the mapping from action indices to action indices.
358 std::set<uint_fast64_t> actionIndicesToHide;
359 for (auto const& action : composition.getActionsToHide()) {
360 STORM_LOG_THROW(generationInfo.program.hasAction(action), storm::exceptions::InvalidArgumentException,
361 "Composition refers to unknown action '" << action << "'.");
362 actionIndicesToHide.insert(generationInfo.program.getActionIndex(action));
363 }
364
365 // Prepare the new offset mapping.
366 std::map<uint_fast64_t, uint_fast64_t> const& synchronizingActionToOffsetMap = boost::any_cast<std::map<uint_fast64_t, uint_fast64_t> const&>(data);
367 std::map<uint_fast64_t, uint_fast64_t> newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap;
368 for (auto const& index : actionIndicesToHide) {
369 newSynchronizingActionToOffsetMap[index] = 0;
370 }
371
372 // Then, we translate the subcomposition.
374 boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(
375 composition.getSubcomposition().accept(*this, newSynchronizingActionToOffsetMap));
376
377 // Perform the hiding and return result.
378 hide(sub, actionIndicesToHide);
379 return sub;
380 }
381
382 virtual boost::any visit(storm::prism::SynchronizingParallelComposition const& composition, boost::any const& data) override {
383 // First, we translate the subcompositions.
385 boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data));
386
387 // Prepare the new offset mapping.
388 std::map<uint_fast64_t, uint_fast64_t> const& synchronizingActionToOffsetMap = boost::any_cast<std::map<uint_fast64_t, uint_fast64_t> const&>(data);
389 std::map<uint_fast64_t, uint_fast64_t> newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap;
390 for (auto const& action : left.synchronizingActionToDecisionDiagramMap) {
391 newSynchronizingActionToOffsetMap[action.first] = action.second.numberOfUsedNondeterminismVariables;
392 }
393
395 boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(
396 composition.getRightSubcomposition().accept(*this, newSynchronizingActionToOffsetMap));
397
398 // Then, determine the action indices on which we need to synchronize.
399 std::set<uint_fast64_t> leftSynchronizationActionIndices = left.getSynchronizingActionIndices();
400 std::set<uint_fast64_t> rightSynchronizationActionIndices = right.getSynchronizingActionIndices();
401 std::set<uint_fast64_t> synchronizationActionIndices;
402 std::set_intersection(leftSynchronizationActionIndices.begin(), leftSynchronizationActionIndices.end(), rightSynchronizationActionIndices.begin(),
403 rightSynchronizationActionIndices.end(), std::inserter(synchronizationActionIndices, synchronizationActionIndices.begin()));
404
405 // Finally, we compose the subcompositions to create the result.
406 composeInParallel(left, right, synchronizationActionIndices);
407 return left;
408 }
409
410 virtual boost::any visit(storm::prism::InterleavingParallelComposition const& composition, boost::any const& data) override {
411 // First, we translate the subcompositions.
413 boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data));
414
416 boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.getRightSubcomposition().accept(*this, data));
417
418 // Finally, we compose the subcompositions to create the result.
419 composeInParallel(left, right, std::set<uint_fast64_t>());
420 return left;
421 }
422
423 virtual boost::any visit(storm::prism::RestrictedParallelComposition const& composition, boost::any const& data) override {
424 // Construct the synchronizing action indices from the synchronizing action names.
425 std::set<uint_fast64_t> synchronizingActionIndices;
426 for (auto const& action : composition.getSynchronizingActions()) {
427 synchronizingActionIndices.insert(generationInfo.program.getActionIndex(action));
428 }
429
430 // Then, we translate the subcompositions.
432 boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(composition.getLeftSubcomposition().accept(*this, data));
433
434 // Prepare the new offset mapping.
435 std::map<uint_fast64_t, uint_fast64_t> const& synchronizingActionToOffsetMap = boost::any_cast<std::map<uint_fast64_t, uint_fast64_t> const&>(data);
436 std::map<uint_fast64_t, uint_fast64_t> newSynchronizingActionToOffsetMap = synchronizingActionToOffsetMap;
437 for (auto const& actionIndex : synchronizingActionIndices) {
438 auto it = left.synchronizingActionToDecisionDiagramMap.find(actionIndex);
439 if (it != left.synchronizingActionToDecisionDiagramMap.end()) {
440 newSynchronizingActionToOffsetMap[actionIndex] = it->second.numberOfUsedNondeterminismVariables;
441 }
442 }
443
445 boost::any_cast<typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram>(
446 composition.getRightSubcomposition().accept(*this, newSynchronizingActionToOffsetMap));
447
448 std::set<uint_fast64_t> leftSynchronizationActionIndices = left.getSynchronizingActionIndices();
449 bool isContainedInLeft = std::includes(leftSynchronizationActionIndices.begin(), leftSynchronizationActionIndices.end(),
450 synchronizingActionIndices.begin(), synchronizingActionIndices.end());
451 STORM_LOG_WARN_COND(isContainedInLeft,
452 "Left subcomposition of composition '" << composition << "' does not include all actions over which to synchronize.");
453
454 std::set<uint_fast64_t> rightSynchronizationActionIndices = right.getSynchronizingActionIndices();
455 bool isContainedInRight = std::includes(rightSynchronizationActionIndices.begin(), rightSynchronizationActionIndices.end(),
456 synchronizingActionIndices.begin(), synchronizingActionIndices.end());
457 STORM_LOG_WARN_COND(isContainedInRight,
458 "Right subcomposition of composition '" << composition << "' does not include all actions over which to synchronize.");
459
460 // Finally, we compose the subcompositions to create the result.
461 composeInParallel(left, right, synchronizingActionIndices);
462 return left;
463 }
464
465 private:
470 void hide(typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& sub, std::set<uint_fast64_t> const& actionIndicesToHide) const {
471 STORM_LOG_TRACE("Hiding actions.");
472
473 for (auto const& actionIndex : actionIndicesToHide) {
474 auto it = sub.synchronizingActionToDecisionDiagramMap.find(actionIndex);
475 if (it != sub.synchronizingActionToDecisionDiagramMap.end()) {
476 sub.independentAction = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, sub.independentAction, it->second);
477 sub.numberOfUsedNondeterminismVariables =
478 std::max(sub.numberOfUsedNondeterminismVariables, sub.independentAction.numberOfUsedNondeterminismVariables);
479 sub.synchronizingActionToDecisionDiagramMap.erase(it);
480 }
481 }
482 }
483
487 typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram rename(typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& sub,
488 std::map<uint_fast64_t, uint_fast64_t> const& renaming) const {
489 STORM_LOG_TRACE("Renaming actions.");
490 std::map<uint_fast64_t, typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram> actionIndexToDdMap;
491
492 // Go through all action DDs with a synchronizing label and rename them if they appear in the renaming.
493 for (auto& action : sub.synchronizingActionToDecisionDiagramMap) {
494 auto renamingIt = renaming.find(action.first);
495 if (renamingIt != renaming.end()) {
496 // If the action is to be renamed and an action with the target index already exists, we need
497 // to combine the action DDs.
498 auto itNewActions = actionIndexToDdMap.find(renamingIt->second);
499 if (itNewActions != actionIndexToDdMap.end()) {
500 actionIndexToDdMap[renamingIt->second] =
501 DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, action.second, itNewActions->second);
502
503 } else {
504 // In this case, we can simply copy the action over.
505 actionIndexToDdMap[renamingIt->second] = action.second;
506 }
507 } else {
508 // If the action is not to be renamed, we need to copy it over. However, if some other action
509 // was renamed to the very same action name before, we need to combine the transitions.
510 auto itNewActions = actionIndexToDdMap.find(action.first);
511 if (itNewActions != actionIndexToDdMap.end()) {
512 actionIndexToDdMap[action.first] =
513 DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, action.second, itNewActions->second);
514 } else {
515 // In this case, we can simply copy the action over.
516 actionIndexToDdMap[action.first] = action.second;
517 }
518 }
519 }
520
521 return typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram(sub.independentAction, actionIndexToDdMap, sub.identity,
522 sub.numberOfUsedNondeterminismVariables);
523 }
524
529 void composeInParallel(typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& left,
530 typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram& right,
531 std::set<uint_fast64_t> const& synchronizationActionIndices) const {
532 STORM_LOG_TRACE("Composing two modules.");
533
534 // Combine the tau action.
535 uint_fast64_t numberOfUsedNondeterminismVariables = right.independentAction.numberOfUsedNondeterminismVariables;
536 left.independentAction = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, left.independentAction,
537 right.independentAction, left.identity, right.identity);
538 numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, left.independentAction.numberOfUsedNondeterminismVariables);
539
540 // Create an empty action for the case where one of the modules does not have a certain action.
541 typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram emptyAction(*generationInfo.manager);
542
543 // Treat all non-tau actions of the left module.
544 for (auto& action : left.synchronizingActionToDecisionDiagramMap) {
545 // If we need to synchronize over this action index, we try to do so now.
546 if (synchronizationActionIndices.find(action.first) != synchronizationActionIndices.end()) {
547 // If we are to synchronize over an action that does not exist in the second module, the result
548 // is that the synchronization is the empty action.
549 if (!right.hasSynchronizingAction(action.first)) {
550 action.second = emptyAction;
551 } else {
552 // Otherwise, the actions of the modules are synchronized.
553 action.second = DdPrismModelBuilder<Type, ValueType>::combineSynchronizingActions(
554 action.second, right.synchronizingActionToDecisionDiagramMap[action.first]);
555 }
556 } else {
557 // If we don't synchronize over this action, we need to construct the interleaving.
558
559 // If both modules contain the action, we need to mutually multiply the other identity.
560 if (right.hasSynchronizingAction(action.first)) {
561 action.second = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(
562 generationInfo, action.second, right.synchronizingActionToDecisionDiagramMap[action.first], left.identity, right.identity);
563 } else {
564 // If only the first module has this action, we need to use a dummy action decision diagram
565 // for the second module.
566 action.second = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(generationInfo, action.second, emptyAction,
567 left.identity, right.identity);
568 }
569 }
570 numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, action.second.numberOfUsedNondeterminismVariables);
571 }
572
573 // Treat all non-tau actions of the right module.
574 for (auto const& actionIndex : right.getSynchronizingActionIndices()) {
575 // Here, we only need to treat actions that the first module does not have, because we have handled
576 // this case earlier.
577 if (!left.hasSynchronizingAction(actionIndex)) {
578 if (synchronizationActionIndices.find(actionIndex) != synchronizationActionIndices.end()) {
579 // If we are to synchronize over this action that does not exist in the first module, the
580 // result is that the synchronization is the empty action.
581 left.synchronizingActionToDecisionDiagramMap[actionIndex] = emptyAction;
582 } else {
583 // If only the second module has this action, we need to use a dummy action decision diagram
584 // for the first module.
585 left.synchronizingActionToDecisionDiagramMap[actionIndex] = DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(
586 generationInfo, emptyAction, right.synchronizingActionToDecisionDiagramMap[actionIndex], left.identity, right.identity);
587 }
588 }
589 numberOfUsedNondeterminismVariables =
590 std::max(numberOfUsedNondeterminismVariables, left.synchronizingActionToDecisionDiagramMap[actionIndex].numberOfUsedNondeterminismVariables);
591 }
592
593 // Combine identity matrices.
594 left.identity = left.identity * right.identity;
595
596 // Keep track of the number of nondeterminism variables used.
597 left.numberOfUsedNondeterminismVariables = std::max(left.numberOfUsedNondeterminismVariables, numberOfUsedNondeterminismVariables);
598 }
599
600 typename DdPrismModelBuilder<Type, ValueType>::GenerationInformation& generationInfo;
601};
602
603template<storm::dd::DdType Type, typename ValueType>
607
608template<storm::dd::DdType Type, typename ValueType>
610 : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(), terminalStates() {
611 // Intentionally left empty.
612}
613
614template<storm::dd::DdType Type, typename ValueType>
616 : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild(std::set<std::string>()) {
617 this->preserveFormula(formula);
618 this->setTerminalStatesFromFormula(formula);
619}
620
621template<storm::dd::DdType Type, typename ValueType>
622DdPrismModelBuilder<Type, ValueType>::Options::Options(std::vector<std::shared_ptr<storm::logic::Formula const>> const& formulas)
623 : buildAllRewardModels(false), rewardModelsToBuild(), buildAllLabels(false), labelsToBuild() {
624 for (auto const& formula : formulas) {
625 this->preserveFormula(*formula);
626 }
627 if (formulas.size() == 1) {
628 this->setTerminalStatesFromFormula(*formulas.front());
629 }
630}
631
632template<storm::dd::DdType Type, typename ValueType>
634 // If we already had terminal states, we need to erase them.
635 terminalStates.clear();
636
637 // If we are not required to build all reward models, we determine the reward models we need to build.
638 if (!buildAllRewardModels) {
639 std::set<std::string> referencedRewardModels = formula.getReferencedRewardModels();
640 rewardModelsToBuild.insert(referencedRewardModels.begin(), referencedRewardModels.end());
641 }
642
643 // Extract all the labels used in the formula.
644 std::vector<std::shared_ptr<storm::logic::AtomicLabelFormula const>> atomicLabelFormulas = formula.getAtomicLabelFormulas();
645 for (auto const& formula : atomicLabelFormulas) {
646 if (!labelsToBuild) {
647 labelsToBuild = std::set<std::string>();
648 }
649 labelsToBuild.get().insert(formula.get()->getLabel());
650 }
651}
652
653template<storm::dd::DdType Type, typename ValueType>
657
658template<storm::dd::DdType Type, typename ValueType>
659struct DdPrismModelBuilder<Type, ValueType>::SystemResult {
661 boost::optional<storm::dd::Add<Type, ValueType>> const& stateActionDd)
662 : allTransitionsDd(allTransitionsDd), globalModule(globalModule), stateActionDd(stateActionDd) {
663 // Intentionally left empty.
664 }
665
668 boost::optional<storm::dd::Add<Type, ValueType>> stateActionDd;
669};
670
671template<storm::dd::DdType Type, typename ValueType>
673 GenerationInformation& generationInfo, storm::prism::Module const& module, storm::dd::Add<Type, ValueType> const& guard,
674 storm::prism::Update const& update) {
675 storm::dd::Add<Type, ValueType> updateDd = generationInfo.manager->template getAddOne<ValueType>();
676
677 STORM_LOG_TRACE("Translating update " << update);
678
679 // Iterate over all assignments (boolean and integer) and build the DD for it.
680 std::vector<storm::prism::Assignment> assignments = update.getAssignments();
681 std::set<storm::expressions::Variable> assignedVariables;
682 for (auto const& assignment : assignments) {
683 // Record the variable as being written.
684 STORM_LOG_TRACE("Assigning to variable " << generationInfo.variableToRowMetaVariableMap->at(assignment.getVariable()).getName());
685 assignedVariables.insert(assignment.getVariable());
686
687 // Translate the written variable.
688 auto const& primedMetaVariable = generationInfo.variableToColumnMetaVariableMap->at(assignment.getVariable());
689 storm::dd::Add<Type, ValueType> writtenVariable = generationInfo.manager->template getIdentity<ValueType>(primedMetaVariable);
690
691 // Translate the expression that is being assigned.
692 storm::dd::Add<Type, ValueType> updateExpression = generationInfo.rowExpressionAdapter->translateExpression(assignment.getExpression());
693
694 // Combine the update expression with the guard.
695 storm::dd::Add<Type, ValueType> result = updateExpression * guard;
696
697 // Combine the variable and the assigned expression.
699 result = result.equals(writtenVariable).template toAdd<ValueType>();
700 result *= guard;
701
702 // Restrict the transitions to the range of the written variable.
703 result = result * generationInfo.manager->getRange(primedMetaVariable).template toAdd<ValueType>();
704
705 updateDd *= result;
706 }
707
708 // Compute the set of assigned global variables.
709 std::set<storm::expressions::Variable> assignedGlobalVariables;
710 std::set_intersection(assignedVariables.begin(), assignedVariables.end(), generationInfo.allGlobalVariables.begin(),
711 generationInfo.allGlobalVariables.end(), std::inserter(assignedGlobalVariables, assignedGlobalVariables.begin()));
712
713 // All unassigned boolean variables need to keep their value.
714 for (storm::prism::BooleanVariable const& booleanVariable : module.getBooleanVariables()) {
715 if (assignedVariables.find(booleanVariable.getExpressionVariable()) == assignedVariables.end()) {
716 STORM_LOG_TRACE("Multiplying identity of variable " << booleanVariable.getName());
717 updateDd *= generationInfo.variableToIdentityMap.at(booleanVariable.getExpressionVariable());
718 }
719 }
720
721 // All unassigned integer variables need to keep their value.
722 for (storm::prism::IntegerVariable const& integerVariable : module.getIntegerVariables()) {
723 if (assignedVariables.find(integerVariable.getExpressionVariable()) == assignedVariables.end()) {
724 STORM_LOG_TRACE("Multiplying identity of variable " << integerVariable.getName());
725 updateDd *= generationInfo.variableToIdentityMap.at(integerVariable.getExpressionVariable());
726 }
727 }
728
729 return UpdateDecisionDiagram(updateDd, assignedGlobalVariables);
730}
731
732template<storm::dd::DdType Type, typename ValueType>
733typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::createCommandDecisionDiagram(
734 GenerationInformation& generationInfo, storm::prism::Module const& module, storm::prism::Command const& command) {
735 STORM_LOG_TRACE("Translating guard " << command.getGuardExpression());
736 storm::dd::Bdd<Type> guard = generationInfo.rowExpressionAdapter->translateBooleanExpression(command.getGuardExpression()) &&
737 generationInfo.moduleToRangeMap[module.getName()].notZero();
738 STORM_LOG_WARN_COND(!guard.isZero(), "The guard '" << command.getGuardExpression() << "' is unsatisfiable.");
739
740 if (!guard.isZero()) {
741 // Create the DDs representing the individual updates.
742 std::vector<UpdateDecisionDiagram> updateResults;
743 for (storm::prism::Update const& update : command.getUpdates()) {
744 updateResults.push_back(createUpdateDecisionDiagram(generationInfo, module, guard.template toAdd<ValueType>(), update));
745
746 STORM_LOG_WARN_COND(!updateResults.back().updateDd.isZero(), "Update '" << update << "' does not have any effect.");
747 }
748
749 // Start by gathering all variables that were written in at least one update.
750 std::set<storm::expressions::Variable> globalVariablesInSomeUpdate;
751
752 // If the command is labeled, we have to analyze which portion of the global variables was written by
753 // any of the updates and make all update results equal w.r.t. this set. If the command is not labeled,
754 // we can already multiply the identities of all global variables.
755 if (command.isLabeled()) {
756 std::for_each(updateResults.begin(), updateResults.end(), [&globalVariablesInSomeUpdate](UpdateDecisionDiagram const& update) {
757 globalVariablesInSomeUpdate.insert(update.assignedGlobalVariables.begin(), update.assignedGlobalVariables.end());
758 });
759 } else {
760 globalVariablesInSomeUpdate = generationInfo.allGlobalVariables;
761 }
762
763 // Then, multiply the missing identities.
764 for (auto& updateResult : updateResults) {
765 std::set<storm::expressions::Variable> missingIdentities;
766 std::set_difference(globalVariablesInSomeUpdate.begin(), globalVariablesInSomeUpdate.end(), updateResult.assignedGlobalVariables.begin(),
767 updateResult.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin()));
768
769 for (auto const& variable : missingIdentities) {
770 STORM_LOG_TRACE("Multiplying identity for variable " << variable.getName() << "[" << variable.getIndex() << "] to update.");
771 updateResult.updateDd *= generationInfo.variableToIdentityMap.at(variable);
772 }
773 }
774
775 // Now combine the update DDs to the command DD.
776 storm::dd::Add<Type, ValueType> commandDd = generationInfo.manager->template getAddZero<ValueType>();
777 auto updateResultsIt = updateResults.begin();
778 for (auto updateIt = command.getUpdates().begin(), updateIte = command.getUpdates().end(); updateIt != updateIte; ++updateIt, ++updateResultsIt) {
779 storm::dd::Add<Type, ValueType> probabilityDd = generationInfo.rowExpressionAdapter->translateExpression(updateIt->getLikelihoodExpression());
780 commandDd += updateResultsIt->updateDd * probabilityDd;
781 }
782
783 return ActionDecisionDiagram(guard, guard.template toAdd<ValueType>() * commandDd, globalVariablesInSomeUpdate);
784 } else {
785 return ActionDecisionDiagram(*generationInfo.manager);
786 }
787}
788
789template<storm::dd::DdType Type, typename ValueType>
790typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::createActionDecisionDiagram(
791 GenerationInformation& generationInfo, storm::prism::Module const& module, uint_fast64_t synchronizationActionIndex,
792 uint_fast64_t nondeterminismVariableOffset) {
793 std::vector<ActionDecisionDiagram> commandDds;
794 for (storm::prism::Command const& command : module.getCommands()) {
795 // Determine whether the command is relevant for the selected action.
796 bool relevant = (synchronizationActionIndex == 0 && !command.isLabeled()) ||
797 (synchronizationActionIndex && command.isLabeled() && command.getActionIndex() == synchronizationActionIndex);
798
799 if (!relevant) {
800 continue;
801 }
802
803 STORM_LOG_TRACE("Translating command " << command);
804
805 // At this point, the command is known to be relevant for the action.
806 commandDds.push_back(createCommandDecisionDiagram(generationInfo, module, command));
807 }
808
809 ActionDecisionDiagram result(*generationInfo.manager);
810 if (!commandDds.empty()) {
811 switch (generationInfo.program.getModelType()) {
814 result = combineCommandsToActionMarkovChain(generationInfo, commandDds);
815 break;
817 result = combineCommandsToActionMDP(generationInfo, commandDds, nondeterminismVariableOffset);
818 break;
819 default:
820 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot translate model of this type.");
821 }
822 }
823
824 return result;
825}
826
827template<storm::dd::DdType Type, typename ValueType>
828std::set<storm::expressions::Variable> DdPrismModelBuilder<Type, ValueType>::equalizeAssignedGlobalVariables(GenerationInformation const& generationInfo,
829 ActionDecisionDiagram& action1,
830 ActionDecisionDiagram& action2) {
831 // Start by gathering all variables that were written in at least one action DD.
832 std::set<storm::expressions::Variable> globalVariablesInActionDd;
833 std::set_union(action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), action2.assignedGlobalVariables.begin(),
834 action2.assignedGlobalVariables.end(), std::inserter(globalVariablesInActionDd, globalVariablesInActionDd.begin()));
835
836 std::set<storm::expressions::Variable> missingIdentitiesInAction1;
837 std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), action1.assignedGlobalVariables.begin(),
838 action1.assignedGlobalVariables.end(), std::inserter(missingIdentitiesInAction1, missingIdentitiesInAction1.begin()));
839 for (auto const& variable : missingIdentitiesInAction1) {
840 action1.transitionsDd *= generationInfo.variableToIdentityMap.at(variable);
841 }
842
843 std::set<storm::expressions::Variable> missingIdentitiesInAction2;
844 std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), action1.assignedGlobalVariables.begin(),
845 action1.assignedGlobalVariables.end(), std::inserter(missingIdentitiesInAction2, missingIdentitiesInAction2.begin()));
846 for (auto const& variable : missingIdentitiesInAction2) {
847 action2.transitionsDd *= generationInfo.variableToIdentityMap.at(variable);
848 }
849
850 return globalVariablesInActionDd;
851}
852
853template<storm::dd::DdType Type, typename ValueType>
854std::set<storm::expressions::Variable> DdPrismModelBuilder<Type, ValueType>::equalizeAssignedGlobalVariables(GenerationInformation const& generationInfo,
855 std::vector<ActionDecisionDiagram>& actionDds) {
856 // Start by gathering all variables that were written in at least one action DD.
857 std::set<storm::expressions::Variable> globalVariablesInActionDd;
858 for (auto const& commandDd : actionDds) {
859 globalVariablesInActionDd.insert(commandDd.assignedGlobalVariables.begin(), commandDd.assignedGlobalVariables.end());
860 }
861
862 STORM_LOG_TRACE("Equalizing assigned global variables.");
863
864 // Then multiply the transitions of each action with the missing identities.
865 for (auto& actionDd : actionDds) {
866 STORM_LOG_TRACE("Equalizing next action.");
867 std::set<storm::expressions::Variable> missingIdentities;
868 std::set_difference(globalVariablesInActionDd.begin(), globalVariablesInActionDd.end(), actionDd.assignedGlobalVariables.begin(),
869 actionDd.assignedGlobalVariables.end(), std::inserter(missingIdentities, missingIdentities.begin()));
870 for (auto const& variable : missingIdentities) {
871 STORM_LOG_TRACE("Multiplying identity of variable " << variable.getName() << ".");
872 actionDd.transitionsDd *= generationInfo.variableToIdentityMap.at(variable);
873 }
874 }
875 return globalVariablesInActionDd;
876}
877
878template<storm::dd::DdType Type, typename ValueType>
879typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::combineCommandsToActionMarkovChain(
880 GenerationInformation& generationInfo, std::vector<ActionDecisionDiagram>& commandDds) {
881 storm::dd::Bdd<Type> allGuards = generationInfo.manager->getBddZero();
882 storm::dd::Add<Type, ValueType> allCommands = generationInfo.manager->template getAddZero<ValueType>();
883 storm::dd::Bdd<Type> temporary;
884
885 // Make all command DDs assign to the same global variables.
886 std::set<storm::expressions::Variable> assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, commandDds);
887
888 // Then combine the commands to the full action DD and multiply missing identities along the way.
889 for (auto& commandDd : commandDds) {
890 // Check for overlapping guards.
891 temporary = commandDd.guardDd && allGuards;
892
893 // Issue a warning if there are overlapping guards in a non-CTMC model.
894 STORM_LOG_WARN_COND(temporary.isZero() || generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC,
895 "Guard of a command overlaps with previous guards.");
896
897 allGuards |= commandDd.guardDd;
898 allCommands += commandDd.transitionsDd;
899 }
900
901 return ActionDecisionDiagram(allGuards, allCommands, assignedGlobalVariables);
902}
903
904template<storm::dd::DdType Type, typename ValueType>
905storm::dd::Add<Type, ValueType> DdPrismModelBuilder<Type, ValueType>::encodeChoice(GenerationInformation& generationInfo,
906 uint_fast64_t nondeterminismVariableOffset,
907 uint_fast64_t numberOfBinaryVariables, int_fast64_t value) {
908 storm::dd::Add<Type, ValueType> result = generationInfo.manager->template getAddZero<ValueType>();
909
910 STORM_LOG_TRACE("Encoding " << value << " with " << numberOfBinaryVariables << " binary variable(s) starting from offset " << nondeterminismVariableOffset
911 << ".");
912
913 std::map<storm::expressions::Variable, int_fast64_t> metaVariableNameToValueMap;
914 for (uint_fast64_t i = 0; i < numberOfBinaryVariables; ++i) {
915 if (value & (1ull << (numberOfBinaryVariables - i - 1))) {
916 metaVariableNameToValueMap.emplace(generationInfo.nondeterminismMetaVariables[nondeterminismVariableOffset + i], 1);
917 } else {
918 metaVariableNameToValueMap.emplace(generationInfo.nondeterminismMetaVariables[nondeterminismVariableOffset + i], 0);
919 }
920 }
921
922 result.setValue(metaVariableNameToValueMap, storm::utility::one<ValueType>());
923 return result;
924}
925
926template<storm::dd::DdType Type, typename ValueType>
927typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::combineCommandsToActionMDP(
928 GenerationInformation& generationInfo, std::vector<ActionDecisionDiagram>& commandDds, uint_fast64_t nondeterminismVariableOffset) {
929 storm::dd::Bdd<Type> allGuards = generationInfo.manager->getBddZero();
930 storm::dd::Add<Type, ValueType> allCommands = generationInfo.manager->template getAddZero<ValueType>();
931
932 // Make all command DDs assign to the same global variables.
933 std::set<storm::expressions::Variable> assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, commandDds);
934
935 // Sum all guards, so we can read off the maximal number of nondeterministic choices in any given state.
936 storm::dd::Add<Type, uint_fast64_t> sumOfGuards = generationInfo.manager->template getAddZero<uint_fast64_t>();
937 for (auto const& commandDd : commandDds) {
938 sumOfGuards += commandDd.guardDd.template toAdd<uint_fast64_t>();
939 allGuards |= commandDd.guardDd;
940 }
941 uint_fast64_t maxChoices = sumOfGuards.getMax();
942
943 STORM_LOG_TRACE("Found " << maxChoices << " local choices.");
944
945 // Depending on the maximal number of nondeterminstic choices, we need to use some variables to encode the nondeterminism.
946 if (maxChoices == 0) {
947 return ActionDecisionDiagram(*generationInfo.manager);
948 } else if (maxChoices == 1) {
949 // Sum up all commands.
950 for (auto const& commandDd : commandDds) {
951 allCommands += commandDd.transitionsDd;
952 }
953 return ActionDecisionDiagram(allGuards, allCommands, assignedGlobalVariables);
954 } else {
955 // Calculate number of required variables to encode the nondeterminism.
956 uint_fast64_t numberOfBinaryVariables = static_cast<uint_fast64_t>(std::ceil(storm::utility::math::log2(maxChoices)));
957
958 storm::dd::Bdd<Type> equalsNumberOfChoicesDd;
959 std::vector<storm::dd::Add<Type, ValueType>> choiceDds(maxChoices, generationInfo.manager->template getAddZero<ValueType>());
960 std::vector<storm::dd::Bdd<Type>> remainingDds(maxChoices, generationInfo.manager->getBddZero());
961
962 for (uint_fast64_t currentChoices = 1; currentChoices <= maxChoices; ++currentChoices) {
963 // Determine the set of states with exactly currentChoices choices.
964 equalsNumberOfChoicesDd = sumOfGuards.equals(generationInfo.manager->getConstant(currentChoices));
965
966 // If there is no such state, continue with the next possible number of choices.
967 if (equalsNumberOfChoicesDd.isZero()) {
968 continue;
969 }
970
971 // Reset the previously used intermediate storage.
972 for (uint_fast64_t j = 0; j < currentChoices; ++j) {
973 choiceDds[j] = generationInfo.manager->template getAddZero<ValueType>();
974 remainingDds[j] = equalsNumberOfChoicesDd;
975 }
976
977 for (std::size_t j = 0; j < commandDds.size(); ++j) {
978 // Check if command guard overlaps with equalsNumberOfChoicesDd. That is, there are states with exactly currentChoices
979 // choices such that one outgoing choice is given by the j-th command.
980 storm::dd::Bdd<Type> guardChoicesIntersection = commandDds[j].guardDd && equalsNumberOfChoicesDd;
981
982 // If there is no such state, continue with the next command.
983 if (guardChoicesIntersection.isZero()) {
984 continue;
985 }
986
987 // Split the nondeterministic choices.
988 for (uint_fast64_t k = 0; k < currentChoices; ++k) {
989 // Calculate the overlapping part of command guard and the remaining DD.
990 storm::dd::Bdd<Type> remainingGuardChoicesIntersection = guardChoicesIntersection && remainingDds[k];
991
992 // Check if we can add some overlapping parts to the current index.
993 if (!remainingGuardChoicesIntersection.isZero()) {
994 // Remove overlapping parts from the remaining DD.
995 remainingDds[k] = remainingDds[k] && !remainingGuardChoicesIntersection;
996
997 // Combine the overlapping part of the guard with command updates and add it to the resulting DD.
998 choiceDds[k] += remainingGuardChoicesIntersection.template toAdd<ValueType>() * commandDds[j].transitionsDd;
999 }
1000
1001 // Remove overlapping parts from the command guard DD
1002 guardChoicesIntersection = guardChoicesIntersection && !remainingGuardChoicesIntersection;
1003
1004 // If the guard DD has become equivalent to false, we can stop here.
1005 if (guardChoicesIntersection.isZero()) {
1006 break;
1007 }
1008 }
1009 }
1010
1011 // Add the meta variables that encode the nondeterminisim to the different choices.
1012 for (uint_fast64_t j = 0; j < currentChoices; ++j) {
1013 allCommands += encodeChoice(generationInfo, nondeterminismVariableOffset, numberOfBinaryVariables, j) * choiceDds[j];
1014 }
1015
1016 // Delete currentChoices out of overlapping DD
1017 sumOfGuards = sumOfGuards * (!equalsNumberOfChoicesDd).template toAdd<uint_fast64_t>();
1018 }
1019
1020 return ActionDecisionDiagram(allGuards, allCommands, assignedGlobalVariables, nondeterminismVariableOffset + numberOfBinaryVariables);
1021 }
1022}
1023
1024template<storm::dd::DdType Type, typename ValueType>
1025typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::combineSynchronizingActions(
1026 ActionDecisionDiagram const& action1, ActionDecisionDiagram const& action2) {
1027 std::set<storm::expressions::Variable> assignedGlobalVariables;
1028 std::set_union(action1.assignedGlobalVariables.begin(), action1.assignedGlobalVariables.end(), action2.assignedGlobalVariables.begin(),
1029 action2.assignedGlobalVariables.end(), std::inserter(assignedGlobalVariables, assignedGlobalVariables.begin()));
1030 return ActionDecisionDiagram(action1.guardDd && action2.guardDd, action1.transitionsDd * action2.transitionsDd, assignedGlobalVariables,
1031 std::max(action1.numberOfUsedNondeterminismVariables, action2.numberOfUsedNondeterminismVariables));
1032}
1033
1034template<storm::dd::DdType Type, typename ValueType>
1035typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(
1036 GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2,
1037 storm::dd::Add<Type, ValueType> const& identityDd1, storm::dd::Add<Type, ValueType> const& identityDd2) {
1038 // First extend the action DDs by the other identities.
1039 STORM_LOG_TRACE("Multiplying identities to combine unsynchronized actions.");
1040 action1.transitionsDd = action1.transitionsDd * identityDd2;
1041 action2.transitionsDd = action2.transitionsDd * identityDd1;
1042
1043 // Then combine the extended action DDs.
1044 return combineUnsynchronizedActions(generationInfo, action1, action2);
1045}
1046
1047template<storm::dd::DdType Type, typename ValueType>
1048typename DdPrismModelBuilder<Type, ValueType>::ActionDecisionDiagram DdPrismModelBuilder<Type, ValueType>::combineUnsynchronizedActions(
1049 GenerationInformation const& generationInfo, ActionDecisionDiagram& action1, ActionDecisionDiagram& action2) {
1050 STORM_LOG_TRACE("Combining unsynchronized actions.");
1051
1052 // Make both action DDs write to the same global variables.
1053 std::set<storm::expressions::Variable> assignedGlobalVariables = equalizeAssignedGlobalVariables(generationInfo, action1, action2);
1054
1055 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC ||
1056 generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) {
1057 return ActionDecisionDiagram(action1.guardDd || action2.guardDd, action1.transitionsDd + action2.transitionsDd, assignedGlobalVariables, 0);
1058 } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
1059 if (action1.transitionsDd.isZero()) {
1060 return ActionDecisionDiagram(action2.guardDd, action2.transitionsDd, assignedGlobalVariables, action2.numberOfUsedNondeterminismVariables);
1061 } else if (action2.transitionsDd.isZero()) {
1062 return ActionDecisionDiagram(action1.guardDd, action1.transitionsDd, assignedGlobalVariables, action1.numberOfUsedNondeterminismVariables);
1063 }
1064
1065 // Bring both choices to the same number of variables that encode the nondeterminism.
1066 uint_fast64_t numberOfUsedNondeterminismVariables = std::max(action1.numberOfUsedNondeterminismVariables, action2.numberOfUsedNondeterminismVariables);
1067 if (action1.numberOfUsedNondeterminismVariables > action2.numberOfUsedNondeterminismVariables) {
1068 storm::dd::Add<Type, ValueType> nondeterminismEncoding = generationInfo.manager->template getAddOne<ValueType>();
1069
1070 for (uint_fast64_t i = action2.numberOfUsedNondeterminismVariables; i < action1.numberOfUsedNondeterminismVariables; ++i) {
1071 nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd<ValueType>();
1072 }
1073 action2.transitionsDd *= nondeterminismEncoding;
1074 } else if (action2.numberOfUsedNondeterminismVariables > action1.numberOfUsedNondeterminismVariables) {
1075 storm::dd::Add<Type, ValueType> nondeterminismEncoding = generationInfo.manager->template getAddOne<ValueType>();
1076
1077 for (uint_fast64_t i = action1.numberOfUsedNondeterminismVariables; i < action2.numberOfUsedNondeterminismVariables; ++i) {
1078 nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd<ValueType>();
1079 }
1080 action1.transitionsDd *= nondeterminismEncoding;
1081 }
1082
1083 // Add a new variable that resolves the nondeterminism between the two choices.
1084 storm::dd::Add<Type, ValueType> combinedTransitions =
1085 generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[numberOfUsedNondeterminismVariables], 1)
1086 .ite(action2.transitionsDd, action1.transitionsDd);
1087
1088 return ActionDecisionDiagram(action1.guardDd || action2.guardDd, combinedTransitions, assignedGlobalVariables, numberOfUsedNondeterminismVariables + 1);
1089 } else {
1090 STORM_LOG_THROW(false, storm::exceptions::InvalidStateException, "Illegal model type.");
1091 }
1092}
1093
1094template<storm::dd::DdType Type, typename ValueType>
1095typename DdPrismModelBuilder<Type, ValueType>::ModuleDecisionDiagram DdPrismModelBuilder<Type, ValueType>::createModuleDecisionDiagram(
1096 GenerationInformation& generationInfo, storm::prism::Module const& module, std::map<uint_fast64_t, uint_fast64_t> const& synchronizingActionToOffsetMap) {
1097 // Start by creating the action DD for the independent action.
1098 ActionDecisionDiagram independentActionDd = createActionDecisionDiagram(generationInfo, module, 0, 0);
1099 uint_fast64_t numberOfUsedNondeterminismVariables = independentActionDd.numberOfUsedNondeterminismVariables;
1100
1101 // Create module DD for all synchronizing actions of the module.
1102 std::map<uint_fast64_t, ActionDecisionDiagram> actionIndexToDdMap;
1103 for (auto const& actionIndex : module.getSynchronizingActionIndices()) {
1104 STORM_LOG_TRACE("Creating DD for action '" << actionIndex << "'.");
1105 ActionDecisionDiagram tmp = createActionDecisionDiagram(generationInfo, module, actionIndex, synchronizingActionToOffsetMap.at(actionIndex));
1106 numberOfUsedNondeterminismVariables = std::max(numberOfUsedNondeterminismVariables, tmp.numberOfUsedNondeterminismVariables);
1107 actionIndexToDdMap.emplace(actionIndex, tmp);
1108 }
1109
1110 return ModuleDecisionDiagram(independentActionDd, actionIndexToDdMap, generationInfo.moduleToIdentityMap.at(module.getName()),
1111 numberOfUsedNondeterminismVariables);
1112}
1113
1114template<storm::dd::DdType Type, typename ValueType>
1115storm::dd::Add<Type, ValueType> DdPrismModelBuilder<Type, ValueType>::getSynchronizationDecisionDiagram(GenerationInformation& generationInfo,
1116 uint_fast64_t actionIndex) {
1117 storm::dd::Add<Type, ValueType> synchronization = generationInfo.manager->template getAddOne<ValueType>();
1118 if (actionIndex != 0) {
1119 for (uint_fast64_t i = 0; i < generationInfo.synchronizationMetaVariables.size(); ++i) {
1120 if ((actionIndex - 1) == i) {
1121 synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 1).template toAdd<ValueType>();
1122 } else {
1123 synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 0).template toAdd<ValueType>();
1124 }
1125 }
1126 } else {
1127 for (uint_fast64_t i = 0; i < generationInfo.synchronizationMetaVariables.size(); ++i) {
1128 synchronization *= generationInfo.manager->getEncoding(generationInfo.synchronizationMetaVariables[i], 0).template toAdd<ValueType>();
1129 }
1130 }
1131 return synchronization;
1132}
1133
1134template<storm::dd::DdType Type, typename ValueType>
1135storm::dd::Add<Type, ValueType> DdPrismModelBuilder<Type, ValueType>::createSystemFromModule(GenerationInformation& generationInfo,
1136 ModuleDecisionDiagram& module) {
1138
1139 // Make sure all actions contain all necessary meta variables.
1140 module.independentAction.ensureContainsVariables(generationInfo.rowMetaVariables, generationInfo.columnMetaVariables);
1141 for (auto& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) {
1142 synchronizingAction.second.ensureContainsVariables(generationInfo.rowMetaVariables, generationInfo.columnMetaVariables);
1143 }
1144
1145 // If the model is an MDP, we need to encode the nondeterminism using additional variables.
1146 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
1147 result = generationInfo.manager->template getAddZero<ValueType>();
1148
1149 // First, determine the highest number of nondeterminism variables that is used in any action and make
1150 // all actions use the same amout of nondeterminism variables.
1151 uint_fast64_t numberOfUsedNondeterminismVariables = module.numberOfUsedNondeterminismVariables;
1152
1153 // Compute missing global variable identities in independent action.
1154 std::set<storm::expressions::Variable> missingIdentities;
1155 std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(),
1156 module.independentAction.assignedGlobalVariables.begin(), module.independentAction.assignedGlobalVariables.end(),
1157 std::inserter(missingIdentities, missingIdentities.begin()));
1158 storm::dd::Add<Type, ValueType> identityEncoding = generationInfo.manager->template getAddOne<ValueType>();
1159 for (auto const& variable : missingIdentities) {
1160 STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to independent action.");
1161 identityEncoding *= generationInfo.variableToIdentityMap.at(variable);
1162 }
1163
1164 // Add variables to independent action DD.
1165 storm::dd::Add<Type, ValueType> nondeterminismEncoding = generationInfo.manager->template getAddOne<ValueType>();
1166 for (uint_fast64_t i = module.independentAction.numberOfUsedNondeterminismVariables; i < numberOfUsedNondeterminismVariables; ++i) {
1167 nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd<ValueType>();
1168 }
1169
1170 result = identityEncoding * module.independentAction.transitionsDd * nondeterminismEncoding;
1171
1172 // Add variables to synchronized action DDs.
1173 std::map<uint_fast64_t, storm::dd::Add<Type, ValueType>> synchronizingActionToDdMap;
1174 for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) {
1175 // Compute missing global variable identities in synchronizing actions.
1176 missingIdentities = std::set<storm::expressions::Variable>();
1177 std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(),
1178 synchronizingAction.second.assignedGlobalVariables.begin(), synchronizingAction.second.assignedGlobalVariables.end(),
1179 std::inserter(missingIdentities, missingIdentities.begin()));
1180 identityEncoding = generationInfo.manager->template getAddOne<ValueType>();
1181 for (auto const& variable : missingIdentities) {
1182 STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to synchronizing action '" << synchronizingAction.first
1183 << "'.");
1184 identityEncoding *= generationInfo.variableToIdentityMap.at(variable);
1185 }
1186
1187 nondeterminismEncoding = generationInfo.manager->template getAddOne<ValueType>();
1188 for (uint_fast64_t i = synchronizingAction.second.numberOfUsedNondeterminismVariables; i < numberOfUsedNondeterminismVariables; ++i) {
1189 nondeterminismEncoding *= generationInfo.manager->getEncoding(generationInfo.nondeterminismMetaVariables[i], 0).template toAdd<ValueType>();
1190 }
1191 synchronizingActionToDdMap.emplace(synchronizingAction.first, identityEncoding * synchronizingAction.second.transitionsDd * nondeterminismEncoding);
1192 }
1193
1194 // Add variables for synchronization.
1195 result *= getSynchronizationDecisionDiagram(generationInfo);
1196
1197 for (auto& synchronizingAction : synchronizingActionToDdMap) {
1198 synchronizingAction.second *= getSynchronizationDecisionDiagram(generationInfo, synchronizingAction.first);
1199 }
1200
1201 // Now, we can simply add all synchronizing actions to the result.
1202 for (auto const& synchronizingAction : synchronizingActionToDdMap) {
1203 result += synchronizingAction.second;
1204 }
1205 } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC ||
1206 generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) {
1207 // Simply add all actions, but make sure to include the missing global variable identities.
1208
1209 // Compute missing global variable identities in independent action.
1210 std::set<storm::expressions::Variable> missingIdentities;
1211 std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(),
1212 module.independentAction.assignedGlobalVariables.begin(), module.independentAction.assignedGlobalVariables.end(),
1213 std::inserter(missingIdentities, missingIdentities.begin()));
1214 storm::dd::Add<Type, ValueType> identityEncoding = generationInfo.manager->template getAddOne<ValueType>();
1215 for (auto const& variable : missingIdentities) {
1216 STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to independent action.");
1217 identityEncoding *= generationInfo.variableToIdentityMap.at(variable);
1218 }
1219
1220 result = identityEncoding * module.independentAction.transitionsDd;
1221 for (auto const& synchronizingAction : module.synchronizingActionToDecisionDiagramMap) {
1222 // Compute missing global variable identities in synchronizing actions.
1223 missingIdentities = std::set<storm::expressions::Variable>();
1224 std::set_difference(generationInfo.allGlobalVariables.begin(), generationInfo.allGlobalVariables.end(),
1225 synchronizingAction.second.assignedGlobalVariables.begin(), synchronizingAction.second.assignedGlobalVariables.end(),
1226 std::inserter(missingIdentities, missingIdentities.begin()));
1227 identityEncoding = generationInfo.manager->template getAddOne<ValueType>();
1228 for (auto const& variable : missingIdentities) {
1229 STORM_LOG_TRACE("Multiplying identity of global variable " << variable.getName() << " to synchronizing action '" << synchronizingAction.first
1230 << "'.");
1231 identityEncoding *= generationInfo.variableToIdentityMap.at(variable);
1232 }
1233
1234 result += identityEncoding * synchronizingAction.second.transitionsDd;
1235 }
1236 } else {
1237 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Illegal model type.");
1238 }
1239 return result;
1240}
1241
1242template<storm::dd::DdType Type, typename ValueType>
1243typename DdPrismModelBuilder<Type, ValueType>::SystemResult DdPrismModelBuilder<Type, ValueType>::createSystemDecisionDiagram(
1244 GenerationInformation& generationInfo) {
1245 ModuleComposer<Type, ValueType> composer(generationInfo);
1246 ModuleDecisionDiagram system =
1247 composer.compose(generationInfo.program.specifiesSystemComposition() ? generationInfo.program.getSystemCompositionConstruct().getSystemComposition()
1248 : *generationInfo.program.getDefaultSystemComposition());
1249
1250 storm::dd::Add<Type, ValueType> result = createSystemFromModule(generationInfo, system);
1251
1252 // Create an auxiliary DD that is used later during the construction of reward models.
1253 boost::optional<storm::dd::Add<Type, ValueType>> stateActionDd;
1254
1255 // For DTMCs, we normalize each row to 1 (to account for non-determinism).
1256 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
1257 stateActionDd = result.sumAbstract(generationInfo.columnMetaVariables);
1258 result = result / stateActionDd.get();
1259 } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
1260 // For MDPs, we need to throw away the nondeterminism variables from the generation information that
1261 // were never used.
1262 for (uint_fast64_t index = system.numberOfUsedNondeterminismVariables; index < generationInfo.nondeterminismMetaVariables.size(); ++index) {
1263 generationInfo.allNondeterminismVariables.erase(generationInfo.nondeterminismMetaVariables[index]);
1264 }
1265 generationInfo.nondeterminismMetaVariables.resize(system.numberOfUsedNondeterminismVariables);
1266 }
1267
1268 return SystemResult(result, system, stateActionDd);
1269}
1270
1271template<storm::dd::DdType Type, typename ValueType>
1272std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>>
1273DdPrismModelBuilder<Type, ValueType>::createRewardModelDecisionDiagrams(
1274 std::vector<std::reference_wrapper<storm::prism::RewardModel const>> const& selectedRewardModels, SystemResult& system,
1275 GenerationInformation& generationInfo, ModuleDecisionDiagram const& globalModule, storm::dd::Add<Type, ValueType> const& reachableStatesAdd,
1276 storm::dd::Add<Type, ValueType> const& transitionMatrix) {
1277 std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> rewardModels;
1278 for (auto const& rewardModel : selectedRewardModels) {
1279 rewardModels.emplace(rewardModel.get().getName(), createRewardModelDecisionDiagrams(generationInfo, rewardModel.get(), globalModule, reachableStatesAdd,
1280 transitionMatrix, system.stateActionDd));
1281 }
1282 return rewardModels;
1283}
1284
1285template<storm::dd::DdType Type, typename ValueType>
1286void checkRewards(storm::dd::Add<Type, ValueType> const& rewards, std::string const& rewardType) {
1287 STORM_LOG_WARN_COND(rewards.getMin() >= 0, "The reward model assigns negative " << rewardType << " to some states.");
1288 STORM_LOG_WARN_COND(!rewards.isZero(), "The reward model declares " << rewardType << " but does not assign any non-zero values.");
1289}
1290
1291template<storm::dd::DdType Type>
1292void checkRewards(storm::dd::Add<Type, storm::RationalFunction> const& rewards, std::string const& rewardType) {
1293 STORM_LOG_WARN_COND(!rewards.isZero(), "The reward model declares " << rewardType << " but does not assign any non-zero values.");
1294}
1295
1296template<storm::dd::DdType Type, typename ValueType>
1297storm::models::symbolic::StandardRewardModel<Type, ValueType> DdPrismModelBuilder<Type, ValueType>::createRewardModelDecisionDiagrams(
1298 GenerationInformation& generationInfo, storm::prism::RewardModel const& rewardModel, ModuleDecisionDiagram const& globalModule,
1299 storm::dd::Add<Type, ValueType> const& reachableStatesAdd, storm::dd::Add<Type, ValueType> const& transitionMatrix,
1300 boost::optional<storm::dd::Add<Type, ValueType>>& stateActionDd) {
1301 // Start by creating the state reward vector.
1302 boost::optional<storm::dd::Add<Type, ValueType>> stateRewards;
1303 if (rewardModel.hasStateRewards()) {
1304 stateRewards = generationInfo.manager->template getAddZero<ValueType>();
1305
1306 for (auto const& stateReward : rewardModel.getStateRewards()) {
1307 storm::dd::Add<Type, ValueType> states = generationInfo.rowExpressionAdapter->translateExpression(stateReward.getStatePredicateExpression());
1308 storm::dd::Add<Type, ValueType> rewards = generationInfo.rowExpressionAdapter->translateExpression(stateReward.getRewardValueExpression());
1309
1310 // Restrict the rewards to those states that satisfy the condition.
1311 rewards = reachableStatesAdd * states * rewards;
1312
1313 // Add the rewards to the global state reward vector.
1314 stateRewards.get() += rewards;
1315 }
1316 // Perform some sanity checks.
1317 checkRewards(stateRewards.get(), "state rewards");
1318 }
1319
1320 // Next, build the state-action reward vector.
1321 boost::optional<storm::dd::Add<Type, ValueType>> stateActionRewards;
1322 if (rewardModel.hasStateActionRewards()) {
1323 stateActionRewards = generationInfo.manager->template getAddZero<ValueType>();
1324
1325 for (auto const& stateActionReward : rewardModel.getStateActionRewards()) {
1326 storm::dd::Add<Type, ValueType> states = generationInfo.rowExpressionAdapter->translateExpression(stateActionReward.getStatePredicateExpression());
1327 storm::dd::Add<Type, ValueType> rewards = generationInfo.rowExpressionAdapter->translateExpression(stateActionReward.getRewardValueExpression());
1328 storm::dd::Add<Type, ValueType> synchronization = generationInfo.manager->template getAddOne<ValueType>();
1329
1330 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
1331 synchronization = getSynchronizationDecisionDiagram(generationInfo, stateActionReward.getActionIndex());
1332 }
1333 ActionDecisionDiagram const& actionDd = stateActionReward.isLabeled()
1334 ? globalModule.synchronizingActionToDecisionDiagramMap.at(stateActionReward.getActionIndex())
1335 : globalModule.independentAction;
1336 states *= actionDd.guardDd.template toAdd<ValueType>() * reachableStatesAdd;
1337 storm::dd::Add<Type, ValueType> stateActionRewardDd = synchronization * states * rewards;
1338
1339 // If we are building the state-action rewards for an MDP, we need to make sure that the reward is
1340 // only given on legal nondeterminism encodings, which is why we multiply with the state-action DD.
1341 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
1342 if (!stateActionDd) {
1343 stateActionDd = transitionMatrix.notZero().existsAbstract(generationInfo.columnMetaVariables).template toAdd<ValueType>();
1344 }
1345 stateActionRewardDd *= stateActionDd.get();
1346 } else if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC ||
1347 generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) {
1348 // For DTMCs and CTMC, we need to multiply the entries with the multiplicity/exit rate of the corresponding action.
1349 stateActionRewardDd *= actionDd.transitionsDd.sumAbstract(generationInfo.columnMetaVariables);
1350 }
1351
1352 // Add the rewards to the global transition reward matrix.
1353 stateActionRewards.get() += stateActionRewardDd;
1354 }
1355
1356 // Scale state-action rewards for DTMCs and CTMCs.
1357 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC ||
1358 generationInfo.program.getModelType() == storm::prism::Program::ModelType::CTMC) {
1359 if (!stateActionDd) {
1360 stateActionDd = transitionMatrix.sumAbstract(generationInfo.columnMetaVariables);
1361 }
1362
1363 stateActionRewards.get() /= stateActionDd.get();
1364 }
1365
1366 // Perform some sanity checks.
1367 checkRewards(stateActionRewards.get(), "action rewards");
1368 }
1369
1370 // Then build the transition reward matrix.
1371 boost::optional<storm::dd::Add<Type, ValueType>> transitionRewards;
1372 if (rewardModel.hasTransitionRewards()) {
1373 transitionRewards = generationInfo.manager->template getAddZero<ValueType>();
1374
1375 for (auto const& transitionReward : rewardModel.getTransitionRewards()) {
1376 storm::dd::Add<Type, ValueType> sourceStates =
1377 generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getSourceStatePredicateExpression());
1378 storm::dd::Add<Type, ValueType> targetStates =
1379 generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getTargetStatePredicateExpression());
1380 storm::dd::Add<Type, ValueType> rewards = generationInfo.rowExpressionAdapter->translateExpression(transitionReward.getRewardValueExpression());
1381
1382 storm::dd::Add<Type, ValueType> synchronization = generationInfo.manager->template getAddOne<ValueType>();
1383
1385 if (transitionReward.isLabeled()) {
1386 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
1387 synchronization = getSynchronizationDecisionDiagram(generationInfo, transitionReward.getActionIndex());
1388 }
1389 transitions = globalModule.synchronizingActionToDecisionDiagramMap.at(transitionReward.getActionIndex()).transitionsDd;
1390 } else {
1391 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::MDP) {
1392 synchronization = getSynchronizationDecisionDiagram(generationInfo);
1393 }
1394 transitions = globalModule.independentAction.transitionsDd;
1395 }
1396
1397 storm::dd::Add<Type, ValueType> transitionRewardDd = synchronization * sourceStates * targetStates * rewards;
1398 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
1399 // For DTMCs we need to keep the weighting for the scaling that follows.
1400 transitionRewardDd = transitions * transitionRewardDd;
1401 } else {
1402 // For all other model types, we do not scale the rewards.
1403 transitionRewardDd = transitions.notZero().template toAdd<ValueType>() * transitionRewardDd;
1404 }
1405
1406 // Add the rewards to the global transition reward matrix.
1407 transitionRewards.get() += transitionRewardDd;
1408 }
1409
1410 // Perform some sanity checks.
1411 checkRewards(transitionRewards.get(), "transition rewards");
1412
1413 // Scale transition rewards for DTMCs.
1414 if (generationInfo.program.getModelType() == storm::prism::Program::ModelType::DTMC) {
1415 transitionRewards.get() /= stateActionDd.get();
1416 }
1417 }
1418
1419 return storm::models::symbolic::StandardRewardModel<Type, ValueType>(stateRewards, stateActionRewards, transitionRewards);
1420}
1421
1422template<storm::dd::DdType Type, typename ValueType>
1423std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdPrismModelBuilder<Type, ValueType>::buildInternal(
1424 storm::prism::Program const& program, Options const& options, std::shared_ptr<storm::dd::DdManager<Type>> const& manager) {
1425 // Start by initializing the structure used for storing all information needed during the model generation.
1426 // In particular, this creates the meta variables used to encode the model.
1427 GenerationInformation generationInfo(program, manager);
1428
1429 SystemResult system = createSystemDecisionDiagram(generationInfo);
1430 storm::dd::Add<Type, ValueType> transitionMatrix = system.allTransitionsDd;
1431
1432 ModuleDecisionDiagram const& globalModule = system.globalModule;
1433
1434 // If we were asked to treat some states as terminal states, we cut away their transitions now.
1435 storm::dd::Bdd<Type> terminalStatesBdd = generationInfo.manager->getBddZero();
1436 if (!options.terminalStates.empty()) {
1437 storm::expressions::Expression terminalExpression = options.terminalStates.asExpression([&program](std::string const& labelName) {
1438 if (program.hasLabel(labelName)) {
1439 return program.getLabelExpression(labelName);
1440 } else {
1441 STORM_LOG_THROW(labelName == "init" || labelName == "deadlock", storm::exceptions::InvalidArgumentException,
1442 "Terminal states refer to illegal label '" << labelName << "'.");
1443 // If the label name is "init" we can abort 'exploration' directly at the initial state. If it is deadlock, we do not have to abort.
1444 return program.getManager().boolean(labelName == "init");
1445 }
1446 });
1447 terminalExpression = terminalExpression.substitute(program.getConstantsSubstitution());
1448 terminalStatesBdd = generationInfo.rowExpressionAdapter->translateExpression(terminalExpression).toBdd();
1449 transitionMatrix *= (!terminalStatesBdd).template toAdd<ValueType>();
1450 }
1451
1452 // Cut the transitions and rewards to the reachable fragment of the state space.
1453 storm::dd::Bdd<Type> initialStates = createInitialStatesDecisionDiagram(generationInfo);
1454
1455 storm::dd::Bdd<Type> transitionMatrixBdd = transitionMatrix.notZero();
1457 transitionMatrixBdd = transitionMatrixBdd.existsAbstract(generationInfo.allNondeterminismVariables);
1458 }
1459
1460 storm::dd::Bdd<Type> reachableStates = storm::utility::dd::computeReachableStates<Type>(initialStates, transitionMatrixBdd, generationInfo.rowMetaVariables,
1461 generationInfo.columnMetaVariables)
1462 .first;
1463 storm::dd::Add<Type, ValueType> reachableStatesAdd = reachableStates.template toAdd<ValueType>();
1464 transitionMatrix *= reachableStatesAdd;
1465 if (system.stateActionDd) {
1466 system.stateActionDd.get() *= reachableStatesAdd;
1467 }
1468
1469 // Detect deadlocks and 1) fix them if requested 2) throw an error otherwise.
1470 storm::dd::Bdd<Type> statesWithTransition = transitionMatrixBdd.existsAbstract(generationInfo.columnMetaVariables);
1471 storm::dd::Bdd<Type> deadlockStates = reachableStates && !statesWithTransition;
1472
1473 // If there are deadlocks, either fix them or raise an error.
1474 if (!deadlockStates.isZero()) {
1475 // If we need to fix deadlocks, we do so now.
1477 STORM_LOG_INFO("Fixing deadlocks in " << deadlockStates.getNonZeroCount() << " states. The first three of these states are: ");
1478
1479 storm::dd::Add<Type, ValueType> deadlockStatesAdd = deadlockStates.template toAdd<ValueType>();
1480 uint_fast64_t count = 0;
1481 for (auto it = deadlockStatesAdd.begin(), ite = deadlockStatesAdd.end(); it != ite && count < 3; ++it, ++count) {
1482 STORM_LOG_INFO((*it).first.toPrettyString(generationInfo.rowMetaVariables) << '\n');
1483 }
1484
1486 storm::dd::Add<Type, ValueType> identity = globalModule.identity;
1487
1488 // Make sure that global variables do not change along the introduced self-loops.
1489 for (auto const& var : generationInfo.allGlobalVariables) {
1490 identity *= generationInfo.variableToIdentityMap.at(var);
1491 }
1492
1493 // For DTMCs, we can simply add the identity of the global module for all deadlock states.
1494 transitionMatrix += deadlockStatesAdd * identity;
1495 } else if (program.getModelType() == storm::prism::Program::ModelType::MDP) {
1496 // For MDPs, however, we need to select an action associated with the self-loop, if we do not
1497 // want to attach a lot of self-loops to the deadlock states.
1498 storm::dd::Add<Type, ValueType> action = generationInfo.manager->template getAddOne<ValueType>();
1499 for (auto const& metaVariable : generationInfo.allNondeterminismVariables) {
1500 action *= generationInfo.manager->template getIdentity<ValueType>(metaVariable);
1501 }
1502 // Make sure that global variables do not change along the introduced self-loops.
1503 for (auto const& var : generationInfo.allGlobalVariables) {
1504 action *= generationInfo.variableToIdentityMap.at(var);
1505 }
1506 transitionMatrix += deadlockStatesAdd * globalModule.identity * action;
1507 }
1508 } else {
1509 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException,
1510 "The model contains " << deadlockStates.getNonZeroCount()
1511 << " deadlock states. Please unset the option to not fix deadlocks, if you want to fix them automatically.");
1512 }
1513 }
1514
1515 // Reduce the deadlock states by the states that we did simply not explore.
1516 deadlockStates = deadlockStates && !terminalStatesBdd;
1517
1518 // Now build the reward models.
1519 std::vector<std::reference_wrapper<storm::prism::RewardModel const>> selectedRewardModels;
1520
1521 // First, we make sure that all selected reward models actually exist.
1522 for (auto const& rewardModelName : options.rewardModelsToBuild) {
1523 STORM_LOG_THROW(rewardModelName.empty() || program.hasRewardModel(rewardModelName), storm::exceptions::InvalidArgumentException,
1524 "Model does not possess a reward model with the name '" << rewardModelName << "'.");
1525 }
1526
1527 for (auto const& rewardModel : program.getRewardModels()) {
1528 if (options.buildAllRewardModels || options.rewardModelsToBuild.find(rewardModel.getName()) != options.rewardModelsToBuild.end()) {
1529 selectedRewardModels.push_back(rewardModel);
1530 }
1531 }
1532 // If no reward model was selected until now and a referenced reward model appears to be unique, we build
1533 // the only existing reward model (given that no explicit name was given for the referenced reward model).
1534 if (selectedRewardModels.empty() && program.getNumberOfRewardModels() == 1 && options.rewardModelsToBuild.size() == 1 &&
1535 *options.rewardModelsToBuild.begin() == "") {
1536 selectedRewardModels.push_back(program.getRewardModel(0));
1537 }
1538
1539 std::unordered_map<std::string, storm::models::symbolic::StandardRewardModel<Type, ValueType>> rewardModels =
1540 createRewardModelDecisionDiagrams(selectedRewardModels, system, generationInfo, globalModule, reachableStatesAdd, transitionMatrix);
1541
1542 // Build the labels that can be accessed as a shortcut.
1543 std::map<std::string, storm::expressions::Expression> labelToExpressionMapping;
1544 for (auto const& label : program.getLabels()) {
1545 labelToExpressionMapping.emplace(label.getName(), label.getStatePredicateExpression());
1546 }
1547
1548 std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> result;
1550 result = std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>>(new storm::models::symbolic::Dtmc<Type, ValueType>(
1551 generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, generationInfo.rowMetaVariables,
1552 generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.rowColumnMetaVariablePairs, labelToExpressionMapping,
1553 rewardModels));
1554 } else if (program.getModelType() == storm::prism::Program::ModelType::CTMC) {
1555 result = std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>>(new storm::models::symbolic::Ctmc<Type, ValueType>(
1556 generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, system.stateActionDd, generationInfo.rowMetaVariables,
1557 generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.rowColumnMetaVariablePairs, labelToExpressionMapping,
1558 rewardModels));
1559 } else if (program.getModelType() == storm::prism::Program::ModelType::MDP) {
1560 result = std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>>(new storm::models::symbolic::Mdp<Type, ValueType>(
1561 generationInfo.manager, reachableStates, initialStates, deadlockStates, transitionMatrix, generationInfo.rowMetaVariables,
1562 generationInfo.rowExpressionAdapter, generationInfo.columnMetaVariables, generationInfo.rowColumnMetaVariablePairs,
1563 generationInfo.allNondeterminismVariables, labelToExpressionMapping, rewardModels));
1564 } else {
1565 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Invalid model type.");
1566 }
1567
1568 if (std::is_same<ValueType, storm::RationalFunction>::value) {
1569 result->addParameters(generationInfo.parameters);
1570 }
1571
1572 return result;
1573}
1574
1575template<storm::dd::DdType Type, typename ValueType>
1576std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> DdPrismModelBuilder<Type, ValueType>::build(storm::prism::Program const& program,
1577 Options const& options) {
1578 if (!std::is_same<ValueType, storm::RationalFunction>::value && program.hasUndefinedConstants()) {
1579 std::vector<std::reference_wrapper<storm::prism::Constant const>> undefinedConstants = program.getUndefinedConstants();
1580 std::stringstream stream;
1581 bool printComma = false;
1582 for (auto const& constant : undefinedConstants) {
1583 if (printComma) {
1584 stream << ", ";
1585 } else {
1586 printComma = true;
1587 }
1588 stream << constant.get().getName() << " (" << constant.get().getType() << ")";
1589 }
1590 stream << ".";
1591 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Program still contains these undefined constants: " + stream.str());
1592 }
1593 STORM_LOG_THROW(!program.hasUnboundedVariables(), storm::exceptions::InvalidArgumentException,
1594 "Program contains unbounded variables which is not supported by the DD engine.");
1595
1596 STORM_LOG_TRACE("Building representation of program:\n" << program << '\n');
1597
1598 auto manager = std::make_shared<storm::dd::DdManager<Type>>();
1599 std::shared_ptr<storm::models::symbolic::Model<Type, ValueType>> result;
1600 manager->execute([&program, &options, &manager, &result, this]() { result = this->buildInternal(program, options, manager); });
1601 return result;
1602}
1603
1604template<storm::dd::DdType Type, typename ValueType>
1606 storm::dd::Bdd<Type> initialStates = generationInfo.rowExpressionAdapter->translateExpression(generationInfo.program.getInitialStatesExpression()).toBdd();
1607
1608 for (auto const& metaVariable : generationInfo.rowMetaVariables) {
1609 initialStates &= generationInfo.manager->getRange(metaVariable);
1610 }
1611
1612 return initialStates;
1613}
1614
1615// Explicitly instantiate the symbolic model builder.
1616template class DdPrismModelBuilder<storm::dd::DdType::CUDD>;
1617template class DdPrismModelBuilder<storm::dd::DdType::Sylvan>;
1618
1619template class DdPrismModelBuilder<storm::dd::DdType::Sylvan, storm::RationalNumber>;
1620template class DdPrismModelBuilder<storm::dd::DdType::Sylvan, storm::RationalFunction>;
1621
1622} // namespace builder
1623} // namespace storm
void setValue(storm::expressions::Variable const &variable, ValueType const &value)
std::shared_ptr< storm::adapters::AddExpressionAdapter< Type, ValueType > > rowExpressionAdapter
std::vector< std::pair< storm::expressions::Variable, storm::expressions::Variable > > rowColumnMetaVariablePairs
std::shared_ptr< std::map< storm::expressions::Variable, storm::expressions::Variable > > variableToColumnMetaVariableMap
std::vector< storm::expressions::Variable > nondeterminismMetaVariables
std::set< storm::expressions::Variable > allGlobalVariables
std::vector< storm::expressions::Variable > synchronizationMetaVariables
std::shared_ptr< std::map< storm::expressions::Variable, storm::expressions::Variable > > variableToRowMetaVariableMap
std::map< storm::expressions::Variable, storm::dd::Add< Type, ValueType > > variableToIdentityMap
std::shared_ptr< storm::dd::DdManager< Type > > manager
std::set< storm::expressions::Variable > allNondeterminismVariables
std::set< storm::RationalFunctionVariable > parameters
std::map< std::string, storm::dd::Add< Type, ValueType > > moduleToRangeMap
std::map< std::string, storm::dd::Add< Type, ValueType > > moduleToIdentityMap
std::set< storm::expressions::Variable > columnMetaVariables
std::set< storm::expressions::Variable > allSynchronizationMetaVariables
GenerationInformation(storm::prism::Program const &program, std::shared_ptr< storm::dd::DdManager< Type > > const &manager)
std::shared_ptr< storm::models::symbolic::Model< Type, ValueType > > build(storm::prism::Program const &program, Options const &options=Options())
Translates the given program into a symbolic model (i.e.
DdPrismModelBuilder< Type, ValueType >::ModuleDecisionDiagram compose(storm::prism::Composition const &composition)
virtual boost::any visit(storm::prism::ModuleComposition const &composition, boost::any const &data) override
std::map< uint_fast64_t, uint_fast64_t > newSynchronizingActionToOffsetMap() const
virtual boost::any visit(storm::prism::SynchronizingParallelComposition const &composition, boost::any const &data) override
virtual boost::any visit(storm::prism::RenamingComposition const &composition, boost::any const &data) override
virtual boost::any visit(storm::prism::HidingComposition const &composition, boost::any const &data) override
virtual boost::any visit(storm::prism::RestrictedParallelComposition const &composition, boost::any const &data) override
std::map< uint_fast64_t, uint_fast64_t > updateSynchronizingActionToOffsetMap(typename DdPrismModelBuilder< Type, ValueType >::ModuleDecisionDiagram const &sub, std::map< uint_fast64_t, uint_fast64_t > const &oldMapping) const
virtual boost::any visit(storm::prism::InterleavingParallelComposition const &composition, boost::any const &data) override
ModuleComposer(typename DdPrismModelBuilder< Type, ValueType >::GenerationInformation &generationInfo)
std::set< storm::RationalFunctionVariable > const & getParameters() const
RationalFunctionType convertVariableToPolynomial(storm::RationalFunctionVariable const &variable)
void create(storm::prism::Program const &program, storm::adapters::AddExpressionAdapter< Type, storm::RationalFunction > &rowExpressionAdapter)
std::set< storm::RationalFunctionVariable > const & getParameters() const
void create(storm::prism::Program const &, storm::adapters::AddExpressionAdapter< Type, ValueType > &)
Bdd< LibraryType > equals(Add< LibraryType, ValueType > const &other) const
Retrieves the function that maps all evaluations to one that have identical function values.
Definition Add.cpp:96
ValueType getMax() const
Retrieves the highest function value of any encoding.
Definition Add.cpp:475
ValueType getMin() const
Retrieves the lowest function value of any encoding.
Definition Add.cpp:470
AddIterator< LibraryType, ValueType > begin(bool enumerateDontCareMetaVariables=true) const
Retrieves an iterator that points to the first meta variable assignment with a non-zero function valu...
Definition Add.cpp:1149
Add< LibraryType, ValueType > sumAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Sum-abstracts from the given meta variables.
Definition Add.cpp:178
AddIterator< LibraryType, ValueType > end() const
Retrieves an iterator that points past the end of the container.
Definition Add.cpp:1161
bool isZero() const
Retrieves whether this ADD represents the constant zero function.
Definition Add.cpp:532
void setValue(storm::expressions::Variable const &metaVariable, int_fast64_t variableValue, ValueType const &targetValue)
Sets the function values of all encodings that have the given value of the meta variable to the given...
Definition Add.cpp:480
Bdd< LibraryType > notZero() const
Computes a BDD that represents the function in which all assignments with a function value unequal to...
Definition Add.cpp:431
Bdd< LibraryType > existsAbstract(std::set< storm::expressions::Variable > const &metaVariables) const
Existentially abstracts from the given meta variables.
Definition Bdd.cpp:178
bool isZero() const
Retrieves whether this DD represents the constant zero function.
Definition Bdd.cpp:547
virtual uint_fast64_t getNonZeroCount() const override
Retrieves the number of encodings that are mapped to a non-zero value.
Definition Bdd.cpp:513
Expression substitute(std::map< Variable, Expression > const &variableToExpressionMap) const
Substitutes all occurrences of the variables according to the given map.
std::vector< std::shared_ptr< AtomicLabelFormula const > > getAtomicLabelFormulas() const
Definition Formula.cpp:483
std::set< std::string > getReferencedRewardModels() const
Definition Formula.cpp:495
This class represents a continuous-time Markov chain.
Definition Ctmc.h:15
This class represents a discrete-time Markov chain.
Definition Dtmc.h:15
This class represents a discrete-time Markov decision process.
Definition Mdp.h:15
std::vector< storm::prism::Update > const & getUpdates() const
Retrieves a vector of all updates associated with this command.
Definition Command.cpp:48
bool isLabeled() const
Retrieves whether the command possesses a synchronization label.
Definition Command.cpp:82
storm::expressions::Expression const & getGuardExpression() const
Retrieves a reference to the guard of the command.
Definition Command.cpp:35
uint_fast64_t getActionIndex() const
Retrieves the action index of this command.
Definition Command.cpp:19
virtual boost::any accept(CompositionVisitor &visitor, boost::any const &data) const =0
std::set< std::string > const & getActionsToHide() const
Composition const & getSubcomposition() const
std::string const & getModuleName() const
std::string const & getName() const
Retrieves the name of the module.
Definition Module.cpp:141
Composition const & getLeftSubcomposition() const
Composition const & getRightSubcomposition() const
std::set< uint_fast64_t > const & getSynchronizingActionIndices() const
Retrieves the set of synchronizing action indices present in the program.
Definition Program.cpp:738
ModelType getModelType() const
Retrieves the model type of the model.
Definition Program.cpp:247
RewardModel const & getRewardModel(std::string const &rewardModelName) const
Retrieves the reward model with the given name.
Definition Program.cpp:816
std::vector< BooleanVariable > const & getGlobalBooleanVariables() const
Retrieves the global boolean variables of the program.
Definition Program.cpp:482
std::vector< std::reference_wrapper< Constant const > > getUndefinedConstants() const
Retrieves the undefined constants in the program.
Definition Program.cpp:368
std::map< storm::expressions::Variable, storm::expressions::Expression > getConstantsSubstitution() const
Retrieves a mapping of all defined constants to their defining expressions.
Definition Program.cpp:406
std::string const & getActionName(uint_fast64_t actionIndex) const
Retrieves the action name of the given action index.
Definition Program.cpp:742
std::vector< Module > const & getModules() const
Retrieves all modules of the program.
Definition Program.cpp:629
std::size_t getNumberOfRewardModels() const
Retrieves the number of reward models in the program.
Definition Program.cpp:812
std::vector< Constant > const & getConstants() const
Retrieves all constants defined in the program.
Definition Program.cpp:402
bool hasUnboundedVariables() const
Definition Program.cpp:271
bool hasLabel(std::string const &labelName) const
Checks whether the program has a label with the given name.
Definition Program.cpp:828
std::vector< IntegerVariable > const & getGlobalIntegerVariables() const
Retrieves the global integer variables of the program.
Definition Program.cpp:486
bool hasUndefinedConstants() const
Retrieves whether there are undefined constants of any type in the program.
Definition Program.cpp:285
bool hasRewardModel() const
Retrieves whether the program has reward models.
Definition Program.cpp:799
Composition const & getSubcomposition() const
std::map< std::string, std::string > const & getActionRenaming() const
std::set< std::string > const & getSynchronizingActions() const
bool hasStateRewards() const
Retrieves whether there are any state rewards.
bool hasTransitionRewards() const
Retrieves whether there are any transition rewards.
std::string const & getName() const
Retrieves the name of the reward model.
bool hasStateActionRewards() const
Retrieves whether there are any state-action rewards.
std::vector< storm::prism::Assignment > const & getAssignments() const
Retrieves a reference to the map of variable names to their respective assignments.
Definition Update.cpp:44
#define STORM_LOG_INFO(message)
Definition logging.h:29
#define STORM_LOG_TRACE(message)
Definition logging.h:17
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
void getTerminalStatesFromFormula(storm::logic::Formula const &formula, std::function< void(storm::expressions::Expression const &, bool)> const &terminalExpressionCallback, std::function< void(std::string const &, bool)> const &terminalLabelCallback)
Traverses the formula.
void checkRewards(storm::dd::Add< Type, ValueType > const &rewards, std::string const &rewardType)
Expression ite(Expression const &condition, Expression const &thenExpression, Expression const &elseExpression)
std::pair< storm::RationalNumber, storm::RationalNumber > count(std::vector< storm::storage::BitVector > const &origSets, std::vector< storm::storage::BitVector > const &intersects, std::vector< storm::storage::BitVector > const &intersectsInfo, storm::RationalNumber val, bool plus, uint64_t remdepth)
SettingsType const & getModule()
Get module.
static double log2(ValueType number)
Definition math.h:14
LabParser.cpp.
Definition cli.cpp:18
RationalFunctionVariable createRFVariable(std::string const &name)
carl::Variable RationalFunctionVariable
carl::RationalFunction< Polynomial, true > RationalFunction
void preserveFormula(storm::logic::Formula const &formula)
Changes the options in a way that ensures that the given formula can be checked on the model once it ...
void setTerminalStatesFromFormula(storm::logic::Formula const &formula)
Analyzes the given formula and sets an expression for the states states of the model that can be trea...
Options()
Creates an object representing the default building options.
DdPrismModelBuilder< Type, ValueType >::ModuleDecisionDiagram globalModule
SystemResult(storm::dd::Add< Type, ValueType > const &allTransitionsDd, DdPrismModelBuilder< Type, ValueType >::ModuleDecisionDiagram const &globalModule, boost::optional< storm::dd::Add< Type, ValueType > > const &stateActionDd)
boost::optional< storm::dd::Add< Type, ValueType > > stateActionDd