From 698d0028d8f794fd2d166650839f116ee454662a Mon Sep 17 00:00:00 2001 From: NAUD Maxence <maxence.naud@cea.fr> Date: Thu, 22 Feb 2024 12:08:43 +0000 Subject: [PATCH] Standardize and optimize TensorImpl, Tensor and arithmetic operators --- include/aidge/backend/TensorImpl.hpp | 53 +++++++++++++++++----------- include/aidge/data/Tensor.hpp | 10 +++--- src/operator/Add.cpp | 21 +++++------ src/operator/Div.cpp | 47 +++++++++++------------- src/operator/Mul.cpp | 48 +++++++++++-------------- src/operator/Pow.cpp | 48 +++++++++++-------------- src/operator/Sub.cpp | 48 +++++++++++-------------- 7 files changed, 129 insertions(+), 146 deletions(-) diff --git a/include/aidge/backend/TensorImpl.hpp b/include/aidge/backend/TensorImpl.hpp index 8539c8e36..9432914f5 100644 --- a/include/aidge/backend/TensorImpl.hpp +++ b/include/aidge/backend/TensorImpl.hpp @@ -12,8 +12,12 @@ #ifndef AIDGE_TENSORIMPL_H_ #define AIDGE_TENSORIMPL_H_ -#include <cstddef> -#include <cstdio> +#include <algorithm> // std::accumulate +#include <cstddef> // std::size_t +#include <functional> // std::multiplies +#include <vector> +#include <utility> // std::pair, std::make_pair + #include "aidge/data/Data.hpp" #include "aidge/utils/Types.h" #include "aidge/utils/ErrorHandling.hpp" @@ -59,23 +63,42 @@ private: */ /** - * This class manages the raw data storage of a Tensor and provide generic copy + * @class TensorImpl + * @brief Class to manage the raw data storage of a Tensor and provide generic copy * primitives from other devices and from/to host. - * It can own the data or not (use setRawPtr() to set an external data owner). - * It only knows the data type and data capacity, but does not handle anything else. + * @note It can own the data or not (use ``setRawPtr()`` to set an external data owner). + * @note It only knows the data type and data capacity, but does not handle anything else. */ class TensorImpl { +protected: + + const char *mBackend; + /// @brief Device id. + const DeviceIdx_t mDevice; + /// Number of elements (to be) stored. + NbElts_t mNbElts; + public: TensorImpl() = delete; - TensorImpl(const char *backend, DeviceIdx_t device, std::vector<DimSize_t> dims) : mBackend(backend), mDevice(device) + + TensorImpl(const char *backend, DeviceIdx_t device, std::vector<DimSize_t> dims) + : mBackend(backend), + mDevice(device) { resize(dims); }; + virtual ~TensorImpl() = default; + + virtual bool operator==(const TensorImpl &othImpl) const = 0; + +public: /** * Return the (backend, device) pair for this implementation. */ - std::pair<std::string, DeviceIdx_t> device() const { return std::make_pair(mBackend, mDevice); } + std::pair<std::string, DeviceIdx_t> device() const noexcept { + return std::make_pair(std::string(mBackend), mDevice); + } /** * Copy data from the same device. @@ -151,11 +174,7 @@ public: * Set the size, in number of elements, that must be stored. */ virtual void resize(std::vector<DimSize_t> dims) { - size_t product = 1; - for (size_t num : dims) { - product *= num; - } - mNbElts = product; + mNbElts = std::accumulate(dims.cbegin(), dims.cend(), std::size_t(1), std::multiplies<std::size_t>()); } /** @@ -168,23 +187,15 @@ public: */ virtual std::size_t scalarSize() const noexcept = 0; constexpr const char *backend() const { return mBackend; } - virtual ~TensorImpl() = default; - virtual bool operator==(const TensorImpl &othImpl) const = 0; /** - * Copy from another backend. + * @brief Copy from another backend. * @param srcImpl Source TensorImpl to copy from. * @param length Number of elements of size scalarSize() to copy * @param srcOffset Source offset (in number of elements). * @param dstOffset Destination offset (in number of elements). */ void copyFrom(const TensorImpl& srcImpl, NbElts_t length, NbElts_t srcOffset = 0, NbElts_t dstOffset = 0); - -protected: - const char *mBackend; - const DeviceIdx_t mDevice; - /// Number of elements (to be) stored - NbElts_t mNbElts; }; } // namespace Aidge diff --git a/include/aidge/data/Tensor.hpp b/include/aidge/data/Tensor.hpp index 555a465f5..3ccd55d3f 100644 --- a/include/aidge/data/Tensor.hpp +++ b/include/aidge/data/Tensor.hpp @@ -106,7 +106,7 @@ class Tensor : public Data, : Data(Type), mDataType(NativeType<VT>::type), mDims({}), mStrides({1}), - mImpl(Registrar<Tensor>::create({"cpu", NativeType<VT>::type})(0, 1)), + mImpl(Registrar<Tensor>::create({"cpu", NativeType<VT>::type})(0, std::vector<std::size_t>())), mSize(1) { *static_cast<VT*>(mImpl->rawPtr()) = static_cast<VT>(val); } @@ -303,7 +303,7 @@ class Tensor : public Data, * @brief Get the data type enum. * @return constexpr DataType */ - constexpr DataType dataType() const { return mDataType; } + constexpr DataType dataType() const noexcept { return mDataType; } /** * @brief Set the DataType of the Tensor and converts data @@ -346,7 +346,7 @@ class Tensor : public Data, * @return true * @return false */ - bool hasImpl() const { return (mImpl) ? true : false; } + bool hasImpl() const noexcept { return mImpl ? true : false; } /** * @brief Get number of dimensions of the Tensor. @@ -381,13 +381,13 @@ class Tensor : public Data, * @brief Return true if Tensor is contiguous in memory. * @return bool */ - constexpr bool isContiguous() const { return mContiguous; } + constexpr bool isContiguous() const noexcept { return mContiguous; } /** * @brief Get the number of elements in the Tensor object. * @return constexpr std::size_t */ - constexpr std::size_t size() const { return mSize; } + constexpr std::size_t size() const noexcept { return mSize; } /** * @brief Change the dimensions of the Tensor object according to the given argument. diff --git a/src/operator/Add.cpp b/src/operator/Add.cpp index a69a77fc6..a54302d06 100644 --- a/src/operator/Add.cpp +++ b/src/operator/Add.cpp @@ -9,7 +9,8 @@ * ********************************************************************************/ -#include <cstddef> // std::size_t +#include <cstddef> // std::size_t +#include <stdexcept> // std::runtime_error #include <string> #include <vector> @@ -42,19 +43,15 @@ void Aidge::Add_Op::computeOutputDims() { std::vector<std::size_t> outDims(outNbDims, 1); for (auto it = outDims.rbegin(); it != outDims.rend(); ++it) { - for (size_t i = 0; i < inputsDims.size(); i++) { + for (std::size_t i = 0; i < nbInputs(); ++i) { if(!inputsDims[i].empty()) { - std::size_t dim = inputsDims[i].back(); + const std::size_t dim = inputsDims[i].back(); inputsDims[i].pop_back(); - if (*it != dim) { - if(dim != 1) { - if (*it != 1) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Add operation"); - } - else { - *it = dim; - } - } + if (*it == 1) { + *it = dim; + } + else if ((dim != *it) && (dim != 1)) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Add operation"); } } } diff --git a/src/operator/Div.cpp b/src/operator/Div.cpp index 66221ce6a..6b55338f4 100644 --- a/src/operator/Div.cpp +++ b/src/operator/Div.cpp @@ -8,12 +8,11 @@ * SPDX-License-Identifier: EPL-2.0 * ********************************************************************************/ -#include <algorithm> -#include <cassert> -#include <cstddef> + +#include <cstddef> // std::size_t +#include <stdexcept> // std::runtime_error #include <string> #include <vector> -#include <utility> #include "aidge/backend/OperatorImpl.hpp" #include "aidge/operator/Div.hpp" @@ -30,30 +29,24 @@ void Aidge::Div_Op::computeOutputDims() { if (!getInput(0)->empty() && !getInput(1)->empty()) { - std::vector<std::vector<std::size_t>> inputsDims{getInput(0)->dims(), getInput(1)->dims()}; - - std::vector<std::size_t> outDims = (inputsDims[0].size() >= inputsDims[1].size()) ? - inputsDims[0] : inputsDims[1]; - - std::vector<std::size_t>::iterator it = outDims.end(); - while (it != outDims.begin()) { - --it; - for (size_t i = 0; i < inputsDims.size(); i++) { - if(!inputsDims[i].empty()) { - std::size_t dim = inputsDims[i].back(); - inputsDims[i].pop_back(); - if (*it != dim) { - if(dim != 1) { - if (*it != 1) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Div Operation"); - } - else { - *it = dim; - } - } - } - } + const std::vector<std::size_t>& inputsDims0 = getInput(0)->dims(); + const std::vector<std::size_t>& inputsDims1 = getInput(1)->dims(); + + std::vector<std::size_t> outDims = (inputsDims0.size() >= inputsDims1.size()) ? inputsDims0 : inputsDims1; + const std::vector<std::size_t>& lowDims = (inputsDims0.size() < inputsDims1.size()) ? inputsDims0 : inputsDims1; + + std::size_t out_id = outDims.size() - 1; + std::size_t low_id = lowDims.size() - 1; + std::size_t i = 0; + while (i++ < lowDims.size()) { + if (outDims[out_id] == 1) { + outDims[out_id] = lowDims[low_id]; + } + else if ((lowDims[low_id] != 1) && (lowDims[low_id] != outDims[out_id])) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Div Operation"); } + --out_id; + --low_id; } mOutputs[0]->resize(outDims); } diff --git a/src/operator/Mul.cpp b/src/operator/Mul.cpp index 5b705c603..e6d8b017c 100644 --- a/src/operator/Mul.cpp +++ b/src/operator/Mul.cpp @@ -8,11 +8,11 @@ * SPDX-License-Identifier: EPL-2.0 * ********************************************************************************/ -#include <algorithm> -#include <cassert> -#include <cstddef> + +#include <cstddef> // std::size_t +#include <stdexcept> // std::runtime_error +#include <string> #include <vector> -#include <utility> #include "aidge/backend/OperatorImpl.hpp" #include "aidge/operator/Mul.hpp" @@ -29,30 +29,24 @@ void Aidge::Mul_Op::computeOutputDims() { if (!getInput(0)->empty() && !getInput(1)->empty()) { - std::vector<std::vector<std::size_t>> inputsDims{getInput(0)->dims(), getInput(1)->dims()}; - - std::vector<std::size_t> outDims = (inputsDims[0].size() >= inputsDims[1].size()) ? - inputsDims[0] : inputsDims[1]; - - std::vector<std::size_t>::iterator it = outDims.end(); - while (it != outDims.begin()) { - --it; - for (size_t i = 0; i < inputsDims.size(); i++) { - if(!inputsDims[i].empty()) { - std::size_t dim = inputsDims[i].back(); - inputsDims[i].pop_back(); - if (*it != dim) { - if(dim != 1) { - if (*it != 1) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Mul Operation"); - } - else { - *it = dim; - } - } - } - } + const std::vector<std::size_t>& inputsDims0 = getInput(0)->dims(); + const std::vector<std::size_t>& inputsDims1 = getInput(1)->dims(); + + std::vector<std::size_t> outDims = (inputsDims0.size() >= inputsDims1.size()) ? inputsDims0 : inputsDims1; + const std::vector<std::size_t>& lowDims = (inputsDims0.size() < inputsDims1.size()) ? inputsDims0 : inputsDims1; + + std::size_t out_id = outDims.size() - 1; + std::size_t low_id = lowDims.size() - 1; + std::size_t i = 0; + while (i++ < lowDims.size()) { + if (outDims[out_id] == 1) { + outDims[out_id] = lowDims[low_id]; + } + else if ((lowDims[low_id] != 1) && (lowDims[low_id] != outDims[out_id])) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Div Operation"); } + --out_id; + --low_id; } mOutputs[0]->resize(outDims); } diff --git a/src/operator/Pow.cpp b/src/operator/Pow.cpp index 850e32173..5e29eae0c 100644 --- a/src/operator/Pow.cpp +++ b/src/operator/Pow.cpp @@ -8,11 +8,11 @@ * SPDX-License-Identifier: EPL-2.0 * ********************************************************************************/ -#include <algorithm> -#include <cassert> -#include <cstddef> + +#include <cstddef> // std::size_t +#include <stdexcept> // std::runtime_error +#include <string> #include <vector> -#include <utility> #include "aidge/backend/OperatorImpl.hpp" #include "aidge/operator/Pow.hpp" @@ -29,30 +29,24 @@ void Aidge::Pow_Op::computeOutputDims() { if (!getInput(0)->empty() && !getInput(1)->empty()) { - std::vector<std::vector<std::size_t>> inputsDims{getInput(0)->dims(), getInput(1)->dims()}; - - std::vector<std::size_t> outDims = (inputsDims[0].size() >= inputsDims[1].size()) ? - inputsDims[0] : inputsDims[1]; - - std::vector<std::size_t>::iterator it = outDims.end(); - while (it != outDims.begin()) { - --it; - for (size_t i = 0; i < inputsDims.size(); i++) { - if(!inputsDims[i].empty()) { - std::size_t dim = inputsDims[i].back(); - inputsDims[i].pop_back(); - if (*it != dim) { - if(dim != 1) { - if (*it != 1) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Pow Operation"); - } - else { - *it = dim; - } - } - } - } + const std::vector<std::size_t>& inputsDims0 = getInput(0)->dims(); + const std::vector<std::size_t>& inputsDims1 = getInput(1)->dims(); + + std::vector<std::size_t> outDims = (inputsDims0.size() >= inputsDims1.size()) ? inputsDims0 : inputsDims1; + const std::vector<std::size_t>& lowDims = (inputsDims0.size() < inputsDims1.size()) ? inputsDims0 : inputsDims1; + + std::size_t out_id = outDims.size() - 1; + std::size_t low_id = lowDims.size() - 1; + std::size_t i = 0; + while (i++ < lowDims.size()) { + if (outDims[out_id] == 1) { + outDims[out_id] = lowDims[low_id]; + } + else if ((lowDims[low_id] != 1) && (lowDims[low_id] != outDims[out_id])) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Div Operation"); } + --out_id; + --low_id; } mOutputs[0]->resize(outDims); } diff --git a/src/operator/Sub.cpp b/src/operator/Sub.cpp index 1fe41140d..9d933bf6c 100644 --- a/src/operator/Sub.cpp +++ b/src/operator/Sub.cpp @@ -8,11 +8,11 @@ * SPDX-License-Identifier: EPL-2.0 * ********************************************************************************/ -#include <algorithm> -#include <cassert> -#include <cstddef> + +#include <cstddef> // std::size_t +#include <stdexcept> // std::runtime_error +#include <string> #include <vector> -#include <utility> #include "aidge/backend/OperatorImpl.hpp" #include "aidge/operator/Sub.hpp" @@ -29,30 +29,24 @@ void Aidge::Sub_Op::computeOutputDims() { if (!getInput(0)->empty() && !getInput(1)->empty()) { - std::vector<std::vector<std::size_t>> inputsDims{getInput(0)->dims(), getInput(1)->dims()}; - - std::vector<std::size_t> outDims = (inputsDims[0].size() >= inputsDims[1].size()) ? - inputsDims[0] : inputsDims[1]; - - std::vector<std::size_t>::iterator it = outDims.end(); - while (it != outDims.begin()) { - --it; - for (size_t i = 0; i < inputsDims.size(); i++) { - if(!inputsDims[i].empty()) { - std::size_t dim = inputsDims[i].back(); - inputsDims[i].pop_back(); - if (*it != dim) { - if(dim != 1) { - if (*it != 1) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Sub Operation"); - } - else { - *it = dim; - } - } - } - } + const std::vector<std::size_t>& inputsDims0 = getInput(0)->dims(); + const std::vector<std::size_t>& inputsDims1 = getInput(1)->dims(); + + std::vector<std::size_t> outDims = (inputsDims0.size() >= inputsDims1.size()) ? inputsDims0 : inputsDims1; + const std::vector<std::size_t>& lowDims = (inputsDims0.size() < inputsDims1.size()) ? inputsDims0 : inputsDims1; + + std::size_t out_id = outDims.size() - 1; + std::size_t low_id = lowDims.size() - 1; + std::size_t i = 0; + while (i++ < lowDims.size()) { + if (outDims[out_id] == 1) { + outDims[out_id] = lowDims[low_id]; + } + else if ((lowDims[low_id] != 1) && (lowDims[low_id] != outDims[out_id])) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Unsopported Tensor shape for Div Operation"); } + --out_id; + --low_id; } mOutputs[0]->resize(outDims); } -- GitLab