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 void Initialize(RModel& model) override {
85 // input must be a graph input, or already initialized intermediate tensor
86 if (!model.CheckIfTensorAlreadyExist(fNX1)){
87 throw std::runtime_error(std::string("TMVA SOFIE Comparision Op Input Tensor ") + fNX1 + "is not found in model");
88 }
89 if (!model.CheckIfTensorAlreadyExist(fNX2)) {
90 throw std::runtime_error(std::string("TMVA SOFIE Comparision Op Input Tensor ") + fNX2 + "is not found in model");
91 }
92 if (model.IsDynamicTensor(fNX1))
93 fDimShapeX1 = model.GetDynamicTensorShape(fNX1);
94 else {
95 fShapeX1 = model.GetTensorShape(fNX1);
97 }
98 if (model.IsDynamicTensor(fNX2))
99 fDimShapeX2 = model.GetDynamicTensorShape(fNX2);
100 else {
101 fShapeX2 = model.GetTensorShape(fNX2);
103 }
104 fTensorType1 = model.GetTensorType(fNX1);
105 fTensorType2 = model.GetTensorType(fNX2);
106 // case of non dynamic tensors
107 if (!fShapeX1.empty() && !fShapeX2.empty()) {
108 bool broadcastX1 = false;
109 bool broadcastX2 = false;
111 // no broadcast needed
113 } else {
114 // Y is the common shape of A and B
116 fBroadcastFlag = ret.first;
117 fShapeY = ret.second;
120 }
121
122
123 // analyze case of constant tensors or shape tensors (which have known shapes but data as Dim values
124 // normal case with non-dynamic tensor is also here
125 T *data1 = nullptr;
126 T *data2 = nullptr;
127 std::unique_ptr<T> broadcastedData1;
128 std::unique_ptr<T> broadcastedData2;
129 // data for shape tensors
130 std::vector<Dim> shapeData1;
131 std::vector<Dim> shapeData2;
133 bool *outData = new bool[length];
134 if (model.IsInitializedTensor(fNX1)) {
135 data1 = static_cast<T *>(model.GetInitializedTensorData(fNX1).get());
136 if (broadcastX1) {
137 broadcastedData1 = std::unique_ptr<T>(
139 data1 = broadcastedData1.get();
140 }
141
142 } else if (model.IsShapeTensor(fNX1)) {
143 shapeData1 = model.GetShapeTensorValues(fNX1);
144 }
145 if (model.IsInitializedTensor(fNX2)) {
146 data2 = static_cast<T *>(model.GetInitializedTensorData(fNX2).get());
147 if (broadcastX2) {
148 broadcastedData2 = std::unique_ptr<T>(
150 data2 = broadcastedData2.get();
151 }
152 } else if (model.IsShapeTensor(fNX2)) {
153 shapeData2 = model.GetShapeTensorValues(fNX2);
154 }
155 if (data1 && data2) {
156 fIsOutputConstant = true;
157 for (size_t i = 0; i < length; i++)
159 model.AddConstantTensor(fNY, fShapeY, outData);
160 if (model.Verbose())
161 std::cout << ComparisionTrait<T, Op>::Name() << " op ---> " << fNY << " "
163 << std::endl;
164 } else if ((data1 || !shapeData1.empty()) && (data2 || !shapeData2.empty())) {
165 fIsOutputConstant = true;
166 if (data1 && !data2) {
167 // data 1 is constant and data2 is shape
168 for (size_t i = 0; i < length; i++) {
169 if (shapeData2[i].isParam) {
170 if (shapeData2[i].dim == size_t(-1) || data1[i] > 0) {
171 fIsOutputConstant = false;
172 break;
173 } else {
174 // assume a comparison is done with .dim = 0
175 shapeData2[i].dim = 0;
176 }
177 }
178 outData[i] = ComparisionTrait<T, Op>::Result(data1[i], static_cast<T>(shapeData2[i].dim));
179 }
180 } else if (!data1 && data2) {
181 // data 1 is shape and dat2 is constant
182 for (size_t i = 0; i < length; i++) {
183 if (shapeData1[i].isParam) {
184 if (shapeData1[i].dim == size_t(-1) || data2[i] > 0) {
185 fIsOutputConstant = false;
186 break;
187 } else {
188 // assume a comparison is done with .dim = 0
189 shapeData1[i].dim = 0;
190 }
191 }
192 outData[i] = ComparisionTrait<T, Op>::Result(static_cast<T>(shapeData1[i].dim), data2[i]);
193 }
194 } else if (!shapeData1.empty() && !shapeData2.empty()) {
195 // both data1 and data2 are shape tensors
196 for (size_t i = 0; i < length; i++) {
197 if (!shapeData1[i].isParam && !shapeData2[i].isParam) {
199 } else if (shapeData1[i].isParam && shapeData2[i].isParam) {
200 if (shapeData1[i].param == shapeData2[i].param)
201 outData[i] = ComparisionTrait<int, Op>::Result(1, 1); // comparison of two equal value
202 else {
203 fIsOutputConstant = false;
204 break;
205 }
206 } else {
207 fIsOutputConstant = false;
208 break;
209 }
210 }
211 }
212 if (fIsOutputConstant) {
213 model.AddConstantTensor(fNY, fShapeY, outData);
214 if (model.Verbose())
215 std::cout << ComparisionTrait<T, Op>::Name() << " op ---> " << fNY << " "
217 << " (constant) " << std::endl;
218 }
219 }
220 delete[] outData;
221 // case of non constant output (no constant or shape tensors)
222 if (!fIsOutputConstant && !fShapeY.empty()) {
223 model.AddIntermediateTensor(fNY, ETensorType::BOOL, fShapeY);
225 if (model.Verbose())
226 std::cout << ComparisionTrait<T, Op>::Name() << " op ---> " << fNY << " "
227 << ConvertShapeToString(fShapeY) << std::endl;
228 }
229 } else {
230 // case of dynamic tensors
231 // case A or B have dynamic shapes. We need to broadcast if shape are not same
233 fBroadcastFlag = ret.first;
234 fDimShapeY = ret.second;
235 // case of all parametric shapes and MultiDirectionalBroadcastShape return the max of the 2
236 // need to do before we declare the output tensor shape and the broadcasted ones
237 if (ret.first & 4) {
238 // check if one of the parameter is an input dimension
239 // define function to find this
240 auto IsInputDimParam = [&](const std::string &p) {
241 auto inputNames = model.GetInputTensorNames();
242 for (auto &input : inputNames) {
243 for (auto &i_s : model.GetDimTensorShape(input)) {
244 if (i_s.isParam && i_s.param == p)
245 return true;
246 }
247 }
248 return false;
249 };
250 for (size_t i = 0; i < fDimShapeY.size(); i++) {
251 auto &s = fDimShapeY[i];
252 if (s.isParam && s.param.find("std::max") != std::string::npos) {
253 if (IsInputDimParam(fDimShapeX1[i].param)) {
254 // case dim is 1 we indicate that the input parameter is equal to 1
255 if (fDimShapeX1[i].dim != 1)
256 s = fDimShapeX1[i];
257 else
258 s = fDimShapeX2[i];
259 } else if (IsInputDimParam(fDimShapeX2[i].param)) {
260 if (fDimShapeX2[i].dim != 1)
261 s = fDimShapeX2[i];
262 else
263 s = fDimShapeX1[i];
264 }
265 }
266 }
267 }
268
269 model.AddIntermediateTensor(fNY, ETensorType::BOOL, fDimShapeY);
270 if (model.Verbose()) {
271 std::cout << ComparisionTrait<T, Op>::Name() << " : " << fNX1 << " " << ConvertDimShapeToString(fDimShapeX1) << " , "
272 << fNX2 << " " << ConvertDimShapeToString(fDimShapeX2) << " --> "
273 << fNY << " " << ConvertDimShapeToString(fDimShapeY) << std::endl;
274 model.PrintIntermediateTensors();
275 }
276 }
277 }
278
279 std::string Generate(std::string opName) override {
280 if (fIsOutputConstant) return "";
281 opName = "op_" + opName;
282
283 if (fDimShapeY.empty()) {
284 throw std::runtime_error("TMVA SOFIE Comparision Op called to Generate without being initialized first");
285 }
286 std::stringstream out;
287 out << SP << "\n//------ " << ComparisionTrait<T,Op>::Name() << " " << opName
288 << " --> " << ConvertShapeToString(fShapeY) << "\n";
289
290 // need to add check if tensors are compatible as in binary operator
291
292 // use same code as Binary operator
296
298 if (fDimShapeX1.empty() ||
299 std::all_of(fDimShapeX1.begin(), fDimShapeX1.end(), [](Dim d) { return d.dim == 1 || d.GetVal() == "1"; })) {
300 compute_idx_X1 = "0";
301 } else {
302 for (size_t i = 0; i < fDimShapeX1.size(); ++i) {
303 if (fDimShapeX1[i].dim == 1 || fDimShapeX1[i].GetVal() == "1")
304 continue;
305 compute_idx_X1 += "idx_" + std::to_string(i + (fDimShapeY.size() - fDimShapeX1.size()));
306 if (stridesA[i].GetVal() != "1")
307 compute_idx_X1 += " * " + stridesA[i].GetVal();
308 compute_idx_X1 += " + ";
309 }
310 // remove last 3 character " + "
311 for (int j = 0; j < 3; j++)
312 compute_idx_X1.pop_back();
313 }
314 if (fDimShapeX2.empty() ||
315 std::all_of(fDimShapeX2.begin(), fDimShapeX2.end(), [](Dim d) { return d.dim == 1 || d.GetVal() == "1"; })) {
316 compute_idx_X2 = "0";
317 } else {
318 for (size_t i = 0; i < fDimShapeX2.size(); ++i) {
319 if (fDimShapeX2[i].dim == 1 || fDimShapeX2[i].GetVal() == "1")
320 continue;
321 compute_idx_X2 += "idx_" + std::to_string(i + (fDimShapeY.size() - fDimShapeX2.size()));
322 if (stridesB[i].GetVal() != "1")
323 compute_idx_X2 += " * " + stridesB[i].GetVal();
324 compute_idx_X2 += " + ";
325 }
326 // remove last 3 character " + "
327 for (int j = 0; j < 3; j++)
328 compute_idx_X2.pop_back();
329 }
330 int nloop = 0;
331 if (fDimShapeY.empty() ||
332 std::all_of(fDimShapeY.begin(), fDimShapeY.end(), [](Dim d) { return d.dim == 1 || d.GetVal() == "1"; })) {
333 compute_idx_Y = "0";
334 } else {
335 for (size_t i = 0; i < fDimShapeY.size(); ++i) {
336 if (fDimShapeY[i].dim != 1 && fDimShapeY[i].GetVal() != "1") {
337 nloop++;
338 for (int j = 0; j < nloop; j++) out << SP;
339 out << "for (size_t idx_" << i << " = 0; idx_" << i << " < " << fDimShapeY[i]
340 << "; ++idx_" << i << "){\n";
341 compute_idx_Y += "idx_" + std::to_string(i);
342 if (stridesY[i].GetVal() != "1")
343 compute_idx_Y += " * " + stridesY[i].GetVal();
344 compute_idx_Y += " + ";
345 }
346 }
347 // remove last 3 characters " + "
348 for (int j = 0; j < 3; j++)
349 compute_idx_Y.pop_back();
350 }
351 for (int j = 0; j < nloop + 1; j++) out << SP;
352 out << "tensor_" << fNY << "[" << compute_idx_Y << "] = "
353 << ComparisionTrait<T,Op>::Op( "tensor_" + fNX1 + "[" + compute_idx_X1 + "]" ,
354 "tensor_" + fNX2 + "[" + compute_idx_X2 + "]") << " ;\n";
355
356
357 for (int i = nloop; i > 0; i--) {
358 for (int j = 0; j < i; j++) out << SP;
359 out << "}\n";
360 }
361
362
363 return out.str();
364 }
365
366};
367
368}//SOFIE
369}//Experimental
370}//TMVA
371
372
373#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::string Generate(std::string opName) override
ROperator_Comparision(const std::string &nameX1, const std::string &nameX2, const std::string &nameY)
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:44
bool fIsOutputConstant
flag to identify if operator has a constant output (no need to generate code)
Definition ROperator.hxx:41
const std::string SP
space used to correctly indent the generated C++ code
Definition ROperator.hxx:40
std::vector< std::string_view > fOutputTensorNames
Definition ROperator.hxx:45
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