Storm 1.14.0.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
Model.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4
33
34namespace storm {
35namespace jani {
36
37const std::string Model::SILENT_ACTION_NAME = "";
38const uint64_t Model::SILENT_ACTION_INDEX = 0;
39
40Model::Model(Model&& other) = default;
41Model& Model::operator=(Model&& other) = default;
42
44 // Intentionally left empty.
45}
46
47Model::Model(std::string const& name, ModelType const& modelType, uint64_t version,
48 boost::optional<std::shared_ptr<storm::expressions::ExpressionManager>> const& expressionManager)
49 : name(name), modelType(modelType), version(version), composition(nullptr) {
50 // Use the provided manager or create a new one.
51 if (expressionManager) {
52 this->expressionManager = expressionManager.get();
53 } else {
54 this->expressionManager = std::make_shared<storm::expressions::ExpressionManager>();
55 }
56
57 // Create an initial restriction.
58 initialStatesRestriction = this->expressionManager->boolean(true);
59
60 // Add a prefined action that represents the silent action.
61 [[maybe_unused]] uint64_t actionIndex = addAction(storm::jani::Action(SILENT_ACTION_NAME));
62 STORM_LOG_ASSERT(actionIndex == SILENT_ACTION_INDEX, "Illegal silent action index.");
63}
64
65Model::Model(Model const& other) {
66 *this = other;
67}
68
70 if (this != &other) {
71 this->name = other.name;
72 this->modelType = other.modelType;
73 this->modelFeatures = other.modelFeatures;
74 this->version = other.version;
75 this->expressionManager = other.expressionManager;
76 this->actions = other.actions;
77 this->actionToIndex = other.actionToIndex;
78 this->nonsilentActionIndices = other.nonsilentActionIndices;
79 this->constants = other.constants;
80 this->constantToIndex = other.constantToIndex;
81 this->globalVariables = other.globalVariables;
82 this->nonTrivialRewardModels = other.nonTrivialRewardModels;
83 this->automata = other.automata;
84 this->automatonToIndex = other.automatonToIndex;
85 this->composition = other.composition;
86 this->initialStatesRestriction = other.initialStatesRestriction;
87 this->globalFunctions = other.globalFunctions;
88
89 // Now that we have copied all the data, we need to fix all assignments as they contain references to the old model.
90 std::map<Variable const*, std::reference_wrapper<Variable const>> remapping;
91 for (auto const& variable : other.getGlobalVariables()) {
92 remapping.emplace(&variable, this->getGlobalVariables().getVariable(variable.getName()));
93 }
94 auto otherAutomatonIt = other.automata.begin();
95 auto thisAutomatonIt = this->automata.begin();
96
97 for (; otherAutomatonIt != other.automata.end(); ++otherAutomatonIt, ++thisAutomatonIt) {
98 for (auto const& variable : otherAutomatonIt->getVariables()) {
99 remapping.emplace(&variable, thisAutomatonIt->getVariables().getVariable(variable.getName()));
100 }
101
102 thisAutomatonIt->changeAssignmentVariables(remapping);
103 }
104 }
105
106 return *this;
107}
108
110 return *expressionManager;
111}
112
113uint64_t Model::getJaniVersion() const {
114 return version;
115}
116
118 return modelType;
119}
120
121void Model::setModelType(ModelType const& newModelType) {
122 modelType = newModelType;
123}
124
126 return modelFeatures;
127}
128
130 return modelFeatures;
131}
132
133std::string const& Model::getName() const {
134 return name;
135}
136
137void Model::setName(std::string const& newName) {
138 name = newName;
139}
140
143 // Intentionally left empty.
144 }
145
146 uint64_t actionIndex;
147 std::vector<uint64_t> components;
148 std::vector<uint64_t> condition;
149 boost::optional<storm::expressions::Expression> rate;
150 std::vector<storm::expressions::Expression> probabilities;
151 std::vector<std::vector<uint64_t>> effects;
152 std::shared_ptr<TemplateEdge> templateEdge;
153};
154
155storm::expressions::Expression createSynchronizedGuard(std::vector<std::reference_wrapper<Edge const>> const& chosenEdges) {
156 STORM_LOG_ASSERT(!chosenEdges.empty(), "Expected non-empty set of edges.");
157 auto it = chosenEdges.begin();
158 storm::expressions::Expression result = it->get().getGuard();
159 ++it;
160 for (; it != chosenEdges.end(); ++it) {
161 result = result && it->get().getGuard();
162 }
163 return result;
164}
165
166ConditionalMetaEdge createSynchronizedMetaEdge(Automaton& automaton, std::vector<std::reference_wrapper<Edge const>> const& edgesToSynchronize) {
167 ConditionalMetaEdge result;
168
169 result.templateEdge = std::make_shared<TemplateEdge>(createSynchronizedGuard(edgesToSynchronize));
170 automaton.registerTemplateEdge(result.templateEdge);
171
172 for (auto const& edge : edgesToSynchronize) {
173 result.condition.push_back(edge.get().getSourceLocationIndex());
174 }
175
176 // Initialize all update iterators.
177 std::vector<std::vector<EdgeDestination>::const_iterator> destinationIterators;
178 for (uint_fast64_t i = 0; i < edgesToSynchronize.size(); ++i) {
179 destinationIterators.push_back(edgesToSynchronize[i].get().getDestinations().cbegin());
180 }
181
182 bool doneDestinations = false;
183 do {
184 // We create the new likelihood expression by multiplying the particapting destination probability expressions.
185 result.probabilities.emplace_back(destinationIterators[0]->getProbability());
186 for (uint_fast64_t i = 1; i < destinationIterators.size(); ++i) {
187 result.probabilities.back() = result.probabilities.back() * destinationIterators[i]->getProbability();
188 }
189
190 // Now concatenate all assignments of all participating destinations.
191 TemplateEdgeDestination templateDestination;
192 for (uint_fast64_t i = 0; i < destinationIterators.size(); ++i) {
193 for (auto const& assignment : destinationIterators[i]->getOrderedAssignments().getAllAssignments()) {
194 templateDestination.addAssignment(assignment);
195 }
196 }
197
198 // Then we are ready to add the new destination.
199 result.templateEdge->addDestination(templateDestination);
200
201 // Finally, add the location effects.
202 result.effects.emplace_back();
203 for (uint_fast64_t i = 0; i < destinationIterators.size(); ++i) {
204 result.effects.back().push_back(destinationIterators[i]->getLocationIndex());
205 }
206
207 // Now check whether there is some update combination we have not yet explored.
208 bool movedIterator = false;
209 for (int_fast64_t j = destinationIterators.size() - 1; j >= 0; --j) {
210 ++destinationIterators[j];
211 if (destinationIterators[j] != edgesToSynchronize[j].get().getDestinations().cend()) {
212 movedIterator = true;
213 break;
214 } else {
215 // Reset the iterator to the beginning of the list.
216 destinationIterators[j] = edgesToSynchronize[j].get().getDestinations().cbegin();
217 }
218 }
219
220 doneDestinations = !movedIterator;
221 } while (!doneDestinations);
222
223 return result;
224}
225
226std::vector<ConditionalMetaEdge> createSynchronizingMetaEdges(Model const& oldModel, Model& newModel, Automaton& newAutomaton,
227 std::vector<std::set<uint64_t>>& synchronizingActionIndices, SynchronizationVector const& vector,
228 std::vector<std::reference_wrapper<Automaton const>> const& composedAutomata,
230 std::vector<ConditionalMetaEdge> result;
231
232 // Gather all participating automata and the corresponding input symbols.
233 std::vector<uint64_t> components;
234 std::vector<std::pair<std::reference_wrapper<Automaton const>, uint64_t>> participatingAutomataAndActions;
235 for (uint64_t i = 0; i < composedAutomata.size(); ++i) {
236 std::string const& actionName = vector.getInput(i);
238 components.push_back(i);
239 uint64_t actionIndex = oldModel.getActionIndex(actionName);
240 // store that automaton occurs in the sync vector.
241 participatingAutomataAndActions.push_back(std::make_pair(composedAutomata[i], actionIndex));
242 // Store for later that this action is one of the possible actions that synchronise
243 synchronizingActionIndices[i].insert(actionIndex);
244 }
245 }
246
247 // What is the action label that should be attached to the composed actions
248 uint64_t resultingActionIndex = Model::SILENT_ACTION_INDEX;
249 if (vector.getOutput() != Model::SILENT_ACTION_NAME) {
250 if (newModel.hasAction(vector.getOutput())) {
251 resultingActionIndex = newModel.getActionIndex(vector.getOutput());
252 } else {
253 resultingActionIndex = newModel.addAction(vector.getOutput());
254 }
255 }
256
257 bool noCombinations = false;
258
259 // Prepare the list that stores for each automaton the list of edges with the participating action.
260 std::vector<std::vector<std::reference_wrapper<storm::jani::Edge const>>> possibleEdges;
261
262 for (auto const& automatonActionPair : participatingAutomataAndActions) {
263 possibleEdges.emplace_back();
264 for (auto const& edge : automatonActionPair.first.get().getEdges()) {
265 if (edge.getActionIndex() == automatonActionPair.second) {
266 possibleEdges.back().push_back(edge);
267 }
268 }
269
270 // If there were no edges with the participating action index, then there is no synchronization possible.
271 if (possibleEdges.back().empty()) {
272 noCombinations = true;
273 break;
274 }
275 }
276
277 // If there are no valid combinations for the action, we need to skip the generation of synchronizing edges.
278 if (!noCombinations) {
279 // Save state of solver so that we can always restore the point where we have exactly the constant values
280 // and variables bounds on the assertion stack.
281 solver.push();
282
283 // Start by creating a fresh auxiliary variable for each edge and link it with the guard.
284 std::vector<std::vector<storm::expressions::Variable>> edgeVariables(possibleEdges.size());
285 std::vector<storm::expressions::Variable> allEdgeVariables;
286 for (uint_fast64_t outerIndex = 0; outerIndex < possibleEdges.size(); ++outerIndex) {
287 // Create auxiliary variables and link them with the guards.
288 for (uint_fast64_t innerIndex = 0; innerIndex < possibleEdges[outerIndex].size(); ++innerIndex) {
289 edgeVariables[outerIndex].push_back(newModel.getManager().declareFreshBooleanVariable());
290 allEdgeVariables.push_back(edgeVariables[outerIndex].back());
291 storm::expressions::Expression guard = eliminateFunctionCallsInExpression(possibleEdges[outerIndex][innerIndex].get().getGuard(), oldModel);
292 solver.add(implies(edgeVariables[outerIndex].back(), guard));
293 }
294
295 storm::expressions::Expression atLeastOneEdgeFromAutomaton = newModel.getManager().boolean(false);
296 for (auto const& edgeVariable : edgeVariables[outerIndex]) {
297 atLeastOneEdgeFromAutomaton = atLeastOneEdgeFromAutomaton || edgeVariable;
298 }
299 solver.add(atLeastOneEdgeFromAutomaton);
300
301 storm::expressions::Expression atMostOneEdgeFromAutomaton = newModel.getManager().boolean(true);
302 for (uint64_t first = 0; first < possibleEdges[outerIndex].size(); ++first) {
303 for (uint64_t second = first + 1; second < possibleEdges[outerIndex].size(); ++second) {
304 atMostOneEdgeFromAutomaton = atMostOneEdgeFromAutomaton && !(edgeVariables[outerIndex][first] && edgeVariables[outerIndex][second]);
305 }
306 }
307 solver.add(atMostOneEdgeFromAutomaton);
308 }
309
310 // Now enumerate all possible combinations.
311 solver.allSat(allEdgeVariables, [&](storm::solver::SmtSolver::ModelReference& modelReference) -> bool {
312 // Now we need to reconstruct the chosen edges from the valuation of the edge variables.
313 std::vector<std::reference_wrapper<Edge const>> chosenEdges;
314
315 for (uint_fast64_t outerIndex = 0; outerIndex < edgeVariables.size(); ++outerIndex) {
316 for (uint_fast64_t innerIndex = 0; innerIndex < edgeVariables[outerIndex].size(); ++innerIndex) {
317 if (modelReference.getBooleanValue(edgeVariables[outerIndex][innerIndex])) {
318 chosenEdges.emplace_back(possibleEdges[outerIndex][innerIndex]);
319 break;
320 }
321 }
322 }
323
324 // Get a basic conditional meta edge that represents the synchronization of the provided edges.
325 // Note that there is still information missing, which we need to add (like the action index etc.).
326 ConditionalMetaEdge conditionalMetaEdge = createSynchronizedMetaEdge(newAutomaton, chosenEdges);
327
328 // Set the participating components.
329 conditionalMetaEdge.components = components;
330
331 // Set the action index.
332 conditionalMetaEdge.actionIndex = resultingActionIndex;
333
334 result.push_back(conditionalMetaEdge);
335
336 return true;
337 });
338
339 solver.pop();
340 }
341
342 return result;
343}
344
345void createCombinedLocation(std::vector<std::reference_wrapper<Automaton const>> const& composedAutomata, Automaton& newAutomaton,
346 std::vector<uint64_t> const& locations, bool initial = false) {
347 std::stringstream locationNameBuilder;
348 for (uint64_t i = 0; i < locations.size(); ++i) {
349 locationNameBuilder << composedAutomata[i].get().getLocation(locations[i]).getName() << "_";
350 }
351
352 uint64_t locationIndex = newAutomaton.addLocation(Location(locationNameBuilder.str()));
353 Location& location = newAutomaton.getLocation(locationIndex);
354 for (uint64_t i = 0; i < locations.size(); ++i) {
355 for (auto const& assignment : composedAutomata[i].get().getLocation(locations[i]).getAssignments()) {
356 location.addTransientAssignment(assignment);
357 }
358 }
359
360 if (initial) {
361 newAutomaton.addInitialLocation(locationIndex);
362 }
363}
364
365void addEdgesToReachableLocations(std::vector<std::reference_wrapper<Automaton const>> const& composedAutomata, Automaton& newAutomaton,
366 std::vector<ConditionalMetaEdge> const& conditionalMetaEdges) {
367 // Maintain a stack of locations that still need to be to explored.
368 std::vector<std::vector<uint64_t>> locationsToExplore;
369
370 // Enumerate all initial location combinations.
371 std::vector<std::set<uint64_t>::const_iterator> initialLocationsIts;
372 std::vector<std::set<uint64_t>::const_iterator> initialLocationsItes;
373 for (auto const& automaton : composedAutomata) {
374 initialLocationsIts.push_back(automaton.get().getInitialLocationIndices().cbegin());
375 initialLocationsItes.push_back(automaton.get().getInitialLocationIndices().cend());
376 }
377 std::vector<uint64_t> initialLocation(composedAutomata.size());
379 initialLocationsIts, initialLocationsItes, [&initialLocation](uint64_t index, uint64_t value) { initialLocation[index] = value; },
380 [&locationsToExplore, &initialLocation]() {
381 locationsToExplore.push_back(initialLocation);
382 return true;
383 });
384
385 // We also maintain a mapping from location combinations to new locations.
386 std::unordered_map<std::vector<uint64_t>, uint64_t, storm::utility::vector::VectorHash<uint64_t>> newLocationMapping;
387
388 // Register all initial locations as new locations.
389 for (auto const& location : locationsToExplore) {
390 uint64_t id = newLocationMapping.size();
391 newLocationMapping[location] = id;
392 createCombinedLocation(composedAutomata, newAutomaton, location, true);
393 }
394
395 // As long as there are locations to explore, do so.
396 while (!locationsToExplore.empty()) {
397 std::vector<uint64_t> currentLocations = std::move(locationsToExplore.back());
398 locationsToExplore.pop_back();
399
400 for (auto const& metaEdge : conditionalMetaEdges) {
401 bool isApplicable = true;
402 for (uint64_t i = 0; i < metaEdge.components.size(); ++i) {
403 if (currentLocations[metaEdge.components[i]] != metaEdge.condition[i]) {
404 isApplicable = false;
405 break;
406 }
407 }
408
409 if (isApplicable) {
410 std::vector<uint64_t> newLocations;
411
412 for (auto const& effect : metaEdge.effects) {
413 std::vector<uint64_t> targetLocationCombination = currentLocations;
414 for (uint64_t i = 0; i < metaEdge.components.size(); ++i) {
415 targetLocationCombination[metaEdge.components[i]] = effect[i];
416 }
417
418 // Check whether the target combination is new.
419 auto it = newLocationMapping.find(targetLocationCombination);
420 if (it != newLocationMapping.end()) {
421 newLocations.emplace_back(it->second);
422 } else {
423 uint64_t id = newLocationMapping.size();
424 newLocationMapping[targetLocationCombination] = id;
425 locationsToExplore.emplace_back(std::move(targetLocationCombination));
426 newLocations.emplace_back(id);
427 createCombinedLocation(composedAutomata, newAutomaton, newLocations);
428 }
429 }
430
431 newAutomaton.addEdge(Edge(newLocationMapping.at(currentLocations), metaEdge.actionIndex, metaEdge.rate, metaEdge.templateEdge, newLocations,
432 metaEdge.probabilities));
433 }
434 }
435 }
436}
437
438Model Model::flattenComposition(std::shared_ptr<storm::utility::solver::SmtSolverFactory> const& smtSolverFactory) const {
439 // If there is only one automaton and then system composition is the standard one, we don't need to modify
440 // the model.
441 if (this->getNumberOfAutomata() == 1 && this->hasStandardComposition()) {
442 return *this;
443 }
444
445 // Check for current restrictions of flatting process.
446 STORM_LOG_THROW(this->hasStandardCompliantComposition(), storm::exceptions::WrongFormatException,
447 "Flatting composition is only supported for standard-compliant compositions.");
448 STORM_LOG_THROW(this->getModelType() == ModelType::DTMC || this->getModelType() == ModelType::MDP, storm::exceptions::InvalidTypeException,
449 "Unable to flatten modules for model of type '" << this->getModelType() << "'.");
450 STORM_LOG_WARN_COND(!this->getModelFeatures().hasArrays(),
451 "Flattening JANI model with arrays is not supported. We'll try but there might be unexpected errors.");
452 if (this->getModelFeatures().hasFunctions()) {
453 for (auto const& aut : automata) {
454 STORM_LOG_THROW(aut.getFunctionDefinitions().empty(), storm::exceptions::NotImplementedException,
455 "Flattening JANI model with local function declarations not implemented. Try to eliminate functions first or make them global.");
456 }
457 }
458
459 // Otherwise, we need to actually flatten composition.
460 Model flattenedModel(this->getName() + "_flattened", this->getModelType(), this->getJaniVersion(), this->getManager().shared_from_this());
461
462 flattenedModel.getModelFeatures() = getModelFeatures();
463
464 // Get an SMT solver for computing possible guard combinations.
465 std::unique_ptr<storm::solver::SmtSolver> solver = smtSolverFactory->create(*expressionManager);
466
467 Composition const& systemComposition = getSystemComposition();
468 if (systemComposition.isAutomatonComposition()) {
469 AutomatonComposition const& automatonComposition = systemComposition.asAutomatonComposition();
470 STORM_LOG_THROW(automatonComposition.getInputEnabledActions().empty(), storm::exceptions::WrongFormatException,
471 "Flatting does not support input-enabling actions.");
472 return createModelFromAutomaton(getAutomaton(automatonComposition.getAutomatonName()));
473 }
474
475 // Ensure that we have a parallel composition from now on.
476 STORM_LOG_THROW(systemComposition.isParallelComposition(), storm::exceptions::WrongFormatException, "Unknown system composition cannot be flattened.");
477 ParallelComposition const& parallelComposition = systemComposition.asParallelComposition();
478
479 // Create the new automaton that will hold the flattened system.
480 Automaton newAutomaton(this->getName() + "_flattened", expressionManager->declareIntegerVariable("_loc_flattened_" + this->getName()));
481
482 std::map<Variable const*, std::reference_wrapper<Variable const>> variableRemapping;
483 for (auto const& variable : getGlobalVariables()) {
484 std::unique_ptr<Variable> renamedVariable = variable.clone();
485 variableRemapping.emplace(&variable, flattenedModel.addVariable(*renamedVariable));
486 }
487
488 for (auto const& constant : getConstants()) {
489 flattenedModel.addConstant(constant);
490 }
491
492 for (auto const& nonTrivRew : getNonTrivialRewardExpressions()) {
493 flattenedModel.addNonTrivialRewardExpression(nonTrivRew.first, nonTrivRew.second);
494 }
495
496 for (auto const& funDef : getGlobalFunctionDefinitions()) {
497 flattenedModel.addFunctionDefinition(funDef.second);
498 }
499
500 std::vector<std::reference_wrapper<Automaton const>> composedAutomata;
501 for (auto const& element : parallelComposition.getSubcompositions()) {
502 STORM_LOG_THROW(element->isAutomatonComposition(), storm::exceptions::WrongFormatException,
503 "Cannot flatten recursive (not standard-compliant) composition.");
504 AutomatonComposition const& automatonComposition = element->asAutomatonComposition();
505 STORM_LOG_THROW(automatonComposition.getInputEnabledActions().empty(), storm::exceptions::WrongFormatException,
506 "Flatting does not support input-enabling actions.");
507 Automaton const& oldAutomaton = this->getAutomaton(automatonComposition.getAutomatonName());
508 composedAutomata.push_back(oldAutomaton);
509
510 // Prefix all variables of this automaton with the automaton's name and add the to the resulting automaton.
511 for (auto const& variable : oldAutomaton.getVariables()) {
512 std::unique_ptr<Variable> renamedVariable = variable.clone();
513 renamedVariable->setName(oldAutomaton.getName() + "_" + renamedVariable->getName());
514 variableRemapping.emplace(&variable, newAutomaton.addVariable(*renamedVariable));
515 }
516 }
517
518 // Prepare the solver.
519 // Assert the values of the constants.
520 for (auto const& constant : this->getConstants()) {
521 if (constant.isDefined()) {
522 if (constant.isBooleanConstant()) {
523 solver->add(storm::expressions::iff(constant.getExpressionVariable(), constant.getExpression()));
524 } else {
525 solver->add(constant.getExpressionVariable() == constant.getExpression());
526 }
527 }
528 }
529 // Assert the bounds of the global variables.
530 for (auto const& variable : newAutomaton.getVariables().getBoundedIntegerVariables()) {
531 solver->add(variable.getRangeExpression());
532 }
533
534 // Perform all necessary synchronizations and keep track which action indices participate in synchronization.
535 std::vector<std::set<uint64_t>> synchronizingActionIndices(composedAutomata.size());
536 std::vector<ConditionalMetaEdge> conditionalMetaEdges;
537 for (auto const& vector : parallelComposition.getSynchronizationVectors()) {
538 // If less then 2 automata participate, there is no need to perform a synchronization.
539 if (vector.getNumberOfActionInputs() <= 1) {
540 continue;
541 }
542
543 // Create all conditional template edges corresponding to this synchronization vector.
544 std::vector<ConditionalMetaEdge> newConditionalMetaEdges =
545 createSynchronizingMetaEdges(*this, flattenedModel, newAutomaton, synchronizingActionIndices, vector, composedAutomata, *solver);
546 conditionalMetaEdges.insert(conditionalMetaEdges.end(), newConditionalMetaEdges.begin(), newConditionalMetaEdges.end());
547 }
548
549 // Now add all edges with action indices that were not mentioned in synchronization vectors.
550 for (uint64_t i = 0; i < composedAutomata.size(); ++i) {
551 Automaton const& automaton = composedAutomata[i].get();
552 for (auto const& edge : automaton.getEdges()) {
553 if (synchronizingActionIndices[i].find(edge.getActionIndex()) == synchronizingActionIndices[i].end()) {
554 uint64_t actionIndex = edge.getActionIndex();
555 if (actionIndex != SILENT_ACTION_INDEX) {
556 std::string actionName = this->getActionIndexToNameMap().at(edge.getActionIndex());
557 if (flattenedModel.hasAction(actionName)) {
558 actionIndex = flattenedModel.getActionIndex(actionName);
559 } else {
560 actionIndex = flattenedModel.addAction(actionName);
561 }
562 }
563
564 conditionalMetaEdges.emplace_back();
565 ConditionalMetaEdge& conditionalMetaEdge = conditionalMetaEdges.back();
566
567 conditionalMetaEdge.templateEdge = std::make_shared<TemplateEdge>(edge.getGuard());
568 newAutomaton.registerTemplateEdge(conditionalMetaEdge.templateEdge);
569 conditionalMetaEdge.actionIndex = edge.getActionIndex();
570 conditionalMetaEdge.components.emplace_back(static_cast<uint64_t>(i));
571 conditionalMetaEdge.condition.emplace_back(edge.getSourceLocationIndex());
572 conditionalMetaEdge.rate = edge.getOptionalRate();
573 for (auto const& destination : edge.getDestinations()) {
574 conditionalMetaEdge.templateEdge->addDestination(destination.getOrderedAssignments());
575 conditionalMetaEdge.effects.emplace_back();
576
577 conditionalMetaEdge.effects.back().emplace_back(destination.getLocationIndex());
578 conditionalMetaEdge.probabilities.emplace_back(destination.getProbability());
579 }
580 }
581 }
582 }
583
584 // Now that all meta edges have been built, we can explore the location space and add all edges based
585 // on the templates.
586 addEdgesToReachableLocations(composedAutomata, newAutomaton, conditionalMetaEdges);
587
588 // Fix all variables mentioned in assignments by applying the constructed remapping.
589 newAutomaton.changeAssignmentVariables(variableRemapping);
590
591 // Finalize the flattened model.
592 storm::expressions::Expression initialStatesRestriction = getManager().boolean(true);
593 for (auto const& automaton : composedAutomata) {
594 if (automaton.get().hasInitialStatesRestriction()) {
595 initialStatesRestriction = initialStatesRestriction && automaton.get().getInitialStatesRestriction();
596 }
597 for (auto const& funDef : automaton.get().getFunctionDefinitions()) {
598 newAutomaton.addFunctionDefinition(funDef.second);
599 }
600 }
601
602 newAutomaton.setInitialStatesRestriction(this->getInitialStatesExpression(composedAutomata));
603 if (this->hasInitialStatesRestriction()) {
605 }
606 flattenedModel.addAutomaton(newAutomaton);
607 flattenedModel.setStandardSystemComposition();
608 flattenedModel.finalize();
609
610 return flattenedModel;
611}
612
613uint64_t Model::addAction(Action const& action) {
614 auto it = actionToIndex.find(action.getName());
615 STORM_LOG_THROW(it == actionToIndex.end(), storm::exceptions::WrongFormatException, "Action with name '" << action.getName() << "' already exists.");
616 actionToIndex.emplace(action.getName(), actions.size());
617 actions.push_back(action);
618 if (action.getName() != SILENT_ACTION_NAME) {
619 nonsilentActionIndices.insert(actions.size() - 1);
620 }
621 return actions.size() - 1;
622}
623
624Action const& Model::getAction(uint64_t index) const {
625 return actions[index];
626}
627
628bool Model::hasAction(std::string const& name) const {
629 return actionToIndex.find(name) != actionToIndex.end();
630}
631
632uint64_t Model::getActionIndex(std::string const& name) const {
633 auto it = actionToIndex.find(name);
634 STORM_LOG_THROW(it != actionToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve index of unknown action '" << name << "'.");
635 return it->second;
636}
637
638std::unordered_map<std::string, uint64_t> const& Model::getActionToIndexMap() const {
639 return actionToIndex;
640}
641
642std::vector<Action> const& Model::getActions() const {
643 return actions;
644}
645
647 return nonsilentActionIndices;
648}
649
650void Model::addConstant(Constant const& constant) {
651 auto it = constantToIndex.find(constant.getName());
652 STORM_LOG_THROW(it == constantToIndex.end(), storm::exceptions::WrongFormatException,
653 "Cannot add constant with name '" << constant.getName() << "', because a constant with that name already exists.");
654 constantToIndex.emplace(constant.getName(), constants.size());
655 constants.push_back(constant);
656 // Note that we should not return a reference to the inserted constant as it might get invalidated when more constants are added.
657}
658
659bool Model::hasConstant(std::string const& name) const {
660 return constantToIndex.find(name) != constantToIndex.end();
661}
662
663void Model::removeConstant(std::string const& name) {
664 auto pos = constantToIndex.find(name);
665 if (pos != constantToIndex.end()) {
666 uint64_t index = pos->second;
667 constants.erase(constants.begin() + index);
668 constantToIndex.erase(pos);
669 for (auto& entry : constantToIndex) {
670 if (entry.second > index) {
671 entry.second--;
672 }
673 }
674 } else {
675 STORM_LOG_ERROR("Could not remove constant: " << name << ".");
676 }
677}
678
679Constant const& Model::getConstant(std::string const& name) const {
680 auto it = constantToIndex.find(name);
681 STORM_LOG_THROW(it != constantToIndex.end(), storm::exceptions::WrongFormatException, "Unable to retrieve unknown constant '" << name << "'.");
682 return constants[it->second];
683}
684
685std::vector<Constant> const& Model::getConstants() const {
686 return constants;
687}
688
689std::vector<Constant>& Model::getConstants() {
690 return constants;
691}
692
693std::size_t Model::getNumberOfEdges() const {
694 size_t res = 0;
695 for (auto const& aut : getAutomata()) {
696 res += aut.getNumberOfEdges();
697 }
698 return res;
699}
700
702 std::size_t res = globalVariables.getNumberOfNontransientVariables();
703 for (auto const& aut : getAutomata()) {
704 res += aut.getVariables().getNumberOfNontransientVariables();
705 }
706 return res;
707}
708
712
713Variable const& Model::addVariable(Variable const& variable) {
714 return globalVariables.addVariable(variable);
715}
716
718 return globalVariables;
719}
720
722 return globalVariables;
723}
724
725std::set<storm::expressions::Variable> Model::getAllExpressionVariables(bool includeLocationExpressionVariables) const {
726 std::set<storm::expressions::Variable> result;
727
728 for (auto const& constant : constants) {
729 result.insert(constant.getExpressionVariable());
730 }
731 for (auto const& variable : this->getGlobalVariables()) {
732 result.insert(variable.getExpressionVariable());
733 }
734 for (auto const& automaton : automata) {
735 auto const& automatonVariables = automaton.getAllExpressionVariables();
736 result.insert(automatonVariables.begin(), automatonVariables.end());
737 if (includeLocationExpressionVariables) {
738 result.insert(automaton.getLocationExpressionVariable());
739 }
740 }
741
742 return result;
743}
744
745std::set<storm::expressions::Variable> Model::getAllLocationExpressionVariables() const {
746 std::set<storm::expressions::Variable> result;
747 for (auto const& automaton : automata) {
748 result.insert(automaton.getLocationExpressionVariable());
749 }
750 return result;
751}
752
753bool Model::hasGlobalVariable(std::string const& name) const {
754 return globalVariables.hasVariable(name);
755}
756
757Variable const& Model::getGlobalVariable(std::string const& name) const {
758 return globalVariables.getVariable(name);
759}
760
762 for (auto const& automaton : automata) {
763 if (automaton.hasTransientVariable()) {
764 return true;
765 }
766 }
767 return false;
768}
769
771 auto insertionRes = globalFunctions.emplace(functionDefinition.getName(), functionDefinition);
772 STORM_LOG_THROW(insertionRes.second, storm::exceptions::InvalidOperationException,
773 " a function with the name " << functionDefinition.getName() << " already exists in this model.");
774 return insertionRes.first->second;
775}
776
777std::unordered_map<std::string, FunctionDefinition> const& Model::getGlobalFunctionDefinitions() const {
778 return globalFunctions;
779}
780
781std::unordered_map<std::string, FunctionDefinition>& Model::getGlobalFunctionDefinitions() {
782 return globalFunctions;
783}
784
786 return *expressionManager;
787}
788
790 return !nonTrivialRewardModels.empty();
791}
792
793bool Model::isNonTrivialRewardModelExpression(std::string const& identifier) const {
794 return nonTrivialRewardModels.count(identifier) > 0;
795}
796
797bool Model::addNonTrivialRewardExpression(std::string const& identifier, storm::expressions::Expression const& rewardExpression) {
798 if (isNonTrivialRewardModelExpression(identifier)) {
799 return false;
800 } else {
801 STORM_LOG_THROW(!globalVariables.hasVariable(identifier) || !globalVariables.getVariable(identifier).isTransient(),
802 storm::exceptions::InvalidArgumentException,
803 "Non trivial reward expression with identifier '" << identifier << "' clashes with global transient variable of the same name.");
804 nonTrivialRewardModels.emplace(identifier, rewardExpression);
805 return true;
806 }
807}
808
810 auto findRes = nonTrivialRewardModels.find(identifier);
811 if (findRes != nonTrivialRewardModels.end()) {
812 return findRes->second;
813 } else {
814 // Check whether the reward model refers to a global variable
815 if (globalVariables.hasVariable(identifier)) {
816 return globalVariables.getVariable(identifier).getExpressionVariable().getExpression();
817 } else {
818 STORM_LOG_THROW(identifier.empty(), storm::exceptions::InvalidArgumentException, "Cannot find unknown reward model '" << identifier << "'.");
819 STORM_LOG_THROW(nonTrivialRewardModels.size() + globalVariables.getNumberOfNumericalTransientVariables() == 1,
820 storm::exceptions::InvalidArgumentException, "Reference to standard reward model is ambiguous.");
821 if (nonTrivialRewardModels.size() == 1) {
822 return nonTrivialRewardModels.begin()->second;
823 } else {
824 for (auto const& variable : globalVariables.getTransientVariables()) {
825 auto const& type = variable.getType();
826 if ((type.isBasicType() && type.asBasicType().isNumericalType()) || (type.isBoundedType() && type.asBoundedType().isNumericalType())) {
827 return variable.getExpressionVariable().getExpression();
828 }
829 }
830 }
831 }
832 }
833 STORM_LOG_THROW(false, storm::exceptions::InvalidArgumentException, "Cannot find unknown reward model '" << identifier << "'.");
835}
836
837std::vector<std::pair<std::string, storm::expressions::Expression>> Model::getAllRewardModelExpressions() const {
838 std::vector<std::pair<std::string, storm::expressions::Expression>> result;
839 for (auto const& nonTrivExpr : nonTrivialRewardModels) {
840 result.emplace_back(nonTrivExpr.first, nonTrivExpr.second);
841 }
842 for (auto const& variable : globalVariables.getTransientVariables()) {
843 auto const& type = variable.getType();
844 if ((type.isBasicType() && type.asBasicType().isNumericalType()) || (type.isBoundedType() && type.asBoundedType().isNumericalType())) {
845 result.emplace_back(variable.getName(), variable.getExpressionVariable().getExpression());
846 }
847 }
848 return result;
849}
850
851std::unordered_map<std::string, storm::expressions::Expression> const& Model::getNonTrivialRewardExpressions() const {
852 return nonTrivialRewardModels;
853}
854
855std::unordered_map<std::string, storm::expressions::Expression>& Model::getNonTrivialRewardExpressions() {
856 return nonTrivialRewardModels;
857}
858
859uint64_t Model::addAutomaton(Automaton const& automaton) {
860 auto it = automatonToIndex.find(automaton.getName());
861 STORM_LOG_THROW(it == automatonToIndex.end(), storm::exceptions::WrongFormatException,
862 "Automaton with name '" << automaton.getName() << "' already exists.");
863 automatonToIndex.emplace(automaton.getName(), automata.size());
864 automata.push_back(automaton);
865 return automata.size() - 1;
866}
867
868std::vector<Automaton>& Model::getAutomata() {
869 return automata;
870}
871
872std::vector<Automaton> const& Model::getAutomata() const {
873 return automata;
874}
875
876bool Model::hasAutomaton(std::string const& name) const {
877 return automatonToIndex.find(name) != automatonToIndex.end();
878}
879
880void Model::replaceAutomaton(uint64_t index, Automaton const& automaton) {
881 automata[index] = automaton;
882}
883
884Automaton& Model::getAutomaton(std::string const& name) {
885 auto it = automatonToIndex.find(name);
886 STORM_LOG_THROW(it != automatonToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve unknown automaton '" << name << "'.");
887 return automata[it->second];
888}
889
891 return automata[index];
892}
893
894Automaton const& Model::getAutomaton(uint64_t index) const {
895 return automata[index];
896}
897
898Automaton const& Model::getAutomaton(std::string const& name) const {
899 auto it = automatonToIndex.find(name);
900 STORM_LOG_THROW(it != automatonToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve unknown automaton '" << name << "'.");
901 return automata[it->second];
902}
903
904uint64_t Model::getAutomatonIndex(std::string const& name) const {
905 auto it = automatonToIndex.find(name);
906 STORM_LOG_THROW(it != automatonToIndex.end(), storm::exceptions::InvalidOperationException, "Unable to retrieve unknown automaton '" << name << "'.");
907 return it->second;
908}
909
910std::size_t Model::getNumberOfAutomata() const {
911 return automata.size();
912}
913
914std::shared_ptr<Composition> Model::getStandardSystemComposition() const {
915 // Determine the action indices used by each of the automata and create the standard subcompositions.
916 std::set<uint64_t> allActionIndices;
917 std::vector<std::set<uint64_t>> automatonActionIndices;
918 std::vector<std::shared_ptr<Composition>> subcompositions;
919 for (auto const& automaton : automata) {
920 automatonActionIndices.push_back(automaton.getActionIndices());
921 automatonActionIndices.back().erase(SILENT_ACTION_INDEX);
922 allActionIndices.insert(automatonActionIndices.back().begin(), automatonActionIndices.back().end());
923 subcompositions.push_back(std::make_shared<AutomatonComposition>(automaton.getName()));
924 }
925
926 // Create the standard synchronization vectors: every automaton with that action participates in the
927 // synchronization.
928 std::vector<storm::jani::SynchronizationVector> synchVectors;
929 for (auto actionIndex : allActionIndices) {
930 std::string const& actionName = this->getAction(actionIndex).getName();
931 std::vector<std::string> synchVectorInputs;
932 for (auto const& actionIndices : automatonActionIndices) {
933 if (actionIndices.find(actionIndex) != actionIndices.end()) {
934 synchVectorInputs.push_back(actionName);
935 } else {
936 synchVectorInputs.push_back(storm::jani::SynchronizationVector::NO_ACTION_INPUT);
937 }
938 }
939 synchVectors.push_back(storm::jani::SynchronizationVector(synchVectorInputs, actionName));
940 }
941
942 return std::make_shared<ParallelComposition>(subcompositions, synchVectors);
943}
944
946 return *composition;
947}
948
950 public:
951 CompositionSimplificationVisitor(std::unordered_map<std::string, std::vector<std::string>> const& automatonToCopiesMap)
952 : automatonToCopiesMap(automatonToCopiesMap) {}
953
954 std::shared_ptr<Composition> simplify(Composition const& oldComposition) {
955 return boost::any_cast<std::shared_ptr<Composition>>(oldComposition.accept(*this, boost::any()));
956 }
957
958 virtual boost::any visit(AutomatonComposition const& composition, boost::any const&) override {
959 std::string name = composition.getAutomatonName();
960 if (automatonToCopiesMap.count(name) != 0) {
961 auto& copies = automatonToCopiesMap[name];
962 STORM_LOG_ASSERT(!copies.empty(), "Not enough copies of automaton " << name << ".");
963 name = copies.back();
964 copies.pop_back();
965 }
966 return std::shared_ptr<Composition>(new AutomatonComposition(name, composition.getInputEnabledActions()));
967 }
968
969 virtual boost::any visit(ParallelComposition const& composition, boost::any const& data) override {
970 std::vector<std::shared_ptr<Composition>> subcomposition;
971 for (auto const& p : composition.getSubcompositions()) {
972 subcomposition.push_back(boost::any_cast<std::shared_ptr<Composition>>(p->accept(*this, data)));
973 }
974 return std::shared_ptr<Composition>(new ParallelComposition(subcomposition, composition.getSynchronizationVectors()));
975 }
976
977 private:
978 std::unordered_map<std::string, std::vector<std::string>> automatonToCopiesMap;
979};
980
983 CompositionInformation info = visitor.getInformation();
985 STORM_LOG_WARN("Unable to simplify non-standard compliant system composition.");
986 }
987
988 // Check whether we need to copy certain automata
989 std::unordered_map<std::string, std::vector<std::string>> automatonToCopiesMap;
990 for (auto const& automatonMultiplicity : info.getAutomatonToMultiplicityMap()) {
991 if (automatonMultiplicity.second > 1) {
992 std::vector<std::string> copies = {automatonMultiplicity.first};
993 // We need to copy this automaton n-1 times.
994 for (uint64_t copyIndex = 1; copyIndex < automatonMultiplicity.second; ++copyIndex) {
995 std::string copyPrefix = "Copy__" + std::to_string(copyIndex) + "_Of";
996 std::string copyAutName = copyPrefix + automatonMultiplicity.first;
997 this->addAutomaton(this->getAutomaton(automatonMultiplicity.first).clone(getManager(), copyAutName, copyPrefix));
998 copies.push_back(copyAutName);
999 }
1000 // For esthetic reasons we reverse the list of copies so that the ones with the lowest index will be pop_back'ed first
1001 std::reverse(copies.begin(), copies.end());
1002 // We insert the copies in reversed order as they will be popped in reversed order, as well.
1003 automatonToCopiesMap[automatonMultiplicity.first] = std::move(copies);
1004 }
1005 }
1006
1007 if (!automatonToCopiesMap.empty()) {
1008 // Traverse the system composition and exchange automata by their copy
1009 auto newComposition = CompositionSimplificationVisitor(automatonToCopiesMap).simplify(getSystemComposition());
1010 this->setSystemComposition(newComposition);
1011 }
1012}
1013
1014void Model::setSystemComposition(std::shared_ptr<Composition> const& composition) {
1015 this->composition = composition;
1016}
1017
1021
1022std::set<std::string> Model::getActionNames(bool includeSilent) const {
1023 std::set<std::string> result;
1024 for (auto const& entry : actionToIndex) {
1025 if (includeSilent || entry.second != SILENT_ACTION_INDEX) {
1026 result.insert(entry.first);
1027 }
1028 }
1029 return result;
1030}
1031
1032std::map<uint64_t, std::string> Model::getActionIndexToNameMap() const {
1033 std::map<uint64_t, std::string> mapping;
1034 uint64_t i = 0;
1035 for (auto const& act : actions) {
1036 mapping[i] = act.getName();
1037 ++i;
1038 }
1039 return mapping;
1040}
1041
1042Model Model::defineUndefinedConstants(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const {
1043 Model result(*this);
1044
1045 std::set<storm::expressions::Variable> definedUndefinedConstants;
1046 for (auto& constant : result.constants) {
1047 // If the constant is already defined, we need to replace the appearances of undefined constants in its
1048 // defining expression
1049 if (constant.isDefined()) {
1050 // Make sure we are not trying to define an already defined constant.
1051 STORM_LOG_THROW(constantDefinitions.find(constant.getExpressionVariable()) == constantDefinitions.end(),
1052 storm::exceptions::InvalidOperationException, "Illegally defining already defined constant '" << constant.getName() << "'.");
1053 } else {
1054 auto const& variableExpressionPair = constantDefinitions.find(constant.getExpressionVariable());
1055
1056 if (variableExpressionPair != constantDefinitions.end()) {
1057 // If we need to define it, we add it to the defined constants and assign it the appropriate expression.
1058 definedUndefinedConstants.insert(constant.getExpressionVariable());
1059
1060 // Make sure the type of the constant is correct.
1061 STORM_LOG_THROW(variableExpressionPair->second.getType() == constant.getType(), storm::exceptions::InvalidOperationException,
1062 "Illegal type of expression defining constant '" << constant.getName() << "'.");
1063
1064 // Now define the constant.
1065 if (constant.hasConstraint()) {
1066 // Constraints need to be evaluated before defining a constant.
1067 using SubMap = std::map<storm::expressions::Variable, storm::expressions::Expression>;
1068 storm::expressions::JaniExpressionSubstitutionVisitor<SubMap> transcendentalsVisitor(SubMap(), true);
1069 constant.setConstraintExpression(transcendentalsVisitor.substitute(constant.getConstraintExpression()));
1070 }
1071 constant.define(variableExpressionPair->second);
1072 }
1073 }
1074 }
1075
1076 return result;
1077}
1078
1080 for (auto const& constant : constants) {
1081 if (!constant.isDefined()) {
1082 return true;
1083 }
1084 }
1085 return false;
1086}
1087
1088std::vector<std::reference_wrapper<Constant const>> Model::getUndefinedConstants() const {
1089 std::vector<std::reference_wrapper<Constant const>> result;
1090
1091 for (auto const& constant : constants) {
1092 if (!constant.isDefined()) {
1093 result.push_back(constant);
1094 }
1095 }
1096
1097 return result;
1098}
1099
1104
1105Model& Model::substituteConstantsInPlace(bool const substituteTranscendentalNumbers) {
1106 // Gather all defining expressions of constants.
1107 std::map<storm::expressions::Variable, storm::expressions::Expression> constantSubstitution;
1108 for (auto& constant : this->getConstants()) {
1109 if (constant.hasConstraint()) {
1110 constant.setConstraintExpression(
1111 substituteJaniExpression(constant.getConstraintExpression(), constantSubstitution, substituteTranscendentalNumbers));
1112 }
1113 if (constant.isDefined()) {
1114 constant.define(substituteJaniExpression(constant.getExpression(), constantSubstitution, substituteTranscendentalNumbers));
1115 constantSubstitution[constant.getExpressionVariable()] = constant.getExpression();
1116 }
1117 }
1118
1119 for (auto& functionDefinition : this->getGlobalFunctionDefinitions()) {
1120 functionDefinition.second.substitute(constantSubstitution, substituteTranscendentalNumbers);
1121 }
1122
1123 // Substitute constants in all global variables.
1124 this->getGlobalVariables().substitute(constantSubstitution, substituteTranscendentalNumbers);
1125
1126 // Substitute constants in initial states expression.
1127 this->setInitialStatesRestriction(substituteJaniExpression(this->getInitialStatesRestriction(), constantSubstitution, substituteTranscendentalNumbers));
1128
1129 for (auto& rewMod : this->getNonTrivialRewardExpressions()) {
1130 rewMod.second = substituteJaniExpression(rewMod.second, constantSubstitution, substituteTranscendentalNumbers);
1131 }
1132
1133 // Substitute constants in variables of automata and their edges.
1134 for (auto& automaton : this->getAutomata()) {
1135 automaton.substitute(constantSubstitution, substituteTranscendentalNumbers);
1136 }
1137 return *this;
1138}
1139
1141 Model result(*this);
1143 result.substituteConstantsInPlace(false);
1144 return result;
1145}
1146
1148 Model result(*this);
1150 result.substituteConstantsInPlace(true);
1151 result.substituteFunctions();
1152 return result;
1153}
1154
1155Model Model::preprocess(std::map<storm::expressions::Variable, storm::expressions::Expression> const& constantDefinitions) const {
1156 // We intentionally do not eliminate function expressions in jani models at this point because that would also remove the function
1157 // declarations from the model. However, those might still be needed to, e.g., process properties that refer to functions.
1158 return this->defineUndefinedConstants(constantDefinitions).substituteConstants();
1159}
1160
1161Model Model::preprocess(std::string const& constantDefinitionString) const {
1162 return this->preprocess(storm::storage::parseConstantDefinitionString(this->getManager(), constantDefinitionString));
1163}
1164
1165std::map<storm::expressions::Variable, storm::expressions::Expression> Model::getConstantsSubstitution() const {
1166 std::map<storm::expressions::Variable, storm::expressions::Expression> result;
1167
1168 for (auto const& constant : constants) {
1169 if (constant.isDefined()) {
1170 result.emplace(constant.getExpressionVariable(), constant.getExpression());
1171 }
1172 }
1173
1174 return result;
1175}
1176
1177void Model::substitute(std::map<storm::expressions::Variable, storm::expressions::Expression> const& substitution, bool const substituteTranscendentalNumbers) {
1178 // substitute in all defining expressions of constants
1179 for (auto& constant : this->getConstants()) {
1180 if (constant.hasConstraint()) {
1181 constant.setConstraintExpression(substituteJaniExpression(constant.getConstraintExpression(), substitution, substituteTranscendentalNumbers));
1182 }
1183 if (constant.isDefined()) {
1184 constant.define(substituteJaniExpression(constant.getExpression(), substitution, substituteTranscendentalNumbers));
1185 }
1186 }
1187
1188 for (auto& functionDefinition : this->getGlobalFunctionDefinitions()) {
1189 functionDefinition.second.substitute(substitution, substituteTranscendentalNumbers);
1190 }
1191
1192 // Substitute in all global variables.
1193 for (auto& variable : this->getGlobalVariables().getBoundedIntegerVariables()) {
1194 variable.substitute(substitution, substituteTranscendentalNumbers);
1195 }
1196 for (auto& variable : this->getGlobalVariables().getArrayVariables()) {
1197 variable.substitute(substitution, substituteTranscendentalNumbers);
1198 }
1199 for (auto& variable : this->getGlobalVariables().getClockVariables()) {
1200 variable.substitute(substitution, substituteTranscendentalNumbers);
1201 }
1202
1203 // Substitute in initial states expression.
1204 this->setInitialStatesRestriction(substituteJaniExpression(this->getInitialStatesRestriction(), substitution, substituteTranscendentalNumbers));
1205
1206 for (auto& rewMod : getNonTrivialRewardExpressions()) {
1207 rewMod.second = substituteJaniExpression(rewMod.second, substitution, substituteTranscendentalNumbers);
1208 }
1209
1210 // Substitute in variables of automata and their edges.
1211 for (auto& automaton : this->getAutomata()) {
1212 automaton.substitute(substitution, substituteTranscendentalNumbers);
1213 }
1214}
1215
1217 std::vector<Property> emptyPropertyVector;
1218 substituteFunctions(emptyPropertyVector);
1219}
1220
1221void Model::substituteFunctions(std::vector<Property>& properties) {
1222 eliminateFunctions(*this, properties);
1223}
1224
1227 return true;
1228 }
1229 for (auto const& a : getAutomata()) {
1230 if (a.getVariables().containsArrayVariables()) {
1231 return true;
1232 }
1233 }
1234 return false;
1235}
1236
1237ArrayEliminatorData Model::eliminateArrays(bool keepNonTrivialArrayAccess) {
1238 ArrayEliminator arrayEliminator;
1239 return arrayEliminator.eliminate(*this, keepNonTrivialArrayAccess);
1240}
1241
1242void Model::eliminateArrays(std::vector<Property>& properties) {
1243 auto data = eliminateArrays(false);
1244 for (auto& p : properties) {
1245 data.transformProperty(p);
1246 }
1247}
1248
1250 std::vector<Property> emptyPropertyVector;
1251 return restrictToFeatures(modelFeatures, emptyPropertyVector);
1252}
1253
1254ModelFeatures Model::restrictToFeatures(ModelFeatures const& features, std::vector<Property>& properties) {
1255 ModelFeatures uncheckedFeatures = getModelFeatures();
1256 // Check if functions need to be eliminated.
1257 if (uncheckedFeatures.hasFunctions() && !features.hasFunctions()) {
1258 substituteFunctions(properties);
1259 }
1260 uncheckedFeatures.remove(ModelFeature::Functions);
1261
1262 // Check if arrays need to be eliminated. This should be done after! eliminating the functions
1263 if (uncheckedFeatures.hasArrays() && !features.hasArrays()) {
1264 eliminateArrays(properties);
1265 }
1266 uncheckedFeatures.remove(ModelFeature::Arrays);
1267
1268 // There is no elimination for state exit rewards
1269 if (features.hasStateExitRewards()) {
1270 uncheckedFeatures.remove(ModelFeature::StateExitRewards);
1271 }
1272
1273 // There is no elimination of derived operators
1274 if (features.hasDerivedOperators()) {
1275 uncheckedFeatures.remove(ModelFeature::DerivedOperators);
1276 }
1277
1278 // There is no elimination of MultiObjective properties
1279 if (features.hasDerivedOperators()) {
1281 }
1282
1283 // There is no elimination of trigonometric operators
1284 if (features.hasTrigonometricFunctions()) {
1286 }
1287
1288 return uncheckedFeatures;
1289}
1290
1292 this->initialStatesRestriction = initialStatesRestriction;
1293}
1294
1296 return this->initialStatesRestriction.isInitialized();
1297}
1298
1300 return initialStatesRestriction;
1301}
1302
1304 if (this->hasInitialStatesRestriction() && !this->getInitialStatesRestriction().isTrue()) {
1305 return true;
1306 } else {
1307 for (auto const& variable : this->getGlobalVariables()) {
1308 if (variable.hasInitExpression() && !variable.isTransient()) {
1309 return true;
1310 }
1311 }
1312
1313 for (auto const& automaton : this->automata) {
1314 if (automaton.hasNonTrivialInitialStates()) {
1315 return true;
1316 }
1317 }
1318 }
1319
1320 return false;
1321}
1322
1324 std::vector<std::reference_wrapper<storm::jani::Automaton const>> allAutomata;
1325 for (auto const& automaton : this->getAutomata()) {
1326 allAutomata.push_back(automaton);
1327 }
1328 return getInitialStatesExpression(allAutomata);
1329}
1330
1332 if (this->hasInitialStatesRestriction() && !this->getInitialStatesRestriction().isTrue()) {
1333 return false;
1334 }
1335
1336 bool result = true;
1337 for (auto const& automaton : this->getAutomata()) {
1338 result &= automaton.hasTrivialInitialStatesExpression();
1339 if (!result) {
1340 break;
1341 }
1342 }
1343 return result;
1344}
1345
1346storm::expressions::Expression Model::getInitialStatesExpression(std::vector<std::reference_wrapper<storm::jani::Automaton const>> const& automata) const {
1347 // Start with the restriction of variables.
1348 storm::expressions::Expression result = initialStatesRestriction;
1349
1350 // Then add initial values for those non-transient variables that have one.
1351 for (auto const& variable : globalVariables) {
1352 if (variable.isTransient()) {
1353 continue;
1354 }
1355
1356 if (variable.hasInitExpression()) {
1357 storm::expressions::Expression newInitExpression;
1358 if (variable.getType().isBasicType() && variable.getType().asBasicType().isBooleanType()) {
1359 newInitExpression = storm::expressions::iff(variable.getExpressionVariable(), variable.getInitExpression());
1360 } else {
1361 newInitExpression = variable.getExpressionVariable() == variable.getInitExpression();
1362 }
1363 result = result && newInitExpression;
1364 }
1365 }
1366
1367 // If we are to include the expressions for the automata, do so now.
1368 for (auto const& automatonReference : automata) {
1369 storm::jani::Automaton const& automaton = automatonReference.get();
1370 if (!automaton.getVariables().empty()) {
1371 storm::expressions::Expression automatonInitialStatesExpression = automaton.getInitialStatesExpression();
1372 if (automatonInitialStatesExpression.isInitialized() && !automatonInitialStatesExpression.isTrue()) {
1373 result = result && automatonInitialStatesExpression;
1374 }
1375 }
1376 }
1377 return result;
1378}
1379
1381 return this->getModelType() == ModelType::DTMC || this->getModelType() == ModelType::CTMC;
1382}
1383
1385 return this->getModelType() == ModelType::DTMC || this->getModelType() == ModelType::MDP;
1386}
1387
1388std::vector<storm::expressions::Expression> Model::getAllRangeExpressions(
1389 std::vector<std::reference_wrapper<storm::jani::Automaton const>> const& automata) const {
1390 std::vector<storm::expressions::Expression> result;
1391 for (auto const& variable : this->getGlobalVariables().getBoundedIntegerVariables()) {
1392 result.push_back(variable.getRangeExpression());
1393 }
1394 STORM_LOG_ASSERT(this->getGlobalVariables().getArrayVariables().empty(), "This operation is unsupported if array variables are present.");
1395
1396 if (automata.empty()) {
1397 for (auto const& automaton : this->getAutomata()) {
1398 std::vector<storm::expressions::Expression> automatonRangeExpressions = automaton.getAllRangeExpressions();
1399 result.insert(result.end(), automatonRangeExpressions.begin(), automatonRangeExpressions.end());
1400 }
1401 } else {
1402 for (auto const& automaton : automata) {
1403 std::vector<storm::expressions::Expression> automatonRangeExpressions = automaton.get().getAllRangeExpressions();
1404 result.insert(result.end(), automatonRangeExpressions.begin(), automatonRangeExpressions.end());
1405 }
1406 }
1407 return result;
1408}
1409
1411 for (auto& automaton : getAutomata()) {
1412 automaton.finalize(*this);
1413 }
1414}
1415
1416void Model::checkValid() const {
1417 // TODO switch to exception based return value.
1419 STORM_LOG_ASSERT(!automata.empty(), "No automata set.");
1420 STORM_LOG_ASSERT(composition != nullptr, "Composition is not set.");
1421}
1422
1424 std::vector<std::reference_wrapper<Automaton const>> allAutomata;
1425 for (auto const& automaton : automata) {
1426 allAutomata.emplace_back(automaton);
1427 }
1428 return getLabelExpression(transientVariable, allAutomata);
1429}
1430
1432 std::vector<std::reference_wrapper<Automaton const>> const& automata) const {
1433 STORM_LOG_THROW(transientVariable.isTransient(), storm::exceptions::InvalidArgumentException, "Expected transient variable.");
1434 auto const& type = transientVariable.getType();
1435 STORM_LOG_THROW(type.isBasicType() && type.asBasicType().isBooleanType(), storm::exceptions::InvalidArgumentException, "Expected boolean variable.");
1436
1438 bool negate = transientVariable.getInitExpression().isTrue();
1439
1440 for (auto const& automaton : automata) {
1441 storm::expressions::Variable const& locationVariable = automaton.get().getLocationExpressionVariable();
1442
1443 for (auto const& location : automaton.get().getLocations()) {
1444 for (auto const& assignment : location.getAssignments().getTransientAssignments()) {
1445 if (assignment.getExpressionVariable() == transientVariable.getExpressionVariable()) {
1446 storm::expressions::Expression newExpression;
1447 if (automaton.get().getNumberOfLocations() <= 1) {
1448 newExpression = (negate ? !assignment.getAssignedExpression() : assignment.getAssignedExpression());
1449 } else {
1450 newExpression = (locationVariable == this->getManager().integer(automaton.get().getLocationIndex(location.getName()))) &&
1451 (negate ? !assignment.getAssignedExpression() : assignment.getAssignedExpression());
1452 }
1453 if (result.isInitialized()) {
1454 result = result || newExpression;
1455 } else {
1456 result = newExpression;
1457 }
1458 }
1459 }
1460 }
1461 }
1462
1463 if (result.isInitialized()) {
1464 if (negate) {
1465 result = !result;
1466 }
1467 } else {
1468 result = this->getManager().boolean(negate);
1469 }
1470
1471 return result;
1472}
1473
1476 CompositionInformation info = visitor.getInformation();
1478 return false;
1479 }
1480 for (auto const& multiplicity : info.getAutomatonToMultiplicityMap()) {
1481 if (multiplicity.second > 1) {
1482 return false;
1483 }
1484 }
1485 return true;
1486}
1487
1490 CompositionInformation info = visitor.getInformation();
1492 return false;
1493 }
1494 return true;
1495}
1496
1498 if (!this->hasUndefinedConstants()) {
1499 return true;
1500 }
1501
1502 // Gather the variables of all undefined constants.
1503 std::set<storm::expressions::Variable> undefinedConstantVariables;
1504 for (auto const& constant : this->getConstants()) {
1505 if (!constant.isDefined()) {
1506 undefinedConstantVariables.insert(constant.getExpressionVariable());
1507 }
1508 }
1509
1510 // Start by checking the defining expressions of all defined constants. If it contains a currently undefined
1511 // constant, we need to mark the target constant as undefined as well.
1512 for (auto const& constant : this->getConstants()) {
1513 if (constant.isDefined()) {
1514 if (constant.getExpression().containsVariable(undefinedConstantVariables)) {
1515 undefinedConstantVariables.insert(constant.getExpressionVariable());
1516 }
1517 }
1518 }
1519
1520 // Check global variable definitions.
1521 if (this->getGlobalVariables().containsVariablesInBoundExpressionsOrInitialValues(undefinedConstantVariables)) {
1522 return false;
1523 }
1524
1525 // Check the automata.
1526 for (auto const& automaton : this->getAutomata()) {
1527 if (!automaton.containsVariablesOnlyInProbabilitiesOrTransientAssignments(undefinedConstantVariables)) {
1528 return false;
1529 }
1530 }
1531
1532 // Check initial states restriction.
1533 if (initialStatesRestriction.containsVariable(undefinedConstantVariables)) {
1534 return false;
1535 }
1536 return true;
1537}
1538
1540 for (auto& automaton : automata) {
1541 // For discrete-time models, we push the assignments to real-valued transient variables (rewards) to the
1542 // edges.
1543 if (this->isDiscreteTimeModel()) {
1544 automaton.pushTransientRealLocationAssignmentsToEdges();
1545 }
1546 automaton.pushEdgeAssignmentsToDestinations();
1547 }
1548}
1549
1551 for (auto& automaton : automata) {
1552 automaton.pushEdgeAssignmentsToDestinations();
1553 }
1554}
1555
1557 for (auto& automaton : this->getAutomata()) {
1558 automaton.liftTransientEdgeDestinationAssignments(maxLevel);
1559 }
1560}
1561
1563 for (auto const& automaton : this->getAutomata()) {
1564 if (automaton.hasTransientEdgeDestinationAssignments()) {
1565 return true;
1566 }
1567 }
1568 return false;
1569}
1570
1571bool Model::usesAssignmentLevels(bool onlyTransient) const {
1572 for (auto const& automaton : this->getAutomata()) {
1573 if (automaton.usesAssignmentLevels(onlyTransient)) {
1574 return true;
1575 }
1576 }
1577 return false;
1578}
1579
1580bool Model::isLinear() const {
1581 bool result = true;
1582
1584 result &= linearityChecker.check(this->getInitialStatesExpression(), true);
1585
1586 for (auto const& automaton : this->getAutomata()) {
1587 result &= automaton.isLinear();
1588 }
1589
1590 return result;
1591}
1592
1594 if (composition->isParallelComposition()) {
1595 return composition->asParallelComposition().areActionsReused();
1596 }
1597 return false;
1598}
1599
1600uint64_t Model::encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex) {
1601 return automatonIndex << 32 | edgeIndex;
1602}
1603
1604std::pair<uint64_t, uint64_t> Model::decodeAutomatonAndEdgeIndices(uint64_t index) {
1605 return std::make_pair(index >> 32, index & ((1ull << 32) - 1));
1606}
1607
1609 Model result(*this);
1610
1611 // Restrict all automata.
1612 for (uint64_t automatonIndex = 0; automatonIndex < result.automata.size(); ++automatonIndex) {
1613 // Compute the set of edges that is to be kept for this automaton.
1614 storm::storage::FlatSet<uint_fast64_t> automatonEdgeIndices;
1615 for (auto const& e : automataAndEdgeIndices) {
1616 auto automatonAndEdgeIndex = decodeAutomatonAndEdgeIndices(e);
1617 if (automatonAndEdgeIndex.first == automatonIndex) {
1618 automatonEdgeIndices.insert(automatonAndEdgeIndex.second);
1619 }
1620 }
1621
1622 result.automata[automatonIndex].restrictToEdges(automatonEdgeIndices);
1623 }
1624
1625 return result;
1626}
1627
1628Model Model::createModelFromAutomaton(Automaton const& automaton) const {
1629 // Copy the full model
1630 Model newModel(*this);
1631
1632 // Replace the automata by the one single selected automaton.
1633 newModel.automata = std::vector<Automaton>({automaton});
1634
1635 // Set the standard composition for the new model to the default one.
1636 newModel.setSystemComposition(newModel.getStandardSystemComposition());
1637
1638 return newModel;
1639}
1640
1641// Helper for writeDotToStream:
1642
1643std::string filterName(std::string const& text) {
1644 std::string result = text;
1645 std::replace_if(result.begin(), result.end(), [](const char& c) { return std::ispunct(c); }, '_');
1646 return result;
1647}
1648
1649void Model::writeDotToStream(std::ostream& outStream) const {
1650 outStream << "digraph " << filterName(name) << " {\n";
1651
1652 std::vector<std::string> actionNames;
1653 for (auto const& act : actions) {
1654 actionNames.push_back(act.getName());
1655 }
1656
1657 for (auto const& automaton : automata) {
1658 automaton.writeDotToStream(outStream, actionNames);
1659 outStream << '\n';
1660 }
1661
1662 outStream << "}";
1663}
1664
1665std::ostream& operator<<(std::ostream& out, Model const& model) {
1666 JsonExporter::toStream(model, std::vector<storm::jani::Property>(), out);
1667 return out;
1668}
1669} // namespace jani
1670} // namespace storm
bool isTrue() const
Checks if the expression is equal to the boolean literal true.
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...
Variable declareFreshBooleanVariable(bool auxiliary=false, std::string const &prefix="_x")
Declares a variable with Boolean type whose name is guaranteed to be unique and not yet in use.
Expression integer(int_fast64_t value) const
Creates an expression that characterizes the given integer literal.
Expression boolean(bool value) const
Creates an expression that characterizes the given boolean literal.
bool check(Expression const &expression, bool booleanIsLinear=false)
Checks that the given expression is linear.
Expression substitute(Expression const &expression)
Substitutes the identifiers in the given expression according to the previously given map and returns...
std::string const & getName() const
Returns the name of the location.
Definition Action.cpp:9
ArrayEliminatorData eliminate(Model &model, bool keepNonTrivialArrayAccess=false)
Eliminates all array references in the given model by replacing them with basic variables.
std::string const & getAutomatonName() const
Retrieves the name of the automaton this composition element refers to.
std::set< std::string > const & getInputEnabledActions() const
VariableSet & getVariables()
Retrieves the variables of this automaton.
Definition Automaton.cpp:59
Automaton clone(storm::expressions::ExpressionManager &manager, std::string const &nameOfClone, std::string const &variablePrefix) const
Definition Automaton.cpp:31
void addEdge(Edge const &edge)
Adds an edge to the automaton.
void registerTemplateEdge(std::shared_ptr< TemplateEdge > const &)
Adds the template edge to the list of edges.
storm::expressions::Expression getInitialStatesExpression() const
Retrieves the expression defining the legal initial values of the automaton's variables.
Location const & getLocation(uint64_t index) const
Retrieves the location with the given index.
void setInitialStatesRestriction(storm::expressions::Expression const &initialStatesRestriction)
Sets the expression restricting the legal initial values of the automaton's variables.
Variable const & addVariable(Variable const &variable)
Adds the given variable to this automaton.
Definition Automaton.cpp:51
FunctionDefinition const & addFunctionDefinition(FunctionDefinition const &functionDefinition)
Adds the given function definition.
Definition Automaton.cpp:79
void addInitialLocation(std::string const &name)
Adds the location with the given name to the initial locations.
uint64_t addLocation(Location const &location)
Adds the given location to the automaton.
void changeAssignmentVariables(std::map< Variable const *, std::reference_wrapper< Variable const > > const &remapping)
Changes all variables in assignments based on the given mapping.
void writeDotToStream(std::ostream &outStream, std::vector< std::string > const &actionNames) const
std::string const & getName() const
Retrieves the name of the automaton.
Definition Automaton.cpp:47
std::vector< Edge > & getEdges()
Retrieves the edges of the automaton.
virtual bool isAutomatonComposition() const
virtual bool isParallelComposition() const
AutomatonComposition const & asAutomatonComposition() const
virtual boost::any accept(CompositionVisitor &visitor, boost::any const &data) const =0
ParallelComposition const & asParallelComposition() const
std::map< std::string, uint64_t > const & getAutomatonToMultiplicityMap() const
std::shared_ptr< Composition > simplify(Composition const &oldComposition)
Definition Model.cpp:954
virtual boost::any visit(ParallelComposition const &composition, boost::any const &data) override
Definition Model.cpp:969
CompositionSimplificationVisitor(std::unordered_map< std::string, std::vector< std::string > > const &automatonToCopiesMap)
Definition Model.cpp:951
virtual boost::any visit(AutomatonComposition const &composition, boost::any const &) override
Definition Model.cpp:958
std::string const & getName() const
Retrieves the name of the constant.
Definition Constant.cpp:30
std::string const & getName() const
Retrieves the name of the function.
static void toStream(storm::jani::Model const &janiModel, std::vector< storm::jani::Property > const &formulas, std::ostream &ostream, bool checkValid=false, bool compact=false)
Jani Location:
Definition Location.h:15
void addTransientAssignment(storm::jani::Assignment const &assignment)
Adds the given transient assignment to this location.
Definition Location.cpp:31
bool hasTrigonometricFunctions() const
void remove(ModelFeature const &modelFeature)
void setInitialStatesRestriction(storm::expressions::Expression const &initialStatesRestriction)
Sets the expression restricting the legal initial values of the global variables.
Definition Model.cpp:1291
bool hasUndefinedConstants() const
Retrieves whether the model still has undefined constants.
Definition Model.cpp:1079
storm::expressions::ExpressionManager & getManager() const
Retrieves the expression manager responsible for the expressions in the model.
Definition Model.cpp:109
std::set< std::string > getActionNames(bool includeSilent=true) const
Retrieves the set of action names.
Definition Model.cpp:1022
std::size_t getNumberOfEdges() const
Retrieves the total number of edges in this model.
Definition Model.cpp:693
Model preprocess(std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions) const
Preprocesses the model by defining the given constant definitions and substituting constants.
Definition Model.cpp:1155
Model & replaceUnassignedVariablesWithConstants()
Replaces each variable to which we never assign a value with a constant.
Definition Model.cpp:1100
storm::storage::FlatSet< uint64_t > const & getNonsilentActionIndices() const
Retrieves all non-silent action indices of the model.
Definition Model.cpp:646
bool hasAction(std::string const &name) const
Checks whether the model has an action with the given name.
Definition Model.cpp:628
Variable const & getGlobalVariable(std::string const &name) const
Retrieves the global variable with the given name if one exists.
Definition Model.cpp:757
std::vector< storm::expressions::Expression > getAllRangeExpressions(std::vector< std::reference_wrapper< storm::jani::Automaton const > > const &automata={}) const
Retrieves a list of expressions that characterize the legal values of the variables in this model.
Definition Model.cpp:1388
VariableSet & getGlobalVariables()
Retrieves the variables of this automaton.
Definition Model.cpp:717
Model()
Creates an uninitialized model.
Definition Model.cpp:43
storm::expressions::ExpressionManager & getExpressionManager() const
Retrieves the manager responsible for the expressions in the JANI model.
Definition Model.cpp:785
std::unordered_map< std::string, storm::expressions::Expression > const & getNonTrivialRewardExpressions() const
Retrieves all available non-trivial reward model names and expressions of the model.
Definition Model.cpp:851
bool hasInitialStatesRestriction() const
Retrieves whether there is an expression restricting the legal initial values of the global variables...
Definition Model.cpp:1295
Model & substituteConstantsInPlace(bool const substituteTranscendentalNumbers)
Substitutes all constants in all expressions of the model.
Definition Model.cpp:1105
bool addNonTrivialRewardExpression(std::string const &identifier, storm::expressions::Expression const &rewardExpression)
Adds a reward expression, i.e., a reward model that does not consist of a single, global,...
Definition Model.cpp:797
storm::expressions::Expression getRewardModelExpression(std::string const &identifier) const
Retrieves the defining reward expression of the reward model with the given identifier.
Definition Model.cpp:809
bool reusesActionsInComposition() const
Checks whether in the composition, actions are reused: That is, if the model is put in parallel compo...
Definition Model.cpp:1593
void setSystemComposition(std::shared_ptr< Composition > const &composition)
Sets the system composition expression of the JANI model.
Definition Model.cpp:1014
static uint64_t encodeAutomatonAndEdgeIndices(uint64_t automatonIndex, uint64_t edgeIndex)
Encode and decode a tuple of automaton and edge index in one 64-bit index.
Definition Model.cpp:1600
Composition const & getSystemComposition() const
Retrieves the system composition expression.
Definition Model.cpp:945
bool hasTransientEdgeDestinationAssignments() const
Retrieves whether there is any transient edge destination assignment in the model.
Definition Model.cpp:1562
storm::expressions::Expression const & getInitialStatesRestriction() const
Gets the expression restricting the legal initial values of the global variables.
Definition Model.cpp:1299
void liftTransientEdgeDestinationAssignments(int64_t maxLevel=0)
Lifts the common edge destination assignments of transient variables to edge assignments.
Definition Model.cpp:1556
void replaceAutomaton(uint64_t index, Automaton const &newAutomaton)
Replaces the automaton at index with a new automaton.
Definition Model.cpp:880
std::shared_ptr< Composition > getStandardSystemComposition() const
Gets the system composition as the standard, fully-synchronizing parallel composition.
Definition Model.cpp:914
InformationObject getModelInformation() const
Returns various information of this model.
Definition Model.cpp:709
std::set< storm::expressions::Variable > getAllExpressionVariables(bool includeLocationExpressionVariables=false) const
Retrieves all expression variables used by this model.
Definition Model.cpp:725
storm::expressions::Expression getInitialStatesExpression() const
Retrieves the expression defining the legal initial values of the variables.
Definition Model.cpp:1323
bool hasStandardComposition() const
Retrieves whether this model has the standard composition, that is it composes all automata in parall...
Definition Model.cpp:1474
static const uint64_t SILENT_ACTION_INDEX
The index of the silent action.
Definition Model.h:658
std::vector< Automaton > & getAutomata()
Retrieves the automata of the model.
Definition Model.cpp:868
ModelType const & getModelType() const
Retrieves the type of the model.
Definition Model.cpp:117
bool hasNonTrivialRewardExpression() const
Returns true iff there is a non-trivial reward model, i.e., a reward model that does not consist of a...
Definition Model.cpp:789
std::vector< Constant > const & getConstants() const
Retrieves the constants of the model.
Definition Model.cpp:685
std::vector< Action > const & getActions() const
Retrieves the actions of the model.
Definition Model.cpp:642
bool undefinedConstantsAreGraphPreserving() const
Checks that undefined constants (parameters) of the model preserve the graph of the underlying model.
Definition Model.cpp:1497
void pushEdgeAssignmentsToDestinations()
Definition Model.cpp:1550
Model substituteConstants() const
Substitutes all constants in all expressions of the model.
Definition Model.cpp:1140
std::size_t getTotalNumberOfNonTransientVariables() const
Number of global and local variables.
Definition Model.cpp:701
storm::expressions::Expression getLabelExpression(Variable const &transientVariable, std::vector< std::reference_wrapper< Automaton const > > const &automata) const
Creates the expression that characterizes all states in which the provided transient boolean variable...
Definition Model.cpp:1431
void addConstant(Constant const &constant)
Adds the given constant to the model.
Definition Model.cpp:650
void substitute(std::map< storm::expressions::Variable, storm::expressions::Expression > const &substitution, bool const substituteTranscendentalNumbers)
Substitutes all expression variables in all expressions of the model.
Definition Model.cpp:1177
uint64_t getJaniVersion() const
Retrieves the JANI-version of the model.
Definition Model.cpp:113
void substituteFunctions()
Substitutes all function calls with the corresponding function definition.
Definition Model.cpp:1216
void setStandardSystemComposition()
Sets the system composition to be the fully-synchronizing parallel composition of all automat.
Definition Model.cpp:1018
Variable const & addVariable(Variable const &variable)
Adds the given variable to this model.
Definition Model.cpp:713
Action const & getAction(uint64_t index) const
Retrieves the action with the given index.
Definition Model.cpp:624
std::vector< std::pair< std::string, storm::expressions::Expression > > getAllRewardModelExpressions() const
Retrieves all available reward model names and expressions of the model.
Definition Model.cpp:837
void checkValid() const
Checks if the model is valid JANI, which should be verified before any further operations are applied...
Definition Model.cpp:1416
std::string const & getName() const
Retrieves the name of the model.
Definition Model.cpp:133
bool hasConstant(std::string const &name) const
Retrieves whether the model has a constant with the given name.
Definition Model.cpp:659
void removeConstant(std::string const &name)
Removes (without checks) a constant from the model.
Definition Model.cpp:663
bool isNonTrivialRewardModelExpression(std::string const &identifier) const
Returns true iff the given identifier corresponds to a non-trivial reward expression i....
Definition Model.cpp:793
bool isDeterministicModel() const
Determines whether this model is a deterministic one in the sense that each state only has one choice...
Definition Model.cpp:1380
bool hasNonGlobalTransientVariable() const
Retrieves whether this model has a non-global transient variable.
Definition Model.cpp:761
void simplifyComposition()
Attempts to simplify the composition.
Definition Model.cpp:981
Model flattenComposition(std::shared_ptr< storm::utility::solver::SmtSolverFactory > const &smtSolverFactory=std::make_shared< storm::utility::solver::SmtSolverFactory >()) const
Flatten the composition to obtain an equivalent model that contains exactly one automaton that has th...
Definition Model.cpp:438
void writeDotToStream(std::ostream &outStream=std::cout) const
Definition Model.cpp:1649
FunctionDefinition const & addFunctionDefinition(FunctionDefinition const &functionDefinition)
Adds the given function definition.
Definition Model.cpp:770
Model defineUndefinedConstants(std::map< storm::expressions::Variable, storm::expressions::Expression > const &constantDefinitions) const
Defines the undefined constants of the model by the given expressions.
Definition Model.cpp:1042
static const std::string SILENT_ACTION_NAME
The name of the silent action.
Definition Model.h:655
bool containsArrayVariables() const
Returns true if at least one array variable occurs in the model.
Definition Model.cpp:1225
Constant const & getConstant(std::string const &name) const
Retrieves the constant with the given name (if any).
Definition Model.cpp:679
std::unordered_map< std::string, uint64_t > const & getActionToIndexMap() const
Retrieves the mapping from action names to their indices.
Definition Model.cpp:638
uint64_t addAction(Action const &action)
Adds an action to the model.
Definition Model.cpp:613
void makeStandardJaniCompliant()
Definition Model.cpp:1539
std::size_t getNumberOfAutomata() const
Retrieves the number of automata in this model.
Definition Model.cpp:910
bool isDiscreteTimeModel() const
Determines whether this model is a discrete-time model.
Definition Model.cpp:1384
bool hasGlobalVariable(std::string const &name) const
Retrieves whether this model has a global variable with the given name.
Definition Model.cpp:753
ModelFeatures const & getModelFeatures() const
Retrieves the enabled model features.
Definition Model.cpp:125
std::map< storm::expressions::Variable, storm::expressions::Expression > getConstantsSubstitution() const
Retrieves a mapping from expression variables associated with defined constants of the model to their...
Definition Model.cpp:1165
bool hasAutomaton(std::string const &name) const
Rerieves whether there exists an automaton with the given name.
Definition Model.cpp:876
Model restrictEdges(storm::storage::FlatSet< uint_fast64_t > const &automataAndEdgeIndices) const
Creates a new model that only contains the selected edges.
Definition Model.cpp:1608
uint64_t addAutomaton(Automaton const &automaton)
Adds the given automaton to the automata of this model.
Definition Model.cpp:859
Automaton & getAutomaton(std::string const &name)
Retrieves the automaton with the given name.
Definition Model.cpp:884
bool hasNonTrivialInitialStates() const
Retrieves whether there are non-trivial initial states in the model or any of the contained automata.
Definition Model.cpp:1303
void setModelType(ModelType const &)
Changes (only) the type declaration of the model.
Definition Model.cpp:121
bool isLinear() const
Checks the model for linearity.
Definition Model.cpp:1580
void setName(std::string const &newName)
Sets the name of the model.
Definition Model.cpp:137
std::map< uint64_t, std::string > getActionIndexToNameMap() const
Builds a map with action indices mapped to their names.
Definition Model.cpp:1032
uint64_t getActionIndex(std::string const &name) const
Get the index of the action.
Definition Model.cpp:632
bool usesAssignmentLevels(bool onlyTransient=false) const
Retrieves whether the model uses an assignment level other than zero.
Definition Model.cpp:1571
void finalize()
After adding all components to the model, this method has to be called.
Definition Model.cpp:1410
std::set< storm::expressions::Variable > getAllLocationExpressionVariables() const
Retrieves all location expression variables used by this model.
Definition Model.cpp:745
bool hasStandardCompliantComposition() const
Checks whether the composition has no nesting.
Definition Model.cpp:1488
uint64_t getAutomatonIndex(std::string const &name) const
Retrieves the index of the given automaton.
Definition Model.cpp:904
ModelFeatures restrictToFeatures(ModelFeatures const &modelFeatures)
Attempts to eliminate all features of this model that are not in the given set of features.
Definition Model.cpp:1249
bool hasTrivialInitialStatesExpression() const
Retrieves whether the initial states expression is trivial in the sense that no automaton has an init...
Definition Model.cpp:1331
Model & operator=(Model const &other)
Copy-assigns the given model.
Definition Model.cpp:69
std::unordered_map< std::string, FunctionDefinition > const & getGlobalFunctionDefinitions() const
Retrieves all global function definitions.
Definition Model.cpp:777
ArrayEliminatorData eliminateArrays(bool keepNonTrivialArrayAccess=false)
Eliminates occurring array variables and expressions by replacing array variables by multiple basic v...
Definition Model.cpp:1237
Model substituteConstantsFunctionsTranscendentals() const
Definition Model.cpp:1147
std::vector< std::reference_wrapper< Constant const > > getUndefinedConstants() const
Retrieves all undefined constants of the model.
Definition Model.cpp:1088
static std::pair< uint64_t, uint64_t > decodeAutomatonAndEdgeIndices(uint64_t index)
Definition Model.cpp:1604
std::vector< SynchronizationVector > const & getSynchronizationVectors() const
Retrieves the synchronization vectors of the parallel composition.
std::vector< std::shared_ptr< Composition > > const & getSubcompositions() const
Retrieves the subcompositions of the parallel composition.
static const std::string NO_ACTION_INPUT
std::vector< std::string > const & getInput() const
static bool isNoActionInput(std::string const &action)
std::string const & getOutput() const
void addAssignment(Assignment const &assignment, bool addToExisting=false)
storm::expressions::Variable const & getExpressionVariable() const
Retrieves the associated expression variable.
Definition Variable.cpp:26
JaniType & getType()
Definition Variable.cpp:67
bool isTransient() const
Definition Variable.cpp:42
storm::expressions::Expression const & getInitExpression() const
Retrieves the initial expression Should only be called if an initial expression is set for this varia...
Definition Variable.cpp:50
detail::Variables< Variable > getBoundedIntegerVariables()
Retrieves the bounded integer variables in this set.
bool hasVariable(std::string const &name) const
Retrieves whether this variable set contains a variable with the given name.
void substitute(std::map< storm::expressions::Variable, storm::expressions::Expression > const &substitution, bool const substituteTranscendentalNumbers)
Applies the given substitution to all variables in this set.
bool empty() const
Retrieves whether this variable set is empty.
void transform(Model &model)
Replaces each variable to which we never assign a value with a constant.
The base class for all model references.
Definition SmtSolver.h:30
virtual bool getBooleanValue(storm::expressions::Variable const &variable) const =0
An interface that captures the functionality of an SMT solver.
Definition SmtSolver.h:21
#define STORM_LOG_WARN(message)
Definition logging.h:28
#define STORM_LOG_ERROR(message)
Definition logging.h:29
#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)
void eliminateFunctions(Model &model, std::vector< Property > &properties)
Eliminates all function references in the given model and the given properties by replacing them with...
std::vector< ConditionalMetaEdge > createSynchronizingMetaEdges(Model const &oldModel, Model &newModel, Automaton &newAutomaton, std::vector< std::set< uint64_t > > &synchronizingActionIndices, SynchronizationVector const &vector, std::vector< std::reference_wrapper< Automaton const > > const &composedAutomata, storm::solver::SmtSolver &solver)
Definition Model.cpp:226
storm::expressions::Expression eliminateFunctionCallsInExpression(storm::expressions::Expression const &expression, Model const &model)
Eliminates all function calls in the given expression by replacing them with their corresponding defi...
storm::expressions::Expression createSynchronizedGuard(std::vector< std::reference_wrapper< Edge const > > const &chosenEdges)
Definition Model.cpp:155
InformationObject collectModelInformation(Model const &model)
storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const &expression, std::map< storm::expressions::Variable, storm::expressions::Expression > const &identifierToExpressionMap, bool const substituteTranscendentalNumbers)
void addEdgesToReachableLocations(std::vector< std::reference_wrapper< Automaton const > > const &composedAutomata, Automaton &newAutomaton, std::vector< ConditionalMetaEdge > const &conditionalMetaEdges)
Definition Model.cpp:365
std::ostream & operator<<(std::ostream &stream, Assignment const &assignment)
std::string filterName(std::string const &text)
Definition Model.cpp:1643
ConditionalMetaEdge createSynchronizedMetaEdge(Automaton &automaton, std::vector< std::reference_wrapper< Edge const > > const &edgesToSynchronize)
Definition Model.cpp:166
void createCombinedLocation(std::vector< std::reference_wrapper< Automaton const > > const &composedAutomata, Automaton &newAutomaton, std::vector< uint64_t > const &locations, bool initial=false)
Definition Model.cpp:345
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.
void forEach(std::vector< IteratorType > const &its, std::vector< IteratorType > const &ites, std::function< void(uint64_t, decltype(*std::declval< IteratorType >()))> const &setValueCallback, std::function< bool()> const &newCombinationCallback)
boost::optional< storm::expressions::Expression > rate
Definition Model.cpp:149
std::vector< uint64_t > components
Definition Model.cpp:147
std::shared_ptr< TemplateEdge > templateEdge
Definition Model.cpp:152
std::vector< storm::expressions::Expression > probabilities
Definition Model.cpp:150
std::vector< uint64_t > condition
Definition Model.cpp:148
std::vector< std::vector< uint64_t > > effects
Definition Model.cpp:151