36 struct EvaluatorInfo {
37 std::shared_ptr<reco::formula::EvaluatorBase> evaluator;
38 std::shared_ptr<reco::formula::EvaluatorBase> top;
40 unsigned int maxNumVariables=0;
41 unsigned int maxNumParameters=0;
44 class ExpressionElementFinderBase {
46 virtual bool checkStart(
char)
const = 0;
48 virtual EvaluatorInfo createEvaluator(std::string::const_iterator, std::string::const_iterator)
const = 0;
50 virtual ~ExpressionElementFinderBase() =
default;
53 std::string::const_iterator findMatchingParenthesis(std::string::const_iterator iBegin, std::string::const_iterator iEnd) {
62 for(
auto it = iBegin+1; it != iEnd; ++it) {
66 }
else if (*it ==
')') {
73 return iBegin +
index;
76 class ConstantFinder :
public ExpressionElementFinderBase {
77 bool checkStart(
char iSymbol)
const final {
78 if( iSymbol ==
'-' or iSymbol ==
'.' or std::isdigit(iSymbol) ) {
84 EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const final {
89 double value = stod(
s, &endIndex);
91 info.nextParseIndex = endIndex;
92 info.evaluator = std::make_shared<reco::formula::ConstantEvaluator>(
value);
93 info.top = info.evaluator;
94 }
catch ( std::invalid_argument ) {}
102 class ParameterFinder :
public ExpressionElementFinderBase {
103 bool checkStart(
char iSymbol)
const final {
104 if( iSymbol ==
'[') {
110 EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const final {
118 info.nextParseIndex = 1;
122 unsigned long value = stoul(
s, &endIndex);
124 if( iBegin+endIndex+1 == iEnd
or *(iBegin+1+endIndex) !=
']' ) {
129 info.nextParseIndex = endIndex+2;
130 info.maxNumParameters = value+1;
131 info.evaluator = std::make_shared<reco::formula::ParameterEvaluator>(
value);
132 info.top = info.evaluator;
133 }
catch ( std::invalid_argument ) {}
140 class VariableFinder :
public ExpressionElementFinderBase {
141 bool checkStart(
char iSymbol)
const final {
142 if( iSymbol ==
'x' or iSymbol ==
'y' or iSymbol ==
'z' or iSymbol ==
't' ) {
148 EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const final {
153 unsigned int index = 4;
167 info.nextParseIndex = 1;
168 info.maxNumVariables = index+1;
169 info.evaluator = std::make_shared<reco::formula::VariableEvaluator>(
index);
170 info.top = info.evaluator;
175 class ExpressionFinder;
177 class FunctionFinder :
public ExpressionElementFinderBase {
179 FunctionFinder(ExpressionFinder
const* iEF):
180 m_expressionFinder(iEF) {};
182 bool checkStart(
char iSymbol)
const final {
183 return std::isalpha(iSymbol);
186 EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const final;
189 ExpressionFinder
const* m_expressionFinder;
193 EvaluatorInfo createBinaryOperatorEvaluator( ExpressionFinder
const&,
194 std::string::const_iterator iBegin,
195 std::string::const_iterator iEnd) ;
197 class ExpressionFinder {
201 m_elements.reserve(4);
202 m_elements.emplace_back(
new FunctionFinder{
this});
203 m_elements.emplace_back(
new ConstantFinder{});
204 m_elements.emplace_back(
new ParameterFinder{});
205 m_elements.emplace_back(
new VariableFinder{});
208 bool checkStart(
char iChar)
const {
209 if (
'(' == iChar
or '-' == iChar
or '+' ==iChar) {
212 for(
auto const&
e : m_elements) {
213 if (
e->checkStart(iChar) ) {
220 EvaluatorInfo createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase> iPreviousBinary)
const {
221 EvaluatorInfo leftEvaluatorInfo ;
222 if( iBegin == iEnd) {
223 return leftEvaluatorInfo;
226 if (*iBegin ==
'+' and iEnd -iBegin > 1 and not std::isdigit( *(iBegin+1) ) ) {
227 leftEvaluatorInfo = createEvaluator(iBegin+1, iEnd, iPreviousBinary);
230 leftEvaluatorInfo.nextParseIndex +=1;
231 if(
nullptr == leftEvaluatorInfo.evaluator.get() ) {
232 return leftEvaluatorInfo;
236 else if (*iBegin ==
'-' and iEnd -iBegin > 1 and not std::isdigit( *(iBegin+1) ) ) {
237 leftEvaluatorInfo = createEvaluator(iBegin+1, iEnd,iPreviousBinary);
240 leftEvaluatorInfo.nextParseIndex +=1;
241 if(
nullptr == leftEvaluatorInfo.evaluator.get() ) {
242 return leftEvaluatorInfo;
244 leftEvaluatorInfo.evaluator = std::make_shared<reco::formula::UnaryMinusEvaluator>(
std::move(leftEvaluatorInfo.top));
245 leftEvaluatorInfo.top = leftEvaluatorInfo.evaluator;
248 else if( *iBegin ==
'(') {
249 auto endParenthesis = findMatchingParenthesis(iBegin,iEnd);
250 if(iBegin== endParenthesis) {
251 return leftEvaluatorInfo;
253 leftEvaluatorInfo = createEvaluator(iBegin+1,endParenthesis,std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
254 ++leftEvaluatorInfo.nextParseIndex;
255 if(leftEvaluatorInfo.evaluator.get() ==
nullptr) {
256 return leftEvaluatorInfo;
259 ++leftEvaluatorInfo.nextParseIndex;
260 leftEvaluatorInfo.top->setPrecedenceToParenthesis();
263 int maxParseDistance = 0;
264 for(
auto const&
e: m_elements) {
265 if(
e->checkStart(*iBegin) ) {
266 leftEvaluatorInfo =
e->createEvaluator(iBegin,iEnd);
267 if(leftEvaluatorInfo.evaluator !=
nullptr) {
270 if (leftEvaluatorInfo.nextParseIndex > maxParseDistance) {
271 maxParseDistance = leftEvaluatorInfo.nextParseIndex;
275 if(leftEvaluatorInfo.evaluator.get() ==
nullptr) {
277 leftEvaluatorInfo.nextParseIndex = maxParseDistance;
278 return leftEvaluatorInfo;
282 if(leftEvaluatorInfo.nextParseIndex == iEnd-iBegin) {
283 if (iPreviousBinary) {
284 iPreviousBinary->setRightEvaluator(leftEvaluatorInfo.top);
285 leftEvaluatorInfo.top = iPreviousBinary;
287 return leftEvaluatorInfo;
291 auto fullExpression = createBinaryOperatorEvaluator(*
this, iBegin+leftEvaluatorInfo.nextParseIndex, iEnd);
292 fullExpression.nextParseIndex +=leftEvaluatorInfo.nextParseIndex;
293 fullExpression.maxNumVariables =
std::max(leftEvaluatorInfo.maxNumVariables, fullExpression.maxNumVariables);
294 fullExpression.maxNumParameters =
std::max(leftEvaluatorInfo.maxNumParameters, fullExpression.maxNumParameters);
295 if (iBegin + fullExpression.nextParseIndex != iEnd) {
297 fullExpression.evaluator.reset();
300 if(fullExpression.evaluator ==
nullptr) {
302 return fullExpression;
306 auto topNode = fullExpression.top;
308 if (iPreviousBinary) {
309 if (iPreviousBinary->precedence() >= fullExpression.evaluator->precedence() ) {
311 binaryEval->setLeftEvaluator(iPreviousBinary);
313 binaryEval->setLeftEvaluator(leftEvaluatorInfo.evaluator);
314 if(iPreviousBinary->precedence()<topNode->precedence() ) {
315 topNode = iPreviousBinary;
316 iPreviousBinary->setRightEvaluator(fullExpression.top);
318 std::shared_ptr<reco::formula::EvaluatorBase> toSwap = iPreviousBinary;
321 iPreviousBinary->setRightEvaluator(toSwap);
325 binaryEval->setLeftEvaluator(leftEvaluatorInfo.top);
327 fullExpression.top = topNode;
328 return fullExpression;
332 std::vector<std::unique_ptr<ExpressionElementFinderBase>> m_elements;
336 template<
typename Op>
337 EvaluatorInfo createBinaryOperatorEvaluatorT(
int iSymbolLength,
339 ExpressionFinder
const& iEF,
340 std::string::const_iterator iBegin,
341 std::string::const_iterator iEnd) {
342 auto op = std::make_shared<reco::formula::BinaryOperatorEvaluator<Op> >(iPrec);
343 EvaluatorInfo evalInfo = iEF.createEvaluator(iBegin+iSymbolLength,iEnd,op);
344 evalInfo.nextParseIndex += iSymbolLength;
346 if(evalInfo.evaluator.get() ==
nullptr) {
350 evalInfo.evaluator = op;
355 double operator()(
double iLHS,
double iRHS)
const {
362 createBinaryOperatorEvaluator( ExpressionFinder
const& iEF,
363 std::string::const_iterator iBegin,
364 std::string::const_iterator iEnd) {
365 EvaluatorInfo evalInfo;
371 return createBinaryOperatorEvaluatorT<std::plus<double>>(1,
378 else if(*iBegin ==
'-') {
379 return createBinaryOperatorEvaluatorT<std::minus<double>>(1,
385 else if(*iBegin ==
'*') {
386 return createBinaryOperatorEvaluatorT<std::multiplies<double>>(1,
392 else if(*iBegin ==
'/') {
393 return createBinaryOperatorEvaluatorT<std::divides<double>>(1,
400 else if(*iBegin ==
'^') {
401 return createBinaryOperatorEvaluatorT<power>(1,
407 else if (*iBegin ==
'<' and iBegin+1 != iEnd and *(iBegin+1) ==
'=') {
408 return createBinaryOperatorEvaluatorT<std::less_equal<double>>(2,
415 else if (*iBegin ==
'>' and iBegin+1 != iEnd and *(iBegin+1) ==
'=') {
416 return createBinaryOperatorEvaluatorT<std::greater_equal<double>>(2,
423 else if (*iBegin ==
'<' ) {
424 return createBinaryOperatorEvaluatorT<std::less<double>>(1,
431 else if (*iBegin ==
'>' ) {
432 return createBinaryOperatorEvaluatorT<std::greater<double>>(1,
439 else if (*iBegin ==
'=' and iBegin+1 != iEnd and *(iBegin+1) ==
'=' ) {
440 return createBinaryOperatorEvaluatorT<std::equal_to<double>>(2,
447 else if (*iBegin ==
'!' and iBegin+1 != iEnd and *(iBegin+1) ==
'=' ) {
448 return createBinaryOperatorEvaluatorT<std::not_equal_to<double>>(2,
459 template<
typename Op>
461 checkForSingleArgFunction(std::string::const_iterator iBegin,
462 std::string::const_iterator iEnd,
463 ExpressionFinder
const* iExpressionFinder,
467 if(iName.size()+2 >
static_cast<unsigned int>(iEnd-iBegin) ) {
470 auto pos = iName.find(&(*iBegin), 0,iName.size());
472 if(std::string::npos ==
pos or *(iBegin+iName.size()) !=
'(') {
476 info.nextParseIndex = iName.size()+1;
478 auto itEndParen = findMatchingParenthesis(iBegin+iName.size(),iEnd);
479 if(iBegin+iName.size() == itEndParen) {
483 auto argEvaluatorInfo = iExpressionFinder->createEvaluator(iBegin+iName.size()+1, itEndParen,
484 std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
485 info.nextParseIndex += argEvaluatorInfo.nextParseIndex;
486 if(argEvaluatorInfo.evaluator.get() ==
nullptr or info.nextParseIndex+1 != 1+itEndParen - iBegin) {
490 ++info.nextParseIndex;
492 info.evaluator = std::make_shared<reco::formula::FunctionOneArgEvaluator>(
std::move(argEvaluatorInfo.top),
494 info.top = info.evaluator;
498 std::string::const_iterator findCommaNotInParenthesis(std::string::const_iterator iBegin,
499 std::string::const_iterator iEnd ) {
501 std::string::const_iterator it = iBegin;
502 for(; it != iEnd; ++it) {
505 }
else if(*it ==
')') {
508 else if( *it ==
',' and level == 0 ) {
517 template<
typename Op>
519 checkForTwoArgsFunction(std::string::const_iterator iBegin,
520 std::string::const_iterator iEnd,
521 ExpressionFinder
const* iExpressionFinder,
525 if(iName.size()+2 >
static_cast<unsigned int>(iEnd-iBegin) ) {
528 auto pos = iName.find(&(*iBegin), 0,iName.size());
530 if(std::string::npos ==
pos or *(iBegin+iName.size()) !=
'(') {
534 info.nextParseIndex = iName.size()+1;
536 auto itEndParen = findMatchingParenthesis(iBegin+iName.size(),iEnd);
537 if(iBegin+iName.size() == itEndParen) {
541 auto itComma = findCommaNotInParenthesis(iBegin+iName.size()+1, itEndParen);
543 auto arg1EvaluatorInfo = iExpressionFinder->createEvaluator(iBegin+iName.size()+1, itComma, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
544 info.nextParseIndex += arg1EvaluatorInfo.nextParseIndex;
545 if(arg1EvaluatorInfo.evaluator.get() ==
nullptr or info.nextParseIndex != itComma-iBegin ) {
549 ++info.nextParseIndex;
551 auto arg2EvaluatorInfo = iExpressionFinder->createEvaluator(itComma+1, itEndParen, std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
552 info.nextParseIndex += arg2EvaluatorInfo.nextParseIndex;
554 if(arg2EvaluatorInfo.evaluator.get() ==
nullptr or info.nextParseIndex+1 != 1+itEndParen - iBegin) {
558 ++info.nextParseIndex;
560 info.evaluator = std::make_shared<reco::formula::FunctionTwoArgsEvaluator>(
std::move(arg1EvaluatorInfo.top),
563 info.top = info.evaluator;
570 double const kLog10Inv = 1./
std::log(10.);
580 const std::string k_TMath__Landau(
"TMath::Landau");
588 FunctionFinder::createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const {
591 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
592 k_erf, [](
double iArg)->
double {
return std::erf(iArg); } );
593 if(info.evaluator.get() !=
nullptr) {
597 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
598 k_TMath__Erf, [](
double iArg)->
double {
return std::erf(iArg); } );
599 if(info.evaluator.get() !=
nullptr) {
603 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
604 k_TMath__Landau, [](
double iArg)->
double {
return TMath::Landau(iArg); } );
605 if(info.evaluator.get() !=
nullptr) {
609 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
610 k_log, [](
double iArg)->
double {
return std::log(iArg); } );
611 if(info.evaluator.get() !=
nullptr) {
615 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
616 k_TMath__Log, [](
double iArg)->
double {
return std::log(iArg); } );
617 if(info.evaluator.get() !=
nullptr) {
621 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
622 k_log10, [](
double iArg)->
double {
return std::log(iArg)*kLog10Inv; } );
623 if(info.evaluator.get() !=
nullptr) {
627 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
628 k_exp, [](
double iArg)->
double {
return std::exp(iArg); } );
629 if(info.evaluator.get() !=
nullptr) {
633 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
634 k_sqrt, [](
double iArg)->
double {
return std::sqrt(iArg); } );
635 if(info.evaluator.get() !=
nullptr) {
639 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
640 k_TMath__Sqrt, [](
double iArg)->
double {
return std::sqrt(iArg); } );
641 if(info.evaluator.get() !=
nullptr) {
645 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
646 k_abs, [](
double iArg)->
double {
return std::abs(iArg); } );
647 if(info.evaluator.get() !=
nullptr) {
651 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
652 k_TMath__Abs, [](
double iArg)->
double {
return std::abs(iArg); } );
653 if(info.evaluator.get() !=
nullptr) {
657 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
658 k_pow, [](
double iArg1,
double iArg2)->
double {
return std::pow(iArg1,iArg2); } );
659 if(info.evaluator.get() !=
nullptr) {
663 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
664 k_TMath__Power, [](
double iArg1,
double iArg2)->
double {
return std::pow(iArg1,iArg2); } );
665 if(info.evaluator.get() !=
nullptr) {
669 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
670 k_max, [](
double iArg1,
double iArg2)->
double {
return std::max(iArg1,iArg2); } );
671 if(info.evaluator.get() !=
nullptr) {
675 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
676 k_min, [](
double iArg1,
double iArg2)->
double {
return std::min(iArg1,iArg2); } );
677 if(info.evaluator.get() !=
nullptr) {
681 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
682 k_TMath__Max, [](
double iArg1,
double iArg2)->
double {
return std::max(iArg1,iArg2); } );
683 if(info.evaluator.get() !=
nullptr) {
687 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
688 k_TMath__Min, [](
double iArg1,
double iArg2)->
double {
return std::min(iArg1,iArg2); } );
689 if(info.evaluator.get() !=
nullptr) {
696 ExpressionFinder
const s_expressionFinder;
712 auto info = s_expressionFinder.createEvaluator(iFormula.begin(), iFormula.end(),std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
714 if(info.nextParseIndex != static_cast<int>(iFormula.size())
or info.top.get() ==
nullptr) {
715 throw cms::Exception(
"FormulaEvaluatorParseError")<<
"While parsing '"<<iFormula<<
"' could not parse beyond '"<<
std::string(iFormula.begin(),iFormula.begin()+info.nextParseIndex) <<
"'";
718 m_nVariables = info.maxNumVariables;
719 m_nParameters = info.maxNumParameters;
728 return m_evaluator->evaluate(iVariables, iParameters);
733 throw cms::Exception(
"WrongNumVariables")<<
"FormulaEvaluator expected at least "<<m_nVariables<<
" but was passed only "<<iSize;
737 throw cms::Exception(
"WrongNumParameters")<<
"FormulaEvaluator expected at least "<<m_nParameters<<
" 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::EventID const &, edm::Timestamp const & > We also list in braces which AR_WATCH_USING_METHOD_ is used for those or
Abs< T >::type abs(const T &t)
Power< A, B >::type pow(const A &a, const B &b)