diff --git a/roofit/CMakeLists.txt b/roofit/CMakeLists.txt index 791a77b842206..76acf8f1c4684 100644 --- a/roofit/CMakeLists.txt +++ b/roofit/CMakeLists.txt @@ -7,6 +7,7 @@ set(roofit_legacy_eval_backend ON CACHE BOOL "" FORCE) add_subdirectory(batchcompute) +add_subdirectory(codegen) if (roofit_multiprocess) add_subdirectory(roofitZMQ) add_subdirectory(multiprocess) diff --git a/roofit/codegen/CMakeLists.txt b/roofit/codegen/CMakeLists.txt new file mode 100644 index 0000000000000..e1e5164c9e25d --- /dev/null +++ b/roofit/codegen/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 1995-2019, Rene Brun and Fons Rademakers. +# All rights reserved. +# +# For the licensing terms see $ROOTSYS/LICENSE. +# For the list of contributors see $ROOTSYS/README/CREDITS. + +############################################################################ +# CMakeLists.txt file for building ROOT rootfit/histfactory package +# @author Pere Mato, CERN +############################################################################ + +ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCodegen + HEADERS + RooFit/CodegenImpl.h + SOURCES + src/CodegenImpl.cxx + DICTIONARY_OPTIONS + "-writeEmptyRootPCM" + DEPENDENCIES + RooFit + RooFitCore + HistFactory +) diff --git a/roofit/codegen/LinkDef.h b/roofit/codegen/LinkDef.h new file mode 100644 index 0000000000000..a18c9b6715f9a --- /dev/null +++ b/roofit/codegen/LinkDef.h @@ -0,0 +1,7 @@ +#ifdef __CLING__ + +#pragma link off all globals; +#pragma link off all classes; +#pragma link off all functions; + +#endif diff --git a/roofit/codegen/inc/RooFit/CodegenImpl.h b/roofit/codegen/inc/RooFit/CodegenImpl.h new file mode 100644 index 0000000000000..48a3a6f9906d5 --- /dev/null +++ b/roofit/codegen/inc/RooFit/CodegenImpl.h @@ -0,0 +1,155 @@ +/* + * Project: RooFit + * Authors: + * Jonas Rembser, CERN 2024 + * + * Copyright (c) 2024, CERN + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted according to the terms + * listed in LICENSE (http://roofit.sourceforge.net/license.txt) + */ + +#ifndef RooFit_Detail_CodegenImpl_h +#define RooFit_Detail_CodegenImpl_h + +#include + +#include + +class ParamHistFunc; +class PiecewiseInterpolation; +class RooAbsArg; +class RooAbsReal; +class RooAddPdf; +class RooAddition; +class RooBernstein; +class RooBifurGauss; +class RooCBShape; +class RooChebychev; +class RooConstVar; +class RooConstraintSum; +class RooEffProd; +class RooEfficiency; +class RooExponential; +class RooExtendPdf; +class RooFormulaVar; +class RooGamma; +class RooGaussian; +class RooGenericPdf; +class RooHistFunc; +class RooHistPdf; +class RooLandau; +class RooLognormal; +class RooMultiVarGaussian; +class RooParamHistFunc; +class RooPoisson; +class RooPolyVar; +class RooPolynomial; +class RooProduct; +class RooRatio; +class RooRealIntegral; +class RooRealSumFunc; +class RooRealSumPdf; +class RooRealVar; +class RooRecursiveFraction; +class RooUniform; + +namespace RooStats { +namespace HistFactory { +class FlexibleInterpVar; +} +} // namespace RooStats + +namespace RooFit { + +namespace Detail { +class RooFixedProdPdf; +class RooNLLVarNew; +class RooNormalizedPdf; +} // namespace Detail + +class CodegenContext; + +void codegenImpl(Detail::RooFixedProdPdf &arg, CodegenContext &ctx); +void codegenImpl(Detail::RooNLLVarNew &arg, CodegenContext &ctx); +void codegenImpl(Detail::RooNormalizedPdf &arg, CodegenContext &ctx); +void codegenImpl(ParamHistFunc &arg, CodegenContext &ctx); +void codegenImpl(PiecewiseInterpolation &arg, CodegenContext &ctx); +void codegenImpl(RooAbsArg &arg, RooFit::CodegenContext &ctx); +void codegenImpl(RooAddPdf &arg, CodegenContext &ctx); +void codegenImpl(RooAddition &arg, CodegenContext &ctx); +void codegenImpl(RooBernstein &arg, CodegenContext &ctx); +void codegenImpl(RooBifurGauss &arg, CodegenContext &ctx); +void codegenImpl(RooCBShape &arg, CodegenContext &ctx); +void codegenImpl(RooChebychev &arg, CodegenContext &ctx); +void codegenImpl(RooConstVar &arg, CodegenContext &ctx); +void codegenImpl(RooConstraintSum &arg, CodegenContext &ctx); +void codegenImpl(RooEffProd &arg, CodegenContext &ctx); +void codegenImpl(RooEfficiency &arg, CodegenContext &ctx); +void codegenImpl(RooExponential &arg, CodegenContext &ctx); +void codegenImpl(RooExtendPdf &arg, CodegenContext &ctx); +void codegenImpl(RooFormulaVar &arg, CodegenContext &ctx); +void codegenImpl(RooGamma &arg, CodegenContext &ctx); +void codegenImpl(RooGaussian &arg, CodegenContext &ctx); +void codegenImpl(RooGenericPdf &arg, CodegenContext &ctx); +void codegenImpl(RooHistFunc &arg, CodegenContext &ctx); +void codegenImpl(RooHistPdf &arg, CodegenContext &ctx); +void codegenImpl(RooLandau &arg, CodegenContext &ctx); +void codegenImpl(RooLognormal &arg, CodegenContext &ctx); +void codegenImpl(RooMultiVarGaussian &arg, CodegenContext &ctx); +void codegenImpl(RooParamHistFunc &arg, CodegenContext &ctx); +void codegenImpl(RooPoisson &arg, CodegenContext &ctx); +void codegenImpl(RooPolyVar &arg, CodegenContext &ctx); +void codegenImpl(RooPolynomial &arg, CodegenContext &ctx); +void codegenImpl(RooProduct &arg, CodegenContext &ctx); +void codegenImpl(RooRatio &arg, CodegenContext &ctx); +void codegenImpl(RooRealIntegral &arg, CodegenContext &ctx); +void codegenImpl(RooRealSumFunc &arg, CodegenContext &ctx); +void codegenImpl(RooRealSumPdf &arg, CodegenContext &ctx); +void codegenImpl(RooRealVar &arg, CodegenContext &ctx); +void codegenImpl(RooRecursiveFraction &arg, CodegenContext &ctx); +void codegenImpl(RooStats::HistFactory::FlexibleInterpVar &arg, CodegenContext &ctx); +void codegenImpl(RooUniform &arg, CodegenContext &ctx); + +std::string codegenIntegralImpl(RooAbsReal &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooBernstein &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooBifurGauss &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooCBShape &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooChebychev &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooEfficiency &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooExponential &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooGamma &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooGaussian &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooHistFunc &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooHistPdf &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooLandau &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooLognormal &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooMultiVarGaussian &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooPoisson &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooPolyVar &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooPolynomial &arg, int code, const char *rangeName, CodegenContext &ctx); +std::string codegenIntegralImpl(RooUniform &arg, int code, const char *rangeName, CodegenContext &ctx); + +template +std::string codegenIntegralImpl(Arg_t &arg, int code, const char *rangeName, CodegenContext &ctx, Prio

