Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Where.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROperator_Where
2#define TMVA_SOFIE_ROperator_Where
3
5#include "TMVA/ROperator.hxx"
6#include "TMVA/RModel.hxx"
7
8#include <sstream>
9
10namespace TMVA{
11namespace Experimental{
12namespace SOFIE{
13
14
15
16template<typename T>
18private:
19
20 bool fIsInputBoolTensor = false;
21
22
23 std::string fNA;
24 std::string fNB;
25 std::string fNC;
26 std::string fNBroadcastedA;
27 std::string fNBroadcastedB;
28 std::string fNBroadcastedC;
29 std::string fNY;
30
31
32 std::vector<size_t> fShapeA;
33 std::vector<size_t> fShapeB;
34 std::vector<size_t> fShapeC;
35 std::vector<size_t> fShapeY;
36
37
38public:
40 ROperator_Where(const std::string & nameA, const std::string & nameB, const std::string & nameC, const std::string & nameY):
41 fNA(UTILITY::Clean_name(nameA)), fNB(UTILITY::Clean_name(nameB)), fNC(UTILITY::Clean_name(nameC)), fNY(UTILITY::Clean_name(nameY)){
44 }
45
46 // type of output given input
47 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override {
48 return input;
49 }
50
51 // shape of output tensors given input tensors
52 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input) override {
53 // assume now inputs have same shape (no broadcasting)
54 auto ret = std::vector<std::vector<size_t>>(1, input[0]); // return vector size 1 with first input
55 return ret;
56 }
57
58 void Initialize(RModel& model) override {
59 // input must be a graph input, or already initialized intermediate tensor
60 if (!model.CheckIfTensorAlreadyExist(fNA)){
61 throw std::runtime_error(std::string("TMVA SOFIE Where Op Input Tensor ") + fNA + "is not found in model");
62 }
63 if (!model.CheckIfTensorAlreadyExist(fNB)) {
64 throw std::runtime_error(std::string("TMVA SOFIE Where Op Input Tensor ") + fNB + "is not found in model");
65 }
66 if (!model.CheckIfTensorAlreadyExist(fNC)) {
67 throw std::runtime_error(std::string("TMVA SOFIE Where Op Input Tensor ") + fNC + "is not found in model");
68 }
69 // check if fNC input tensor is boolean
70 if (model.IsReadyInputTensor(fNC))
71 fIsInputBoolTensor = true;
72 // check broadcast for A, B and C
73 fShapeA = model.GetTensorShape(fNA);
74 fShapeB = model.GetTensorShape(fNB);
75 fShapeC = model.GetTensorShape(fNC);
77 if (broadcast) {
78 // find shape to broadcast between A,B,C looking for max length
82 bool broadcastA = false, broadcastB = false, broadcastC = false;
83 if (lengthA >= lengthB && lengthA >= lengthC) {
85 //broadcast B and C if different than A
88 }
89 else if (lengthB >= lengthA && lengthB >= lengthC) {
91 //broadcast A and C if different than B
94 }
95 else if (lengthC >= lengthA && lengthC >= lengthB) {
97 //broadcast A and B if different than C
100 }
101
102 // Broadcast A to Y
103 if (broadcastA) {
104 fNBroadcastedA = "BC_" + fNA + "_to_" + fNY;
105 if (model.IsInitializedTensor(fNA)) {
106 auto data = model.GetInitializedTensorData(fNA);
107 std::shared_ptr<void> broadcastedData(
108 UTILITY::UnidirectionalBroadcast<T>(static_cast<T *>(data.get()), fShapeA, fShapeY),
109 std::default_delete<T[]>());
110 // Update the data and the shape of A
113 } else {
114 // Add an intermediate tensor for broadcasting A
116 }
117 }
118 // Broadcast B to Y
119 if (broadcastB) {
120 fNBroadcastedB = "BC_" + fNB + "_to_" + fNY;
121 if (model.IsInitializedTensor(fNB)) {
122 auto data = model.GetInitializedTensorData(fNB);
123 std::shared_ptr<void> broadcastedData(
124 UTILITY::UnidirectionalBroadcast<T>(static_cast<T *>(data.get()), fShapeB, fShapeY),
125 std::default_delete<T[]>());
126 // do not update tensor B but add broadcasted one (since it can be input to some other operators)
129 } else {
130 // Add an intermediate tensor for broadcasting B
132 }
133 }
134 // Broadcast C to Y
135 if (broadcastC) {
136 fNBroadcastedC = "BC_" + fNC + "_to_" + fNY;
137 if (model.IsInitializedTensor(fNC)) {
138 auto data = model.GetInitializedTensorData(fNC);
139 std::shared_ptr<void> broadcastedData(
140 UTILITY::UnidirectionalBroadcast<T>(static_cast<T *>(data.get()), fShapeC, fShapeY),
141 std::default_delete<T[]>());
142 // do not update tensor C but add broadcasted one (since it can be input to some other operators)
145 } else {
146 // Add an intermediate tensor for broadcasting B
148 }
149 }
150 } else {
152 }
153 // check case of constant output (if all inputs are defined)
154 if (model.IsInitializedTensor(fNC)) {
155
156 std::string nameC = fNBroadcastedC.empty()? fNC : fNBroadcastedC;
157 auto dataC = static_cast<bool *>(model.GetInitializedTensorData(nameC).get());
159 T * dataA = nullptr;
160 T * dataB = nullptr;
161 std::vector<Dim> shapeDataA;
162 std::vector<Dim> shapeDataB;
163 if (model.IsInitializedTensor(fNA)) {
164 std::string nameA = fNBroadcastedA.empty()? fNA : fNBroadcastedA;
165 dataA = static_cast<T *>(model.GetInitializedTensorData(nameA).get());
166 // flag tensors to not be written in a file
168 } else if (model.IsShapeTensor(fNA))
170 if (model.IsInitializedTensor(fNB)) {
171 std::string nameB = fNBroadcastedB.empty()? fNB : fNBroadcastedB;
172 dataB = static_cast<T *>(model.GetInitializedTensorData(nameB).get());
174 } else if (model.IsShapeTensor(fNB))
176
177 std::vector<T> dataY;
178 std::vector<Dim> shapeDataY;
179
180 bool isOutputConstantTensor = true;
181 if (dataA && dataB) {
183 for (size_t i = 0; i < dataY.size(); i++)
184 dataY[i] = (dataC[i]) ? dataA[i] : dataB[i];
185 }
186 else if (dataA && shapeDataB.size()>0 ) {
188 for (size_t i = 0; i < shapeDataY.size(); i++) {
189 shapeDataY[i] = (dataC[i]) ? Dim{size_t(dataA[i])} : shapeDataB[i];
190 isOutputConstantTensor &= !shapeDataY[i].isParam;
191 }
192 }
193 else if (dataB && shapeDataA.size()>0 ) {
195 for (size_t i = 0; i < shapeDataY.size(); i++) {
196 shapeDataY[i] = (dataC[i]) ? shapeDataB[i] : Dim{size_t(dataB[i])};
197 isOutputConstantTensor &= !shapeDataY[i].isParam;
198 }
199 }
200 else if (shapeDataB.size() > 0 && shapeDataA.size()>0 ) {
202 for (size_t i = 0; i < shapeDataY.size(); i++) {
203 shapeDataY[i] = (dataC[i]) ? shapeDataA[i] : shapeDataB[i];
204 isOutputConstantTensor &= !shapeDataY[i].isParam;
205 }
206 }
207 fIsOutputConstant = true; // this contains both case constant tensor output ans shape tensor output
208 if (isOutputConstantTensor && dataY.empty()) {
209 dataY.resize(shapeDataY.size());
210 for (size_t i = 0; i < shapeDataY.size(); i++)
211 dataY[i] = static_cast<T>(shapeDataY[i].dim);
212 }
213 if (dataY.size() > 0)
214 model.AddConstantTensor<T>(fNY, fShapeY, dataY.data());
215 else if (shapeDataY.size() > 0 )
216 model.AddShapeTensor(fNY, shapeDataY, fShapeY.size() == 0);
217 else {
218 fIsOutputConstant = false;
219 }
220 if (fIsOutputConstant && model.Verbose())
221 std::cout << "Where op ---> " << fNY << " " << ConvertShapeToString(fShapeY) << " : "
223 << ((dataY.size() > 0) ? " (constant)" : " (shape)") << std::endl;
224
225 // output is a constant tensor
227 }
228 if (!fIsOutputConstant) {
230 if (model.Verbose())
231 std::cout << "Where op " << " condition : " << fNC << " " << ConvertShapeToString(fShapeC) <<
232 " X " << fNA << " " << ConvertShapeToString(fShapeA) << " Y " << fNB << " " << ConvertShapeToString(fShapeB)
233 << " ---> " << fNY << " " << ConvertShapeToString(fShapeY) << std::endl;
234 }
235 }
236
237 std::string GenerateInitCode() override {
238 std::stringstream out;
239 return out.str();
240 }
241
242 std::string Generate(std::string opName) override {
243
244 if (fIsOutputConstant) return "";
245
246 opName = "op_" + opName;
247
248 if (fShapeY.empty()) {
249 throw std::runtime_error("TMVA SOFIE Where Op called to Generate without being initialized first");
250 }
251 std::stringstream out;
252 out << SP << "\n//-------- Where " << opName << " --> " << ConvertShapeToString(fShapeY) << "\n";
254 std::string typeName = TensorType<T>::Name();
255 // Broadcast A if it's uninitialized
256 if (fShapeA != fShapeY) {
257 out << SP << "// Broadcasting uninitialized tensor " << fNA << "\n";
258 //out << SP << "{\n";
259 out << SP << "TMVA::Experimental::SOFIE::UTILITY::UnidirectionalBroadcast<" << typeName << ">(tensor_" << fNA << ", " << ConvertShapeToString(fShapeA) << ", " << ConvertShapeToString(fShapeY)
260 << ", fTensor_" << fNBroadcastedA << ");\n";
261 }
262 // Broadcast B if it's uninitialized
263 if (fShapeB != fShapeY) {
264 out << SP << "// Broadcasting uninitialized tensor " << fNB << "\n";
265 //out << SP << "{\n";
266 out << SP << "TMVA::Experimental::SOFIE::UTILITY::UnidirectionalBroadcast<" << typeName << ">(tensor_" << fNB << ", " << ConvertShapeToString(fShapeB) << ", " << ConvertShapeToString(fShapeY)
267 << ", fTensor_" << fNBroadcastedB << ");\n";
268 }
269 // Broadcast C if it's uninitialized
270 if (fShapeC != fShapeY) {
271 // special case if C is an input tensor
272 if (fIsInputBoolTensor) {
274 out << SP << "std::vector<std::uint8_t> fTensor_" << fNC << "(tensor_" << fNC << ", tensor_" << fNC << " + " << inputLength << ");\n";
275 }
276 out << SP << "// Broadcasting uninitialized tensor " << fNC << "\n";
277 //out << SP << "{\n";
278 out << SP << "TMVA::Experimental::SOFIE::UTILITY::UnidirectionalBroadcast<std::uint8_t>(fTensor_" << fNC << ".data(), " << ConvertShapeToString(fShapeC) << ", " << ConvertShapeToString(fShapeY)
279 << ", fTensor_" << fNBroadcastedC << ");\n";
280 }
281 std::string nameA = fNBroadcastedA.empty()? fNA : fNBroadcastedA;
282 std::string nameB = fNBroadcastedB.empty()? fNB : fNBroadcastedB;
283 std::string nameC = fNBroadcastedC.empty()? fNC : fNBroadcastedC;
284 out << SP << "for (size_t id = 0; id < " << length << " ; id++){\n";
285 // get output tensor applying condition
286 out << SP << SP << "tensor_" << fNY << "[id] = " << "(fTensor_" << nameC << "[id]) ? tensor_"
287 << nameA << "[id] : tensor_" + nameB + "[id];\n";
288 out << SP << "}\n";
289 return out.str();
290 }
291
292};
293
294}//SOFIE
295}//Experimental
296}//TMVA
297
298
299#endif //TMVA_SOFIE_ROperator_Where
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
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:29
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:247
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:122
void AddConstantTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition RModel.cxx:193
bool IsShapeTensor(const std::string &name) const
check if a tensor is a shape tensor
Definition RModel.cxx:211
bool IsInitializedTensor(const std::string &name) const
Definition RModel.cxx:220
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition RModel.cxx:312
void SetNotWritableInitializedTensor(const std::string &tensor_name)
Definition RModel.cxx:321
ETensorType GetTensorType(std::string name) const
Definition RModel.cxx:90
const std::vector< Dim > & GetShapeTensorValues(const std::string &tensor_name) const
Definition RModel.cxx:215
bool IsReadyInputTensor(const std::string &name) const
Definition RModel.cxx:241
void AddShapeTensor(const std::string &name, const std::vector< Dim > &shapeValues, bool scalar=false)
Definition RModel.cxx:203
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input) override
std::string Generate(std::string opName) override
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
ROperator_Where(const std::string &nameA, const std::string &nameB, const std::string &nameC, 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::size_t ConvertShapeToLength(const std::vector< size_t > &shape)
std::string ConvertValuesToString(size_t n, const T *data)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
create variable transformations