Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TUnuranSampler.cxx
Go to the documentation of this file.
1 // @(#)root/unuran:$Id$
2 // Authors: L. Moneta, J. Leydold Wed Feb 28 2007
3 
4 /**********************************************************************
5  * *
6  * Copyright (c) 2010 LCG ROOT Math Team, CERN/PH-SFT *
7  * *
8  * *
9  **********************************************************************/
10 
11 // Implementation file for class TUnuranSampler
12 #include "TUnuranSampler.h"
13 
14 #include "TUnuranContDist.h"
15 #include "TUnuranDiscrDist.h"
16 #include "TUnuranMultiContDist.h"
17 #include "TUnuran.h"
20 #include "Fit/DataRange.h"
21 //#include "Math/WrappedTF1.h"
22 
23 #include "TRandom.h"
24 #include "TError.h"
25 
26 #include "TF1.h"
27 #include <cassert>
28 #include <cmath>
29 
30 ClassImp(TUnuranSampler);
31 
32 TUnuranSampler::TUnuranSampler() : ROOT::Math::DistSampler(),
33  fOneDim(false),
34  fDiscrete(false),
35  fHasMode(false), fHasArea(false),
36  fMode(0), fArea(0),
37  fFunc1D(0),
38  fUnuran(new TUnuran() )
39 {
40  fLevel = ROOT::Math::DistSamplerOptions::DefaultPrintLevel();
41 }
42 
43 TUnuranSampler::~TUnuranSampler() {
44  assert(fUnuran != 0);
45  delete fUnuran;
46 }
47 
48 bool TUnuranSampler::Init(const char * algo) {
49  // initialize unuran classes using the given algorithm
50  assert (fUnuran != 0 );
51  if (NDim() == 0) {
52  Error("TUnuranSampler::Init","Distribution function has not been set ! Need to call SetFunction first.");
53  return false;
54  }
55 
56  if (fLevel < 0) fLevel = ROOT::Math::DistSamplerOptions::DefaultPrintLevel();
57 
58  TString method(algo);
59  if (method.IsNull() ) {
60  if (NDim() == 1) method = ROOT::Math::DistSamplerOptions::DefaultAlgorithm1D();
61  else method = ROOT::Math::DistSamplerOptions::DefaultAlgorithmND();
62  }
63  method.ToUpper();
64 
65  bool ret = false;
66  if (NDim() == 1) {
67  // check if distribution is discrete by
68  // using first string in the method name is "D"
69  if (method.First("D") == 0) {
70  if (fLevel>1) Info("TUnuranSampler::Init","Initialize one-dim discrete distribution with method %s",method.Data());
71  ret = DoInitDiscrete1D(method);
72  }
73  else {
74  if (fLevel>1) Info("TUnuranSampler::Init","Initialize one-dim continuous distribution with method %s",method.Data());
75  ret = DoInit1D(method);
76  }
77  }
78  else {
79  if (fLevel>1) Info("TUnuranSampler::Init","Initialize multi-dim continuous distribution with method %s",method.Data());
80  ret = DoInitND(method);
81  }
82  // set print level in UNURAN (must be done after having initialized) -
83  if (fLevel>0) {
84  //fUnuran->SetLogLevel(fLevel); ( seems not to work disable for the time being)
85  if (ret) Info("TUnuranSampler::Init","Successfully initailized Unuran with method %s",method.Data() );
86  else Error("TUnuranSampler::Init","Failed to initailize Unuran with method %s",method.Data() );
87  // seems not to work in UNURAN (cll only when level > 0 )
88  }
89  return ret;
90 }
91 
92 
93 bool TUnuranSampler::Init(const ROOT::Math::DistSamplerOptions & opt ) {
94  // default initialization with algorithm name
95  SetPrintLevel(opt.PrintLevel() );
96  return Init(opt.Algorithm().c_str() );
97 }
98 
99 
100 bool TUnuranSampler::DoInit1D(const char * method) {
101  // initilize for 1D sampling
102  // need to create 1D interface from Multidim one
103  // (to do: use directly 1D functions ??)
104  fOneDim = true;
105  TUnuranContDist * dist = 0;
106  if (fFunc1D == 0) {
107  ROOT::Math::OneDimMultiFunctionAdapter<> function(ParentPdf() );
108  dist = new TUnuranContDist(function,0,false,true);
109  }
110  else {
111  dist = new TUnuranContDist(*fFunc1D); // no need to copy the function
112  }
113  // set range in distribution (support only one range)
114  const ROOT::Fit::DataRange & range = PdfRange();
115  if (range.Size(0) > 0) {
116  double xmin, xmax;
117  range.GetRange(0,xmin,xmax);
118  dist->SetDomain(xmin,xmax);
119  }
120  if (fHasMode) dist->SetMode(fMode);
121  if (fHasArea) dist->SetPdfArea(fArea);
122 
123  bool ret = false;
124  if (method) ret = fUnuran->Init(*dist, method);
125  else ret = fUnuran->Init(*dist);
126  delete dist;
127  return ret;
128 }
129 
130 bool TUnuranSampler::DoInitDiscrete1D(const char * method) {
131  // initilize for 1D sampling of discrete distributions
132  fOneDim = true;
133  fDiscrete = true;
134  TUnuranDiscrDist * dist = 0;
135  if (fFunc1D == 0) {
136  // need to copy the passed function pointer in this case
137  ROOT::Math::OneDimMultiFunctionAdapter<> function(ParentPdf() );
138  dist = new TUnuranDiscrDist(function,true);
139  }
140  else {
141  // no need to copy the function since fFunc1D is managed outside
142  dist = new TUnuranDiscrDist(*fFunc1D, false);
143  }
144  // set range in distribution (support only one range)
145  // otherwise 0, inf is assumed
146  const ROOT::Fit::DataRange & range = PdfRange();
147  if (range.Size(0) > 0) {
148  double xmin, xmax;
149  range.GetRange(0,xmin,xmax);
150  if (xmin < 0) {
151  Warning("DoInitDiscrete1D","range starts from negative values - set minimum to zero");
152  xmin = 0;
153  }
154  dist->SetDomain(int(xmin+0.1),int(xmax+0.1));
155  }
156  if (fHasMode) dist->SetMode(int(fMode+0.1));
157  if (fHasArea) dist->SetProbSum(fArea);
158 
159  bool ret = fUnuran->Init(*dist, method);
160  delete dist;
161  return ret;
162 }
163 
164 
165 bool TUnuranSampler::DoInitND(const char * method) {
166  // initilize for 1D sampling
167  TUnuranMultiContDist dist(ParentPdf());
168  // set range in distribution (support only one range)
169  const ROOT::Fit::DataRange & range = PdfRange();
170  if (range.IsSet()) {
171  std::vector<double> xmin(range.NDim() );
172  std::vector<double> xmax(range.NDim() );
173  range.GetRange(&xmin[0],&xmax[0]);
174  dist.SetDomain(&xmin.front(),&xmax.front());
175 // std::cout << " range is min = ";
176 // for (int j = 0; j < NDim(); ++j) std::cout << xmin[j] << " ";
177 // std::cout << " max = ";
178 // for (int j = 0; j < NDim(); ++j) std::cout << xmax[j] << " ";
179 // std::cout << std::endl;
180  }
181  fOneDim = false;
182  if (method) return fUnuran->Init(dist, method);
183  return fUnuran->Init(dist);
184 }
185 
186 void TUnuranSampler::SetFunction(TF1 * pdf) {
187  // set function from a TF1 pointer
188  SetFunction<TF1>(*pdf, pdf->GetNdim());
189 }
190 
191 void TUnuranSampler::SetRandom(TRandom * r) {
192  // set random generator (must be called before Init to have effect)
193  fUnuran->SetRandom(r);
194 }
195 
196 void TUnuranSampler::SetSeed(unsigned int seed) {
197  // set random generator seed (must be called before Init to have effect)
198  fUnuran->SetSeed(seed);
199 }
200 
201 TRandom * TUnuranSampler::GetRandom() {
202  // get random generator used
203  return fUnuran->GetRandom();
204 }
205 
206 double TUnuranSampler::Sample1D() {
207  // sample 1D distributions
208  return (fDiscrete) ? (double) fUnuran->SampleDiscr() : fUnuran->Sample();
209 }
210 
211 bool TUnuranSampler::Sample(double * x) {
212  // sample multi-dim distributions
213  if (!fOneDim) return fUnuran->SampleMulti(x);
214  x[0] = Sample1D();
215  return true;
216 }
217 
218 
219 bool TUnuranSampler::SampleBin(double prob, double & value, double *error) {
220  // sample a bin according to Poisson statistics
221 
222  TRandom * r = fUnuran->GetRandom();
223  if (!r) return false;
224  value = r->Poisson(prob);
225  if (error) *error = std::sqrt(value);
226  return true;
227 }