p) +{ + if constexpr (std::is_same, PrioLowest>::value) { + return codegenIntegralImpl(arg, code, rangeName, ctx); + } else { + return codegenIntegralImpl(arg, code, rangeName, ctx, p.next()); + } +} + +template +struct CodegenIntegralImplCaller { + + static auto call(RooAbsReal &arg, int code, const char *rangeName, RooFit::CodegenContext &ctx) + { + return codegenIntegralImpl(static_cast(arg), code, rangeName, ctx, PrioHighest{}); + } +}; + +} // namespace RooFit + +#endif diff --git a/roofit/codegen/src/CodegenImpl.cxx b/roofit/codegen/src/CodegenImpl.cxx new file mode 100644 index 0000000000000..eec3f065c49d8 --- /dev/null +++ b/roofit/codegen/src/CodegenImpl.cxx @@ -0,0 +1,847 @@ +/* + * Project: RooFit + * Authors: + * Garima Singh, CERN 2023 + * Jonas Rembser, CERN 2024 + * + * Copyright (c) 2024, CERN + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted according to the terms + * listed in LICENSE (http://roofit.sourceforge.net/license.txt) + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RooFitImplHelpers.h" + +#include + +namespace RooFit { + +namespace { + +std::string mathFunc(std::string const &name) +{ + return "RooFit::Detail::MathFuncs::" + name; +} + +void rooHistTranslateImpl(RooAbsArg const &arg, CodegenContext &ctx, int intOrder, RooDataHist const &dataHist, + const RooArgSet &obs, bool correctForBinSize, bool cdfBoundaries) +{ + if (intOrder != 0 && !(!cdfBoundaries && !correctForBinSize && intOrder == 1 && obs.size() == 1)) { + ooccoutE(&arg, InputArguments) << "RooHistPdf::weight(" << arg.GetName() + << ") ERROR: codegen currently only supports non-interpolation cases." + << std::endl; + return; + } + + if (intOrder == 1) { + RooAbsBinning const &binning = *dataHist.getBinnings()[0]; + std::string weightArr = dataHist.declWeightArrayForCodeSquash(ctx, correctForBinSize); + ctx.addResult(&arg, ctx.buildCall(mathFunc("interpolate1d"), binning.lowBound(), binning.highBound(), *obs[0], + binning.numBins(), weightArr)); + return; + } + std::string const &offset = dataHist.calculateTreeIndexForCodeSquash(&arg, ctx, obs); + std::string weightArr = dataHist.declWeightArrayForCodeSquash(ctx, correctForBinSize); + ctx.addResult(&arg, "*(" + weightArr + " + " + offset + ")"); +} + +std::string realSumPdfTranslateImpl(CodegenContext &ctx, RooAbsArg const &arg, RooArgList const &funcList, + RooArgList const &coefList, bool normalize) +{ + bool noLastCoeff = funcList.size() != coefList.size(); + + std::string const &funcName = ctx.buildArg(funcList); + std::string const &coeffName = ctx.buildArg(coefList); + std::string const &coeffSize = std::to_string(coefList.size()); + + std::string sum = ctx.getTmpVarName(); + std::string coeffSum = ctx.getTmpVarName(); + ctx.addToCodeBody(&arg, "double " + sum + " = 0;\ndouble " + coeffSum + "= 0;\n"); + + std::string iterator = "i_" + ctx.getTmpVarName(); + std::string subscriptExpr = "[" + iterator + "]"; + + std::string code = "for(int " + iterator + " = 0; " + iterator + " < " + coeffSize + "; " + iterator + "++) {\n" + + sum + " += " + funcName + subscriptExpr + " * " + coeffName + subscriptExpr + ";\n"; + code += coeffSum + " += " + coeffName + subscriptExpr + ";\n"; + code += "}\n"; + + if (noLastCoeff) { + code += sum + " += " + funcName + "[" + coeffSize + "]" + " * (1 - " + coeffSum + ");\n"; + } else if (normalize) { + code += sum + " /= " + coeffSum + ";\n"; + } + ctx.addToCodeBody(&arg, code); + + return sum; +} + +} // namespace + +void codegenImpl(Detail::RooFixedProdPdf &arg, CodegenContext &ctx) +{ + if (arg.cache()._isRearranged) { + ctx.addResult(&arg, ctx.buildCall(mathFunc("ratio"), *arg.cache()._rearrangedNum, *arg.cache()._rearrangedDen)); + } else { + ctx.addResult(&arg, ctx.buildCall(mathFunc("product"), arg.cache()._partList, arg.cache()._partList.size())); + } +} + +void codegenImpl(ParamHistFunc &arg, CodegenContext &ctx) +{ + std::string const &idx = arg.dataHist().calculateTreeIndexForCodeSquash(&arg, ctx, arg.dataVars(), true); + std::string const ¶mNames = ctx.buildArg(arg.paramList()); + + ctx.addResult(&arg, paramNames + "[" + idx + "]"); +} + +void codegenImpl(PiecewiseInterpolation &arg, CodegenContext &ctx) +{ + auto const &interpCodes = arg.interpolationCodes(); + + std::size_t n = interpCodes.size(); + + std::string resName = "total_" + ctx.getTmpVarName(); + for (std::size_t i = 0; i < n; ++i) { + if (interpCodes[i] != interpCodes[0]) { + oocoutE(&arg, InputArguments) + << "FlexibleInterpVar::evaluate ERROR: Code Squashing AD does not yet support having " + "different interpolation codes for the same class object " + << std::endl; + } + } + + // The PiecewiseInterpolation class is used in the context of HistFactory + // models, where is is always used the same way: all RooAbsReals in _lowSet, + // _histSet, and also nominal are 1D RooHistFuncs with with same structure. + // + // Therefore, we can make a big optimization: we get the bin index only once + // here in the generated code for PiecewiseInterpolation. Then, we also + // rearrange the histogram data in such a way that we can always pass the + // same arrays to the free function that implements the interpolation, just + // with a dynamic offset calculated from the bin index. + RooDataHist const &nomHist = dynamic_cast(*arg.nominalHist()).dataHist(); + int nBins = nomHist.numEntries(); + std::vector valsNominal; + std::vector valsLow; + std::vector valsHigh; + for (int i = 0; i < nBins; ++i) { + valsNominal.push_back(nomHist.weight(i)); + } + for (int i = 0; i < nBins; ++i) { + for (std::size_t iParam = 0; iParam < n; ++iParam) { + valsLow.push_back(dynamic_cast(arg.lowList()[iParam]).dataHist().weight(i)); + valsHigh.push_back(dynamic_cast(arg.highList()[iParam]).dataHist().weight(i)); + } + } + std::string idxName = ctx.getTmpVarName(); + std::string valsNominalStr = ctx.buildArg(valsNominal); + std::string valsLowStr = ctx.buildArg(valsLow); + std::string valsHighStr = ctx.buildArg(valsHigh); + std::string nStr = std::to_string(n); + std::string code; + + std::string lowName = ctx.getTmpVarName(); + std::string highName = ctx.getTmpVarName(); + std::string nominalName = ctx.getTmpVarName(); + code += "unsigned int " + idxName + " = " + + nomHist.calculateTreeIndexForCodeSquash(&arg, ctx, + dynamic_cast(*arg.nominalHist()).variables()) + + ";\n"; + code += "double const* " + lowName + " = " + valsLowStr + " + " + nStr + " * " + idxName + ";\n"; + code += "double const* " + highName + " = " + valsHighStr + " + " + nStr + " * " + idxName + ";\n"; + code += "double " + nominalName + " = *(" + valsNominalStr + " + " + idxName + ");\n"; + + std::string funcCall = ctx.buildCall(mathFunc("flexibleInterp"), interpCodes[0], arg.paramList(), n, lowName, + highName, 1.0, nominalName, 0.0); + code += "double " + resName + " = " + funcCall + ";\n"; + + if (arg.positiveDefinite()) { + code += resName + " = " + resName + " < 0 ? 0 : " + resName + ";\n"; + } + + ctx.addToCodeBody(&arg, code); + ctx.addResult(&arg, resName); +} + +//////////////////////////////////////////////////////////////////////////////// +/// This function defines a translation for each RooAbsReal based object that can be used +/// to express the class as simple C++ code. The function adds the code represented by +/// each class as an std::string (that is later concatenated with code strings from translate calls) +/// to form the C++ code that AD tools can understand. Any class that wants to support AD, has to +/// implement this function. +/// +/// \param[in] ctx An object to manage auxiliary information for code-squashing. Also takes the +/// code string that this class outputs into the squashed code through the 'addToCodeBody' function. +void codegenImpl(RooAbsArg &arg, RooFit::CodegenContext &ctx) +{ + std::stringstream errorMsg; + errorMsg << "Translate function for class \"" << arg.ClassName() << "\" has not yet been implemented."; + oocoutE(&arg, Minimization) << errorMsg.str() << std::endl; + return ctx.addResult(&arg, "1.0"); +} + +void codegenImpl(RooAddPdf &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, realSumPdfTranslateImpl(ctx, arg, arg.pdfList(), arg.coefList(), true)); +} + +void codegenImpl(RooMultiVarGaussian &arg, CodegenContext &ctx) +{ + auto const &covI = arg.covarianceMatrixInverse(); + std::span covISpan{covI.GetMatrixArray(), static_cast(covI.GetNoElements())}; + ctx.addResult(&arg, + ctx.buildCall(mathFunc("multiVarGaussian"), arg.xVec().size(), arg.xVec(), arg.muVec(), covISpan)); +} + +void codegenImpl(RooAddition &arg, CodegenContext &ctx) +{ + if (arg.list().empty()) { + ctx.addResult(&arg, "0.0"); + } + std::string result; + if (arg.list().size() > 1) + result += "("; + + std::size_t i = 0; + for (auto *component : static_range_cast(arg.list())) { + + if (!dynamic_cast(component) || arg.list().size() == 1) { + result += ctx.getResult(*component); + ++i; + if (i < arg.list().size()) + result += '+'; + continue; + } + result += ctx.buildFunction(*component, ctx.outputSizes()) + "(params, obs, xlArr)"; + ++i; + if (i < arg.list().size()) + result += '+'; + } + if (arg.list().size() > 1) + result += ')'; + ctx.addResult(&arg, result); +} + +void codegenImpl(RooBernstein &arg, CodegenContext &ctx) +{ + arg.fillBuffer(); + ctx.addResult(&arg, ctx.buildCall(mathFunc("bernstein"), arg.x(), arg.xmin(), arg.xmax(), arg.coefList(), + arg.coefList().size())); +} + +void codegenImpl(RooBifurGauss &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, + ctx.buildCall(mathFunc("bifurGauss"), arg.getX(), arg.getMean(), arg.getSigmaL(), arg.getSigmaR())); +} + +void codegenImpl(RooCBShape &arg, CodegenContext &ctx) +{ + ctx.addResult( + &arg, ctx.buildCall(mathFunc("cbShape"), arg.getM(), arg.getM0(), arg.getSigma(), arg.getAlpha(), arg.getN())); +} + +void codegenImpl(RooChebychev &arg, CodegenContext &ctx) +{ + // first bring the range of the variable _x to the normalised range [-1, 1] + // calculate sum_k c_k T_k(x) where x is given in the normalised range, + // c_0 = 1, and the higher coefficients are given in _coefList + double xmax = static_cast(arg.x()).getMax(arg.refRangeName()); + double xmin = static_cast(arg.x()).getMin(arg.refRangeName()); + + ctx.addResult(&arg, + ctx.buildCall(mathFunc("chebychev"), arg.coefList(), arg.coefList().size(), arg.x(), xmin, xmax)); +} + +void codegenImpl(RooConstVar &arg, CodegenContext &ctx) +{ + // Just return a stringy-field version of the const value. + // Formats to the maximum precision. + constexpr auto max_precision{std::numeric_limits::digits10 + 1}; + std::stringstream ss; + ss.precision(max_precision); + // Just use toString to make sure we do not output 'inf'. + // This is really ugly for large numbers... + ss << std::fixed << RooNumber::toString(arg.getVal()); + ctx.addResult(&arg, ss.str()); +} + +void codegenImpl(RooConstraintSum &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, ctx.buildCall(mathFunc("constraintSum"), arg.list(), arg.list().size())); +} + +void codegenImpl(RooGamma &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, ctx.buildCall("TMath::GammaDist", arg.getX(), arg.getGamma(), arg.getMu(), arg.getBeta())); +} + +void codegenImpl(RooFormulaVar &arg, CodegenContext &ctx) +{ + arg.getVal(); // to trigger the creation of the TFormula + std::string funcName = arg.getUniqueFuncName(); + ctx.collectFunction(funcName); + ctx.addResult(&arg, ctx.buildCall(funcName, arg.dependents())); +} + +void codegenImpl(RooEffProd &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, ctx.buildCall(mathFunc("effProd"), arg.eff(), arg.pdf())); +} + +void codegenImpl(RooEfficiency &arg, CodegenContext &ctx) +{ + RooAbsCategory const &cat = arg.cat(); + int sigCatIndex = cat.lookupIndex(arg.sigCatName()); + ctx.addResult(&arg, ctx.buildCall(mathFunc("efficiency"), arg.effFunc(), cat, sigCatIndex)); +} + +void codegenImpl(RooExponential &arg, CodegenContext &ctx) +{ + // Build a call to the stateless exponential defined later. + std::string coef; + if (arg.negateCoefficient()) { + coef += "-"; + } + coef += ctx.getResult(arg.coefficient()); + ctx.addResult(&arg, "std::exp(" + coef + " * " + ctx.getResult(arg.variable()) + ")"); +} + +void codegenImpl(RooExtendPdf &arg, CodegenContext &ctx) +{ + // Use the result of the underlying pdf. + ctx.addResult(&arg, ctx.getResult(arg.pdf())); +} + +void codegenImpl(RooGaussian &arg, CodegenContext &ctx) +{ + // Build a call to the stateless gaussian defined later. + ctx.addResult(&arg, ctx.buildCall(mathFunc("gaussian"), arg.getX(), arg.getMean(), arg.getSigma())); +} + +void codegenImpl(RooGenericPdf &arg, CodegenContext &ctx) +{ + arg.getVal(); // to trigger the creation of the TFormula + std::string funcName = arg.getUniqueFuncName(); + ctx.collectFunction(funcName); + ctx.addResult(&arg, ctx.buildCall(funcName, arg.dependents())); +} + +void codegenImpl(RooHistFunc &arg, CodegenContext &ctx) +{ + rooHistTranslateImpl(arg, ctx, arg.getInterpolationOrder(), arg.dataHist(), arg.variables(), false, + arg.getCdfBoundaries()); +} + +void codegenImpl(RooHistPdf &arg, CodegenContext &ctx) +{ + rooHistTranslateImpl(arg, ctx, arg.getInterpolationOrder(), arg.dataHist(), arg.variables(), !arg.haveUnitNorm(), + arg.getCdfBoundaries()); +} + +void codegenImpl(RooLandau &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, ctx.buildCall(mathFunc("landau"), arg.getX(), arg.getMean(), arg.getSigma())); +} + +void codegenImpl(RooLognormal &arg, CodegenContext &ctx) +{ + std::string funcName = arg.useStandardParametrization() ? "logNormalEvaluateStandard" : "logNormal"; + ctx.addResult(&arg, ctx.buildCall(mathFunc(funcName), arg.getX(), arg.getShapeK(), arg.getMedian())); +} + +void codegenImpl(Detail::RooNLLVarNew &arg, CodegenContext &ctx) +{ + if (arg.binnedL() && !arg.pdf().getAttribute("BinnedLikelihoodActiveYields")) { + std::stringstream errorMsg; + errorMsg << "codegen: binned likelihood optimization is only supported when raw pdf " + "values can be interpreted as yields." + << " This is not the case for HistFactory models written with ROOT versions before 6.26.00"; + oocoutE(&arg, InputArguments) << errorMsg.str() << std::endl; + throw std::runtime_error(errorMsg.str()); + } + + std::string weightSumName = RooFit::Detail::makeValidVarName(arg.GetName()) + "WeightSum"; + std::string resName = RooFit::Detail::makeValidVarName(arg.GetName()) + "Result"; + ctx.addResult(&arg, resName); + ctx.addToGlobalScope("double " + weightSumName + " = 0.0;\n"); + ctx.addToGlobalScope("double " + resName + " = 0.0;\n"); + + const bool needWeightSum = arg.expectedEvents() || arg.simCount() > 1; + + if (needWeightSum) { + auto scope = ctx.beginLoop(&arg); + ctx.addToCodeBody(weightSumName + " += " + ctx.getResult(arg.weightVar()) + ";\n"); + } + if (arg.simCount() > 1) { + std::string simCountStr = std::to_string(static_cast(arg.simCount())); + ctx.addToCodeBody(resName + " += " + weightSumName + " * std::log(" + simCountStr + ");\n"); + } + + // Begin loop scope for the observables and weight variable. If the weight + // is a scalar, the context will ignore it for the loop scope. The closing + // brackets of the loop is written at the end of the scopes lifetime. + { + auto scope = ctx.beginLoop(&arg); + std::string term = ctx.buildCall(mathFunc("nll"), arg.pdf(), arg.weightVar(), arg.binnedL(), 0); + ctx.addToCodeBody(&arg, resName + " += " + term + ";"); + } + if (arg.expectedEvents()) { + std::string expected = ctx.getResult(*arg.expectedEvents()); + ctx.addToCodeBody(resName + " += " + expected + " - " + weightSumName + " * std::log(" + expected + ");\n"); + } +} + +void codegenImpl(Detail::RooNormalizedPdf &arg, CodegenContext &ctx) +{ + // For now just return function/normalization integral. + ctx.addResult(&arg, ctx.getResult(arg.pdf()) + "/" + ctx.getResult(arg.normIntegral())); +} + +void codegenImpl(RooParamHistFunc &arg, CodegenContext &ctx) +{ + std::string const &idx = arg.dataHist().calculateTreeIndexForCodeSquash(&arg, ctx, arg.xList()); + std::string arrName = ctx.buildArg(arg.paramList()); + std::string result = arrName + "[" + idx + "]"; + if (arg.relParam()) { + // get weight[idx] * binv[idx]. Here we get the bin volume for the first element as we assume the distribution to + // be binned uniformly. + double binV = arg.dataHist().binVolume(0); + std::string weightArr = arg.dataHist().declWeightArrayForCodeSquash(ctx, false); + result += " * *(" + weightArr + " + " + idx + ") * " + std::to_string(binV); + } + ctx.addResult(&arg, result); +} + +void codegenImpl(RooPoisson &arg, CodegenContext &ctx) +{ + std::string xName = ctx.getResult(arg.getX()); + if (!arg.getNoRounding()) + xName = "std::floor(" + xName + ")"; + + ctx.addResult(&arg, ctx.buildCall(mathFunc("poisson"), xName, arg.getMean())); +} + +void codegenImpl(RooPolyVar &arg, CodegenContext &ctx) +{ + const unsigned sz = arg.coefList().size(); + if (!sz) { + ctx.addResult(&arg, std::to_string(arg.lowestOrder() ? 1. : 0.)); + return; + } + + ctx.addResult(&arg, ctx.buildCall(mathFunc("polynomial"), arg.coefList(), sz, arg.lowestOrder(), arg.x())); +} + +void codegenImpl(RooPolynomial &arg, CodegenContext &ctx) +{ + const unsigned sz = arg.coefList().size(); + if (!sz) { + ctx.addResult(&arg, std::to_string(arg.lowestOrder() ? 1. : 0.)); + return; + } + + ctx.addResult(&arg, ctx.buildCall(mathFunc("polynomial"), arg.coefList(), sz, arg.lowestOrder(), arg.x())); +} + +void codegenImpl(RooProduct &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, ctx.buildCall(mathFunc("product"), arg.realComponents(), arg.realComponents().size())); +} + +void codegenImpl(RooRatio &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, ctx.buildCall(mathFunc("ratio"), arg.numerator(), arg.denominator())); +} + +namespace { + +std::string codegenIntegral(RooAbsReal &arg, int code, const char *rangeName, CodegenContext &ctx) +{ + using Func = std::string (*)(RooAbsReal &, int, const char *, CodegenContext &); + + Func func; + + TClass *tclass = arg.IsA(); + + // Cache the overload resolutions + static std::unordered_map dispatchMap; + + auto found = dispatchMap.find(tclass); + + if (found != dispatchMap.end()) { + func = found->second; + } else { + // Can probably done with CppInterop in the future to avoid string manipulation. + std::stringstream cmd; + cmd << "&RooFit::CodegenIntegralImplCaller<" << tclass->GetName() << ">::call;"; + func = reinterpret_cast(gInterpreter->ProcessLine(cmd.str().c_str())); + dispatchMap[tclass] = func; + } + + return func(arg, code, rangeName, ctx); +} + +} // namespace + +void codegenImpl(RooRealIntegral &arg, CodegenContext &ctx) +{ + if (arg.numIntCatVars().empty() && arg.numIntRealVars().empty()) { + ctx.addResult(&arg, codegenIntegral(const_cast(arg.integrand()), arg.mode(), arg.intRange(), ctx)); + return; + } + + if (arg.intVars().size() != 1 || arg.numIntRealVars().size() != 1) { + std::stringstream errorMsg; + errorMsg << "Only analytical integrals and 1D numeric integrals are supported for AD for class" + << arg.integrand().GetName(); + oocoutE(&arg, Minimization) << errorMsg.str() << std::endl; + throw std::runtime_error(errorMsg.str().c_str()); + } + + auto &intVar = static_cast(*arg.numIntRealVars()[0]); + + std::string obsName = ctx.getTmpVarName(); + std::string oldIntVarResult = ctx.getResult(intVar); + ctx.addResult(&intVar, "obs[0]"); + + std::string funcName = ctx.buildFunction(arg.integrand(), {}); + + std::stringstream ss; + + ss << "double " << obsName << "[1];\n"; + + std::string resName = RooFit::Detail::makeValidVarName(arg.GetName()) + "Result"; + ctx.addResult(&arg, resName); + ctx.addToGlobalScope("double " + resName + " = 0.0;\n"); + + // TODO: once Clad has support for higher-order functions (follow also the + // Clad issue #637), we could refactor this code into an actual function + // instead of hardcoding it here as a string. + ss << "{\n" + << " const int n = 1000; // number of sampling points\n" + << " double d = " << intVar.getMax(arg.intRange()) << " - " << intVar.getMin(arg.intRange()) << ";\n" + << " double eps = d / n;\n" + << " for (int i = 0; i < n; ++i) {\n" + << " " << obsName << "[0] = " << intVar.getMin(arg.intRange()) << " + eps * i;\n" + << " double tmpA = " << funcName << "(params, " << obsName << ", xlArr);\n" + << " " << obsName << "[0] = " << intVar.getMin(arg.intRange()) << " + eps * (i + 1);\n" + << " double tmpB = " << funcName << "(params, " << obsName << ", xlArr);\n" + << " " << resName << " += (tmpA + tmpB) * 0.5 * eps;\n" + << " }\n" + << "}\n"; + + ctx.addToGlobalScope(ss.str()); + + ctx.addResult(&intVar, oldIntVarResult); +} + +void codegenImpl(RooRealSumFunc &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, realSumPdfTranslateImpl(ctx, arg, arg.funcList(), arg.coefList(), false)); +} + +void codegenImpl(RooRealSumPdf &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, realSumPdfTranslateImpl(ctx, arg, arg.funcList(), arg.coefList(), false)); +} + +void codegenImpl(RooRealVar &arg, CodegenContext &ctx) +{ + if (!arg.isConstant()) { + ctx.addResult(&arg, arg.GetName()); + } + // Just return a formatted version of the const value. + // Formats to the maximum precision. + constexpr auto max_precision{std::numeric_limits::digits10 + 1}; + std::stringstream ss; + ss.precision(max_precision); + // Just use toString to make sure we do not output 'inf'. + // This is really ugly for large numbers... + ss << std::fixed << RooNumber::toString(arg.getVal()); + ctx.addResult(&arg, ss.str()); +} + +void codegenImpl(RooRecursiveFraction &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, ctx.buildCall(mathFunc("recursiveFraction"), arg.variables(), arg.variables().size())); +} + +void codegenImpl(RooStats::HistFactory::FlexibleInterpVar &arg, CodegenContext &ctx) +{ + auto const &interpCodes = arg.interpolationCodes(); + + unsigned int n = interpCodes.size(); + + int interpCode = interpCodes[0]; + // To get consistent codes with the PiecewiseInterpolation + if (interpCode == 4) { + interpCode = 5; + } + + for (unsigned int i = 1; i < n; i++) { + if (interpCodes[i] != interpCodes[0]) { + oocoutE(&arg, InputArguments) + << "FlexibleInterpVar::evaluate ERROR: Code Squashing AD does not yet support having " + "different interpolation codes for the same class object " + << std::endl; + } + } + + std::string const &resName = ctx.buildCall(mathFunc("flexibleInterp"), interpCode, arg.variables(), n, arg.low(), + arg.high(), arg.globalBoundary(), arg.nominal(), 1.0); + ctx.addResult(&arg, resName); +} + +void codegenImpl(RooUniform &arg, CodegenContext &ctx) +{ + ctx.addResult(&arg, "1.0"); +} + +//////////////////////////////////////////////////////////////////////////////// +/// This function defines the analytical integral translation for the class. +/// +/// \param[in] code The code that decides the integrands. +/// \param[in] rangeName Name of the normalization range. +/// \param[in] ctx An object to manage auxiliary information for code-squashing. +/// +/// \returns The representative code string of the integral for the given object. +std::string codegenIntegralImpl(RooAbsReal &arg, int, const char *, CodegenContext &) +{ + std::stringstream errorMsg; + errorMsg << "An analytical integral function for class \"" << arg.ClassName() << "\" has not yet been implemented."; + oocoutE(&arg, Minimization) << errorMsg.str() << std::endl; + throw std::runtime_error(errorMsg.str().c_str()); +} + +std::string codegenIntegralImpl(RooBernstein &arg, int, const char *rangeName, CodegenContext &ctx) +{ + arg.fillBuffer(); // to get the right xmin() and xmax() + auto &x = dynamic_cast(arg.x()); + return ctx.buildCall(mathFunc("bernsteinIntegral"), x.getMin(rangeName), x.getMax(rangeName), arg.xmin(), arg.xmax(), + arg.coefList(), arg.coefList().size()); +} + +std::string codegenIntegralImpl(RooBifurGauss &arg, int code, const char *rangeName, CodegenContext &ctx) +{ + auto &constant = code == 1 ? arg.getMean() : arg.getX(); + auto &integrand = dynamic_cast(code == 1 ? arg.getX() : arg.getMean()); + + return ctx.buildCall(mathFunc("bifurGaussIntegral"), integrand.getMin(rangeName), integrand.getMax(rangeName), + constant, arg.getSigmaL(), arg.getSigmaR()); +} + +std::string codegenIntegralImpl(RooCBShape &arg, int /*code*/, const char *rangeName, CodegenContext &ctx) +{ + auto &m = dynamic_cast(arg.getM()); + return ctx.buildCall(mathFunc("cbShapeIntegral"), m.getMin(rangeName), m.getMax(rangeName), arg.getM0(), + arg.getSigma(), arg.getAlpha(), arg.getN()); +} + +std::string codegenIntegralImpl(RooChebychev &arg, int, const char *rangeName, CodegenContext &ctx) +{ + auto &x = dynamic_cast(arg.x()); + double xmax = x.getMax(arg.refRangeName()); + double xmin = x.getMin(arg.refRangeName()); + unsigned int sz = arg.coefList().size(); + + return ctx.buildCall(mathFunc("chebychevIntegral"), arg.coefList(), sz, xmin, xmax, x.getMin(rangeName), + x.getMax(rangeName)); +} + +std::string codegenIntegralImpl(RooEfficiency &, int, const char *, CodegenContext &) +{ + return "1.0"; +} + +std::string codegenIntegralImpl(RooExponential &arg, int code, const char *rangeName, CodegenContext &ctx) +{ + bool isOverX = code == 1; + + std::string constant; + if (arg.negateCoefficient() && isOverX) { + constant += "-"; + } + constant += ctx.getResult(isOverX ? arg.coefficient() : arg.variable()); + + auto &integrand = dynamic_cast(isOverX ? arg.variable() : arg.coefficient()); + + double min = integrand.getMin(rangeName); + double max = integrand.getMax(rangeName); + + if (!isOverX && arg.negateCoefficient()) { + std::swap(min, max); + min = -min; + max = -max; + } + + return ctx.buildCall(mathFunc("exponentialIntegral"), min, max, constant); +} + +std::string codegenIntegralImpl(RooGamma &arg, int, const char *rangeName, CodegenContext &ctx) +{ + auto &x = dynamic_cast(arg.getX()); + const std::string a = + ctx.buildCall("ROOT::Math::gamma_cdf", x.getMax(rangeName), arg.getGamma(), arg.getBeta(), arg.getMu()); + const std::string b = + ctx.buildCall("ROOT::Math::gamma_cdf", x.getMin(rangeName), arg.getGamma(), arg.getBeta(), arg.getMu()); + return a + " - " + b; +} + +std::string codegenIntegralImpl(RooGaussian &arg, int code, const char *rangeName, CodegenContext &ctx) +{ + auto &constant = code == 1 ? arg.getMean() : arg.getX(); + auto &integrand = dynamic_cast(code == 1 ? arg.getX() : arg.getMean()); + + return ctx.buildCall(mathFunc("gaussianIntegral"), integrand.getMin(rangeName), integrand.getMax(rangeName), + constant, arg.getSigma()); +} + +namespace { + +std::string rooHistIntegralTranslateImpl(int code, RooAbsArg const &arg, RooDataHist const &dataHist, + const RooArgSet &obs, bool histFuncMode) +{ + if (((2 << obs.size()) - 1) != code) { + oocoutE(&arg, InputArguments) << "RooHistPdf::integral(" << arg.GetName() + << ") ERROR: AD currently only supports integrating over all histogram observables." + << std::endl; + return ""; + } + return std::to_string(dataHist.sum(histFuncMode)); +} + +} // namespace + +std::string codegenIntegralImpl(RooHistFunc &arg, int code, const char *, CodegenContext &) +{ + return rooHistIntegralTranslateImpl(code, arg, arg.dataHist(), arg.variables(), true); +} + +std::string codegenIntegralImpl(RooHistPdf &arg, int code, const char *, CodegenContext &) +{ + return rooHistIntegralTranslateImpl(code, arg, arg.dataHist(), arg.variables(), false); +} + +std::string codegenIntegralImpl(RooLandau &arg, int, const char *rangeName, CodegenContext &ctx) +{ + // Don't do anything with "code". It can only be "1" anyway (see + // implementation of getAnalyticalIntegral). + auto &x = dynamic_cast(arg.getX()); + const std::string a = ctx.buildCall("ROOT::Math::landau_cdf", x.getMax(rangeName), arg.getSigma(), arg.getMean()); + const std::string b = ctx.buildCall("ROOT::Math::landau_cdf", x.getMin(rangeName), arg.getSigma(), arg.getMean()); + return ctx.getResult(arg.getSigma()) + " * " + "(" + a + " - " + b + ")"; +} + +std::string codegenIntegralImpl(RooLognormal &arg, int, const char *rangeName, CodegenContext &ctx) +{ + std::string funcName = arg.useStandardParametrization() ? "logNormalIntegralStandard" : "logNormalIntegral"; + auto &x = dynamic_cast(arg.getX()); + return ctx.buildCall(mathFunc(funcName), x.getMin(rangeName), x.getMax(rangeName), arg.getMedian(), arg.getShapeK()); +} + +std::string codegenIntegralImpl(RooMultiVarGaussian &arg, int code, const char *rangeName, CodegenContext &) +{ + if (code != -1) { + std::stringstream errorMsg; + errorMsg << "Partial integrals over RooMultiVarGaussian are not supported."; + oocoutE(&arg, Minimization) << errorMsg.str() << std::endl; + throw std::runtime_error(errorMsg.str().c_str()); + } + + return std::to_string(arg.analyticalIntegral(code, rangeName)); +} + +std::string codegenIntegralImpl(RooPoisson &arg, int code, const char *rangeName, CodegenContext &ctx) +{ + assert(code == 1 || code == 2); + std::string xName = ctx.getResult(arg.getX()); + if (!arg.getNoRounding()) + xName = "std::floor(" + xName + ")"; + + auto &integrand = dynamic_cast(code == 1 ? arg.getX() : arg.getMean()); + // Since the integral function is the same for both codes, we need to make sure the indexed observables do not appear + // in the function if they are not required. + xName = code == 1 ? "0" : xName; + return ctx.buildCall(mathFunc("poissonIntegral"), code, arg.getMean(), xName, integrand.getMin(rangeName), + integrand.getMax(rangeName), arg.getProtectNegativeMean()); +} + +std::string codegenIntegralImpl(RooPolyVar &arg, int, const char *rangeName, CodegenContext &ctx) +{ + auto &x = dynamic_cast(arg.x()); + const double xmin = x.getMin(rangeName); + const double xmax = x.getMax(rangeName); + const unsigned sz = arg.coefList().size(); + if (!sz) + return std::to_string(arg.lowestOrder() ? xmax - xmin : 0.0); + + return ctx.buildCall(mathFunc("polynomialIntegral"), arg.coefList(), sz, arg.lowestOrder(), xmin, xmax); +} + +std::string codegenIntegralImpl(RooPolynomial &arg, int, const char *rangeName, CodegenContext &ctx) +{ + auto &x = dynamic_cast(arg.x()); + const double xmin = x.getMin(rangeName); + const double xmax = x.getMax(rangeName); + const unsigned sz = arg.coefList().size(); + if (!sz) + return std::to_string(arg.lowestOrder() ? xmax - xmin : 0.0); + + return ctx.buildCall(mathFunc("polynomialIntegral"), arg.coefList(), sz, arg.lowestOrder(), xmin, xmax); +} + +std::string codegenIntegralImpl(RooUniform &arg, int code, const char *rangeName, CodegenContext &) +{ + // The integral of a uniform distribution is static, so we can just hardcode + // the result in a string. + return std::to_string(arg.analyticalIntegral(code, rangeName)); +} + +} // namespace RooFit diff --git a/roofit/doc/developers/roofit_ad.md b/roofit/doc/developers/roofit_ad.md index 5f8e09ca1c699..7b7c6ae957fb5 100644 --- a/roofit/doc/developers/roofit_ad.md +++ b/roofit/doc/developers/roofit_ad.md @@ -94,8 +94,8 @@ computation, but without any overhead that is hard to digest by the AD tool. On a high level, this *code generation* is implemented as follows: 1. The computation graph is visited recursively by a - RooFit::CodegenContext object, via the virtual - RooAbsArg::translate() function that implements the translation of a + RooFit::CodegenContext object, via the + RooFit::codegenImpl(RooAbsArg &, RooFit::CodegenContext &) function that implements the translation of a given RooFit class to minimal C++ code. This is an example of the visitor pattern. @@ -124,10 +124,10 @@ separate header file. Since Clad prefers the code for models to be within a single translation unit, in many classes, this has been implemented by moving the computational aspects of the RooFit class -to free functions in a single header file named [MathFuncs] (and/or -[MathFuncs], where relevant). This approach enables easier debugging - (e.g., you can standalone-compile the generated code with just a few header -files copied outside ROOT) +to free functions in a single header file named [MathFuncs]. +This approach enables easier debugging +(e.g., you can standalone-compile the generated code with just a few header +files copied outside ROOT). *Refactoring* It is important to refactor the code such that: @@ -153,14 +153,14 @@ installation. Please note the following recommendations: header file (e.g., as part of the class definition), and - if/when your class is upstreamed to RooFit, expect to move into the -`RooFit::detail` namespace and their implementations into `MathFuncs.h`. +`RooFit::Detail` namespace and their implementations into `MathFuncs.h`. \htmlonly \endhtmlonly -*Overriding the Translate Function*: The `RooAbsArg::translate()` function -needs to be overridden to specify how the class is translating to C++ code +*Overloading the code generation function*: The `RooFit::codegenImpl()` function +needs to be overloaded to specify how the class is translating to C++ code that is using the aforementioned free function. **Sample Steps**: To add Code Generation support to an existing RooFit class, @@ -176,25 +176,27 @@ This implementation must be compatible with the syntax supported by Clad. can reduce code duplication and potential for bugs. This may require some effort if an extensive caching infrastructure is used in your model. -**3. Add translate():** RooFit classes are extended using a (typically) simple - `translate()` function that extracts the mathematically differentiable +**3. Add RooFit::codegenImpl():** Define a (typically) simple + `RooFit::codegenImpl()` function that extracts the mathematically differentiable properties out of the RooFit classes that make up the statistical model. +This function needs to be declared in a public header file, such that it is known to the interpreter. -The `translate()` function helps implement the Code Squashing logic that is +The `RooFit::codegenImpl()` function helps implement the code generation logic that is used to optimize numerical evaluations. It accomplishes this by using a small subset of helper functions that are available in the -`RooFit::CodegenContext` and `RooFuncWrapper` classes -(see Appendix B). It converts a RooFit expression into a form that can be +`RooFit::CodegenContext` class (see Appendix B). +It converts a RooFit expression into a form that can be efficiently evaluated by Clad. -The `translate()` function returns an `std::string` representing the +The `RooFit::codegenImpl()` function places a `std::string` inside the `RooFit::CodegenContext`. +This string is representing the underlying mathematical notation of the class as code, that can later be concatenated into a single string representing the entire model. This string of code is then just-in-time compiled by Cling (a C++ interpreter for Root). -**4. analyticalIntegral() Use Case:** If your class includes (or should +**4. RooFit::codegenIntegralImpl() Use Case:** If your class includes (or should include) the `analyticalIntegral()` function, then a simple -`buildCallToAnalyticIntegral()` function needs to be created to help call the +`RooFit::codegenIntegralImpl()` function needs to be defined to help call the `analyticalIntegral()` function. @@ -277,20 +279,21 @@ together. > Directory path: [roofit/roofitcore/inc/RooFit/Detail/MathFuncs.h](https://github.com/root-project/root/blob/master/roofit/roofitcore/inc/RooFit/Detail/MathFuncs.h) -### Step 2. Override RooAbsArg::translate() +### Step 2. Overload RooFit::codegenImpl() -**translate() Example 1:** Continuing our RooPoisson example: +**RooFit::codegenImpl() Example 1:** Continuing our RooPoisson example: -To translate the `RooPoisson` class, create a translate function and in it -include a call to the updated function. +To translate the `RooPoisson` class, create a code generation function and in it +include a call to the free function. ``` {.cpp} -void RooPoisson::translate(RooFit::CodegenContext &ctx) const +void RooFit::codegenImpl(RooPoisson &arg, RooFit::CodegenContext &ctx) { - std::string xName = ctx.getResult(x); - if (!_noRounding) + std::string xName = ctx.getResult(arg.getX()); + if (!arg.getNoRounding()) xName = "std::floor(" + xName + ")"; - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::poissonEvaluate", xName, mean)); + + ctx.addResult(&arg, ctx.buildCall("RooFit::Detail::MathFuncs::poisson", xName, arg.getMean())); } ``` @@ -299,58 +302,59 @@ member of RooPoisson) is retrieved and stored in the `xName` variable. Next, there's an `if` condition that does an operation on `x` (may or may not round it to the nearest integer, depending on the condition). -The important part is where the `RooPoisson::addResult()` function helps add +The important part is where the `RooFit::CodegenContext::addResult()` function adds the result of evaluating the Poisson function to the context (`ctx`). It uses -the `RooPoisson::buildCall()` method to construct a function call to the fully +the `RooFit::CodegenContext::buildCall()` method to construct a function call to the fully qualified name of `MathFuncs::poissonEvaluate` (which now resides in the -`MathFuncs` file), with arguments `xName` and `mean`. +`MathFuncs` file), with arguments `xName` and the mean of the Poisson. -Essentially, the `RooPoisson::translate()` function constructs a function call +Essentially, the `RooFit::codegenImpl()` function constructs a function call to evaluate the Poisson function using 'x' and 'mean' variables, and adds the result to the context. Helper Functions: -- `getResult()` helps lookup the result of a child node (the string that the -child node previously saved in a variable using the `addResult()` function). +- `RooFit::CodegenContext::getResult()` helps lookup the result of a child node (the string that the +child node previously saved in a variable using the `RooFit::CodegenContext::addResult()` function). -- `addResult()` It may include a function call, an expression, or something +- `RooFit::CodegenContext::addResult()` It may include a function call, an expression, or something more complicated. For a specific class, it will add whatever is represented on the right-hand side to the result of that class, which can then be propagated in the rest of the compute graph. -\note For each `translate()` function, it is important to call `addResult()` since this is what enables the squashing to happen. +\note For each `RooFit::codegenImpl()` function, it is important to call `RooFit::CodegenContext::addResult()` since this is what enables the squashing to happen. **translate() Example 2:** Following is a code snippet from `RooGaussian.cxx` *after* it has AD support. ``` {.cpp} -void RooGaussian::translate(RooFit::CodegenContext &ctx) const +void RooFit::codegenImpl(RooGaussian &arg, RooFit::CodegenContext &ctx) { - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::gaussianEvaluate", x, mean, sigma)); + // Build a call to the stateless gaussian defined later. + ctx.addResult(&arg, ctx.buildCall("RooFit::Detail::MathFuncs::gaussian", arg.getX(), arg.getMean(), arg.getSigma())); } ``` -Here we can see that the `RooGaussian::translate()` function constructs a -function call using the `buildCall()` method. It specifies the fully qualified -name of the `gaussianEvaluate` function (which is now part of the +Here we can see that the `RooFit::codegenImpl(RooGaussian &, RooFit::CodegenContext &)` function constructs a +function call using the `RooFit::CodegenContext::buildCall()` method. It specifies the fully qualified +name of the `gaussian` function (which is now part of the `MathFuncs` file), and includes the x, mean, and sigma variables as arguments to this function call. Helper Function: -- `buildCall()` helps build a function call. Requires the fully qualified name - (`RooFit::Detail::MathFuncs::gaussianEvaluate`) of the function. When -this external `buildCall()` function is called, internally, the `getResult()` +- `RooFit::CodegenContext::buildCall()` helps build a function call. Requires the fully qualified name + (`RooFit::Detail::MathFuncs::gaussian`) of the function. When +this external `RooFit::CodegenContext::buildCall()` function is called, internally, the `RooFit::CodegenContext::getResult()` function is called on the input RooFit objects (e.g., x, mean, sigma). That's the only way to propagate these upwards into the compute graph. -**translate() Example 3:** A more complicated example of a `translate()` +**translate() Example 3:** A more complicated example of a `RooFit::codegenImpl()` function can be seen here: ``` {.cpp} -void RooNLLVarNew::translate(RooFit::CodegenContext &ctx) const +void RooFit::codegenImpl(RooFit::Detail::RooNLLVarNew &arg, RooFit::CodegenContext &ctx) { std::string weightSumName = ctx.makeValidVarName(GetName()) + "WeightSum"; std::string resName = ctx.makeValidVarName(GetName()) + "Result"; @@ -376,14 +380,14 @@ void RooNLLVarNew::translate(RooFit::CodegenContext &ctx) const > Source: - [RooNLLVarNew](https://github.com/root-project/root/blob/master/roofit/roofitcore/src/RooNLLVarNew.cxx) -The complexity of the `RooNLLVarNew::translate()` function in this example can +The complexity of the `RooFit::codegenImpl()` function in this example can be attributed to the more complex scenarios/operations specific to the computation of negative log-likelihood (NLL) values for probability density functions (PDFs) in RooFit, especially for simultaneous fits (multiple simultaneous PDFs being considered) and binned likelihoods (adding further complexity). -In this example, the `RooNLLVarNew::translate()` function generates code to +In this example, the `RooFit::codegenImpl()` function generates code to compute the Negative Log likelihood (NLL). We can see that the intermediate result variable `resName` is added to the context so that it can be accessed and used in the generated code. This variable is made available globally diff --git a/roofit/histfactory/inc/RooStats/HistFactory/FlexibleInterpVar.h b/roofit/histfactory/inc/RooStats/HistFactory/FlexibleInterpVar.h index e2f134531f437..d1a7f2243e257 100644 --- a/roofit/histfactory/inc/RooStats/HistFactory/FlexibleInterpVar.h +++ b/roofit/histfactory/inc/RooStats/HistFactory/FlexibleInterpVar.h @@ -55,11 +55,10 @@ namespace HistFactory{ double nominal() const { return _nominal; } const std::vector& low() const { return _low; } const std::vector& high() const { return _high; } + double globalBoundary() const { return _interpBoundary;} void doEval(RooFit::EvalContext &) const override; - void translate(RooFit::CodegenContext &ctx) const override; - protected: RooListProxy _paramList ; diff --git a/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h b/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h index 6e3517b0dbd06..c6006d65365b5 100644 --- a/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h +++ b/roofit/histfactory/inc/RooStats/HistFactory/ParamHistFunc.h @@ -46,6 +46,8 @@ class ParamHistFunc : public RooAbsReal { const RooArgSet* get(Int_t masterIdx) const { return _dataSet.get( masterIdx ) ; } const RooArgSet* get(const RooArgSet& coord) const { return _dataSet.get( coord ) ; } + RooDataHist const& dataHist() const { return _dataSet; } + double binVolume() const { return _dataSet.binVolume(); } bool forceAnalyticalInt(const RooAbsArg&) const override { return true ; } @@ -61,6 +63,7 @@ class ParamHistFunc : public RooAbsReal { std::list* plotSamplingHint(RooAbsRealLValue& obs, double xlo, double xhi) const override; bool isBinnedDistribution(const RooArgSet& obs) const override { return _dataVars.overlaps(obs); } + const RooArgList& dataVars() const { return _dataVars; } protected: @@ -103,8 +106,6 @@ class ParamHistFunc : public RooAbsReal { double evaluate() const override; void doEval(RooFit::EvalContext &) const override; - void translate(RooFit::CodegenContext &ctx) const override; - private: static NumBins getNumBinsPerDim(RooArgSet const& vars); diff --git a/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h b/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h index df7384168560a..fcf30fcbd3f03 100644 --- a/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h +++ b/roofit/histfactory/inc/RooStats/HistFactory/PiecewiseInterpolation.h @@ -69,8 +69,6 @@ class PiecewiseInterpolation : public RooAbsReal { std::list* plotSamplingHint(RooAbsRealLValue& obs, double xlo, double xhi) const override ; bool isBinnedDistribution(const RooArgSet& obs) const override ; - void translate(RooFit::CodegenContext &ctx) const override; - protected: class CacheElem : public RooAbsCacheElement { diff --git a/roofit/histfactory/src/FlexibleInterpVar.cxx b/roofit/histfactory/src/FlexibleInterpVar.cxx index 673d25fa3a4b3..ecd0eb018d904 100644 --- a/roofit/histfactory/src/FlexibleInterpVar.cxx +++ b/roofit/histfactory/src/FlexibleInterpVar.cxx @@ -231,29 +231,6 @@ double FlexibleInterpVar::evaluate() const return total; } -void FlexibleInterpVar::translate(RooFit::CodegenContext &ctx) const -{ - unsigned int n = _interpCode.size(); - - int interpCode = _interpCode[0]; - // To get consistent codes with the PiecewiseInterpolation - if (interpCode == 4) { - interpCode = 5; - } - - for (unsigned int i = 1; i < n; i++) { - if (_interpCode[i] != _interpCode[0]) { - coutE(InputArguments) << "FlexibleInterpVar::evaluate ERROR: Code Squashing AD does not yet support having " - "different interpolation codes for the same class object " - << std::endl; - } - } - - std::string const &resName = ctx.buildCall("RooFit::Detail::MathFuncs::flexibleInterp", interpCode, - _paramList, n, _low, _high, _interpBoundary, _nominal, 1.0); - ctx.addResult(this, resName); -} - void FlexibleInterpVar::doEval(RooFit::EvalContext &ctx) const { double total(_nominal); diff --git a/roofit/histfactory/src/ParamHistFunc.cxx b/roofit/histfactory/src/ParamHistFunc.cxx index 3fb7963efd780..e05af08615322 100644 --- a/roofit/histfactory/src/ParamHistFunc.cxx +++ b/roofit/histfactory/src/ParamHistFunc.cxx @@ -560,21 +560,6 @@ double ParamHistFunc::evaluate() const return getParameter().getVal(); } -void ParamHistFunc::translate(RooFit::CodegenContext &ctx) const -{ - auto const &n = _numBinsPerDim; - - // check if _numBins needs to be filled - if (n.x == 0) { - _numBinsPerDim = getNumBinsPerDim(_dataVars); - } - - std::string const &idx = _dataSet.calculateTreeIndexForCodeSquash(this, ctx, _dataVars, true); - std::string const ¶mNames = ctx.buildArg(_paramSet); - - ctx.addResult(this, paramNames + "[" + idx + "]"); -} - //////////////////////////////////////////////////////////////////////////////// /// Find all bins corresponding to the values of the observables in `evalData`, and evaluate /// the associated parameters. diff --git a/roofit/histfactory/src/PiecewiseInterpolation.cxx b/roofit/histfactory/src/PiecewiseInterpolation.cxx index c9f6967f3ebbf..83f550716d951 100644 --- a/roofit/histfactory/src/PiecewiseInterpolation.cxx +++ b/roofit/histfactory/src/PiecewiseInterpolation.cxx @@ -178,68 +178,6 @@ double PiecewiseInterpolation::evaluate() const } -void PiecewiseInterpolation::translate(RooFit::CodegenContext &ctx) const -{ - std::size_t n = _interpCode.size(); - - std::string resName = "total_" + ctx.getTmpVarName(); - for (std::size_t i = 0; i < n; ++i) { - if (_interpCode[i] != _interpCode[0]) { - coutE(InputArguments) << "FlexibleInterpVar::evaluate ERROR: Code Squashing AD does not yet support having " - "different interpolation codes for the same class object " - << endl; - } - } - - // The PiecewiseInterpolation class is used in the context of HistFactory - // models, where is is always used the same way: all RooAbsReals in _lowSet, - // _histSet, and also nominal are 1D RooHistFuncs with with same structure. - // - // Therefore, we can make a big optimization: we get the bin index only once - // here in the generated code for PiecewiseInterpolation. Then, we also - // rearrange the histogram data in such a way that we can always pass the - // same arrays to the free function that implements the interpolation, just - // with a dynamic offset calculated from the bin index. - RooDataHist const &nomHist = dynamic_cast(*_nominal).dataHist(); - int nBins = nomHist.numEntries(); - std::vector valsNominal; - std::vector valsLow; - std::vector valsHigh; - for (int i = 0; i < nBins; ++i) { - valsNominal.push_back(nomHist.weight(i)); - } - for (int i = 0; i < nBins; ++i) { - for (std::size_t iParam = 0; iParam < n; ++iParam) { - valsLow.push_back(dynamic_cast(_lowSet[iParam]).dataHist().weight(i)); - valsHigh.push_back(dynamic_cast(_highSet[iParam]).dataHist().weight(i)); - } - } - std::string idxName = ctx.getTmpVarName(); - std::string valsNominalStr = ctx.buildArg(valsNominal); - std::string valsLowStr = ctx.buildArg(valsLow); - std::string valsHighStr = ctx.buildArg(valsHigh); - std::string nStr = std::to_string(n); - std::string code; - - std::string lowName = ctx.getTmpVarName(); - std::string highName = ctx.getTmpVarName(); - std::string nominalName = ctx.getTmpVarName(); - code += "unsigned int " + idxName + " = " + nomHist.calculateTreeIndexForCodeSquash(this, ctx, dynamic_cast(*_nominal).variables()) + ";\n"; - code += "double const* " + lowName + " = " + valsLowStr + " + " + nStr + " * " + idxName + ";\n"; - code += "double const* " + highName + " = " + valsHighStr + " + " + nStr + " * " + idxName + ";\n"; - code += "double " + nominalName + " = *(" + valsNominalStr + " + " + idxName + ");\n"; - - std::string funcCall = ctx.buildCall("RooFit::Detail::MathFuncs::flexibleInterp", _interpCode[0], _paramSet, n, - lowName, highName, 1.0, nominalName, 0.0); - code += "double " + resName + " = " + funcCall + ";\n"; - - if (_positiveDefinite) - code += resName + " = " + resName + " < 0 ? 0 : " + resName + ";\n"; - - ctx.addToCodeBody(this, code); - ctx.addResult(this, resName); -} - namespace { inline double broadcast(std::span const &s, std::size_t i) diff --git a/roofit/roofit/inc/RooBernstein.h b/roofit/roofit/inc/RooBernstein.h index 5b3f02552e079..ca91009d1e9d0 100644 --- a/roofit/roofit/inc/RooBernstein.h +++ b/roofit/roofit/inc/RooBernstein.h @@ -32,15 +32,18 @@ class RooBernstein : public RooAbsPdf { double analyticalIntegral(Int_t code, const char *rangeName = nullptr) const override; void selectNormalizationRange(const char *rangeName = nullptr, bool force = false) override; - void translate(RooFit::CodegenContext &ctx) const override; - std::string buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext &ctx) const override; + RooAbsRealLValue const &x() const { return *_x; } + RooArgList const &coefList() const { return _coefList; } -private: + // Implementation detail. Do not use. void fillBuffer() const; + // Implementation detail. Do not use. inline double xmin() const { return _buffer[_coefList.size()]; } + // Implementation detail. Do not use. inline double xmax() const { return _buffer[_coefList.size() + 1]; } +private: + RooTemplateProxy _x; RooListProxy _coefList; std::string _refRangeName; diff --git a/roofit/roofit/inc/RooBifurGauss.h b/roofit/roofit/inc/RooBifurGauss.h index d6a9ae64431d5..9f0902f34bc5e 100644 --- a/roofit/roofit/inc/RooBifurGauss.h +++ b/roofit/roofit/inc/RooBifurGauss.h @@ -31,9 +31,17 @@ class RooBifurGauss : public RooAbsPdf { Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName = nullptr) const override; double analyticalIntegral(Int_t code, const char *rangeName = nullptr) const override; - void translate(RooFit::CodegenContext &ctx) const override; - std::string buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext &ctx) const override; + /// Get the x variable. + RooAbsReal const& getX() const { return x.arg(); } + + /// Get the mean parameter. + RooAbsReal const& getMean() const { return mean.arg(); } + + /// Get the left sigma parameter. + RooAbsReal const& getSigmaL() const { return sigmaL.arg(); } + + /// Get the right sigma parameter. + RooAbsReal const& getSigmaR() const { return sigmaR.arg(); } protected: RooRealProxy x; diff --git a/roofit/roofit/inc/RooCBShape.h b/roofit/roofit/inc/RooCBShape.h index 7fc24a69c1550..2886915215765 100644 --- a/roofit/roofit/inc/RooCBShape.h +++ b/roofit/roofit/inc/RooCBShape.h @@ -23,7 +23,7 @@ class RooRealVar; class RooCBShape : public RooAbsPdf { public: - RooCBShape() {} ; + RooCBShape() {} RooCBShape(const char *name, const char *title, RooAbsReal& _m, RooAbsReal& _m0, RooAbsReal& _sigma, RooAbsReal& _alpha, RooAbsReal& _n); @@ -38,9 +38,11 @@ class RooCBShape : public RooAbsPdf { Int_t getMaxVal(const RooArgSet& vars) const override ; double maxVal(Int_t code) const override ; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::CodegenContext &ctx) const override; + RooAbsReal const& getM() const { return m.arg(); } + RooAbsReal const& getM0() const { return m0.arg(); } + RooAbsReal const& getSigma() const { return sigma.arg(); } + RooAbsReal const& getAlpha() const { return alpha.arg(); } + RooAbsReal const& getN() const { return n.arg(); } protected: diff --git a/roofit/roofit/inc/RooChebychev.h b/roofit/roofit/inc/RooChebychev.h index 2c94254ee5865..a4b67e6f8e6fd 100644 --- a/roofit/roofit/inc/RooChebychev.h +++ b/roofit/roofit/inc/RooChebychev.h @@ -37,11 +37,12 @@ class RooChebychev : public RooAbsPdf { void selectNormalizationRange(const char* rangeName=nullptr, bool force=false) override ; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::CodegenContext &ctx) const override; + RooAbsReal const &x() const { return *_x; } + RooArgList const &coefList() const { return _coefList; } - private: + const char *refRangeName() const { return RooNameReg::str(_refRangeName); } + +private: RooRealProxy _x; RooListProxy _coefList ; mutable TNamed* _refRangeName = nullptr; diff --git a/roofit/roofit/inc/RooExponential.h b/roofit/roofit/inc/RooExponential.h index 0894e91b8fdb3..4e8e004d65139 100644 --- a/roofit/roofit/inc/RooExponential.h +++ b/roofit/roofit/inc/RooExponential.h @@ -38,10 +38,6 @@ class RooExponential : public RooAbsPdf { bool negateCoefficient() const { return _negateCoefficient; } - void translate(RooFit::CodegenContext &ctx) const override; - std::string buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext &ctx) const override; - protected: RooRealProxy x; RooRealProxy c; diff --git a/roofit/roofit/inc/RooGamma.h b/roofit/roofit/inc/RooGamma.h index a05b5823d3980..99ba0771ee7a8 100644 --- a/roofit/roofit/inc/RooGamma.h +++ b/roofit/roofit/inc/RooGamma.h @@ -31,9 +31,10 @@ class RooGamma : public RooAbsPdf { Int_t getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, bool staticInitOK=true) const override; void generateEvent(Int_t code) override; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::CodegenContext &ctx) const override; + RooAbsReal const &getX() const { return *x; } + RooAbsReal const &getGamma() const { return *gamma; } + RooAbsReal const &getBeta() const { return *beta; } + RooAbsReal const &getMu() const { return *mu; } protected: diff --git a/roofit/roofit/inc/RooGaussian.h b/roofit/roofit/inc/RooGaussian.h index 6e5d82fdc0486..3b487f447683d 100644 --- a/roofit/roofit/inc/RooGaussian.h +++ b/roofit/roofit/inc/RooGaussian.h @@ -50,10 +50,6 @@ class RooGaussian : public RooAbsPdf { /// Get the sigma parameter. RooAbsReal const& getSigma() const { return sigma.arg(); } - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::CodegenContext &ctx) const override; - protected: RooRealProxy x ; diff --git a/roofit/roofit/inc/RooLandau.h b/roofit/roofit/inc/RooLandau.h index eccaa37d1a67d..e303ab5182291 100644 --- a/roofit/roofit/inc/RooLandau.h +++ b/roofit/roofit/inc/RooLandau.h @@ -37,9 +37,9 @@ class RooLandau : public RooAbsPdf { Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName = nullptr) const override; double analyticalIntegral(Int_t code, const char *rangeName) const override; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::CodegenContext &ctx) const override; + RooAbsReal const& getX() const { return *x; } + RooAbsReal const& getMean() const { return *mean; } + RooAbsReal const& getSigma() const { return *sigma; } protected: diff --git a/roofit/roofit/inc/RooLognormal.h b/roofit/roofit/inc/RooLognormal.h index a2ef80a9009fd..bed014bcc57df 100644 --- a/roofit/roofit/inc/RooLognormal.h +++ b/roofit/roofit/inc/RooLognormal.h @@ -28,10 +28,6 @@ class RooLognormal : public RooAbsPdf { Int_t getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool staticInitOK = true) const override; void generateEvent(Int_t code) override; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(int code, const char *rangeName, RooFit::CodegenContext &ctx) const override; - /// Get the x variable. RooAbsReal const &getX() const { return x.arg(); } diff --git a/roofit/roofit/inc/RooParamHistFunc.h b/roofit/roofit/inc/RooParamHistFunc.h index 15edbe59d1bb3..31b9c25f38ae5 100644 --- a/roofit/roofit/inc/RooParamHistFunc.h +++ b/roofit/roofit/inc/RooParamHistFunc.h @@ -43,9 +43,10 @@ class RooParamHistFunc : public RooAbsReal { double getNominal(Int_t ibin) const ; double getNominalError(Int_t ibin) const ; + const RooArgList& xList() const { return _x ; } const RooArgList& paramList() const { return _p ; } - - void translate(RooFit::CodegenContext &ctx) const override; + const RooDataHist& dataHist() const { return _dh ; } + bool relParam() const { return _relParam; } protected: diff --git a/roofit/roofit/inc/RooPoisson.h b/roofit/roofit/inc/RooPoisson.h index c0d6e30562de5..9b4bb7ef3d893 100644 --- a/roofit/roofit/inc/RooPoisson.h +++ b/roofit/roofit/inc/RooPoisson.h @@ -39,16 +39,14 @@ class RooPoisson : public RooAbsPdf { /// Switch on or off protection against negative means. void protectNegativeMean(bool flag = true) {_protectNegative = flag;} + bool getProtectNegativeMean() const { return _protectNegative; } + /// Get the x variable. RooAbsReal const& getX() const { return x.arg(); } /// Get the mean parameter. RooAbsReal const& getMean() const { return mean.arg(); } - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(int code, const char *rangeName, RooFit::CodegenContext &ctx) const override; - protected: RooRealProxy x ; diff --git a/roofit/roofit/inc/RooPolynomial.h b/roofit/roofit/inc/RooPolynomial.h index 3188d35b7b295..1dcc58d32a040 100644 --- a/roofit/roofit/inc/RooPolynomial.h +++ b/roofit/roofit/inc/RooPolynomial.h @@ -48,10 +48,6 @@ class RooPolynomial : public RooAbsPdf { // pdf is a reducer node because it doesn't depend on the observables. bool isReducerNode() const override { return _coefList.empty(); } - void translate(RooFit::CodegenContext &ctx) const override; - std::string buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext &ctx) const override; - protected: RooRealProxy _x; RooListProxy _coefList; diff --git a/roofit/roofit/inc/RooUniform.h b/roofit/roofit/inc/RooUniform.h index 33009892e4b8f..fc19c09ee99b1 100644 --- a/roofit/roofit/inc/RooUniform.h +++ b/roofit/roofit/inc/RooUniform.h @@ -34,10 +34,6 @@ class RooUniform : public RooAbsPdf { Int_t getGenerator(const RooArgSet& directVars, RooArgSet &generateVars, bool staticInitOK=true) const override; void generateEvent(Int_t code) override; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::CodegenContext &ctx) const override; - protected: RooListProxy x ; diff --git a/roofit/roofit/src/RooBernstein.cxx b/roofit/roofit/src/RooBernstein.cxx index b4dcba2a4f9d7..e4fd2125cf6a6 100644 --- a/roofit/roofit/src/RooBernstein.cxx +++ b/roofit/roofit/src/RooBernstein.cxx @@ -81,13 +81,6 @@ double RooBernstein::evaluate() const return RooFit::Detail::MathFuncs::bernstein(_x, xmin(), xmax(), _buffer.data(), _coefList.size()); } -void RooBernstein::translate(RooFit::CodegenContext &ctx) const -{ - fillBuffer(); - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::bernstein", _x, xmin(), xmax(), _coefList, - _coefList.size())); -} - /// Compute multiple values of Bernstein distribution. void RooBernstein::doEval(RooFit::EvalContext &ctx) const { @@ -106,11 +99,3 @@ double RooBernstein::analyticalIntegral(Int_t /*code*/, const char *rangeName) c return RooFit::Detail::MathFuncs::bernsteinIntegral(_x.min(rangeName), _x.max(rangeName), xmin(), xmax(), _buffer.data(), _coefList.size()); } - -std::string RooBernstein::buildCallToAnalyticIntegral(Int_t /*code*/, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - fillBuffer(); // to get the right xmin() and xmax() - return ctx.buildCall("RooFit::Detail::MathFuncs::bernsteinIntegral", _x.min(rangeName), _x.max(rangeName), - xmin(), xmax(), _coefList, _coefList.size()); -} diff --git a/roofit/roofit/src/RooBifurGauss.cxx b/roofit/roofit/src/RooBifurGauss.cxx index 9ce1a6d044785..90e1e9d5788aa 100644 --- a/roofit/roofit/src/RooBifurGauss.cxx +++ b/roofit/roofit/src/RooBifurGauss.cxx @@ -60,13 +60,6 @@ double RooBifurGauss::evaluate() const return RooFit::Detail::MathFuncs::bifurGauss(x, mean, sigmaL, sigmaR); } -//////////////////////////////////////////////////////////////////////////////// - -void RooBifurGauss::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::bifurGauss", x, mean, sigmaL, sigmaR)); -} - //////////////////////////////////////////////////////////////////////////////// /// Compute multiple values of BifurGauss distribution. void RooBifurGauss::doEval(RooFit::EvalContext & ctx) const @@ -96,15 +89,3 @@ double RooBifurGauss::analyticalIntegral(Int_t code, const char *rangeName) cons return RooFit::Detail::MathFuncs::bifurGaussIntegral(integrand.min(rangeName), integrand.max(rangeName), constant, sigmaL, sigmaR); } - -//////////////////////////////////////////////////////////////////////////////// - -std::string RooBifurGauss::buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - auto &constant = code == 1 ? mean : x; - auto &integrand = code == 1 ? x : mean; - - return ctx.buildCall("RooFit::Detail::MathFuncs::bifurGaussIntegral", integrand.min(rangeName), - integrand.max(rangeName), constant, sigmaL, sigmaR); -} diff --git a/roofit/roofit/src/RooCBShape.cxx b/roofit/roofit/src/RooCBShape.cxx index 7f49e9df07a52..54e876c72db0b 100644 --- a/roofit/roofit/src/RooCBShape.cxx +++ b/roofit/roofit/src/RooCBShape.cxx @@ -64,11 +64,6 @@ double RooCBShape::evaluate() const return RooFit::Detail::MathFuncs::cbShape(m, m0, sigma, alpha, n); } -void RooCBShape::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::cbShape", m, m0, sigma, alpha, n)); -} - //////////////////////////////////////////////////////////////////////////////// /// Compute multiple values of Crystal ball Shape distribution. void RooCBShape::doEval(RooFit::EvalContext &ctx) const @@ -95,13 +90,6 @@ double RooCBShape::analyticalIntegral(Int_t /*code*/, const char *rangeName) con return cbShapeIntegral(m.min(rangeName), m.max(rangeName), m0, sigma, alpha, n); } -std::string -RooCBShape::buildCallToAnalyticIntegral(Int_t /*code*/, const char *rangeName, RooFit::CodegenContext &ctx) const -{ - return ctx.buildCall("RooFit::Detail::MathFuncs::cbShapeIntegral", - m.min(rangeName), m.max(rangeName), m0, sigma, alpha, n); -} - //////////////////////////////////////////////////////////////////////////////// /// Advertise that we know the maximum of self for given (m0,alpha,n,sigma) diff --git a/roofit/roofit/src/RooChebychev.cxx b/roofit/roofit/src/RooChebychev.cxx index 826b4b88df165..c98caa702c9c4 100644 --- a/roofit/roofit/src/RooChebychev.cxx +++ b/roofit/roofit/src/RooChebychev.cxx @@ -90,18 +90,6 @@ double RooChebychev::evaluate() const return RooFit::Detail::MathFuncs::chebychev(coeffs.data(), _coefList.size(), _x, xmin, xmax); } -void RooChebychev::translate(RooFit::CodegenContext &ctx) const -{ - // first bring the range of the variable _x to the normalised range [-1, 1] - // calculate sum_k c_k T_k(x) where x is given in the normalised range, - // c_0 = 1, and the higher coefficients are given in _coefList - double xmax = _x.max(_refRangeName ? _refRangeName->GetName() : nullptr); - double xmin = _x.min(_refRangeName ? _refRangeName->GetName() : nullptr); - - ctx.addResult(this, - ctx.buildCall("RooFit::Detail::MathFuncs::chebychev", _coefList, _coefList.size(), _x, xmin, xmax)); -} - //////////////////////////////////////////////////////////////////////////////// /// Compute multiple values of Chebychev. void RooChebychev::doEval(RooFit::EvalContext &ctx) const @@ -121,37 +109,24 @@ void RooChebychev::doEval(RooFit::EvalContext &ctx) const Int_t RooChebychev::getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* /* rangeName */) const { - if (matchArgs(allVars, analVars, _x)) return 1; - return 0; + return matchArgs(allVars, analVars, _x) ? 1 : 0; } //////////////////////////////////////////////////////////////////////////////// -double RooChebychev::analyticalIntegral(Int_t code, const char* rangeName) const +double RooChebychev::analyticalIntegral(Int_t code, const char *rangeName) const { - assert(1 == code); (void)code; + assert(1 == code); + (void)code; - double xmax = _x.max(_refRangeName ? _refRangeName->GetName() : nullptr); - double xmaxFull = _x.max(rangeName); - double xmin = _x.min(_refRangeName ? _refRangeName->GetName() : nullptr); - double xminFull = _x.min(rangeName); - unsigned int sz = _coefList.size(); - - std::vector coeffs; - for (auto it : _coefList) - coeffs.push_back(static_cast(*it).getVal()); - - return RooFit::Detail::MathFuncs::chebychevIntegral(coeffs.data(), sz, xmin, xmax, xminFull, xmaxFull); -} - -std::string RooChebychev::buildCallToAnalyticIntegral(Int_t /* code */, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ double xmax = _x.max(_refRangeName ? _refRangeName->GetName() : nullptr); - double xmaxFull = _x.max(rangeName); double xmin = _x.min(_refRangeName ? _refRangeName->GetName() : nullptr); - double xminFull = _x.min(rangeName); unsigned int sz = _coefList.size(); - return ctx.buildCall("RooFit::Detail::MathFuncs::chebychevIntegral", _coefList, sz, xmin, xmax, xminFull, xmaxFull); + std::vector coeffs; + for (auto it : _coefList) + coeffs.push_back(static_cast(*it).getVal()); + + return RooFit::Detail::MathFuncs::chebychevIntegral(coeffs.data(), sz, xmin, xmax, _x.min(rangeName), + _x.max(rangeName)); } diff --git a/roofit/roofit/src/RooExponential.cxx b/roofit/roofit/src/RooExponential.cxx index dd2ffd10f5b10..2c7e7c27164bb 100644 --- a/roofit/roofit/src/RooExponential.cxx +++ b/roofit/roofit/src/RooExponential.cxx @@ -110,43 +110,3 @@ double RooExponential::analyticalIntegral(Int_t code, const char *rangeName) con return RooFit::Detail::MathFuncs::exponentialIntegral(min, max, constant); } - -//////////////////////////////////////////////////////////////////////////////// - -void RooExponential::translate(RooFit::CodegenContext &ctx) const -{ - // Build a call to the stateless exponential defined later. - std::string coef; - if (_negateCoefficient) { - coef += "-"; - } - coef += ctx.getResult(c); - ctx.addResult(this, "std::exp(" + coef + " * " + ctx.getResult(x) + ")"); -} - -//////////////////////////////////////////////////////////////////////////////// - -std::string RooExponential::buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - bool isOverX = code == 1; - - std::string constant; - if (_negateCoefficient && isOverX) { - constant += "-"; - } - constant += ctx.getResult(isOverX ? c : x); - - auto &integrand = isOverX ? x : c; - - double min = integrand.min(rangeName); - double max = integrand.max(rangeName); - - if (!isOverX && _negateCoefficient) { - std::swap(min, max); - min = -min; - max = -max; - } - - return ctx.buildCall("RooFit::Detail::MathFuncs::exponentialIntegral", min, max, constant); -} diff --git a/roofit/roofit/src/RooGamma.cxx b/roofit/roofit/src/RooGamma.cxx index 5d9e607cd00b4..6ef6941647446 100644 --- a/roofit/roofit/src/RooGamma.cxx +++ b/roofit/roofit/src/RooGamma.cxx @@ -85,13 +85,6 @@ double RooGamma::evaluate() const return TMath::GammaDist(x, gamma, mu, beta) ; } -//////////////////////////////////////////////////////////////////////////////// - -void RooGamma::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("TMath::GammaDist", x, gamma, mu, beta)); -} - //////////////////////////////////////////////////////////////////////////////// /// Compute multiple values of Gamma PDF. void RooGamma::doEval(RooFit::EvalContext &ctx) const @@ -117,16 +110,6 @@ double RooGamma::analyticalIntegral(Int_t /*code*/, const char *rangeName) const ROOT::Math::gamma_cdf(x.min(rangeName), gamma, beta, mu); } -//////////////////////////////////////////////////////////////////////////////// - -std::string RooGamma::buildCallToAnalyticIntegral(Int_t /*code*/, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - const std::string a = ctx.buildCall("ROOT::Math::gamma_cdf", x.max(rangeName), gamma, beta, mu); - const std::string b = ctx.buildCall("ROOT::Math::gamma_cdf", x.min(rangeName), gamma, beta, mu); - return a + " - " + b; -} - namespace { inline double randomGamma(double gamma, double beta, double mu, double xmin, double xmax) diff --git a/roofit/roofit/src/RooGaussian.cxx b/roofit/roofit/src/RooGaussian.cxx index 75c741417a981..ca31e50bcabab 100644 --- a/roofit/roofit/src/RooGaussian.cxx +++ b/roofit/roofit/src/RooGaussian.cxx @@ -126,23 +126,3 @@ void RooGaussian::generateEvent(Int_t code) return; } - -//////////////////////////////////////////////////////////////////////////////// - -void RooGaussian::translate(RooFit::CodegenContext &ctx) const -{ - // Build a call to the stateless gaussian defined later. - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::gaussian", x, mean, sigma)); -} - -//////////////////////////////////////////////////////////////////////////////// - -std::string RooGaussian::buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - auto& constant = code == 1 ? mean : x; - auto& integrand = code == 1 ? x : mean; - - return ctx.buildCall("RooFit::Detail::MathFuncs::gaussianIntegral", - integrand.min(rangeName), integrand.max(rangeName), constant, sigma); -} diff --git a/roofit/roofit/src/RooLandau.cxx b/roofit/roofit/src/RooLandau.cxx index a0e461d3c93ac..cc29e989d4bc4 100644 --- a/roofit/roofit/src/RooLandau.cxx +++ b/roofit/roofit/src/RooLandau.cxx @@ -61,13 +61,6 @@ double RooLandau::evaluate() const return RooFit::Detail::MathFuncs::landau(x, mean, sigma); } -//////////////////////////////////////////////////////////////////////////////// - -void RooLandau::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::landau", x, mean, sigma)); -} - //////////////////////////////////////////////////////////////////////////////// /// Compute multiple values of Landau distribution. void RooLandau::doEval(RooFit::EvalContext &ctx) const @@ -103,18 +96,6 @@ Double_t RooLandau::analyticalIntegral(Int_t /*code*/, const char *rangeName) co //////////////////////////////////////////////////////////////////////////////// -std::string RooLandau::buildCallToAnalyticIntegral(Int_t /*code*/, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - // Don't do anything with "code". It can only be "1" anyway (see - // implementation of getAnalyticalIntegral). - const std::string a = ctx.buildCall("ROOT::Math::landau_cdf", x.max(rangeName), sigma, mean); - const std::string b = ctx.buildCall("ROOT::Math::landau_cdf", x.min(rangeName), sigma, mean); - return ctx.getResult(sigma) + " * " + "(" + a + " - " + b + ")"; -} - -//////////////////////////////////////////////////////////////////////////////// - void RooLandau::generateEvent(Int_t code) { assert(1 == code); (void)code; diff --git a/roofit/roofit/src/RooLognormal.cxx b/roofit/roofit/src/RooLognormal.cxx index 1ab9474722d6c..a251b62127561 100644 --- a/roofit/roofit/src/RooLognormal.cxx +++ b/roofit/roofit/src/RooLognormal.cxx @@ -82,12 +82,6 @@ double RooLognormal::evaluate() const return ROOT::Math::lognormal_pdf(x, ln_m0, ln_k); } -void RooLognormal::translate(RooFit::CodegenContext &ctx) const -{ - std::string funcName = _useStandardParametrization ? "logNormalEvaluateStandard" : "logNormal"; - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::" + funcName, x, k, m0)); -} - //////////////////////////////////////////////////////////////////////////////// /// Compute multiple values of Lognormal distribution. void RooLognormal::doEval(RooFit::EvalContext &ctx) const @@ -116,13 +110,6 @@ double RooLognormal::analyticalIntegral(Int_t /*code*/, const char *rangeName) c return 0.5 * (RooMath::erf(scaledMax / (root2 * ln_k)) - RooMath::erf(scaledMin / (root2 * ln_k))); } -std::string RooLognormal::buildCallToAnalyticIntegral(int /*code*/, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - std::string funcName = _useStandardParametrization ? "logNormalIntegralStandard" : "logNormalIntegral"; - return ctx.buildCall("RooFit::Detail::MathFuncs::" + funcName, x.min(rangeName), x.max(rangeName), m0, k); -} - //////////////////////////////////////////////////////////////////////////////// Int_t RooLognormal::getGenerator(const RooArgSet &directVars, RooArgSet &generateVars, bool /*staticInitOK*/) const diff --git a/roofit/roofit/src/RooParamHistFunc.cxx b/roofit/roofit/src/RooParamHistFunc.cxx index bcd3d04e574fb..42e954dfb8313 100644 --- a/roofit/roofit/src/RooParamHistFunc.cxx +++ b/roofit/roofit/src/RooParamHistFunc.cxx @@ -77,21 +77,6 @@ double RooParamHistFunc::evaluate() const return _relParam ? ret * getNominal(idx) : ret; } -void RooParamHistFunc::translate(RooFit::CodegenContext &ctx) const -{ - std::string const &idx = _dh.calculateTreeIndexForCodeSquash(this, ctx, _x); - std::string arrName = ctx.buildArg(_p); - std::string result = arrName + "[" + idx + "]"; - if (_relParam) { - // get weight[idx] * binv[idx]. Here we get the bin volume for the first element as we assume the distribution to - // be binned uniformly. - double binV = _dh.binVolume(0); - std::string weightArr = _dh.declWeightArrayForCodeSquash(ctx, false); - result += " * *(" + weightArr + " + " + idx + ") * " + std::to_string(binV); - } - ctx.addResult(this, result); -} - //////////////////////////////////////////////////////////////////////////////// double RooParamHistFunc::getActual(Int_t ibin) diff --git a/roofit/roofit/src/RooPoisson.cxx b/roofit/roofit/src/RooPoisson.cxx index 7a872e4f94751..efffd71712c03 100644 --- a/roofit/roofit/src/RooPoisson.cxx +++ b/roofit/roofit/src/RooPoisson.cxx @@ -64,15 +64,6 @@ double RooPoisson::evaluate() const return RooFit::Detail::MathFuncs::poisson(k, mean); } -void RooPoisson::translate(RooFit::CodegenContext &ctx) const -{ - std::string xName = ctx.getResult(x); - if (!_noRounding) - xName = "std::floor(" + xName + ")"; - - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::poisson", xName, mean)); -} - //////////////////////////////////////////////////////////////////////////////// /// Compute multiple values of the Poisson distribution. void RooPoisson::doEval(RooFit::EvalContext &ctx) const @@ -102,22 +93,6 @@ double RooPoisson::analyticalIntegral(Int_t code, const char* rangeName) const code, mean, _noRounding ? x : std::floor(x), integrand.min(rangeName), integrand.max(rangeName), _protectNegative); } -std::string -RooPoisson::buildCallToAnalyticIntegral(int code, const char *rangeName, RooFit::CodegenContext &ctx) const -{ - R__ASSERT(code == 1 || code == 2); - std::string xName = ctx.getResult(x); - if (!_noRounding) - xName = "std::floor(" + xName + ")"; - - RooRealProxy const &integrand = code == 1 ? x : mean; - // Since the integral function is the same for both codes, we need to make sure the indexed observables do not appear - // in the function if they are not required. - xName = code == 1 ? "0" : xName; - return ctx.buildCall("RooFit::Detail::MathFuncs::poissonIntegral", code, mean, xName, - integrand.min(rangeName), integrand.max(rangeName), _protectNegative); -} - //////////////////////////////////////////////////////////////////////////////// /// Advertise internal generator in x diff --git a/roofit/roofit/src/RooPolynomial.cxx b/roofit/roofit/src/RooPolynomial.cxx index 053b95ff7df58..39384cf8ee990 100644 --- a/roofit/roofit/src/RooPolynomial.cxx +++ b/roofit/roofit/src/RooPolynomial.cxx @@ -111,17 +111,6 @@ double RooPolynomial::evaluate() const return RooFit::Detail::MathFuncs::polynomial(_wksp.data(), sz, _lowestOrder, _x); } -void RooPolynomial::translate(RooFit::CodegenContext &ctx) const -{ - const unsigned sz = _coefList.size(); - if (!sz) { - ctx.addResult(this, std::to_string((_lowestOrder ? 1. : 0.))); - return; - } - - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::polynomial", _coefList, sz, _lowestOrder, _x)); -} - /// Compute multiple values of Polynomial. void RooPolynomial::doEval(RooFit::EvalContext &ctx) const { @@ -151,16 +140,3 @@ double RooPolynomial::analyticalIntegral(Int_t code, const char *rangeName) cons return RooFit::Detail::MathFuncs::polynomialIntegral(_wksp.data(), sz, _lowestOrder, xmin, xmax); } - -std::string RooPolynomial::buildCallToAnalyticIntegral(Int_t /* code */, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - const double xmin = _x.min(rangeName); - const double xmax = _x.max(rangeName); - const unsigned sz = _coefList.size(); - if (!sz) - return std::to_string(_lowestOrder ? xmax - xmin : 0.0); - - return ctx.buildCall("RooFit::Detail::MathFuncs::polynomialIntegral", _coefList, sz, _lowestOrder, - xmin, xmax); -} diff --git a/roofit/roofit/src/RooUniform.cxx b/roofit/roofit/src/RooUniform.cxx index 5b232e541e5b1..71793251f55f4 100644 --- a/roofit/roofit/src/RooUniform.cxx +++ b/roofit/roofit/src/RooUniform.cxx @@ -50,11 +50,6 @@ double RooUniform::evaluate() const return 1 ; } -void RooUniform::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, "1.0"); -} - //////////////////////////////////////////////////////////////////////////////// /// Advertise analytical integral @@ -93,14 +88,6 @@ double RooUniform::analyticalIntegral(Int_t code, const char* rangeName) const return ret ; } -std::string RooUniform::buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext & /*ctx*/) const -{ - // The integral of a uniform distribution is static, so we can just hardcode - // the result in a string. - return std::to_string(analyticalIntegral(code, rangeName)); -} - //////////////////////////////////////////////////////////////////////////////// /// Advertise internal generator diff --git a/roofit/roofitcore/CMakeLists.txt b/roofit/roofitcore/CMakeLists.txt index 4ec41da7c0d15..d82756854233f 100644 --- a/roofit/roofitcore/CMakeLists.txt +++ b/roofit/roofitcore/CMakeLists.txt @@ -116,10 +116,12 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore RooFactoryWSTool.h RooFirstMoment.h RooFit.h - RooFit/Config.h RooFit/CodegenContext.h + RooFit/Config.h RooFit/Detail/MathFuncs.h RooFit/Detail/NormalizationHelpers.h + RooFit/Detail/RooNLLVarNew.h + RooFit/Detail/RooNormalizedPdf.h RooFit/EvalContext.h RooFit/Evaluator.h RooFit/Floats.h @@ -132,8 +134,8 @@ ROOT_STANDARD_LIBRARY_PACKAGE(RooFitCore RooFit/TestStatistics/RooSubsidiaryL.h RooFit/TestStatistics/RooSumL.h RooFit/TestStatistics/RooUnbinnedL.h - RooFit/TestStatistics/buildLikelihood.h RooFit/TestStatistics/SharedOffset.h + RooFit/TestStatistics/buildLikelihood.h RooFitLegacy/RooCatTypeLegacy.h RooFitLegacy/RooCategorySharedProperties.h RooFitLegacy/RooTreeData.h diff --git a/roofit/roofitcore/inc/LinkDef.h b/roofit/roofitcore/inc/LinkDef.h index 4e643d16459fb..83fa0c52e8ac5 100644 --- a/roofit/roofitcore/inc/LinkDef.h +++ b/roofit/roofitcore/inc/LinkDef.h @@ -233,6 +233,7 @@ #pragma link C++ class RooRealSumFunc + ; #pragma link C++ class RooResolutionModel+ ; #pragma link C++ class RooTruthModel+ ; +#pragma link C++ class RooFit::Detail::RooFixedProdPdf+ ; #pragma link C++ class RooProdPdf+ ; #pragma read sourceClass="RooProdPdf" targetClass="RooProdPdf" version="[-5]" \ source="RooLinkedList _pdfNSetList" target="_pdfNSetList" \ @@ -334,5 +335,7 @@ #pragma link off class RooErrorHandler+ ; #pragma link C++ class RooBinSamplingPdf+; #pragma link C++ class RooBinWidthFunction+; +#pragma link C++ class RooFit::Detail::RooNLLVarNew+; +#pragma link C++ class RooFit::Detail::RooNormalizedPdf+ ; #endif diff --git a/roofit/roofitcore/inc/RooAbsArg.h b/roofit/roofitcore/inc/RooAbsArg.h index f7d83f36f59bf..655ed128dfbcf 100644 --- a/roofit/roofitcore/inc/RooAbsArg.h +++ b/roofit/roofitcore/inc/RooAbsArg.h @@ -521,8 +521,6 @@ class RooAbsArg : public TNamed, public RooPrintable { virtual bool isCategory() const { return false; } - virtual void translate(RooFit::CodegenContext &ctx) const; - protected: void graphVizAddConnections(std::set >&) ; diff --git a/roofit/roofitcore/inc/RooAbsReal.h b/roofit/roofitcore/inc/RooAbsReal.h index 2c5d22b7d507a..5300c32c3b84a 100644 --- a/roofit/roofitcore/inc/RooAbsReal.h +++ b/roofit/roofitcore/inc/RooAbsReal.h @@ -389,9 +389,6 @@ class RooAbsReal : public RooAbsArg { if(!hasGradient()) throw std::runtime_error("RooAbsReal::gradient(double *) not implemented by this class!"); } - virtual std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::CodegenContext &ctx) const; - // PlotOn with command list virtual RooPlot* plotOn(RooPlot* frame, RooLinkedList& cmdList) const ; diff --git a/roofit/roofitcore/inc/RooAddPdf.h b/roofit/roofitcore/inc/RooAddPdf.h index 1face4668cbfc..26dfa58ec646e 100644 --- a/roofit/roofitcore/inc/RooAddPdf.h +++ b/roofit/roofitcore/inc/RooAddPdf.h @@ -93,8 +93,6 @@ class RooAddPdf : public RooAbsPdf { CacheMode canNodeBeCached() const override { return RooAbsArg::NotAdvised ; }; void setCacheAndTrackHints(RooArgSet&) override; - void translate(RooFit::CodegenContext &ctx) const override; - std::unique_ptr compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext & ctx) const override; protected: diff --git a/roofit/roofitcore/inc/RooAddition.h b/roofit/roofitcore/inc/RooAddition.h index 9b29befeebaaf..d07f5c3e49454 100644 --- a/roofit/roofitcore/inc/RooAddition.h +++ b/roofit/roofitcore/inc/RooAddition.h @@ -56,8 +56,6 @@ class RooAddition : public RooAbsReal { void doEval(RooFit::EvalContext &) const override; - void translate(RooFit::CodegenContext &ctx) const override; - protected: RooArgList _ownedList ; ///< List of owned components diff --git a/roofit/roofitcore/inc/RooConstVar.h b/roofit/roofitcore/inc/RooConstVar.h index aceac109df01e..1772124d77326 100644 --- a/roofit/roofitcore/inc/RooConstVar.h +++ b/roofit/roofitcore/inc/RooConstVar.h @@ -48,8 +48,6 @@ class RooConstVar final : public RooAbsReal { _value = value; } - void translate(RooFit::CodegenContext &ctx) const override; - protected: double evaluate() const override { diff --git a/roofit/roofitcore/inc/RooConstraintSum.h b/roofit/roofitcore/inc/RooConstraintSum.h index c659dd18ab8de..cf38ded44c96f 100644 --- a/roofit/roofitcore/inc/RooConstraintSum.h +++ b/roofit/roofitcore/inc/RooConstraintSum.h @@ -45,7 +45,6 @@ class RooConstraintSum : public RooAbsReal { std::unique_ptr compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext & ctx) const override; - void translate(RooFit::CodegenContext &ctx) const override; protected: RooListProxy _set1 ; ///< Set of constraint terms diff --git a/roofit/roofitcore/inc/RooEffProd.h b/roofit/roofitcore/inc/RooEffProd.h index ad9d8f431a686..3b9e65e8c4bfd 100644 --- a/roofit/roofitcore/inc/RooEffProd.h +++ b/roofit/roofitcore/inc/RooEffProd.h @@ -28,12 +28,13 @@ class RooEffProd: public RooAbsPdf { RooAbsGenContext* genContext(const RooArgSet &vars, const RooDataSet *prototype, const RooArgSet* auxProto, bool verbose) const override; + RooAbsReal const& pdf() const { return *_pdf; } + RooAbsReal const& eff() const { return *_eff; } + protected: // Function evaluation double evaluate() const override ; - void translate(RooFit::CodegenContext &ctx) const override; - RooRealProxy _pdf ; ///< Probability Density function RooRealProxy _eff; ///< Efficiency function diff --git a/roofit/roofitcore/inc/RooEfficiency.h b/roofit/roofitcore/inc/RooEfficiency.h index 36e660784e343..829706aae9330 100644 --- a/roofit/roofitcore/inc/RooEfficiency.h +++ b/roofit/roofitcore/inc/RooEfficiency.h @@ -33,14 +33,16 @@ class RooEfficiency : public RooAbsPdf { Int_t getAnalyticalIntegral(RooArgSet& allVars, RooArgSet& analVars, const char* rangeName=nullptr) const override ; double analyticalIntegral(Int_t code, const char* rangeName=nullptr) const override ; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::CodegenContext &ctx) const override; + + RooAbsCategory const& cat() const { return *_cat; } + RooAbsReal const& effFunc() const { return *_effFunc; } + std::string sigCatName() const { return _sigCatName.Data(); } protected: // Function evaluation double evaluate() const override ; + RooCategoryProxy _cat ; ///< Accept/reject categort RooRealProxy _effFunc ; ///< Efficiency modeling function TString _sigCatName ; ///< Name of accept state of accept/reject category diff --git a/roofit/roofitcore/inc/RooExtendPdf.h b/roofit/roofitcore/inc/RooExtendPdf.h index ccdac65c8fcbe..c0ffad65c5b10 100644 --- a/roofit/roofitcore/inc/RooExtendPdf.h +++ b/roofit/roofitcore/inc/RooExtendPdf.h @@ -48,7 +48,7 @@ class RooExtendPdf : public RooAbsPdf { double expectedEvents(const RooArgSet* nset) const override ; std::unique_ptr createExpectedEventsFunc(const RooArgSet* nset) const override; - void translate(RooFit::CodegenContext &ctx) const override; + RooAbsPdf const& pdf() const { return *_pdf; } protected: diff --git a/roofit/roofitcore/inc/RooFit/CodegenContext.h b/roofit/roofitcore/inc/RooFit/CodegenContext.h index c45ae2bb77ffb..c65bc0294a449 100644 --- a/roofit/roofitcore/inc/RooFit/CodegenContext.h +++ b/roofit/roofitcore/inc/RooFit/CodegenContext.h @@ -32,6 +32,15 @@ class RooTemplateProxy; namespace RooFit { +template +struct Prio { + static_assert(P >= 1 && P <= 10, "P must be 1 <= P <= 10!"); + static auto next() { return Prio

