Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_BasicNary.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_BASICNARY
2#define TMVA_SOFIE_ROPERATOR_BASICNARY
3
5#include "TMVA/ROperator.hxx"
6#include "TMVA/RModel.hxx"
7
8#include <vector>
9#include <sstream>
10#include <algorithm>
11
12namespace TMVA{
13namespace Experimental{
14namespace SOFIE{
15
17
18template<typename T, EBasicNaryOperator Op>
20
21template<typename T>
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];
29 }
30 out << "});\n";
31 return out.str();
32 }
33};
34
35template<typename T>
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];
43 }
44 out << "});\n";
45 return out.str();
46 }
47};
48
49template<typename T>
51
52template<>
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];
60 }
61 out << ") / float(" << inputs.size() << ");\n";
62 return out.str();
63 }
64};
65
66template<typename T>
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];
74 }
75 out << ";\n";
76 return out.str();
77 }
78};
79
80template <typename T, EBasicNaryOperator Op>
82{
83
84private:
85
86 std::vector<std::string> fNInputs;
87 std::string fNY;
88 std::vector<std::vector<Dim>> fShapeInputs;
89
90 std::vector<std::string> fNBroadcastedInputs;
91 std::vector<size_t> fShapeY;
92 std::vector<Dim> fDimShapeY;
93
94 bool fBroadcast = false;
95
96 std::string fType;
97
98public:
100
101 ROperator_BasicNary( const std::vector<std::string> & inputNames, const std::string& nameY):
102 fNY(UTILITY::Clean_name(nameY)){
103 fNInputs.reserve(inputNames.size());
104 for (auto & name : inputNames)
106
107 fInputTensorNames.resize(fNInputs.size());
108 std::transform(fNInputs.begin(), fNInputs.end(), fInputTensorNames.begin(),
109 [](const std::string& s) -> std::string_view { return s; });
111 }
112
113 // type of output given input
114 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override {
115 return input;
116 }
117
118 // shape of output tensors given input tensors
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]);
121 return ret;
122 }
123
124 void Initialize(RModel& model) override {
125 std::vector<std::vector<size_t>> inputShapes;
126 for (auto &it : fNInputs) {
127 if (!model.CheckIfTensorAlreadyExist(it)) {
128 throw std::runtime_error("TMVA SOFIE BasicNary Op Input Tensor " + it + " is not found in model");
129 }
130 fShapeInputs.push_back(model.GetDimTensorShape(it));
131 if (fNInputs.size()> 2) {
132 if (model.IsDimInputTensor(it))
133 throw std::runtime_error("TMVA SOFIE BasicNary : supports only 2 inputs for dynamic tensors");
134 else
135 inputShapes.push_back(model.GetTensorShape(it));
136 }
137 }
138 // Find the common shape of the input tensors
139 if (fShapeInputs.size() > 2 ) {
140 // support dynamic tensors now for input list of size=2
143 } else if (fShapeInputs.size() == 2 ) {
145 // use same code as in BinaryOperator (need to extend for input sizes > 2)
146 fBroadcast = ret.first;
147 fDimShapeY = ret.second;
148 // case of all parametric shapes and MultiDirectionalBroadcastShape return the max of the 2
149 // need to do before we declare the output tensor shape and the broadcasted ones
150 if (ret.first & 4) {
151 // check if one of the parameter is an input dimension
152 // define function to find this
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)
158 return true;
159 }
160 }
161 return false;
162 };
163 auto & shapeA = fShapeInputs[0];
164 auto & shapeB = fShapeInputs[1];
165 for (size_t i = 0; i < fDimShapeY.size(); i++) {
166 auto &s = fDimShapeY[i];
167 if (s.isParam && s.param.find("std::max") != std::string::npos) {
168 if (IsInputDimParam(shapeA[i].param)) {
169 // case dim is 1 we indicate that the input parameter is equal to 1
170 if (shapeA[i].dim != 1)
171 s = shapeA[i];
172 else
173 s = shapeB[i];
174 } else if (IsInputDimParam(shapeB[i].param)) {
175 if (shapeB[i].dim != 1)
176 s = shapeB[i];
177 else
178 s = shapeA[i];
179 }
180 }
181 }
182 }
183 } else if (fShapeInputs.size() == 1 ) {
185 }
186 if (!fShapeY.empty())
188 else
190
191
193
194 if (model.Verbose()) {
195 std::cout << NaryOperatorTraits<T, Op>::Name() << " : ";
196 if (fNInputs.size() == 2)
197 std::cout << ConvertShapeToString(fShapeInputs[0]) << " , "
199 std::cout << " --> " << ConvertShapeToString(fDimShapeY) << std::endl;
200 }
201 }
202
203 std::string Generate(std::string OpName) override {
204 OpName = "op_" + OpName;
205 if (fDimShapeY.empty()) {
206 throw std::runtime_error("TMVA SOFIE BasicNary called to Generate without being initialized first");
207 }
208 std::stringstream out;
210 out << SP << "\n//------ BasicNary operator\n";
211
212 int nInputs = fNInputs.size();
213
214 if (nInputs == 1) {
215 out << SP << "std::copy(tensor_" << fNInputs[0] << ", tensor_" << fNInputs[0] << " + ";
216 out << length << ", tensor_" << fNY << ");\n";
217 } else {
218
219 // implement operator without broadcasting, but using loos on all indices
220 std::vector<std::vector<Dim>> inputStrides(nInputs);
221 for (int i = 0; i < nInputs; i++)
223
225
226 // make loop on output indices
227 std::string compute_idx_Y;
228 int nloop = 0;
229 if (fDimShapeY.empty() ||
230 std::all_of(fDimShapeY.begin(), fDimShapeY.end(), [](Dim d) { return d.dim == 1 || d.GetVal() == "1"; })) {
231 compute_idx_Y = "0";
232 } else {
233 for (size_t i = 0; i < fDimShapeY.size(); ++i) {
234 if (fDimShapeY[i].dim != 1 && fDimShapeY[i].GetVal() != "1") {
235 nloop++;
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 += " + ";
243 }
244 }
245 // remove last 3 characters " + "
246 for (int j = 0; j < 3; j++)
247 compute_idx_Y.pop_back();
248 }
249 // find indices for input tensors
250 std::vector<std::string> inputs(nInputs);
251 for (int ipt = 0; ipt < nInputs; ipt++ ) {
252 std::string compute_idx_X;
253 auto & shape = fShapeInputs[ipt];
254 auto & stride = inputStrides[ipt];
255 if (shape.empty() ||
256 std::all_of(shape.begin(), shape.end(), [](Dim d) { return d.dim == 1 || d.GetVal() == "1"; })) {
257 compute_idx_X = "0";
258 } else {
259 for (size_t i = 0; i < shape.size(); ++i) {
260 if (shape[i].dim == 1 || shape[i].GetVal() == "1")
261 continue;
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 += " + ";
266 }
267 // remove last 3 character " + "
268 for (int j = 0; j < 3; j++)
269 compute_idx_X.pop_back();
270 }
271 inputs[ipt] = "tensor_" + fNInputs[ipt] + "[" + compute_idx_X + "]";
272 }
273
274 // perform the operation
275 for (int j = 0; j < nloop + 1; j++) out << SP;
276 std::string output = "tensor_" + fNY + "[" + compute_idx_Y + "]";
278
279 for (int i = nloop; i > 0; i--) {
280 for (int j = 0; j < i; j++) out << SP;
281 out << "}\n";
282 }
283 }
284 return out.str();
285 }
286
287 std::vector<std::string> GetStdLibs() override {return { std::string("cmath") }; }
288};
289
290}//SOFIE
291}//Experimental
292}//TMVA
293
294
295#endif //TMVA_SOFIE_ROPERATOR_BasicNary
#define d(i)
Definition RSha256.hxx:102
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void input
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h length
char name[80]
Definition TGX11.cxx:110
std::vector< size_t > GetTensorShape(const std::string &name) const
Definition RModel.cxx:29
std::vector< Dim > GetDimTensorShape(const std::string &name) const
Definition RModel.cxx:65
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:262
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:122
bool IsDimInputTensor(const std::string &name) const
Definition RModel.cxx:252
ETensorType GetTensorType(std::string name) const
Definition RModel.cxx:90
const std::vector< std::string > & GetInputTensorNames() const
Definition RModel.hxx:206
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input) override
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
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
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:47
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:42
std::vector< std::string_view > fOutputTensorNames
Definition ROperator.hxx:48
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::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)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
create variable transformations
static std::string Op(const std::string &res, std::vector< std::string > &inputs)
static std::string Op(const std::string &res, std::vector< std::string > &inputs)
static std::string Op(const std::string &res, std::vector< std::string > &inputs)
static std::string Op(const std::string &res, std::vector< std::string > &inputs)
static void output()