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

Last change on this file since 3109 was 3109, checked in by cmv, 19 years ago

RandomInterp() + documentation FunRan et Tirage gaussien cmv 20/11/06

File size: 8.7 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 an histogram
102If pdf=true, h is a probability density fonction (not necessary normalised).
103If pdf=false, h is a distribution function (not necessarly normalized to 1).
104See FunRan::FunRan(FunRan::Func...) for further comments.
105*/
106FunRan::FunRan(Histo &h, bool pdf)
107 : Histo(h)
108{
109 if(mBins<=1)
110 throw RangeCheckError("FunRan::FunRan less than 2 bins requested");
111 create_DF(pdf);
112}
113
114/********* Methode *********/
115void FunRan::create_DF(bool pdf)
116// Creation (si necessaire) et normalisation de la DF
117{
118 // On fabrique la FD si necessaire
119 if(pdf)
120 for(int_4 i=1;i<mBins;i++) (*this)(i) += (*this)(i-1);
121
122 // On normalise la FD
123 if((*this)(mBins-1)<=0.)
124 throw RangeCheckError("FunRan::FunRan(Histo) not a distribution function last bin is <=0");
125 for(int_4 i=0;i<mBins;i++) (*this)(i) /= (*this)(mBins-1);
126}
127
128/********* Methode *********/
129/*! Tirage avec retour du numero de bin entre 0 et mBins-1.
130It returns the first bin whose content is greater or equal
131to the random uniform number (in [0,1[)
132*/
133int_4 FunRan::BinRandom()
134{
135 // recherche du premier bin plus grand ou egal a z
136 r_8 z=drand01();
137 for(int_4 i=0;i<mBins;i++) if(z<(*this)(i)) return i;
138 return mBins-1;
139}
140
141/********* Methode *********/
142/*! Tirage avec retour abscisse du bin non interpole. */
143r_8 FunRan::Random()
144{
145 r_8 z=drand01();
146 int ibin = mBins-1;
147 for(int_4 i=0;i<mBins;i++) if(z<(*this)(i)) {ibin=i; break;}
148 return BinCenter(ibin);
149}
150
151/********* Methode *********/
152/*! Tirage avec retour abscisse du bin interpole. */
153r_8 FunRan::RandomInterp(void)
154{
155 r_8 z=drand01();
156 int ibin = mBins-1;
157 r_8 z1=0., z2;
158 for(int_4 i=0;i<mBins;i++) {
159 z2 = (*this)(i);
160 if(z<z2) {ibin=i; break;}
161 z1 = z2;
162 }
163
164 // l'algorithme garanti que "z2-z1 != 0" et "z1<z2"
165 return BinLowEdge(ibin) + (z-z1)/(z2-z1)*binWidth;
166
167}
168
169////////////////////////////////////////////////////////////////////////////
170/*!
171 \class SOPHYA::FunRan2D
172 \ingroup NTools
173 Classe for generating random variables from 2D function
174*/
175
176/********* Methode *********/
177/*! Creator for random from a table */
178FunRan2D::FunRan2D(r_8 *tab, int_4 nBinX, int_4 nBinY)
179{
180 // Tirage en X, somme sur les Y.
181 r_8* tabX = new r_8[nBinX];
182 for (int_4 i=0; i<nBinX; i++) {
183 tabX[i] = 0;
184 for (int_4 j=0; j<nBinY; j++) {
185 tabX[i] += tab[i*nBinY +j];
186 }
187 }
188 ranX = new FunRan(tabX, nBinX);
189 delete[] tabX;
190
191 ranY = new FunRan* [nBinX];
192
193 for (int_4 k=0; k<nBinX; k++)
194 ranY[k] = new FunRan(tab + nBinY*k, nBinY);
195
196 nx = nBinX;
197}
198
199/********* Methode *********/
200/*! Creator for random from a table */
201FunRan2D::FunRan2D(r_8 **tab, int_4 nBinX, int_4 nBinY)
202{
203 // Tirage en X, somme sur les Y.
204 r_8* tabX = new r_8[nBinX];
205 for (int_4 i=0; i<nBinX; i++) {
206 tabX[i] = 0;
207 for (int_4 j=0; j<nBinY; j++) {
208 tabX[i] += tab[i][j];
209 }
210 }
211 ranX = new FunRan(tabX, nBinX);
212
213 ranY = new FunRan* [nBinX];
214
215 for (int_4 k=0; k<nBinX; k++)
216 if (tabX[k] != 0)
217 ranY[k] = new FunRan(tab[k], nBinY);
218 else ranY[k] = NULL;
219
220 delete[] tabX;
221 nx = nBinX;
222}
223
224/********* Methode *********/
225/*! Destructor */
226FunRan2D::~FunRan2D()
227{
228 for (int_4 i=nx-1; i>=0; i--)
229 delete ranY[i];
230
231 delete[] ranY;
232
233 delete ranX;
234}
235
236/********* Methode *********/
237/*! Tirage avec retour du numeros de bin. */
238void FunRan2D::BinRandom(int_4& x, int_4& y)
239{
240 x = ranX->BinRandom();
241 y = ranY[x]->BinRandom();
242}
243
244/********* Methode *********/
245/*! Tirage avec retour abscisse et ordonnee du bin interpole. */
246void FunRan2D::Random(r_8& x, r_8& y)
247{
248 x = ranX->Random();
249 int_4 i = int_4(ceil(x));
250 y = ranY[i]->Random();
251}
252
253
254
255/////////////////////////////////////////////////////////////////
256/*
257**** Remarques sur complex< r_8 > ComplexGaussRan(double sig) ****
258
259--- variables gaussiennes x,y independantes
260x gaussien: pdf f(x) = 1/(sqrt(2Pi) Sx) exp(-(x-Mx)^2/(2 Sx^2))
261y gaussien: pdf f(y) = 1/(sqrt(2Pi) Sy) exp(-(y-My)^2/(2 Sy^2))
262x,y independants --> pdf f(x,y) = f(x) f(y)
263On a:
264 <x> = Integrate[x*f(x)] = Mx
265 <x^2> = Integrate[x^2*f(x)] = Mx^2 + Sx^2
266
267--- On cherche la pdf g(r,t) du module et de la phase
268 x = r cos(t) , y = r sin(t)
269 r=sqrt(x^2+y^2 , t=atan2(y,x)
270 (r,t) --> (x,y): le Jacobien = r
271
272 g(r,t) = r f(x,y) = r f(x) f(y)
273 = r/(2Pi Sx Sy) exp(-(x-Mx)^2/(2 Sx^2)) exp(-(y-My)^2/(2 Sy^2))
274
275- Le cas general est complique
276 (cf D.Pelat cours DEA "bruits et signaux" section 4.5)
277
278- Cas ou "Mx = My = 0" et "Sx = Sy = S"
279 c'est la pdf du module et de la phase d'un nombre complexe
280 dont les parties reelles et imaginaires sont independantes
281 et sont distribuees selon des gaussiennes de variance S^2
282 g(r,t) = r/(2Pi S^2) exp(-r^2/(2 S^2))
283 La distribution de "r" est donc:
284 g(r) = Integrate[g(r,t),{t,0,2Pi}]
285 = r/S^2 exp(-r^2/(2 S^2))
286 La distribution de "t" est donc:
287 g(t) = Integrate[g(r,t),{r,0,Infinity}]
288 = 1 / 2Pi (distribution uniforme sur [0,2Pi[)
289 Les variables aleatoires r,t sont independantes:
290 g(r,t) = g(r) g(t)
291On a:
292 <r> = Integrate[r*g(r)] = sqrt(PI/2)*S
293 <r^2> = Integrate[r^2*g(r)] = 2*S^2
294 <r^3> = Integrate[r^3*g(r)] = 3*sqrt(PI/2)*S^3
295 <r^4> = Integrate[r^4*g(r)] = 8*S^4
296
297- Attention:
298La variable complexe "c = x+iy = r*exp(i*t)" ainsi definie verifie:
299 <|c|^2> = <c c*> = <x^2+y^2> = <r^2> = 2 S^2
300Si on veut generer une variable complexe gaussienne telle que
301 <c c*> = s^2 alors il faut prendre S = s/sqrt(2) comme argument
302
303*/
Note: See TracBrowser for help on using the repository browser.