From d39f04f3c3662e0eafdeb2a805fd6f6a3b8be296 Mon Sep 17 00:00:00 2001 From: Olivier BICHLER <olivier.bichler@cea.fr> Date: Fri, 14 Feb 2025 17:57:29 +0100 Subject: [PATCH] Add Select, Mod and CryptoHash operators --- include/aidge/operator/CryptoHash.hpp | 126 +++++++++++++++++ include/aidge/operator/Mod.hpp | 128 ++++++++++++++++++ include/aidge/operator/Select.hpp | 92 +++++++++++++ include/aidge/utils/Registrar.hpp | 13 +- python_binding/operator/pybind_CryptoHash.cpp | 38 ++++++ python_binding/operator/pybind_Mod.cpp | 60 ++++++++ python_binding/operator/pybind_Select.cpp | 49 +++++++ python_binding/pybind_core.cpp | 6 + src/operator/CryptoHash.cpp | 64 +++++++++ src/operator/Mod.cpp | 89 ++++++++++++ src/operator/Select.cpp | 110 +++++++++++++++ 11 files changed, 774 insertions(+), 1 deletion(-) create mode 100644 include/aidge/operator/CryptoHash.hpp create mode 100644 include/aidge/operator/Mod.hpp create mode 100644 include/aidge/operator/Select.hpp create mode 100644 python_binding/operator/pybind_CryptoHash.cpp create mode 100644 python_binding/operator/pybind_Mod.cpp create mode 100644 python_binding/operator/pybind_Select.cpp create mode 100644 src/operator/CryptoHash.cpp create mode 100644 src/operator/Mod.cpp create mode 100644 src/operator/Select.cpp diff --git a/include/aidge/operator/CryptoHash.hpp b/include/aidge/operator/CryptoHash.hpp new file mode 100644 index 000000000..266adecd3 --- /dev/null +++ b/include/aidge/operator/CryptoHash.hpp @@ -0,0 +1,126 @@ +/******************************************************************************** + * 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_OPERATOR_CRYPTOHASH_H_ +#define AIDGE_CORE_OPERATOR_CRYPTOHASH_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "aidge/utils/Registrar.hpp" +#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/graph/Node.hpp" +#include "aidge/utils/StaticAttributes.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge { +/** + * @enum CryptoHashAttr + * @brief Attributes for the CryptoHash operator. + */ +enum class CryptoHashAttr { + CryptoHashFunction ///< Cryptographic hash function to use. +}; + +/** + * @enum CryptoHashFunction + * @brief Cryptographic hash function. + */ +enum class CryptoHashFunction { + SHA256 ///< SHA256 +}; + +/** + * @brief Produce a cryptographic hash from the input. + * + * @see OperatorTensor + * @see Registrable + */ +class CryptoHash_Op : public OperatorTensor, + public Registrable<CryptoHash_Op, std::string, std::function<std::shared_ptr<OperatorImpl>(const CryptoHash_Op&)>> { + +public: + static const std::string Type; + +private: + using Attributes_ = StaticAttributes<CryptoHashAttr, CryptoHashFunction>; + template <CryptoHashAttr e> using attr = typename Attributes_::template attr<e>; + const std::shared_ptr<Attributes_> mAttributes; + +public: + CryptoHash_Op(); + + /** + * @brief Copy-constructor. + * @param op CryptoHash_Op to copy. + * @details Copies the operator attributes and its output tensor(s), but not + * its input tensors. The new operator has no associated input. + */ + CryptoHash_Op(const CryptoHash_Op& op); + + /** + * @brief Clone the operator using its copy-constructor. + * @see Operator::CryptoHash_Op + */ + std::shared_ptr<Operator> clone() const override; + + bool forwardDims(bool allowDataDependency = false) override final; + + void setBackend(const std::string& name, DeviceIdx_t device = 0) override; + std::set<std::string> getAvailableBackends() const override; + + /** + * @brief Get the attributes of the operator. + * @return A shared pointer to the attributes. + */ + inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; } + + /** + * @brief Get or modify the `crypto_hash_function` attribute. + * @return Reference to the `crypto_hash_function` attribute. + */ + inline CryptoHashFunction& cryptoHashFunction() const noexcept { return mAttributes->getAttr<CryptoHashAttr::CryptoHashFunction>(); } + + static const std::vector<std::string> getInputsName(){ + return {"data_input"}; + } + static const std::vector<std::string> getOutputsName(){ + return {"data_output"}; + } +}; + +std::shared_ptr<Node> CryptoHash(const std::string& name = ""); + +} // namespace Aidge + +namespace { + +/** + * @brief EnumStrings specialization for CryptoHashAttr. + */ +template <> +const char* const EnumStrings<Aidge::CryptoHashAttr>::data[] = { + "crypto_hash_function" +}; + +/** + * @brief EnumStrings specialization for CryptoHashFunction. + */ +template <> +const char* const EnumStrings<Aidge::CryptoHashFunction>::data[] = { + "sha256" +}; + +} // namespace + +#endif /* AIDGE_CORE_OPERATOR_CRYPTOHASH_H_ */ diff --git a/include/aidge/operator/Mod.hpp b/include/aidge/operator/Mod.hpp new file mode 100644 index 000000000..56a9381e0 --- /dev/null +++ b/include/aidge/operator/Mod.hpp @@ -0,0 +1,128 @@ +/******************************************************************************** + * 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_OPERATOR_MOD_H_ +#define AIDGE_CORE_OPERATOR_MOD_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "aidge/utils/Registrar.hpp" +#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/graph/Node.hpp" +#include "aidge/utils/StaticAttributes.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge { +enum class ModAttr { +/** + * @brief Enable fmod like behavior + * + * Whether the operator should behave like fmod (default is false meaning it + * will do integer mods); Set this to true to force fmod treatment + */ + Fmod +}; + +/** + * @brief Description of an element-wise binary modulus operation on input Tensors, + * supporting NumPy broadcasting. + * + * For each pair of elements x and y from the input Tensors, the function + * is defined as: + * `f(x, y) = x mod y + * + * Broadcasting adjusts shapes of the input Tensors to make them compatible: + * - Tensors are aligned from the rightmost dimensions. + * - Dimensions are compatible if they are equal, one of them is 1, or missing. + * + * The output Tensor shape is determined by taking the maximum size along + * each dimension of the input Tensors after broadcasting. + * + * Examples: + * 1. Input A: (3, 4, 2), Input B: (2), Output: (3, 4, 2) + * 2. Input A: (1, 5, 3), Input B: (2, 1, 3), Output: (2, 5, 3) + * + * @see OperatorTensor + * @see Registrable + */ +class Mod_Op : public OperatorTensor, + public Registrable<Mod_Op, std::string, std::function<std::shared_ptr<OperatorImpl>(const Mod_Op&)>> { + +public: + static const std::string Type; + +private: + using Attributes_ = StaticAttributes<ModAttr, bool>; + template <ModAttr e> using attr = typename Attributes_::template attr<e>; + const std::shared_ptr<Attributes_> mAttributes; + +public: + Mod_Op(); + + /** + * @brief Copy-constructor. + * @param op Mod_Op to copy. + * @details Copies the operator attributes and its output tensor(s), but not + * its input tensors. The new operator has no associated input. + */ + Mod_Op(const Mod_Op& op); + + /** + * @brief Clone the operator using its copy-constructor. + * @see Operator::Mod_Op + */ + std::shared_ptr<Operator> clone() const override; + + bool forwardDims(bool allowDataDependency = false) override final; + + void setBackend(const std::string& name, DeviceIdx_t device = 0) override; + std::set<std::string> getAvailableBackends() const override; + + /** + * @brief Get the attributes of the operator. + * @return A shared pointer to the attributes. + */ + inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; } + + /** + * @brief Get or modify the `fmod` attribute. + * @return Reference to the `fmod` attribute. + */ + inline bool& fmod() const noexcept { return mAttributes->getAttr<ModAttr::Fmod>(); } + + static const std::vector<std::string> getInputsName(){ + return {"dividend", "divisor"}; + } + static const std::vector<std::string> getOutputsName(){ + return {"remainder"}; + } +}; + +std::shared_ptr<Node> Mod(const std::string& name = ""); + +} // namespace Aidge + +namespace { + +/** + * @brief EnumStrings specialization for ModAttr. + */ +template <> +const char* const EnumStrings<Aidge::ModAttr>::data[] = { + "fmod" +}; + +} // namespace + +#endif /* AIDGE_CORE_OPERATOR_MOD_H_ */ diff --git a/include/aidge/operator/Select.hpp b/include/aidge/operator/Select.hpp new file mode 100644 index 000000000..4dcace84e --- /dev/null +++ b/include/aidge/operator/Select.hpp @@ -0,0 +1,92 @@ +/******************************************************************************** + * 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_OPERATOR_SELECT_H_ +#define AIDGE_CORE_OPERATOR_SELECT_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/graph/Node.hpp" +#include "aidge/utils/ErrorHandling.hpp" +#include "aidge/utils/Types.h" +#include "aidge/utils/Registrar.hpp" + +namespace Aidge { +/** + * @brief Implementation of the Select operator. + * @note This operator implementation is agnostic to the backend and is located here instead of in aidge_backend. + */ +class Select_OpImpl : public OperatorImpl { +public: + /** + * @brief Constructor for Select_OpImpl. + * @param[in] op The Operator instance. + * @param[in] backend The backend name (optional). + */ + Select_OpImpl(const Operator& op, const std::string& backend = "") + : OperatorImpl(op, backend) {} + + /** + * @brief Perform the forward operation for the reshape. + */ + void forward() override; + void backward() override; +}; + +/** + * @brief + * @see OperatorTensor + * @see Registrable + */ +class Select_Op : public OperatorTensor, + public Registrable<Select_Op, + std::string, + std::function<std::shared_ptr<OperatorImpl>(const Select_Op&)>> +{ +public: + static const std::string Type; + + Select_Op(const Aidge::IOIndex_t nbIn); + + /** + * @brief Copy-constructor. + * @param op Select_Op to copy. + * @details Copies the operator attributes and its output tensor(s), but not + * its input tensors. The new operator has no associated input. + */ + Select_Op(const Select_Op& op); + + /** + * @brief Clone the operator using its copy-constructor. + * @see Operator::Select_Op + */ + std::shared_ptr<Operator> clone() const override; + + bool forwardDims(bool allowDataDependency = false) override final; + + void setBackend(const std::string& name, DeviceIdx_t device = 0) override; + std::set<std::string> getAvailableBackends() const override; + + static const std::vector<std::string> getInputsName() { + return {"select", "data_input_0", "data_input_n"}; + } + static const std::vector<std::string> getOutputsName() { + return {"data_output"}; + } +}; + +std::shared_ptr<Node> Select(const IOIndex_t nbIn, const std::string& name = ""); +} + +#endif /* AIDGE_CORE_OPERATOR_SELECT_H_ */ diff --git a/include/aidge/utils/Registrar.hpp b/include/aidge/utils/Registrar.hpp index 28dab05f8..a2f33eea5 100644 --- a/include/aidge/utils/Registrar.hpp +++ b/include/aidge/utils/Registrar.hpp @@ -76,9 +76,20 @@ struct Registrar { } static auto create(const registrar_key& key) { - AIDGE_ASSERT(exists(key), "missing or invalid registrar key: {} for registrable object {}\nDid you include/import the corresponding module?\nIf so, it is possible that the object is not yet supported.", key, typeid(C).name()); + if (!exists(key)) { + Log::error("missing or invalid registrar key: {} for registrable object {}\nDid you include/import the corresponding module?\nIf so, it is possible that the object is not yet supported.", key, typeid(C).name()); + + Log::info("Available registrar keys are:"); + for(const auto& keyValue : C::registry()) { + Log::info("- {}", keyValue.first); + } + + AIDGE_THROW_OR_ABORT(std::runtime_error, "missing or invalid registrar key"); + } + return C::registry().at(key); } + static std::set<registrar_key> getKeys(){ std::set<registrar_key> keys; for(const auto& keyValue : C::registry()) diff --git a/python_binding/operator/pybind_CryptoHash.cpp b/python_binding/operator/pybind_CryptoHash.cpp new file mode 100644 index 000000000..923f91b60 --- /dev/null +++ b/python_binding/operator/pybind_CryptoHash.cpp @@ -0,0 +1,38 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + + #include <pybind11/pybind11.h> + + #include "aidge/data/Tensor.hpp" + #include "aidge/operator/CryptoHash.hpp" + #include "aidge/operator/OperatorTensor.hpp" + + namespace py = pybind11; + namespace Aidge { + + void init_CryptoHash(py::module& m) { + py::enum_<CryptoHashFunction>(m, "crypto_hash_function") + .value("SHA256", CryptoHashFunction::SHA256) + .export_values(); + + py::class_<CryptoHash_Op, std::shared_ptr<CryptoHash_Op>, OperatorTensor>(m, "CryptoHashOp", py::multiple_inheritance()) + .def(py::init<>()) + .def_static("get_inputs_name", &CryptoHash_Op::getInputsName) + .def_static("get_outputs_name", &CryptoHash_Op::getOutputsName) + .def_readonly_static("Type", &CryptoHash_Op::Type); + + declare_registrable<CryptoHash_Op>(m, "CryptoHashOp"); + + m.def("CryptoHash", &CryptoHash, py::arg("name") = ""); + } + + } // namespace Aidge + \ No newline at end of file diff --git a/python_binding/operator/pybind_Mod.cpp b/python_binding/operator/pybind_Mod.cpp new file mode 100644 index 000000000..aa88f2068 --- /dev/null +++ b/python_binding/operator/pybind_Mod.cpp @@ -0,0 +1,60 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + + #include <pybind11/pybind11.h> + + #include "aidge/data/Tensor.hpp" + #include "aidge/operator/Mod.hpp" + #include "aidge/operator/OperatorTensor.hpp" + + namespace py = pybind11; + namespace Aidge { + + void init_Mod(py::module& m) { + py::class_<Mod_Op, std::shared_ptr<Mod_Op>, OperatorTensor>(m, "ModOp", py::multiple_inheritance(), + R"mydelimiter( + Initialize a Mod operator. + This operator performs element-wise binary modulus between two input tensors. + The operation is defined as: + Output = Input1 mod Input2 + The output tensor shape is determined by taking the maximum size along each dimension of the input tensors after broadcasting. + Examples: + Input A: (3, 4, 2), Input B: (2), Output: (3, 4, 2) + Input A: (1, 5, 3), Input B: (2, 1, 3), Output: (2, 5, 3) + :param name : Name of the node (optional). + :type name : str + )mydelimiter") + .def(py::init<>()) + .def_static("get_inputs_name", &Mod_Op::getInputsName) + .def_static("get_outputs_name", &Mod_Op::getOutputsName) + .def_readonly_static("Type", &Mod_Op::Type); + + declare_registrable<Mod_Op>(m, "ModOp"); + + m.def("Mod", &Mod, py::arg("name") = "", + R"mydelimiter( + Initialize a node containing a Mod operator that performs element-wise binary modulus between two tensors. + The operation is defined as: + Output = Input1 mod Input2 + The output tensor shape is determined by taking the maximum size along each dimension of the input tensors after broadcasting. + Examples: + Input A: (3, 4, 2), Input B: (2), Output: (3, 4, 2) + Input A: (1, 5, 3), Input B: (2, 1, 3), Output: (2, 5, 3) + + :param name : Name of the node (optional). + :type name : str + :return: A node containing the Mod operator. + :rtype: :py:class:`ModOp` + )mydelimiter"); + } + + } // namespace Aidge + \ No newline at end of file diff --git a/python_binding/operator/pybind_Select.cpp b/python_binding/operator/pybind_Select.cpp new file mode 100644 index 000000000..0cb858acd --- /dev/null +++ b/python_binding/operator/pybind_Select.cpp @@ -0,0 +1,49 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + +#include <pybind11/pybind11.h> +#include <string> + +#include "aidge/data/Tensor.hpp" +#include "aidge/operator/Select.hpp" +#include "aidge/operator/OperatorTensor.hpp" + +namespace py = pybind11; +namespace Aidge { + +void init_Select(py::module& m) { + py::class_<Select_Op, std::shared_ptr<Select_Op>, OperatorTensor>(m, "SelectOp", py::multiple_inheritance(), + R"mydelimiter( + Initialize a Select operator. + + :param nb_inputs : The number of input tensors to select from. + :type nb_inputs : :py:class:`int` + )mydelimiter") + .def(py::init<const IOIndex_t>(), + py::arg("nb_inputs")) + .def_static("get_inputs_name", &Select_Op::getInputsName) + .def_static("get_outputs_name", &Select_Op::getOutputsName) + .def_readonly_static("Type", &Select_Op::Type); + + declare_registrable<Select_Op>(m, "SelectOp"); + + m.def("Select", &Select, py::arg("nb_inputs"), py::arg("name") = "", + R"mydelimiter( + Initialize a node containing a Select operator. + + :param nb_inputs : The number of input tensors to select from. + :type nb_inputs : :py:class:`int` + :param name : Name of the node. + :type name : :py:class:`str` + )mydelimiter"); +} + +} // namespace Aidge diff --git a/python_binding/pybind_core.cpp b/python_binding/pybind_core.cpp index ef1111b39..b2aa93dc9 100644 --- a/python_binding/pybind_core.cpp +++ b/python_binding/pybind_core.cpp @@ -48,6 +48,7 @@ void init_Concat(py::module&); void init_ConstantOfShape(py::module&); void init_Conv(py::module&); void init_ConvDepthWise(py::module&); +void init_CryptoHash(py::module&); void init_DepthToSpace(py::module&); void init_Div(py::module&); void init_Equal(py::module&); @@ -67,6 +68,7 @@ void init_MatMul(py::module&); void init_MaxPooling(py::module&); void init_Memorize(py::module&); void init_MetaOperatorDefs(py::module&); +void init_Mod(py::module&); void init_Mul(py::module&); void init_Pad(py::module&); void init_Pop(py::module&); @@ -79,6 +81,7 @@ void init_Reshape(py::module&); void init_Resize(py::module&); void init_Round(py::module&); void init_Scaling(py::module&); +void init_Select(py::module&); void init_Shape(py::module&); void init_Sigmoid(py::module&); void init_Slice(py::module&); @@ -149,6 +152,7 @@ void init_Aidge(py::module& m) { init_Conv(m); init_ConvDepthWise(m); init_ConstantOfShape(m); + init_CryptoHash(m); init_DepthToSpace(m); init_Div(m); init_Equal(m); @@ -168,6 +172,7 @@ void init_Aidge(py::module& m) { init_MaxPooling(m); init_Memorize(m); init_MetaOperatorDefs(m); + init_Mod(m); init_Mul(m); init_Pad(m); init_Pop(m); @@ -179,6 +184,7 @@ void init_Aidge(py::module& m) { init_Resize(m); init_Round(m); init_Scaling(m); + init_Select(m); init_Shape(m); init_Sigmoid(m); init_Slice(m); diff --git a/src/operator/CryptoHash.cpp b/src/operator/CryptoHash.cpp new file mode 100644 index 000000000..f6656cd61 --- /dev/null +++ b/src/operator/CryptoHash.cpp @@ -0,0 +1,64 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + +#include <cstddef> // std::size_t +#include <stdexcept> // std::runtime_error +#include <string> +#include <vector> + +#include "aidge/data/Tensor.hpp" +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/operator/CryptoHash.hpp" +#include "aidge/utils/Types.h" +#include "aidge/utils/ErrorHandling.hpp" + +const std::string Aidge::CryptoHash_Op::Type = "CryptoHash"; + +Aidge::CryptoHash_Op::CryptoHash_Op() + : OperatorTensor(Type, {InputCategory::Data}, 1), + mAttributes(std::make_shared<Attributes_>( + attr<CryptoHashAttr::CryptoHashFunction>(CryptoHashFunction::SHA256))) +{} + +Aidge::CryptoHash_Op::CryptoHash_Op(const Aidge::CryptoHash_Op& op) + : OperatorTensor(op), + mAttributes(op.mAttributes) +{ + if (op.mImpl){ + SET_IMPL_MACRO(CryptoHash_Op, *this, op.backend()); + }else{ + mImpl = nullptr; + } +} + +std::shared_ptr<Aidge::Operator> Aidge::CryptoHash_Op::clone() const { + return std::make_shared<CryptoHash_Op>(*this); +} + +bool Aidge::CryptoHash_Op::forwardDims(bool /*allowDataDependency*/) { + mOutputs[0]->resize({256}); + return true; +} + +void Aidge::CryptoHash_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t device) { + SET_IMPL_MACRO(CryptoHash_Op, *this, name); + mOutputs[0]->setBackend(name, device); +} + +std::set<std::string> Aidge::CryptoHash_Op::getAvailableBackends() const { + return Registrar<CryptoHash_Op>::getKeys(); +} + +/////////////////////////////////////////// + +std::shared_ptr<Aidge::Node> Aidge::CryptoHash(const std::string& name) { + return std::make_shared<Node>(std::make_shared<CryptoHash_Op>(), name); +} diff --git a/src/operator/Mod.cpp b/src/operator/Mod.cpp new file mode 100644 index 000000000..038a3c284 --- /dev/null +++ b/src/operator/Mod.cpp @@ -0,0 +1,89 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + +#include <cstddef> // std::size_t +#include <stdexcept> // std::runtime_error +#include <string> +#include <vector> + +#include "aidge/data/Tensor.hpp" +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/operator/Mod.hpp" +#include "aidge/utils/Types.h" +#include "aidge/utils/ErrorHandling.hpp" + +const std::string Aidge::Mod_Op::Type = "Mod"; + +Aidge::Mod_Op::Mod_Op() + : OperatorTensor(Type, {InputCategory::Data, InputCategory::Data}, 1), + mAttributes(std::make_shared<Attributes_>( + attr<ModAttr::Fmod>(false))) +{} + +Aidge::Mod_Op::Mod_Op(const Aidge::Mod_Op& op) + : OperatorTensor(op), + mAttributes(op.mAttributes) +{ + if (op.mImpl){ + SET_IMPL_MACRO(Mod_Op, *this, op.backend()); + }else{ + mImpl = nullptr; + } +} + +std::shared_ptr<Aidge::Operator> Aidge::Mod_Op::clone() const { + return std::make_shared<Mod_Op>(*this); +} + +bool Aidge::Mod_Op::forwardDims(bool /*allowDataDependency*/) { + if (inputsAssociated()) { + 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, "Incompatible Tensor shape for Mod Operation: {} for input#0 vs {} for input#1", + inputsDims0, inputsDims1); + } + --out_id; + --low_id; + } + mOutputs[0]->resize(outDims); + return true; + } + + return false; +} + + +void Aidge::Mod_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t device) { + SET_IMPL_MACRO(Mod_Op, *this, name); + mOutputs[0]->setBackend(name, device); +} + +std::set<std::string> Aidge::Mod_Op::getAvailableBackends() const { + return Registrar<Mod_Op>::getKeys(); +} + +/////////////////////////////////////////// + +std::shared_ptr<Aidge::Node> Aidge::Mod(const std::string& name) { + return std::make_shared<Node>(std::make_shared<Mod_Op>(), name); +} \ No newline at end of file diff --git a/src/operator/Select.cpp b/src/operator/Select.cpp new file mode 100644 index 000000000..67e792cd0 --- /dev/null +++ b/src/operator/Select.cpp @@ -0,0 +1,110 @@ +/******************************************************************************** + * 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 + * + ********************************************************************************/ + +#include <cstddef> // std::size_t +#include <stdexcept> // std::runtime_error +#include <string> +#include <vector> + +#include "aidge/data/Tensor.hpp" +#include "aidge/operator/Select.hpp" +#include "aidge/utils/Types.h" +#include "aidge/utils/ErrorHandling.hpp" +#include "aidge/utils/Registrar.hpp" + +void Aidge::Select_OpImpl::forward() { + const Select_Op& op = dynamic_cast<const Select_Op&>(mOp); + AIDGE_ASSERT(op.getInput(0)->size() > 0, "Select input is empty!"); + + std::shared_ptr<Tensor> selectFallback; + const auto& select = op.getInput(0)->refCastFrom(selectFallback, DataType::Int32, "cpu"); + const auto selectVal = select.get<int32_t>(0); + AIDGE_ASSERT(selectVal >= 0 && selectVal < op.nbInputs() - 1, "Select input out of range. Expected value in range [0, {}], got {}", op.nbInputs() - 2, selectVal); + + op.getOutput(0)->getImpl()->copy(op.getInput(selectVal + 1)->getImpl()->rawPtr(), op.getInput(selectVal + 1)->size()); +} + +void Aidge::Select_OpImpl::backward() { + const Select_Op& op = dynamic_cast<const Select_Op&>(mOp); + AIDGE_ASSERT(op.getInput(0)->size() > 0, "Select input is empty!"); + + std::shared_ptr<Tensor> selectFallback; + const auto& select = op.getInput(0)->refCastFrom(selectFallback, DataType::Int32, "cpu"); + const auto selectVal = select.get<int32_t>(0); + AIDGE_ASSERT(selectVal >= 0 && selectVal < op.nbInputs() - 1, "Select input out of range. Expected value in range [0, {}], got {}", op.nbInputs() - 2, selectVal); + + op.getInput(selectVal + 1)->grad()->getImpl()->copy(op.getOutput(0)->grad()->getImpl()->rawPtr(), op.getOutput(0)->size()); +} + +////////////////////////////////////////////////// + +const std::string Aidge::Select_Op::Type = "Select"; + +Aidge::Select_Op::Select_Op(const Aidge::IOIndex_t nbIn) + : OperatorTensor(Type, std::vector<InputCategory>(nbIn + 1, InputCategory::Data), 1) +{ + // ctor + AIDGE_ASSERT(nbIn > 1, "Select operator should have at least two inputs."); + mImpl = std::make_shared<Select_OpImpl>(*this); +} + +Aidge::Select_Op::Select_Op(const Select_Op& op) + : OperatorTensor(op) +{ + if (!op.backend().empty()) { + SET_IMPL_MACRO(Select_Op, *this, op.backend()); + } + else { + mImpl = std::make_shared<Select_OpImpl>(*this); + } +} + +std::shared_ptr<Aidge::Operator> Aidge::Select_Op::clone() const { + return std::make_shared<Select_Op>(*this); +} + +bool Aidge::Select_Op::forwardDims(bool /*allowDataDependency*/) { + if (inputsAssociated()) { + // First input is select input + const auto expectedDims = getInput(1)->dims(); + for (std::size_t i = 2; i < nbInputs(); ++i) { + if (expectedDims != getInput(i)->dims()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, + "{} operator's inputs should have the same dimensions: expected {} (input #0), given {} (input #{})", + type(), expectedDims, getInput(i)->dims(), i); + } + } + mOutputs[0]->resize(expectedDims); + return true; + } + + return false; +} + +void Aidge::Select_Op::setBackend(const std::string& name, DeviceIdx_t device) { + if (Registrar<Select_Op>::exists({name})){ + SET_IMPL_MACRO(Select_Op, *this, name); + } + else { + mImpl = std::make_shared<Select_OpImpl>(*this); + } + mOutputs[0]->setBackend(name, device); +} + +std::set<std::string> Aidge::Select_Op::getAvailableBackends() const { + return Registrar<Select_Op>::getKeys(); +} + +//////////////////////////////////////////////////////////////////////////////// + +std::shared_ptr<Aidge::Node> Aidge::Select(const Aidge::IOIndex_t nbIn, const std::string& name) { + return std::make_shared<Node>(std::make_shared<Select_Op>(nbIn), name); +} -- GitLab