From 621ad7ab14db5c107193705a7bf7d6417bd3b4f6 Mon Sep 17 00:00:00 2001
From: Charles Villard <charles.villard@cea.fr>
Date: Thu, 17 Oct 2024 11:47:31 +0200
Subject: [PATCH 1/6] edit: Node: fix optional inputs in node treated as input
 graph

---
 include/aidge/graph/Node.hpp |  4 ++--
 src/graph/Node.cpp           | 15 ++++++++++++---
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/include/aidge/graph/Node.hpp b/include/aidge/graph/Node.hpp
index 7319db245..d2357548e 100644
--- a/include/aidge/graph/Node.hpp
+++ b/include/aidge/graph/Node.hpp
@@ -286,10 +286,10 @@ public:
       if ((inputCategory(i) == InputCategory::Data || inputCategory(i) == InputCategory::OptionalData)
         && input(i).second == gk_IODefaultIndex)
       {
-        break;
+        return i;
       }
     }
-    return (i < nbInputs()) ? i : gk_IODefaultIndex;
+    return gk_IODefaultIndex;
   }
 
   /**
diff --git a/src/graph/Node.cpp b/src/graph/Node.cpp
index 74e0cab37..19eaa6d14 100644
--- a/src/graph/Node.cpp
+++ b/src/graph/Node.cpp
@@ -147,7 +147,9 @@ bool Aidge::Node::valid() const {
 Aidge::IOIndex_t Aidge::Node::getNbFreeDataInputs() const {
     IOIndex_t nbFreeDataIn = 0;
     for (IOIndex_t i = 0; i < nbInputs(); ++i) {
-        if (input(i).second == gk_IODefaultIndex) {
+        if ((inputCategory(i) == InputCategory::Data
+             || inputCategory(i) == InputCategory::OptionalData)
+            && input(i).second == gk_IODefaultIndex) {
             ++nbFreeDataIn;
         }
     }
@@ -389,10 +391,17 @@ void Aidge::Node::addChild(const std::shared_ptr<Node>& otherNode, const IOIndex
 void Aidge::Node::addChild(std::shared_ptr<GraphView> otherView, const IOIndex_t outId,
                            std::pair<std::shared_ptr<Node>, IOIndex_t> otherInId) {
     if (!otherInId.first) {
-        AIDGE_ASSERT(otherView->inputNodes().size() == 1U,
+        AIDGE_ASSERT(otherView->getNbFreeDataInputs() == 1U,
             "Input node of GraphView {} need to be specified, because it has more than one input ({} inputs), when trying to add it as a child of node {} (of type {})",
             otherView->name(), otherView->inputNodes().size(), name(), type());
-        otherInId.first = *(otherView->inputNodes().begin());
+
+        otherInId.first = *(std::find_if(
+            otherView->inputNodes().begin(),
+            otherView->inputNodes().end(),
+            [](const auto &node) {
+                return node->getFirstFreeDataInput() != gk_IODefaultIndex;
+            }
+        ));
     }
     otherInId.second = (otherInId.second != gk_IODefaultIndex)
                                ? otherInId.second
-- 
GitLab


From 990eed919a89a937557610b80cd5084231e16a50 Mon Sep 17 00:00:00 2001
From: Charles Villard <charles.villard@cea.fr>
Date: Thu, 23 Jan 2025 16:24:39 +0100
Subject: [PATCH 2/6] WIP: filter input with bitwise category

---
 include/aidge/graph/GraphView.hpp    |  2 +-
 include/aidge/operator/Operator.hpp  | 17 ++++--
 include/aidge/utils/BitwiseUtils.hpp | 87 ++++++++++++++++++++++++++++
 src/graph/GraphView.cpp              |  4 +-
 4 files changed, 102 insertions(+), 8 deletions(-)
 create mode 100644 include/aidge/utils/BitwiseUtils.hpp

diff --git a/include/aidge/graph/GraphView.hpp b/include/aidge/graph/GraphView.hpp
index 081c429e8..507d34f15 100644
--- a/include/aidge/graph/GraphView.hpp
+++ b/include/aidge/graph/GraphView.hpp
@@ -136,7 +136,7 @@ public:
 ///////////////////////////////////////////////////////
 public:
     /** @brief Get reference to the set of input Nodes. */
