Skip to content
Snippets Groups Projects
Commit 5c13d82d authored by Houssem ROUIS's avatar Houssem ROUIS
Browse files

add Sum operator

parent b9016985
No related branches found
No related tags found
1 merge request!350Draft: Fix import tests
......@@ -80,6 +80,7 @@
#include "aidge/operator/Split.hpp"
#include "aidge/operator/Sqrt.hpp"
#include "aidge/operator/Sub.hpp"
#include "aidge/operator/Sum.hpp"
#include "aidge/operator/Transpose.hpp"
#include "aidge/scheduler/Scheduler.hpp"
#include "aidge/stimuli/Stimulus.hpp"
......
/********************************************************************************
* Copyright (c) 2025 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_SUM_H_
#define AIDGE_CORE_OPERATOR_SUM_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 Description of an element-wise Sum operation on multiple input Tensors,
* supporting NumPy broadcasting.
*
* For each N of elements x0, x1, ..., xN from the input Tensors, the function
* is defined as:
* `f(x0, ..., xN) = x0 + x1 + ... + xN`
*
* 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.
*
* @example Input 1: (3, 4, 2), Input 2: (2), Output: (3, 4, 2)
* @example Input 1: (1, 5, 3), Input 2: (2, 1, 3), Input 3 : (2), Output: (2, 5, 3)
*
* @see OperatorTensor
* @see Registrable
*/
class Sum_Op : public OperatorTensor,
public Registrable<Sum_Op,
std::string,
std::function<std::shared_ptr<OperatorImpl>(const Sum_Op&)>>
{
public:
static const std::string Type;
Sum_Op() = delete;
Sum_Op(const IOIndex_t nbIn);
/**
* @brief Copy-constructor.
* @param op Sum_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.
*/
Sum_Op(const Sum_Op& op);
/**
* @brief Clone the operator using its copy-constructor.
* @see Operator::Sum_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 {"data_input_0", "data_input_n"};
}
static const std::vector<std::string> getOutputsName() {
return {"data_output"};
}
};
std::shared_ptr<Node> Sum(const IOIndex_t nbIn, const std::string& name = "");
}
#endif /* AIDGE_CORE_OPERATOR_SUM_H_ */
\ No newline at end of file
/********************************************************************************
* Copyright (c) 2025 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 <memory>
#include <pybind11/pybind11.h>
#include "aidge/operator/Sum.hpp"
#include "aidge/operator/OperatorTensor.hpp"
#include "aidge/utils/Types.h"
namespace py = pybind11;
namespace Aidge {
void declare_Sum(py::module &m) {
py::class_<Sum_Op, std::shared_ptr<Sum_Op>, OperatorTensor>(m, "SumOp", py::multiple_inheritance(),
R"mydelimiter(
Initialize a Sum operator.
This operator performs element-wise addition between multiple input tensors.
The operation is defined as:
Output = Input1 + Input2 + ... + InputN
The output tensor shape is determined by taking the maximum size along each dimension of the input tensors after broadcasting.
Examples:
Input 1: (3, 4, 2), Input 2: (2), Output: (3, 4, 2)
Input 1: (1, 5, 3), Input 2: (2, 1, 3), Input 3: (2), Output: (2, 5, 3)
:param name : Name of the node (optional).
:type name : str
)mydelimiter")
.def(py::init<const IOIndex_t>(), py::arg("nb_inputs"))
.def_static("get_inputs_name", &Sum_Op::getInputsName)
.def_static("get_outputs_name", &Sum_Op::getOutputsName)
.def_readonly_static("Type", &Sum_Op::Type);
declare_registrable<Sum_Op>(m, "SumOp");
m.def("Sum", &Sum, py::arg("nb_inputs"), py::arg("name") = "",
R"mydelimiter(
Initialize a node containing a sum operator that performs element-wise addition between multiple tensors.
The operation is defined as:
Output = Input1 + Input2 + ... + InputN
The output tensor shape is determined by taking the maximum size along each dimension of the input tensors after broadcasting.
Examples:
Input 1: (3, 4, 2), Input 2: (2), Output: (3, 4, 2)
Input 1: (1, 5, 3), Input 2: (2, 1, 3), Input 3: (2), Output: (2, 5, 3)
:param nb_inputs : number of inputs to sum.
:type nb_inputs : int
:param name : Name of the node (optional).
:type name : str
:return: A node containing the Sum operator.
:rtype: :py:class:`SumOp`
)mydelimiter");
}
void init_Sum(py::module &m) {
declare_Sum(m);
}
} // namespace Aidge
\ No newline at end of file
/********************************************************************************
* 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/Sum.hpp"
#include "aidge/utils/Types.h"
#include "aidge/utils/ErrorHandling.hpp"
#include "aidge/utils/Registrar.hpp"
const std::string Aidge::Sum_Op::Type = "Sum";
Aidge::Sum_Op::Sum_Op(const IOIndex_t nbIn)
: OperatorTensor(Type, std::vector<InputCategory>(nbIn, InputCategory::Data), 1) {
if (nbIn == 0) {
AIDGE_THROW_OR_ABORT(std::runtime_error, "Sum operator should have at least one input.");
}
}
Aidge::Sum_Op::Sum_Op(const Sum_Op& op)
: OperatorTensor(op)
{
if (op.mImpl) {
SET_IMPL_MACRO(Sum_Op, *this, op.backend());
} else {
mImpl = nullptr;
}
}
std::shared_ptr<Aidge::Operator> Aidge::Sum_Op::clone() const {
return std::make_shared<Sum_Op>(*this);
}
bool Aidge::Sum_Op::forwardDims(bool /*allowDataDependency*/) {
if (inputsAssociated()) {
std::vector<std::vector<std::size_t>> inputsDims(nbInputs());
for (std::size_t i = 0; i < nbInputs(); i++) {
inputsDims[i] = getInput(i)->dims();
}
std::size_t outNbDims = 1;
for(std::size_t i = 0; i < nbInputs(); ++i) {
outNbDims = (inputsDims[i].size() > outNbDims) ? inputsDims[i].size() : outNbDims;
}
std::vector<std::size_t> outDims(outNbDims, 1);
for (auto it = outDims.rbegin(); it != outDims.rend(); ++it) {
for (std::size_t i = 0; i < nbInputs(); ++i) {
if(!inputsDims[i].empty()) {
const std::size_t dim = inputsDims[i].back();
inputsDims[i].pop_back();
if (*it == 1) {
*it = dim;
}
else if ((dim != *it) && (dim != 1)) {
AIDGE_THROW_OR_ABORT(std::runtime_error, "Incompatible Tensor shape for Add Operation: {} for previous inputs vs {} for input#{}",
outDims, getInput(i)->dims(), i);
}
}
}
}
mOutputs[0]->resize(outDims);
return true;
}
return false;
}
void Aidge::Sum_Op::setBackend(const std::string& name, DeviceIdx_t device) {
SET_IMPL_MACRO(Sum_Op, *this, name);
mOutputs[0]->setBackend(name, device);
}
std::set<std::string> Aidge::Sum_Op::getAvailableBackends() const {
return Registrar<Sum_Op>::getKeys();
}
////////////////////////////////////////////////////////////////////////////////
std::shared_ptr<Aidge::Node> Aidge::Sum(const IOIndex_t nbIn, const std::string& name) {
return std::make_shared<Node>(std::make_shared<Sum_Op>(nbIn), name);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment