How to draw random numbers from a probability density given in ROOT::Math?

Dear all,

I am trying to write a Monte Carlo simulation that needs data that are distributed after the negative binomial probability. ROOT provides the corresponding pdf already, so I thought it must be easy to use this one …

Here’s a minimal ‘working’ example (1.5 KB). That’s how I thought this should be done:

double my_negative_binomial_pdf(double* x, double* par)
{
	const unsigned int k = static_cast<unsigned int>(x[0]);
	const double p = par[0];
	const double n = par[1];
	Double_t f = ROOT::Math::negative_binomial_pdf(k, p, n);
	return f;
}

void neg_binomial_plot(unsigned int runs=1000)
{
	TCanvas *c = new TCanvas("c", "negative binomial", 900, 700);
	TH1D* h = new TH1D("h", "negative binomial", 150, 0., 75.);
	
	const double XMin = 0.;
	const double XMax = 100.;
	const int NParm = 2;
	
	TF1* fNegBinomial = new TF1("fNegBinomial", my_negative_binomial_pdf, XMin, XMax, NParm);
	fNegBinomial->SetParameter(0, 0.25); // p
	fNegBinomial->SetParameter(1, 2000); // n
	
	for (unsigned int r=0; r<runs; r++)
	{	
		const double val = fNegBinomial->GetRandom();
		h->Fill(val);
	}
	
	c->cd();
	h->Draw();

}

Unfortunately, this will end up in a histogram with 1000 entries in the 0-bin. I am pretty sure it should be a distribution with a mean of ~2000. But I don’t get what I misunderstood about ROOT’s random number generation.

Any insight is highly appreciated! Thanks!
pbiel

{
  double XMin = 0., XMax = 10000.;
  TF1 *f = new TF1("fNegBinomial",
                   "ROOT::Math::negative_binomial_pdf(x, [0], [1])",
                   XMin, XMax);
  f->SetParNames("p", "n");
  f->SetNpx(10000);
  // f->Print();
  f->SetParameters(0.25, 2000.); // "p", "n"
  new TCanvas("c_f", "c_f"); f->Draw();
  TH1D *h = new TH1D("h", "negative binomial", 1000, XMin, XMax);
  Int_t runs = 1000;
  h->FillRandom("fNegBinomial", runs);
  new TCanvas("c_h", "c_h"); h->Draw();
}

Hi! Thanks for your quick reply!

Unfortunately, when I try to execute your code, I get the following error message

Error in <TFormula::Compile>:  Non integer value for parameter number : ""
Error in <TF1::TF1>: function: fNegBinomial/ROOT::Math::negative_binomial_pdf(x, [p], [n]) has 0 parameters instead of 1
Error in <TH1D::FillRandom>: Unknown function: fNegBinomial
Warning in <TF1::EvalParOld>: Found an unsupported opcode (0)

 *** Break *** bus error
 Generating stack trace...
 0x00007ff002063c1d in TF1::Paint(char const*) + 0x3cd from /usr/lib64/root/5.34/libHist.so
 0x00007ff00107325b in TPad::PaintModified() + 0x23b from /usr/lib64/root/5.34/libGpad.so
 0x00007ff001086cba in TCanvas::Update() + 0x10a from /usr/lib64/root/5.34/libGpad.so
 0x00007ff005fe68d4 in TCint::UpdateAllCanvases() + 0x44 from /usr/lib64/root/libCore.so.5.34
 0x00007ff005fe6a20 in TCint::ProcessLine(char const*, TInterpreter::EErrorCode*) + 0x100 from /usr/lib64/root/libCore.so.5.34
 0x00007ff005fe1ed7 in TCint::ProcessLineSynch(char const*, TInterpreter::EErrorCode*) + 0x87 from /usr/lib64/root/libCore.so.5.34
 0x00007ff005b5eb3c in TRint::HandleTermInput() + 0x2cc from /usr/lib64/root/libRint.so.5.34
 0x00007ff005ff24d0 in TUnixSystem::CheckDescriptors() + 0x1c0 from /usr/lib64/root/libCore.so.5.34
 0x00007ff005ff3b18 in TUnixSystem::DispatchOneEvent(bool) + 0x508 from /usr/lib64/root/libCore.so.5.34
 0x00007ff005f23094 in TSystem::InnerLoop() + 0x44 from /usr/lib64/root/libCore.so.5.34
 0x00007ff005f21b4f in TSystem::Run() + 0x6f from /usr/lib64/root/libCore.so.5.34
 0x00007ff005f8ab6f in TApplication::Run(bool) + 0x1f from /usr/lib64/root/libCore.so.5.34
 0x00007ff005b5fc74 in TRint::Run(bool) + 0x414 from /usr/lib64/root/libRint.so.5.34
 0x0000561be2dba35c in main + 0x4c from /usr/bin/root.exe
 0x00007ff0051b434a in __libc_start_main + 0xea from /lib64/libc.so.6
 0x0000561be2dba3ba in _start + 0x2a from /usr/bin/root.exe

