Storm 1.11.1.1
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
DFTJsonParser.cpp
Go to the documentation of this file.
2
3#include <boost/algorithm/string.hpp>
4#include <iostream>
5
13#include "storm/io/file.h"
15
16namespace storm::dft {
17namespace parser {
18
19template<typename ValueType>
21 std::ifstream file;
22 storm::io::openFile(filename, file);
23 Json jsonInput;
24 file >> jsonInput;
26 return parseJson(jsonInput);
27}
28
29template<typename ValueType>
31 Json jsonInput = Json::parse(jsonString);
32 return parseJson(jsonInput);
33}
34
35template<typename ValueType>
37 // Initialize DFT builder and value parser
40 std::string toplevelName = "";
42
43 std::string currentLocation;
44 try {
45 // Try to parse parameters
46 currentLocation = "parameters";
47 if (jsonInput.count("parameters") > 0) {
48 Json parameters = jsonInput.at("parameters");
49 STORM_LOG_THROW(parameters.empty() || (std::is_same<ValueType, storm::RationalFunction>::value), storm::exceptions::NotSupportedException,
50 "Parameters are only allowed when using rational functions.");
51 for (auto const& parameter : parameters) {
52 valueParser.addParameter(parseValue(parameter));
53 }
54 }
55
56 currentLocation = "nodes";
57 Json const& nodes = jsonInput.at("nodes");
58 // Start by building mapping from ids to their unique names
59 std::map<std::string, std::string> nameMapping;
60 std::set<std::string> names;
61 for (auto const& element : nodes) {
62 Json data = element.at("data");
63 std::string id = data.at("id");
64 std::string name = parseName(data.at("name"));
65 STORM_LOG_THROW(names.find(name) == names.end(), storm::exceptions::WrongFormatException, "Element '" << name << "' was already declared.");
66 names.insert(name);
67 nameMapping[id] = name;
68 }
69
70 // Parse nodes
71 for (auto const& element : nodes) {
72 currentLocation = parseValue(element);
73 Json const& data = element.at("data");
74 std::string name = parseName(data.at("name"));
75 // TODO: use contains() if modernjson is updated
76 if (data.count("relevant") > 0) {
77 bool isRelevant = data.at("relevant");
78 if (isRelevant) {
79 relevantEvents.insert(name);
80 }
81 }
82 // Create list of children
83 std::vector<std::string> childNames;
84 // TODO: use contains() if modernjson is updated
85 if (data.count("children") > 0) {
86 for (auto const& child : data.at("children")) {
87 STORM_LOG_THROW(nameMapping.find(child) != nameMapping.end(), storm::exceptions::WrongFormatException,
88 "Child '" << child << "' for element '" << name << "' was not defined.");
89 childNames.push_back(nameMapping.at(child));
90 }
91 }
92
93 std::string type = data.at("type");
94 if (type == "and") {
95 builder.addAndGate(name, childNames);
96 } else if (type == "or") {
97 builder.addOrGate(name, childNames);
98 } else if (type == "vot") {
99 STORM_LOG_THROW(data.count("voting") > 0, storm::exceptions::WrongFormatException, "Voting gate '" << name << "' requires parameter 'voting'.");
100 std::string votThreshold = parseValue(data.at("voting"));
101 builder.addVotingGate(name, storm::parser::parseNumber<size_t>(votThreshold), childNames);
102 } else if (type == "pand") {
103 if (data.count("inclusive") > 0) {
104 bool inclusive = data.at("inclusive");
105 builder.addPandGate(name, childNames, inclusive);
106 } else {
107 builder.addPandGate(name, childNames);
108 }
109 } else if (type == "por") {
110 if (data.count("inclusive") > 0) {
111 bool inclusive = data.at("inclusive");
112 builder.addPorGate(name, childNames, inclusive);
113 } else {
114 builder.addPorGate(name, childNames);
115 }
116 } else if (type == "spare") {
117 builder.addSpareGate(name, childNames);
118 } else if (type == "seq") {
119 builder.addSequenceEnforcer(name, childNames);
120 } else if (type == "mutex") {
121 builder.addMutex(name, childNames);
122 } else if (type == "fdep") {
123 builder.addPdep(name, childNames, storm::utility::one<ValueType>());
124 } else if (type == "pdep") {
125 STORM_LOG_THROW(data.count("probability") > 0, storm::exceptions::WrongFormatException,
126 "PDEP '" << name << "' requires parameter 'probability'.");
127 ValueType probability = valueParser.parseValue(parseValue(data.at("probability")));
128 if (storm::utility::isZero<ValueType>(probability)) {
129 // Skip element. Otherwise, trying to add layout information later on will fail
130 STORM_LOG_WARN("Dependency " << name << " with probability 0 is superfluous and will not be added.");
131 continue;
132 }
133 builder.addPdep(name, childNames, probability);
134 } else if (boost::starts_with(type, "be")) {
135 parseBasicElement(name, type, data, builder, valueParser);
136 } else if (type == "compound") {
137 STORM_LOG_TRACE("Ignoring compound node '" << name << "'.");
138 } else {
139 STORM_LOG_THROW(false, storm::exceptions::NotSupportedException, "Type name '" << type << "' not recognized.");
140 }
141
142 if (element.find("position") != element.end()) {
143 // Set layout positions
144 Json position = element.at("position");
145 double x = position.at("x");
146 double y = position.at("y");
147 builder.addLayoutInfo(name, x / 7, y / 7);
148 }
149 }
150
151 STORM_LOG_THROW(jsonInput.count("toplevel") > 0, storm::exceptions::WrongFormatException,
152 "Top level element must be specified via parameter 'toplevel'.");
153 std::string topLevelId = parseValue(jsonInput.at("toplevel"));
154 STORM_LOG_THROW(nameMapping.find(topLevelId) != nameMapping.end(), storm::exceptions::WrongFormatException,
155 "Top level element with id '" << topLevelId << "' was not defined.");
156 builder.setTopLevel(nameMapping.at(topLevelId));
157
158 } catch (storm::exceptions::BaseException const& exception) {
159 STORM_LOG_THROW(false, storm::exceptions::FileIoException, "A parsing exception occurred in " << currentLocation << ": " << exception.what());
160 } catch (std::exception const& exception) {
161 STORM_LOG_THROW(false, storm::exceptions::FileIoException, "An exception occurred during parsing in " << currentLocation << ": " << exception.what());
162 }
163
164 // Build DFT
166 // Set relevant events
167 dft.setRelevantEvents(relevantEvents, false);
168 STORM_LOG_DEBUG("Relevant events: " << dft.getRelevantEventsString());
169 return dft;
170}
171
172template<typename ValueType>
173std::string DFTJsonParser<ValueType>::parseName(std::string const& name) {
174 std::string newName = name;
175 std::replace(newName.begin(), newName.end(), ' ', '_');
176 std::replace(newName.begin(), newName.end(), '-', '_');
177 return newName;
178}
179
180template<typename ValueType>
181std::string DFTJsonParser<ValueType>::parseValue(Json value) {
182 if (value.is_string()) {
183 return value.get<std::string>();
184 } else {
185 std::stringstream stream;
186 stream << value;
187 return stream.str();
188 }
189}
190
191template<typename ValueType>
192void DFTJsonParser<ValueType>::parseBasicElement(std::string const& name, std::string const& type, Json input,
194 std::string distribution = "exponential"; // Default is exponential distribution
195 if (input.count("distribution") > 0) {
196 distribution = input.at("distribution");
197 // Handle short-form for exponential distribution
198 if (distribution == "exp") {
199 distribution = "exponential";
200 }
201 }
202 STORM_LOG_THROW(type == "be" || (type == "be_exp" && distribution == "exponential"), storm::exceptions::WrongFormatException,
203 "BE type '" << type << "' and distribution '" << distribution << " do not agree.");
204
205 if (distribution == "const") {
206 // Constant failed/failsafe
207 STORM_LOG_THROW(input.count("failed") > 0, storm::exceptions::WrongFormatException, "Constant BE '" << name << "' requires parameter 'failed'.");
208 bool failed = input.at("failed");
209 builder.addBasicElementConst(name, failed);
210 } else if (distribution == "probability") {
211 // Constant probability distribution
212 STORM_LOG_THROW(input.count("prob") > 0, storm::exceptions::WrongFormatException,
213 "BE '" << name << "' with probability distribution requires parameter 'prob'.");
214 ValueType probability = valueParser.parseValue(parseValue(input.at("prob")));
215 ValueType dormancy = storm::utility::one<ValueType>();
216 if (input.count("dorm") > 0) {
217 dormancy = valueParser.parseValue(parseValue(input.at("dorm")));
218 } else {
219 STORM_LOG_WARN("No dormancy factor was provided for basic element '" << name << "'. Assuming dormancy factor of 1.");
220 }
221 builder.addBasicElementProbability(name, probability, dormancy);
222 } else if (distribution == "exponential") {
223 // Exponential distribution
224 STORM_LOG_THROW(input.count("rate") > 0, storm::exceptions::WrongFormatException,
225 "BE '" << name << "' with exponential distribution requires parameter 'rate'.");
226 ValueType rate = valueParser.parseValue(parseValue(input.at("rate")));
227 ValueType dormancy = storm::utility::one<ValueType>();
228 if (input.count("dorm") > 0) {
229 dormancy = valueParser.parseValue(parseValue(input.at("dorm")));
230 } else {
231 STORM_LOG_WARN("No dormancy factor was provided for basic element '" << name << "'. Assuming dormancy factor of 1.");
232 }
233 bool transient = false;
234 if (input.count("transient") > 0) {
235 transient = input.at("transient");
236 }
237 builder.addBasicElementExponential(name, rate, dormancy, transient);
238 } else if (distribution == "erlang") {
239 // Erlang distribution
240 STORM_LOG_THROW(input.count("rate") > 0, storm::exceptions::WrongFormatException,
241 "BE '" << name << "' with Erlang distribution requires parameter 'rate'.");
242 ValueType rate = valueParser.parseValue(parseValue(input.at("rate")));
243 STORM_LOG_THROW(input.count("phases") > 0, storm::exceptions::WrongFormatException,
244 "BE '" << name << "' with Erlang distribution requires parameter 'phases'.");
245 size_t phases = storm::parser::parseNumber<size_t>(parseValue(input.at("phases")));
246 ValueType dormancy = storm::utility::one<ValueType>();
247 if (input.count("dorm") > 0) {
248 dormancy = valueParser.parseValue(parseValue(input.at("dorm")));
249 } else {
250 STORM_LOG_WARN("No dormancy factor was provided for basic element '" << name << "'. Assuming dormancy factor of 1.");
251 }
252 builder.addBasicElementErlang(name, rate, phases, dormancy);
253 } else if (distribution == "weibull") {
254 // Weibull distribution
255 STORM_LOG_THROW(input.count("shape") > 0, storm::exceptions::WrongFormatException,
256 "BE '" << name << "' with Weibull distribution requires parameter 'shape'.");
257 ValueType shape = valueParser.parseValue(parseValue(input.at("shape")));
258 STORM_LOG_THROW(input.count("rate") > 0, storm::exceptions::WrongFormatException,
259 "BE '" << name << "' with Weibull distribution requires parameter 'rate'.");
260 ValueType rate = valueParser.parseValue(parseValue(input.at("rate")));
261 builder.addBasicElementWeibull(name, shape, rate);
262 } else if (distribution == "lognormal") {
263 // Log-normal distribution
264 STORM_LOG_THROW(input.count("mean") > 0, storm::exceptions::WrongFormatException,
265 "BE '" << name << "' with Log-normal distribution requires parameter 'mean'.");
266 ValueType mean = valueParser.parseValue(parseValue(input.at("mean")));
267 STORM_LOG_THROW(input.count("stddev") > 0, storm::exceptions::WrongFormatException,
268 "BE '" << name << "' with Log-normal distribution requires parameter 'stddev'.");
269 ValueType stddev = valueParser.parseValue(parseValue(input.at("stddev")));
270 builder.addBasicElementLogNormal(name, mean, stddev);
271 } else {
272 STORM_LOG_THROW(false, storm::exceptions::WrongFormatException, "Distribution " << distribution << " not known.");
273 }
274}
275
276// Explicitly instantiate the class.
277template class DFTJsonParser<double>;
278template class DFTJsonParser<RationalFunction>;
279
280} // namespace parser
281} // namespace storm::dft
void addPdep(std::string const &name, std::vector< std::string > const &children, ValueType probability)
Create (probabilistic) dependency (PDEP) and add it to DFT.
void addOrGate(std::string const &name, std::vector< std::string > const &children)
Create OR-gate and add it to DFT.
void addVotingGate(std::string const &name, unsigned threshold, std::vector< std::string > const &children)
Create VOTing-gate and add it to DFT.
void addBasicElementErlang(std::string const &name, ValueType rate, unsigned phases, ValueType dormancyFactor)
Create BE with Erlang distribution and add it to DFT.
void addLayoutInfo(std::string const &name, double x, double y)
Add layout information for DFT element.
void addSpareGate(std::string const &name, std::vector< std::string > const &children)
Create SPARE-gate and add it to DFT.
void addBasicElementConst(std::string const &name, bool failed)
Create BE which is constant failed or constant failsafe and add it to DFT.
storm::dft::storage::DFT< ValueType > build()
Create DFT.
void addAndGate(std::string const &name, std::vector< std::string > const &children)
Create AND-gate and add it to DFT.
void addBasicElementProbability(std::string const &name, ValueType probability, ValueType dormancyFactor)
Create BE with constant (Bernoulli) distribution and add it to DFT.
void setTopLevel(std::string const &tle)
Set top level element.
void addBasicElementExponential(std::string const &name, ValueType rate, ValueType dormancyFactor, bool transient=false)
Create BE with exponential distribution and add it to DFT.
void addPorGate(std::string const &name, std::vector< std::string > const &children, bool inclusive=true)
Create POR-gate and add it to DFT.
void addSequenceEnforcer(std::string const &name, std::vector< std::string > const &children)
Create sequence enforcer (SEQ) and add it to DFT.
void addPandGate(std::string const &name, std::vector< std::string > const &children, bool inclusive=true)
Create PAND-gate and add it to DFT.
void addBasicElementWeibull(std::string const &name, ValueType shape, ValueType rate)
Create BE with Weibull distribution and add it to DFT.
void addBasicElementLogNormal(std::string const &name, ValueType mean, ValueType standardDeviation)
Create BE with log-normal distribution and add it to DFT.
void addMutex(std::string const &name, std::vector< std::string > const &children)
Create mutual exclusion-gate (MUTEX) and add it to DFT.
Parser for DFT in custom JSON format.
static storm::dft::storage::DFT< ValueType > parseJsonFromFile(std::string const &filename)
Parse DFT from JSON format given as file and build DFT.
static storm::dft::storage::DFT< ValueType > parseJsonFromString(std::string const &jsonString)
Parse DFT from JSON format given as a string and build DFT.
Represents a Dynamic Fault Tree.
Definition DFT.h:52
std::string getRelevantEventsString() const
Get a string containing the list of all relevant events.
Definition DFT.cpp:716
void setRelevantEvents(storm::dft::utility::RelevantEvents const &relevantEvents, bool const allowDCForRelevant) const
Set the relevance flag for all elements according to the given relevant events.
Definition DFT.cpp:690
void insert(std::string const &name)
Add relevant event.
This class represents the base class of all exception classes.
virtual const char * what() const noexcept override
Retrieves the message associated with this exception.
Parser for values according to their ValueType.
Definition ValueParser.h:23
void addParameter(std::string const &parameter)
Add declaration of parameter.
ValueType parseValue(std::string const &value) const
Parse ValueType from string.
#define STORM_LOG_WARN(message)
Definition logging.h:25
#define STORM_LOG_DEBUG(message)
Definition logging.h:18
#define STORM_LOG_TRACE(message)
Definition logging.h:12
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
SFTBDDChecker::ValueType ValueType
void closeFile(std::ofstream &stream)
Close the given file after writing.
Definition file.h:47
void openFile(std::string const &filepath, std::ofstream &filestream, bool append=false, bool silent=false)
Open the given file for writing.
Definition file.h:18