From 5aa49ccf649778c9ed2846bdda332cb16ba831bf Mon Sep 17 00:00:00 2001
From: Olivier BICHLER <olivier.bichler@cea.fr>
Date: Thu, 28 Sep 2023 16:48:10 +0200
Subject: [PATCH] Unified interface for parameters

---
 include/aidge/aidge.hpp                       |   5 +-
 include/aidge/data/Data.hpp                   |   2 +-
 include/aidge/hook/hook.hpp                   |   2 +-
 include/aidge/operator/AvgPooling.hpp         |  10 +-
 include/aidge/operator/BatchNorm.hpp          |  10 +-
 include/aidge/operator/Conv.hpp               |  10 +-
 include/aidge/operator/ConvDepthWise.hpp      |  10 +-
 include/aidge/operator/FC.hpp                 |  10 +-
 include/aidge/operator/GenericOperator.hpp    |  46 +-
 include/aidge/operator/LeakyReLU.hpp          |  10 +-
 include/aidge/operator/Matmul.hpp             |  10 +-
 include/aidge/operator/MaxPooling.hpp         |  10 +-
 include/aidge/operator/Producer.hpp           |   2 +-
 include/aidge/operator/Scaling.hpp            |  10 +-
 include/aidge/utils/CParameter.hpp            | 106 -----
 include/aidge/utils/DynamicParameters.hpp     | 147 +++++++
 include/aidge/utils/Parameters.hpp            |  59 +++
 .../{Parameter.hpp => StaticParameters.hpp}   | 393 +++++++++---------
 python_binding/operator/pybind_Add.cpp        |   1 -
 python_binding/operator/pybind_AvgPooling.cpp |   3 +-
 python_binding/operator/pybind_BatchNorm.cpp  |   3 +-
 python_binding/operator/pybind_Conv.cpp       |   3 +-
 .../operator/pybind_ConvDepthWise.cpp         |   3 +-
 python_binding/operator/pybind_FC.cpp         |   3 +-
 .../operator/pybind_GenericOperator.cpp       |  41 +-
 python_binding/operator/pybind_LeakyReLU.cpp  |   3 +-
 python_binding/operator/pybind_Matmul.cpp     |   3 +-
 python_binding/operator/pybind_MaxPooling.cpp |   3 +-
 python_binding/operator/pybind_Producer.cpp   |   1 -
 python_binding/pybind_core.cpp                |   4 +-
 python_binding/utils/pybind_Parameter.cpp     |  23 +-
 src/graphmatching/NodeRegex.cpp               |   2 +-
 32 files changed, 486 insertions(+), 462 deletions(-)
 delete mode 100644 include/aidge/utils/CParameter.hpp
 create mode 100644 include/aidge/utils/DynamicParameters.hpp
 create mode 100644 include/aidge/utils/Parameters.hpp
 rename include/aidge/utils/{Parameter.hpp => StaticParameters.hpp} (69%)

diff --git a/include/aidge/aidge.hpp b/include/aidge/aidge.hpp
index cfda3ac7f..0ae6d89ae 100644
--- a/include/aidge/aidge.hpp
+++ b/include/aidge/aidge.hpp
@@ -42,8 +42,9 @@
 #include "aidge/operator/Softmax.hpp"
 #include "aidge/operator/Scaling.hpp"
 #include "aidge/scheduler/Scheduler.hpp"
-#include "aidge/utils/CParameter.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/Parameters.hpp"
+#include "aidge/utils/StaticParameters.hpp"
+#include "aidge/utils/DynamicParameters.hpp"
 #include "aidge/utils/Recipies.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
