Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
JaniGSPNBuilder.cpp
Go to the documentation of this file.
1#include "JaniGSPNBuilder.h"
2
3#include <memory>
4
6
8namespace storm {
9namespace builder {
10
11storm::jani::Model* JaniGSPNBuilder::build(std::string const& automatonName) {
13 if (gspn.getNumberOfTimedTransitions() == 0) {
15 } else if (gspn.getNumberOfImmediateTransitions() == 0) {
17 }
18 storm::jani::Model* model = new storm::jani::Model(gspn.getName(), modelType, janiVersion, expressionManager);
19 storm::jani::Automaton mainAutomaton(automatonName, expressionManager->declareIntegerVariable("loc"));
20 addVariables(model);
21 uint64_t locId = addLocation(mainAutomaton);
22 addEdges(mainAutomaton, locId);
23 model->addAutomaton(mainAutomaton);
26 model->finalize();
27 return model;
28}
29
30void JaniGSPNBuilder::addVariables(storm::jani::Model* model) {
31 for (auto const& place : gspn.getPlaces()) {
32 std::shared_ptr<storm::jani::Variable> janiVar = nullptr;
33 if (!place.hasRestrictedCapacity()) {
34 // Effectively no capacity limit known
35 janiVar = storm::jani::Variable::makeIntegerVariable(place.getName(), expressionManager->getVariable(place.getName()),
36 expressionManager->integer(place.getNumberOfInitialTokens()), false);
37 } else {
38 assert(place.hasRestrictedCapacity());
39 janiVar = storm::jani::Variable::makeBoundedIntegerVariable(place.getName(), expressionManager->getVariable(place.getName()),
40 expressionManager->integer(place.getNumberOfInitialTokens()), false,
41 expressionManager->integer(0), expressionManager->integer(place.getCapacity()));
42 }
43 assert(janiVar != nullptr);
44 assert(vars.count(place.getID()) == 0);
45 vars[place.getID()] = &model->addVariable(*janiVar);
46 }
47}
48
49uint64_t JaniGSPNBuilder::addLocation(storm::jani::Automaton& automaton) {
50 uint64_t janiLoc = automaton.addLocation(storm::jani::Location("loc"));
51 automaton.addInitialLocation("loc");
52 return janiLoc;
53}
54
55void JaniGSPNBuilder::addEdges(storm::jani::Automaton& automaton, uint64_t locId) {
56 uint64_t lastPriority = -1;
57 storm::expressions::Expression lastPriorityGuard = expressionManager->boolean(false);
58 storm::expressions::Expression priorityGuard = expressionManager->boolean(true);
59
60 for (auto const& partition : gspn.getPartitions()) {
61 storm::expressions::Expression guard = expressionManager->boolean(false);
62
63 assert(lastPriority >= partition.priority);
64 if (lastPriority > partition.priority) {
65 priorityGuard = priorityGuard && !lastPriorityGuard;
66 lastPriority = partition.priority;
67 } else {
68 assert(lastPriority == partition.priority);
69 }
70
71 // Compute enabled weight expression.
72 storm::expressions::Expression totalWeight = expressionManager->rational(0.0);
73 for (auto const& transId : partition.transitions) {
74 auto const& trans = gspn.getImmediateTransitions()[transId];
75 if (trans.noWeightAttached()) {
76 continue;
77 }
78 storm::expressions::Expression destguard = expressionManager->boolean(true);
79 for (auto const& inPlaceEntry : trans.getInputPlaces()) {
80 destguard = destguard && (vars[inPlaceEntry.first]->getExpressionVariable() >= inPlaceEntry.second);
81 }
82 for (auto const& inhibPlaceEntry : trans.getInhibitionPlaces()) {
83 destguard = destguard && (vars[inhibPlaceEntry.first]->getExpressionVariable() < inhibPlaceEntry.second);
84 }
85 totalWeight = totalWeight + storm::expressions::ite(destguard, expressionManager->rational(trans.getWeight()), expressionManager->rational(0.0));
86 }
87 totalWeight = totalWeight.simplify();
88
89 std::vector<storm::jani::OrderedAssignments> oas;
90 std::vector<storm::expressions::Expression> probabilities;
91 std::vector<uint64_t> destinationLocations;
92 for (auto const& transId : partition.transitions) {
93 auto const& trans = gspn.getImmediateTransitions()[transId];
94 if (trans.noWeightAttached()) {
95 std::cout << "ERROR -- no weights attached at transition\n";
96 continue;
97 }
98 storm::expressions::Expression destguard = expressionManager->boolean(true);
99 std::vector<storm::jani::Assignment> assignments;
100 for (auto const& inPlaceEntry : trans.getInputPlaces()) {
101 destguard = destguard && (vars[inPlaceEntry.first]->getExpressionVariable() >= inPlaceEntry.second);
102 if (trans.getOutputPlaces().count(inPlaceEntry.first) == 0) {
103 assignments.emplace_back(storm::jani::LValue(*vars[inPlaceEntry.first]),
104 (vars[inPlaceEntry.first])->getExpressionVariable() - inPlaceEntry.second);
105 }
106 }
107 for (auto const& inhibPlaceEntry : trans.getInhibitionPlaces()) {
108 destguard = destguard && (vars[inhibPlaceEntry.first]->getExpressionVariable() < inhibPlaceEntry.second);
109 }
110 for (auto const& outputPlaceEntry : trans.getOutputPlaces()) {
111 if (trans.getInputPlaces().count(outputPlaceEntry.first) == 0) {
112 assignments.emplace_back(storm::jani::LValue(*vars[outputPlaceEntry.first]),
113 (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second);
114 } else {
115 assignments.emplace_back(
116 storm::jani::LValue(*vars[outputPlaceEntry.first]),
117 (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second - trans.getInputPlaces().at(outputPlaceEntry.first));
118 }
119 }
120 destguard = destguard.simplify();
121 guard = guard || destguard;
122
123 oas.emplace_back(assignments);
124 destinationLocations.emplace_back(locId);
125 probabilities.emplace_back(
126 storm::expressions::ite(destguard, (expressionManager->rational(trans.getWeight()) / totalWeight), expressionManager->rational(0.0)));
127 }
128
129 std::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>((priorityGuard && guard).simplify());
130 automaton.registerTemplateEdge(templateEdge);
131
132 for (auto const& oa : oas) {
133 templateEdge->addDestination(storm::jani::TemplateEdgeDestination(oa));
134 }
135 storm::jani::Edge e(locId, storm::jani::Model::SILENT_ACTION_INDEX, boost::none, templateEdge, destinationLocations, probabilities);
136 automaton.addEdge(e);
137 lastPriorityGuard = lastPriorityGuard || guard;
138 }
139 for (auto const& trans : gspn.getTimedTransitions()) {
140 if (storm::utility::isZero(trans.getRate())) {
141 STORM_LOG_WARN("Transitions with rate zero are not allowed in JANI. Skipping this transition");
142 continue;
143 }
144 storm::expressions::Expression guard = expressionManager->boolean(true);
145
146 std::vector<storm::jani::Assignment> assignments;
147 for (auto const& inPlaceEntry : trans.getInputPlaces()) {
148 guard = guard && (vars[inPlaceEntry.first]->getExpressionVariable() >= inPlaceEntry.second);
149 if (trans.getOutputPlaces().count(inPlaceEntry.first) == 0) {
150 assignments.emplace_back(storm::jani::LValue(*vars[inPlaceEntry.first]),
151 (vars[inPlaceEntry.first])->getExpressionVariable() - inPlaceEntry.second);
152 }
153 }
154 for (auto const& inhibPlaceEntry : trans.getInhibitionPlaces()) {
155 guard = guard && (vars[inhibPlaceEntry.first]->getExpressionVariable() < inhibPlaceEntry.second);
156 }
157 for (auto const& outputPlaceEntry : trans.getOutputPlaces()) {
158 if (trans.getInputPlaces().count(outputPlaceEntry.first) == 0) {
159 assignments.emplace_back(storm::jani::LValue(*vars[outputPlaceEntry.first]),
160 (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second);
161 } else {
162 assignments.emplace_back(
163 storm::jani::LValue(*vars[outputPlaceEntry.first]),
164 (vars[outputPlaceEntry.first])->getExpressionVariable() + outputPlaceEntry.second - trans.getInputPlaces().at(outputPlaceEntry.first));
165 }
166 }
167
168 std::shared_ptr<storm::jani::TemplateEdge> templateEdge = std::make_shared<storm::jani::TemplateEdge>(guard);
169 automaton.registerTemplateEdge(templateEdge);
170
171 storm::expressions::Expression rate = expressionManager->rational(trans.getRate());
172 if (trans.hasInfiniteServerSemantics() || (trans.hasKServerSemantics() && !trans.hasSingleServerSemantics())) {
173 STORM_LOG_THROW(trans.hasKServerSemantics() || !trans.getInputPlaces().empty(), storm::exceptions::InvalidModelException,
174 "Unclear semantics: Found a transition with infinite-server semantics and without input place.");
175 storm::expressions::Expression enablingDegree;
176 bool firstArgumentOfMinExpression = true;
177 if (trans.hasKServerSemantics()) {
178 enablingDegree = expressionManager->integer(trans.getNumberOfServers());
179 firstArgumentOfMinExpression = false;
180 }
181 for (auto const& inPlaceEntry : trans.getInputPlaces()) {
182 storm::expressions::Expression enablingDegreeInPlace =
183 vars[inPlaceEntry.first]->getExpressionVariable() / expressionManager->integer(inPlaceEntry.second); // Integer division!
184 if (firstArgumentOfMinExpression == true) {
185 enablingDegree = enablingDegreeInPlace;
186 firstArgumentOfMinExpression = false;
187 } else {
188 enablingDegree = storm::expressions::minimum(enablingDegree, enablingDegreeInPlace);
189 }
190 }
191 rate = rate * enablingDegree;
192 }
193
194 templateEdge->addDestination(assignments);
195 storm::jani::Edge e(locId, storm::jani::Model::SILENT_ACTION_INDEX, rate, templateEdge, {locId}, {expressionManager->integer(1)});
196 automaton.addEdge(e);
197 }
198}
199
200storm::jani::Variable const& JaniGSPNBuilder::addDeadlockTransientVariable(storm::jani::Model* model, std::string name, bool ignoreCapacities,
201 bool ignoreInhibitorArcs, bool ignoreEmptyPlaces) {
202 storm::expressions::Expression transientValue = expressionManager->boolean(true);
203
204 // build the conjunction over all transitions
205 std::vector<storm::gspn::Transition const*> transitions;
206 transitions.reserve(gspn.getNumberOfImmediateTransitions() + gspn.getNumberOfTimedTransitions());
207 for (auto const& t : gspn.getImmediateTransitions()) {
208 transitions.push_back(&t);
209 }
210 for (auto const& t : gspn.getTimedTransitions()) {
211 transitions.push_back(&t);
212 }
213 bool firstTransition = true;
214 for (auto const& transition : transitions) {
215 // build the disjunction over all in/out places and inhibitor arcs
216 storm::expressions::Expression transitionDisabled = expressionManager->boolean(false);
217 bool firstPlace = true;
218 if (!ignoreEmptyPlaces) {
219 for (auto const& placeIdMult : transition->getInputPlaces()) {
220 storm::expressions::Expression placeBlocksTransition =
221 (vars.at(placeIdMult.first)->getExpressionVariable() < expressionManager->integer(placeIdMult.second));
222 if (firstPlace) {
223 transitionDisabled = placeBlocksTransition;
224 firstPlace = false;
225 } else {
226 transitionDisabled = transitionDisabled || placeBlocksTransition;
227 }
228 }
229 }
230 if (!ignoreInhibitorArcs) {
231 for (auto const& placeIdMult : transition->getInhibitionPlaces()) {
232 storm::expressions::Expression placeBlocksTransition =
233 (vars.at(placeIdMult.first)->getExpressionVariable() >= expressionManager->integer(placeIdMult.second));
234 if (firstPlace) {
235 transitionDisabled = placeBlocksTransition;
236 firstPlace = false;
237 } else {
238 transitionDisabled = transitionDisabled || placeBlocksTransition;
239 }
240 }
241 }
242 if (!ignoreCapacities) {
243 for (auto const& placeIdMult : transition->getOutputPlaces()) {
244 auto const& place = gspn.getPlace(placeIdMult.first);
245 if (place->hasRestrictedCapacity()) {
246 storm::expressions::Expression placeBlocksTransition =
247 (vars.at(placeIdMult.first)->getExpressionVariable() + expressionManager->integer(placeIdMult.second) >
248 expressionManager->integer(place->getCapacity()));
249 if (firstPlace) {
250 transitionDisabled = placeBlocksTransition;
251 firstPlace = false;
252 } else {
253 transitionDisabled = transitionDisabled || placeBlocksTransition;
254 }
255 }
256 }
257 }
258
259 if (firstTransition) {
260 transientValue = transitionDisabled;
261 firstTransition = false;
262 } else {
263 transientValue = transientValue && transitionDisabled;
264 }
265 }
266
267 return addTransientVariable(model, name, transientValue);
268}
269
271 auto exprVar = expressionManager->declareBooleanVariable(name);
272 auto const& janiVar = model->addVariable(*storm::jani::Variable::makeBooleanVariable(name, exprVar, expressionManager->boolean(false), true));
273 storm::jani::Assignment assignment(storm::jani::LValue(janiVar), expression);
274 model->getAutomata().front().getLocations().front().addTransientAssignment(assignment);
275 return janiVar;
276}
277
278std::string getUniqueVarName(storm::expressions::ExpressionManager const& manager, std::string name) {
279 std::string res = name;
280 while (manager.hasVariable(res)) {
281 res.append("_");
282 }
283 return res;
284}
285
286std::vector<storm::jani::Property> JaniGSPNBuilder::getStandardProperties(storm::jani::Model* model,
287 std::shared_ptr<storm::logic::AtomicExpressionFormula> atomicFormula,
288 std::string name, std::string description, bool maximal) {
289 std::vector<storm::jani::Property> standardProperties;
290 std::string dirShort = maximal ? "Max" : "Min";
291 std::string dirLong = maximal ? "maximal" : "minimal";
292 storm::solver::OptimizationDirection optimizationDirection =
293 maximal ? storm::solver::OptimizationDirection::Maximize : storm::solver::OptimizationDirection::Minimize;
294 std::set<storm::expressions::Variable> emptySet;
295
296 // Build reachability property
297 auto reachFormula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(
298 std::make_shared<storm::logic::EventuallyFormula>(atomicFormula, storm::logic::FormulaContext::Probability),
299 storm::logic::OperatorInformation(optimizationDirection));
300 standardProperties.emplace_back(dirShort + "PrReach" + name, reachFormula, emptySet,
301 "The " + dirLong + " probability to eventually reach " + description + ".");
302
303 // Build time bounded reachability property
304 // Add variable for time bound
305 auto exprTB = expressionManager->declareRationalVariable(getUniqueVarName(*expressionManager, "TIME_BOUND"));
306 auto janiTB = storm::jani::Constant(exprTB.getName(), exprTB);
307 model->addConstant(janiTB);
308 storm::logic::TimeBound tb(false, janiTB.getExpressionVariable().getExpression());
310
311 auto trueFormula = std::make_shared<storm::logic::BooleanLiteralFormula>(true);
312 auto reachTimeBoundFormula = std::make_shared<storm::logic::ProbabilityOperatorFormula>(
313 std::make_shared<storm::logic::BoundedUntilFormula>(trueFormula, atomicFormula, boost::none, tb, tbr),
314 storm::logic::OperatorInformation(optimizationDirection));
315 standardProperties.emplace_back(dirShort + "PrReach" + name + "TB", reachTimeBoundFormula, emptySet,
316 "The " + dirLong + " probability to reach " + description + " within 'TIME_BOUND' steps.");
317
318 // Use complementary direction for expected time
319 dirShort = maximal ? "Min" : "Max";
320 dirLong = maximal ? "minimal" : "maximal";
321 optimizationDirection = maximal ? storm::solver::OptimizationDirection::Minimize : storm::solver::OptimizationDirection::Maximize;
322
323 // Build expected time property
324 auto expTimeFormula = std::make_shared<storm::logic::TimeOperatorFormula>(
325 std::make_shared<storm::logic::EventuallyFormula>(atomicFormula, storm::logic::FormulaContext::Time),
326 storm::logic::OperatorInformation(optimizationDirection));
327 standardProperties.emplace_back(dirShort + "ExpTime" + name, expTimeFormula, emptySet, "The " + dirLong + " expected time to reach " + description + ".");
328 return standardProperties;
329}
330
331std::vector<storm::jani::Property> JaniGSPNBuilder::getDeadlockProperties(storm::jani::Model* model) {
332 auto const& deadlockVar = addDeadlockTransientVariable(model, getUniqueVarName(*expressionManager, "deadl"));
333 auto deadlockFormula = std::make_shared<storm::logic::AtomicExpressionFormula>(deadlockVar.getExpressionVariable().getExpression());
334 return getStandardProperties(model, deadlockFormula, "Deadlock", "a deadlock", true);
335}
336
337} // namespace builder
338} // namespace storm
storm::jani::Model * build(std::string const &automatonName="gspn_automaton")
std::vector< storm::jani::Property > getDeadlockProperties(storm::jani::Model *model)
Get standard properties (reachability, time bounded reachability, expected time) for deadlocks.
std::vector< storm::jani::Property > getStandardProperties(storm::jani::Model *model, std::shared_ptr< storm::logic::AtomicExpressionFormula > atomicFormula, std::string name, std::string description, bool maximal)
Get standard properties (reachability, time bounded reachability, expected time) for a given atomic f...
storm::jani::Variable const & addTransientVariable(storm::jani::Model *model, std::string name, storm::expressions::Expression expression)
Add transient variable representing given expression.
Expression simplify() const
Simplifies the expression according to some basic rules.
This class is responsible for managing a set of typed variables and all expressions using these varia...
uint64_t getNumberOfTimedTransitions() const
Definition GSPN.cpp:49
uint64_t getNumberOfImmediateTransitions() const
Definition GSPN.cpp:45
std::vector< ImmediateTransition< GSPN::WeightType > > const & getImmediateTransitions() const
Returns the vector of immediate transitions in this gspn.
Definition GSPN.cpp:57
storm::gspn::Place const * getPlace(uint64_t id) const
Returns the place with the corresponding id.
Definition GSPN.cpp:77
std::string const & getName() const
Returns the name of the gspn.
Definition GSPN.cpp:244
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.
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.
Jani Location:
Definition Location.h:15
ModelFeatures & add(ModelFeature const &modelFeature)
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
void addConstant(Constant const &constant)
Adds the given constant to the model.
Definition Model.cpp:654
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
ModelFeatures const & getModelFeatures() const
Retrieves the enabled model features.
Definition Model.cpp:129
uint64_t addAutomaton(Automaton const &automaton)
Adds the given automaton to the automata of this model.
Definition Model.cpp:863
void finalize()
After adding all components to the model, this method has to be called.
Definition Model.cpp:1399
static std::shared_ptr< Variable > makeIntegerVariable(std::string const &name, storm::expressions::Variable const &variable, boost::optional< storm::expressions::Expression > const &initValue, bool transient)
Definition Variable.cpp:115
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
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
std::string getUniqueVarName(storm::expressions::ExpressionManager const &manager, std::string name)
Expression ite(Expression const &condition, Expression const &thenExpression, Expression const &elseExpression)
Expression minimum(Expression const &first, Expression const &second)
ValueType simplify(ValueType value)
bool isZero(ValueType const &a)
Definition constants.cpp:41
LabParser.cpp.
Definition cli.cpp:18