[3600] | 1 | #include "sopnamsp.h"
|
---|
| 2 | #include "machdefs.h"
|
---|
[3601] | 3 | #include <iostream>
|
---|
[3600] | 4 | #include "pexceptions.h"
|
---|
[3601] | 5 | #include "randr48.h"
|
---|
[3600] | 6 | #include "tsfunran.h"
|
---|
| 7 |
|
---|
| 8 |
|
---|
| 9 | ////////////////////////////////////////////////////////////////////////////
|
---|
| 10 | /*!
|
---|
| 11 | \class SOPHYA::TsFunRan
|
---|
| 12 | \ingroup NTools
|
---|
| 13 | Classe for generating random variables from 1D function
|
---|
| 14 | */
|
---|
| 15 |
|
---|
| 16 |
|
---|
| 17 | /********* Methode *********/
|
---|
| 18 | /*! Creator from a function.
|
---|
| 19 | \verbatim
|
---|
| 20 | - if pdf==true: f est une densite de probabilite (PDF)
|
---|
| 21 | non necessairement normalisee
|
---|
| 22 | if pdf==false: f est une fonction de distribution (DF).
|
---|
| 23 | non necessairement normalisee
|
---|
| 24 | - Le tirage aleatoire est fait sur un histogramme
|
---|
| 25 | Histo(xMin,xMax,nBin) (voir convention dans Histo).
|
---|
| 26 | - Chaque bin de l'histogramme contient la valeur de la PDF
|
---|
| 27 | (ou de la DF) au centre du bin: h(i)=f(BinCenter(i))
|
---|
| 28 | - Les valeurs retournees sont les valeurs du centre des bins
|
---|
| 29 | pour le tirage non interpole et toutes les valeurs
|
---|
| 30 | entre [xmin,xmax] pour le tirage interpole
|
---|
| 31 | - La pdf doit etre interpretee comme etant nulle
|
---|
| 32 | pour des x<=xmin et x>=xmax
|
---|
| 33 | - Dans le bin "i" entre [x1,x2[ et de centre x0, h(i)=pdf(x0).
|
---|
| 34 | Pour le tirage interpole, la DF est approximee par un segment
|
---|
| 35 | et pdf(x0) est l'exces de proba entre x1 et x2:
|
---|
| 36 | bin 0 entre [xmin,BinHighEdge(0)[ :
|
---|
| 37 | la pdf va de 0 a pdf(BinCenter(0))
|
---|
| 38 | bin 1 entre [BinLowEdge(1),BinHighEdge(1)[:
|
---|
| 39 | la pdf va de pdf(BinCenter(0)) a pdf(BinCenter(1))
|
---|
| 40 | ...
|
---|
| 41 | bin n-1 entre [BinLowEdge(n-1),xmax[:
|
---|
| 42 | la pdf va de pdf(BinCenter(n-2)) a pdf(BinCenter(n-1))
|
---|
| 43 | \endverbatim
|
---|
| 44 | */
|
---|
| 45 | TsFunRan::TsFunRan(TsFunRan::Func f, r_8 xMin, r_8 xMax, int_4 nBin, bool pdf)
|
---|
[3601] | 46 | : Histo(xMin,xMax,nBin), rg_(NULL), internal_rg_(false)
|
---|
[3600] | 47 | {
|
---|
| 48 | if(nBin<=1)
|
---|
| 49 | throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
|
---|
| 50 | for(int_4 i=0;i<nBin;i++) (*this)(i) = f(BinCenter(i));
|
---|
[3601] | 51 | rg_ = new DR48RandGen();
|
---|
[3600] | 52 | create_DF(pdf);
|
---|
| 53 | }
|
---|
| 54 |
|
---|
| 55 | /********* Methode *********/
|
---|
| 56 | /*! Creator from a ClassFunc
|
---|
| 57 | See TsFunRan::TsFunRan(TsFunRan::Func...) for further comments.
|
---|
| 58 | */
|
---|
| 59 | TsFunRan::TsFunRan(ClassFunc& f, r_8 xMin, r_8 xMax, int_4 nBin, bool pdf)
|
---|
[3601] | 60 | : Histo(xMin,xMax,nBin), rg_(NULL), internal_rg_(false)
|
---|
[3600] | 61 | {
|
---|
| 62 | if(nBin<=1)
|
---|
| 63 | throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
|
---|
| 64 | for(int_4 i=0;i<nBin;i++) (*this)(i) = f(BinCenter(i));
|
---|
[3601] | 65 | rg_ = new DR48RandGen();
|
---|
[3600] | 66 | create_DF(pdf);
|
---|
| 67 | }
|
---|
| 68 |
|
---|
| 69 | /********* Methode *********/
|
---|
| 70 | /*! Creator from an table.
|
---|
| 71 | If pdf=true, tab is a probability density fonction (not necessary normalised).
|
---|
| 72 | If pdf=false, tab is a distribution function (not necessarly normalized to 1).
|
---|
| 73 | The return random values will be between 0 and nBin-1.
|
---|
| 74 | See TsFunRan::TsFunRan(TsFunRan::Func...) for further comments.
|
---|
| 75 | */
|
---|
| 76 | TsFunRan::TsFunRan(r_8 *tab, int_4 nBin, bool pdf)
|
---|
[3601] | 77 | : Histo(-0.5,nBin-0.5,nBin), rg_(NULL), internal_rg_(false)
|
---|
[3600] | 78 | {
|
---|
| 79 | if(nBin<=1)
|
---|
| 80 | throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
|
---|
| 81 | for(int_4 i=0;i<nBin;i++) (*this)(i) = tab[i];
|
---|
[3601] | 82 | rg_ = new DR48RandGen();
|
---|
[3600] | 83 | create_DF(pdf);
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | /********* Methode *********/
|
---|
| 87 | /*! Creator from an table.
|
---|
| 88 | If pdf=true, tab is a probability density fonction (not necessary normalised).
|
---|
| 89 | If pdf=false, tab is a distribution function (not necessarly normalized to 1).
|
---|
| 90 | The content of tab is identified has the content of
|
---|
| 91 | an Histogram define by Histo(xMin,xMax,nBin).
|
---|
| 92 | See FunRan::TsFunRan(TsFunRan::Func...) for further comments.
|
---|
| 93 | */
|
---|
| 94 | TsFunRan::TsFunRan(r_8 *tab, int_4 nBin, r_8 xMin, r_8 xMax, bool pdf)
|
---|
[3601] | 95 | : Histo(xMin,xMax,nBin), rg_(NULL), internal_rg_(false)
|
---|
[3600] | 96 | {
|
---|
| 97 | if(nBin<=1)
|
---|
| 98 | throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
|
---|
| 99 | for(int_4 i=0;i<nBin;i++) (*this)(i) = tab[i];
|
---|
[3601] | 100 | rg_ = new DR48RandGen();
|
---|
[3600] | 101 | create_DF(pdf);
|
---|
| 102 | }
|
---|
| 103 |
|
---|
| 104 | /********* Methode *********/
|
---|
| 105 | /*! Creator from a TVector
|
---|
| 106 | */
|
---|
| 107 | TsFunRan::TsFunRan(TVector<r_8>& tab, int_4 nBin, bool pdf)
|
---|
[3601] | 108 | : Histo(-0.5,nBin-0.5,nBin), rg_(NULL), internal_rg_(false)
|
---|
[3600] | 109 | {
|
---|
| 110 | if(nBin<=1)
|
---|
| 111 | throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
|
---|
| 112 | for(int_4 i=0;i<nBin;i++) (*this)(i) = tab(i);
|
---|
[3601] | 113 | rg_ = new DR48RandGen();
|
---|
[3600] | 114 | create_DF(pdf);
|
---|
| 115 | }
|
---|
| 116 |
|
---|
| 117 | /********* Methode *********/
|
---|
| 118 | /*! Creator from a TVector
|
---|
| 119 | */
|
---|
| 120 | TsFunRan::TsFunRan(TVector<r_8>& tab, int_4 nBin, r_8 xMin, r_8 xMax, bool pdf)
|
---|
[3601] | 121 | : Histo(xMin,xMax,nBin), rg_(NULL), internal_rg_(false)
|
---|
[3600] | 122 | {
|
---|
| 123 | if(nBin<=1)
|
---|
| 124 | throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
|
---|
| 125 | for(int_4 i=0;i<nBin;i++) (*this)(i) = tab(i);
|
---|
[3601] | 126 | rg_ = new DR48RandGen();
|
---|
[3600] | 127 | create_DF(pdf);
|
---|
| 128 | }
|
---|
| 129 |
|
---|
| 130 | /********* Methode *********/
|
---|
| 131 | /*! Creator from an histogram
|
---|
| 132 | If pdf=true, h is a probability density fonction (not necessary normalised).
|
---|
| 133 | If pdf=false, h is a distribution function (not necessarly normalized to 1).
|
---|
| 134 | See TsFunRan::TsFunRan(TsFunRan::Func...) for further comments.
|
---|
| 135 | */
|
---|
| 136 | TsFunRan::TsFunRan(Histo &h, bool pdf)
|
---|
[3601] | 137 | : Histo(h), rg_(NULL), internal_rg_(false)
|
---|
[3600] | 138 | {
|
---|
| 139 | if(mBins<=1)
|
---|
| 140 | throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
|
---|
[3601] | 141 | rg_ = new DR48RandGen();
|
---|
[3600] | 142 | create_DF(pdf);
|
---|
| 143 | }
|
---|
| 144 |
|
---|
| 145 | /********* Methode *********/
|
---|
| 146 | /*! Creator by copy */
|
---|
| 147 | TsFunRan::TsFunRan(const TsFunRan& fh)
|
---|
[3601] | 148 | : Histo(fh), rg_(fh.rg_), internal_rg_(false)
|
---|
[3600] | 149 | {
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | /********* Methode *********/
|
---|
| 153 | /*! Creator by default */
|
---|
| 154 | TsFunRan::TsFunRan(void)
|
---|
[3601] | 155 | : rg_(NULL), internal_rg_(false)
|
---|
[3600] | 156 | {
|
---|
| 157 | }
|
---|
| 158 |
|
---|
| 159 | /********* Methode *********/
|
---|
| 160 | TsFunRan::~TsFunRan(void)
|
---|
| 161 | {
|
---|
[3601] | 162 | if(rg_!=NULL && internal_rg_) delete rg_;
|
---|
[3600] | 163 | }
|
---|
| 164 |
|
---|
| 165 | /********* Methode *********/
|
---|
| 166 | void TsFunRan::create_DF(bool pdf)
|
---|
| 167 | // Creation (si necessaire) et normalisation de la DF
|
---|
| 168 | {
|
---|
| 169 | // On fabrique la FD si necessaire
|
---|
| 170 | if(pdf)
|
---|
| 171 | for(int_4 i=1;i<mBins;i++) (*this)(i) += (*this)(i-1);
|
---|
| 172 |
|
---|
| 173 | // On normalise la FD
|
---|
| 174 | if((*this)(mBins-1)<=0.) {
|
---|
| 175 | cout<<"TsFunRan::TsFunRan(Histo) not a distribution function last bin is <=0"<<endl;
|
---|
| 176 | throw RangeCheckError("TsFunRan::TsFunRan(Histo) not a distribution function last bin is <=0");
|
---|
| 177 | }
|
---|
| 178 | for(int_4 i=0;i<mBins;i++) (*this)(i) /= (*this)(mBins-1);
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | /********* Methode *********/
|
---|
[3601] | 182 | void TsFunRan::SetRandomGenerator(RandomGeneratorInterface* rg)
|
---|
[3600] | 183 | {
|
---|
[3601] | 184 | if(rg_!=NULL && internal_rg_) delete rg_;
|
---|
| 185 | rg_ = rg;
|
---|
[3600] | 186 | }
|
---|
| 187 |
|
---|
| 188 | /********* Methode *********/
|
---|
| 189 | /*! Tirage avec retour du numero de bin entre 0 et mBins-1.
|
---|
| 190 | It returns the first bin whose content is greater or equal
|
---|
| 191 | to the random uniform number (in [0,1[)
|
---|
| 192 | */
|
---|
| 193 | int_4 TsFunRan::BinRandom()
|
---|
| 194 | {
|
---|
| 195 | // recherche du premier bin plus grand ou egal a z
|
---|
| 196 | r_8 z=rg_->Flat01();
|
---|
| 197 | for(int_4 i=0;i<mBins;i++) if(z<(*this)(i)) return i;
|
---|
| 198 | return mBins-1;
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 | /********* Methode *********/
|
---|
| 202 | /*! Tirage avec retour abscisse du bin non interpole. */
|
---|
| 203 | r_8 TsFunRan::Random()
|
---|
| 204 | {
|
---|
| 205 | r_8 z=rg_->Flat01();
|
---|
| 206 | int ibin = mBins-1;
|
---|
| 207 | for(int_4 i=0;i<mBins;i++) if(z<(*this)(i)) {ibin=i; break;}
|
---|
| 208 | return BinCenter(ibin);
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 | /********* Methode *********/
|
---|
| 212 | /*! Tirage avec retour abscisse du bin interpole. */
|
---|
| 213 | r_8 TsFunRan::RandomInterp(void)
|
---|
| 214 | {
|
---|
| 215 | r_8 z=rg_->Flat01();
|
---|
| 216 | int ibin = mBins-1;
|
---|
| 217 | r_8 z1=0., z2;
|
---|
| 218 | for(int_4 i=0;i<mBins;i++) {
|
---|
| 219 | z2 = (*this)(i);
|
---|
| 220 | if(z<z2) {ibin=i; break;}
|
---|
| 221 | z1 = z2;
|
---|
| 222 | }
|
---|
| 223 |
|
---|
| 224 | // l'algorithme garanti que "z2-z1 != 0" et "z1<z2"
|
---|
| 225 | return BinLowEdge(ibin) + (z-z1)/(z2-z1)*binWidth;
|
---|
| 226 |
|
---|
| 227 | }
|
---|
| 228 |
|
---|