From a1ca1f8dad00714a0ec1f56a9e403bcd5299efc3 Mon Sep 17 00:00:00 2001 From: hrouis <houssemeddine.rouis92@gmail.com> Date: Fri, 26 Jan 2024 11:41:39 +0100 Subject: [PATCH] add ArithmeticOperator class --- include/aidge/operator/ArithmeticOperator.hpp | 112 ++++++++++ include/aidge/operator/Div.hpp | 20 +- include/aidge/operator/Mul.hpp | 19 +- include/aidge/operator/Pow.hpp | 20 +- include/aidge/operator/Sub.hpp | 20 +- python_binding/operator/pybind_Div.cpp | 4 +- python_binding/operator/pybind_Mul.cpp | 4 +- python_binding/operator/pybind_Pow.cpp | 4 +- python_binding/operator/pybind_Sub.cpp | 4 +- src/operator/ArithmeticOperator.cpp | 192 ++++++++++++++++++ src/operator/Div.cpp | 17 +- src/operator/Mul.cpp | 17 +- src/operator/Pow.cpp | 17 +- src/operator/Sub.cpp | 17 +- 14 files changed, 332 insertions(+), 135 deletions(-) create mode 100644 include/aidge/operator/ArithmeticOperator.hpp create mode 100644 src/operator/ArithmeticOperator.cpp diff --git a/include/aidge/operator/ArithmeticOperator.hpp b/include/aidge/operator/ArithmeticOperator.hpp new file mode 100644 index 000000000..d2a0bfb77 --- /dev/null +++ b/include/aidge/operator/ArithmeticOperator.hpp @@ -0,0 +1,112 @@ +/******************************************************************************** + * Copyright (c) 2024 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_ARITHMETICOPERATOR_H_ +#define AIDGE_CORE_OPERATOR_ARITHMETICOPERATOR_H_ + +#include <memory> +#include <string> +#include <vector> + +#include "aidge/backend/OperatorImpl.hpp" +#include "aidge/data/Tensor.hpp" +#include "aidge/operator/Operator.hpp" +#include "aidge/utils/Types.h" + +namespace Aidge { + +class ArithmeticOperator : public Operator { + /* TODO: Add an attribute specifying the type of Data used by the Operator. + * The same way ``Type`` attribute specifies the type of Operator. Hence this + * attribute could be checked in the forwardDims function to assert Operators + * being used work with Tensors and cast them to OpertorTensor instead of + * Operator. + */ + /* TODO: Maybe change type attribute of Data object by an enum instead of an + * array of char. Faster comparisons. + */ +protected: + std::vector<std::shared_ptr<Tensor>> mInputs; + std::vector<std::shared_ptr<Tensor>> mOutputs; + +public: + ArithmeticOperator() = delete; + + ArithmeticOperator(const std::string& type) + : Operator(type, 2, 0, 1, OperatorType::Tensor), + mInputs(std::vector<std::shared_ptr<Tensor>>(2, nullptr)), + mOutputs(std::vector<std::shared_ptr<Tensor>>(1)) { + mOutputs[0] = std::make_shared<Tensor>(); + mOutputs[0]->setDataType(DataType::Float32); + } + + ArithmeticOperator(const ArithmeticOperator& other) + : Operator(other), + mInputs(std::vector<std::shared_ptr<Tensor>>(2, nullptr)), + mOutputs(std::vector<std::shared_ptr<Tensor>>(1)) { + mOutputs[0] = std::make_shared<Tensor>(); + } + + ~ArithmeticOperator(); + +public: + /////////////////////////////////////////////////// + virtual void associateInput(const IOIndex_t inputIdx, + const std::shared_ptr<Data>& data) override; + /////////////////////////////////////////////////// + + /////////////////////////////////////////////////// + // Tensor access + // input management + void setInput(const IOIndex_t inputIdx, const std::shared_ptr<Data>& data) override final; + void setInput(const IOIndex_t inputIdx, std::shared_ptr<Data>&& data) override final; + const std::shared_ptr<Tensor>& getInput(const IOIndex_t inputIdx) const; + inline std::shared_ptr<Data> getRawInput(const IOIndex_t inputIdx) const override final { + return std::static_pointer_cast<Data>(getInput(inputIdx)); + } + + // output management + void setOutput(const IOIndex_t outputIdx, const std::shared_ptr<Data>& data) override; + void setOutput(const IOIndex_t outputIdx, std::shared_ptr<Data>&& data) override; + virtual const std::shared_ptr<Tensor>& getOutput(const IOIndex_t outputIdx) const; + inline std::shared_ptr<Aidge::Data> getRawOutput(const Aidge::IOIndex_t outputIdx) const override final { + return std::static_pointer_cast<Data>(getOutput(outputIdx)); + } + + static const std::vector<std::string> getInputsName(){ + return {"data_input1", "data_input2"}; + } + static const std::vector<std::string> getOutputsName(){ + return {"data_output"}; + } + /////////////////////////////////////////////////// + + /////////////////////////////////////////////////// + // Tensor dimensions + /** + * @brief For a given output feature area, compute the associated receptive + * field for each data input. + * @param firstIdx First index of the output feature. + * @param outputDims Size of output feature. + * @param outputIdx Index of the output. Default 0. + * @return std::vector<std::pair<std::size_t, std::vector<DimSize_t>>> + * For each dataInput Tensor of the Operator, the first index and dimensions of the feature area. + */ + virtual std::vector<std::pair<std::vector<Aidge::DimSize_t>, std::vector<DimSize_t>>> computeReceptiveField(const std::vector<DimSize_t>& firstEltDims, const std::vector<DimSize_t>& outputDims, const IOIndex_t outputIdx = 0) const; + virtual void computeOutputDims(); + virtual bool outputDimsForwarded() const; + /////////////////////////////////////////////////// + + virtual void setDataType(const DataType& dataType) const override; +}; +} // namespace Aidge + +#endif // AIDGE_CORE_OPERATOR_ARITHMETICOPERATOR_H_ \ No newline at end of file diff --git a/include/aidge/operator/Div.hpp b/include/aidge/operator/Div.hpp index 94b755e0f..ec4319e6b 100644 --- a/include/aidge/operator/Div.hpp +++ b/include/aidge/operator/Div.hpp @@ -17,7 +17,7 @@ #include <vector> #include "aidge/utils/Registrar.hpp" -#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/operator/ArithmeticOperator.hpp" #include "aidge/backend/OperatorImpl.hpp" #include "aidge/data/Tensor.hpp" #include "aidge/graph/Node.hpp" @@ -25,21 +25,19 @@ namespace Aidge { -class Div_Op : public OperatorTensor, +class Div_Op : public ArithmeticOperator, public Registrable<Div_Op, std::string, std::unique_ptr<OperatorImpl>(const Div_Op&)> { public: static const std::string Type; - Div_Op() : OperatorTensor(Type, 2, 0, 1) {} + Div_Op() : ArithmeticOperator(Type) {} /** * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated). * @param op Operator to copy. */ - Div_Op(const Div_Op& op) - : OperatorTensor(op) - { + Div_Op(const Div_Op& op) : ArithmeticOperator(op){ mImpl = op.mImpl ? Registrar<Div_Op>::create(op.mOutputs[0]->getImpl()->backend())(*this) : nullptr; } @@ -51,20 +49,10 @@ public: return std::make_shared<Div_Op>(*this); } - void computeOutputDims() override final; - - void setBackend(const std::string& name, DeviceIdx_t device = 0) override { mImpl = Registrar<Div_Op>::create(name)(*this); mOutputs[0]->setBackend(name, device); } - - static const std::vector<std::string> getInputsName(){ - return {"data_input"}; - } - static const std::vector<std::string> getOutputsName(){ - return {"data_output"}; - } }; inline std::shared_ptr<Node> Div(const std::string& name = "") { diff --git a/include/aidge/operator/Mul.hpp b/include/aidge/operator/Mul.hpp index 78b2fa5f9..2a1ad1d5b 100644 --- a/include/aidge/operator/Mul.hpp +++ b/include/aidge/operator/Mul.hpp @@ -17,7 +17,7 @@ #include <vector> #include "aidge/utils/Registrar.hpp" -#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/operator/ArithmeticOperator.hpp" #include "aidge/backend/OperatorImpl.hpp" #include "aidge/data/Tensor.hpp" #include "aidge/graph/Node.hpp" @@ -28,21 +28,19 @@ namespace Aidge { /** * @brief Tensor element-wise multiplication. */ -class Mul_Op : public OperatorTensor, +class Mul_Op : public ArithmeticOperator, public Registrable<Mul_Op, std::string, std::unique_ptr<OperatorImpl>(const Mul_Op&)> { public: static const std::string Type; - Mul_Op() : OperatorTensor(Type, 2, 0, 1) {} + Mul_Op() : ArithmeticOperator(Type) {} /** * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), * but not its input tensors (the new operator has no input associated). * @param op Operator to copy. */ - Mul_Op(const Mul_Op& op) - : OperatorTensor(op) - { + Mul_Op(const Mul_Op& op) : ArithmeticOperator(op){ mImpl = op.mImpl ? Registrar<Mul_Op>::create(op.mOutputs[0]->getImpl()->backend())(*this) : nullptr; } @@ -54,19 +52,10 @@ public: return std::make_shared<Mul_Op>(*this); } - void computeOutputDims() override final; - void setBackend(const std::string& name, DeviceIdx_t device = 0) override { mImpl = Registrar<Mul_Op>::create(name)(*this); mOutputs[0]->setBackend(name, device); } - - static const std::vector<std::string> getInputsName(){ - return {"data_input"}; - } - static const std::vector<std::string> getOutputsName(){ - return {"data_output"}; - } }; inline std::shared_ptr<Node> Mul(const std::string& name = "") { diff --git a/include/aidge/operator/Pow.hpp b/include/aidge/operator/Pow.hpp index d498cacc7..f1bd3ad51 100644 --- a/include/aidge/operator/Pow.hpp +++ b/include/aidge/operator/Pow.hpp @@ -17,7 +17,7 @@ #include <vector> #include "aidge/utils/Registrar.hpp" -#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/operator/ArithmeticOperator.hpp" #include "aidge/backend/OperatorImpl.hpp" #include "aidge/data/Tensor.hpp" #include "aidge/data/Data.hpp" @@ -26,20 +26,18 @@ namespace Aidge { -class Pow_Op : public OperatorTensor, +class Pow_Op : public ArithmeticOperator, public Registrable<Pow_Op, std::string, std::unique_ptr<OperatorImpl>(const Pow_Op&)> { public: static const std::string Type; - Pow_Op() : OperatorTensor(Type, 2, 0, 1) {} + Pow_Op() : ArithmeticOperator(Type) {} /** * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated). * @param op Operator to copy. */ - Pow_Op(const Pow_Op& op) - : OperatorTensor(op) - { + Pow_Op(const Pow_Op& op) : ArithmeticOperator(op){ mImpl = op.mImpl ? Registrar<Pow_Op>::create(op.mOutputs[0]->getImpl()->backend())(*this) : nullptr; } @@ -51,20 +49,10 @@ public: return std::make_shared<Pow_Op>(*this); } - void computeOutputDims() override final; - - void setBackend(const std::string& name, DeviceIdx_t device = 0) override { mImpl = Registrar<Pow_Op>::create(name)(*this); mOutputs[0]->setBackend(name, device); } - - static const std::vector<std::string> getInputsName(){ - return {"data_input"}; - } - static const std::vector<std::string> getOutputsName(){ - return {"data_output"}; - } }; inline std::shared_ptr<Node> Pow(const std::string& name = "") { diff --git a/include/aidge/operator/Sub.hpp b/include/aidge/operator/Sub.hpp index ee5efa24d..d00e9f5f0 100644 --- a/include/aidge/operator/Sub.hpp +++ b/include/aidge/operator/Sub.hpp @@ -17,7 +17,7 @@ #include <vector> #include "aidge/utils/Registrar.hpp" -#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/operator/ArithmeticOperator.hpp" #include "aidge/backend/OperatorImpl.hpp" #include "aidge/data/Tensor.hpp" #include "aidge/data/Data.hpp" @@ -26,7 +26,7 @@ namespace Aidge { -class Sub_Op : public OperatorTensor, +class Sub_Op : public ArithmeticOperator, public Registrable<Sub_Op, std::string, std::unique_ptr<OperatorImpl>(const Sub_Op&)> { public: // FIXME: change accessibility @@ -36,15 +36,13 @@ public: public: static const std::string Type; - Sub_Op() : OperatorTensor(Type, 2, 0, 1) {} + Sub_Op() : ArithmeticOperator(Type) {} /** * @brief Copy-constructor. Copy the operator attributes and its output tensor(s), but not its input tensors (the new operator has no input associated). * @param op Operator to copy. */ - Sub_Op(const Sub_Op& op) - : OperatorTensor(op) - { + Sub_Op(const Sub_Op& op) : ArithmeticOperator(op){ mImpl = op.mImpl ? Registrar<Sub_Op>::create(op.mOutputs[0]->getImpl()->backend())(*this) : nullptr; } @@ -56,20 +54,10 @@ public: return std::make_shared<Sub_Op>(*this); } - void computeOutputDims() override final; - - void setBackend(const std::string& name, DeviceIdx_t device = 0) override { mImpl = Registrar<Sub_Op>::create(name)(*this); mOutputs[0]->setBackend(name, device); } - - static const std::vector<std::string> getInputsName(){ - return {"data_input"}; - } - static const std::vector<std::string> getOutputsName(){ - return {"data_output"}; - } }; inline std::shared_ptr<Node> Sub(const std::string& name = "") { diff --git a/python_binding/operator/pybind_Div.cpp b/python_binding/operator/pybind_Div.cpp index 6d14510f3..ff9933cdc 100644 --- a/python_binding/operator/pybind_Div.cpp +++ b/python_binding/operator/pybind_Div.cpp @@ -12,13 +12,13 @@ #include <pybind11/pybind11.h> #include "aidge/operator/Div.hpp" -#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/operator/ArithmeticOperator.hpp" namespace py = pybind11; namespace Aidge { void init_Div(py::module& m) { - py::class_<Div_Op, std::shared_ptr<Div_Op>, OperatorTensor>(m, "DivOp", py::multiple_inheritance()) + py::class_<Div_Op, std::shared_ptr<Div_Op>, ArithmeticOperator>(m, "DivOp", py::multiple_inheritance()) .def("get_inputs_name", &Div_Op::getInputsName) .def("get_outputs_name", &Div_Op::getOutputsName); diff --git a/python_binding/operator/pybind_Mul.cpp b/python_binding/operator/pybind_Mul.cpp index 21f510d98..7ad55c3ad 100644 --- a/python_binding/operator/pybind_Mul.cpp +++ b/python_binding/operator/pybind_Mul.cpp @@ -12,13 +12,13 @@ #include <pybind11/pybind11.h> #include "aidge/operator/Mul.hpp" -#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/operator/ArithmeticOperator.hpp" namespace py = pybind11; namespace Aidge { void init_Mul(py::module& m) { - py::class_<Mul_Op, std::shared_ptr<Mul_Op>, OperatorTensor>(m, "MulOp", py::multiple_inheritance()) + py::class_<Mul_Op, std::shared_ptr<Mul_Op>, ArithmeticOperator>(m, "MulOp", py::multiple_inheritance()) .def("get_inputs_name", &Mul_Op::getInputsName) .def("get_outputs_name", &Mul_Op::getOutputsName); diff --git a/python_binding/operator/pybind_Pow.cpp b/python_binding/operator/pybind_Pow.cpp index 09d1e4ad2..7bc8f05a8 100644 --- a/python_binding/operator/pybind_Pow.cpp +++ b/python_binding/operator/pybind_Pow.cpp @@ -12,13 +12,13 @@ #include <pybind11/pybind11.h> #include "aidge/operator/Pow.hpp" -#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/operator/ArithmeticOperator.hpp" namespace py = pybind11; namespace Aidge { void init_Pow(py::module& m) { - py::class_<Pow_Op, std::shared_ptr<Pow_Op>, OperatorTensor>(m, "PowOp", py::multiple_inheritance()) + py::class_<Pow_Op, std::shared_ptr<Pow_Op>, ArithmeticOperator>(m, "PowOp", py::multiple_inheritance()) .def("get_inputs_name", &Pow_Op::getInputsName) .def("get_outputs_name", &Pow_Op::getOutputsName); diff --git a/python_binding/operator/pybind_Sub.cpp b/python_binding/operator/pybind_Sub.cpp index dce1ab6cb..c2670389e 100644 --- a/python_binding/operator/pybind_Sub.cpp +++ b/python_binding/operator/pybind_Sub.cpp @@ -12,13 +12,13 @@ #include <pybind11/pybind11.h> #include "aidge/operator/Sub.hpp" -#include "aidge/operator/OperatorTensor.hpp" +#include "aidge/operator/ArithmeticOperator.hpp" namespace py = pybind11; namespace Aidge { void init_Sub(py::module& m) { - py::class_<Sub_Op, std::shared_ptr<Sub_Op>, OperatorTensor>(m, "SubOp", py::multiple_inheritance()) + py::class_<Sub_Op, std::shared_ptr<Sub_Op>, ArithmeticOperator>(m, "SubOp", py::multiple_inheritance()) .def("get_inputs_name", &Sub_Op::getInputsName) .def("get_outputs_name", &Sub_Op::getOutputsName); diff --git a/src/operator/ArithmeticOperator.cpp b/src/operator/ArithmeticOperator.cpp new file mode 100644 index 000000000..b2ea9dd12 --- /dev/null +++ b/src/operator/ArithmeticOperator.cpp @@ -0,0 +1,192 @@ +/******************************************************************************** + * 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 <cassert> +#include <memory> + +#include "aidge/operator/ArithmeticOperator.hpp" +#include "aidge/data/Data.hpp" +#include "aidge/data/Tensor.hpp" +#include "aidge/utils/Types.h" +#include "aidge/utils/ErrorHandling.hpp" + + +void Aidge::ArithmeticOperator::associateInput(const Aidge::IOIndex_t inputIdx, const std::shared_ptr<Aidge::Data>& data) { + if (inputIdx >= 2) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator has %hu inputs", type().c_str(),2); + } + if (strcmp((data)->type(), Tensor::Type) != 0) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Input data must be of Tensor type"); + } + mInputs[inputIdx] = std::dynamic_pointer_cast<Tensor>(data); +} + +void Aidge::ArithmeticOperator::setInput(const Aidge::IOIndex_t inputIdx, const std::shared_ptr<Aidge::Data>& data) { + if (strcmp(data->type(), "Tensor") != 0) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator only accepts Tensors as inputs", type().c_str()); + } + if (getInput(inputIdx)) { + *mInputs[inputIdx] = *std::dynamic_pointer_cast<Tensor>(data); + } else { + mInputs[inputIdx] = std::make_shared<Tensor>(*std::dynamic_pointer_cast<Tensor>(data)); + } +} + +Aidge::ArithmeticOperator::~ArithmeticOperator() = default; + +void Aidge::ArithmeticOperator::setInput(const Aidge::IOIndex_t inputIdx, std::shared_ptr<Aidge::Data>&& data) { + if (strcmp(data->type(), "Tensor") != 0) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator only accepts Tensors as inputs", type().c_str()); + } + if (getInput(inputIdx)) { + *mInputs[inputIdx] = std::move(*std::dynamic_pointer_cast<Tensor>(data)); + } else { + mInputs[inputIdx] = std::make_shared<Tensor>(std::move(*std::dynamic_pointer_cast<Tensor>(data))); + } +} + +const std::shared_ptr<Aidge::Tensor>& Aidge::ArithmeticOperator::getInput(const Aidge::IOIndex_t inputIdx) const { + if (inputIdx >= nbInputs()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator has %hu inputs", type().c_str(), nbInputs()); + } + return mInputs[inputIdx]; +} + +void Aidge::ArithmeticOperator::setOutput(const Aidge::IOIndex_t outputIdx, const std::shared_ptr<Aidge::Data>& data) { + if (strcmp(data->type(), "Tensor") != 0) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator only accepts Tensors as inputs", type().c_str()); + } + if (outputIdx >= nbOutputs()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator has %hu outputs", type().c_str(), nbOutputs()); + } + *mOutputs[outputIdx] = *std::dynamic_pointer_cast<Tensor>(data); +} + +void Aidge::ArithmeticOperator::setOutput(const Aidge::IOIndex_t outputIdx, std::shared_ptr<Aidge::Data>&& data) { + if (strcmp(data->type(), "Tensor") != 0) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator only accepts Tensors as inputs", type().c_str()); + } + if (outputIdx >= nbOutputs()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator has %hu outputs", type().c_str(), nbOutputs()); + } + *mOutputs[outputIdx] = std::move(*std::dynamic_pointer_cast<Tensor>(data)); +} + +const std::shared_ptr<Aidge::Tensor>& Aidge::ArithmeticOperator::getOutput(const Aidge::IOIndex_t outputIdx) const { + if (outputIdx >= nbOutputs()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "%s Operator has %hu outputs", type().c_str(), nbOutputs()); + } + return mOutputs[outputIdx]; +} + + +std::vector<std::pair<std::vector<Aidge::DimSize_t>, std::vector<Aidge::DimSize_t>>> Aidge::ArithmeticOperator::computeReceptiveField( + const std::vector<DimSize_t>& firstEltDims, + const std::vector<Aidge::DimSize_t>& outputDims, + const Aidge::IOIndex_t outputIdx) const +{ + static_cast<void>(outputIdx); + if (outputIdx >= nbOutputs()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Operator output index out of range."); + } + if (nbInputs() != nbData()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Operator has attributes. Must be handled in an overrided function."); + } + if (!outputDimsForwarded() || getOutput(0)->nbDims() != outputDims.size()) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Given outputDim out of range or output dim not forwarded yet."); + } + for (DimIdx_t i = 0; i < outputDims.size(); ++i) { + if (((outputDims[i] + firstEltDims[i]) > getOutput(0)->dims()[i]) || (outputDims[i] == 0)) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Given outputDim out of range for dimension %lu (%lu + %lu)", static_cast<std::size_t>(i), firstEltDims[i], outputDims[i]); + } + } + // return the same Tensor description as given in function parameter for each data input + return std::vector<std::pair<std::vector<Aidge::DimSize_t>, std::vector<Aidge::DimSize_t>>>(nbData(),std::pair<std::vector<Aidge::DimSize_t>, std::vector<Aidge::DimSize_t>>(firstEltDims, outputDims)); +} + +void Aidge::ArithmeticOperator::computeOutputDims() { + // check inputs have been associated + if (!getInput(0) || !getInput(1)) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "At least one input was not connected"); + } + + // if (getInput(0)->empty() || getInput(1)->empty()) { + // AIDGE_THROW_OR_ABORT(std::runtime_error, "At least one input is empty"); + // } + + std::vector<std::vector<std::size_t>> inputsDims; + for (std::size_t i = 0; i < nbInputs(); i++) + { + inputsDims.push_back(getInput(i)->dims()); + } + + std::size_t outNbDims = 1; + + for(size_t i=0; i<inputsDims.size() ; ++i) + outNbDims = inputsDims[i].size()>outNbDims?inputsDims[i].size():outNbDims; + + std::vector<std::size_t> outDims(outNbDims, 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 Arithmetic Operation"); + } + else + { + *it = dim; + } + } + } + } + } + } + mOutputs[0]->resize(outDims); +} + +bool Aidge::ArithmeticOperator::outputDimsForwarded() const { + bool forwarded = true; + // check both inputs and outputs have been filled + for (IOIndex_t i = 0; i < nbInputs(); ++i) { + forwarded &= mInputs[i] ? !(getInput(i)->empty()) : false; + } + for (IOIndex_t i = 0; i < nbOutputs(); ++i) { + forwarded &= !(getOutput(i)->empty()); + } + return forwarded; +} + +void Aidge::ArithmeticOperator::setDataType(const DataType& dataType) const { + for (IOIndex_t i = 0; i < nbOutputs(); ++i) { + getOutput(i)->setDataType(dataType); + } + for (IOIndex_t i = 0; i < nbInputs(); ++i) { + if (!getInput(i)) { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Input was not set"); + } + else { + getInput(i)->setDataType(dataType); + } + } +} \ No newline at end of file diff --git a/src/operator/Div.cpp b/src/operator/Div.cpp index 85db3ac6e..e5fe78b31 100644 --- a/src/operator/Div.cpp +++ b/src/operator/Div.cpp @@ -20,19 +20,4 @@ #include "aidge/utils/Types.h" #include "aidge/utils/ErrorHandling.hpp" -const std::string Aidge::Div_Op::Type = "Div"; - -void Aidge::Div_Op::computeOutputDims() { - // check inputs have been associated - if (!getInput(0) || !getInput(1)) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "At least one input was not connected"); - } - - if ((!getInput(0)->empty()) && - ((getInput(1)->size() == 1) || // div by a single value - (getInput(1)->size() == getInput(0)->size()) || // div elem-wise - (getInput(1)->nbDims() == 1 && getInput(1)->size() == getInput(0)->dims()[getInput(0)->nbDims()-1]))) // div by a Tensor with one dimension of output size - { - mOutputs[0]->resize(getInput(0)->dims()); - } -} \ No newline at end of file +const std::string Aidge::Div_Op::Type = "Div"; \ No newline at end of file diff --git a/src/operator/Mul.cpp b/src/operator/Mul.cpp index bc268263e..4de84e45b 100644 --- a/src/operator/Mul.cpp +++ b/src/operator/Mul.cpp @@ -19,19 +19,4 @@ #include "aidge/utils/Types.h" #include "aidge/utils/ErrorHandling.hpp" -const std::string Aidge::Mul_Op::Type = "Mul"; - -void Aidge::Mul_Op::computeOutputDims() { - // check inputs have been associated - if (!getInput(0) || !getInput(1)) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "At least one input was not connected"); - } - - if ((!getInput(0)->empty()) && - ((getInput(1)->size() == 1) || // mul by a single value - (getInput(1)->size() == getInput(0)->size()) || // mul elem-wise - (getInput(1)->nbDims() == 1 && getInput(1)->size() == getInput(0)->dims()[getInput(0)->nbDims()-1]))) // mul by a Tensor with one dimension of output size - { - mOutputs[0]->resize(getInput(0)->dims()); - } -} \ No newline at end of file +const std::string Aidge::Mul_Op::Type = "Mul"; \ No newline at end of file diff --git a/src/operator/Pow.cpp b/src/operator/Pow.cpp index de1f0c369..932b31e97 100644 --- a/src/operator/Pow.cpp +++ b/src/operator/Pow.cpp @@ -19,19 +19,4 @@ #include "aidge/utils/Types.h" #include "aidge/utils/ErrorHandling.hpp" -const std::string Aidge::Pow_Op::Type = "Pow"; - -void Aidge::Pow_Op::computeOutputDims() { - // check inputs have been associated - if (!getInput(0) || !getInput(1)) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "At least one input was not connected"); - } - - if ((!getInput(0)->empty()) && - ((getInput(1)->size() == 1) || // pow by a single value - (getInput(1)->size() == getInput(0)->size()) || // pow elem-wise - (getInput(1)->nbDims() == 1 && getInput(1)->size() == getInput(0)->dims()[getInput(0)->nbDims()-1]))) // pow by a Tensor with one dimension of output size - { - mOutputs[0]->resize(getInput(0)->dims()); - } -} \ No newline at end of file +const std::string Aidge::Pow_Op::Type = "Pow"; \ No newline at end of file diff --git a/src/operator/Sub.cpp b/src/operator/Sub.cpp index 639eaf798..74f9e8ca1 100644 --- a/src/operator/Sub.cpp +++ b/src/operator/Sub.cpp @@ -19,19 +19,4 @@ #include "aidge/utils/Types.h" #include "aidge/utils/ErrorHandling.hpp" -const std::string Aidge::Sub_Op::Type = "Sub"; - -void Aidge::Sub_Op::computeOutputDims() { - // check inputs have been associated - if (!getInput(0) || !getInput(1)) { - AIDGE_THROW_OR_ABORT(std::runtime_error, "At least one input was not connected"); - } - - if ((!getInput(0)->empty()) && - ((getInput(1)->size() == 1) || // sub by a single value - (getInput(1)->size() == getInput(0)->size()) || // sub elem-wise - (getInput(1)->nbDims() == 1 && getInput(1)->size() == getInput(0)->dims()[getInput(0)->nbDims()-1]))) // sub by a Tensor with one dimension of output size - { - mOutputs[0]->resize(getInput(0)->dims()); - } -} \ No newline at end of file +const std::string Aidge::Sub_Op::Type = "Sub"; \ No newline at end of file -- GitLab