source: Sophya/trunk/SophyaLib/NTools/perandom.cc@ 3608

Last change on this file since 3608 was 3608, checked in by cmv, 16 years ago

delete de tsfunran.cc,h sans interet + FunRan avec TVector, cmv 29/04/2009

File size: 9.6 KB
Line 
1#include "sopnamsp.h"
2#include "machdefs.h"
3#include "pexceptions.h"
4#include "perandom.h"
5#include "pemath.h"
6#include <iostream>
7
8
9////////////////////////////////////////////////////////////////////////////
10/*!
11 \class SOPHYA::FunRan
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*/
45FunRan::FunRan(FunRan::Func f, r_8 xMin, r_8 xMax, int_4 nBin, bool pdf)
46 : Histo(xMin,xMax,nBin)
47{
48 if(nBin<=1)
49 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
50 for(int_4 i=0;i<nBin;i++) (*this)(i) = f(BinCenter(i));
51 create_DF(pdf);
52}
53
54/********* Methode *********/
55/*! Creator from a ClassFunc
56See FunRan::FunRan(FunRan::Func...) for further comments.
57*/
58FunRan::FunRan(ClassFunc& f, r_8 xMin, r_8 xMax, int_4 nBin, bool pdf)
59 : Histo(xMin,xMax,nBin)
60{
61 if(nBin<=1)
62 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
63 for(int_4 i=0;i<nBin;i++) (*this)(i) = f(BinCenter(i));
64 create_DF(pdf);
65}
66
67/********* Methode *********/
68/*! Creator from an table.
69If pdf=true, tab is a probability density fonction (not necessary normalised).
70If pdf=false, tab is a distribution function (not necessarly normalized to 1).
71The return random values will be between 0 and nBin-1.
72See FunRan::FunRan(FunRan::Func...) for further comments.
73*/
74FunRan::FunRan(r_8 *tab, int_4 nBin, bool pdf)
75: Histo(-0.5,nBin-0.5,nBin)
76{
77 if(nBin<=1)
78 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
79 for(int_4 i=0;i<nBin;i++) (*this)(i) = tab[i];
80 create_DF(pdf);
81}
82
83/********* Methode *********/
84/*! Creator from an table.
85If pdf=true, tab is a probability density fonction (not necessary normalised).
86If pdf=false, tab is a distribution function (not necessarly normalized to 1).
87The content of tab is identified has the content of
88an Histogram define by Histo(xMin,xMax,nBin).
89See FunRan::FunRan(FunRan::Func...) for further comments.
90*/
91FunRan::FunRan(r_8 *tab, int_4 nBin, r_8 xMin, r_8 xMax, bool pdf)
92: Histo(xMin,xMax,nBin)
93{
94 if(nBin<=1)
95 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
96 for(int_4 i=0;i<nBin;i++) (*this)(i) = tab[i];
97 create_DF(pdf);
98}
99
100/********* Methode *********/
101/*! Creator from a TVector
102*/
103FunRan::FunRan(TVector<r_8>& tab, bool pdf)
104: Histo(-0.5,tab.Size()-0.5,tab.Size())
105{
106 if(tab.Size()<=1)
107 throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
108 for(int_4 i=0;i<tab.Size();i++) (*this)(i) = tab(i);
109 create_DF(pdf);
110}
111
112/********* Methode *********/
113/*! Creator from a TVector
114*/
115FunRan::FunRan(TVector<r_8>& tab, r_8 xMin, r_8 xMax, bool pdf)
116: Histo(xMin,xMax,tab.Size())
117{
118 if(tab.Size()<=1)
119 throw RangeCheckError("TsFunRan::TsFunRan less than 2 bins requested");
120 for(int_4 i=0;i<tab.Size();i++) (*this)(i) = tab(i);
121 create_DF(pdf);
122}
123
124/********* Methode *********/
125/*! Creator from an histogram
126If pdf=true, h is a probability density fonction (not necessary normalised).
127If pdf=false, h is a distribution function (not necessarly normalized to 1).
128See FunRan::FunRan(FunRan::Func...) for further comments.
129*/
130FunRan::FunRan(Histo &h, bool pdf)
131 : Histo(h)
132{
133 if(mBins<=1)
134 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
135 create_DF(pdf);
136}
137
138/********* Methode *********/
139/*! Creator by copy */
140FunRan::FunRan(const FunRan& fh)
141 : Histo(fh)
142{
143}
144
145/********* Methode *********/
146/*! Creator by default */
147FunRan::FunRan(void)
148{
149}
150
151/********* Methode *********/
152void FunRan::create_DF(bool pdf)
153// Creation (si necessaire) et normalisation de la DF
154{
155 // On fabrique la FD si necessaire
156 if(pdf)
157 for(int_4 i=1;i<mBins;i++) (*this)(i) += (*this)(i-1);
158
159 // On normalise la FD
160 if((*this)(mBins-1)<=0.) {
161 cout<<"FunRan::FunRan(Histo) not a distribution function last bin is <=0"<<endl;
162 throw RangeCheckError("FunRan::FunRan(Histo) not a distribution function last bin is <=0");
163 }
164 for(int_4 i=0;i<mBins;i++) (*this)(i) /= (*this)(mBins-1);
165}
166
167/********* Methode *********/
168/*! Tirage avec retour du numero de bin entre 0 et mBins-1.
169It returns the first bin whose content is greater or equal
170to the random uniform number (in [0,1[)
171*/
172int_4 FunRan::BinRandom()
173{
174 // recherche du premier bin plus grand ou egal a z
175 r_8 z=drand01();
176 for(int_4 i=0;i<mBins;i++) if(z<(*this)(i)) return i;
177 return mBins-1;
178}
179
180/********* Methode *********/
181/*! Tirage avec retour abscisse du bin non interpole. */
182r_8 FunRan::Random()
183{
184 r_8 z=drand01();
185 int ibin = mBins-1;
186 for(int_4 i=0;i<mBins;i++) if(z<(*this)(i)) {ibin=i; break;}
187 return BinCenter(ibin);
188}
189
190/********* Methode *********/
191/*! Tirage avec retour abscisse du bin interpole. */
192r_8 FunRan::RandomInterp(void)
193{
194 r_8 z=drand01();
195 int ibin = mBins-1;
196 r_8 z1=0., z2;
197 for(int_4 i=0;i<mBins;i++) {
198 z2 = (*this)(i);
199 if(z<z2) {ibin=i; break;}
200 z1 = z2;
201 }
202
203 // l'algorithme garanti que "z2-z1 != 0" et "z1<z2"
204 return BinLowEdge(ibin) + (z-z1)/(z2-z1)*binWidth;
205
206}
207
208////////////////////////////////////////////////////////////////////////////
209/*!
210 \class SOPHYA::FunRan2D
211 \ingroup NTools
212 Classe for generating random variables from 2D function
213*/
214
215/********* Methode *********/
216/*! Creator for random from a table */
217FunRan2D::FunRan2D(r_8 *tab, int_4 nBinX, int_4 nBinY)
218{
219 // Tirage en X, somme sur les Y.
220 r_8* tabX = new r_8[nBinX];
221 for (int_4 i=0; i<nBinX; i++) {
222 tabX[i] = 0;
223 for (int_4 j=0; j<nBinY; j++) {
224 tabX[i] += tab[i*nBinY +j];
225 }
226 }
227 ranX = new FunRan(tabX, nBinX);
228 delete[] tabX;
229
230 ranY = new FunRan* [nBinX];
231
232 for (int_4 k=0; k<nBinX; k++)
233 ranY[k] = new FunRan(tab + nBinY*k, nBinY);
234
235 nx = nBinX;
236}
237
238/********* Methode *********/
239/*! Creator for random from a table */
240FunRan2D::FunRan2D(r_8 **tab, int_4 nBinX, int_4 nBinY)
241{
242 // Tirage en X, somme sur les Y.
243 r_8* tabX = new r_8[nBinX];
244 for (int_4 i=0; i<nBinX; i++) {
245 tabX[i] = 0;
246 for (int_4 j=0; j<nBinY; j++) {
247 tabX[i] += tab[i][j];
248 }
249 }
250 ranX = new FunRan(tabX, nBinX);
251
252 ranY = new FunRan* [nBinX];
253
254 for (int_4 k=0; k<nBinX; k++)
255 if (tabX[k] != 0)
256 ranY[k] = new FunRan(tab[k], nBinY);
257 else ranY[k] = NULL;
258
259 delete[] tabX;
260 nx = nBinX;
261}
262
263/********* Methode *********/
264/*! Destructor */
265FunRan2D::~FunRan2D()
266{
267 for (int_4 i=nx-1; i>=0; i--)
268 delete ranY[i];
269
270 delete[] ranY;
271
272 delete ranX;
273}
274
275/********* Methode *********/
276/*! Tirage avec retour du numeros de bin. */
277void FunRan2D::BinRandom(int_4& x, int_4& y)
278{
279 x = ranX->BinRandom();
280 y = ranY[x]->BinRandom();
281}
282
283/********* Methode *********/
284/*! Tirage avec retour abscisse et ordonnee du bin interpole. */
285void FunRan2D::Random(r_8& x, r_8& y)
286{
287 x = ranX->Random();
288 int_4 i = int_4(ceil(x));
289 y = ranY[i]->Random();
290}
291
292
293
294/////////////////////////////////////////////////////////////////
295/*
296**** Remarques sur complex< r_8 > ComplexGaussRan(double sig) ****
297
298--- variables gaussiennes x,y independantes
299x gaussien: pdf f(x) = 1/(sqrt(2Pi) Sx) exp(-(x-Mx)^2/(2 Sx^2))
300y gaussien: pdf f(y) = 1/(sqrt(2Pi) Sy) exp(-(y-My)^2/(2 Sy^2))
301x,y independants --> pdf f(x,y) = f(x) f(y)
302On a:
303 <x> = Integrate[x*f(x)] = Mx
304 <x^2> = Integrate[x^2*f(x)] = Mx^2 + Sx^2
305
306--- On cherche la pdf g(r,t) du module et de la phase
307 x = r cos(t) , y = r sin(t)
308 r=sqrt(x^2+y^2 , t=atan2(y,x)
309 (r,t) --> (x,y): le Jacobien = r
310
311 g(r,t) = r f(x,y) = r f(x) f(y)
312 = r/(2Pi Sx Sy) exp(-(x-Mx)^2/(2 Sx^2)) exp(-(y-My)^2/(2 Sy^2))
313
314- Le cas general est complique
315 (cf D.Pelat cours DEA "bruits et signaux" section 4.5)
316
317- Cas ou "Mx = My = 0" et "Sx = Sy = S"
318 c'est la pdf du module et de la phase d'un nombre complexe
319 dont les parties reelles et imaginaires sont independantes
320 et sont distribuees selon des gaussiennes de variance S^2
321 g(r,t) = r/(2Pi S^2) exp(-r^2/(2 S^2))
322 La distribution de "r" est donc:
323 g(r) = Integrate[g(r,t),{t,0,2Pi}]
324 = r/S^2 exp(-r^2/(2 S^2))
325 La distribution de "t" est donc:
326 g(t) = Integrate[g(r,t),{r,0,Infinity}]
327 = 1 / 2Pi (distribution uniforme sur [0,2Pi[)
328 Les variables aleatoires r,t sont independantes:
329 g(r,t) = g(r) g(t)
330On a:
331 <r> = Integrate[r*g(r)] = sqrt(PI/2)*S
332 <r^2> = Integrate[r^2*g(r)] = 2*S^2
333 <r^3> = Integrate[r^3*g(r)] = 3*sqrt(PI/2)*S^3
334 <r^4> = Integrate[r^4*g(r)] = 8*S^4
335
336- Attention:
337La variable complexe "c = x+iy = r*exp(i*t)" ainsi definie verifie:
338 <|c|^2> = <c c*> = <x^2+y^2> = <r^2> = 2 S^2
339Si on veut generer une variable complexe gaussienne telle que
340 <c c*> = s^2 alors il faut prendre S = s/sqrt(2) comme argument
341
342*/
Note: See TracBrowser for help on using the repository browser.