Loading [MathJax]/extensions/TeX/AMSsymbols.js
Radium Engine  1.5.28
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
DataflowGraph.cpp
1
2#include <Dataflow/Core/DataflowGraph.hpp>
3
4#include <Dataflow/Core/Port.hpp>
5
6#include <fstream>
7#include <map>
8
9#include <Core/Utils/Log.hpp>
10#include <memory>
11
12namespace Ra {
13namespace Dataflow {
14namespace Core {
15
16RA_SINGLETON_IMPLEMENTATION( PortFactory );
17
18using namespace Ra::Core::Utils;
19
20DataflowGraph::DataflowGraph( const std::string& name ) : DataflowGraph( name, node_typename() ) {}
21
22DataflowGraph::DataflowGraph( const std::string& instanceName, const std::string& typeName ) :
23 Node( instanceName, typeName ) {}
24
26 if ( m_ready ) {
27 Node::init();
28 std::for_each( m_nodes_by_level.begin(), m_nodes_by_level.end(), []( const auto& level ) {
29 std::for_each( level.begin(), level.end(), []( auto node ) {
30 if ( !node->is_initialized() ) { node->init(); }
31 } );
32 } );
33 }
34}
35
36bool DataflowGraph::execute() {
37 if ( m_inputs.size() > 0 || m_outputs.size() > 0 ) return true;
38
39 if ( !m_ready ) {
40 if ( !compile() ) { return false; }
41 }
42 bool result = true;
44 m_nodes_by_level.begin(), m_nodes_by_level.end(), [&result]( const auto& level ) {
45 std::for_each( level.begin(), level.end(), [&result]( auto node ) {
46 bool executed = node->execute();
47 if ( !executed ) {
48 LOG( logERROR ) << "Execution failed with node " << node->instance_name()
49 << " (" << node->model_name() << ").";
50 }
51 result = result && executed;
52 } );
53 } );
54 return result;
55}
56
57void DataflowGraph::destroy() {
59 m_nodes_by_level.begin(), m_nodes_by_level.end(), []( auto& level ) { level.clear(); } );
60 m_nodes_by_level.clear();
61 m_nodes.clear();
62 Node::destroy();
63 needs_recompile();
64}
65
66void DataflowGraph::saveToJson( const std::string& jsonFilePath ) {
67 if ( !jsonFilePath.empty() ) {
68 nlohmann::json data;
69 toJson( data );
70 std::ofstream file( jsonFilePath );
71 file << std::setw( 4 ) << data << std::endl;
72 m_should_save = false;
73 }
74}
75
76void DataflowGraph::toJsonInternal( nlohmann::json& data ) const {
77 nlohmann::json nodes = nlohmann::json::array();
78 nlohmann::json connections = nlohmann::json::array();
79 nlohmann::json graph;
80
81 for ( const auto& n : m_nodes ) {
82 nlohmann::json nodeData;
83 n->toJson( nodeData );
84 nodes.push_back( nodeData );
85 // skip input_node's input connection
86 if ( n != m_input_node ) {
87 for ( const auto& input : n->inputs() ) {
88 if ( input->is_linked() ) {
89 nlohmann::json link = nlohmann::json::object();
90 auto portOut = input->link();
91 auto nodeOut = portOut->node();
92 if ( auto casted = dynamic_cast<GraphOutputNode*>( nodeOut ); casted ) {
93 nodeOut = casted->graph();
94 }
95
96 link["out_node"] = nodeOut->instance_name();
97 link["out_port"] = portOut->name();
98 link["in_node"] = n->instance_name();
99 link["in_port"] = input->name();
100 connections.push_back( link );
101 }
102 }
103 }
104 }
105
106 // write the common content of the Node to the json data
107 graph["nodes"] = nodes;
108 graph["connections"] = connections;
109 // Fill the specific concrete node information
110 data.emplace( "graph", graph );
111}
112
113std::optional<nlohmann::json> read_json( const std::string& jsonFilePath ) {
114 std::ifstream f( jsonFilePath );
115 nlohmann::json j = nlohmann::json::parse( f, nullptr, false );
116
117 if ( j.is_discarded() ) {
118 LOG( logERROR ) << jsonFilePath << " is not a valid json file !!";
119 return std::nullopt;
120 }
121 return j;
122}
123
124bool DataflowGraph::loadFromJson( const std::string& jsonFilePath ) {
125 auto j = read_json( jsonFilePath );
126 if ( !j ) return false;
127
128 m_should_save = false;
129 return fromJson( *j );
130}
131
133getLinkInfo( const std::string& which,
134 const nlohmann::json& linkData,
135 const std::map<std::string, std::shared_ptr<Node>>& nodeByName ) {
136 std::string field = which + "_node";
137 std::shared_ptr<Node> node { nullptr };
138
139 auto itNode = nodeByName.find( linkData[field] );
140 if ( itNode != nodeByName.end() ) { node = itNode->second; }
141 else {
142 // Error, could not find the node
143 std::string msg = std::string { "Node " } + which + " named " +
144 std::string( linkData[field] ) + " not found in cache " + " : " +
145 linkData.dump();
146 return { nullptr, msg };
147 }
148
149 std::string port;
150 std::string err;
151
152 field = which + "_port";
153 if ( linkData.contains( field ) ) {
154 auto p = node->port_by_name( which, linkData[field] ).second;
155 if ( p != nullptr ) { port = p->name(); }
156 else { err = linkData[field]; }
157 }
158 else {
159 field = which + "_index";
160 if ( linkData.contains( field ) ) {
161 auto p = node->port_by_index( which, Node::PortIndex { int { linkData[field] } } );
162 if ( p != nullptr ) { port = p->name(); }
163 else { err = std::to_string( int { linkData[field] } ); }
164 }
165 }
166 if ( port.empty() ) {
167 std::string msg = std::string { "Port " } + which + " " + err + " not found in node " +
168 node->instance_name() + " : " + linkData.dump();
169 return { nullptr, msg };
170 }
171 return { node, port };
172}
173
174bool DataflowGraph::fromJsonInternal( const nlohmann::json& data ) {
175 if ( data.contains( "graph" ) ) {
176 // indicate that the graph must be recompiled after loading
177 needs_recompile();
178 // load the graph
179 auto factories = NodeFactoriesManager::factory_manager();
180
182 if ( auto nodes_itr = data["graph"].find( "nodes" ); nodes_itr != data["graph"].end() ) {
183 auto nodes = *nodes_itr;
184 for ( auto& n : nodes ) {
185 if ( !n["model"].contains( "name" ) ) {
186 LOG( logERROR ) << "Found a node without model description." << n.dump()
187 << "Unable to build an instance.";
188 return false;
189 }
190 std::string nodeTypeName = n["model"]["name"];
191 std::string instanceName;
192
193 if ( auto instance_itr = n.find( "instance" ); instance_itr != n.end() ) {
194 instanceName = *instance_itr;
195 }
196 else {
197 LOG( logERROR )
198 << "Found a node of type " << nodeTypeName << " without identification ";
199 return false;
200 }
201 // create and adds node to this
202 auto newNode = factories.create_node( nodeTypeName, n, this );
203 if ( newNode ) {
204 if ( !instanceName.empty() ) {
205 auto [it, inserted] = nodeByName.insert( { instanceName, newNode } );
206 if ( !inserted ) {
207 LOG( logERROR ) << "DataflowGraph::loadFromJson : duplicated node name "
208 << nodeTypeName;
209 return false;
210 }
211 }
212 if ( nodeTypeName == GraphInputNode::node_typename() ) {
213 m_input_node = std::dynamic_pointer_cast<GraphInputNode>( newNode );
214 m_input_node->set_graph( this );
215 }
216 if ( nodeTypeName == GraphOutputNode::node_typename() ) {
217 m_output_node = std::dynamic_pointer_cast<GraphOutputNode>( newNode );
218 m_output_node->set_graph( this );
219 }
220 }
221 else {
222 LOG( logERROR ) << "Unable to create the node " << nodeTypeName;
223 return false;
224 }
225 }
226 }
227 if ( auto links_itr = data["graph"].find( "connections" );
228 links_itr != data["graph"].end() ) {
229 auto links = *links_itr;
230 for ( auto& l : links ) {
231 auto [nodeFrom, fromOutput] = getLinkInfo( "out", l, nodeByName );
232 if ( nodeFrom == nullptr ) {
233 LOG( logERROR ) << "DataflowGraph::loadFromJson: error when parsing JSON."
234 << " Could not find the link source (" << fromOutput
235 << "). Link not added.";
236 return false;
237 }
238 auto [nodeTo, toInput] = getLinkInfo( "in", l, nodeByName );
239 if ( nodeTo == nullptr ) {
240 LOG( logERROR )
241 << "DataflowGraph::loadFromJson: error when parsing JSON."
242 << " Could not find the link target (" << toInput << "). Link not added.";
243 return false;
244 }
245 if ( !add_link( nodeFrom, fromOutput, nodeTo, toInput ) ) {
246 LOG( logERROR )
247 << "DataflowGraph::loadFromJson: error when parsing JSON"
248 << ": Could not add a link (missing or wrong information, please refer to "
249 "the previous error messages). Link not added.";
250 return false;
251 }
252 }
253 }
254 generate_ports();
255 }
256 return true;
257}
258
259bool DataflowGraph::add_node( std::shared_ptr<Node> newNode ) {
260 // Check if the new node already exists (= same name and type)
261 if ( !has_node_by_name( newNode->instance_name(), newNode->model_name() ) ) {
262 m_nodes.emplace_back( std::move( newNode ) );
263 needs_recompile();
264 return true;
265 }
266 else { return false; }
267}
268
269bool DataflowGraph::remove_node( std::shared_ptr<Node> node ) {
270 // This is to prevent graph destruction from the graph editor, depending on how it is used
271 if ( m_nodesAndLinksProtected ) { return false; }
272
273 if ( auto itr = std::find( m_nodes.begin(), m_nodes.end(), node ); itr != m_nodes.end() ) {
274 m_nodes.erase( itr );
275 needs_recompile();
276 return true;
277 }
278 return false;
279}
280
281bool DataflowGraph::are_ports_compatible( const Node* nodeFrom,
282 const PortBaseOut* portOut,
283 const Node* nodeTo,
284 const PortBaseIn* portIn ) {
285 // Compare types
286 if ( !( portIn->type() == portOut->type() ) ) {
287 Log::link_type_mismatch( nodeFrom, portOut, nodeTo, portIn );
288 return false;
289 }
290
291 // Check if input is connected
292 if ( portIn->is_linked() ) {
293 Log::already_linked( nodeTo, portIn );
294 return false;
295 }
296 return true;
297}
298
299void nodeNotFoundMessage( const std::string& type, const std::string& name, const Node* node ) {
300 LOG( logERROR ) << "DataflowGraph::add_link Unable to find " << type << "input port " << name
301 << " from destination node " << node->instance_name() << " ("
302 << node->model_name() << ")";
303}
304
305bool DataflowGraph::add_link( const std::shared_ptr<Node>& nodeFrom,
306 const std::string& nodeFromOutputName,
307 const std::shared_ptr<Node>& nodeTo,
308 const std::string& nodeToInputName ) {
309 if ( !are_nodes_valids( nodeFrom.get(), nodeTo.get(), true ) ) { return false; }
310
311 auto [inputIdx, inputPort] = nodeTo->input_by_name( nodeToInputName );
312 if ( !inputPort ) {
313 nodeNotFoundMessage( "input", nodeToInputName, nodeTo.get() );
314 return false;
315 }
316 auto [outputIdx, outputPort] = nodeFrom->output_by_name( nodeFromOutputName );
317 if ( !outputPort ) {
318 nodeNotFoundMessage( "output", nodeFromOutputName, nodeFrom.get() );
319 return false;
320 }
321
322 return add_link( outputPort, inputPort );
323}
324
325bool DataflowGraph::add_link( const std::shared_ptr<Node>& nodeFrom,
326 Node::PortIndex portOutIdx,
327 const std::shared_ptr<Node>& nodeTo,
328 Node::PortIndex portInIdx ) {
329
330 if ( !are_nodes_valids( nodeFrom.get(), nodeTo.get(), true ) ) { return false; }
331 if ( check_last_port_io_nodes( nodeFrom.get(), portOutIdx, nodeTo.get(), portInIdx ) ) {
332 if ( m_input_node && nodeFrom == m_input_node &&
333 portOutIdx == m_input_node->outputs().size() ) {
334 auto portIn = nodeTo->input_by_index( portInIdx );
335 if ( !portIn ) {
336 Log::bad_port_index( "input", nodeTo->model_name(), portInIdx );
337 return false;
338 }
339 auto idx = m_input_node->add_output_port( portIn );
340 return idx.isValid();
341 }
342 if ( nodeTo && nodeTo == m_output_node && portInIdx == m_output_node->inputs().size() ) {
343 auto portOut = nodeFrom->output_by_index( portOutIdx );
344 if ( !portOut ) {
345 Log::bad_port_index( "output", nodeFrom->model_name(), portOutIdx );
346 return false;
347 }
348 auto idx = m_output_node->add_input_port( portOut );
349 return idx.isValid();
350 }
351 }
352
353 auto portOut = nodeFrom->output_by_index( portOutIdx );
354 auto portIn = nodeTo->input_by_index( portInIdx );
355
356 if ( !portOut ) {
357 Log::bad_port_index( "output", nodeFrom->model_name(), portOutIdx );
358 return false;
359 }
360 if ( !portIn ) {
361 Log::bad_port_index( "input", nodeTo->model_name(), portInIdx );
362 return false;
363 }
364
365 return add_link( portOut, portIn );
366}
367
368bool DataflowGraph::add_link( Node::PortBaseOutRawPtr outputPort,
369 Node::PortBaseInRawPtr inputPort ) {
370 auto nodeFrom = outputPort->node();
371 auto nodeTo = inputPort->node();
372 if ( !are_nodes_valids( nodeFrom, nodeTo ) ) { return false; }
373 // Compare types
374 if ( !are_ports_compatible( nodeFrom, outputPort, nodeTo, inputPort ) ) { return false; }
375 // port can be connected
376 inputPort->connect( outputPort );
377 // The state of the graph changes, set it to not ready
378 needs_recompile();
379 return true;
380}
381
382bool DataflowGraph::remove_link( std::shared_ptr<Node> node, const std::string& nodeInputName ) {
383 auto [idx, port] = node->input_by_name( nodeInputName );
384 return remove_link( node, idx );
385}
386
387bool DataflowGraph::remove_link( std::shared_ptr<Node> node, const PortIndex& in_port_index ) {
388 // This is to prevent graph destruction from the graph editor, depending on how it is used
389 if ( m_nodesAndLinksProtected ) { return false; }
390
391 // Check node's existence in the graph
392 bool ret = false;
393 if ( // node in graph
394 contains_node_recursive( node.get() ) &&
395 // port index valid
396 in_port_index.isValid() &&
397 // port index less than input size
398 static_cast<size_t>( in_port_index ) < node->inputs().size() ) {
399 ret = node->inputs()[in_port_index]->disconnect();
400 if ( ret ) needs_recompile();
401 }
402 return ret;
403}
404
405bool DataflowGraph::has_node_by_name( const std::string& instance,
406 const std::string& model ) const {
407 return std::find_if( m_nodes.begin(), m_nodes.end(), [instance, model]( const auto& p ) {
408 return p->model_name() == model && p->instance_name() == instance;
409 } ) != m_nodes.end();
410}
411
412bool DataflowGraph::contains_node_recursive( const Node* node ) const {
413 if ( !node ) return false;
414 for ( const auto& n : m_nodes ) {
415 if ( n.get() == node ) return true;
416 auto g = dynamic_cast<DataflowGraph*>( n.get() );
417 if ( g ) {
418 if ( g->contains_node_recursive( node ) ) return true;
419 }
420 }
421 return false;
422}
423
424void DataflowGraph::generate_ports() {
425 if ( m_input_node ) m_inputs = m_input_node->inputs();
426 if ( m_output_node ) m_outputs = m_output_node->outputs();
427}
428
429bool DataflowGraph::compile() {
430
431 // Find useful nodes (directly or indirectly connected to a Sink)
432
435
436 if ( m_output_node ) {
437 backtrack_graph( m_output_node.get(), infoNodes );
438 infoNodes.emplace( m_output_node.get(), std::pair<int, std::vector<Node*>>( 0, {} ) );
439 }
440 for ( auto const& n : m_nodes ) {
441 // Find all active sinks, skip m_output_node
442 if ( n->is_output() && n != m_output_node ) {
443 // if a linked port exists, backtrace
444 if ( std::any_of( n->inputs().begin(), n->inputs().end(), []( const auto& p ) {
445 return p->is_linked();
446 } ) ) {
447
448 infoNodes.emplace( n.get(), std::pair<int, std::vector<Node*>>( 0, {} ) );
449 // recursively add the predecessors of the sink
450 backtrack_graph( n.get(), infoNodes );
451 }
452 else {
453 LOG( logWARNING ) << "Sink Node " << n->instance_name()
454 << " is inactive (belongs to the graph but not connected)";
455 }
456 }
457 }
458 // Compute the level (rank of execution) of useful nodes
459 int maxLevel = 0;
460 for ( auto& infNode : infoNodes ) {
461 auto n = infNode.first;
462 // Compute the nodes' level starting from sources
463 if ( n->is_input() || n == m_input_node.get() ) {
464
465 // set level to 0 because node is source
466 infNode.second.first = 0;
467 // Tag successors (go through graph)
468 maxLevel = std::max( maxLevel, traverse_graph( n, infoNodes ) );
469 }
470 }
471 m_nodes_by_level.clear();
472 m_nodes_by_level.resize( infoNodes.size() != 0 ? maxLevel + 1 : 0 );
473 for ( auto& infNode : infoNodes ) {
474 CORE_ASSERT( size_t( infNode.second.first ) < m_nodes_by_level.size(),
475 std::string( "Node " ) + infNode.first->instance_name() + " is at level " +
476 std::to_string( infNode.second.first ) + " but level max is " +
477 std::to_string( maxLevel ) );
478
479 m_nodes_by_level[infNode.second.first].push_back( infNode.first );
480 }
481
482 // For each level
483 for ( auto& lvl : m_nodes_by_level ) {
484 // For each node
485 for ( size_t j = 0; j < lvl.size(); j++ ) {
486 if ( !lvl[j]->compile() ) { return m_ready = false; }
487 // For each input
488 for ( size_t k = 0; k < lvl[j]->inputs().size(); k++ ) {
489 if ( lvl[j] != m_input_node.get() && lvl[j]->inputs()[k]->is_link_mandatory() &&
490 !lvl[j]->inputs()[k]->is_linked() ) {
491 LOG( logERROR )
492 << "Node <" << lvl[j]->instance_name() << "> is not ready" << std::endl;
493 return m_ready = false;
494 }
495 }
496 }
497 }
498 generate_ports();
499 m_ready = true;
500 init();
501 return m_ready;
502}
503
504void DataflowGraph::clear_nodes() {
505 for ( size_t i = 0; i < m_nodes_by_level.size(); i++ ) {
506 m_nodes_by_level[i].clear();
507 m_nodes_by_level[i].shrink_to_fit();
508 }
509 m_nodes_by_level.clear();
510 m_nodes_by_level.shrink_to_fit();
511 m_nodes.erase( m_nodes.begin(), m_nodes.end() );
512 m_nodes.shrink_to_fit();
513 m_inputs.erase( m_inputs.begin(), m_inputs.end() );
514 m_inputs.shrink_to_fit();
515 m_outputs.erase( m_outputs.begin(), m_outputs.end() );
516 m_outputs.shrink_to_fit();
517 m_should_save = true;
518}
519
520void DataflowGraph::backtrack_graph(
521 Node* current,
523 for ( auto& input : current->inputs() ) {
524 if ( input->link() ) {
525 Node* previous = input->link()->node();
526 if ( previous && previous != m_input_node.get() ) {
527 auto previousInInfoNodes = infoNodes.find( previous );
528 if ( previousInInfoNodes != infoNodes.end() ) {
529 // If the previous node is already in the map,
530 // find if the current node is already a successor node
531 auto& previousSuccessors = previousInInfoNodes->second.second;
532 bool foundCurrent = std::any_of( previousSuccessors.begin(),
533 previousSuccessors.end(),
534 [current]( auto c ) { return c == current; } );
535 if ( !foundCurrent ) {
536 // If the current node is not a successor node, add it to the list
537 previousSuccessors.push_back( current );
538 }
539 }
540 else {
541 // Add node to info nodes
542 std::vector<Node*> successors;
543 successors.push_back( current );
544 infoNodes.emplace(
545 previous,
546 std::pair<int, std::vector<Node*>>( 0, std::move( successors ) ) );
547 backtrack_graph( previous, infoNodes );
548 }
549 }
550 }
551 }
552}
553
554int DataflowGraph::traverse_graph(
555 Node* current,
556 std::unordered_map<Node*, std::pair<int, std::vector<Node*>>>& infoNodes ) {
557
558 int maxLevel = 0;
559 if ( infoNodes.find( current ) != infoNodes.end() ) {
560
561 for ( auto const& successor : infoNodes[current].second ) {
562 // Successors is a least +1 level
563 infoNodes[successor].first =
564 std::max( infoNodes[successor].first, infoNodes[current].first + 1 );
565 maxLevel = std::max(
566 maxLevel,
567 std::max( infoNodes[successor].first, traverse_graph( successor, infoNodes ) ) );
568 }
569 }
570
571 return maxLevel;
572}
573
574std::shared_ptr<Node> DataflowGraph::node( const std::string& instanceNameNode ) const {
575 auto nodeIt =
576 std::find_if( m_nodes.begin(), m_nodes.end(), [instanceNameNode]( const auto& n ) {
577 return n->instance_name() == instanceNameNode;
578 } );
579 if ( nodeIt != m_nodes.end() ) { return *nodeIt; }
580 LOG( logERROR ) << "DataflowGraph::node : The node with the instance name \""
581 << instanceNameNode << "\" has not been found";
582 return { nullptr };
583}
584
585std::shared_ptr<DataflowGraph> DataflowGraph::loadGraphFromJsonFile( const std::string& filename ) {
586
587 auto oj = read_json( filename );
588 if ( !oj ) return nullptr;
589 const auto& j = *oj;
590
591 bool valid = false;
592
593 if ( j.contains( "instance" ) && j.contains( "model" ) ) {
594 valid = j["model"].contains( "name" );
595 }
596 if ( !valid ) {
597 LOG( logERROR ) << "loadGraphFromJsonFile :" << filename
598 << " does not contain a valid json NodeGraph\n";
599 return nullptr;
600 }
601
602 std::string instanceName = j["instance"];
603 std::string graphType = j["model"]["name"];
604
605 LOG( logINFO ) << "Loading the graph " << instanceName << ", with type " << graphType << "\n";
606
608 auto node = factories.create_node( graphType, j );
609
610 if ( node == nullptr ) {
611 LOG( logERROR ) << "Unable to load a graph with type " << graphType << "\n";
612 return nullptr;
613 }
614
615 auto graph = std::dynamic_pointer_cast<DataflowGraph>( node );
616 if ( graph != nullptr ) {
617 graph->m_should_save = false;
618 return graph;
619 }
620
621 LOG( logERROR ) << "Loaded graph failed (not derived from DataflowGraph) " << graphType << "\n";
622
623 return nullptr;
624}
625
626bool DataflowGraph::are_nodes_valids( const Node* nodeFrom,
627 const Node* nodeTo,
628 bool verbose ) const {
629 using namespace Ra::Core::Utils;
630 // Check node "from" existence in the graph
631 if ( !contains_node_recursive( nodeFrom ) ) {
632 if ( verbose ) Log::unable_to_find( "initial node", nodeFrom->instance_name() );
633 return false;
634 }
635
636 // Check node "to" existence in the graph
637 if ( !contains_node_recursive( nodeTo ) ) {
638 if ( verbose ) Log::unable_to_find( "destination node", nodeTo->instance_name() );
639 return false;
640 }
641
642 if ( ( nodeFrom == m_input_node.get() || nodeFrom == m_output_node.get() ) &&
643 ( nodeTo == m_input_node.get() || nodeTo == m_output_node.get() ) ) {
644 if ( verbose ) Log::try_to_link_input_to_output();
645 return false;
646 }
647 return true;
648}
649
650void DataflowGraph::Log::already_linked( const Node* node, const PortBase* port ) {
651 LOG( logERROR )
652 << "DataflowGraph::add_link destination port not available (already linked) for "
653 << node->instance_name() << " (" << node->model_name() << "), port " << port->name();
654}
655
656void DataflowGraph::Log::link_type_mismatch( const Node* nodeFrom,
657 const PortBase* portOut,
658 const Node* nodeTo,
659 const PortBase* portIn ) {
660 LOG( logERROR ) << "DataflowGraph link type mismatch from " << nodeFrom->display_name() << " ("
661 << nodeFrom->model_name() << ") / " << portOut->name() << " with type "
662 << portOut->port_typename() << ")"
663 << " to " << nodeTo->display_name() << " (" << nodeTo->model_name() << ") / "
664 << portIn->name() << " ( with type " << portIn->port_typename() << ") ";
665}
666
667void DataflowGraph::Log::unable_to_find( const std::string& type,
668 const std::string& instanceName ) {
669 LOG( logERROR ) << "DataflowGraph::add_link Unable to find " << type << " " << instanceName;
670}
671
672void DataflowGraph::Log::bad_port_index( const std::string& type,
673 const std::string& instanceName,
674 Node::PortIndex idx ) {
675 LOG( logERROR ) << "DataflowGraph::add_link node " << instanceName << " as no " << type
676 << " port with index " << idx;
677}
678
679void DataflowGraph::Log::try_to_link_input_to_output() {
680 LOG( logERROR ) << "DataflowGraph could not link input to ouput directrly";
681}
682
683} // namespace Core
684} // namespace Dataflow
685} // namespace Ra
T any_of(T... args)
Represent a set of connected nodes that define a Direct Acyclic Computational Graph Ownership of node...
void init() override
Initializes the node content.
DataflowGraph(const std::string &name)
Base abstract class for all the nodes added and used by the node system.
Definition Node.hpp:40
const std::string & instance_name() const
Gets the instance name of the node.
Definition Node.hpp:447
virtual void init()
Initializes the node content.
Definition Node.hpp:428
const PortBaseInCollection & inputs() const
Gets the in ports of the node.
Definition Node.hpp:455
std::type_index type() const
Gets the type of the data (efficient for comparisons).
Definition Port.hpp:56
T clear(T... args)
T emplace(T... args)
T empty(T... args)
T endl(T... args)
T find(T... args)
T for_each(T... args)
T get(T... args)
T insert(T... args)
T max(T... args)
T move(T... args)
auto factory_manager() -> NodeFactorySet &
Allow static initialization without init order problems.
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:4
T dynamic_pointer_cast(T... args)
T push_back(T... args)
T setw(T... args)
T size(T... args)
T to_string(T... args)