Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
Program.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <boost/algorithm/string/join.hpp>
5#include <sstream>
6
25
26namespace storm {
27namespace prism {
29 public:
30 CompositionValidityChecker(storm::prism::Program const& program) : program(program) {
31 // Intentionally left empty.
32 }
33
34 void check(Composition const& composition) {
35 composition.accept(*this, boost::any());
36 STORM_LOG_THROW(appearingModules.size() == program.getNumberOfModules(), storm::exceptions::WrongFormatException,
37 "Not every module is used in the system composition.");
38 }
39
40 virtual boost::any visit(ModuleComposition const& composition, boost::any const&) override {
41 bool isValid = program.hasModule(composition.getModuleName());
42 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
43 "The module \"" << composition.getModuleName() << "\" referred to in the system composition does not exist.");
44 isValid = appearingModules.find(composition.getModuleName()) == appearingModules.end();
45 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
46 "The module \"" << composition.getModuleName() << "\" is referred to more than once in the system composition.");
47 appearingModules.insert(composition.getModuleName());
48 std::set<uint_fast64_t> synchronizingActionIndices = program.getModule(composition.getModuleName()).getSynchronizingActionIndices();
49 return synchronizingActionIndices;
50 }
51
52 virtual boost::any visit(RenamingComposition const& composition, boost::any const& data) override {
53 std::set<uint_fast64_t> subSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getSubcomposition().accept(*this, data));
54
55 std::set<uint_fast64_t> newSynchronizingActionIndices = subSynchronizingActionIndices;
56 for (auto const& namePair : composition.getActionRenaming()) {
57 if (!program.hasAction(namePair.first)) {
58 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << namePair.first << "'.");
59 } else if (!program.hasAction(namePair.second)) {
60 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << namePair.second << "'.");
61 } else {
62 uint_fast64_t fromIndex = program.getActionIndex(namePair.first);
63 uint_fast64_t toIndex = program.getActionIndex(namePair.second);
64 auto it = subSynchronizingActionIndices.find(fromIndex);
66 it != subSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException,
67 "Cannot rename action '" << namePair.first << "', because module '" << composition.getSubcomposition() << " does not have this action.");
68 newSynchronizingActionIndices.erase(newSynchronizingActionIndices.find(fromIndex));
69 newSynchronizingActionIndices.insert(toIndex);
70 }
71 }
72
73 return newSynchronizingActionIndices;
74 }
75
76 virtual boost::any visit(HidingComposition const& composition, boost::any const& data) override {
77 std::set<uint_fast64_t> subSynchronizingActionIndices = boost::any_cast<std::set<uint_fast64_t>>(composition.getSubcomposition().accept(*this, data));
78
79 for (auto const& action : composition.getActionsToHide()) {
80 if (!program.hasAction(action)) {
81 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << action << "'.");
82 } else {
83 uint_fast64_t index = program.getActionIndex(action);
84 auto it = subSynchronizingActionIndices.find(index);
85 STORM_LOG_THROW(it != subSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException,
86 "Cannot hide action '" << action << "', because module '" << composition.getSubcomposition() << " does not have this action.");
87 subSynchronizingActionIndices.erase(it);
88 }
89 }
90
91 return subSynchronizingActionIndices;
92 }
93
94 virtual boost::any visit(SynchronizingParallelComposition const& composition, boost::any const& data) override {
95 std::set<uint_fast64_t> leftSynchronizingActionIndices =
96 boost::any_cast<std::set<uint_fast64_t>>(composition.getLeftSubcomposition().accept(*this, data));
97 std::set<uint_fast64_t> rightSynchronizingActionIndices =
98 boost::any_cast<std::set<uint_fast64_t>>(composition.getRightSubcomposition().accept(*this, data));
99
100 std::set<uint_fast64_t> synchronizingActionIndices;
101 std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(),
102 rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin()));
103
104 return synchronizingActionIndices;
105 }
106
107 virtual boost::any visit(InterleavingParallelComposition const& composition, boost::any const& data) override {
108 std::set<uint_fast64_t> leftSynchronizingActionIndices =
109 boost::any_cast<std::set<uint_fast64_t>>(composition.getLeftSubcomposition().accept(*this, data));
110 std::set<uint_fast64_t> rightSynchronizingActionIndices =
111 boost::any_cast<std::set<uint_fast64_t>>(composition.getRightSubcomposition().accept(*this, data));
112
113 std::set<uint_fast64_t> synchronizingActionIndices;
114 std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(),
115 rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin()));
116
117 return synchronizingActionIndices;
118 }
119
120 virtual boost::any visit(RestrictedParallelComposition const& composition, boost::any const& data) override {
121 std::set<uint_fast64_t> leftSynchronizingActionIndices =
122 boost::any_cast<std::set<uint_fast64_t>>(composition.getLeftSubcomposition().accept(*this, data));
123 std::set<uint_fast64_t> rightSynchronizingActionIndices =
124 boost::any_cast<std::set<uint_fast64_t>>(composition.getRightSubcomposition().accept(*this, data));
125
126 for (auto const& action : composition.getSynchronizingActions()) {
127 if (!program.hasAction(action)) {
128 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "System composition refers to unknown action '" << action << "'.");
129 } else {
130 uint_fast64_t index = program.getActionIndex(action);
131 auto it = leftSynchronizingActionIndices.find(index);
132 STORM_LOG_THROW(it != leftSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException,
133 "Cannot synchronize on action '" << action << "', because module '" << composition.getLeftSubcomposition()
134 << " does not have this action.");
135 it = rightSynchronizingActionIndices.find(index);
136 STORM_LOG_THROW(it != rightSynchronizingActionIndices.end(), storm::exceptions::WrongFormatException,
137 "Cannot synchronize on action '" << action << "', because module '" << composition.getRightSubcomposition()
138 << " does not have this action.");
139 }
140 }
141
142 std::set<uint_fast64_t> synchronizingActionIndices;
143 std::set_union(leftSynchronizingActionIndices.begin(), leftSynchronizingActionIndices.end(), rightSynchronizingActionIndices.begin(),
144 rightSynchronizingActionIndices.end(), std::inserter(synchronizingActionIndices, synchronizingActionIndices.begin()));
145
146 return synchronizingActionIndices;
147 }
148
149 private:
150 storm::prism::Program const& program;
151 std::set<std::string> appearingModules;
152};
153
154Program::Program(std::shared_ptr<storm::expressions::ExpressionManager> manager, ModelType modelType, std::vector<Constant> const& constants,
155 std::vector<BooleanVariable> const& globalBooleanVariables, std::vector<IntegerVariable> const& globalIntegerVariables,
156 std::vector<Formula> const& formulas, std::vector<Player> const& players, std::vector<Module> const& modules,
157 std::map<std::string, uint_fast64_t> const& actionToIndexMap, std::vector<RewardModel> const& rewardModels, std::vector<Label> const& labels,
158 std::vector<ObservationLabel> const& observationLabels, boost::optional<InitialConstruct> const& initialConstruct,
159 boost::optional<SystemCompositionConstruct> const& compositionConstruct, bool prismCompatibility, std::string const& filename,
160 uint_fast64_t lineNumber, bool finalModel)
161 : LocatedInformation(filename, lineNumber),
162 manager(manager),
163 modelType(modelType),
164 constants(constants),
165 constantToIndexMap(),
166 globalBooleanVariables(globalBooleanVariables),
167 globalBooleanVariableToIndexMap(),
168 globalIntegerVariables(globalIntegerVariables),
169 globalIntegerVariableToIndexMap(),
170 formulas(formulas),
171 formulaToIndexMap(),
172 players(players),
173 modules(modules),
174 moduleToIndexMap(),
175 rewardModels(rewardModels),
176 rewardModelToIndexMap(),
177 systemCompositionConstruct(compositionConstruct),
178 labels(labels),
179 labelToIndexMap(),
180 observationLabels(observationLabels),
181 actionToIndexMap(actionToIndexMap),
182 indexToActionMap(),
183 actions(),
184 synchronizingActionIndices(),
185 actionIndicesToModuleIndexMap(),
186 variableToModuleIndexMap(),
187 possiblySynchronizingCommands(),
188 prismCompatibility(prismCompatibility) {
189 // Start by creating the necessary mappings from the given ones.
190 this->createMappings();
191
192 // Set the initial construct if given.
193 if (initialConstruct) {
194 this->initialConstruct = initialConstruct.get();
195 } else {
196 // Otherwise, we create the missing initial values.
197 this->createMissingInitialValues();
198 for (auto& modules : this->modules) {
199 modules.createMissingInitialValues();
200 }
201 }
202
203 uint64_t highestGlobalIndex = this->getHighestCommandIndex();
204 possiblySynchronizingCommands = storage::BitVector(highestGlobalIndex + 1);
205 std::set<uint64_t> possiblySynchronizingActionIndices;
206 for (uint64_t syncAction : synchronizingActionIndices) {
207 if (getModuleIndicesByActionIndex(syncAction).size() > 1) {
208 possiblySynchronizingActionIndices.insert(syncAction);
209 }
210 }
211 for (auto const& module : getModules()) {
212 for (auto const& command : module.getCommands()) {
213 if (command.isLabeled()) {
214 if (possiblySynchronizingActionIndices.count(command.getActionIndex()) > 0) {
215 possiblySynchronizingCommands.set(command.getGlobalIndex());
216 }
217 }
218 }
219 }
220
221 if (finalModel) {
222 // If the model is supposed to be a CTMC, but contains probabilistic commands, we transform them to Markovian
223 // commands and issue a warning.
224 if (modelType == storm::prism::Program::ModelType::CTMC && prismCompatibility) {
225 bool hasProbabilisticCommands = false;
226 for (auto& module : this->modules) {
227 for (auto& command : module.getCommands()) {
228 if (!command.isMarkovian()) {
229 command.setMarkovian(true);
230 hasProbabilisticCommands = true;
231 }
232 }
233 }
234 STORM_LOG_WARN_COND(!hasProbabilisticCommands,
235 "The input model is a CTMC, but uses probabilistic commands like they are used in PRISM. Consider rewriting the commands to "
236 "use Markovian commands instead.");
237 }
238 // Then check the validity.
240 }
241}
242
244 return modelType;
245}
246
248 return modelType == ModelType::DTMC || modelType == ModelType::MDP || modelType == ModelType::POMDP || modelType == ModelType::SMG;
249}
250
252 return modelType == ModelType::DTMC || modelType == ModelType::CTMC;
253}
254
256 return modelType == ModelType::POMDP;
257}
258
260 size_t res = 0;
261 for (auto const& module : this->getModules()) {
262 res += module.getNumberOfCommands();
263 }
264 return res;
265}
266
268 for (auto const& globalIntegerVariable : this->globalIntegerVariables) {
269 if (!globalIntegerVariable.hasLowerBoundExpression() || !globalIntegerVariable.hasUpperBoundExpression()) {
270 return true;
271 }
272 }
273 for (auto const& module : modules) {
274 if (module.hasUnboundedVariables()) {
275 return true;
276 }
277 }
278 return false;
279}
280
282 for (auto const& constant : this->getConstants()) {
283 if (!constant.isDefined()) {
284 return true;
285 }
286 }
287 return false;
288}
289
291 if (!this->hasUndefinedConstants()) {
292 return true;
293 }
294
295 // Gather the variables of all undefined constants.
296 std::set<storm::expressions::Variable> undefinedConstantVariables;
297 for (auto const& constant : this->getConstants()) {
298 if (!constant.isDefined()) {
299 undefinedConstantVariables.insert(constant.getExpressionVariable());
300 }
301 }
302
303 // Start by checking the defining expressions of all defined constants. If it contains a currently undefined
304 // constant, we need to mark the target constant as undefined as well.
305 for (auto const& constant : this->getConstants()) {
306 if (constant.isDefined()) {
307 if (constant.getExpression().containsVariable(undefinedConstantVariables)) {
308 undefinedConstantVariables.insert(constant.getExpressionVariable());
309 }
310 }
311 }
312
313 // Now check initial value and range expressions of global variables.
314 for (auto const& booleanVariable : this->getGlobalBooleanVariables()) {
315 if (booleanVariable.hasInitialValue()) {
316 if (booleanVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) {
317 return false;
318 }
319 }
320 }
321 for (auto const& integerVariable : this->getGlobalIntegerVariables()) {
322 if (integerVariable.hasInitialValue()) {
323 if (integerVariable.getInitialValueExpression().containsVariable(undefinedConstantVariables)) {
324 return false;
325 }
326 }
327 if (integerVariable.hasLowerBoundExpression() && integerVariable.getLowerBoundExpression().containsVariable(undefinedConstantVariables)) {
328 return false;
329 }
330 if (integerVariable.hasUpperBoundExpression() && integerVariable.getUpperBoundExpression().containsVariable(undefinedConstantVariables)) {
331 return false;
332 }
333 }
334
335 // Proceed by checking each of the modules.
336 for (auto const& module : this->getModules()) {
337 if (!module.containsVariablesOnlyInUpdateProbabilities(undefinedConstantVariables)) {
338 return false;
339 }
340 }
341
342 // Check the reward models.
343 for (auto const& rewardModel : this->getRewardModels()) {
344 rewardModel.containsVariablesOnlyInRewardValueExpressions(undefinedConstantVariables);
345 }
346
347 // Initial construct.
348 if (this->hasInitialConstruct()) {
349 if (this->getInitialConstruct().getInitialStatesExpression().containsVariable(undefinedConstantVariables)) {
350 return false;
351 }
352 }
353
354 // Labels.
355 for (auto const& label : this->getLabels()) {
356 if (label.getStatePredicateExpression().containsVariable(undefinedConstantVariables)) {
357 return false;
358 }
359 }
360
361 return true;
362}
363
364std::vector<std::reference_wrapper<storm::prism::Constant const>> Program::getUndefinedConstants() const {
365 std::vector<std::reference_wrapper<storm::prism::Constant const>> result;
366 for (auto const& constant : this->getConstants()) {
367 if (!constant.isDefined()) {
368 result.push_back(constant);
369 }
370 }
371 return result;
372}
373
375 std::stringstream stream;
376 bool printComma = false;
377 for (auto const& constant : getUndefinedConstants()) {
378 if (printComma) {
379 stream << ", ";
380 } else {
381 printComma = true;
382 }
383 stream << constant.get().getName() << " (" << constant.get().getType() << ")";
384 }
385 stream << ".";
386 return stream.str();
387}
388
389bool Program::hasConstant(std::string const& constantName) const {
390 return this->constantToIndexMap.find(constantName) != this->constantToIndexMap.end();
391}
392
393Constant const& Program::getConstant(std::string const& constantName) const {
394 auto const& constantIndexPair = this->constantToIndexMap.find(constantName);
395 return this->getConstants()[constantIndexPair->second];
396}
397
398std::vector<Constant> const& Program::getConstants() const {
399 return this->constants;
400}
401
402std::map<storm::expressions::Variable, storm::expressions::Expression> Program::getConstantsSubstitution() const {
403 return getConstantsFormulasSubstitution(true, false);
404}
405
406std::map<storm::expressions::Variable, storm::expressions::Expression> Program::getFormulasSubstitution() const {
407 return getConstantsFormulasSubstitution(false, true);
408}
409
410std::map<storm::expressions::Variable, storm::expressions::Expression> Program::getConstantsFormulasSubstitution(bool getConstantsSubstitution,
411 bool getFormulasSubstitution) const {
412 std::map<storm::expressions::Variable, storm::expressions::Expression> result;
414 for (auto const& constant : this->getConstants()) {
415 if (constant.isDefined()) {
416 result.emplace(constant.getExpressionVariable(), constant.getExpression().substitute(result));
417 }
418 }
419 }
421 for (auto const& formula : this->getFormulas()) {
422 result.emplace(formula.getExpressionVariable(), formula.getExpression().substitute(result));
423 }
424 }
425 return result;
426}
427
428std::map<storm::expressions::Variable, storm::expressions::Expression> Program::getSubstitutionForRenamedModule(
429 Module const& renamedModule, std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution) const {
430 auto renaming = getFinalRenamingOfModule(renamedModule);
431 std::map<storm::expressions::Variable, storm::expressions::Expression> renamingAsSubstitution;
432 for (auto const& renamingPair : renaming) {
433 if (getManager().hasVariable(renamingPair.first)) {
434 STORM_LOG_ASSERT(getManager().hasVariable(renamingPair.second), "Variable not found in renaming.");
435 renamingAsSubstitution.emplace(getManager().getVariable(renamingPair.first), getManager().getVariableExpression(renamingPair.second));
436 }
437 }
438
439 std::map<storm::expressions::Variable, storm::expressions::Expression> newSubstitution;
440 for (auto const& substVarExpr : substitution) {
441 newSubstitution.emplace(substVarExpr.first, storm::jani::substituteJaniExpression(substVarExpr.second, renamingAsSubstitution, false));
442 }
443 return newSubstitution;
444}
445
446std::map<std::string, std::string> Program::getFinalRenamingOfModule(Module const& renamedModule) const {
447 std::vector<Module const*> moduleStack = {&renamedModule};
448 while (moduleStack.back()->isRenamedFromModule()) {
449 moduleStack.push_back(&getModule(moduleStack.back()->getBaseModule()));
450 }
451
452 STORM_LOG_ASSERT(!moduleStack.back()->isRenamedFromModule(), "Last module should not be renamed.");
453 moduleStack.pop_back();
454 STORM_LOG_ASSERT(moduleStack.empty() || moduleStack.back()->isRenamedFromModule(), "Expected renamed module.");
455 std::map<std::string, std::string> currentRenaming;
456 while (!moduleStack.empty()) {
457 Module const& currentModule = *moduleStack.back();
458 moduleStack.pop_back();
459 STORM_LOG_ASSERT(currentModule.isRenamedFromModule(), "Expected renamed module.");
460 std::map<std::string, std::string> newRenaming = currentModule.getRenaming();
461 for (auto const& renaimingPair : newRenaming) {
462 auto findRes = currentRenaming.find(renaimingPair.second);
463 if (findRes != currentRenaming.end()) {
464 newRenaming[renaimingPair.second] = findRes->second;
465 currentRenaming.erase(findRes);
466 }
467 }
468 newRenaming.insert(currentRenaming.begin(), currentRenaming.end());
469 currentRenaming = std::move(newRenaming);
470 }
471 return currentRenaming;
472}
473
474std::size_t Program::getNumberOfConstants() const {
475 return this->getConstants().size();
476}
477
478std::vector<BooleanVariable> const& Program::getGlobalBooleanVariables() const {
479 return this->globalBooleanVariables;
480}
481
482std::vector<IntegerVariable> const& Program::getGlobalIntegerVariables() const {
483 return this->globalIntegerVariables;
484}
485
486std::set<storm::expressions::Variable> Program::getAllExpressionVariables(bool includeConstants) const {
487 std::set<storm::expressions::Variable> result;
488
489 if (includeConstants) {
490 for (auto const& constant : constants) {
491 result.insert(constant.getExpressionVariable());
492 }
493 }
494 for (auto const& variable : globalBooleanVariables) {
495 result.insert(variable.getExpressionVariable());
496 }
497 for (auto const& variable : globalIntegerVariables) {
498 result.insert(variable.getExpressionVariable());
499 }
500 for (auto const& module : modules) {
501 auto const& moduleVariables = module.getAllExpressionVariables();
502 result.insert(moduleVariables.begin(), moduleVariables.end());
503 }
504
505 return result;
506}
507
508std::vector<storm::expressions::Expression> Program::getAllRangeExpressions() const {
509 std::vector<storm::expressions::Expression> result;
510 for (auto const& globalIntegerVariable : this->globalIntegerVariables) {
511 if (globalIntegerVariable.hasLowerBoundExpression() || globalIntegerVariable.hasUpperBoundExpression()) {
512 result.push_back(globalIntegerVariable.getRangeExpression());
513 }
514 }
515
516 for (auto const& module : modules) {
517 std::vector<storm::expressions::Expression> moduleRangeExpressions = module.getAllRangeExpressions();
518 result.insert(result.end(), moduleRangeExpressions.begin(), moduleRangeExpressions.end());
519 }
520
521 return result;
522}
523
524bool Program::globalBooleanVariableExists(std::string const& variableName) const {
525 return this->globalBooleanVariableToIndexMap.count(variableName) > 0;
526}
527
528bool Program::globalIntegerVariableExists(std::string const& variableName) const {
529 return this->globalIntegerVariableToIndexMap.count(variableName) > 0;
530}
531
532BooleanVariable const& Program::getGlobalBooleanVariable(std::string const& variableName) const {
533 auto const& nameIndexPair = this->globalBooleanVariableToIndexMap.find(variableName);
534 STORM_LOG_THROW(nameIndexPair != this->globalBooleanVariableToIndexMap.end(), storm::exceptions::OutOfRangeException,
535 "Unknown boolean variable '" << variableName << "'.");
536 return this->getGlobalBooleanVariables()[nameIndexPair->second];
537}
538
539IntegerVariable const& Program::getGlobalIntegerVariable(std::string const& variableName) const {
540 auto const& nameIndexPair = this->globalIntegerVariableToIndexMap.find(variableName);
541 STORM_LOG_THROW(nameIndexPair != this->globalIntegerVariableToIndexMap.end(), storm::exceptions::OutOfRangeException,
542 "Unknown integer variable '" << variableName << "'.");
543 return this->getGlobalIntegerVariables()[nameIndexPair->second];
544}
545
547 return this->getGlobalBooleanVariables().size();
548}
549
551 return this->getGlobalIntegerVariables().size();
552}
553
554std::vector<Formula> const& Program::getFormulas() const {
555 return this->formulas;
556}
557
558std::vector<Player> const& Program::getPlayers() const {
559 return this->players;
560}
561
562std::size_t Program::getNumberOfPlayers() const {
563 return this->getPlayers().size();
564}
565
566storm::storage::PlayerIndex const& Program::getIndexOfPlayer(std::string const& playerName) const {
567 return this->playerToIndexMap.at(playerName);
568}
569
570std::map<std::string, storm::storage::PlayerIndex> const& Program::getPlayerNameToIndexMapping() const {
571 return playerToIndexMap;
572}
573
574std::vector<storm::storage::PlayerIndex> Program::buildModuleIndexToPlayerIndexMap() const {
575 std::vector<storm::storage::PlayerIndex> result(this->getModules().size(), storm::storage::INVALID_PLAYER_INDEX);
576 for (storm::storage::PlayerIndex i = 0; i < this->getPlayers().size(); ++i) {
577 for (auto const& module : this->getPlayers()[i].getModules()) {
578 STORM_LOG_ASSERT(hasModule(module), "Module " << module << " not found.");
579 STORM_LOG_ASSERT(moduleToIndexMap.at(module) < this->getModules().size(), "Module index " << moduleToIndexMap.at(module) << " out of range.");
580 result[moduleToIndexMap.at(module)] = i;
581 }
582 }
583 return result;
584}
585
586std::map<uint64_t, storm::storage::PlayerIndex> Program::buildActionIndexToPlayerIndexMap() const {
587 std::map<uint64_t, storm::storage::PlayerIndex> result;
588 // First insert an invalid player index for all available actions
589 for (auto const& action : indexToActionMap) {
590 result.emplace_hint(result.end(), action.first, storm::storage::INVALID_PLAYER_INDEX);
591 }
592 // Now set the actual player indices.
593 // Note that actions that are not assigned to a player will still have INVALID_PLAYER_INDEX afterwards
594 for (storm::storage::PlayerIndex i = 0; i < this->getPlayers().size(); ++i) {
595 for (auto const& act : this->getPlayers()[i].getActions()) {
596 STORM_LOG_ASSERT(hasAction(act), "Action " << act << " not found.");
597 result[actionToIndexMap.at(act)] = i;
598 }
599 }
600 return result;
601}
602
603std::size_t Program::getNumberOfFormulas() const {
604 return this->getFormulas().size();
605}
606
607std::size_t Program::getNumberOfModules() const {
608 return this->getModules().size();
609}
610
611storm::prism::Module const& Program::getModule(uint_fast64_t index) const {
612 return this->modules[index];
613}
614
615bool Program::hasModule(std::string const& moduleName) const {
616 return this->moduleToIndexMap.find(moduleName) != this->moduleToIndexMap.end();
617}
618
619Module const& Program::getModule(std::string const& moduleName) const {
620 auto const& nameIndexPair = this->moduleToIndexMap.find(moduleName);
621 STORM_LOG_THROW(nameIndexPair != this->moduleToIndexMap.end(), storm::exceptions::OutOfRangeException, "Unknown module '" << moduleName << "'.");
622 return this->getModules()[nameIndexPair->second];
623}
624
625std::vector<storm::prism::Module> const& Program::getModules() const {
626 return this->modules;
627}
628
629std::map<std::string, uint_fast64_t> const& Program::getActionNameToIndexMapping() const {
630 return actionToIndexMap;
631}
632
634 uint64_t result = 0;
635 for (auto const& m : modules) {
636 result += m.getNumberOfUnlabeledCommands();
637 }
638 return result;
639}
640
642 return static_cast<bool>(initialConstruct);
643}
644
645storm::prism::InitialConstruct const& Program::getInitialConstruct() const {
646 return this->initialConstruct.get();
647}
648
649boost::optional<InitialConstruct> const& Program::getOptionalInitialConstruct() const {
650 return this->initialConstruct;
651}
652
654 STORM_LOG_THROW(hasInitialConstruct(), exceptions::InvalidOperationException, "We can only update the initial construct, if it already exists.");
655 this->initialConstruct = boost::make_optional(InitialConstruct(newExpression));
656}
657
659 // If there is an initial construct, return its expression. If not, we construct the expression from the
660 // initial values of the variables (which have to exist).
661 if (this->hasInitialConstruct()) {
662 return this->getInitialConstruct().getInitialStatesExpression();
663 } else {
665
666 for (auto const& variable : this->getGlobalBooleanVariables()) {
667 if (result.isInitialized()) {
668 result = result && storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
669 } else {
670 result = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
671 }
672 }
673 for (auto const& variable : this->getGlobalIntegerVariables()) {
674 if (result.isInitialized()) {
675 result = result && variable.getExpressionVariable() == variable.getInitialValueExpression();
676 } else {
677 result = variable.getExpressionVariable() == variable.getInitialValueExpression();
678 }
679 }
680 for (auto const& module : this->getModules()) {
681 for (auto const& variable : module.getBooleanVariables()) {
682 if (result.isInitialized()) {
683 result = result && storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
684 } else {
685 result = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitialValueExpression());
686 }
687 }
688 for (auto const& variable : module.getIntegerVariables()) {
689 if (result.isInitialized()) {
690 result = result && variable.getExpressionVariable() == variable.getInitialValueExpression();
691 } else {
692 result = variable.getExpressionVariable() == variable.getInitialValueExpression();
693 }
694 }
695 }
696
697 // If there are no variables, there is no restriction on the initial states.
698 if (!result.isInitialized()) {
699 result = manager->boolean(true);
700 }
701
702 return result;
703 }
704}
705
707 for (auto const& module : this->modules) {
708 for (auto const& command : module.getCommands()) {
709 for (auto const& update : command.getUpdates()) {
710 if (update.isLikelihoodInterval()) {
711 return true;
712 }
713 }
714 }
715 }
716 return false;
717}
718
720 return static_cast<bool>(systemCompositionConstruct);
721}
722
724 return systemCompositionConstruct.get();
725}
726
727boost::optional<SystemCompositionConstruct> Program::getOptionalSystemCompositionConstruct() const {
728 return systemCompositionConstruct;
729}
730
731std::shared_ptr<Composition> Program::getDefaultSystemComposition() const {
732 std::shared_ptr<Composition> current = std::make_shared<ModuleComposition>(this->modules.front().getName());
733
734 for (uint_fast64_t index = 1; index < this->modules.size(); ++index) {
735 std::shared_ptr<Composition> newComposition =
736 std::make_shared<SynchronizingParallelComposition>(current, std::make_shared<ModuleComposition>(this->modules[index].getName()));
737 current = newComposition;
738 }
739
740 return current;
741}
742
743std::set<std::string> const& Program::getActions() const {
744 return this->actions;
745}
746
747std::set<uint_fast64_t> const& Program::getSynchronizingActionIndices() const {
748 return this->synchronizingActionIndices;
749}
750
751std::string const& Program::getActionName(uint_fast64_t actionIndex) const {
752 auto const& indexNamePair = this->indexToActionMap.find(actionIndex);
753 STORM_LOG_THROW(indexNamePair != this->indexToActionMap.end(), storm::exceptions::InvalidArgumentException, "Unknown action index " << actionIndex << ".");
754 return indexNamePair->second;
755}
756
757uint_fast64_t Program::getActionIndex(std::string const& actionName) const {
758 auto const& nameIndexPair = this->actionToIndexMap.find(actionName);
759 STORM_LOG_THROW(nameIndexPair != this->actionToIndexMap.end(), storm::exceptions::InvalidArgumentException, "Unknown action name '" << actionName << "'.");
760 return nameIndexPair->second;
761}
762
763bool Program::hasAction(std::string const& actionName) const {
764 return this->actionToIndexMap.find(actionName) != this->actionToIndexMap.end();
765}
766
767bool Program::hasAction(uint_fast64_t const& actionIndex) const {
768 return this->indexToActionMap.find(actionIndex) != this->indexToActionMap.end();
769}
770
771std::set<uint_fast64_t> const& Program::getModuleIndicesByAction(std::string const& action) const {
772 auto const& nameIndexPair = this->actionToIndexMap.find(action);
773 STORM_LOG_THROW(nameIndexPair != this->actionToIndexMap.end(), storm::exceptions::OutOfRangeException, "Action name '" << action << "' does not exist.");
774 return this->getModuleIndicesByActionIndex(nameIndexPair->second);
775}
776
777std::set<uint_fast64_t> const& Program::getModuleIndicesByActionIndex(uint_fast64_t actionIndex) const {
778 auto const& actionModuleSetPair = this->actionIndicesToModuleIndexMap.find(actionIndex);
779 STORM_LOG_THROW(actionModuleSetPair != this->actionIndicesToModuleIndexMap.end(), storm::exceptions::OutOfRangeException,
780 "Action with index '" << actionIndex << "' does not exist.");
781 return actionModuleSetPair->second;
782}
783
784uint_fast64_t Program::getModuleIndexByVariable(std::string const& variableName) const {
785 auto const& variableNameToModuleIndexPair = this->variableToModuleIndexMap.find(variableName);
786 STORM_LOG_THROW(variableNameToModuleIndexPair != this->variableToModuleIndexMap.end(), storm::exceptions::OutOfRangeException,
787 "Variable '" << variableName << "' does not exist.");
788 return variableNameToModuleIndexPair->second;
789}
790
791std::pair<uint_fast64_t, uint_fast64_t> Program::getModuleCommandIndexByGlobalCommandIndex(uint_fast64_t globalCommandIndex) const {
792 uint_fast64_t moduleIndex = 0;
793 for (auto const& module : modules) {
794 uint_fast64_t commandIndex = 0;
795 for (auto const& command : module.getCommands()) {
796 if (command.getGlobalIndex() == globalCommandIndex) {
797 return std::pair<uint_fast64_t, uint_fast64_t>(moduleIndex, commandIndex);
798 }
799 ++commandIndex;
800 }
801 ++moduleIndex;
802 }
803 // This point should not be reached if the globalCommandIndex is valid
804 STORM_LOG_THROW(false, storm::exceptions::OutOfRangeException, "Global command index '" << globalCommandIndex << "' does not exist.");
805 return std::pair<uint_fast64_t, uint_fast64_t>(0, 0);
806}
807
809 return !this->rewardModels.empty();
810}
811
812bool Program::hasRewardModel(std::string const& name) const {
813 auto const& nameIndexPair = this->rewardModelToIndexMap.find(name);
814 return nameIndexPair != this->rewardModelToIndexMap.end();
815}
816
817std::vector<storm::prism::RewardModel> const& Program::getRewardModels() const {
818 return this->rewardModels;
819}
820
822 return this->getRewardModels().size();
823}
824
825storm::prism::RewardModel const& Program::getRewardModel(std::string const& name) const {
826 auto const& nameIndexPair = this->rewardModelToIndexMap.find(name);
827 STORM_LOG_THROW(nameIndexPair != this->rewardModelToIndexMap.end(), storm::exceptions::OutOfRangeException,
828 "Reward model '" << name << "' does not exist.");
829 return this->getRewardModels()[nameIndexPair->second];
830}
831
832RewardModel const& Program::getRewardModel(uint_fast64_t index) const {
833 STORM_LOG_THROW(this->getNumberOfRewardModels() > index, storm::exceptions::OutOfRangeException, "Reward model with index " << index << " does not exist.");
834 return this->rewardModels[index];
835}
836
837bool Program::hasLabel(std::string const& labelName) const {
838 auto it = std::find_if(labels.begin(), labels.end(), [&labelName](storm::prism::Label const& label) { return label.getName() == labelName; });
839 return it != labels.end();
840}
841
842std::vector<Label> const& Program::getLabels() const {
843 return this->labels;
844}
845
846bool Program::hasFormula(std::string const& formulaName) const {
847 return this->formulaToIndexMap.find(formulaName) != this->formulaToIndexMap.end();
848}
849
850Formula const& Program::getFormula(std::string const& formulaName) const {
851 STORM_LOG_ASSERT(this->hasFormula(formulaName), "Formula with name '" << formulaName << "' does not exist.");
852 return formulas[this->formulaToIndexMap.at(formulaName)];
853}
854
855std::vector<storm::expressions::Expression> Program::getAllGuards(bool negated) const {
856 std::vector<storm::expressions::Expression> allGuards;
857 for (auto const& module : modules) {
858 for (auto const& command : module.getCommands()) {
859 allGuards.push_back(negated ? !command.getGuardExpression() : command.getGuardExpression());
860 }
861 }
862 return allGuards;
863}
864
865storm::expressions::Expression const& Program::getLabelExpression(std::string const& label) const {
866 auto const& labelIndexPair = labelToIndexMap.find(label);
867 STORM_LOG_THROW(labelIndexPair != labelToIndexMap.end(), storm::exceptions::InvalidArgumentException,
868 "Cannot retrieve expression for unknown label '" << label << "'.");
869 return this->labels[labelIndexPair->second].getStatePredicateExpression();
870}
871
872std::map<std::string, storm::expressions::Expression> Program::getLabelToExpressionMapping() const {
873 std::map<std::string, storm::expressions::Expression> result;
874 for (auto const& label : labels) {
875 result.emplace(label.getName(), label.getStatePredicateExpression());
876 }
877 return result;
878}
879
880std::size_t Program::getNumberOfLabels() const {
881 return this->getLabels().size();
882}
883
884void Program::addLabel(std::string const& name, storm::expressions::Expression const& statePredicateExpression) {
885 auto it = std::find_if(this->labels.begin(), this->labels.end(), [&name](storm::prism::Label const& label) { return label.getName() == name; });
886 STORM_LOG_THROW(it == this->labels.end(), storm::exceptions::InvalidArgumentException,
887 "Cannot add a label '" << name << "', because a label with that name already exists.");
888 this->labels.emplace_back(name, statePredicateExpression);
889}
890
891void Program::removeLabel(std::string const& name) {
892 auto it = std::find_if(this->labels.begin(), this->labels.end(), [&name](storm::prism::Label const& label) { return label.getName() == name; });
893 STORM_LOG_THROW(it != this->labels.end(), storm::exceptions::InvalidArgumentException, "Canno remove unknown label '" << name << "'.");
894 this->labels.erase(it);
895}
896
898 this->rewardModels.clear();
899 this->rewardModelToIndexMap.clear();
900}
901
902void Program::filterLabels(std::set<std::string> const& labelSet) {
903 std::vector<storm::prism::Label> newLabels;
904 newLabels.reserve(labelSet.size());
905
906 // Now filter the labels by the criterion whether or not their name appears in the given label set.
907 for (auto it = labels.begin(), ite = labels.end(); it != ite; ++it) {
908 auto setIt = labelSet.find(it->getName());
909 if (setIt != labelSet.end()) {
910 newLabels.emplace_back(*it);
911 }
912 }
913
914 // Move the new labels in place.
915 this->labels = std::move(newLabels);
916}
917
918std::vector<ObservationLabel> const& Program::getObservationLabels() const {
919 return this->observationLabels;
920}
921
923 return this->observationLabels.size();
924}
925
927 return possiblySynchronizingCommands;
928}
929
931 std::vector<storm::prism::Module> newModules;
932 newModules.reserve(this->getNumberOfModules());
933
934 for (auto const& module : this->getModules()) {
935 newModules.push_back(module.restrictCommands(indexSet));
936 }
937
938 return Program(this->manager, this->getModelType(), this->getConstants(), this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(),
939 this->getFormulas(), this->getPlayers(), newModules, this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(),
940 this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
941}
942
943void Program::createMappings() {
944 // Build the mappings for constants, global variables, formulas, modules, reward models and labels.
945 for (uint_fast64_t constantIndex = 0; constantIndex < this->getNumberOfConstants(); ++constantIndex) {
946 this->constantToIndexMap[this->getConstants()[constantIndex].getName()] = constantIndex;
947 }
948 for (uint_fast64_t globalVariableIndex = 0; globalVariableIndex < this->getNumberOfGlobalBooleanVariables(); ++globalVariableIndex) {
949 this->globalBooleanVariableToIndexMap[this->getGlobalBooleanVariables()[globalVariableIndex].getName()] = globalVariableIndex;
950 }
951 for (uint_fast64_t globalVariableIndex = 0; globalVariableIndex < this->getNumberOfGlobalIntegerVariables(); ++globalVariableIndex) {
952 this->globalIntegerVariableToIndexMap[this->getGlobalIntegerVariables()[globalVariableIndex].getName()] = globalVariableIndex;
953 }
954 for (uint_fast64_t formulaIndex = 0; formulaIndex < this->getNumberOfFormulas(); ++formulaIndex) {
955 this->formulaToIndexMap[this->getFormulas()[formulaIndex].getName()] = formulaIndex;
956 }
957 for (uint_fast64_t labelIndex = 0; labelIndex < this->getNumberOfLabels(); ++labelIndex) {
958 this->labelToIndexMap[this->getLabels()[labelIndex].getName()] = labelIndex;
959 }
960 for (uint_fast64_t moduleIndex = 0; moduleIndex < this->getNumberOfModules(); ++moduleIndex) {
961 this->moduleToIndexMap[this->getModules()[moduleIndex].getName()] = moduleIndex;
962 }
963 for (storm::storage::PlayerIndex playerIndex = 0; playerIndex < this->getNumberOfPlayers(); ++playerIndex) {
964 this->playerToIndexMap[this->getPlayers()[playerIndex].getName()] = playerIndex;
965 }
966 for (uint_fast64_t rewardModelIndex = 0; rewardModelIndex < this->getNumberOfRewardModels(); ++rewardModelIndex) {
967 this->rewardModelToIndexMap[this->getRewardModels()[rewardModelIndex].getName()] = rewardModelIndex;
968 }
969
970 for (auto const& actionIndexPair : this->getActionNameToIndexMapping()) {
971 this->actions.insert(actionIndexPair.first);
972 this->indexToActionMap.emplace(actionIndexPair.second, actionIndexPair.first);
973
974 // Only let all non-zero indices be synchronizing.
975 if (actionIndexPair.second != 0) {
976 this->synchronizingActionIndices.insert(actionIndexPair.second);
977 this->actionIndicesToModuleIndexMap[actionIndexPair.second] = std::set<uint_fast64_t>();
978 }
979 }
980
981 // Build the mapping from action names to module indices so that the lookup can later be performed quickly.
982 for (unsigned int moduleIndex = 0; moduleIndex < this->getNumberOfModules(); moduleIndex++) {
983 Module const& module = this->getModule(moduleIndex);
984
985 for (auto const& actionIndex : module.getSynchronizingActionIndices()) {
986 this->actionIndicesToModuleIndexMap[actionIndex].insert(moduleIndex);
987 }
988
989 // Put in the appropriate entries for the mapping from variable names to module index.
990 for (auto const& booleanVariable : module.getBooleanVariables()) {
991 this->variableToModuleIndexMap[booleanVariable.getName()] = moduleIndex;
992 }
993 for (auto const& integerVariable : module.getIntegerVariables()) {
994 this->variableToModuleIndexMap[integerVariable.getName()] = moduleIndex;
995 }
996 for (auto const& clockVariable : module.getClockVariables()) {
997 this->variableToModuleIndexMap[clockVariable.getName()] = moduleIndex;
998 }
999 }
1000}
1001
1002Program Program::defineUndefinedConstants(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const {
1003 // For sanity checking, we keep track of all undefined constants that we define in the course of this procedure.
1004 std::set<storm::expressions::Variable> definedUndefinedConstants;
1005
1006 std::vector<Constant> newConstants;
1007 newConstants.reserve(this->getNumberOfConstants());
1008 for (auto const& constant : this->getConstants()) {
1009 // If the constant is already defined, we need to replace the appearances of undefined constants in its
1010 // defining expression
1011 if (constant.isDefined()) {
1012 // Make sure we are not trying to define an already defined constant.
1013 STORM_LOG_THROW(constantDefinitions.find(constant.getExpressionVariable()) == constantDefinitions.end(),
1014 storm::exceptions::InvalidArgumentException, "Illegally defining already defined constant '" << constant.getName() << "'.");
1015
1016 // Now replace the occurrences of undefined constants in its defining expression.
1017 newConstants.emplace_back(constant.getExpressionVariable(), constant.getExpression().substitute(constantDefinitions), constant.getFilename(),
1018 constant.getLineNumber());
1019 } else {
1020 auto const& variableExpressionPair = constantDefinitions.find(constant.getExpressionVariable());
1021
1022 // If the constant is not defined by the mapping, we leave it like it is.
1023 if (variableExpressionPair == constantDefinitions.end()) {
1024 newConstants.emplace_back(constant);
1025 } else {
1026 // Otherwise, we add it to the defined constants and assign it the appropriate expression.
1027 definedUndefinedConstants.insert(constant.getExpressionVariable());
1028
1029 // Make sure the type of the constant is correct.
1030 STORM_LOG_THROW(variableExpressionPair->second.getType() == constant.getType(), storm::exceptions::InvalidArgumentException,
1031 "Illegal type of expression defining constant '" << constant.getName() << "'.");
1032
1033 // Now create the defined constant.
1034 newConstants.emplace_back(constant.getExpressionVariable(), variableExpressionPair->second, constant.getFilename(), constant.getLineNumber());
1035 }
1036 }
1037 }
1038
1039 return Program(this->manager, this->getModelType(), newConstants, this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(), this->getFormulas(),
1040 this->getPlayers(), this->getModules(), this->getActionNameToIndexMapping(), this->getRewardModels(), this->getLabels(),
1041 this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
1042}
1043
1045 return substituteConstantsFormulas(true, false);
1046}
1047
1049 return substituteConstantsFormulas(false, true);
1050}
1051
1053 // TODO support in constants, initial construct, and rewards
1054
1055 std::vector<Formula> newFormulas;
1056 newFormulas.reserve(this->getNumberOfFormulas());
1057 for (auto const& oldFormula : this->getFormulas()) {
1058 newFormulas.emplace_back(oldFormula.substituteNonStandardPredicates());
1059 }
1060
1061 std::vector<BooleanVariable> newBooleanVariables;
1062 newBooleanVariables.reserve(this->getNumberOfGlobalBooleanVariables());
1063 for (auto const& booleanVariable : this->getGlobalBooleanVariables()) {
1064 newBooleanVariables.emplace_back(booleanVariable.substituteNonStandardPredicates());
1065 }
1066
1067 std::vector<IntegerVariable> newIntegerVariables;
1068 newBooleanVariables.reserve(this->getNumberOfGlobalIntegerVariables());
1069 for (auto const& integerVariable : this->getGlobalIntegerVariables()) {
1070 newIntegerVariables.emplace_back(integerVariable.substituteNonStandardPredicates());
1071 }
1072
1073 std::vector<Module> newModules;
1074 newModules.reserve(this->getNumberOfModules());
1075 for (auto const& module : this->getModules()) {
1076 newModules.emplace_back(module.substituteNonStandardPredicates());
1077 }
1078
1079 std::vector<Label> newLabels;
1080 newLabels.reserve(this->getNumberOfLabels());
1081 for (auto const& label : this->getLabels()) {
1082 newLabels.emplace_back(label.substituteNonStandardPredicates());
1083 }
1084
1085 std::vector<ObservationLabel> newObservationLabels;
1086 newObservationLabels.reserve(this->getNumberOfObservationLabels());
1087 for (auto const& label : this->getObservationLabels()) {
1088 newObservationLabels.emplace_back(label.substituteNonStandardPredicates());
1089 }
1090
1091 return Program(this->manager, this->getModelType(), this->getConstants(), newBooleanVariables, newIntegerVariables, newFormulas, this->getPlayers(),
1092 newModules, this->getActionNameToIndexMapping(), this->getRewardModels(), newLabels, newObservationLabels, initialConstruct,
1093 this->getOptionalSystemCompositionConstruct(), prismCompatibility);
1094}
1095
1097 // Formulas need to be substituted first. otherwise, constants appearing in formula expressions can not be handled properly
1099 return this->substituteFormulas().substituteConstants();
1100 }
1101
1102 // We start by creating the appropriate substitution.
1103 std::map<storm::expressions::Variable, storm::expressions::Expression> substitution =
1105
1106 std::vector<Constant> newConstants;
1107 newConstants.reserve(this->getNumberOfConstants());
1108 for (auto const& oldConstant : this->getConstants()) {
1109 newConstants.push_back(oldConstant.substitute(substitution));
1110 }
1111
1112 std::vector<Formula> newFormulas;
1113 newFormulas.reserve(this->getNumberOfFormulas());
1114 for (auto const& oldFormula : this->getFormulas()) {
1115 newFormulas.emplace_back(oldFormula.substitute(substitution));
1116 }
1117
1118 std::vector<BooleanVariable> newBooleanVariables;
1119 newBooleanVariables.reserve(this->getNumberOfGlobalBooleanVariables());
1120 for (auto const& booleanVariable : this->getGlobalBooleanVariables()) {
1121 newBooleanVariables.emplace_back(booleanVariable.substitute(substitution));
1122 }
1123
1124 std::vector<IntegerVariable> newIntegerVariables;
1125 newBooleanVariables.reserve(this->getNumberOfGlobalIntegerVariables());
1126 for (auto const& integerVariable : this->getGlobalIntegerVariables()) {
1127 newIntegerVariables.emplace_back(integerVariable.substitute(substitution));
1128 }
1129
1130 std::vector<Module> newModules;
1131 newModules.reserve(this->getNumberOfModules());
1132 for (auto const& module : this->getModules()) {
1133 if (module.isRenamedFromModule()) {
1134 // The renaming needs to be applied to the substitution as well.
1135 auto renamedSubstitution = getSubstitutionForRenamedModule(module, substitution);
1136 newModules.emplace_back(module.substitute(renamedSubstitution));
1137 } else {
1138 newModules.emplace_back(module.substitute(substitution));
1139 }
1140 }
1141
1142 std::vector<RewardModel> newRewardModels;
1143 newRewardModels.reserve(this->getNumberOfRewardModels());
1144 for (auto const& rewardModel : this->getRewardModels()) {
1145 newRewardModels.emplace_back(rewardModel.substitute(substitution));
1146 }
1147
1148 boost::optional<storm::prism::InitialConstruct> newInitialConstruct;
1149 if (this->hasInitialConstruct()) {
1150 newInitialConstruct = this->getInitialConstruct().substitute(substitution);
1151 }
1152
1153 std::vector<Label> newLabels;
1154 newLabels.reserve(this->getNumberOfLabels());
1155 for (auto const& label : this->getLabels()) {
1156 newLabels.emplace_back(label.substitute(substitution));
1157 }
1158
1159 std::vector<ObservationLabel> newObservationLabels;
1160 newObservationLabels.reserve(this->getNumberOfObservationLabels());
1161 for (auto const& label : this->getObservationLabels()) {
1162 newObservationLabels.emplace_back(label.substitute(substitution));
1163 }
1164
1165 return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, newFormulas, this->getPlayers(), newModules,
1166 this->getActionNameToIndexMapping(), newRewardModels, newLabels, newObservationLabels, newInitialConstruct,
1167 this->getOptionalSystemCompositionConstruct(), prismCompatibility);
1168}
1169
1170Program Program::preprocess(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const {
1172}
1173
1174Program Program::preprocess(std::string const& constantDefinitionString) const {
1175 return this->preprocess(storm::storage::parseConstantDefinitionString(this->getManager(), constantDefinitionString));
1176}
1177
1178Program Program::labelUnlabelledCommands(std::map<uint64_t, std::string> const& nameSuggestions) const {
1179 for (auto const& entry : nameSuggestions) {
1180 STORM_LOG_THROW(!hasAction(entry.second), storm::exceptions::InvalidArgumentException, "Cannot suggest names already in the program.");
1181 }
1182 std::vector<Module> newModules;
1183 std::vector<RewardModel> newRewardModels;
1184 std::map<std::string, uint64_t> newActionNameToIndexMapping = getActionNameToIndexMapping();
1185
1186 uint64_t oldId = 1;
1187 if (!getSynchronizingActionIndices().empty()) {
1188 oldId = *(getSynchronizingActionIndices().rbegin()) + 1;
1189 }
1190 uint64_t newId = oldId;
1191 for (auto const& module : modules) {
1192 newModules.push_back(module.labelUnlabelledCommands(nameSuggestions, newId, newActionNameToIndexMapping));
1193 }
1194
1195 std::vector<std::pair<uint64_t, std::string>> newActionNames;
1196 for (auto const& entry : newActionNameToIndexMapping) {
1197 if (!hasAction(entry.first)) {
1198 newActionNames.emplace_back(entry.second, entry.first);
1199 }
1200 }
1201 for (auto const& rewardModel : rewardModels) {
1202 newRewardModels.push_back(rewardModel.labelUnlabelledCommands(newActionNames));
1203 }
1204
1205 return Program(this->manager, this->getModelType(), this->getConstants(), this->getGlobalBooleanVariables(), this->getGlobalIntegerVariables(),
1206 this->getFormulas(), this->getPlayers(), newModules, newActionNameToIndexMapping, newRewardModels, this->getLabels(),
1207 this->getObservationLabels(), this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
1208}
1209
1211 std::vector<BooleanVariable> newBooleanVariables = globalBooleanVariables;
1212 for (auto& newVar : newBooleanVariables) {
1213 newVar.setInitialValueExpression(storm::expressions::Expression());
1214 }
1215
1216 std::vector<IntegerVariable> newIntegerVariables = globalIntegerVariables;
1217 for (auto& newVar : newIntegerVariables) {
1218 newVar.setInitialValueExpression(storm::expressions::Expression());
1219 }
1220
1221 std::vector<Module> newModules = this->getModules();
1222 for (auto& module : newModules) {
1223 module.removeVariableInitialization();
1224 }
1225
1226 return Program(this->manager, this->getModelType(), this->getConstants(), newBooleanVariables, newIntegerVariables, this->getFormulas(), this->getPlayers(),
1227 newModules, this->actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getObservationLabels(),
1229}
1230
1232 bool observable) const {
1233 STORM_LOG_THROW(this->getModelType() == ModelType::POMDP || observable, storm::exceptions::InvalidArgumentException,
1234 "Variables can only be unobservable in POMDPs.");
1235 std::vector<BooleanVariable> newBooleanVariables = globalBooleanVariables;
1236 std::vector<IntegerVariable> newIntegerVariables = globalIntegerVariables;
1237 std::vector<Constant> newConstants = constants;
1238 auto newEnd = std::remove(newConstants.begin(), newConstants.end(), c);
1239 newConstants.erase(newEnd, newConstants.end()); // Erase is necessary based on Erase-remove idiom
1240 // The following throw is moved here as this is cheaper.
1241 STORM_LOG_THROW(newConstants.size() == constants.size() - 1, exceptions::InvalidArgumentException, "Can only replace a constant if it is present.");
1242 if (c.getType().isBooleanType()) {
1243 newBooleanVariables.emplace_back(c.getExpressionVariable(), c.getExpression(), observable);
1244 } else {
1245 newIntegerVariables.emplace_back(c.getExpressionVariable(), lowerBound, upperBound, c.getExpression(), observable);
1246 }
1247 return Program(this->manager, this->getModelType(), newConstants, newBooleanVariables, newIntegerVariables, this->getFormulas(), this->getPlayers(),
1248 modules, this->actionToIndexMap, this->getRewardModels(), this->getLabels(), this->getObservationLabels(),
1249 this->getOptionalInitialConstruct(), this->getOptionalSystemCompositionConstruct(), prismCompatibility);
1250}
1251
1253 // Start by checking the constant declarations.
1254 std::set<storm::expressions::Variable> all;
1255 std::set<storm::expressions::Variable> allGlobals;
1256 std::set<storm::expressions::Variable> globalVariables;
1257 std::set<storm::expressions::Variable> constants;
1258 for (auto const& constant : this->getConstants()) {
1259 // Check defining expressions of defined constants.
1260 if (constant.isDefined()) {
1261 std::set<storm::expressions::Variable> containedVariables = constant.getExpression().getVariables();
1262 std::set<storm::expressions::Variable> illegalVariables;
1263 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1264 std::inserter(illegalVariables, illegalVariables.begin()));
1265 bool isValid = illegalVariables.empty();
1266
1267 if (!isValid) {
1268 std::vector<std::string> illegalVariableNames;
1269 for (auto const& var : illegalVariables) {
1270 illegalVariableNames.push_back(var.getName());
1271 }
1272 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1273 "Error in " << constant.getFilename() << ", line " << constant.getLineNumber()
1274 << ": defining expression refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",")
1275 << ".");
1276 }
1277 }
1278
1279 // Record the new identifier for future checks.
1280 constants.insert(constant.getExpressionVariable());
1281 all.insert(constant.getExpressionVariable());
1282 allGlobals.insert(constant.getExpressionVariable());
1283 }
1284
1285 // Now we check the variable declarations. We start with the global variables.
1286 std::set<storm::expressions::Variable> variables;
1287 for (auto const& variable : this->getGlobalBooleanVariables()) {
1288 if (variable.hasInitialValue()) {
1289 STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException,
1290 "Error for " << variable.getName() << " (" << variable.getFilename() << ", line " << variable.getLineNumber()
1291 << "): illegal to specify initial value if an initial construct is present.");
1292
1293 // Check the initial value of the variable.
1294 std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables();
1295 std::set<storm::expressions::Variable> illegalVariables;
1296 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1297 std::inserter(illegalVariables, illegalVariables.begin()));
1298 bool isValid = illegalVariables.empty();
1299
1300 if (!isValid) {
1301 std::vector<std::string> illegalVariableNames;
1302 for (auto const& var : illegalVariables) {
1303 illegalVariableNames.push_back(var.getName());
1304 }
1305 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1306 "Error in " << variable.getFilename() << ", line " << variable.getLineNumber()
1307 << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",")
1308 << ".");
1309 }
1310 }
1311
1312 // Record the new identifier for future checks.
1313 variables.insert(variable.getExpressionVariable());
1314 all.insert(variable.getExpressionVariable());
1315 allGlobals.insert(variable.getExpressionVariable());
1316 globalVariables.insert(variable.getExpressionVariable());
1317 }
1318 for (auto const& variable : this->getGlobalIntegerVariables()) {
1319 // Check that bound expressions of the range.
1320 if (variable.hasLowerBoundExpression()) {
1321 std::set<storm::expressions::Variable> containedVariables = variable.getLowerBoundExpression().getVariables();
1322 std::set<storm::expressions::Variable> illegalVariables;
1323 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1324 std::inserter(illegalVariables, illegalVariables.begin()));
1325 bool isValid = illegalVariables.empty();
1326
1327 if (!isValid) {
1328 std::vector<std::string> illegalVariableNames;
1329 for (auto const& var : illegalVariables) {
1330 illegalVariableNames.push_back(var.getName());
1331 }
1332 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1333 "Error in " << variable.getFilename() << ", line " << variable.getLineNumber()
1334 << ": lower bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",")
1335 << ".");
1336 }
1337 }
1338
1339 if (variable.hasUpperBoundExpression()) {
1340 std::set<storm::expressions::Variable> containedVariables = variable.getUpperBoundExpression().getVariables();
1341 std::set<storm::expressions::Variable> illegalVariables;
1342 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1343 std::inserter(illegalVariables, illegalVariables.begin()));
1344 bool isValid = illegalVariables.empty();
1345 if (!isValid) {
1346 std::vector<std::string> illegalVariableNames;
1347 for (auto const& var : illegalVariables) {
1348 illegalVariableNames.push_back(var.getName());
1349 }
1350 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1351 "Error in " << variable.getFilename() << ", line " << variable.getLineNumber()
1352 << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",")
1353 << ".");
1354 }
1355 }
1356
1357 if (variable.hasInitialValue()) {
1358 STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException,
1359 "Error for " << variable.getName() << " (" << variable.getFilename() << ", line " << variable.getLineNumber()
1360 << "): illegal to specify initial value if an initial construct is present.");
1361
1362 // Check the initial value of the variable.
1363 std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables();
1364 std::set<storm::expressions::Variable> illegalVariables;
1365 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1366 std::inserter(illegalVariables, illegalVariables.begin()));
1367 bool isValid = illegalVariables.empty();
1368 if (!isValid) {
1369 std::vector<std::string> illegalVariableNames;
1370 for (auto const& var : illegalVariables) {
1371 illegalVariableNames.push_back(var.getName());
1372 }
1373 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1374 "Error in " << variable.getFilename() << ", line " << variable.getLineNumber()
1375 << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",")
1376 << ".");
1377 }
1378 }
1379
1380 // Record the new identifier for future checks.
1381 variables.insert(variable.getExpressionVariable());
1382 all.insert(variable.getExpressionVariable());
1383 allGlobals.insert(variable.getExpressionVariable());
1384 globalVariables.insert(variable.getExpressionVariable());
1385 }
1386
1387 // Now go through the variables of the modules.
1388 for (auto const& module : this->getModules()) {
1389 for (auto const& variable : module.getBooleanVariables()) {
1390 if (variable.hasInitialValue()) {
1391 STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException,
1392 "Error for " << module.getName() << "." << variable.getName() << " (" << variable.getFilename() << ", line "
1393 << variable.getLineNumber() << "): illegal to specify initial value if an initial construct is present.");
1394
1395 // Check the initial value of the variable.
1396 std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables();
1397 std::set<storm::expressions::Variable> illegalVariables;
1398 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1399 std::inserter(illegalVariables, illegalVariables.begin()));
1400 bool isValid = illegalVariables.empty();
1401 if (!isValid) {
1402 std::vector<std::string> illegalVariableNames;
1403 for (auto const& var : illegalVariables) {
1404 illegalVariableNames.push_back(var.getName());
1405 }
1407 isValid, storm::exceptions::WrongFormatException,
1408 "Error in " << variable.getFilename() << ", line " << variable.getLineNumber()
1409 << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
1410 }
1411 }
1412
1413 // Record the new identifier for future checks.
1414 variables.insert(variable.getExpressionVariable());
1415 all.insert(variable.getExpressionVariable());
1416 }
1417 for (auto const& variable : module.getIntegerVariables()) {
1418 // Check that bound expressions of the range.
1419 if (variable.hasLowerBoundExpression()) {
1420 std::set<storm::expressions::Variable> containedVariables = variable.getLowerBoundExpression().getVariables();
1421 std::set<storm::expressions::Variable> illegalVariables;
1422 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1423 std::inserter(illegalVariables, illegalVariables.begin()));
1424 bool isValid = illegalVariables.empty();
1425 if (!isValid) {
1426 std::vector<std::string> illegalVariableNames;
1427 for (auto const& var : illegalVariables) {
1428 illegalVariableNames.push_back(var.getName());
1429 }
1430 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1431 "Error in " << variable.getFilename() << ", line " << variable.getLineNumber()
1432 << ": lower bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",")
1433 << ".");
1434 }
1435 }
1436
1437 if (variable.hasUpperBoundExpression()) {
1438 std::set<storm::expressions::Variable> containedVariables = variable.getUpperBoundExpression().getVariables();
1439 std::set<storm::expressions::Variable> illegalVariables;
1440
1441 illegalVariables.clear();
1442 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1443 std::inserter(illegalVariables, illegalVariables.begin()));
1444 bool isValid = illegalVariables.empty();
1445 if (!isValid) {
1446 std::vector<std::string> illegalVariableNames;
1447 for (auto const& var : illegalVariables) {
1448 illegalVariableNames.push_back(var.getName());
1449 }
1450 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1451 "Error in " << variable.getFilename() << ", line " << variable.getLineNumber()
1452 << ": upper bound expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",")
1453 << ".");
1454 }
1455 }
1456
1457 if (variable.hasInitialValue()) {
1458 STORM_LOG_THROW(!this->hasInitialConstruct(), storm::exceptions::WrongFormatException,
1459 "Error for " << module.getName() << "." << variable.getName() << " (" << variable.getFilename() << ", line "
1460 << variable.getLineNumber() << "): illegal to specify initial value if an initial construct is present.");
1461
1462 // Check the initial value of the variable.
1463 std::set<storm::expressions::Variable> containedVariables = variable.getInitialValueExpression().getVariables();
1464 std::set<storm::expressions::Variable> illegalVariables;
1465 illegalVariables.clear();
1466 std::set_difference(containedVariables.begin(), containedVariables.end(), constants.begin(), constants.end(),
1467 std::inserter(illegalVariables, illegalVariables.begin()));
1468 bool isValid = illegalVariables.empty();
1469 if (!isValid) {
1470 std::vector<std::string> illegalVariableNames;
1471 for (auto const& var : illegalVariables) {
1472 illegalVariableNames.push_back(var.getName());
1473 }
1475 isValid, storm::exceptions::WrongFormatException,
1476 "Error in " << variable.getFilename() << ", line " << variable.getLineNumber()
1477 << ": initial value expression refers to unknown constants: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
1478 }
1479 }
1480
1481 // Record the new identifier for future checks.
1482 variables.insert(variable.getExpressionVariable());
1483 all.insert(variable.getExpressionVariable());
1484 }
1485
1486 for (auto const& variable : module.getClockVariables()) {
1487 // Record the new identifier for future checks.
1488 variables.insert(variable.getExpressionVariable());
1489 all.insert(variable.getExpressionVariable());
1490 }
1491 }
1492
1493 // Create the set of valid identifiers for future checks.
1494 std::set<storm::expressions::Variable> variablesAndConstants;
1495 std::set_union(variables.begin(), variables.end(), constants.begin(), constants.end(), std::inserter(variablesAndConstants, variablesAndConstants.begin()));
1496
1497 // Collect the formula placeholders and check formulas
1498 for (auto const& formula : this->getFormulas()) {
1499 std::set<storm::expressions::Variable> containedVariables = formula.getExpression().getVariables();
1500 bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1501 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1502 "Error in " << formula.getFilename() << ", line " << formula.getLineNumber() << ": expression '" << formula.getExpression()
1503 << "'of formula '" << formula.getName() << "' refers to unknown identifiers.");
1504 if (formula.hasExpressionVariable()) {
1505 all.insert(formula.getExpressionVariable());
1506 variablesAndConstants.insert(formula.getExpressionVariable());
1507 }
1508 }
1509
1510 // Check the commands and invariants of the modules.
1511 bool hasProbabilisticCommand = false;
1512 bool hasMarkovianCommand = false;
1513 bool hasLabeledMarkovianCommand = false;
1514 std::map<std::pair<storm::expressions::Variable, uint64_t>, std::pair<uint64_t, std::string>> writtenGlobalVariables;
1515 for (auto const& module : this->getModules()) {
1516 std::set<storm::expressions::Variable> legalVariables = globalVariables;
1517 for (auto const& variable : module.getBooleanVariables()) {
1518 legalVariables.insert(variable.getExpressionVariable());
1519 }
1520 for (auto const& variable : module.getIntegerVariables()) {
1521 legalVariables.insert(variable.getExpressionVariable());
1522 }
1523 for (auto const& variable : module.getClockVariables()) {
1524 legalVariables.insert(variable.getExpressionVariable());
1525 }
1526
1527 if (module.hasInvariant()) {
1528 std::set<storm::expressions::Variable> containedVariables = module.getInvariant().getVariables();
1529 std::set<storm::expressions::Variable> illegalVariables;
1530 std::set_difference(containedVariables.begin(), containedVariables.end(), variablesAndConstants.begin(), variablesAndConstants.end(),
1531 std::inserter(illegalVariables, illegalVariables.begin()));
1532 bool isValid = illegalVariables.empty();
1533 if (!isValid) {
1534 std::vector<std::string> illegalVariableNames;
1535 for (auto const& var : illegalVariables) {
1536 illegalVariableNames.push_back(var.getName());
1537 }
1538 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1539 "Error in " << module.getFilename() << ", line " << module.getLineNumber() << ": invariant " << module.getInvariant()
1540 << " refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
1541 }
1542 STORM_LOG_THROW(module.getInvariant().hasBooleanType(), storm::exceptions::WrongFormatException,
1543 "Error in " << module.getFilename() << ", line " << module.getLineNumber() << ": invariant " << module.getInvariant()
1544 << " must evaluate to type 'bool'.");
1545 }
1546
1547 for (auto& command : module.getCommands()) {
1548 // Check the guard.
1549 std::set<storm::expressions::Variable> containedVariables = command.getGuardExpression().getVariables();
1550 std::set<storm::expressions::Variable> illegalVariables;
1551 std::set_difference(containedVariables.begin(), containedVariables.end(), variablesAndConstants.begin(), variablesAndConstants.end(),
1552 std::inserter(illegalVariables, illegalVariables.begin()));
1553 bool isValid = illegalVariables.empty();
1554 if (!isValid) {
1555 std::vector<std::string> illegalVariableNames;
1556 for (auto const& var : illegalVariables) {
1557 illegalVariableNames.push_back(var.getName());
1558 }
1559 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1560 "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": guard " << command.getGuardExpression()
1561 << " refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
1562 }
1564 command.getGuardExpression().hasBooleanType(), storm::exceptions::WrongFormatException,
1565 "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": expression for guard must evaluate to type 'bool'.");
1566
1567 // Record which types of commands were seen.
1568 if (command.isMarkovian()) {
1569 hasMarkovianCommand = true;
1570 } else {
1571 hasProbabilisticCommand = true;
1572 }
1573
1574 // If the command is Markovian and labeled, we throw an error or raise a warning, depending on
1575 // whether or not the PRISM compatibility mode was enabled.
1576 if (command.isMarkovian() && command.isLabeled()) {
1577 hasLabeledMarkovianCommand = true;
1578 }
1579
1580 // Check all updates.
1581 for (auto const& update : command.getUpdates()) {
1582 containedVariables.clear();
1583 if (update.isLikelihoodInterval()) {
1584 update.getLikelihoodExpressionInterval().first.gatherVariables(containedVariables);
1585 update.getLikelihoodExpressionInterval().second.gatherVariables(containedVariables);
1586 } else {
1587 update.getLikelihoodExpression().gatherVariables(containedVariables);
1588 }
1589 illegalVariables.clear();
1590 std::set_difference(containedVariables.begin(), containedVariables.end(), variablesAndConstants.begin(), variablesAndConstants.end(),
1591 std::inserter(illegalVariables, illegalVariables.begin()));
1592 isValid = illegalVariables.empty();
1593 if (!isValid) {
1594 std::vector<std::string> illegalVariableNames;
1595 for (auto const& var : illegalVariables) {
1596 illegalVariableNames.push_back(var.getName());
1597 }
1599 isValid, storm::exceptions::WrongFormatException,
1600 "Error in " << command.getFilename() << ", line " << command.getLineNumber()
1601 << ": likelihood expression refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
1602 }
1603
1604 // Check all assignments.
1605 std::set<storm::expressions::Variable> alreadyAssignedVariables;
1606 for (auto const& assignment : update.getAssignments()) {
1607 storm::expressions::Variable assignedVariable = manager->getVariable(assignment.getVariableName());
1608
1609 if (legalVariables.find(assignedVariable) == legalVariables.end()) {
1610 if (all.find(assignedVariable) != all.end()) {
1611 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException,
1612 "Error in " << command.getFilename() << ", line " << command.getLineNumber()
1613 << ": assignment illegally refers to variable '" << assignment.getVariableName() << "'.");
1614 } else {
1615 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException,
1616 "Error in " << command.getFilename() << ", line " << command.getLineNumber()
1617 << ": assignment refers to unknown variable '" << assignment.getVariableName() << "'.");
1618 }
1619 }
1620 STORM_LOG_THROW(alreadyAssignedVariables.find(assignedVariable) == alreadyAssignedVariables.end(), storm::exceptions::WrongFormatException,
1621 "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": duplicate assignment to variable '"
1622 << assignment.getVariableName() << "'.");
1623 STORM_LOG_THROW(assignedVariable.getType() == assignment.getExpression().getType() ||
1624 (assignedVariable.getType().isRationalType() && assignment.getExpression().getType().isNumericalType()),
1625 storm::exceptions::WrongFormatException,
1626 "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": illegally assigning a value of type '"
1627 << assignment.getExpression().getType() << "' to variable '" << assignment.getVariableName() << "' of type '"
1628 << assignedVariable.getType() << "'.");
1629
1630 if (command.isLabeled() && globalVariables.find(assignedVariable) != globalVariables.end()) {
1631 std::pair<storm::expressions::Variable, uint64_t> variableActionIndexPair(assignedVariable, command.getActionIndex());
1632 std::pair<uint64_t, std::string> lineModuleNamePair(command.getLineNumber(), module.getName());
1633 auto insertionResult = writtenGlobalVariables.emplace(variableActionIndexPair, lineModuleNamePair);
1635 insertionResult.second || insertionResult.first->second.second == module.getName(), storm::exceptions::WrongFormatException,
1636 "Error in " << command.getFilename() << ", line " << command.getLineNumber() << ": Syncronizing command with action label '"
1637 << command.getActionName() << "' illegally assigns a value to global variable '" << assignedVariable.getName()
1638 << "'. Previous assignment to the variable at line " << insertionResult.first->second.first << " in module '"
1639 << insertionResult.first->second.second << "'.");
1640 }
1641
1642 containedVariables = assignment.getExpression().getVariables();
1643 illegalVariables.clear();
1644 std::set_difference(containedVariables.begin(), containedVariables.end(), variablesAndConstants.begin(), variablesAndConstants.end(),
1645 std::inserter(illegalVariables, illegalVariables.begin()));
1646 isValid = illegalVariables.empty();
1647 if (!isValid) {
1648 std::vector<std::string> illegalVariableNames;
1649 for (auto const& var : illegalVariables) {
1650 illegalVariableNames.push_back(var.getName());
1651 }
1653 isValid, storm::exceptions::WrongFormatException,
1654 "Error in " << command.getFilename() << ", line " << command.getLineNumber()
1655 << ": assigned expression refers to unknown identifiers: " << boost::algorithm::join(illegalVariableNames, ",") << ".");
1656 }
1657
1658 // Add the current variable to the set of assigned variables (of this update).
1659 alreadyAssignedVariables.insert(assignedVariable);
1660 }
1661 }
1662 }
1663 }
1664
1665 if (hasLabeledMarkovianCommand) {
1666 if (prismCompatibility) {
1668 false, "The model uses synchronizing Markovian commands. This may lead to unexpected verification results, because of unclear semantics.");
1669 } else {
1670 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException,
1671 "The model uses synchronizing Markovian commands. This may lead to unexpected verification results, because of unclear semantics.");
1672 }
1673 }
1674
1676 STORM_LOG_THROW(!hasMarkovianCommand, storm::exceptions::WrongFormatException, "Discrete-time model must not have Markovian commands.");
1677 } else if (this->getModelType() == Program::ModelType::CTMC) {
1678 STORM_LOG_THROW(!hasProbabilisticCommand, storm::exceptions::WrongFormatException,
1679 "The input model is a CTMC, but uses probabilistic commands like they are used in PRISM. Please use Markovian commands instead or turn "
1680 "on the PRISM compatibility mode using the flag '-pc'.");
1681 }
1682
1683 // Now check the reward models.
1684 for (auto const& rewardModel : this->getRewardModels()) {
1685 for (auto const& stateReward : rewardModel.getStateRewards()) {
1686 std::set<storm::expressions::Variable> containedVariables = stateReward.getStatePredicateExpression().getVariables();
1687 bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1688 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1689 "Error in " << stateReward.getFilename() << ", line " << stateReward.getLineNumber()
1690 << ": state reward expression refers to unknown identifiers.");
1692 stateReward.getStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException,
1693 "Error in " << stateReward.getFilename() << ", line " << stateReward.getLineNumber() << ": state predicate must evaluate to type 'bool'.");
1694
1695 containedVariables = stateReward.getRewardValueExpression().getVariables();
1696 isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1697 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1698 "Error in " << stateReward.getFilename() << ", line " << stateReward.getLineNumber()
1699 << ": state reward value expression refers to unknown identifiers.");
1700 STORM_LOG_THROW(stateReward.getRewardValueExpression().hasNumericalType(), storm::exceptions::WrongFormatException,
1701 "Error in " << stateReward.getFilename() << ", line " << stateReward.getLineNumber()
1702 << ": reward value expression must evaluate to numerical type.");
1703 }
1704
1705 for (auto const& stateActionReward : rewardModel.getStateActionRewards()) {
1706 std::set<storm::expressions::Variable> containedVariables = stateActionReward.getStatePredicateExpression().getVariables();
1707 bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1708 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1709 "Error in " << stateActionReward.getFilename() << ", line " << stateActionReward.getLineNumber()
1710 << ": state reward expression refers to unknown identifiers.");
1711 STORM_LOG_THROW(stateActionReward.getStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException,
1712 "Error in " << stateActionReward.getFilename() << ", line " << stateActionReward.getLineNumber()
1713 << ": state predicate must evaluate to type 'bool'.");
1714
1715 containedVariables = stateActionReward.getRewardValueExpression().getVariables();
1716 isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1717 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1718 "Error in " << stateActionReward.getFilename() << ", line " << stateActionReward.getLineNumber()
1719 << ": state reward value expression refers to unknown identifiers.");
1720 STORM_LOG_THROW(stateActionReward.getRewardValueExpression().hasNumericalType(), storm::exceptions::WrongFormatException,
1721 "Error in " << stateActionReward.getFilename() << ", line " << stateActionReward.getLineNumber()
1722 << ": reward value expression must evaluate to numerical type.");
1723 }
1724
1725 for (auto const& transitionReward : rewardModel.getTransitionRewards()) {
1726 std::set<storm::expressions::Variable> containedVariables = transitionReward.getSourceStatePredicateExpression().getVariables();
1727 bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1728 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1729 "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber()
1730 << ": state reward expression refers to unknown identifiers.");
1731 STORM_LOG_THROW(transitionReward.getSourceStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException,
1732 "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber()
1733 << ": state predicate must evaluate to type 'bool'.");
1734
1735 containedVariables = transitionReward.getTargetStatePredicateExpression().getVariables();
1736 isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1737 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1738 "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber()
1739 << ": state reward expression refers to unknown identifiers.");
1740 STORM_LOG_THROW(transitionReward.getTargetStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException,
1741 "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber()
1742 << ": state predicate must evaluate to type 'bool'.");
1743
1744 containedVariables = transitionReward.getRewardValueExpression().getVariables();
1745 isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1746 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1747 "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber()
1748 << ": state reward value expression refers to unknown identifiers.");
1749 STORM_LOG_THROW(transitionReward.getRewardValueExpression().hasNumericalType(), storm::exceptions::WrongFormatException,
1750 "Error in " << transitionReward.getFilename() << ", line " << transitionReward.getLineNumber()
1751 << ": reward value expression must evaluate to numerical type.");
1752 }
1753 }
1754
1755 // Check the initial states expression.
1756 if (this->hasInitialConstruct()) {
1757 std::set<storm::expressions::Variable> containedIdentifiers = this->getInitialConstruct().getInitialStatesExpression().getVariables();
1758 bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedIdentifiers.begin(), containedIdentifiers.end());
1759 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1760 "Error in " << this->getInitialConstruct().getFilename() << ", line " << this->getInitialConstruct().getLineNumber()
1761 << ": initial construct refers to unknown identifiers.");
1762 }
1763
1764 // Check the system composition if given.
1765 if (systemCompositionConstruct) {
1766 CompositionValidityChecker checker(*this);
1767 checker.check(systemCompositionConstruct.get().getSystemComposition());
1768 }
1769
1770 // Check the labels.
1771 for (auto const& label : this->getLabels()) {
1772 std::set<storm::expressions::Variable> containedVariables = label.getStatePredicateExpression().getVariables();
1773 bool isValid = std::includes(variablesAndConstants.begin(), variablesAndConstants.end(), containedVariables.begin(), containedVariables.end());
1774 STORM_LOG_THROW(isValid, storm::exceptions::WrongFormatException,
1775 "Error in " << label.getFilename() << ", line " << label.getLineNumber() << ": label expression refers to unknown identifiers.");
1776 STORM_LOG_THROW(label.getStatePredicateExpression().hasBooleanType(), storm::exceptions::WrongFormatException,
1777 "Error in " << label.getFilename() << ", line " << label.getLineNumber() << ": label predicate must evaluate to type 'bool'.");
1778 }
1779
1780 // Check the players
1781 for (auto const& player : this->getPlayers()) {
1782 // The stored action/module names shall be available
1783 for (auto const& controlledAction : player.getActions()) {
1784 STORM_LOG_THROW(this->hasAction(controlledAction), storm::exceptions::InternalException,
1785 "Error in " << player.getFilename() << ", line " << player.getLineNumber() << ": The player controlled action " << controlledAction
1786 << " is not available.");
1787 }
1788 for (auto const& controlledModule : player.getModules()) {
1789 STORM_LOG_THROW(this->hasModule(controlledModule), storm::exceptions::InternalException,
1790 "Error in " << player.getFilename() << ", line " << player.getLineNumber() << ": The player controlled module " << controlledModule
1791 << " is not available.");
1792 }
1793 }
1794
1796 // We check for each global variable and each labeled command, whether there is at most one instance writing to that variable.
1797 std::set<std::pair<std::string, std::string>> globalBVarsWrittenToByCommand;
1798 std::set<std::pair<std::string, std::string>> globalIVarsWrittenToByCommand;
1799 for (auto const& module : this->getModules()) {
1800 std::set<std::pair<std::string, std::string>> globalBVarsWrittenToByCommandInThisModule;
1801 std::set<std::pair<std::string, std::string>> globalIVarsWrittenToByCommandInThisModule;
1802 for (auto const& command : module.getCommands()) {
1803 if (!command.isLabeled()) {
1804 continue;
1805 }
1806 for (auto const& update : command.getUpdates()) {
1807 for (auto const& assignment : update.getAssignments()) {
1808 if (this->globalBooleanVariableExists(assignment.getVariable().getName())) {
1809 globalBVarsWrittenToByCommandInThisModule.insert({assignment.getVariable().getName(), command.getActionName()});
1810 } else if (this->globalIntegerVariableExists(assignment.getVariable().getName())) {
1811 globalIVarsWrittenToByCommandInThisModule.insert({assignment.getVariable().getName(), command.getActionName()});
1812 }
1813 }
1814 }
1815 }
1816 for (auto const& entry : globalIVarsWrittenToByCommandInThisModule) {
1817 STORM_LOG_THROW(globalIVarsWrittenToByCommand.find(entry) == globalIVarsWrittenToByCommand.end(), storm::exceptions::WrongFormatException,
1818 "Error in " << module.getFilename() << ", line " << module.getLineNumber()
1819 << ": assignment of (possibly) synchronizing command with label '" << entry.second
1820 << "' writes to global variable '" << entry.first << "'.");
1821 }
1822 for (auto const& entry : globalBVarsWrittenToByCommandInThisModule) {
1823 STORM_LOG_THROW(globalBVarsWrittenToByCommand.find(entry) == globalBVarsWrittenToByCommand.end(), storm::exceptions::WrongFormatException,
1824 "Error in " << module.getFilename() << ", line " << module.getLineNumber()
1825 << ": assignment of (possibly) synchronizing command with label '" << entry.second
1826 << "' writes to global variable '" << entry.first << "'.");
1827 }
1828 }
1829 }
1830}
1831
1833 // Start by substituting the constants, because this will potentially erase some commands or even actions.
1834 Program substitutedProgram = this->substituteConstantsFormulas();
1835
1836 // As we possibly delete some commands and some actions might be dropped from modules altogether, we need to
1837 // maintain a list of actions that we need to remove in other modules. For example, if module A loses all [a]
1838 // commands, we need to delete all [a] commands from all other modules as well. If we do not do that, we will
1839 // remove the forced synchronization that was there before.
1840 std::set<uint_fast64_t> actionIndicesToDelete;
1841
1842 std::vector<Module> newModules;
1843 std::vector<Constant> newConstants = substitutedProgram.getConstants();
1844 for (auto const& module : substitutedProgram.getModules()) {
1845 // Discard all commands with a guard equivalent to false and remove identity assignments from the updates.
1846 std::vector<Command> newCommands;
1847 for (auto const& command : module.getCommands()) {
1848 if (!command.getGuardExpression().isFalse()) {
1849 newCommands.emplace_back(command.simplify());
1850 }
1851 }
1852
1853 // Substitute variables by global constants if possible.
1854 std::map<storm::expressions::Variable, storm::expressions::Expression> booleanVars;
1855 std::map<storm::expressions::Variable, storm::expressions::Expression> integerVars;
1856 for (auto const& variable : module.getBooleanVariables()) {
1857 booleanVars.emplace(variable.getExpressionVariable(), variable.getInitialValueExpression());
1858 }
1859 for (auto const& variable : module.getIntegerVariables()) {
1860 integerVars.emplace(variable.getExpressionVariable(), variable.getInitialValueExpression());
1861 }
1862
1863 // Collect all variables that are being written. These variables cannot be turned to constants.
1864 for (auto const& command : newCommands) {
1865 // Check all updates.
1866 for (auto const& update : command.getUpdates()) {
1867 // Check all assignments.
1868 for (auto const& assignment : update.getAssignments()) {
1869 if (assignment.getVariable().getType().isBooleanType()) {
1870 auto it = booleanVars.find(assignment.getVariable());
1871 if (it != booleanVars.end()) {
1872 booleanVars.erase(it);
1873 }
1874 } else {
1875 auto it = integerVars.find(assignment.getVariable());
1876 if (it != integerVars.end()) {
1877 integerVars.erase(it);
1878 }
1879 }
1880 }
1881 }
1882 }
1883
1884 std::vector<storm::prism::BooleanVariable> newBooleanVars;
1885 for (auto const& variable : module.getBooleanVariables()) {
1886 if (booleanVars.find(variable.getExpressionVariable()) == booleanVars.end()) {
1887 newBooleanVars.push_back(variable);
1888 }
1889 }
1890 std::vector<storm::prism::IntegerVariable> newIntegerVars;
1891 for (auto const& variable : module.getIntegerVariables()) {
1892 if (integerVars.find(variable.getExpressionVariable()) == integerVars.end()) {
1893 newIntegerVars.push_back(variable);
1894 }
1895 }
1896
1897 for (auto const& variable : module.getBooleanVariables()) {
1898 if (booleanVars.find(variable.getExpressionVariable()) != booleanVars.end()) {
1899 if (variable.hasInitialValue()) {
1900 newConstants.emplace_back(variable.getExpressionVariable(), variable.getInitialValueExpression());
1901 } else {
1902 newBooleanVars.push_back(variable);
1903 }
1904 }
1905 }
1906 for (auto const& variable : module.getIntegerVariables()) {
1907 if (integerVars.find(variable.getExpressionVariable()) != integerVars.end()) {
1908 if (variable.hasInitialValue()) {
1909 newConstants.emplace_back(variable.getExpressionVariable(), variable.getInitialValueExpression());
1910 } else {
1911 newIntegerVars.push_back(variable);
1912 }
1913 }
1914 }
1915
1916 // we currently do not simplify clock variables or invariants
1917 newModules.emplace_back(module.getName(), newBooleanVars, newIntegerVars, module.getClockVariables(), module.getInvariant(), newCommands);
1918
1919 // Determine the set of action indices that have been deleted entirely.
1920 std::set_difference(module.getSynchronizingActionIndices().begin(), module.getSynchronizingActionIndices().end(),
1921 newModules.back().getSynchronizingActionIndices().begin(), newModules.back().getSynchronizingActionIndices().end(),
1922 std::inserter(actionIndicesToDelete, actionIndicesToDelete.begin()));
1923 }
1924
1925 // If we have to delete whole actions, do so now.
1926 std::map<std::string, uint_fast64_t> newActionToIndexMap;
1927 std::vector<RewardModel> newRewardModels;
1928 std::vector<Player> newPlayers;
1929 if (!actionIndicesToDelete.empty()) {
1931 std::set_difference(this->getSynchronizingActionIndices().begin(), this->getSynchronizingActionIndices().end(), actionIndicesToDelete.begin(),
1932 actionIndicesToDelete.end(), std::inserter(actionsToKeep, actionsToKeep.begin()));
1933
1934 // Insert the silent action as this is not contained in the synchronizing action indices.
1935 actionsToKeep.insert(0);
1936
1937 std::vector<Module> cleanedModules;
1938 cleanedModules.reserve(newModules.size());
1939 for (auto const& module : newModules) {
1940 cleanedModules.emplace_back(module.restrictActionIndices(actionsToKeep));
1941 }
1942 newModules = std::move(cleanedModules);
1943
1944 newRewardModels.reserve(substitutedProgram.getNumberOfRewardModels());
1945 for (auto const& rewardModel : substitutedProgram.getRewardModels()) {
1946 newRewardModels.emplace_back(rewardModel.restrictActionRelatedRewards(actionsToKeep));
1947 }
1948
1949 // Restrict action name to index mapping. Old action indices remain valid.
1950 for (auto const& entry : this->getActionNameToIndexMapping()) {
1951 if (actionsToKeep.find(entry.second) != actionsToKeep.end()) {
1952 newActionToIndexMap.emplace(entry.first, entry.second);
1953 }
1954 }
1955
1956 // Restrict player controlled actions
1957 for (auto const& player : this->getPlayers()) {
1958 std::unordered_set<std::string> newControlledActions;
1959 for (auto const& act : player.getActions()) {
1960 if (newActionToIndexMap.count(act) != 0) {
1961 newControlledActions.insert(act);
1962 }
1963 }
1964 newPlayers.emplace_back(player.getName(), player.getModules(), newControlledActions, player.getFilename(), player.getLineNumber());
1965 }
1966 }
1967
1968 std::vector<Label> newLabels;
1969 for (auto const& label : this->getLabels()) {
1970 newLabels.emplace_back(label.getName(), label.getStatePredicateExpression().simplify());
1971 }
1972
1973 return Program(this->manager, modelType, newConstants, getGlobalBooleanVariables(), getGlobalIntegerVariables(), getFormulas(),
1974 actionIndicesToDelete.empty() ? this->getPlayers() : newPlayers, newModules,
1975 actionIndicesToDelete.empty() ? getActionNameToIndexMapping() : newActionToIndexMap,
1976 actionIndicesToDelete.empty() ? this->getRewardModels() : newRewardModels, newLabels, getObservationLabels(), getOptionalInitialConstruct(),
1977 this->getOptionalSystemCompositionConstruct(), prismCompatibility);
1978}
1979
1980Program Program::flattenModules(std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const {
1981 // If the current program has only one module, we can simply return a copy.
1982 if (this->getNumberOfModules() == 1) {
1983 return Program(*this);
1984 }
1985
1986 STORM_LOG_THROW(this->getModelType() == ModelType::DTMC || this->getModelType() == ModelType::MDP, storm::exceptions::InvalidTypeException,
1987 "Unable to flatten modules for model of type '" << this->getModelType() << "'.");
1988
1989 // Otherwise, we need to actually flatten the contained modules.
1990
1991 // Get an SMT solver for computing the possible guard combinations.
1992 std::unique_ptr<storm::solver::SmtSolver> solver = smtSolverFactory->create(*manager);
1993
1994 // Set up the data we need to gather to create the flat module.
1995 std::stringstream newModuleName;
1996 std::vector<storm::prism::BooleanVariable> allBooleanVariables;
1997 std::vector<storm::prism::IntegerVariable> allIntegerVariables;
1998 std::vector<storm::prism::ClockVariable> allClockVariables;
1999 std::vector<storm::prism::Command> newCommands;
2000 uint_fast64_t nextCommandIndex = 0;
2001 uint_fast64_t nextUpdateIndex = 0;
2002
2003 // Assert the values of the constants.
2004 for (auto const& constant : this->getConstants()) {
2005 if (constant.isDefined()) {
2006 if (constant.getType().isBooleanType()) {
2007 solver->add(storm::expressions::iff(constant.getExpressionVariable(), constant.getExpression()));
2008 } else {
2009 solver->add(constant.getExpressionVariable() == constant.getExpression());
2010 }
2011 }
2012 }
2013
2014 // Assert the bounds of the global variables.
2015 for (auto const& variable : this->getGlobalIntegerVariables()) {
2016 solver->add(variable.getRangeExpression());
2017 }
2018
2019 // Make the global variables local, such that the resulting module covers all occurring variables. Note that
2020 // this is just for simplicity and is not needed.
2021 allBooleanVariables.insert(allBooleanVariables.end(), this->getGlobalBooleanVariables().begin(), this->getGlobalBooleanVariables().end());
2022 allIntegerVariables.insert(allIntegerVariables.end(), this->getGlobalIntegerVariables().begin(), this->getGlobalIntegerVariables().end());
2023 storm::expressions::Expression newInvariant;
2024
2025 // Now go through the modules, gather the variables, construct the name of the new module and assert the
2026 // bounds of the discovered variables.
2027 for (auto const& module : this->getModules()) {
2028 newModuleName << module.getName() << "_";
2029 allBooleanVariables.insert(allBooleanVariables.end(), module.getBooleanVariables().begin(), module.getBooleanVariables().end());
2030 allIntegerVariables.insert(allIntegerVariables.end(), module.getIntegerVariables().begin(), module.getIntegerVariables().end());
2031 allClockVariables.insert(allClockVariables.end(), module.getClockVariables().begin(), module.getClockVariables().end());
2032
2033 for (auto const& variable : module.getIntegerVariables()) {
2034 solver->add(variable.getRangeExpression());
2035 }
2036
2037 if (module.hasInvariant()) {
2038 newInvariant = newInvariant.isInitialized() ? (newInvariant && module.getInvariant()) : module.getInvariant();
2039 }
2040
2041 // The commands without a synchronizing action name, can simply be copied (plus adjusting the global
2042 // indices of the command and its updates).
2043 for (auto const& command : module.getCommands()) {
2044 if (!command.isLabeled()) {
2045 std::vector<storm::prism::Update> updates;
2046 updates.reserve(command.getUpdates().size());
2047
2048 for (auto const& update : command.getUpdates()) {
2049 updates.push_back(
2050 storm::prism::Update(nextUpdateIndex, update.getLikelihoodExpression(), update.getAssignments(), update.getFilename(), 0));
2051 ++nextUpdateIndex;
2052 }
2053
2054 newCommands.push_back(storm::prism::Command(nextCommandIndex, command.isMarkovian(), actionToIndexMap.find("")->second, "",
2055 command.getGuardExpression(), updates, command.getFilename(), 0));
2056 ++nextCommandIndex;
2057 }
2058 }
2059 }
2060
2061 // Save state of solver so that we can always restore the point where we have exactly the constant values
2062 // and variables bounds on the assertion stack.
2063 solver->push();
2064
2065 // Now we need to enumerate all possible combinations of synchronizing commands. For this, we iterate over
2066 // all actions and let the solver enumerate the possible combinations of commands that can be enabled together.
2067 for (auto const& actionIndex : this->getSynchronizingActionIndices()) {
2068 bool noCombinationsForAction = false;
2069
2070 // Prepare the list that stores for each module the list of commands with the given action.
2071 std::vector<std::vector<std::reference_wrapper<storm::prism::Command const>>> possibleCommands;
2072
2073 for (auto const& module : this->getModules()) {
2074 // If the module has no command with this action, we can skip it.
2075 if (!module.hasActionIndex(actionIndex)) {
2076 continue;
2077 }
2078
2079 std::set<uint_fast64_t> const& commandIndices = module.getCommandIndicesByActionIndex(actionIndex);
2080
2081 // If there is no command even though the module has this action, there is no valid command
2082 // combination with this action.
2083 if (commandIndices.empty()) {
2084 noCombinationsForAction = true;
2085 break;
2086 }
2087
2088 // Prepare empty list of commands for this module.
2089 possibleCommands.push_back(std::vector<std::reference_wrapper<storm::prism::Command const>>());
2090
2091 // Add references to the commands labeled with the current action.
2092 for (auto const& commandIndex : commandIndices) {
2093 possibleCommands.back().push_back(module.getCommand(commandIndex));
2094 }
2095 }
2096
2097 // If there are no valid combinations for the action, we need to skip the generation of synchronizing
2098 // commands.
2099 if (!noCombinationsForAction) {
2100 // Save the solver state to be able to restore it when this action index is done.
2101 solver->push();
2102
2103 // Start by creating a fresh auxiliary variable for each command and link it with the guard.
2104 std::vector<std::vector<storm::expressions::Variable>> commandVariables(possibleCommands.size());
2105 std::vector<storm::expressions::Variable> allCommandVariables;
2106 for (uint_fast64_t outerIndex = 0; outerIndex < possibleCommands.size(); ++outerIndex) {
2107 // Create auxiliary variables and link them with the guards.
2108 for (uint_fast64_t innerIndex = 0; innerIndex < possibleCommands[outerIndex].size(); ++innerIndex) {
2109 commandVariables[outerIndex].push_back(manager->declareFreshBooleanVariable());
2110 allCommandVariables.push_back(commandVariables[outerIndex].back());
2111 solver->add(implies(commandVariables[outerIndex].back(), possibleCommands[outerIndex][innerIndex].get().getGuardExpression()));
2112 }
2113
2114 storm::expressions::Expression atLeastOneCommandFromModule = manager->boolean(false);
2115 for (auto const& commandVariable : commandVariables[outerIndex]) {
2116 atLeastOneCommandFromModule = atLeastOneCommandFromModule || commandVariable;
2117 }
2118 solver->add(atLeastOneCommandFromModule);
2119 }
2120
2121 // Now we are in a position to start the enumeration over all command variables. While doing so, we
2122 // keep track of previously seen command combinations, because the AllSat procedures are not
2123 // always guaranteed to only provide distinct models.
2124 std::unordered_set<std::vector<uint_fast64_t>, storm::utility::vector::VectorHash<uint_fast64_t>> seenCommandCombinations;
2125 solver->allSat(allCommandVariables, [&](storm::solver::SmtSolver::ModelReference& modelReference) -> bool {
2126 // Now we need to reconstruct the chosen commands from the valuation of the command variables.
2127 std::vector<std::vector<std::reference_wrapper<Command const>>> chosenCommands(possibleCommands.size());
2128
2129 for (uint_fast64_t outerIndex = 0; outerIndex < commandVariables.size(); ++outerIndex) {
2130 for (uint_fast64_t innerIndex = 0; innerIndex < commandVariables[outerIndex].size(); ++innerIndex) {
2131 if (modelReference.getBooleanValue(commandVariables[outerIndex][innerIndex])) {
2132 chosenCommands[outerIndex].push_back(possibleCommands[outerIndex][innerIndex]);
2133 }
2134 }
2135 }
2136
2137 // Now that we have retrieved the commands, we need to build their synchronizations and add them
2138 // to the flattened module.
2139 std::vector<std::vector<std::reference_wrapper<Command const>>::const_iterator> iterators;
2140 for (auto const& element : chosenCommands) {
2141 iterators.push_back(element.begin());
2142 }
2143
2144 bool movedAtLeastOneIterator = false;
2145 std::vector<std::reference_wrapper<Command const>> commandCombination(chosenCommands.size(), chosenCommands.front().front());
2146 std::vector<uint_fast64_t> commandCombinationIndices(iterators.size());
2147 do {
2148 for (uint_fast64_t index = 0; index < iterators.size(); ++index) {
2149 commandCombination[index] = *iterators[index];
2150 commandCombinationIndices[index] = commandCombination[index].get().getGlobalIndex();
2151 }
2152
2153 // Only add the command combination if it was not previously seen.
2154 auto seenIt = seenCommandCombinations.find(commandCombinationIndices);
2155 if (seenIt == seenCommandCombinations.end()) {
2156 newCommands.push_back(synchronizeCommands(nextCommandIndex, actionIndex, nextUpdateIndex, indexToActionMap.find(actionIndex)->second,
2157 commandCombination));
2158 seenCommandCombinations.insert(commandCombinationIndices);
2159
2160 // Move the counters appropriately.
2161 ++nextCommandIndex;
2162 nextUpdateIndex += newCommands.back().getNumberOfUpdates();
2163 }
2164
2165 movedAtLeastOneIterator = false;
2166 for (uint_fast64_t index = 0; index < iterators.size(); ++index) {
2167 ++iterators[index];
2168 if (iterators[index] != chosenCommands[index].cend()) {
2169 movedAtLeastOneIterator = true;
2170 break;
2171 } else {
2172 iterators[index] = chosenCommands[index].cbegin();
2173 }
2174 }
2175 } while (movedAtLeastOneIterator);
2176
2177 return true;
2178 });
2179
2180 solver->pop();
2181 }
2182 }
2183
2184 // Finally, we can create the module and the program and return it.
2185 storm::prism::Module singleModule(newModuleName.str(), allBooleanVariables, allIntegerVariables, allClockVariables, newInvariant, newCommands,
2186 this->getFilename(), 0);
2187
2188 return Program(manager, this->getModelType(), this->getConstants(), std::vector<storm::prism::BooleanVariable>(),
2189 std::vector<storm::prism::IntegerVariable>(), this->getFormulas(), this->getPlayers(), {singleModule}, actionToIndexMap,
2190 this->getRewardModels(), this->getLabels(), this->getObservationLabels(), this->getOptionalInitialConstruct(),
2191 this->getOptionalSystemCompositionConstruct(), prismCompatibility, this->getFilename(), 0, true);
2192}
2193
2194std::vector<Constant> Program::usedConstants() const {
2195 std::unordered_set<expressions::Variable> vars;
2196 for (auto const& m : this->modules) {
2197 for (auto const& c : m.getCommands()) {
2198 auto const& found_gex = c.getGuardExpression().getVariables();
2199 vars.insert(found_gex.begin(), found_gex.end());
2200 for (auto const& u : c.getUpdates()) {
2201 auto const& found_lex = u.getLikelihoodExpression().getVariables();
2202 vars.insert(found_lex.begin(), found_lex.end());
2203 for (auto const& a : u.getAssignments()) {
2204 auto const& found_ass = a.getExpression().getVariables();
2205 vars.insert(found_ass.begin(), found_ass.end());
2206 }
2207 }
2208 }
2209 for (auto const& v : m.getBooleanVariables()) {
2210 if (v.hasInitialValue()) {
2211 auto const& found_def = v.getInitialValueExpression().getVariables();
2212 vars.insert(found_def.begin(), found_def.end());
2213 }
2214 }
2215 for (auto const& v : m.getIntegerVariables()) {
2216 if (v.hasInitialValue()) {
2217 auto const& found_def = v.getInitialValueExpression().getVariables();
2218 vars.insert(found_def.begin(), found_def.end());
2219 }
2220 }
2221 }
2222
2223 for (auto const& f : this->formulas) {
2224 auto const& found_def = f.getExpression().getVariables();
2225 vars.insert(found_def.begin(), found_def.end());
2226 }
2227
2228 for (auto const& v : this->constants) {
2229 if (v.isDefined()) {
2230 auto const& found_def = v.getExpression().getVariables();
2231 vars.insert(found_def.begin(), found_def.end());
2232 }
2233 }
2234
2235 for (auto const& v : this->globalBooleanVariables) {
2236 if (v.hasInitialValue()) {
2237 auto const& found_def = v.getExpression().getVariables();
2238 vars.insert(found_def.begin(), found_def.end());
2239 }
2240 }
2241
2242 for (auto const& v : this->globalIntegerVariables) {
2243 if (v.hasInitialValue()) {
2244 auto const& found_def = v.getExpression().getVariables();
2245 vars.insert(found_def.begin(), found_def.end());
2246 }
2247 }
2248
2249 std::unordered_set<uint64_t> varIndices;
2250 for (auto const& v : vars) {
2251 varIndices.insert(v.getIndex());
2252 }
2253
2254 std::vector<Constant> usedConstants;
2255 for (auto const& c : this->constants) {
2256 if (varIndices.count(c.getExpressionVariable().getIndex())) {
2257 usedConstants.push_back(c);
2258 }
2259 }
2260
2261 return usedConstants;
2262}
2263
2264std::unordered_map<uint_fast64_t, std::string> Program::buildCommandIndexToActionNameMap() const {
2265 std::unordered_map<uint_fast64_t, std::string> res;
2266 for (auto const& m : this->modules) {
2267 for (auto const& c : m.getCommands()) {
2268 res.emplace(c.getGlobalIndex(), c.getActionName());
2269 }
2270 }
2271 return res;
2272}
2273
2274std::unordered_map<uint_fast64_t, std::string> Program::buildActionIndexToActionNameMap() const {
2275 std::unordered_map<uint_fast64_t, std::string> res;
2276 for (auto const& nameIndexPair : actionToIndexMap) {
2277 res.emplace(nameIndexPair.second, nameIndexPair.first);
2278 }
2279 return res;
2280}
2281
2282std::unordered_map<uint_fast64_t, uint_fast64_t> Program::buildCommandIndexToActionIndex() const {
2283 std::unordered_map<uint_fast64_t, uint_fast64_t> res;
2284 for (auto const& m : this->modules) {
2285 for (auto const& c : m.getCommands()) {
2286 res.emplace(c.getGlobalIndex(), c.getActionIndex());
2287 }
2288 }
2289 return res;
2290}
2291
2292Command Program::synchronizeCommands(uint_fast64_t newCommandIndex, uint_fast64_t actionIndex, uint_fast64_t firstUpdateIndex, std::string const& actionName,
2293 std::vector<std::reference_wrapper<Command const>> const& commands) const {
2294 // To construct the synchronous product of the commands, we need to store a list of its updates.
2295 std::vector<storm::prism::Update> newUpdates;
2296 uint_fast64_t numberOfUpdates = 1;
2297 for (uint_fast64_t i = 0; i < commands.size(); ++i) {
2298 numberOfUpdates *= commands[i].get().getNumberOfUpdates();
2299 }
2300 newUpdates.reserve(numberOfUpdates);
2301
2302 // Initialize all update iterators.
2303 std::vector<std::vector<storm::prism::Update>::const_iterator> updateIterators;
2304 for (uint_fast64_t i = 0; i < commands.size(); ++i) {
2305 updateIterators.push_back(commands[i].get().getUpdates().cbegin());
2306 }
2307
2308 bool doneUpdates = false;
2309 do {
2310 // We create the new likelihood expression by multiplying the particapting updates' expressions.
2311 storm::expressions::Expression newLikelihoodExpression = updateIterators[0]->getLikelihoodExpression();
2312 for (uint_fast64_t i = 1; i < updateIterators.size(); ++i) {
2313 newLikelihoodExpression = newLikelihoodExpression * updateIterators[i]->getLikelihoodExpression();
2314 }
2315
2316 // Now concatenate all assignments of all participating updates.
2317 std::vector<storm::prism::Assignment> newAssignments;
2318 for (uint_fast64_t i = 0; i < updateIterators.size(); ++i) {
2319 newAssignments.insert(newAssignments.end(), updateIterators[i]->getAssignments().begin(), updateIterators[i]->getAssignments().end());
2320 }
2321
2322 // Then we are ready to create the new update.
2323 newUpdates.push_back(storm::prism::Update(firstUpdateIndex, newLikelihoodExpression, newAssignments, this->getFilename(), 0));
2324 ++firstUpdateIndex;
2325
2326 // Now check whether there is some update combination we have not yet explored.
2327 bool movedIterator = false;
2328 for (int_fast64_t j = updateIterators.size() - 1; j >= 0; --j) {
2329 ++updateIterators[j];
2330 if (updateIterators[j] != commands[j].get().getUpdates().cend()) {
2331 movedIterator = true;
2332 break;
2333 } else {
2334 // Reset the iterator to the beginning of the list.
2335 updateIterators[j] = commands[j].get().getUpdates().cbegin();
2336 }
2337 }
2338
2339 doneUpdates = !movedIterator;
2340 } while (!doneUpdates);
2341
2342 storm::expressions::Expression newGuard = commands[0].get().getGuardExpression();
2343 for (uint_fast64_t i = 1; i < commands.size(); ++i) {
2344 newGuard = newGuard && commands[i].get().getGuardExpression();
2345 }
2346
2347 return Command(newCommandIndex, false, actionIndex, actionName, newGuard, newUpdates, this->getFilename(), 0);
2348}
2349
2350storm::jani::Model Program::toJani(bool allVariablesGlobal, std::string suffix) const {
2352 auto janiModel = converter.convert(*this, allVariablesGlobal, {}, suffix);
2353 STORM_LOG_WARN_COND(!converter.labelsWereRenamed(), "Labels were renamed in PRISM-to-JANI conversion, but the mapping is not stored.");
2354 STORM_LOG_WARN_COND(!converter.rewardModelsWereRenamed(), "Rewardmodels were renamed in PRISM-to-JANI conversion, but the mapping is not stored.");
2355 return janiModel;
2356}
2357
2358std::pair<storm::jani::Model, std::vector<storm::jani::Property>> Program::toJani(std::vector<storm::jani::Property> const& properties, bool allVariablesGlobal,
2359 std::string suffix) const {
2361 std::set<storm::expressions::Variable> variablesToMakeGlobal;
2362 if (!allVariablesGlobal) {
2363 for (auto const& prop : properties) {
2364 auto vars = prop.getUsedVariablesAndConstants();
2365 variablesToMakeGlobal.insert(vars.begin(), vars.end());
2366 }
2367 }
2368 auto janiModel = converter.convert(*this, allVariablesGlobal, variablesToMakeGlobal, suffix);
2369 std::vector<storm::jani::Property> newProperties;
2370 if (converter.labelsWereRenamed() || converter.rewardModelsWereRenamed()) {
2371 newProperties = converter.applyRenaming(properties);
2372 } else {
2373 newProperties = properties; // Nothing to be done here. Notice that the copy operation is suboptimal.
2374 }
2375 return std::make_pair(janiModel, newProperties);
2376}
2377
2378uint64_t Program::getHighestCommandIndex() const {
2379 uint64_t highest = 0;
2380 for (auto const& m : getModules()) {
2381 for (auto const& c : m.getCommands()) {
2382 highest = std::max(highest, c.getGlobalIndex());
2383 }
2384 }
2385 return highest;
2386}
2387
2389 return *this->manager;
2390}
2391
2392void Program::createMissingInitialValues() {
2393 for (auto& variable : globalBooleanVariables) {
2394 variable.createMissingInitialValue();
2395 }
2396 for (auto& variable : globalIntegerVariables) {
2397 variable.createMissingInitialValue();
2398 }
2399}
2400
2401std::ostream& operator<<(std::ostream& out, Program::ModelType const& type) {
2402 switch (type) {
2404 out << "undefined";
2405 break;
2407 out << "dtmc";
2408 break;
2410 out << "ctmc";
2411 break;
2413 out << "mdp";
2414 break;
2416 out << "ctmdp";
2417 break;
2419 out << "ma";
2420 break;
2422 out << "pomdp";
2423 break;
2425 out << "pta";
2426 break;
2428 out << "smg";
2429 break;
2430 }
2431 return out;
2432}
2433
2434std::ostream& operator<<(std::ostream& stream, Program const& program) {
2435 stream << program.getModelType() << '\n';
2436 for (auto const& constant : program.getConstants()) {
2437 stream << constant << '\n';
2438 }
2439 stream << '\n';
2440
2441 for (auto const& player : program.getPlayers()) {
2442 stream << player << '\n';
2443 }
2444
2445 for (auto const& variable : program.getGlobalBooleanVariables()) {
2446 stream << "global " << variable << '\n';
2447 }
2448 for (auto const& variable : program.getGlobalIntegerVariables()) {
2449 stream << "global " << variable << '\n';
2450 }
2451 stream << '\n';
2452
2453 for (auto const& formula : program.getFormulas()) {
2454 stream << formula << '\n';
2455 }
2456 stream << '\n';
2457
2458 for (auto const& module : program.getModules()) {
2459 stream << module << '\n';
2460 }
2461
2462 for (auto const& rewardModel : program.getRewardModels()) {
2463 stream << rewardModel << '\n';
2464 }
2465
2466 for (auto const& label : program.getLabels()) {
2467 stream << label << '\n';
2468 }
2469
2470 if (program.hasInitialConstruct()) {
2471 stream << program.getInitialConstruct() << '\n';
2472 }
2473
2474 if (program.specifiesSystemComposition()) {
2475 stream << program.getSystemCompositionConstruct();
2476 }
2477
2478 return stream;
2479}
2480
2481} // namespace prism
2482} // namespace storm
bool isInitialized() const
Checks whether the object encapsulates a base-expression.
This class is responsible for managing a set of typed variables and all expressions using these varia...
bool isBooleanType() const
Checks whether this type is a boolean type.
Definition Type.cpp:194
bool isRationalType() const
Checks whether this type is a rational type.
Definition Type.cpp:234
Type const & getType() const
Retrieves the type of the variable.
Definition Variable.cpp:50
std::string const & getName() const
Retrieves the name of the variable.
Definition Variable.cpp:46
storm::expressions::Expression const & getGuardExpression() const
Retrieves a reference to the guard of the command.
Definition Command.cpp:35
virtual boost::any accept(CompositionVisitor &visitor, boost::any const &data) const =0
virtual boost::any visit(InterleavingParallelComposition const &composition, boost::any const &data) override
Definition Program.cpp:107
virtual boost::any visit(SynchronizingParallelComposition const &composition, boost::any const &data) override
Definition Program.cpp:94
void check(Composition const &composition)
Definition Program.cpp:34
virtual boost::any visit(RestrictedParallelComposition const &composition, boost::any const &data) override
Definition Program.cpp:120
virtual boost::any visit(ModuleComposition const &composition, boost::any const &) override
Definition Program.cpp:40
virtual boost::any visit(HidingComposition const &composition, boost::any const &data) override
Definition Program.cpp:76
CompositionValidityChecker(storm::prism::Program const &program)
Definition Program.cpp:30
virtual boost::any visit(RenamingComposition const &composition, boost::any const &data) override
Definition Program.cpp:52
storm::expressions::Variable const & getExpressionVariable() const
Retrieves the expression variable associated with this constant.
Definition Constant.cpp:26
storm::expressions::Type const & getType() const
Retrieves the type of the constant.
Definition Constant.cpp:22
storm::expressions::Expression const & getExpression() const
Retrieves the expression that defines the constant.
Definition Constant.cpp:34
std::set< std::string > const & getActionsToHide() const
Composition const & getSubcomposition() const
uint_fast64_t getLineNumber() const
Retrieves the line number in which the information was found.
std::string const & getFilename() const
Retrieves the name of the file in which the information was found.
LocatedInformation(std::string const &filename, uint_fast64_t lineNumber)
Constructs a located information with the given filename and line number.
std::string const & getModuleName() const
std::map< std::string, std::string > const & getRenaming() const
If the module was created via renaming, this method returns the applied renaming of identifiers used ...
Definition Module.cpp:173
bool isRenamedFromModule() const
Retrieves whether this module was created from another module via renaming.
Definition Module.cpp:163
Composition const & getLeftSubcomposition() const
Composition const & getRightSubcomposition() const
Program replaceConstantByVariable(Constant const &c, expressions::Expression const &lowerBound, expressions::Expression const &upperBound, bool observable=true) const
Substitutes the given constant by a fresh global variable that is bound between lowerBound and upperB...
Definition Program.cpp:1231
std::set< uint_fast64_t > const & getSynchronizingActionIndices() const
Retrieves the set of synchronizing action indices present in the program.
Definition Program.cpp:747
Formula const & getFormula(std::string const &formulaName) const
Definition Program.cpp:850
void checkValidity(Program::ValidityCheckLevel lvl=Program::ValidityCheckLevel::READYFORPROCESSING) const
Checks the validity of the program.
Definition Program.cpp:1252
std::map< std::string, std::string > getFinalRenamingOfModule(Module const &renamedModule) const
Gets the renaming of a module after flattening all renamings.
Definition Program.cpp:446
bool hasIntervalUpdates() const
Retrieves whether the program considers at least one update with an interval probability/rate.
Definition Program.cpp:706
ModelType getModelType() const
Retrieves the model type of the model.
Definition Program.cpp:243
Program defineUndefinedConstants(std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions) const
Defines the undefined constants according to the given map and returns the resulting program.
Definition Program.cpp:1002
std::vector< storm::expressions::Expression > getAllRangeExpressions() const
Retrieves a list of expressions that characterize the legal ranges of all variables.
Definition Program.cpp:508
std::vector< RewardModel > const & getRewardModels() const
Retrieves the reward models of the program.
Definition Program.cpp:817
std::vector< Player > const & getPlayers() const
Retrieves the players of the program.
Definition Program.cpp:558
RewardModel const & getRewardModel(std::string const &rewardModelName) const
Retrieves the reward model with the given name.
Definition Program.cpp:825
std::vector< BooleanVariable > const & getGlobalBooleanVariables() const
Retrieves the global boolean variables of the program.
Definition Program.cpp:478
ModelType
An enum for the different model types.
Definition Program.h:35
std::set< std::string > const & getActions() const
Retrieves the set of actions present in the program.
Definition Program.cpp:743
std::set< uint_fast64_t > const & getModuleIndicesByAction(std::string const &action) const
Retrieves the indices of all modules within this program that contain commands that are labelled with...
Definition Program.cpp:771
std::vector< std::reference_wrapper< Constant const > > getUndefinedConstants() const
Retrieves the undefined constants in the program.
Definition Program.cpp:364
storm::storage::PlayerIndex const & getIndexOfPlayer(std::string const &playerName) const
Retrieves the index of the player in the program.
Definition Program.cpp:566
bool isPartiallyObservable() const
Retrieves whether the model has restricted observability.
Definition Program.cpp:255
std::pair< uint_fast64_t, uint_fast64_t > getModuleCommandIndexByGlobalCommandIndex(uint_fast64_t globalCommandIndex) const
Retrieves the index of the module and the (local) index of the command with the given global command ...
Definition Program.cpp:791
bool hasAction(std::string const &actionName) const
Retrieves whether the program has an action with the given name.
Definition Program.cpp:763
std::size_t getNumberOfLabels() const
Retrieves the number of labels in the program.
Definition Program.cpp:880
boost::optional< SystemCompositionConstruct > getOptionalSystemCompositionConstruct() const
Retrieves the system composition construct (if any) and none otherwise.
Definition Program.cpp:727
std::map< storm::expressions::Variable, storm::expressions::Expression > getConstantsSubstitution() const
Retrieves a mapping of all defined constants to their defining expressions.
Definition Program.cpp:402
std::string const & getActionName(uint_fast64_t actionIndex) const
Retrieves the action name of the given action index.
Definition Program.cpp:751
std::vector< Module > const & getModules() const
Retrieves all modules of the program.
Definition Program.cpp:625
bool isDiscreteTimeModel() const
Retrieves whether the model is a discrete-time model, i.e.
Definition Program.cpp:247
storm::expressions::Expression const & getLabelExpression(std::string const &label) const
Retrieves the expression associated with the given label, if it exists.
Definition Program.cpp:865
std::unordered_map< uint_fast64_t, std::string > buildCommandIndexToActionNameMap() const
Definition Program.cpp:2264
Program substituteNonStandardPredicates() const
Substitutes all nonstandard predicates in expressions of the program by their defining expressions.
Definition Program.cpp:1052
std::vector< ObservationLabel > const & getObservationLabels() const
Retrieves all observation labels that are defined by this program.
Definition Program.cpp:918
Module const & getModule(uint_fast64_t index) const
Retrieves the module with the given index.
Definition Program.cpp:611
uint_fast64_t getActionIndex(std::string const &actionName) const
Retrieves the index of the action with the given name.
Definition Program.cpp:757
IntegerVariable const & getGlobalIntegerVariable(std::string const &variableName) const
Retrieves a the global integer variable with the given name.
Definition Program.cpp:539
std::set< uint_fast64_t > const & getModuleIndicesByActionIndex(uint_fast64_t actionIndex) const
Retrieves the indices of all modules within this program that contain commands that are labelled with...
Definition Program.cpp:777
std::map< uint_fast64_t, storm::storage::PlayerIndex > buildActionIndexToPlayerIndexMap() const
Retrieves a vector whose i'th entry corresponds to the player controlling action with index i.
Definition Program.cpp:586
bool isDeterministicModel() const
Retrieves whether the model is one without nondeterministic choices, i.e.
Definition Program.cpp:251
std::map< storm::expressions::Variable, storm::expressions::Expression > getConstantsFormulasSubstitution(bool getConstantsSubstitution=true, bool getFormulasSubstitution=true) const
Retrieves a mapping of all defined constants and formula variables to their defining expressions.
Definition Program.cpp:410
std::vector< storm::expressions::Expression > getAllGuards(bool negated=false) const
Retrieves all guards appearing in the program.
Definition Program.cpp:855
void removeLabel(std::string const &name)
Removes the label with the given name from the program.
Definition Program.cpp:891
bool undefinedConstantsAreGraphPreserving() const
Checks that undefined constants (parameters) of the model preserve the graph of the underlying model.
Definition Program.cpp:290
std::size_t getNumberOfRewardModels() const
Retrieves the number of reward models in the program.
Definition Program.cpp:821
std::size_t getNumberOfPlayers() const
Retrieves the number of players in the program.
Definition Program.cpp:562
void updateInitialStatesExpression(expressions::Expression const &newExpression)
Sets a new initial states expression.
Definition Program.cpp:653
Constant const & getConstant(std::string const &constantName) const
Retrieves the constant with the given name if it exists.
Definition Program.cpp:393
std::map< std::string, uint_fast64_t > const & getActionNameToIndexMapping() const
Retrieves the mapping of action names to their indices.
Definition Program.cpp:629
size_t getNumberOfCommands() const
The total number of commands in the prism file.
Definition Program.cpp:259
Program labelUnlabelledCommands(std::map< uint64_t, std::string > const &nameSuggestions={}) const
Give commands that do not have an action name an action, which can be helpful for debugging and under...
Definition Program.cpp:1178
SystemCompositionConstruct const & getSystemCompositionConstruct() const
If the program specifies a system composition construct, this method retrieves it.
Definition Program.cpp:723
Program substituteConstants() const
Substitutes all constants appearing in the expressions of the program by their defining expressions.
Definition Program.cpp:1044
Program substituteFormulas() const
Substitutes all formulas appearing in the expressions of the program by their defining expressions.
Definition Program.cpp:1048
std::size_t getNumberOfObservationLabels() const
Retrieves the number of observation labels in the program.
Definition Program.cpp:922
std::map< std::string, storm::storage::PlayerIndex > const & getPlayerNameToIndexMapping() const
Definition Program.cpp:570
std::size_t getNumberOfConstants() const
Retrieves the number of all constants defined in the program.
Definition Program.cpp:474
Program(std::shared_ptr< storm::expressions::ExpressionManager > manager, ModelType modelType, std::vector< Constant > const &constants, std::vector< BooleanVariable > const &globalBooleanVariables, std::vector< IntegerVariable > const &globalIntegerVariables, std::vector< Formula > const &formulas, std::vector< Player > const &players, std::vector< Module > const &modules, std::map< std::string, uint_fast64_t > const &actionToIndexMap, std::vector< RewardModel > const &rewardModels, std::vector< Label > const &labels, std::vector< ObservationLabel > const &observationLabels, boost::optional< InitialConstruct > const &initialConstruct, boost::optional< SystemCompositionConstruct > const &compositionConstruct, bool prismCompatibility, std::string const &filename="", uint_fast64_t lineNumber=0, bool finalModel=true)
Creates a program with the given model type, undefined constants, global variables,...
Definition Program.cpp:154
std::set< storm::expressions::Variable > getAllExpressionVariables(bool includeConstants=true) const
Retrieves all expression variables used by this program.
Definition Program.cpp:486
bool globalIntegerVariableExists(std::string const &variableName) const
Retrieves whether a global Integer variable with the given name exists.
Definition Program.cpp:528
std::unordered_map< uint_fast64_t, std::string > buildActionIndexToActionNameMap() const
Definition Program.cpp:2274
bool hasFormula(std::string const &formulaName) const
Definition Program.cpp:846
BooleanVariable const & getGlobalBooleanVariable(std::string const &variableName) const
Retrieves a the global boolean variable with the given name.
Definition Program.cpp:532
void filterLabels(std::set< std::string > const &labelSet)
Removes all labels that are not contained in the given set from the program.
Definition Program.cpp:902
bool hasModule(std::string const &moduleName) const
Retrieves whether the program has a module with the given name.
Definition Program.cpp:615
Program substituteConstantsFormulas(bool substituteConstants=true, bool substituteFormulas=true) const
Substitutes all constants and/or formulas appearing in the expressions of the program by their defini...
Definition Program.cpp:1096
bool globalBooleanVariableExists(std::string const &variableName) const
Retrieves whether a global Boolean variable with the given name exists.
Definition Program.cpp:524
std::unordered_map< uint_fast64_t, uint_fast64_t > buildCommandIndexToActionIndex() const
Definition Program.cpp:2282
std::vector< Constant > const & getConstants() const
Retrieves all constants defined in the program.
Definition Program.cpp:398
std::map< storm::expressions::Variable, storm::expressions::Expression > getFormulasSubstitution() const
Retrieves a mapping of all formula variables to their defining expressions.
Definition Program.cpp:406
bool hasUnboundedVariables() const
Definition Program.cpp:267
storm::expressions::ExpressionManager & getManager() const
Retrieves the manager responsible for the expressions of this program.
Definition Program.cpp:2388
Program replaceVariableInitializationByInitExpression() const
Replace the initialization in variables by an init-expression.
Definition Program.cpp:1210
std::vector< Constant > usedConstants() const
Retrieves the constants that are actually used in the program.
Definition Program.cpp:2194
bool hasLabel(std::string const &labelName) const
Checks whether the program has a label with the given name.
Definition Program.cpp:837
std::vector< storm::storage::PlayerIndex > buildModuleIndexToPlayerIndexMap() const
Retrieves a vector whose i'th entry corresponds to the player controlling module i.
Definition Program.cpp:574
std::vector< IntegerVariable > const & getGlobalIntegerVariables() const
Retrieves the global integer variables of the program.
Definition Program.cpp:482
std::size_t getNumberOfGlobalIntegerVariables() const
Retrieves the number of global integer variables of the program.
Definition Program.cpp:550
std::string getUndefinedConstantsAsString() const
Retrieves the undefined constants in the program as a comma-separated string.
Definition Program.cpp:374
std::size_t getNumberOfFormulas() const
Retrieves the number of formulas in the program.
Definition Program.cpp:603
bool hasConstant(std::string const &constantName) const
Retrieves whether the given constant exists in the program.
Definition Program.cpp:389
storm::expressions::Expression getInitialStatesExpression() const
Retrieves an expression characterizing the initial states.
Definition Program.cpp:658
void addLabel(std::string const &name, storm::expressions::Expression const &statePredicateExpression)
Adds a label with the given name and defining expression to the program.
Definition Program.cpp:884
std::size_t getNumberOfModules() const
Retrieves the number of modules in the program.
Definition Program.cpp:607
bool hasInitialConstruct() const
Retrieves whether the program specifies an initial construct.
Definition Program.cpp:641
Program restrictCommands(storm::storage::FlatSet< uint_fast64_t > const &indexSet) const
Creates a new program that drops all commands whose indices are not in the given set.
Definition Program.cpp:930
Program flattenModules(std::shared_ptr< storm::utility::solver::SmtSolverFactory > const &smtSolverFactory=std::shared_ptr< storm::utility::solver::SmtSolverFactory >(new storm::utility::solver::SmtSolverFactory())) const
Creates an equivalent program that contains exactly one module.
Definition Program.cpp:1980
bool hasUndefinedConstants() const
Retrieves whether there are undefined constants of any type in the program.
Definition Program.cpp:281
bool specifiesSystemComposition() const
Retrieves whether the program specifies a system composition in terms of process algebra operations o...
Definition Program.cpp:719
std::shared_ptr< Composition > getDefaultSystemComposition() const
Retrieves the default system composition for this program.
Definition Program.cpp:731
std::vector< Label > const & getLabels() const
Retrieves all labels that are defined by the probabilitic program.
Definition Program.cpp:842
uint64_t getNumberOfUnlabeledCommands() const
Definition Program.cpp:633
storm::storage::BitVector const & getPossiblySynchronizingCommands() const
Compute the (labelled) commands in the program that may be synchronizing.
Definition Program.cpp:926
uint_fast64_t getModuleIndexByVariable(std::string const &variableName) const
Retrieves the index of the module in which the given variable name was declared.
Definition Program.cpp:784
bool hasRewardModel() const
Retrieves whether the program has reward models.
Definition Program.cpp:808
std::map< std::string, storm::expressions::Expression > getLabelToExpressionMapping() const
Retrieves a mapping from all labels in the program to their defining expressions.
Definition Program.cpp:872
Program simplify()
Entry point for static analysis for simplify.
Definition Program.cpp:1832
Program preprocess(std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions) const
Preprocesses the program by defining the given constant definitions, substituting constants and formu...
Definition Program.cpp:1170
std::map< storm::expressions::Variable, storm::expressions::Expression > getSubstitutionForRenamedModule(Module const &renamedModule, std::map< storm::expressions::Variable, storm::expressions::Expression > const &substitution) const
Applies the renaming of a renamed module to the given substitution.
Definition Program.cpp:428
std::size_t getNumberOfGlobalBooleanVariables() const
Retrieves the number of global boolean variables of the program.
Definition Program.cpp:546
storm::jani::Model toJani(bool allVariablesGlobal=true, std::string suffix="") const
Converts the PRISM model into an equivalent JANI model.
Definition Program.cpp:2350
std::vector< Formula > const & getFormulas() const
Retrieves the formulas defined in the program.
Definition Program.cpp:554
Composition const & getSubcomposition() const
std::map< std::string, std::string > const & getActionRenaming() const
std::set< std::string > const & getSynchronizingActions() const
The base class for all model references.
Definition SmtSolver.h:30
virtual bool getBooleanValue(storm::expressions::Variable const &variable) const =0
A bit vector that is internally represented as a vector of 64-bit values.
Definition BitVector.h:16
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:9
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:36
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:28
Expression iff(Expression const &first, Expression const &second)
storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const &expression, std::map< storm::expressions::Variable, storm::expressions::Expression > const &identifierToExpressionMap, bool const substituteTranscendentalNumbers)
std::ostream & operator<<(std::ostream &stream, Assignment const &assignment)
PlayerIndex const INVALID_PLAYER_INDEX
Definition PlayerIndex.h:8
uint64_t PlayerIndex
Definition PlayerIndex.h:7
boost::container::flat_set< Key, std::less< Key >, boost::container::new_allocator< Key > > FlatSet
Redefinition of flat_set was needed, because from Boost 1.70 on the default allocator is set to void.
Definition BoostTypes.h:13
std::map< storm::expressions::Variable, storm::expressions::Expression > parseConstantDefinitionString(storm::expressions::ExpressionManager const &manager, std::string const &constantDefinitionString)
Parses a comma-separated string of constant definitions (e.g.