35 struct EvaluatorInfo {
36 std::shared_ptr<reco::formula::EvaluatorBase> evaluator;
37 std::shared_ptr<reco::formula::EvaluatorBase> top;
39 unsigned int maxNumVariables=0;
40 unsigned int maxNumParameters=0;
43 class ExpressionElementFinderBase {
45 virtual bool checkStart(
char)
const = 0;
47 virtual EvaluatorInfo createEvaluator(std::string::const_iterator, std::string::const_iterator)
const = 0;
50 std::string::const_iterator findMatchingParenthesis(std::string::const_iterator iBegin, std::string::const_iterator iEnd) {
59 for(
auto it = iBegin+1; it != iEnd; ++it) {
63 }
else if (*it ==
')') {
70 return iBegin +
index;
73 class ConstantFinder :
public ExpressionElementFinderBase {
74 virtual bool checkStart(
char iSymbol)
const override final {
75 if( iSymbol ==
'-' or iSymbol ==
'.' or std::isdigit(iSymbol) ) {
81 virtual EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const override final {
86 double value = stod(
s, &endIndex);
88 info.nextParseIndex = endIndex;
89 info.evaluator = std::make_shared<reco::formula::ConstantEvaluator>(
value);
90 info.top = info.evaluator;
91 }
catch ( std::invalid_argument ) {}
99 class ParameterFinder :
public ExpressionElementFinderBase {
100 virtual bool checkStart(
char iSymbol)
const override final {
101 if( iSymbol ==
'[') {
107 virtual EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const override final {
115 info.nextParseIndex = 1;
119 unsigned long value = stoul(
s, &endIndex);
121 if( iBegin+endIndex+1 == iEnd
or *(iBegin+1+endIndex) !=
']' ) {
126 info.nextParseIndex = endIndex+2;
127 info.maxNumParameters = value+1;
128 info.evaluator = std::make_shared<reco::formula::ParameterEvaluator>(
value);
129 info.top = info.evaluator;
130 }
catch ( std::invalid_argument ) {}
137 class VariableFinder :
public ExpressionElementFinderBase {
138 virtual bool checkStart(
char iSymbol)
const override final {
139 if( iSymbol ==
'x' or iSymbol ==
'y' or iSymbol ==
'z' or iSymbol ==
't' ) {
145 virtual EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const override final {
150 unsigned int index = 4;
164 info.nextParseIndex = 1;
165 info.maxNumVariables = index+1;
166 info.evaluator = std::make_shared<reco::formula::VariableEvaluator>(
index);
167 info.top = info.evaluator;
172 class ExpressionFinder;
174 class FunctionFinder :
public ExpressionElementFinderBase {
176 FunctionFinder(ExpressionFinder
const* iEF):
177 m_expressionFinder(iEF) {};
179 virtual bool checkStart(
char iSymbol)
const override final {
180 return std::isalpha(iSymbol);
183 virtual EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const override final;
186 ExpressionFinder
const* m_expressionFinder;
190 EvaluatorInfo createBinaryOperatorEvaluator( ExpressionFinder
const&,
191 std::string::const_iterator iBegin,
192 std::string::const_iterator iEnd) ;
194 class ExpressionFinder {
198 m_elements.reserve(4);
199 m_elements.emplace_back(
new FunctionFinder{
this});
200 m_elements.emplace_back(
new ConstantFinder{});
201 m_elements.emplace_back(
new ParameterFinder{});
202 m_elements.emplace_back(
new VariableFinder{});
205 bool checkStart(
char iChar)
const {
206 if (
'(' == iChar
or '-' == iChar
or '+' ==iChar) {
209 for(
auto const&
e : m_elements) {
210 if (
e->checkStart(iChar) ) {
217 EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase> iPreviousBinary)
const {
218 EvaluatorInfo leftEvaluatorInfo ;
219 if( iBegin == iEnd) {
220 return leftEvaluatorInfo;
223 if (*iBegin ==
'+' and iEnd -iBegin > 1 and not std::isdigit( *(iBegin+1) ) ) {
224 leftEvaluatorInfo = createEvaluator(iBegin+1, iEnd, iPreviousBinary);
227 leftEvaluatorInfo.nextParseIndex +=1;
228 if(
nullptr == leftEvaluatorInfo.evaluator.get() ) {
229 return leftEvaluatorInfo;
233 else if (*iBegin ==
'-' and iEnd -iBegin > 1 and not std::isdigit( *(iBegin+1) ) ) {
234 leftEvaluatorInfo = createEvaluator(iBegin+1, iEnd,iPreviousBinary);
237 leftEvaluatorInfo.nextParseIndex +=1;
238 if(
nullptr == leftEvaluatorInfo.evaluator.get() ) {
239 return leftEvaluatorInfo;
241 leftEvaluatorInfo.evaluator = std::make_shared<reco::formula::UnaryMinusEvaluator>(
std::move(leftEvaluatorInfo.evaluator));
242 leftEvaluatorInfo.top = leftEvaluatorInfo.evaluator;
245 else if( *iBegin ==
'(') {
246 auto endParenthesis = findMatchingParenthesis(iBegin,iEnd);
247 if(iBegin== endParenthesis) {
248 return leftEvaluatorInfo;
250 leftEvaluatorInfo = createEvaluator(iBegin+1,endParenthesis,std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
251 ++leftEvaluatorInfo.nextParseIndex;
252 if(leftEvaluatorInfo.evaluator.get() ==
nullptr) {
253 return leftEvaluatorInfo;
256 ++leftEvaluatorInfo.nextParseIndex;
257 leftEvaluatorInfo.evaluator->setPrecedenceToParenthesis();
260 int maxParseDistance = 0;
261 for(
auto const&
e: m_elements) {
262 if(
e->checkStart(*iBegin) ) {
263 leftEvaluatorInfo =
e->createEvaluator(iBegin,iEnd);
264 if(leftEvaluatorInfo.evaluator !=
nullptr) {
267 if (leftEvaluatorInfo.nextParseIndex > maxParseDistance) {
268 maxParseDistance = leftEvaluatorInfo.nextParseIndex;
272 if(leftEvaluatorInfo.evaluator.get() ==
nullptr) {
274 leftEvaluatorInfo.nextParseIndex = maxParseDistance;
275 return leftEvaluatorInfo;
279 if(leftEvaluatorInfo.nextParseIndex == iEnd-iBegin) {
280 if (iPreviousBinary) {
281 iPreviousBinary->setRightEvaluator(leftEvaluatorInfo.top);
282 leftEvaluatorInfo.top = iPreviousBinary;
284 return leftEvaluatorInfo;
288 auto fullExpression = createBinaryOperatorEvaluator(*
this, iBegin+leftEvaluatorInfo.nextParseIndex, iEnd);
289 fullExpression.nextParseIndex +=leftEvaluatorInfo.nextParseIndex;
290 fullExpression.maxNumVariables =
std::max(leftEvaluatorInfo.maxNumVariables, fullExpression.maxNumVariables);
291 fullExpression.maxNumParameters =
std::max(leftEvaluatorInfo.maxNumParameters, fullExpression.maxNumParameters);
292 if (iBegin + fullExpression.nextParseIndex != iEnd) {
294 fullExpression.evaluator.reset();
298 auto topNode = fullExpression.top;
300 if (iPreviousBinary) {
301 if (iPreviousBinary->precedence() >= fullExpression.evaluator->precedence() ) {
303 binaryEval->setLeftEvaluator(iPreviousBinary);
305 binaryEval->setLeftEvaluator(leftEvaluatorInfo.evaluator);
306 if(iPreviousBinary->precedence()<topNode->precedence() ) {
307 topNode = iPreviousBinary;
308 iPreviousBinary->setRightEvaluator(fullExpression.top);
310 std::shared_ptr<reco::formula::EvaluatorBase> toSwap = iPreviousBinary;
313 iPreviousBinary->setRightEvaluator(toSwap);
317 binaryEval->setLeftEvaluator(leftEvaluatorInfo.evaluator);
318 if (topNode->precedence() > binaryEval->precedence()) {
319 topNode = fullExpression.evaluator;
322 fullExpression.top = topNode;
323 return fullExpression;
327 std::vector<std::unique_ptr<ExpressionElementFinderBase>> m_elements;
331 template<
typename Op>
332 EvaluatorInfo createBinaryOperatorEvaluatorT(
int iSymbolLength,
334 ExpressionFinder
const& iEF,
335 std::string::const_iterator iBegin,
336 std::string::const_iterator iEnd) {
337 auto op = std::make_shared<reco::formula::BinaryOperatorEvaluator<Op> >(iPrec);
338 EvaluatorInfo evalInfo = iEF.createEvaluator(iBegin+iSymbolLength,iEnd,op);
339 evalInfo.nextParseIndex += iSymbolLength;
341 if(evalInfo.evaluator.get() ==
nullptr) {
345 evalInfo.evaluator = op;
350 double operator()(
double iLHS,
double iRHS)
const {
357 createBinaryOperatorEvaluator( ExpressionFinder
const& iEF,
358 std::string::const_iterator iBegin,
359 std::string::const_iterator iEnd) {
360 EvaluatorInfo evalInfo;
366 return createBinaryOperatorEvaluatorT<std::plus<double>>(1,
373 else if(*iBegin ==
'-') {
374 return createBinaryOperatorEvaluatorT<std::minus<double>>(1,
380 else if(*iBegin ==
'*') {
381 return createBinaryOperatorEvaluatorT<std::multiplies<double>>(1,
387 else if(*iBegin ==
'/') {
388 return createBinaryOperatorEvaluatorT<std::divides<double>>(1,
395 else if(*iBegin ==
'^') {
396 return createBinaryOperatorEvaluatorT<power>(1,
402 else if (*iBegin ==
'<' and iBegin+1 != iEnd and *(iBegin+1) ==
'=') {
403 return createBinaryOperatorEvaluatorT<std::less_equal<double>>(2,
410 else if (*iBegin ==
'>' and iBegin+1 != iEnd and *(iBegin+1) ==
'=') {
411 return createBinaryOperatorEvaluatorT<std::greater_equal<double>>(2,
418 else if (*iBegin ==
'<' ) {
419 return createBinaryOperatorEvaluatorT<std::less<double>>(1,
426 else if (*iBegin ==
'>' ) {
427 return createBinaryOperatorEvaluatorT<std::greater<double>>(1,
434 else if (*iBegin ==
'=' and iBegin+1 != iEnd and *(iBegin+1) ==
'=' ) {
435 return createBinaryOperatorEvaluatorT<std::equal_to<double>>(2,
442 else if (*iBegin ==
'!' and iBegin+1 != iEnd and *(iBegin+1) ==
'=' ) {
443 return createBinaryOperatorEvaluatorT<std::not_equal_to<double>>(2,
454 template<
typename Op>
456 checkForSingleArgFunction(std::string::const_iterator iBegin,
457 std::string::const_iterator iEnd,
458 ExpressionFinder
const* iExpressionFinder,
462 if(iName.size()+2 >
static_cast<unsigned int>(iEnd-iBegin) ) {
465 auto pos = iName.find(&(*iBegin), 0,iName.size());
467 if(std::string::npos == pos
or *(iBegin+iName.size()) !=
'(') {
471 info.nextParseIndex = iName.size()+1;
473 auto itEndParen = findMatchingParenthesis(iBegin+iName.size(),iEnd);
474 if(iBegin+iName.size() == itEndParen) {
478 auto argEvaluatorInfo = iExpressionFinder->createEvaluator(iBegin+iName.size()+1, itEndParen,
479 std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
480 info.nextParseIndex += argEvaluatorInfo.nextParseIndex;
481 if(argEvaluatorInfo.evaluator.get() ==
nullptr or info.nextParseIndex+1 != 1+itEndParen - iBegin) {
485 ++info.nextParseIndex;
487 info.evaluator = std::make_shared<reco::formula::FunctionOneArgEvaluator>(
std::move(argEvaluatorInfo.evaluator),
489 info.top = info.evaluator;
493 std::string::const_iterator findCommaNotInParenthesis(std::string::const_iterator iBegin,
494 std::string::const_iterator iEnd ) {
496 std::string::const_iterator it = iBegin;
497 for(; it != iEnd; ++it) {
500 }
else if(*it ==
')') {
503 else if( *it ==
',' and level == 0 ) {
512 template<
typename Op>
514 checkForTwoArgsFunction(std::string::const_iterator iBegin,
515 std::string::const_iterator iEnd,
516 ExpressionFinder
const* iExpressionFinder,
520 if(iName.size()+2 >
static_cast<unsigned int>(iEnd-iBegin) ) {
523 auto pos = iName.find(&(*iBegin), 0,iName.size());
525 if(std::string::npos == pos
or *(iBegin+iName.size()) !=
'(') {
529 info.nextParseIndex = iName.size()+1;
531 auto itEndParen = findMatchingParenthesis(iBegin+iName.size(),iEnd);
532 if(iBegin+iName.size() == itEndParen) {
536 auto itComma = findCommaNotInParenthesis(iBegin+iName.size()+1, itEndParen);
538 auto arg1EvaluatorInfo = iExpressionFinder->createEvaluator(iBegin+iName.size()+1, itComma, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
539 info.nextParseIndex += arg1EvaluatorInfo.nextParseIndex;
540 if(arg1EvaluatorInfo.evaluator.get() ==
nullptr or info.nextParseIndex != itComma-iBegin ) {
544 ++info.nextParseIndex;
546 auto arg2EvaluatorInfo = iExpressionFinder->createEvaluator(itComma+1, itEndParen, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
547 info.nextParseIndex += arg2EvaluatorInfo.nextParseIndex;
549 if(arg2EvaluatorInfo.evaluator.get() ==
nullptr or info.nextParseIndex+1 != 1+itEndParen - iBegin) {
553 ++info.nextParseIndex;
555 info.evaluator = std::make_shared<reco::formula::FunctionTwoArgsEvaluator>(
std::move(arg1EvaluatorInfo.evaluator),
558 info.top = info.evaluator;
564 static const std::string k_TMath__Log(
"TMath::Log");
565 double const kLog10Inv = 1./
std::log(10.);
568 static const std::string k_TMath__Power(
"TMath::Power");
571 static const std::string k_TMath__Max(
"TMath::Max");
572 static const std::string k_TMath__Min(
"TMath::Min");
576 FunctionFinder::createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const {
579 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
580 k_log, [](
double iArg)->
double {
return std::log(iArg); } );
581 if(info.evaluator.get() !=
nullptr) {
585 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
586 k_TMath__Log, [](
double iArg)->
double {
return std::log(iArg); } );
587 if(info.evaluator.get() !=
nullptr) {
591 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
592 k_log10, [](
double iArg)->
double {
return std::log(iArg)*kLog10Inv; } );
593 if(info.evaluator.get() !=
nullptr) {
597 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
598 k_exp, [](
double iArg)->
double {
return std::exp(iArg); } );
599 if(info.evaluator.get() !=
nullptr) {
603 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
604 k_pow, [](
double iArg1,
double iArg2)->
double {
return std::pow(iArg1,iArg2); } );
605 if(info.evaluator.get() !=
nullptr) {
609 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
610 k_TMath__Power, [](
double iArg1,
double iArg2)->
double {
return std::pow(iArg1,iArg2); } );
611 if(info.evaluator.get() !=
nullptr) {
615 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
616 k_max, [](
double iArg1,
double iArg2)->
double {
return std::max(iArg1,iArg2); } );
617 if(info.evaluator.get() !=
nullptr) {
621 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
622 k_min, [](
double iArg1,
double iArg2)->
double {
return std::min(iArg1,iArg2); } );
623 if(info.evaluator.get() !=
nullptr) {
627 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
628 k_TMath__Max, [](
double iArg1,
double iArg2)->
double {
return std::max(iArg1,iArg2); } );
629 if(info.evaluator.get() !=
nullptr) {
633 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
634 k_TMath__Min, [](
double iArg1,
double iArg2)->
double {
return std::min(iArg1,iArg2); } );
635 if(info.evaluator.get() !=
nullptr) {
642 static ExpressionFinder
const s_expressionFinder;
658 auto info = s_expressionFinder.createEvaluator(iFormula.begin(), iFormula.end(),std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
660 if(info.nextParseIndex != static_cast<int>(iFormula.size())
or info.top.get() ==
nullptr) {
661 throw cms::Exception(
"FormulaEvaluatorParseError")<<
"While parsing '"<<iFormula<<
"' could not parse beyond '"<<
std::string(iFormula.begin(),iFormula.begin()+info.nextParseIndex) <<
"'";
674 return m_evaluator->evaluate(iVariables, iParameters);
679 throw cms::Exception(
"WrongNumVariables")<<
"FormulaEvaluator expected at least "<<
m_nVariables<<
" but was passed only "<<iSize;
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::EventIDconst &, edm::Timestampconst & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Power< A, B >::type pow(const A &a, const B &b)