From e342d7879a8df53b18477119814cf01060bd1d39 Mon Sep 17 00:00:00 2001
From: NAUD Maxence <maxence.naud@cea.fr>
Date: Wed, 26 Mar 2025 17:10:26 +0100
Subject: [PATCH] fix: error related to 'fma' call with different input types.
 Also simplify GlobalAvgPooling logic

---
 .../cpu/operator/GlobalAveragePoolingImpl.hpp |  3 +-
 .../GlobalAveragePoolingImpl_kernels.hpp      | 95 ++++++++-----------
 .../backend/cpu/operator/ReduceMeanImpl.hpp   |  1 -
 .../cpu/operator/ReduceMeanImpl_kernels.hpp   | 20 ++--
 src/operator/GlobalAveragePoolingImpl.cpp     |  6 +-
 5 files changed, 52 insertions(+), 73 deletions(-)

diff --git a/include/aidge/backend/cpu/operator/GlobalAveragePoolingImpl.hpp b/include/aidge/backend/cpu/operator/GlobalAveragePoolingImpl.hpp
index 4e04b1a5..a71174c0 100644
--- a/include/aidge/backend/cpu/operator/GlobalAveragePoolingImpl.hpp
+++ b/include/aidge/backend/cpu/operator/GlobalAveragePoolingImpl.hpp
@@ -18,12 +18,11 @@
 #include "aidge/backend/cpu/operator/OperatorImpl.hpp"
 #include "aidge/operator/GlobalAveragePooling.hpp"
 #include "aidge/utils/Registrar.hpp"
