File indexing completed on 2026-09-06 09:22:28
0001 #ifndef TMVA_SOFIE_ROPERATOR_RANGE
0002 #define TMVA_SOFIE_ROPERATOR_RANGE
0003
0004 #include "TMVA/SOFIE_common.hxx"
0005 #include "TMVA/ROperator.hxx"
0006 #include "TMVA/RModel.hxx"
0007
0008 #include <sstream>
0009 #include <algorithm>
0010
0011 namespace TMVA{
0012 namespace Experimental{
0013 namespace SOFIE{
0014
0015 template <typename T>
0016 class ROperator_Range final : public ROperator
0017 {
0018 private:
0019
0020 std::string fNStart;
0021 std::string fNLimit;
0022 std::string fNDelta;
0023 std::string fNOutput;
0024 std::vector<Dim> fShape;
0025 std::string fType;
0026
0027 public:
0028 ROperator_Range(){}
0029
0030 ROperator_Range(std::string start, std::string limit, std::string delta, std::string nameOutput):
0031 fNStart(start), fNLimit(limit), fNDelta(delta),
0032 fNOutput(UTILITY::Clean_name(nameOutput)) {
0033 if (std::is_same<T, float>::value) {
0034 fType = "float";
0035 } else if (std::is_same<T, int64_t>::value) {
0036 fType = "int64_t";
0037 }
0038 static_assert( (std::is_same_v<T, float> || std::is_same_v<T, int64_t>),
0039 "TMVA::SOFIE - Unsupported type by Range operator");
0040 {
0041 fInputTensorNames = { fNStart, fNLimit, fNDelta };
0042 fOutputTensorNames = { fNOutput };
0043 }
0044 }
0045
0046 void Initialize(RModel& model) override {
0047
0048 if (!model.CheckIfTensorAlreadyExist(fNStart)) {
0049 throw
0050 std::runtime_error("TMVA SOFIE Range Op Input Tensor " + fNStart + "is not found in model");
0051 }
0052 if (!model.CheckIfTensorAlreadyExist(fNLimit)) {
0053 throw
0054 std::runtime_error("TMVA SOFIE Range Op Input Tensor " + fNLimit + "is not found in model");
0055 }
0056 if (!model.CheckIfTensorAlreadyExist(fNDelta)) {
0057 throw
0058 std::runtime_error("TMVA SOFIE Range Op Input Tensor " + fNDelta + "is not found in model");
0059 }
0060 ETensorType type = ConvertStringToType(fType);
0061
0062
0063
0064 auto analyzeInput = [&](const std::string & tName, T & value, Dim & dim) {
0065 int ftype = 0;
0066 if (model.IsInitializedTensor(tName)) {
0067 T * data = static_cast<T*>(model.GetInitializedTensorData(tName).get());
0068 if (!data)
0069 throw std::runtime_error("TMVA SOFIE Range Op Input Tensor has invalid input data");
0070 value = *data;
0071 ftype = 1;
0072 } else if (model.IsShapeTensor(tName)) {
0073 auto data = model.GetShapeTensorValues(tName);
0074 dim = data[0];
0075 if (!dim.isParam) {
0076 value = static_cast<T>(dim.dim);
0077 ftype = 1;
0078 } else
0079 ftype = 2;
0080 }
0081 return ftype;
0082 };
0083
0084 T start_value;
0085 T limit_value;
0086 T delta_value;
0087 Dim start_dim;
0088 Dim limit_dim;
0089 Dim delta_dim;
0090 int res1 = analyzeInput(fNStart, start_value, start_dim);
0091 int res2 = analyzeInput(fNLimit, limit_value, limit_dim);
0092 int res3 = analyzeInput(fNDelta, delta_value, delta_dim);
0093 if (res1 == 0 || res2 == 0 || res3 == 0) {
0094
0095
0096 fShape = {Dim{"range_size_" + fNStart + "_" + fNLimit}};
0097 model.AddDynamicTensor(fNOutput, type, fShape);
0098 } else if (res1 == 1 && res2 == 1 && res3 == 1) {
0099 size_t number_of_elements = std::max(static_cast<int>(std::ceil((limit_value - start_value) / delta_value )) , 0 );
0100 fIsOutputConstant = true;
0101
0102
0103 std::vector<T> output(number_of_elements);
0104 for (size_t i=0; i<number_of_elements; ++i) {
0105 output[i] = start_value + (i * delta_value);
0106 }
0107 std::vector<size_t> shape = {number_of_elements};
0108 model.AddConstantTensor(fNOutput,shape, output.data());
0109 fShape = ConvertShapeToDim(shape);
0110
0111 } else {
0112 std::string start = (res1 == 1) ? std::to_string(start_value) : start_dim.GetVal();
0113 std::string limit = (res2 == 1) ? std::to_string(limit_value) : limit_dim.GetVal();
0114 std::string delta = (res3 == 1) ? std::to_string(delta_value) : delta_dim.GetVal();
0115 std::stringstream s;
0116 if (type == ETensorType::FLOAT ) {
0117 if (delta_value == 1)
0118 s << "std::max(std::ceil("<< limit << " - " << start << "),0.0f)";
0119 else
0120 s << "std::max(std::ceil(("<< limit << " - " << start << ")/" << delta << "),0.0f)";
0121 } else if (type == ETensorType::INT64 ) {
0122 if (delta == "1") {
0123 if (start == "0")
0124 s << limit;
0125 else
0126 s << "std::max((" << limit << " - " << start << "),0L)";
0127 } else {
0128 if (start == "0")
0129 s << "((" << limit << ")/" << delta << ")";
0130 else
0131 s << "std::max((" << limit << " - " << start << ")/"<< delta << "),0L)";
0132 }
0133 } else {
0134 throw
0135 std::runtime_error("TMVA SOFIE Range Op Input Tensor " + ConvertTypeToString(type) + "is not supported");
0136 }
0137
0138
0139 fShape = { Dim {s.str(), static_cast<size_t>(-1)} };
0140 model.AddDynamicTensor(fNOutput,type, fShape);
0141 }
0142
0143
0144 if (model.Verbose()) {
0145 std::cout << "Range -> output is " << fNOutput << " : " << ConvertDimShapeToString(fShape);
0146 if (fIsOutputConstant) std::cout << " : " << ConvertValuesToString(model.GetTensorData<T>(fNOutput));
0147 std::cout << std::endl;
0148 }
0149 }
0150
0151 std::string Generate(std::string opName) override {
0152
0153 std::stringstream out;
0154 out << "\n//------ Range " << opName << "---> " << ConvertDimShapeToString(fShape) << "\n";
0155 if (fIsOutputConstant) return out.str();
0156
0157 opName = "op_" + opName;
0158 if (fShape.empty()) {
0159 throw std::runtime_error("TMVA SOFIE Range operator called to Generate without being initialized first");
0160 }
0161
0162 std::string outputSizeVar;
0163 std::string outputSize = fShape[0].param;
0164 if (outputSize.find("range_size") != std::string::npos) {
0165 outputSizeVar = outputSize;
0166 outputSize = "static_cast<size_t>(std::max(std::ceil((static_cast<float>(*tensor_" + fNLimit +
0167 ") - static_cast<float>(*tensor_" + fNStart + ")) / static_cast<float>(*tensor_" + fNDelta + ")), 0.0f))";
0168 } else {
0169 outputSizeVar = "range_" + opName;
0170 }
0171 out << SP << "size_t " << outputSizeVar << " = " << outputSize << ";\n";
0172 out << SP << "for (size_t i = 0; i < " << outputSizeVar << "; i++) {\n";
0173 out << SP << SP << "tensor_" << fNOutput << "[i] = *tensor_" << fNStart << " + i * (*tensor_" << fNDelta << ");\n";
0174 out << SP << "}\n";
0175
0176 return out.str();
0177 }
0178 };
0179
0180 }
0181 }
0182 }
0183
0184 #endif