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