Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Comparision.hxx
Go to the documentation of this file.
1
2#ifndef TMVA_SOFIE_ROperator_Comparision
3#define TMVA_SOFIE_ROperator_Comparision
4
6#include "TMVA/ROperator.hxx"
7#include "TMVA/RModel.hxx"
8
9#include <sstream>
10
11namespace TMVA{
12namespace Experimental{
13namespace SOFIE{
14
16
17template <typename T, EComparisionOperator Op1>
19
20template <typename T>
21struct ComparisionTrait<T, Eq> {
22 static const std::string Name() { return "Equal"; }
23 static std::string Op(const std::string & t1, const std::string t2) { return t1 + " == " + t2; }
24 static bool Result(T v1, T v2) { return v1 == v2;}
25};
26
27template <typename T>
29 static const std::string Name() { return "Less"; }
30 static std::string Op(const std::string & t1, const std::string t2) { return t1 + " < " + t2; }
31 static bool Result(T v1, T v2) { return v1 < v2;}
32};
33
34template <typename T>
36 static const std::string Name() { return "LessOrEqual"; }
37 static std::string Op(const std::string & t1, const std::string t2) { return t1 + " <= " + t2; }
38 static bool Result(T v1, T v2) { return v1 <= v2;}
39};
40
41template <typename T>
43 static const std::string Name() { return "Greater"; }
44 static std::string Op(const std::string & t1, const std::string t2) { return t1 + " > " + t2; }
45 static bool Result(T v1, T v2) { return v1 > v2;}
46};
47
48template <typename T>
50 static const std::string Name() { return "GreaterOrEqual"; }
51 static std::string Op(const std::string & t1, const std::string t2) { return t1 + " >= " + t2 ; }
52 static bool Result(T v1, T v2) { return v1 >= v2;}
53};
54
55template<typename T, EComparisionOperator Op>
57private:
58
59 std::string fNX1;
60 std::string fNX2;
61 std::string fNY;
62 std::vector<size_t> fShapeX1;
63 std::vector<size_t> fShapeX2;
64 std::vector<Dim> fDimShapeX1;
65 std::vector<Dim> fDimShapeX2;
66 std::vector<size_t> fShapeY;
67 std::vector<Dim> fDimShapeY;
71
72
73public:
75 ROperator_Comparision(const std::string & nameX1, const std::string & nameX2, const std::string & nameY):
76 fNX1(UTILITY::Clean_name(nameX1)), fNX2(UTILITY::Clean_name(nameX2)), fNY(UTILITY::Clean_name(nameY)){
78
79 // output will be a boolean vector so should not be considered for memory optimized pool
81 }
82
83 // type of output given input
84 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override {
85 return input;
86 }
87
88 // shape of output tensors given input tensors
89 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input) override {
90 auto ret = input; // return vector size 1 with first input
91 return ret;
92 }
93
94 void Initialize(RModel& model) override {
95 // input must be a graph input, or already initialized intermediate tensor
97 throw std::runtime_error(std::string("TMVA SOFIE Comparision Op Input Tensor ") + fNX1 + "is not found in model");
98 }
99 if (!model.CheckIfTensorAlreadyExist(fNX2)) {
100 throw std::runtime_error(std::string("TMVA SOFIE Comparision Op Input Tensor ") + fNX2 + "is not found in model");
101 }
102 if (model.IsDynamicTensor(fNX1))
104 else {
107 }
108 if (model.IsDynamicTensor(fNX2))
110 else {
113 }
116 // case of non dynamic tensors
117 if (!fShapeX1.empty() && !fShapeX2.empty()) {
118 bool broadcastX1 = false;
119 bool broadcastX2 = false;
121 // no broadcast needed
123 } else {
124 // Y is the common shape of A and B
126 fBroadcastFlag = ret.first;
127 fShapeY = ret.second;
130 }
131
132
133 // analyze case of constant tensors or shape tensors (which have known shapes but data as Dim values
134 // normal case with non-dynamic tensor is also here
135 T *data1 = nullptr;
136 T *data2 = nullptr;
137 std::unique_ptr<T> broadcastedData1;
138 std::unique_ptr<T> broadcastedData2;
139 // data for shape tensors
140 std::vector<Dim> shapeData1;
141 std::vector<Dim> shapeData2;
143 bool *outData = new bool[length];
144 if (model.IsInitializedTensor(fNX1)) {
145 data1 = static_cast<T *>(model.GetInitializedTensorData(fNX1).get());
146 if (broadcastX1) {
147 broadcastedData1 = std::unique_ptr<T>(
149 data1 = broadcastedData1.get();
150 }
151
152 } else if (model.IsShapeTensor(fNX1)) {
154 }
155 if (model.IsInitializedTensor(fNX2)) {
156 data2 = static_cast<T *>(model.GetInitializedTensorData(fNX2).get());
157 if (broadcastX2) {
158 broadcastedData2 = std::unique_ptr<T>(
160 data2 = broadcastedData2.get();
161 }
162 } else if (model.IsShapeTensor(fNX2)) {
164 }
165 if (data1 && data2) {
166 fIsOutputConstant = true;
167 for (size_t i = 0; i < length; i++)
170 if (model.Verbose())
171 std::cout << ComparisionTrait<T, Op>::Name() << " op ---> " << fNY << " "
173 << std::endl;
174 } else if ((data1 || !shapeData1.empty()) && (data2 || !shapeData2.empty())) {
175 fIsOutputConstant = true;
176 if (data1 && !data2) {
177 // data 1 is constant and data2 is shape
178 for (size_t i = 0; i < length; i++) {
179 if (shapeData2[i].isParam) {
180 if (shapeData2[i].dim == size_t(-1) || data1[i] > 0) {
181 fIsOutputConstant = false;
182 break;
183 } else {
184 // assume a comparison is done with .dim = 0
185 shapeData2[i].dim = 0;
186 }
187 }
188 outData[i] = ComparisionTrait<T, Op>::Result(data1[i], static_cast<T>(shapeData2[i].dim));
189 }
190 } else if (!data1 && data2) {
191 // data 1 is shape and dat2 is constant
192 for (size_t i = 0; i < length; i++) {
193 if (shapeData1[i].isParam) {
194 if (shapeData1[i].dim == size_t(-1) || data2[i] > 0) {
195 fIsOutputConstant = false;
196 break;
197 } else {
198 // assume a comparison is done with .dim = 0
199 shapeData1[i].dim = 0;
200 }
201 }
202 outData[i] = ComparisionTrait<T, Op>::Result(static_cast<T>(shapeData1[i].dim), data2[i]);
203 }
204 } else if (!shapeData1.empty() && !shapeData2.empty()) {
205 // both data1 and data2 are shape tensors
206 for (size_t i = 0; i < length; i++) {
207 if (!shapeData1[i].isParam && !shapeData2[i].isParam) {
209 } else if (shapeData1[i].isParam && shapeData2[i].isParam) {
210 if (shapeData1[i].param == shapeData2[i].param)
211 outData[i] = ComparisionTrait<int, Op>::Result(1, 1); // comparison of two equal value
212 else {
213 fIsOutputConstant = false;
214 break;
215 }
216 } else {
217 fIsOutputConstant = false;
218 break;
219 }
220 }
221 }
222 if (fIsOutputConstant) {
224 if (model.Verbose())
225 std::cout << ComparisionTrait<T, Op>::Name() << " op ---> " << fNY << " "
227 << " (constant) " << std::endl;
228 }
229 }
230 delete[] outData;
231 // case of non constant output (no constant or shape tensors)
232 if (!fIsOutputConstant && !fShapeY.empty()) {
235 if (model.Verbose())
236 std::cout << ComparisionTrait<T, Op>::Name() << " op ---> " << fNY << " "
237 << ConvertShapeToString(fShapeY) << std::endl;
238 }
239 } else {
240 // case of dynamic tensors
241 // case A or B have dynamic shapes. We need to broadcast if shape are not same
243 fBroadcastFlag = ret.first;
244 fDimShapeY = ret.second;
245 // case of all parametric shapes and MultiDirectionalBroadcastShape return the max of the 2
246 // need to do before we declare the output tensor shape and the broadcasted ones
247 if (ret.first & 4) {
248 // check if one of the parameter is an input dimension
249 // define function to find this
250 auto IsInputDimParam = [&](const std::string &p) {
251 auto inputNames = model.GetInputTensorNames();
252 for (auto &input : inputNames) {
253 for (auto &i_s : model.GetDimTensorShape(input)) {
254 if (i_s.isParam && i_s.param == p)
255 return true;
256 }
257 }
258 return false;
259 };
260 for (size_t i = 0; i < fDimShapeY.size(); i++) {
261 auto &s = fDimShapeY[i];
262 if (s.isParam && s.param.find("std::max") != std::string::npos) {
263 if (IsInputDimParam(fDimShapeX1[i].param)) {
264 // case dim is 1 we indicate that the input parameter is equal to 1
265 if (fDimShapeX1[i].dim != 1)
266 s = fDimShapeX1[i];
267 else
268 s = fDimShapeX2[i];
269 } else if (IsInputDimParam(fDimShapeX2[i].param)) {
270 if (fDimShapeX2[i].dim != 1)
271 s = fDimShapeX2[i];
272 else
273 s = fDimShapeX1[i];
274 }
275 }
276 }
277 }
278
280 if (model.Verbose()) {
281 std::cout << ComparisionTrait<T, Op>::Name() << " : " << fNX1 << " " << ConvertDimShapeToString(fDimShapeX1) << " , "
282 << fNX2 << " " << ConvertDimShapeToString(fDimShapeX2) << " --> "
283 << fNY << " " << ConvertDimShapeToString(fDimShapeY) << std::endl;
285 }
286 }
287 }
288
289 std::string Generate(std::string opName) override {
290 if (fIsOutputConstant) return "";
291 opName = "op_" + opName;
292
293 if (fDimShapeY.empty()) {
294 throw std::runtime_error("TMVA SOFIE Comparision Op called to Generate without being initialized first");
295 }
296 std::stringstream out;
297 out << SP << "\n//------ " << ComparisionTrait<T,Op>::Name() << " " << opName
298 << " --> " << ConvertShapeToString(fShapeY) << "\n";
299
300 // need to add check if tensors are compatible as in binary operator
301
302 // use same code as Binary operator
306
308 if (fDimShapeX1.empty() ||
309 std::all_of(fDimShapeX1.begin(), fDimShapeX1.end(), [](Dim d) { return d.dim == 1 || d.GetVal() == "1"; })) {
310 compute_idx_X1 = "0";
311 } else {
312 for (size_t i = 0; i < fDimShapeX1.size(); ++i) {
313 if (fDimShapeX1[i].dim == 1 || fDimShapeX1[i].GetVal() == "1")
314 continue;
315 compute_idx_X1 += "idx_" + std::to_string(i + (fDimShapeY.size() - fDimShapeX1.size()));
316 if (stridesA[i].GetVal() != "1")
317 compute_idx_X1 += " * " + stridesA[i].GetVal();
318 compute_idx_X1 += " + ";
319 }
320 // remove last 3 character " + "
321 for (int j = 0; j < 3; j++)
322 compute_idx_X1.pop_back();
323 }
324 if (fDimShapeX2.empty() ||
325 std::all_of(fDimShapeX2.begin(), fDimShapeX2.end(), [](Dim d) { return d.dim == 1 || d.GetVal() == "1"; })) {
326 compute_idx_X2 = "0";
327 } else {
328 for (size_t i = 0; i < fDimShapeX2.size(); ++i) {
329 if (fDimShapeX2[i].dim == 1 || fDimShapeX2[i].GetVal() == "1")
330 continue;
331 compute_idx_X2 += "idx_" + std::to_string(i + (fDimShapeY.size() - fDimShapeX2.size()));
332 if (stridesB[i].GetVal() != "1")
333 compute_idx_X2 += " * " + stridesB[i].GetVal();
334 compute_idx_X2 += " + ";
335 }
336 // remove last 3 character " + "
337 for (int j = 0; j < 3; j++)
338 compute_idx_X2.pop_back();
339 }
340 int nloop = 0;
341 if (fDimShapeY.empty() ||
342 std::all_of(fDimShapeY.begin(), fDimShapeY.end(), [](Dim d) { return d.dim == 1 || d.GetVal() == "1"; })) {
343 compute_idx_Y = "0";
344 } else {
345 for (size_t i = 0; i < fDimShapeY.size(); ++i) {
346 if (fDimShapeY[i].dim != 1 && fDimShapeY[i].GetVal() != "1") {
347 nloop++;
348 for (int j = 0; j < nloop; j++) out << SP;
349 out << "for (size_t idx_" << i << " = 0; idx_" << i << " < " << fDimShapeY[i]
350 << "; ++idx_" << i << "){\n";
351 compute_idx_Y += "idx_" + std::to_string(i);
352 if (stridesY[i].GetVal() != "1")
353 compute_idx_Y += " * " + stridesY[i].GetVal();
354 compute_idx_Y += " + ";
355 }
356 }
357 // remove last 3 characters " + "
358 for (int j = 0; j < 3; j++)
359 compute_idx_Y.pop_back();
360 }
361 for (int j = 0; j < nloop + 1; j++) out << SP;
362 out << "tensor_" << fNY << "[" << compute_idx_Y << "] = "
363 << ComparisionTrait<T,Op>::Op( "tensor_" + fNX1 + "[" + compute_idx_X1 + "]" ,
364 "tensor_" + fNX2 + "[" + compute_idx_X2 + "]") << " ;\n";
365
366
367 for (int i = nloop; i > 0; i--) {
368 for (int j = 0; j < i; j++) out << SP;
369 out << "}\n";
370 }
371
372
373 return out.str();
374 }
375
376};
377
378}//SOFIE
379}//Experimental
380}//TMVA
381
382
383#endif //TMVA_SOFIE_ROperator_Comparision
#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
std::vector< size_t > GetTensorShape(const std::string &name) const
Definition RModel.cxx:64
std::vector< Dim > GetDimTensorShape(const std::string &name) const
Definition RModel.cxx:100
bool IsDynamicTensor(const std::string &name) const
Definition RModel.cxx:296
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:311
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:157
void AddConstantTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition RModel.cxx:242
bool IsShapeTensor(const std::string &name) const
check if a tensor is a shape tensor
Definition RModel.cxx:270
bool IsInitializedTensor(const std::string &name) const
Definition RModel.cxx:283
std::vector< Dim > GetDynamicTensorShape(const std::string &name) const
Definition RModel.cxx:111
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition RModel.cxx:376
ETensorType GetTensorType(std::string name) const
Definition RModel.cxx:125
const std::vector< std::string > & GetInputTensorNames() const
Definition RModel.hxx:199
const std::vector< Dim > & GetShapeTensorValues(const std::string &tensor_name) const
Definition RModel.cxx:278
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
std::string Generate(std::string opName) override
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input) override
ROperator_Comparision(const std::string &nameX1, const std::string &nameX2, const std::string &nameY)
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:50
bool fIsOutputConstant
flag to identify if operator has a constant output (no need to generate code)
Definition ROperator.hxx:47
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:45
std::vector< std::string_view > fOutputTensorNames
Definition ROperator.hxx:51
bool AreSameShape(const std::vector< size_t > &, const std::vector< size_t > &)
std::vector< size_t > MultidirectionalBroadcastShape(std::vector< std::vector< size_t > >)
T * UnidirectionalBroadcast(const T *data, const std::vector< size_t > &shape, const std::vector< size_t > &targetShape)
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::size_t ConvertShapeToLength(const std::vector< size_t > &shape)
std::string ConvertValuesToString(size_t n, const T *data, size_t maxprint=-1)
std::vector< Dim > ConvertShapeToDim(const std::vector< size_t > &shape)
Convert shape from integer format to dynamic one (based on Dim)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
create variable transformations
static std::string Op(const std::string &t1, const std::string t2)
static std::string Op(const std::string &t1, const std::string t2)
static std::string Op(const std::string &t1, const std::string t2)
static std::string Op(const std::string &t1, const std::string t2)
static std::string Op(const std::string &t1, const std::string t2)
auto * t1
Definition textangle.C:20