Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
JaniLocationExpander.cpp
Go to the documentation of this file.
2
4
7
11
12namespace storm {
13namespace jani {
14JaniLocationExpander::JaniLocationExpander(Model const &origModel) : original(origModel) {}
15
16JaniLocationExpander::ReturnType JaniLocationExpander::transform(std::string const &automatonName, std::string const &variableName) {
17 STORM_LOG_THROW(original.hasAutomaton(automatonName), storm::exceptions::IllegalArgumentException,
18 "Model has no automaton with name " << automatonName << ". ");
19 STORM_LOG_THROW(original.getAutomaton(automatonName).hasVariable(variableName) || original.hasGlobalVariable(variableName),
20 storm::exceptions::IllegalArgumentException, "Automaton " << automatonName << " has no variable with name " << variableName << ". ");
21 newModel = original;
22 AutomatonAndIndices newAutomaton = transformAutomaton(original.getAutomaton(automatonName), variableName, true);
23 newModel.replaceAutomaton(newModel.getAutomatonIndex(automatonName), newAutomaton.newAutomaton);
24 return {newModel, newAutomaton.newIndices};
25}
26
27JaniLocationExpander::AutomatonAndIndices JaniLocationExpander::transformAutomaton(Automaton const &automaton, std::string const &variableName,
28 bool useTransientVariables) {
29 Automaton newAutomaton(automaton.getName(), automaton.getLocationExpressionVariable());
30 NewIndices newIndices;
31 std::map<Variable const *, std::reference_wrapper<Variable const>> variableRemapping;
32
33 for (auto const &localVariable : automaton.getVariables()) {
34 newAutomaton.addVariable(localVariable); // The expanded variable is also added, but will be set to transient later
35
36 std::reference_wrapper<Variable const> ref_w = std::cref(newAutomaton.getVariables().getVariable(localVariable.getName()));
37
38 variableRemapping.insert(std::pair<Variable const *, std::reference_wrapper<Variable const>>(&localVariable, ref_w));
39 }
40
41 bool isGlobalVariable = !automaton.hasVariable(variableName);
42 VariableSet &containingSet = isGlobalVariable ? newModel.getGlobalVariables() : newAutomaton.getVariables();
43
44 const bool substituteTranscendentalNumbers = false;
45 auto &var = containingSet.getVariable(variableName);
46 bool isBoundedInteger = var.getType().isBoundedType() && var.getType().asBoundedType().isIntegerType();
47 bool isBool = var.getType().isBasicType() && var.getType().asBasicType().isBooleanType();
48
49 STORM_LOG_THROW(isBoundedInteger || isBool, storm::exceptions::InvalidOperationException,
50 "Variable to be eliminated has to be an bounded integer or boolean variable.");
51 STORM_LOG_THROW(var.hasInitExpression(), storm::exceptions::InvalidOperationException, "Variable to be eliminated has to have an initexpression.");
52 STORM_LOG_THROW(!var.isTransient(), storm::exceptions::InvalidOperationException, "Cannot eliminate transient variable");
53
54 storm::expressions::Variable eliminatedExpressionVariable = var.getExpressionVariable();
55
56 // As we are using transitive variables, we're no longer really eliminating variables and the initialStatesRestriction should hopefully still work
57 // STORM_LOG_THROW(!automaton.getInitialStatesRestriction().containsVariable({eliminatedExpressionVariable}), storm::exceptions::NotSupportedException,
58 // "Elimination of variable that occurs in the initial state restriction is not allowed");
59 newAutomaton.setInitialStatesRestriction(automaton.getInitialStatesRestriction());
60 uint32_t initialValueIndex; // The index in variableDomain of the initial value
61
62 if (isBoundedInteger) {
63 auto biVariable = containingSet.getVariable(variableName).getType().asBoundedType();
64
65 int64_t variableUpperBound = biVariable.getUpperBound().evaluateAsInt();
66 int64_t variableLowerBound = biVariable.getLowerBound().evaluateAsInt();
67 int64_t initialVariableValue = containingSet.getVariable(variableName).getInitExpression().evaluateAsInt();
68 for (int64_t i = variableLowerBound; i <= variableUpperBound; i++) {
69 newIndices.variableDomain.push_back(original.getExpressionManager().integer(i));
70 }
71 initialValueIndex = initialVariableValue - variableLowerBound;
72
73 containingSet.eraseVariable(var.getExpressionVariable());
74 auto newVar = Variable::makeBoundedIntegerVariable(variableName, var.getExpressionVariable(), var.getInitExpression(), true, biVariable.getLowerBound(),
75 biVariable.getUpperBound());
76 containingSet.addVariable(*newVar);
77
78 } else if (isBool) {
79 auto boolVariable = containingSet.getVariable(variableName).getType().asBasicType();
80 newIndices.variableDomain.push_back(original.getExpressionManager().boolean(false));
81 newIndices.variableDomain.push_back(original.getExpressionManager().boolean(true));
82 bool initialValue = containingSet.getVariable(variableName).getInitExpression().evaluateAsBool();
83 if (initialValue) {
84 initialValueIndex = 1;
85 } else {
86 initialValueIndex = 0;
87 }
88
89 containingSet.eraseVariable(containingSet.getVariable(variableName).getExpressionVariable());
90 auto newVar = Variable::makeBooleanVariable(variableName, var.getExpressionVariable(), var.getInitExpression(), true);
91 containingSet.addVariable(*newVar);
92 }
93
94 const Variable &newVariablePointer = containingSet.getVariable(variableName);
95
96 // This map will only ever contain a single entry: the variable to be eliminated. It is used during substitutions
97 std::map<storm::expressions::Variable, storm::expressions::Expression> substitutionMap;
98
99 for (auto const &loc : automaton.getLocations()) {
100 uint64_t origIndex = automaton.getLocationIndex(loc.getName());
101
102 if (excludedLocations.count(origIndex) > 0) {
103 STORM_LOG_THROW(loc.getAssignments().empty(), storm::exceptions::IllegalArgumentException,
104 "Locations with assignments cannot be excluded during expansion");
105 STORM_LOG_THROW(automaton.getEdgesFromLocation(origIndex).empty(), storm::exceptions::IllegalArgumentException,
106 "Locations with outgoing edges cannot be excluded during expansion");
107
108 Location newLoc(loc.getName(), OrderedAssignments());
109 uint64_t newLocationIndex = newAutomaton.addLocation(newLoc);
110 newIndices.excludedLocationsToNewIndices[origIndex] = newLocationIndex;
111 for (uint64_t i = 0; i < newIndices.variableDomain.size(); i++) {
112 newIndices.locationVariableValueMap[origIndex][i] = newLocationIndex;
113 }
114 } else {
115 for (uint64_t i = 0; i < newIndices.variableDomain.size(); i++) {
116 std::string newLocationName = loc.getName() + "_" + variableName + "_" + newIndices.variableDomain[i].toString();
117 substitutionMap[eliminatedExpressionVariable] = newIndices.variableDomain[i];
118
119 OrderedAssignments newAssignments = loc.getAssignments().clone();
120 newAssignments.substitute(substitutionMap, substituteTranscendentalNumbers);
121
122 Location newLoc(newLocationName, newAssignments);
123
124 if (useTransientVariables)
125 newLoc.addTransientAssignment(Assignment(newVariablePointer, newIndices.variableDomain[i], 0));
126
127 uint64_t newLocationIndex = newAutomaton.addLocation(newLoc);
128 newIndices.locationVariableValueMap[origIndex][i] = newLocationIndex;
129 }
130 }
131 }
132
133 for (uint64_t const &initialLoc : automaton.getInitialLocationIndices()) {
134 newAutomaton.addInitialLocation(newIndices.locationVariableValueMap[initialLoc][initialValueIndex]);
135 }
136
137 for (auto const &edge : automaton.getEdges()) {
138 for (auto const &newValueAndLocation : newIndices.locationVariableValueMap[edge.getSourceLocationIndex()]) {
139 int64_t currentValueIndex = newValueAndLocation.first;
140
141 substitutionMap[eliminatedExpressionVariable] = newIndices.variableDomain[currentValueIndex];
142
143 uint64_t newSourceIndex = newValueAndLocation.second;
144 storm::expressions::Expression newGuard = substituteJaniExpression(edge.getGuard(), substitutionMap, substituteTranscendentalNumbers).simplify();
145 if (!newGuard.containsVariables() && !newGuard.evaluateAsBool()) {
146 continue;
147 }
148 bool isEdgeInvalid = false; // This is set when a destination leads to an out-of-range location. A warning will be emitted and the edge will not be
149 // added to the list of edges
150 std::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>(newGuard);
151
152 STORM_LOG_THROW(edge.getAssignments().empty(), storm::exceptions::NotImplementedException, "Support for edge-assignments is not implemented");
153
154 std::vector<std::pair<uint64_t, storm::expressions::Expression>> destinationLocationsAndProbabilities;
155 for (auto const &destination : edge.getDestinations()) {
156 OrderedAssignments oa(destination.getOrderedAssignments().clone());
157 oa.substitute(substitutionMap, substituteTranscendentalNumbers);
158
159 int64_t newValueIndex = currentValueIndex;
160 for (auto const &assignment : oa) {
161 if (assignment.getVariable().getExpressionVariable().getIndex() == var.getExpressionVariable().getIndex()) {
162 if (isBoundedInteger) {
163 // TODO: This index computation seems unnecessarily cumbersome
164 newValueIndex = assignment.getAssignedExpression().evaluateAsInt() - newIndices.variableDomain[0].evaluateAsInt();
165 } else if (isBool) {
166 if (assignment.getAssignedExpression().evaluateAsBool()) {
167 newValueIndex = 1;
168 } else {
169 newValueIndex = 0;
170 }
171 }
172 oa.remove(assignment);
173 break;
174 }
175 }
176
177 if (newValueIndex < 0 || newValueIndex >= static_cast<int64_t>(newIndices.variableDomain.size())) {
179 "Found edge that would lead to out-of-range location during unfolding. This edge will not be added to the unfolded model. It is "
180 "possible that the edge guard is unsatisfiable, in which case this message can be ignored.");
181 isEdgeInvalid = true;
182 continue; // Abort this iteration to prevent weird behaviour below when accessing a non-existent element of
183 // locationVariableValueMap[destination.getLocationIndex()]
184 }
185
186 if (!useTransientVariables)
187 STORM_LOG_THROW(true, storm::exceptions::NotImplementedException, "Unfolding without transient variables is not implemented");
188 // oa.add(Assignment(*uncastVar, original.getExpressionManager().integer(value)));
189
190 TemplateEdgeDestination ted(oa);
191 templateEdge->addDestination(ted);
192 destinationLocationsAndProbabilities.emplace_back(
193 newIndices.locationVariableValueMap[destination.getLocationIndex()][newValueIndex],
194 substituteJaniExpression(destination.getProbability(), substitutionMap, substituteTranscendentalNumbers));
195 }
196
197 if (!isEdgeInvalid) {
198 templateEdge->finalize(newModel);
199 newAutomaton.addEdge(storm::jani::Edge(newSourceIndex, edge.getActionIndex(),
200 edge.hasRate() ? boost::optional<storm::expressions::Expression>(substituteJaniExpression(
201 edge.getRate(), substitutionMap, substituteTranscendentalNumbers))
202 : boost::none,
203 templateEdge, destinationLocationsAndProbabilities));
204 newAutomaton.registerTemplateEdge(templateEdge);
205 }
206 }
207 }
208
209 newAutomaton.changeAssignmentVariables(variableRemapping);
210
211 return {newAutomaton, newIndices};
212}
213
215 excludedLocations.insert(index);
216}
217} // namespace jani
218} // namespace storm
Expression simplify() const
Simplifies the expression according to some basic rules.
bool evaluateAsBool(Valuation const *valuation=nullptr) const
Evaluates the expression under the valuation of variables given by the valuation and returns the resu...
bool containsVariables() const
Retrieves whether the expression contains a variable.
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.
Type const & getType() const
Retrieves the type of the variable.
Definition Variable.cpp:50
storm::expressions::Expression const & getInitialStatesRestriction() const
Gets the expression restricting the legal initial values of the automaton's variables.
bool hasVariable(std::string const &name) const
Definition Automaton.cpp:55
storm::expressions::Variable const & getLocationExpressionVariable() const
Retrieves the expression variable that represents the location of this automaton.
Edges getEdgesFromLocation(std::string const &name)
Retrieves the edges of the location with the given name.
std::string const & getName() const
Retrieves the name of the automaton.
Definition Automaton.cpp:47
uint64_t getLocationIndex(std::string const &name) const
ReturnType transform(std::string const &automatonName, std::string const &variableName)
virtual bool isBoundedType() const
Definition JaniType.cpp:15
VariableSet & getGlobalVariables()
Retrieves the variables of this automaton.
Definition Model.cpp:721
storm::expressions::ExpressionManager & getExpressionManager() const
Retrieves the manager responsible for the expressions in the JANI model.
Definition Model.cpp:789
void replaceAutomaton(uint64_t index, Automaton const &newAutomaton)
Replaces the automaton at index with a new automaton.
Definition Model.cpp:884
bool hasGlobalVariable(std::string const &name) const
Retrieves whether this model has a global variable with the given name.
Definition Model.cpp:757
bool hasAutomaton(std::string const &name) const
Rerieves whether there exists an automaton with the given name.
Definition Model.cpp:880
Automaton & getAutomaton(std::string const &name)
Retrieves the automaton with the given name.
Definition Model.cpp:888
uint64_t getAutomatonIndex(std::string const &name) const
Retrieves the index of the given automaton.
Definition Model.cpp:908
static std::shared_ptr< Variable > makeBooleanVariable(std::string const &name, storm::expressions::Variable const &variable, boost::optional< storm::expressions::Expression > const &initValue, bool transient)
Definition Variable.cpp:110
static std::shared_ptr< Variable > makeBoundedIntegerVariable(std::string const &name, storm::expressions::Variable const &variable, boost::optional< storm::expressions::Expression > const &initValue, bool transient, boost::optional< storm::expressions::Expression > const &lowerBound, boost::optional< storm::expressions::Expression > const &upperBound)
Definition Variable.cpp:136
JaniType & getType()
Definition Variable.cpp:67
Variable const & getVariable(std::string const &name) const
Retrieves the variable with the given name.
bool empty() const
Determines whether this set of edges is empty.
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
storm::expressions::Expression substituteJaniExpression(storm::expressions::Expression const &expression, std::map< storm::expressions::Variable, storm::expressions::Expression > const &identifierToExpressionMap, bool const substituteTranscendentalNumbers)
LabParser.cpp.
Definition cli.cpp:18