77 RooFormula::RooFormula() : TNamed()
90 RooFormula::RooFormula(
const char* name,
const char* formula,
const RooArgList& varList,
91 bool checkVariables) :
92 TNamed(name, formula), _tFormula{
nullptr}
94 _origList.add(varList);
95 _isCategory = findCategoryServers(_origList);
97 std::string processedFormula = processFormula(formula);
99 cxcoutD(InputArguments) <<
"RooFormula '" << GetName() <<
"' will be compiled as "
100 <<
"\n\t" << processedFormula
102 <<
"\n\t" << reconstructFormula(processedFormula)
103 <<
"\n with the parameters " << _origList << endl;
106 if (!processedFormula.empty())
107 _tFormula = std::make_unique<TFormula>(name, processedFormula.c_str(),
false);
109 if (!_tFormula || !_tFormula->IsValid()) {
110 coutF(InputArguments) <<
"RooFormula '" << GetName() <<
"' did not compile."
111 <<
"\nInput:\n\t" << formula
112 <<
"\nProcessed:\n\t" << processedFormula << endl;
113 _tFormula.reset(
nullptr);
116 RooArgList useList = usedVariables();
117 if (checkVariables && _origList.size() != useList.size()) {
118 coutI(InputArguments) <<
"The formula " << GetName() <<
" claims to use the variables " << _origList
119 <<
" but only " << useList <<
" seem to be in use."
120 <<
"\n inputs: " << formula
121 <<
"\n interpretation: " << reconstructFormula(processedFormula) << std::endl;
129 RooFormula::RooFormula(
const RooFormula& other,
const char* name) :
130 TNamed(name ? name : other.GetName(), other.GetTitle()), RooPrintable(other)
132 _origList.add(other._origList);
133 _isCategory = findCategoryServers(_origList);
135 TFormula* newTF =
nullptr;
136 if (other._tFormula) {
137 newTF =
new TFormula(*other._tFormula);
138 newTF->SetName(GetName());
141 _tFormula.reset(newTF);
145 #if !defined(__GNUC__) || defined(__clang__) || (__GNUC__ > 4) || ( __GNUC__ == 4 && __GNUC_MINOR__ > 8)
146 #define ROOFORMULA_HAVE_STD_REGEX
152 std::string RooFormula::processFormula(std::string formula)
const {
154 cxcoutD(InputArguments) <<
"Preprocessing formula step 1: find category tags (catName::catState) in "
158 std::regex categoryReg(
"(\\w+)::(\\w+)");
159 std::map<std::string, int> categoryStates;
160 for (sregex_iterator matchIt = sregex_iterator(formula.begin(), formula.end(), categoryReg);
161 matchIt != sregex_iterator(); ++matchIt) {
162 assert(matchIt->size() == 3);
163 const std::string fullMatch = (*matchIt)[0];
164 const std::string catName = (*matchIt)[1];
165 const std::string catState = (*matchIt)[2];
167 const auto catVariable =
dynamic_cast<const RooAbsCategory*
>(_origList.find(catName.c_str()));
169 cxcoutD(InputArguments) <<
"Formula " << GetName() <<
" uses '::' to reference a category state as '" << fullMatch
170 <<
"' but a category '" << catName <<
"' cannot be found in the input variables." << endl;
174 const RooCatType* catType = catVariable->lookupType(catState.c_str(),
false);
176 coutE(InputArguments) <<
"Formula " << GetName() <<
" uses '::' to reference a category state as '" << fullMatch
177 <<
"' but the category '" << catName <<
"' does not seem to have the state '" << catState <<
"'." << endl;
178 throw std::invalid_argument(formula);
180 const int catNum = catType->getVal();
182 categoryStates[fullMatch] = catNum;
183 cxcoutD(InputArguments) <<
"\n\t" << fullMatch <<
"\tname=" << catName <<
"\tstate=" << catState <<
"=" << catNum;
185 cxcoutD(InputArguments) <<
"-- End of category tags --"<< endl;
188 for (
const auto& catState : categoryStates) {
189 std::stringstream replacement;
190 replacement << catState.second;
191 formula = std::regex_replace(formula, std::regex(catState.first), replacement.str());
194 cxcoutD(InputArguments) <<
"Preprocessing formula step 2: replace category tags\n\t" << formula << endl;
197 std::regex ordinalRegex(
"@([0-9]+)");
198 formula = std::regex_replace(formula, ordinalRegex,
"x[$1]");
200 cxcoutD(InputArguments) <<
"Preprocessing formula step 3: replace '@'-references\n\t" << formula << endl;
203 for (
unsigned int i = 0; i < _origList.size(); ++i) {
204 const auto& var = _origList[i];
205 std::string regex =
"\\b";
206 regex += var.GetName();
207 regex +=
"\\b(?!\\[)";
208 std::regex findParameterRegex(regex);
210 std::stringstream replacement;
211 replacement <<
"x[" << i <<
"]";
212 formula = std::regex_replace(formula, findParameterRegex, replacement.str());
214 cxcoutD(InputArguments) <<
"Preprocessing formula step 4: replace named references: "
215 << var.GetName() <<
" --> " << replacement.str()
216 <<
"\n\t" << formula << endl;
219 cxcoutD(InputArguments) <<
"Final formula:\n\t" << formula << endl;
227 RooArgList RooFormula::usedVariables()
const {
229 if (_tFormula ==
nullptr)
232 const std::string formula(_tFormula->GetTitle());
234 std::set<unsigned int> matchedOrdinals;
235 std::regex newOrdinalRegex(
"\\bx\\[([0-9]+)\\]");
236 for (sregex_iterator matchIt = sregex_iterator(formula.begin(), formula.end(), newOrdinalRegex);
237 matchIt != sregex_iterator(); ++matchIt) {
238 assert(matchIt->size() == 2);
239 std::stringstream matchString((*matchIt)[1]);
243 matchedOrdinals.insert(i);
246 for (
unsigned int i : matchedOrdinals) {
247 useList.add(_origList[i]);
257 std::string RooFormula::reconstructFormula(std::string internalRepr)
const {
258 for (
unsigned int i = 0; i < _origList.size(); ++i) {
259 const auto& var = _origList[i];
260 std::stringstream regexStr;
261 regexStr <<
"x\\[" << i <<
"\\]|@" << i;
262 std::regex regex(regexStr.str());
264 std::string replacement = std::string(
"[") + var.GetName() +
"]";
265 internalRepr = std::regex_replace(internalRepr, regex, replacement);
270 #endif //GCC < 4.9 Check
276 std::vector<bool> RooFormula::findCategoryServers(
const RooAbsCollection& collection)
const {
277 std::vector<bool> output;
279 for (
unsigned int i = 0; i < collection.size(); ++i) {
280 output.push_back(dynamic_cast<const RooAbsCategory*>(collection[i]));
290 Bool_t RooFormula::reCompile(
const char* newFormula)
292 std::string processed = processFormula(newFormula);
293 auto newTF = std::make_unique<TFormula>(GetName(), processed.c_str(),
false);
295 if (!newTF->IsValid()) {
296 coutE(InputArguments) << __func__ <<
": new equation doesn't compile, formula unchanged" << endl;
300 _tFormula = std::move(newTF);
301 SetTitle(newFormula);
305 void RooFormula::dump()
const
307 printMultiline(std::cout, 0);
316 Bool_t RooFormula::changeDependents(
const RooAbsCollection& newDeps, Bool_t mustReplaceAll, Bool_t nameChange)
319 bool errorStat =
false;
321 for (
const auto arg : _origList) {
322 RooAbsReal* replace = (RooAbsReal*) arg->findNewServer(newDeps,nameChange) ;
324 _origList.replace(*arg, *replace);
326 if (arg->getStringAttribute(
"origName")) {
327 replace->setStringAttribute(
"origName",arg->getStringAttribute(
"origName")) ;
329 replace->setStringAttribute(
"origName",arg->GetName()) ;
332 }
else if (mustReplaceAll) {
333 coutE(LinkStateMgmt) << __func__ <<
": cannot find replacement for " << arg->GetName() << endl;
338 _isCategory = findCategoryServers(_origList);
352 Double_t RooFormula::eval(
const RooArgSet* nset)
const
355 coutF(Eval) << __func__ <<
" (" << GetName() <<
"): Formula didn't compile: " << GetTitle() << endl;
356 std::string what =
"Formula ";
358 what +=
" didn't compile.";
359 throw std::invalid_argument(what);
362 std::vector<double> pars;
363 pars.reserve(_origList.size());
364 for (
unsigned int i = 0; i < _origList.size(); ++i) {
365 if (_isCategory[i]) {
366 const auto& cat =
static_cast<RooAbsCategory&
>(_origList[i]);
367 pars.push_back(cat.getIndex());
369 const auto& real =
static_cast<RooAbsReal&
>(_origList[i]);
370 pars.push_back(real.getVal(nset));
374 return _tFormula->EvalPar(pars.data());
381 void RooFormula::printMultiline(ostream& os, Int_t , Bool_t , TString indent)
const
383 os << indent <<
"--- RooFormula ---" << endl;
384 os << indent <<
" Formula: '" << GetTitle() <<
"'" << endl;
385 os << indent <<
" Interpretation: '" << reconstructFormula(GetTitle()) <<
"'" << endl;
387 os << indent <<
"Servers: " << _origList <<
"\n";
388 os << indent <<
"In use : " << actualDependents() << endl;
395 void RooFormula::printValue(ostream& os)
const
397 os << const_cast<RooFormula*>(
this)->eval(0) ;
404 void RooFormula::printName(ostream& os)
const
413 void RooFormula::printTitle(ostream& os)
const
422 void RooFormula::printClassName(ostream& os)
const
424 os << IsA()->GetName() ;
431 void RooFormula::printArgs(ostream& os)
const
433 os <<
"[ actualVars=";
434 for (
const auto arg : usedVariables()) {
435 os <<
" " << arg->GetName();
444 #ifndef ROOFORMULA_HAVE_STD_REGEX
457 std::string RooFormula::processFormula(std::string formula)
const {
458 TString formulaTString = formula.c_str();
460 cxcoutD(InputArguments) <<
"Preprocessing formula step 1: find category tags (catName::catState) in "
461 << formulaTString.Data() << endl;
464 TPRegexp categoryReg(
"(\\w+)::(\\w+)");
465 std::map<std::string, int> categoryStates;
468 std::unique_ptr<TObjArray> matches(categoryReg.MatchS(formulaTString,
"", offset, 3));
469 if (matches->GetEntries() == 0)
472 std::string fullMatch =
static_cast<TObjString*
>(matches->At(0))->GetString().Data();
473 std::string catName =
static_cast<TObjString*
>(matches->At(1))->GetString().Data();
474 std::string catState =
static_cast<TObjString*
>(matches->At(2))->GetString().Data();
475 offset = formulaTString.Index(categoryReg, offset) + fullMatch.size();
477 const auto catVariable =
dynamic_cast<const RooAbsCategory*
>(_origList.find(catName.c_str()));
479 cxcoutD(InputArguments) <<
"Formula " << GetName() <<
" uses '::' to reference a category state as '" << fullMatch
480 <<
"' but a category '" << catName <<
"' cannot be found in the input variables." << endl;
484 const RooCatType* catType = catVariable->lookupType(catState.c_str(),
false);
486 coutE(InputArguments) <<
"Formula " << GetName() <<
" uses '::' to reference a category state as '" << fullMatch
487 <<
"' but the category '" << catName <<
"' does not seem to have the state '" << catState <<
"'." << endl;
488 throw std::invalid_argument(formula);
490 const int catNum = catType->getVal();
492 categoryStates[fullMatch] = catNum;
493 cxcoutD(InputArguments) <<
"\n\t" << fullMatch <<
"\tname=" << catName <<
"\tstate=" << catState <<
"=" << catNum;
494 }
while (offset != -1);
495 cxcoutD(InputArguments) <<
"-- End of category tags --"<< endl;
498 for (
const auto& catState : categoryStates) {
499 std::stringstream replacement;
500 replacement << catState.second;
501 formulaTString.ReplaceAll(catState.first.c_str(), replacement.str().c_str());
504 cxcoutD(InputArguments) <<
"Preprocessing formula step 2: replace category tags\n\t" << formulaTString.Data() << endl;
507 TPRegexp ordinalRegex(
"@([0-9]+)");
510 nsub = ordinalRegex.Substitute(formulaTString,
"x[$1]");
513 cxcoutD(InputArguments) <<
"Preprocessing formula step 3: replace '@'-references\n\t" << formulaTString.Data() << endl;
516 for (
unsigned int i = 0; i < _origList.size(); ++i) {
517 const auto& var = _origList[i];
518 TString regex =
"\\b";
519 regex += var.GetName();
520 regex +=
"\\b([^[]|$)";
521 TPRegexp findParameterRegex(regex);
523 std::stringstream replacement;
524 replacement <<
"x[" << i <<
"]$1";
527 nsub2 = findParameterRegex.Substitute(formulaTString, replacement.str().c_str());
530 cxcoutD(InputArguments) <<
"Preprocessing formula step 4: replace named references: "
531 << var.GetName() <<
" --> " << replacement.str()
532 <<
"\n\t" << formulaTString.Data() << endl;
535 cxcoutD(InputArguments) <<
"Final formula:\n\t" << formulaTString << endl;
537 return formulaTString.Data();
543 RooArgList RooFormula::usedVariables()
const {
545 if (_tFormula ==
nullptr)
548 const TString formulaTString = _tFormula->GetTitle();
550 std::set<unsigned int> matchedOrdinals;
551 TPRegexp newOrdinalRegex(
"\\bx\\[([0-9]+)\\]");
554 std::unique_ptr<TObjArray> matches(newOrdinalRegex.MatchS(formulaTString,
"", offset, 2));
555 if (matches->GetEntries() == 0)
558 std::string fullMatch =
static_cast<TObjString*
>(matches->At(0))->GetString().Data();
559 std::string ordinal =
static_cast<TObjString*
>(matches->At(1))->GetString().Data();
560 offset = formulaTString.Index(newOrdinalRegex, offset) + fullMatch.size();
562 std::stringstream matchString(ordinal.c_str());
566 matchedOrdinals.insert(i);
567 }
while (offset != -1);
569 for (
unsigned int i : matchedOrdinals) {
570 useList.add(_origList[i]);
580 std::string RooFormula::reconstructFormula(std::string internalRepr)
const {
581 TString internalReprT = internalRepr.c_str();
583 for (
unsigned int i = 0; i < _origList.size(); ++i) {
584 const auto& var = _origList[i];
585 std::stringstream regexStr;
586 regexStr <<
"x\\[" << i <<
"\\]|@" << i;
587 TPRegexp regex(regexStr.str().c_str());
589 std::string replacement = std::string(
"[") + var.GetName() +
"]";
590 regex.Substitute(internalReprT, replacement.c_str());
593 return internalReprT.Data();
595 #endif //GCC < 4.9 Check