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