Back to home page

EIC code displayed by LXR

 
 

    


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        //input must be a graph input, or already initialized intermediate tensor
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; // type of input (0 intermediate, 1 constant , 2 shape)
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          // cannot know at compile time- need to do fully at run time
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          // compute output
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 { // case of a shape tensor
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 }//SOFIE
0181 }//Experimental
0182 }//TMVA
0183 
0184 #endif //TMVA_SOFIE_ROPERATOR_RANGE