/brief Class implementing a computation graph
In the context of nrp-core a computation graph is defined as a directed, acyclic property graph in which nodes are associated to objects of type ComputationalNode and which implements a 'compute' method. Nodes use Ports to communicate with each other. Nodes are uniquely identified in the graph by an 'id' attribute which is of type string. Edges in the graph represent connections between nodes, ie. between ports in the source and target nodes.
Nodes can be of three types: 'Input', 'Output' and 'Functional'. 'Input' nodes can only be source nodes in edges. 'Output' nodes can only be target nodes in edges. 'Functional' nodes can be both source and target.
The graph itself implements a 'compute' function which calls 'compute' on all the nodes in the graph in the right order. The latter is defined as follows: within a graph 'compute' operation, a node must always be executed after all the source nodes in edges for which the former is target.
The former definition on the execution order allows to divide the graph in layers which must be executed sequentially. Nodes in each layer can be executed in parallel.
The first layer will always be composed of nodes which have no inputs. These include 'Input' nodes and 'Functional' with no inputs. For convenience, the latter are moved to the second layer (with no consequences) and the first layer is kept with 'Input' nodes only. In the same way, all 'Output' nodes are moved to a separate layer which is executed the last.