diff --git a/include/aidge/data/Tensor.hpp b/include/aidge/data/Tensor.hpp
index 8d9f77bc41b0fa5225e7201d2e4d03eb2ff72502..8f3d7c6b4797b161836f1d65616c1be5417cbab4 100644
--- a/include/aidge/data/Tensor.hpp
+++ b/include/aidge/data/Tensor.hpp
@@ -12,6 +12,7 @@
 #ifndef AIDGE_CORE_DATA_TENSOR_H_
 #define AIDGE_CORE_DATA_TENSOR_H_
 
+#include <algorithm>
 #include <cstddef>      // std::size_t
 #include <cstring>
 #include <functional>   // std::multiplies
@@ -25,6 +26,7 @@
 #include "aidge/backend/TensorImpl.hpp"
 #include "aidge/data/Data.hpp"
 
+#include "aidge/utils/ErrorHandling.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/utils/Types.h"
 #include "aidge/utils/ArrayHelpers.hpp"
@@ -625,16 +627,19 @@ public:
      * @return std::vector<DimSize_t>
      */
     std::vector<std::size_t> getCoord(std::size_t flatIdx) const {
-        std::vector<std::size_t> coordIdx(mDims.size());
-        std::size_t i = mDims.size();
-
-        while (i-- > 0) {
-            coordIdx[i] = (flatIdx % mDims[i]);
-            flatIdx/=mDims[i];
-        }
-        return coordIdx;
+    	return Tensor::getCoord(mDims, flatIdx);
     }
 
+    /**
+     * @brief From the the 1D contiguous index, return the coordinate of an element in the tensor.
+     * Beware: do not use this function with the storage index!
+     *
+     * @param flatIdx 1D contiguous index of the value considering a flatten, contiguous, tensor.
+     * @return std::vector<DimSize_t>
+     */
+	static std::vector<std::size_t>
+	getCoord(const std::vector<Aidge::DimSize_t> &dimensions, std::size_t flattenedIdx); 
+
     /**
      * @brief From the coordinate returns the 1D contiguous index of an element in the tensor.
      * If the number of coordinates is inferior to the number of dimensions,
@@ -647,17 +652,33 @@ public:
      * @return DimSize_t Contiguous index
      */
     std::size_t getIdx(const std::vector<std::size_t>& coordIdx) const {
-        AIDGE_ASSERT(coordIdx.size() <= mDims.size(), "Coordinates does not match number of dimensions");
-        std::size_t flatIdx = 0;
-        for(std::size_t i = 0; i < mDims.size(); ++i) {
-            auto coord = i < coordIdx.size() ? coordIdx[i]: 0;
-            AIDGE_ASSERT(coord < mDims[i], "Coordinates dimensions does not fit the dimensions of the tensor");
-            auto nextDimSize  = i + 1 < mDims.size() ? mDims[i + 1]: 1;
-            flatIdx = (flatIdx + coord) * nextDimSize;
-        }
-        return flatIdx;
+        return Tensor::getIdx(mDims,coordIdx);
     }
 
