Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
ROperator_Tile.hxx
Go to the documentation of this file.
1#ifndef TMVA_SOFIE_ROPERATOR_Tile
2#define TMVA_SOFIE_ROPERATOR_Tile
3
5#include "TMVA/ROperator.hxx"
6#include "TMVA/RModel.hxx"
7
8#include <sstream>
9
10namespace TMVA{
11namespace Experimental{
12namespace SOFIE{
13
14template <typename T>
16{
17
18private:
19
20 std::string fNRepeats;
21 std::string fNInput;
22 std::string fNY;
23 std::vector<Dim>fShapeInput;
24 std::vector<Dim> fShapeY;
25
26public:
28 ROperator_Tile(std::string nameRepeat, std::string nameInput, std::string nameY):
29 fNRepeats(UTILITY::Clean_name(nameRepeat)),fNInput(UTILITY::Clean_name(nameInput)), fNY(UTILITY::Clean_name(nameY)){
30 // the repeats tensor is only used at generation time, so it is not a runtime input
33 }
34
35 std::vector<Dim> DoShapeInference(const std::vector<Dim> & input, const std::vector<size_t> repeat) {
36 std::vector<Dim> ret = input;
37 for(size_t i=0; i < repeat.size(); i++) {
38 if (repeat[i] != 1) {
39 if (ret[i].isParam) {
40 // parenthesize in case the dimension is a compound expression (e.g. "bsize + 1")
41 ret[i] = Dim{ std::string("(" + ret[i].GetVal() + ")*" + std::to_string(repeat[i])), static_cast<size_t>(-1) };
42 } else {
43 ret[i]=Dim { ret[i].dim *repeat[i] };
44 }
45 }
46 }
47 return ret;
48 }
49
50 void Initialize(RModel& model) override {
51 //input must be a graph input, or already initialized intermediate tensor
52 if (model.CheckIfTensorAlreadyExist(fNInput) == false){
53 throw std::runtime_error("TMVA SOFIE Tile Op Input Tensor is not found in model");
54 }
55 if (model.CheckIfTensorAlreadyExist(fNRepeats) == false){
56 throw std::runtime_error("TMVA SOFIE Tile Op Input Tensor is not found in model");
57 }
58 fShapeInput=model.GetDimTensorShape(fNInput);
59
60 // if repeats vector is not initialized we cannot deduce shape of output
61 // not support for time being this case
62 if (!model.IsInitializedTensor(fNRepeats)) {
63 throw std::runtime_error("TMVA SOFIE Tile Op: non-initialized repeats input is not supported");
64 }
65
66 // Retrieve the data pointer for the repeats tensor
67 auto repptr = model.GetInitializedTensorData(fNRepeats);
68 // Cast the raw pointer to the appropriate type (size_t*)
69 auto repeats_data = static_cast<int64_t*>(repptr.get());
70 if (repeats_data == nullptr) {
71 throw std::runtime_error("Failed to retrieve the data for the repeats tensor.");
72 }
73 // Get the shape of the repeats tensor to determine the number of elements
74 auto repeats_shape = model.GetTensorShape(fNRepeats);
75 // Ensure the repeats tensor is 1D and get the number of elements
76 if (repeats_shape.size() != 1) {
77 throw std::runtime_error("Repeats tensor is not 1D.");
78 }
79 size_t num_elements = repeats_shape[0];
80 // Convert the data to a vector of size_t
81 std::vector<size_t> repeats_vector(num_elements);
83
84
86
87 // the repeats are baked into the generated code, so the tensor is not
88 // needed at runtime and must not be written in the weight file
89 model.SetNotWritableInitializedTensor(fNRepeats);
90
91 model.AddIntermediateTensor(fNY, model.GetTensorType(fNInput), fShapeY);
92
93 if (model.Verbose())
94 std::cout << "Tile: " << fNInput << " " << ConvertDimShapeToString(fShapeInput) << " -> " << fNY << " with shape " << ConvertDimShapeToString(fShapeY)
95 << " given repeats " << ConvertShapeToString(repeats_vector) << std::endl;
96 }
97
98 std::string Generate(std::string OpName) override {
99 OpName = "op_" + OpName;
100 if (fShapeInput.empty() || fShapeY.empty()) {
101 throw std::runtime_error("TMVA SOFIE Tile Op called to Generate without being initialized first");
102 }
103
104 std::stringstream out;
105 out << "///-------- Tile operator " << OpName << "\n";
106 out << "{\n";
107
108 const int rank = fShapeInput.size();
109
110 // shapes can contain dynamic (parametric) dimensions, so they are emitted
111 // as expressions evaluated at runtime in the generated code
112 out << SP << "const size_t input_shape[" << rank << "] = " << ConvertDimShapeToString(fShapeInput) << ";\n";
113 out << SP << "const size_t output_shape[" << rank << "] = " << ConvertDimShapeToString(fShapeY) << ";\n\n";
114
115 // Pre-calculating the input strides to find element positions (the output
116 // index just advances sequentially in the loop nest below).
117 out << SP << "size_t input_strides[" << rank << "];\n";
118 out << SP << "input_strides[" << rank - 1 << "] = 1;\n";
119 out << SP << "for (int i = " << rank - 2 << "; i >= 0; --i) {\n";
120 out << SP << SP << "input_strides[i] = input_strides[i+1] * input_shape[i+1];\n";
121 out << SP << "}\n\n";
122
123 // One loop per output axis: o<i> is the output coordinate and ic<i> the
124 // corresponding input coordinate, kept in sync via a wrap-around counter
125 // so no division or modulo is needed per element.
126 out << SP << "size_t out_idx = 0;\n";
127 std::string indent = SP;
128 for (int i = 0; i < rank; ++i) {
129 out << indent << "for (size_t o" << i << " = 0, ic" << i << " = 0; o" << i
130 << " < output_shape[" << i << "]; ++o" << i << ") {\n";
131 indent += SP;
132 out << indent << "const size_t in_off" << i << " = "
133 << (i == 0 ? std::string() : "in_off" + std::to_string(i - 1) + " + ")
134 << "ic" << i << " * input_strides[" << i << "];\n";
135 }
136 out << indent << "tensor_" << fNY << "[out_idx++] = tensor_" << fNInput << "[in_off" << rank - 1 << "];\n";
137 for (int i = rank - 1; i >= 0; --i) {
138 out << indent << "if (++ic" << i << " == input_shape[" << i << "]) ic" << i << " = 0;\n";
139 indent.resize(indent.size() - SP.size());
140 out << indent << "}\n";
141 }
142
143 out << "}\n"; // End of scope
144 return out.str();
145 }
146};
147
148}//SOFIE
149}//Experimental
150}//TMVA
151
152#endif //TMVA_SOFIE_ROPERATOR_Tile
static void indent(ostringstream &buf, int indent_level)
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 input
const_iterator begin() const
ROperator_Tile(std::string nameRepeat, std::string nameInput, std::string nameY)
std::vector< Dim > DoShapeInference(const std::vector< Dim > &input, const std::vector< size_t > repeat)
std::string Generate(std::string OpName) override
void Initialize(RModel &model) override
std::vector< std::string_view > fInputTensorNames
Definition ROperator.hxx:44
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
std::string ConvertDimShapeToString(const std::vector< Dim > &shape)
std::string ConvertShapeToString(const std::vector< size_t > &shape)
create variable transformations