Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-04-06 12:01:19

0001 // -*- C++ -*-
0002 //
0003 // Package:     CommonTools/Utils
0004 // Class  :     FormulaEvaluator
0005 //
0006 // Implementation:
0007 //     [Notes on implementation]
0008 //
0009 // Original Author:  Christopher Jones
0010 //         Created:  Thu, 24 Sep 2015 19:07:58 GMT
0011 //
0012 
0013 // system include files
0014 #include <cassert>
0015 #include <functional>
0016 #include <cstdlib>
0017 #include <cmath>
0018 #include "TMath.h"
0019 
0020 //#define DEBUG_AST
0021 #if defined(DEBUG_AST)
0022 #include <iostream>
0023 #endif
0024 // user include files
0025 #include "CommonTools/Utils/interface/FormulaEvaluator.h"
0026 #include "formulaEvaluatorBase.h"
0027 #include "formulaUnaryMinusEvaluator.h"
0028 #include "formulaBinaryOperatorEvaluator.h"
0029 #include "formulaConstantEvaluator.h"
0030 #include "formulaVariableEvaluator.h"
0031 #include "formulaParameterEvaluator.h"
0032 #include "formulaFunctionOneArgEvaluator.h"
0033 #include "formulaFunctionTwoArgsEvaluator.h"
0034 #include "FWCore/Utilities/interface/Exception.h"
0035 
0036 using namespace reco;
0037 
0038 namespace {
0039 
0040 #if defined(DEBUG_AST)
0041   void printAST(formula::EvaluatorBase* e) {
0042     std::cout << "printAST" << std::endl;
0043     for (auto const& n : e->abstractSyntaxTree()) {
0044       std::cout << n << std::endl;
0045     }
0046   }
0047 #define DEBUG_STATE(_v_) std::cout << _v_ << std::endl
0048 #else
0049   inline void printAST(void*) {}
0050 #define DEBUG_STATE(_v_)
0051 #endif
0052   //Formula Parser Code
0053   struct EvaluatorInfo {
0054     std::shared_ptr<reco::formula::EvaluatorBase> evaluator;
0055     std::shared_ptr<reco::formula::EvaluatorBase> top;
0056     int nextParseIndex = 0;
0057     unsigned int maxNumVariables = 0;
0058     unsigned int maxNumParameters = 0;
0059   };
0060 
0061   class ExpressionElementFinderBase {
0062   public:
0063     virtual bool checkStart(char) const = 0;
0064 
0065     virtual EvaluatorInfo createEvaluator(std::string::const_iterator, std::string::const_iterator) const = 0;
0066 
0067     virtual ~ExpressionElementFinderBase() = default;
0068   };
0069 
0070   std::string::const_iterator findMatchingParenthesis(std::string::const_iterator iBegin,
0071                                                       std::string::const_iterator iEnd) {
0072     if (iBegin == iEnd) {
0073       return iBegin;
0074     }
0075     if (*iBegin != '(') {
0076       return iBegin;
0077     }
0078     int level = 1;
0079     size_t index = 0;
0080     for (auto it = iBegin + 1; it != iEnd; ++it) {
0081       ++index;
0082       if (*it == '(') {
0083         ++level;
0084       } else if (*it == ')') {
0085         --level;
0086         if (level == 0) {
0087           break;
0088         }
0089       }
0090     }
0091     return iBegin + index;
0092   }
0093 
0094   class ConstantFinder : public ExpressionElementFinderBase {
0095     bool checkStart(char iSymbol) const final {
0096       if (iSymbol == '-' or iSymbol == '.' or std::isdigit(iSymbol)) {
0097         return true;
0098       }
0099       return false;
0100     }
0101 
0102     EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final {
0103       EvaluatorInfo info;
0104       try {
0105         size_t endIndex = 0;
0106         std::string s(iBegin, iEnd);
0107         double value = stod(s, &endIndex);
0108 
0109         info.nextParseIndex = endIndex;
0110         info.evaluator = std::make_shared<reco::formula::ConstantEvaluator>(value);
0111         info.top = info.evaluator;
0112       } catch (std::invalid_argument const&) {
0113       }
0114 
0115       return info;
0116     }
0117   };
0118 
0119   class ParameterFinder : public ExpressionElementFinderBase {
0120     bool checkStart(char iSymbol) const final {
0121       if (iSymbol == '[') {
0122         return true;
0123       }
0124       return false;
0125     }
0126 
0127     EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final {
0128       EvaluatorInfo info;
0129       if (iEnd == iBegin) {
0130         return info;
0131       }
0132       if (*iBegin != '[') {
0133         return info;
0134       }
0135       info.nextParseIndex = 1;
0136       try {
0137         size_t endIndex = 0;
0138         std::string s(iBegin + 1, iEnd);
0139         unsigned long value = stoul(s, &endIndex);
0140 
0141         if (iBegin + endIndex + 1 == iEnd or *(iBegin + 1 + endIndex) != ']') {
0142           return info;
0143         }
0144 
0145         info.nextParseIndex = endIndex + 2;
0146         info.maxNumParameters = value + 1;
0147         info.evaluator = std::make_shared<reco::formula::ParameterEvaluator>(value);
0148         info.top = info.evaluator;
0149       } catch (std::invalid_argument const&) {
0150       }
0151 
0152       return info;
0153     }
0154   };
0155 
0156   class VariableFinder : public ExpressionElementFinderBase {
0157     bool checkStart(char iSymbol) const final {
0158       if (iSymbol == 'x' or iSymbol == 'y' or iSymbol == 'z' or iSymbol == 't') {
0159         return true;
0160       }
0161       return false;
0162     }
0163 
0164     EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final {
0165       EvaluatorInfo info;
0166       if (iBegin == iEnd) {
0167         return info;
0168       }
0169       unsigned int index = 4;
0170       switch (*iBegin) {
0171         case 'x': {
0172           index = 0;
0173           break;
0174         }
0175         case 'y': {
0176           index = 1;
0177           break;
0178         }
0179         case 'z': {
0180           index = 2;
0181           break;
0182         }
0183         case 't': {
0184           index = 3;
0185           break;
0186         }
0187       }
0188       if (index == 4) {
0189         return info;
0190       }
0191       info.nextParseIndex = 1;
0192       info.maxNumVariables = index + 1;
0193       info.evaluator = std::make_shared<reco::formula::VariableEvaluator>(index);
0194       info.top = info.evaluator;
0195       return info;
0196     }
0197   };
0198 
0199   class ExpressionFinder;
0200 
0201   class FunctionFinder : public ExpressionElementFinderBase {
0202   public:
0203     FunctionFinder(ExpressionFinder const* iEF) : m_expressionFinder(iEF){};
0204 
0205     bool checkStart(char iSymbol) const final { return std::isalpha(iSymbol); }
0206 
0207     EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final;
0208 
0209   private:
0210     ExpressionFinder const* m_expressionFinder;
0211   };
0212 
0213   EvaluatorInfo createBinaryOperatorEvaluator(ExpressionFinder const&,
0214                                               std::string::const_iterator iBegin,
0215                                               std::string::const_iterator iEnd);
0216 
0217   class ExpressionFinder {
0218   public:
0219     ExpressionFinder() {
0220       m_elements.reserve(4);
0221       m_elements.emplace_back(new FunctionFinder{this});
0222       m_elements.emplace_back(new ConstantFinder{});
0223       m_elements.emplace_back(new ParameterFinder{});
0224       m_elements.emplace_back(new VariableFinder{});
0225     }
0226 
0227     bool checkStart(char iChar) const {
0228       if ('(' == iChar or '-' == iChar or '+' == iChar) {
0229         return true;
0230       }
0231       for (auto const& e : m_elements) {
0232         if (e->checkStart(iChar)) {
0233           return true;
0234         }
0235       }
0236       return false;
0237     }
0238 
0239     EvaluatorInfo createEvaluator(std::string::const_iterator iBegin,
0240                                   std::string::const_iterator iEnd,
0241                                   std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase> iPreviousBinary) const {
0242       EvaluatorInfo leftEvaluatorInfo;
0243 
0244       if (iBegin == iEnd) {
0245         return leftEvaluatorInfo;
0246       }
0247       //Start with '+'
0248       if (*iBegin == '+' and iEnd - iBegin > 1 and not std::isdigit(*(iBegin + 1))) {
0249         leftEvaluatorInfo = createEvaluator(iBegin + 1, iEnd, iPreviousBinary);
0250 
0251         //have to account for the '+' we skipped over
0252         leftEvaluatorInfo.nextParseIndex += 1;
0253         if (nullptr == leftEvaluatorInfo.evaluator.get()) {
0254           return leftEvaluatorInfo;
0255         }
0256       }
0257       //Start with '-'
0258       else if (*iBegin == '-' and iEnd - iBegin > 1 and not std::isdigit(*(iBegin + 1))) {
0259         leftEvaluatorInfo = createEvaluator(iBegin + 1, iEnd, iPreviousBinary);
0260 
0261         //have to account for the '+' we skipped over
0262         leftEvaluatorInfo.nextParseIndex += 1;
0263         if (nullptr == leftEvaluatorInfo.evaluator.get()) {
0264           return leftEvaluatorInfo;
0265         }
0266         leftEvaluatorInfo.evaluator =
0267             std::make_shared<reco::formula::UnaryMinusEvaluator>(std::move(leftEvaluatorInfo.top));
0268         leftEvaluatorInfo.top = leftEvaluatorInfo.evaluator;
0269       }
0270       //Start with '('
0271       else if (*iBegin == '(') {
0272         auto endParenthesis = findMatchingParenthesis(iBegin, iEnd);
0273         if (iBegin == endParenthesis) {
0274           return leftEvaluatorInfo;
0275         }
0276         leftEvaluatorInfo =
0277             createEvaluator(iBegin + 1, endParenthesis, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
0278         ++leftEvaluatorInfo.nextParseIndex;
0279         if (leftEvaluatorInfo.evaluator.get() == nullptr) {
0280           return leftEvaluatorInfo;
0281         }
0282         //need to account for closing parenthesis
0283         ++leftEvaluatorInfo.nextParseIndex;
0284         leftEvaluatorInfo.top->setPrecedenceToParenthesis();
0285         DEBUG_STATE("close parenthesis");
0286         printAST(leftEvaluatorInfo.top.get());
0287         leftEvaluatorInfo.evaluator = leftEvaluatorInfo.top;
0288       } else {
0289         //Does not start with a '('
0290         int maxParseDistance = 0;
0291         for (auto const& e : m_elements) {
0292           if (e->checkStart(*iBegin)) {
0293             leftEvaluatorInfo = e->createEvaluator(iBegin, iEnd);
0294             if (leftEvaluatorInfo.evaluator != nullptr) {
0295               break;
0296             }
0297             if (leftEvaluatorInfo.nextParseIndex > maxParseDistance) {
0298               maxParseDistance = leftEvaluatorInfo.nextParseIndex;
0299             }
0300           }
0301         }
0302         if (leftEvaluatorInfo.evaluator.get() == nullptr) {
0303           //failed to parse
0304           leftEvaluatorInfo.nextParseIndex = maxParseDistance;
0305           return leftEvaluatorInfo;
0306         }
0307       }
0308       //did we evaluate the full expression?
0309       if (leftEvaluatorInfo.nextParseIndex == iEnd - iBegin) {
0310         if (iPreviousBinary) {
0311           iPreviousBinary->setRightEvaluator(leftEvaluatorInfo.top);
0312           leftEvaluatorInfo.top = iPreviousBinary;
0313         }
0314         DEBUG_STATE("full expression");
0315         printAST(leftEvaluatorInfo.evaluator.get());
0316         return leftEvaluatorInfo;
0317       }
0318 
0319       //see if this is a binary expression
0320       auto fullExpression = createBinaryOperatorEvaluator(*this, iBegin + leftEvaluatorInfo.nextParseIndex, iEnd);
0321       fullExpression.nextParseIndex += leftEvaluatorInfo.nextParseIndex;
0322       fullExpression.maxNumVariables = std::max(leftEvaluatorInfo.maxNumVariables, fullExpression.maxNumVariables);
0323       fullExpression.maxNumParameters = std::max(leftEvaluatorInfo.maxNumParameters, fullExpression.maxNumParameters);
0324       if (iBegin + fullExpression.nextParseIndex != iEnd) {
0325         //did not parse the full expression
0326         fullExpression.evaluator.reset();
0327       }
0328 
0329       if (fullExpression.evaluator == nullptr) {
0330         //we had a parsing problem
0331         return fullExpression;
0332       }
0333 
0334       DEBUG_STATE("binary before precedence handling");
0335       printAST(fullExpression.evaluator.get());
0336       //Now to handle precedence
0337       auto topNode = fullExpression.top;
0338       auto binaryEval = dynamic_cast<reco::formula::BinaryOperatorEvaluatorBase*>(fullExpression.evaluator.get());
0339       if (iPreviousBinary) {
0340         if (iPreviousBinary->precedence() >= fullExpression.evaluator->precedence()) {
0341           DEBUG_STATE("prec >=");
0342           iPreviousBinary->setRightEvaluator(leftEvaluatorInfo.evaluator);
0343           binaryEval->setLeftEvaluator(iPreviousBinary);
0344         } else {
0345           binaryEval->setLeftEvaluator(leftEvaluatorInfo.evaluator);
0346           if (iPreviousBinary->precedence() < topNode->precedence()) {
0347             DEBUG_STATE(" switch topNode");
0348             topNode = iPreviousBinary;
0349             iPreviousBinary->setRightEvaluator(fullExpression.top);
0350           } else {
0351             DEBUG_STATE("swapping");
0352             //We need to take the lhs of a  binary expression directly or indirectly connected
0353             // to the present node and swap it with the rhs of the 'previous' binary expression
0354             // becuase we need the present expression to be evaluated earlier than the 'previous'.
0355             std::shared_ptr<reco::formula::EvaluatorBase> toSwap = iPreviousBinary;
0356             auto parentBinary = dynamic_cast<reco::formula::BinaryOperatorEvaluatorBase*>(topNode.get());
0357             do {
0358               if (parentBinary->lhs() == binaryEval or
0359                   parentBinary->lhs()->precedence() > iPreviousBinary->precedence()) {
0360                 parentBinary->swapLeftEvaluator(toSwap);
0361                 iPreviousBinary->setRightEvaluator(toSwap);
0362               } else {
0363                 //try the next one in the chain
0364                 parentBinary = const_cast<reco::formula::BinaryOperatorEvaluatorBase*>(
0365                     dynamic_cast<const reco::formula::BinaryOperatorEvaluatorBase*>(parentBinary->lhs()));
0366                 assert(parentBinary != nullptr);
0367               }
0368             } while (iPreviousBinary->rhs() == nullptr);
0369           }
0370         }
0371       } else {
0372         binaryEval->setLeftEvaluator(leftEvaluatorInfo.top);
0373       }
0374       DEBUG_STATE("finished binary");
0375       printAST(binaryEval);
0376       DEBUG_STATE("present top");
0377       printAST(topNode.get());
0378       fullExpression.top = topNode;
0379       return fullExpression;
0380     }
0381 
0382   private:
0383     std::vector<std::unique_ptr<ExpressionElementFinderBase>> m_elements;
0384   };
0385 
0386   template <typename Op>
0387   EvaluatorInfo createBinaryOperatorEvaluatorT(int iSymbolLength,
0388                                                reco::formula::EvaluatorBase::Precedence iPrec,
0389                                                ExpressionFinder const& iEF,
0390                                                std::string::const_iterator iBegin,
0391                                                std::string::const_iterator iEnd) {
0392     auto op = std::make_shared<reco::formula::BinaryOperatorEvaluator<Op>>(iPrec);
0393     EvaluatorInfo evalInfo = iEF.createEvaluator(iBegin + iSymbolLength, iEnd, op);
0394     evalInfo.nextParseIndex += iSymbolLength;
0395 
0396     if (evalInfo.evaluator.get() == nullptr) {
0397       return evalInfo;
0398     }
0399 
0400     evalInfo.evaluator = op;
0401     return evalInfo;
0402   }
0403 
0404   struct power {
0405     double operator()(double iLHS, double iRHS) const { return std::pow(iLHS, iRHS); }
0406   };
0407 
0408   EvaluatorInfo createBinaryOperatorEvaluator(ExpressionFinder const& iEF,
0409                                               std::string::const_iterator iBegin,
0410                                               std::string::const_iterator iEnd) {
0411     EvaluatorInfo evalInfo;
0412     if (iBegin == iEnd) {
0413       return evalInfo;
0414     }
0415 
0416     if (*iBegin == '+') {
0417       return createBinaryOperatorEvaluatorT<std::plus<double>>(
0418           1, reco::formula::EvaluatorBase::Precedence::kPlusMinus, iEF, iBegin, iEnd);
0419     }
0420 
0421     else if (*iBegin == '-') {
0422       return createBinaryOperatorEvaluatorT<std::minus<double>>(
0423           1, reco::formula::EvaluatorBase::Precedence::kPlusMinus, iEF, iBegin, iEnd);
0424     } else if (*iBegin == '*') {
0425       return createBinaryOperatorEvaluatorT<std::multiplies<double>>(
0426           1, reco::formula::EvaluatorBase::Precedence::kMultDiv, iEF, iBegin, iEnd);
0427     } else if (*iBegin == '/') {
0428       return createBinaryOperatorEvaluatorT<std::divides<double>>(
0429           1, reco::formula::EvaluatorBase::Precedence::kMultDiv, iEF, iBegin, iEnd);
0430     }
0431 
0432     else if (*iBegin == '^') {
0433       return createBinaryOperatorEvaluatorT<power>(
0434           1, reco::formula::EvaluatorBase::Precedence::kPower, iEF, iBegin, iEnd);
0435     } else if (*iBegin == '<' and iBegin + 1 != iEnd and *(iBegin + 1) == '=') {
0436       return createBinaryOperatorEvaluatorT<std::less_equal<double>>(
0437           2, reco::formula::EvaluatorBase::Precedence::kComparison, iEF, iBegin, iEnd);
0438 
0439     } else if (*iBegin == '>' and iBegin + 1 != iEnd and *(iBegin + 1) == '=') {
0440       return createBinaryOperatorEvaluatorT<std::greater_equal<double>>(
0441           2, reco::formula::EvaluatorBase::Precedence::kComparison, iEF, iBegin, iEnd);
0442 
0443     } else if (*iBegin == '<') {
0444       return createBinaryOperatorEvaluatorT<std::less<double>>(
0445           1, reco::formula::EvaluatorBase::Precedence::kComparison, iEF, iBegin, iEnd);
0446 
0447     } else if (*iBegin == '>') {
0448       return createBinaryOperatorEvaluatorT<std::greater<double>>(
0449           1, reco::formula::EvaluatorBase::Precedence::kComparison, iEF, iBegin, iEnd);
0450 
0451     } else if (*iBegin == '=' and iBegin + 1 != iEnd and *(iBegin + 1) == '=') {
0452       return createBinaryOperatorEvaluatorT<std::equal_to<double>>(
0453           2, reco::formula::EvaluatorBase::Precedence::kIdentity, iEF, iBegin, iEnd);
0454 
0455     } else if (*iBegin == '!' and iBegin + 1 != iEnd and *(iBegin + 1) == '=') {
0456       return createBinaryOperatorEvaluatorT<std::not_equal_to<double>>(
0457           2, reco::formula::EvaluatorBase::Precedence::kIdentity, iEF, iBegin, iEnd);
0458     }
0459     return evalInfo;
0460   }
0461 
0462   template <typename Op>
0463   EvaluatorInfo checkForSingleArgFunction(std::string::const_iterator iBegin,
0464                                           std::string::const_iterator iEnd,
0465                                           ExpressionFinder const* iExpressionFinder,
0466                                           const std::string& iName,
0467                                           Op op) {
0468     EvaluatorInfo info;
0469     if (iName.size() + 2 > static_cast<unsigned int>(iEnd - iBegin)) {
0470       return info;
0471     }
0472     auto pos = iName.find(&(*iBegin), 0, iName.size());
0473 
0474     if (std::string::npos == pos or *(iBegin + iName.size()) != '(') {
0475       return info;
0476     }
0477 
0478     info.nextParseIndex = iName.size() + 1;
0479 
0480     auto itEndParen = findMatchingParenthesis(iBegin + iName.size(), iEnd);
0481     if (iBegin + iName.size() == itEndParen) {
0482       return info;
0483     }
0484 
0485     auto argEvaluatorInfo = iExpressionFinder->createEvaluator(
0486         iBegin + iName.size() + 1, itEndParen, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
0487     info.nextParseIndex += argEvaluatorInfo.nextParseIndex;
0488     if (argEvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex + 1 != 1 + itEndParen - iBegin) {
0489       return info;
0490     }
0491     //account for closing parenthesis
0492     ++info.nextParseIndex;
0493 
0494     info.evaluator = std::make_shared<reco::formula::FunctionOneArgEvaluator>(std::move(argEvaluatorInfo.top), op);
0495     info.top = info.evaluator;
0496     return info;
0497   }
0498 
0499   std::string::const_iterator findCommaNotInParenthesis(std::string::const_iterator iBegin,
0500                                                         std::string::const_iterator iEnd) {
0501     int level = 0;
0502     std::string::const_iterator it = iBegin;
0503     for (; it != iEnd; ++it) {
0504       if (*it == '(') {
0505         ++level;
0506       } else if (*it == ')') {
0507         --level;
0508       } else if (*it == ',' and level == 0) {
0509         return it;
0510       }
0511     }
0512 
0513     return it;
0514   }
0515 
0516   template <typename Op>
0517   EvaluatorInfo checkForTwoArgsFunction(std::string::const_iterator iBegin,
0518                                         std::string::const_iterator iEnd,
0519                                         ExpressionFinder const* iExpressionFinder,
0520                                         const std::string& iName,
0521                                         Op op) {
0522     EvaluatorInfo info;
0523     if (iName.size() + 2 > static_cast<unsigned int>(iEnd - iBegin)) {
0524       return info;
0525     }
0526     auto pos = iName.find(&(*iBegin), 0, iName.size());
0527 
0528     if (std::string::npos == pos or *(iBegin + iName.size()) != '(') {
0529       return info;
0530     }
0531 
0532     info.nextParseIndex = iName.size() + 1;
0533 
0534     auto itEndParen = findMatchingParenthesis(iBegin + iName.size(), iEnd);
0535     if (iBegin + iName.size() == itEndParen) {
0536       return info;
0537     }
0538 
0539     auto itComma = findCommaNotInParenthesis(iBegin + iName.size() + 1, itEndParen);
0540 
0541     auto arg1EvaluatorInfo = iExpressionFinder->createEvaluator(
0542         iBegin + iName.size() + 1, itComma, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
0543     info.nextParseIndex += arg1EvaluatorInfo.nextParseIndex;
0544     if (arg1EvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex != itComma - iBegin) {
0545       return info;
0546     }
0547     //account for commas
0548     ++info.nextParseIndex;
0549 
0550     auto arg2EvaluatorInfo = iExpressionFinder->createEvaluator(
0551         itComma + 1, itEndParen, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
0552     info.nextParseIndex += arg2EvaluatorInfo.nextParseIndex;
0553 
0554     if (arg2EvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex + 1 != 1 + itEndParen - iBegin) {
0555       return info;
0556     }
0557     //account for closing parenthesis
0558     ++info.nextParseIndex;
0559 
0560     info.evaluator = std::make_shared<reco::formula::FunctionTwoArgsEvaluator>(
0561         std::move(arg1EvaluatorInfo.top), std::move(arg2EvaluatorInfo.top), op);
0562     info.top = info.evaluator;
0563     return info;
0564   }
0565 
0566   const std::string k_log("log");
0567   const std::string k_log10("log10");
0568   const std::string k_TMath__Log("TMath::Log");
0569   double const kLog10Inv = 1. / std::log(10.);
0570   const std::string k_exp("exp");
0571   const std::string k_pow("pow");
0572   const std::string k_TMath__Power("TMath::Power");
0573   const std::string k_max("max");
0574   const std::string k_min("min");
0575   const std::string k_TMath__Max("TMath::Max");
0576   const std::string k_TMath__Min("TMath::Min");
0577   const std::string k_TMath__Erf("TMath::Erf");
0578   const std::string k_erf("erf");
0579   const std::string k_TMath__Landau("TMath::Landau");
0580   const std::string k_sqrt("sqrt");
0581   const std::string k_TMath__Sqrt("TMath::Sqrt");
0582   const std::string k_abs("abs");
0583   const std::string k_TMath__Abs("TMath::Abs");
0584   const std::string k_cos("cos");
0585   const std::string k_TMath__Cos("TMath::Cos");
0586   const std::string k_sin("sin");
0587   const std::string k_TMath__Sin("TMath::Sin");
0588   const std::string k_tan("tan");
0589   const std::string k_TMath__Tan("TMath::Tan");
0590   const std::string k_acos("acos");
0591   const std::string k_TMath__ACos("TMath::ACos");
0592   const std::string k_asin("asin");
0593   const std::string k_TMath__ASin("TMath::ASin");
0594   const std::string k_atan("atan");
0595   const std::string k_TMath__ATan("TMath::ATan");
0596   const std::string k_atan2("atan2");
0597   const std::string k_TMath__ATan2("TMath::ATan2");
0598   const std::string k_cosh("cosh");
0599   const std::string k_TMath__CosH("TMath::CosH");
0600   const std::string k_sinh("sinh");
0601   const std::string k_TMath__SinH("TMath::SinH");
0602   const std::string k_tanh("tanh");
0603   const std::string k_TMath__TanH("TMath::TanH");
0604   const std::string k_acosh("acosh");
0605   const std::string k_TMath__ACosH("TMath::ACosH");
0606   const std::string k_asinh("asinh");
0607   const std::string k_TMath__ASinH("TMath::ASinH");
0608   const std::string k_atanh("atanh");
0609   const std::string k_TMath__ATanH("TMath::ATanH");
0610 
0611   EvaluatorInfo FunctionFinder::createEvaluator(std::string::const_iterator iBegin,
0612                                                 std::string::const_iterator iEnd) const {
0613     EvaluatorInfo info;
0614 
0615     info = checkForSingleArgFunction(
0616         iBegin, iEnd, m_expressionFinder, k_erf, [](double iArg) -> double { return std::erf(iArg); });
0617     if (info.evaluator.get() != nullptr) {
0618       return info;
0619     }
0620 
0621     info = checkForSingleArgFunction(
0622         iBegin, iEnd, m_expressionFinder, k_TMath__Erf, [](double iArg) -> double { return std::erf(iArg); });
0623     if (info.evaluator.get() != nullptr) {
0624       return info;
0625     }
0626 
0627     info = checkForSingleArgFunction(
0628         iBegin, iEnd, m_expressionFinder, k_TMath__Landau, [](double iArg) -> double { return TMath::Landau(iArg); });
0629     if (info.evaluator.get() != nullptr) {
0630       return info;
0631     }
0632 
0633     info = checkForSingleArgFunction(
0634         iBegin, iEnd, m_expressionFinder, k_log, [](double iArg) -> double { return std::log(iArg); });
0635     if (info.evaluator.get() != nullptr) {
0636       return info;
0637     }
0638 
0639     info = checkForSingleArgFunction(
0640         iBegin, iEnd, m_expressionFinder, k_TMath__Log, [](double iArg) -> double { return std::log(iArg); });
0641     if (info.evaluator.get() != nullptr) {
0642       return info;
0643     }
0644 
0645     info = checkForSingleArgFunction(
0646         iBegin, iEnd, m_expressionFinder, k_log10, [](double iArg) -> double { return std::log(iArg) * kLog10Inv; });
0647     if (info.evaluator.get() != nullptr) {
0648       return info;
0649     }
0650 
0651     info = checkForSingleArgFunction(
0652         iBegin, iEnd, m_expressionFinder, k_exp, [](double iArg) -> double { return std::exp(iArg); });
0653     if (info.evaluator.get() != nullptr) {
0654       return info;
0655     }
0656 
0657     info = checkForSingleArgFunction(
0658         iBegin, iEnd, m_expressionFinder, k_sqrt, [](double iArg) -> double { return std::sqrt(iArg); });
0659     if (info.evaluator.get() != nullptr) {
0660       return info;
0661     }
0662 
0663     info = checkForSingleArgFunction(
0664         iBegin, iEnd, m_expressionFinder, k_TMath__Sqrt, [](double iArg) -> double { return std::sqrt(iArg); });
0665     if (info.evaluator.get() != nullptr) {
0666       return info;
0667     }
0668 
0669     info = checkForSingleArgFunction(
0670         iBegin, iEnd, m_expressionFinder, k_abs, [](double iArg) -> double { return std::abs(iArg); });
0671     if (info.evaluator.get() != nullptr) {
0672       return info;
0673     }
0674 
0675     info = checkForSingleArgFunction(
0676         iBegin, iEnd, m_expressionFinder, k_TMath__Abs, [](double iArg) -> double { return std::abs(iArg); });
0677     if (info.evaluator.get() != nullptr) {
0678       return info;
0679     }
0680 
0681     info = checkForSingleArgFunction(
0682         iBegin, iEnd, m_expressionFinder, k_cos, [](double iArg) -> double { return std::cos(iArg); });
0683     if (info.evaluator.get() != nullptr) {
0684       return info;
0685     }
0686 
0687     info = checkForSingleArgFunction(
0688         iBegin, iEnd, m_expressionFinder, k_TMath__Cos, [](double iArg) -> double { return std::cos(iArg); });
0689     if (info.evaluator.get() != nullptr) {
0690       return info;
0691     }
0692 
0693     info = checkForSingleArgFunction(
0694         iBegin, iEnd, m_expressionFinder, k_sin, [](double iArg) -> double { return std::sin(iArg); });
0695     if (info.evaluator.get() != nullptr) {
0696       return info;
0697     }
0698 
0699     info = checkForSingleArgFunction(
0700         iBegin, iEnd, m_expressionFinder, k_TMath__Sin, [](double iArg) -> double { return std::sin(iArg); });
0701     if (info.evaluator.get() != nullptr) {
0702       return info;
0703     }
0704 
0705     info = checkForSingleArgFunction(
0706         iBegin, iEnd, m_expressionFinder, k_tan, [](double iArg) -> double { return std::tan(iArg); });
0707     if (info.evaluator.get() != nullptr) {
0708       return info;
0709     }
0710 
0711     info = checkForSingleArgFunction(
0712         iBegin, iEnd, m_expressionFinder, k_TMath__Tan, [](double iArg) -> double { return std::tan(iArg); });
0713     if (info.evaluator.get() != nullptr) {
0714       return info;
0715     }
0716 
0717     info = checkForSingleArgFunction(
0718         iBegin, iEnd, m_expressionFinder, k_acos, [](double iArg) -> double { return std::acos(iArg); });
0719     if (info.evaluator.get() != nullptr) {
0720       return info;
0721     }
0722 
0723     info = checkForSingleArgFunction(
0724         iBegin, iEnd, m_expressionFinder, k_TMath__ACos, [](double iArg) -> double { return std::acos(iArg); });
0725     if (info.evaluator.get() != nullptr) {
0726       return info;
0727     }
0728 
0729     info = checkForSingleArgFunction(
0730         iBegin, iEnd, m_expressionFinder, k_asin, [](double iArg) -> double { return std::asin(iArg); });
0731     if (info.evaluator.get() != nullptr) {
0732       return info;
0733     }
0734 
0735     info = checkForSingleArgFunction(
0736         iBegin, iEnd, m_expressionFinder, k_TMath__ASin, [](double iArg) -> double { return std::asin(iArg); });
0737     if (info.evaluator.get() != nullptr) {
0738       return info;
0739     }
0740 
0741     info = checkForSingleArgFunction(
0742         iBegin, iEnd, m_expressionFinder, k_atan, [](double iArg) -> double { return std::atan(iArg); });
0743     if (info.evaluator.get() != nullptr) {
0744       return info;
0745     }
0746 
0747     info = checkForSingleArgFunction(
0748         iBegin, iEnd, m_expressionFinder, k_TMath__ATan, [](double iArg) -> double { return std::atan(iArg); });
0749     if (info.evaluator.get() != nullptr) {
0750       return info;
0751     }
0752 
0753     info = checkForSingleArgFunction(
0754         iBegin, iEnd, m_expressionFinder, k_cosh, [](double iArg) -> double { return std::cosh(iArg); });
0755     if (info.evaluator.get() != nullptr) {
0756       return info;
0757     }
0758 
0759     info = checkForSingleArgFunction(
0760         iBegin, iEnd, m_expressionFinder, k_TMath__CosH, [](double iArg) -> double { return std::cosh(iArg); });
0761     if (info.evaluator.get() != nullptr) {
0762       return info;
0763     }
0764 
0765     info = checkForSingleArgFunction(
0766         iBegin, iEnd, m_expressionFinder, k_sinh, [](double iArg) -> double { return std::sinh(iArg); });
0767     if (info.evaluator.get() != nullptr) {
0768       return info;
0769     }
0770 
0771     info = checkForSingleArgFunction(
0772         iBegin, iEnd, m_expressionFinder, k_TMath__SinH, [](double iArg) -> double { return std::sinh(iArg); });
0773     if (info.evaluator.get() != nullptr) {
0774       return info;
0775     }
0776 
0777     info = checkForSingleArgFunction(
0778         iBegin, iEnd, m_expressionFinder, k_tanh, [](double iArg) -> double { return std::tanh(iArg); });
0779     if (info.evaluator.get() != nullptr) {
0780       return info;
0781     }
0782 
0783     info = checkForSingleArgFunction(
0784         iBegin, iEnd, m_expressionFinder, k_TMath__TanH, [](double iArg) -> double { return std::tanh(iArg); });
0785     if (info.evaluator.get() != nullptr) {
0786       return info;
0787     }
0788 
0789     info = checkForSingleArgFunction(
0790         iBegin, iEnd, m_expressionFinder, k_acosh, [](double iArg) -> double { return std::acosh(iArg); });
0791     if (info.evaluator.get() != nullptr) {
0792       return info;
0793     }
0794 
0795     info = checkForSingleArgFunction(
0796         iBegin, iEnd, m_expressionFinder, k_TMath__ACosH, [](double iArg) -> double { return std::acosh(iArg); });
0797     if (info.evaluator.get() != nullptr) {
0798       return info;
0799     }
0800 
0801     info = checkForSingleArgFunction(
0802         iBegin, iEnd, m_expressionFinder, k_asinh, [](double iArg) -> double { return std::asinh(iArg); });
0803     if (info.evaluator.get() != nullptr) {
0804       return info;
0805     }
0806 
0807     info = checkForSingleArgFunction(
0808         iBegin, iEnd, m_expressionFinder, k_TMath__ASinH, [](double iArg) -> double { return std::asinh(iArg); });
0809     if (info.evaluator.get() != nullptr) {
0810       return info;
0811     }
0812 
0813     info = checkForSingleArgFunction(
0814         iBegin, iEnd, m_expressionFinder, k_atanh, [](double iArg) -> double { return std::atanh(iArg); });
0815     if (info.evaluator.get() != nullptr) {
0816       return info;
0817     }
0818 
0819     info = checkForSingleArgFunction(
0820         iBegin, iEnd, m_expressionFinder, k_TMath__ATanH, [](double iArg) -> double { return std::atanh(iArg); });
0821     if (info.evaluator.get() != nullptr) {
0822       return info;
0823     }
0824 
0825     info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder, k_atan2, [](double iArg1, double iArg2) -> double {
0826       return std::atan2(iArg1, iArg2);
0827     });
0828     if (info.evaluator.get() != nullptr) {
0829       return info;
0830     }
0831 
0832     info = checkForTwoArgsFunction(
0833         iBegin, iEnd, m_expressionFinder, k_TMath__ATan2, [](double iArg1, double iArg2) -> double {
0834           return std::atan2(iArg1, iArg2);
0835         });
0836     if (info.evaluator.get() != nullptr) {
0837       return info;
0838     }
0839 
0840     info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder, k_pow, [](double iArg1, double iArg2) -> double {
0841       return std::pow(iArg1, iArg2);
0842     });
0843     if (info.evaluator.get() != nullptr) {
0844       return info;
0845     }
0846 
0847     info = checkForTwoArgsFunction(
0848         iBegin, iEnd, m_expressionFinder, k_TMath__Power, [](double iArg1, double iArg2) -> double {
0849           return std::pow(iArg1, iArg2);
0850         });
0851     if (info.evaluator.get() != nullptr) {
0852       return info;
0853     }
0854 
0855     info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder, k_max, [](double iArg1, double iArg2) -> double {
0856       return std::max(iArg1, iArg2);
0857     });
0858     if (info.evaluator.get() != nullptr) {
0859       return info;
0860     }
0861 
0862     info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder, k_min, [](double iArg1, double iArg2) -> double {
0863       return std::min(iArg1, iArg2);
0864     });
0865     if (info.evaluator.get() != nullptr) {
0866       return info;
0867     }
0868 
0869     info = checkForTwoArgsFunction(
0870         iBegin, iEnd, m_expressionFinder, k_TMath__Max, [](double iArg1, double iArg2) -> double {
0871           return std::max(iArg1, iArg2);
0872         });
0873     if (info.evaluator.get() != nullptr) {
0874       return info;
0875     }
0876 
0877     info = checkForTwoArgsFunction(
0878         iBegin, iEnd, m_expressionFinder, k_TMath__Min, [](double iArg1, double iArg2) -> double {
0879           return std::min(iArg1, iArg2);
0880         });
0881     if (info.evaluator.get() != nullptr) {
0882       return info;
0883     }
0884 
0885     return info;
0886   };
0887 
0888   ExpressionFinder const s_expressionFinder;
0889 
0890 }  // namespace
0891 //
0892 // constants, enums and typedefs
0893 //
0894 
0895 //
0896 // static data member definitions
0897 //
0898 
0899 //
0900 // constructors and destructor
0901 //
0902 FormulaEvaluator::FormulaEvaluator(std::string const& iFormula) {
0903   //remove white space
0904   std::string formula;
0905   formula.reserve(iFormula.size());
0906   std::copy_if(iFormula.begin(), iFormula.end(), std::back_inserter(formula), [](const char iC) { return iC != ' '; });
0907 
0908   auto info = s_expressionFinder.createEvaluator(
0909       formula.begin(), formula.end(), std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
0910 
0911   if (info.nextParseIndex != static_cast<int>(formula.size()) or info.top.get() == nullptr) {
0912     auto lastIndex = info.nextParseIndex;
0913     if (formula.size() != iFormula.size()) {
0914       lastIndex = 0;
0915       for (decltype(info.nextParseIndex) index = 0; index < info.nextParseIndex; ++index, ++lastIndex) {
0916         while (iFormula[lastIndex] != formula[index]) {
0917           assert(iFormula[lastIndex] == ' ');
0918           ++lastIndex;
0919         }
0920       }
0921     }
0922     throw cms::Exception("FormulaEvaluatorParseError")
0923         << "While parsing '" << iFormula << "' could not parse beyond '"
0924         << std::string(iFormula.begin(), iFormula.begin() + lastIndex) << "'";
0925   }
0926 
0927   DEBUG_STATE("DONE parsing");
0928   printAST(info.top.get());
0929 
0930   m_evaluator = std::move(info.top);
0931   m_nVariables = info.maxNumVariables;
0932   m_nParameters = info.maxNumParameters;
0933 }
0934 
0935 //
0936 // const member functions
0937 //
0938 double FormulaEvaluator::evaluate(double const* iVariables, double const* iParameters) const {
0939   return m_evaluator->evaluate(iVariables, iParameters);
0940 }
0941 
0942 void FormulaEvaluator::throwWrongNumberOfVariables(size_t iSize) const {
0943   throw cms::Exception("WrongNumVariables")
0944       << "FormulaEvaluator expected at least " << m_nVariables << " but was passed only " << iSize;
0945 }
0946 void FormulaEvaluator::throwWrongNumberOfParameters(size_t iSize) const {
0947   throw cms::Exception("WrongNumParameters")
0948       << "FormulaEvaluator expected at least " << m_nParameters << " but was passed only " << iSize;
0949 }
0950 
0951 std::vector<std::string> FormulaEvaluator::abstractSyntaxTree() const { return m_evaluator->abstractSyntaxTree(); }