1#ifndef TMVA_SOFIE_ROPERATOR_BASICNARY
2#define TMVA_SOFIE_ROPERATOR_BASICNARY
18template<
typename T, EBasicNaryOperator Op>
23 static const std::string
Name() {
return "Max";}
24 static std::string
Op(
const std::string& res, std::vector<std::string>& inputs) {
25 std::stringstream out;
26 out << res <<
" = std::max({ " << inputs[0];
27 for (
size_t i = 1; i < inputs.size(); i++) {
28 out <<
", " << inputs[i];
37 static const std::string
Name() {
return "Min";}
38 static std::string
Op(
const std::string& res, std::vector<std::string>& inputs) {
39 std::stringstream out;
40 out << res <<
" = std::min({ " << inputs[0];
41 for (
size_t i = 1; i < inputs.size(); i++) {
42 out <<
", " << inputs[i];
54 static const std::string
Name() {
return "Mean";}
55 static std::string
Op(
const std::string& res, std::vector<std::string>& inputs) {
56 std::stringstream out;
57 out << res <<
" = (" << inputs[0];
58 for (
size_t i = 1; i < inputs.size(); i++) {
59 out <<
" + " << inputs[i];
61 out <<
") / float(" << inputs.size() <<
");\n";
68 static const std::string
Name() {
return "Sum";}
69 static std::string
Op(
const std::string& res, std::vector<std::string>& inputs) {
70 std::stringstream out;
71 out << res <<
" = " << inputs[0];
72 for (
size_t i = 1; i < inputs.size(); i++) {
73 out <<
" + " << inputs[i];
80template <
typename T, EBasicNaryOperator Op>
103 fNInputs.reserve(inputNames.size());
109 [](
const std::string& s) -> std::string_view { return s; });
114 std::vector<ETensorType>
TypeInference(std::vector<ETensorType> input)
override {
119 std::vector<std::vector<size_t>>
ShapeInference(std::vector<std::vector<size_t>> input)
override {
120 auto ret = std::vector<std::vector<size_t>>(1, input[0]);
125 std::vector<std::vector<size_t>> inputShapes;
127 if (!model.CheckIfTensorAlreadyExist(it)) {
128 throw std::runtime_error(
"TMVA SOFIE BasicNary Op Input Tensor " + it +
" is not found in model");
132 if (model.IsDimInputTensor(it))
133 throw std::runtime_error(
"TMVA SOFIE BasicNary : supports only 2 inputs for dynamic tensors");
135 inputShapes.push_back(model.GetTensorShape(it));
153 auto IsInputDimParam = [&](
const std::string &p) {
154 auto inputNames = model.GetInputTensorNames();
155 for (
auto &input : inputNames) {
156 for (
auto &i_s : model.GetDimTensorShape(input)) {
157 if (i_s.isParam && i_s.param == p)
165 for (
size_t i = 0; i <
fDimShapeY.size(); i++) {
167 if (s.isParam && s.param.find(
"std::max") != std::string::npos) {
168 if (IsInputDimParam(shapeA[i].param)) {
170 if (shapeA[i].dim != 1)
174 }
else if (IsInputDimParam(shapeB[i].param)) {
175 if (shapeB[i].dim != 1)
194 if (model.Verbose()) {
195 std::cout << NaryOperatorTraits<T, Op>::Name() <<
" : ";
203 std::string
Generate(std::string OpName)
override {
204 OpName =
"op_" + OpName;
206 throw std::runtime_error(
"TMVA SOFIE BasicNary called to Generate without being initialized first");
208 std::stringstream out;
210 out <<
SP <<
"\n//------ BasicNary operator\n";
215 out <<
SP <<
"std::copy(tensor_" <<
fNInputs[0] <<
", tensor_" <<
fNInputs[0] <<
" + ";
216 out << length <<
", tensor_" <<
fNY <<
");\n";
220 std::vector<std::vector<Dim>> inputStrides(nInputs);
221 for (
int i = 0; i < nInputs; i++)
227 std::string compute_idx_Y;
233 for (
size_t i = 0; i <
fDimShapeY.size(); ++i) {
236 for (
int j = 0; j < nloop; j++) out <<
SP;
237 out <<
"for (size_t idx_" << i <<
" = 0; idx_" << i <<
" < " <<
fDimShapeY[i]
238 <<
"; ++idx_" << i <<
"){\n";
239 compute_idx_Y +=
"idx_" + std::to_string(i);
240 if (stridesY[i].GetVal() !=
"1")
241 compute_idx_Y +=
" * " + stridesY[i].GetVal();
242 compute_idx_Y +=
" + ";
246 for (
int j = 0; j < 3; j++)
247 compute_idx_Y.pop_back();
250 std::vector<std::string> inputs(nInputs);
251 for (
int ipt = 0; ipt < nInputs; ipt++ ) {
252 std::string compute_idx_X;
254 auto & stride = inputStrides[ipt];
256 std::all_of(shape.begin(), shape.end(), [](
Dim d) { return d.dim == 1 || d.GetVal() ==
"1"; })) {
259 for (
size_t i = 0; i < shape.size(); ++i) {
260 if (shape[i].dim == 1 || shape[i].GetVal() ==
"1")
262 compute_idx_X +=
"idx_" + std::to_string(i + (
fDimShapeY.size() - shape.size()));
263 if (stride[i].GetVal() !=
"1")
264 compute_idx_X +=
" * " + stride[i].GetVal();
265 compute_idx_X +=
" + ";
268 for (
int j = 0; j < 3; j++)
269 compute_idx_X.pop_back();
271 inputs[ipt] =
"tensor_" +
fNInputs[ipt] +
"[" + compute_idx_X +
"]";
275 for (
int j = 0; j < nloop + 1; j++) out <<
SP;
276 std::string output =
"tensor_" +
fNY +
"[" + compute_idx_Y +
"]";
277 out << NaryOperatorTraits<T,Op>::Op(output, inputs);
279 for (
int i = nloop; i > 0; i--) {
280 for (
int j = 0; j < i; j++) out <<
SP;
287 std::vector<std::string>
GetStdLibs()
override {
return { std::string(
"cmath") }; }
std::vector< std::vector< Dim > > fShapeInputs
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input) override
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
std::vector< size_t > fShapeY
std::vector< std::string > fNBroadcastedInputs
ROperator_BasicNary(const std::vector< std::string > &inputNames, const std::string &nameY)
std::vector< std::string > GetStdLibs() override
std::string Generate(std::string OpName) override
void Initialize(RModel &model) override
std::vector< std::string > fNInputs
std::vector< Dim > fDimShapeY
std::vector< std::string_view > fInputTensorNames
const std::string SP
space used to correctly indent the generated C++ code
std::vector< std::string_view > fOutputTensorNames
std::string Clean_name(std::string input_tensor_name)
std::vector< size_t > MultidirectionalBroadcastShape(std::vector< std::vector< size_t > >)
std::vector< size_t > ComputeStrideFromShape(const std::vector< size_t > &shape)
compute stride of a tensor given its shape (assume layout is row-major)
std::string ConvertDimShapeToString(const std::vector< Dim > &shape)
std::vector< Dim > ConvertShapeToDim(const std::vector< size_t > &shape)
Convert shape from integer format to dynamic one (based on Dim).
std::string ConvertTypeToString(ETensorType type)
std::string ConvertDimShapeToLength(const std::vector< Dim > &shape)
create variable transformations
static std::string Op(const std::string &res, std::vector< std::string > &inputs)
static const std::string Name()
static std::string Op(const std::string &res, std::vector< std::string > &inputs)
static const std::string Name()
static const std::string Name()
static std::string Op(const std::string &res, std::vector< std::string > &inputs)
static const std::string Name()
static std::string Op(const std::string &res, std::vector< std::string > &inputs)