1#include <catch2/catch_test_macros.hpp>
3#include <Dataflow/Core/DataflowGraph.hpp>
4#include <Dataflow/Core/Functionals/FunctionNode.hpp>
5#include <Dataflow/Core/Functionals/ReduceNode.hpp>
6#include <Dataflow/Core/Functionals/TransformNode.hpp>
7#include <Dataflow/Core/Functionals/Types.hpp>
8#include <Dataflow/Core/Node.hpp>
9#include <Dataflow/Core/NodeFactory.hpp>
10#include <Dataflow/Core/PortIn.hpp>
11#include <Dataflow/Core/PortOut.hpp>
12#include <Dataflow/Core/Sinks/Types.hpp>
13#include <Dataflow/Core/Sources/FunctionSource.hpp>
14#include <Dataflow/Core/Sources/SingleDataSourceNode.hpp>
15#include <Dataflow/Core/Sources/Types.hpp>
17#include <nlohmann/json.hpp>
24using namespace Ra::Dataflow::Core;
28 const auto& nodes = g.
nodes();
30 for (
const auto& n : nodes ) {
31 std::cout <<
"\t\"" << n->instance_name() <<
"\" of type \"" << n->model_name() <<
"\"\n";
34 for (
const auto& p : n->inputs() ) {
35 std::cout <<
"\t\t\t\"" << p->name() <<
"\" with type " << p->port_typename();
36 if ( p->is_linked() ) {
37 std::cout <<
" linked to " << p->link()->node()->display_name() <<
" "
43 for (
const auto& p : n->outputs() ) {
44 std::cout <<
"\t\t\t\"" << p->name() <<
"\" with type " << p->port_typename();
52 std::cout <<
"Nodes of the graph, sorted by level after compiling the graph :\n";
53 for (
size_t i = 0; i < cn.size(); ++i ) {
55 for (
const auto n : cn[i] ) {
56 std::cout <<
"\t\t\"" << n->instance_name() <<
"\"\n";
61using PortIndex = Ra::Dataflow::Core::Node::PortIndex;
63TEST_CASE(
"Dataflow/Core/Graph/Json",
"[unittests][Dataflow][Core][Graph]" ) {
65 SECTION(
"not a json" ) {
66 auto result = g.
loadFromJson(
"data/Dataflow/NotAJsonFile.json" );
69 SECTION(
"loading empty graph" ) {
70 nlohmann::json emptyJson = {};
71 auto result = g.
fromJson( emptyJson );
74 SECTION(
"missing instance" ) {
75 nlohmann::json noId = { {
"model", {
"name",
"Core DataflowGraph" } } };
79 SECTION(
"missing model" ) {
80 nlohmann::json noModel = { {
"instance",
"No model in this node" } };
84 SECTION(
"missing instance data -> loads an empty graph" ) {
85 nlohmann::json noGraph = { {
"instance",
"Missing instance data for model" },
86 {
"model", {
"name",
"Core DataflowGraph" } } };
90 SECTION(
"trying to instance an unknown node type" ) {
91 nlohmann::json NotANode = {
92 {
"instance",
"graph with unknown node" },
94 { {
"name",
"Core DataflowGraph" },
97 { { {
"instance",
"NotANode" },
98 {
"model", { {
"name",
"NotANode" } } } } } } } } } } };
99 auto result = g.
fromJson( NotANode );
102 SECTION(
"trying to instance an unknown node type" ) {
103 nlohmann::json NoModelName = {
104 {
"instance",
"graph with missing node model information" },
106 { {
"name",
"Core DataflowGraph" },
109 { { {
"instance",
"Unknown model" },
110 {
"model", { {
"extra",
"NotaTypeName" } } } } } } } } } } };
111 auto result = g.
fromJson( NoModelName );
114 SECTION(
"trying to instance an unknown node type" ) {
115 nlohmann::json noInstanceIdentification = {
116 {
"instance",
"graph with missing node model information" },
118 { {
"name",
"Core DataflowGraph" },
120 { {
"nodes", { { {
"model", { {
"name",
"Source<Scalar>" } } } } } } } } } } };
121 auto result = g.
fromJson( noInstanceIdentification );
124 SECTION(
"errors in the connection description" ) {
125 nlohmann::json reusingNodeIdentification = {
126 {
"instance",
"graph with wrong connection" },
128 { {
"name",
"Core DataflowGraph" },
131 { { {
"instance",
"Source" }, {
"model", { {
"name",
"Source<Scalar>" } } } },
132 { {
"instance",
"Source" }, {
"model", { {
"name",
"Sink<int>" } } } } } },
133 {
"connections", { { {
"out_node",
"wrongId" } } } } } } } } };
134 auto result = g.
fromJson( reusingNodeIdentification );
137 SECTION(
"wrong connection 0" ) {
138 nlohmann::json reusingNodeIdentification = {
139 {
"instance",
"graph with wrong connection" },
141 { {
"name",
"Core DataflowGraph" },
144 { { {
"model", { {
"name",
"Source<Scalar>" } } } },
145 { {
"model", { {
"name",
"Sink<int>" } } } } } },
146 {
"connections", { { {
"out_node",
"wrongId" } } } } } } } } };
147 auto result = g.
fromJson( reusingNodeIdentification );
150 SECTION(
"wrong connection 1" ) {
151 nlohmann::json wrongConnection = {
152 {
"instance",
"graph with wrong connection" },
154 { {
"name",
"Core DataflowGraph" },
157 { { {
"instance",
"SourceScalar" },
158 {
"model", { {
"name",
"Source<Scalar>" } } } },
159 { {
"instance",
"SinkInt" }, {
"model", { {
"name",
"Sink<int>" } } } } } },
160 {
"connections", { { {
"out_node",
"wrongId" } } } } } } } } };
161 auto result = g.
fromJson( wrongConnection );
164 SECTION(
"wrong connection 2" ) {
165 nlohmann::json wrongConnection = {
166 {
"instance",
"Test Graph Inline" },
168 { {
"name",
"Core DataflowGraph" },
171 { { {
"instance",
"SourceScalar" },
172 {
"model", { {
"name",
"Source<Scalar>" } } } },
173 { {
"instance",
"SinkInt" }, {
"model", { {
"name",
"Sink<int>" } } } } } },
175 { { {
"out_node",
"SourceScalar" }, {
"out_index", 2 } } } } } } } } };
176 auto result = g.
fromJson( wrongConnection );
179 SECTION(
"wrong connection 3" ) {
180 nlohmann::json wrongConnection = {
181 {
"instance",
"Test Graph Inline" },
183 { {
"name",
"Core DataflowGraph" },
186 { { {
"instance",
"SourceScalar" },
187 {
"model", { {
"name",
"Source<Scalar>" } } } },
188 { {
"instance",
"SinkInt" }, {
"model", { {
"name",
"Sink<int>" } } } } } },
190 { { {
"out_node",
"SourceScalar" },
192 {
"in_node",
"Sink" },
193 {
"in_port",
"from" } } } } } } } } };
194 auto result = g.
fromJson( wrongConnection );
197 SECTION(
"wrong connection 4" ) {
198 nlohmann::json wrongConnection = {
199 {
"instance",
"Test Graph Inline" },
201 { {
"name",
"Core DataflowGraph" },
204 { { {
"instance",
"SourceScalar" },
205 {
"model", { {
"name",
"Source<Scalar>" } } } },
206 { {
"instance",
"SinkInt" }, {
"model", { {
"name",
"Sink<int>" } } } } } },
208 { { {
"out_node",
"SourceScalar" },
210 {
"in_node",
"SinkInt" },
211 {
"in_port",
"from" } } } } } } } } };
212 auto result = g.
fromJson( wrongConnection );
215 SECTION(
"correct graph" ) {
216 nlohmann::json goodSimpleGraph = {
217 {
"instance",
"Test Graph Inline" },
219 { {
"name",
"Core DataflowGraph" },
222 { { {
"instance",
"SourceScalar" },
223 {
"model", { {
"name",
"Source<Scalar>" } } } },
224 { {
"instance",
"SinkScalar" },
225 {
"model", { {
"name",
"Sink<Scalar>" } } } } } },
227 { { {
"out_node",
"SourceScalar" },
228 {
"out_port",
"to" },
229 {
"in_node",
"SinkScalar" },
230 {
"in_index", 0 } } } } } } } } };
232 REQUIRE( g.
fromJson( goodSimpleGraph ) );
235 auto duplicatedNodeName =
237 REQUIRE( !g.
add_node( duplicatedNodeName ) );
241 auto sinkScalarNode = g.
node(
"Sink" );
242 REQUIRE( sinkScalarNode ==
nullptr );
244 sinkScalarNode = g.
node(
"SinkScalar" );
245 REQUIRE( sinkScalarNode !=
nullptr );
247 auto sourceScalarNode = g.
node(
"SourceScalar" );
248 REQUIRE( sourceScalarNode !=
nullptr );
255 REQUIRE( !g.
add_link( sourceIntNode,
"to", sinkIntNode,
"from" ) );
256 REQUIRE( !g.
can_link( sourceIntNode, PortIndex { 0 }, sinkIntNode, PortIndex { 0 } ) );
257 REQUIRE( !g.
add_link( sourceIntNode, PortIndex { 0 }, sinkIntNode, PortIndex { 0 } ) );
259 REQUIRE( g.
add_node( sourceIntNode ) );
260 REQUIRE( !g.
add_link( sourceIntNode,
"to", sinkIntNode,
"from" ) );
261 REQUIRE( !g.
can_link( sourceIntNode, PortIndex { 0 }, sinkIntNode, PortIndex { 0 } ) );
262 REQUIRE( !g.
add_link( sourceIntNode, PortIndex { 0 }, sinkIntNode, PortIndex { 0 } ) );
264 REQUIRE( g.
add_node( sinkIntNode ) );
268 REQUIRE( !g.
add_link( sourceIntNode,
"out", sinkIntNode,
"from" ) );
269 REQUIRE( !g.
add_link( sourceIntNode, PortIndex { 10 }, sinkIntNode, PortIndex { 0 } ) );
270 REQUIRE( !g.
add_link( sourceIntNode, PortIndex { 0 }, sinkIntNode, PortIndex { 10 } ) );
271 REQUIRE( !g.
can_link( sourceIntNode, PortIndex { 10 }, sinkIntNode, PortIndex { 0 } ) );
272 REQUIRE( !g.
can_link( sourceIntNode, PortIndex { 0 }, sinkIntNode, PortIndex { 10 } ) );
273 REQUIRE( !g.
add_link( sourceIntNode,
"to", sinkIntNode,
"in" ) );
276 REQUIRE( g.
add_link( sourceIntNode,
"to", sinkIntNode,
"from" ) );
279 REQUIRE( !g.
add_link( sourceIntNode,
"to", sinkIntNode,
"from" ) );
282 REQUIRE( !g.
add_link( sourceIntNode,
"to", sinkScalarNode,
"from" ) );
296 REQUIRE( !g.
remove_link( sinkIntNode, PortIndex { 0 } ) );
297 REQUIRE( g.
add_link( sourceIntNode, PortIndex { 0 }, sinkIntNode, PortIndex { 0 } ) );
298 REQUIRE( !g.
remove_link( sinkIntNode, PortIndex { 10 } ) );
299 REQUIRE( g.
remove_link( sinkIntNode, PortIndex { 0 } ) );
310 auto nullNode = g.
node(
"SourceInt" );
311 REQUIRE( nullNode ==
nullptr );
312 nullNode = g.
node(
"SinkInt" );
313 REQUIRE( nullNode ==
nullptr );
315 nullNode = g.
node(
"SourceScalar" );
316 REQUIRE( nullNode ==
nullptr );
317 nullNode = g.
node(
"SinkScalar" );
318 REQUIRE( nullNode ==
nullptr );
324TEST_CASE(
"Dataflow/Core/Graph/Node failed execution",
"[unittests][Dataflow][Core][Graph]" ) {
326 auto sourceIntNode = g.
add_node<Sources::IntSource>(
"SourceInt" );
327 auto sinkIntNode = g.
add_node<Sinks::IntSink>(
"SinkInt" );
328 class FailFunction :
public Functionals::TransformInt
331 explicit FailFunction(
const std::string& instanceName ) : FunctionNode( instanceName ) {}
332 bool execute() {
return false; }
334 auto failNode = g.
add_node<FailFunction>(
"FailNode" );
336 REQUIRE( g.
add_link( sourceIntNode,
"to", failNode,
"data" ) );
337 REQUIRE( g.
add_link( failNode,
"result", sinkIntNode,
"from" ) );
342TEST_CASE(
"Dataflow/Core/Graph/Inspection of a graph",
"[unittests][Dataflow][Core][Graph]" ) {
345 using namespace Ra::Dataflow::Core;
354 REGISTER_TYPE_TO_FACTORY( coreFactory, ScalarVectorSource, Sources );
355 REGISTER_TYPE_TO_FACTORY( coreFactory, ScalarFilterSource, Sources );
356 REGISTER_TYPE_TO_FACTORY( coreFactory, ScalarFunctionSource, Sources );
357 REGISTER_TYPE_TO_FACTORY( coreFactory, ScalarPredicateSource, Sources );
358 REGISTER_TYPE_TO_FACTORY( coreFactory, ReduceNode, Functionals );
359 REGISTER_TYPE_TO_FACTORY( coreFactory, TransformNode, Functionals );
361 std::cout <<
"Loading graph data/Dataflow/ExampleGraph.json\n";
371 const auto& nodes = g->
nodes();
382 auto n = g->
node(
"validation value" );
383 auto useCount = n.use_count();
384 REQUIRE( n->instance_name() ==
"validation value" );
388 REQUIRE( n.use_count() == useCount - 1 );
396 auto found =
std::find_if( cn[0].begin(), cn[0].end(), [](
const auto& nn ) {
397 return nn->instance_name() ==
"Validator";
399 REQUIRE( found == cn[0].end() );
402 n = g->
node(
"Validator" );
403 REQUIRE( n->instance_name() ==
"Validator" );
410 std::cout <<
"####### Graph after sink and source removal\n";
415using namespace Ra::Dataflow::Core;
416template <
typename DataType_a,
typename DataType_b = DataType_a,
typename DataType_r = DataType_a>
427 REQUIRE( a->node() == source_a.get() );
432 REQUIRE( b->node() == source_b.get() );
437 REQUIRE( r->node() == sink.get() );
443 REQUIRE( g->
add_link( source_a,
"to", op,
"a" ) );
444 REQUIRE( g->
add_link( op,
"result", sink,
"from" ) );
450 REQUIRE( g->
add_link( source_b,
"to", op,
"b" ) );
452 return { g, a, b, r };
455TEST_CASE(
"Dataflow/Core/Nodes",
"[unittests][Dataflow][Core][Nodes]" ) {
456 SECTION(
"Operations on Scalar" ) {
457 using DataType = Scalar;
459 typename TestNode::BinaryOperator
add = [](
typename TestNode::Arg1_type a,
460 typename TestNode::Arg2_type b ) ->
461 typename TestNode::Res_type {
return a + b; };
463 auto [g, a, b, r] = createGraph<DataType>(
"test scalar binary op", add );
467 a->set_default_value( x );
468 REQUIRE( a->data<DataType>() == x );
471 b->set_default_value( y );
472 REQUIRE( b->data<DataType>() == y );
477 auto& z = r->data<DataType>();
478 REQUIRE( z == x + y );
480 REQUIRE_THROWS( r->data<
int>() );
482 std::cout << x <<
" + " << y <<
" == " << z <<
"\n";
488 SECTION(
"Operations on Vectors" ) {
489 using DataType = Ra::Core::Vector3;
491 typename TestNode::BinaryOperator
add = [](
typename TestNode::Arg1_type a,
492 typename TestNode::Arg2_type b ) ->
493 typename TestNode::Res_type {
return a + b; };
495 auto [g, a, b, r] = createGraph<DataType>(
"test Vector3 binary op", add );
497 DataType x { 1_ra, 2_ra, 3_ra };
498 a->set_default_value( x );
499 REQUIRE( a->data<DataType>() == x );
501 DataType y { 3_ra, 2_ra, 1_ra };
502 b->set_default_value( y );
503 REQUIRE( b->data<DataType>() == y );
507 auto& z = r->data<DataType>();
508 REQUIRE( z == x + y );
510 std::cout <<
"[" << x.transpose() <<
"] + [" << y.transpose() <<
"] == [" << z.transpose()
517 SECTION(
"Operations on VectorArrays" ) {
520 typename TestNode::BinaryOperator
add = [](
typename TestNode::Arg1_type a,
521 typename TestNode::Arg2_type b ) ->
522 typename TestNode::Res_type {
return a + b; };
524 auto [g, a, b, r] = createGraph<DataType>(
"test Vector3 binary op", add );
526 DataType x { { 1_ra, 2_ra }, { 3_ra, 4_ra } };
527 a->set_default_value( x );
528 REQUIRE( a->data<DataType>() == x );
530 DataType y { { 5_ra, 6_ra }, { 7_ra, 8_ra } };
531 b->set_default_value( y );
532 REQUIRE( b->data<DataType>() == y );
536 auto& z = r->data<DataType>();
537 for (
size_t i = 0; i < z.size(); i++ ) {
538 REQUIRE( z[i] == x[i] + y[i] );
542 for (
const auto& t : x ) {
543 std::cout <<
"[" << t.transpose() <<
"] ";
546 for (
const auto& t : y ) {
547 std::cout <<
"[" << t.transpose() <<
"] ";
550 for (
const auto& t : z ) {
551 std::cout <<
"[" << t.transpose() <<
"] ";
559 SECTION(
"Operations between VectorArray and Scalar" ) {
561 using DataType_b = Scalar;
567 typename TestNode::BinaryOperator op = [](
typename TestNode::Arg1_type a,
568 typename TestNode::Arg2_type b ) ->
569 typename TestNode::Res_type {
return a * b; };
570 auto [g, a, b, r] = createGraph<DataType_a, DataType_b, DataType_r>(
571 "test Vector2 x Scalar binary op", op );
573 DataType_a x { { 1_ra, 2_ra }, { 3_ra, 4_ra } };
574 a->set_default_value( x );
575 REQUIRE( a->data<DataType_a>() == x );
577 DataType_b y { 5_ra };
578 b->set_default_value( y );
579 REQUIRE( b->data<DataType_b>() == y );
583 auto& z = r->data<DataType_r>();
584 for (
size_t i = 0; i < z.size(); i++ ) {
585 REQUIRE( z[i] == x[i] * y );
589 for (
const auto& t : x ) {
590 std::cout <<
"[" << t.transpose() <<
"] ";
593 for (
const auto& t : z ) {
594 std::cout <<
"[" << t.transpose() <<
"] ";
600 REQUIRE( opNode !=
nullptr );
602 typename TestNode::BinaryOperator f = [](
typename TestNode::Arg1_type arg1,
603 typename TestNode::Arg2_type arg2 ) ->
604 typename TestNode::Res_type {
return arg1 / arg2; };
605 opNode->set_operator( f );
609 for (
size_t i = 0; i < z.size(); i++ ) {
610 REQUIRE( z[i] == x[i] / y );
614 for (
const auto& t : x ) {
615 std::cout <<
"[" << t.transpose() <<
"] ";
618 for (
const auto& t : z ) {
619 std::cout <<
"[" << t.transpose() <<
"] ";
626 SECTION(
"Operations between Scalar and VectorArray" ) {
627 using namespace Ra::Dataflow::Core;
628 using DataType_a = Scalar;
632 typename TestNode::BinaryOperator op = [](
typename TestNode::Arg1_type a,
633 typename TestNode::Arg2_type b ) ->
634 typename TestNode::Res_type {
return a * b; };
635 auto [g, a, b, r] = createGraph<DataType_a, DataType_b, DataType_r>(
636 "test Vector2 x Scalar binary op", op );
638 DataType_a x { 4_ra };
639 a->set_default_value( x );
640 REQUIRE( a->data<DataType_a>() == x );
642 DataType_b y { { 1_ra, 2_ra }, { 3_ra, 4_ra } };
643 b->set_default_value( y );
644 REQUIRE( b->data<DataType_b>() == y );
648 auto& z = r->data<DataType_r>();
649 for (
size_t i = 0; i < z.size(); i++ ) {
650 REQUIRE( z[i] == x * y[i] );
654 for (
const auto& t : y ) {
655 std::cout <<
"[" << t.transpose() <<
"] ";
658 for (
const auto& t : z ) {
659 std::cout <<
"[" << t.transpose() <<
"] ";
666 SECTION(
"Transform/reduce/filter/test" ) {
676 DoubleFunction doubleMe = [](
const Scalar& x ) -> Scalar {
return 2_ra * x; };
678 nodeD->set_data( doubleMe );
682 nodeN->set_data( 0_ra );
686 struct MeanOperator {
688 Scalar operator()(
const Scalar& m,
const Scalar& x ) {
689 return m + ( ( x - m ) / ( ++n ) );
693 ReduceOperator::function_type m = MeanOperator();
713 Sources::ScalarBinaryPredicateSource::function_type predicate =
714 [](
const Scalar& a,
const Scalar& b ) ->
bool {
return 2_ra * a == b; };
715 nodePred->set_data( predicate );
729 REQUIRE( g->
add_node( meanCalculator ) );
730 REQUIRE( g->
add_node( doubleMeanCalculator ) );
734 REQUIRE( g->
add_link( nodeS,
"to", meanCalculator,
"data" ) );
735 REQUIRE( g->
add_link( nodeM,
"to", meanCalculator,
"op" ) );
736 REQUIRE( g->
add_link( nodeN,
"to", meanCalculator,
"init" ) );
737 REQUIRE( g->
add_link( meanCalculator,
"result", nodeR,
"from" ) );
738 REQUIRE( g->
add_link( nodeS,
"to", nodeT,
"data" ) );
739 REQUIRE( g->
add_link( nodeD,
"to", nodeT,
"op" ) );
740 REQUIRE( g->
add_link( nodeT,
"result", doubleMeanCalculator,
"data" ) );
741 REQUIRE( g->
add_link( doubleMeanCalculator,
"result", nodeRD,
"from" ) );
742 REQUIRE( g->
add_link( nodeM,
"to", doubleMeanCalculator,
"op" ) );
746 REQUIRE( g->
add_node( validator ) );
747 REQUIRE( g->
add_link( meanCalculator,
"result", validator,
"a" ) );
748 REQUIRE( g->
add_link( doubleMeanCalculator,
"result", validator,
"b" ) );
749 REQUIRE( g->
add_link( nodePred,
"to", validator,
"op" ) );
750 REQUIRE( g->
add_link( validator,
"result", sinkB,
"from" ) );
770 for (
size_t n = 0; n < test.capacity(); ++n ) {
771 test.push_back( dis( gen ) );
773 input->set_default_value( test );
776 ReduceOperator::function_type m1 = MeanOperator();
777 inputR->set_default_value( m1 );
781 auto& result = output->data<Scalar>();
782 auto& resultD = outputD->data<Scalar>();
783 auto& resultB = outputB->data<
bool>();
785 std::cout <<
"Computed mean ( ref ): " << result <<
"\n";
786 std::cout <<
"Computed mean ( tra ): " << resultD <<
"\n";
788 std::cout <<
"Ratio ( expected 2 ): " << resultD / result <<
" -- validator --> "
793 REQUIRE( resultD / result == 2_ra );
This class implements ContainerIntrospectionInterface for AlignedStdVector.
Represent a set of connected nodes that define a Direct Acyclic Computational Graph Ownership of node...
bool add_link(const std::shared_ptr< Node > &nodeFrom, const std::string &nodeFromOutputName, const std::shared_ptr< Node > &nodeTo, const std::string &nodeToInputName)
Connects two nodes of the graph.
bool loadFromJson(const std::string &jsonFilePath)
Loads nodes and links from a JSON file.
void setNodesAndLinksProtection(bool on)
protect nodes and links from deletion.
virtual bool add_node(std::shared_ptr< Node > newNode)
Adds a node to the graph.
Node::PortBaseInRawPtr input_node_port(const std::string &nodeName, const std::string &portName)
Gets an input port form a node of the graph.
size_t node_count() const
Gets the number of nodes.
const std::vector< std::shared_ptr< Node > > & nodes() const
Get the vector of all the nodes on the graph.
virtual void clear_nodes()
Deletes all nodes from the render graph.
bool compile() override
Compile the graph to check its validity and simplify it.
void destroy() override
Delete the node's content.
bool remove_link(std::shared_ptr< Node > node, const std::string &nodeInputName)
Removes the link connected to a node's input port.
std::shared_ptr< Node > node(const std::string &instanceNameNode) const
bool is_compiled() const
Test if the graph is compiled.
Node::PortBaseOutRawPtr output_node_port(const std::string &nodeName, const std::string &portName)
Gets an output port from a node of the graph.
virtual bool remove_node(std::shared_ptr< Node > node)
Removes a node from the graph.
const std::vector< std::vector< Node * > > & nodes_by_level() const
Gets the nodes ordered by level (after compilation)
bool can_link(const std::shared_ptr< Node > &nodeFrom, Node::PortIndex portOutIdx, const std::shared_ptr< Node > &nodeTo, Node::PortIndex portInIdx) const
bool nodesAndLinksProtection() const
get the protection status protect nodes and links from deletion
static std::shared_ptr< DataflowGraph > loadGraphFromJsonFile(const std::string &filename)
Load a graph from the given file.
bool execute() override
Executes the node.
Apply a binary operation on its input.
Reduce an iterable collection using a given operator.
const std::string & instance_name() const
Gets the instance name of the node.
bool fromJson(const nlohmann::json &data)
Unserialized the content of the node.
Node that deliver a std::function<R( Args... )}}>
Base class for nodes that will give access to some input data to the graph. This class can be used to...
Quaternion add(const Quaternion &q1, const Quaternion &q2)
Returns the sum of two quaternions.
auto default_factory() -> NodeFactorySet::mapped_type
Gets the "default" factory for nodes exported by the Core dataflow library.
T dynamic_pointer_cast(T... args)