27#include <unordered_map>
34#pragma optimize("",off)
213static std::unordered_map<std::string, void *>
gClingFunctions = std::unordered_map<std::string, void * >();
220 for (
int i = 0; i < nobjects; ++i) {
221 if (fromv5[i] && target[i]) {
222 TFormula fnew(fromv5[i]->GetName(), fromv5[i]->GetExpFormula());
238 const static std::set<char> ops {
'+',
'^',
'-',
'/',
'*',
'<',
'>',
'|',
'&',
'!',
'=',
'?',
'%'};
239 return ops.end() != ops.find(
c);
246 char brackets[] = {
')',
'(',
'{',
'}'};
247 Int_t bracketsLen =
sizeof(brackets)/
sizeof(
char);
248 for(
Int_t i = 0; i < bracketsLen; ++i)
270 if ( (formula[i] ==
'e' || formula[i] ==
'E') && (i > 0 && i < formula.
Length()-1) ) {
272 if ( (isdigit(formula[i-1]) || formula[i-1] ==
'.') && ( isdigit(formula[i+1]) || formula[i+1] ==
'+' || formula[i+1] ==
'-' ) )
282 if ( (formula[i] ==
'x' || formula[i] ==
'X') && (i > 0 && i < formula.
Length()-1) && formula[i-1] ==
'0') {
283 if (isdigit(formula[i+1]) )
285 static char hex_values[12] = {
'a',
'A',
'b',
'B',
'c',
'C',
'd',
'D',
'e',
'E',
'f',
'F'};
286 for (
int jjj = 0; jjj < 12; ++jjj) {
287 if (formula[i+1] == hex_values[jjj])
304 Bool_t foundOpenParenthesis =
false;
305 if (pos == 0 || pos == formula.
Length()-1)
return false;
306 for (
int i = pos-1; i >=0; i--) {
307 if (formula[i] ==
']' )
return false;
308 if (formula[i] ==
'[' ) {
309 foundOpenParenthesis =
true;
313 if (!foundOpenParenthesis )
return false;
316 for (
int i = pos+1; i < formula.
Length(); i++) {
317 if (formula[i] ==
']' )
return true;
330 TRegexp numericPattern(
"p?[0-9]+");
333 int patternStart = numericPattern.
Index(
a, &len);
334 bool aNumeric = (patternStart == 0 && len ==
a.Length());
336 patternStart = numericPattern.
Index(
b, &len);
337 bool bNumeric = (patternStart == 0 && len ==
b.Length());
339 if (aNumeric && !bNumeric)
341 else if (!aNumeric && bNumeric)
343 else if (!aNumeric && !bNumeric)
346 int aInt = (
a[0] ==
'p') ?
TString(
a(1,
a.Length())).
Atoi() :
a.Atoi();
347 int bInt = (
b[0] ==
'p') ?
TString(
b(1,
b.Length())).
Atoi() :
b.Atoi();
358 for (
int i = 0; i < formula.
Length(); i++) {
361 if (isalpha(formula[i]) || formula[i] ==
'{' || formula[i] ==
'[') {
365 || (formula[i] ==
'{' && formula[j] ==
'}'));
373 if (substitutions.find(
name) != substitutions.end()) {
377 }
else if (isalpha(formula[i])) {
380 i +=
name.Length() - 1;
405 if (strlen(
name)!=1)
return false;
406 for (
auto const & specialName : {
"x",
"y",
"z",
"t"}){
407 if (strcmp(
name,specialName)==0)
return true;
420 gROOT->GetListOfFunctions()->Remove(
this);
425 for (
int i = 0; i < nLinParts; ++i)
delete fLinearParts[i];
432 fClingInput(formula),fFormula(formula)
441#ifndef R__HAS_VECCORE
457 if (addToGlobList &&
gROOT) {
462 gROOT->GetListOfFunctions()->Remove(old);
464 Error(
"TFormula",
"The name %s is reserved as a TFormula variable name.\n",
name);
466 gROOT->GetListOfFunctions()->Add(
this);
478 fClingInput(formula),fFormula(formula)
490 for (
int i = 0; i < npar; ++i) {
494 assert (
fNpar == npar);
504 if (addToGlobList &&
gROOT) {
509 gROOT->GetListOfFunctions()->Remove(old);
511 Error(
"TFormula",
"The name %s is reserved as a TFormula variable name.\n",
name);
513 gROOT->GetListOfFunctions()->Add(
this);
518 Error(
"TFormula",
"Syntax error in building the lambda expression %s", formula );
523 TNamed(formula.GetName(),formula.GetTitle())
531 gROOT->GetListOfFunctions()->Remove(old);
534 Error(
"TFormula",
"The name %s is reserved as a TFormula variable name.\n",formula.
GetName());
536 gROOT->GetListOfFunctions()->Add(
this);
556 std::string lambdaExpression = formula;
580 TString lineExpr =
TString::Format(
"std::function<double(double*,double*)> %s = %s ;",lambdaName.
Data(), lambdaExpression.c_str() );
607 if (formula.
IsNull() )
return -1;
619 return (ret) ? 0 : 1;
629 return (ret) ? 0 : 1;
658 for (
int i = 0; i < nLinParts; ++i)
delete fnew.
fLinearParts[i];
665 for (
int i = 0; i < nLinParts; ++i) {
669 linearOld->
Copy(*linearNew);
694 Error(
"TFormula",
"Syntax error in building the lambda expression %s",
fFormula.
Data() );
741 for (
int i = 0; i < nLinParts; ++i)
delete fLinearParts[i];
748static std::unique_ptr<TMethodCall>
750 bool IsVectorized,
bool IsGradient =
false) {
751 std::unique_ptr<TMethodCall> Method = std::unique_ptr<TMethodCall>(
new TMethodCall());
753 TString prototypeArguments =
"";
754 if (HasVariables || HasParameters) {
756 prototypeArguments.
Append(
"ROOT::Double_v*");
758 prototypeArguments.
Append(
"Double_t*");
760 auto AddDoublePtrParam = [&prototypeArguments] () {
761 prototypeArguments.
Append(
",");
762 prototypeArguments.
Append(
"Double_t*");
773 Method->InitWithPrototype(FuncName, prototypeArguments);
774 if (!Method->IsValid()) {
775 Error(
"prepareMethod",
776 "Can't compile function %s prototype with arguments %s", FuncName,
777 prototypeArguments.
Data());
785 if (!method)
return nullptr;
789 Error(
"prepareFuncPtr",
"Callfunc retuned from Cling is not valid");
796 Error(
"prepareFuncPtr",
"Compiled function pointer is null");
832 TString triggerAutoparsing =
"namespace ROOT_TFormula_triggerAutoParse {\n"; triggerAutoparsing +=
fClingInput +
"\n}";
851 const TString defvars[] = {
"x",
"y",
"z",
"t"};
852 const pair<TString, Double_t> defconsts[] = {{
"pi",
TMath::Pi()},
870 const pair<TString,TString> funShortcuts[] =
871 { {
"sin",
"TMath::Sin" },
872 {
"cos",
"TMath::Cos" }, {
"exp",
"TMath::Exp"}, {
"log",
"TMath::Log"}, {
"log10",
"TMath::Log10"},
873 {
"tan",
"TMath::Tan"}, {
"sinh",
"TMath::SinH"}, {
"cosh",
"TMath::CosH"},
874 {
"tanh",
"TMath::TanH"}, {
"asin",
"TMath::ASin"}, {
"acos",
"TMath::ACos"},
875 {
"atan",
"TMath::ATan"}, {
"atan2",
"TMath::ATan2"}, {
"sqrt",
"TMath::Sqrt"},
876 {
"ceil",
"TMath::Ceil"}, {
"floor",
"TMath::Floor"}, {
"pow",
"TMath::Power"},
877 {
"binomial",
"TMath::Binomial"},{
"abs",
"TMath::Abs"},
878 {
"min",
"TMath::Min"},{
"max",
"TMath::Max"},{
"sign",
"TMath::Sign" },
882 std::vector<TString> defvars2(10);
883 for (
int i = 0; i < 9; ++i)
886 for (
const auto &var : defvars) {
887 int pos =
fVars.size();
900 for (
auto con : defconsts) {
901 fConsts[con.first] = con.second;
906 for (
auto fun : funShortcuts) {
919 const pair<TString,TString> vecFunShortcuts[] =
920 { {
"sin",
"vecCore::math::Sin" },
921 {
"cos",
"vecCore::math::Cos" }, {
"exp",
"vecCore::math::Exp"}, {
"log",
"vecCore::math::Log"}, {
"log10",
"vecCore::math::Log10"},
922 {
"tan",
"vecCore::math::Tan"},
924 {
"asin",
"vecCore::math::ASin"},
925 {
"acos",
"TMath::Pi()/2-vecCore::math::ASin"},
926 {
"atan",
"vecCore::math::ATan"},
927 {
"atan2",
"vecCore::math::ATan2"}, {
"sqrt",
"vecCore::math::Sqrt"},
928 {
"ceil",
"vecCore::math::Ceil"}, {
"floor",
"vecCore::math::Floor"}, {
"pow",
"vecCore::math::Pow"},
929 {
"cbrt",
"vecCore::math::Cbrt"},{
"abs",
"vecCore::math::Abs"},
930 {
"min",
"vecCore::math::Min"},{
"max",
"vecCore::math::Max"},{
"sign",
"vecCore::math::Sign" }
934 for (
auto fun : vecFunShortcuts) {
954 Bool_t defaultVariable =
false;
956 Int_t openingBracketPos = formula.
Index(
'(', polPos);
957 Bool_t defaultCounter = openingBracketPos ==
kNPOS;
958 Bool_t defaultDegree =
true;
959 Int_t degree, counter;
961 if (!defaultCounter) {
964 sdegree = formula(polPos + 3, openingBracketPos - polPos - 3);
966 defaultCounter =
true;
968 if (!defaultCounter) {
969 degree = sdegree.
Atoi();
970 counter =
TString(formula(openingBracketPos + 1, formula.
Index(
')', polPos) - openingBracketPos)).
Atoi();
972 Int_t temp = polPos + 3;
973 while (temp < formula.
Length() && isdigit(formula[temp])) {
974 defaultDegree =
false;
977 degree =
TString(formula(polPos + 3, temp - polPos - 3)).
Atoi();
982 if (polPos - 1 < 0 || !
IsFunctionNameChar(formula[polPos - 1]) || formula[polPos - 1] ==
':') {
984 defaultVariable =
true;
986 Int_t tmp = polPos - 1;
990 variable = formula(tmp + 1, polPos - (tmp + 1));
992 Int_t param = counter + 1;
994 while (tmp <= degree) {
1004 replacement.
Insert(0,
'(');
1008 if (defaultCounter && !defaultDegree) {
1010 }
else if (defaultCounter && defaultDegree) {
1013 pattern =
TString::Format(
"%spol%d(%d)", (defaultVariable ?
"" : variable.
Data()), degree, counter);
1017 Error(
"HandlePolN",
"Error handling polynomial function - expression is %s - trying to replace %s with %s ",
1021 if (formula == pattern) {
1027 polPos = formula.
Index(
"pol");
1053 map< pair<TString,Int_t> ,pair<TString,TString> > functions;
1056 map<TString,Int_t> functionsNumbers;
1057 functionsNumbers[
"gaus"] = 100;
1058 functionsNumbers[
"bigaus"] = 102;
1059 functionsNumbers[
"landau"] = 400;
1060 functionsNumbers[
"expo"] = 200;
1061 functionsNumbers[
"crystalball"] = 500;
1072 formula.
ReplaceAll(
"xylandau",
"landau[x,y]");
1075 const char * defaultVariableNames[] = {
"x",
"y",
"z"};
1077 for (map<pair<TString, Int_t>, pair<TString, TString>>::iterator it = functions.begin(); it != functions.end();
1080 TString funName = it->first.first;
1081 Int_t funDim = it->first.second;
1091 Int_t iposBefore = funPos - 1;
1094 if (iposBefore >= 0) {
1095 assert(iposBefore < formula.
Length());
1100 funPos = formula.
Index(funName, lastFunPos);
1105 Bool_t isNormalized =
false;
1106 if (lastFunPos < formula.
Length()) {
1108 isNormalized = (formula[lastFunPos] ==
'n');
1111 if (lastFunPos < formula.
Length()) {
1112 char c = formula[lastFunPos];
1115 if (isalnum(
c) || (!
IsOperator(
c) &&
c !=
'(' &&
c !=
')' &&
c !=
'[' &&
c !=
']')) {
1117 funPos = formula.
Index(funName, lastFunPos);
1126 std::vector<TString> variables;
1129 Bool_t defaultVariables =
false;
1132 Int_t openingBracketPos = funPos + funName.
Length() + (isNormalized ? 1 : 0);
1134 if (openingBracketPos > formula.
Length() || formula[openingBracketPos] !=
'[') {
1136 variables.resize(dim);
1137 for (
Int_t idim = 0; idim < dim; ++idim)
1138 variables[idim] = defaultVariableNames[idim];
1139 defaultVariables =
true;
1142 closingBracketPos = formula.
Index(
']', openingBracketPos);
1143 varList = formula(openingBracketPos + 1, closingBracketPos - openingBracketPos - 1);
1145 variables.resize(dim);
1150 varName.
Append(varList[i]);
1152 if (varList[i] ==
',') {
1153 variables[Nvar] = varName;
1160 variables[Nvar] = varName;
1165 if (dim != funDim) {
1166 pair<TString, Int_t> key = make_pair(funName, dim);
1167 if (functions.find(key) == functions.end()) {
1168 Error(
"PreProcessFormula",
"Dimension of function %s is detected to be of dimension %d and is not "
1169 "compatible with existing pre-defined function which has dim %d",
1170 funName.
Data(), dim, funDim);
1174 funPos = formula.
Index(funName, lastFunPos);
1179 Int_t openingParenthesisPos = (closingBracketPos ==
kNPOS) ? openingBracketPos : closingBracketPos + 1;
1180 bool defaultCounter = (openingParenthesisPos > formula.
Length() || formula[openingParenthesisPos] !=
'(');
1185 if (defaultCounter) {
1191 TRegexp counterPattern(
"([0-9]+)");
1193 if (counterPattern.
Index(formula, &len, openingParenthesisPos) == -1) {
1194 funPos = formula.
Index(funName, funPos + 1);
1198 TString(formula(openingParenthesisPos + 1, formula.
Index(
')', funPos) - openingParenthesisPos - 1))
1204 TString body = (isNormalized ? it->second.second : it->second.first);
1205 if (isNormalized && body ==
"") {
1206 Error(
"PreprocessFormula",
"%d dimension function %s has no normalized form.", it->first.second,
1210 for (
int i = 0; i < body.
Length(); ++i) {
1211 if (body[i] ==
'{') {
1215 TString variable = variables[num];
1219 i += variable.
Length() - 1;
1220 }
else if (body[i] ==
'[') {
1223 while (tmp < body.
Length() && body[tmp] !=
']') {
1230 body.
Replace(i + 1, tmp - 1 - i, replacement, replacement.
Length());
1231 i += replacement.
Length() + 1;
1235 if (defaultCounter && defaultVariables) {
1238 if (!defaultCounter && defaultVariables) {
1239 pattern =
TString::Format(
"%s%s(%d)", funName.
Data(), (isNormalized ?
"n" :
""), counter);
1241 if (defaultCounter && !defaultVariables) {
1244 if (!defaultCounter && !defaultVariables) {
1252 fNumber = functionsNumbers[funName] + 10 * (dim - 1);
1259 funPos = formula.
Index(funName);
1269 TRegexp rangePattern(
"\\[[0-9]+\\.\\.[0-9]+\\]");
1272 while ((matchIdx = rangePattern.
Index(formula, &len, matchIdx)) != -1) {
1273 int startIdx = matchIdx + 1;
1274 int endIdx = formula.
Index(
"..", startIdx) + 2;
1278 if (endCnt <= startCnt)
1279 Error(
"HandleParamRanges",
"End parameter (%d) <= start parameter (%d) in parameter range", endCnt, startCnt);
1282 for (
int cnt = startCnt; cnt < endCnt; cnt++)
1287 formula.
Replace(matchIdx, formula.
Index(
"]", matchIdx) + 1 - matchIdx, newString);
1289 matchIdx += newString.
Length();
1303 std::map<std::pair<TString, Int_t>, std::pair<TString, TString>> parFunctions;
1311 if (formula[i] ==
'[') {
1312 while (formula[i] !=
']')
1317 if (formula[i] ==
'\"') {
1320 while (formula[i] !=
'\"');
1334 if (isalpha(formula[i]) && !
IsOperator(formula[i])) {
1347 std::vector<int> argSeparators;
1348 argSeparators.push_back(j);
1350 for (k = j + 1; depth >= 1 && k < formula.
Length(); k++) {
1351 if (formula[k] ==
',' && depth == 1) {
1353 argSeparators.push_back(k);
1354 }
else if (formula[k] ==
'(')
1356 else if (formula[k] ==
')')
1359 argSeparators.push_back(k - 1);
1370 TF1 *
f1 =
dynamic_cast<TF1 *
>(obj);
1378 bool nameRecognized = (
f !=
nullptr);
1385 ndim =
f->GetNdim();
1386 npar =
f->GetNpar();
1387 replacementFormula =
f->GetExpFormula();
1391 for (
auto keyval : parFunctions) {
1393 pair<TString, Int_t> name_ndim = keyval.first;
1395 pair<TString, TString> formulaPair = keyval.second;
1398 if (
name == name_ndim.first)
1399 replacementFormula = formulaPair.first;
1400 else if (
name == name_ndim.first +
"n" && formulaPair.second !=
"")
1401 replacementFormula = formulaPair.second;
1406 ndim = name_ndim.second;
1411 while ((idx = replacementFormula.
Index(
'[', idx)) !=
kNPOS) {
1412 npar = max(npar, 1 +
TString(replacementFormula(idx + 1, replacementFormula.
Length())).
Atoi());
1413 idx = replacementFormula.
Index(
']', idx);
1415 Error(
"HandleFunctionArguments",
"Square brackets not matching in formula %s",
1416 (
const char *)replacementFormula);
1423 if (nArguments == ndim + npar || nArguments == npar || nArguments == ndim) {
1424 nameRecognized =
true;
1429 if (nameRecognized && ndim > 4)
1430 Error(
"HandleFunctionArguments",
"Number of dimensions %d greater than 4. Cannot parse formula.", ndim);
1433 if (nameRecognized && j < formula.
Length() && formula[j] ==
'(') {
1438 map<TString, TString> argSubstitutions;
1440 const char *defaultVariableNames[] = {
"x",
"y",
"z",
"t"};
1443 bool canReplace =
false;
1444 if (nArguments == ndim + npar) {
1446 for (
int argNr = 0; argNr < nArguments; argNr++) {
1450 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1457 argSubstitutions[oldName] = newName;
1460 argSubstitutions[defaultVariableNames[argNr]] = newName;
1463 int parNr = argNr - ndim;
1466 argSubstitutions[oldName] = newName;
1469 if (
f && oldName == newName)
1475 }
else if (nArguments == npar) {
1480 bool varsImplicit =
true;
1481 for (
int argNr = 0; argNr < nArguments && varsImplicit; argNr++) {
1482 int openIdx = argSeparators[argNr] + 1;
1483 int closeIdx = argSeparators[argNr + 1] - 1;
1486 if (formula[openIdx] !=
'[' || formula[closeIdx] !=
']' || closeIdx <= openIdx + 1)
1487 varsImplicit =
false;
1490 for (
int idx = openIdx + 1; idx < closeIdx && varsImplicit; idx++)
1492 varsImplicit =
false;
1495 Warning(
"HandleFunctionArguments",
1496 "Argument %d is not a parameter. Cannot assume variables are implicit.", argNr);
1503 for (
int dim = 0; dim < ndim; dim++) {
1504 argSubstitutions[
TString::Format(
"{V%d}", dim)] = defaultVariableNames[dim];
1508 for (
int argNr = 0; argNr < nArguments; argNr++) {
1512 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1516 argSubstitutions[oldName] = newName;
1519 if (
f && oldName == newName)
1526 if (!canReplace && nArguments == ndim) {
1530 for (
int argNr = 0; argNr < nArguments; argNr++) {
1533 TString(formula(argSeparators[argNr] + 1, argSeparators[argNr + 1] - argSeparators[argNr] - 1));
1537 argSubstitutions[oldName] = newName;
1540 argSubstitutions[defaultVariableNames[argNr]] = newName;
1545 for (
int parNr = 0; parNr < npar; parNr++)
1559 formula.
Replace(i, k - i, replacementFormula);
1560 i += replacementFormula.
Length() - 1;
1563 Warning(
"HandleFunctionArguments",
"Unable to make replacement. Number of parameters doesn't work : "
1564 "%d arguments, %d dimensions, %d parameters",
1565 nArguments, ndim, npar);
1588 Int_t temp = caretPos;
1591 if (formula[temp] ==
')') {
1594 while (depth != 0 && temp > 0) {
1595 if (formula[temp] ==
')')
1597 if (formula[temp] ==
'(')
1612 assert(temp + 1 >= 0);
1613 Int_t leftPos = temp + 1;
1614 left = formula(leftPos, caretPos - leftPos);
1620 if (temp >= formula.
Length()) {
1621 Error(
"HandleExponentiation",
"Invalid position of operator ^");
1624 if (formula[temp] ==
'(') {
1627 while (depth != 0 && temp < formula.
Length()) {
1628 if (formula[temp] ==
')')
1630 if (formula[temp] ==
'(')
1637 if (formula[temp] ==
'-' || formula[temp] ==
'+')
1643 while (temp < formula.
Length() && ((depth > 0) || !
IsOperator(formula[temp]))) {
1649 if (temp < formula.
Length() && formula[temp] ==
'(')
1651 if (temp < formula.
Length() && formula[temp] ==
')') {
1659 right = formula(caretPos + 1, (temp - 1) - caretPos);
1669 caretPos = formula.
Last(
'^');
1680 if (linPos ==
kNPOS )
return;
1682 assert(nofLinParts > 0);
1693 while (temp >= 0 && formula[temp] !=
'@') {
1696 left = formula(temp + 1, linPos - (temp + 1));
1699 while (temp < formula.
Length() && formula[temp] !=
'@') {
1702 TString right = formula(linPos + 1, temp - (linPos + 1));
1709 Nlinear += (
first) ? 2 : 1;
1719 linPos = formula.
Index(
"@");
1803 if (formula[i] ==
'[') {
1807 while (i < formula.
Length() && formula[i] !=
']') {
1808 param.
Append(formula[i++]);
1813 int paramIndex = -1;
1815 paramIndex = param.
Atoi();
1819 for (
int idx = 0; idx <= paramIndex; ++idx) {
1839 formula.
Replace(tmp, i - tmp, replacement, replacement.
Length());
1843 int deltai = replacement.
Length() - (i-tmp);
1849 if (formula[i] ==
'\"') {
1853 }
while (formula[i] !=
'\"');
1871 if (isalpha(formula[i]) &&
1879 if (formula[i] ==
':' && ((i + 1) < formula.
Length())) {
1880 if (formula[i + 1] ==
':') {
1889 name.Append(formula[i++]);
1892 if (formula[i] ==
'(') {
1894 if (formula[i] ==
')') {
1901 while (depth != 0 && i < formula.
Length()) {
1902 switch (formula[i]) {
1903 case '(': depth++;
break;
1904 case ')': depth--;
break;
1912 body.
Append(formula[i++]);
1917 formula.
Replace(i - originalBodyLen, originalBodyLen, body, body.
Length());
1918 i += body.
Length() - originalBodyLen;
1936 TF1 *
f1 =
dynamic_cast<TF1 *
>(obj);
1946 TString replacementFormula =
f->GetExpFormula();
1959 std::vector<TString> newNames;
1962 newNames.resize(
f->GetNpar());
1964 for (
int jpar =
f->GetNpar() - 1; jpar >= 0; --jpar) {
1972 replacementFormula.
ReplaceAll(oldName, newName);
1973 newNames[jpar] = newName;
1975 newNames[jpar] =
f->GetParName(jpar);
1983 for (
int jpar = 0; jpar <
f->GetNpar(); ++jpar) {
1984 if (nparOffset > 0) {
1986 assert((
int)newNames.size() ==
f->GetNpar());
1993 replacementFormula.
Insert(0,
'(');
1994 replacementFormula.
Insert(replacementFormula.
Length(),
')');
1997 i += replacementFormula.
Length() -
name.Length();
2041 for (list<TFormulaFunction>::iterator funcsIt =
fFuncs.begin(); funcsIt !=
fFuncs.end(); ++funcsIt) {
2058 while (index !=
kNPOS) {
2062 if ((index > 0) && (isalpha(formula[index - 1]) || formula[index - 1] ==
':')) {
2063 index = formula.
Index(shortcut, i2);
2066 if (i2 < formula.
Length() && formula[i2] !=
'(') {
2067 index = formula.
Index(shortcut, i2);
2073 index = formula.
Index(shortcut, inext);
2080#ifdef TFORMULA_CHECK_FUNCTIONS
2086 size_t index =
name.rfind(
"::");
2087 assert(index != std::string::npos);
2095 TIter next(methodList);
2097 while ((p = (
TMethod *)next())) {
2098 if (strcmp(p->
GetName(), functionName.
Data()) == 0 &&
2113 if (
f && fun.
GetNargs() <=
f->GetNargs() && fun.
GetNargs() >=
f->GetNargs() -
f->GetNargsOpt()) {
2121 Info(
"TFormula",
"Could not find %s function with %d argument(s)", fun.
GetName(), fun.
GetNargs());
2144 map<TString, TFormulaVariable>::iterator varsIt =
fVars.find(fun.
GetName());
2145 if (varsIt !=
fVars.end()) {
2148 Double_t value = (*varsIt).second.fValue;
2154 int varDim = (*varsIt).second.fArrayPos;
2155 if (varDim >=
fNdim) {
2160 if (
v.second.fArrayPos < varDim && !
v.second.fFound) {
2162 v.second.fFound =
true;
2183 int digit = sdigit.
Atoi();
2184 if (digit >=
fNdim) {
2187 for (
int j = 0; j <
fNdim; ++j) {
2191 fVars[vname].fFound =
true;
2206 if (paramsIt !=
fParams.end()) {
2223 map<TString, Double_t>::iterator constIt =
fConsts.find(fun.
GetName());
2224 if (constIt !=
fConsts.end()) {
2243 if (!hasParameters) {
2257 if (inputIntoCling) {
2260 std::string inputFormula(formula.
Data());
2264 std::string inputFormulaVecFlag = inputFormula;
2266 inputFormulaVecFlag +=
" (vectorized)";
2271 TString argumentsPrototype =
TString::Format(
"%s%s%s", ( (hasVariables || hasParameters) ? (argType +
" *x").Data() :
""),
2272 (hasParameters ?
"," :
""), (hasParameters ?
"Double_t *p" :
""));
2289 inputIntoCling =
false;
2299 argumentsPrototype.
Data(), inputFormula.c_str());
2318 if (inputIntoCling) {
2344 for (list<TFormulaFunction>::iterator it =
fFuncs.begin(); it !=
fFuncs.end(); ++it) {
2346 if (!it->fFound && !it->IsFuncCall()) {
2348 if (it->GetNargs() == 0)
2349 Error(
"ProcessFormula",
"\"%s\" has not been matched in the formula expression", it->GetName());
2351 Error(
"ProcessFormula",
"Could not find %s function with %d argument(s)", it->GetName(), it->GetNargs());
2362 auto itvar =
fVars.begin();
2365 if (!itvar->second.fFound) {
2367 itvar =
fVars.erase(itvar);
2370 }
while (itvar !=
fVars.end());
2381 make_pair(make_pair(
"gaus", 1), make_pair(
"[0]*exp(-0.5*(({V0}-[1])/[2])*(({V0}-[1])/[2]))",
2382 "[0]*exp(-0.5*(({V0}-[1])/[2])*(({V0}-[1])/[2]))/(sqrt(2*pi)*[2])")));
2383 functions.insert(make_pair(make_pair(
"landau", 1), make_pair(
"[0]*TMath::Landau({V0},[1],[2],false)",
2384 "[0]*TMath::Landau({V0},[1],[2],true)")));
2385 functions.insert(make_pair(make_pair(
"expo", 1), make_pair(
"exp([0]+[1]*{V0})",
"")));
2387 make_pair(make_pair(
"crystalball", 1), make_pair(
"[0]*ROOT::Math::crystalball_function({V0},[3],[4],[2],[1])",
2388 "[0]*ROOT::Math::crystalball_pdf({V0},[3],[4],[2],[1])")));
2390 make_pair(make_pair(
"breitwigner", 1), make_pair(
"[0]*ROOT::Math::breitwigner_pdf({V0},[2],[1])",
2391 "[0]*ROOT::Math::breitwigner_pdf({V0},[2],[4],[1])")));
2393 functions.insert(make_pair(make_pair(
"cheb0", 1), make_pair(
"ROOT::Math::Chebyshev0({V0},[0])",
"")));
2394 functions.insert(make_pair(make_pair(
"cheb1", 1), make_pair(
"ROOT::Math::Chebyshev1({V0},[0],[1])",
"")));
2395 functions.insert(make_pair(make_pair(
"cheb2", 1), make_pair(
"ROOT::Math::Chebyshev2({V0},[0],[1],[2])",
"")));
2396 functions.insert(make_pair(make_pair(
"cheb3", 1), make_pair(
"ROOT::Math::Chebyshev3({V0},[0],[1],[2],[3])",
"")));
2398 make_pair(make_pair(
"cheb4", 1), make_pair(
"ROOT::Math::Chebyshev4({V0},[0],[1],[2],[3],[4])",
"")));
2400 make_pair(make_pair(
"cheb5", 1), make_pair(
"ROOT::Math::Chebyshev5({V0},[0],[1],[2],[3],[4],[5])",
"")));
2402 make_pair(make_pair(
"cheb6", 1), make_pair(
"ROOT::Math::Chebyshev6({V0},[0],[1],[2],[3],[4],[5],[6])",
"")));
2404 make_pair(make_pair(
"cheb7", 1), make_pair(
"ROOT::Math::Chebyshev7({V0},[0],[1],[2],[3],[4],[5],[6],[7])",
"")));
2405 functions.insert(make_pair(make_pair(
"cheb8", 1),
2406 make_pair(
"ROOT::Math::Chebyshev8({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8])",
"")));
2407 functions.insert(make_pair(make_pair(
"cheb9", 1),
2408 make_pair(
"ROOT::Math::Chebyshev9({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8],[9])",
"")));
2410 make_pair(make_pair(
"cheb10", 1),
2411 make_pair(
"ROOT::Math::Chebyshev10({V0},[0],[1],[2],[3],[4],[5],[6],[7],[8],[9],[10])",
"")));
2414 make_pair(make_pair(
"gaus", 2), make_pair(
"[0]*exp(-0.5*(({V0}-[1])/[2])^2 - 0.5*(({V1}-[3])/[4])^2)",
"")));
2416 make_pair(make_pair(
"landau", 2),
2417 make_pair(
"[0]*TMath::Landau({V0},[1],[2],false)*TMath::Landau({V1},[3],[4],false)",
"")));
2418 functions.insert(make_pair(make_pair(
"expo", 2), make_pair(
"exp([0]+[1]*{V0})",
"exp([0]+[1]*{V0}+[2]*{V1})")));
2421 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)",
"")));
2424 make_pair(make_pair(
"bigaus", 2), make_pair(
"[0]*ROOT::Math::bigaussian_pdf({V0},{V1},[2],[4],[5],[1],[3])",
2425 "[0]*ROOT::Math::bigaussian_pdf({V0},{V1},[2],[4],[5],[1],[3])")));
2517 if (i < 0 || i >=
n ) {
2518 Error(
"GetLinearPart",
"Formula %s has only %d linear parts - requested %d",
GetName(),
n,i);
2564 Bool_t anyNewVar =
false;
2565 for (
Int_t i = 0; i < size; ++i) {
2567 const TString &vname = vars[i];
2577 Int_t multiplier = 2;
2578 if (
fFuncs.size() > 100) {
2603 Error(
"SetName",
"The name \'%s\' is reserved as a TFormula variable name.\n"
2604 "\tThis function will not be renamed.",
2609 auto listOfFunctions =
gROOT->GetListOfFunctions();
2610 TObject* thisAsFunctionInList =
nullptr;
2612 if (listOfFunctions){
2613 thisAsFunctionInList = listOfFunctions->
FindObject(
this);
2614 if (thisAsFunctionInList) listOfFunctions->Remove(thisAsFunctionInList);
2617 if (thisAsFunctionInList) listOfFunctions->Add(thisAsFunctionInList);
2631 for(
Int_t i = 0; i < size; ++i)
2635 fVars[
v.first].fValue =
v.second;
2638 Error(
"SetVariables",
"Variable %s is not defined.",
v.first.Data());
2649 if (
fVars.end() == nameIt) {
2650 Error(
"GetVariable",
"Variable %s is not defined.",
name);
2653 return nameIt->second.fValue;
2662 if (
fVars.end() == nameIt) {
2663 Error(
"GetVarNumber",
"Variable %s is not defined.",
name);
2666 return nameIt->second.fArrayPos;
2674 if (ivar < 0 || ivar >=
fNdim)
return "";
2677 for (
auto &
v :
fVars) {
2678 if (
v.second.fArrayPos == ivar)
return v.first;
2680 Error(
"GetVarName",
"Variable with index %d not found !!",ivar);
2691 Error(
"SetVariable",
"Variable %s is not defined.",
name.Data());
2730 auto ret =
fParams.insert(std::make_pair(
name, pos));
2736 if (ret.first ==
fParams.begin())
2739 auto previous = (ret.first);
2741 pos = previous->second + 1;
2749 Warning(
"inserting parameter %s at pos %d when vector size is %d \n",
name.Data(), pos,
2759 for (
auto it = ret.first; it !=
fParams.end(); ++it) {
2769 if (processFormula) {
2797 Error(
"GetParameter",
"Parameter %s is not defined.",
name);
2812 Error(
"GetParameter",
"wrong index used - use GetParameter(name)");
2821 if (ipar < 0 || ipar >=
fNpar)
return "";
2825 if (p.second == ipar)
return p.first.Data();
2827 Error(
"GetParName",
"Parameter with index %d not found !!",ipar);
2860 Error(
"SetParameter",
"Parameter %s is not defined.",
name.Data());
2867 for (map<TString, TFormulaVariable>::iterator it =
fParams.begin(); it !=
fParams.end(); ++it) {
2868 if (!it->second.fFound) {
2887 for(
Int_t i = 0 ; i < size ; ++i)
2889 pair<TString, Double_t> p = params[i];
2891 Error(
"SetParameters",
"Parameter %s is not defined", p.first.Data());
2894 fParams[p.first].fValue = p.second;
2895 fParams[p.first].fFound =
true;
2899 for (map<TString, TFormulaVariable>::iterator it =
fParams.begin(); it !=
fParams.end(); ++it) {
2900 if (!it->second.fFound) {
2911 if(!params || size < 0 || size >
fNpar)
return;
2914 Warning(
"SetParameters",
"size is not same of cling parameter size %d - %d",size,
int(
fClingParameters.size()) );
2915 for (
Int_t i = 0; i < size; ++i) {
2963 if (param < 0 || param >=
fNpar)
return;
2972 const char *name4,
const char *name5,
const char *name6,
const char *name7,
2973 const char *name8,
const char *name9,
const char *name10)
3003 if (ipar < 0 || ipar >
fNpar) {
3004 Error(
"SetParName",
"Wrong Parameter index %d ",ipar);
3010 if (it.second == ipar) {
3018 Error(
"SetParName",
"Parameter %d is not existing.",ipar);
3031 if (!formula.
IsNull() ) {
3033 for(list<TFormulaFunction>::iterator it =
fFuncs.begin(); it !=
fFuncs.end(); ++it)
3035 if (oldName == it->GetName()) {
3042 Error(
"SetParName",
"Parameter %s is not defined.", oldName.
Data());
3058#ifdef R__HAS_VECCORE
3060 Info(
"SetVectorized",
"Cannot vectorized a function of zero dimension");
3065 Error(
"SetVectorized",
"Cannot set vectorized to %d -- Formula is missing", vectorized);
3084 Warning(
"SetVectorized",
"Cannot set vectorized -- try building with option -Dbuiltin_veccore=On");
3094#ifdef R__HAS_VECCORE
3098 return vecCore::Get( ret, 0 );
3105 Info(
"EvalPar",
"Function is vectorized - converting Double_t into ROOT::Double_v and back");
3108 const int maxDim = 4;
3109 std::array<ROOT::Double_v, maxDim> xvec;
3110 for (
int i = 0; i <
fNdim; i++)
3114 return vecCore::Get(ans, 0);
3117 std::vector<ROOT::Double_v> xvec(
fNdim);
3118 for (
int i = 0; i <
fNdim; i++)
3122 return vecCore::Get(ans, 0);
3127 Error(
"EvalPar",
"Formula is vectorized (even though VECCORE is disabled!)");
3149 gInterpreter->Declare(
"#include <Math/CladDerivator.h>\n#pragma clad OFF");
3160 "#pragma clad ON\n" +
3161 "void " + GradReqFuncName +
"() {\n" +
3162 "clad::gradient(" + std::string(
fClingName.
Data()) +
");\n }\n" +
3173 GradFuncName.c_str(),
3187 Error(
"GradientPar",
"Could not initialize the formula!");
3192 Error(
"GradientPar",
"Could not generate a gradient for the formula %s!",
3197 if ((
int)result.size() <
fNpar) {
3199 "The size of gradient result is %zu but %d is required. Resizing.",
3200 result.size(),
fNpar);
3201 result.resize(
fNpar);
3223 (*fGradFuncPtr)(0, 2, args,
nullptr);
3235 (*fGradFuncPtr)(0, 3, args,
nullptr);
3240#ifdef R__HAS_VECCORE
3250 return DoEvalVec(
x, params);
3253 return DoEval(
nullptr, params);
3258 Info(
"EvalPar",
"Function is not vectorized - converting ROOT::Double_v into Double_t and back");
3260 const int vecSize = vecCore::VectorSize<ROOT::Double_v>();
3261 std::vector<Double_t> xscalars(vecSize*
fNdim);
3263 for (
int i = 0; i < vecSize; i++)
3264 for (
int j = 0; j <
fNdim; j++)
3265 xscalars[i*
fNdim+j] = vecCore::Get(
x[j],i);
3268 for (
int i = 0; i < vecSize; i++)
3269 vecCore::Set(answers, i,
DoEval(&xscalars[i*
fNdim], params));
3280 double xxx[4] = {
x,
y,z,t};
3289 double xxx[3] = {
x,
y,z};
3298 double xxx[2] = {
x,
y};
3321 Error(
"Eval",
"Formula is invalid and not ready to execute ");
3322 for (
auto it =
fFuncs.begin(); it !=
fFuncs.end(); ++it) {
3325 printf(
"%s is unknown.\n", fun.
GetName());
3337 auto thisFormula =
const_cast<TFormula*
>(
this);
3341 Error(
"DoEval",
"Formula has error and it is not properly initialized ");
3347 std::function<
double(
double *,
double *)> & fptr = * ( (std::function<
double(
double *,
double *)> *)
fLambdaPtr);
3350 double *
v =
const_cast<double*
>(
x);
3351 double * p = (params) ?
const_cast<double*
>(params) :
const_cast<double*
>(
fClingParameters.data());
3358 double * vars = (
x) ?
const_cast<double*
>(
x) :
const_cast<double*
>(
fClingVariables.data());
3361 (*fFuncPtr)(0, 1, args, &result);
3363 double *pars = (params) ?
const_cast<double *
>(params) :
const_cast<double *
>(
fClingParameters.data());
3365 (*fFuncPtr)(0, 2, args, &result);
3372#ifdef R__HAS_VECCORE
3376 Error(
"Eval",
"Formula is invalid and not ready to execute ");
3377 for (
auto it =
fFuncs.begin(); it !=
fFuncs.end(); ++it) {
3380 printf(
"%s is unknown.\n", fun.
GetName());
3392 auto thisFormula =
const_cast<TFormula*
>(
this);
3396 Error(
"DoEval",
"Formula has error and it is not properly initialized ");
3408 (*fFuncPtr)(0, 1, args, &result);
3410 double *pars = (params) ?
const_cast<double *
>(params) :
const_cast<double *
>(
fClingParameters.data());
3412 (*fFuncPtr)(0, 2, args, &result);
3429 Info(
"ReInitializeEvalMethod",
"compile now lambda expression function using Cling");
3436 if (!
fLazyInitialization)
Warning(
"ReInitializeEvalMethod",
"Formula is NOT properly initialized - try calling again TFormula::PrepareEvalMethod");
3495 std::size_t found = clingFunc.find(
"return");
3496 std::size_t found2 = clingFunc.rfind(
";");
3497 if (found == std::string::npos || found2 == std::string::npos) {
3498 Error(
"GetExpFormula",
"Invalid Cling expression - return default formula expression");
3503 if (!opt.
Contains(
"P"))
return clingFormula;
3506 while (i < clingFormula.
Length()-2 ) {
3508 if (clingFormula[i] ==
'p' && clingFormula[i+1] ==
'[' && isdigit(clingFormula[i+2]) ) {
3510 while ( isdigit(clingFormula[j]) ) { j++;}
3511 if (clingFormula[j] !=
']') {
3512 Error(
"GetExpFormula",
"Parameters not found - invalid expression - return default cling formula");
3513 return clingFormula;
3515 TString parNumbName = clingFormula(i+2,j-i-2);
3516 int parNumber = parNumbName.
Atoi();
3517 assert(parNumber <
fNpar);
3519 clingFormula.
Replace(i,j-i+1, replacement );
3520 i += replacement.
Length();
3524 return clingFormula;
3530 while (i < expFormula.
Length()-2 ) {
3532 if (expFormula[i] ==
'[') {
3534 while ( expFormula[j] !=
']' ) { j++;}
3535 if (expFormula[j] !=
']') {
3536 Error(
"GetExpFormula",
"Parameter names not found - invalid expression - return default formula");
3539 TString parName = expFormula(i+1,j-i-1);
3541 expFormula.
Replace(i,j-i+1, replacement );
3542 i += replacement.
Length();
3548 Warning(
"GetExpFormula",
"Invalid option - return default formula expression");
3553 std::unique_ptr<TInterpreterValue>
v =
gInterpreter->MakeInterpreterValue();
3555 return v->ToString();
3564 printf(
" Formula expression: \n");
3573 printf(
"List of Variables: \n");
3575 for (
int ivar = 0; ivar <
fNdim ; ++ivar) {
3580 printf(
"List of Parameters: \n");
3585 for (
int ipar = 0; ipar <
fNpar ; ++ipar) {
3589 printf(
"Expression passed to Cling:\n");
3592 printf(
"Generated Gradient:\n");
3599 Warning(
"Print",
"Formula is not ready to execute. Missing parameters/variables");
3600 for (list<TFormulaFunction>::const_iterator it =
fFuncs.begin(); it !=
fFuncs.end(); ++it) {
3603 printf(
"%s is unknown.\n", fun.
GetName());
3626 if (
b.IsReading() ) {
3630 if (v <= 8 && v > 3 &&
v != 6) {
3634 fold->
Streamer(
b,
v, R__s, R__c, TFormula::Class());
3643 Error(
"Streamer",
"Old formula read from file is NOT valid");
3651 b.ReadClassBuffer(TFormula::Class(),
this,
v, R__s, R__c);
3696 if (
fNpar != (
int) parValues.size() ) {
3697 Error(
"Streamer",
"number of parameters computed (%d) is not same as the stored parameters (%d)",
fNpar,
int(parValues.size()) );
3700 if (
v > 11 &&
fNdim != ndim) {
3701 Error(
"Streamer",
"number of dimension computed (%d) is not same as the stored value (%d)",
fNdim, ndim );
3716 assert(
fNpar == (
int) parValues.size() );
3719 if (
fParams.size() != paramMap.size() ) {
3720 Warning(
"Streamer",
"number of parameters list found (%zu) is not same as the stored one (%zu) - use re-created list",
fParams.size(),paramMap.size()) ;
3736 gROOT->GetListOfFunctions()->Add(
this);
3739 Error(
"Streamer",
"Formula read from file is NOT ready to execute");
3747 Error(
"Streamer",
"Reading version %d is not supported",
v);
3753 b.WriteClassBuffer(TFormula::Class(),
this);
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
void GetParameters(TFitEditor::FuncParams_t &pars, TF1 *func)
Stores the parameters of the given function into pars.
R__EXTERN TInterpreter * gCling
R__EXTERN TVirtualMutex * gROOTMutex
typedef void((*Func_t)())
#define R__LOCKGUARD(mutex)
Buffer base class used for serializing objects.
TClass instances represent classes, structs and namespaces in the ROOT type system.
const TList * GetListOfAllPublicMethods(Bool_t load=kTRUE)
Returns a list of all public methods of this class and its base classes.
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
virtual TFormula * GetFormula()
Global functions class (global functions are obtained from CINT).
Int_t GetNargsOpt() const
Number of function optional (default) arguments.
Int_t GetNargs() const
Number of function arguments.
virtual Bool_t Declare(const char *code)=0
virtual Bool_t CallFunc_IsValid(CallFunc_t *) const
virtual Long_t ProcessLine(const char *line, EErrorCode *error=0)=0
virtual CallFuncIFacePtr_t CallFunc_IFacePtr(CallFunc_t *) const
Method or function calling interface.
CallFunc_t * GetCallFunc() const
Each ROOT class (see TClass) has a linked list of methods.
The TNamed class is the base class for all named ROOT classes.
virtual void Copy(TObject &named) const
Copy this to obj.
virtual void SetName(const char *name)
Set the name of the TNamed.
virtual const char * GetTitle() const
Returns title of object.
virtual const char * GetName() const
Returns name of object.
Mother of all ROOT objects.
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Regular expression class.
Ssiz_t Index(const TString &str, Ssiz_t *len, Ssiz_t start=0) const
Find the first occurrence of the regexp in string and return the position, or -1 if there is no match...
TString & Insert(Ssiz_t pos, const char *s)
Int_t Atoi() const
Return integer value of string.
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
const char * Data() const
Bool_t IsDigit() const
Returns true if all characters in string are digits (0-9) or white spaces, i.e.
TString & ReplaceAll(const TString &s1, const TString &s2)
Ssiz_t Last(char c) const
Find last occurrence of a character c.
void ToUpper()
Change string to upper case.
Int_t CountChar(Int_t c) const
Return number of times character c occurs in the string.
TString & Append(const char *cs)
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
constexpr Double_t G()
Gravitational constant in: .
constexpr Double_t C()
Velocity of light in .
Short_t Max(Short_t a, Short_t b)
Double_t QuietNaN()
Returns a quiet NaN as defined by IEEE 754
Double_t Floor(Double_t x)
constexpr Double_t K()
Boltzmann's constant in .
constexpr Double_t Sqrt2()
constexpr Double_t E()
Base of natural log:
constexpr Double_t Sigma()
Stefan-Boltzmann constant in .
constexpr Double_t H()
Planck's constant in .
constexpr Double_t LogE()
Base-10 log of e (to convert ln to log)
constexpr Double_t Ln10()
Natural log of 10 (to convert log to ln)
constexpr Double_t EulerGamma()
Euler-Mascheroni Constant.
constexpr Double_t R()
Universal gas constant ( ) in
Double_t Log10(Double_t x)
Double_t Infinity()
Returns an infinity as defined by the IEEE standard.
void(* Generic_t)(void *, int, void **, void *)