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");
584 FunctionFinder::createEvaluator(std::string::const_iterator iBegin, std::string::const_iterator iEnd)
const {
587 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
588 k_erf, [](
double iArg)->
double {
return std::erf(iArg); } );
589 if(info.evaluator.get() !=
nullptr) {
593 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
594 k_TMath__Erf, [](
double iArg)->
double {
return std::erf(iArg); } );
595 if(info.evaluator.get() !=
nullptr) {
599 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
600 k_TMath__Landau, [](
double iArg)->
double {
return TMath::Landau(iArg); } );
601 if(info.evaluator.get() !=
nullptr) {
605 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
606 k_log, [](
double iArg)->
double {
return std::log(iArg); } );
607 if(info.evaluator.get() !=
nullptr) {
611 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
612 k_TMath__Log, [](
double iArg)->
double {
return std::log(iArg); } );
613 if(info.evaluator.get() !=
nullptr) {
617 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
618 k_log10, [](
double iArg)->
double {
return std::log(iArg)*kLog10Inv; } );
619 if(info.evaluator.get() !=
nullptr) {
623 info = checkForSingleArgFunction(iBegin, iEnd, m_expressionFinder,
624 k_exp, [](
double iArg)->
double {
return std::exp(iArg); } );
625 if(info.evaluator.get() !=
nullptr) {
629 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
630 k_pow, [](
double iArg1,
double iArg2)->
double {
return std::pow(iArg1,iArg2); } );
631 if(info.evaluator.get() !=
nullptr) {
635 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
636 k_TMath__Power, [](
double iArg1,
double iArg2)->
double {
return std::pow(iArg1,iArg2); } );
637 if(info.evaluator.get() !=
nullptr) {
641 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
642 k_max, [](
double iArg1,
double iArg2)->
double {
return std::max(iArg1,iArg2); } );
643 if(info.evaluator.get() !=
nullptr) {
647 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
648 k_min, [](
double iArg1,
double iArg2)->
double {
return std::min(iArg1,iArg2); } );
649 if(info.evaluator.get() !=
nullptr) {
653 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
654 k_TMath__Max, [](
double iArg1,
double iArg2)->
double {
return std::max(iArg1,iArg2); } );
655 if(info.evaluator.get() !=
nullptr) {
659 info = checkForTwoArgsFunction(iBegin, iEnd, m_expressionFinder,
660 k_TMath__Min, [](
double iArg1,
double iArg2)->
double {
return std::min(iArg1,iArg2); } );
661 if(info.evaluator.get() !=
nullptr) {
668 ExpressionFinder
const s_expressionFinder;
684 auto info = s_expressionFinder.createEvaluator(iFormula.begin(), iFormula.end(),std::shared_ptr<reco::formula::BinaryOperatorEvaluatorBase>());
686 if(info.nextParseIndex != static_cast<int>(iFormula.size())
or info.top.get() ==
nullptr) {
687 throw cms::Exception(
"FormulaEvaluatorParseError")<<
"While parsing '"<<iFormula<<
"' could not parse beyond '"<<
std::string(iFormula.begin(),iFormula.begin()+info.nextParseIndex) <<
"'";
690 m_nVariables = info.maxNumVariables;
691 m_nParameters = info.maxNumParameters;
700 return m_evaluator->evaluate(iVariables, iParameters);
705 throw cms::Exception(
"WrongNumVariables")<<
"FormulaEvaluator expected at least "<<m_nVariables<<
" but was passed only "<<iSize;
709 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
Power< A, B >::type pow(const A &a, const B &b)