https://github.com/root-project/root
Tip revision: 49ae85f5fe419209f949b04e8253a0015b8946a0 authored by Axel Naumann on 27 November 2023, 18:27:38 UTC
[foundation] Update version file to 6.30.02.
[foundation] Update version file to 6.30.02.
Tip revision: 49ae85f
TFormulaTests.cxx
#include <cassert>
#include <vector>
#include <algorithm>
#include <stdlib.h>
#include <TROOT.h>
#include <TSystem.h>
#include <TMath.h>
#include <TBenchmark.h>
#include <TSystem.h>
#include <TApplication.h>
#include <TFormula.h>
#include <v5/TFormula.h>
#include <TRandom.h>
#include <iostream>
#include "TFormulaParsingTests.h"
#include "TFormulaVecTests.h"
using namespace std;
template<typename F, typename S, typename T>
struct Triple
{
F first;
S second;
T third;
Triple() {}
Triple(const F &f, const S &s, const T &t): first(f),second(s),third(t) {}
};
typedef pair<TString,Double_t> SDpair;
TString testFormula;
SDpair *testVars;
SDpair *testParams;
Int_t Nparams;
Int_t Nvars;
class TFormulaTests : public TFormula
{
protected:
public:
TFormulaTests(TString name, TString formula): TFormula(name,formula){}
~TFormulaTests() override{}
Bool_t ParserNew();
Bool_t GetVarVal();
Bool_t GetParVal();
Bool_t AddVar();
Bool_t SetVar();
Bool_t AddVars();
Bool_t SetVars();
Bool_t SetPar1();
Bool_t SetPar2();
Bool_t SetPars1();
Bool_t SetPars2();
Bool_t Eval();
Bool_t Stress(Int_t n = 10000);
Bool_t Parser();
Bool_t Vectorize();
};
Bool_t TFormulaTests::GetVarVal()
{
Bool_t successful = true;
for(Int_t i = 0; i < Nvars; ++i)
{
SDpair var = testVars[i];
if(var.second != GetVariable(var.first) || var.second != fVars[var.first].fValue)
{
printf("fail:%s\t%lf\n",var.first.Data(), var.second);
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::GetParVal()
{
Bool_t successful = true;
for(Int_t i = 0 ; i < Nparams; ++i)
{
SDpair param = testParams[i];
if(param.second != GetParameter(param.first) )//|| param.second != fParams[param.first].fValue)
{
printf("fail:%s\t%lf\n",param.first.Data(), param.second);
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::AddVar()
{
Bool_t successful = true;
TFormula *test = new TFormula("AddVarTest","var1 + var2 + var3");
TString vars[] = {"var1","var2","var3"};
for(Int_t i = 0; i < 3; ++i)
{
test->AddVariable(vars[i],i);
}
for(Int_t i = 0; i < 3; ++i)
{
if(test->GetVariable(vars[i]) != (Double_t)i)
{
printf("fail:%s\n",vars[i].Data());
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::SetVar()
{
Bool_t successful = true;
TFormula *test = new TFormula("SetVarTest","var1 + var2 + var3");
SDpair *vars = new SDpair[3];
vars[0] = SDpair("var",1);
vars[1] = SDpair("var2",2);
vars[2] = SDpair("var3",3);
test->SetVariables(vars, 3);
for(Int_t i = 0 ; i < 3; ++i)
{
SDpair var = vars[i];
test->SetVariable(var.first,var.second + 100.0);
}
for(Int_t i = 0 ; i < 3; ++i)
{
SDpair var = vars[i];
if(test->GetVariable(var.first) != var.second + 100.0)
{
printf("fail:%s\t%lf\n",var.first.Data(),var.second);
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::AddVars()
{
Bool_t successful = true;
TFormula *test = new TFormula("AddVarsTest","var1 + var2 + var3");
TString vars[] = {"var1","var2","var3"};
// SDpair *vars = new SDpair[3];
// vars[0] = SDpair("var",1);
// vars[1] = SDpair("var2",2);
// vars[2] = SDpair("var3",3);
test->AddVariables(vars, 3);
for(Int_t i = 0; i < 3; ++i)
{
if(test->GetVariable(vars[i]) != 0.0)
{
printf("fail:%s\t%lf\n",vars[i].Data(),test->GetVariable(vars[i]));
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::SetVars()
{
Bool_t successful = true;
TFormula *test = new TFormula("SetVarsTest","var1 + var2 + var3");
SDpair *vars = new SDpair[3];
vars[0] = SDpair("var",1);
vars[1] = SDpair("var2",2);
vars[2] = SDpair("var3",3);
test->SetVariables(vars, 3);
for(Int_t i = 0 ; i < 3; ++i)
{
SDpair v = vars[i];
v.second += 100.0;
}
test->SetVariables(vars,3);
for(Int_t i = 0; i < 3; ++i)
{
SDpair v = vars[i];
if(test->GetVariable(v.first) != v.second)
{
printf("fail:%s\t%lf\n",v.first.Data(),v.second);
successful = false;
}
}
delete[] vars;
return successful;
}
Bool_t TFormulaTests::SetPar1()
{
Bool_t successful = true;
TFormula *test = new TFormula("SetParTest1","[0] + [te_st]");
SDpair *params = new SDpair[2];
params[0] = SDpair("0",1);
params[1] = SDpair("te_st",2);
for(Int_t i = 0 ; i < 2; ++i)
{
SDpair p = params[i];
test->SetParameter(p.first,p.second);
}
for(Int_t i = 0 ; i < 2; ++i)
{
SDpair p = params[i];
if(test->GetParameter(p.first) != p.second)
{
printf("fail:%s\t%lf\n",p.first.Data(), p.second);
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::SetPar2()
{
Bool_t successful = true;
TFormula *test = new TFormula("SetParTest2","[0] + [1]+[2]");
Double_t params[] = { 123,456,789 };
for(Int_t i = 0; i < 3; ++i)
{
test->SetParameter(i,params[i]);
}
for(Int_t i = 0; i < 3; ++i)
{
if(test->GetParameter(i) != params[i])
{
printf("fail:%d\t%lf\n",i, params[i]);
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::SetPars2()
{
Bool_t successful = true;
TFormula *test = new TFormula("SetParsTest2","[0] + [1]+[2]");
Double_t params[] = { 123,456,789};
test->SetParameters(params);
for(Int_t i = 0; i < 3; ++i)
{
if(test->GetParameter(i) != params[i])
{
printf("fail:%d\t%lf\n",i, params[i]);
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::SetPars1()
{
Bool_t successful = true;
TFormula *test = new TFormula("SetParsTest1","[0] + [te_st]");
SDpair *params = new SDpair[2];
params[0] = SDpair("0",1);
params[1] = SDpair("te_st",2);
test->SetParameter(params[0].first,params[0].second);
test->SetParameter(params[1].first,params[1].second);
for(Int_t i = 0 ; i < 2; ++i)
{
SDpair p = params[i];
if(test->GetParameter(p.first) != p.second)
{
printf("fail:%s\t%lf\n",p.first.Data(), p.second);
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::Eval()
{
Bool_t successful = true;
TFormula *test = new TFormula("EvalTest","y^z^t - sin(cos(x))");
Double_t x,y,z,t;
x = TMath::Pi();
y = 2.0;
z = 3.0;
t = 4.0;
Double_t result = TMath::Power(y,TMath::Power(z,t)) - TMath::Sin(TMath::Cos(x));
Double_t TFresult = test->Eval(x,y,z,t);
if(!TMath::AreEqualAbs(result,TFresult,0.00001))
{
printf("TF:%lf\tTMath::%lf\n",TFresult,result);
successful = false;
}
return successful;
}
Bool_t TFormulaTests::ParserNew()
{
//x_1- [test]^(TMath::Sin(pi*var*TMath::DegToRad())) - var1pol2(0) + gausn(0)*ylandau(0)+zexpo(10)
Bool_t successful = true;
Triple<TString,TString,Int_t> *funcs = new Triple<TString,TString,Int_t>[24]; //name,body,Nargs
funcs[0] = Triple<TString,TString,Int_t>("x_1","",0);
funcs[1] = Triple<TString,TString,Int_t>("var","",0);
funcs[2] = Triple<TString,TString,Int_t>("var1","",0);
funcs[3] = Triple<TString,TString,Int_t>("test","",0);
funcs[4] = Triple<TString,TString,Int_t>("0","",0);
funcs[5] = Triple<TString,TString,Int_t>("1","",0);
funcs[6] = Triple<TString,TString,Int_t>("pi","",0);
funcs[7] = Triple<TString,TString,Int_t>("2","",0);
funcs[8] = Triple<TString,TString,Int_t>("10","",0);
funcs[9] = Triple<TString,TString,Int_t>("11","",0);
funcs[10] = Triple<TString,TString,Int_t>("x","",0);
funcs[11] = Triple<TString,TString,Int_t>("y","",0);
funcs[12] = Triple<TString,TString,Int_t>("z","",0);
funcs[13] = Triple<TString,TString,Int_t>("false","",0);
funcs[14] = Triple<TString,TString,Int_t>("pow","{var1},2",2);
funcs[15] = Triple<TString,TString,Int_t>("pow","{var1},1",2);
funcs[16] = Triple<TString,TString,Int_t>("pow","{[test]},(TMath::Sin({pi}*{var}*TMath::DegToRad()))",2);
funcs[17] = Triple<TString,TString,Int_t>("exp","{[10]}+{[11]}*{z}",1);
funcs[18] = Triple<TString,TString,Int_t>("TMath::Landau","{y},{[0]},{[1]},{false}",4);
funcs[19] = Triple<TString,TString,Int_t>("sqrt","2*{pi}",1);
funcs[20] = Triple<TString,TString,Int_t>("exp","-0.5*pow((({x}-{[1]})/{[2]}),2)",1);
funcs[21] = Triple<TString,TString,Int_t>("pow","(({x}-{[1]})/{[2]}),2",2);
funcs[22] = Triple<TString,TString,Int_t>("TMath::Sin","{pi}*{var}*TMath::DegToRad()",1);
funcs[23] = Triple<TString,TString,Int_t>("TMath::DegToRad","",0);
TString vars[] = {"x_1","var","var1"};
TString params[] = {"test","0","1","2"};
for(Int_t i = 0; i < 24 ; ++i)
{
Triple<TString,TString,Int_t> func = funcs[i];
TFormulaFunction f(func.first,func.second,func.third);
if(find(fFuncs.begin(),fFuncs.end(),f) == fFuncs.end())
{
printf("fail:%s\t%s\n",func.first.Data(),func.second.Data());
successful = false;
}
}
for(Int_t i = 0 ; i < 3 ;++i)
{
TString var = vars[i];
if(fVars.find(var) == fVars.end())
{
printf("fail:%s\n",var.Data());
successful = false;
}
}
for(Int_t i = 0; i < 4; ++i)
{
TString param = params[i];
if(fParams.find(param) == fParams.end())
{
printf("fail:%s\n",param.Data());
successful = false;
}
}
return successful;
}
Bool_t TFormulaTests::Stress(Int_t n)
{
#ifdef OLD
TString formula = "x";
SDpair *vars = new SDpair[n];
SDpair *params = new SDpair[n*5];
gBenchmark->Start("TFormula Stress Total Time");
for(Int_t i = 0; i < n ; ++i)
{
vars[i] = SDpair(TString::Format("x%d",i),i+1);
params[i] = SDpair(TString::Format("p%d",i),i+1);
formula.Append(TString::Format("+ %s + %s*gausn(0) - [%d]",vars[i].first.Data(),vars[i].first.Data(),i));
//cout << formula.Data() << endl;
}
for(Int_t i = n; i < n*5; ++i)
{
params[i] = SDpair(TString::Format("p%d",i),i+1);
formula.Append(TString::Format("*[%d]",i));
//cout << formula.Data() << endl;
}
#else
TString formula = "x";
//SDpair *vars = new SDpair[n];
SDpair *params = new SDpair[n*5];
std::vector<double> parv;
gBenchmark->Start("TFormula Stress Total Time");
int i0 = 0;
for(Int_t i = 0; i < n ; i+=5)
{
// vars[i] = SDpair(TString::Format("x",i),i+1);
for (int j = 0; j < 5; ++j) {
double val = 2.0;
params[i+j] = SDpair(TString::Format("p%d",i+j),val);
//cout << "set parameter " << i+j << " value " << j+1 << endl;
parv.push_back(val);
}
formula.Append(TString::Format("*[%d]+ y*[%d]*[%d] + z*gausn(%d)*[%d] - [%d]*t",i,i+1,i+1,i+2,i+3,i+4));
//formula.Append(TString::Format("*[%d]+ y*[%d]*[%d] + z*gausn(%d) - [%d]*t",i,i+1,i+1,i+2,i+5));
//cout << formula.Data() << endl;
i0 = i;
}
i0 += 5;
for(Int_t i = i0; i < n*5; ++i)
{
double val = i;
params[i] = SDpair(TString::Format("p%d",i),val);
//cout << "set parameter " << i << " value " << i+1 << endl;
parv.push_back(val);
formula.Append(TString::Format("+[%d]",i));
//cout << formula.Data() << endl;
}
#endif
// new version with only 4 variables but n-parameters
gBenchmark->Start(TString::Format("TFormula Initialization with %d variables and %d parameters\n",n,n*5));
TFormula *test = new TFormula("TFStressTest",formula);
gBenchmark->Show(TString::Format("TFormula Initialization with %d variables and %d parameters\n",n,n*5));
// gBenchmark->Start(TString::Format("Adding %d variables\n",n));
// test->AddVariables(vars,n);
// gBenchmark->Show(TString::Format("Adding %d variables\n",n));
gBenchmark->Start(TString::Format("Setting %d parameters\n",n*5));
for (int i = 0; i < n*5; ++i)
test->SetParameter(params[i].first, params[i].second);
gBenchmark->Show(TString::Format("Setting %d parameters\n",n*5));
int neval = n*1000;
gBenchmark->Start(TString::Format("%d Evaluations\n",neval));
double xx[4] = {3,3,3,3};
TRandom rndm;
TStopwatch w; w.Start();
double s = 0;
for(Int_t i = 0; i < neval; ++i)
{
if (i > 0) rndm.RndmArray(4,xx);
double f = test->EvalPar(xx,0);
if (i == 0) printf(" f = %20.16g \n",f);
if (TMath::Even(i) ) s += f;
else s -= f;
}
printf("Evaluation time :\t");
w.Print();
std::cout << "result = " << s << std::endl;
gBenchmark->Show(TString::Format("%d Evaluations\n",neval));
//test->Print("v");
gBenchmark->Show("TFormula Stress Total Time");
std::cout << "\n\n Testing old TFormula \n" << endl;
ROOT::v5::TFormula::SetMaxima(5000,5000,5000);
gBenchmark->Start(TString::Format("ROOT::v5::TFormula Initialization with %d variables and %d parameters\n",n,n*5));
ROOT::v5::TFormula *testOld = new ROOT::v5::TFormula("TFStressTestOld",formula);
gBenchmark->Show(TString::Format("ROOT::v5::TFormula Initialization with %d variables and %d parameters\n",n,n*5));
// gBenchmark->Start(TString::Format("Adding %d variables\n",n));
// test->AddVariables(vars,n);
// gBenchmark->Show(TString::Format("Adding %d variables\n",n));
gBenchmark->Start(TString::Format("ROOT::v5::TFormula: Setting %d parameters\n",n*5));
testOld->SetParameters(&parv[0]);
gBenchmark->Show( TString::Format("ROOT::v5::TFormula: Setting %d parameters\n",n*5));
gBenchmark->Start(TString::Format("ROOT::v5::TFormula: %d Evaluations\n",neval));
TRandom rndm2;
std::cout << "start evaluatuons " << std::endl;
s = 0;
w.Start();
double xx2[4] = {3,3,3,3};
for(Int_t i = 0; i < neval; ++i)
{
if (i > 0) rndm2.RndmArray(4,xx2);
double f = testOld->EvalPar(xx2,0);
if (i == 0) printf(" f = %20.16g \n",f);
if (TMath::Even(i) ) s += f;
else s -= f;
}
printf("Evaluation time :\t");
w.Print();
std::cout << "result = " << s << std::endl;
gBenchmark->Show(TString::Format("ROOT::v5::TFormula: %d Evaluations\n",neval));
//testOld->Print("v");
gBenchmark->Show("ROOT::v5::TFormula Stress Total Time");
return true;
}
bool TFormulaTests::Parser() {
std::cout << "Test parsing of expression compatible with old TFormula" << std::endl;
TFormulaParsingTests t;
int nfailed = t.runTests();
if (nfailed != 0) {
std::cout << "ERROR - Parsing test of TFormula failed - number of failures is " << nfailed << std::endl;
return false;
}
return true;
}
bool TFormulaTests::Vectorize() {
std::cout << "Test creating vectorized Formula" << std::endl;
bool ok = testVecFormula();
if (!ok) {
std::cout << "ERROR - Creating Vectorized TFormula failed " << std::endl;
return false;
}
return true;
}
int main(int argc, char **argv)
{
printf("starting .....\n");
TApplication theApp("App", &argc, argv);
gBenchmark = new TBenchmark();
Int_t n = 100;
if(argc > 1)
n = TString(argv[1]).Atoi();
printf("************************************************\n");
printf("================TFormula Tests===============\n");
printf("************************************************\n");
testFormula = "x- [test]^(TMath::Sin(pi*var*TMath::DegToRad())) - var1pol2(0) + gausn(0)*landau(0)+expo(10)";
//testFormula = "x - [test]^(TMath::Sin(pi*y*TMath::DegToRad())) - pol2(0) + gausn(0)*landau(0)+expo(10)";
printf("creating formula .....\n");
TFormulaTests * test = new TFormulaTests("TFtests","");
test->AddVariable("var",0);
test->AddVariable("var1",0);
test->Compile(testFormula);
#ifdef LATER
Nparams = 6;
Nvars = 6;
testParams = new SDpair[Nparams];
testVars = new SDpair[Nvars];
testParams[0] = SDpair("test",123);
testParams[1] = SDpair("0",456);
testParams[2] = SDpair("1",789);
testParams[3] = SDpair("2",123);
testParams[4] = SDpair("10",123);
testParams[5] = SDpair("11",456);
testVars[0] = SDpair("x_1",123);
testVars[1] = SDpair("var",456);
testVars[2] = SDpair("var1",789);
testVars[3] = SDpair("x",123);
testVars[4] = SDpair("y",456);
testVars[5] = SDpair("z",123);
test->AddVariables(testVars,Nvars);
test->SetParameters(testParams);
printf("Parser test:%s\n",(test->ParserNew() ? "PASSED" : "FAILED"));
printf("GetVariableValue test:%s\n",(test->GetVarVal() ? "PASSED" : "FAILED"));
printf("GetParameterValue test:%s\n",(test->GetParVal() ? "PASSED" : "FAILED"));
printf("AddVariable test:%s\n",(test->AddVar() ? "PASSED" : "FAILED"));
printf("AddVariables test:%s\n",(test->AddVars() ? "PASSED" : "FAILED"));
printf("SetVariable test:%s\n",(test->SetVar() ? "PASSED" : "FAILED"));
printf("SetVariables test:%s\n",(test->SetVars() ? "PASSED" : "FAILED"));
printf("SetParameter1 test:%s\n",(test->SetPar1() ? "PASSED" : "FAILED"));
printf("SetParameter2 test:%s\n",(test->SetPar2() ? "PASSED" : "FAILED"));
printf("SetParameters1 test:%s\n",(test->SetPars1() ? "PASSED" : "FAILED"));
printf("SetParameters2 test:%s\n",(test->SetPars2() ? "PASSED" : "FAILED"));
printf("Eval test:%s\n",(test->Eval() ? "PASSED" : "FAILED"));
#endif
printf("Stress test:%s\n",(test->Stress(n) ? "PASSED" : "FAILED"));
printf("Parsing test:%s\n",(test->Parser() ? "PASSED" : "FAILED"));
printf("Vectorization test:%s\n",(test->Vectorize() ? "PASSED" : "FAILED"));
return 0;
}