Hedgehog  3.1.0
A library to generate hybrid pipeline workflow systems
Loading...
Searching...
No Matches
graph.h
Go to the documentation of this file.
1// NIST-developed software is provided by NIST as a public service. You may use, copy and distribute copies of the
2// software in any medium, provided that you keep intact this entire notice. You may improve`, modify and create
3// derivative works of the software or any portion of the software, and you may copy and distribute such modifications
4// or works. Modified works should carry a notice stating that you changed the software and should note the date and
5// nature of any such change. Please explicitly acknowledge the National Institute of Standards and Technology as the
6// source of the software. NIST-developed software is expressly provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND,
7// EXPRESS, IMPLIED, IN FACT OR ARISING BY OPERATION OF LAW, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
8// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT AND DATA ACCURACY. NIST NEITHER REPRESENTS NOR
9// WARRANTS THAT THE OPERATION OF THE SOFTWARE WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT ANY DEFECTS WILL BE
10// CORRECTED. NIST DOES NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF THE SOFTWARE OR THE RESULTS
11// THEREOF, INCLUDING BUT NOT LIMITED TO THE CORRECTNESS, ACCURACY, RELIABILITY, OR USEFULNESS OF THE SOFTWARE. You
12// are solely responsible for determining the appropriateness of using and distributing the software and you assume
13// all risks associated with its use, including but not limited to the risks and costs of program errors, compliance
14// with applicable laws, damage to or loss of data, programs or equipment, and the unavailability or interruption of
15// operation. This software is not intended to be used in any situation where a failure could cause risk of injury or
16// damage to property. The software developed by NIST employees is not subject to copyright protection within the
17// United States.
18
19#ifndef HEDGEHOG_CX_GRAPH_H_
20#define HEDGEHOG_CX_GRAPH_H_
21
22#ifdef HH_ENABLE_HH_CX
23
24#include "node.h"
25
26#include "../tools/concepts.h"
27#include "../tools/types_nodes_map.h"
28
29#include "../../src/tools/meta_functions.h"
30
32namespace hh_cx {
33
34#ifndef DOXYGEN_SHOULD_SKIP_THIS
37template<tool::HedgehogDynamicGraphForStaticAnalysis GraphType>
38class AbstractTest;
39#endif //DOXYGEN_SHOULD_SKIP_THIS
40
43template<tool::HedgehogDynamicGraphForStaticAnalysis GraphType>
44class Graph : public Node<GraphType> {
45 private:
46 std::vector<hh_cx::behavior::AbstractNode const *>
47 registeredNodes_{};
48
49 std::vector<std::string>
50 registeredNodesName_{};
51
52 tool::TypesNodesMap
53 inputNodes_{},
54 outputNodes_{};
55
56 std::vector<std::vector<std::vector<std::string>>>
57 adjacencyMatrix_{},
58 ROEdges_{},
59 constEdges_{};
60
61 std::vector<AbstractTest<GraphType> const *> tests_{};
62
63 std::string report_{};
64
65 public:
68 constexpr explicit Graph(std::string const &name) : hh_cx::Node<GraphType>(name) {}
69
71 constexpr virtual ~Graph() = default;
72
77 [[nodiscard]] constexpr bool isLinked(
78 hh_cx::behavior::AbstractNode const *sender,
79 hh_cx::behavior::AbstractNode const *receiver) const {
80 return isLinked(nodeId(sender), nodeId(receiver));
81 }
82
87 [[nodiscard]] constexpr bool isLinked(
88 size_t const senderId,
89 size_t const receiverId) const {
90 if (senderId >= numberNodesRegistered() || receiverId >= numberNodesRegistered()) {
91 throw (std::runtime_error("The node you are trying to get does not exist in the graph."));
92 }
93 return !adjacencyMatrix_.at(senderId).at(receiverId).empty();
94 }
95
101 [[nodiscard]] constexpr bool isROLinked(
102 hh_cx::behavior::AbstractNode const *sender,
103 hh_cx::behavior::AbstractNode const *receiver,
104 std::string const &typeName) const {
105 return isROLinked(nodeId(sender), nodeId(receiver), typeName);
106 }
107
113 [[nodiscard]] constexpr bool isROLinked(
114 size_t const senderId,
115 size_t const receiverId,
116 std::string const &typeName) const {
117 if (senderId >= numberNodesRegistered() || receiverId >= numberNodesRegistered()) {
118 throw (std::runtime_error("The node you are trying to get does not exist in the graph."));
119 }
120 auto listROType = ROEdges_.at(senderId).at(receiverId);
121 return std::find(listROType.cbegin(), listROType.cend(), typeName) != listROType.cend();
122 }
123
129 [[nodiscard]] constexpr bool isConstLinked(
130 hh_cx::behavior::AbstractNode const *sender,
131 hh_cx::behavior::AbstractNode const *receiver,
132 std::string const &typeName) const {
133 return isConstLinked(nodeId(sender), nodeId(receiver), typeName);
134 }
135
141 [[nodiscard]] constexpr bool isConstLinked(
142 size_t const senderId,
143 size_t const receiverId,
144 std::string const &typeName) const {
145 if (senderId >= numberNodesRegistered() || receiverId >= numberNodesRegistered()) {
146 throw (std::runtime_error("The node you are trying to get does not exist in the graph."));
147 }
148 auto listConstType = constEdges_.at(senderId).at(receiverId);
149 return std::find(listConstType.cbegin(), listConstType.cend(), typeName) != listConstType.cend();
150 }
151
154 [[nodiscard]] constexpr std::string const &report() const { return report_; }
155
158 [[nodiscard]] constexpr std::vector<hh_cx::behavior::AbstractNode const *> const &registeredNodes() const {
159 return registeredNodes_;
160 }
161
164 [[nodiscard]] constexpr std::vector<std::string> const &registeredNodesName() const {
165 return registeredNodesName_;
166 }
169 [[nodiscard]] constexpr std::pair<size_t, size_t> maxEdgeSizes() const {
170 size_t maxNumberEdges = 0, maxEdgeTypeSize = 0;
171 for (auto const &sender : adjacencyMatrix_) {
172 for (auto const &receiver : sender) {
173 if (maxNumberEdges < receiver.size()) { maxNumberEdges = receiver.size(); }
174 for (auto const &outputType : receiver) {
175 if (maxEdgeTypeSize < outputType.size() + 1) { maxEdgeTypeSize = outputType.size() + 1; }
176 }
177 }
178 }
179 return {maxNumberEdges, maxEdgeTypeSize};
180 }
181
184 [[nodiscard]] constexpr size_t maxNodeNameSize() const {
185 size_t maxNodeNameSize = 0;
186 for (auto const &nodeName : registeredNodesName_) {
187 if (nodeName.size() > maxNodeNameSize) { maxNodeNameSize = nodeName.size(); }
188 }
189 return maxNodeNameSize;
190 }
191
194 [[nodiscard]] constexpr std::vector<std::vector<std::vector<std::string>>> const &adjacencyMatrix() const {
195 return adjacencyMatrix_;
196 }
197
200 [[nodiscard]] constexpr tool::TypesNodesMap const &inputNodes() const { return inputNodes_; }
201
204 [[nodiscard]] constexpr tool::TypesNodesMap const &outputNodes() const { return outputNodes_; }
205
210 [[nodiscard]] constexpr std::vector<std::vector<std::string>> const &
211 adjacentNodesTypes(hh_cx::behavior::AbstractNode const *node) const {
212 return adjacencyMatrix_.at(nodeId(node));
213 }
214
218 [[nodiscard]] constexpr std::vector<hh_cx::behavior::AbstractNode const *>
219 adjacentNodes(hh_cx::behavior::AbstractNode const *node) const {
220
221 std::vector<hh_cx::behavior::AbstractNode const *> adjacentNodes{};
222
223 for (auto const &possibleReceiver : this->registeredNodes_) {
224 if (isLinked(node, possibleReceiver)) {
225 adjacentNodes.push_back(possibleReceiver);
226 }
227 }
228 return adjacentNodes;
229 }
230
235 [[nodiscard]] constexpr std::vector<hh_cx::behavior::AbstractNode const *>
236 adjacentNodes(hh_cx::behavior::AbstractNode const *node, std::string const &type) const {
237
238 std::vector<hh_cx::behavior::AbstractNode const *> adjacentNodes{};
239
240 for (auto const &possibleReceiver : this->registeredNodes_) {
241 auto const &connectionTypes = this->adjacencyMatrix_.at(nodeId(node)).at(nodeId(possibleReceiver));
242 if (std::find(connectionTypes.cbegin(), connectionTypes.cend(), type) != connectionTypes.cend()) {
243 adjacentNodes.push_back(possibleReceiver);
244
245 }
246 }
247
248 return adjacentNodes;
249 }
250
253 [[nodiscard]] constexpr size_t numberNodesRegistered() const { return registeredNodes_.size(); }
254
258 template<tool::HedgehogStaticNode InputNode>
259 constexpr void inputs(InputNode const &inputNode) {
261 static_assert(std::tuple_size_v<commonTypes> != 0,
262 "The node can not be an input node, at least one of its input types should be the same of "
263 "the graph input types");
264
265 splitInputNodeRegistration<commonTypes>(inputNode, std::make_index_sequence<std::tuple_size_v<commonTypes>>());
266 }
267
272 template<class InputType, tool::HedgehogStaticNode InputNode>
273 constexpr void input(InputNode const &inputNode) {
274 auto typeName = hh::tool::typeToStr<InputType>();
275 static_assert(
276 hh::tool::isContainedInTuple_v<InputType, typename InputNode::inputs_t> &&
277 hh::tool::isContainedInTuple_v<InputType, typename GraphType::inputs_t>,
278 "The input type is not shared by the node and the graph.");
279 registerNode(&inputNode);
280 inputNodes_.insert(typeName, &inputNode);
281 }
282
286 template<tool::HedgehogStaticNode OutputNode>
287 constexpr void outputs(OutputNode const &outputNode) {
289 static_assert(std::tuple_size_v<commonTypes> != 0,
290 "The node can not be an output node, at least one of its output types should be the same of "
291 "the graph iouput types");
292 splitOutputNodeRegistration<commonTypes>(outputNode, std::make_index_sequence<std::tuple_size_v<commonTypes>>{});
293 }
294
299 template<class OutputType, tool::HedgehogStaticNode OutputNode>
300 constexpr void output(OutputNode const &outputNode) {
301 auto typeName = hh::tool::typeToStr<OutputType>();
302 static_assert(
303 hh::tool::isContainedInTuple_v<OutputType, typename OutputNode::outputs_t> &&
304 hh::tool::isContainedInTuple_v<OutputType, typename GraphType::outputs_t>,
305 "The output type is not shared by the node and the graph.");
306 registerNode(&outputNode);
307 outputNodes_.insert(typeName, &outputNode);
308 }
309
315 template<tool::HedgehogStaticNode SenderNode, tool::HedgehogStaticNode ReceiverNode>
316 constexpr void edges(SenderNode const &senderNode, ReceiverNode const &receiverNode) {
318 static_assert(std::tuple_size_v<commonTypes> != 0,
319 "The edge cannot be created, there is no common type between the nodes.");
320
321 splitEdgeRegistration<commonTypes>(senderNode,
322 receiverNode,
323 std::make_index_sequence<std::tuple_size_v<commonTypes>>{});
324 }
325
332 template<class EdgeType, tool::HedgehogStaticNode SenderNode, tool::HedgehogStaticNode ReceiverNode>
333 constexpr void edge(SenderNode &senderNode, ReceiverNode &receiverNode) {
334 using sender_outputs_t = typename SenderNode::outputs_t;
335 using receiver_inputs_t = typename ReceiverNode::inputs_t;
336 using ro_receiver_inputs_t = typename ReceiverNode::ro_type_t;
337 std::string typeName = hh::tool::typeToStr<EdgeType>();
338 static_assert(
339 hh::tool::isContainedInTuple_v<EdgeType, sender_outputs_t>
340 && hh::tool::isContainedInTuple_v<EdgeType, receiver_inputs_t>,
341 "The edge cannot be created, the type is not part of the sender's outputs or receiver's inputs.");
342
343 registerNode(&senderNode);
344 registerNode(&receiverNode);
345
346 adjacencyMatrix_.at(nodeId(&senderNode)).at(nodeId(&receiverNode)).push_back(typeName);
347
348 if constexpr (hh::tool::isContainedInTuple_v<EdgeType, ro_receiver_inputs_t>) {
349 ROEdges_.at(nodeId(&senderNode)).at(nodeId(&receiverNode)).push_back(typeName);
350 }
351
352 if constexpr (std::is_const_v<EdgeType>) {
353 constEdges_.at(nodeId(&senderNode)).at(nodeId(&receiverNode)).push_back(typeName);
354 }
355 }
356
361 template<class Node>
362 requires std::is_base_of_v<hh_cx::behavior::AbstractNode, Node>
363 constexpr size_t nodeId(Node *node) const {
364 if (std::find(registeredNodes_.cbegin(), registeredNodes_.cend(), node) == registeredNodes_.cend()) {
365 throw (std::runtime_error("The node you are trying to get does not exist in the graph."));
366 }
367 size_t nodeId = 0;
368 for (auto registeredNode : registeredNodes_) {
369 if (registeredNode == node) { return nodeId; }
370 else { ++nodeId; }
371 }
372 return nodeId;
373 }
374
378 [[nodiscard]] constexpr hh_cx::behavior::AbstractNode const *node(size_t id) const {
379 if (id >= registeredNodes_.size()) { throw (std::runtime_error("The node you are requesting does not exist.")); }
380 else { return registeredNodes_.at(id); }
381 }
382
386 template<class UserTest>
387 requires std::is_base_of_v<AbstractTest<GraphType>, UserTest>
388 constexpr void addTest(UserTest *test) {
389 // Add the test if not already added
390 if (std::find(tests_.cbegin(), tests_.cend(), test) == tests_.cend()) {
391 tests_.push_back(test);
392 test->test(this);
393 report_.append(test->errorMessage());
394 report_.append("\n");
395 }
396 }
397
400 [[nodiscard]] constexpr bool isValid() const {
401 bool ret = true;
402 for (auto const &test : tests_) { ret &= test->isGraphValid(); }
403 return ret;
404 }
405
406 private:
412 template<class CommonInputs, class T, std::size_t... Is>
413 constexpr void splitInputNodeRegistration(T const &node, std::index_sequence<Is...>) {
414 (input<std::tuple_element_t<Is, CommonInputs>>(node), ...);
415 }
416
422 template<class CommonOutputs, class T, std::size_t... Is>
423 constexpr void splitOutputNodeRegistration(T const &node, std::index_sequence<Is...>) {
424 (output<std::tuple_element_t<Is, CommonOutputs>>(node), ...);
425 }
426
434 template<class CommonTypes, class S, class R, std::size_t... Is>
435 constexpr void splitEdgeRegistration(S const &sender, R const &receiver, std::index_sequence<Is...>) {
436 (edge<std::tuple_element_t<Is, CommonTypes>>(sender, receiver), ...);
437 }
438
441 constexpr void registerNode(hh_cx::behavior::AbstractNode const *node) {
442 if (std::find(registeredNodes_.cbegin(), registeredNodes_.cend(), node) == registeredNodes_.cend()) {
443 validateName(node);
444 registeredNodes_.push_back(node);
445 registeredNodesName_.push_back(node->name());
446 adjacencyMatrix_.emplace_back();
447 ROEdges_.emplace_back();
448 constEdges_.emplace_back();
449
450 for (auto &sender : adjacencyMatrix_) { sender.resize(registeredNodes_.size()); }
451 for (auto &sender : ROEdges_) { sender.resize(registeredNodes_.size()); }
452 for (auto &sender : constEdges_) { sender.resize(registeredNodes_.size()); }
453 }
454 }
455
458 constexpr void validateName(hh_cx::behavior::AbstractNode const *node) {
459 if (std::any_of(
460 registeredNodes_.cbegin(), registeredNodes_.cend(),
461 [&node](auto const &registeredNode) { return node->name() == registeredNode->name(); })) {
462 throw std::runtime_error("Another node with the same name has already been registered.");
463 }
464 }
465};
466}
467#endif //HH_ENABLE_HH_CX
468#endif //HEDGEHOG_CX_GRAPH_H_
typename internals::Intersect< Tuple1, Tuple2 >::type Intersect_t
Helper getting the intersection of types between two type tuples.