+    /**
+     * @brief From the coordinate returns the 1D contiguous index of an element in the tensor.
+     * If the number of coordinates is inferior to the number of dimensions,
+     * the remaining coordinates are assumed to be 0.
+     * Beware: the contiguous index will only correspond to the storage index
+     * if the tensor is contiguous!
+     * Note that the coordIdx may be an empty vector.
+     *
+     * @param coordIdx Coordinate to an element in the tensor
+     * @return DimSize_t Contiguous index
+     */
+	static std::size_t getIdx(const std::vector<DimSize_t>& tensorDims, const std::vector<std::size_t>& coords);
+	
+    /**
+     * @brief check if index is in bound of given tensor dimensions
+     * @warning this function is templated in order to welcome cases like interpolation where indexes are not integers.
+     * However, the only types accepted are floating, integer & size_t
+     * @param tensorDims : tensor dimensions
+     * @param coords : coords of the tensor you want to flattened index of 
+     * @return true if all coords are in bound. False otherwise
+     */
+    template<typename T>
+    static bool isInBounds(const std::vector<DimSize_t>& tensorDims, const std::vector<T>& coords);
+
     /**
      * @brief From the coordinate returns the 1D storage index of an element in the tensor.
      * If the number of coordinates is inferior to the number of dimensions,
diff --git a/python_binding/data/pybind_Tensor.cpp b/python_binding/data/pybind_Tensor.cpp
index b972c87dcda8f912ff40feef0001b95d5feac71e..a6dcf8aa5d3d9440735cf41bde49abf34a3410b1 100644
--- a/python_binding/data/pybind_Tensor.cpp
+++ b/python_binding/data/pybind_Tensor.cpp
@@ -329,9 +329,8 @@ void init_Tensor(py::module& m){
     .def("capacity", &Tensor::capacity)
     .def("resize", (void (Tensor::*)(const std::vector<DimSize_t>&, std::vector<DimSize_t>)) &Tensor::resize, py::arg("dims"), py::arg("strides") = std::vector<DimSize_t>())
     .def("has_impl", &Tensor::hasImpl)
-    .def("get_coord", &Tensor::getCoord)
-    .def("get_idx", &Tensor::getIdx)
-    .def_static("get_available_backends", &Tensor::getAvailableBackends)
+    .def("get_coord", (std::vector<std::size_t> (Tensor::*)(const std::size_t) &Tensor::getCoord, py::arg("flatIdx"))
+    .def("get_idx",(std::size_t (Tensor::*)(const std::vector<std::size_t> &) &Tensor::getIdx, py::arg("coords"))
     .def("undefined", &Tensor::undefined)
     .def("cpy_transpose", (void (Tensor::*)(const Tensor& src, const std::vector<DimSize_t>& transpose)) &Tensor::copyTranspose, py::arg("src"), py::arg("transpose"))
 
diff --git a/src/data/Tensor.cpp b/src/data/Tensor.cpp
index 3dcdcc65d0ef40b0443eb5b9662111420ce4fb86..5a336e93151fe9347c218325a88bcbda50884dc8 100644
--- a/src/data/Tensor.cpp
+++ b/src/data/Tensor.cpp
@@ -11,9 +11,11 @@
 
 #include "aidge/data/Tensor.hpp"
 
+#include <algorithm>
 #include <cstddef>
 #include <vector>
 
+#include "aidge/data/half.hpp"
 #include "aidge/utils/ErrorHandling.hpp"
 #include "aidge/utils/Registrar.hpp"
 #include "aidge/operator/Abs.hpp"
@@ -675,7 +677,58 @@ const Aidge::Tensor& Aidge::Tensor::ref(std::shared_ptr<Tensor>& fallback,
 
 std::set<std::string> Aidge::Tensor::getAvailableBackends() {
     std::set<std::string> backendsList;
-    for (const auto& tupleKey : Registrar<Tensor>::getKeys())
+    for (const auto& tupleKey : Registrar<Tensor>::getKeys()) {
         backendsList.insert(std::get<0>(tupleKey));
+    }
     return backendsList;
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////
+// COORDINATES MANIPULATION
+std::vector<std::size_t>
+Aidge::Tensor::getCoord(const std::vector<Aidge::DimSize_t> &tensorDims,
+                  std::size_t flatIdx) {
+        std::vector<std::size_t> coordIdx(tensorDims.size());
+        std::size_t i = tensorDims.size();
+
+        while (i-- > 0) {
+            coordIdx[i] = (flatIdx % tensorDims[i]);
+            flatIdx/=tensorDims[i];
+        }
+        return coordIdx;
+}
+
+
+std::size_t Aidge::Tensor::getIdx(const std::vector<Aidge::DimSize_t> &tensorDims, const std::vector<std::size_t>& coordIdx) {
+   AIDGE_ASSERT(coordIdx.size() <= tensorDims.size(), "Tensor::getIdx(): Coordinates does not match number of dimensions.\n\tCoords : {}\n\tDimensions: {}",coordIdx, tensorDims);
+   std::size_t flatIdx = 0;
+    for(std::size_t i = 0; i < tensorDims.size(); ++i) {
+        auto coord = i < coordIdx.size() ? coordIdx[i]: 0;
+        AIDGE_ASSERT(coord < tensorDims[i], "Coordinates dimensions does not fit the dimensions of the tensor");
+        auto nextDimSize  = i + 1 < tensorDims.size() ? tensorDims[i + 1]: 1;
+        flatIdx = (flatIdx + coord) * nextDimSize;
+    }
+    return flatIdx;
+}
+
+template<typename T>
+bool Aidge::Tensor::isInBounds(const std::vector<Aidge::DimSize_t>& tensorDims, const std::vector<T>& coords){
+    AIDGE_ASSERT(coords.size() == tensorDims.size(),
+                 "Coordinates({}) to compare have not "
+                 "the same number of dimension as tensor dimensions({}), aborting.",
+                 coords,
+                 tensorDims);
+    T i;
+    bool isInBound {true};
+    for(i = 0 ; i < static_cast<T>(coords.size()) && isInBound; ++i ){
+        isInBound = coords[i] >= 0 && coords[i] < static_cast<T>(tensorDims[i]) ;
+    }
+    return isInBound;
+}
+template bool Tensor::isInBounds(const std::vector<DimSize_t>& tensorDims, const std::vector<int16_t>& coords);
+template bool Tensor::isInBounds(const std::vector<DimSize_t>& tensorDims, const std::vector<int32_t>& coords);
+template bool Tensor::isInBounds(const std::vector<DimSize_t>& tensorDims, const std::vector<int64_t>& coords);
+template bool Tensor::isInBounds(const std::vector<DimSize_t>& tensorDims, const std::vector<DimSize_t>& coords);
+template bool Tensor::isInBounds(const std::vector<DimSize_t>& tensorDims, const std::vector<float>& coords);
+template bool Tensor::isInBounds(const std::vector<DimSize_t>& tensorDims, const std::vector<double>& coords);
+
diff --git a/unit_tests/data/Test_Tensor.cpp b/unit_tests/data/Test_Tensor.cpp
index 4462eb91ed6c6cdfce77b47b6a1a8808eec88423..cebc995d5bd2e0120937b8a81acd773b08cb5861 100644
--- a/unit_tests/data/Test_Tensor.cpp
+++ b/unit_tests/data/Test_Tensor.cpp
@@ -9,9 +9,9 @@
  *
  ********************************************************************************/
 
