35void replaceAll(std::string &str,
const std::string &from,
const std::string &to)
40 while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
41 str.replace(start_pos, from.length(), to);
42 start_pos += to.length();
50namespace Experimental {
54 :
RooAbsReal{
name, title}, _params{
"!params",
"List of parameters", this}, _useEvaluator{useEvaluator}
57 _absReal = std::make_unique<RooEvaluatorWrapper>(obj,
const_cast<RooAbsData *
>(
data),
false,
"", simPdf,
false);
68 std::map<RooFit::Detail::DataKey, std::size_t> nodeOutputSizes =
70 auto found = spans.find(key);
71 return found != spans.end() ? found->second.size() : -1;
79 ctx.
addResult(param,
"params[" + std::to_string(idx) +
"]");
84 const char *obsName = item.first->GetName();
88 if (item.second.size == 1) {
89 ctx.addResult(obsName,
"obs[" + std::to_string(item.second.idx) +
"]");
91 ctx.addResult(obsName,
"obs");
92 ctx.addVecObs(obsName, item.second.idx);
99 _funcName = ctx.buildFunction(obj, nodeOutputSizes);
108 _params(
"!params", this, other._params),
109 _funcName(other._funcName),
112 _hasGradient(other._hasGradient),
113 _gradientVarBuffer(other._gradientVarBuffer),
114 _observables(other._observables)
118std::map<RooFit::Detail::DataKey, std::span<const double>>
122 std::stack<std::vector<double>> vectorBuffers;
123 std::map<RooFit::Detail::DataKey, std::span<const double>> spans;
126 spans = RooFit::BatchModeDataHelpers::getDataSpans(*
data,
"", simPdf,
true,
false, vectorBuffers);
130 for (
auto const &item : spans) {
131 std::size_t
n = item.second.size();
134 for (std::size_t i = 0; i <
n; ++i) {
141 for (
auto *param : paramSet) {
143 std::stringstream errorMsg;
144 errorMsg <<
"In creation of function " << GetName()
145 <<
" wrapper: input param expected to be of type RooAbsReal.";
147 throw std::runtime_error(errorMsg.str().c_str());
149 if (spans.find(param) == spans.end()) {
153 _gradientVarBuffer.resize(_params.size());
158void RooFuncWrapper::createGradient()
160 std::string gradName = _funcName +
"_grad_0";
161 std::string requestName = _funcName +
"_req";
164 gInterpreter->Declare(
"#include <Math/CladDerivator.h>\n");
167 std::stringstream requestFuncStrm;
168 requestFuncStrm <<
"#pragma clad ON\n"
169 "void " << requestName <<
"() {\n"
170 " clad::gradient(" << _funcName <<
", \"params\");\n"
174 if (!
gInterpreter->Declare(requestFuncStrm.str().c_str())) {
175 std::stringstream errorMsg;
176 errorMsg <<
"Function " << GetName() <<
" could not be differentiated. See above for details.";
178 throw std::runtime_error(errorMsg.str().c_str());
181 _grad =
reinterpret_cast<Grad>(
gInterpreter->ProcessLine((gradName +
";").c_str()));
185void RooFuncWrapper::gradient(
double *out)
const
187 updateGradientVarBuffer();
188 std::fill(out, out + _params.size(), 0.0);
190 _grad(_gradientVarBuffer.data(), _observables.data(), _xlArr.data(), out);
193void RooFuncWrapper::updateGradientVarBuffer()
const
195 std::transform(_params.begin(), _params.end(), _gradientVarBuffer.begin(),
196 [](
RooAbsArg *obj) { return static_cast<RooAbsReal *>(obj)->getVal(); });
199double RooFuncWrapper::evaluate()
const
202 return _absReal->getVal();
203 updateGradientVarBuffer();
205 return _func(_gradientVarBuffer.data(), _observables.data(), _xlArr.data());
208void RooFuncWrapper::gradient(
const double *
x,
double *
g)
const
210 std::fill(
g,
g + _params.size(), 0.0);
212 _grad(
const_cast<double *
>(
x), _observables.data(), _xlArr.data(),
g);
216void RooFuncWrapper::writeDebugMacro(std::string
const &
filename)
const
218 std::stringstream allCode;
219 std::set<std::string> seenFunctions;
222 for (std::string
const &
name : _collectedFunctions) {
223 if (seenFunctions.count(
name) > 0) {
226 seenFunctions.insert(
name);
227 std::unique_ptr<TInterpreterValue>
v =
gInterpreter->MakeInterpreterValue();
229 std::string s =
v->ToString();
230 for (
int i = 0; i < 2; ++i) {
231 s = s.erase(0, s.find(
"\n") + 1);
233 allCode << s << std::endl;
236 std::ofstream outFile;
238 outFile << R
"(//auto-generated test macro
239#include <RooFit/Detail/MathFuncs.h>
240#include <Math/CladDerivator.h>
242#pragma cling optimize(2)
246void gradient_request() {
248 << _funcName << R"(, "params");
253 updateGradientVarBuffer();
255 auto writeVector = [&](std::string
const &
name, std::span<const double>
vec) {
256 std::stringstream decl;
257 decl <<
"std::vector<double> " <<
name <<
" = {";
258 for (std::size_t i = 0; i <
vec.size(); ++i) {
262 if (i <
vec.size() - 1)
267 std::string declStr = decl.str();
269 replaceAll(declStr,
"inf",
"std::numeric_limits<double>::infinity()");
270 replaceAll(declStr,
"nan",
"NAN");
275 outFile <<
"// clang-format off\n" << std::endl;
276 writeVector(
"parametersVec", _gradientVarBuffer);
277 outFile << std::endl;
278 writeVector(
"observablesVec", _observables);
279 outFile << std::endl;
280 writeVector(
"auxConstantsVec", _xlArr);
281 outFile << std::endl;
282 outFile <<
"// clang-format on\n" << std::endl;
285// To run as a ROOT macro
289 std::vector<double> gradientVec(parametersVec.size());
291 auto func = [&](std::span<double> params) {
293 << _funcName << R"((params.data(), observablesVec.data(), auxConstantsVec.data());
295 auto grad = [&](std::span<double> params, std::span<double> out) {
297 << _funcName << R"(_grad_0(parametersVec.data(), observablesVec.data(), auxConstantsVec.data(),
301 grad(parametersVec, gradientVec);
303 auto numDiff = [&](int i) {
304 const double eps = 1e-6;
305 std::vector<double> p{parametersVec};
306 p[i] = parametersVec[i] - eps;
307 double funcValDown = func(p);
308 p[i] = parametersVec[i] + eps;
309 double funcValUp = func(p);
310 return (funcValUp - funcValDown) / (2 * eps);
313 for (std::size_t i = 0; i < parametersVec.size(); ++i) {
314 std::cout << i << ":" << std::endl;
315 std::cout << " numr : " << numDiff(i) << std::endl;
316 std::cout << " clad : " << gradientVec[i] << std::endl;
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Common abstract base class for objects that represent a value and a "shape" in RooFit.
RooFit::OwningPtr< RooArgSet > getParameters(const RooAbsData *data, bool stripDisconnected=true) const
Create a list of leaf nodes in the arg tree starting with ourself as top node that don't match any of...
Abstract base class for binned and unbinned datasets.
Abstract base class for objects that represent a real value and implements functionality common to al...
RooArgSet is a container object that can hold multiple RooAbsArg objects.
A class to maintain the context for squashing of RooFit models into code.
void addResult(RooAbsArg const *key, std::string const &value)
A function to save an expression that includes/depends on the result of the input node.
A wrapper class to store a C++ function of type 'double (*)(double*, double*)'.
double(*)(double *, double const *, double const *) Func
std::unique_ptr< RooAbsReal > _absReal
std::vector< std::string > _collectedFunctions
std::vector< double > _xlArr
std::vector< double > _observables
std::map< RooFit::Detail::DataKey, std::span< const double > > loadParamsAndData(RooArgSet const ¶mSet, const RooAbsData *data, RooSimultaneous const *simPdf)
std::map< RooFit::Detail::DataKey, ObsInfo > _obsInfos
void(*)(double *, double const *, double const *, double *) Grad
RooFuncWrapper(const char *name, const char *title, RooAbsReal &obj, const RooAbsData *data=nullptr, RooSimultaneous const *simPdf=nullptr, bool useEvaluator=false)
Facilitates simultaneous fitting of multiple PDFs to subsets of a given dataset.
void replaceAll(std::string &inOut, std::string_view what, std::string_view with)
The namespace RooFit contains mostly switches that change the behaviour of functions of PDFs (or othe...