Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /EICrecon/src/services/evaluator/EvaluatorSvc.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

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