NRP Core  1.4.1
functional_node.h
Go to the documentation of this file.
1 /* * NRP Core - Backend infrastructure to synchronize simulations
2  *
3  * Copyright 2020-2023 NRP Team
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * This project has received funding from the European Union’s Horizon 2020
18  * Framework Programme for Research and Innovation under the Specific Grant
19  * Agreement No. 945539 (Human Brain Project SGA3).
20  */
21 
22 #ifndef FUNCTIONAL_NODE_H
23 #define FUNCTIONAL_NODE_H
24 
25 #include <array>
26 #include <functional>
27 #include <tuple>
28 
34 
36 
43 public:
44 
45  FunctionalNodeBase(const std::string &id) :
47  {}
48 
52  virtual Port* getInputById(const std::string& /*id*/) { return nullptr; }
53 
57  virtual Port* getOutputById(const std::string& /*id*/) { return nullptr; }
58 
59 
60  // TODO: throw 'not implemented' in empty virtual and override functions
61  void configure() override {}
62  void compute() override {}
63 
73  void registerF2FEdge(const std::string& i_port, const std::string& address)
74  { _f2fEdges[i_port] = address; }
75 
76 protected:
77 
78  void graphLoadedCB() override
79  { createF2FEdges(); }
80 
84  virtual void createEdge(const std::string& /*port_id*/, Port* /*out_port*/)
85  { }
86 
88  { _f2fEdges.clear(); }
89 
91 
92 private:
93 
97  void createF2FEdges()
98  {
99  // Create edges to other functional nodes
100  for (auto& [in_port, address]: _f2fEdges) {
101  std::string node_id, out_port;
102  std::tie(node_id, out_port) = parseNodeAddress(address);
103  createF2FEdge(in_port, node_id, out_port);
104  }
105 
106  // Clear registered edges
108  }
109 
110  void createF2FEdge(const std::string & in_port, const std::string & node_id, const std::string & out_port)
111  {
112  std::string address = "/" + node_id + "/" + out_port;
113 
114  // Get the other node
116  if(!node)
117  throw NRPException::logCreate("While creating the F2F edge '" + address +
118  "'. A Functional node with name '" + node_id + "' could not be found in the computational graph. Be sure that the edge"
119  " address is correctly formatted and the connected node exists.");
120 
121  // Get output port
122  Port* o_port = node->getOutputById(out_port);
123  if(!o_port)
124  throw NRPException::logCreate("While creating the F2F edge '" + address +
125  "'. Functional node '" + node_id + "' doesn't have a declared output '"+ out_port +"'. Be sure that the edge"
126  " address is correctly formatted and the specified output exists.");
127 
128  // Create edge
129  createEdge(in_port, o_port);
130  }
131 
133  std::map<std::string, std::string> _f2fEdges;
134 };
135 
139 class F2FEdge {
140 public:
141 
142  F2FEdge(const std::string &keyword, const std::string &address) :
143  _keyword(keyword),
144  _address(address)
145  { }
146 
152  boost::python::object pySetup(const boost::python::object& obj)
153  {
154  // Register edge in FN
155  try {
156  std::shared_ptr<FunctionalNodeBase> f = boost::python::extract<std::shared_ptr<FunctionalNodeBase> >(
157  obj);
158  f->registerF2FEdge(_keyword, _address);
159  }
160  catch (const boost::python::error_already_set&) {
161  std::string error_msg = "An error occurred while creating the F2FEdge '" + _address +
162  "'. Check that Functional Node definition is correct";
163  PyErr_Print();
164  throw NRPException::logCreate(error_msg);
165  }
166 
167  // Returns FunctionalNode
168  return obj;
169  }
170 
171 protected:
172 
173  std::string _keyword;
174  std::string _address;
175 };
176 
177 
178 template<typename, typename>
180 
189 template<typename... INPUT_TYPES, typename... OUTPUT_TYPES>
190 class FunctionalNode<std::tuple<INPUT_TYPES...>, std::tuple<OUTPUT_TYPES...> > : public FunctionalNodeBase {
191 
192 protected:
193 
195  template <std::size_t N>
196  using input_n_t = typename std::tuple_element<N, std::tuple<INPUT_TYPES...>>::type;
197 
199  template <std::size_t N>
200  using output_n_t = typename std::tuple_element<N, std::tuple<OUTPUT_TYPES...>>::type;
201 
202  using inputs_t = std::tuple<const INPUT_TYPES* ...>;
203  using outputs_t = std::tuple<OUTPUT_TYPES ...>;
204 
209  using params_t = decltype(std::tuple_cat(std::declval<inputs_t>(), std::declval<outputs_t>()));
210 
211 
212 public:
213 
217  template <std::size_t N, class T_IN, class T_OUT>
218  InputPort<T_IN, T_OUT>* registerInput(const std::string& id)
219  {
220  if constexpr (N >= sizeof...(INPUT_TYPES)) {
221  std::stringstream s;
222  s << "In Functional node '" << this->id() << "'. Attempt to register input with index " << N <<
223  ", which is greater than the number of inputs in this node: " << sizeof...(INPUT_TYPES);
224  throw NRPException::logCreate(s.str());
225  }
226  else if constexpr (!std::is_same_v<input_n_t<N>, T_OUT>) {
227  std::stringstream s;
228  s << "In Functional node '" << this->id() << "'. Attempt to register input with index " << N << " and type '" << typeid(T_OUT).name() <<
229  "', but index " << N << " is of type " << typeid(input_n_t<N>).name();
230  throw NRPException::logCreate(s.str());
231  }
232  else if(_inputPorts.at(N)) {
233  std::stringstream s;
234  s << "In Functional node '" << this->id() << "'. Attempt to register input with index " << N << ", but index "
235  << N << " is already registered.";
236  throw NRPException::logCreate(s.str());
237  }
238 
239  using std::placeholders::_1;
240  std::function<void(const T_OUT*)> f = std::bind( &FunctionalNode::newInputCallback<N, T_OUT>, this, _1 );
241  InputPort<T_IN, T_OUT>* port = new InputPort<T_IN, T_OUT>(id, this, f, 1);
242  _inputPorts.at(N).reset(port);
243 
244  return port;
245  }
246 
250  Port* getInputByIndex(size_t idx)
251  {
252  if (idx >= _inputPorts.size()) {
253  std::stringstream s;
254  s << "In Functional node '" << this->id() << "'. Attempt to get input with index " << idx <<
255  ", which is greater than the number of inputs in this node: " << _inputPorts.size() - 1;
256  throw NRPException::logCreate(s.str());
257  }
258 
259  return _inputPorts.at(idx).get();
260  }
261 
265  Port* getInputById(const std::string& id) override
266  {
267  for(auto& e : _inputPorts)
268  if (e && e->id() == id)
269  return e.get();
270 
271  std::stringstream s;
272  s << "In Functional node '" << this->id() << "'. Input with id '" << id << "' not found";
273  NRPLogger::info(s.str());
274 
275  return nullptr;
276  }
277 
281  template <std::size_t N, class T>
282  OutputPort<T>* registerOutput(const std::string& id)
283  {
284  if constexpr (N >= sizeof...(OUTPUT_TYPES)) {
285  std::stringstream s;
286  s << "In Functional node '" << this->id() << "'. Attempt to register output with index " << N <<
287  ", which is greater than the number of outputs in this node: " << sizeof...(OUTPUT_TYPES);
288  throw NRPException::logCreate(s.str());
289  }
290  else if constexpr (!std::is_same_v<output_n_t<N>, T>) {
291  std::stringstream s;
292  s << "In Functional node '" << this->id() << "'. Attempt to register output with index " << N << " and type '"
293  << typeid(T).name() << "', but index " << N << " is of type " << typeid(output_n_t<N>).name();
294  throw NRPException::logCreate(s.str());
295  }
296  else if(std::get<N>(_outputPorts)) {
297  std::stringstream s;
298  s << "In Functional node '" << this->id() << "'. Attempt to register output with index " << N << ", but index "
299  << N << " is already registered.";
300  throw NRPException::logCreate(s.str());
301  }
302 
303  OutputPort<T>* port = new OutputPort<T>(id, this);
304  std::get<N>(_outputPorts).reset(port);
305 
306  return port;
307  }
308 
312  template <std::size_t N>
314  {
315  if constexpr (N >= sizeof...(OUTPUT_TYPES)) {
316  std::stringstream s;
317  s << "In Functional node '" << this->id() << "'. Attempt to get or register output with index " << N <<
318  ", which is greater than the number of outputs in this node: " << sizeof...(OUTPUT_TYPES);
319  throw NRPException::logCreate(s.str());
320  }
321 
322  return std::get<N>(_outputPorts).get();
323  }
324 
328  Port* getOutputById(const std::string& id) override
329  { return getOutputByIdTuple(id); }
330 
331  template <std::size_t N = 0>
332  Port* getOutputByIdTuple(const std::string& id)
333  {
334  if constexpr (N < sizeof...(OUTPUT_TYPES)) {
335  if (std::get<N>(_outputPorts) && std::get<N>(_outputPorts)->id() == id)
336  return std::get<N>(_outputPorts).get();
337  else
338  return getOutputByIdTuple<N+1>(id);
339  }
340 
341  std::stringstream s;
342  s << "In Functional node '" << this->id() << "'. Attempt to get output with id '" << id << "', but it is not registered.";
343  NRPLogger::info(s.str());
344 
345  return nullptr;
346  }
347 
348 protected:
349 
353  void createEdge(const std::string& port_id, Port* out_port) override
354  { createEdgeTuple(port_id, out_port); }
355 
356  template <std::size_t N = 0>
357  void createEdgeTuple(const std::string& port_id, Port* out_port)
358  {
359  std::stringstream error_msg;
360  error_msg << "In Functional node '" << this->id() << "'. Error While creating edge to port '" << port_id << "'. ";
361 
362  if constexpr (N < sizeof...(INPUT_TYPES)) {
363  if (_inputPorts.at(N) && _inputPorts.at(N)->id() == port_id) {
364  // Try cast ports
365  // Limitation: this will only work if InputPort T_IN = T_OUT.
366  // When creating input ports T_IN is lost, no way to recover it.
367  // Currently this is the only case supported by createFNFactoryModule though
368  InputPort<input_n_t<N>, input_n_t<N>>* in_port = dynamic_cast<InputPort<input_n_t<N>, input_n_t<N>>*>(_inputPorts.at(N).get());
369  OutputPort<input_n_t<N>>* o_port = dynamic_cast<OutputPort<input_n_t<N>>*>(out_port);
370 
371  if(!in_port) {
372  error_msg << "The port T_IN and T_OUT types are not equal. Currently this is the only supported case.";
373  throw NRPException::logCreate(error_msg.str());
374  }
375  else if(!o_port) {
376  error_msg << "Attempt to connect to port '" << out_port->id() << "', but they are of different types.";
377  throw NRPException::logCreate(error_msg.str());
378  }
379 
381 
382  }
383  else
384  createEdgeTuple<N+1>(port_id, out_port);
385  }
386  else {
387  error_msg << "This port is not registered in the node.";
388  throw NRPException::logCreate(error_msg.str());
389  }
390  }
391 
395  void configure() override
396  {
397  if(boundInputPorts() < std::tuple_size_v<inputs_t>) {
398  std::stringstream s;
399  s << "Functional node " << this->id() << " has been declared with " << std::tuple_size_v<inputs_t> <<
400  " inputs, but only " << boundInputPorts() << " are bounded" << std::endl;
401  NRPLogger::info(s.str());
402  }
403 
404  if(boundOutputPorts() < std::tuple_size_v<outputs_t>) {
405  std::stringstream s;
406  s << "Functional node " << this->id() << " has been declared with " << std::tuple_size_v<outputs_t>
407  <<
408  " outputs, but only " << boundOutputPorts() << " are bounded" << std::endl;
409  NRPLogger::info(s.str());
410  }
411  }
412 
416  void compute() override final
417  {
418  if(_execPolicy == FunctionalNodePolicies::ExecutionPolicy::ALWAYS || _hasNew) {
419  // Execute _function and send outputs if _function returns true
420  if(_function(_params))
421  sendOutputs();
422  }
423 
424  _hasNew = false;
425  }
426 
431  FunctionalNodeBase(id),
432  _function(f),
433  _execPolicy(policy)
434  { initInputs(); }
435 
439  template<size_t N = 0>
440  void initInputs()
441  {
442  if constexpr ( N < sizeof...(INPUT_TYPES)) {
443  std::get<N>(_params) = nullptr;
444  initInputs<N+1>();
445  }
446  }
447 
451  template <size_t N, class T>
452  void newInputCallback(const T* value)
453  {
454  std::get<N>(_params) = value;
455  this->_hasNew = this->_hasNew || value != nullptr;
456  }
457 
461  template<size_t N = 0>
462  void sendOutputs()
463  {
464  if constexpr ( N < sizeof...(OUTPUT_TYPES)) {
465  if (std::get<N>(_outputPorts))
466  std::get<N>(_outputPorts)->publish(&std::get<sizeof...(INPUT_TYPES) + N>(_params));
467 
468  sendOutputs<N+1>();
469  }
470  }
471 
473  {
474  size_t n = 0;
475  for(auto p : _inputPorts)
476  n += p ? 1 : 0;
477 
478  return n;
479  }
480 
481  template<size_t N = 0>
483  {
484  if constexpr (N < sizeof...(OUTPUT_TYPES)) {
485  size_t n = std::get<N>(_outputPorts) ? 1 : 0;
486  return n + boundOutputPorts<N+1>();
487  }
488 
489  return 0;
490  }
491 
495  std::function<bool(params_t&)> _function;
496 
497  friend class FunctionalNodeFactory;
498  friend class ComputationalNodes_FUNCTIONAL_NODE_Test;
499  friend class ComputationalNodes_FUNCTIONAL_NODE_FACTORY_Test;
500  friend class ComputationalGraphPythonNodes_PYTHON_FUNCTIONAL_NODE_Test;
501  friend class ComputationalGraphPythonNodes_PYTHON_DECORATORS_BASIC_Test;
502 
503 private:
504 
506  std::array< std::shared_ptr<Port>, sizeof...(INPUT_TYPES) > _inputPorts;
508  std::tuple< std::shared_ptr< OutputPort<OUTPUT_TYPES> > ...> _outputPorts;
509 
510  bool _hasNew = false;
512 };
513 
514 #endif //FUNCTIONAL_NODE_H
ComputationalGraphManager::registerEdge
void registerEdge(OutputPort< T_IN > *source, InputPort< T_IN, T_OUT > *target)
Connects an InputPort to an Output port and registers an edge in the graph between their parent nodes...
Definition: computational_graph_manager.h:107
F2FEdge::_address
std::string _address
Definition: functional_node.h:174
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::outputs_t
std::tuple< OUTPUT_TYPES ... > outputs_t
Definition: functional_node.h:203
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::boundInputPorts
size_t boundInputPorts()
Definition: functional_node.h:472
nrp_logger.h
FunctionalNodeBase::clearEdgeRequests
void clearEdgeRequests()
Definition: functional_node.h:87
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::inputs_t
std::tuple< const INPUT_TYPES *... > inputs_t
Definition: functional_node.h:202
F2FEdge::F2FEdge
F2FEdge(const std::string &keyword, const std::string &address)
Definition: functional_node.h:142
FunctionalNodePolicies::ExecutionPolicy
ExecutionPolicy
Possible execution policies for this node.
Definition: computational_node_policies.h:41
Port
Base class implementing a port in the computational graph.
Definition: port.h:30
FunctionalNodeFactory
Creates an instance of FunctionalNode with the right template given a function signature.
Definition: functional_node_factory.h:47
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::newInputCallback
void newInputCallback(const T *value)
Process incoming new msg.
Definition: functional_node.h:452
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::input_n_t
typename std::tuple_element< N, std::tuple< INPUT_TYPES... > >::type input_n_t
Type of the nth element in INPUT_TYPES parameter pack.
Definition: functional_node.h:196
FunctionalNodeBase::ComputationalGraphPythonNodes_F2F_EDGES_Test
friend class ComputationalGraphPythonNodes_F2F_EDGES_Test
Definition: functional_node.h:90
Port::id
const std::string & id()
Returns the port 'id'.
Definition: port.h:47
FunctionalNodeBase::FunctionalNodeBase
FunctionalNodeBase(const std::string &id)
Definition: functional_node.h:45
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::FunctionalNode
FunctionalNode(const std::string &id, std::function< bool(params_t &)> f, FunctionalNodePolicies::ExecutionPolicy policy=FunctionalNodePolicies::ExecutionPolicy::ON_NEW_INPUT)
Constructor.
Definition: functional_node.h:430
FunctionalNodeBase::getInputById
virtual Port * getInputById(const std::string &)
Returns an InputPort by id.
Definition: functional_node.h:52
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::boundOutputPorts
size_t boundOutputPorts()
Definition: functional_node.h:482
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::getInputByIndex
Port * getInputByIndex(size_t idx)
Returns an InputPort by index.
Definition: functional_node.h:250
python_grpc_engine.type
type
Definition: python_grpc_engine.py:63
F2FEdge
Helper class used to implement a F2FEdge Python decorator.
Definition: functional_node.h:139
FunctionalNode
Definition: functional_node.h:179
FunctionalNodeBase::graphLoadedCB
void graphLoadedCB() override
Function called by the Computational Graph to nodes that the graph has been completely loaded.
Definition: functional_node.h:78
ComputationalNode::id
const std::string & id() const
Returns the node 'id'.
Definition: computational_node.h:57
NRPLogger::info
static void info(const FormatString &fmt, const Args &...args)
NRP logging function with message formatting for info level.
Definition: nrp_logger.h:138
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::getOutputByIdTuple
Port * getOutputByIdTuple(const std::string &id)
Definition: functional_node.h:332
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::createEdgeTuple
void createEdgeTuple(const std::string &port_id, Port *out_port)
Definition: functional_node.h:357
FunctionalNodeBase::configure
void configure() override
Configures the node making it ready to execute 'compute'.
Definition: functional_node.h:61
FunctionalNodeBase::getOutputById
virtual Port * getOutputById(const std::string &)
Returns an OutputPort by id.
Definition: functional_node.h:57
FunctionalNodeBase
Non-abstract, non-templated base class for the FunctionalNode class.
Definition: functional_node.h:42
ComputationalGraphManager::getInstance
static ComputationalGraphManager & getInstance()
Get singleton instance of ComputationalGraphManager.
Definition: computational_graph_manager.cpp:31
FunctionalNodePolicies::ON_NEW_INPUT
@ ON_NEW_INPUT
Definition: computational_node_policies.h:43
computational_node.h
ComputationalGraphManager::getNode
ComputationalNode * getNode(const std::string &id)
Retrieve a node from the graph as a pointer.
Definition: computational_graph_manager.h:95
ComputationalNode::parseNodeAddress
static std::pair< std::string, std::string > parseNodeAddress(const std::string &address, bool hasPort=true)
Parses a computational node address returning the node id and the port (if any) contained in the addr...
Definition: computational_node.h:106
FunctionalNodeBase::createEdge
virtual void createEdge(const std::string &, Port *)
Create an edge in the graph between this node 'port_id' input port and o_port.
Definition: functional_node.h:84
computational_graph_manager.h
computational_node_policies.h
FunctionalNodePolicies::ALWAYS
@ ALWAYS
Definition: computational_node_policies.h:42
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::configure
void configure() override
Configure. Print warnings if node is not fully connected.
Definition: functional_node.h:395
output_port.h
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::_function
std::function< bool(params_t &)> _function
function performing main computation in this node. It sets the output part of _params from its input ...
Definition: functional_node.h:495
NRPException::logCreate
static EXCEPTION logCreate(LOG_EXCEPTION_T &exception, const std::string &msg, NRPLogger::spdlog_out_fcn_t spdlogCall=NRPLogger::critical)
Definition: nrp_exceptions.h:73
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::createEdge
void createEdge(const std::string &port_id, Port *out_port) override
Create an edge in the graph between this node 'port_id' input port and o_port.
Definition: functional_node.h:353
F2FEdge::pySetup
boost::python::object pySetup(const boost::python::object &obj)
call function in the decorator
Definition: functional_node.h:152
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::params_t
decltype(std::tuple_cat(std::declval< inputs_t >(), std::declval< outputs_t >())) params_t
Type representing the argument of _function.
Definition: functional_node.h:209
OutputPort
Implementation of an output port in the computation graph.
Definition: output_port.h:36
FunctionalNodeBase::registerF2FEdge
void registerF2FEdge(const std::string &i_port, const std::string &address)
Request the registration of an edge between an output port in another functional node an i_port input...
Definition: functional_node.h:73
ComputationalNode::Functional
@ Functional
Definition: computational_node.h:38
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::compute
void compute() override final
Compute. Execute '_function' and send its outputs out.
Definition: functional_node.h:416
InputPort
Implementation of an input port in the computation graph.
Definition: input_port.h:42
python_json_engine.port
port
Definition: python_json_engine.py:197
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::getOutputByIndex
Port * getOutputByIndex()
Returns an OutputPort by index.
Definition: functional_node.h:313
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::getInputById
Port * getInputById(const std::string &id) override
Returns an InputPort by id.
Definition: functional_node.h:265
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::initInputs
void initInputs()
Init all inputs to a nullptr.
Definition: functional_node.h:440
FunctionalNodeBase::compute
void compute() override
Requests the node to execute its computation.
Definition: functional_node.h:62
F2FEdge::_keyword
std::string _keyword
Definition: functional_node.h:173
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::_params
params_t _params
function performing main computation in this node
Definition: functional_node.h:493
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::sendOutputs
void sendOutputs()
Sends all outputs through connected to ports.
Definition: functional_node.h:462
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::registerOutput
OutputPort< T > * registerOutput(const std::string &id)
Creates an OutputPort and connect it to an output specified by N. Returns the created port.
Definition: functional_node.h:282
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::output_n_t
typename std::tuple_element< N, std::tuple< OUTPUT_TYPES... > >::type output_n_t
Type of the nth element in OUTPUT_TYPES parameter pack.
Definition: functional_node.h:200
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::getOutputById
Port * getOutputById(const std::string &id) override
Returns an OutputPort by id.
Definition: functional_node.h:328
ComputationalNode
Base class implementing a node in the computational graph.
Definition: computational_node.h:31
input_port.h
FunctionalNode< std::tuple< INPUT_TYPES... >, std::tuple< OUTPUT_TYPES... > >::registerInput
InputPort< T_IN, T_OUT > * registerInput(const std::string &id)
Creates an InputPort and connect it to an input specified by N. Returns the created port.
Definition: functional_node.h:218