diff --git a/include/aidge/data/Data.hpp b/include/aidge/data/Data.hpp
index 81b7810a8..652ca1f7c 100644
--- a/include/aidge/data/Data.hpp
+++ b/include/aidge/data/Data.hpp
@@ -12,7 +12,7 @@
 #ifndef AIDGE_DATA_H_
 #define AIDGE_DATA_H_
 
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/Parameters.hpp"
 
 namespace Aidge {
 enum class DataType {
diff --git a/include/aidge/hook/hook.hpp b/include/aidge/hook/hook.hpp
index 0448659b9..661f78e57 100644
--- a/include/aidge/hook/hook.hpp
+++ b/include/aidge/hook/hook.hpp
@@ -17,7 +17,7 @@
 #ifndef Hook_H_
 #define Hook_H_
 
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/Parameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include <memory>
 
diff --git a/include/aidge/operator/AvgPooling.hpp b/include/aidge/operator/AvgPooling.hpp
index bf76bd458..63ac52d54 100644
--- a/include/aidge/operator/AvgPooling.hpp
+++ b/include/aidge/operator/AvgPooling.hpp
@@ -21,7 +21,7 @@
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/operator/Producer.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
 
@@ -31,7 +31,7 @@ enum class AvgPoolingParam { StrideDims, KernelDims, PaddingDims };
 template <DimIdx_t DIM>
 class AvgPooling_Op : public Operator,
                 public Registrable<AvgPooling_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const AvgPooling_Op<DIM> &)>,
-                public Parameterizable<AvgPoolingParam,
+                public StaticParameters<AvgPoolingParam,
                                        std::array<DimSize_t, DIM>,
                                        std::array<DimSize_t, DIM>,
                                        std::array<DimSize_t, (DIM<<1) >> {
@@ -45,18 +45,18 @@ public:
 
     AvgPooling_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<AvgPoolingParam,
+    using Parameters_ = StaticParameters<AvgPoolingParam,
                                              std::array<DimSize_t, DIM>,
                                              std::array<DimSize_t, DIM>,
                                              std::array<DimSize_t, (DIM<<1)> >;
     template <AvgPoolingParam e>
-    using param = typename Parameterizable_::template param<e>;
+    using param = typename Parameters_::template param<e>;
 
     constexpr AvgPooling_Op(const std::array<DimSize_t, DIM> &kernel_dims,
                             const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
                             const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0))
         : Operator(Type),
-          Parameterizable_(param<AvgPoolingParam::StrideDims>(stride_dims),
+          Parameters_(param<AvgPoolingParam::StrideDims>(stride_dims),
                            param<AvgPoolingParam::KernelDims>(kernel_dims),
                            param<AvgPoolingParam::PaddingDims>(padding_dims)),
           mOutput(std::make_shared<Tensor>()) {
diff --git a/include/aidge/operator/BatchNorm.hpp b/include/aidge/operator/BatchNorm.hpp
index 6861c1359..f308cc249 100644
--- a/include/aidge/operator/BatchNorm.hpp
+++ b/include/aidge/operator/BatchNorm.hpp
@@ -21,7 +21,7 @@
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/operator/Producer.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 
 namespace Aidge {
@@ -31,7 +31,7 @@ enum class BatchNormParam { Epsilon, Momentum };
 template <DimIdx_t DIM>
 class BatchNorm_Op : public Operator,
                 public Registrable<BatchNorm_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const BatchNorm_Op<DIM> &)>,
-                public Parameterizable<BatchNormParam, float, float> {
+                public StaticParameters<BatchNormParam, float, float> {
 public:
     // FIXME: change accessibility
     std::array<std::shared_ptr<Tensor>, 5> mInputs = {std::make_shared<Tensor>(), std::make_shared<Tensor>(),
@@ -44,13 +44,13 @@ public:
 
     BatchNorm_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<BatchNormParam, float, float>;
+    using Parameters_ = StaticParameters<BatchNormParam, float, float>;
     template <BatchNormParam e>
-    using param = typename Parameterizable_::template param<e>;
+    using param = typename Parameters_::template param<e>;
 
     constexpr BatchNorm_Op(float epsilon, float momentum)
         : Operator(Type),
-          Parameterizable_(param<BatchNormParam::Epsilon>(epsilon),
+          Parameters_(param<BatchNormParam::Epsilon>(epsilon),
                            param<BatchNormParam::Momentum>(momentum)),
           mOutput(std::make_shared<Tensor>()) {
         setDatatype(DataType::Float32);
diff --git a/include/aidge/operator/Conv.hpp b/include/aidge/operator/Conv.hpp
index 1edc94b96..868bc7af1 100644
--- a/include/aidge/operator/Conv.hpp
+++ b/include/aidge/operator/Conv.hpp
@@ -21,7 +21,7 @@
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/operator/Producer.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
 
@@ -31,7 +31,7 @@ enum class ConvParam { StrideDims, DilationDims, InChannels, OutChannels, Kernel
 template <DimIdx_t DIM>
 class Conv_Op : public Operator,
                 public Registrable<Conv_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const Conv_Op<DIM> &)>,
-                public Parameterizable<ConvParam, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, DimSize_t,
+                public StaticParameters<ConvParam, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>, DimSize_t,
                                        DimSize_t, std::array<DimSize_t, DIM>, std::array<DimSize_t, (DIM<<1) >> {
 public:
     // FIXME: change accessibility
@@ -44,10 +44,10 @@ public:
 
     Conv_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<ConvParam, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>,
+    using Parameters_ = StaticParameters<ConvParam, std::array<DimSize_t, DIM>, std::array<DimSize_t, DIM>,
                                              DimSize_t, DimSize_t, std::array<DimSize_t, DIM>, std::array<DimSize_t, (DIM<<1) >>;
     template <ConvParam e>
-    using param = typename Parameterizable_::template param<e>;
+    using param = typename Parameters_::template param<e>;
 
     constexpr Conv_Op(DimSize_t in_channels,
                       DimSize_t out_channels,
@@ -56,7 +56,7 @@ public:
                       const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0),
                       const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1))
         : Operator(Type),
-          Parameterizable_(param<ConvParam::StrideDims>(stride_dims),
+          Parameters_(param<ConvParam::StrideDims>(stride_dims),
                            param<ConvParam::DilationDims>(dilation_dims),
                            param<ConvParam::InChannels>(in_channels),
                            param<ConvParam::OutChannels>(out_channels),
diff --git a/include/aidge/operator/ConvDepthWise.hpp b/include/aidge/operator/ConvDepthWise.hpp
index 95a2ff55b..ac6580a8e 100644
--- a/include/aidge/operator/ConvDepthWise.hpp
+++ b/include/aidge/operator/ConvDepthWise.hpp
@@ -21,7 +21,7 @@
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/operator/Producer.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
 
@@ -31,7 +31,7 @@ enum class ConvDepthWiseParam { StrideDims, DilationDims, Channels, KernelDims,
 template <DimIdx_t DIM>
 class ConvDepthWise_Op : public Operator,
                 public Registrable<ConvDepthWise_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const ConvDepthWise_Op<DIM> &)>,
-                public Parameterizable<ConvDepthWiseParam,
+                public StaticParameters<ConvDepthWiseParam,
                                        std::array<DimSize_t, DIM>,
                                        std::array<DimSize_t, DIM>,
                                        DimSize_t,
@@ -48,21 +48,21 @@ class ConvDepthWise_Op : public Operator,
 
     ConvDepthWise_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<ConvDepthWiseParam,
+    using Parameters_ = StaticParameters<ConvDepthWiseParam,
                                              std::array<DimSize_t, DIM>,
                                              std::array<DimSize_t, DIM>,
                                              DimSize_t,
                                              std::array<DimSize_t, DIM>,
                                              std::array<DimSize_t, (DIM<<1) >>;
     template <ConvDepthWiseParam e>
-    using param = typename Parameterizable_::template param<e>;
+    using param = typename Parameters_::template param<e>;
 
     constexpr ConvDepthWise_Op(const std::array<DimSize_t, DIM> &kernel_dims,
                                const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
                                const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0),
                                const std::array<DimSize_t, DIM> &dilation_dims = create_array<DimSize_t,DIM>(1))
         : Operator(Type),
-          Parameterizable_(param<ConvDepthWiseParam::StrideDims>(stride_dims),
+          Parameters_(param<ConvDepthWiseParam::StrideDims>(stride_dims),
                            param<ConvDepthWiseParam::DilationDims>(dilation_dims),
                            param<ConvDepthWiseParam::Channels>(0),
                            param<ConvDepthWiseParam::KernelDims>(kernel_dims),
diff --git a/include/aidge/operator/FC.hpp b/include/aidge/operator/FC.hpp
index db92dc9c7..3f36f11d2 100644
--- a/include/aidge/operator/FC.hpp
+++ b/include/aidge/operator/FC.hpp
@@ -23,7 +23,7 @@
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/operator/Producer.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 
 namespace Aidge {
@@ -33,7 +33,7 @@ class FC_Op : public Operator,
               public Registrable<FC_Op,
                                  std::string,
                                  std::unique_ptr<OperatorImpl>(const FC_Op &)>,
-              public Parameterizable<FCParam, DimSize_t, bool> {
+              public StaticParameters<FCParam, DimSize_t, bool> {
 public:
     // FIXME: change accessibility
     std::array<std::shared_ptr<Tensor>, 3> mInputs = {std::make_shared<Tensor>(), std::make_shared<Tensor>(), std::make_shared<Tensor>()};
@@ -44,12 +44,12 @@ public:
 
     FC_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<FCParam, DimSize_t, bool>;
-    template <FCParam e> using param = typename Parameterizable_::template param<e>;
+    using Parameters_ = StaticParameters<FCParam, DimSize_t, bool>;
+    template <FCParam e> using param = typename Parameters_::template param<e>;
 
     FC_Op(DimSize_t out_channels, bool noBias)
             : Operator(Type),
-            Parameterizable_(
+            Parameters_(
                 param<FCParam::OutChannels>(out_channels),
                 param<FCParam::NoBias>(noBias)),
             mOutput(std::make_shared<Tensor>())
diff --git a/include/aidge/operator/GenericOperator.hpp b/include/aidge/operator/GenericOperator.hpp
index 12fb7e167..9561dd12d 100644
--- a/include/aidge/operator/GenericOperator.hpp
+++ b/include/aidge/operator/GenericOperator.hpp
@@ -19,16 +19,16 @@
 
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
-#include "aidge/utils/CParameter.hpp"
+#include "aidge/utils/DynamicParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
 
 namespace Aidge {
 class GenericOperator_Op
     : public Operator,
-      public Registrable<GenericOperator_Op, std::string, std::unique_ptr<OperatorImpl>(std::shared_ptr<GenericOperator_Op>)> {
+      public Registrable<GenericOperator_Op, std::string, std::unique_ptr<OperatorImpl>(std::shared_ptr<GenericOperator_Op>)>,
+      public DynamicParameters {
    private:
-    CParameter mParams;
     IOIndex_t mNbDataIn;
     IOIndex_t mNbIn;
     IOIndex_t mNbOut;
@@ -49,46 +49,6 @@ class GenericOperator_Op
         }
     }
 
-    /**
-     * @brief Get the Parameter object identified by its name.
-     * @tparam T expected parameter type.
-     * @param key Parameter name.
-     * @details assert if T is not the actual parameter type, if the parameter
-     * does not exist or internal parameter position is invalid.
-     * @todo Returning a T const& ? But dangerous => may get an address within
-     * param buffer that will get invalid after the CParam death.
-     * @note at() throws if the parameter does not exist, using find to test
-     * for parameter existance
-     * @return template<class T> The parameter.
-     */
-    template <class T>
-    const T& getParameter(std::string const &key) const {
-        return mParams.Get<const T>(key);
-    }
-
-    template <class T>
-    T& getParameter(std::string const &key) {
-        return mParams.Get<T>(key);
-    }
-
-    ///\brief Add a parameter value, identified by its name
-    ///\tparam T expected parameter type
-    ///\param i_ParamName Parameter name
-    ///\param i_Value Parameter value
-    ///\todo Pass i_Value by ref if large or not trivial
-    ///\bug If parameter already exists, its value is changed but written in the
-    /// internal buffer in a new location (previous value is still in memory at
-    /// its previous location)
-    template <class T>
-    void addParameter(std::string const &key, T&& value) {
-        mParams.Add<T>(key, std::forward<T>(value));
-    }
-
-
-    std::string getParameterType(std::string const &key) { return mParams.getParamType(key); }
-
-    std::vector<std::string> getParametersName() { return mParams.getParametersName(); }
-
     // Override Virtual Opertor methods
     void associateInput(const IOIndex_t /*inputIdx*/, std::shared_ptr<Data> /*data*/) override final {
         printf("Info: using associateInput() on a GenericOperator.\n");
diff --git a/include/aidge/operator/LeakyReLU.hpp b/include/aidge/operator/LeakyReLU.hpp
index 1dff2550a..f9f4c6fd4 100644
--- a/include/aidge/operator/LeakyReLU.hpp
+++ b/include/aidge/operator/LeakyReLU.hpp
@@ -15,7 +15,7 @@
 #include <vector>
 #include <memory>
 
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
@@ -31,7 +31,7 @@ enum class LeakyReLUParam {
 
 class LeakyReLU_Op : public Operator,
     public Registrable<LeakyReLU_Op, std::string, std::unique_ptr<OperatorImpl>(const LeakyReLU_Op&)>,
-    public Parameterizable<LeakyReLUParam, float> {
+    public StaticParameters<LeakyReLUParam, float> {
 public:
     // FIXME: change accessibility
     std::shared_ptr<Tensor> mInput = std::make_shared<Tensor>();
@@ -42,12 +42,12 @@ public:
 
     LeakyReLU_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<LeakyReLUParam, float>;
-    template <LeakyReLUParam e> using param = typename Parameterizable_::template param<e>;
+    using Parameters_ = StaticParameters<LeakyReLUParam, float>;
+    template <LeakyReLUParam e> using param = typename Parameters_::template param<e>;
 
     LeakyReLU_Op(float negativeSlope)
             : Operator(Type),
-            Parameterizable_(
+            Parameters_(
                 param<LeakyReLUParam::NegativeSlope>(negativeSlope))
     {
         setDatatype(DataType::Float32);
diff --git a/include/aidge/operator/Matmul.hpp b/include/aidge/operator/Matmul.hpp
index 639b36691..e768bf7e4 100644
--- a/include/aidge/operator/Matmul.hpp
+++ b/include/aidge/operator/Matmul.hpp
@@ -23,7 +23,7 @@
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/operator/Producer.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 
 namespace Aidge {
@@ -33,7 +33,7 @@ class Matmul_Op : public Operator,
               public Registrable<Matmul_Op,
                                  std::string,
                                  std::unique_ptr<OperatorImpl>(const Matmul_Op &)>,
-              public Parameterizable<MatmulParam, DimSize_t> {
+              public StaticParameters<MatmulParam, DimSize_t> {
 public:
     std::array<std::shared_ptr<Tensor>, 2> mInputs = {std::make_shared<Tensor>(), std::make_shared<Tensor>()};
     const std::shared_ptr<Tensor> mOutput = std::make_shared<Tensor>();
@@ -43,12 +43,12 @@ public:
 
     Matmul_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<MatmulParam, DimSize_t>;
-    template <MatmulParam e> using param = typename Parameterizable_::template param<e>;
+    using Parameters_ = StaticParameters<MatmulParam, DimSize_t>;
+    template <MatmulParam e> using param = typename Parameters_::template param<e>;
 
     Matmul_Op(DimSize_t out_channels)
             : Operator(Type),
-            Parameterizable_(
+            Parameters_(
                 param<MatmulParam::OutChannels>(out_channels)),
             mOutput(std::make_shared<Tensor>())
     {
diff --git a/include/aidge/operator/MaxPooling.hpp b/include/aidge/operator/MaxPooling.hpp
index 073243e80..cf85af9b4 100644
--- a/include/aidge/operator/MaxPooling.hpp
+++ b/include/aidge/operator/MaxPooling.hpp
@@ -21,7 +21,7 @@
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/operator/Producer.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
 
@@ -31,7 +31,7 @@ enum class MaxPoolingParam { StrideDims, KernelDims, PaddingDims };
 template <DimIdx_t DIM>
 class MaxPooling_Op : public Operator,
                 public Registrable<MaxPooling_Op<DIM>, std::string, std::unique_ptr<OperatorImpl>(const MaxPooling_Op<DIM> &)>,
-                public Parameterizable<MaxPoolingParam,
+                public StaticParameters<MaxPoolingParam,
                                        std::array<DimSize_t, DIM>,
                                        std::array<DimSize_t, DIM>,
                                        std::array<DimSize_t, (DIM<<1) >> {
@@ -45,18 +45,18 @@ public:
 
     MaxPooling_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<MaxPoolingParam,
+    using Parameters_ = StaticParameters<MaxPoolingParam,
                                              std::array<DimSize_t, DIM>,
                                              std::array<DimSize_t, DIM>,
                                              std::array<DimSize_t, (DIM<<1)> >;
     template <MaxPoolingParam e>
-    using param = typename Parameterizable_::template param<e>;
+    using param = typename Parameters_::template param<e>;
 
     constexpr MaxPooling_Op(const std::array<DimSize_t, DIM> &kernel_dims,
                             const std::array<DimSize_t, DIM> &stride_dims = create_array<DimSize_t,DIM>(1),
                             const std::array<DimSize_t, (DIM<<1)> &padding_dims = create_array<DimSize_t,(DIM<<1)>(0))
         : Operator(Type),
-          Parameterizable_(param<MaxPoolingParam::StrideDims>(stride_dims),
+          Parameters_(param<MaxPoolingParam::StrideDims>(stride_dims),
                            param<MaxPoolingParam::KernelDims>(kernel_dims),
                            param<MaxPoolingParam::PaddingDims>(padding_dims)),
           mOutput(std::make_shared<Tensor>()) {
diff --git a/include/aidge/operator/Producer.hpp b/include/aidge/operator/Producer.hpp
index acdc69b69..e2f6daa4a 100644
--- a/include/aidge/operator/Producer.hpp
+++ b/include/aidge/operator/Producer.hpp
@@ -19,7 +19,7 @@
 #include "aidge/data/Tensor.hpp"
 #include "aidge/graph/Node.hpp"
 #include "aidge/operator/Operator.hpp"
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 
 namespace Aidge {
diff --git a/include/aidge/operator/Scaling.hpp b/include/aidge/operator/Scaling.hpp
index e158ecd75..3499b501b 100644
--- a/include/aidge/operator/Scaling.hpp
+++ b/include/aidge/operator/Scaling.hpp
@@ -17,7 +17,7 @@
 
 
 
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/StaticParameters.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
@@ -33,7 +33,7 @@ enum class ScalingParam {
 
 class Scaling_Op : public Operator,
     public Registrable<Scaling_Op, std::string, std::unique_ptr<OperatorImpl>(const Scaling_Op&)>,
-    public Parameterizable<ScalingParam, float> {
+    public StaticParameters<ScalingParam, float> {
 public:
     // FIXME: change accessibility
     std::shared_ptr<Tensor> mInput = std::make_shared<Tensor>();
@@ -44,12 +44,12 @@ public:
 
     Scaling_Op() = delete;
 
-    using Parameterizable_ = Parameterizable<ScalingParam, float>;
-    template <ScalingParam e> using param = typename Parameterizable_::template param<e>;
+    using Parameters_ = StaticParameters<ScalingParam, float>;
+    template <ScalingParam e> using param = typename Parameters_::template param<e>;
 
     Scaling_Op(float scalingFactor)
             : Operator(Type),
-            Parameterizable_(
+            Parameters_(
                 param<ScalingParam::scalingFactor>(scalingFactor))
     {
         setDatatype(DataType::Float32);
diff --git a/include/aidge/utils/CParameter.hpp b/include/aidge/utils/CParameter.hpp
deleted file mode 100644
index 7d60ed239..000000000
--- a/include/aidge/utils/CParameter.hpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/********************************************************************************
- * Copyright (c) 2023 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_CPARAMETER_H_
-#define AIDGE_CPARAMETER_H_
-
-#include <map>
-#include <vector>
-#include <type_traits>
-#include <typeinfo>
-#include <assert.h>
-
-#include "aidge/utils/Any.hpp"
-
-
-namespace Aidge {
-
-///\todo store also a fix-sized code that indicates the type
-///\todo managing complex types or excluding non-trivial, non-aggregate types
-class CParameter {
-private:
-    template<typename _ValueType>
-    inline _ValueType& any_cast_ref(const _any& __any)
-    {
-        using _Up =  std::remove_cv_t<std::remove_reference_t<_ValueType>>;
-        assert(((std::is_reference<_ValueType>::value || std::is_copy_constructible<_ValueType>::value) && "Template argument must be a reference or CopyConstructible type"));
-        assert((std::is_constructible<_ValueType, const _Up&>::value && "Template argument must be constructible from a const value."));
-        assert(std::is_object<_Up>::value);
-        assert(__any.type() == typeid(_Up));
-        if (_any::Manager<_Up>::access(&__any)) { // assess if _any object is empty
-            return *static_cast<_ValueType*>(_any::Manager<_Up>::access(&__any));
-        }
-        throw std::bad_cast();
-    }
-public:
-    // not copyable, not movable
-    CParameter(CParameter const &) = delete;
-    CParameter(CParameter &&) = delete;
-    CParameter &operator=(CParameter const &) = delete;
-    CParameter &operator=(CParameter &&) = delete;
-    CParameter() : m_Params({}){};
-    ~CParameter() = default;
-
-    /**
-     * \brief Returning a parameter identified by its name
-     * \tparam T expected parameter type
-     * \param i_ParamName Parameter name
-     * \details assert if T is not the actual parameter type, if the parameter does not
-     *  exist or interna parameter position is invalid.
-     * \todo Returning a T const& ? But dangerous => the client may get an address within
-     *  param buffer that will get invalid after the CParam death.
-     * \note at() throws if the parameter does not exist, using find to test for parameter existance
-     */
-    template<class T> T& Get(const std::string i_ParamName)
-    {
-        return any_cast_ref<T>(m_Buffer[m_Params.at(i_ParamName)]);
-    }
-
-    // template<class T> const T& Get(const std::string i_ParamName) const
-    // {
-    //     return any_cast<T>(m_Buffer[m_Params.at(i_ParamName)]);
-    // }
-
-    ///\brief Add a parameter value, identified by its name
-    ///\tparam T expected parameter type
-    ///\param i_ParamName Parameter name
-    ///\param i_Value Parameter value
-    ///\todo Pass i_Value by ref if large or not trivial
-    ///\bug If parameter already exists, its value is changed but written in the
-    /// internal buffer in a new location (previous value is still in memory at its previous location)
-    template<class T> void Add(const std::string &i_ParamName, T&& i_Value)
-    {
-        m_Params[i_ParamName] = m_Buffer.size(); // Copy pointer offset
-        m_Buffer.push_back(_any(std::forward<T>(i_Value)));
-    }
-
-
-    std::string getParamType(std::string const &i_ParamName){
-        return m_Buffer[m_Params.at(i_ParamName)].type().name();
-    }
-
-    std::vector<std::string> getParametersName(){
-        std::vector<std::string> parametersName;
-        for(auto const& it: m_Params)
-            parametersName.push_back(it.first);
-        return parametersName;
-    }
-
-private:
-    std::map<std::string, std::size_t> m_Params; // { Param name : offset }
-
-    ///\brief All raw pointers to parameters values concatenated. Use custom any class compatible with C++14.
-    std::vector<_any> m_Buffer = {};
-};
-
-}
-
-#endif /* AIDGE_CPARAMETER_H_ */
diff --git a/include/aidge/utils/DynamicParameters.hpp b/include/aidge/utils/DynamicParameters.hpp
new file mode 100644
index 000000000..3a66e5c74
--- /dev/null
+++ b/include/aidge/utils/DynamicParameters.hpp
@@ -0,0 +1,147 @@
+/********************************************************************************
+ * Copyright (c) 2023 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_CORE_UTILS_DYNAMICPARAMETERS_H_
+#define AIDGE_CORE_UTILS_DYNAMICPARAMETERS_H_
+
+#include <map>
+#include <vector>
+#include <type_traits>
+#include <typeinfo>
+#include <cassert>
+#include <string>
+
+#include "aidge/utils/Any.hpp"
+#include "aidge/utils/Parameters.hpp"
+
+
+namespace Aidge {
+
+///\todo store also a fix-sized code that indicates the type
+///\todo managing complex types or excluding non-trivial, non-aggregate types
+class DynamicParameters : public Parameters {
+private:
+    template<typename _ValueType>
+    inline _ValueType& any_cast_ref(const _any& __any)
+    {
+        using _Up =  std::remove_cv_t<std::remove_reference_t<_ValueType>>;
+        assert(((std::is_reference<_ValueType>::value || std::is_copy_constructible<_ValueType>::value) && "Template argument must be a reference or CopyConstructible type"));
+        assert((std::is_constructible<_ValueType, const _Up&>::value && "Template argument must be constructible from a const value."));
+        assert(std::is_object<_Up>::value);
+        assert(__any.type() == typeid(_Up));
+        if (_any::Manager<_Up>::access(&__any)) { // assess if _any object is empty
+            return *static_cast<_ValueType*>(_any::Manager<_Up>::access(&__any));
+        }
+        throw std::bad_cast();
+    }
+
+    template<typename _ValueType>
+    inline const _ValueType& any_cast_ref(const _any& __any) const
+    {
+        using _Up =  std::remove_cv_t<std::remove_reference_t<_ValueType>>;
+        assert(((std::is_reference<_ValueType>::value || std::is_copy_constructible<_ValueType>::value) && "Template argument must be a reference or CopyConstructible type"));
+        assert((std::is_constructible<_ValueType, const _Up&>::value && "Template argument must be constructible from a const value."));
+        assert(std::is_object<_Up>::value);
+        assert(__any.type() == typeid(_Up));
+        if (_any::Manager<_Up>::access(&__any)) { // assess if _any object is empty
+            return *static_cast<const _ValueType*>(_any::Manager<_Up>::access(&__any));
+        }
+        throw std::bad_cast();
+    }
+public:
+    /**
+     * \brief Returning a parameter identified by its name
+     * \tparam T expected parameter type
+     * \param name Parameter name
+     * \details assert if T is not the actual parameter type, if the parameter does not
+     *  exist or interna parameter position is invalid.
+     * \todo Returning a T const& ? But dangerous => the client may get an address within
+     *  param buffer that will get invalid after the CParam death.
+     * \note at() throws if the parameter does not exist, using find to test for parameter existance
+     */
+    template<class T> T& getParameter(const std::string& name)
+    {
+        return any_cast_ref<T>(mBuffer[mParams.at(name)]);
+    }
+
+    template<class T> const T& getParameter(const std::string& name) const
+    {
+        return any_cast_ref<T>(mBuffer[mParams.at(name)]);
+    }
+
+    ///\brief Add a parameter value, identified by its name
+    ///\tparam T expected parameter type
+    ///\param name Parameter name
+    ///\param value Parameter value
+    ///\todo Pass value by ref if large or not trivial
+    ///\bug If parameter already exists, its value is changed but written in the
+    /// internal buffer in a new location (previous value is still in memory at its previous location)
+    template<class T> void addParameter(const std::string& name, T&& value)
+    {
+        mParams[name] = mBuffer.size(); // Copy pointer offset
+        mBuffer.push_back(_any(std::forward<T>(value)));
+    }
+
+    //////////////////////////////////////
+    ///     Generic Parameters API
+    //////////////////////////////////////
+    bool isParameter(const std::string& name) const override final {
+        return (mParams.find(name) != mParams.end());
+    }
+
+    std::string getParameterType(const std::string& name) const override final {
+        return mBuffer[mParams.at(name)].type().name();
+    }
+
+    std::vector<std::string> getParametersName() const override final {
+        std::vector<std::string> parametersName;
+        for(auto const& it: mParams)
+            parametersName.push_back(it.first);
+        return parametersName;
+    }
+
+    #ifdef PYBIND
+    py::object getPy(const std::string& name) const {
+        py::object res = py::none();
+        const std::string paramType = getParameterType(name);
+        if(paramType == typeid(int).name())
+            res = py::cast(getParameter<int>(name));
+        else if(paramType == typeid(float).name())
+            res = py::cast(getParameter<float>(name));
+        else if(paramType == typeid(bool).name())
+            res = py::cast(getParameter<bool>(name));
+        else if(paramType == typeid(std::string).name())
+            res = py::cast(getParameter<std::string>(name));
+        else if(paramType == typeid(std::vector<bool>).name())
+            res = py::cast(getParameter<std::vector<bool>>(name));
+        else if(paramType == typeid(std::vector<int>).name())
+            res = py::cast(getParameter<std::vector<int>>(name));
+        else if(paramType == typeid(std::vector<float>).name())
+            res = py::cast(getParameter<std::vector<float>>(name));
+        else if(paramType == typeid(std::vector<std::string>).name())
+            res = py::cast(getParameter<std::vector<std::string>>(name));
+        else {
+            throw py::key_error("Failed to convert parameter type " + name + ", this issue may come from typeid function which gave an unknown key : [" + paramType + "]. Please open an issue asking to add the support for this key.");
+        }
+        return res;
+    };
+    #endif
+
+private:
+    std::map<std::string, std::size_t> mParams; // { Param name : offset }
+
+    ///\brief All raw pointers to parameters values concatenated. Use custom any class compatible with C++14.
+    std::vector<_any> mBuffer;
+};
+
+}
+
+#endif /* AIDGE_CORE_UTILS_DYNAMICPARAMETERS_H_ */
diff --git a/include/aidge/utils/Parameters.hpp b/include/aidge/utils/Parameters.hpp
new file mode 100644
index 000000000..d71a932aa
--- /dev/null
+++ b/include/aidge/utils/Parameters.hpp
@@ -0,0 +1,59 @@
+/********************************************************************************
+ * Copyright (c) 2023 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_CORE_UTILS_PARAMETERS_H_
+#define AIDGE_CORE_UTILS_PARAMETERS_H_
+
+#ifdef PYBIND
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+#endif
+#include <vector>
+#include <string>
+
+#ifdef PYBIND
+namespace py = pybind11;
+#endif
+
+namespace {
+// This is the type that will hold all the strings. Each enumerate type will
+// declare its own specialization.
+template <typename T> struct EnumStrings {
+    static const char* const data[];
+};
+}
+
+namespace Aidge {
+template<class T, std::size_t N>
+constexpr std::size_t size(T (&)[N]) { return N; }
+
+/* This abstract class allows to avoid binding Parametrizable.
+*  Otherwise we would need to bind every template possible of Parametrizable.
+*  Every operators can access the methods of this class by inheriting from
+*  Parameters in the binding code.
+*/
+class Parameters {
+public:
+    virtual bool isParameter(const std::string& name) const = 0;
+    virtual std::string getParameterType(const std::string& name) const = 0;
+    virtual std::vector<std::string> getParametersName() const = 0;
+
+#ifdef PYBIND
+    /* Bindable get function, does not recquire any templating.
+    *  This is thanks to py::object which allow the function to
+    *  be agnostic from its return type.
+    */
+    virtual py::object getPy(const std::string& name) const = 0;
+#endif
+};
+}
+
+#endif /* AIDGE_CORE_UTILS_PARAMETERS_H_ */
diff --git a/include/aidge/utils/Parameter.hpp b/include/aidge/utils/StaticParameters.hpp
similarity index 69%
rename from include/aidge/utils/Parameter.hpp
rename to include/aidge/utils/StaticParameters.hpp
index b0c6e3595..1cedd5842 100644
--- a/include/aidge/utils/Parameter.hpp
+++ b/include/aidge/utils/StaticParameters.hpp
@@ -1,197 +1,196 @@
-/********************************************************************************
- * Copyright (c) 2023 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_CORE_UTILS_PARAMETER_H_
-#define AIDGE_CORE_UTILS_PARAMETER_H_
-
-#ifdef PYBIND
-#include <pybind11/pybind11.h>
-#include <pybind11/stl.h>
-#include <string> // Add this inclue to print error
-#endif
-#include <tuple>
-#include <cassert>
-#include <cstddef>
-
-#ifdef PYBIND
-namespace py = pybind11;
-#endif
-
-namespace {
-// This is the type that will hold all the strings. Each enumerate type will
-// declare its own specialization.
-template <typename T> struct EnumStrings {
-    static const char* const data[];
-};
-}
-
-namespace Aidge {
-template<class T, std::size_t N>
-constexpr std::size_t size(T (&)[N]) { return N; }
-
-#ifdef PYBIND
-/* This abstract class allows to avoid binding Parametrizable.
-*  Otherwise we would need to bind every template possible of Parametrizable.
-*  Every operators can access the methods of this class by inheriting from
-*  PyAbstractParametrizable in the binding code.
-*/
-class PyAbstractParametrizable{
-    public:
-        /* Bindable get function, does not recquire any templating.
-        *  This is thanks to py::object which allow the function to
-        *  be agnostic from its return type.
-        */
-        virtual py::object getPy(const char* /*name*/) = 0;
-};
-#endif
-
-template <class PARAM_ENUM, class ...T>
-class Parameterizable
-#ifdef PYBIND
-    : public PyAbstractParametrizable
-#endif
-    {
-public:
-    using Parameters = std::tuple<T...>;
-
-    // Helper class to pass to the constructor
-    template <PARAM_ENUM paramEnum>
-    class param {
-    public:
-        constexpr param(const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& v) : value(v) {}
-        const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type value;
-    };
-
-/*
-    // Direct tuple initialization
-    Parameterizable(T... params) : mParams({params...}) {
-
-    }
-*/
-
-    // Constructor for parameters initialization.
-    // Compile-time garantee that every parameter is initialized.
-    template <PARAM_ENUM ...paramEnum> // non-type parameter pack
-    constexpr Parameterizable(const param<paramEnum>&&... params) {
-        // Check number of params consistency
-        static_assert(sizeof...(params) == std::tuple_size<std::tuple<T...>>::value, "wrong number of parameters in constructor");
-        // static_assert(size(EnumStrings<PARAM_ENUM>::data) == std::tuple_size<std::tuple<T...>>::value, "wrong number of parameters in enum string");
-
-        // Check no duplicates
-        constexpr std::array<PARAM_ENUM, std::tuple_size<std::tuple<T...>>::value> pe = { paramEnum... };
-        static_assert(!hasDuplicates(pe), "duplicate parameter"); // requires C++14
-
-        // Init params with constructor arguments
-        const std::array<PARAM_ENUM, std::tuple_size<std::tuple<T...>>::value> p = { ((void)(get<paramEnum>() = params.value), paramEnum) ... };
-        (void)p; // avoid unused warning
-    }
-
-    // Compile-time access with enum
-    template <PARAM_ENUM paramEnum>
-    constexpr typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& get() {
-        return std::get<static_cast<std::size_t>(paramEnum)>(mParams);
-    }
-
-    template <PARAM_ENUM paramEnum>
-    constexpr const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& get() const {
-        return std::get<static_cast<std::size_t>(paramEnum)>(mParams);
-    }
-
-    // Runtime access with enum
-    template <typename R>
-    constexpr R& get(PARAM_ENUM paramEnum) {
-        return get<R>(static_cast<std::size_t>(paramEnum));
-    }
-
-    template <typename R>
-    constexpr const R& get(PARAM_ENUM paramEnum) const {
-        return get<R>(static_cast<std::size_t>(paramEnum));
-    }
-
-    // Runtime existance check with name
-    constexpr bool isParam(const char* name) const {
-        for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
-            if (strcmp(EnumStrings<PARAM_ENUM>::data[i], name) == 0) {
-                return true;
-            }
-        }
-
-        return false;
-    }
-
-    // Runtime access with name
-    template <typename R>
-    constexpr R& get(const char* name) {
-        for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
-            if (strcmp(EnumStrings<PARAM_ENUM>::data[i], name) == 0) {
-                return get<R>(i);
-            }
-        }
-
-        assert(false && "parameter not found");
-    }
-
-    template <typename R, std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value-1>
-    constexpr typename std::enable_if<(SIZE > 0), R&>::type get(std::size_t i) {
-        if (i == SIZE) {
-            if (std::is_same<R, typename std::tuple_element<SIZE,std::tuple<T...>>::type>::value) {
-                return reinterpret_cast<R&>(std::get<SIZE>(mParams));
-            }
-            else {
-                assert(false && "wrong parameter type");
-            }
-        }
-        else {
-            return get<R, SIZE-1>(i);
-        }
-    }
-
-    template <typename R, std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value-1>
-    constexpr typename std::enable_if<(SIZE <= 0), R&>::type get(std::size_t i) {
-        assert(false && "parameter not found");
-    }
-
-    constexpr const std::tuple<T...>& getParams() const {
-        return mParams;
-    }
-
-    #ifdef PYBIND
-    py::object getPy(const char* name){
-        for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
-            if (strcmp(EnumStrings<PARAM_ENUM>::data[i], name) == 0) {
-                // https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/pytypes.h#L1119-L1138
-                // Normal accessor would not work has we convert the tuple to a py::object which can be anything
-                return py::detail::accessor_policies::tuple_item::get(py::cast(mParams), static_cast<py::size_t>(i));
-            }
-        }
-        throw py::value_error("Parameter : " + std::string(name) + " does not exist." );
-    };
-    #endif
-
-private:
-    template <typename V, std::size_t N>
-    static constexpr bool hasDuplicates(const std::array<V, N>& array) {
-        for (std::size_t i = 1; i < N; i++) {
-            for (std::size_t j = 0; j < i; j++) {
-                if (array[i] == array[j]) {
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    std::tuple<T...> mParams;
-};
-}
-
-#endif /* AIDGE_CORE_UTILS_PARAMETER_H_ */
+/********************************************************************************
+ * Copyright (c) 2023 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_CORE_UTILS_STATICPARAMETERS_H_
+#define AIDGE_CORE_UTILS_STATICPARAMETERS_H_
+
+#include <tuple>
+#include <cassert>
+#include <cstddef>
+
+#include "aidge/utils/Parameters.hpp"
+
+namespace Aidge {
+template <class PARAM_ENUM, class ...T>
+class StaticParameters : public Parameters {
+public:
+    using Params = std::tuple<T...>;
+
+    // Helper class to pass to the constructor
+    template <PARAM_ENUM paramEnum>
+    class param {
+    public:
+        constexpr param(const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& v) : value(v) {}
+        const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type value;
+    };
+
+/*
+    // Direct tuple initialization
+    StaticParameters(T... params) : mParams({params...}) {
+
+    }
+*/
+
+    // Constructor for parameters initialization.
+    // Compile-time garantee that every parameter is initialized.
+    template <PARAM_ENUM ...paramEnum> // non-type parameter pack
+    constexpr StaticParameters(const param<paramEnum>&&... params) {
+        // Check number of params consistency
+        static_assert(sizeof...(params) == std::tuple_size<std::tuple<T...>>::value, "wrong number of parameters in constructor");
+        // static_assert(size(EnumStrings<PARAM_ENUM>::data) == std::tuple_size<std::tuple<T...>>::value, "wrong number of parameters in enum string");
+
+        // Check no duplicates
+        constexpr std::array<PARAM_ENUM, std::tuple_size<std::tuple<T...>>::value> pe = { paramEnum... };
+        static_assert(!hasDuplicates(pe), "duplicate parameter"); // requires C++14
+
+        // Init params with constructor arguments
+        const std::array<PARAM_ENUM, std::tuple_size<std::tuple<T...>>::value> p = { ((void)(get<paramEnum>() = params.value), paramEnum) ... };
+        (void)p; // avoid unused warning
+    }
+
+    // Compile-time access with enum
+    template <PARAM_ENUM paramEnum>
+    constexpr typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& get() {
+        return std::get<static_cast<std::size_t>(paramEnum)>(mParams);
+    }
+
+    template <PARAM_ENUM paramEnum>
+    constexpr const typename std::tuple_element<static_cast<std::size_t>(paramEnum),std::tuple<T...>>::type& get() const {
+        return std::get<static_cast<std::size_t>(paramEnum)>(mParams);
+    }
+
+    // Runtime access with enum
+    template <typename R>
+    constexpr R& get(PARAM_ENUM paramEnum) {
+        return get<R>(static_cast<std::size_t>(paramEnum));
+    }
+
+    template <typename R>
+    constexpr const R& get(PARAM_ENUM paramEnum) const {
+        return get<R>(static_cast<std::size_t>(paramEnum));
+    }
+
+    // Runtime access with name
+    template <typename R>
+    constexpr R& get(const char* name) {
+        for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
+            if (strcmp(EnumStrings<PARAM_ENUM>::data[i], name) == 0) {
+                return get<R>(i);
+            }
+        }
+
+        assert(false && "parameter not found");
+    }
+
+    template <typename R, std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value-1>
+    constexpr typename std::enable_if<(SIZE > 0), R&>::type get(std::size_t i) {
+        if (i == SIZE) {
+            if (std::is_same<R, typename std::tuple_element<SIZE,std::tuple<T...>>::type>::value) {
+                return reinterpret_cast<R&>(std::get<SIZE>(mParams));
+            }
+            else {
+                assert(false && "wrong parameter type");
+            }
+        }
+        else {
+            return get<R, SIZE-1>(i);
+        }
+    }
+
+    template <typename R, std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value-1>
+    constexpr typename std::enable_if<(SIZE <= 0), R&>::type get(std::size_t /*i*/) {
+        assert(false && "parameter not found");
+    }
+
+    template <std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value-1>
+    constexpr typename std::enable_if<(SIZE > 0), std::string>::type getType(std::size_t i) const {
+        if (i == SIZE) {
+            return typeid(typename std::tuple_element<SIZE,std::tuple<T...>>::type).name();
+        }
+        else {
+            return getType<SIZE-1>(i);
+        }
+    }
+
+    template <std::size_t SIZE = std::tuple_size<std::tuple<T...>>::value-1>
+    constexpr typename std::enable_if<(SIZE <= 0), std::string>::type getType(std::size_t /*i*/) const {
+        assert(false && "parameter not found");
+    }
+
+    constexpr const std::tuple<T...>& getStaticParameters() const {
+        return mParams;
+    }
+
+    //////////////////////////////////////
+    ///     Generic Parameters API
+    //////////////////////////////////////
+    // Runtime existance check with name
+    constexpr bool isParameter(const std::string& name) const override final {
+        for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
+            if (name == EnumStrings<PARAM_ENUM>::data[i]) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    // Runtime type access with name
+    constexpr std::string getParameterType(const std::string& name) const override final {
+        for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
+            if (name == EnumStrings<PARAM_ENUM>::data[i]) {
+                return getType(i);
+            }
+        }
+
+        assert(false && "parameter not found");
+    }
+
+    std::vector<std::string> getParametersName() const override final {
+        std::vector<std::string> parametersName;
+        for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
+            parametersName.push_back(EnumStrings<PARAM_ENUM>::data[i]);
+        }
+        return parametersName;
+    }
+
+    #ifdef PYBIND
+    py::object getPy(const std::string& name) const {
+        for (std::size_t i = 0; i < size(EnumStrings<PARAM_ENUM>::data); ++i) {
+            if (name == EnumStrings<PARAM_ENUM>::data[i]) {
+                // https://github.com/pybind/pybind11/blob/f3e0602802c7840992c97f4960515777cad6a5c7/include/pybind11/pytypes.h#L1119-L1138
+                // Normal accessor would not work has we convert the tuple to a py::object which can be anything
+                return py::detail::accessor_policies::tuple_item::get(py::cast(mParams), static_cast<py::size_t>(i));
+            }
+        }
+        throw py::value_error("Parameter : " + name + " does not exist." );
+    };
+    #endif
+
+private:
+    template <typename V, std::size_t N>
+    static constexpr bool hasDuplicates(const std::array<V, N>& array) {
+        for (std::size_t i = 1; i < N; i++) {
+            for (std::size_t j = 0; j < i; j++) {
+                if (array[i] == array[j]) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    std::tuple<T...> mParams;
+};
+}
+
+#endif /* AIDGE_CORE_UTILS_STATICPARAMETERS_H_ */
diff --git a/python_binding/operator/pybind_Add.cpp b/python_binding/operator/pybind_Add.cpp
index 3efcf7c53..ab8b4cf7b 100644
--- a/python_binding/operator/pybind_Add.cpp
+++ b/python_binding/operator/pybind_Add.cpp
@@ -12,7 +12,6 @@
 #include <pybind11/pybind11.h>
 
 #include "aidge/operator/Add.hpp"
-#include "aidge/utils/Parameter.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/utils/Types.h"
diff --git a/python_binding/operator/pybind_AvgPooling.cpp b/python_binding/operator/pybind_AvgPooling.cpp
index ecbb743d3..3d44ab90c 100644
--- a/python_binding/operator/pybind_AvgPooling.cpp
+++ b/python_binding/operator/pybind_AvgPooling.cpp
@@ -16,7 +16,6 @@
 #include <vector>
 #include <array>
 
-#include "aidge/utils/Parameter.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/AvgPooling.hpp"
 #include "aidge/operator/Operator.hpp"
@@ -27,7 +26,7 @@ namespace py = pybind11;
 namespace Aidge {
 
 template <DimIdx_t DIM> void declare_AvgPoolingOp(py::module &m) {
-  py::class_<AvgPooling_Op<DIM>, std::shared_ptr<AvgPooling_Op<DIM>>, Operator, PyAbstractParametrizable>(
+  py::class_<AvgPooling_Op<DIM>, std::shared_ptr<AvgPooling_Op<DIM>>, Operator, Parameters>(
     m, ("AvgPoolingOp" + std::to_string(DIM) + "D").c_str(),
     py::multiple_inheritance())
   .def(py::init<const std::array<DimSize_t, DIM> &,
diff --git a/python_binding/operator/pybind_BatchNorm.cpp b/python_binding/operator/pybind_BatchNorm.cpp
index 70d9bce00..146d3f10b 100644
--- a/python_binding/operator/pybind_BatchNorm.cpp
+++ b/python_binding/operator/pybind_BatchNorm.cpp
@@ -14,7 +14,6 @@
 
 #include "aidge/operator/BatchNorm.hpp"
 #include "aidge/operator/Operator.hpp"
-#include "aidge/utils/Parameter.hpp"
 #include "aidge/utils/Types.h"
 
 namespace py = pybind11;
@@ -22,7 +21,7 @@ namespace Aidge {
 
 template <DimSize_t DIM>
 void declare_BatchNormOp(py::module& m) {
-    py::class_<BatchNorm_Op<DIM>, std::shared_ptr<BatchNorm_Op<DIM>>, Operator, PyAbstractParametrizable>(m, ("BatchNorm_Op" + std::to_string(DIM) + "D").c_str(), py::multiple_inheritance());
+    py::class_<BatchNorm_Op<DIM>, std::shared_ptr<BatchNorm_Op<DIM>>, Operator, Parameters>(m, ("BatchNorm_Op" + std::to_string(DIM) + "D").c_str(), py::multiple_inheritance());
 
     m.def(("BatchNorm" + std::to_string(DIM) + "D").c_str(), &BatchNorm<DIM>, py::arg("epsilon") = 1.0e-5F, py::arg("momentum") = 0.1F, py::arg("name") = "");
 }
diff --git a/python_binding/operator/pybind_Conv.cpp b/python_binding/operator/pybind_Conv.cpp
index 7e366305f..af4a5d648 100644
--- a/python_binding/operator/pybind_Conv.cpp
+++ b/python_binding/operator/pybind_Conv.cpp
@@ -16,7 +16,6 @@
 #include <vector>
 #include <array>
 
-#include "aidge/utils/Parameter.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/Conv.hpp"
 #include "aidge/operator/Operator.hpp"
@@ -26,7 +25,7 @@ namespace py = pybind11;
 namespace Aidge {
 
 template <DimIdx_t DIM> void declare_ConvOp(py::module &m) {
-  py::class_<Conv_Op<DIM>, std::shared_ptr<Conv_Op<DIM>>, Operator, PyAbstractParametrizable>(
+  py::class_<Conv_Op<DIM>, std::shared_ptr<Conv_Op<DIM>>, Operator, Parameters>(
     m, ("ConvOp" + std::to_string(DIM) + "D").c_str(),
     py::multiple_inheritance())
   .def(py::init<DimSize_t,
diff --git a/python_binding/operator/pybind_ConvDepthWise.cpp b/python_binding/operator/pybind_ConvDepthWise.cpp
index 8a81e7ba1..333bad8bb 100644
--- a/python_binding/operator/pybind_ConvDepthWise.cpp
+++ b/python_binding/operator/pybind_ConvDepthWise.cpp
@@ -16,7 +16,6 @@
 #include <vector>
 #include <array>
 
-#include "aidge/utils/Parameter.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/ConvDepthWise.hpp"
 #include "aidge/operator/Operator.hpp"
@@ -27,7 +26,7 @@ namespace py = pybind11;
 namespace Aidge {
 
 template <DimIdx_t DIM> void declare_ConvDepthWiseOp(py::module &m) {
-  py::class_<ConvDepthWise_Op<DIM>, std::shared_ptr<ConvDepthWise_Op<DIM>>, Operator, PyAbstractParametrizable>(
+  py::class_<ConvDepthWise_Op<DIM>, std::shared_ptr<ConvDepthWise_Op<DIM>>, Operator, Parameters>(
     m, ("ConvDepthWiseOp" + std::to_string(DIM) + "D").c_str(),
     py::multiple_inheritance())
   .def(py::init<const std::array<DimSize_t, DIM> &,
diff --git a/python_binding/operator/pybind_FC.cpp b/python_binding/operator/pybind_FC.cpp
index 3b4137c6f..963db0caa 100644
--- a/python_binding/operator/pybind_FC.cpp
+++ b/python_binding/operator/pybind_FC.cpp
@@ -12,7 +12,6 @@
 #include <pybind11/pybind11.h>
 
 #include "aidge/operator/FC.hpp"
-#include "aidge/utils/Parameter.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/utils/Types.h"
@@ -21,7 +20,7 @@ namespace py = pybind11;
 namespace Aidge {
 
 void declare_FC(py::module &m) {
-  py::class_<FC_Op, std::shared_ptr<FC_Op>, Operator, PyAbstractParametrizable>(m, "FC_Op", py::multiple_inheritance());
+  py::class_<FC_Op, std::shared_ptr<FC_Op>, Operator, Parameters>(m, "FC_Op", py::multiple_inheritance());
 
   m.def("FC", &FC, py::arg("out_channels"), py::arg("nobias") = false, py::arg("name") = "");
 }
diff --git a/python_binding/operator/pybind_GenericOperator.cpp b/python_binding/operator/pybind_GenericOperator.cpp
index bec59eaf2..3e2c195e8 100644
--- a/python_binding/operator/pybind_GenericOperator.cpp
+++ b/python_binding/operator/pybind_GenericOperator.cpp
@@ -21,46 +21,7 @@ namespace Aidge {
 
 void init_GenericOperator(py::module& m) {
     py::class_<GenericOperator_Op, std::shared_ptr<GenericOperator_Op>, Operator>(m, "GenericOperatorOp",
-                                                                                  py::multiple_inheritance())
-    .def("get_parameter_type", &GenericOperator_Op::getParameterType)
-    .def("get_parameters_name", &GenericOperator_Op::getParametersName)
-    .def("add_parameter", &GenericOperator_Op::addParameter<bool>)
-    .def("add_parameter", &GenericOperator_Op::addParameter<int>)
-    .def("add_parameter", &GenericOperator_Op::addParameter<float>)
-    .def("add_parameter", &GenericOperator_Op::addParameter<std::string>)
-    .def("add_parameter", &GenericOperator_Op::addParameter<std::vector<bool>>)
-    .def("add_parameter", &GenericOperator_Op::addParameter<std::vector<int>>)
-    .def("add_parameter", &GenericOperator_Op::addParameter<std::vector<float>>)
-    .def("add_parameter", &GenericOperator_Op::addParameter<std::vector<std::string>>)
-    .def("get_parameter", [](GenericOperator_Op& self, std::string key) -> py::object {
-        /*
-        This getParameter method returns the good python type without having to have
-        prior knowledge of the parameter type.
-        */
-        py::object res = py::none();
-        std::string paramType = self.getParameterType(key);
-        if(paramType == typeid(int).name())
-            res = py::cast(self.getParameter<int>(key));
-        else if(paramType == typeid(float).name())
-            res = py::cast(self.getParameter<float>(key));
-        else if(paramType == typeid(bool).name())
-            res = py::cast(self.getParameter<bool>(key));
-        else if(paramType == typeid(std::string).name())
-            res = py::cast(self.getParameter<std::string>(key));
-        else if(paramType == typeid(std::vector<bool>).name())
-            res = py::cast(self.getParameter<std::vector<bool>>(key));
-        else if(paramType == typeid(std::vector<int>).name())
-            res = py::cast(self.getParameter<std::vector<int>>(key));
-        else if(paramType == typeid(std::vector<float>).name())
-            res = py::cast(self.getParameter<std::vector<float>>(key));
-        else if(paramType == typeid(std::vector<std::string>).name())
-            res = py::cast(self.getParameter<std::vector<std::string>>(key));
-        else {
-            throw py::key_error("Failed to convert parameter type " + key + ", this issue may come from typeid function which gave an unknown key : [" + paramType + "]. Please open an issue asking to add the support for this key.");
-        }
-        return res;
-    });
-
+                                                                                  py::multiple_inheritance());
     m.def("GenericOperator", &GenericOperator, py::arg("type"), py::arg("nbDataIn"), py::arg("nbIn"), py::arg("nbOut"),
           py::arg("name") = "");
 }
diff --git a/python_binding/operator/pybind_LeakyReLU.cpp b/python_binding/operator/pybind_LeakyReLU.cpp
index c062d93f5..0592a2869 100644
--- a/python_binding/operator/pybind_LeakyReLU.cpp
+++ b/python_binding/operator/pybind_LeakyReLU.cpp
@@ -13,13 +13,12 @@
 
 #include "aidge/operator/LeakyReLU.hpp"
 #include "aidge/operator/Operator.hpp"
-#include "aidge/utils/Parameter.hpp"
 
 namespace py = pybind11;
 namespace Aidge {
 
 void init_LeakyReLU(py::module& m) {
-    py::class_<LeakyReLU_Op, std::shared_ptr<LeakyReLU_Op>, Operator, PyAbstractParametrizable>(m, "LeakyReLU_Op", py::multiple_inheritance());
+    py::class_<LeakyReLU_Op, std::shared_ptr<LeakyReLU_Op>, Operator, Parameters>(m, "LeakyReLU_Op", py::multiple_inheritance());
 
     m.def("LeakyReLU", &LeakyReLU, py::arg("negative_slope") = 0.0f, py::arg("name") = "");
 }
diff --git a/python_binding/operator/pybind_Matmul.cpp b/python_binding/operator/pybind_Matmul.cpp
index b6ae27289..4ad18ff74 100644
--- a/python_binding/operator/pybind_Matmul.cpp
+++ b/python_binding/operator/pybind_Matmul.cpp
@@ -12,7 +12,6 @@
 #include <pybind11/pybind11.h>
 
 #include "aidge/operator/Matmul.hpp"
-#include "aidge/utils/Parameter.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/utils/Types.h"
@@ -21,7 +20,7 @@ namespace py = pybind11;
 namespace Aidge {
 
 void declare_Matmul(py::module &m) {
-  py::class_<Matmul_Op, std::shared_ptr<Matmul_Op>, Operator, PyAbstractParametrizable>(m, "Matmul_Op", py::multiple_inheritance());
+  py::class_<Matmul_Op, std::shared_ptr<Matmul_Op>, Operator, Parameters>(m, "Matmul_Op", py::multiple_inheritance());
 
   m.def("Matmul", &Matmul, py::arg("out_channels"), py::arg("name") = "");
 }
diff --git a/python_binding/operator/pybind_MaxPooling.cpp b/python_binding/operator/pybind_MaxPooling.cpp
index 9bd951c44..45daf075e 100644
--- a/python_binding/operator/pybind_MaxPooling.cpp
+++ b/python_binding/operator/pybind_MaxPooling.cpp
@@ -16,7 +16,6 @@
 #include <vector>
 #include <array>
 
-#include "aidge/utils/Parameter.hpp"
 #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/MaxPooling.hpp"
 #include "aidge/operator/Operator.hpp"
@@ -27,7 +26,7 @@ namespace py = pybind11;
 namespace Aidge {
 
 template <DimIdx_t DIM> void declare_MaxPoolingOp(py::module &m) {
-  py::class_<MaxPooling_Op<DIM>, std::shared_ptr<MaxPooling_Op<DIM>>, Operator, PyAbstractParametrizable>(
+  py::class_<MaxPooling_Op<DIM>, std::shared_ptr<MaxPooling_Op<DIM>>, Operator, Parameters>(
     m, ("MaxPoolingOp" + std::to_string(DIM) + "D").c_str(),
     py::multiple_inheritance())
   .def(py::init<const std::array<DimSize_t, DIM> &,
diff --git a/python_binding/operator/pybind_Producer.cpp b/python_binding/operator/pybind_Producer.cpp
index ea9880800..e1c351255 100644
--- a/python_binding/operator/pybind_Producer.cpp
+++ b/python_binding/operator/pybind_Producer.cpp
@@ -13,7 +13,6 @@
 #include <pybind11/stl.h>
 
 #include "aidge/utils/Types.h"
-#include "aidge/utils/Parameter.hpp"
 // #include "aidge/backend/OperatorImpl.hpp"
 #include "aidge/operator/Operator.hpp"
 #include "aidge/operator/Producer.hpp"
diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp
index 78418d51a..293e33ff0 100644
--- a/python_binding/pybind_core.cpp
+++ b/python_binding/pybind_core.cpp
@@ -17,7 +17,7 @@ namespace Aidge {
 void init_Data(py::module&);
 void init_Tensor(py::module&);
 void init_OperatorImpl(py::module&);
-void init_Parameterizable(py::module&);
+void init_Parameters(py::module&);
 void init_Operator(py::module&);
 
 void init_Add(py::module&);
@@ -65,7 +65,7 @@ void init_Aidge(py::module& m){
     init_Connector(m);
 
     init_OperatorImpl(m);
-    init_Parameterizable(m);
+    init_Parameters(m);
     init_Operator(m);
     init_Add(m);
     init_AvgPooling(m);
diff --git a/python_binding/utils/pybind_Parameter.cpp b/python_binding/utils/pybind_Parameter.cpp
index 358316ea0..f9344796e 100644
--- a/python_binding/utils/pybind_Parameter.cpp
+++ b/python_binding/utils/pybind_Parameter.cpp
@@ -1,12 +1,25 @@
 #include <pybind11/pybind11.h>
-#include "aidge/utils/Parameter.hpp"
+#include "aidge/utils/Parameters.hpp"
+#include "aidge/utils/DynamicParameters.hpp"
 
 namespace py = pybind11;
 namespace Aidge {
-void init_Parameterizable(py::module& m){
-    py::class_<PyAbstractParametrizable, std::shared_ptr<PyAbstractParametrizable>>(m, "PyAbstractParametrizable")
-    .def("get", &PyAbstractParametrizable::getPy, py::arg("name"))
-    ;
+void init_Parameters(py::module& m){
+    py::class_<Parameters, std::shared_ptr<Parameters>>(m, "Parameters")
+    .def("is_parameter", &Parameters::isParameter)
+    .def("get_parameter_type", &Parameters::getParameterType)
+    .def("get_parameters_name", &Parameters::getParametersName)
+    .def("get_parameter", &Parameters::getPy, py::arg("name"));
+
+    py::class_<DynamicParameters, std::shared_ptr<DynamicParameters>>(m, "DynamicParameters")
+    .def("add_parameter", &DynamicParameters::addParameter<bool>)
+    .def("add_parameter", &DynamicParameters::addParameter<int>)
+    .def("add_parameter", &DynamicParameters::addParameter<float>)
+    .def("add_parameter", &DynamicParameters::addParameter<std::string>)
+    .def("add_parameter", &DynamicParameters::addParameter<std::vector<bool>>)
+    .def("add_parameter", &DynamicParameters::addParameter<std::vector<int>>)
+    .def("add_parameter", &DynamicParameters::addParameter<std::vector<float>>)
+    .def("add_parameter", &DynamicParameters::addParameter<std::vector<std::string>>);
 }
 }
 
diff --git a/src/graphmatching/NodeRegex.cpp b/src/graphmatching/NodeRegex.cpp
index bbb116d1b..5fa984eb6 100644
--- a/src/graphmatching/NodeRegex.cpp
+++ b/src/graphmatching/NodeRegex.cpp
@@ -39,7 +39,7 @@ bool Aidge::NodeRegex::isA(std::string NodeType){
 /**bool NodeRegex::_is(string &Node_op){
     // Parsing the condition is done in the initialization of the NodeRegex
     
-    // assert parameters exist in the node with the parameter function isParam()
+    // assert parameters exist in the node with the parameter function isParameter()
 
     // get the parameters
 
-- 
GitLab