57 template<
class GradFunc = IGradModelFunction>
103 deriv = 0.5 * ( f2 -
f1 )/
h;
106 deriv = (
f1 - f0 )/
h;
122 std::copy(p, p+
fN,
fVec.begin());
130 std::copy(p, p+
fN,
fVec.begin());
131 for (
unsigned int k = 0; k <
fN; ++k) {
137 void Gradient(
const double *
x,
const double * p,
double f0,
double *
g) {
140 for (
unsigned int k = 0; k <
fN; ++k) {
150 g[k] = 0.5 * ( f2 -
f1 )/
h;
153 g[k] = (
f1 - f0 )/
h;
166 mutable std::vector<double>
fVec;
173 if (rval > - std::numeric_limits<double>::max() && rval < std::numeric_limits<double>::max() )
177 return -std::numeric_limits<double>::max();
180 return + std::numeric_limits<double>::max();
187 if (rval > - std::numeric_limits<double>::max() && rval < std::numeric_limits<double>::max() )
191 rval = -std::numeric_limits<double>::max();
196 rval = + std::numeric_limits<double>::max();
205 template <
class GFunc>
207 const double *
x1,
const double *
x2,
const double * p,
double *
g) {
213 unsigned int npar = gfunc.NPar();
214 for (
unsigned int k = 0; k < npar; ++k ) {
216 g[k] = igDerEval(
x1,
x2 );
238 unsigned int n =
data.Size();
250 bool useBinIntegral = fitOpt.
fIntegral &&
data.HasBinEdges();
255 std::cout <<
"\n\nFit data size = " <<
n << std::endl;
256 std::cout <<
"evaluate chi2 using function " << &func <<
" " << p << std::endl;
257 std::cout <<
"use empty bins " << fitOpt.
fUseEmpty << std::endl;
258 std::cout <<
"use integral " << useBinIntegral << std::endl;
259 std::cout <<
"use binvolume " << useBinVolume << std::endl;
260 std::cout <<
"use Exp Errors " << useExpErrors << std::endl;
261 std::cout <<
"use all error=1 " << fitOpt.
fErrors1 << std::endl;
262 if (isWeighted) std::cout <<
"Weighted data set - sumw = " <<
data.SumOfContent() <<
" sumw2 = " <<
data.SumOfError2() << std::endl;
275 double maxResValue = std::numeric_limits<double>::max() /
n;
276 double wrefVolume = 1.0;
283 auto mapFunction = [&](
const unsigned i){
288 const auto x1 =
data.GetCoordComponent(i, 0);
289 const auto y =
data.Value(i);
290 auto invError =
data.InvError(i);
294 const double *
x =
nullptr;
295 std::vector<double> xc;
296 double binVolume = 1.0;
298 unsigned int ndim =
data.NDim();
299 xc.resize(
data.NDim());
300 for (
unsigned int j = 0; j < ndim; ++j) {
301 double xx = *
data.GetCoordComponent(i, j);
302 double x2 =
data.GetBinUpEdgeComponent(i, j);
303 binVolume *= std::abs(
x2 - xx);
304 xc[j] = (useBinIntegral) ? xx : 0.5*(
x2 + xx);
308 binVolume *= wrefVolume;
309 }
else if(
data.NDim() > 1) {
312 xc.resize(
data.NDim());
314 for (
unsigned int j = 1; j <
data.NDim(); ++j)
315 xc[j] = *
data.GetCoordComponent(i, j);
323 if (!useBinIntegral) {
327 fval = func (
x, p );
333 std::vector<double>
x2(
data.NDim());
334 data.GetBinUpEdgeCoordinates(i,
x2.data());
335 fval = igEval(
x,
x2.data());
339 if (useBinVolume) fval *= binVolume;
343 double invWeight = 1.0;
349 invWeight =
y * invError * invError;
353 invWeight =
data.SumOfContent()/
data.SumOfError2();
356 double invError2 = (fval > 0) ? invWeight / fval : 0.0;
357 invError = std::sqrt(invError2);
362 std::cout <<
x[0] <<
" " <<
y <<
" " << 1./invError <<
" params : ";
363 for (
unsigned int ipar = 0; ipar < func.
NPar(); ++ipar)
364 std::cout << p[ipar] <<
"\t";
365 std::cout <<
"\tfval = " << fval <<
" bin volume " << binVolume <<
" ref " << wrefVolume << std::endl;
370 double tmp = (
y -fval )* invError;
371 double resval = tmp * tmp;
375 if ( resval < maxResValue )
386 auto redFunction = [](
const std::vector<double> & objs){
387 return std::accumulate(objs.begin(), objs.end(),
double{});
394 Warning(
"FitUtil::EvaluateChi2",
"Multithread execution policy requires IMT, which is disabled. Changing "
395 "to ROOT::EExecutionPolicy::kSequential.");
402 for (
unsigned int i=0; i<
n; ++i) {
403 res += mapFunction(i);
415 Error(
"FitUtil::EvaluateChi2",
"Execution policy unknown. Available choices:\n ROOT::EExecutionPolicy::kSequential (default)\n ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
435 unsigned int n =
data.Size();
438 std::cout <<
"\n\nFit data size = " <<
n << std::endl;
439 std::cout <<
"evaluate effective chi2 using function " << &func <<
" " << p << std::endl;
442 assert(
data.HaveCoordErrors() ||
data.HaveAsymErrors());
446 unsigned int ndim = func.
NDim();
448 double maxResValue = std::numeric_limits<double>::max() /
n;
450 auto mapFunction = [&](
const unsigned i) {
460 std::vector<double>
x(ndim);
461 std::vector<double>
ex(ndim);
462 for (
unsigned int icoord = 0; icoord < ndim; ++icoord) {
463 x[icoord] = *
data.GetCoordComponent(i, icoord);
464 ex[icoord] =
data.GetCoordErrorComponent(i, icoord);
467 double y =
data.Value(i);
469 double fval = func(
x.data(), p );
471 double delta_y_func =
y - fval;
475 if (!
data.HaveAsymErrors() )
478 double eylow = 0, eyhigh = 0;
479 data.GetAsymError(i, eylow, eyhigh);
480 if ( delta_y_func < 0)
488 while ( j < ndim &&
ex[j] == 0.) { j++; }
495 double kPrecision = 1.E-8;
496 for (
unsigned int icoord = 0; icoord < ndim; ++icoord) {
498 if (
ex[icoord] > 0) {
502 double x0=
x[icoord];
503 double h = std::max(
kEps* std::abs(
ex[icoord]), 8.0*kPrecision*(std::abs(x0) + kPrecision) );
505 double edx =
ex[icoord] * deriv;
508 std::cout <<
"error for coord " << icoord <<
" = " <<
ex[icoord] <<
" deriv " << deriv << std::endl;
513 double w2 = (e2 > 0) ? 1.0/e2 : 0;
514 double resval = w2 * (
y - fval ) * (
y - fval);
517 std::cout <<
x[0] <<
" " <<
y <<
" ex " <<
ex[0] <<
" ey " <<
ey <<
" params : ";
518 for (
unsigned int ipar = 0; ipar < func.
NPar(); ++ipar)
519 std::cout << p[ipar] <<
"\t";
520 std::cout <<
"\tfval = " << fval <<
"\tresval = " << resval << std::endl;
525 return ( resval < maxResValue ) ? resval : maxResValue;
530 auto redFunction = [](
const std::vector<double> & objs) {
531 return std::accumulate(objs.begin(), objs.end(),
double{});
538 Warning(
"FitUtil::EvaluateChi2Effective",
"Multithread execution policy requires IMT, which is disabled. Changing "
539 "to ROOT::EExecutionPolicy::kSequential.");
546 for (
unsigned int i = 0; i <
n; ++i) {
547 chi2 += mapFunction(i);
556 Error(
"FitUtil::EvaluateChi2Effective",
"Execution policy unknown. Available choices:\n ROOT::EExecutionPolicy::kSequential (default)\n ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
564 std::cout <<
"chi2 = " << chi2 <<
" n = " << nPoints << std::endl;
581 MATH_ERROR_MSG(
"FitUtil::EvaluateChi2Residual",
"Error on the coordinates are not used in calculating Chi2 residual");
585 double y, invError = 0;
588 bool useBinIntegral = fitOpt.
fIntegral &&
data.HasBinEdges();
593 const double *
x1 =
data.GetPoint(i,
y, invError);
595 unsigned int ndim =
data.NDim();
596 double binVolume = 1.0;
597 const double *
x2 =
nullptr;
598 if (useBinVolume || useBinIntegral)
x2 =
data.BinUpEdge(i);
600 std::vector<double> xc;
603 if (!useBinIntegral) {
605 for (
unsigned int j = 0; j < ndim; ++j) {
606 binVolume *= std::abs(
x2[j]-
x1[j] );
607 xc[j] = 0.5*(
x2[j]+
x1[j]);
611 if (useNormBinVolume) binVolume /=
data.RefVolume();
614 const double *
x = (useBinVolume) ? xc.data() :
x1;
619 double fval0 = (useBinIntegral) ? igEval(
x1,
x2) : func (
x, p );
623 if (useBinVolume) fval = fval0*binVolume;
629 double invWeight = 1.0;
631 invWeight =
y * invError * invError;
632 if (
y == 0) invWeight = (
data.SumOfError2() > 0) ?
data.SumOfContent()/
data.SumOfError2() : 1.0;
635 double invError2 = (fval > 0) ? invWeight / fval : 0.0;
636 invError = std::sqrt(invError2);
640 double resval = (
y -fval ) * invError;
648 unsigned int npar = func.
NPar();
654 if (!
h ) useFullHessian =
false;
656 if (useFullHessian && (!gfunc || useBinIntegral || (gfunc && !gfunc->
HasParameterHessian())))
657 return std::numeric_limits<double>::quiet_NaN();
661 if (!useBinIntegral ) {
663 if (useFullHessian) {
674 if (!useBinIntegral ) {
676 gc.ParameterGradient(
x, p, fval0,
g);
683 for (
unsigned int k = 0; k < npar; ++k) {
685 if (useBinVolume)
g[k] *= binVolume;
687 for (
unsigned int l = 0;
l <= k;
l++) {
688 unsigned int idx =
l + k * (k + 1) / 2;
689 if (useFullHessian) {
690 h[idx] *= 2.* resval * (-invError);
691 if (useBinVolume)
h[idx] *= binVolume;
697 h[idx] += 2. *
g[k]*
g[
l];
717 if (
data.HaveCoordErrors()) {
719 "Error on the coordinates are not used in calculating Chi2 gradient");
723 const IGradModelFunction *fg =
dynamic_cast<const IGradModelFunction *
>(&
f);
724 assert(fg !=
nullptr);
726 const IGradModelFunction &func = *fg;
729 std::cout <<
"\n\nFit data size = " << nPoints << std::endl;
730 std::cout <<
"evaluate chi2 using function gradient " << &func <<
" " << p << std::endl;
733 const DataOptions &fitOpt =
data.Opt();
734 bool useBinIntegral = fitOpt.fIntegral &&
data.HasBinEdges();
735 bool useBinVolume = (fitOpt.fBinVolume &&
data.HasBinEdges());
737 double wrefVolume = 1.0;
739 if (fitOpt.fNormBinVolume) wrefVolume /=
data.RefVolume();
747 IntegralEvaluator<> igEval(func, p, useBinIntegral,igType);
749 unsigned int npar = func.NPar();
750 unsigned initialNPoints =
data.Size();
752 std::vector<bool> isPointRejected(initialNPoints);
754 auto mapFunction = [&](
const unsigned int i) {
756 std::vector<double> gradFunc(npar);
757 std::vector<double> pointContribution(npar);
759 const auto x1 =
data.GetCoordComponent(i, 0);
760 const auto y =
data.Value(i);
761 auto invError =
data.Error(i);
763 invError = (invError != 0.0) ? 1.0 / invError : 1;
767 const double *
x =
nullptr;
768 std::vector<double> xc;
770 unsigned int ndim =
data.NDim();
771 double binVolume = 1;
774 for (
unsigned int j = 0; j < ndim; ++j) {
775 double x1_j = *
data.GetCoordComponent(i, j);
776 double x2_j =
data.GetBinUpEdgeComponent(i, j);
777 binVolume *= std::abs(x2_j - x1_j);
778 xc[j] = (useBinIntegral) ? x1_j : 0.5 * (x2_j + x1_j);
784 binVolume *= wrefVolume;
785 }
else if (ndim > 1) {
788 for (
unsigned int j = 1; j < ndim; ++j)
789 xc[j] = *
data.GetCoordComponent(i, j);
795 if (!useBinIntegral) {
797 func.ParameterGradient(
x, p, &gradFunc[0]);
799 std::vector<double>
x2(
data.NDim());
800 data.GetBinUpEdgeCoordinates(i,
x2.data());
803 fval = igEval(
x,
x2.data());
810 std::cout <<
x[0] <<
" " <<
y <<
" " << 1. / invError <<
" params : ";
811 for (
unsigned int ipar = 0; ipar < npar; ++ipar)
812 std::cout << p[ipar] <<
"\t";
813 std::cout <<
"\tfval = " << fval << std::endl;
816 isPointRejected[i] =
true;
818 return pointContribution;
822 unsigned int ipar = 0;
823 for (; ipar < npar; ++ipar) {
827 gradFunc[ipar] *= binVolume;
831 double dfval = gradFunc[ipar];
837 pointContribution[ipar] = -2.0 * (
y - fval) * invError * invError * gradFunc[ipar];
842 isPointRejected[i] =
true;
845 return pointContribution;
849 auto redFunction = [&](
const std::vector<std::vector<double>> &pointContributions) {
850 std::vector<double>
result(npar);
852 for (
auto const &pointContribution : pointContributions) {
853 for (
unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
854 result[parameterIndex] += pointContribution[parameterIndex];
860 std::vector<double>
g(npar);
865 Warning(
"FitUtil::EvaluateChi2Gradient",
"Multithread execution policy requires IMT, which is disabled. Changing "
866 "to ROOT::EExecutionPolicy::kSequential.");
872 std::vector<std::vector<double>> allGradients(initialNPoints);
873 for (
unsigned int i = 0; i < initialNPoints; ++i) {
874 allGradients[i] = mapFunction(i);
876 g = redFunction(allGradients);
880 ROOT::TThreadExecutor pool;
882 g = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, initialNPoints), redFunction, chunks);
890 Error(
"FitUtil::EvaluateChi2Gradient",
891 "Execution policy unknown. Available choices:\n 0: Serial (default)\n 1: MultiThread (requires IMT)\n");
900 nPoints = initialNPoints;
902 if (std::any_of(isPointRejected.begin(), isPointRejected.end(), [](
bool point) { return point; })) {
903 unsigned nRejected = std::accumulate(isPointRejected.begin(), isPointRejected.end(), 0);
904 assert(nRejected <= initialNPoints);
905 nPoints = initialNPoints - nRejected;
909 "Error - too many points rejected for overflow in gradient calculation");
913 std::copy(
g.begin(),
g.end(), grad);
932 const double *
x =
data.Coords(i);
933 double fval = func (
x, p );
936 if (
g ==
nullptr)
return logPdf;
950 gc.ParameterGradient(
x, p, fval,
g );
953 for (
unsigned int ipar = 0; ipar < func.
NPar(); ++ipar) {
958 std::cout <<
x[i] <<
"\t";
959 std::cout <<
"\tpar = [ " << func.
NPar() <<
" ] = ";
960 for (
unsigned int ipar = 0; ipar < func.
NPar(); ++ipar)
961 std::cout << p[ipar] <<
"\t";
962 std::cout <<
"\tfval = " << fval;
963 std::cout <<
"\tgrad = [ ";
964 for (
unsigned int ipar = 0; ipar < func.
NPar(); ++ipar)
965 std::cout <<
g[ipar] <<
"\t";
966 std::cout <<
" ] " << std::endl;
974 int iWeight,
bool extended,
unsigned int &nPoints,
979 unsigned int n =
data.Size();
983 bool normalizeFunc =
false;
987 (
const_cast<IModelFunctionTempl<double> &
>(func)).
SetParameters(p);
990 nPoints =
data.Size();
995 if (!normalizeFunc) {
996 if (
data.NDim() == 1) {
997 const double *
x =
data.GetCoordComponent(0,0);
1001 std::vector<double>
x(
data.NDim());
1002 for (
unsigned int j = 0; j <
data.NDim(); ++j)
1003 x[j] = *
data.GetCoordComponent(0, j);
1010 if (normalizeFunc) {
1012 std::vector<double>
xmin(
data.NDim());
1013 std::vector<double>
xmax(
data.NDim());
1014 IntegralEvaluator<> igEval(func, p,
true);
1016 if (
data.Range().Size() > 0) {
1018 for (
unsigned int ir = 0; ir <
data.Range().
Size(); ++ir) {
1020 norm += igEval.Integral(
xmin.data(),
xmax.data());
1026 if (func(
xmin.data(), p) != 0 || func(
xmax.data(), p) != 0) {
1028 "A range has not been set and the function is not zero at +/- inf");
1031 norm = igEval.Integral(&
xmin[0], &
xmax[0]);
1037 auto mapFunction = [&](
const unsigned i) {
1042 if (
data.NDim() > 1) {
1043 std::vector<double>
x(
data.NDim());
1044 for (
unsigned int j = 0; j <
data.NDim(); ++j)
1045 x[j] = *
data.GetCoordComponent(i, j);
1046#ifdef USE_PARAMCACHE
1047 fval = func(
x.data());
1049 fval = func(
x.data(), p);
1054 const auto x =
data.GetCoordComponent(i, 0);
1055#ifdef USE_PARAMCACHE
1063 fval = fval * (1 / norm);
1068 double weight =
data.Weight(i);
1075 W2 = weight * weight;
1079 return LikelihoodAux<double>(logval, W, W2);
1090 auto redFunction = [](
const std::vector<LikelihoodAux<double>> & objs){
1091 auto l0 = LikelihoodAux<double>(0.0,0.0,0.0);
1092 for (
auto &
l : objs ) {
1102 Warning(
"FitUtil::EvaluateLogL",
"Multithread execution policy requires IMT, which is disabled. Changing "
1103 "to ROOT::EExecutionPolicy::kSequential.");
1112 for (
unsigned int i=0; i<
n; ++i) {
1113 auto resArray = mapFunction(i);
1114 logl+=resArray.logvalue;
1115 sumW+=resArray.weight;
1116 sumW2+=resArray.weight2;
1120 ROOT::TThreadExecutor pool;
1122 auto resArray = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0,
n), redFunction, chunks);
1123 logl=resArray.logvalue;
1124 sumW=resArray.weight;
1125 sumW2=resArray.weight2;
1131 Error(
"FitUtil::EvaluateLogL",
"Execution policy unknown. Available choices:\n ROOT::EExecutionPolicy::kSequential (default)\n ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
1136 double extendedTerm = 0;
1140 if (!normalizeFunc) {
1141 IntegralEvaluator<> igEval( func, p,
true);
1142 std::vector<double>
xmin(
data.NDim());
1143 std::vector<double>
xmax(
data.NDim());
1146 if (
data.Range().Size() > 0 ) {
1148 for (
unsigned int ir = 0; ir <
data.Range().
Size(); ++ir) {
1150 nuTot += igEval.Integral(
xmin.data(),
xmax.data());
1156 if (func(
xmin.data(), p) != 0 || func(
xmax.data(), p) != 0) {
1157 MATH_ERROR_MSG(
"FitUtil::EvaluateLogLikelihood",
"A range has not been set and the function is not zero at +/- inf");
1160 nuTot = igEval.Integral(&
xmin[0],&
xmax[0]);
1166 extendedTerm = - nuTot;
1170 extendedTerm = - (sumW2 / sumW) * nuTot;
1179 logl += extendedTerm;
1184 std::cout <<
"Evaluated log L for parameters (";
1185 for (
unsigned int ip = 0; ip < func.NPar(); ++ip)
1186 std::cout <<
" " << p[ip];
1187 std::cout <<
") fval = " << -logl << std::endl;
1199 assert(fg !=
nullptr);
1203 unsigned int npar = func.
NPar();
1204 unsigned initialNPoints =
data.Size();
1209 std::cout <<
"\n===> Evaluate Gradient for parameters ";
1210 for (
unsigned int ip = 0; ip < npar; ++ip)
1211 std::cout <<
" " << p[ip];
1215 const double kdmax1 = std::sqrt(std::numeric_limits<double>::max());
1216 const double kdmax2 = std::numeric_limits<double>::max() / (4 * initialNPoints);
1218 auto mapFunction = [&](
const unsigned int i) {
1219 std::vector<double> gradFunc(npar);
1220 std::vector<double> pointContribution(npar);
1223 const double *
x =
nullptr;
1224 std::vector<double> xc;
1225 if (
data.NDim() > 1) {
1226 xc.resize(
data.NDim() );
1227 for (
unsigned int j = 0; j <
data.NDim(); ++j)
1228 xc[j] = *
data.GetCoordComponent(i, j);
1231 x =
data.GetCoordComponent(i, 0);
1234 double fval = func(
x, p);
1235 func.ParameterGradient(
x, p, &gradFunc[0]);
1240 if (i < 5 || (i >
data.Size()-5) ) {
1241 if (
data.NDim() > 1) std::cout << i <<
" x " <<
x[0] <<
" y " <<
x[1] <<
" func " << fval
1242 <<
" gradient " << gradFunc[0] <<
" " << gradFunc[1] <<
" " << gradFunc[3] << std::endl;
1243 else std::cout << i <<
" x " <<
x[0] <<
" gradient " << gradFunc[0] <<
" " << gradFunc[1] <<
" " << gradFunc[3] << std::endl;
1248 for (
unsigned int kpar = 0; kpar < npar; ++kpar) {
1250 pointContribution[kpar] = -1. / fval * gradFunc[kpar];
1251 else if (gradFunc[kpar] != 0) {
1252 double gg = kdmax1 * gradFunc[kpar];
1254 gg = std::min(gg, kdmax2);
1256 gg = std::max(gg, -kdmax2);
1257 pointContribution[kpar] = -gg;
1262 return pointContribution;
1266 auto redFunction = [&](
const std::vector<std::vector<double>> &pointContributions) {
1267 std::vector<double>
result(npar);
1269 for (
auto const &pointContribution : pointContributions) {
1270 for (
unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
1271 result[parameterIndex] += pointContribution[parameterIndex];
1277 std::vector<double>
g(npar);
1282 Warning(
"FitUtil::EvaluateLogLGradient",
"Multithread execution policy requires IMT, which is disabled. Changing "
1283 "to ROOT::EExecutionPolicy::kSequential.");
1289 std::vector<std::vector<double>> allGradients(initialNPoints);
1290 for (
unsigned int i = 0; i < initialNPoints; ++i) {
1291 allGradients[i] = mapFunction(i);
1293 g = redFunction(allGradients);
1297 ROOT::TThreadExecutor pool;
1299 g = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, initialNPoints), redFunction, chunks);
1303 Error(
"FitUtil::EvaluateLogLGradient",
"Execution policy unknown. Available choices:\n "
1304 "ROOT::EExecutionPolicy::kSequential (default)\n "
1305 "ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
1314 std::copy(
g.begin(),
g.end(), grad);
1315 nPoints =
data.Size();
1318 std::cout <<
"FitUtil.cxx : Final gradient ";
1319 for (
unsigned int param = 0; param < npar; param++) {
1320 std::cout <<
" " << grad[param];
1333 const double *
x1 =
data.GetPoint(i,
y);
1336 bool useBinIntegral = fitOpt.
fIntegral &&
data.HasBinEdges();
1340 const double *
x2 =
nullptr;
1342 double binVolume = 1;
1343 std::vector<double> xc;
1345 unsigned int ndim =
data.NDim();
1347 for (
unsigned int j = 0; j < ndim; ++j) {
1348 double x2j =
data.GetBinUpEdgeComponent(i, j);
1349 binVolume *= std::abs( x2j-
x1[j] );
1350 xc[j] = 0.5*(x2j+
x1[j]);
1353 binVolume /=
data.RefVolume();
1356 const double *
x = (useBinVolume) ? &xc.front() :
x1;
1359 if (!useBinIntegral ) {
1360 fval0 = func (
x, p );
1364 std::vector<double> vx2(
data.NDim());
1365 data.GetBinUpEdgeCoordinates(i, vx2.data());
1366 fval0 = igEval(
x1, vx2.data() ) ;
1368 double fval = fval0;
1369 if (useBinVolume) fval = fval0*binVolume;
1372 fval = std::max(fval, 0.0);
1373 double nlogPdf = fval;
1379 if (
g ==
nullptr)
return nlogPdf;
1381 unsigned int npar = func.
NPar();
1386 if (useFullHessian && (!gfunc || useBinIntegral || (gfunc && !gfunc->
HasParameterHessian())))
1387 return std::numeric_limits<double>::quiet_NaN();
1392 if (!useBinIntegral ) {
1394 if (useFullHessian &&
h) {
1396 return std::numeric_limits<double>::quiet_NaN();
1398 if (!goodHessFunc) {
1399 return std::numeric_limits<double>::quiet_NaN();
1411 if (!useBinIntegral )
1412 gc.ParameterGradient(
x, p, fval0,
g);
1419 double coeffGrad = (fval > 0) ? (1. -
y/fval) : ( (
y > 0) ? std::sqrt( std::numeric_limits<double>::max() ) : 1. );
1420 double coeffHess = (fval > 0) ?
y/(fval*fval) : ( (
y > 0) ? std::sqrt( std::numeric_limits<double>::max() ) : 0. );
1422 coeffGrad *= binVolume;
1423 coeffHess *= binVolume*binVolume;
1425 for (
unsigned int k = 0; k < npar; ++k) {
1428 for (
unsigned int l = k;
l < npar; ++
l) {
1429 unsigned int idx = k +
l * (
l + 1) / 2;
1430 if (useFullHessian) {
1431 h[idx] *= coeffGrad;
1437 h[idx] += coeffHess *
g[k]*
g[
l];
1448 std::cout <<
"x = " <<
x[0] <<
" y " <<
y <<
" fval " << fval <<
" logPdf = " << nlogPdf <<
" gradient : ";
1449 for (
unsigned int ipar = 0; ipar < npar; ++ipar)
1450 std::cout <<
g[ipar] <<
"\t";
1452 std::cout <<
"\thessian : ";
1453 for (
unsigned int ipar = 0; ipar < npar; ++ipar) {
1455 for (
unsigned int jpar = 0; jpar <= ipar; ++jpar) {
1456 std::cout <<
h[ipar + jpar * (jpar + 1) / 2] <<
"\t";
1461 std::cout << std::endl;
1489 unsigned int n =
data.Size();
1491#ifdef USE_PARAMCACHE
1495 nPoints =
data.Size();
1500 bool useBinIntegral = fitOpt.
fIntegral &&
data.HasBinEdges();
1502 bool useW2 = (iWeight == 2);
1505 double wrefVolume = 1.0;
1512 std::cout <<
"Evaluate PoissonLogL for params = [ ";
1513 for (
unsigned int j = 0; j < func.NPar(); ++j) std::cout << p[j] <<
" , ";
1514 std::cout <<
"] - data size = " <<
n <<
" useBinIntegral " << useBinIntegral <<
" useBinVolume "
1515 << useBinVolume <<
" useW2 " << useW2 <<
" wrefVolume = " << wrefVolume << std::endl;
1524#ifdef USE_PARAMCACHE
1525 IntegralEvaluator<> igEval(func,
nullptr, useBinIntegral, igType);
1527 IntegralEvaluator<> igEval(func, p, useBinIntegral, igType);
1530 auto mapFunction = [&](
const unsigned i) {
1531 auto x1 =
data.GetCoordComponent(i, 0);
1532 auto y = *
data.ValuePtr(i);
1534 const double *
x =
nullptr;
1535 std::vector<double> xc;
1537 double binVolume = 1.0;
1540 unsigned int ndim =
data.NDim();
1541 xc.resize(
data.NDim());
1542 for (
unsigned int j = 0; j < ndim; ++j) {
1543 double xx = *
data.GetCoordComponent(i, j);
1544 double x2 =
data.GetBinUpEdgeComponent(i, j);
1545 binVolume *= std::abs(
x2 - xx);
1546 xc[j] = (useBinIntegral) ? xx : 0.5 * (
x2 + xx);
1550 binVolume *= wrefVolume;
1551 }
else if (
data.NDim() > 1) {
1552 xc.resize(
data.NDim());
1554 for (
unsigned int j = 1; j <
data.NDim(); ++j) {
1555 xc[j] = *
data.GetCoordComponent(i, j);
1562 if (!useBinIntegral) {
1563#ifdef USE_PARAMCACHE
1571 std::vector<double>
x2(
data.NDim());
1572 data.GetBinUpEdgeCoordinates(i,
x2.data());
1573 fval = igEval(
x,
x2.data());
1575 if (useBinVolume) fval *= binVolume;
1581 if (i % NSAMPLE == 0) {
1582 std::cout <<
"evt " << i <<
" x = [ ";
1583 for (
unsigned int j = 0; j < func.NDim(); ++j) std::cout <<
x[j] <<
" , ";
1586 std::cout <<
"x2 = [ ";
1587 for (
unsigned int j = 0; j < func.NDim(); ++j) std::cout <<
data.GetBinUpEdgeComponent(i, j) <<
" , ";
1590 std::cout <<
" y = " <<
y <<
" fval = " << fval << std::endl;
1597 fval = std::max(fval, 0.0);
1599 double nloglike = 0;
1608 double weight = 1.0;
1610 double error =
data.Error(i);
1611 weight = (error * error) /
y;
1616 weight =
data.SumOfError2()/
data.SumOfContent();
1619 nloglike += weight * ( fval -
y);
1627 if (extended) nloglike = fval -
y;
1636 std::cout <<
" nll = " << nloglike << std::endl;
1643 auto redFunction = [](
const std::vector<double> &objs) {
1644 return std::accumulate(objs.begin(), objs.end(),
double{});
1651 Warning(
"FitUtil::EvaluatePoissonLogL",
"Multithread execution policy requires IMT, which is disabled. Changing "
1652 "to ROOT::EExecutionPolicy::kSequential.");
1659 for (
unsigned int i = 0; i <
n; ++i) {
1660 res += mapFunction(i);
1664 ROOT::TThreadExecutor pool;
1666 res = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0,
n), redFunction, chunks);
1672 Error(
"FitUtil::EvaluatePoissonLogL",
1673 "Execution policy unknown. Available choices:\n ROOT::EExecutionPolicy::kSequential (default)\n ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
1677 std::cout <<
"Loglikelihood = " << res << std::endl;
1689 assert(fg !=
nullptr);
1693#ifdef USE_PARAMCACHE
1698 bool useBinIntegral = fitOpt.fIntegral &&
data.HasBinEdges();
1699 bool useBinVolume = (fitOpt.fBinVolume &&
data.HasBinEdges());
1701 double wrefVolume = 1.0;
1702 if (useBinVolume && fitOpt.fNormBinVolume)
1703 wrefVolume /=
data.RefVolume();
1711 IntegralEvaluator<> igEval(func, p, useBinIntegral, igType);
1713 unsigned int npar = func.NPar();
1714 unsigned initialNPoints =
data.Size();
1716 auto mapFunction = [&](
const unsigned int i) {
1718 std::vector<double> gradFunc(npar);
1719 std::vector<double> pointContribution(npar);
1721 const auto x1 =
data.GetCoordComponent(i, 0);
1722 const auto y =
data.Value(i);
1723 auto invError =
data.Error(i);
1725 invError = (invError != 0.0) ? 1.0 / invError : 1;
1729 const double *
x =
nullptr;
1730 std::vector<double> xc;
1732 unsigned ndim =
data.NDim();
1733 double binVolume = 1.0;
1738 for (
unsigned int j = 0; j < ndim; ++j) {
1739 double x1_j = *
data.GetCoordComponent(i, j);
1740 double x2_j =
data.GetBinUpEdgeComponent(i, j);
1741 binVolume *= std::abs(x2_j - x1_j);
1742 xc[j] = (useBinIntegral) ? x1_j : 0.5 * (x2_j + x1_j);
1748 binVolume *= wrefVolume;
1749 }
else if (ndim > 1) {
1752 for (
unsigned int j = 1; j < ndim; ++j)
1753 xc[j] = *
data.GetCoordComponent(i, j);
1759 if (!useBinIntegral) {
1761 func.ParameterGradient(
x, p, &gradFunc[0]);
1765 std::vector<double>
x2(
data.NDim());
1766 data.GetBinUpEdgeCoordinates(i,
x2.data());
1767 fval = igEval(
x,
x2.data());
1776 if (i < 5 || (i >
data.Size()-5) ) {
1777 if (
data.NDim() > 1) std::cout << i <<
" x " <<
x[0] <<
" y " <<
x[1] <<
" func " << fval
1778 <<
" gradient " << gradFunc[0] <<
" " << gradFunc[1] <<
" " << gradFunc[3] << std::endl;
1779 else std::cout << i <<
" x " <<
x[0] <<
" gradient " << gradFunc[0] <<
" " << gradFunc[1] <<
" " << gradFunc[3] << std::endl;
1785 for (
unsigned int ipar = 0; ipar < npar; ++ipar) {
1789 gradFunc[ipar] *= binVolume;
1793 pointContribution[ipar] = gradFunc[ipar] * (1. -
y / fval);
1794 else if (gradFunc[ipar] != 0) {
1795 const double kdmax1 = std::sqrt(std::numeric_limits<double>::max());
1796 const double kdmax2 = std::numeric_limits<double>::max() / (4 * initialNPoints);
1797 double gg = kdmax1 * gradFunc[ipar];
1799 gg = std::min(gg, kdmax2);
1801 gg = std::max(gg, -kdmax2);
1802 pointContribution[ipar] = -gg;
1807 return pointContribution;
1811 auto redFunction = [&](
const std::vector<std::vector<double>> &pointContributions) {
1812 std::vector<double>
result(npar);
1814 for (
auto const &pointContribution : pointContributions) {
1815 for (
unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
1816 result[parameterIndex] += pointContribution[parameterIndex];
1822 std::vector<double>
g(npar);
1827 Warning(
"FitUtil::EvaluatePoissonLogLGradient",
1828 "Multithread execution policy requires IMT, which is disabled. Changing "
1829 "to ROOT::EExecutionPolicy::kSequential.");
1835 std::vector<std::vector<double>> allGradients(initialNPoints);
1836 for (
unsigned int i = 0; i < initialNPoints; ++i) {
1837 allGradients[i] = mapFunction(i);
1839 g = redFunction(allGradients);
1843 ROOT::TThreadExecutor pool;
1845 g = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, initialNPoints), redFunction, chunks);
1854 Error(
"FitUtil::EvaluatePoissonLogLGradient",
1855 "Execution policy unknown. Available choices:\n 0: Serial (default)\n 1: MultiThread (requires IMT)\n");
1864 std::copy(
g.begin(),
g.end(), grad);
1867 std::cout <<
"***** Final gradient : ";
1868 for (
unsigned int ii = 0; ii< npar; ++ii) std::cout << grad[ii] <<
" ";
1877 if (nEvents/ncpu < 1000)
return ncpu;
1878 return nEvents/1000;
1882#ifdef R__HAS_STD_EXPERIMENTAL_SIMD
1890 return T{std::numeric_limits<typename T::value_type>::max()};
1893template <
typename V,
typename S>
1894void Load(V &
v, S
const *ptr)
1896 for (
size_t i = 0; i < V::size(); ++i)
1900template <
typename T>
1901auto ReduceAdd(
const T &
v)
1903 typename T::value_type
result(0);
1904 for (
size_t i = 0; i < T::size(); ++i) {
1910template <
typename T>
1911bool MaskEmpty(T
mask)
1913 for (
size_t i = 0; i < T::size(); ++i)
1919template <
class T = ROOT::Double_v>
1920auto Int2Mask(
unsigned i)
1923 for (
unsigned j = 0; j < T::size(); j++) {
1941 unsigned int n =
data.Size();
1942 nPoints =
data.Size();
1945#ifdef USE_PARAMCACHE
1952 const DataOptions &fitOpt =
data.Opt();
1953 if (fitOpt.fBinVolume || fitOpt.fIntegral || fitOpt.fExpErrors)
1954 Error(
"FitUtil::EvaluateChi2",
1955 "The vectorized implementation doesn't support Integrals, BinVolume or ExpErrors\n. Aborting operation.");
1959 double maxResValue = std::numeric_limits<double>::max() /
n;
1960 std::vector<double> ones{1., 1., 1., 1.};
1961 auto vecSize = Double_v::size();
1963 auto mapFunction = [&](
unsigned int i) {
1965 Double_v
x1,
y, invErrorVec;
1966 Load(
x1,
data.GetCoordComponent(i * vecSize, 0));
1967 Load(
y,
data.ValuePtr(i * vecSize));
1968 const auto invError =
data.ErrorPtr(i * vecSize);
1969 auto invErrorptr = (invError !=
nullptr) ? invError : &ones.front();
1970 Load(invErrorVec, invErrorptr);
1973 std::vector<Double_v> xc;
1974 if (
data.NDim() > 1) {
1975 xc.resize(
data.NDim());
1977 for (
unsigned int j = 1; j <
data.NDim(); ++j)
1978 Load(xc[j],
data.GetCoordComponent(i * vecSize, j));
1986#ifdef USE_PARAMCACHE
1992 Double_v tmp = (
y - fval) * invErrorVec;
1993 Double_v chi2 = tmp * tmp;
1996 where(chi2 > maxResValue, chi2) = maxResValue;
2001 auto redFunction = [](
const std::vector<Double_v> &objs) {
2002 return std::accumulate(objs.begin(), objs.end(), Double_v{});
2010 Warning(
"FitUtil::EvaluateChi2",
"Multithread execution policy requires IMT, which is disabled. Changing "
2011 "to ::ROOT::EExecutionPolicy::kSequential.");
2018 ROOT::TSequentialExecutor pool;
2019 res = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0,
data.Size() / vecSize), redFunction);
2022 ROOT::TThreadExecutor pool;
2024 res = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0,
data.Size() / vecSize), redFunction, chunks);
2027 Error(
"FitUtil::EvaluateChi2",
2028 "Execution policy unknown. Available choices:\n ::ROOT::EExecutionPolicy::kSequential (default)\n "
2029 "::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
2033 if (
data.Size() % vecSize != 0)
2034 where(Int2Mask(
data.Size() % vecSize), res) = res + mapFunction(
data.Size() / vecSize);
2036 return ReduceAdd(res);
2040 const double *
const p,
int iWeight,
bool extended,
unsigned int &nPoints,
2044 unsigned int n =
data.Size();
2045 nPoints =
data.Size();
2048 bool normalizeFunc =
false;
2051#ifdef USE_PARAMCACHE
2058 if (!normalizeFunc) {
2059 if (
data.NDim() == 1) {
2061 Load(
x,
data.GetCoordComponent(0, 0));
2064 std::vector<Double_v>
x(
data.NDim());
2065 for (
unsigned int j = 0; j <
data.NDim(); ++j)
2066 Load(
x[j],
data.GetCoordComponent(0, j));
2074 if (normalizeFunc) {
2076 std::vector<double>
xmin(
data.NDim());
2077 std::vector<double>
xmax(
data.NDim());
2080 if (
data.Range().Size() > 0) {
2082 for (
unsigned int ir = 0; ir <
data.Range().
Size(); ++ir) {
2084 norm += igEval.Integral(
xmin.data(),
xmax.data());
2092 Load(xmin_v,
xmin.data());
2093 Load(xmax_v,
xmax.data());
2094 if (ReduceAdd(func(&xmin_v, p)) != 0 || ReduceAdd(func(&xmax_v, p)) != 0) {
2096 "A range has not been set and the function is not zero at +/- inf");
2099 norm = igEval.Integral(&
xmin[0], &
xmax[0]);
2105 auto vecSize = Double_v::size();
2106 unsigned int numVectors =
n / vecSize;
2108 auto mapFunction = [&, p](
const unsigned i) {
2116 Load(
x1,
data.GetCoordComponent(i * vecSize, 0));
2117 const Double_v *
x =
nullptr;
2118 unsigned int ndim =
data.NDim();
2119 std::vector<Double_v> xc;
2123 for (
unsigned int j = 1; j < ndim; ++j)
2124 Load(xc[j],
data.GetCoordComponent(i * vecSize, j));
2130#ifdef USE_PARAMCACHE
2137 if (i < 5 || (i > numVectors - 5)) {
2139 std::cout << i <<
" x " <<
x[0] <<
" fval = " << fval;
2141 std::cout << i <<
" x " <<
x[0] <<
" y " <<
x[1] <<
" fval = " << fval;
2146 fval = fval * (1 / norm);
2152 if (
data.WeightsPtr(i) ==
nullptr)
2155 Load(weight,
data.WeightsPtr(i * vecSize));
2162 W2 = weight * weight;
2167 if (i < 5 || (i > numVectors - 5)) {
2168 std::cout <<
" " << fval <<
" logfval " << logval << std::endl;
2175 auto redFunction = [](
const std::vector<LikelihoodAux<Double_v>> &objs) {
2176 return std::accumulate(
2186 Warning(
"FitUtil::EvaluateLogL",
"Multithread execution policy requires IMT, which is disabled. Changing "
2187 "to ::ROOT::EExecutionPolicy::kSequential.");
2195 ROOT::Fit::FitUtil::LikelihoodAux<Double_v> resArray;
2197 ROOT::TSequentialExecutor pool;
2198 resArray = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0,
data.Size() / vecSize), redFunction);
2201 ROOT::TThreadExecutor pool;
2203 resArray = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0,
data.Size() / vecSize), redFunction, chunks);
2206 Error(
"FitUtil::EvaluateLogL",
2207 "Execution policy unknown. Available choices:\n ::ROOT::EExecutionPolicy::kSequential (default)\n "
2208 "::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
2212 sumW_v = resArray.
weight;
2216 unsigned int remainingPoints =
n % vecSize;
2217 if (remainingPoints > 0) {
2218 auto remainingPointsContribution = mapFunction(numVectors);
2220 auto remainingMask = Int2Mask(remainingPoints);
2221 where(remainingMask, logl_v) = logl_v + remainingPointsContribution.logvalue;
2222 where(remainingMask, sumW_v) = sumW_v + remainingPointsContribution.weight;
2223 where(remainingMask, sumW2_v) = sumW2_v + remainingPointsContribution.weight2;
2227 double logl = ReduceAdd(logl_v);
2228 double sumW = ReduceAdd(sumW_v);
2229 double sumW2 = ReduceAdd(sumW2_v);
2233 double extendedTerm = 0;
2237 if (!normalizeFunc) {
2239 std::vector<double>
xmin(
data.NDim());
2240 std::vector<double>
xmax(
data.NDim());
2243 if (
data.Range().Size() > 0) {
2245 for (
unsigned int ir = 0; ir <
data.Range().
Size(); ++ir) {
2247 nuTot += igEval.Integral(
xmin.data(),
xmax.data());
2253 Double_v xmin_v, xmax_v;
2254 Load(xmin_v,
xmin.data());
2255 Load(xmax_v,
xmax.data());
2256 if (ReduceAdd(func(&xmin_v, p)) != 0 || ReduceAdd(func(&xmax_v, p)) != 0) {
2258 "A range has not been set and the function is not zero at +/- inf");
2261 nuTot = igEval.Integral(&
xmin[0], &
xmax[0]);
2267 extendedTerm = -nuTot;
2271 extendedTerm = -(sumW2 / sumW) * nuTot;
2280 logl += extendedTerm;
2284 std::cout <<
"Evaluated log L for parameters (";
2285 for (
unsigned int ip = 0; ip < func.NPar(); ++ip)
2286 std::cout <<
" " << p[ip];
2287 std::cout <<
") nll = " << -logl << std::endl;
2294 const double *p,
int iWeight,
bool extended,
unsigned int,
2312#ifdef USE_PARAMCACHE
2315 auto vecSize = Double_v::size();
2317 const DataOptions &fitOpt =
data.Opt();
2318 if (fitOpt.fExpErrors || fitOpt.fIntegral)
2319 Error(
"FitUtil::EvaluateChi2",
2320 "The vectorized implementation doesn't support Integrals or BinVolume\n. Aborting operation.");
2321 bool useW2 = (iWeight == 2);
2323 auto mapFunction = [&](
unsigned int i) {
2325 Load(
y,
data.ValuePtr(i * vecSize));
2328 if (
data.NDim() > 1) {
2329 std::vector<Double_v>
x(
data.NDim());
2330 for (
unsigned int j = 0; j <
data.NDim(); ++j)
2331 Load(
x[j],
data.GetCoordComponent(i * vecSize, j));
2332#ifdef USE_PARAMCACHE
2333 fval = func(
x.data());
2335 fval = func(
x.data(), p);
2340 Load(
x,
data.GetCoordComponent(i * vecSize, 0));
2341#ifdef USE_PARAMCACHE
2350 where(fval < 0.0, fval) = 0.0;
2352 Double_v nloglike{};
2361 Double_v error = 0.0;
2362 Load(error,
data.ErrorPtr(i * vecSize));
2366 where(
m, weight) = (error * error) /
y;
2367 where(!
m, weight) = Double_v{
data.SumOfError2() /
data.SumOfContent()};
2369 nloglike = weight * (fval -
y);
2371 where(
y != 0, nloglike) =
2380 nloglike = fval -
y;
2389 auto redFunction = [](
const std::vector<Double_v> &objs) {
2390 return std::accumulate(objs.begin(), objs.end(), Double_v{});
2397 Warning(
"FitUtil::Evaluate<T>::EvalPoissonLogL",
2398 "Multithread execution policy requires IMT, which is disabled. Changing "
2399 "to ::ROOT::EExecutionPolicy::kSequential.");
2406 for (
unsigned int i = 0; i < (
data.Size() / vecSize); i++) {
2407 res += mapFunction(i);
2411 ROOT::TThreadExecutor pool;
2413 res = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0,
data.Size() / vecSize), redFunction, chunks);
2416 Error(
"FitUtil::Evaluate<T>::EvalPoissonLogL",
2417 "Execution policy unknown. Available choices:\n ::ROOT::EExecutionPolicy::kSequential (default)\n "
2418 "::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
2422 if (
data.Size() % vecSize != 0)
2423 where(Int2Mask(
data.Size() % vecSize), res) = res + mapFunction(
data.Size() / vecSize);
2425 return ReduceAdd(res);
2433auto CheckInfNaNValues(Double_v &rval)
2435 auto mask = rval > -NumericMax<Double_v>() && rval < NumericMax<Double_v>();
2438 where(!
mask, rval) = +NumericMax<Double_v>();
2441 where(!
mask && rval < 0, rval) = -NumericMax<Double_v>();
2458 if (
data.HaveCoordErrors()) {
2460 "Error on the coordinates are not used in calculating Chi2 gradient");
2465 assert(fg !=
nullptr);
2469 const DataOptions &fitOpt =
data.Opt();
2470 if (fitOpt.fBinVolume || fitOpt.fIntegral || fitOpt.fExpErrors)
2471 Error(
"FitUtil::EvaluateChi2Gradient",
"The vectorized implementation doesn't support Integrals,"
2472 "BinVolume or ExpErrors\n. Aborting operation.");
2474 unsigned int npar = func.NPar();
2475 auto vecSize = Double_v::size();
2476 unsigned initialNPoints =
data.Size();
2477 unsigned numVectors = initialNPoints / vecSize;
2480 std::vector<Double_v::mask_type> validPointsMasks(numVectors + 1);
2482 auto mapFunction = [&](
const unsigned int i) {
2484 std::vector<Double_v> gradFunc(npar);
2485 std::vector<Double_v> pointContributionVec(npar);
2487 Double_v
x1,
y, invError;
2489 Load(
x1,
data.GetCoordComponent(i * vecSize, 0));
2490 Load(
y,
data.ValuePtr(i * vecSize));
2491 const auto invErrorPtr =
data.ErrorPtr(i * vecSize);
2493 if (invErrorPtr ==
nullptr)
2496 Load(invError, invErrorPtr);
2502 const Double_v *
x =
nullptr;
2504 unsigned int ndim =
data.NDim();
2507 std::vector<Double_v> xc;
2511 for (
unsigned int j = 1; j < ndim; ++j)
2512 Load(xc[j],
data.GetCoordComponent(i * vecSize, j));
2519 func.ParameterGradient(
x, p, &gradFunc[0]);
2521 validPointsMasks[i] = CheckInfNaNValues(fval);
2522 if (MaskEmpty(validPointsMasks[i])) {
2524 return pointContributionVec;
2528 for (
unsigned int ipar = 0; ipar < npar; ++ipar) {
2531 validPointsMasks[i] = CheckInfNaNValues(gradFunc[ipar]);
2533 if (MaskEmpty(validPointsMasks[i])) {
2538 where(validPointsMasks[i], pointContributionVec[ipar]) =
2539 -2.0 * (
y - fval) * invError * invError * gradFunc[ipar];
2542 return pointContributionVec;
2546 auto redFunction = [&](
const std::vector<std::vector<Double_v>> &partialResults) {
2547 std::vector<Double_v>
result(npar);
2549 for (
auto const &pointContributionVec : partialResults) {
2550 for (
unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
2551 result[parameterIndex] += pointContributionVec[parameterIndex];
2557 std::vector<Double_v> gVec(npar);
2558 std::vector<double>
g(npar);
2566 Warning(
"FitUtil::EvaluateChi2Gradient",
"Multithread execution policy requires IMT, which is disabled. Changing "
2567 "to ::ROOT::EExecutionPolicy::kSequential.");
2573 ROOT::TSequentialExecutor pool;
2574 gVec = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, numVectors), redFunction);
2578 ROOT::TThreadExecutor pool;
2580 gVec = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, numVectors), redFunction, chunks);
2584 Error(
"FitUtil::EvaluateChi2Gradient",
2585 "Execution policy unknown. Available choices:\n 0: Serial (default)\n 1: MultiThread (requires IMT)\n");
2589 unsigned int remainingPoints = initialNPoints % vecSize;
2590 if (remainingPoints > 0) {
2591 auto remainingPointsContribution = mapFunction(numVectors);
2593 auto remainingMask = Int2Mask(remainingPoints);
2594 for (
unsigned int param = 0; param < npar; param++) {
2595 where(remainingMask, gVec[param]) = gVec[param] + remainingPointsContribution[param];
2599 for (
unsigned int param = 0; param < npar; param++) {
2600 grad[param] = ReduceAdd(gVec[param]);
2604 nPoints = initialNPoints;
2606 if (std::any_of(validPointsMasks.begin(), validPointsMasks.end(), [](
auto validPoints) {
2608 for (size_t i = 0; i < Double_v::mask_type::size(); ++i)
2609 if (!validPoints[i])
2613 unsigned nRejected = 0;
2615 for (
const auto &
mask : validPointsMasks) {
2616 for (
unsigned int i = 0; i < vecSize; i++) {
2617 nRejected += !
mask[i];
2621 assert(nRejected <= initialNPoints);
2622 nPoints = initialNPoints - nRejected;
2624 if (nPoints < npar) {
2626 "Too many points rejected for overflow in gradient calculation");
2632 const double *p,
double *grad,
unsigned int &,
2638 assert(fg !=
nullptr);
2644 const DataOptions &fitOpt =
data.Opt();
2645 if (fitOpt.fBinVolume || fitOpt.fIntegral || fitOpt.fExpErrors)
2646 Error(
"FitUtil::EvaluatePoissonLogLGradient",
"The vectorized implementation doesn't support Integrals,"
2647 "BinVolume or ExpErrors\n. Aborting operation.");
2649 unsigned int npar = func.NPar();
2650 auto vecSize = Double_v::size();
2651 unsigned initialNPoints =
data.Size();
2652 unsigned numVectors = initialNPoints / vecSize;
2654 auto mapFunction = [&](
const unsigned int i) {
2656 std::vector<Double_v> gradFunc(npar);
2657 std::vector<Double_v> pointContributionVec(npar);
2661 Load(
x1,
data.GetCoordComponent(i * vecSize, 0));
2662 Load(
y,
data.ValuePtr(i * vecSize));
2666 const Double_v *
x =
nullptr;
2668 unsigned ndim =
data.NDim();
2669 std::vector<Double_v> xc;
2673 for (
unsigned int j = 1; j < ndim; ++j)
2674 Load(xc[j],
data.GetCoordComponent(i * vecSize, j));
2681 func.ParameterGradient(
x, p, &gradFunc[0]);
2684 for (
unsigned int ipar = 0; ipar < npar; ++ipar) {
2685 auto positiveValuesMask = fval > 0;
2688 where(positiveValuesMask, pointContributionVec[ipar]) = gradFunc[ipar] * (1. -
y / fval);
2690 auto validNegativeValuesMask = !positiveValuesMask && gradFunc[ipar] != 0;
2692 if (!MaskEmpty(validNegativeValuesMask)) {
2693 const Double_v kdmax1 =
sqrt(NumericMax<Double_v>());
2694 const Double_v kdmax2 = NumericMax<Double_v>() / (4 * initialNPoints);
2695 Double_v gg = kdmax1 * gradFunc[ipar];
2697 where(
mask, pointContributionVec[ipar]) = min(gg, kdmax2);
2698 where(!
mask, pointContributionVec[ipar]) =
max(gg, -kdmax2);
2699 pointContributionVec[ipar] = -pointContributionVec[ipar];
2706 if (i < 5 || (i >
data.Size() - 5)) {
2707 if (
data.NDim() > 1)
2708 std::cout << i <<
" x " <<
x[0] <<
" y " <<
x[1];
2710 std::cout << i <<
" x " <<
x[0];
2711 std::cout <<
" func " << fval <<
" gradient ";
2712 for (
unsigned int ii = 0; ii < npar; ++ii)
2713 std::cout <<
" " << pointContributionVec[ii];
2719 return pointContributionVec;
2723 auto redFunction = [&](
const std::vector<std::vector<Double_v>> &partialResults) {
2724 std::vector<Double_v>
result(npar);
2726 for (
auto const &pointContributionVec : partialResults) {
2727 for (
unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
2728 result[parameterIndex] += pointContributionVec[parameterIndex];
2734 std::vector<Double_v> gVec(npar);
2742 Warning(
"FitUtil::EvaluatePoissonLogLGradient",
2743 "Multithread execution policy requires IMT, which is disabled. Changing "
2744 "to ::ROOT::EExecutionPolicy::kSequential.");
2750 ROOT::TSequentialExecutor pool;
2751 gVec = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, numVectors), redFunction);
2755 ROOT::TThreadExecutor pool;
2757 gVec = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, numVectors), redFunction, chunks);
2761 Error(
"FitUtil::EvaluatePoissonLogLGradient",
"Execution policy unknown. Available choices:\n "
2762 "::ROOT::EExecutionPolicy::kSequential (default)\n "
2763 "::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
2767 unsigned int remainingPoints = initialNPoints % vecSize;
2768 if (remainingPoints > 0) {
2769 auto remainingPointsContribution = mapFunction(numVectors);
2771 auto remainingMask = Int2Mask(remainingPoints);
2772 for (
unsigned int param = 0; param < npar; param++) {
2773 where(remainingMask, gVec[param]) = gVec[param] + remainingPointsContribution[param];
2777 for (
unsigned int param = 0; param < npar; param++) {
2778 grad[param] = ReduceAdd(gVec[param]);
2782 std::cout <<
"***** Final gradient : ";
2783 for (
unsigned int ii = 0; ii < npar; ++ii)
2784 std::cout << grad[ii] <<
" ";
2790 const double *p,
double *grad,
unsigned int &,
2796 assert(fg !=
nullptr);
2800 unsigned int npar = func.NPar();
2801 auto vecSize = Double_v::size();
2802 unsigned initialNPoints =
data.Size();
2803 unsigned numVectors = initialNPoints / vecSize;
2806 std::cout <<
"\n===> Evaluate Gradient for parameters ";
2807 for (
unsigned int ip = 0; ip < npar; ++ip)
2808 std::cout <<
" " << p[ip];
2814 const Double_v kdmax1 =
sqrt(NumericMax<Double_v>());
2815 const Double_v kdmax2 = NumericMax<Double_v>() / (4 * initialNPoints);
2817 auto mapFunction = [&](
const unsigned int i) {
2818 std::vector<Double_v> gradFunc(npar);
2819 std::vector<Double_v> pointContributionVec(npar);
2822 Load(
x1,
data.GetCoordComponent(i * vecSize, 0));
2824 const Double_v *
x =
nullptr;
2826 unsigned int ndim =
data.NDim();
2827 std::vector<Double_v> xc(ndim);
2831 for (
unsigned int j = 1; j < ndim; ++j)
2832 Load(xc[j],
data.GetCoordComponent(i * vecSize, j));
2838 Double_v fval = func(
x, p);
2839 func.ParameterGradient(
x, p, &gradFunc[0]);
2842 if (i < 5 || (i > numVectors - 5)) {
2844 std::cout << i <<
" x " <<
x[0] <<
" y " <<
x[1] <<
" gradient " << gradFunc[0] <<
" " << gradFunc[1]
2845 <<
" " << gradFunc[3] << std::endl;
2847 std::cout << i <<
" x " <<
x[0] <<
" gradient " << gradFunc[0] <<
" " << gradFunc[1] <<
" "
2848 << gradFunc[3] << std::endl;
2852 auto positiveValues = fval > 0;
2854 for (
unsigned int kpar = 0; kpar < npar; ++kpar) {
2855 if (!MaskEmpty(positiveValues)) {
2856 where(positiveValues, pointContributionVec[kpar]) = -1. / fval * gradFunc[kpar];
2859 auto nonZeroGradientValues = !positiveValues && gradFunc[kpar] != 0;
2860 if (!MaskEmpty(nonZeroGradientValues)) {
2861 Double_v gg = kdmax1 * gradFunc[kpar];
2862 auto mask = nonZeroGradientValues && gg > 0;
2863 where(
mask, pointContributionVec[kpar]) = -min(gg, kdmax2);
2864 where(!
mask, pointContributionVec[kpar]) = -
max(gg, -kdmax2);
2869 return pointContributionVec;
2873 auto redFunction = [&](
const std::vector<std::vector<Double_v>> &pointContributions) {
2874 std::vector<Double_v>
result(npar);
2876 for (
auto const &pointContributionVec : pointContributions) {
2877 for (
unsigned int parameterIndex = 0; parameterIndex < npar; parameterIndex++)
2878 result[parameterIndex] += pointContributionVec[parameterIndex];
2884 std::vector<Double_v> gVec(npar);
2885 std::vector<double>
g(npar);
2893 Warning(
"FitUtil::EvaluateLogLGradient",
"Multithread execution policy requires IMT, which is disabled. Changing "
2894 "to ::ROOT::EExecutionPolicy::kSequential.");
2900 ROOT::TSequentialExecutor pool;
2901 gVec = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, numVectors), redFunction);
2905 ROOT::TThreadExecutor pool;
2907 gVec = pool.
MapReduce(mapFunction, ROOT::TSeq<unsigned>(0, numVectors), redFunction, chunks);
2911 Error(
"FitUtil::EvaluateLogLGradient",
"Execution policy unknown. Available choices:\n "
2912 "::ROOT::EExecutionPolicy::kSequential (default)\n "
2913 "::ROOT::EExecutionPolicy::kMultiThread (requires IMT)\n");
2917 unsigned int remainingPoints = initialNPoints % vecSize;
2918 if (remainingPoints > 0) {
2919 auto remainingPointsContribution = mapFunction(numVectors);
2921 auto remainingMask = Int2Mask(initialNPoints % vecSize);
2922 for (
unsigned int param = 0; param < npar; param++) {
2923 where(remainingMask, gVec[param]) = gVec[param] + remainingPointsContribution[param];
2927 for (
unsigned int param = 0; param < npar; param++) {
2928 grad[param] = ReduceAdd(gVec[param]);
2932 std::cout <<
"Final gradient ";
2933 for (
unsigned int param = 0; param < npar; param++) {
2934 std::cout <<
" " << grad[param];
#define MATH_ERROR_MSG(loc, str)
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
void Warning(const char *location, const char *msgfmt,...)
Use this function in warning situations.
void SetParameters(TFitEditor::FuncParams_t &pars, TF1 *func)
Restore the parameters from pars into the function.
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t mask
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t result
Option_t Option_t TPoint TPoint const char x2
Option_t Option_t TPoint TPoint const char x1
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void gc
externTVirtualMutex * gROOTMutex
#define R__LOCKGUARD(mutex)
Class describing the binned data sets : vectors of x coordinates, y values and optionally error on y ...
SimpleGradientCalculator(int gdim, const IModelFunction &func, double eps=2.E-8, int istrat=1)
const IModelFunction & fFunc
std::vector< double > fVec
double ParameterDerivative(const double *x, const double *p, int ipar) const
void Gradient(const double *x, const double *p, double f0, double *g)
unsigned int NDim() const
void ParameterGradient(const double *x, const double *p, double f0, double *g)
unsigned int NPar() const
double DoParameterDerivative(const double *x, const double *p, double f0, int k) const
Class describing the un-binned data sets (just x coordinates values) of any dimensions.
virtual unsigned int NDim() const =0
Retrieve the dimension of the function.
virtual unsigned int NPar() const =0
Return the number of Parameters.
virtual void ParameterGradient(const T *x, const double *p, T *grad) const
Evaluate the all the derivatives (gradient vector) of the function with respect to the parameters at ...
virtual bool HasParameterHessian() const
virtual bool ParameterHessian(const T *, const double *, T *) const
Evaluate the all the Hessian (second derivatives matrix) of the function with respect to the paramete...
OneDimMultiFunctionAdapter class to wrap a multidimensional function in one dimensional one.
void SetCoord(int icoord)
User class for calculating the derivatives of a function.
double Derivative1(double x)
Returns the first derivative of the function at point x, computed by Richardson's extrapolation metho...
auto MapReduce(F func, unsigned nTimes, R redfunc) -> InvokeResult_t< F >
Execute a function without arguments several times (Map) and accumulate the results into a single val...
A pseudo container class which is a generator of indices.
This class provides a simple interface to execute the same task multiple times in parallel threads,...
auto MapReduce(F func, unsigned nTimes, R redfunc) -> InvokeResult_t< F >
Execute a function nTimes in parallel (Map) and accumulate the results into a single value (Reduce).
Type
enumeration specifying the integration types.
@ kGAUSS
simple Gauss integration method with fixed rule
@ kDEFAULT
default type specified in the static options
namespace defining utility free functions using in Fit for evaluating the various fit method function...
ROOT::Math::IParamMultiGradFunction IGradModelFunction
ROOT::Math::IParamMultiFunction IModelFunction
void CalculateGradientIntegral(const GFunc &gfunc, const double *x1, const double *x2, const double *p, double *g)
double EvaluatePoissonBinPdf(const IModelFunction &func, const BinData &data, const double *x, unsigned int ipoint, double *g=nullptr, double *h=nullptr, bool hasGrad=false, bool fullHessian=false)
evaluate the pdf contribution to the Poisson LogL given a model function and the BinPoint data.
ROOT::Math::IParamMultiFunctionTempl< T > IModelFunctionTempl
double CorrectValue(double rval)
void EvaluatePoissonLogLGradient(const IModelFunction &func, const BinData &data, const double *p, double *grad, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
evaluate the Poisson LogL given a model function and the data at the point p.
double EvaluateChi2Residual(const IModelFunction &func, const BinData &data, const double *p, unsigned int ipoint, double *g=nullptr, double *h=nullptr, bool hasGrad=false, bool fullHessian=false)
evaluate the residual contribution to the Chi2 given a model function and the BinPoint data and if th...
double EvaluatePoissonLogL(const IModelFunction &func, const BinData &data, const double *p, int iWeight, bool extended, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
evaluate the Poisson LogL given a model function and the data at the point p.
double EvaluateChi2Effective(const IModelFunction &func, const BinData &data, const double *x, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
evaluate the effective Chi2 given a model function and the data at the point x.
void EvaluateLogLGradient(const IModelFunction &func, const UnBinData &data, const double *p, double *grad, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
evaluate the LogL gradient given a model function and the data at the point p.
double EvaluatePdf(const IModelFunction &func, const UnBinData &data, const double *p, unsigned int ipoint, double *g=nullptr, double *h=nullptr, bool hasGrad=false, bool fullHessian=false)
evaluate the pdf contribution to the LogL given a model function and the BinPoint data.
ROOT::Math::IParamMultiGradFunctionTempl< T > IGradModelFunctionTempl
bool CheckInfNaNValue(double &rval)
unsigned setAutomaticChunking(unsigned nEvents)
double EvaluateLogL(const IModelFunction &func, const UnBinData &data, const double *p, int iWeight, bool extended, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
evaluate the LogL given a model function and the data at the point x.
double EvaluateChi2(const IModelFunction &func, const BinData &data, const double *p, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy, unsigned nChunks=0)
Chi2 Functions.
void EvaluateChi2Gradient(const IModelFunction &func, const BinData &data, const double *p, double *grad, unsigned int &nPoints, ::ROOT::EExecutionPolicy executionPolicy=::ROOT::EExecutionPolicy::kSequential, unsigned nChunks=0)
evaluate the Chi2 gradient given a model function and the data at the point p.
Namespace for the fitting classes.
void(off) SmallVectorTemplateBase< T
T EvalLog(T x)
safe evaluation of log(x) with a protections against negative or zero argument to the log smooth line...
VecExpr< UnaryOp< Sqrt< T >, VecExpr< A, T, D >, T >, T, D > sqrt(const VecExpr< A, T, D > &rhs)
UInt_t GetThreadPoolSize()
Returns the size of ROOT's thread pool.
__device__ AFloat max(AFloat x, AFloat y)
DataOptions : simple structure holding the options on how the data are filled.
bool fErrors1
use all errors equal to 1, i.e. fit without errors (default is false)
bool fNormBinVolume
normalize data by a normalized the bin volume (bin volume divided by a reference value)
bool fUseEmpty
use empty bins (default is false) with a fixed error of 1
bool fIntegral
use integral of bin content instead of bin center (default is false)
bool fExpErrors
use expected errors from the function and not from the data
bool fBinVolume
normalize data by the bin volume (it is used in the Poisson likelihood fits)
double operator()(const double *x, const double *p) const
void SetDerivComponent(unsigned int ipar)
unsigned int NDim() const
ParamDerivFunc(const GradFunc &f)