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