← Documentation
ADS-IDAC Engine 5.0.0
fault_tree.cpp
Go to the documentation of this file.
2
3#include <algorithm>
4#include <sstream>
5
6namespace faulttree {
7
8namespace {
9
10const char *typeName(GateType type) {
11 switch (type) {
12 case GateType::Basic: return "basic event";
13 case GateType::And: return "AND gate";
14 case GateType::Or: return "OR gate";
15 case GateType::KofN: return "K/N gate";
16 case GateType::Not: return "NOT gate";
17 }
18 return "unknown";
19}
20
21} // namespace
22
24 if (node.name.empty()) { throw FaultTreeError("a fault tree node must have a name"); }
25 if (index_.find(node.name) != index_.end()) {
26 throw FaultTreeError("duplicate fault tree node '" + node.name + "'");
27 }
28 index_.emplace(node.name, nodes_.size());
29 nodes_.push_back(std::move(node));
30}
31
32bool FaultTree::hasNode(const std::string &name) const {
33 return index_.find(name) != index_.end();
34}
35
36const Node &FaultTree::node(const std::string &name) const {
37 auto it = index_.find(name);
38 if (it == index_.end()) {
39 throw FaultTreeError("no fault tree node named '" + name + "'");
40 }
41 return nodes_[it->second];
42}
43
44Node &FaultTree::mutableNode(const std::string &name) {
45 auto it = index_.find(name);
46 if (it == index_.end()) {
47 throw FaultTreeError("no fault tree node named '" + name + "'");
48 }
49 return nodes_[it->second];
50}
51
52void FaultTree::setTop(const std::string &name) {
53 if (!hasNode(name)) {
54 throw FaultTreeError("cannot set top event to unknown node '" + name + "'");
55 }
56 top_ = name;
57}
58
59const std::string &FaultTree::top() const {
60 if (top_.empty()) { throw FaultTreeError("the fault tree has no top event"); }
61 return top_;
62}
63
64std::vector<std::string> FaultTree::basicEventNames() const {
65 std::vector<std::string> names;
66 for (const auto &node : nodes_) {
67 if (node.type == GateType::Basic) { names.push_back(node.name); }
68 }
69 return names;
70}
71
72void FaultTree::setBasicEventProbability(const std::string &name,
73 double probability) {
74 Node &target = mutableNode(name);
75 if (target.type != GateType::Basic) {
76 throw FaultTreeError("'" + name + "' is a " + typeName(target.type) +
77 ", not a basic event");
78 }
79 if (!(probability >= 0.0 && probability <= 1.0)) {
80 std::ostringstream out;
81 out << "probability " << probability << " for '" << name
82 << "' is outside [0, 1]";
83 throw FaultTreeError(out.str());
84 }
85 target.probability = probability;
86}
87
88void FaultTree::validate() const {
89 if (nodes_.empty()) { throw FaultTreeError("the fault tree is empty"); }
90 if (top_.empty()) { throw FaultTreeError("the fault tree has no top event"); }
91
92 for (const auto &node : nodes_) {
93 switch (node.type) {
94 case GateType::Basic:
95 if (!node.children.empty()) {
96 throw FaultTreeError("basic event '" + node.name + "' cannot have inputs");
97 }
98 if (!(node.probability >= 0.0 && node.probability <= 1.0)) {
99 std::ostringstream out;
100 out << "basic event '" << node.name << "' has probability "
101 << node.probability << ", outside [0, 1]";
102 throw FaultTreeError(out.str());
103 }
104 break;
105 case GateType::Not:
106 if (node.children.size() != 1) {
107 throw FaultTreeError("NOT gate '" + node.name +
108 "' must have exactly one input");
109 }
110 break;
111 case GateType::KofN:
112 if (node.children.empty()) {
113 throw FaultTreeError("K/N gate '" + node.name + "' has no inputs");
114 }
115 if (node.k < 1 || static_cast<std::size_t>(node.k) > node.children.size()) {
116 std::ostringstream out;
117 out << "K/N gate '" << node.name << "' has k=" << node.k << " with "
118 << node.children.size() << " inputs";
119 throw FaultTreeError(out.str());
120 }
121 break;
122 case GateType::And:
123 case GateType::Or:
124 if (node.children.empty()) {
125 throw FaultTreeError(std::string(typeName(node.type)) + " '" +
126 node.name + "' has no inputs");
127 }
128 break;
129 }
130
131 for (std::size_t i = 0; i < node.children.size(); ++i) {
132 const std::string &child = node.children[i];
133 if (!hasNode(child)) {
134 throw FaultTreeError("node '" + node.name + "' references unknown input '" +
135 child + "'");
136 }
137 if (child == node.name) {
138 throw FaultTreeError("node '" + node.name + "' is its own input");
139 }
140 // The same event wired into one gate twice is a modelling mistake: it is
141 // idempotent for AND and OR, and it silently changes what k means for a
142 // K/N gate. Refuse rather than guess which was intended. (An event
143 // feeding *several* gates is the normal shared/common-cause case and is
144 // handled exactly.)
145 for (std::size_t j = 0; j < i; ++j) {
146 if (node.children[j] == child) {
147 throw FaultTreeError("node '" + node.name + "' lists input '" + child +
148 "' more than once");
149 }
150 }
151 }
152 }
153
154 // Cycle detection: iterative depth-first search with a colour marking, so a
155 // deep tree cannot overflow the stack.
156 enum class Colour { White, Grey, Black };
157 std::vector<Colour> colour(nodes_.size(), Colour::White);
158 std::vector<std::pair<std::size_t, std::size_t>> stack; // (node, next child)
159
160 for (std::size_t start = 0; start < nodes_.size(); ++start) {
161 if (colour[start] != Colour::White) { continue; }
162 stack.emplace_back(start, 0);
163 colour[start] = Colour::Grey;
164 while (!stack.empty()) {
165 auto &[current, next_child] = stack.back();
166 const Node &node = nodes_[current];
167 if (next_child < node.children.size()) {
168 std::size_t child = index_.at(node.children[next_child]);
169 ++next_child;
170 if (colour[child] == Colour::Grey) {
171 throw FaultTreeError("the fault tree contains a cycle through '" +
172 nodes_[child].name + "'");
173 }
174 if (colour[child] == Colour::White) {
175 colour[child] = Colour::Grey;
176 stack.emplace_back(child, 0);
177 }
178 } else {
179 colour[current] = Colour::Black;
180 stack.pop_back();
181 }
182 }
183 }
184}
185
186} // namespace faulttree
Exception type of the fault tree model, the .fta reader and the quantifier.
Definition: fault_tree.hpp:37
const Node & node(const std::string &name) const
Looks a node up by name.
Definition: fault_tree.cpp:36
std::vector< Node > nodes_
insertion order
Definition: fault_tree.hpp:152
void setBasicEventProbability(const std::string &name, double probability)
Definition: fault_tree.cpp:72
const std::string & top() const
Name of the top event.
Definition: fault_tree.cpp:59
std::unordered_map< std::string, std::size_t > index_
name to position in nodes_
Definition: fault_tree.hpp:153
bool hasNode(const std::string &name) const
Tests whether a node of this name has been added.
Definition: fault_tree.cpp:32
std::vector< std::string > basicEventNames() const
Definition: fault_tree.cpp:64
void validate() const
Definition: fault_tree.cpp:88
void addNode(Node node)
Adds a node at the end of the node list.
Definition: fault_tree.cpp:23
Node & mutableNode(const std::string &name)
Non-const lookup. Throws FaultTreeError when the name is unknown.
Definition: fault_tree.cpp:44
void setTop(const std::string &name)
Designates the top event.
Definition: fault_tree.cpp:52
std::string top_
empty until setTop()
Definition: fault_tree.hpp:154
Fault tree model of the faulttree library: FaultTreeError, GateType, Node, and the FaultTree containe...
GateType
Kind of a fault tree node: a basic event or one of four gate types.
Definition: fault_tree.hpp:48
@ Or
fails when any input fails (.fta type 1)
@ KofN
fails when at least k inputs fail (.fta type 6)
@ Basic
basic event, quantified by probability
@ Not
fails when its single input does not (.fta type 7)
@ And
fails when every input fails (.fta type 0)
One fault tree node: a basic event or a gate, identified by name.
Definition: fault_tree.hpp:62
std::string name
Identity of the node within a tree. Must be non-empty and unique.
Definition: fault_tree.hpp:64
std::vector< std::string > children
inputs by name, in gate input order; empty for basic events
Definition: fault_tree.hpp:69
GateType type
Basic event or gate kind. Decides which of the fields below are used.
Definition: fault_tree.hpp:66
int k
K/N gates only: threshold, 1 <= k <= number of inputs.
Definition: fault_tree.hpp:68
double probability
failure probability in [0, 1]; basic events only
Definition: fault_tree.hpp:67