Hedgehog  3.1.0
A library to generate hybrid pipeline workflow systems
Loading...
Searching...
No Matches
defroster.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_DEFROSTER_H_
20#define HEDGEHOG_CX_DEFROSTER_H_
21
22#ifdef HH_ENABLE_HH_CX
23
24#include <array>
25#include <ostream>
26#include "../tools/type_nodes_map_array.h"
27#include "../tools/concepts.h"
28#include "graph.h"
29
31namespace hh_cx {
32
46template<class DynGraphType, class name_t, class report_t, class adjacencyMatrix_t, class registeredNodesName_t, class inputMap_t, class outputMap_t>
47class Defroster {
48 private:
49 name_t const name_;
50 bool const isValid_;
51 report_t const report_;
52 adjacencyMatrix_t const adjacencyMatrix_;
53 registeredNodesName_t const registeredNodesName_;
54 inputMap_t const inputMap_;
55 outputMap_t const outputMap_;
56 public:
66 constexpr Defroster(
67 name_t const name,
68 bool const isValid,
69 report_t const &report,
70 adjacencyMatrix_t const &adjacencyMatrix,
71 registeredNodesName_t const &registeredNodesName,
72 inputMap_t const &inputMap,
73 outputMap_t const &outputMap)
74 : name_(name),
75 isValid_(isValid),
76 report_(report),
77 adjacencyMatrix_(adjacencyMatrix),
78 registeredNodesName_(registeredNodesName),
79 inputMap_(inputMap),
80 outputMap_(outputMap) {}
81
83 constexpr virtual ~Defroster() = default;
84
87 [[nodiscard]] std::string graphName() const { return std::string(name_.data()); }
88
91 [[nodiscard]] constexpr bool isValid() const { return isValid_; }
92
95 [[nodiscard]] std::string report() const { return std::string(report_.data()); }
96
105 template<class ...Args>
106 auto map(Args... args) const {
107 if constexpr (sizeof...(args) > 0 && sizeof...(args) % 2 != 0) {
108 throw std::runtime_error(
109 "The map function only accepts an even number of parameters as follows: name1, dynNode1, name2, dynNode2...");
110 }
111 std::set<std::string> validatedNames{};
112 auto [names, dynNodes] = validateAndSplit(validatedNames, args...);
113 return generateGraph(names, dynNodes);
114 }
115
116 private:
126 template<class NodeName, tool::HedgehogConnectableNode Node, class ...Args>
127 requires std::is_convertible_v<NodeName, std::string>
128 auto validateAndSplit(
129 std::set<std::string> &setName,
130 NodeName const &nodeName, std::shared_ptr<Node> node, Args... args) const {
131 bool nameFound = false;
132 std::string name = nodeName;
133 for (size_t nameId = 0; nameId < registeredNodesName_.size() && !nameFound; ++nameId) {
134 if (std::string(registeredNodesName_.at(nameId).data()) == name) { nameFound = true; }
135 }
136 if (!nameFound) {
137 std::ostringstream oss;
138 oss << "The node name identifier \"" << name
139 << "\" has not been found in the list of names identifier of static nodes.";
140 throw std::runtime_error(oss.str());
141 } else {
142 if (setName.insert(name).second == false) {
143 std::ostringstream oss;
144 oss << "The node name identifier \"" << name << "\" has already been used to map a dynamic node.";
145 throw std::runtime_error(oss.str());
146 }
147 if constexpr (sizeof...(args) > 0) {
148 auto [names, dynNodes] = validateAndSplit(setName, args...);
149 std::vector<std::string> newNames{nodeName};
150 newNames.insert(newNames.end(), names.cbegin(), names.cend());
151 return std::make_pair(
152 newNames,
153 std::tuple_cat(std::tuple<std::shared_ptr<Node>>{node}, dynNodes)
154 );
155 } else {
156 if (registeredNodesName_.size() != setName.size()) {
157 std::ostringstream oss;
158 oss << "There are static nodes that are not mapped.";
159 throw std::runtime_error(oss.str());
160 }
161 return std::make_pair(
162 std::vector<std::string>{nodeName},
163 std::tuple<std::shared_ptr<Node>>{node}
164 );
165 }
166 }
167 }
168
175 template<class T, class U, class ...Args>
176 auto validateAndSplit(std::set<std::string> &, T const &, U const &, Args...) const {
177 std::ostringstream oss;
178 oss << "The map function has not the rights type, the sequence of types " << hh::tool::typeToStr<T>() << " "
179 << hh::tool::typeToStr<U>()
180 << " has been found";
181 throw std::runtime_error(oss.str());
182 }
183
189 template<class DynamicNodes>
190 auto generateGraph(std::vector<std::string> const &dynamicNameIds,
191 DynamicNodes const &dynamicNodes) const {
192 auto graph = std::make_shared<DynGraphType>(this->graphName());
193 std::vector<typename hh_cx::tool::UniqueVariantFromTuple_t<DynamicNodes>> dynamicNodesVariant;
194 populateVariants(dynamicNodes, dynamicNodesVariant);
195
196 // Deal with input nodes
197 setInputNodes<DynamicNodes>(graph, dynamicNameIds, dynamicNodesVariant);
198
199 // Deal with output nodes
200 setOutputNodes<DynamicNodes>(graph, dynamicNameIds, dynamicNodesVariant);
201
202 // Deal with edges
203 setEdges<DynamicNodes>(graph, dynamicNameIds, dynamicNodesVariant);
204
205 return graph;
206 }
207
213 template<class DynamicNodes>
214 void setInputNodes(
215 std::shared_ptr<DynGraphType> graph,
216 std::vector<std::string> const &dynamicNameIds,
217 std::vector<typename hh_cx::tool::UniqueVariantFromTuple_t<DynamicNodes>> dynamicNodesVariant) const {
218 using GraphInputsTuple = typename DynGraphType::inputs_t;
219
220 // For all ids for a type
221 for (auto const &inputNodeNameToTypes : inputMap_.mapNodeNameToTypeNames()) {
222 // Get the variant
223 auto staticNameId = inputNodeNameToTypes.first;
224 auto positionDynNode =
225 std::distance(
226 dynamicNameIds.begin(),
227 std::find(dynamicNameIds.begin(), dynamicNameIds.end(), staticNameId)
228 );
229 auto dynamicNode = dynamicNodesVariant.at(positionDynNode);
230 // Visit the variant
231 std::visit([&](auto const &node) {
232 // Get the common types between the node and the graph
233 using IntersectionInputTypes =
234 hh::tool::Intersect_t<GraphInputsTuple, typename std::remove_reference_t<decltype(*node)>::inputs_t>;
235 // For all of these types
236 for (auto const &typeName : inputNodeNameToTypes.second) {
237 // If the connection type from the map is in the common types
238 if (isTypeNameInTuple<IntersectionInputTypes>(
239 typeName, std::make_index_sequence<std::tuple_size_v<IntersectionInputTypes>>{})
240 ) {
241 // Set the node as input
242 setNodeAsGraphInput<IntersectionInputTypes>(
243 typeName, node, graph, std::make_index_sequence<std::tuple_size_v<IntersectionInputTypes>>{}
244 );
245 } else {
246 // else throw an error
247 std::ostringstream oss;
248 oss << "Problem during mapping: the node " << node->name() << " cannot be set as input of the graph " <<
249 graphName() << " for the type " << typeName;
250 throw std::runtime_error(oss.str());
251 }
252 }
253 }, dynamicNode);
254 }
255 }
256
262 template<class DynamicNodes>
263 void setOutputNodes(
264 std::shared_ptr<DynGraphType> graph,
265 std::vector<std::string> const &dynamicNameIds,
266 std::vector<typename hh_cx::tool::UniqueVariantFromTuple_t<DynamicNodes>> dynamicNodesVariant) const {
267 using GraphOutputsTuple = typename DynGraphType::outputs_t;
268 // For all ids for a type
269 for (auto const &outputNodeNameToTypes : outputMap_.mapNodeNameToTypeNames()) {
270 // Get the variant
271 auto staticNameId = outputNodeNameToTypes.first;
272 auto positionDynNode =
273 std::distance(
274 dynamicNameIds.begin(),
275 std::find(dynamicNameIds.begin(), dynamicNameIds.end(), staticNameId)
276 );
277 auto dynamicNode = dynamicNodesVariant.at(positionDynNode);
278 // Visit the variant
279 std::visit([&](auto const &node) {
280 // Get the common types between the node and the graph
281 using IntersectionOutputTypes =
282 hh::tool::Intersect_t<GraphOutputsTuple, typename std::remove_reference_t<decltype(*node)>::outputs_t>;
283 // For all of these types
284 for (auto const &typeName : outputNodeNameToTypes.second) {
285 // If the connection type from the map is in the common types
286 if (isTypeNameInTuple<IntersectionOutputTypes>(
287 typeName, std::make_index_sequence<std::tuple_size_v<IntersectionOutputTypes>>{})
288 ) {
289 // Set the node as input
290 setNodeAsGraphOutput<IntersectionOutputTypes>(
291 typeName, node, graph, std::make_index_sequence<std::tuple_size_v<IntersectionOutputTypes>>{}
292 );
293 } else {
294 // else throw an error
295 std::ostringstream oss;
296 oss << "Problem during mapping: the node " << node->name() << " cannot be set as input of the graph " <<
297 graphName() << " for the type " << typeName;
298 throw std::runtime_error(oss.str());
299 }
300 }
301 }, dynamicNode);
302 }
303 }
304
310 template<class DynamicNodes>
311 void setEdges(
312 std::shared_ptr<DynGraphType> graph,
313 std::vector<std::string> const &dynamicNameIds,
314 std::vector<typename hh_cx::tool::UniqueVariantFromTuple_t<DynamicNodes>> dynamicNodesVariant) const {
315
316 // For all nodes as sender
317 for (size_t senderId = 0; senderId < adjacencyMatrix_.size(); ++senderId) {
318 // Get the name-id
319 auto staticSenderNodeNameId = std::string(registeredNodesName_.at(senderId).data());
320 // Get the dynamic variant
321 auto positionSenderDynNode =
322 std::distance(
323 dynamicNameIds.begin(),
324 std::find(dynamicNameIds.begin(), dynamicNameIds.end(), staticSenderNodeNameId)
325 );
326 auto dynamicSenderNodeVariant = dynamicNodesVariant.at(positionSenderDynNode);\
327 // Visit the variant
328 std::visit([&](auto const &dynamicSenderNode) {
329 // For all the nodes as receiver
330 for (size_t receiverId = 0; receiverId < adjacencyMatrix_.at(senderId).size(); ++receiverId) {
331 // Get the name-id
332 auto staticReceiverNodeNameId = std::string(registeredNodesName_.at(receiverId).data());
333 // Get the variant
334 auto positionReceiverDynNode =
335 std::distance(
336 dynamicNameIds.begin(),
337 std::find(dynamicNameIds.begin(), dynamicNameIds.end(), staticReceiverNodeNameId)
338 );
339 auto dynamicReceiverNodeVariant = dynamicNodesVariant.at(positionReceiverDynNode);
340 // Visit the vriant
341 std::visit([&](auto const &dynamicReceiverNode) {
342 // Get the common types between the 2 nodes
343 using commonTypesDynamicNodes =
345 typename std::remove_reference_t<decltype(*dynamicSenderNode)>::outputs_t,
346 typename std::remove_reference_t<decltype(*dynamicReceiverNode)>::inputs_t>;
347
348 // For all the types in the adjacency matrix
349 for (size_t typeId = 0; typeId < adjacencyMatrix_.at(senderId).at(receiverId).size(); ++typeId) {
350 auto typeName = std::string(adjacencyMatrix_.at(senderId).at(receiverId).at(typeId).data());
351 if (!typeName.empty()) {
352 // If the connexion type is in the common types
353 if (isTypeNameInTuple<commonTypesDynamicNodes>(
354 typeName, std::make_index_sequence<std::tuple_size_v<commonTypesDynamicNodes>>{})
355 ) {
356 // Set the edge
357 setEdge<commonTypesDynamicNodes>(
358 typeName,
359 dynamicSenderNode,
360 dynamicReceiverNode,
361 graph,
362 std::make_index_sequence<std::tuple_size_v<commonTypesDynamicNodes>>{}
363 );
364 } else {
365 // else, throw an error
366 std::ostringstream oss;
367 oss
368 << "Problem during mapping: the node " << dynamicSenderNode->name()
369 << " cannot be set linked to " << dynamicReceiverNode->name()
370 << " for the type " << typeName;
371 throw std::runtime_error(oss.str());
372 }
373 }
374 }
375 }, dynamicReceiverNodeVariant);
376 }
377 }, dynamicSenderNodeVariant);
378 }
379 }
380
387 template<size_t Position = 0, class Tuple, class VectorVariant>
388 void populateVariants(Tuple const &tup, VectorVariant &vectorVariant) const {
389 if constexpr (Position < std::tuple_size_v<Tuple>) {
390 vectorVariant.emplace_back(std::get<Position>(tup));
391 populateVariants<Position + 1, Tuple, VectorVariant>(tup, vectorVariant);
392 }
393 }
394
403 template<class TupleOfTypes, class NodeType, class GraphType, size_t... Indices>
404 void setNodeAsGraphInput(std::string const &typeName,
405 NodeType &node,
406 GraphType &graph,
407 std::index_sequence<Indices...>) const {
408 (setNodeAsGraphInputType<std::tuple_element_t<Indices, TupleOfTypes>>(typeName, node, graph), ...);
409 }
410
418 template<class T, class NodeType, class GraphType>
419 void setNodeAsGraphInputType(std::string const &typeName, NodeType &node, GraphType &graph) const {
420 if (hh::tool::typeToStr<T>() == typeName) { graph->template input<T>(node); }
421 }
422
431 template<class TupleOfTypes, class NodeType, class GraphType, size_t... Indices>
432 void setNodeAsGraphOutput(std::string const &typeName,
433 NodeType &node,
434 GraphType &graph,
435 std::index_sequence<Indices...>) const {
436 (setNodeAsGraphOutputType<std::tuple_element_t<Indices, TupleOfTypes>>(typeName, node, graph), ...);
437 }
438
446 template<class T, class NodeType, class GraphType>
447 void setNodeAsGraphOutputType(std::string const &typeName, NodeType &node, GraphType &graph) const {
448 if (hh::tool::typeToStr<T>() == typeName) { graph->template output<T>(node); }
449 }
450
461 template<class TupleOfTypes, class SenderNodeType, class ReceiverNodeType, class GraphType, size_t... Indices>
462 void setEdge(std::string const &typeName,
463 SenderNodeType &sender,
464 ReceiverNodeType &receiver,
465 GraphType &graph,
466 std::index_sequence<Indices...>) const {
467 (setEdgeType<std::tuple_element_t<Indices, TupleOfTypes>>(typeName, sender, receiver, graph), ...);
468 }
469
479 template<class T, class SenderNodeType, class ReceiverNodeType, class GraphType>
480 void setEdgeType(std::string const &typeName,
481 SenderNodeType &sender,
482 ReceiverNodeType &receiver,
483 GraphType &graph) const {
484 if (hh::tool::typeToStr<T>() == typeName) { graph->template edge<T>(sender, receiver); }
485 }
486
492 template<class TupleOfTypes, size_t... Indices>
493 [[nodiscard]] bool isTypeNameInTuple(std::string const &typeName, std::index_sequence<Indices...>) const {
494 return (isSameTypeName<std::tuple_element_t<Indices, TupleOfTypes>>(typeName) || ...);
495 }
496
501 template<class T>
502 [[nodiscard]] inline bool isSameTypeName(std::string const &typeName) const {
503 return hh::tool::typeToStr<T>() == typeName;
504 }
505};
506
611template<auto FctGraph>
612constexpr auto createDefroster() {
613 // Static graph
614 auto graph = FctGraph();
615 static_assert(
616 std::is_base_of_v<hh_cx::Graph<typename decltype(graph)::dynamic_node_t>, decltype(graph)>,
617 "The callable given to the createDefroster function should 1) be a constexpr function and 2) return a valid hh_cx::Graph");
618 using DynGraphType = typename decltype(graph)::dynamic_node_t;
619
620
621 // Static sizes
622 constexpr size_t
623 graphNameSize = FctGraph().name().size() + 1,
624 reportSize = FctGraph().report().size() + 1,
625 numberNodes = FctGraph().numberNodesRegistered(),
626 maxNodeNameSize = FctGraph().maxNodeNameSize() + 1,
627 maxNumberEdges = FctGraph().maxEdgeSizes().first,
628 maxEdgeTypeSize = FctGraph().maxEdgeSizes().second,
629 nbTypesInput = FctGraph().inputNodes().nbTypes(),
630 maxTypeSizeInput = FctGraph().inputNodes().maxTypeSize() + 1,
631 maxNumberNodesInput = FctGraph().inputNodes().maxNumberNodes(),
632 maxSizeNameInput = FctGraph().inputNodes().maxSizeName() + 1,
633 nbTypesOutput = FctGraph().outputNodes().nbTypes(),
634 maxTypeSizeOutput = FctGraph().outputNodes().maxTypeSize() + 1,
635 maxNumberNodesOutput = FctGraph().outputNodes().maxNumberNodes(),
636 maxSizeNameOutput = FctGraph().outputNodes().maxSizeName() + 1;
637
638 // Get Graph name
639 auto const &graphName = graph.name();
640 std::array<char, graphNameSize> nameArray;
641 std::copy(graphName.cbegin(), graphName.cend(), nameArray.begin());
642 nameArray.at(graphName.size()) = '\0';
643
644 // Get graph validity
645 bool isGraphValid = graph.isValid();
646
647 // Copy reports
648 auto const &reportString = graph.report();
649 std::array<char, reportSize> reportArray{};
650 std::copy(reportString.begin(), reportString.end(), reportArray.begin());
651 reportArray.at(reportString.size()) = '\0';
652
653 // Copy adjacency matrix
654 auto const &adjacencyMatrix = graph.adjacencyMatrix();
655 std::array<std::array<std::array<std::array<char, maxEdgeTypeSize>, maxNumberEdges>, numberNodes>, numberNodes>
656 adjacencyMatrixArray{};
657
658 for (size_t senderId = 0; senderId < adjacencyMatrix.size(); ++senderId) {
659 for (size_t receiverId = 0; receiverId < adjacencyMatrix.at(senderId).size(); ++receiverId) {
660 for (size_t typeId = 0; typeId < adjacencyMatrix.at(senderId).at(receiverId).size(); ++typeId) {
661 std::copy(
662 adjacencyMatrix.at(senderId).at(receiverId).at(typeId).cbegin(),
663 adjacencyMatrix.at(senderId).at(receiverId).at(typeId).cend(),
664 adjacencyMatrixArray.at(senderId).at(receiverId).at(typeId).begin()
665 );
666 }
667 }
668 }
669
670 // Copy registered nodes
671 std::array<std::array<char, maxNodeNameSize>, numberNodes> registeredNodesNameArray;
672 auto const &registeredNodesName = graph.registeredNodesName();
673 for (size_t nodeId = 0; nodeId < numberNodes; ++nodeId) {
674 std::copy(
675 registeredNodesName.at(nodeId).cbegin(), registeredNodesName.at(nodeId).cend(),
676 registeredNodesNameArray.at(nodeId).begin()
677 );
678 registeredNodesNameArray.at(nodeId).at(registeredNodesName.at(nodeId).size()) = '\0';
679 }
680
681 // Copy Input nodes
682 auto inputTypeNodesMap = graph.inputNodes();
683 hh_cx::tool::TypeNodesMapArray<nbTypesInput, maxTypeSizeInput, maxNumberNodesInput, maxSizeNameInput>
684 inputTypeNodesMapArray{};
685 for (size_t typeId = 0; typeId < inputTypeNodesMap.nbTypes(); ++typeId) {
686 std::copy(
687 inputTypeNodesMap.types().at(typeId).cbegin(), inputTypeNodesMap.types().at(typeId).cend(),
688 inputTypeNodesMapArray.types().at(typeId).begin()
689 );
690 for (size_t nodeId = 0; nodeId < inputTypeNodesMap.nodesName().at(typeId).size(); ++nodeId) {
691 std::copy(
692 inputTypeNodesMap.nodesName().at(typeId).at(nodeId).cbegin(),
693 inputTypeNodesMap.nodesName().at(typeId).at(nodeId).cend(),
694 inputTypeNodesMapArray.nodes().at(typeId).at(nodeId).begin()
695 );
696 }
697 }
698
699 // Copy Output nodes
700 auto outputTypeNodesMap = graph.outputNodes();
701 hh_cx::tool::TypeNodesMapArray<nbTypesOutput, maxTypeSizeOutput, maxNumberNodesOutput, maxSizeNameOutput>
702 outputTypeNodesMapArray{};
703 for (size_t typeId = 0; typeId < outputTypeNodesMap.nbTypes(); ++typeId) {
704 std::copy(
705 outputTypeNodesMap.types().at(typeId).cbegin(), outputTypeNodesMap.types().at(typeId).cend(),
706 outputTypeNodesMapArray.types().at(typeId).begin()
707 );
708 for (size_t nodeId = 0; nodeId < outputTypeNodesMap.nodesName().at(typeId).size(); ++nodeId) {
709 std::copy(
710 outputTypeNodesMap.nodesName().at(typeId).at(nodeId).cbegin(),
711 outputTypeNodesMap.nodesName().at(typeId).at(nodeId).cend(),
712 outputTypeNodesMapArray.nodes().at(typeId).at(nodeId).begin()
713 );
714 }
715 }
716
717 return hh_cx::Defroster<
718 DynGraphType,
719 decltype(nameArray),
720 decltype(reportArray),
721 decltype(adjacencyMatrixArray),
722 decltype(registeredNodesNameArray),
723 decltype(inputTypeNodesMapArray),
724 decltype(outputTypeNodesMapArray)
725 >(
726 nameArray,
727 isGraphValid, reportArray,
728 adjacencyMatrixArray, registeredNodesNameArray,
729 inputTypeNodesMapArray, outputTypeNodesMapArray);
730}
731}
732#endif //HH_ENABLE_HH_CX
733
734#endif //HEDGEHOG_CX_DEFROSTER_H_
typename internals::Intersect< Tuple1, Tuple2 >::type Intersect_t
Helper getting the intersection of types between two type tuples.