Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
GreatSpnEditorProjectParser.cpp
Go to the documentation of this file.
2#include <boost/algorithm/string.hpp>
3
4#ifdef STORM_HAVE_XERCES
5
6#include <algorithm>
7#include <iostream>
8
10
15
16namespace {
17bool isOnlyWhitespace(std::string const& in) {
18 return std::all_of(in.begin(), in.end(), [](char c) { return std::isspace(static_cast<unsigned char>(c)); });
19}
20} // namespace
21
22namespace storm {
23namespace parser {
24
25GreatSpnEditorProjectParser::GreatSpnEditorProjectParser(std::string const& constantDefinitionString)
26 : manager(std::make_shared<storm::expressions::ExpressionManager>()) {
27 if (constantDefinitionString != "") {
28 std::vector<std::string> constDefs;
29 boost::split(constDefs, constantDefinitionString, boost::is_any_of(","));
30 for (auto const& pair : constDefs) {
31 std::vector<std::string> keyvaluepair;
32 boost::split(keyvaluepair, pair, boost::is_any_of("="));
33 STORM_LOG_THROW(keyvaluepair.size() == 2, storm::exceptions::WrongFormatException,
34 "Expected a constant definition of the form N=42 but got " << pair);
35 constantDefinitions.emplace(keyvaluepair.at(0), keyvaluepair.at(1));
36 }
37 }
38}
39
40storm::gspn::GSPN* GreatSpnEditorProjectParser::parse(xercesc::DOMElement const* elementRoot) {
41 if (storm::adapters::XMLtoString(elementRoot->getTagName()) == "project") {
42 traverseProjectElement(elementRoot);
43 return builder.buildGspn(manager, constantsSubstitution);
44 } else {
45 // If the top-level node is not a "pnml" or "" node, then throw an exception.
46 STORM_LOG_THROW(false, storm::exceptions::UnexpectedException, "Failed to identify the root element.\n");
47 }
48}
49
50void GreatSpnEditorProjectParser::traverseProjectElement(xercesc::DOMNode const* const node) {
51 // traverse attributes
52 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
53 auto attr = node->getAttributes()->item(i);
54 auto name = storm::adapters::getName(attr);
55
56 if (name.compare("version") == 0 || name.compare("name") == 0) {
57 // ignore node (contains only whitespace)
58 } else {
59 // Found node or attribute which is at the moment not handled by this parser.
60 // Notify the user and continue the parsing.
61 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
62 }
63 }
64
65 // traverse children
66 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
67 auto child = node->getChildNodes()->item(i);
68 auto name = storm::adapters::getName(child);
69
70 if (name.compare("gspn") == 0) {
71 traverseGspnElement(child);
72 } else if (isOnlyWhitespace(name)) {
73 // ignore node (contains only whitespace)
74 } else {
75 // Found node or attribute which is at the moment nod handled by this parser.
76 // Notify the user and continue the parsing.
77 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
78 }
79 }
80}
81
82void GreatSpnEditorProjectParser::traverseGspnElement(xercesc::DOMNode const* const node) {
83 // traverse attributes
84 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
85 auto attr = node->getAttributes()->item(i);
86 auto name = storm::adapters::getName(attr);
87
88 if (name.compare("name") == 0) {
89 builder.setGspnName(storm::adapters::XMLtoString(attr->getNodeValue()));
90 } else if (name.compare("show-color-cmd") == 0 || name.compare("show-fluid-cmd") == 0 || name.compare("zoom") == 0) {
91 // ignore node
92 } else {
93 // Found node or attribute which is at the moment not handled by this parser.
94 // Notify the user and continue the parsing.
95 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
96 }
97 }
98
99 // traverse children
100 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
101 auto child = node->getChildNodes()->item(i);
102 auto name = storm::adapters::getName(child);
103
104 if (name.compare("nodes") == 0) {
105 traverseNodesElement(child);
106 } else if (name.compare("edges") == 0) {
107 traverseEdgesElement(child);
108 } else if (isOnlyWhitespace(name)) {
109 // ignore node (contains only whitespace)
110 } else {
111 // Found node or attribute which is at the moment nod handled by this parser.
112 // Notify the user and continue the parsing.
113 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
114 }
115 }
116}
117
118void GreatSpnEditorProjectParser::traverseNodesElement(xercesc::DOMNode const* const node) {
119 // traverse attributes
120 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
121 auto attr = node->getAttributes()->item(i);
122 auto name = storm::adapters::getName(attr);
123
124 // Found node or attribute which is at the moment not handled by this parser.
125 // Notify the user and continue the parsing.
126 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
127 }
128
129 // traverse children
130 // First pass: find constant definitions
131 constantsSubstitution.clear();
132 expressionParser = std::make_shared<storm::parser::ExpressionParser>(*manager);
133 std::unordered_map<std::string, storm::expressions::Expression> identifierMapping;
134 expressionParser->setIdentifierMapping(identifierMapping);
135 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
136 auto child = node->getChildNodes()->item(i);
137 auto name = storm::adapters::getName(child);
138 if (name.compare("constant") == 0 || name.compare("template") == 0) {
139 traverseConstantOrTemplateElement(child);
140 }
141 }
142 // Update the expression parser to make the newly created variables known to it
143 expressionParser = std::make_shared<storm::parser::ExpressionParser>(*manager);
144 for (auto const& var : manager->getVariables()) {
145 identifierMapping.emplace(var.getName(), var.getExpression());
146 }
147 expressionParser->setIdentifierMapping(identifierMapping);
148 // Second pass: traverse other children
149 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
150 auto child = node->getChildNodes()->item(i);
151 auto name = storm::adapters::getName(child);
152
153 if (name.compare("place") == 0) {
154 traversePlaceElement(child);
155 } else if (name.compare("transition") == 0) {
156 traverseTransitionElement(child);
157 } else if (name.compare("constant") == 0 || name.compare("template") == 0) {
158 // Ignore constant def in second pass
159 } else if (isOnlyWhitespace(name)) {
160 // ignore node (contains only whitespace)
161 } else {
162 // Found node or attribute which is at the moment nod handled by this parser.
163 // Notify the user and continue the parsing.
164 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
165 }
166 }
167}
168
169void GreatSpnEditorProjectParser::traverseConstantOrTemplateElement(xercesc::DOMNode const* const node) {
170 std::string identifier;
172 std::string valueStr = "";
173
174 // traverse attributes
175 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
176 auto attr = node->getAttributes()->item(i);
177 auto name = storm::adapters::getName(attr);
178
179 if (name.compare("name") == 0) {
180 identifier = storm::adapters::XMLtoString(attr->getNodeValue());
181 } else if (name.compare("consttype") == 0 || name.compare("type") == 0) {
182 if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("REAL") == 0) {
183 type = manager->getRationalType();
184 } else if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("INTEGER") == 0) {
185 type = manager->getIntegerType();
186 } else {
187 STORM_PRINT_AND_LOG("Unknown consttype: " << storm::adapters::XMLtoString(attr->getNodeValue()) << '\n');
188 }
189 } else if (name.compare("value") == 0) {
190 valueStr = storm::adapters::XMLtoString(attr->getNodeValue());
191 } else if ((name == "x") || (name == "y")) {
192 // Ignore
193 } else {
194 // Found node or attribute which is at the moment not handled by this parser.
195 // Notify the user and continue the parsing.
196 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
197 }
198 }
199
200 STORM_LOG_THROW(!manager->hasVariable(identifier), storm::exceptions::NotSupportedException,
201 "Multiple definitions of constant '" << identifier << "' were found.");
202 if (valueStr == "") {
203 auto constDef = constantDefinitions.find(identifier);
204 STORM_LOG_THROW(constDef != constantDefinitions.end(), storm::exceptions::NotSupportedException,
205 "Constant '" << identifier << "' has no value defined.");
206 valueStr = constDef->second;
207 }
209 if (type.isRationalType()) {
210 var = manager->declareRationalVariable(identifier);
211 expressionParser->setAcceptDoubleLiterals(true);
212 } else if (type.isIntegerType()) {
213 var = manager->declareIntegerVariable(identifier);
214 expressionParser->setAcceptDoubleLiterals(false);
215 } else {
216 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Unknown type of constant" << type << ".");
217 }
218 constantsSubstitution.emplace(var, expressionParser->parseFromString(valueStr));
219
220 // traverse children
221 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
222 auto child = node->getChildNodes()->item(i);
223 auto name = storm::adapters::getName(child);
224
225 if (isOnlyWhitespace(name)) {
226 // ignore node (contains only whitespace)
227 } else {
228 // Found node or attribute which is at the moment nod handled by this parser.
229 // Notify the user and continue the parsing.
230 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
231 }
232 }
233}
234
235void GreatSpnEditorProjectParser::traverseEdgesElement(xercesc::DOMNode const* const node) {
236 // traverse attributes
237 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
238 auto attr = node->getAttributes()->item(i);
239 auto name = storm::adapters::getName(attr);
240
241 // Found node or attribute which is at the moment not handled by this parser.
242 // Notify the user and continue the parsing.
243 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
244 }
245
246 // traverse children
247 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
248 auto child = node->getChildNodes()->item(i);
249 auto name = storm::adapters::getName(child);
250
251 if (name.compare("arc") == 0) {
252 traverseArcElement(child);
253 } else if (isOnlyWhitespace(name)) {
254 // ignore node (contains only whitespace)
255 } else {
256 // Found node or attribute which is at the moment nod handled by this parser.
257 // Notify the user and continue the parsing.
258 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
259 }
260 }
261}
262
263bool ignorePlaceAttribute(std::string const& name) {
264 // TODO we should probably not ignore x-servers but check that it is 0.5.
265 if ((name == "label-x") || (name == "label-y") || (name == "x") || (name == "y")) {
266 return true;
267 }
268 return false;
269}
270
271void GreatSpnEditorProjectParser::traversePlaceElement(xercesc::DOMNode const* const node) {
272 // traverse attributes
273 std::string placeName;
274 uint64_t initialTokens = 0;
275
276 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
277 auto attr = node->getAttributes()->item(i);
278 auto name = storm::adapters::getName(attr);
279
280 if (name.compare("name") == 0) {
281 placeName = storm::adapters::XMLtoString(attr->getNodeValue());
282 } else if (name.compare("marking") == 0) {
283 initialTokens = parseInt(storm::adapters::XMLtoString(attr->getNodeValue()));
284 } else if (ignorePlaceAttribute(name)) {
285 // ignore node
286 } else {
287 // Found node or attribute which is at the moment not handled by this parser.
288 // Notify the user and continue the parsing.
289 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
290 }
291 }
292
293 // traverse children
294 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
295 auto child = node->getChildNodes()->item(i);
296 auto name = storm::adapters::getName(child);
297
298 if (isOnlyWhitespace(name)) {
299 // ignore node (contains only whitespace)
300 } else {
301 // Found node or attribute which is at the moment nod handled by this parser.
302 // Notify the user and continue the parsing.
303 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
304 }
305 }
306 builder.addPlace(boost::none, initialTokens, placeName);
307}
308
309bool ignoreTransitionAttribute(std::string const& name) {
310 // TODO we should probably not ignore x-servers but check that it is 0.5.
311 if ((name == "label-x") || (name == "label-y") || (name == "x") || (name == "y") || (name == "nservers-x") || (name == "delay-x") || (name == "delay-y") ||
312 (name == "rotation")) {
313 return true;
314 }
315 return false;
316}
317
318void GreatSpnEditorProjectParser::traverseTransitionElement(xercesc::DOMNode const* const node) {
319 std::string transitionName;
320 bool immediateTransition;
321 double rate = 1.0; // The default rate in GreatSPN.
322 double weight = 1.0; // The default weight in GreatSpn
323 uint64_t priority = 1; // The default priority in GreatSpn
324 boost::optional<uint64_t> numServers;
325
326 // traverse attributes
327 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
328 auto attr = node->getAttributes()->item(i);
329 auto name = storm::adapters::getName(attr);
330
331 if (name.compare("name") == 0) {
332 transitionName = storm::adapters::XMLtoString(attr->getNodeValue());
333 } else if (name.compare("type") == 0) {
334 if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("EXP") == 0) {
335 immediateTransition = false;
336 } else if (storm::adapters::XMLtoString(attr->getNodeValue()).compare("IMM") == 0) {
337 immediateTransition = true;
338 } else {
339 STORM_PRINT_AND_LOG("unknown transition type: " << storm::adapters::XMLtoString(attr->getNodeValue()));
340 }
341 } else if (name.compare("delay") == 0) {
342 rate = parseReal(storm::adapters::XMLtoString(attr->getNodeValue()));
343 } else if (name.compare("weight") == 0) {
344 weight = parseReal(storm::adapters::XMLtoString(attr->getNodeValue()));
345 } else if (name.compare("priority") == 0) {
346 priority = parseInt(storm::adapters::XMLtoString(attr->getNodeValue()));
347 } else if (name.compare("nservers") == 0) {
348 std::string nservers = storm::adapters::XMLtoString(attr->getNodeValue());
349 if (nservers == "Single") {
350 numServers = 1;
351 } else if (nservers == "Infinite") {
352 // Ignore this case as we assume infinite by default (similar to GreatSpn)
353 } else {
354 numServers = parseInt(nservers);
355 }
356 } else if (ignoreTransitionAttribute(name)) {
357 // ignore node
358 } else {
359 // Found node or attribute which is at the moment not handled by this parser.
360 // Notify the user and continue the parsing.
361 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
362 }
363 }
364
365 if (immediateTransition) {
366 builder.addImmediateTransition(priority, weight, transitionName);
367 } else {
368 builder.addTimedTransition(0, rate, numServers, transitionName);
369 }
370
371 // traverse children
372 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
373 auto child = node->getChildNodes()->item(i);
374 auto name = storm::adapters::getName(child);
375
376 if (isOnlyWhitespace(name)) {
377 // ignore node (contains only whitespace)
378 } else {
379 // Found node or attribute which is at the moment nod handled by this parser.
380 // Notify the user and continue the parsing.
381 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
382 }
383 }
384}
385
386bool ignoreArcAttribute(std::string const& name) {
387 if ((name == "mult-x") || (name == "mult-y") || (name == "mult-k")) {
388 return true;
389 }
390 return false;
391}
392
393bool ignoreArcChild(std::string const& name) {
394 if (name == "point") {
395 return true;
396 }
397 return false;
398}
399
400void GreatSpnEditorProjectParser::traverseArcElement(xercesc::DOMNode const* const node) {
401 std::string head = "____NOT_SET____";
402 std::string tail = "____NOT_SET____";
403 std::string kind = "____NOT_SET____";
404 uint_fast64_t mult = 1;
405
406 // traverse attributes
407 for (uint_fast64_t i = 0; i < node->getAttributes()->getLength(); ++i) {
408 auto attr = node->getAttributes()->item(i);
409 auto name = storm::adapters::getName(attr);
410
411 if (name.compare("head") == 0) {
412 head = storm::adapters::XMLtoString(attr->getNodeValue());
413 } else if (name.compare("tail") == 0) {
414 tail = storm::adapters::XMLtoString(attr->getNodeValue());
415 } else if (name.compare("kind") == 0 || name.compare("type") == 0) {
416 kind = storm::adapters::XMLtoString(attr->getNodeValue());
417 } else if (name.compare("mult") == 0) {
418 mult = parseInt(storm::adapters::XMLtoString(attr->getNodeValue()));
419 } else if (ignoreArcAttribute(name)) {
420 // ignore node
421 } else {
422 // Found node or attribute which is at the moment not handled by this parser.
423 // Notify the user and continue the parsing.
424 STORM_PRINT_AND_LOG("unknown attribute (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
425 }
426 }
427
428 STORM_LOG_THROW(head.compare("____NOT_SET____") != 0, storm::exceptions::WrongFormatException, "Arc must have a head");
429 STORM_LOG_THROW(tail.compare("____NOT_SET____") != 0, storm::exceptions::WrongFormatException, "Arc must have a tail");
430 STORM_LOG_THROW(kind.compare("____NOT_SET____") != 0, storm::exceptions::WrongFormatException, "Arc must have a kind");
431
432 if (kind.compare("INPUT") == 0) {
433 builder.addInputArc(tail, head, mult);
434 } else if (kind.compare("INHIBITOR") == 0) {
435 builder.addInhibitionArc(tail, head, mult);
436 } else if (kind.compare("OUTPUT") == 0) {
437 builder.addOutputArc(tail, head, mult);
438 } else {
439 // TODO error!
440 }
441
442 // traverse children
443 for (uint_fast64_t i = 0; i < node->getChildNodes()->getLength(); ++i) {
444 auto child = node->getChildNodes()->item(i);
445 auto name = storm::adapters::getName(child);
446
447 if (isOnlyWhitespace(name)) {
448 // ignore node (contains only whitespace)
449 } else if (ignoreArcChild(name)) {
450 // ignore
451 } else {
452 // Found node or attribute which is at the moment nod handled by this parser.
453 // Notify the user and continue the parsing.
454 STORM_PRINT_AND_LOG("unknown child (node=" + storm::adapters::XMLtoString(node->getNodeName()) + "): " + name + "\n");
455 }
456 }
457}
458
459int64_t GreatSpnEditorProjectParser::parseInt(std::string str) {
460 expressionParser->setAcceptDoubleLiterals(false);
461 auto expr = expressionParser->parseFromString(str).substitute(constantsSubstitution);
462 STORM_LOG_ASSERT(!expr.containsVariables(), "Can not evaluate expression " << str << " as it contains undefined variables.");
463 return expr.evaluateAsInt();
464}
465
466double GreatSpnEditorProjectParser::parseReal(std::string str) {
467 expressionParser->setAcceptDoubleLiterals(true);
468 auto expr = expressionParser->parseFromString(str).substitute(constantsSubstitution);
469 STORM_LOG_ASSERT(!expr.containsVariables(), "Can not evaluate expression " << str << " as it contains undefined variables.");
470 return expr.evaluateAsDouble();
471}
472
473} // namespace parser
474} // namespace storm
475#endif
bool isIntegerType() const
Checks whether this type is an integral type.
Definition Type.cpp:182
bool isRationalType() const
Checks whether this type is a rational type.
Definition Type.cpp:214
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
#define STORM_PRINT_AND_LOG(message)
Definition macros.h:68
SettingsManager const & manager()
Retrieves the settings manager.
std::set< storm::RationalFunctionVariable > getVariables(std::vector< storm::RationalFunction > const &vector)
LabParser.cpp.
Definition cli.cpp:18