-#include "aidge/utils/Types.h"
 
 namespace Aidge {
 // Operator implementation entry point for the backend
 using GlobalAveragePoolingImpl_cpu = OperatorImpl_cpu<GlobalAveragePooling_Op,
-    void(const std::vector<DimSize_t> &, const void *, void *)>;
+    void(const std::shared_ptr<Tensor>&, void *)>;
 
 // Implementation entry point registration to Operator
 REGISTRAR(GlobalAveragePooling_Op, "cpu", Aidge::GlobalAveragePoolingImpl_cpu::create);
diff --git a/include/aidge/backend/cpu/operator/GlobalAveragePoolingImpl_kernels.hpp b/include/aidge/backend/cpu/operator/GlobalAveragePoolingImpl_kernels.hpp
index 7a47ccf3..40dd3a69 100644
--- a/include/aidge/backend/cpu/operator/GlobalAveragePoolingImpl_kernels.hpp
+++ b/include/aidge/backend/cpu/operator/GlobalAveragePoolingImpl_kernels.hpp
@@ -12,92 +12,71 @@
 #ifndef AIDGE_CPU_OPERATOR_GLOBALAVERAGEPOOLINGIMPL_KERNELS_H_
 #define AIDGE_CPU_OPERATOR_GLOBALAVERAGEPOOLINGIMPL_KERNELS_H_
 
-#include <cstddef>
-#include <functional>  // std::multiplies
-#include <numeric>     // std::accumulate
+#include <cstddef>     // std::size_t
 #include <vector>
 
 #include "aidge/backend/cpu/operator/GlobalAveragePoolingImpl.hpp"
-#include "aidge/data/Data.hpp"
-#include "aidge/utils/ErrorHandling.hpp"
+#include "aidge/data/Tensor.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
 
-
 namespace Aidge {
 
 template <typename T>
-typename std::enable_if<std::is_floating_point<T>::value, T>::type
-stableMean(const T* vec, size_t size) {
-  T mean = 0;
-  for (size_t i = 0; i < size; ++i) {
-    mean = std::fma<T>(vec[i] - mean, 1.0f / (i + 1), mean);
-  }
-  return mean;
+typename std::enable_if_t<std::is_floating_point<T>::value, T>
+static stableMean(const T* vec, std::size_t size) {
+    T mean{0};
+    for (std::size_t i = 0; i < size; ++i) {
+        mean = std::fma(vec[i] - mean, static_cast<T>(1) / static_cast<T>(i + 1), mean);
+    }
+    return mean;
 }
 
 // Specialization for integers: perform the mean computation in float
 template <typename T>
-typename std::enable_if<!std::is_floating_point<T>::value, double>::type
-stableMean(const T* vec, size_t size) {
-  double mean = 0;
-  for (size_t i = 0; i < size; ++i) {
-    mean = std::fma<double>(vec[i] - mean, 1.0f / (i + 1), mean);
-  }
-  return mean;
-}
-
-template <typename T>
-typename std::enable_if<std::is_floating_point<T>::value, T>::type
-castFromFloat(T value) {
-  return value;
-}
-
-template <typename T>
-typename std::enable_if<!std::is_floating_point<T>::value, T>::type
-castFromFloat(double value) {
-  return static_cast<T>(std::nearbyint(value));
+typename std::enable_if_t<!std::is_floating_point<T>::value, double>
+static stableMean(const T* vec, std::size_t size) {
+    double mean{0};
+    for (std::size_t i = 0; i < size; ++i) {
+        mean = std::fma<double>(static_cast<double>(vec[i]) - mean, 1.0 / static_cast<double>(i + 1), mean);
+    }
+    return mean;
 }
 
-template <class I, class O>
-void GlobalAveragePoolingImpl_cpu_forward_kernel(
-    const std::vector<DimSize_t> &dims, const void *input_, void *output_) {
-  // error checking
-    AIDGE_ASSERT(dims.size() >= 3,"GlobalAveragePool needs at least a 3 dimensions "
-                 "input, number of input dim : {}",
-                 dims.size());
+template <DataType DT_I, DataType DT_O = DT_I>
+void GlobalAveragePoolingImpl_cpu_forward_kernel(const std::shared_ptr<Tensor>& inputTensor, void *output_) {
 
-  // computation
-  const I *input = static_cast<const I *>(input_);
-  O *output = static_cast<O *>(output_);
+    // computation
+    using I = cpptype_t<DT_I>;
+    using O = cpptype_t<DT_O>;
+    const I *input = static_cast<const I *>(inputTensor->getImpl()->rawPtr());
+    O *output = static_cast<O *>(output_);
+    const auto& dims = inputTensor->dims();
 
-  DimSize_t nb_elems = std::accumulate(dims.begin(), dims.end(), std::size_t(1),
-                                       std::multiplies<std::size_t>());
+    const DimSize_t strides_channels = inputTensor->strides()[1];
 
-  const DimSize_t in_batch_nb_elems{nb_elems / dims[0]};
-  const DimSize_t in_channel_nb_elems{in_batch_nb_elems / dims[1]};
-  const DimSize_t out_batch_nb_elems{dims[1]};
-  // parse channel by channel and fill each output with the average of the
-  // values in the channel
-  for (DimSize_t batch = 0; batch < dims[0]; ++batch) {
-    for (DimSize_t channel = 0; channel < dims[1]; ++channel) {
-      const I *filter_start = std::next(
-          input, (batch * in_batch_nb_elems) + (channel * in_channel_nb_elems));
-      output[batch * out_batch_nb_elems + channel] = castFromFloat<O>(stableMean<I>(filter_start, in_channel_nb_elems));
+    // parse channel by channel and fill each output with the average of the
+    // values in the channel
+    std::size_t input_idx = 0;
+    std::size_t output_idx = 0;
+    for (DimSize_t batch = 0; batch < dims[0]; ++batch) {
+        for (DimSize_t channel = 0; channel < dims[1]; ++channel) {
+            output[output_idx++] = static_cast<O>(stableMean<I>(input + input_idx, strides_channels));
+            input_idx += strides_channels;
+        }
     }
-  }
 }
 
 // Kernels registration to implementation entry point
 REGISTRAR(GlobalAveragePoolingImpl_cpu,
     {DataType::Float32},
-    {ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<float, float>, nullptr});
+    {ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<DataType::Float32>, nullptr});
 REGISTRAR(GlobalAveragePoolingImpl_cpu,
     {DataType::Float64},
-    {ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<double, double>, nullptr});
+    {ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<DataType::Float64>, nullptr});
 REGISTRAR(GlobalAveragePoolingImpl_cpu,
     {DataType::Int32},
-    {ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<int32_t, int32_t>, nullptr});
+    {ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<DataType::Int32>, nullptr});
 } // namespace Aidge
 
 #endif /* AIDGE_CPU_OPERATOR_GLOBALAVERAGEPOOLINGIMPL_KERNELS_H_ */
diff --git a/include/aidge/backend/cpu/operator/ReduceMeanImpl.hpp b/include/aidge/backend/cpu/operator/ReduceMeanImpl.hpp
index 1c50805d..d6c60c35 100644
--- a/include/aidge/backend/cpu/operator/ReduceMeanImpl.hpp
+++ b/include/aidge/backend/cpu/operator/ReduceMeanImpl.hpp
@@ -12,7 +12,6 @@
 #ifndef AIDGE_CPU_OPERATOR_REDUCEMEANIMPL_H_
 #define AIDGE_CPU_OPERATOR_REDUCEMEANIMPL_H_
 
-#include <array>
 #include <memory>
 #include <tuple>
 #include <vector>
diff --git a/include/aidge/backend/cpu/operator/ReduceMeanImpl_kernels.hpp b/include/aidge/backend/cpu/operator/ReduceMeanImpl_kernels.hpp
index a1562322..73aa283d 100644
--- a/include/aidge/backend/cpu/operator/ReduceMeanImpl_kernels.hpp
+++ b/include/aidge/backend/cpu/operator/ReduceMeanImpl_kernels.hpp
@@ -25,39 +25,39 @@
 #include "aidge/utils/Registrar.hpp"
 
 namespace Aidge {
-    
+
 template <typename T>
-using Acc_T = typename std::conditional<std::is_floating_point<T>::value, T, double>::type;
+using Acc_T = typename std::conditional_t<std::is_floating_point<T>::value, T, double>;
 
 template <typename T>
 typename std::enable_if<std::is_floating_point<T>::value, T>::type
-stableMean(const T* vec, size_t len, size_t stride) {
+stableMean(const T* vec, std::size_t len, std::size_t stride) {
   T mean = 0;
-  for (size_t i = 0; i < len; ++i) {
-    mean = std::fma<T>(vec[i * stride] - mean, 1.0f / (i + 1), mean);
+  for (std::size_t i = 0; i < len; ++i) {
+    mean = std::fma(vec[i * stride] - mean, static_cast<T>(1) / static_cast<T>(i + 1), mean);
   }
   return mean;
 }
 
 // Specialization for integers: perform the mean computation in float
 template <typename T>
-typename std::enable_if<!std::is_floating_point<T>::value, double>::type
-stableMean(const T* vec, size_t len, size_t stride) {
+typename std::enable_if_t<!std::is_floating_point<T>::value, double>
+stableMean(const T* vec, std::size_t len, std::size_t stride) {
   double mean = 0;
   for (size_t i = 0; i < len; ++i) {
-    mean = std::fma<double>(vec[i * stride] - mean, 1.0f / (i + 1), mean);
+    mean = std::fma<double>(static_cast<double>(vec[i * stride]) - mean, 1.0 / static_cast<double>(i + 1), mean);
   }
   return mean;
 }
 
 template <typename T>
-typename std::enable_if<std::is_floating_point<T>::value, T>::type
+typename std::enable_if_t<std::is_floating_point<T>::value, T>
 castFromFloat(T value) {
   return value;
 }
 
 template <typename T>
-typename std::enable_if<!std::is_floating_point<T>::value, T>::type
+typename std::enable_if_t<!std::is_floating_point<T>::value, T>
 castFromFloat(double value) {
   return static_cast<T>(std::nearbyint(value));
 }
diff --git a/src/operator/GlobalAveragePoolingImpl.cpp b/src/operator/GlobalAveragePoolingImpl.cpp
index c53f92e1..1b6d9a06 100644
--- a/src/operator/GlobalAveragePoolingImpl.cpp
+++ b/src/operator/GlobalAveragePoolingImpl.cpp
@@ -30,13 +30,15 @@ void Aidge::GlobalAveragePoolingImpl_cpu::forward()
     const GlobalAveragePooling_Op& op_ = static_cast<const GlobalAveragePooling_Op&>(mOp);
     // Check if input is provided
     AIDGE_ASSERT(op_.getInput(0), "missing input 0");
+    // error checking
+    AIDGE_ASSERT(op_.getInput(0)->nbDims() >= 3,"GlobalAveragePool needs at least a 3 dimensions "
+    "input. Got input dims {}", op_.getInput(0)->dims());
 
     // Find the correct kernel type
     const auto impl = Registrar<GlobalAveragePoolingImpl_cpu>::create(getBestMatch(getRequiredSpec()));
 
     // Call kernel
-    impl.forward(op_.getInput(0)->dims(),
-               op_.getInput(0)->getImpl()->rawPtr(),
+    impl.forward(op_.getInput(0),
                op_.getOutput(0)->getImpl()->rawPtr());
 }
 
-- 
GitLab