From 084292ab638923f9260d3a9f813227ada0728565 Mon Sep 17 00:00:00 2001 From: moneta <lorenzo.moneta@cern.ch> Date: Mon, 15 Jun 2020 10:46:09 +0200 Subject: [PATCH] Fix in TFormula the parsing of user defined functions which contain pre-defined functions (e.g. gaus) in their name. Fixes ROOT-10815. For example when a user defines a function with the name "f1gaus" and then reuses that name could cause in same case an error parsing the expression. Example : ``` TF1 f1("f1gaus","gaus"); TF1 f2("f2gaus","f1gaus+gaus(3)"); ``` If the function name is for example "fgaus" it was working before, but not if a character number is used before the pre-defined function name such as "f1gaus". Add also a test for parsing these cases in TFormulaParsingTest. This commit fixes ROOT-10815 --- hist/hist/src/TFormula.cxx | 5 +++-- test/TFormulaParsingTests.h | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/hist/hist/src/TFormula.cxx b/hist/hist/src/TFormula.cxx index 05e1dfaf471..64ae71e82b2 100644 --- a/hist/hist/src/TFormula.cxx +++ b/hist/hist/src/TFormula.cxx @@ -1101,13 +1101,14 @@ void TFormula::HandleParametrizedFunctions(TString &formula) // should also check that function is not something else (e.g. exponential - parse the expo) Int_t lastFunPos = funPos + funName.Length(); - // check that first and last character is not alphanumeric + // check that first and last character is not a special character Int_t iposBefore = funPos - 1; // std::cout << "looping on funpos is " << funPos << " formula is " << formula << " function " << funName << // std::endl; if (iposBefore >= 0) { assert(iposBefore < formula.Length()); - if (isalpha(formula[iposBefore])) { + //if (isalpha(formula[iposBefore])) { + if (IsFunctionNameChar(formula[iposBefore])) { // std::cout << "previous character for function " << funName << " is " << formula[iposBefore] << "- skip // " << std::endl; funPos = formula.Index(funName, lastFunPos); diff --git a/test/TFormulaParsingTests.h b/test/TFormulaParsingTests.h index 93915b15800..b462256df27 100644 --- a/test/TFormulaParsingTests.h +++ b/test/TFormulaParsingTests.h @@ -1017,6 +1017,37 @@ bool test51() { return ok; } +bool test52() { + // test for bug 10815 + // mixing user previous defined functions (available in gROOT) + // and pre-defined functions + bool ok = true; + TF1 f1("f1gaus","[0]*gaus(1)",-10,10); + TF1 f2("f2","[0]*f1gaus",-10,10); + f1.SetParameters(2,3,1,2); + f2.SetParameters(3,2,3,1,2); + ok &= TMath::AreEqualAbs( f1.Eval(1), 2.*3.*TMath::Gaus(1,1,2), 1.E-10); + if (!ok) Error("test52","Error testing f1"); + bool ret = TMath::AreEqualAbs( f2.Eval(1), 3.*2.*3.*TMath::Gaus(1,1,2), 1.E-10); + if (!ret) Error("test52","Error testing f2"); + ok &= ret; + TF1 f3("f3","f1gaus*gaus(4)",-10,10); + f3.SetParameters(2,3,1,2,3,2,3); + ret = TMath::AreEqualAbs( f3.Eval(1), 2.*3.*TMath::Gaus(1,1,2) * 3. * TMath::Gaus(1,2,3), 1.E-10); + if (!ret) Error("test52","Error testing f3"); + ok &= ret; + // check also after + TF1 f4("gaus2a","[0]*gaus(1)",-10,10); + TF1 f5("f2","[0]*gaus2a",-10,10); + f4.SetParameters(2,3,1,2); + f5.SetParameters(3,2,3,1,2); + ret = TMath::AreEqualAbs( f5.Eval(1), 3.*f4.Eval(1),1.E-10); + if (!ret) Error("test52","Error testing f4 & f5"); + return ok; + +} + + /////////////////////////////////////////////////////////////////////////////////////// void PrintError(int itest) { @@ -1087,6 +1118,7 @@ int runTests(bool debug = false) { IncrTest(itest); if (!test49() ) { PrintError(itest); } IncrTest(itest); if (!test50() ) { PrintError(itest); } IncrTest(itest); if (!test51() ) { PrintError(itest); } + IncrTest(itest); if (!test52() ) { PrintError(itest); } std::cout << ".\n"; -- GitLab