27 #include <unordered_map>
33 #pragma optimize("",off)
208 static const TString gNamePrefix =
"TFormula__";
212 static std::unordered_map<std::string, void *> gClingFunctions = std::unordered_map<std::string, void * >();
214 static void R__v5TFormulaUpdater(Int_t nobjects, TObject **from, TObject **to)
216 auto **fromv5 = (ROOT::v5::TFormula **)from;
217 auto **target = (TFormula **)to;
219 for (
int i = 0; i < nobjects; ++i) {
220 if (fromv5[i] && target[i]) {
221 TFormula fnew(fromv5[i]->GetName(), fromv5[i]->GetExpFormula());
223 target[i]->SetParameters(fromv5[i]->GetParameters());
228 using TFormulaUpdater_t = void (*)(Int_t nobjects, TObject **from, TObject **to);
229 bool R__SetClonesArrayTFormulaUpdater(TFormulaUpdater_t func);
231 int R__RegisterTFormulaUpdaterTrigger = R__SetClonesArrayTFormulaUpdater(R__v5TFormulaUpdater);
234 Bool_t TFormula::IsOperator(
const char c)
237 const static std::set<char> ops {
'+',
'^',
'-',
'/',
'*',
'<',
'>',
'|',
'&',
'!',
'=',
'?',
'%'};
238 return ops.end() != ops.find(c);
242 Bool_t TFormula::IsBracket(
const char c)
245 char brackets[] = {
')',
'(',
'{',
'}'};
246 Int_t bracketsLen =
sizeof(brackets)/
sizeof(
char);
247 for(Int_t i = 0; i < bracketsLen; ++i)
254 Bool_t TFormula::IsFunctionNameChar(
const char c)
256 return !IsBracket(c) && !IsOperator(c) && c !=
',' && c !=
' ';
260 Bool_t TFormula::IsDefaultVariableName(
const TString &name)
262 return name ==
"x" || name ==
"z" || name ==
"y" || name ==
"t";
266 Bool_t TFormula::IsScientificNotation(
const TString & formula,
int i)
269 if ( (formula[i] ==
'e' || formula[i] ==
'E') && (i > 0 && i < formula.Length()-1) ) {
271 if ( (isdigit(formula[i-1]) || formula[i-1] ==
'.') && ( isdigit(formula[i+1]) || formula[i+1] ==
'+' || formula[i+1] ==
'-' ) )
278 Bool_t TFormula::IsHexadecimal(
const TString & formula,
int i)
281 if ( (formula[i] ==
'x' || formula[i] ==
'X') && (i > 0 && i < formula.Length()-1) && formula[i-1] ==
'0') {
282 if (isdigit(formula[i+1]) )
284 static char hex_values[12] = {
'a',
'A',
'b',
'B',
'c',
'C',
'd',
'D',
'e',
'E',
'f',
'F'};
285 for (
int jjj = 0; jjj < 12; ++jjj) {
286 if (formula[i+1] == hex_values[jjj])
301 Bool_t TFormula::IsAParameterName(
const TString & formula,
int pos) {
303 Bool_t foundOpenParenthesis =
false;
304 if (pos == 0 || pos == formula.Length()-1)
return false;
305 for (
int i = pos-1; i >=0; i--) {
306 if (formula[i] ==
']' )
return false;
307 if (formula[i] ==
'[' ) {
308 foundOpenParenthesis =
true;
312 if (!foundOpenParenthesis )
return false;
315 for (
int i = pos+1; i < formula.Length(); i++) {
316 if (formula[i] ==
']' )
return true;
323 bool TFormulaParamOrder::operator() (
const TString& a,
const TString& b)
const {
329 TRegexp numericPattern(
"p?[0-9]+");
332 int patternStart = numericPattern.Index(a, &len);
333 bool aNumeric = (patternStart == 0 && len == a.Length());
335 patternStart = numericPattern.Index(b, &len);
336 bool bNumeric = (patternStart == 0 && len == b.Length());
338 if (aNumeric && !bNumeric)
340 else if (!aNumeric && bNumeric)
342 else if (!aNumeric && !bNumeric)
345 int aInt = (a[0] ==
'p') ? TString(a(1, a.Length())).Atoi() : a.Atoi();
346 int bInt = (b[0] ==
'p') ? TString(b(1, b.Length())).Atoi() : b.Atoi();
353 void TFormula::ReplaceAllNames(TString &formula, map<TString, TString> &substitutions)
357 for (
int i = 0; i < formula.Length(); i++) {
360 if (isalpha(formula[i]) || formula[i] ==
'{' || formula[i] ==
'[') {
363 j < formula.Length() && (IsFunctionNameChar(formula[j])
364 || (formula[i] ==
'{' && formula[j] ==
'}'));
367 TString name = (TString)formula(i, j - i);
372 if (substitutions.find(name) != substitutions.end()) {
373 formula.Replace(i, name.Length(),
"(" + substitutions[name] +
")");
374 i += substitutions[name].Length() + 2 - 1;
376 }
else if (isalpha(formula[i])) {
379 i += name.Length() - 1;
391 fReadyToExecute =
false;
392 fClingInitialized =
false;
393 fAllParametersSetted =
false;
400 fLambdaPtr =
nullptr;
404 static bool IsReservedName(
const char* name){
405 if (strlen(name)!=1)
return false;
406 for (
auto const & specialName : {
"x",
"y",
"z",
"t"}){
407 if (strcmp(name,specialName)==0)
return true;
413 TFormula::~TFormula()
418 if (!TestBit(TFormula::kNotGlobal) && gROOT ) {
419 R__LOCKGUARD(gROOTMutex);
420 gROOT->GetListOfFunctions()->Remove(
this);
426 int nLinParts = fLinearParts.size();
428 for (
int i = 0; i < nLinParts; ++i)
delete fLinearParts[i];
433 TFormula::TFormula(
const char *name,
const char *formula,
bool addToGlobList,
bool vectorize) :
434 TNamed(name,formula),
435 fClingInput(formula),fFormula(formula)
437 fReadyToExecute =
false;
438 fClingInitialized =
false;
444 fLambdaPtr =
nullptr;
445 fVectorized = vectorize;
446 #ifndef R__HAS_VECCORE
453 if (addToGlobList && gROOT) {
455 R__LOCKGUARD(gROOTMutex);
456 old =
dynamic_cast<TFormula*
> ( gROOT->GetListOfFunctions()->FindObject(name) );
458 gROOT->GetListOfFunctions()->Remove(old);
459 if (IsReservedName(name))
460 Error(
"TFormula",
"The name %s is reserved as a TFormula variable name.\n",name);
462 gROOT->GetListOfFunctions()->Add(
this);
464 SetBit(kNotGlobal,!addToGlobList);
469 if (!fFormula.IsNull() ) {
470 PreProcessFormula(fFormula);
472 PrepareFormula(fFormula);
480 TFormula::TFormula(
const char *name,
const char *formula,
int ndim,
int npar,
bool addToGlobList) :
481 TNamed(name,formula),
482 fClingInput(formula),fFormula(formula)
484 fReadyToExecute =
false;
485 fClingInitialized =
false;
489 fLambdaPtr =
nullptr;
491 fGradFuncPtr =
nullptr;
495 for (
int i = 0; i < npar; ++i) {
496 DoAddParameter(TString::Format(
"p%d",i), 0,
false);
498 fAllParametersSetted =
true;
499 assert (fNpar == npar);
501 bool ret = InitLambdaExpression(formula);
505 SetBit(TFormula::kLambda);
507 fReadyToExecute =
true;
509 if (addToGlobList && gROOT) {
511 R__LOCKGUARD(gROOTMutex);
512 old =
dynamic_cast<TFormula*
> ( gROOT->GetListOfFunctions()->FindObject(name) );
514 gROOT->GetListOfFunctions()->Remove(old);
515 if (IsReservedName(name))
516 Error(
"TFormula",
"The name %s is reserved as a TFormula variable name.\n",name);
518 gROOT->GetListOfFunctions()->Add(
this);
520 SetBit(kNotGlobal,!addToGlobList);
523 Error(
"TFormula",
"Syntax error in building the lambda expression %s", formula );
527 TFormula::TFormula(
const TFormula &formula) :
528 TNamed(formula.GetName(),formula.GetTitle()), fMethod(nullptr)
532 if (!TestBit(TFormula::kNotGlobal) && gROOT ) {
533 R__LOCKGUARD(gROOTMutex);
534 TFormula *old = (TFormula*)gROOT->GetListOfFunctions()->FindObject(formula.GetName());
536 gROOT->GetListOfFunctions()->Remove(old);
538 if (IsReservedName(formula.GetName())) {
539 Error(
"TFormula",
"The name %s is reserved as a TFormula variable name.\n",formula.GetName());
541 gROOT->GetListOfFunctions()->Add(
this);
549 TFormula& TFormula::operator=(
const TFormula &rhs)
559 Bool_t TFormula::InitLambdaExpression(
const char * formula) {
561 std::string lambdaExpression = formula;
565 R__LOCKGUARD(gROOTMutex);
567 auto funcit = gClingFunctions.find(lambdaExpression);
568 if (funcit != gClingFunctions.end() ) {
569 fLambdaPtr = funcit->second;
570 fClingInitialized =
true;
577 R__ASSERT(gInterpreter);
580 auto hasher = gClingFunctions.hash_function();
581 TString lambdaName = TString::Format(
"lambda__id%zu", hasher(lambdaExpression) );
585 TString lineExpr = TString::Format(
"std::function<double(double*,double*)> %s = %s ;",lambdaName.Data(), lambdaExpression.c_str() );
586 gInterpreter->ProcessLine(lineExpr);
587 fLambdaPtr = (
void*) gInterpreter->ProcessLine(TString(lambdaName)+TString(
";"));
588 if (fLambdaPtr !=
nullptr) {
589 R__LOCKGUARD(gROOTMutex);
590 gClingFunctions.insert ( std::make_pair ( lambdaExpression, fLambdaPtr) );
591 fClingInitialized =
true;
594 fClingInitialized =
false;
604 Int_t TFormula::Compile(
const char *expression)
606 TString formula = expression;
607 if (formula.IsNull() ) {
609 if (formula.IsNull() ) formula = GetTitle();
612 if (formula.IsNull() )
return -1;
615 if (IsValid() && formula == fFormula )
return 0;
618 if (!fFormula.IsNull() ) Clear();
622 if (TestBit(TFormula::kLambda) ) {
623 bool ret = InitLambdaExpression(fFormula);
624 return (ret) ? 0 : 1;
627 if (fVars.empty() ) FillDefaults();
630 PreProcessFormula(fFormula);
632 bool ret = PrepareFormula(fFormula);
634 return (ret) ? 0 : 1;
638 void TFormula::Copy(TObject &obj)
const
642 TFormula & fnew =
dynamic_cast<TFormula&
>(obj);
644 fnew.fClingParameters = fClingParameters;
645 fnew.fClingVariables = fClingVariables;
647 fnew.fFuncs = fFuncs;
649 fnew.fParams = fParams;
650 fnew.fConsts = fConsts;
651 fnew.fFunctionsShortcuts = fFunctionsShortcuts;
652 fnew.fFormula = fFormula;
655 fnew.fNumber = fNumber;
656 fnew.fVectorized = fVectorized;
657 fnew.SetParameters(GetParameters());
661 int nLinParts = fnew.fLinearParts.size();
663 for (
int i = 0; i < nLinParts; ++i)
delete fnew.fLinearParts[i];
664 fnew.fLinearParts.clear();
667 nLinParts = fLinearParts.size();
669 fnew.fLinearParts.reserve(nLinParts);
670 for (
int i = 0; i < nLinParts; ++i) {
671 TFormula * linearNew =
new TFormula();
672 TFormula * linearOld = (TFormula*) fLinearParts[i];
674 linearOld->Copy(*linearNew);
675 fnew.fLinearParts.push_back(linearNew);
678 Warning(
"Copy",
"Function %s - expr %s has a dummy linear part %d",GetName(),GetExpFormula().Data(),i);
682 fnew.fClingInput = fClingInput;
683 fnew.fReadyToExecute = fReadyToExecute;
684 fnew.fClingInitialized = fClingInitialized;
685 fnew.fAllParametersSetted = fAllParametersSetted;
686 fnew.fClingName = fClingName;
687 fnew.fSavedInputFormula = fSavedInputFormula;
688 fnew.fLazyInitialization = fLazyInitialization;
691 if (fLambdaPtr && TestBit(TFormula::kLambda)) {
693 bool ret = fnew.InitLambdaExpression(fnew.fFormula);
695 fnew.SetBit(TFormula::kLambda);
696 fnew.fReadyToExecute =
true;
699 Error(
"TFormula",
"Syntax error in building the lambda expression %s", fFormula.Data() );
700 fnew.fReadyToExecute =
false;
704 if (fnew.fMethod)
delete fnew.fMethod;
706 TMethodCall *m =
new TMethodCall(*fMethod);
712 TMethodCall *m =
new TMethodCall(*fGradMethod);
713 fnew.fGradMethod.reset(m);
716 fnew.fFuncPtr = fFuncPtr;
717 fnew.fGradGenerationInput = fGradGenerationInput;
718 fnew.fGradFuncPtr = fGradFuncPtr;
726 void TFormula::Clear(Option_t * )
735 if(fMethod) fMethod->Delete();
738 fClingVariables.clear();
739 fClingParameters.clear();
740 fReadyToExecute =
false;
741 fClingInitialized =
false;
742 fAllParametersSetted =
false;
747 fFunctionsShortcuts.clear();
750 int nLinParts = fLinearParts.size();
752 for (
int i = 0; i < nLinParts; ++i)
delete fLinearParts[i];
754 fLinearParts.clear();
759 static std::unique_ptr<TMethodCall>
760 prepareMethod(
bool HasParameters,
bool HasVariables,
const char* FuncName,
761 bool IsVectorized,
bool IsGradient =
false) {
762 std::unique_ptr<TMethodCall> Method = std::unique_ptr<TMethodCall>(
new TMethodCall());
764 TString prototypeArguments =
"";
765 if (HasVariables || HasParameters) {
767 prototypeArguments.Append(
"ROOT::Double_v*");
769 prototypeArguments.Append(
"Double_t*");
771 auto AddDoublePtrParam = [&prototypeArguments] () {
772 prototypeArguments.Append(
",");
773 prototypeArguments.Append(
"Double_t*");
784 Method->InitWithPrototype(FuncName, prototypeArguments);
785 if (!Method->IsValid()) {
786 Error(
"prepareMethod",
787 "Can't compile function %s prototype with arguments %s", FuncName,
788 prototypeArguments.Data());
795 static TInterpreter::CallFuncIFacePtr_t::Generic_t
796 prepareFuncPtr(TMethodCall *Method) {
797 if (!Method)
return nullptr;
798 CallFunc_t *callfunc = Method->GetCallFunc();
800 if (!gCling->CallFunc_IsValid(callfunc)) {
801 Error(
"prepareFuncPtr",
"Callfunc retuned from Cling is not valid");
805 TInterpreter::CallFuncIFacePtr_t::Generic_t Result
806 = gCling->CallFunc_IFacePtr(callfunc).fGeneric;
808 Error(
"prepareFuncPtr",
"Compiled function pointer is null");
820 bool TFormula::PrepareEvalMethod()
823 Bool_t hasParameters = (fNpar > 0);
824 Bool_t hasVariables = (fNdim > 0);
825 fMethod = prepareMethod(hasParameters, hasVariables, fClingName,
826 fVectorized).release();
827 if (!fMethod)
return false;
828 fFuncPtr = prepareFuncPtr(fMethod);
836 void TFormula::InputFormulaIntoCling()
839 if (!fClingInitialized && fReadyToExecute && fClingInput.Length() > 0) {
845 TString triggerAutoparsing =
"namespace ROOT_TFormula_triggerAutoParse {\n"; triggerAutoparsing += fClingInput +
"\n}";
846 gCling->ProcessLine(triggerAutoparsing);
849 fClingInput = TString(
"#pragma cling optimize(2)\n") + fClingInput;
853 gCling->Declare(fClingInput);
854 fClingInitialized = PrepareEvalMethod();
855 if (!fClingInitialized) Error(
"InputFormulaIntoCling",
"Error compiling formula expression in Cling");
862 void TFormula::FillDefaults()
864 const TString defvars[] = {
"x",
"y",
"z",
"t"};
865 const pair<TString, Double_t> defconsts[] = {{
"pi", TMath::Pi()},
866 {
"sqrt2", TMath::Sqrt2()},
867 {
"infinity", TMath::Infinity()},
869 {
"ln10", TMath::Ln10()},
870 {
"loge", TMath::LogE()},
875 {
"sigma", TMath::Sigma()},
877 {
"eg", TMath::EulerGamma()},
883 const pair<TString,TString> funShortcuts[] =
884 { {
"sin",
"TMath::Sin" },
885 {
"cos",
"TMath::Cos" }, {
"exp",
"TMath::Exp"}, {
"log",
"TMath::Log"}, {
"log10",
"TMath::Log10"},
886 {
"tan",
"TMath::Tan"}, {
"sinh",
"TMath::SinH"}, {
"cosh",
"TMath::CosH"},
887 {
"tanh",
"TMath::TanH"}, {
"asin",
"TMath::ASin"}, {
"acos",
"TMath::ACos"},
888 {
"atan",
"TMath::ATan"}, {
"atan2",
"TMath::ATan2"}, {
"sqrt",
"TMath::Sqrt"},
889 {
"ceil",
"TMath::Ceil"}, {
"floor",
"TMath::Floor"}, {
"pow",
"TMath::Power"},
890 {
"binomial",
"TMath::Binomial"},{
"abs",
"TMath::Abs"},
891 {
"min",
"TMath::Min"},{
"max",
"TMath::Max"},{
"sign",
"TMath::Sign" },
895 std::vector<TString> defvars2(10);
896 for (
int i = 0; i < 9; ++i)
897 defvars2[i] = TString::Format(
"x[%d]",i);
899 for (
const auto &var : defvars) {
900 int pos = fVars.size();
901 fVars[var] = TFormulaVariable(var, 0, pos);
902 fClingVariables.push_back(0);
913 for (
auto con : defconsts) {
914 fConsts[con.first] = con.second;
917 FillVecFunctionsShurtCuts();
919 for (
auto fun : funShortcuts) {
920 fFunctionsShortcuts[fun.first] = fun.second;
930 void TFormula::FillVecFunctionsShurtCuts() {
931 #ifdef R__HAS_VECCORE
932 const pair<TString,TString> vecFunShortcuts[] =
933 { {
"sin",
"vecCore::math::Sin" },
934 {
"cos",
"vecCore::math::Cos" }, {
"exp",
"vecCore::math::Exp"}, {
"log",
"vecCore::math::Log"}, {
"log10",
"vecCore::math::Log10"},
935 {
"tan",
"vecCore::math::Tan"},
937 {
"asin",
"vecCore::math::ASin"},
938 {
"acos",
"TMath::Pi()/2-vecCore::math::ASin"},
939 {
"atan",
"vecCore::math::ATan"},
940 {
"atan2",
"vecCore::math::ATan2"}, {
"sqrt",
"vecCore::math::Sqrt"},
941 {
"ceil",
"vecCore::math::Ceil"}, {
"floor",
"vecCore::math::Floor"}, {
"pow",
"vecCore::math::Pow"},
942 {
"cbrt",
"vecCore::math::Cbrt"},{
"abs",
"vecCore::math::Abs"},
943 {
"min",
"vecCore::math::Min"},{
"max",
"vecCore::math::Max"},{
"sign",
"vecCore::math::Sign" }
947 for (
auto fun : vecFunShortcuts) {
948 fFunctionsShortcuts[fun.first] = fun.second;
962 void TFormula::HandlePolN(TString &formula)
964 Int_t polPos = formula.Index(
"pol");
965 while (polPos != kNPOS && !IsAParameterName(formula, polPos)) {
967 Bool_t defaultVariable =
false;
969 Int_t openingBracketPos = formula.Index(
'(', polPos);
970 Bool_t defaultCounter = openingBracketPos == kNPOS;
971 Bool_t defaultDegree =
true;
972 Int_t degree, counter;
974 if (!defaultCounter) {
977 sdegree = formula(polPos + 3, openingBracketPos - polPos - 3);
978 if (!sdegree.IsDigit())
979 defaultCounter =
true;
981 if (!defaultCounter) {
982 degree = sdegree.Atoi();
983 counter = TString(formula(openingBracketPos + 1, formula.Index(
')', polPos) - openingBracketPos)).Atoi();
985 Int_t temp = polPos + 3;
986 while (temp < formula.Length() && isdigit(formula[temp])) {
987 defaultDegree =
false;
990 degree = TString(formula(polPos + 3, temp - polPos - 3)).Atoi();
994 TString replacement = TString::Format(
"[%d]", counter);
995 if (polPos - 1 < 0 || !IsFunctionNameChar(formula[polPos - 1]) || formula[polPos - 1] ==
':') {
997 defaultVariable =
true;
999 Int_t tmp = polPos - 1;
1000 while (tmp >= 0 && IsFunctionNameChar(formula[tmp]) && formula[tmp] !=
':') {
1003 variable = formula(tmp + 1, polPos - (tmp + 1));
1005 Int_t param = counter + 1;
1007 while (tmp <= degree) {
1009 replacement.Append(TString::Format(
"+[%d]*%s^%d", param, variable.Data(), tmp));
1011 replacement.Append(TString::Format(
"+[%d]*%s", param, variable.Data()));
1017 replacement.Insert(0,
'(');
1018 replacement.Append(
')');
1021 if (defaultCounter && !defaultDegree) {
1022 pattern = TString::Format(
"%spol%d", (defaultVariable ?
"" : variable.Data()), degree);
1023 }
else if (defaultCounter && defaultDegree) {
1024 pattern = TString::Format(
"%spol", (defaultVariable ?
"" : variable.Data()));
1026 pattern = TString::Format(
"%spol%d(%d)", (defaultVariable ?
"" : variable.Data()), degree, counter);
1029 if (!formula.Contains(pattern)) {
1030 Error(
"HandlePolN",
"Error handling polynomial function - expression is %s - trying to replace %s with %s ",
1031 formula.Data(), pattern.Data(), replacement.Data());
1034 if (formula == pattern) {
1037 fNumber = 300 + degree;
1039 formula.ReplaceAll(pattern, replacement);
1040 polPos = formula.Index(
"pol");
1063 void TFormula::HandleParametrizedFunctions(TString &formula)
1066 map< pair<TString,Int_t> ,pair<TString,TString> > functions;
1067 FillParametrizedFunctions(functions);
1069 map<TString,Int_t> functionsNumbers;
1070 functionsNumbers[
"gaus"] = 100;
1071 functionsNumbers[
"bigaus"] = 102;
1072 functionsNumbers[
"landau"] = 400;
1073 functionsNumbers[
"expo"] = 200;
1074 functionsNumbers[
"crystalball"] = 500;
1077 formula.ReplaceAll(
"xyzgaus",
"gaus[x,y,z]");
1078 formula.ReplaceAll(
"xygaus",
"gaus[x,y]");
1079 formula.ReplaceAll(
"xgaus",
"gaus[x]");
1080 formula.ReplaceAll(
"ygaus",
"gaus[y]");
1081 formula.ReplaceAll(
"zgaus",
"gaus[z]");
1082 formula.ReplaceAll(
"xexpo",
"expo[x]");
1083 formula.ReplaceAll(
"yexpo",
"expo[y]");
1084 formula.ReplaceAll(
"zexpo",
"expo[z]");
1085 formula.ReplaceAll(
"xylandau",
"landau[x,y]");
1086 formula.ReplaceAll(
"xyexpo",
"expo[x,y]");
1088 const char * defaultVariableNames[] = {
"x",
"y",
"z"};
1090 for (map<pair<TString, Int_t>, pair<TString, TString>>::iterator it = functions.begin(); it != functions.end();
1093 TString funName = it->first.first;
1094 Int_t funDim = it->first.second;
1095 Int_t funPos = formula.Index(funName);
1098 while (funPos != kNPOS && !IsAParameterName(formula, funPos)) {
1101 Int_t lastFunPos = funPos + funName.Length();
1104 Int_t iposBefore = funPos - 1;
1107 if (iposBefore >= 0) {
1108 assert(iposBefore < formula.Length());
1109 if (isalpha(formula[iposBefore])) {
1112 funPos = formula.Index(funName, lastFunPos);
1117 Bool_t isNormalized =
false;
1118 if (lastFunPos < formula.Length()) {
1120 isNormalized = (formula[lastFunPos] ==
'n');
1123 if (lastFunPos < formula.Length()) {
1124 char c = formula[lastFunPos];
1127 if (isalnum(c) || (!IsOperator(c) && c !=
'(' && c !=
')' && c !=
'[' && c !=
']')) {
1129 funPos = formula.Index(funName, lastFunPos);
1136 SetBit(kNormalized, 1);
1138 std::vector<TString> variables;
1140 TString varList =
"";
1141 Bool_t defaultVariables =
false;
1144 Int_t openingBracketPos = funPos + funName.Length() + (isNormalized ? 1 : 0);
1145 Int_t closingBracketPos = kNPOS;
1146 if (openingBracketPos > formula.Length() || formula[openingBracketPos] !=
'[') {
1148 variables.resize(dim);
1149 for (Int_t idim = 0; idim < dim; ++idim)
1150 variables[idim] = defaultVariableNames[idim];
1151 defaultVariables =
true;
1154 closingBracketPos = formula.Index(
']', openingBracketPos);
1155 varList = formula(openingBracketPos + 1, closingBracketPos - openingBracketPos - 1);
1156 dim = varList.CountChar(
',') + 1;
1157 variables.resize(dim);
1159 TString varName =
"";
1160 for (Int_t i = 0; i < varList.Length(); ++i) {
1161 if (IsFunctionNameChar(varList[i])) {
1162 varName.Append(varList[i]);
1164 if (varList[i] ==
',') {
1165 variables[Nvar] = varName;
1172 variables[Nvar] = varName;
1177 if (dim != funDim) {
1178 pair<TString, Int_t> key = make_pair(funName, dim);
1179 if (functions.find(key) == functions.end()) {
1180 Error(
"PreProcessFormula",
"Dimension of function %s is detected to be of dimension %d and is not "
1181 "compatible with existing pre-defined function which has dim %d",
1182 funName.Data(), dim, funDim);
1186 funPos = formula.Index(funName, lastFunPos);
1191 Int_t openingParenthesisPos = (closingBracketPos == kNPOS) ? openingBracketPos : closingBracketPos + 1;
1192 bool defaultCounter = (openingParenthesisPos > formula.Length() || formula[openingParenthesisPos] !=
'(');
1197 if (defaultCounter) {
1203 TRegexp counterPattern(
"([0-9]+)");
1205 if (counterPattern.Index(formula, &len, openingParenthesisPos) == -1) {
1206 funPos = formula.Index(funName, funPos + 1);
1210 TString(formula(openingParenthesisPos + 1, formula.Index(
')', funPos) - openingParenthesisPos - 1))
1216 TString body = (isNormalized ? it->second.second : it->second.first);
1217 if (isNormalized && body ==
"") {
1218 Error(
"PreprocessFormula",
"%d dimension function %s has no normalized form.", it->first.second,
1222 for (
int i = 0; i < body.Length(); ++i) {
1223 if (body[i] ==
'{') {
1226 Int_t num = TString(body(i, body.Index(
'}', i) - i)).Atoi();
1227 TString variable = variables[num];
1228 TString pattern = TString::Format(
"{V%d}", num);
1230 body.Replace(i, pattern.Length(), variable, variable.Length());
1231 i += variable.Length() - 1;
1232 }
else if (body[i] ==
'[') {
1235 while (tmp < body.Length() && body[tmp] !=
']') {
1238 Int_t num = TString(body(i + 1, tmp - 1 - i)).Atoi();
1240 TString replacement = TString::Format(
"%d", num);
1242 body.Replace(i + 1, tmp - 1 - i, replacement, replacement.Length());
1243 i += replacement.Length() + 1;
1247 if (defaultCounter && defaultVariables) {
1248 pattern = TString::Format(
"%s%s", funName.Data(), (isNormalized ?
"n" :
""));
1250 if (!defaultCounter && defaultVariables) {
1251 pattern = TString::Format(
"%s%s(%d)", funName.Data(), (isNormalized ?
"n" :
""), counter);
1253 if (defaultCounter && !defaultVariables) {
1254 pattern = TString::Format(
"%s%s[%s]", funName.Data(), (isNormalized ?
"n" :
""), varList.Data());
1256 if (!defaultCounter && !defaultVariables) {
1258 TString::Format(
"%s%s[%s](%d)", funName.Data(), (isNormalized ?
"n" :
""), varList.Data(), counter);
1260 TString replacement = body;
1263 if (fNumber == 0 && formula.Length() <= (pattern.Length() - funPos) + 1) {
1264 fNumber = functionsNumbers[funName] + 10 * (dim - 1);
1269 formula.Replace(funPos, pattern.Length(), replacement, replacement.Length());
1271 funPos = formula.Index(funName);
1279 void TFormula::HandleParamRanges(TString &formula)
1281 TRegexp rangePattern(
"\\[[0-9]+\\.\\.[0-9]+\\]");
1284 while ((matchIdx = rangePattern.Index(formula, &len, matchIdx)) != -1) {
1285 int startIdx = matchIdx + 1;
1286 int endIdx = formula.Index(
"..", startIdx) + 2;
1287 int startCnt = TString(formula(startIdx, formula.Length())).Atoi();
1288 int endCnt = TString(formula(endIdx, formula.Length())).Atoi();
1290 if (endCnt <= startCnt)
1291 Error(
"HandleParamRanges",
"End parameter (%d) <= start parameter (%d) in parameter range", endCnt, startCnt);
1293 TString newString =
"[";
1294 for (
int cnt = startCnt; cnt < endCnt; cnt++)
1295 newString += TString::Format(
"%d],[", cnt);
1296 newString += TString::Format(
"%d]", endCnt);
1299 formula.Replace(matchIdx, formula.Index(
"]", matchIdx) + 1 - matchIdx, newString);
1301 matchIdx += newString.Length();
1310 void TFormula::HandleFunctionArguments(TString &formula)
1315 std::map<std::pair<TString, Int_t>, std::pair<TString, TString>> parFunctions;
1316 FillParametrizedFunctions(parFunctions);
1319 for (Int_t i = 0; i < formula.Length(); ++i) {
1323 if (formula[i] ==
'[') {
1324 while (formula[i] !=
']')
1329 if (formula[i] ==
'\"') {
1332 while (formula[i] !=
'\"');
1336 if (IsScientificNotation(formula, i))
1339 if (IsHexadecimal(formula, i)) {
1340 while (!IsOperator(formula[i]) && i < formula.Length())
1346 if (isalpha(formula[i]) && !IsOperator(formula[i])) {
1350 for (j = i; j < formula.Length() && IsFunctionNameChar(formula[j]); j++)
1352 TString name = (TString)formula(i, j - i);
1359 std::vector<int> argSeparators;
1360 argSeparators.push_back(j);
1362 for (k = j + 1; depth >= 1 && k < formula.Length(); k++) {
1363 if (formula[k] ==
',' && depth == 1) {
1365 argSeparators.push_back(k);
1366 }
else if (formula[k] ==
'(')
1368 else if (formula[k] ==
')')
1371 argSeparators.push_back(k - 1);
1376 R__LOCKGUARD(gROOTMutex);
1377 obj = gROOT->GetListOfFunctions()->FindObject(name);
1379 TFormula *f =
dynamic_cast<TFormula *
>(obj);
1382 TF1 *f1 =
dynamic_cast<TF1 *
>(obj);
1384 f = f1->GetFormula();
1390 bool nameRecognized = (f !=
nullptr);
1395 TString replacementFormula;
1397 ndim = f->GetNdim();
1398 npar = f->GetNpar();
1399 replacementFormula = f->GetExpFormula();
1403 for (
auto keyval : parFunctions) {
1405 pair<TString, Int_t> name_ndim = keyval.first;
1407 pair<TString, TString> formulaPair = keyval.second;
1410 if (name == name_ndim.first)
1411 replacementFormula = formulaPair.first;
1412 else if (name == name_ndim.first +
"n" && formulaPair.second !=
"")
1413 replacementFormula = formulaPair.second;
1418 ndim = name_ndim.second;
1423 while ((idx = replacementFormula.Index(
'[', idx)) != kNPOS) {
1424 npar = max(npar, 1 + TString(replacementFormula(idx + 1, replacementFormula.Length())).Atoi());
1425 idx = replacementFormula.Index(
']', idx);
1427 Error(
"HandleFunctionArguments",
"Square brackets not matching in formula %s",
1428 (
const char *)replacementFormula);
1435 if (nArguments == ndim + npar || nArguments == npar || nArguments == ndim) {
1436 nameRecognized =
true;
1441 if (nameRecognized && ndim > 4)
1442 Error(
"HandleFunctionArguments",
"Number of dimensions %d greater than 4. Cannot parse formula.", ndim);
1445 if (nameRecognized && j < formula.Length() && formula[j] ==
'(') {
1450 map<TString, TString> argSubstitutions;
1452 const char *defaultVariableNames[] = {
"x",
"y",
"z",
"t"};
1455 bool canReplace =
false;
1456 if (nArguments == ndim + npar) {
1458 for (
int argNr = 0; argNr < nArguments; argNr++) {
1462 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1463 PreProcessFormula(newName);
1468 TString oldName = (f) ? TString::Format(
"x[%d]", argNr) : TString::Format(
"{V%d}", argNr);
1469 argSubstitutions[oldName] = newName;
1472 argSubstitutions[defaultVariableNames[argNr]] = newName;
1475 int parNr = argNr - ndim;
1477 (f) ? TString::Format(
"[%s]", f->GetParName(parNr)) : TString::Format(
"[%d]", parNr);
1478 argSubstitutions[oldName] = newName;
1481 if (f && oldName == newName)
1482 DoAddParameter(f->GetParName(parNr), f->GetParameter(parNr),
false);
1487 }
else if (nArguments == npar) {
1492 bool varsImplicit =
true;
1493 for (
int argNr = 0; argNr < nArguments && varsImplicit; argNr++) {
1494 int openIdx = argSeparators[argNr] + 1;
1495 int closeIdx = argSeparators[argNr + 1] - 1;
1498 if (formula[openIdx] !=
'[' || formula[closeIdx] !=
']' || closeIdx <= openIdx + 1)
1499 varsImplicit =
false;
1502 for (
int idx = openIdx + 1; idx < closeIdx && varsImplicit; idx++)
1503 if (!IsFunctionNameChar(formula[idx]))
1504 varsImplicit =
false;
1507 Warning(
"HandleFunctionArguments",
1508 "Argument %d is not a parameter. Cannot assume variables are implicit.", argNr);
1515 for (
int dim = 0; dim < ndim; dim++) {
1516 argSubstitutions[TString::Format(
"{V%d}", dim)] = defaultVariableNames[dim];
1520 for (
int argNr = 0; argNr < nArguments; argNr++) {
1522 (f) ? TString::Format(
"[%s]", f->GetParName(argNr)) : TString::Format(
"[%d]", argNr);
1524 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1527 PreProcessFormula(newName);
1528 argSubstitutions[oldName] = newName;
1531 if (f && oldName == newName)
1532 DoAddParameter(f->GetParName(argNr), f->GetParameter(argNr),
false);
1538 if (!canReplace && nArguments == ndim) {
1542 for (
int argNr = 0; argNr < nArguments; argNr++) {
1543 TString oldName = (f) ? TString::Format(
"x[%d]", argNr) : TString::Format(
"{V%d}", argNr);
1545 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1548 PreProcessFormula(newName);
1549 argSubstitutions[oldName] = newName;
1552 argSubstitutions[defaultVariableNames[argNr]] = newName;
1557 for (
int parNr = 0; parNr < npar; parNr++)
1558 DoAddParameter(f->GetParName(parNr), f->GetParameter(parNr),
false);
1565 ReplaceAllNames(replacementFormula, argSubstitutions);
1571 formula.Replace(i, k - i, replacementFormula);
1572 i += replacementFormula.Length() - 1;
1575 Warning(
"HandleFunctionArguments",
"Unable to make replacement. Number of parameters doesn't work : "
1576 "%d arguments, %d dimensions, %d parameters",
1577 nArguments, ndim, npar);
1594 void TFormula::HandleExponentiation(TString &formula)
1596 Int_t caretPos = formula.Last(
'^');
1597 while (caretPos != kNPOS && !IsAParameterName(formula, caretPos)) {
1599 TString right, left;
1600 Int_t temp = caretPos;
1603 if (formula[temp] ==
')') {
1606 while (depth != 0 && temp > 0) {
1607 if (formula[temp] ==
')')
1609 if (formula[temp] ==
'(')
1620 if (temp >= 2 && IsScientificNotation(formula, temp - 1))
1622 }
while (temp >= 0 && !IsOperator(formula[temp]) && !IsBracket(formula[temp]));
1624 assert(temp + 1 >= 0);
1625 Int_t leftPos = temp + 1;
1626 left = formula(leftPos, caretPos - leftPos);
1632 if (temp >= formula.Length()) {
1633 Error(
"HandleExponentiation",
"Invalid position of operator ^");
1636 if (formula[temp] ==
'(') {
1639 while (depth != 0 && temp < formula.Length()) {
1640 if (formula[temp] ==
')')
1642 if (formula[temp] ==
'(')
1649 if (formula[temp] ==
'-' || formula[temp] ==
'+')
1655 while (temp < formula.Length() && ((depth > 0) || !IsOperator(formula[temp]))) {
1658 if (temp >= 2 && IsScientificNotation(formula, temp))
1661 if (temp < formula.Length() && formula[temp] ==
'(')
1663 if (temp < formula.Length() && formula[temp] ==
')') {
1671 right = formula(caretPos + 1, (temp - 1) - caretPos);
1674 TString pattern = TString::Format(
"%s^%s", left.Data(), right.Data());
1675 TString replacement = TString::Format(
"pow(%s,%s)", left.Data(), right.Data());
1679 formula.Replace(leftPos, pattern.Length(), replacement, replacement.Length());
1681 caretPos = formula.Last(
'^');
1688 void TFormula::HandleLinear(TString &formula)
1691 Int_t linPos = formula.Index(
"@");
1692 if (linPos == kNPOS )
return;
1693 Int_t nofLinParts = formula.CountChar((
int)
'@');
1694 assert(nofLinParts > 0);
1695 fLinearParts.reserve(nofLinParts + 1);
1698 while (linPos != kNPOS && !IsAParameterName(formula, linPos)) {
1705 while (temp >= 0 && formula[temp] !=
'@') {
1708 left = formula(temp + 1, linPos - (temp + 1));
1711 while (temp < formula.Length() && formula[temp] !=
'@') {
1714 TString right = formula(linPos + 1, temp - (linPos + 1));
1717 (first) ? TString::Format(
"%s@%s", left.Data(), right.Data()) : TString::Format(
"@%s", right.Data());
1718 TString replacement =
1719 (first) ? TString::Format(
"([%d]*(%s))+([%d]*(%s))", Nlinear, left.Data(), Nlinear + 1, right.Data())
1720 : TString::Format(
"+([%d]*(%s))", Nlinear, right.Data());
1721 Nlinear += (first) ? 2 : 1;
1723 formula.ReplaceAll(pattern, replacement);
1725 TFormula *lin1 =
new TFormula(
"__linear1", left,
false);
1726 fLinearParts.push_back(lin1);
1728 TFormula *lin2 =
new TFormula(
"__linear2", right,
false);
1729 fLinearParts.push_back(lin2);
1731 linPos = formula.Index(
"@");
1743 void TFormula::PreProcessFormula(TString &formula)
1745 formula.ReplaceAll(
"**",
"^");
1746 formula.ReplaceAll(
"++",
"@");
1747 formula.ReplaceAll(
" ",
"");
1748 HandlePolN(formula);
1749 HandleParametrizedFunctions(formula);
1750 HandleParamRanges(formula);
1751 HandleFunctionArguments(formula);
1752 HandleExponentiation(formula);
1754 HandleLinear(formula);
1757 formula.ReplaceAll(
"--",
"- -");
1758 formula.ReplaceAll(
"++",
"+ +");
1765 Bool_t TFormula::PrepareFormula(TString &formula)
1768 fReadyToExecute =
false;
1769 ExtractFunctors(formula);
1774 fClingInput = formula;
1776 fFormula.ReplaceAll(
"{",
"");
1777 fFormula.ReplaceAll(
"}",
"");
1786 ProcessFormula(fClingInput);
1789 if (fNumber != 0) SetPredefinedParamNames();
1791 return fReadyToExecute && fClingInitialized;
1804 void TFormula::ExtractFunctors(TString &formula)
1811 for (Int_t i = 0; i < formula.Length(); ++i) {
1815 if (formula[i] ==
'[') {
1819 while (i < formula.Length() && formula[i] !=
']') {
1820 param.Append(formula[i++]);
1825 int paramIndex = -1;
1826 if (param.IsDigit()) {
1827 paramIndex = param.Atoi();
1828 param.Insert(0,
'p');
1829 if (paramIndex >= fNpar || fParams.find(param) == fParams.end()) {
1831 for (
int idx = 0; idx <= paramIndex; ++idx) {
1832 TString pname = TString::Format(
"p%d", idx);
1833 if (fParams.find(pname) == fParams.end())
1834 DoAddParameter(pname, 0,
false);
1839 param.ReplaceAll(
"\\s",
" ");
1844 if (fParams.find(param) == fParams.end() || GetParNumber(param) < 0 ||
1845 (unsigned)GetParNumber(param) >= fClingParameters.size()) {
1847 DoAddParameter(param, 0,
false);
1850 TString replacement = TString::Format(
"{[%s]}", param.Data());
1851 formula.Replace(tmp, i - tmp, replacement, replacement.Length());
1852 fFuncs.push_back(TFormulaFunction(param));
1855 int deltai = replacement.Length() - (i-tmp);
1861 if (formula[i] ==
'\"') {
1865 }
while (formula[i] !=
'\"');
1868 if (IsScientificNotation(formula, i))
1871 if (IsHexadecimal(formula, i)) {
1874 while (!IsOperator(formula[i]) && i < formula.Length()) {
1883 if (isalpha(formula[i]) &&
1884 !IsOperator(formula[i]))
1889 while (i < formula.Length() && IsFunctionNameChar(formula[i])) {
1891 if (formula[i] ==
':' && ((i + 1) < formula.Length())) {
1892 if (formula[i + 1] ==
':') {
1901 name.Append(formula[i++]);
1904 if (formula[i] ==
'(') {
1906 if (formula[i] ==
')') {
1907 fFuncs.push_back(TFormulaFunction(name, body, 0));
1913 while (depth != 0 && i < formula.Length()) {
1914 switch (formula[i]) {
1915 case '(': depth++;
break;
1916 case ')': depth--;
break;
1924 body.Append(formula[i++]);
1927 Int_t originalBodyLen = body.Length();
1928 ExtractFunctors(body);
1929 formula.Replace(i - originalBodyLen, originalBodyLen, body, body.Length());
1930 i += body.Length() - originalBodyLen;
1931 fFuncs.push_back(TFormulaFunction(name, body, args));
1940 if (!IsReservedName(name))
1942 R__LOCKGUARD(gROOTMutex);
1943 obj = gROOT->GetListOfFunctions()->FindObject(name);
1945 TFormula *f =
dynamic_cast<TFormula *
>(obj);
1948 TF1 *f1 =
dynamic_cast<TF1 *
>(obj);
1950 f = f1->GetFormula();
1958 TString replacementFormula = f->GetExpFormula();
1963 PreProcessFormula(replacementFormula);
1971 std::vector<TString> newNames;
1974 newNames.resize(f->GetNpar());
1976 for (
int jpar = f->GetNpar() - 1; jpar >= 0; --jpar) {
1978 TString pj = TString(f->GetParName(jpar));
1979 if (pj[0] ==
'p' && TString(pj(1, pj.Length())).IsDigit()) {
1980 TString oldName = TString::Format(
"[%s]", f->GetParName(jpar));
1981 TString newName = TString::Format(
"[p%d]", nparOffset + jpar);
1984 replacementFormula.ReplaceAll(oldName, newName);
1985 newNames[jpar] = newName;
1987 newNames[jpar] = f->GetParName(jpar);
1991 ExtractFunctors(replacementFormula);
1995 for (
int jpar = 0; jpar < f->GetNpar(); ++jpar) {
1996 if (nparOffset > 0) {
1998 assert((
int)newNames.size() == f->GetNpar());
1999 SetParameter(newNames[jpar], f->GetParameter(jpar));
2002 SetParameter(f->GetParName(jpar), f->GetParameter(jpar));
2005 replacementFormula.Insert(0,
'(');
2006 replacementFormula.Insert(replacementFormula.Length(),
')');
2007 formula.Replace(i - name.Length(), name.Length(), replacementFormula, replacementFormula.Length());
2009 i += replacementFormula.Length() - name.Length();
2020 TString replacement = TString::Format(
"{%s}", name.Data());
2021 formula.Replace(i - name.Length(), name.Length(), replacement, replacement.Length());
2023 fFuncs.push_back(TFormulaFunction(name));
2049 void TFormula::ProcessFormula(TString &formula)
2053 for (list<TFormulaFunction>::iterator funcsIt = fFuncs.begin(); funcsIt != fFuncs.end(); ++funcsIt) {
2054 TFormulaFunction &fun = *funcsIt;
2060 if (fun.IsFuncCall()) {
2062 map<TString, TString>::iterator it = fFunctionsShortcuts.find(fun.GetName());
2063 if (it != fFunctionsShortcuts.end()) {
2064 TString shortcut = it->first;
2065 TString full = it->second;
2069 Ssiz_t index = formula.Index(shortcut, 0);
2070 while (index != kNPOS) {
2073 Ssiz_t i2 = index + shortcut.Length();
2074 if ((index > 0) && (isalpha(formula[index - 1]) || formula[index - 1] ==
':')) {
2075 index = formula.Index(shortcut, i2);
2078 if (i2 < formula.Length() && formula[i2] !=
'(') {
2079 index = formula.Index(shortcut, i2);
2083 formula.Replace(index, shortcut.Length(), full);
2084 Ssiz_t inext = index + full.Length();
2085 index = formula.Index(shortcut, inext);
2092 #ifdef TFORMULA_CHECK_FUNCTIONS
2094 if (fun.fName.Contains(
"::"))
2097 std::string name(fun.fName.Data());
2098 size_t index = name.rfind(
"::");
2099 assert(index != std::string::npos);
2100 TString className = fun.fName(0, fun.fName(0, index).Length());
2101 TString functionName = fun.fName(index + 2, fun.fName.Length());
2103 Bool_t silent =
true;
2104 TClass *tclass = TClass::GetClass(className, silent);
2106 const TList *methodList = tclass->GetListOfAllPublicMethods();
2107 TIter next(methodList);
2109 while ((p = (TMethod *)next())) {
2110 if (strcmp(p->GetName(), functionName.Data()) == 0 &&
2111 (fun.GetNargs() <= p->GetNargs() && fun.GetNargs() >= p->GetNargs() - p->GetNargsOpt())) {
2121 R__LOCKGUARD(gROOTMutex);
2122 f = (TFunction *)gROOT->GetListOfGlobalFunctions(
true)->FindObject(fun.fName);
2125 if (f && fun.GetNargs() <= f->GetNargs() && fun.GetNargs() >= f->GetNargs() - f->GetNargsOpt()) {
2133 Info(
"TFormula",
"Could not find %s function with %d argument(s)", fun.GetName(), fun.GetNargs());
2140 R__LOCKGUARD(gROOTMutex);
2141 old = (TFormula *)gROOT->GetListOfFunctions()->FindObject(gNamePrefix + fun.fName);
2147 TString pattern = TString::Format(
"{%s}", fun.GetName());
2148 TString replacement = old->GetExpFormula();
2149 PreProcessFormula(replacement);
2150 ExtractFunctors(replacement);
2151 formula.ReplaceAll(pattern, replacement);
2156 map<TString, TFormulaVariable>::iterator varsIt = fVars.find(fun.GetName());
2157 if (varsIt != fVars.end()) {
2159 TString name = (*varsIt).second.GetName();
2160 Double_t value = (*varsIt).second.fValue;
2162 AddVariable(name, value);
2163 if (!fVars[name].fFound) {
2165 fVars[name].fFound =
true;
2166 int varDim = (*varsIt).second.fArrayPos;
2167 if (varDim >= fNdim) {
2171 for (
auto &v : fVars) {
2172 if (v.second.fArrayPos < varDim && !v.second.fFound) {
2173 AddVariable(v.first, v.second.fValue);
2174 v.second.fFound =
true;
2180 TString pattern = TString::Format(
"{%s}", name.Data());
2181 TString replacement = TString::Format(
"x[%d]", (*varsIt).second.fArrayPos);
2182 formula.ReplaceAll(pattern, replacement);
2192 TString funname = fun.GetName();
2193 if (funname.Contains(
"x[") && funname.Contains(
"]")) {
2194 TString sdigit = funname(2, funname.Index(
"]"));
2195 int digit = sdigit.Atoi();
2196 if (digit >= fNdim) {
2199 for (
int j = 0; j < fNdim; ++j) {
2200 TString vname = TString::Format(
"x[%d]", j);
2201 if (fVars.find(vname) == fVars.end()) {
2202 fVars[vname] = TFormulaVariable(vname, 0, j);
2203 fVars[vname].fFound =
true;
2204 AddVariable(vname, 0.);
2211 TString pattern = TString::Format(
"{%s}", funname.Data());
2212 formula.ReplaceAll(pattern, funname);
2217 auto paramsIt = fParams.find(fun.GetName());
2218 if (paramsIt != fParams.end()) {
2220 TString pattern = TString::Format(
"{[%s]}", fun.GetName());
2222 if (formula.Index(pattern) != kNPOS) {
2224 TString replacement = TString::Format(
"p[%d]", (*paramsIt).second);
2226 formula.ReplaceAll(pattern, replacement);
2235 map<TString, Double_t>::iterator constIt = fConsts.find(fun.GetName());
2236 if (constIt != fConsts.end()) {
2237 TString pattern = TString::Format(
"{%s}", fun.GetName());
2238 TString value = TString::Format(
"%lf", (*constIt).second);
2239 formula.ReplaceAll(pattern, value);
2251 if (!fReadyToExecute) {
2252 fReadyToExecute =
true;
2253 Bool_t hasVariables = (fNdim > 0);
2254 Bool_t hasParameters = (fNpar > 0);
2255 if (!hasParameters) {
2256 fAllParametersSetted =
true;
2265 if (!hasVariables) fVectorized=
false;
2268 Bool_t inputIntoCling = (formula.Length() > 0);
2269 if (inputIntoCling) {
2272 std::string inputFormula(formula.Data());
2276 std::string inputFormulaVecFlag = inputFormula;
2278 inputFormulaVecFlag +=
" (vectorized)";
2280 TString argType = fVectorized ?
"ROOT::Double_v" :
"Double_t";
2283 TString argumentsPrototype = TString::Format(
"%s%s%s", ( (hasVariables || hasParameters) ? (argType +
" *x").Data() :
""),
2284 (hasParameters ?
"," :
""), (hasParameters ?
"Double_t *p" :
""));
2287 fClingName = gNamePrefix;
2290 R__LOCKGUARD(gROOTMutex);
2296 auto funcit = gClingFunctions.find(inputFormulaVecFlag);
2298 if (funcit != gClingFunctions.end()) {
2299 fFuncPtr = (TFormula::CallFuncSignature)funcit->second;
2300 fClingInitialized =
true;
2301 inputIntoCling =
false;
2307 auto hasher = gClingFunctions.hash_function();
2308 fClingName = TString::Format(
"%s__id%zu", gNamePrefix.Data(), hasher(inputFormulaVecFlag));
2310 fClingInput = TString::Format(
"%s %s(%s){ return %s ; }", argType.Data(), fClingName.Data(),
2311 argumentsPrototype.Data(), inputFormula.c_str());
2330 if (inputIntoCling) {
2331 if (!fLazyInitialization) {
2332 InputFormulaIntoCling();
2333 if (fClingInitialized) {
2336 R__LOCKGUARD(gROOTMutex);
2337 gClingFunctions.insert(std::make_pair(inputFormulaVecFlag, (
void *)fFuncPtr));
2340 if (!fClingInitialized) {
2342 fSavedInputFormula = inputFormulaVecFlag;
2346 fAllParametersSetted =
true;
2347 fClingInitialized =
true;
2354 if (!fClingInitialized && !fLazyInitialization) {
2356 for (list<TFormulaFunction>::iterator it = fFuncs.begin(); it != fFuncs.end(); ++it) {
2358 if (!it->fFound && !it->IsFuncCall()) {
2360 if (it->GetNargs() == 0)
2361 Error(
"ProcessFormula",
"\"%s\" has not been matched in the formula expression", it->GetName());
2363 Error(
"ProcessFormula",
"Could not find %s function with %d argument(s)", it->GetName(), it->GetNargs());
2366 Error(
"ProcessFormula",
"Formula \"%s\" is invalid !", GetExpFormula().Data() );
2367 fReadyToExecute =
false;
2373 if (fReadyToExecute) {
2374 auto itvar = fVars.begin();
2377 if (!itvar->second.fFound) {
2379 itvar = fVars.erase(itvar);
2382 }
while (itvar != fVars.end());
2389 void TFormula::FillParametrizedFunctions(map<pair<TString, Int_t>, pair<TString, TString>> &functions)
2393 make_pair(make_pair(
"gaus", 1), make_pair(
"[0]*exp(-0.5*(({V0}-[1])/[2])*(({V0}-[1])/[2]))",
2394 "[0]*exp(-0.5*(({V0}-[1])/[2])*(({V0}-[1])/[2]))/(sqrt(2*pi)*[2])")));
2395 functions.insert(make_pair(make_pair(
"landau", 1), make_pair(
"[0]*TMath::Landau({V0},[1],[2],false)",
2396 "[0]*TMath::Landau({V0},[1],[2],true)")));
2397 functions.insert(make_pair(make_pair(
"expo", 1), make_pair(
"exp([0]+[1]*{V0})",
"")));
2399 make_pair(make_pair(
"crystalball", 1), make_pair(
"[0]*ROOT::Math::crystalball_function({V0},[3],[4],[2],[1])",
2400 "[0]*ROOT::Math::crystalball_pdf({V0},[3],[4],[2],[1])")));
2402 make_pair(make_pair(
"breitwigner", 1), make_pair(
"[0]*ROOT::Math::breitwigner_pdf({V0},[2],[1])",
2403 "[0]*ROOT::Math::breitwigner_pdf({V0},[2],[4],[1])")));
2405 functions.insert(make_pair(make_pair(
"cheb0", 1), make_pair(
"ROOT::Math::Chebyshev0({V0},[0])",
"")));
2406 functions.insert(make_pair(make_pair(
"cheb1", 1), make_pair(
"ROOT::Math::Chebyshev1({V0},[0],[1])",
"")));
2407 functions.insert(make_pair(make_pair(
"cheb2", 1), make_pair(
"ROOT::Math::Chebyshev2({V0},[0],[1],[2])",
"")));
2408 functions.insert(make_pair(make_pair(
"cheb3", 1), make_pair(
"ROOT::Math::Chebyshev3({V0},[0],[1],[2],[3])",
"")));
2410 make_pair(make_pair(
"cheb4", 1), make_pair(
"ROOT::Math::Chebyshev4({V0},[0],[1],[2],[3],[4])",
"")));
2412 make_pair(make_pair(
"cheb5", 1), make_pair(
"ROOT::Math::Chebyshev5({V0},[0],[1],[2],[3],[4],[5])",
"")));
2414 make_pair(make_pair(
"cheb6", 1), make_pair(
"ROOT::Math::Chebyshev6({V0},[0],[1],[2],[3],[4],[5],[6])",
"")));
2416 make_pair(make_pair(
"cheb7", 1), make_pair(
"ROOT::Math::Chebyshev7({V0},[0],[1],[2],[3],[4],[5],[6],[7])",
"")));
2417 functions.insert(make_pair(make_pair(
"cheb8", 1),
2418 make_pair(
"ROOT::Math::Chebyshev8({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8])",
"")));
2419 functions.insert(make_pair(make_pair(
"cheb9", 1),
2420 make_pair(
"ROOT::Math::Chebyshev9({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8],[9])",
"")));
2422 make_pair(make_pair(
"cheb10", 1),
2423 make_pair(
"ROOT::Math::Chebyshev10({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8],[9],[10])",
"")));
2426 make_pair(make_pair(
"gaus", 2), make_pair(
"[0]*exp(-0.5*(({V0}-[1])/[2])^2 - 0.5*(({V1}-[3])/[4])^2)",
"")));
2428 make_pair(make_pair(
"landau", 2),
2429 make_pair(
"[0]*TMath::Landau({V0},[1],[2],false)*TMath::Landau({V1},[3],[4],false)",
"")));
2430 functions.insert(make_pair(make_pair(
"expo", 2), make_pair(
"exp([0]+[1]*{V0})",
"exp([0]+[1]*{V0}+[2]*{V1})")));
2433 make_pair(make_pair(
"gaus", 3), make_pair(
"[0]*exp(-0.5*(({V0}-[1])/[2])^2 - 0.5*(({V1}-[3])/[4])^2 - 0.5*(({V2}-[5])/[6])^2)",
"")));
2436 make_pair(make_pair(
"bigaus", 2), make_pair(
"[0]*ROOT::Math::bigaussian_pdf({V0},{V1},[2],[4],[5],[1],[3])",
2437 "[0]*ROOT::Math::bigaussian_pdf({V0},{V1},[2],[4],[5],[1],[3])")));
2443 void TFormula::SetPredefinedParamNames() {
2445 if (fNumber == 0)
return;
2447 if (fNumber == 100) {
2448 SetParName(0,
"Constant");
2449 SetParName(1,
"Mean");
2450 SetParName(2,
"Sigma");
2453 if (fNumber == 110) {
2454 SetParName(0,
"Constant");
2455 SetParName(1,
"MeanX");
2456 SetParName(2,
"SigmaX");
2457 SetParName(3,
"MeanY");
2458 SetParName(4,
"SigmaY");
2461 if (fNumber == 120) {
2462 SetParName(0,
"Constant");
2463 SetParName(1,
"MeanX");
2464 SetParName(2,
"SigmaX");
2465 SetParName(3,
"MeanY");
2466 SetParName(4,
"SigmaY");
2467 SetParName(5,
"MeanZ");
2468 SetParName(6,
"SigmaZ");
2471 if (fNumber == 112) {
2472 SetParName(0,
"Constant");
2473 SetParName(1,
"MeanX");
2474 SetParName(2,
"SigmaX");
2475 SetParName(3,
"MeanY");
2476 SetParName(4,
"SigmaY");
2477 SetParName(5,
"Rho");
2480 if (fNumber == 200) {
2481 SetParName(0,
"Constant");
2482 SetParName(1,
"Slope");
2485 if (fNumber == 400) {
2486 SetParName(0,
"Constant");
2487 SetParName(1,
"MPV");
2488 SetParName(2,
"Sigma");
2491 if (fNumber == 500) {
2492 SetParName(0,
"Constant");
2493 SetParName(1,
"Mean");
2494 SetParName(2,
"Sigma");
2495 SetParName(3,
"Alpha");
2499 if (fNumber == 600) {
2500 SetParName(0,
"Constant");
2501 SetParName(1,
"Mean");
2502 SetParName(2,
"Gamma");
2525 const TObject* TFormula::GetLinearPart(Int_t i)
const
2527 if (!fLinearParts.empty()) {
2528 int n = fLinearParts.size();
2529 if (i < 0 || i >= n ) {
2530 Error(
"GetLinearPart",
"Formula %s has only %d linear parts - requested %d",GetName(),n,i);
2533 return fLinearParts[i];
2541 void TFormula::AddVariable(
const TString &name,
double value)
2543 if (fVars.find(name) != fVars.end()) {
2544 TFormulaVariable &var = fVars[name];
2549 if (var.fArrayPos < 0) {
2550 var.fArrayPos = fVars.size();
2552 if (var.fArrayPos >= (
int)fClingVariables.size()) {
2553 fClingVariables.resize(var.fArrayPos + 1);
2555 fClingVariables[var.fArrayPos] = value;
2557 TFormulaVariable var(name, value, fVars.size());
2559 fClingVariables.push_back(value);
2560 if (!fFormula.IsNull()) {
2562 ProcessFormula(fClingInput);
2574 void TFormula::AddVariables(
const TString *vars,
const Int_t size)
2576 Bool_t anyNewVar =
false;
2577 for (Int_t i = 0; i < size; ++i) {
2579 const TString &vname = vars[i];
2581 TFormulaVariable &var = fVars[vname];
2582 if (var.fArrayPos < 0) {
2585 var.fArrayPos = fVars.size();
2588 if (var.fArrayPos >= (
int)fClingVariables.capacity()) {
2589 Int_t multiplier = 2;
2590 if (fFuncs.size() > 100) {
2591 multiplier = TMath::Floor(TMath::Log10(fFuncs.size()) * 10);
2593 fClingVariables.reserve(multiplier * fClingVariables.capacity());
2595 fClingVariables.push_back(0.0);
2603 if (anyNewVar && !fFormula.IsNull()) {
2604 ProcessFormula(fClingInput);
2612 void TFormula::SetName(
const char* name)
2614 if (IsReservedName(name)) {
2615 Error(
"SetName",
"The name \'%s\' is reserved as a TFormula variable name.\n"
2616 "\tThis function will not be renamed.",
2621 auto listOfFunctions = gROOT->GetListOfFunctions();
2622 TObject* thisAsFunctionInList =
nullptr;
2623 R__LOCKGUARD(gROOTMutex);
2624 if (listOfFunctions){
2625 thisAsFunctionInList = listOfFunctions->FindObject(
this);
2626 if (thisAsFunctionInList) listOfFunctions->Remove(thisAsFunctionInList);
2628 TNamed::SetName(name);
2629 if (thisAsFunctionInList) listOfFunctions->Add(thisAsFunctionInList);
2641 void TFormula::SetVariables(
const pair<TString,Double_t> *vars,
const Int_t size)
2643 for(Int_t i = 0; i < size; ++i)
2646 if (fVars.find(v.first) != fVars.end()) {
2647 fVars[v.first].fValue = v.second;
2648 fClingVariables[fVars[v.first].fArrayPos] = v.second;
2650 Error(
"SetVariables",
"Variable %s is not defined.", v.first.Data());
2658 Double_t TFormula::GetVariable(
const char *name)
const
2660 const auto nameIt = fVars.find(name);
2661 if (fVars.end() == nameIt) {
2662 Error(
"GetVariable",
"Variable %s is not defined.", name);
2665 return nameIt->second.fValue;
2671 Int_t TFormula::GetVarNumber(
const char *name)
const
2673 const auto nameIt = fVars.find(name);
2674 if (fVars.end() == nameIt) {
2675 Error(
"GetVarNumber",
"Variable %s is not defined.", name);
2678 return nameIt->second.fArrayPos;
2684 TString TFormula::GetVarName(Int_t ivar)
const
2686 if (ivar < 0 || ivar >= fNdim)
return "";
2689 for (
auto & v : fVars) {
2690 if (v.second.fArrayPos == ivar)
return v.first;
2692 Error(
"GetVarName",
"Variable with index %d not found !!",ivar);
2700 void TFormula::SetVariable(
const TString &name, Double_t value)
2702 if (fVars.find(name) == fVars.end()) {
2703 Error(
"SetVariable",
"Variable %s is not defined.", name.Data());
2706 fVars[name].fValue = value;
2707 fClingVariables[fVars[name].fArrayPos] = value;
2715 void TFormula::DoAddParameter(
const TString &name, Double_t value, Bool_t processFormula)
2720 if(fParams.find(name) != fParams.end() )
2722 int ipos = fParams[name];
2726 ipos = fParams.size();
2727 fParams[name] = ipos;
2730 if (ipos >= (
int)fClingParameters.size()) {
2731 if (ipos >= (
int)fClingParameters.capacity())
2732 fClingParameters.reserve(TMath::Max(
int(fParams.size()), ipos + 1));
2733 fClingParameters.insert(fClingParameters.end(), ipos + 1 - fClingParameters.size(), 0.0);
2735 fClingParameters[ipos] = value;
2740 int pos = fParams.size();
2742 auto ret = fParams.insert(std::make_pair(name, pos));
2748 if (ret.first == fParams.begin())
2751 auto previous = (ret.first);
2753 pos = previous->second + 1;
2756 if (pos < (
int)fClingParameters.size())
2757 fClingParameters.insert(fClingParameters.begin() + pos, value);
2760 if (pos > (
int)fClingParameters.size())
2761 Warning(
"inserting parameter %s at pos %d when vector size is %d \n", name.Data(), pos,
2762 (int)fClingParameters.size());
2764 if (pos >= (
int)fClingParameters.capacity())
2765 fClingParameters.reserve(TMath::Max(
int(fParams.size()), pos + 1));
2766 fClingParameters.insert(fClingParameters.end(), pos + 1 - fClingParameters.size(), 0.0);
2767 fClingParameters[pos] = value;
2771 for (
auto it = ret.first; it != fParams.end(); ++it) {
2781 if (processFormula) {
2783 fClingInput.ReplaceAll(name, TString::Format(
"[%s]", name.Data()));
2784 ProcessFormula(fClingInput);
2793 Int_t TFormula::GetParNumber(
const char * name)
const {
2794 auto it = fParams.find(name);
2795 if (it == fParams.end()) {
2805 Double_t TFormula::GetParameter(
const char * name)
const
2807 const int i = GetParNumber(name);
2809 Error(
"GetParameter",
"Parameter %s is not defined.",name);
2810 return TMath::QuietNaN();
2813 return GetParameter( i );
2819 Double_t TFormula::GetParameter(Int_t param)
const
2822 if(param >=0 && param < (
int) fClingParameters.size())
2823 return fClingParameters[param];
2824 Error(
"GetParameter",
"wrong index used - use GetParameter(name)");
2825 return TMath::QuietNaN();
2831 const char * TFormula::GetParName(Int_t ipar)
const
2833 if (ipar < 0 || ipar >= fNpar)
return "";
2836 for (
auto & p : fParams) {
2837 if (p.second == ipar)
return p.first.Data();
2839 Error(
"GetParName",
"Parameter with index %d not found !!",ipar);
2845 Double_t* TFormula::GetParameters()
const
2847 if(!fClingParameters.empty())
2848 return const_cast<Double_t*>(&fClingParameters[0]);
2852 void TFormula::GetParameters(Double_t *params)
const
2854 for (Int_t i = 0; i < fNpar; ++i) {
2855 if (Int_t(fClingParameters.size()) > i)
2856 params[i] = fClingParameters[i];
2865 void TFormula::SetParameter(
const char *name, Double_t value)
2867 SetParameter( GetParNumber(name), value);
2871 if (fParams.find(name) == fParams.end()) {
2872 Error(
"SetParameter",
"Parameter %s is not defined.", name.Data());
2875 fParams[name].fValue = value;
2876 fParams[name].fFound =
true;
2877 fClingParameters[fParams[name].fArrayPos] = value;
2878 fAllParametersSetted =
true;
2879 for (map<TString, TFormulaVariable>::iterator it = fParams.begin(); it != fParams.end(); ++it) {
2880 if (!it->second.fFound) {
2881 fAllParametersSetted =
false;
2897 void TFormula::SetParameters(
const pair<TString,Double_t> *params,
const Int_t size)
2899 for(Int_t i = 0 ; i < size ; ++i)
2901 pair<TString, Double_t> p = params[i];
2902 if (fParams.find(p.first) == fParams.end()) {
2903 Error(
"SetParameters",
"Parameter %s is not defined", p.first.Data());
2906 fParams[p.first].fValue = p.second;
2907 fParams[p.first].fFound =
true;
2908 fClingParameters[fParams[p.first].fArrayPos] = p.second;
2910 fAllParametersSetted =
true;
2911 for (map<TString, TFormulaVariable>::iterator it = fParams.begin(); it != fParams.end(); ++it) {
2912 if (!it->second.fFound) {
2913 fAllParametersSetted =
false;
2921 void TFormula::DoSetParameters(
const Double_t *params, Int_t size)
2923 if(!params || size < 0 || size > fNpar)
return;
2925 if (size != (
int) fClingParameters.size() ) {
2926 Warning(
"SetParameters",
"size is not same of cling parameter size %d - %d",size,
int(fClingParameters.size()) );
2927 for (Int_t i = 0; i < size; ++i) {
2928 TString name = TString::Format(
"%d", i);
2929 SetParameter(name, params[i]);
2933 fAllParametersSetted =
true;
2934 std::copy(params, params+size, fClingParameters.begin() );
2942 void TFormula::SetParameters(
const Double_t *params)
2944 DoSetParameters(params,fNpar);
2952 void TFormula::SetParameters(Double_t p0, Double_t p1, Double_t p2, Double_t p3, Double_t p4, Double_t p5, Double_t p6,
2953 Double_t p7, Double_t p8, Double_t p9, Double_t p10)
2955 if(fNpar >= 1) SetParameter(0,p0);
2956 if(fNpar >= 2) SetParameter(1,p1);
2957 if(fNpar >= 3) SetParameter(2,p2);
2958 if(fNpar >= 4) SetParameter(3,p3);
2959 if(fNpar >= 5) SetParameter(4,p4);
2960 if(fNpar >= 6) SetParameter(5,p5);
2961 if(fNpar >= 7) SetParameter(6,p6);
2962 if(fNpar >= 8) SetParameter(7,p7);
2963 if(fNpar >= 9) SetParameter(8,p8);
2964 if(fNpar >= 10) SetParameter(9,p9);
2965 if(fNpar >= 11) SetParameter(10,p10);
2973 void TFormula::SetParameter(Int_t param, Double_t value)
2975 if (param < 0 || param >= fNpar)
return;
2976 assert(
int(fClingParameters.size()) == fNpar);
2977 fClingParameters[param] = value;
2983 void TFormula::SetParNames(
const char *name0,
const char *name1,
const char *name2,
const char *name3,
2984 const char *name4,
const char *name5,
const char *name6,
const char *name7,
2985 const char *name8,
const char *name9,
const char *name10)
2988 SetParName(0, name0);
2990 SetParName(1, name1);
2992 SetParName(2, name2);
2994 SetParName(3, name3);
2996 SetParName(4, name4);
2998 SetParName(5, name5);
3000 SetParName(6, name6);
3002 SetParName(7, name7);
3004 SetParName(8, name8);
3006 SetParName(9, name9);
3008 SetParName(10, name10);
3012 void TFormula::SetParName(Int_t ipar,
const char * name)
3015 if (ipar < 0 || ipar > fNpar) {
3016 Error(
"SetParName",
"Wrong Parameter index %d ",ipar);
3021 for (
auto &it : fParams) {
3022 if (it.second == ipar) {
3024 fParams.erase(oldName);
3025 fParams.insert(std::make_pair(name, ipar) );
3029 if (oldName.IsNull() ) {
3030 Error(
"SetParName",
"Parameter %d is not existing.",ipar);
3035 if (! TestBit(TFormula::kLambda)) ReplaceParamName(fFormula, oldName, name);
3042 void TFormula::ReplaceParamName(TString & formula,
const TString & oldName,
const TString & name){
3043 if (!formula.IsNull() ) {
3045 for(list<TFormulaFunction>::iterator it = fFuncs.begin(); it != fFuncs.end(); ++it)
3047 if (oldName == it->GetName()) {
3054 Error(
"SetParName",
"Parameter %s is not defined.", oldName.Data());
3058 TString newName = name;
3059 newName.ReplaceAll(
" ",
"\\s");
3060 TString pattern = TString::Format(
"[%s]", oldName.Data());
3061 TString replacement = TString::Format(
"[%s]", newName.Data());
3062 formula.ReplaceAll(pattern, replacement);
3068 void TFormula::SetVectorized(Bool_t vectorized)
3070 #ifdef R__HAS_VECCORE
3072 Info(
"SetVectorized",
"Cannot vectorized a function of zero dimension");
3075 if (vectorized != fVectorized) {
3077 Error(
"SetVectorized",
"Cannot set vectorized to %d -- Formula is missing", vectorized);
3079 fVectorized = vectorized;
3082 fClingInitialized =
false;
3083 fReadyToExecute =
false;
3085 fClingInput = fFormula;
3091 FillVecFunctionsShurtCuts();
3092 PreProcessFormula(fFormula);
3093 PrepareFormula(fFormula);
3097 Warning(
"SetVectorized",
"Cannot set vectorized -- try building with option -Dbuiltin_veccore=On");
3102 Double_t TFormula::EvalPar(
const Double_t *x,
const Double_t *params)
const
3105 return DoEval(x, params);
3107 #ifdef R__HAS_VECCORE
3109 if (fNdim == 0 || !x) {
3110 ROOT::Double_v ret = DoEvalVec(
nullptr, params);
3111 return vecCore::Get( ret, 0 );
3118 Info(
"EvalPar",
"Function is vectorized - converting Double_t into ROOT::Double_v and back");
3121 const int maxDim = 4;
3122 std::array<ROOT::Double_v, maxDim> xvec;
3123 for (
int i = 0; i < fNdim; i++)
3126 ROOT::Double_v ans = DoEvalVec(xvec.data(), params);
3127 return vecCore::Get(ans, 0);
3130 std::vector<ROOT::Double_v> xvec(fNdim);
3131 for (
int i = 0; i < fNdim; i++)
3134 ROOT::Double_v ans = DoEvalVec(xvec.data(), params);
3135 return vecCore::Get(ans, 0);
3140 Error(
"EvalPar",
"Formula is vectorized (even though VECCORE is disabled!)");
3141 return TMath::QuietNaN();
3145 bool TFormula::fIsCladRuntimeIncluded =
false;
3147 static bool functionExists(
const string &Name) {
3148 return gInterpreter->GetFunction(0, Name.c_str());
3152 bool TFormula::GenerateGradientPar()
3158 if (!HasGradientGenerationFailed()) {
3160 if (!TFormula::fIsCladRuntimeIncluded) {
3161 TFormula::fIsCladRuntimeIncluded =
true;
3162 gInterpreter->Declare(
"#include <Math/CladDerivator.h>\n#pragma clad OFF");
3169 if (!functionExists(GetGradientFuncName())) {
3170 std::string GradReqFuncName = GetGradientFuncName() +
"_req";
3172 fGradGenerationInput = std::string(
"#pragma cling optimize(2)\n") +
3173 "#pragma clad ON\n" +
3174 "void " + GradReqFuncName +
"() {\n" +
3175 "clad::gradient(" + std::string(fClingName.Data()) +
");\n }\n" +
3178 if (!gInterpreter->Declare(fGradGenerationInput.c_str()))
3182 Bool_t hasParameters = (fNpar > 0);
3183 Bool_t hasVariables = (fNdim > 0);
3184 std::string GradFuncName = GetGradientFuncName();
3185 fGradMethod = prepareMethod(hasParameters, hasVariables,
3186 GradFuncName.c_str(),
3188 fGradFuncPtr = prepareFuncPtr(fGradMethod.get());
3194 void TFormula::GradientPar(
const Double_t *x, TFormula::GradientStorage& result)
3196 if (DoEval(x) == TMath::QuietNaN())
3199 if (!fClingInitialized) {
3200 Error(
"GradientPar",
"Could not initialize the formula!");
3204 if (!GenerateGradientPar()) {
3205 Error(
"GradientPar",
"Could not generate a gradient for the formula %s!",
3210 if ((
int)result.size() < fNpar) {
3211 Warning(
"GradientPar",
3212 "The size of gradient result is %zu but %d is required. Resizing.",
3213 result.size(), fNpar);
3214 result.resize(fNpar);
3216 GradientPar(x, result.data());
3219 void TFormula::GradientPar(
const Double_t *x, Double_t *result)
3222 const double * vars = (x) ? x : fClingVariables.data();
3236 (*fGradFuncPtr)(0, 2, args,
nullptr);
3245 const double *pars = fClingParameters.data();
3248 (*fGradFuncPtr)(0, 3, args,
nullptr);
3253 #ifdef R__HAS_VECCORE
3260 ROOT::Double_v TFormula::EvalParVec(
const ROOT::Double_v *x,
const Double_t *params)
const
3263 return DoEvalVec(x, params);
3265 if (fNdim == 0 || !x)
3266 return DoEval(
nullptr, params);
3271 Info(
"EvalPar",
"Function is not vectorized - converting ROOT::Double_v into Double_t and back");
3273 const int vecSize = vecCore::VectorSize<ROOT::Double_v>();
3274 std::vector<Double_t> xscalars(vecSize*fNdim);
3276 for (
int i = 0; i < vecSize; i++)
3277 for (
int j = 0; j < fNdim; j++)
3278 xscalars[i*fNdim+j] = vecCore::Get(x[j],i);
3280 ROOT::Double_v answers(0.);
3281 for (
int i = 0; i < vecSize; i++)
3282 vecCore::Set(answers, i, DoEval(&xscalars[i*fNdim], params));
3291 Double_t TFormula::Eval(Double_t x, Double_t y, Double_t z, Double_t t)
const
3293 double xxx[4] = {x,y,z,t};
3294 return EvalPar(xxx,
nullptr);
3300 Double_t TFormula::Eval(Double_t x, Double_t y , Double_t z)
const
3302 double xxx[3] = {x,y,z};
3303 return EvalPar(xxx,
nullptr);
3309 Double_t TFormula::Eval(Double_t x, Double_t y)
const
3311 double xxx[2] = {x,y};
3312 return EvalPar(xxx,
nullptr);
3318 Double_t TFormula::Eval(Double_t x)
const
3321 return EvalPar(xxx,
nullptr);
3330 Double_t TFormula::DoEval(
const double * x,
const double * params)
const
3332 if(!fReadyToExecute)
3334 Error(
"Eval",
"Formula is invalid and not ready to execute ");
3335 for (
auto it = fFuncs.begin(); it != fFuncs.end(); ++it) {
3336 TFormulaFunction fun = *it;
3338 printf(
"%s is unknown.\n", fun.GetName());
3341 return TMath::QuietNaN();
3345 if (!fClingInitialized && fLazyInitialization) {
3347 R__LOCKGUARD(gROOTMutex);
3348 auto thisFormula =
const_cast<TFormula*
>(
this);
3349 thisFormula->ReInitializeEvalMethod();
3351 if (!fClingInitialized) {
3352 Error(
"DoEval",
"Formula has error and it is not properly initialized ");
3353 return TMath::QuietNaN();
3356 if (fLambdaPtr && TestBit(TFormula::kLambda)) {
3357 std::function<double(double *, double *)> & fptr = * ( (std::function<double(double *, double *)> *) fLambdaPtr);
3360 double * v =
const_cast<double*
>(x);
3361 double * p = (params) ? const_cast<double*>(params) :
const_cast<double*
>(fClingParameters.data());
3366 Double_t result = 0;
3368 double * vars = (x) ? const_cast<double*>(x) :
const_cast<double*
>(fClingVariables.data());
3371 (*fFuncPtr)(0, 1, args, &result);
3373 double *pars = (params) ? const_cast<double *>(params) :
const_cast<double *
>(fClingParameters.data());
3375 (*fFuncPtr)(0, 2, args, &result);
3382 #ifdef R__HAS_VECCORE
3383 ROOT::Double_v TFormula::DoEvalVec(
const ROOT::Double_v *x,
const double *params)
const
3385 if (!fReadyToExecute) {
3386 Error(
"Eval",
"Formula is invalid and not ready to execute ");
3387 for (
auto it = fFuncs.begin(); it != fFuncs.end(); ++it) {
3388 TFormulaFunction fun = *it;
3390 printf(
"%s is unknown.\n", fun.GetName());
3393 return TMath::QuietNaN();
3397 if (!fClingInitialized && fLazyInitialization) {
3399 R__LOCKGUARD(gROOTMutex);
3400 auto thisFormula =
const_cast<TFormula*
>(
this);
3401 thisFormula->ReInitializeEvalMethod();
3404 ROOT::Double_v result = 0;
3407 ROOT::Double_v *vars =
const_cast<ROOT::Double_v *
>(x);
3410 (*fFuncPtr)(0, 1, args, &result);
3412 double *pars = (params) ? const_cast<double *>(params) :
const_cast<double *
>(fClingParameters.data());
3414 (*fFuncPtr)(0, 2, args, &result);
3418 #endif // R__HAS_VECCORE
3427 void TFormula::ReInitializeEvalMethod() {
3430 if (TestBit(TFormula::kLambda) ) {
3431 Info(
"ReInitializeEvalMethod",
"compile now lambda expression function using Cling");
3432 InitLambdaExpression(fFormula);
3433 fLazyInitialization =
false;
3440 if (!fLazyInitialization) Warning(
"ReInitializeEvalMethod",
"Formula is NOT properly initialized - try calling again TFormula::PrepareEvalMethod");
3446 R__LOCKGUARD(gROOTMutex);
3452 auto funcit = gClingFunctions.find(fSavedInputFormula);
3454 if (funcit != gClingFunctions.end()) {
3455 fFuncPtr = (TFormula::CallFuncSignature)funcit->second;
3456 fClingInitialized =
true;
3457 fLazyInitialization =
false;
3462 InputFormulaIntoCling();
3463 if (fClingInitialized && !fLazyInitialization) Info(
"ReInitializeEvalMethod",
"Formula is now properly initialized !!");
3464 fLazyInitialization =
false;
3467 if (fClingInitialized) {
3468 R__ASSERT(!fSavedInputFormula.empty());
3471 R__LOCKGUARD(gROOTMutex);
3472 gClingFunctions.insert(std::make_pair(fSavedInputFormula, (
void *)fFuncPtr));
3486 TString TFormula::GetExpFormula(Option_t *option)
const
3488 TString opt(option);
3489 if (opt.IsNull() || TestBit(TFormula::kLambda) )
return fFormula;
3497 if (opt.Contains(
"CLING") ) {
3498 std::string clingFunc = fClingInput.Data();
3499 std::size_t found = clingFunc.find(
"return");
3500 std::size_t found2 = clingFunc.rfind(
";");
3501 if (found == std::string::npos || found2 == std::string::npos) {
3502 Error(
"GetExpFormula",
"Invalid Cling expression - return default formula expression");
3505 TString clingFormula = fClingInput(found+7,found2-found-7);
3507 if (!opt.Contains(
"P"))
return clingFormula;
3510 while (i < clingFormula.Length()-2 ) {
3512 if (clingFormula[i] ==
'p' && clingFormula[i+1] ==
'[' && isdigit(clingFormula[i+2]) ) {
3514 while ( isdigit(clingFormula[j]) ) { j++;}
3515 if (clingFormula[j] !=
']') {
3516 Error(
"GetExpFormula",
"Parameters not found - invalid expression - return default cling formula");
3517 return clingFormula;
3519 TString parNumbName = clingFormula(i+2,j-i-2);
3520 int parNumber = parNumbName.Atoi();
3521 assert(parNumber < fNpar);
3522 TString replacement = TString::Format(
"%f",GetParameter(parNumber));
3523 clingFormula.Replace(i,j-i+1, replacement );
3524 i += replacement.Length();
3528 return clingFormula;
3530 if (opt.Contains(
"P") ) {
3532 TString expFormula = fFormula;
3534 while (i < expFormula.Length()-2 ) {
3536 if (expFormula[i] ==
'[') {
3538 while ( expFormula[j] !=
']' ) { j++;}
3539 if (expFormula[j] !=
']') {
3540 Error(
"GetExpFormula",
"Parameter names not found - invalid expression - return default formula");
3543 TString parName = expFormula(i+1,j-i-1);
3544 TString replacement = TString::Format(
"%g",GetParameter(parName));
3545 expFormula.Replace(i,j-i+1, replacement );
3546 i += replacement.Length();
3552 Warning(
"GetExpFormula",
"Invalid option - return default formula expression");
3556 TString TFormula::GetGradientFormula()
const {
3557 std::unique_ptr<TInterpreterValue> v = gInterpreter->MakeInterpreterValue();
3558 gInterpreter->Evaluate(GetGradientFuncName().c_str(), *v);
3559 return v->ToString();
3565 void TFormula::Print(Option_t *option)
const
3567 printf(
" %20s : %s Ndim= %d, Npar= %d, Number= %d \n",GetName(),GetTitle(), fNdim,fNpar,fNumber);
3568 printf(
" Formula expression: \n");
3569 printf(
"\t%s \n",fFormula.Data() );
3570 TString opt(option);
3575 if (opt.Contains(
"V") ) {
3576 if (fNdim > 0 && !TestBit(TFormula::kLambda)) {
3577 printf(
"List of Variables: \n");
3578 assert(
int(fClingVariables.size()) >= fNdim);
3579 for (
int ivar = 0; ivar < fNdim ; ++ivar) {
3580 printf(
"Var%4d %20s = %10f \n",ivar,GetVarName(ivar).Data(), fClingVariables[ivar]);
3584 printf(
"List of Parameters: \n");
3585 if (
int(fClingParameters.size()) < fNpar)
3586 Error(
"Print",
"Number of stored parameters in vector %zu in map %zu is different than fNpar %d",fClingParameters.size(), fParams.size(), fNpar);
3587 assert(
int(fClingParameters.size()) >= fNpar);
3589 for (
int ipar = 0; ipar < fNpar ; ++ipar) {
3590 printf(
"Par%4d %20s = %10f \n",ipar,GetParName(ipar), fClingParameters[ipar] );
3593 printf(
"Expression passed to Cling:\n");
3594 printf(
"\t%s\n",fClingInput.Data() );
3596 printf(
"Generated Gradient:\n");
3597 printf(
"%s\n", fGradGenerationInput.c_str());
3598 printf(
"%s\n", GetGradientFormula().Data());
3601 if(!fReadyToExecute)
3603 Warning(
"Print",
"Formula is not ready to execute. Missing parameters/variables");
3604 for (list<TFormulaFunction>::const_iterator it = fFuncs.begin(); it != fFuncs.end(); ++it) {
3605 TFormulaFunction fun = *it;
3607 printf(
"%s is unknown.\n", fun.GetName());
3611 if (!fAllParametersSetted) {
3628 void TFormula::Streamer(TBuffer &b)
3630 if (b.IsReading() ) {
3632 Version_t v = b.ReadVersion(&R__s, &R__c);
3634 if (v <= 8 && v > 3 && v != 6) {
3636 ROOT::v5::TFormula * fold =
new ROOT::v5::TFormula();
3638 fold->Streamer(b, v, R__s, R__c, TFormula::Class());
3640 TFormula fnew(fold->GetName(), fold->GetExpFormula() );
3645 SetParameters(fold->GetParameters() );
3646 if (!fReadyToExecute ) {
3647 Error(
"Streamer",
"Old formula read from file is NOT valid");
3655 b.ReadClassBuffer(TFormula::Class(),
this, v, R__s, R__c);
3664 if (fFormula.IsNull() )
return;
3668 std::vector<double> parValues = fClingParameters;
3669 auto paramMap = fParams;
3670 fNpar = fParams.size();
3672 fLazyInitialization =
true;
3674 if (!TestBit(TFormula::kLambda) ) {
3685 fClingParameters.clear();
3690 PreProcessFormula(fFormula);
3694 PrepareFormula(fFormula);
3700 if (fNpar != (
int) parValues.size() ) {
3701 Error(
"Streamer",
"number of parameters computed (%d) is not same as the stored parameters (%d)",fNpar,
int(parValues.size()) );
3704 if (v > 11 && fNdim != ndim) {
3705 Error(
"Streamer",
"number of dimension computed (%d) is not same as the stored value (%d)",fNdim, ndim );
3711 if (!fLazyInitialization) {
3712 bool ret = InitLambdaExpression(fFormula);
3714 fClingInitialized =
true;
3717 fReadyToExecute =
true;
3720 assert(fNpar == (
int) parValues.size() );
3721 std::copy( parValues.begin(), parValues.end(), fClingParameters.begin() );
3723 if (fParams.size() != paramMap.size() ) {
3724 Warning(
"Streamer",
"number of parameters list found (%zu) is not same as the stored one (%zu) - use re-created list",fParams.size(),paramMap.size()) ;
3738 if (!TestBit(kNotGlobal)) {
3739 R__LOCKGUARD(gROOTMutex);
3740 gROOT->GetListOfFunctions()->Add(
this);
3742 if (!fReadyToExecute ) {
3743 Error(
"Streamer",
"Formula read from file is NOT ready to execute");
3751 Error(
"Streamer",
"Reading version %d is not supported",v);
3757 b.WriteClassBuffer(TFormula::Class(),
this);