Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Transpose.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_TRANSPOSE
2#define TMVA_SOFIE_ROPERATOR_TRANSPOSE
3
5#include "TMVA/ROperator.hxx"
6#include "TMVA/RModel.hxx"
7
8#include <sstream>
9#include <cassert>
10
11namespace TMVA{
12namespace Experimental{
13namespace SOFIE{
14
15
16
18{
19
20private:
21
22 std::vector<int64_t> fAttrPerm;
23
24 std::string fNX;
25 std::string fNY;
26 std::vector<Dim> fShapeX;
27 std::vector<Dim> fShapeY;
28
29public:
30
32 ROperator_Transpose(std::vector<int64_t> attr_perm, std::string nameData, std::string nameOutput):
33 fAttrPerm(attr_perm), fNX(UTILITY::Clean_name(nameData)), fNY(UTILITY::Clean_name(nameOutput)) {
36 }
37
38
39 std::vector<ETensorType> TypeInference(std::vector<ETensorType> input) override {
40 return input;
41 }
42
43 std::vector<std::vector<size_t>> ShapeInference(std::vector<std::vector<size_t>> input) override {
44 if (input.size() > 1) throw std::runtime_error("TMVA SOFIE Tranpose Op Shape Inference only need 1 input tensor");
45 auto& data = input[0];
46 if (fAttrPerm.size() != data.size() )
47 throw std::runtime_error("TMVA SOFIE Tranpose Op - Invalid axes attributes");
48
49 std::vector<size_t> output_shape(fAttrPerm.size());
50 for (size_t i = 0; i < fAttrPerm.size(); i++){
52 }
53 std::vector<std::vector<size_t>> ret;
54 ret.push_back(output_shape);
55 return ret;
56 }
57
58 template<class T>
60 // case input is a constant or initialized tensor we perform here the transpose
61 // here we know the shape
64 fIsOutputConstant = true;
65
69 auto inputData = static_cast<T *>(model.GetInitializedTensorData(fNX).get());
70 size_t dim = fShapeX.size();
71 std::vector<size_t> outputIdx(dim);
72 std::vector<T> outputData(length);
73 for (size_t i = 0; i < length; i++) {
74 outputIdx[0] = i / outStrides[0];
75 for (size_t j = 1; j < dim; j++) {
76 outputIdx[j] = (i % outStrides[j - 1]) / outStrides[j];
77 }
78 // compute input index
79 size_t inputIndex = 0;
80 for (size_t j = 0; j < dim; j++) {
81 // find value in fAtrrPerm corresponding to j
82 int k = std::find(fAttrPerm.begin(), fAttrPerm.end(), j) - fAttrPerm.begin();
84 }
86 }
87 model.AddConstantTensor<T>(fNY, shapeY, outputData.data());
88 if (model.Verbose()) {
89 std::cout << "Transpose: output is a constant tensor " << ConvertShapeToString(shapeY) << " : "
90 << ConvertValuesToString(outputData) << std::endl;
91 }
92 }
93
94 void Initialize(RModel& model) override {
95 if (model.CheckIfTensorAlreadyExist(fNX) == false){ //input must be a graph input, or already initialized intermediate tensor
96 std::cout<<"Input tensor for transpose: "<<fNX<<'\n';
97 throw std::runtime_error("TMVA SOFIE Tranpose Op Input Tensor is not found in model");
98 }
100 if (fAttrPerm.empty()){
101 fAttrPerm.reserve(fShapeX.size());
102 for (int i = fShapeX.size() - 1; i >= 0; i--){
103 fAttrPerm.push_back(i);
104 }
105 }
106
107 // inference of output shape
108 if (fAttrPerm.size() != fShapeX.size() )
109 throw std::runtime_error("TMVA SOFIE Tranpose Op - Invalid axes attributes");
110
111 fShapeY.resize(fAttrPerm.size());
112 for (size_t i = 0; i < fAttrPerm.size(); i++){
113 fShapeY[i] = fShapeX[fAttrPerm[i]];
114 }
115
116 if (model.IsInitializedTensor(fNX) ) {
117 auto type = model.GetTensorType(fNX);
118 switch(type) {
121 break;
124 break;
127 break;
130 break;
131 default:
132 std::cout << "Transpose - no support for initialized tensor of type " << ConvertTypeToString(type) << std::endl;
133 }
134 return;
135 }
136 // case of intermediate tensors (non constant)
138 if (model.Verbose()) {
139 std::cout << "Transpose ---> " << fNY << " " << ConvertDimShapeToString(fShapeY) << std::endl;
140 }
141 }
142
143 std::string Generate(std::string opName) override {
144 if (fIsOutputConstant) return ""; //no op for constant tensors
145 opName = "op_" + opName;
146 if (fShapeX.empty() || fShapeY.empty()){
147 throw std::runtime_error("TMVA SOFIE Transpose Op called to Generate without being initialized first");
148 }
151
153 size_t rank = fShapeX.size();
154 bool isDynamic = (intShapeX.empty() && rank > 0);
155
156 std::string constQualifier = (isDynamic) ? "const" : "constexpr";
157
158 std::stringstream out;
159
160 out << SP << "///------- Transpose operator " << opName << ConvertDimShapeToString(fShapeX)
161 << " --> " << ConvertDimShapeToString(fShapeY) << std::endl;
162
163 // Implement more efficient implementation of transpose operator using strides
164 // For 2-dim rank tensors we could have an optimised implementation for rank = 2 tensors using Tiles
165
166 // General implementation : start pre-computing strides as const expr
167 // Emit strides for X (input) and Y (output) as constexpr
168 out << SP << "{\n";
169 out << SP << SP << "// Pre-baked input strides (row-major)\n";
170 out << SP << SP << constQualifier << " size_t " << opName << "_strX[] = {";
171 for (size_t i = 0; i < rank; ++i)
172 out << stridesX[i] << (i + 1 < rank ? ", " : "");
173 out << "};\n";
174
175 out << SP << SP << "// Pre-baked output strides (row-major)\n";
176 out << SP << SP << constQualifier << " size_t " << opName << "_strY[] = {";
177 for (size_t i = 0; i < rank; ++i)
178 out << stridesY[i] << (i + 1 < rank ? ", " : "");
179 out << "};\n\n";
180
181 // Check if last perm axis == rank-1 (contiguous inner axis fast path)
182 bool innerContiguous = (fAttrPerm.back() == (int64_t) (rank - 1));
183 size_t outerRank = innerContiguous ? rank - 1 : rank;
185 : 1;
186
187 if (innerContiguous && !isDynamic && innerSize > 1) {
188 // ---- Fast path: innermost axis is contiguous in source -----
189 out << SP << SP
190 << "// Fast path: last permuted axis is contiguous in source\n";
191 out << SP << SP
192 << "// Inner " << innerSize << " elements copied with pointer arithmetic\n";
193
194 // Nested loops over all axes except the last
196
197 // Compute flat src and dst offsets for the current outer indices
198 out << SP << SP << SP << "size_t src_off = ";
199 for (size_t i = 0; i < outerRank; ++i) {
200 out << "idx_" << i << " * " << opName << "_strX["
201 << fAttrPerm[i] << "]";
202 if (i + 1 < outerRank) out << " + ";
203 }
204 out << ";\n";
205
206 out << SP << SP << SP << "size_t dst_off = ";
207 for (size_t i = 0; i < outerRank; ++i) {
208 out << "idx_" << i << " * " << opName << "_strY[" << i << "]";
209 if (i + 1 < outerRank) out << " + ";
210 }
211 out << ";\n";
212
213 // Inner memcpy-style copy over the contiguous axis
214 out << SP << SP << SP
215 << "std::copy(tensor_" << fNX << " + src_off, "
216 << "tensor_" << fNX << " + src_off + " << innerSize << ", "
217 << "tensor_" << fNY << " + dst_off);\n";
218
220
221 } else {
222
223 // ---- General path: per-element index arithmetic -------------
224 out << SP << SP << "// General N-D transpose\n";
225
227
228 // Flat source index: sum over perm[i] * strideX[perm[i]]
229 out << SP << SP << SP << "size_t src_idx = ";
230 for (size_t i = 0; i < rank; ++i) {
231 out << "idx_" << i << " * " << opName << "_strX[" << fAttrPerm[i] << "]";
232 if (i + 1 < rank) out << " + ";
233 }
234 out << ";\n";
235
236 // Flat destination index: sum over i * strideY[i]
237 out << SP << SP << SP << "size_t dst_idx = ";
238 for (size_t i = 0; i < rank; ++i) {
239 out << "idx_" << i << " * " << opName << "_strY[" << i << "]";
240 if (i + 1 < rank) out << " + ";
241 }
242 out << ";\n";
243
244 out << SP << SP << SP
245 << "tensor_" << fNY << "[dst_idx] = "
246 << "tensor_" << fNX << "[src_idx];\n";
247
249
250 }
251
252 out << SP << "}\n";
253 return out.str();
254 }
255
256
257};
258
259}//SOFIE
260}//Experimental
261}//TMVA
262
263
264#endif //TMVA_SOFIE_ROPERATOR_TRANSPOSE
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
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 Atom_t Int_t ULong_t ULong_t unsigned char prop_list Atom_t Atom_t Atom_t Time_t type
std::vector< Dim > GetDimTensorShape(const std::string &name) const
Definition RModel.cxx:87
void AddIntermediateTensor(std::string tensor_name, ETensorType type, std::vector< Dim > dim_shape)
Definition RModel.cxx:284
bool CheckIfTensorAlreadyExist(std::string tensor_name)
Definition RModel.cxx:144
void AddConstantTensor(std::string tensor_name, ETensorType type, std::vector< std::size_t > shape, std::shared_ptr< void > data)
Definition RModel.cxx:215
bool IsInitializedTensor(const std::string &name) const
Definition RModel.cxx:256
std::shared_ptr< void > GetInitializedTensorData(std::string tensor_name)
Definition RModel.cxx:349
ETensorType GetTensorType(std::string name) const
Definition RModel.cxx:112
std::vector< ETensorType > TypeInference(std::vector< ETensorType > input) override
std::string Generate(std::string opName) override
ROperator_Transpose(std::vector< int64_t > attr_perm, std::string nameData, std::string nameOutput)
std::vector< std::vector< size_t > > ShapeInference(std::vector< std::vector< size_t > > input) override
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
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< size_t > ConvertShapeToInt(const std::vector< Dim > &shape)
Convert shape based on Dim to integer format.
std::string ConvertTypeToString(ETensorType type)
void EmitNestedLoops(std::stringstream &out, size_t loopRank, const std::vector< Dim > shape)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
void CloseNestedLoops(std::stringstream &out, size_t loopRank)
create variable transformations