-#include <array>
 #include <cstddef>     // std::size_t
 #include <cstdint>     // std::uint8_t, std::uint16_t, std::int32_t
+#include <cstdlib>
 #include <numeric>     // std::accumulate, std::inner_product
 #include <functional>  // std::multiplies
 #include <random>      // std::mt19937,
@@ -365,7 +365,40 @@ TEST_CASE("[core/data] Tensor(other)", "[Tensor][extract][zeros][print]") {
             }
         }
     }
-
+    SECTION("Index & coord manipulation"){
+            Tensor tensor;
+            std::vector<DimSize_t> dims {2,2};
+            int nbVal = std::accumulate(dims.begin(), 
+                                        dims.end(), 
+                                        1,
+                                        std::multiplies<DimSize_t>());                    
+            float* values = static_cast<float*>(malloc(nbVal * sizeof(float)));
+            values[0] = 0;
+            values[1] = 1;
+            values[2] = 2;
+            values[3] = 3;
+            tensor.setDataType(DataType::Int32);
+            tensor.setBackend("cpu");
+            tensor.resize(dims);
+            tensor.getImpl()->setRawPtr(values, 4);
+            std::vector<std::size_t> coords;
+        SECTION("getIdx"){
+            CHECK(Tensor::getIdx(tensor.dims(), std::vector<std::size_t>({1,1}) ) == 3);
+            CHECK(Tensor::getIdx(tensor.dims(), std::vector<std::size_t>({1,0}) ) == 2);
+            // No check to ensure if value is in bounds
+            CHECK_THROWS(Tensor::getIdx(tensor.dims(), std::vector<std::size_t>({0,2}) ));
+        }
+        SECTION("getCoord"){
+            CHECK(Tensor::getCoord(tensor.dims(),  3 ) ==std::vector<std::size_t>({1,1}));
+            CHECK(Tensor::getCoord(tensor.dims(),  2 ) ==std::vector<std::size_t>({1,0}));
+        }
+        SECTION("isInBound"){
+            CHECK_THROWS(Tensor::isInBounds(dims, std::vector<DimSize_t>({1,2,4,5})) == true);
+            CHECK(Tensor::isInBounds(dims, std::vector<DimSize_t>({1,2})) == false);
+            CHECK(Tensor::isInBounds(dims, std::vector<int>({-1,1})) == false);
+            CHECK(Tensor::isInBounds(dims, std::vector<DimSize_t>({1,1})) == true);
+        }
+    }
     SECTION("Tensor extract") {
         bool equal;