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, std::string::const_iterator iEnd) {
71  if (iBegin == iEnd) {
72  return iBegin;
73  }
74  if( *iBegin != '(') {
75  return iBegin;
76  }
77  int level = 1;
78  size_t index = 0;
79  for( auto it = iBegin+1; it != iEnd; ++it) {
80  ++index;
81  if (*it == '(') {
82  ++level;
83  } else if (*it == ')') {
84  --level;
85  if (level == 0) {
86  break;
87  }
88  }
89  }
90  return iBegin + index;
91  }
92 
93  class ConstantFinder : public ExpressionElementFinderBase {
94  bool checkStart(char iSymbol) const final {
95  if( iSymbol == '-' or iSymbol == '.' or std::isdigit(iSymbol) ) {
96  return true;
97  }
98  return false;
99  }
100 
101  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final {
102  EvaluatorInfo info;
103  try {
104  size_t endIndex=0;
105  std::string s(iBegin,iEnd);
106  double value = stod(s, &endIndex);
107 
108  info.nextParseIndex = endIndex;
109  info.evaluator = std::make_shared<reco::formula::ConstantEvaluator>(value);
110  info.top = info.evaluator;
111  } catch ( std::invalid_argument const& ) {}
112 
113  return info;
114 
115  }
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 
146  info.nextParseIndex = endIndex+2;
147  info.maxNumParameters = value+1;
148  info.evaluator = std::make_shared<reco::formula::ParameterEvaluator>(value);
149  info.top = info.evaluator;
150  } catch ( std::invalid_argument const& ) {}
151 
152  return info;
153 
154  }
155  };
156 
157  class VariableFinder : public ExpressionElementFinderBase {
158  bool checkStart(char iSymbol) const final {
159  if( iSymbol == 'x' or iSymbol == 'y' or iSymbol == 'z' or iSymbol == 't' ) {
160  return true;
161  }
162  return false;
163  }
164 
165  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final {
166  EvaluatorInfo info;
167  if(iBegin == iEnd) {
168  return info;
169  }
170  unsigned int index = 4;
171  switch (*iBegin) {
172  case 'x':
173  { index = 0; break;}
174  case 'y':
175  { index = 1; break;}
176  case 'z':
177  { index = 2; break;}
178  case 't':
179  {index = 3; break;}
180  }
181  if(index == 4) {
182  return info;
183  }
184  info.nextParseIndex = 1;
185  info.maxNumVariables = index+1;
186  info.evaluator = std::make_shared<reco::formula::VariableEvaluator>(index);
187  info.top = info.evaluator;
188  return info;
189  }
190  };
191 
192  class ExpressionFinder;
193 
194  class FunctionFinder : public ExpressionElementFinderBase {
195  public:
196  FunctionFinder(ExpressionFinder const* iEF):
197  m_expressionFinder(iEF) {};
198 
199  bool checkStart(char iSymbol) const final {
200  return std::isalpha(iSymbol);
201  }
202 
203  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const final;
204 
205  private:
206  ExpressionFinder const* m_expressionFinder;
207  };
208 
209 
210  EvaluatorInfo createBinaryOperatorEvaluator( ExpressionFinder const&,
211  std::string::const_iterator iBegin,
212  std::string::const_iterator iEnd) ;
213 
214  class ExpressionFinder {
215 
216  public:
217  ExpressionFinder() {
218  m_elements.reserve(4);
219  m_elements.emplace_back(new FunctionFinder{this});
220  m_elements.emplace_back(new ConstantFinder{});
221  m_elements.emplace_back(new ParameterFinder{});
222  m_elements.emplace_back(new VariableFinder{});
223  }
224 
225  bool checkStart(char iChar) const {
226  if ( '(' == iChar or '-' == iChar or '+' ==iChar) {
227  return true;
228  }
229  for( auto const& e : m_elements) {
230  if (e->checkStart(iChar) ) {
231  return true;
232  }
233  }
234  return false;
235  }
236 
237  EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase> iPreviousBinary) const {
238  EvaluatorInfo leftEvaluatorInfo ;
239 
240  if( iBegin == iEnd) {
241  return leftEvaluatorInfo;
242  }
243  //Start with '+'
244  if (*iBegin == '+' and iEnd -iBegin > 1 and not std::isdigit( *(iBegin+1) ) ) {
245  leftEvaluatorInfo = createEvaluator(iBegin+1, iEnd, iPreviousBinary);
246 
247  //have to account for the '+' we skipped over
248  leftEvaluatorInfo.nextParseIndex +=1;
249  if( nullptr == leftEvaluatorInfo.evaluator.get() ) {
250  return leftEvaluatorInfo;
251  }
252  }
253  //Start with '-'
254  else if (*iBegin == '-' and iEnd -iBegin > 1 and not std::isdigit( *(iBegin+1) ) ) {
255  leftEvaluatorInfo = createEvaluator(iBegin+1, iEnd,iPreviousBinary);
256 
257  //have to account for the '+' we skipped over
258  leftEvaluatorInfo.nextParseIndex +=1;
259  if( nullptr == leftEvaluatorInfo.evaluator.get() ) {
260  return leftEvaluatorInfo;
261  }
262  leftEvaluatorInfo.evaluator = std::make_shared<reco::formula::UnaryMinusEvaluator>( std::move(leftEvaluatorInfo.top));
263  leftEvaluatorInfo.top = leftEvaluatorInfo.evaluator;
264  }
265  //Start with '('
266  else if( *iBegin == '(') {
267  auto endParenthesis = findMatchingParenthesis(iBegin,iEnd);
268  if(iBegin== endParenthesis) {
269  return leftEvaluatorInfo;
270  }
271  leftEvaluatorInfo = createEvaluator(iBegin+1,endParenthesis,std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
272  ++leftEvaluatorInfo.nextParseIndex;
273  if(leftEvaluatorInfo.evaluator.get() == nullptr) {
274  return leftEvaluatorInfo;
275  }
276  //need to account for closing parenthesis
277  ++leftEvaluatorInfo.nextParseIndex;
278  leftEvaluatorInfo.top->setPrecedenceToParenthesis();
279  DEBUG_STATE("close parenthesis");
280  printAST(leftEvaluatorInfo.top.get());
281  leftEvaluatorInfo.evaluator = leftEvaluatorInfo.top;
282  } else {
283  //Does not start with a '('
284  int maxParseDistance = 0;
285  for( auto const& e: m_elements) {
286  if(e->checkStart(*iBegin) ) {
287  leftEvaluatorInfo = e->createEvaluator(iBegin,iEnd);
288  if(leftEvaluatorInfo.evaluator != nullptr) {
289  break;
290  }
291  if (leftEvaluatorInfo.nextParseIndex > maxParseDistance) {
292  maxParseDistance = leftEvaluatorInfo.nextParseIndex;
293  }
294  }
295  }
296  if(leftEvaluatorInfo.evaluator.get() == nullptr) {
297  //failed to parse
298  leftEvaluatorInfo.nextParseIndex = maxParseDistance;
299  return leftEvaluatorInfo;
300  }
301  }
302  //did we evaluate the full expression?
303  if(leftEvaluatorInfo.nextParseIndex == iEnd-iBegin) {
304  if (iPreviousBinary) {
305  iPreviousBinary->setRightEvaluator(leftEvaluatorInfo.top);
306  leftEvaluatorInfo.top = iPreviousBinary;
307  }
308  DEBUG_STATE("full expression");
309  printAST(leftEvaluatorInfo.evaluator.get());
310  return leftEvaluatorInfo;
311  }
312 
313  //see if this is a binary expression
314  auto fullExpression = createBinaryOperatorEvaluator(*this, iBegin+leftEvaluatorInfo.nextParseIndex, iEnd);
315  fullExpression.nextParseIndex +=leftEvaluatorInfo.nextParseIndex;
316  fullExpression.maxNumVariables = std::max(leftEvaluatorInfo.maxNumVariables, fullExpression.maxNumVariables);
317  fullExpression.maxNumParameters = std::max(leftEvaluatorInfo.maxNumParameters, fullExpression.maxNumParameters);
318  if (iBegin + fullExpression.nextParseIndex != iEnd) {
319  //did not parse the full expression
320  fullExpression.evaluator.reset();
321  }
322 
323  if(fullExpression.evaluator == nullptr) {
324  //we had a parsing problem
325  return fullExpression;
326  }
327 
328  DEBUG_STATE("binary before precedence handling");
329  printAST(fullExpression.evaluator.get());
330  //Now to handle precedence
331  auto topNode = fullExpression.top;
332  auto binaryEval = dynamic_cast<reco::formula::BinaryOperatorEvaluatorBase*>(fullExpression.evaluator.get());
333  if (iPreviousBinary) {
334  if (iPreviousBinary->precedence() >= fullExpression.evaluator->precedence() ) {
335  DEBUG_STATE("prec >=");
336  iPreviousBinary->setRightEvaluator(leftEvaluatorInfo.evaluator);
337  binaryEval->setLeftEvaluator(iPreviousBinary);
338  } else {
339  binaryEval->setLeftEvaluator(leftEvaluatorInfo.evaluator);
340  if(iPreviousBinary->precedence()<topNode->precedence() ) {
341  DEBUG_STATE(" switch topNode");
342  topNode = iPreviousBinary;
343  iPreviousBinary->setRightEvaluator(fullExpression.top);
344  } else {
345  DEBUG_STATE("swapping");
346  //We need to take the lhs of a binary expression directly or indirectly connected
347  // to the present node and swap it with the rhs of the 'previous' binary expression
348  // becuase we need the present expression to be evaluated earlier than the 'previous'.
349  std::shared_ptr<reco::formula::EvaluatorBase> toSwap = iPreviousBinary;
350  auto parentBinary = dynamic_cast<reco::formula::BinaryOperatorEvaluatorBase*>(topNode.get());
351  do {
352  if(parentBinary->lhs() == binaryEval or parentBinary->lhs()->precedence() > iPreviousBinary->precedence()) {
353  parentBinary->swapLeftEvaluator(toSwap);
354  iPreviousBinary->setRightEvaluator(toSwap);
355  } else {
356  //try the next one in the chain
357  parentBinary = const_cast<reco::formula::BinaryOperatorEvaluatorBase*>( dynamic_cast<const reco::formula::BinaryOperatorEvaluatorBase*>(parentBinary->lhs()));
358  assert(parentBinary != nullptr);
359  }
360  } while(iPreviousBinary->rhs() == nullptr);
361  }
362  }
363  } else {
364  binaryEval->setLeftEvaluator(leftEvaluatorInfo.top);
365  }
366  DEBUG_STATE("finished binary");
367  printAST(binaryEval);
368  DEBUG_STATE("present top");
369  printAST(topNode.get());
370  fullExpression.top = topNode;
371  return fullExpression;
372  }
373 
374  private:
375  std::vector<std::unique_ptr<ExpressionElementFinderBase>> m_elements;
376 
377  };
378 
379  template<typename Op>
380  EvaluatorInfo createBinaryOperatorEvaluatorT(int iSymbolLength,
382  ExpressionFinder const& iEF,
383  std::string::const_iterator iBegin,
384  std::string::const_iterator iEnd) {
385  auto op = std::make_shared<reco::formula::BinaryOperatorEvaluator<Op> >(iPrec);
386  EvaluatorInfo evalInfo = iEF.createEvaluator(iBegin+iSymbolLength,iEnd,op);
387  evalInfo.nextParseIndex += iSymbolLength;
388 
389  if(evalInfo.evaluator.get() == nullptr) {
390  return evalInfo;
391  }
392 
393  evalInfo.evaluator = op;
394  return evalInfo;
395  }
396 
397  struct power {
398  double operator()(double iLHS, double iRHS) const {
399  return std::pow(iLHS,iRHS);
400  }
401  };
402 
403 
404  EvaluatorInfo
405  createBinaryOperatorEvaluator( ExpressionFinder const& iEF,
406  std::string::const_iterator iBegin,
407  std::string::const_iterator iEnd) {
408  EvaluatorInfo evalInfo;
409  if(iBegin == iEnd) {
410  return evalInfo;
411  }
412 
413  if(*iBegin == '+') {
414  return createBinaryOperatorEvaluatorT<std::plus<double>>(1,
416  iEF,
417  iBegin,
418  iEnd);
419  }
420 
421  else if(*iBegin == '-') {
422  return createBinaryOperatorEvaluatorT<std::minus<double>>(1,
424  iEF,
425  iBegin,
426  iEnd);
427  }
428  else if(*iBegin == '*') {
429  return createBinaryOperatorEvaluatorT<std::multiplies<double>>(1,
431  iEF,
432  iBegin,
433  iEnd);
434  }
435  else if(*iBegin == '/') {
436  return createBinaryOperatorEvaluatorT<std::divides<double>>(1,
438  iEF,
439  iBegin,
440  iEnd);
441  }
442 
443  else if(*iBegin == '^') {
444  return createBinaryOperatorEvaluatorT<power>(1,
446  iEF,
447  iBegin,
448  iEnd);
449  }
450  else if (*iBegin =='<' and iBegin+1 != iEnd and *(iBegin+1) == '=') {
451  return createBinaryOperatorEvaluatorT<std::less_equal<double>>(2,
453  iEF,
454  iBegin,
455  iEnd);
456 
457  }
458  else if (*iBegin =='>' and iBegin+1 != iEnd and *(iBegin+1) == '=') {
459  return createBinaryOperatorEvaluatorT<std::greater_equal<double>>(2,
461  iEF,
462  iBegin,
463  iEnd);
464 
465  }
466  else if (*iBegin =='<' ) {
467  return createBinaryOperatorEvaluatorT<std::less<double>>(1,
469  iEF,
470  iBegin,
471  iEnd);
472 
473  }
474  else if (*iBegin =='>' ) {
475  return createBinaryOperatorEvaluatorT<std::greater<double>>(1,
477  iEF,
478  iBegin,
479  iEnd);
480 
481  }
482  else if (*iBegin =='=' and iBegin+1 != iEnd and *(iBegin+1) == '=' ) {
483  return createBinaryOperatorEvaluatorT<std::equal_to<double>>(2,
485  iEF,
486  iBegin,
487  iEnd);
488 
489  }
490  else if (*iBegin =='!' and iBegin+1 != iEnd and *(iBegin+1) == '=' ) {
491  return createBinaryOperatorEvaluatorT<std::not_equal_to<double>>(2,
493  iEF,
494  iBegin,
495  iEnd);
496 
497  }
498  return evalInfo;
499  }
500 
501 
502  template<typename Op>
503  EvaluatorInfo
504  checkForSingleArgFunction(std::string::const_iterator iBegin,
505  std::string::const_iterator iEnd,
506  ExpressionFinder const* iExpressionFinder,
507  const std::string& iName,
508  Op op) {
509  EvaluatorInfo info;
510  if(iName.size()+2 > static_cast<unsigned int>(iEnd-iBegin) ) {
511  return info;
512  }
513  auto pos = iName.find(&(*iBegin), 0,iName.size());
514 
515  if(std::string::npos == pos or *(iBegin+iName.size()) != '(') {
516  return info;
517  }
518 
519  info.nextParseIndex = iName.size()+1;
520 
521  auto itEndParen = findMatchingParenthesis(iBegin+iName.size(),iEnd);
522  if(iBegin+iName.size() == itEndParen) {
523  return info;
524  }
525 
526  auto argEvaluatorInfo = iExpressionFinder->createEvaluator(iBegin+iName.size()+1, itEndParen,
527  std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
528  info.nextParseIndex += argEvaluatorInfo.nextParseIndex;
529  if(argEvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex+1 != 1+itEndParen - iBegin) {
530  return info;
531  }
532  //account for closing parenthesis
533  ++info.nextParseIndex;
534 
535  info.evaluator = std::make_shared<reco::formula::FunctionOneArgEvaluator>(std::move(argEvaluatorInfo.top),
536  op);
537  info.top = info.evaluator;
538  return info;
539  }
540 
541  std::string::const_iterator findCommaNotInParenthesis(std::string::const_iterator iBegin,
542  std::string::const_iterator iEnd ) {
543  int level = 0;
544  std::string::const_iterator it = iBegin;
545  for(; it != iEnd; ++it) {
546  if (*it == '(') {
547  ++level;
548  } else if(*it == ')') {
549  --level;
550  }
551  else if( *it ==',' and level == 0 ) {
552  return it;
553  }
554  }
555 
556  return it;
557  }
558 
559 
560  template<typename Op>
561  EvaluatorInfo
562  checkForTwoArgsFunction(std::string::const_iterator iBegin,
563  std::string::const_iterator iEnd,
564  ExpressionFinder const* iExpressionFinder,
565  const std::string& iName,
566  Op op) {
567  EvaluatorInfo info;
568  if(iName.size()+2 > static_cast<unsigned int>(iEnd-iBegin) ) {
569  return info;
570  }
571  auto pos = iName.find(&(*iBegin), 0,iName.size());
572 
573  if(std::string::npos == pos or *(iBegin+iName.size()) != '(') {
574  return info;
575  }
576 
577  info.nextParseIndex = iName.size()+1;
578 
579  auto itEndParen = findMatchingParenthesis(iBegin+iName.size(),iEnd);
580  if(iBegin+iName.size() == itEndParen) {
581  return info;
582  }
583 
584  auto itComma = findCommaNotInParenthesis(iBegin+iName.size()+1, itEndParen);
585 
586  auto arg1EvaluatorInfo = iExpressionFinder->createEvaluator(iBegin+iName.size()+1, itComma, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
587  info.nextParseIndex += arg1EvaluatorInfo.nextParseIndex;
588  if(arg1EvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex != itComma-iBegin ) {
589  return info;
590  }
591  //account for commas
592  ++info.nextParseIndex;
593 
594  auto arg2EvaluatorInfo = iExpressionFinder->createEvaluator(itComma+1, itEndParen, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
595  info.nextParseIndex += arg2EvaluatorInfo.nextParseIndex;
596 
597  if(arg2EvaluatorInfo.evaluator.get() == nullptr or info.nextParseIndex+1 != 1+itEndParen - iBegin) {
598  return info;
599  }
600  //account for closing parenthesis
601  ++info.nextParseIndex;
602 
603  info.evaluator = std::make_shared<reco::formula::FunctionTwoArgsEvaluator>(std::move(arg1EvaluatorInfo.top),
604  std::move(arg2EvaluatorInfo.top),
605  op);
606  info.top = info.evaluator;
607  return info;
608  }
609 
610  const std::string k_log("log");
611  const std::string k_log10("log10");
612  const std::string k_TMath__Log("TMath::Log");
613  double const kLog10Inv = 1./std::log(10.);
614  const std::string k_exp("exp");
615  const std::string k_pow("pow");
616  const std::string k_TMath__Power("TMath::Power");
617  const std::string k_max("max");
618  const std::string k_min("min");
619  const std::string k_TMath__Max("TMath::Max");
620  const std::string k_TMath__Min("TMath::Min");
621  const std::string k_TMath__Erf("TMath::Erf");
622  const std::string k_erf("erf");
623  const std::string k_TMath__Landau("TMath::Landau");
624  const std::string k_sqrt("sqrt");
625  const std::string k_TMath__Sqrt("TMath::Sqrt");
626  const std::string k_abs("abs");
627  const std::string k_TMath__Abs("TMath::Abs");
628 
629 
630  EvaluatorInfo
631  FunctionFinder::createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd) const {
632  EvaluatorInfo info;
633 
634  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
635  k_erf, [](double iArg)->double { return std::erf(iArg); } );
636  if(info.evaluator.get() != nullptr) {
637  return info;
638  }
639 
640  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
641  k_TMath__Erf, [](double iArg)->double { return std::erf(iArg); } );
642  if(info.evaluator.get() != nullptr) {
643  return info;
644  }
645 
646  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
647  k_TMath__Landau, [](double iArg)->double { return TMath::Landau(iArg); } );
648  if(info.evaluator.get() != nullptr) {
649  return info;
650  }
651 
652  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
653  k_log, [](double iArg)->double { return std::log(iArg); } );
654  if(info.evaluator.get() != nullptr) {
655  return info;
656  }
657 
658  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
659  k_TMath__Log, [](double iArg)->double { return std::log(iArg); } );
660  if(info.evaluator.get() != nullptr) {
661  return info;
662  }
663 
664  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
665  k_log10, [](double iArg)->double { return std::log(iArg)*kLog10Inv; } );
666  if(info.evaluator.get() != nullptr) {
667  return info;
668  }
669 
670  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
671  k_exp, [](double iArg)->double { return std::exp(iArg); } );
672  if(info.evaluator.get() != nullptr) {
673  return info;
674  }
675 
676  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
677  k_sqrt, [](double iArg)->double { return std::sqrt(iArg); } );
678  if(info.evaluator.get() != nullptr) {
679  return info;
680  }
681 
682  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
683  k_TMath__Sqrt, [](double iArg)->double { return std::sqrt(iArg); } );
684  if(info.evaluator.get() != nullptr) {
685  return info;
686  }
687 
688  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
689  k_abs, [](double iArg)->double { return std::abs(iArg); } );
690  if(info.evaluator.get() != nullptr) {
691  return info;
692  }
693 
694  info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
695  k_TMath__Abs, [](double iArg)->double { return std::abs(iArg); } );
696  if(info.evaluator.get() != nullptr) {
697  return info;
698  }
699 
700  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
701  k_pow, [](double iArg1, double iArg2)->double { return std::pow(iArg1,iArg2); } );
702  if(info.evaluator.get() != nullptr) {
703  return info;
704  }
705 
706  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
707  k_TMath__Power, [](double iArg1, double iArg2)->double { return std::pow(iArg1,iArg2); } );
708  if(info.evaluator.get() != nullptr) {
709  return info;
710  }
711 
712  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
713  k_max, [](double iArg1, double iArg2)->double { return std::max(iArg1,iArg2); } );
714  if(info.evaluator.get() != nullptr) {
715  return info;
716  }
717 
718  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
719  k_min, [](double iArg1, double iArg2)->double { return std::min(iArg1,iArg2); } );
720  if(info.evaluator.get() != nullptr) {
721  return info;
722  }
723 
724  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
725  k_TMath__Max, [](double iArg1, double iArg2)->double { return std::max(iArg1,iArg2); } );
726  if(info.evaluator.get() != nullptr) {
727  return info;
728  }
729 
730  info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
731  k_TMath__Min, [](double iArg1, double iArg2)->double { return std::min(iArg1,iArg2); } );
732  if(info.evaluator.get() != nullptr) {
733  return info;
734  }
735 
736  return info;
737  };
738 
739  ExpressionFinder const s_expressionFinder;
740 
741 }
742 //
743 // constants, enums and typedefs
744 //
745 
746 //
747 // static data member definitions
748 //
749 
750 //
751 // constructors and destructor
752 //
754 {
755  //remove white space
757  formula.reserve(iFormula.size());
758  std::copy_if(iFormula.begin(), iFormula.end(), std::back_inserter(formula), [](const char iC) { return iC != ' '; } );
759 
760  auto info = s_expressionFinder.createEvaluator(formula.begin(), formula.end(),std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
761 
762  if(info.nextParseIndex != static_cast<int>(formula.size()) or info.top.get() == nullptr) {
763  auto lastIndex = info.nextParseIndex;
764  if(formula.size() != iFormula.size()) {
765  lastIndex =0;
766  for(decltype(info.nextParseIndex) index=0; index < info.nextParseIndex; ++index, ++lastIndex) {
767  while(iFormula[lastIndex] != formula[index]) {
768  assert(iFormula[lastIndex]==' ');
769  ++lastIndex;
770  }
771  }
772  }
773  throw cms::Exception("FormulaEvaluatorParseError")<<"While parsing '"<<iFormula<<"' could not parse beyond '"<<std::string(iFormula.begin(),iFormula.begin()+lastIndex) <<"'";
774  }
775 
776  DEBUG_STATE("DONE parsing");
777  printAST(info.top.get());
778 
779  m_evaluator = std::move(info.top);
780  m_nVariables = info.maxNumVariables;
781  m_nParameters = info.maxNumParameters;
782 }
783 
784 //
785 // const member functions
786 //
787 double
788 FormulaEvaluator::evaluate(double const* iVariables, double const* iParameters) const
789 {
790  return m_evaluator->evaluate(iVariables, iParameters);
791 }
792 
793 void
795  throw cms::Exception("WrongNumVariables")<<"FormulaEvaluator expected at least "<<m_nVariables<<" but was passed only "<<iSize;
796 }
797 void
799  throw cms::Exception("WrongNumParameters")<<"FormulaEvaluator expected at least "<<m_nParameters<<" but was passed only "<<iSize;
800 }
801 
802 std::vector<std::string>
804  return m_evaluator->abstractSyntaxTree();
805 }
static const TGPicture * info(bool iBackgroundIsBlack)
void swapLeftEvaluator(std::shared_ptr< EvaluatorBase > &iNew)
#define DEBUG_STATE(_v_)
virtual std::vector< std::string > abstractSyntaxTree() const =0
T sqrt(T t)
Definition: SSEVec.h:18
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
double evaluate(V const &iVariables, P const &iParameters) const
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
Definition: value.py:1
T min(T a, T b)
Definition: MathUtil.h:58
void throwWrongNumberOfParameters(size_t) const
static std::atomic< unsigned int > lastIndex
Definition: DDValue.cc:12
FormulaEvaluator(std::string const &iFormula)
std::vector< std::string > abstractSyntaxTree() const
fixed size matrix
void throwWrongNumberOfVariables(size_t) const
Power< A, B >::type pow(const A &a, const B &b)
Definition: Power.h:40
def move(src, dest)
Definition: eostools.py:511