I still have an issue understanding the second string in the constructor for TF1. Not sure how the arguments are meant to be passed here.

Since it tells us the value for parameter number is "", I thought it would be wise to simply state the number of parameters (which is two if I’m not horribly mistaken).
With

TH1D *h = new TH1D("h", "negative binomial", 1000, XMin, XMax, 2);

however, I get the following error:

Info in <TUnixSystem::ACLiC>: creating shared library /home/bielefeldt/./test_cpp.so
In file included from /home/bielefeldt/test_cpp_ACLiC_dict.h:34:0,
                 from /home/bielefeldt/test_cpp_ACLiC_dict.cxx:17:
/home/bielefeldt/./test.cpp: In function ‘void test()’:
/home/bielefeldt/./test.cpp:17:67: error: no matching function for call to ‘TH1D::TH1D(const char [2], const char [18], int, double&, double&, int)’
   TH1D *h = new TH1D("h", "negative binomial", 1000, XMin, XMax, 2);
                                                                   ^
In file included from /usr/include/root/TH1D.h:25:0,
                 from /home/bielefeldt/./test.cpp:2,
                 from /home/bielefeldt/test_cpp_ACLiC_dict.h:34,
                 from /home/bielefeldt/test_cpp_ACLiC_dict.cxx:17:
/usr/include/root/TH1.h:585:4: note: candidate: TH1D::TH1D(const TH1D&)
    TH1D(const TH1D &h1d);
    ^~~~
/usr/include/root/TH1.h:585:4: note:   candidate expects 1 argument, 6 provided
/usr/include/root/TH1.h:584:4: note: candidate: TH1D::TH1D(const TVectorD&)
    TH1D(const TVectorD &v);
    ^~~~
/usr/include/root/TH1.h:584:4: note:   candidate expects 1 argument, 6 provided
/usr/include/root/TH1.h:583:4: note: candidate: TH1D::TH1D(const char*, const char*, Int_t, const Double_t*)
    TH1D(const char *name,const char *title,Int_t nbinsx,const Double_t *xbins);
    ^~~~
/usr/include/root/TH1.h:583:4: note:   candidate expects 4 arguments, 6 provided
/usr/include/root/TH1.h:582:4: note: candidate: TH1D::TH1D(const char*, const char*, Int_t, const Float_t*)
    TH1D(const char *name,const char *title,Int_t nbinsx,const Float_t  *xbins);
    ^~~~
/usr/include/root/TH1.h:582:4: note:   candidate expects 4 arguments, 6 provided
/usr/include/root/TH1.h:581:4: note: candidate: TH1D::TH1D(const char*, const char*, Int_t, Double_t, Double_t)
    TH1D(const char *name,const char *title,Int_t nbinsx,Double_t xlow,Double_t xup);
    ^~~~
/usr/include/root/TH1.h:581:4: note:   candidate expects 5 arguments, 6 provided
/usr/include/root/TH1.h:580:4: note: candidate: TH1D::TH1D()
    TH1D();
    ^~~~
/usr/include/root/TH1.h:580:4: note:   candidate expects 0 arguments, 6 provided
g++: error: /home/bielefeldt/test_cpp_ACLiC_dict.o: Datei oder Verzeichnis nicht gefunden
Error in <ACLiC>: Compilation failed!

I modified the example code above so that it can be used with ROOT 5.34, too.

Argh, ok, could have seen that … (and the error msg could have been a bit more helpful^^)

Would you mind explaining a tiny bit how the string with the function and parameters is meant to be understood? Is x just always x? (In the function itself, that’s the variable k, isn’t it?) Why the [0] and [1]? That’s somehow the entries of the parameter array?
The way this is handled still confuses me …

TF1

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.