-    std::set<NodePtr> inputNodes() const;
+    std::set<NodePtr> inputNodes(InputCategory filter = InputCategory::All) const;
 
     /** @brief Get reference to the set of output Nodes. */
     std::set<NodePtr> outputNodes() const;
diff --git a/include/aidge/operator/Operator.hpp b/include/aidge/operator/Operator.hpp
index 0392dcfa2..35432faf2 100644
--- a/include/aidge/operator/Operator.hpp
+++ b/include/aidge/operator/Operator.hpp
@@ -17,6 +17,8 @@
 #include <string>
 #include <vector>
 #include <utility>
+#include <type_traits>
+#include <cstddef>
 
 #ifdef PYBIND
 #include <pybind11/pybind11.h>
@@ -27,6 +29,7 @@
 #include "aidge/data/Data.hpp"
 #include "aidge/utils/Attributes.hpp"
 #include "aidge/utils/Types.h"
+#include "aidge/utils/BitwiseUtils.hpp"
 
 #ifdef PYBIND
 namespace py = pybind11;
@@ -56,12 +59,16 @@ enum class OperatorType {
  * @enum InputCategory
  * @brief Describes the category of an input for an operator.
  */
-enum class InputCategory {
-    Data,          /**< Regular data input. */
-    Param,         /**< Parameter input. */
-    OptionalData,  /**< Optional data input. */
-    OptionalParam  /**< Optional parameter input. */
+enum class InputCategory : unsigned int {
+    Optional = 1 << 0, // First bit indicate if optional
+    Data = 1 << 1, /**< Regular data input. */
+    OptionalData = (1 << 1) | Optional, /**< Optional data input. */
+    Param = 1 << 2,  /**< Parameter input. */
+    OptionalParam = (1 << 2) | Optional, /**< Optional parameter input. */
+    All = static_cast<unsigned int>(-1)
 };
+template <>
+constexpr bool enable_bitmask_operators<InputCategory> = true;
 
 /**
  * @class Operator
diff --git a/include/aidge/utils/BitwiseUtils.hpp b/include/aidge/utils/BitwiseUtils.hpp
new file mode 100644
index 000000000..208115fa1
--- /dev/null
+++ b/include/aidge/utils/BitwiseUtils.hpp
@@ -0,0 +1,87 @@
+/********************************************************************************
+ * Copyright (c) 2024 CEA-List
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * http://www.eclipse.org/legal/epl-2.0.
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ ********************************************************************************/
+#ifndef AIDGE_BITWISEUTILS_H_
+#define AIDGE_BITWISEUTILS_H_
+
+#include <type_traits>
+
+namespace Aidge
+{
+
+// Define a trait to enable bitwise operators for an enum class
+template <typename E>
+constexpr bool enable_bitmask_operators = false;
+
+// Define bitwise OR
+template <typename E>
+constexpr typename std::enable_if_t<enable_bitmask_operators<E>, E>
+operator|(E lhs, E rhs) {
+    using underlying = typename std::underlying_type_t<E>;
+    return static_cast<E>(static_cast<underlying>(lhs) | static_cast<underlying>(rhs));
+}
+
+// Define bitwise AND
+template <typename E>
+constexpr typename std::enable_if_t<enable_bitmask_operators<E>, E>
+operator&(E lhs, E rhs) {
+    using underlying = typename std::underlying_type_t<E>;
+    return static_cast<E>(static_cast<underlying>(lhs) & static_cast<underlying>(rhs));
+}
+
+// Define bitwise XOR
+template <typename E>
+constexpr typename std::enable_if_t<enable_bitmask_operators<E>, E>
+operator^(E lhs, E rhs) {
+    using underlying = typename std::underlying_type_t<E>;
+    return static_cast<E>(static_cast<underlying>(lhs) ^ static_cast<underlying>(rhs));
+}
+
+// Define bitwise NOT
+template <typename E>
+constexpr typename std::enable_if_t<enable_bitmask_operators<E>, E>
+operator~(E value) {
+    using underlying = typename std::underlying_type_t<E>;
+    return static_cast<E>(~static_cast<underlying>(value));
+}
+
+// Define compound OR assignment
+template <typename E>
+constexpr typename std::enable_if_t<enable_bitmask_operators<E>, E&>
+operator|=(E& lhs, E rhs) {
+    lhs = lhs | rhs;
+    return lhs;
+}
+
+// Define compound AND assignment
+template <typename E>
+constexpr typename std::enable_if_t<enable_bitmask_operators<E>, E&>
+operator&=(E& lhs, E rhs) {
+    lhs = lhs & rhs;
+    return lhs;
+}
+
+// Define compound XOR assignment
+template <typename E>
+constexpr typename std::enable_if_t<enable_bitmask_operators<E>, E&>
+operator^=(E& lhs, E rhs) {
+    lhs = lhs ^ rhs;
+    return lhs;
+}
+
+template <typename E>
+constexpr auto to_underlying(E e) noexcept
+{
+    return static_cast<std::underlying_type_t<E>>(e);
+}
+
+} // namespace Aidge
+
+#endif //
diff --git a/src/graph/GraphView.cpp b/src/graph/GraphView.cpp
index c45bacf46..9d6557054 100644
--- a/src/graph/GraphView.cpp
+++ b/src/graph/GraphView.cpp
@@ -299,11 +299,11 @@ void Aidge::GraphView::setRootNode(NodePtr node) {
 //        TENSOR MANAGEMENT
 ///////////////////////////////////////////////////////
 
-std::set<std::shared_ptr<Aidge::Node>> Aidge::GraphView::inputNodes() const {
+std::set<std::shared_ptr<Aidge::Node>> Aidge::GraphView::inputNodes(InputCategory filter) const {
     std::set<std::shared_ptr<Aidge::Node>> nodes;
     for (const auto& node : mInputNodes) {
         // Do not include dummy inputs
-        if (node.first) {
+        if (node.first && to_underlying(node.first->inputCategory(node.second) & filter)) {
             nodes.insert(node.first);
         }
     }
-- 
GitLab


From 12f38762985153309c772cb3b076adf6844babb6 Mon Sep 17 00:00:00 2001
From: Charles Villard <charles.villard@cea.fr>
Date: Thu, 30 Jan 2025 17:24:39 +0100
Subject: [PATCH 3/6] add: pybind: add filter using bitwise enum

---
 python_binding/graph/pybind_GraphView.cpp   |  1 +
 python_binding/operator/pybind_Operator.cpp | 12 +++++++-----
 python_binding/pybind_core.cpp              | 12 ++++++------
 3 files changed, 14 insertions(+), 11 deletions(-)

diff --git a/python_binding/graph/pybind_GraphView.cpp b/python_binding/graph/pybind_GraphView.cpp
index d1b99c305..4abb07fac 100644
--- a/python_binding/graph/pybind_GraphView.cpp
+++ b/python_binding/graph/pybind_GraphView.cpp
@@ -50,6 +50,7 @@ void init_GraphView(py::module& m) {
           )mydelimiter")
 
           .def("get_input_nodes", &GraphView::inputNodes,
+          py::arg("filter") = Aidge::InputCategory::All,
           R"mydelimiter(
           Get set of input Nodes.
 
diff --git a/python_binding/operator/pybind_Operator.cpp b/python_binding/operator/pybind_Operator.cpp
index 18708adee..94b41f691 100644
--- a/python_binding/operator/pybind_Operator.cpp
+++ b/python_binding/operator/pybind_Operator.cpp
@@ -28,11 +28,13 @@ void init_Operator(py::module& m){
         .value("Data", OperatorType::Data)
         .value("Tensor", OperatorType::Tensor);
 
-    py::enum_<InputCategory>(m, "InputCategory")
-        .value("Data", InputCategory::Data)
-        .value("Param", InputCategory::Param)
-        .value("OptionalData", InputCategory::OptionalData)
-        .value("OptionalParam", InputCategory::OptionalParam);
+    py::enum_<Aidge::InputCategory>(m, "InputCategory", py::arithmetic())
+        .value("Optional", Aidge::InputCategory::Optional)
+        .value("Data", Aidge::InputCategory::Data)
+        .value("OptionalData", Aidge::InputCategory::OptionalData)
+        .value("Param", Aidge::InputCategory::Param)
+        .value("OptionalParam", Aidge::InputCategory::OptionalParam)
+        .value("All", Aidge::InputCategory::All);
 
     py::class_<Operator, std::shared_ptr<Operator>>(m, "Operator")
     .def("__repr__", &Operator::repr)
diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp
index 61a0a271c..ea738ccea 100644
--- a/python_binding/pybind_core.cpp
+++ b/python_binding/pybind_core.cpp
@@ -135,12 +135,6 @@ void init_Aidge(py::module& m) {
     init_Attributes(m);
     init_Spikegen(m);
 
-    init_Node(m);
-    init_GraphView(m);
-    init_OpArgs(m);
-    init_Connector(m);
-    init_SinglePassGraphMatching(m);
-
     init_OperatorImpl(m);
     init_Log(m);
     init_Operator(m);
@@ -149,6 +143,12 @@ void init_Aidge(py::module& m) {
     init_StaticAnalysis(m);
     init_DynamicAnalysis(m);
 
+    init_Node(m);
+    init_GraphView(m);
+    init_OpArgs(m);
+    init_Connector(m);
+    init_SinglePassGraphMatching(m);
+
     init_Abs(m);
     init_Add(m);
     init_And(m);
-- 
GitLab


From d564899aebb7bfaa021aaa635c4f5e3153c8f37d Mon Sep 17 00:00:00 2001
From: Charles Villard <charles.villard@cea.fr>
Date: Fri, 14 Feb 2025 07:32:06 +0100
Subject: [PATCH 4/6] edit: Operator: inline bitwise operation

---
 include/aidge/operator/Operator.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/aidge/operator/Operator.hpp b/include/aidge/operator/Operator.hpp
index 35432faf2..61b1407aa 100644
--- a/include/aidge/operator/Operator.hpp
+++ b/include/aidge/operator/Operator.hpp
@@ -68,7 +68,7 @@ enum class InputCategory : unsigned int {
     All = static_cast<unsigned int>(-1)
 };
 template <>
-constexpr bool enable_bitmask_operators<InputCategory> = true;
+inline constexpr bool enable_bitmask_operators<InputCategory> = true;
 
 /**
  * @class Operator
-- 
GitLab


From da1f66657b246710443176e1678090dd82a27f18 Mon Sep 17 00:00:00 2001
From: Charles Villard <charles.villard@cea.fr>
Date: Thu, 20 Mar 2025 15:20:28 +0100
Subject: [PATCH 5/6] edit: Operator.hpp: preprocessor check compiler for
 compatibility

---
 include/aidge/operator/Operator.hpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/include/aidge/operator/Operator.hpp b/include/aidge/operator/Operator.hpp
index 61b1407aa..b53c47c18 100644
--- a/include/aidge/operator/Operator.hpp
+++ b/include/aidge/operator/Operator.hpp
@@ -67,8 +67,16 @@ enum class InputCategory : unsigned int {
     OptionalParam = (1 << 2) | Optional, /**< Optional parameter input. */
     All = static_cast<unsigned int>(-1)
 };
+
+
+#ifdef _MSC_VER
+template <>
+constexpr bool enable_bitmask_operators<InputCategory> = true;
+#else
 template <>
 inline constexpr bool enable_bitmask_operators<InputCategory> = true;
+#endif
+
 
 /**
  * @class Operator
-- 
GitLab


From f8378f9526df995edd7d4e25e6812b9823e757b4 Mon Sep 17 00:00:00 2001
From: Charles Villard <charles.villard@cea.fr>
Date: Wed, 26 Mar 2025 14:15:28 +0000
Subject: [PATCH 6/6] Change old data check to new bitwise filter

---
 include/aidge/graph/Node.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/aidge/graph/Node.hpp b/include/aidge/graph/Node.hpp
index d2357548e..c06cf0c8b 100644
--- a/include/aidge/graph/Node.hpp
+++ b/include/aidge/graph/Node.hpp
@@ -283,7 +283,7 @@ public:
   inline IOIndex_t getFirstFreeDataInput() const {
     IOIndex_t i = 0;
     for (; i < nbInputs(); ++i) {
-      if ((inputCategory(i) == InputCategory::Data || inputCategory(i) == InputCategory::OptionalData)
+      if (to_underlying(inputCategory(i) & InputCategory::Data)
         && input(i).second == gk_IODefaultIndex)
       {
         return i;
-- 
GitLab