Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-09 07:53:31

0001 // SPDX-License-Identifier: LGPL-3.0-or-later
0002 // Copyright (C) 2024 Dmitry Kalinkin
0003 
0004 #include <algorithms/logger.h>
0005 #include <exception>
0006 #include <functional>
0007 #include <mutex>
0008 #include <stdexcept>
0009 #include <string>
0010 #include <unordered_map>
0011 #include <utility>
0012 #include <vector>
0013 
0014 namespace eicrecon {
0015 
0016 /**
0017  * @brief Provides an interface to a compiler that converts string expressions
0018  * to native `std::function`.
0019  *
0020  * The underlying implementation relies on ROOT's TInterpreter, but this may
0021  * change in the future. User can inspect the full C++ code by setting
0022  * `-PEvaluatorSvc:LogLevel=debug`, the list of provided variables is apparent
0023  * from the same output.
0024  *
0025  * Currently, return type is fixed to `double`, and all input parameters have
0026  * to be convertible to double.
0027  */
0028 class EvaluatorSvc : public algorithms::LoggedService<EvaluatorSvc> {
0029 public:
0030   void init();
0031 
0032   /**
0033    * @brief Compile expression `expr` to std::function
0034    * @param expr String expression to compile (e.g. `"0.998"`, `"a + b"`)
0035    * @param Args Types of arguments for the resulting function
0036    * @param transform Function providing mapping from Args
0037    *
0038    * The `Args` must be default-constructible types, since transform need to be
0039    * called at compilation time to determine the list of available parameters.
0040    */
0041   template <class... Args>
0042   std::function<double(Args...)>
0043   compile(const std::string& expr,
0044           std::function<std::unordered_map<std::string, double>(Args...)> transform) {
0045     try {
0046       // trivial function if string is representation of float
0047       std::size_t pos;
0048       float expr_value = std::stof(expr, &pos);
0049       if (pos < expr.size()) {
0050         throw std::invalid_argument("unparsed trailing characters");
0051       }
0052       return [expr_value](Args... /* args */) { return expr_value; };
0053     } catch (std::exception& e) {
0054       // more complicated function otherwise
0055       std::vector<std::string> params;
0056       // Call transform with default values to detect parameter names
0057       for (auto& p : transform(Args{}...)) {
0058         params.push_back(p.first);
0059       }
0060       auto compiled_expr = _compile(expr, params);
0061       return [compiled_expr, transform](Args... args) {
0062         return compiled_expr(transform(std::forward<Args>(args)...));
0063       };
0064     }
0065   };
0066 
0067   /**
0068    * @brief Compile expression `expr` to std::function
0069    * @param expr String expression to compile (e.g. `"a + b"`)
0070    * @param params List of parameter names used in the expression (e.g. `{"a", "b"}`)
0071    *
0072    * The resulting function accepts a dictionary (`std::unordered_map`) of
0073    * parameter values.
0074    */
0075   std::function<double(const std::unordered_map<std::string, double>&)>
0076   _compile(const std::string& expr, std::vector<std::string> params);
0077 
0078 private:
0079   unsigned int m_function_id = 0;
0080   std::mutex m_interpreter_mutex;
0081 
0082   ALGORITHMS_DEFINE_LOGGED_SERVICE(EvaluatorSvc);
0083 };
0084 
0085 } // namespace eicrecon