1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
|
;
; Alain Coulais, 5 Janvier 2011, under GNU GPL v2 or later
;
; few tests can help to check whether the
; computations are in good range or not
;
; this code should be able to run on box without X11,
; and should be OK for Z, SVG and PS
;
; Nota-bene : IDL moved to Mersemme Twister since 8.2.2
;
; ---------------------------------------
; Modifications history :
;
; - 2017-11-09 : AC (uncommited at that time)
; * renaming with prefix "TEST_";
; * adding error counting for TEST_RANDOM_BINOMIAL.
; * adding TEST_RANDOM_MERSENNE since GDL can now have
; same numerical outputs than IDL since 8.4 (and FL since 0.79.41)
; * adding TEST_RANDOM_ULONG
;
; - 2017-12-13 : AC. adding TEST_RANDOM_POISSON, num. tests found.
;
; ----------------------------------------------
;
function STATUS_VERSION_OF_RANDOM, verbose=verbose, test=test
;
status=1
;
DEFSYSV, '!gdl', exists=isGDL
;
; Mersenne Twister in GDL since March 20, 2017 ...
; rev. 1.143 in "gsl_fin.cpp", GDL 0.9.7 CVS, Epoch ~1490047893
;
mess1_GDL_obsolete='Obsolete GDL version, Mersenne Twister Random not in use'
mess2a_GDL_maybe='MAY BE Obsolete GDL version'
mess2b_GDL_maybe='MAY BE Mersenne Twister Random not in use'
mess3_IDL_obsolete='Obsolete IDL version, Mersenne Twister Random not in use'
;
if isGDL then begin
;; testing the GDL side/version
;;
if KEYWORD_SET(verbose) then begin
MESSAGE, /continue, 'GDL detected'
help, /struct, !gdl
help, /struct, !version
endif
;;
gdl_version=GDL_VERSION()
;;
;; before 0.9.7, always not OK; since 0.9.8 always OK
;; always OK since 0.9.7 SVN,
;;
if (gdl_version LT 907) then begin
MESSAGE, /Continue, mess1_GDL_obsolete
status=0
endif else begin
if (gdl_version EQ 907) then begin
if (!gdl.epoch LT 1490047893L) then begin
MESSAGE, /Continue, mess1_GDL_obsolete
status=0
endif else begin
if (STRPOS(!GDL.release, 'SVN') LT 0) then begin
;; we don't put status wrong but result may be wrong !!
MESSAGE, /Continue, mess2a_GDL_maybe
MESSAGE, /Continue, mess2b_GDL_maybe
endif
endelse
endif
endelse
endif else begin
if KEYWORD_SET(verbose) then begin
MESSAGE, /continue, 'IDL detected'
help, /struct, !version
endif
;; testing IDL side
if (!version.release LT '8.2.2') then begin
MESSAGE, /Continue, mess3_IDL_obsolete
MESSAGE, /Continue, 'Required IDL version > 8.2.2'
MESSAGE, /Continue, 'Detected IDL version '+!version.release
status=0
endif
endelse
;
if KEYWORD_SET(test) then STOP
;
return, status
;
end
;
; ----------------------------------------------
; Warning ! We have to carrefully manage SEED to
; be able to call multiple times the code ...
; OK in FL 41, IDL 84 and GDL 0.9.8 (0.9.7 CVS/SVN)
;
pro TEST_RANDOM_MERSENNE, cumul_errors, test=test, verbose=verbose
;
nb_errors=0
;
; tolerance
eps = 1e-5
;
; seed value : not a parameter because fixed numerical outputs ...
seed=10
;
nbp=20
indices=4*INDGEN(5)
;;
; /RAN1 could be used to insure that the values returned are equal with the non-parallel old mersenne twister,
; as /RAN1 gives values identical to IDL. However it would be necessary to modify the logic below.
;
if dsfmt_exists() then begin
exptd_u_f=[0.683328,0.511748,0.712392,0.974657,0.267097]
exptd_u_d=[ 0.6833279104279921, 0.5117476599880262, 0.7123919069196021, 0.9746571081546436, 0.2670968079969038]
exptd_n_f=[ -1.0257840, -0.8902389, 0.2266469, 0.2755476, 0.9339375]
exptd_n_d=[ -1.0257840075947602, -0.8902389633612189, 0.2266468876086417, 0.2755475765848067, 0.9339375254286939]
endif else begin
exptd_u_f=[0.771321, 0.633648, 0.498507, 0.198063, 0.169111]
exptd_u_d=[0.77132064, 0.49850701, 0.16911084, 0.0039482663, 0.72175532]
exptd_n_f=[-0.746100, -0.872054, 2.67669, -0.797426, 1.13531]
exptd_n_d=[1.3315865, 0.62133597, 0.0042914309, -0.96506567, -1.1366022]
endelse
fseed=seed
res=RANDOMU(fseed, nbp) & res=res[indices]
if (MAX(ABS(exptd_u_f-res)) GT eps) then ERRORS_ADD, nb_errors, 'Rand U & Float'
;
fseed=seed
res=RANDOMU(fseed, nbp, /double) & res=res[indices]
if (MAX(ABS(exptd_u_d-res)) GT eps) then ERRORS_ADD, nb_errors, 'Rand U & Double'
;
fseed=seed
res=RANDOMN(fseed, nbp) & res=res[indices]
if (MAX(ABS(exptd_n_f-res)) GT eps) then ERRORS_ADD, nb_errors, 'Rand N & Float'
;
fseed=seed
res=RANDOMN(fseed, nbp, /double) & res=res[indices]
if (MAX(ABS(exptd_n_d-res)) GT eps) then ERRORS_ADD, nb_errors, 'Rand N & Double'
;
; ----- final ----
;
BANNER_FOR_TESTSUITE, 'TEST_RANDOM_MERSENNE', nb_errors, /status, verb=verbose
ERRORS_CUMUL, cumul_errors, nb_errors
;
if KEYWORD_SET(test) then STOP
;
end
;
; ---------------------------------------
; ULONG keyword appeared in IDL 8.2.2
;
pro TEST_RANDOM_ULONG, cumul_errors, test=test, verbose=verbose
;
nb_errors=0
seed=10
nbp=5
;
; these values are the same for all 4 cases ...
if dsfmt_exists() then begin
exp_ul10=[ 1060878149, 1956351291, 1923111058, 1181360106, 1349992422]
endif else begin
exp_ul10=[3312796937, 1283169405, 89128932, 2124247567, 2721498432]
endelse
;
txt='case ULong '
;
; we need to reset "seed" to avoid it to be changed
;
seed=10 & res_ul10uf=RANDOMU(seed, nbp, /ULong)
seed=10 & res_ul10ud=RANDOMU(seed, nbp, /double, /ULong)
seed=10 & res_ul10nf=RANDOMN(seed, nbp, /ULong)
seed=10 & res_ul10nd=RANDOMN(seed, nbp, /double, /ULong)
;
if ~ARRAY_EQUAL(res_ul10uf, exp_ul10) then ERRORS_ADD, nb_errors, txt+'U Float'
if ~ARRAY_EQUAL(res_ul10ud, exp_ul10) then ERRORS_ADD, nb_errors, txt+'U Double'
if ~ARRAY_EQUAL(res_ul10nf, exp_ul10) then ERRORS_ADD, nb_errors, txt+'N Float'
if ~ARRAY_EQUAL(res_ul10nd, exp_ul10) then ERRORS_ADD, nb_errors, txt+'n Double'
;
; ----- final ----
;
BANNER_FOR_TESTSUITE, 'TEST_RANDOM_ULONG', nb_errors, /status, verb=verbose
ERRORS_CUMUL, cumul_errors, nb_errors
;
if KEYWORD_SET(test) then STOP
;
end
;
; ---------------------------------------
; because regression was introduced between July 17 and October 2
pro TEST_RANDOM_BASICS
;
a=RANDOMU(seed)
a=RANDOMU(1)
;
a=RANDOMU(seed, 12)
a=RANDOMU(1,12)
;
a=RANDOMU(seed, [12,3])
a=RANDOMU(1, [12,3])
;
end
;
; ---------------------------------------
;
pro PLOT_BATONS, values, offset=offset, color=color, psym=psym, $
linestyle=linestyle, _extra=_extra
;
if ~KEYWORD_SET(offset) then off=0 else off=offset
;
if ~KEYWORD_SET(psym) then mypsym=5 else mypsym=psym
;
for ii=0, N_ELEMENTS(values)-1 do begin
PLOTS, [ii,ii]+off, [0, values[ii]], color=color, linestyle=linestyle
PLOTS, ii+off, values[ii], color=color, psym=mypsym, _extra=_extra
endfor
;
end
;
; ---------------------------------------
; see figures in https://fr.wikipedia.org/wiki/Loi_de_Poisson
;
pro TEST_RANDOM_POISSON, errors, nb_points=nb_points, $
verbose=verbose, test=test
;
nb_pbs=0
;
if ((!d.name EQ 'X') or (!d.name EQ 'WIN')) then WINDOW, 0
;
DEVICE, get_decomposed=old_decomposed
if NOT(old_decomposed) then DEVICE, decomposed=1
;
if KEYWORD_SET(nb_points) then nbps=nb_points else nbps=100000
nbps_f=FLOAT(nbps)
;
if KEYWORD_SET(verbose) then print, 'We use : ', nbps, ' points'
;
; statistical test, will be OK whether dSFMT is used or not.
;
res_l1=HISTOGRAM(RANDOMN(seed, nbps, poisson=1))/nbps_f
res_l4=HISTOGRAM(RANDOMN(seed, nbps, poisson=4))/nbps_f
res_l10=HISTOGRAM(RANDOMN(seed, nbps, poisson=10))/nbps_f
;
;indices=INDGEN(N_ELEMENTS(res_l10))
indices=20
xranges=[-0.5, MAX(indices)+0.5]
;
PLOT, INDGEN(N_ELEMENTS(res_l1)), res_l1, xrange=xranges, /xstyle, $
xtitle='k', ytitle='P(X=k)', title='Poisson law', /nodata
;
PLOT_BATONS, res_l1, col='ff'x, psym=psym, line=2
PLOT_BATONS, res_l4, off=0.05, col='ffff'x, psym=psym, line=2
PLOT_BATONS, res_l10, off=0.1, col='ffffff'x, psym=psym, line=2
;
; Is the sum of all the values equal to One ?!
;
eps=(MACHAR()).eps
txt='Case Poisson Sum '
if (ABS(TOTAL(res_l1)-1.0) GT 5.*eps) then ERRORS_ADD, nb_pbs, txt+'1'
if (ABS(TOTAL(res_l4)-1.0) GT 5.*eps) then ERRORS_ADD, nb_pbs, txt+'1'
if (ABS(TOTAL(res_l10)-1.0) GT 5.*eps) then ERRORS_ADD, nb_pbs, txt+'1'
;
; Are the Max in the expected range ?
; if nbps == 10000, you have 1 over 10 calls to fail
;
vals=[0.369090,0.196335,0.125015]
tol=0.01
txt='Case Poisson Max '
if (ABS(MAX(res_l1-vals[0])) GT tol) then ERRORS_ADD, nb_pbs, txt+'1'
if (ABS(MAX(res_l4)-vals[1]) GT tol) then ERRORS_ADD, nb_pbs, txt+'4'
if (ABS(MAX(res_l10)-vals[2]) GT tol) then ERRORS_ADD, nb_pbs, txt+'10'
;
; ----- final ----
;
BANNER_FOR_TESTSUITE, "TEST_RANDOM_POISSON", nb_pbs, /status, verb=verbose
ERRORS_CUMUL, errors, nb_pbs
;
if KEYWORD_SET(test) then STOP
;
DEVICE, decomposed=old_decomposed
;
end
;
; ---------------------------------------
;
; note by AC 2017-12-13 : can be extend as "test_random_poison" above
; (but different numerical values !) no time to do it now :(
;
pro TEST_RANDOM_GAMMA, test=test
;
nbps=200000
nbps_f=FLOAT(nbps)
;
PLOT, HISTOGRAM(RANDOMN(seed, nbps, gamma=1), BINSIZE=0.1)/nbps_f
OPLOT, HISTOGRAM(RANDOMN(seed, nbps, gamma=2), BINSIZE=0.1)/nbps_f
OPLOT, HISTOGRAM(RANDOMN(seed, nbps, gamma=3), BINSIZE=0.1)/nbps_f
OPLOT, HISTOGRAM(RANDOMN(seed, nbps, gamma=4), BINSIZE=0.1)/nbps_f
;
if KEYWORD_SET(test) then STOP
;
end
;
; ---------------------------------------
; we try to have the output for all the mode
;
pro TEST_RANDOM_ALL_GAMMA, verbose=verbose
;
init_device_mode=!d.name
;
list_device_mode=['NULL', 'PS', 'X', 'SVG', 'Z', 'WIN']
;
for ii=0, N_ELEMENTS(list_device_mode)-1 do begin
;;
command='SET_PLOT, "'+list_device_mode[ii]+'"'
test_mode=EXECUTE(command)
;;
if KEYWORD_SET(verbose) then begin
print, 'Testing mode '+list_device_mode[ii]+', status : ', test_mode
endif
if (test_mode EQ 0) then begin
print, 'Testing mode '+list_device_mode[ii]+' : SKIPPED !'
CONTINUE
endif
;;
if ((!d.name EQ 'X') or (!d.name EQ 'WIN')) then WINDOW, 1
;;
if (!d.name EQ 'SVG') OR (!d.name EQ 'PS') then begin
file='output_test_random_gamma.'+STRLOWCASE(!d.name)
DEVICE, file=file
endif
;;
TEST_RANDOM_GAMMA
;;
if (!d.name EQ 'SVG') OR (!d.name EQ 'PS') then begin
DEVICE, /close
if KEYWORD_SET(verbose) then print, 'file generated : <<'+file+'>>'
endif
print, 'Testing mode '+list_device_mode[ii]+', status : Processed'
endfor
;
; switching back to initial device mode (HELP, /device)
SET_PLOT, init_device_mode
;
end
;
; ------------------------------------------
;
; Idea: when the number is big enough, mean value
; of the realization should be close to the "value".
; If computation is wrong (e.g. calling bad noise, algo),
; we can expect not to have goor prediction ;-)
; (and this test fails "often" when NPB =< 100)
;
pro TEST_RANDOM_BINOMIAL, cumul_errors, nbp=nbp, amplitude=amplitude, $
help=help, verbose=verbose, test=test
;
if KEYWORD_SET(help) then begin
print, 'pro TEST_RANDOM_BINOMIAL, cumul_errors, nbp=nbp, amplitude=amplitude, $'
print, ' help=help, verbose=verbose, test=test'
return
endif
;
if ~KEYWORD_SET(nbp) then nbp=10000
if ~KEYWORD_SET(amplitude) then amplitude=10.
;
; Amplitude is a strictly posivite Integer
;
amplitude=FLOOR(amplitude)
if (amplitude EQ 1) then ratio=50. else ratio=100.
;
values=[0.10,0.25,0.50,0.75,0.90]
errors=0
;
if KEYWORD_SET(verbose) then begin
print, 'Runing TEST_RANDOM_BINOMIAL for amplitude : ', amplitude
print, format='(6A12)', ['Amplitude', 'values', 'expected', 'Mean', 'disp.', 'Error']
endif
for ii=0, N_ELEMENTS(values)-1 do begin
resu=RANDOMU(seed, nbp, BINOMIAL=[amplitude,values[ii]])
dispersion=ABS(MEAN(resu)-amplitude*values[ii])
if (dispersion GT amplitude/ratio) then begin
txt='bad result for (amplitude, value) : ('+string(amplitude)+','+string(values)+')'
ERRORS_ADDS, errors, txt
endif
if KEYWORD_SET(verbose) then begin
print, format='(i12,4f12,6x,I1.1)', amplitude, values[ii], $
amplitude*values[ii], MEAN(resu), dispersion, (dispersion GT amplitude/100.)
endif
;;
endfor
;
; ----- final ----
;
BANNER_FOR_TESTSUITE, "TEST_RANDOM_BINOMIAL", errors, /status, verb=verbose
ERRORS_CUMUL, cumul_errors, errors
;
if KEYWORD_SET(test) then STOP
;
end
;
; ------------------------------------------
; testable extensions welcome
;
pro TEST_RANDOM, no_exit=no_exit, help=help, verbose=verbose, test=test
;
if KEYWORD_SET(help) then begin
print, 'pro TEST_RANDOM, no_exit=no_exit, help=help, verbose=verbose, test=test'
endif
;
cumul_errors=0
;
TEST_RANDOM_POISSON, cumul_errors, verbose=verbose
;
TEST_RANDOM_BASICS
;
; test the various DEVICE ...
TEST_RANDOM_ALL_GAMMA
;
TEST_RANDOM_BINOMIAL, cumul_errors, verbose=verbose, ampl=1.
TEST_RANDOM_BINOMIAL, cumul_errors, verbose=verbose, ampl=1.5
TEST_RANDOM_BINOMIAL, cumul_errors, verbose=verbose, ampl=10.
TEST_RANDOM_BINOMIAL, cumul_errors, verbose=verbose, ampl=100.
;
; testing the SEEDs ... (Mersenne) IDL 8.2.2+, GDL 0.9.7 SVN+
;
if STATUS_VERSION_OF_RANDOM() then begin
TEST_RANDOM_ULONG, cumul_errors, test=test, verbose=verbose
TEST_RANDOM_MERSENNE, cumul_errors, test=test, verbose=verbose
endif else begin
BANNER_FOR_TESTSUITE, 'TEST_RANDOM_ULONG', 'Too old version detected'
BANNER_FOR_TESTSUITE, 'TEST_RANDOM_SEED', 'Too old version detected'
endelse
;
; ----------------- final message ----------
;
BANNER_FOR_TESTSUITE, "TEST_RANDOM", cumul_errors
;
; if /debug OR /test nodes, we don't want to exit
if (cumul_errors GT 0) then begin
if ~KEYWORD_SET(verbose) then MESSAGE, /continue, 're-run with /verbose for details'
if ~(KEYWORD_SET(test) or KEYWORD_SET(no_exit)) then EXIT, status=1
endif
;
if KEYWORD_SET(no_exit) OR KEYWORD_SET(test) then STOP
;
end
|