{}; } +}; + +using PrioHighest = Prio<1>; +using PrioLowest = Prio<10>; + /// @brief A class to maintain the context for squashing of RooFit models into code. class CodegenContext { public: @@ -109,7 +118,7 @@ class CodegenContext { std::vector const &collectedFunctions() { return _collectedFunctions; } std::string - buildFunction(RooAbsArg const &arg, std::map const &outputSizes); + buildFunction(RooAbsArg const &arg, std::map const &outputSizes = {}); auto const &outputSizes() const { return _nodeOutputSizes; } @@ -217,6 +226,27 @@ std::string CodegenContext::buildArgSpanImpl(std::span arr) return arrName; } +template +void codegenImpl(Arg_t &arg, RooFit::CodegenContext &ctx, Prio

p) +{ + if constexpr (std::is_same, PrioLowest>::value) { + return codegenImpl(arg, ctx); + } else { + return codegenImpl(arg, ctx, p.next()); + } +} + +template +struct CodegenImplCaller { + + static auto call(RooAbsArg &arg, RooFit::CodegenContext &ctx) { + return codegenImpl(static_cast(arg), ctx, PrioHighest{}); + } + +}; + +void codegen(RooAbsArg &arg, RooFit::CodegenContext &ctx); + } // namespace RooFit #endif diff --git a/roofit/roofitcore/src/RooNLLVarNew.h b/roofit/roofitcore/inc/RooFit/Detail/RooNLLVarNew.h similarity index 86% rename from roofit/roofitcore/src/RooNLLVarNew.h rename to roofit/roofitcore/inc/RooFit/Detail/RooNLLVarNew.h index 89954aa431809..d7ef8e8fda613 100644 --- a/roofit/roofitcore/src/RooNLLVarNew.h +++ b/roofit/roofitcore/inc/RooFit/Detail/RooNLLVarNew.h @@ -23,6 +23,9 @@ #include +namespace RooFit { +namespace Detail { + class RooNLLVarNew : public RooAbsReal { public: @@ -52,7 +55,11 @@ class RooNLLVarNew : public RooAbsReal { void setSimCount(int simCount) { _simCount = simCount; } - void translate(RooFit::CodegenContext &ctx) const override; + RooAbsPdf const &pdf() const { return *_pdf; } + RooAbsReal const &weightVar() const { return *_weightVar; } + bool binnedL() const { return _binnedL; } + int simCount() const { return _simCount; } + RooAbsReal const *expectedEvents() const { return _expectedEvents ? &**_expectedEvents : nullptr; } private: double evaluate() const override { return _value; } @@ -77,7 +84,11 @@ class RooNLLVarNew : public RooAbsReal { std::vector _binw; mutable ROOT::Math::KahanSum _offset{0.}; /// #include +namespace RooFit { +namespace Detail { + class RooNormalizedPdf : public RooAbsPdf { public: RooNormalizedPdf(RooAbsPdf &pdf, RooArgSet const &normSet) : _pdf("numerator", "numerator", this, pdf), _normIntegral( "denominator", "denominator", this, - std::unique_ptr{pdf.createIntegral(normSet, *pdf.getIntegratorConfig(), pdf.normRange())}, - true, false), + std::unique_ptr{pdf.createIntegral(normSet, *pdf.getIntegratorConfig(), pdf.normRange())}, true, + false), _normSet{normSet} { auto name = std::string(pdf.GetName()) + "_over_" + _normIntegral->GetName(); @@ -51,7 +54,8 @@ class RooNormalizedPdf : public RooAbsPdf { return _pdf->getAnalyticalIntegralWN(allVars, analVars, &_normSet, rangeName); } /// Forward calculation of analytical integrals to input p.d.f - double analyticalIntegralWN(Int_t code, const RooArgSet * /*normSet*/, const char *rangeName = nullptr) const override + double + analyticalIntegralWN(Int_t code, const RooArgSet * /*normSet*/, const char *rangeName = nullptr) const override { return _pdf->analyticalIntegralWN(code, &_normSet, rangeName); } @@ -64,10 +68,11 @@ class RooNormalizedPdf : public RooAbsPdf { return _pdf->createExpectedEventsFunc(&_normSet); } - void translate(RooFit::CodegenContext &ctx) const override; - bool canComputeBatchWithCuda() const override { return true; } + RooAbsPdf const &pdf() const { return *_pdf; } + RooAbsReal const &normIntegral() const { return *_normIntegral; } + protected: void doEval(RooFit::EvalContext &) const override; double evaluate() const override @@ -85,6 +90,11 @@ class RooNormalizedPdf : public RooAbsPdf { RooTemplateProxy _pdf; RooRealProxy _normIntegral; RooArgSet _normSet; + + ClassDefOverride(RooFit::Detail::RooNormalizedPdf, 0); }; +} // namespace Detail +} // namespace RooFit + #endif diff --git a/roofit/roofitcore/inc/RooFormulaVar.h b/roofit/roofitcore/inc/RooFormulaVar.h index 7fe78095869ee..3fd0b228a12ac 100644 --- a/roofit/roofitcore/inc/RooFormulaVar.h +++ b/roofit/roofitcore/inc/RooFormulaVar.h @@ -74,7 +74,8 @@ class RooFormulaVar : public RooAbsReal { // Function evaluation double evaluate() const override ; void doEval(RooFit::EvalContext &ctx) const override; - void translate(RooFit::CodegenContext &ctx) const override; + + std::string getUniqueFuncName() const; protected: // Post-processing of server redirection diff --git a/roofit/roofitcore/inc/RooGenericPdf.h b/roofit/roofitcore/inc/RooGenericPdf.h index 64b58ce855734..4fc0bfad5e463 100644 --- a/roofit/roofitcore/inc/RooGenericPdf.h +++ b/roofit/roofitcore/inc/RooGenericPdf.h @@ -59,6 +59,8 @@ class RooGenericPdf : public RooAbsPdf { const char* expression() const { return _formExpr.Data(); } const RooArgList& dependents() const { return _actualVars; } + std::string getUniqueFuncName() const; + protected: RooFormula& formula() const ; @@ -67,7 +69,6 @@ class RooGenericPdf : public RooAbsPdf { RooListProxy _actualVars ; double evaluate() const override ; void doEval(RooFit::EvalContext &) const override; - void translate(RooFit::CodegenContext &ctx) const override; // Post-processing of server redirection bool redirectServersHook(const RooAbsCollection& newServerList, bool mustReplaceAll, bool nameChange, bool isRecursive) override ; diff --git a/roofit/roofitcore/inc/RooHistFunc.h b/roofit/roofitcore/inc/RooHistFunc.h index 1da24ad220eab..4a7be1f6f19d5 100644 --- a/roofit/roofitcore/inc/RooHistFunc.h +++ b/roofit/roofitcore/inc/RooHistFunc.h @@ -99,10 +99,6 @@ class RooHistFunc : public RooAbsReal { Int_t getBin() const; std::vector getBins(RooFit::EvalContext & ctx) const; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(int code, const char *rangeName, RooFit::CodegenContext &ctx) const override; - RooArgSet const &variables() const { return _depList; } protected: diff --git a/roofit/roofitcore/inc/RooHistPdf.h b/roofit/roofitcore/inc/RooHistPdf.h index 3b803648e71a1..e55d35f561ebf 100644 --- a/roofit/roofitcore/inc/RooHistPdf.h +++ b/roofit/roofitcore/inc/RooHistPdf.h @@ -95,11 +95,9 @@ class RooHistPdf : public RooAbsPdf { void doEval(RooFit::EvalContext &) const override; - void translate(RooFit::CodegenContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(int code, const char *rangeName, RooFit::CodegenContext &ctx) const override; + RooArgSet const &variables() const { return _pdfObsList; } - protected: +protected: bool areIdentical(const RooDataHist& dh1, const RooDataHist& dh2) ; bool importWorkspaceHook(RooWorkspace& ws) override ; @@ -147,13 +145,6 @@ class RooHistPdf : public RooAbsPdf { double xlo, double xhi); - static void rooHistTranslateImpl(RooAbsArg const *klass, RooFit::CodegenContext &ctx, int intOrder, - RooDataHist const *dataHist, const RooArgSet &obs, bool correctForBinSize, bool cdfBoundaries); - - static std::string rooHistIntegralTranslateImpl(int code, RooAbsArg const *klass, RooDataHist const *dataHist, - const RooArgSet &obs, bool histFuncMode); - -private: inline void initializeOwnedDataHist(std::unique_ptr &&dataHist) { _ownedDataHist = std::move(dataHist); diff --git a/roofit/roofitcore/inc/RooMultiVarGaussian.h b/roofit/roofitcore/inc/RooMultiVarGaussian.h index e30c185c9f6f9..4712359c764ee 100644 --- a/roofit/roofitcore/inc/RooMultiVarGaussian.h +++ b/roofit/roofitcore/inc/RooMultiVarGaussian.h @@ -49,6 +49,7 @@ class RooMultiVarGaussian : public RooAbsPdf { void generateEvent(Int_t code) override; const TMatrixDSym& covarianceMatrix() const { return _cov ; } + const TMatrixDSym& covarianceMatrixInverse() const { return _covI ; } const RooArgList& xVec() const { return _x;} const RooArgList& muVec() const { return _mu; } @@ -84,10 +85,6 @@ class RooMultiVarGaussian : public RooAbsPdf { static void blockDecompose(const TMatrixD& input, const std::vector& map1, const std::vector& map2, TMatrixDSym& S11, TMatrixD& S12, TMatrixD& S21, TMatrixDSym& S22) ; - void translate(RooFit::Detail::CodeSquashContext &ctx) const override; - std::string - buildCallToAnalyticIntegral(Int_t code, const char *rangeName, RooFit::Detail::CodeSquashContext &ctx) const override; - protected: void decodeCode(Int_t code, std::vector& map1, std::vector& map2) const; diff --git a/roofit/roofitcore/inc/RooPolyVar.h b/roofit/roofitcore/inc/RooPolyVar.h index 6ea0f1cba15fa..ff3bd3d88c7d0 100644 --- a/roofit/roofitcore/inc/RooPolyVar.h +++ b/roofit/roofitcore/inc/RooPolyVar.h @@ -34,9 +34,9 @@ class RooPolyVar : public RooAbsReal { Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &analVars, const char *rangeName = nullptr) const override; double analyticalIntegral(Int_t code, const char *rangeName = nullptr) const override; - void translate(RooFit::CodegenContext &ctx) const override; - std::string buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::CodegenContext &ctx) const override; + RooRealProxy const &x() const { return _x; } + RooArgList const &coefList() const { return _coefList; } + int lowestOrder() const { return _lowestOrder; } protected: RooRealProxy _x; diff --git a/roofit/roofitcore/inc/RooProdPdf.h b/roofit/roofitcore/inc/RooProdPdf.h index abe8b14f2aa9d..272b9a5cb9410 100644 --- a/roofit/roofitcore/inc/RooProdPdf.h +++ b/roofit/roofitcore/inc/RooProdPdf.h @@ -30,6 +30,12 @@ typedef RooArgList* pRooArgList ; typedef RooLinkedList* pRooLinkedList ; +namespace RooFit { +namespace Detail { +class RooFixedProdPdf; +} +} + class RooProdPdf : public RooAbsPdf { public: @@ -98,6 +104,25 @@ class RooProdPdf : public RooAbsPdf { std::unique_ptr compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext & ctx) const override; + // The cache object. Internal, do not use. + class CacheElem final : public RooAbsCacheElement { + public: + CacheElem() : _isRearranged(false) { } + // Payload + RooArgList _partList ; + RooArgList _numList ; + RooArgList _denList ; + RooArgList _ownedList ; + std::vector> _normList; + bool _isRearranged ; + std::unique_ptr _rearrangedNum{}; + std::unique_ptr _rearrangedDen{}; + // Cache management functions + RooArgList containedArgs(Action) override ; + void printCompactTreeHook(std::ostream&, const char *, Int_t, Int_t) override ; + void writeToStream(std::ostream& os) const ; + } ; + private: std::unique_ptr fillNormSetForServer(RooArgSet const& normSet, RooAbsArg const& server) const; @@ -131,25 +156,6 @@ class RooProdPdf : public RooAbsPdf { CacheMode canNodeBeCached() const override { return RooAbsArg::NotAdvised ; } ; void setCacheAndTrackHints(RooArgSet&) override ; - // The cache object - class CacheElem final : public RooAbsCacheElement { - public: - CacheElem() : _isRearranged(false) { } - // Payload - RooArgList _partList ; - RooArgList _numList ; - RooArgList _denList ; - RooArgList _ownedList ; - std::vector> _normList; - bool _isRearranged ; - std::unique_ptr _rearrangedNum{}; - std::unique_ptr _rearrangedDen{}; - // Cache management functions - RooArgList containedArgs(Action) override ; - void printCompactTreeHook(std::ostream&, const char *, Int_t, Int_t) override ; - void writeToStream(std::ostream& os) const ; - } ; - std::unique_ptr createCacheElem(const RooArgSet* nset, const RooArgSet* iset, const char* isetRangeName=nullptr) const; mutable RooObjCacheManager _cacheMgr ; //! The cache manager @@ -163,7 +169,7 @@ class RooProdPdf : public RooAbsPdf { friend class RooProdGenContext ; - friend class RooFixedProdPdf ; + friend class RooFit::Detail::RooFixedProdPdf ; RooAbsGenContext* genContext(const RooArgSet &vars, const RooDataSet *prototype=nullptr, const RooArgSet *auxProto=nullptr, bool verbose= false) const override ; @@ -190,5 +196,73 @@ class RooProdPdf : public RooAbsPdf { ClassDefOverride(RooProdPdf,6) // PDF representing a product of PDFs }; +namespace RooFit { +namespace Detail { + +/// A RooProdPdf with a fixed normalization set can be replaced by this class. +/// Its purpose is to provide the right client-server interface for the +/// evaluation of RooProdPdf cache elements that were created for a given +/// normalization set. +class RooFixedProdPdf : public RooAbsPdf { +public: + RooFixedProdPdf(std::unique_ptr &&prodPdf, RooArgSet const &normSet); + RooFixedProdPdf(const RooFixedProdPdf &other, const char *name = nullptr); + + inline TObject *clone(const char *newname) const override { return new RooFixedProdPdf(*this, newname); } + + inline bool selfNormalized() const override { return true; } + + inline bool canComputeBatchWithCuda() const override { return true; } + + inline void doEval(RooFit::EvalContext &ctx) const override { _prodPdf->doEvalImpl(this, *_cache, ctx); } + + inline ExtendMode extendMode() const override { return _prodPdf->extendMode(); } + inline double expectedEvents(const RooArgSet * /*nset*/) const override + { + return _prodPdf->expectedEvents(&_normSet); + } + inline std::unique_ptr createExpectedEventsFunc(const RooArgSet * /*nset*/) const override + { + return _prodPdf->createExpectedEventsFunc(&_normSet); + } + + // Analytical Integration handling + inline bool forceAnalyticalInt(const RooAbsArg &dep) const override { return _prodPdf->forceAnalyticalInt(dep); } + inline Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &analVars, const RooArgSet *normSet, + const char *rangeName = nullptr) const override + { + return _prodPdf->getAnalyticalIntegralWN(allVars, analVars, normSet, rangeName); + } + inline Int_t + getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &numVars, const char *rangeName = nullptr) const override + { + return _prodPdf->getAnalyticalIntegral(allVars, numVars, rangeName); + } + inline double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName) const override + { + return _prodPdf->analyticalIntegralWN(code, normSet, rangeName); + } + inline double analyticalIntegral(Int_t code, const char *rangeName = nullptr) const override + { + return _prodPdf->analyticalIntegral(code, rangeName); + } + + RooProdPdf::CacheElem const &cache() const { return *_cache; } + +private: + void initialize(); + + inline double evaluate() const override { return _prodPdf->calculate(*_cache); } + + RooArgSet _normSet; + std::unique_ptr _cache; + RooSetProxy _servers; + std::unique_ptr _prodPdf; + + ClassDefOverride(RooFit::Detail::RooFixedProdPdf, 0); +}; + +} // namespace Detail +} // namespace RooFit #endif diff --git a/roofit/roofitcore/inc/RooProduct.h b/roofit/roofitcore/inc/RooProduct.h index fcb2d0977f0b1..8f5e9700d90ec 100644 --- a/roofit/roofitcore/inc/RooProduct.h +++ b/roofit/roofitcore/inc/RooProduct.h @@ -63,7 +63,6 @@ class RooProduct : public RooAbsReal { CacheMode canNodeBeCached() const override { return RooAbsArg::NotAdvised ; } ; void setCacheAndTrackHints(RooArgSet&) override ; - void translate(RooFit::CodegenContext &ctx) const override; protected: void ioStreamerPass2() override ; diff --git a/roofit/roofitcore/inc/RooRatio.h b/roofit/roofitcore/inc/RooRatio.h index 0e24a8d0347e7..fd8bf7bdc124d 100644 --- a/roofit/roofitcore/inc/RooRatio.h +++ b/roofit/roofitcore/inc/RooRatio.h @@ -31,13 +31,14 @@ class RooRatio : public RooAbsReal { TObject *clone(const char *newname) const override { return new RooRatio(*this, newname); } ~RooRatio() override; + RooAbsReal const &numerator() const { return *_numerator; } + RooAbsReal const &denominator() const { return *_denominator; } + protected: double evaluate() const override; void doEval(RooFit::EvalContext &) const override; inline bool canComputeBatchWithCuda() const override { return true; } - void translate(RooFit::CodegenContext &ctx) const override; - RooRealProxy _numerator; RooRealProxy _denominator; diff --git a/roofit/roofitcore/inc/RooRealIntegral.h b/roofit/roofitcore/inc/RooRealIntegral.h index 40a0624d75b46..d28d2047cf64a 100644 --- a/roofit/roofitcore/inc/RooRealIntegral.h +++ b/roofit/roofitcore/inc/RooRealIntegral.h @@ -78,10 +78,10 @@ class RooRealIntegral : public RooAbsReal { std::unique_ptr compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext & ctx) const override; - void translate(RooFit::CodegenContext &ctx) const override; - inline RooArgSet const* funcNormSet() const { return _funcNormSet.get(); } + int mode() const { return _mode; } + protected: mutable bool _valid = false; diff --git a/roofit/roofitcore/inc/RooRealSumFunc.h b/roofit/roofitcore/inc/RooRealSumFunc.h index 0f3f55fa51ca2..9f8cef5afd50e 100644 --- a/roofit/roofitcore/inc/RooRealSumFunc.h +++ b/roofit/roofitcore/inc/RooRealSumFunc.h @@ -60,8 +60,6 @@ class RooRealSumFunc : public RooAbsReal { std::unique_ptr compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext & ctx) const override; - void translate(RooFit::CodegenContext &ctx) const override; - protected: mutable RooObjCacheManager _normIntMgr; //! The integration cache manager diff --git a/roofit/roofitcore/inc/RooRealSumPdf.h b/roofit/roofitcore/inc/RooRealSumPdf.h index 4dee397a8a005..4c913c47e4588 100644 --- a/roofit/roofitcore/inc/RooRealSumPdf.h +++ b/roofit/roofitcore/inc/RooRealSumPdf.h @@ -71,8 +71,6 @@ class RooRealSumPdf : public RooAbsPdf { std::unique_ptr createExpectedEventsFunc(const RooArgSet* nset) const override; - void translate(RooFit::CodegenContext &ctx) const override; - protected: class CacheElem : public RooAbsCacheElement { @@ -109,9 +107,6 @@ class RooRealSumPdf : public RooAbsPdf { bool doFloor, bool & hasWarnedBefore); - static std::string translateImpl(RooFit::CodegenContext &ctx, RooAbsArg const *klass, - RooArgList const &funcList, RooArgList const &coefList, bool normalize=false); - static bool checkObservables(RooAbsReal const &caller, RooArgSet const *nset, RooArgList const &funcList, RooArgList const &coefList); diff --git a/roofit/roofitcore/inc/RooRealVar.h b/roofit/roofitcore/inc/RooRealVar.h index f2ff2af1dfe3c..73cea994065fc 100644 --- a/roofit/roofitcore/inc/RooRealVar.h +++ b/roofit/roofitcore/inc/RooRealVar.h @@ -132,8 +132,6 @@ class RooRealVar : public RooAbsRealLValue { static void cleanup() ; - void translate(RooFit::CodegenContext &ctx) const override; - protected: static bool _printScientific ; diff --git a/roofit/roofitcore/inc/RooRecursiveFraction.h b/roofit/roofitcore/inc/RooRecursiveFraction.h index bff61f7880869..c4f4592e2b88a 100644 --- a/roofit/roofitcore/inc/RooRecursiveFraction.h +++ b/roofit/roofitcore/inc/RooRecursiveFraction.h @@ -19,9 +19,6 @@ #include "RooAbsReal.h" #include "RooListProxy.h" -class RooRealVar; -class RooArgList ; - class RooRecursiveFraction : public RooAbsReal { public: @@ -31,7 +28,7 @@ class RooRecursiveFraction : public RooAbsReal { RooRecursiveFraction(const RooRecursiveFraction& other, const char *name = nullptr); TObject* clone(const char* newname) const override { return new RooRecursiveFraction(*this, newname); } - void translate(RooFit::CodegenContext &ctx) const override; + RooArgList const &variables() const { return _list; } protected: diff --git a/roofit/roofitcore/src/BatchModeDataHelpers.cxx b/roofit/roofitcore/src/BatchModeDataHelpers.cxx index 274d084b049f4..180ca3cc68f81 100644 --- a/roofit/roofitcore/src/BatchModeDataHelpers.cxx +++ b/roofit/roofitcore/src/BatchModeDataHelpers.cxx @@ -19,7 +19,7 @@ #include #include "RooFitImplHelpers.h" -#include "RooNLLVarNew.h" +#include "RooFit/Detail/RooNLLVarNew.h" #include @@ -93,8 +93,8 @@ getSingleDataSpans(RooAbsData const &data, std::string_view rangeName, std::stri assignSpan(weight, {buffer.data(), nNonZeroWeight}); assignSpan(weightSumW2, {bufferSumW2.data(), nNonZeroWeight}); } - insert(RooNLLVarNew::weightVarName, weight); - insert(RooNLLVarNew::weightVarNameSumW2, weightSumW2); + insert(RooFit::Detail::RooNLLVarNew::weightVarName, weight); + insert(RooFit::Detail::RooNLLVarNew::weightVarNameSumW2, weightSumW2); } // Get the real-valued batches and cast the also to double branches to put in diff --git a/roofit/roofitcore/src/FitHelpers.cxx b/roofit/roofitcore/src/FitHelpers.cxx index 97bfeefe975bf..8e5b45ac0c86f 100644 --- a/roofit/roofitcore/src/FitHelpers.cxx +++ b/roofit/roofitcore/src/FitHelpers.cxx @@ -42,7 +42,7 @@ #include "ConstraintHelpers.h" #include "RooEvaluatorWrapper.h" #include "RooFitImplHelpers.h" -#include "RooNLLVarNew.h" +#include "RooFit/Detail/RooNLLVarNew.h" #ifdef ROOFIT_LEGACY_EVAL_BACKEND #include "RooChi2Var.h" @@ -50,6 +50,8 @@ #include "RooXYChi2Var.h" #endif +using RooFit::Detail::RooNLLVarNew; + namespace { constexpr int extendedFitDefault = 2; diff --git a/roofit/roofitcore/src/RooAbsAnaConvPdf.cxx b/roofit/roofitcore/src/RooAbsAnaConvPdf.cxx index 3d1b3fd16d209..fce6647ff30e1 100644 --- a/roofit/roofitcore/src/RooAbsAnaConvPdf.cxx +++ b/roofit/roofitcore/src/RooAbsAnaConvPdf.cxx @@ -62,7 +62,7 @@ #include "RooAbsAnaConvPdf.h" -#include "RooNormalizedPdf.h" +#include "RooFit/Detail/RooNormalizedPdf.h" #include "RooMsgService.h" #include "Riostream.h" #include "RooResolutionModel.h" @@ -677,7 +677,7 @@ RooAbsAnaConvPdf::compileForNormSet(RooArgSet const &normSet, RooFit::Detail::Co std::unique_ptr pdfClone(static_cast(_convSet[0].Clone())); ctx.compileServers(*pdfClone, normSet); - auto newArg = std::make_unique(*pdfClone, normSet); + auto newArg = std::make_unique(*pdfClone, normSet); // The direct servers are this pdf and the normalization integral, which // don't need to be compiled further. @@ -717,7 +717,7 @@ RooAbsAnaConvPdf::compileForNormSet(RooArgSet const &normSet, RooFit::Detail::Co ctx.compileServers(*pdfClone, normSet); // Finally, this RooAbsAnaConvPdf needs to be normalized - auto newArg = std::make_unique(*pdfClone, normSet); + auto newArg = std::make_unique(*pdfClone, normSet); // The direct servers are this pdf and the normalization integral, which // don't need to be compiled further. diff --git a/roofit/roofitcore/src/RooAbsArg.cxx b/roofit/roofitcore/src/RooAbsArg.cxx index e07b94105d257..e3ba07d9b8c1b 100644 --- a/roofit/roofitcore/src/RooAbsArg.cxx +++ b/roofit/roofitcore/src/RooAbsArg.cxx @@ -2515,23 +2515,6 @@ std::unique_ptr RooAbsArg::compileForNormSet(RooArgSet const & normSe } -//////////////////////////////////////////////////////////////////////////////// -/// This function defines a translation for each RooAbsReal based object that can be used -/// to express the class as simple C++ code. The function adds the code represented by -/// each class as an std::string (that is later concatenated with code strings from translate calls) -/// to form the C++ code that AD tools can understand. Any class that wants to support AD, has to -/// implement this function. -/// -/// \param[in] ctx An object to manage auxiliary information for code-squashing. Also takes the -/// code string that this class outputs into the squashed code through the 'addToCodeBody' function. -void RooAbsArg::translate(RooFit::CodegenContext & /*ctx*/) const -{ - std::stringstream errorMsg; - errorMsg << "Translate function for class \"" << ClassName() << "\" has not yet been implemented."; - coutE(Minimization) << errorMsg.str() << std::endl; - throw std::runtime_error(errorMsg.str().c_str()); -} - /// Sets the token for retrieving results in the BatchMode. For internal use only. void RooAbsArg::setDataToken(std::size_t index) { diff --git a/roofit/roofitcore/src/RooAbsCachedPdf.cxx b/roofit/roofitcore/src/RooAbsCachedPdf.cxx index 66e40bd792f4a..f462298fc72f8 100644 --- a/roofit/roofitcore/src/RooAbsCachedPdf.cxx +++ b/roofit/roofitcore/src/RooAbsCachedPdf.cxx @@ -33,7 +33,7 @@ for changes to trigger a refilling of the cache histogram. #include "RooDataHist.h" #include "RooHistPdf.h" #include "RooExpensiveObjectCache.h" -#include "RooNormalizedPdf.h" +#include "RooFit/Detail/RooNormalizedPdf.h" ClassImp(RooAbsCachedPdf); @@ -415,7 +415,7 @@ RooAbsCachedPdf::compileForNormSet(RooArgSet const &normSet, RooFit::Detail::Com std::unique_ptr pdfClone(static_cast(this->Clone())); ctx.compileServers(*pdfClone, {}); - auto newArg = std::make_unique(*pdfClone, normSet); + auto newArg = std::make_unique(*pdfClone, normSet); // The direct servers are this pdf and the normalization integral, which // don't need to be compiled further. diff --git a/roofit/roofitcore/src/RooAbsPdf.cxx b/roofit/roofitcore/src/RooAbsPdf.cxx index bd5b77c57fc30..46e4eadf1c423 100644 --- a/roofit/roofitcore/src/RooAbsPdf.cxx +++ b/roofit/roofitcore/src/RooAbsPdf.cxx @@ -138,7 +138,7 @@ called for each data event. #include "RooAbsPdf.h" #include "FitHelpers.h" -#include "RooNormalizedPdf.h" +#include "RooFit/Detail/RooNormalizedPdf.h" #include "RooMsgService.h" #include "RooArgSet.h" #include "RooArgProxy.h" @@ -2793,7 +2793,7 @@ RooAbsPdf::compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileCo std::unique_ptr pdfClone(static_cast(this->Clone())); ctx.compileServers(*pdfClone, normSet); - auto newArg = std::make_unique(*pdfClone, normSet); + auto newArg = std::make_unique(*pdfClone, normSet); // The direct servers are this pdf and the normalization integral, which // don't need to be compiled further. diff --git a/roofit/roofitcore/src/RooAbsReal.cxx b/roofit/roofitcore/src/RooAbsReal.cxx index 2f532a3b9c5cf..f1bb7c1db4a7d 100644 --- a/roofit/roofitcore/src/RooAbsReal.cxx +++ b/roofit/roofitcore/src/RooAbsReal.cxx @@ -4414,23 +4414,6 @@ void RooAbsReal::doEval(RooFit::EvalContext & ctx) const } } -//////////////////////////////////////////////////////////////////////////////// -/// This function defines the analytical integral translation for the class. -/// -/// \param[in] code The code that decides the integrands. -/// \param[in] rangeName Name of the normalization range. -/// \param[in] ctx An object to manage auxiliary information for code-squashing. -/// -/// \returns The representative code string of the integral for the given object. -std::string RooAbsReal::buildCallToAnalyticIntegral(Int_t /* code */, const char * /* rangeName */, - RooFit::CodegenContext & /*ctx*/) const -{ - std::stringstream errorMsg; - errorMsg << "An analytical integral function for class \"" << ClassName() << "\" has not yet been implemented."; - coutE(Minimization) << errorMsg.str() << std::endl; - throw std::runtime_error(errorMsg.str().c_str()); -} - double RooAbsReal::_DEBUG_getVal(const RooArgSet* normalisationSet) const { const bool tmpFast = _fast; diff --git a/roofit/roofitcore/src/RooAddPdf.cxx b/roofit/roofitcore/src/RooAddPdf.cxx index d89559831beda..9773b8185e3c8 100644 --- a/roofit/roofitcore/src/RooAddPdf.cxx +++ b/roofit/roofitcore/src/RooAddPdf.cxx @@ -545,11 +545,6 @@ double RooAddPdf::getValV(const RooArgSet* normSet) const return _value; } -void RooAddPdf::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, RooRealSumPdf::translateImpl(ctx, this, _pdfList, _coefList, true)); -} - //////////////////////////////////////////////////////////////////////////////// /// Compute addition of PDFs in batches. void RooAddPdf::doEval(RooFit::EvalContext & ctx) const diff --git a/roofit/roofitcore/src/RooAddition.cxx b/roofit/roofitcore/src/RooAddition.cxx index b28d0c55151fc..0f6e61d2de176 100644 --- a/roofit/roofitcore/src/RooAddition.cxx +++ b/roofit/roofitcore/src/RooAddition.cxx @@ -33,7 +33,7 @@ in the two sets. #include "RooErrorHandler.h" #include "RooArgSet.h" #include "RooNameReg.h" -#include "RooNLLVarNew.h" +#include "RooFit/Detail/RooNLLVarNew.h" #include "RooMsgService.h" #include "RooBatchCompute.h" @@ -154,35 +154,6 @@ void RooAddition::doEval(RooFit::EvalContext &ctx) const RooBatchCompute::compute(ctx.config(this), RooBatchCompute::AddPdf, ctx.output(), pdfs, coefs); } -//////////////////////////////////////////////////////////////////////////////// - -void RooAddition::translate(RooFit::CodegenContext &ctx) const -{ - if (_set.empty()) { - ctx.addResult(this, "0.0"); - } - std::string result; - if (_set.size() > 1) - result += "("; - - std::size_t i = 0; - for (auto *component : static_range_cast(_set)) { - - if (!dynamic_cast(component) || _set.size() == 1) { - result += ctx.getResult(*component); - ++i; - if (i < _set.size()) result += '+'; - continue; - } - result += ctx.buildFunction(*component, ctx.outputSizes()) + "(params, obs, xlArr)"; - ++i; - if (i < _set.size()) result += '+'; - } - if (_set.size() > 1) - result += ')'; - ctx.addResult(this, result); -} - //////////////////////////////////////////////////////////////////////////////// /// Return the default error level for MINUIT error analysis /// If the addition contains one or more RooNLLVars and @@ -199,7 +170,7 @@ double RooAddition::defaultErrorLevel() const std::unique_ptr comps{getComponents()}; for(RooAbsArg * arg : *comps) { - if (dynamic_cast(arg)) { + if (dynamic_cast(arg)) { nllArg = static_cast(arg) ; } #ifdef ROOFIT_LEGACY_EVAL_BACKEND diff --git a/roofit/roofitcore/src/RooClassFactory.cxx b/roofit/roofitcore/src/RooClassFactory.cxx index 8db3a94dcdeff..a6fd99cea777e 100644 --- a/roofit/roofitcore/src/RooClassFactory.cxx +++ b/roofit/roofitcore/src/RooClassFactory.cxx @@ -506,8 +506,7 @@ class CLASS_NAME : public BASE_NAME { CLASS_NAME(const char *name, const char *title,)"; // Insert list of input arguments - unsigned int i ; - for (i=0 ; i::digits10 + 1}; - std::stringstream ss; - ss.precision(max_precision); - // Just use toString to make sure we do not output 'inf'. - // This is really ugly for large numbers... - ss << std::fixed << RooNumber::toString(_value); - ctx.addResult(this, ss.str()); -} diff --git a/roofit/roofitcore/src/RooConstraintSum.cxx b/roofit/roofitcore/src/RooConstraintSum.cxx index f464812ba49ba..3401c694d3115 100644 --- a/roofit/roofitcore/src/RooConstraintSum.cxx +++ b/roofit/roofitcore/src/RooConstraintSum.cxx @@ -79,11 +79,6 @@ double RooConstraintSum::evaluate() const return sum; } -void RooConstraintSum::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::constraintSum", _set1, _set1.size())); -} - void RooConstraintSum::doEval(RooFit::EvalContext &ctx) const { double sum(0); diff --git a/roofit/roofitcore/src/RooEffProd.cxx b/roofit/roofitcore/src/RooEffProd.cxx index 4d3cf88e2aa11..44b6acd916289 100644 --- a/roofit/roofitcore/src/RooEffProd.cxx +++ b/roofit/roofitcore/src/RooEffProd.cxx @@ -71,8 +71,3 @@ RooAbsGenContext* RooEffProd::genContext(const RooArgSet &vars, const RooDataSet static_cast(_eff.arg()), vars,prototype,auxProto,verbose) ; } - -void RooEffProd::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::effProd", _eff, _pdf)); -} diff --git a/roofit/roofitcore/src/RooEfficiency.cxx b/roofit/roofitcore/src/RooEfficiency.cxx index 1ca1ff9928fc4..05f2e9f5e598c 100644 --- a/roofit/roofitcore/src/RooEfficiency.cxx +++ b/roofit/roofitcore/src/RooEfficiency.cxx @@ -86,15 +86,3 @@ double RooEfficiency::analyticalIntegral(int /*code*/, const char * /*rangeName* { return 1.0; } - -void RooEfficiency::translate(RooFit::CodegenContext &ctx) const -{ - int sigCatIndex = _cat->lookupIndex(_sigCatName.Data()); - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::efficiency", _effFunc, _cat, sigCatIndex)); -} - -std::string RooEfficiency::buildCallToAnalyticIntegral(int /*code*/, const char * /*rangeName*/, - RooFit::CodegenContext &) const -{ - return "1.0"; -} diff --git a/roofit/roofitcore/src/RooExtendPdf.cxx b/roofit/roofitcore/src/RooExtendPdf.cxx index e12529fdb8080..55f347675592e 100644 --- a/roofit/roofitcore/src/RooExtendPdf.cxx +++ b/roofit/roofitcore/src/RooExtendPdf.cxx @@ -172,10 +172,3 @@ std::unique_ptr RooExtendPdf::createExpectedEventsFunc(const RooArgS } return out; } - - -void RooExtendPdf::translate(RooFit::CodegenContext &ctx) const -{ - // Use the result of the underlying pdf. - ctx.addResult(this, ctx.getResult(_pdf)); -} diff --git a/roofit/roofitcore/src/RooFit/CodegenContext.cxx b/roofit/roofitcore/src/RooFit/CodegenContext.cxx index ccbe801b17f17..44238a5b0ff2e 100644 --- a/roofit/roofitcore/src/RooFit/CodegenContext.cxx +++ b/roofit/roofitcore/src/RooFit/CodegenContext.cxx @@ -19,6 +19,8 @@ #include #include +#include +#include namespace { @@ -27,7 +29,7 @@ bool startsWith(std::string_view str, std::string_view prefix) return str.size() >= prefix.size() && 0 == str.compare(0, prefix.size(), prefix); } -} +} // namespace namespace RooFit { @@ -71,7 +73,7 @@ std::string const &CodegenContext::getResult(RooAbsArg const &arg) } // Now, recursively call translate into the current argument to load the correct result. - arg.translate(*this); + RooFit::codegen(const_cast(arg), *this); return _nodeNames.at(arg.namePtr()); } @@ -268,13 +270,14 @@ void CodegenContext::collectFunction(std::string const &name) /// @brief Assemble and return the final code with the return expression and global statements. /// @param returnExpr The string representation of what the squashed function should return, usually the head node. /// @return The name of the declared function. -std::string CodegenContext::buildFunction(RooAbsArg const &arg, std::map const &outputSizes) +std::string +CodegenContext::buildFunction(RooAbsArg const &arg, std::map const &outputSizes) { CodegenContext ctx; ctx._nodeOutputSizes = outputSizes; ctx._vecObsIndices = _vecObsIndices; // We only want to take over parameters and observables - for (auto const& item : _nodeNames) { + for (auto const &item : _nodeNames) { if (startsWith(item.second, "params[") || startsWith(item.second, "obs[")) { ctx._nodeNames.insert(item); } @@ -306,4 +309,30 @@ std::string CodegenContext::buildFunction(RooAbsArg const &arg, std::map dispatchMap; + + auto found = dispatchMap.find(tclass); + + if (found != dispatchMap.end()) { + func = found->second; + } else { + // Can probably done with CppInterop in the future to avoid string manipulation. + std::stringstream cmd; + cmd << "&RooFit::CodegenImplCaller<" << tclass->GetName() << ">::call;"; + func = reinterpret_cast(gInterpreter->ProcessLine(cmd.str().c_str())); + dispatchMap[tclass] = func; + } + + return func(arg, ctx); +} + } // namespace RooFit diff --git a/roofit/roofitcore/src/RooFormulaVar.cxx b/roofit/roofitcore/src/RooFormulaVar.cxx index 786b7a6598e94..0a4d98d372d09 100644 --- a/roofit/roofitcore/src/RooFormulaVar.cxx +++ b/roofit/roofitcore/src/RooFormulaVar.cxx @@ -313,10 +313,7 @@ double RooFormulaVar::defaultErrorLevel() const return 1.0 ; } -void RooFormulaVar::translate(RooFit::CodegenContext &ctx) const +std::string RooFormulaVar::getUniqueFuncName() const { - getVal(); // to trigger the creation of the TFormula - std::string funcName = _formula->getTFormula()->GetUniqueFuncName().Data(); - ctx.collectFunction(funcName); - ctx.addResult(this, ctx.buildCall(funcName, _actualVars)); + return getFormula().getTFormula()->GetUniqueFuncName().Data(); } diff --git a/roofit/roofitcore/src/RooGenericPdf.cxx b/roofit/roofitcore/src/RooGenericPdf.cxx index d515c53c3bea4..33679d015b945 100644 --- a/roofit/roofitcore/src/RooGenericPdf.cxx +++ b/roofit/roofitcore/src/RooGenericPdf.cxx @@ -202,10 +202,7 @@ void RooGenericPdf::writeToStream(ostream& os, bool compact) const } } -void RooGenericPdf::translate(RooFit::CodegenContext &ctx) const +std::string RooGenericPdf::getUniqueFuncName() const { - getVal(); // to trigger the creation of the TFormula - std::string funcName = _formula->getTFormula()->GetUniqueFuncName().Data(); - ctx.collectFunction(funcName); - ctx.addResult(this, ctx.buildCall(funcName, _actualVars)); + return formula().getTFormula()->GetUniqueFuncName().Data(); } diff --git a/roofit/roofitcore/src/RooHistFunc.cxx b/roofit/roofitcore/src/RooHistFunc.cxx index 586cb4ea4de6a..108d0f53dab96 100644 --- a/roofit/roofitcore/src/RooHistFunc.cxx +++ b/roofit/roofitcore/src/RooHistFunc.cxx @@ -190,11 +190,6 @@ double RooHistFunc::evaluate() const return ret ; } -void RooHistFunc::translate(RooFit::CodegenContext &ctx) const -{ - RooHistPdf::rooHistTranslateImpl(this, ctx, _intOrder, _dataHist, _depList, false, _cdfBoundaries); -} - void RooHistFunc::doEval(RooFit::EvalContext & ctx) const { std::span output = ctx.output(); @@ -322,12 +317,6 @@ bool RooHistFunc::forceAnalyticalInt(const RooAbsArg& dep) const return RooHistPdf::forceAnalyticalInt(_depList, dep); } -std::string RooHistFunc::buildCallToAnalyticIntegral(int code, const char * /* rangeName */, - RooFit::CodegenContext & /* ctx */) const -{ - return RooHistPdf::rooHistIntegralTranslateImpl(code, this, _dataHist, _depList, true); -} - //////////////////////////////////////////////////////////////////////////////// /// Return sampling hint for making curves of (projections) of this function /// as the recursive division strategy of RooCurve cannot deal efficiently diff --git a/roofit/roofitcore/src/RooHistPdf.cxx b/roofit/roofitcore/src/RooHistPdf.cxx index 4726b11f98ad3..ee0c2a81b3d15 100644 --- a/roofit/roofitcore/src/RooHistPdf.cxx +++ b/roofit/roofitcore/src/RooHistPdf.cxx @@ -222,34 +222,6 @@ double RooHistPdf::evaluate() const return std::max(ret, 0.0); } -void RooHistPdf::rooHistTranslateImpl(RooAbsArg const *klass, RooFit::CodegenContext &ctx, int intOrder, - RooDataHist const *dataHist, const RooArgSet &obs, bool correctForBinSize, - bool cdfBoundaries) -{ - if (intOrder != 0 && !(!cdfBoundaries && !correctForBinSize && intOrder == 1 && obs.size() == 1)) { - ooccoutE(klass, InputArguments) << "RooHistPdf::weight(" << klass->GetName() - << ") ERROR: Code Squashing currently only supports non-interpolation cases." - << std::endl; - return; - } - - if (intOrder == 1) { - RooAbsBinning const &binning = *dataHist->getBinnings()[0]; - std::string weightArr = dataHist->declWeightArrayForCodeSquash(ctx, correctForBinSize); - ctx.addResult(klass, ctx.buildCall("RooFit::Detail::MathFuncs::interpolate1d", binning.lowBound(), - binning.highBound(), *obs[0], binning.numBins(), weightArr)); - return; - } - std::string const &offset = dataHist->calculateTreeIndexForCodeSquash(klass, ctx, obs); - std::string weightArr = dataHist->declWeightArrayForCodeSquash(ctx, correctForBinSize); - ctx.addResult(klass, "*(" + weightArr + " + " + offset + ")"); -} - -void RooHistPdf::translate(RooFit::CodegenContext &ctx) const -{ - rooHistTranslateImpl(this, ctx, _intOrder, _dataHist, _pdfObsList, !_unitNorm, _cdfBoundaries); -} - //////////////////////////////////////////////////////////////////////////////// /// Return the total volume spanned by the observables of the RooHistPdf @@ -395,24 +367,6 @@ double RooHistPdf::analyticalIntegral(Int_t code, return ret ; } -std::string RooHistPdf::rooHistIntegralTranslateImpl(int code, RooAbsArg const *klass, RooDataHist const *dataHist, - const RooArgSet &obs, bool histFuncMode) -{ - if (((2 << obs.size()) - 1) != code) { - oocoutE(klass, InputArguments) - << "RooHistPdf::integral(" << klass->GetName() - << ") ERROR: AD currently only supports integrating over all histogram observables." << std::endl; - return ""; - } - return std::to_string(dataHist->sum(histFuncMode)); -} - -std::string RooHistPdf::buildCallToAnalyticIntegral(int code, const char * /*rangeName */, - RooFit::CodegenContext & /* ctx */) const -{ - return rooHistIntegralTranslateImpl(code, this, _dataHist, _pdfObsList, false); -} - //////////////////////////////////////////////////////////////////////////////// /// Determine integration scenario. If no interpolation is used, /// RooHistPdf can perform all integrals over its dependents diff --git a/roofit/roofitcore/src/RooMultiVarGaussian.cxx b/roofit/roofitcore/src/RooMultiVarGaussian.cxx index 8c66cada01437..f760968ddfa03 100644 --- a/roofit/roofitcore/src/RooMultiVarGaussian.cxx +++ b/roofit/roofitcore/src/RooMultiVarGaussian.cxx @@ -187,12 +187,6 @@ double RooMultiVarGaussian::evaluate() const return exp(-0.5*alpha) ; } -void RooMultiVarGaussian::translate(RooFit::Detail::CodeSquashContext &ctx) const -{ - std::span covISpan{_covI.GetMatrixArray(), static_cast(_covI.GetNoElements())}; - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::multiVarGaussian", _x.size(), _x, _mu, covISpan)); -} - //////////////////////////////////////////////////////////////////////////////// Int_t RooMultiVarGaussian::getAnalyticalIntegral(RooArgSet& allVarsIn, RooArgSet& analVars, const char* rangeName) const @@ -314,20 +308,6 @@ double RooMultiVarGaussian::analyticalIntegral(Int_t code, const char* /*rangeNa } -std::string RooMultiVarGaussian::buildCallToAnalyticIntegral(Int_t code, const char *rangeName, - RooFit::Detail::CodeSquashContext & /*ctx*/) const -{ - if (code != -1) { - std::stringstream errorMsg; - errorMsg << "Partial integrals over RooMultiVarGaussian are not supported."; - coutE(Minimization) << errorMsg.str() << std::endl; - throw std::runtime_error(errorMsg.str().c_str()); - } - - return std::to_string(analyticalIntegral(code, rangeName)); -} - - //////////////////////////////////////////////////////////////////////////////// /// Check if cache entry was previously created diff --git a/roofit/roofitcore/src/RooNLLVarNew.cxx b/roofit/roofitcore/src/RooNLLVarNew.cxx index 58319804ea71f..f5edc2205fb17 100644 --- a/roofit/roofitcore/src/RooNLLVarNew.cxx +++ b/roofit/roofitcore/src/RooNLLVarNew.cxx @@ -23,7 +23,7 @@ This class calls functions from `RooBatchCompute` library to provide faster computation times. **/ -#include "RooNLLVarNew.h" +#include "RooFit/Detail/RooNLLVarNew.h" #include #include @@ -46,6 +46,11 @@ computation times. #include #include +ClassImp(RooFit::Detail::RooNLLVarNew); + +namespace RooFit { +namespace Detail { + // Declare constexpr static members to make them available if odr-used in C++14. constexpr const char *RooNLLVarNew::weightVarName; constexpr const char *RooNLLVarNew::weightVarNameSumW2; @@ -331,46 +336,7 @@ void RooNLLVarNew::finalizeResult(RooFit::EvalContext &ctx, ROOT::Math::KahanSum ctx.setOutputWithOffset(this, result, _offset); } -void RooNLLVarNew::translate(RooFit::CodegenContext &ctx) const -{ - if (_binnedL && !_pdf->getAttribute("BinnedLikelihoodActiveYields")) { - std::stringstream errorMsg; - errorMsg << "RooNLLVarNew::translate(): binned likelihood optimization is only supported when raw pdf " - "values can be interpreted as yields." - << " This is not the case for HistFactory models written with ROOT versions before 6.26.00"; - coutE(InputArguments) << errorMsg.str() << std::endl; - throw std::runtime_error(errorMsg.str()); - } - - std::string weightSumName = RooFit::Detail::makeValidVarName(GetName()) + "WeightSum"; - std::string resName = RooFit::Detail::makeValidVarName(GetName()) + "Result"; - ctx.addResult(this, resName); - ctx.addToGlobalScope("double " + weightSumName + " = 0.0;\n"); - ctx.addToGlobalScope("double " + resName + " = 0.0;\n"); - - const bool needWeightSum = _expectedEvents || _simCount > 1; - - if (needWeightSum) { - auto scope = ctx.beginLoop(this); - ctx.addToCodeBody(weightSumName + " += " + ctx.getResult(*_weightVar) + ";\n"); - } - if (_simCount > 1) { - std::string simCountStr = std::to_string(static_cast(_simCount)); - ctx.addToCodeBody(resName + " += " + weightSumName + " * std::log(" + simCountStr + ");\n"); - } - - // Begin loop scope for the observables and weight variable. If the weight - // is a scalar, the context will ignore it for the loop scope. The closing - // brackets of the loop is written at the end of the scopes lifetime. - { - auto scope = ctx.beginLoop(this); - std::string term = ctx.buildCall("RooFit::Detail::MathFuncs::nll", _pdf, _weightVar, _binnedL, 0); - ctx.addToCodeBody(this, resName + " += " + term + ";"); - } - if (_expectedEvents) { - std::string expected = ctx.getResult(**_expectedEvents); - ctx.addToCodeBody(resName + " += " + expected + " - " + weightSumName + " * std::log(" + expected + ");\n"); - } -} +} // namespace Detail +} // namespace RooFit /// \endcond diff --git a/roofit/roofitcore/src/RooNormalizedPdf.cxx b/roofit/roofitcore/src/RooNormalizedPdf.cxx index 4c23fe3e7531d..a2db2b8477fd2 100644 --- a/roofit/roofitcore/src/RooNormalizedPdf.cxx +++ b/roofit/roofitcore/src/RooNormalizedPdf.cxx @@ -10,11 +10,14 @@ * listed in LICENSE (http://roofit.sourceforge.net/license.txt) */ -#include "RooNormalizedPdf.h" +#include "RooFit/Detail/RooNormalizedPdf.h" + #include "RooBatchCompute.h" #include +ClassImp(RooFit::Detail::RooNormalizedPdf); + /** * \class RooNormalizedPdf * @@ -22,6 +25,9 @@ * normalization set into a new self-normalized pdf. */ +namespace RooFit { +namespace Detail { + void RooNormalizedPdf::doEval(RooFit::EvalContext &ctx) const { auto nums = ctx.at(_pdf); @@ -48,8 +54,5 @@ void RooNormalizedPdf::doEval(RooFit::EvalContext &ctx) const } } -void RooNormalizedPdf::translate(RooFit::CodegenContext &ctx) const -{ - // For now just return function/normalization integral. - ctx.addResult(this, ctx.getResult(_pdf) + "/" + ctx.getResult(_normIntegral)); -} +} // namespace Detail +} // namespace RooFit diff --git a/roofit/roofitcore/src/RooPolyVar.cxx b/roofit/roofitcore/src/RooPolyVar.cxx index 13a75e2742d88..e2dc18fcd5bc7 100644 --- a/roofit/roofitcore/src/RooPolyVar.cxx +++ b/roofit/roofitcore/src/RooPolyVar.cxx @@ -112,17 +112,6 @@ double RooPolyVar::evaluate() const return RooFit::Detail::MathFuncs::polynomial(_wksp.data(), sz, _lowestOrder, _x); } -void RooPolyVar::translate(RooFit::CodegenContext &ctx) const -{ - const unsigned sz = _coefList.size(); - if (!sz) { - ctx.addResult(this, std::to_string((_lowestOrder ? 1. : 0.))); - return; - } - - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::polynomial", _coefList, sz, _lowestOrder, _x)); -} - void RooPolyVar::doEvalImpl(RooAbsArg const *caller, RooFit::EvalContext &ctx, RooAbsReal const &x, RooArgList const &coefs, int lowestOrder) { @@ -187,15 +176,3 @@ double RooPolyVar::analyticalIntegral(Int_t code, const char *rangeName) const return RooFit::Detail::MathFuncs::polynomialIntegral(_wksp.data(), sz, _lowestOrder, xmin, xmax); } - -std::string RooPolyVar::buildCallToAnalyticIntegral(Int_t /* code */, const char *rangeName, - RooFit::CodegenContext &ctx) const -{ - const double xmin = _x.min(rangeName); - const double xmax = _x.max(rangeName); - const unsigned sz = _coefList.size(); - if (!sz) - return std::to_string(_lowestOrder ? xmax - xmin : 0.0); - - return ctx.buildCall("RooFit::Detail::MathFuncs::polynomialIntegral", _coefList, sz, _lowestOrder, xmin, xmax); -} diff --git a/roofit/roofitcore/src/RooProdPdf.cxx b/roofit/roofitcore/src/RooProdPdf.cxx index a7071860f8fc2..e9ddd0e1e6654 100644 --- a/roofit/roofitcore/src/RooProdPdf.cxx +++ b/roofit/roofitcore/src/RooProdPdf.cxx @@ -73,6 +73,7 @@ have to appear in any specific place in the list. using std::endl, std::string, std::vector, std::list, std::ostream, std::map, std::ostringstream; +ClassImp(RooFit::Detail::RooFixedProdPdf); ClassImp(RooProdPdf); @@ -2311,98 +2312,6 @@ std::unique_ptr RooProdPdf::fillNormSetForServer(RooArgSet const &nor } } -/// A RooProdPdf with a fixed normalization set can be replaced by this class. -/// Its purpose is to provide the right client-server interface for the -/// evaluation of RooProdPdf cache elements that were created for a given -/// normalization set. -class RooFixedProdPdf : public RooAbsPdf { -public: - RooFixedProdPdf(std::unique_ptr &&prodPdf, RooArgSet const &normSet) - : RooAbsPdf(prodPdf->GetName(), prodPdf->GetTitle()), _normSet{normSet}, - _servers("!servers", "List of servers", this), _prodPdf{std::move(prodPdf)} - { - initialize(); - } - RooFixedProdPdf(const RooFixedProdPdf &other, const char *name = nullptr) - : RooAbsPdf(other, name), _normSet{other._normSet}, - _servers("!servers", "List of servers", this), _prodPdf{static_cast(other._prodPdf->Clone())} - { - initialize(); - } - TObject *clone(const char *newname) const override { return new RooFixedProdPdf(*this, newname); } - - bool selfNormalized() const override { return true; } - - inline bool canComputeBatchWithCuda() const override { return true; } - - void doEval(RooFit::EvalContext &ctx) const override - { - _prodPdf->doEvalImpl(this, *_cache, ctx); - } - - void translate(RooFit::CodegenContext &ctx) const override - { - if (_cache->_isRearranged) { - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::ratio", *_cache->_rearrangedNum, *_cache->_rearrangedDen)); - } else { - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::product", _cache->_partList, _cache->_partList.size())); - } - } - - ExtendMode extendMode() const override { return _prodPdf->extendMode(); } - double expectedEvents(const RooArgSet * /*nset*/) const override { return _prodPdf->expectedEvents(&_normSet); } - std::unique_ptr createExpectedEventsFunc(const RooArgSet * /*nset*/) const override - { - return _prodPdf->createExpectedEventsFunc(&_normSet); - } - - // Analytical Integration handling - bool forceAnalyticalInt(const RooAbsArg &dep) const override { return _prodPdf->forceAnalyticalInt(dep); } - Int_t getAnalyticalIntegralWN(RooArgSet &allVars, RooArgSet &analVars, const RooArgSet *normSet, - const char *rangeName = nullptr) const override - { - return _prodPdf->getAnalyticalIntegralWN(allVars, analVars, normSet, rangeName); - } - Int_t getAnalyticalIntegral(RooArgSet &allVars, RooArgSet &numVars, const char *rangeName = nullptr) const override - { - return _prodPdf->getAnalyticalIntegral(allVars, numVars, rangeName); - } - double analyticalIntegralWN(Int_t code, const RooArgSet *normSet, const char *rangeName) const override - { - return _prodPdf->analyticalIntegralWN(code, normSet, rangeName); - } - double analyticalIntegral(Int_t code, const char *rangeName = nullptr) const override - { - return _prodPdf->analyticalIntegral(code, rangeName); - } - -private: - void initialize() - { - _cache = _prodPdf->createCacheElem(&_normSet, nullptr); - auto &cache = *_cache; - - // The actual servers for a given normalization set depend on whether the - // cache is rearranged or not. See RooProdPdf::calculateBatch to see - // which args in the cache are used directly. - if (cache._isRearranged) { - _servers.add(*cache._rearrangedNum); - _servers.add(*cache._rearrangedDen); - } else { - for (std::size_t i = 0; i < cache._partList.size(); ++i) { - _servers.add(cache._partList[i]); - } - } - } - - double evaluate() const override { return _prodPdf->calculate(*_cache); } - - RooArgSet _normSet; - std::unique_ptr _cache; - RooSetProxy _servers; - std::unique_ptr _prodPdf; -}; - std::unique_ptr RooProdPdf::compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileContext &ctx) const { @@ -2426,8 +2335,50 @@ RooProdPdf::compileForNormSet(RooArgSet const &normSet, RooFit::Detail::CompileC ctx.compileServer(*server, *prodPdfClone, depList); } - auto fixedProdPdf = std::make_unique(std::move(prodPdfClone), normSet); + auto fixedProdPdf = std::make_unique(std::move(prodPdfClone), normSet); ctx.markAsCompiled(*fixedProdPdf); return fixedProdPdf; } + +namespace RooFit { +namespace Detail { + +RooFixedProdPdf::RooFixedProdPdf(std::unique_ptr &&prodPdf, RooArgSet const &normSet) + : RooAbsPdf(prodPdf->GetName(), prodPdf->GetTitle()), + _normSet{normSet}, + _servers("!servers", "List of servers", this), + _prodPdf{std::move(prodPdf)} +{ + initialize(); +} + +RooFixedProdPdf::RooFixedProdPdf(const RooFixedProdPdf &other, const char *name) + : RooAbsPdf(other, name), + _normSet{other._normSet}, + _servers("!servers", "List of servers", this), + _prodPdf{static_cast(other._prodPdf->Clone())} +{ + initialize(); +} + +void RooFixedProdPdf::initialize() +{ + _cache = _prodPdf->createCacheElem(&_normSet, nullptr); + auto &cache = *_cache; + + // The actual servers for a given normalization set depend on whether the + // cache is rearranged or not. See RooProdPdf::calculateBatch to see + // which args in the cache are used directly. + if (cache._isRearranged) { + _servers.add(*cache._rearrangedNum); + _servers.add(*cache._rearrangedDen); + } else { + for (std::size_t i = 0; i < cache._partList.size(); ++i) { + _servers.add(cache._partList[i]); + } + } +} + +} // namespace Detail +} // namespace RooFit diff --git a/roofit/roofitcore/src/RooProduct.cxx b/roofit/roofitcore/src/RooProduct.cxx index 9eff60b366a0b..e08dffbf0f223 100644 --- a/roofit/roofitcore/src/RooProduct.cxx +++ b/roofit/roofitcore/src/RooProduct.cxx @@ -488,13 +488,6 @@ void RooProduct::setCacheAndTrackHints(RooArgSet& trackNodes) } } -//////////////////////////////////////////////////////////////////////////////// - -void RooProduct::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::product", _compRSet, _compRSet.size())); -} - //////////////////////////////////////////////////////////////////////////////// /// Customized printing of arguments of a RooProduct to more intuitively reflect the contents of the /// product operator construction diff --git a/roofit/roofitcore/src/RooRatio.cxx b/roofit/roofitcore/src/RooRatio.cxx index 53a6d55cfd06b..3d05f4f250cb4 100644 --- a/roofit/roofitcore/src/RooRatio.cxx +++ b/roofit/roofitcore/src/RooRatio.cxx @@ -123,8 +123,3 @@ void RooRatio::doEval(RooFit::EvalContext &ctx) const RooBatchCompute::compute(ctx.config(this), RooBatchCompute::Ratio, ctx.output(), {ctx.at(_numerator), ctx.at(_denominator)}); } - -void RooRatio::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::ratio", _numerator, _denominator)); -} diff --git a/roofit/roofitcore/src/RooRealIntegral.cxx b/roofit/roofitcore/src/RooRealIntegral.cxx index 4e40317e9c3d7..5d2b61f3c2289 100644 --- a/roofit/roofitcore/src/RooRealIntegral.cxx +++ b/roofit/roofitcore/src/RooRealIntegral.cxx @@ -35,7 +35,6 @@ integration is performed in the various implementations of the RooAbsIntegrator #include #include #include -#include #include #include #include @@ -45,8 +44,6 @@ integration is performed in the various implementations of the RooAbsIntegrator #include #include -#include "RooFitImplHelpers.h" - #include #include @@ -1031,58 +1028,6 @@ void RooRealIntegral::setAllowComponentSelection(bool allow){ _respectCompSelect = allow; } -void RooRealIntegral::translate(RooFit::CodegenContext &ctx) const -{ - if (_sumList.empty() && _intList.empty()) { - ctx.addResult(this, _function.arg().buildCallToAnalyticIntegral(_mode, RooNameReg::str(_rangeName), ctx)); - return; - } - - if (intVars().size() != 1 || _intList.size() != 1) { - std::stringstream errorMsg; - errorMsg << "Only analytical integrals and 1D numeric integrals are supported for AD for class" - << _function.GetName(); - coutE(Minimization) << errorMsg.str() << std::endl; - throw std::runtime_error(errorMsg.str().c_str()); - } - - auto &intVar = static_cast(*_intList[0]); - - std::string obsName = ctx.getTmpVarName(); - std::string oldIntVarResult = ctx.getResult(intVar); - ctx.addResult(&intVar, "obs[0]"); - - std::string funcName = ctx.buildFunction(*_function, {}); - - std::stringstream ss; - - ss << "double " << obsName << "[1];\n"; - - std::string resName = RooFit::Detail::makeValidVarName(GetName()) + "Result"; - ctx.addResult(this, resName); - ctx.addToGlobalScope("double " + resName + " = 0.0;\n"); - - // TODO: once Clad has support for higher-order functions (follow also the - // Clad issue #637), we could refactor this code into an actual function - // instead of hardcoding it here as a string. - ss << "{\n" - << " const int n = 1000; // number of sampling points\n" - << " double d = " << intVar.getMax(intRange()) << " - " << intVar.getMin(intRange()) << ";\n" - << " double eps = d / n;\n" - << " for (int i = 0; i < n; ++i) {\n" - << " " << obsName << "[0] = " << intVar.getMin(intRange()) << " + eps * i;\n" - << " double tmpA = " << funcName << "(params, " << obsName << ", xlArr);\n" - << " " << obsName << "[0] = " << intVar.getMin(intRange()) << " + eps * (i + 1);\n" - << " double tmpB = " << funcName << "(params, " << obsName << ", xlArr);\n" - << " " << resName << " += (tmpA + tmpB) * 0.5 * eps;\n" - << " }\n" - << "}\n"; - - ctx.addToGlobalScope(ss.str()); - - ctx.addResult(&intVar, oldIntVarResult); -} - //////////////////////////////////////////////////////////////////////////////// /// Customized printing of arguments of a RooRealIntegral to more intuitively reflect the contents of the /// integration operation diff --git a/roofit/roofitcore/src/RooRealSumFunc.cxx b/roofit/roofitcore/src/RooRealSumFunc.cxx index d8297ce3593c5..d509b7a623923 100644 --- a/roofit/roofitcore/src/RooRealSumFunc.cxx +++ b/roofit/roofitcore/src/RooRealSumFunc.cxx @@ -114,11 +114,6 @@ double RooRealSumFunc::evaluate() const return RooRealSumPdf::evaluate(*this, _funcList, _coefList, _doFloor || _doFloorGlobal, _haveWarned); } -void RooRealSumFunc::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, RooRealSumPdf::translateImpl(ctx, this, _funcList, _coefList)); -} - //_____________________________________________________________________________ bool RooRealSumFunc::checkObservables(const RooArgSet *nset) const { diff --git a/roofit/roofitcore/src/RooRealSumPdf.cxx b/roofit/roofitcore/src/RooRealSumPdf.cxx index 53725970c9848..2b4b648cf721c 100644 --- a/roofit/roofitcore/src/RooRealSumPdf.cxx +++ b/roofit/roofitcore/src/RooRealSumPdf.cxx @@ -46,7 +46,7 @@ to the fractions of the various functions. **This requires setting the last argu #include "RooRealSumPdf.h" -#include "RooNormalizedPdf.h" +#include "RooFit/Detail/RooNormalizedPdf.h" #include "RooRealIntegral.h" #include "RooRealProxy.h" #include "RooRealVar.h" @@ -297,42 +297,6 @@ void RooRealSumPdf::doEval(RooFit::EvalContext & ctx) const } } -std::string RooRealSumPdf::translateImpl(RooFit::CodegenContext &ctx, RooAbsArg const *klass, - RooArgList const &funcList, RooArgList const &coefList, bool normalize) -{ - bool noLastCoeff = funcList.size() != coefList.size(); - - std::string const &funcName = ctx.buildArg(funcList); - std::string const &coeffName = ctx.buildArg(coefList); - std::string const &coeffSize = std::to_string(coefList.size()); - - std::string sum = ctx.getTmpVarName(); - std::string coeffSum = ctx.getTmpVarName(); - ctx.addToCodeBody(klass, "double " + sum + " = 0;\ndouble " + coeffSum + "= 0;\n"); - - std::string iterator = "i_" + ctx.getTmpVarName(); - std::string subscriptExpr = "[" + iterator + "]"; - - std::string code = "for(int " + iterator + " = 0; " + iterator + " < " + coeffSize + "; " + iterator + "++) {\n" + - sum + " += " + funcName + subscriptExpr + " * " + coeffName + subscriptExpr + ";\n"; - code += coeffSum + " += " + coeffName + subscriptExpr + ";\n"; - code += "}\n"; - - if (noLastCoeff) { - code += sum + " += " + funcName + "[" + coeffSize + "]" + " * (1 - " + coeffSum + ");\n"; - } else if (normalize) { - code += sum + " /= " + coeffSum + ";\n"; - } - ctx.addToCodeBody(klass, code); - - return sum; -} - -void RooRealSumPdf::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, translateImpl(ctx, this, _funcList, _coefList)); -} - bool RooRealSumPdf::checkObservables(RooAbsReal const& caller, RooArgSet const* nset, RooArgList const& funcList, RooArgList const& coefList) { @@ -777,7 +741,7 @@ RooRealSumPdf::compileForNormSet(RooArgSet const &normSet, RooFit::Detail::Compi RooArgSet depList; pdfClone->getObservables(&normSet, depList); - auto newArg = std::make_unique(*pdfClone, depList); + auto newArg = std::make_unique(*pdfClone, depList); // The direct servers are this pdf and the normalization integral, which // don't need to be compiled further. diff --git a/roofit/roofitcore/src/RooRealVar.cxx b/roofit/roofitcore/src/RooRealVar.cxx index ca6594b4599fd..a1c2c3790b6f4 100644 --- a/roofit/roofitcore/src/RooRealVar.cxx +++ b/roofit/roofitcore/src/RooRealVar.cxx @@ -82,22 +82,6 @@ void RooRealVar::cleanup() //////////////////////////////////////////////////////////////////////////////// -void RooRealVar::translate(RooFit::CodegenContext &ctx) const -{ - if(!isConstant()) { - ctx.addResult(this, GetName()); - } - // Just return a formatted version of the const value. - // Formats to the maximum precision. - constexpr auto max_precision{std::numeric_limits::digits10 + 1}; - std::stringstream ss; - ss.precision(max_precision); - // Just use toString to make sure we do not output 'inf'. - // This is really ugly for large numbers... - ss << std::fixed << RooNumber::toString(_value); - ctx.addResult(this, ss.str()); -} - /// Return a dummy object to use when properties are not initialised. RooRealVarSharedProperties& RooRealVar::_nullProp() { diff --git a/roofit/roofitcore/src/RooRecursiveFraction.cxx b/roofit/roofitcore/src/RooRecursiveFraction.cxx index 1ed2a039a817a..8a9d7f10cad4d 100644 --- a/roofit/roofitcore/src/RooRecursiveFraction.cxx +++ b/roofit/roofitcore/src/RooRecursiveFraction.cxx @@ -87,8 +87,3 @@ double RooRecursiveFraction::evaluate() const return prod ; } - -void RooRecursiveFraction::translate(RooFit::CodegenContext &ctx) const -{ - ctx.addResult(this, ctx.buildCall("RooFit::Detail::MathFuncs::recursiveFraction", _list, _list.size())); -}