CMS 3D CMS Logo

FormulaEvaluator.cc
Go to the documentation of this file.
1 // -*- C++ -*-
2 //
3 // Package: CommonTools/Utils
4 // Class : FormulaEvaluator
5 //
6 // Implementation:
7 // [Notes on implementation]
8 //
9 // Original Author: Christopher Jones
10 // Created: Thu, 24 Sep 2015 19:07:58 GMT
11 //
12 
13 // system include files
14 #include <cassert>
15 #include <functional>
16 #include <cstdlib>
17 #include <cmath>
18 #include "TMath.h"
19 
20 //#define DEBUG_AST
21 #if defined(DEBUG_AST)
22 #include <iostream>
23 #endif
24 // user include files
26 #include "formulaEvaluatorBase.h"
35 
36 using namespace reco;
37 
38 namespace {
39 
40 #if defined(DEBUG_AST)
41  void printAST(formula::EvaluatorBase* e) {
42  std::cout << "printAST" << std::endl;
43  for (auto const& n : e->abstractSyntaxTree()) {
44  std::cout << n << std::endl;
45  }
46  }
47 #define DEBUG_STATE(_v_) std::cout << _v_ << std::endl
48 #else
49  inline void printAST(void*) {}
50 #define DEBUG_STATE(_v_)
51 #endif
52  //Formula Parser Code
53  struct EvaluatorInfo {
54  std::shared_ptr<reco::formula::EvaluatorBase> evaluator;
55  std::shared_ptr<reco::formula::EvaluatorBase> top;
56  int nextParseIndex = 0;
57  unsigned int maxNumVariables = 0;
58  unsigned int maxNumParameters = 0;
59  };
60 
61  class ExpressionElementFinderBase {
62  public:
63  virtual bool checkStart(char) const = 0;
64 
65  virtual EvaluatorInfo createEvaluator(std::string::const_iterator, std::string::const_iterator) const = 0;
66 
67  virtual ~ExpressionElementFinderBase() = default;
68  };
69 
70  std::string::const_iterator findMatchingParenthesis(std::string::const_iterator iBegin,
71  std::string::const_iterator iEnd) {
72  if (iBegin == iEnd) {
73  return iBegin;
74  }
75  if (*iBegin != '(') {
76  return iBegin;
77  }
78  int level = 1;
79  size_t index = 0;
80  for (auto it = iBegin + 1; it != iEnd; ++it) {
81  ++index;
82  if (*it == '(') {
83  ++level;
84  } else if (*it == ')') {
85  --level;
86  if (level == 0) {
87  break;
88  }
89  }
90  }
91  return iBegin + index;
92  }
93 
94  class ConstantFinder : public ExpressionElementFinderBase {
95  bool checkStart(char iSymbol) const final {
96  if (iSymbol == '-' or iSymbol == '.' or std::isdigit(iSymbol)) {
97  return true;
98  }
99  return false;
100  }
101 
102  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final {
103  EvaluatorInfo info;
104  try {
105  size_t endIndex = 0;
106  std::string s(iBegin, iEnd);
107  double value = stod(s, &endIndex);
108 
109  info.nextParseIndex = endIndex;
110  info.evaluator = std::make_shared<reco::formula::ConstantEvaluator>(value);
111  info.top = info.evaluator;
112  } catch (std::invalid_argument const&) {
113  }
114 
115  return info;
116  }
117  };
118 
119  class ParameterFinder : public ExpressionElementFinderBase {
120  bool checkStart(char iSymbol) const final {
121  if (iSymbol == '[') {
122  return true;
123  }
124  return false;
125  }
126 
127  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final {
128  EvaluatorInfo info;
129  if (iEnd == iBegin) {
130  return info;
131  }
132  if (*iBegin != '[') {
133  return info;
134  }
135  info.nextParseIndex = 1;
136  try {
137  size_t endIndex = 0;
138  std::string s(iBegin + 1, iEnd);
139  unsigned long value = stoul(s, &endIndex);
140 
141  if (iBegin + endIndex + 1 == iEnd or *(iBegin + 1 + endIndex) != ']') {
142  return info;
143  }
144 
145  info.nextParseIndex = endIndex + 2;
146  info.maxNumParameters = value + 1;
147  info.evaluator = std::make_shared<reco::formula::ParameterEvaluator>(value);
148  info.top = info.evaluator;
149  } catch (std::invalid_argument const&) {
150  }
151 
152  return info;
153  }
154  };
155 
156  class VariableFinder : public ExpressionElementFinderBase {
157  bool checkStart(char iSymbol) const final {
158  if (iSymbol == 'x' or iSymbol == 'y' or iSymbol == 'z' or iSymbol == 't') {
159  return true;
160  }
161  return false;
162  }
163 
164  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final {
165  EvaluatorInfo info;
166  if (iBegin == iEnd) {
167  return info;
168  }
169  unsigned int index = 4;
170  switch (*iBegin) {
171  case 'x': {
172  index = 0;
173  break;
174  }
175  case 'y': {
176  index = 1;
177  break;
178  }
179  case 'z': {
180  index = 2;
181  break;
182  }
183  case 't': {
184  index = 3;
185  break;
186  }
187  }
188  if (index == 4) {
189  return info;
190  }
191  info.nextParseIndex = 1;
192  info.maxNumVariables = index + 1;
193  info.evaluator = std::make_shared<reco::formula::VariableEvaluator>(index);
194  info.top = info.evaluator;
195  return info;
196  }
197  };
198 
199  class ExpressionFinder;
200 
201  class FunctionFinder : public ExpressionElementFinderBase {
202  public:
203  FunctionFinder(ExpressionFinder const* iEF) : m_expressionFinder(iEF){};
204 
205  bool checkStart(char iSymbol) const final { return std::isalpha(iSymbol); }
206 
207  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final;
208 
209  private:
210  ExpressionFinder const* m_expressionFinder;
211  };
212 
213  EvaluatorInfo createBinaryOperatorEvaluator(ExpressionFinder const&,
214  std::string::const_iterator iBegin,
215  std::string::const_iterator iEnd);
216 
217  class ExpressionFinder {
218  public:
219  ExpressionFinder() {
220  m_elements.reserve(4);
221  m_elements.emplace_back(new FunctionFinder{this});
222  m_elements.emplace_back(new ConstantFinder{});
223  m_elements.emplace_back(new ParameterFinder{});
224  m_elements.emplace_back(new VariableFinder{});
225  }
226 
227  bool checkStart(char iChar) const {
228  if ('(' == iChar or '-' == iChar or '+' == iChar) {
229  return true;
230  }
231  for (auto const& e : m_elements) {
232  if (e->checkStart(iChar)) {
233  return true;
234  }
235  }
236  return false;
237  }
238 
239  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin,
240  std::string::const_iterator iEnd,
241  std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase> iPreviousBinary) const {
242  EvaluatorInfo leftEvaluatorInfo;
243 
244  if (iBegin == iEnd) {
245  return leftEvaluatorInfo;
246  }
247  //Start with '+'
248  if (*iBegin == '+' and iEnd - iBegin > 1 and not std::isdigit(*(iBegin + 1))) {
249  leftEvaluatorInfo = createEvaluator(iBegin + 1, iEnd, iPreviousBinary);
250 
251  //have to account for the '+' we skipped over
252  leftEvaluatorInfo.nextParseIndex += 1;
253  if (nullptr == leftEvaluatorInfo.evaluator.get()) {
254  return leftEvaluatorInfo;
255  }
256  }
257  //Start with '-'
258  else if (*iBegin == '-' and iEnd - iBegin > 1 and not std::isdigit(*(iBegin + 1))) {
259  leftEvaluatorInfo = createEvaluator(iBegin + 1, iEnd, iPreviousBinary);
260 
261  //have to account for the '+' we skipped over
262  leftEvaluatorInfo.nextParseIndex += 1;
263  if (nullptr == leftEvaluatorInfo.evaluator.get()) {
264  return leftEvaluatorInfo;
265  }
266  leftEvaluatorInfo.evaluator =
267  std::make_shared<reco::formula::UnaryMinusEvaluator>(std::move(leftEvaluatorInfo.top));
268  leftEvaluatorInfo.top = leftEvaluatorInfo.evaluator;
269  }
270  //Start with '('
271  else if (*iBegin == '(') {
272  auto endParenthesis = findMatchingParenthesis(iBegin, iEnd);
273  if (iBegin == endParenthesis) {
274  return leftEvaluatorInfo;
275  }
276  leftEvaluatorInfo =
277  createEvaluator(iBegin + 1, endParenthesis, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
278  ++leftEvaluatorInfo.nextParseIndex;
279  if (leftEvaluatorInfo.evaluator.get() == nullptr) {
280  return leftEvaluatorInfo;
281  }
282  //need to account for closing parenthesis
283  ++leftEvaluatorInfo.nextParseIndex;
284  leftEvaluatorInfo.top->setPrecedenceToParenthesis();
285  DEBUG_STATE("close parenthesis");
286  printAST(leftEvaluatorInfo.top.get());
287  leftEvaluatorInfo.evaluator = leftEvaluatorInfo.top;
288  } else {
289  //Does not start with a '('
290  int maxParseDistance = 0;
291  for (auto const& e : m_elements) {
292  if (e->checkStart(*iBegin)) {
293  leftEvaluatorInfo = e->createEvaluator(iBegin, iEnd);
294  if (leftEvaluatorInfo.evaluator != nullptr) {
295  break;
296  }
297  if (leftEvaluatorInfo.nextParseIndex > maxParseDistance) {
298  maxParseDistance = leftEvaluatorInfo.nextParseIndex;
299  }
300  }
301  }
302  if (leftEvaluatorInfo.evaluator.get() == nullptr) {
303  //failed to parse
304  leftEvaluatorInfo.nextParseIndex = maxParseDistance;
305  return leftEvaluatorInfo;
306  }
307  }
308  //did we evaluate the full expression?
309  if (leftEvaluatorInfo.nextParseIndex == iEnd - iBegin) {
310  if (iPreviousBinary) {
311  iPreviousBinary->setRightEvaluator(leftEvaluatorInfo.top);
312  leftEvaluatorInfo.top = iPreviousBinary;
313  }
314  DEBUG_STATE("full expression");
315  printAST(leftEvaluatorInfo.evaluator.get());
316  return leftEvaluatorInfo;
317  }
318 
319  //see if this is a binary expression
320  auto fullExpression = createBinaryOperatorEvaluator(*this, iBegin + leftEvaluatorInfo.nextParseIndex, iEnd);
321  fullExpression.nextParseIndex += leftEvaluatorInfo.nextParseIndex;
322  fullExpression.maxNumVariables = std::max(leftEvaluatorInfo.maxNumVariables, fullExpression.maxNumVariables);
323  fullExpression.maxNumParameters = std::max(leftEvaluatorInfo.maxNumParameters, fullExpression.maxNumParameters);
324  if (iBegin + fullExpression.nextParseIndex != iEnd) {
325  //did not parse the full expression
326  fullExpression.evaluator.reset();
327  }
328 
329  if (fullExpression.evaluator == nullptr) {
330  //we had a parsing problem
331  return fullExpression;
332  }
333 
334  DEBUG_STATE("binary before precedence handling");
335  printAST(fullExpression.evaluator.get());
336  //Now to handle precedence
337  auto topNode = fullExpression.top;
338  auto binaryEval = dynamic_cast<reco::formula::BinaryOperatorEvaluatorBase*>(fullExpression.evaluator.get());
339  if (iPreviousBinary) {
340  if (iPreviousBinary->precedence() >= fullExpression.evaluator->precedence()) {
341  DEBUG_STATE("prec >=");
342  iPreviousBinary->setRightEvaluator(leftEvaluatorInfo.evaluator);
343  binaryEval->setLeftEvaluator(iPreviousBinary);
344  } else {
345  binaryEval->setLeftEvaluator(leftEvaluatorInfo.evaluator);
346  if (iPreviousBinary->precedence() < topNode->precedence()) {
347  DEBUG_STATE(" switch topNode");
348  topNode = iPreviousBinary;
349  iPreviousBinary->setRightEvaluator(fullExpression.top);
350  } else {
351  DEBUG_STATE("swapping");
352  //We need to take the lhs of a binary expression directly or indirectly connected
353  // to the present node and swap it with the rhs of the 'previous' binary expression
354  // becuase we need the present expression to be evaluated earlier than the 'previous'.
355  std::shared_ptr<reco::formula::EvaluatorBase> toSwap = iPreviousBinary;
356  auto parentBinary = dynamic_cast<reco::formula::BinaryOperatorEvaluatorBase*>(topNode.get());
357  do {
358  if (parentBinary->lhs() == binaryEval or
359  parentBinary->lhs()->precedence() > iPreviousBinary->precedence()) {
360  parentBinary->swapLeftEvaluator(toSwap);
361  iPreviousBinary->setRightEvaluator(toSwap);
362  } else {
363  //try the next one in the chain
364  parentBinary = const_cast<reco::formula::BinaryOperatorEvaluatorBase*>(
365  dynamic_cast<const reco::formula::BinaryOperatorEvaluatorBase*>(parentBinary->lhs()));
366  assert(parentBinary != nullptr);
367  }
368  } while (iPreviousBinary->rhs() == nullptr);
369  }
370  }
371  } else {
372  binaryEval->setLeftEvaluator(leftEvaluatorInfo.top);
373  }
374  DEBUG_STATE("finished binary");
375  printAST(binaryEval);
376  DEBUG_STATE("present top");
377  printAST(topNode.get());
378  fullExpression.top = topNode;
379  return fullExpression;
380  }
381 
382  private:
383  std::vector<std::unique_ptr<ExpressionElementFinderBase>> m_elements;
384  };
385 
386  template <typename Op>
387  EvaluatorInfo createBinaryOperatorEvaluatorT(int iSymbolLength,
389  ExpressionFinder const& iEF,
390  std::string::const_iterator iBegin,
391  std::string::const_iterator iEnd) {
392  auto op = std::make_shared<reco::formula::BinaryOperatorEvaluator<Op>>(iPrec);
393  EvaluatorInfo evalInfo = iEF.createEvaluator(iBegin + iSymbolLength, iEnd, op);
394  evalInfo.nextParseIndex += iSymbolLength;
395 
396  if (evalInfo.evaluator.get() == nullptr) {
397  return evalInfo;
398  }
399 
400  evalInfo.evaluator = op;
401  return evalInfo;
402  }
403 
404  struct power {
405  double operator()(double iLHS, double iRHS) const { return std::pow(iLHS, iRHS); }
406  };
407 
408  EvaluatorInfo createBinaryOperatorEvaluator(ExpressionFinder const& iEF,
409  std::string::const_iterator iBegin,
410  std::string::const_iterator iEnd) {
411  EvaluatorInfo evalInfo;
412  if (iBegin == iEnd) {
413  return evalInfo;
414  }
415 
416  if (*iBegin == '+') {
417  return createBinaryOperatorEvaluatorT<std::plus<double>>(
419  }
420 
421  else if (*iBegin == '-') {
422  return createBinaryOperatorEvaluatorT<std::minus<double>>(
424  } else if (*iBegin == '*') {
425  return createBinaryOperatorEvaluatorT<std::multiplies<double>>(
427  } else if (*iBegin == '/') {
428  return createBinaryOperatorEvaluatorT<std::divides<double>>(
430  }
431 
432  else if (*iBegin == '^') {
433  return createBinaryOperatorEvaluatorT<power>(
435  } else if (*iBegin == '<' and iBegin + 1 != iEnd and *(iBegin + 1) == '=') {
436  return createBinaryOperatorEvaluatorT<std::less_equal<double>>(
438 
439  } else if (*iBegin == '>' and iBegin + 1 != iEnd and *(iBegin + 1) == '=') {
440  return createBinaryOperatorEvaluatorT<std::greater_equal<double>>(
442 
443  } else if (*iBegin == '<') {
444  return createBinaryOperatorEvaluatorT<std::less<double>>(
446 
447  } else if (*iBegin == '>') {
448  return createBinaryOperatorEvaluatorT<std::greater<double>>(
450 
451  } else if (*iBegin == '=' and iBegin + 1 != iEnd and *(iBegin + 1) == '=') {
452  return createBinaryOperatorEvaluatorT<std::equal_to<double>>(
454 
455  } else if (*iBegin == '!' and iBegin + 1 != iEnd and *(iBegin + 1) == '=') {
456  return createBinaryOperatorEvaluatorT<std::not_equal_to<double>>(
458  }
459  return evalInfo;
460  }
461 
462  template <typename Op>
463  EvaluatorInfo checkForSingleArgFunction(std::string::const_iterator iBegin,
464  std::string::const_iterator iEnd,
465  ExpressionFinder const* iExpressionFinder,
466  const std::string& iName,
467  Op op) {
468  EvaluatorInfo info;
469  if (iName.size() + 2 > static_cast<unsigned int>(iEnd - iBegin)) {
470  return info;
471  }
472  auto pos = iName.find(&(*iBegin), 0, iName.size());
473 
474  if (std::string::npos == pos or *(iBegin + iName.size()) != '(') {
475  return info;
476  }
477 
478  info.nextParseIndex = iName.size() + 1;
479 
480  auto itEndParen = findMatchingParenthesis(iBegin + iName.size(), iEnd);
481  if (iBegin + iName.size() == itEndParen) {
482  return info;
483  }
484 
485  auto argEvaluatorInfo = iExpressionFinder->createEvaluator(
486  iBegin + iName.size() + 1, itEndParen, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
487  info.nextParseIndex += argEvaluatorInfo.nextParseIndex;
488  if (argEvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex + 1 != 1 + itEndParen - iBegin) {
489  return info;
490  }
491  //account for closing parenthesis
492  ++info.nextParseIndex;
493 
494  info.evaluator = std::make_shared<reco::formula::FunctionOneArgEvaluator>(std::move(argEvaluatorInfo.top), op);
495  info.top = info.evaluator;
496  return info;
497  }
498 
499  std::string::const_iterator findCommaNotInParenthesis(std::string::const_iterator iBegin,
500  std::string::const_iterator iEnd) {
501  int level = 0;
502  std::string::const_iterator it = iBegin;
503  for (; it != iEnd; ++it) {
504  if (*it == '(') {
505  ++level;
506  } else if (*it == ')') {
507  --level;
508  } else if (*it == ',' and level == 0) {
509  return it;
510  }
511  }
512 
513  return it;
514  }
515 
516  template <typename Op>
517  EvaluatorInfo checkForTwoArgsFunction(std::string::const_iterator iBegin,
518  std::string::const_iterator iEnd,
519  ExpressionFinder const* iExpressionFinder,
520  const std::string& iName,
521  Op op) {
522  EvaluatorInfo info;
523  if (iName.size() + 2 > static_cast<unsigned int>(iEnd - iBegin)) {
524  return info;
525  }
526  auto pos = iName.find(&(*iBegin), 0, iName.size());
527 
528  if (std::string::npos == pos or *(iBegin + iName.size()) != '(') {
529  return info;
530  }
531 
532  info.nextParseIndex = iName.size() + 1;
533 
534  auto itEndParen = findMatchingParenthesis(iBegin + iName.size(), iEnd);
535  if (iBegin + iName.size() == itEndParen) {
536  return info;
537  }
538 
539  auto itComma = findCommaNotInParenthesis(iBegin + iName.size() + 1, itEndParen);
540 
541  auto arg1EvaluatorInfo = iExpressionFinder->createEvaluator(
542  iBegin + iName.size() + 1, itComma, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
543  info.nextParseIndex += arg1EvaluatorInfo.nextParseIndex;
544  if (arg1EvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex != itComma - iBegin) {
545  return info;
546  }
547  //account for commas
548  ++info.nextParseIndex;
549 
550  auto arg2EvaluatorInfo = iExpressionFinder->createEvaluator(
551  itComma + 1, itEndParen, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
552  info.nextParseIndex += arg2EvaluatorInfo.nextParseIndex;
553 
554  if (arg2EvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex + 1 != 1 + itEndParen - iBegin) {
555  return info;
556  }
557  //account for closing parenthesis
558  ++info.nextParseIndex;
559 
560  info.evaluator = std::make_shared<reco::formula::FunctionTwoArgsEvaluator>(
561  std::move(arg1EvaluatorInfo.top), std::move(arg2EvaluatorInfo.top), op);
562  info.top = info.evaluator;
563  return info;
564  }
565 
566  const std::string k_log("log");
567  const std::string k_log10("log10");
568  const std::string k_TMath__Log("TMath::Log");
569  double const kLog10Inv = 1. / std::log(10.);
570  const std::string k_exp("exp");
571  const std::string k_pow("pow");
572  const std::string k_TMath__Power("TMath::Power");
573  const std::string k_max("max");
574  const std::string k_min("min");
575  const std::string k_TMath__Max("TMath::Max");
576  const std::string k_TMath__Min("TMath::Min");
577  const std::string k_TMath__Erf("TMath::Erf");
578  const std::string k_erf("erf");
579  const std::string k_TMath__Landau("TMath::Landau");
580  const std::string k_sqrt("sqrt");
581  const std::string k_TMath__Sqrt("TMath::Sqrt");
582  const std::string k_abs("abs");
583  const std::string k_TMath__Abs("TMath::Abs");
584  const std::string k_cos("cos");
585  const std::string k_TMath__Cos("TMath::Cos");
586  const std::string k_sin("sin");
587  const std::string k_TMath__Sin("TMath::Sin");
588  const std::string k_tan("tan");
589  const std::string k_TMath__Tan("TMath::Tan");
590  const std::string k_acos("acos");
591  const std::string k_TMath__ACos("TMath::ACos");
592  const std::string k_asin("asin");
593  const std::string k_TMath__ASin("TMath::ASin");
594  const std::string k_atan("atan");
595  const std::string k_TMath__ATan("TMath::ATan");
596  const std::string k_atan2("atan2");
597  const std::string k_TMath__ATan2("TMath::ATan2");
598  const std::string k_cosh("cosh");
599  const std::string k_TMath__CosH("TMath::CosH");
600  const std::string k_sinh("sinh");
601  const std::string k_TMath__SinH("TMath::SinH");
602  const std::string k_tanh("tanh");
603  const std::string k_TMath__TanH("TMath::TanH");
604  const std::string k_acosh("acosh");
605  const std::string k_TMath__ACosH("TMath::ACosH");
606  const std::string k_asinh("asinh");
607  const std::string k_TMath__ASinH("TMath::ASinH");
608  const std::string k_atanh("atanh");
609  const std::string k_TMath__ATanH("TMath::ATanH");
610 
611  EvaluatorInfo FunctionFinder::createEvaluator(std::string::const_iterator iBegin,
612  std::string::const_iterator iEnd) const {
613  EvaluatorInfo info;
614 
615  info = checkForSingleArgFunction(
616  iBegin, iEnd, m_expressionFinder, k_erf, [](double iArg) -> double { return std::erf(iArg); });
617  if (info.evaluator.get() != nullptr) {
618  return info;
619  }
620 
621  info = checkForSingleArgFunction(
622  iBegin, iEnd, m_expressionFinder, k_TMath__Erf, [](double iArg) -> double { return std::erf(iArg); });
623  if (info.evaluator.get() != nullptr) {
624  return info;
625  }
626 
627  info = checkForSingleArgFunction(
628  iBegin, iEnd, m_expressionFinder, k_TMath__Landau, [](double iArg) -> double { return TMath::Landau(iArg); });
629  if (info.evaluator.get() != nullptr) {
630  return info;
631  }
632 
633  info = checkForSingleArgFunction(
634  iBegin, iEnd, m_expressionFinder, k_log, [](double iArg) -> double { return std::log(iArg); });
635  if (info.evaluator.get() != nullptr) {
636  return info;
637  }
638 
639  info = checkForSingleArgFunction(
640  iBegin, iEnd, m_expressionFinder, k_TMath__Log, [](double iArg) -> double { return std::log(iArg); });
641  if (info.evaluator.get() != nullptr) {
642  return info;
643  }
644 
645  info = checkForSingleArgFunction(
646  iBegin, iEnd, m_expressionFinder, k_log10, [](double iArg) -> double { return std::log(iArg) * kLog10Inv; });
647  if (info.evaluator.get() != nullptr) {
648  return info;
649  }
650 
651  info = checkForSingleArgFunction(
652  iBegin, iEnd, m_expressionFinder, k_exp, [](double iArg) -> double { return std::exp(iArg); });
653  if (info.evaluator.get() != nullptr) {
654  return info;
655  }
656 
657  info = checkForSingleArgFunction(
658  iBegin, iEnd, m_expressionFinder, k_sqrt, [](double iArg) -> double { return std::sqrt(iArg); });
659  if (info.evaluator.get() != nullptr) {
660  return info;
661  }
662 
663  info = checkForSingleArgFunction(
664  iBegin, iEnd, m_expressionFinder, k_TMath__Sqrt, [](double iArg) -> double { return std::sqrt(iArg); });
665  if (info.evaluator.get() != nullptr) {
666  return info;
667  }
668 
669  info = checkForSingleArgFunction(
670  iBegin, iEnd, m_expressionFinder, k_abs, [](double iArg) -> double { return std::abs(iArg); });
671  if (info.evaluator.get() != nullptr) {
672  return info;
673  }
674 
675  info = checkForSingleArgFunction(
676  iBegin, iEnd, m_expressionFinder, k_TMath__Abs, [](double iArg) -> double { return std::abs(iArg); });
677  if (info.evaluator.get() != nullptr) {
678  return info;
679  }
680 
681  info = checkForSingleArgFunction(
682  iBegin, iEnd, m_expressionFinder, k_cos, [](double iArg) -> double { return std::cos(iArg); });
683  if (info.evaluator.get() != nullptr) {
684  return info;
685  }
686 
687  info = checkForSingleArgFunction(
688  iBegin, iEnd, m_expressionFinder, k_TMath__Cos, [](double iArg) -> double { return std::cos(iArg); });
689  if (info.evaluator.get() != nullptr) {
690  return info;
691  }
692 
693  info = checkForSingleArgFunction(
694  iBegin, iEnd, m_expressionFinder, k_sin, [](double iArg) -> double { return std::sin(iArg); });
695  if (info.evaluator.get() != nullptr) {
696  return info;
697  }
698 
699  info = checkForSingleArgFunction(
700  iBegin, iEnd, m_expressionFinder, k_TMath__Sin, [](double iArg) -> double { return std::sin(iArg); });
701  if (info.evaluator.get() != nullptr) {
702  return info;
703  }
704 
705  info = checkForSingleArgFunction(
706  iBegin, iEnd, m_expressionFinder, k_tan, [](double iArg) -> double { return std::tan(iArg); });
707  if (info.evaluator.get() != nullptr) {
708  return info;
709  }
710 
711  info = checkForSingleArgFunction(
712  iBegin, iEnd, m_expressionFinder, k_TMath__Tan, [](double iArg) -> double { return std::tan(iArg); });
713  if (info.evaluator.get() != nullptr) {
714  return info;
715  }
716 
717  info = checkForSingleArgFunction(
718  iBegin, iEnd, m_expressionFinder, k_acos, [](double iArg) -> double { return std::acos(iArg); });
719  if (info.evaluator.get() != nullptr) {
720  return info;
721  }
722 
723  info = checkForSingleArgFunction(
724  iBegin, iEnd, m_expressionFinder, k_TMath__ACos, [](double iArg) -> double { return std::acos(iArg); });
725  if (info.evaluator.get() != nullptr) {
726  return info;
727  }
728 
729  info = checkForSingleArgFunction(
730  iBegin, iEnd, m_expressionFinder, k_asin, [](double iArg) -> double { return std::asin(iArg); });
731  if (info.evaluator.get() != nullptr) {
732  return info;
733  }
734 
735  info = checkForSingleArgFunction(
736  iBegin, iEnd, m_expressionFinder, k_TMath__ASin, [](double iArg) -> double { return std::asin(iArg); });
737  if (info.evaluator.get() != nullptr) {
738  return info;
739  }
740 
741  info = checkForSingleArgFunction(
742  iBegin, iEnd, m_expressionFinder, k_atan, [](double iArg) -> double { return std::atan(iArg); });
743  if (info.evaluator.get() != nullptr) {
744  return info;
745  }
746 
747  info = checkForSingleArgFunction(
748  iBegin, iEnd, m_expressionFinder, k_TMath__ATan, [](double iArg) -> double { return std::atan(iArg); });
749  if (info.evaluator.get() != nullptr) {
750  return info;
751  }
752 
753  info = checkForSingleArgFunction(
754  iBegin, iEnd, m_expressionFinder, k_cosh, [](double iArg) -> double { return std::cosh(iArg); });
755  if (info.evaluator.get() != nullptr) {
756  return info;
757  }
758 
759  info = checkForSingleArgFunction(
760  iBegin, iEnd, m_expressionFinder, k_TMath__CosH, [](double iArg) -> double { return std::cosh(iArg); });
761  if (info.evaluator.get() != nullptr) {
762  return info;
763  }
764 
765  info = checkForSingleArgFunction(
766  iBegin, iEnd, m_expressionFinder, k_sinh, [](double iArg) -> double { return std::sinh(iArg); });
767  if (info.evaluator.get() != nullptr) {
768  return info;
769  }
770 
771  info = checkForSingleArgFunction(
772  iBegin, iEnd, m_expressionFinder, k_TMath__SinH, [](double iArg) -> double { return std::sinh(iArg); });
773  if (info.evaluator.get() != nullptr) {
774  return info;
775  }
776 
777  info = checkForSingleArgFunction(
778  iBegin, iEnd, m_expressionFinder, k_tanh, [](double iArg) -> double { return std::tanh(iArg); });
779  if (info.evaluator.get() != nullptr) {
780  return info;
781  }
782 
783  info = checkForSingleArgFunction(
784  iBegin, iEnd, m_expressionFinder, k_TMath__TanH, [](double iArg) -> double { return std::tanh(iArg); });
785  if (info.evaluator.get() != nullptr) {
786  return info;
787  }
788 
789  info = checkForSingleArgFunction(
790  iBegin, iEnd, m_expressionFinder, k_acosh, [](double iArg) -> double { return std::acosh(iArg); });
791  if (info.evaluator.get() != nullptr) {
792  return info;
793  }
794 
795  info = checkForSingleArgFunction(
796  iBegin, iEnd, m_expressionFinder, k_TMath__ACosH, [](double iArg) -> double { return std::acosh(iArg); });
797  if (info.evaluator.get() != nullptr) {
798  return info;
799  }
800 
801  info = checkForSingleArgFunction(
802  iBegin, iEnd, m_expressionFinder, k_asinh, [](double iArg) -> double { return std::asinh(iArg); });
803  if (info.evaluator.get() != nullptr) {
804  return info;
805  }
806 
807  info = checkForSingleArgFunction(
808  iBegin, iEnd, m_expressionFinder, k_TMath__ASinH, [](double iArg) -> double { return std::asinh(iArg); });
809  if (info.evaluator.get() != nullptr) {
810  return info;
811  }
812 
813  info = checkForSingleArgFunction(
814  iBegin, iEnd, m_expressionFinder, k_atanh, [](double iArg) -> double { return std::atanh(iArg); });
815  if (info.evaluator.get() != nullptr) {
816  return info;
817  }
818 
819  info = checkForSingleArgFunction(
820  iBegin, iEnd, m_expressionFinder, k_TMath__ATanH, [](double iArg) -> double { return std::atanh(iArg); });
821  if (info.evaluator.get() != nullptr) {
822  return info;
823  }
824 
825  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder, k_atan2, [](double iArg1, double iArg2) -> double {
826  return std::atan2(iArg1, iArg2);
827  });
828  if (info.evaluator.get() != nullptr) {
829  return info;
830  }
831 
832  info = checkForTwoArgsFunction(
833  iBegin, iEnd, m_expressionFinder, k_TMath__ATan2, [](double iArg1, double iArg2) -> double {
834  return std::atan2(iArg1, iArg2);
835  });
836  if (info.evaluator.get() != nullptr) {
837  return info;
838  }
839 
840  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder, k_pow, [](double iArg1, double iArg2) -> double {
841  return std::pow(iArg1, iArg2);
842  });
843  if (info.evaluator.get() != nullptr) {
844  return info;
845  }
846 
847  info = checkForTwoArgsFunction(
848  iBegin, iEnd, m_expressionFinder, k_TMath__Power, [](double iArg1, double iArg2) -> double {
849  return std::pow(iArg1, iArg2);
850  });
851  if (info.evaluator.get() != nullptr) {
852  return info;
853  }
854 
855  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder, k_max, [](double iArg1, double iArg2) -> double {
856  return std::max(iArg1, iArg2);
857  });
858  if (info.evaluator.get() != nullptr) {
859  return info;
860  }
861 
862  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder, k_min, [](double iArg1, double iArg2) -> double {
863  return std::min(iArg1, iArg2);
864  });
865  if (info.evaluator.get() != nullptr) {
866  return info;
867  }
868 
869  info = checkForTwoArgsFunction(
870  iBegin, iEnd, m_expressionFinder, k_TMath__Max, [](double iArg1, double iArg2) -> double {
871  return std::max(iArg1, iArg2);
872  });
873  if (info.evaluator.get() != nullptr) {
874  return info;
875  }
876 
877  info = checkForTwoArgsFunction(
878  iBegin, iEnd, m_expressionFinder, k_TMath__Min, [](double iArg1, double iArg2) -> double {
879  return std::min(iArg1, iArg2);
880  });
881  if (info.evaluator.get() != nullptr) {
882  return info;
883  }
884 
885  return info;
886  };
887 
888  ExpressionFinder const s_expressionFinder;
889 
890 } // namespace
891 //
892 // constants, enums and typedefs
893 //
894 
895 //
896 // static data member definitions
897 //
898 
899 //
900 // constructors and destructor
901 //
903  //remove white space
905  formula.reserve(iFormula.size());
906  std::copy_if(iFormula.begin(), iFormula.end(), std::back_inserter(formula), [](const char iC) { return iC != ' '; });
907 
908  auto info = s_expressionFinder.createEvaluator(
909  formula.begin(), formula.end(), std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
910 
911  if (info.nextParseIndex != static_cast<int>(formula.size()) or info.top.get() == nullptr) {
912  auto lastIndex = info.nextParseIndex;
913  if (formula.size() != iFormula.size()) {
914  lastIndex = 0;
915  for (decltype(info.nextParseIndex) index = 0; index < info.nextParseIndex; ++index, ++lastIndex) {
916  while (iFormula[lastIndex] != formula[index]) {
917  assert(iFormula[lastIndex] == ' ');
918  ++lastIndex;
919  }
920  }
921  }
922  throw cms::Exception("FormulaEvaluatorParseError")
923  << "While parsing '" << iFormula << "' could not parse beyond '"
924  << std::string(iFormula.begin(), iFormula.begin() + lastIndex) << "'";
925  }
926 
927  DEBUG_STATE("DONE parsing");
928  printAST(info.top.get());
929 
930  m_evaluator = std::move(info.top);
931  m_nVariables = info.maxNumVariables;
932  m_nParameters = info.maxNumParameters;
933 }
934 
935 //
936 // const member functions
937 //
938 double FormulaEvaluator::evaluate(double const* iVariables, double const* iParameters) const {
939  return m_evaluator->evaluate(iVariables, iParameters);
940 }
941 
943  throw cms::Exception("WrongNumVariables")
944  << "FormulaEvaluator expected at least " << m_nVariables << " but was passed only " << iSize;
945 }
947  throw cms::Exception("WrongNumParameters")
948  << "FormulaEvaluator expected at least " << m_nParameters << " but was passed only " << iSize;
949 }
950 
951 std::vector<std::string> FormulaEvaluator::abstractSyntaxTree() const { return m_evaluator->abstractSyntaxTree(); }
static const TGPicture * info(bool iBackgroundIsBlack)
double evaluate(V const &iVariables, P const &iParameters) const
void throwWrongNumberOfVariables(size_t) const
void tanh(data_T data[CONFIG_T::n_in], res_T res[CONFIG_T::n_in])
Sin< T >::type sin(const T &t)
Definition: Sin.h:22
assert(be >=bs)
void swapLeftEvaluator(std::shared_ptr< EvaluatorBase > &iNew)
#define DEBUG_STATE(_v_)
T sqrt(T t)
Definition: SSEVec.h:19
The Signals That Services Can Subscribe To This is based on ActivityRegistry and is current per Services can connect to the signals distributed by the ActivityRegistry in order to monitor the activity of the application Each possible callback has some defined which we here list in angle e< void, edm::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Definition: Activities.doc:12
Cos< T >::type cos(const T &t)
Definition: Cos.h:22
Tan< T >::type tan(const T &t)
Definition: Tan.h:22
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
std::vector< std::string > abstractSyntaxTree() const
Definition: value.py:1
static std::atomic< unsigned int > lastIndex
Definition: DDValue.cc:12
constexpr unsigned int power(unsigned int base, unsigned int exponent)
FormulaEvaluator(std::string const &iFormula)
fixed size matrix
std::shared_ptr< formula::EvaluatorBase const > m_evaluator
void throwWrongNumberOfParameters(size_t) const
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:29
def move(src, dest)
Definition: eostools.py:511
dd4hep::tools::Evaluator & evaluator()