diff --git a/include/aidge/graph/Node.hpp b/include/aidge/graph/Node.hpp index 51cc9c444edf03febf4416149e9160df0bbfca9c..e438c67401d0644a141a57b6abe18ad11f76578b 100644 --- a/include/aidge/graph/Node.hpp +++ b/include/aidge/graph/Node.hpp @@ -41,6 +41,16 @@ class GraphView; /** * @brief Object carrying the topological information of the computational graph. + * A Node contains : + * - mName: the name of the Node, should be unique + * - mViews: a set of pointers to GraphView instances including this Node instance + * - mOperator: a pointer to the Operator associated to the node + * - mParents: a vector of parent nodes, which are its inputs + * - mIdOutParents: a vector of indexes, which tells for all the parent nodes from which of their output we take the value + * - mChildren: a vector of vector of children nodes, which lists all the recipient nodes, for all of the outputs + * - mIdInChildren: a vector of vector of indexes, which gives for all the recipient nodes in which of their input the current value is taken + * - mForward: queue of forward propagation function + * - mBackward: queue of backward propagation function */ class Node : public std::enable_shared_from_this<Node> { private: @@ -68,11 +78,13 @@ private: std::deque<std::function<bool()>> mBackward; public: +#ifndef DOXYGEN_SHOULD_SKIP_THIS Node() = delete; +#endif /* DOXYGEN_SHOULD_SKIP_THIS */ /** - * @brief Construct a new Node object associated with the input Operator. - * @param op Operator giving the Node its number of connections. + * @brief Construct a new Node object associated with the inputted Operator. + * @param op The Operator of the Node, it determines its number of connections. * @param attrs Attributes for the Node. */ Node(std::shared_ptr<Operator> op, std::shared_ptr<DynamicAttributes> attrs); @@ -80,7 +92,7 @@ public: /** * @brief Construct a new Node object associated with the input Operator. - * @param op Operator giving the Node its number of connections. + * @param op The Operator of the Node, it determines its number of connections. * @param name (optional) name for the Node. */ Node(std::shared_ptr<Operator> op, const std::string& name = ""); @@ -115,6 +127,7 @@ public: /** * @brief Functional operator for user-friendly connection interface using an ordered set of Connectors. * @param ctors Ordered Connectors linking their associated Node to the input of the current Node with the same index. + * @warning length of ctors must be lower than the number of input of the Node * @return Connector */ Connector operator()(const std::vector<Connector> &ctors); @@ -135,7 +148,7 @@ public: /** * @brief Set the Node name. - * @warning Undefined behaviour when several Nodes have the same name. + * @warning Undefined behaviour when several Nodes have the same name, use createUniqueName to avoid complications. * @param name New name for the node. */ void setName(const std::string &name); @@ -143,16 +156,16 @@ public: /** * @brief Given the parameter name generate a new name which is unique * in all the GraphView which contains this node. - * To generate the new name the method is called recursively and append - * the caracter ``_``. - * If no duplicate return name, this is the exit condition. + * @details if the inputted name is not yet used, it will be used as is + * if it is used, the returned name will be "name_X" + * name being the inputted name and X the smaller integer allowing name uniqueness * @param name Base name to make unique. * @return A unique name in all the GraphView which contains this one. */ std::string createUniqueName(std::string name); /** - * @brief Type of the node. + * @brief Type of the Node's operator. * @return std::string */ inline std::string type() const { return mOperator->type(); } @@ -185,22 +198,22 @@ public: /** * @brief Whether or not every input of the Node is linked to a Parent. * If true then the Node is ready to be executed. - * @return true - * @return false + * @return bool */ bool valid() const; /** - * @brief List of pair <Parent, ID of the data intput>. When an input is not - * linked to any Parent, the pair is <nullptr, gk_IODefaultIndex>. + * @brief List the pairs <Parent, ID of the data intput> of the Node's inputs. + * @details When an input is not linked to any Parent, the pair is <nullptr, gk_IODefaultIndex>. * Data inputs exclude inputs expecting parameters (weights or bias). * @return std::vector<std::pair<std::shared_ptr<Node>, IOIndex_t>> */ std::vector<std::pair<NodePtr, IOIndex_t>> dataInputs() const; /** - * @brief List of pair <Parent, ID of the parent output>. When an input is not linked - * to any Parent, the pair is <nullptr, gk_IODefaultIndex>. + * @brief List the pairs <Parent, ID of the in put> of the Node's inputs. + * @details When an input is not linked to any Parent, the pair is <nullptr, gk_IODefaultIndex>. + * as opposed to dataInputs, inputs includes inputs expecting parameters (weights or biases) * @return std::vector<std::pair<std::shared_ptr<Node>, IOIndex_t>> */ std::vector<std::pair<NodePtr, IOIndex_t>> inputs() const; @@ -208,7 +221,7 @@ public: /** * @brief Parent and its output Tensor ID linked to the inID-th input Tensor. * If the input is not linked to any Parent, the pair is <nullptr, gk_IODefaultIndex>. - * @param inID + * @param inID : the ID of the input that we want to know its parent * @return std::pair<std::shared_ptr<Node>, IOIndex_t> */ inline std::pair<NodePtr, IOIndex_t> input(const IOIndex_t inID) const { @@ -219,7 +232,7 @@ public: /** * @brief Get the lowest index in the InputData Parent list equal to the - * nullptr. + * nullptr (i.e. the ID of the first free data input). * Data inputs exclude inputs expecting parameters (weights or bias). * @return std::size_t */ @@ -235,22 +248,27 @@ public: return (i < nbInputs()) ? i : gk_IODefaultIndex; } - + /** + * @brief Returns the number of free data inputs of the Node + * (i.e. data inputs that are not linked to an other node) + * @warning Node cannot run until all of its inputs are filled" + * @return IOIndex_t + */ IOIndex_t getNbFreeDataInputs() const; /** - * @brief List input ids of children linked to outputs of the node. The vector - * size is garanteed to match the number of outputs of the node. If there is - * no connection to a given output, the corresponding sub-vector will be empty. + * @brief Lists Nodes and input ids of children linked to each of the outputs of the node. + * @details Primary vector size matches the number of outputs of the node as each sub-vector + * will contain the children taking from a different output + * If there is no connection to a given output, the corresponding sub-vector will be empty. * @return std::vector<std::vector<std::pair<std::shared_ptr<Node>, * IOIndex_t>>> */ std::vector<std::vector<std::pair<NodePtr, IOIndex_t>>> outputs() const; /** - * @brief Children and their input Tensor ID linked to the outId-th output - * Tensor. - * @param outId + * @brief Lists Nodes and input ids of children linked to specified output of the Node + * @param outId ID of the output from which we want to know the children * @return std::vector<std::pair<std::shared_ptr<Node>, IOIndex_t>> */ std::vector<std::pair<NodePtr, IOIndex_t>> @@ -258,7 +276,7 @@ public: /** * @brief Number of inputs, including both data and learnable parameters. - * @details [data, data, weight, bias] => 4 + * @details ex: [data, data, weight, bias] => 4 * @return IOIndex_t */ inline IOIndex_t nbInputs() const noexcept { return getOperator()->nbInputs(); } @@ -266,6 +284,7 @@ public: /** * @brief Category of a specific input (Data or Param, optional or not). * Data inputs exclude inputs expecting parameters (weights or bias). + * @details ex: [data, data, weight, bias] => 2 * @return InputCategory */ inline InputCategory inputCategory(IOIndex_t idx) const { @@ -274,8 +293,8 @@ public: /** * @brief Returns whether the given node parent index is a back edge - * A back edge is defined by the operator and node parent index - * correspond to operator input index. + * A back edge is a Node's input coming from the output of a Node later later in the GraphView + * @details the information is stored and taken from the Operator object of the Node * @return true if the operator defines it as a back edge */ inline bool parentIsBackEdge(IOIndex_t idx) const { @@ -284,6 +303,7 @@ public: /** * @brief Number of inputs linked to a Parent's output. + * @warning Inputs that are not linked will prevent the node from functioning * @return IOIndex_t */ IOIndex_t nbValidInputs() const; @@ -323,6 +343,12 @@ public: mViews.insert(std::weak_ptr<GraphView>(graphPtr)); } + /** + * @brief Remove the reference of this Node to the GraphView passed as argument. + * @warning This function does not remove the reference of the GraphView to the Node. + * As such, this function is used in other function and should be not used as is by an user + * @param graphPtr Pointer to GraphView to remove from the list. + */ inline void removeView(const std::shared_ptr<GraphView> &graphPtr) { mViews.erase(graphPtr); } @@ -333,7 +359,7 @@ public: * @param outId ID of the current Node output to connect to the other Node. * Default to 0. * @param otherInId ID of the other Node input to connect to the current Node. - * Default to the first avaible data input. + * Default to the first available data input. */ void addChild(NodePtr otherNode, const IOIndex_t outId = IOIndex_t(0), @@ -356,8 +382,9 @@ public: std::pair<NodePtr, IOIndex_t>(nullptr, gk_IODefaultIndex)); /** - * @brief Get the list of parent Nodes. As an input is linked to a unique Node, - * if none is linked then the parent is a nullptr. + * @brief Get the list of parent Nodes. + * Each input can only be linked to one Node. + * If an input has no linked node, the associated parent is nullptr * @return std::vector<std::shared_ptr<Node>> */ std::vector<NodePtr> getParents() const; @@ -380,16 +407,28 @@ public: */ NodePtr popParent(const IOIndex_t inId); + /** + * @brief unlinks the parent from the Node and replaces it with nullptr (for coherence with remaining parents) + * @param inId Input index of the parent to be removed + * @return std::bool true if parent has been removed. + */ bool removeParent(const IOIndex_t inId); /** * @brief Get the set of pointers to children Nodes linked to the current Node.object. * @details The returned set does not include any nullptr as an output maybe linked to - * an undifined number of Nodes. It does not change the computation of its associated Operator. + * an undefined number of Nodes. It does not change the computation of its associated Operator. * @return std::set<std::shared_ptr<Node>>> */ std::set<NodePtr> getChildren() const; +/** + * @brief Get all sets of children of the node + * @details Each output of the Node have a set of children (might be empty) + * Those sets are ordered in a set of set of children + * + * @returns std::vector<std::vector<std::shared_ptr<Node>>> + */ std::vector<std::vector<NodePtr>> getOrderedChildren() const; /** @@ -401,7 +440,7 @@ public: /** * @brief Remove registered child from children list of specified output if possible. - * If so, also remove current Node from child Node from parent. + * If so, also remove current Node from child's parent. * @param std::shared_ptr<Node> Node to remove. * @param outId Output index. Default 0. * @return true Child found and removed for given output index. @@ -466,14 +505,21 @@ public: /** * @brief Get the set of pointers to connected node at a distance of a delta. - * @details the recution are cut - * Return a nullptr is nofing found. - * @param delta Input delta. - * @return std::shared_ptr<Node> + * @details positive value are toward children, negative toward parents (ex: -2 would give grandparents) + * Return a nullptr is nothing found. + * @param int delta Input delta. + * @param std::set<Aidge::NodePtr> nodeSee is used in the recursion to avoid looping on the same nodes, + * should be empty when calling the method + * @return std::set<Aidge::NodePtr> set of nodes within expected distance from the original node */ - std::set<NodePtr> getNodeDelta(int delta,std::set<Aidge::NodePtr> nodeSee); +/** + * @brief Makes an object taking all relevant info of the node into some string. + * being in a string would allow these information to be easily shown. + * As it shows the node's connection it is a tool for comprehension or debugging of the Node and graph. + * thanks to pybind, this object should be accessible in python. + */ #ifdef PYBIND std::string repr() const { std::string nodeString{fmt::format("Node(name='{}', optype='{}'", name(), type())}; @@ -510,8 +556,8 @@ private: /** * @brief Set the idInChildren parameter. - * @param inID - * @param newNodeOutID + * @param IOIndex_t inID + * @param IOIndex_t newNodeOutID */ void setInputId(const IOIndex_t inID, const IOIndex_t newNodeOutID); diff --git a/python_binding/graph/pybind_Node.cpp b/python_binding/graph/pybind_Node.cpp index 35f6327444a874d8f5c2e94da6520244e095263a..7993282fbe072e85513b96aeaa6766e26afe1c18 100644 --- a/python_binding/graph/pybind_Node.cpp +++ b/python_binding/graph/pybind_Node.cpp @@ -28,7 +28,10 @@ void init_Node(py::module& m) { R"mydelimiter( Name of the Node. )mydelimiter") - .def("clone", (NodePtr (Node::*)() const) &Node::clone) + .def("clone", (NodePtr (Node::*)() const) &Node::clone, + R"mydelimiter( + Clone the Node and its Operator. The new Node has no connection. + )mydelimiter") .def("type", &Node::type, R"mydelimiter( Type of the node. @@ -72,7 +75,7 @@ void init_Node(py::module& m) { R"mydelimiter( Link another Node to an output of the current Node. - :param other_node: Pointer to the other Node. + :param other_node: Pointer to the other Node that will be given as a child to the current Node :type other_node: :py:class: Node :param out_id: ID of the output of the current Node to connect to the other Node. (If Node has 1 output max ID is 0). Default to 0. :type out_id: int @@ -144,7 +147,7 @@ void init_Node(py::module& m) { .def("get_nb_inputs", &Node::nbInputs, R"mydelimiter( - Number of inputs. + Number of inputs of the Node. :rtype: int )mydelimiter") @@ -159,21 +162,26 @@ void init_Node(py::module& m) { .def("get_nb_outputs", &Node::nbOutputs, R"mydelimiter( - Number of outputs. + Number of outputs of the Node. :rtype: int )mydelimiter") - .def("get_parent", &Node::getParent, py::arg("in_id")) - - .def("get_parents", &Node::getParents, + .def("get_parent", &Node::getParent, py::arg("in_id"), R"mydelimiter( - Get parents. + Get the pointer to parent of the specified input index. + This pointer is nullptr if no parent is linked to that input. + )mydelimiter") + + .def("get_parents", &Node::getParents,R"mydelimiter( + Get the list of parent Nodes. + Each input can only be linked to one Node. + If an input has no linked node, the associated parent is nullptr )mydelimiter") .def("get_children", (std::set<std::shared_ptr<Node>> (Node::*)() const) &Node::getChildren, R"mydelimiter( - Get children. + Returns a set of all children of the Node )mydelimiter") .def("__call__",