1 /** 2 Authors: [Ilya Yaroshenko](http://9il.github.io) 3 4 Copyright: © 2014-2015 [Ilya Yaroshenko](http://9il.github.io) 5 6 License: MIT 7 */ 8 module atmosphere.estimate.generalized_inverse_gaussian; 9 10 import std.traits; 11 import std.typecons; 12 import std.math; 13 14 import atmosphere.statistic: GeneralizedInverseGaussinStatistic, GeneralizedInverseGaussinFixedLambdaStatistic; 15 16 /++ 17 Estimates parameters of the proper generalized inverse Gaussian distribution. 18 19 Params: 20 stat = GIG statistica. 21 sample = obeservation. 22 weights = sample weights. 23 relTolerance = Relative tolerance. 24 absTolerance = Absolute tolerance. 25 26 Preconditions: $(D ax) and $(D bx) shall be finite reals. $(BR) 27 $(D relTolerance) shall be normal positive real. $(BR) 28 $(D absTolerance) shall be normal positive real no less then $(D T.epsilon*2). 29 30 References: "Algorithms for Minimization without Derivatives", Richard Brent, Prentice-Hall, Inc. (1973) 31 32 See_Also: `atmosphere.params` 33 +/ 34 Tuple!(T, "lambda", T, "eta", T, "omega") 35 properGeneralizedInverseGaussianEstimate(T) 36 ( 37 in T[] sample, 38 in T relTolerance = sqrt(T.epsilon), 39 in T absTolerance = sqrt(T.epsilon), 40 ) 41 if(isFloatingPoint!T) 42 { 43 return properGeneralizedInverseGaussianEstimate(GeneralizedInverseGaussinStatistic!T(sample), relTolerance, absTolerance); 44 } 45 46 /// 47 unittest 48 { 49 import std.range; 50 import std.random; 51 import atmosphere.random; 52 import atmosphere.likelihood; 53 auto length = 1000; 54 auto lambda = -2.0, eta = 1.4, omega = 2.3; 55 auto rng = Random(1234); 56 auto sample = ProperGeneralizedInverseGaussianSRNG!double(rng, lambda, eta, omega).take(length).array; 57 auto params1 = properGeneralizedInverseGaussianEstimate(sample); 58 auto params2 = properGeneralizedInverseGaussianFixedLambdaEstimate!double(lambda, sample); 59 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, eta, omega, sample); 60 auto lh1 = properGeneralizedInverseGaussianLikelihood(params1.lambda, params1.eta, params1.omega, sample); 61 auto lh2 = properGeneralizedInverseGaussianLikelihood(lambda, params2.eta, params2.omega, sample); 62 assert(lh0 <= lh1); 63 assert(lh0 <= lh2); 64 assert(lh2 <= lh1); 65 } 66 67 ///ditto 68 Tuple!(T, "lambda", T, "eta", T, "omega") 69 properGeneralizedInverseGaussianEstimate(T) 70 ( 71 in T[] sample, 72 in T[] weights, 73 in T relTolerance = sqrt(T.epsilon), 74 in T absTolerance = sqrt(T.epsilon), 75 ) 76 if(isFloatingPoint!T) 77 { 78 return properGeneralizedInverseGaussianEstimate(GeneralizedInverseGaussinStatistic!T(sample, weights), relTolerance, absTolerance); 79 } 80 81 /// 82 unittest 83 { 84 import std.range; 85 import std.random; 86 import atmosphere.random; 87 import atmosphere.likelihood; 88 auto length = 1000; 89 auto lambda = -2.0, eta = 1.4, omega = 2.3; 90 auto rng = Random(1234); 91 auto sample = ProperGeneralizedInverseGaussianSRNG!double(rng, lambda, eta, omega).take(length).array; 92 auto weights = iota(1.0, length + 1.0).array; 93 auto params1 = properGeneralizedInverseGaussianEstimate!double(sample, weights); 94 auto params2 = properGeneralizedInverseGaussianFixedLambdaEstimate!double(lambda, sample, weights); 95 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, eta, omega, sample, weights); 96 auto lh1 = properGeneralizedInverseGaussianLikelihood(params1.lambda, params1.eta, params1.omega, sample, weights); 97 auto lh2 = properGeneralizedInverseGaussianLikelihood(lambda, params2.eta, params2.omega, sample, weights); 98 assert(lh0 <= lh1); 99 assert(lh0 <= lh2); 100 assert(lh2 <= lh1); 101 } 102 103 104 ///ditto 105 Tuple!(T, "lambda", T, "eta", T, "omega") 106 properGeneralizedInverseGaussianEstimate(T) 107 ( 108 in GeneralizedInverseGaussinStatistic!T stat, 109 in T relTolerance = sqrt(T.epsilon), 110 in T absTolerance = sqrt(T.epsilon), 111 ) 112 if(isFloatingPoint!T) 113 body { 114 import atmosphere.likelihood.generalized_inverse_gaussian; 115 immutable prod = stat.mean * stat.meani; 116 if(!isFinite(prod) || prod <= 1) 117 return typeof(return)(T.nan, T.nan, T.nan); 118 immutable u = prod / (prod - 1); 119 assert(isFinite(u)); 120 immutable statFL = cast(GeneralizedInverseGaussinFixedLambdaStatistic!T) stat; 121 T f(T lambda) { 122 immutable params = properGeneralizedInverseGaussianFixedLambdaEstimate!T(lambda, statFL); 123 with(params) 124 { 125 import std.conv; 126 //assert(eta >= T.min_normal || eta, eta.to!string); 127 assert(omega >= T.min_normal, omega.to!string); 128 return eta.isNormal ? 129 -properGeneralizedInverseGaussianLikelihood!T(lambda, eta, omega, stat) 130 : -T.infinity; 131 } 132 } 133 import atmosphere.math: findLocalMin; 134 immutable flm = findLocalMin!T(&f, -u, u, relTolerance, absTolerance); 135 immutable lambda = flm.x; 136 immutable params = properGeneralizedInverseGaussianFixedLambdaEstimate!T(lambda, statFL); 137 with(params) return typeof(return)(lambda, eta, omega); 138 } 139 140 /++ 141 Estimates parameters of the generalized inverse Gaussian distribution. 142 143 Params: 144 stat = GIG statistica. 145 sample = obeservation. 146 weights = sample weights. 147 relTolerance = Relative tolerance. 148 absTolerance = Absolute tolerance. 149 150 Preconditions: $(D ax) and $(D bx) shall be finite reals. $(BR) 151 $(D relTolerance) shall be normal positive real. $(BR) 152 $(D absTolerance) shall be normal positive real no less then $(D T.epsilon*2). 153 154 References: "Algorithms for Minimization without Derivatives", Richard Brent, Prentice-Hall, Inc. (1973) 155 156 See_Also: `atmosphere.params` 157 +/ 158 Tuple!(T, "lambda", T, "chi", T, "psi") 159 generalizedInverseGaussianEstimate(T) 160 ( 161 in T[] sample, 162 in T relTolerance = sqrt(T.epsilon), 163 in T absTolerance = sqrt(T.epsilon), 164 ) 165 if(isFloatingPoint!T) 166 { 167 return generalizedInverseGaussianEstimate(GeneralizedInverseGaussinStatistic!T(sample), relTolerance, absTolerance); 168 } 169 170 /// 171 unittest 172 { 173 import std.range; 174 import std.random; 175 import atmosphere.random; 176 import atmosphere.likelihood; 177 import atmosphere.params; 178 auto length = 1000; 179 auto lambda = -2.0, chi = 1.4, psi = 2.3; 180 auto rng = Random(1234); 181 auto sample = new GeneralizedInverseGaussianRNG!double(rng, lambda, chi, psi).take(length).array; 182 auto params1 = generalizedInverseGaussianEstimate(sample); 183 auto params2 = generalizedInverseGaussianFixedLambdaEstimate!double(lambda, sample); 184 auto p0 = GIGChiPsi!double(chi, psi); 185 auto p1 = GIGChiPsi!double(params1.chi, params1.psi); 186 auto p2 = GIGChiPsi!double(params2.chi, params2.psi); 187 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, p0.eta, p0.omega, sample); 188 auto lh1 = properGeneralizedInverseGaussianLikelihood(params1.lambda, p1.eta, p1.omega, sample); 189 auto lh2 = properGeneralizedInverseGaussianLikelihood(lambda, p2.eta, p2.omega, sample); 190 assert(lh0 <= lh1); 191 assert(lh0 <= lh2); 192 assert(lh2 <= lh1); 193 } 194 195 196 ///ditto 197 Tuple!(T, "lambda", T, "chi", T, "psi") 198 generalizedInverseGaussianEstimate(T) 199 ( 200 in T[] sample, 201 in T[] weights, 202 in T relTolerance = sqrt(T.epsilon), 203 in T absTolerance = sqrt(T.epsilon), 204 ) 205 if(isFloatingPoint!T) 206 { 207 return generalizedInverseGaussianEstimate(GeneralizedInverseGaussinStatistic!T(sample, weights), relTolerance, absTolerance); 208 } 209 210 /// 211 unittest 212 { 213 import std.range; 214 import std.random; 215 import atmosphere.random; 216 import atmosphere.likelihood; 217 import atmosphere.params; 218 auto length = 1000; 219 auto lambda = -2.0, chi = 1.4, psi = 2.3; 220 auto rng = Random(1234); 221 auto sample = new GeneralizedInverseGaussianRNG!double(rng, lambda, chi, psi).take(length).array; 222 auto weights = iota(1.0, length + 1.0).array; 223 auto params1 = generalizedInverseGaussianEstimate!double(sample, weights); 224 auto params2 = generalizedInverseGaussianFixedLambdaEstimate!double(lambda, sample, weights); 225 auto p0 = GIGChiPsi!double(chi, psi); 226 auto p1 = GIGChiPsi!double(params1.chi, params1.psi); 227 auto p2 = GIGChiPsi!double(params2.chi, params2.psi); 228 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, p0.eta, p0.omega, sample, weights); 229 auto lh1 = properGeneralizedInverseGaussianLikelihood(params1.lambda, p1.eta, p1.omega, sample, weights); 230 auto lh2 = properGeneralizedInverseGaussianLikelihood(lambda, p2.eta, p2.omega, sample, weights); 231 assert(lh0 <= lh1); 232 assert(lh0 <= lh2); 233 assert(lh2 <= lh1); 234 } 235 236 ///ditto 237 Tuple!(T, "lambda", T, "chi", T, "psi") 238 generalizedInverseGaussianEstimate(T) 239 ( 240 in GeneralizedInverseGaussinStatistic!T stat, 241 in T relTolerance = sqrt(T.epsilon), 242 in T absTolerance = sqrt(T.epsilon), 243 ) 244 if(isFloatingPoint!T) 245 body { 246 import atmosphere.params : GIGEtaOmega; 247 import atmosphere.estimate.gamma; 248 import atmosphere.estimate.inverse_gamma; 249 import atmosphere.likelihood.gamma; 250 import atmosphere.likelihood.inverse_gamma; 251 import atmosphere.likelihood.generalized_inverse_gaussian; 252 import atmosphere.statistic: GammaStatistic, InverseGammaStatistic; 253 254 immutable prod = stat.mean * stat.meani; 255 if(!isFinite(prod) || prod <= 1) 256 return typeof(return)(T.nan, T.nan, T.nan); 257 immutable u = prod / (prod - 1); 258 assert(isFinite(u)); 259 260 immutable gammaStat = cast(GammaStatistic!T)stat; 261 immutable inverseGammaStat = cast(InverseGammaStatistic!T)stat; 262 263 immutable gammaParams = gammaEstimate!T(gammaStat); 264 immutable inverseGammaParams = inverseGammaEstimate!T(inverseGammaStat); 265 immutable properParams = properGeneralizedInverseGaussianEstimate!T(stat, relTolerance, absTolerance); 266 import std.stdio; 267 268 T gammaLikelihood = gammaLikelihood!T(gammaParams.shape, gammaParams.scale, gammaStat); 269 T inverseGammaLikelihood = inverseGammaLikelihood!T(inverseGammaParams.shape, inverseGammaParams.scale, inverseGammaStat); 270 271 T properLikelihood = properParams.eta >= T.min_normal && properParams.omega >= T.min_normal ? 272 properGeneralizedInverseGaussianLikelihood!T(properParams.lambda, properParams.eta, properParams.omega, stat) 273 : 0; 274 275 if(!(gammaLikelihood > -T.infinity)) 276 gammaLikelihood = -T.infinity; 277 if(!(inverseGammaLikelihood > -T.infinity)) 278 inverseGammaLikelihood = -T.infinity; 279 if(!(properLikelihood > -T.infinity)) 280 properLikelihood = -T.infinity; 281 if(properLikelihood > gammaLikelihood && properLikelihood > inverseGammaLikelihood) 282 with(GIGEtaOmega!T(properParams.eta, properParams.omega)) return typeof(return)(properParams.lambda, chi, psi); 283 if(gammaLikelihood > inverseGammaLikelihood) 284 with( gammaParams) return typeof(return)(shape, 0, 2 / scale); 285 if(gammaLikelihood < inverseGammaLikelihood) 286 with(inverseGammaParams) return typeof(return)(-shape, scale / 2, 0); 287 return typeof(return).init; 288 } 289 290 291 /++ 292 Estimates parameters of the proper generalized inverse Gaussian distribution for fixed `lambda`. 293 294 See_Also: `atmosphere.params` 295 +/ 296 Tuple!(T, "eta", T, "omega") 297 properGeneralizedInverseGaussianFixedLambdaEstimate(T)(in T lambda, in T[] sample) 298 if(isFloatingPoint!T) 299 { 300 return properGeneralizedInverseGaussianFixedLambdaEstimate(lambda, GeneralizedInverseGaussinFixedLambdaStatistic!T(sample)); 301 } 302 303 /// 304 unittest 305 { 306 import std.range; 307 import std.random; 308 import atmosphere.random; 309 import atmosphere.likelihood; 310 auto length = 1000; 311 auto lambda = -2.0, eta = 1.4, omega = 2.3; 312 auto rng = Random(1234); 313 auto sample = ProperGeneralizedInverseGaussianSRNG!double(rng, lambda, eta, omega).take(length).array; 314 auto params = properGeneralizedInverseGaussianFixedLambdaEstimate!double(lambda, sample); 315 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, eta, omega, sample); 316 auto lh1 = properGeneralizedInverseGaussianLikelihood(lambda, params.eta, params.omega, sample); 317 assert(lh0 <= lh1); 318 } 319 320 321 ///ditto 322 Tuple!(T, "eta", T, "omega") 323 properGeneralizedInverseGaussianFixedLambdaEstimate(T)(in T lambda, in T[] sample, in T[] weights) 324 if(isFloatingPoint!T) 325 { 326 return properGeneralizedInverseGaussianFixedLambdaEstimate(lambda, GeneralizedInverseGaussinFixedLambdaStatistic!T(sample, weights)); 327 } 328 329 /// 330 unittest 331 { 332 import std.range; 333 import std.random; 334 import atmosphere.random; 335 import atmosphere.likelihood; 336 auto length = 1000; 337 auto lambda = -2.0, eta = 1.4, omega = 2.3; 338 auto rng = Random(1234); 339 auto sample = ProperGeneralizedInverseGaussianSRNG!double(rng, lambda, eta, omega).take(length).array; 340 auto weights = iota(1.0, length + 1.0).array; 341 auto params = properGeneralizedInverseGaussianFixedLambdaEstimate!double(lambda, sample, weights); 342 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, eta, omega, sample, weights); 343 auto lh1 = properGeneralizedInverseGaussianLikelihood(lambda, params.eta, params.omega, sample, weights); 344 assert(lh0 <= lh1); 345 } 346 347 ///ditto 348 Tuple!(T, "eta", T, "omega") 349 properGeneralizedInverseGaussianFixedLambdaEstimate(T) 350 (in T lambda, in GeneralizedInverseGaussinFixedLambdaStatistic!T stat) 351 if(isFloatingPoint!T) 352 in { 353 assert(isFinite(lambda)); 354 } 355 body { 356 import std.numeric: findRoot; 357 import atmosphere.math; 358 immutable prod = stat.mean * stat.meani; 359 if(!isFinite(prod) || prod <= 1) 360 return typeof(return)(T.nan, T.nan); 361 immutable u = prod / (prod - 1); 362 assert(isFinite(u)); 363 immutable alambda = fabs(lambda); 364 if(alambda >= u) 365 { 366 return typeof(return)(alambda > 0 ? 0 : T.infinity, 0); 367 } 368 369 T f(T omega) //@safe pure nothrow @nogc 370 out(r) { 371 assert(isFinite(r)); 372 } 373 body { 374 assert(!isNaN(omega)); 375 assert(omega >= 0); 376 assert(omega < T.infinity); 377 auto r = besselKD(alambda, omega) - prod; 378 return r == T.infinity ? T.max : r; 379 } 380 immutable a = T.min_normal; 381 immutable b = T.max; 382 T fa = f(a); 383 if(fa == T.infinity) 384 fa = T.max; 385 T omega = void; 386 if(fa <= 0) 387 omega = a; 388 else 389 { 390 immutable fb = f(b); 391 if(fb >= 0) 392 omega = b; 393 else 394 { 395 immutable r = findRoot(&f, a, b, fa, fb, (T a, T b) => false); 396 // Return the first value if it is smaller or NaN 397 omega = !(fabs(r[2]) > fabs(r[3])) ? r[0] : r[1]; 398 } 399 400 } 401 402 assert(omega >= T.min_normal); 403 immutable eta = sqrt(stat.mean / stat.meani) / besselKRM(lambda, omega); 404 auto ret = typeof(return)(eta, omega); 405 return ret; 406 } 407 408 409 /++ 410 Estimates parameters of the generalized inverse Gaussian distribution for fixed `lambda`. 411 412 See_Also: `atmosphere.params` 413 +/ 414 Tuple!(T, "chi", T, "psi") 415 generalizedInverseGaussianFixedLambdaEstimate(T)(in T lambda, in T[] sample) 416 if(isFloatingPoint!T) 417 { 418 return generalizedInverseGaussianFixedLambdaEstimate(lambda, GeneralizedInverseGaussinFixedLambdaStatistic!T(sample)); 419 } 420 421 /// 422 unittest 423 { 424 import std.range; 425 import std.random; 426 import atmosphere.random; 427 import atmosphere.likelihood; 428 import atmosphere.params; 429 auto length = 1000; 430 auto lambda = -2.0, chi = 1.4, psi = 2.3; 431 auto rng = Random(1234); 432 auto sample = new GeneralizedInverseGaussianRNG!double(rng, lambda, chi, psi).take(length).array; 433 auto params = generalizedInverseGaussianFixedLambdaEstimate!double(lambda, sample); 434 auto p0 = GIGChiPsi!double(chi, psi); 435 auto p1 = GIGChiPsi!double(params.chi, params.psi); 436 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, p0.chi, p0.psi, sample); 437 auto lh1 = properGeneralizedInverseGaussianLikelihood(lambda, p1.chi, p1.psi, sample); 438 assert(lh0 <= lh1); 439 } 440 441 442 ///ditto 443 Tuple!(T, "chi", T, "psi") 444 generalizedInverseGaussianFixedLambdaEstimate(T)(in T lambda, in T[] sample, in T[] weights) 445 if(isFloatingPoint!T) 446 { 447 return generalizedInverseGaussianFixedLambdaEstimate(lambda, GeneralizedInverseGaussinFixedLambdaStatistic!T(sample, weights)); 448 } 449 450 /// 451 unittest 452 { 453 import std.range; 454 import std.random; 455 import atmosphere.random; 456 import atmosphere.likelihood; 457 import atmosphere.params; 458 auto length = 1000; 459 auto lambda = -2.0, chi = 1.4, psi = 2.3; 460 auto rng = Random(1234); 461 auto sample = new GeneralizedInverseGaussianRNG!double(rng, lambda, chi, psi).take(length).array; 462 auto weights = iota(1.0, length + 1.0).array; 463 auto params = generalizedInverseGaussianFixedLambdaEstimate!double(lambda, sample, weights); 464 auto p0 = GIGChiPsi!double(chi, psi); 465 auto p1 = GIGChiPsi!double(params.chi, params.psi); 466 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, p0.chi, p0.psi, sample, weights); 467 auto lh1 = properGeneralizedInverseGaussianLikelihood(lambda, p1.chi, p1.psi, sample, weights); 468 assert(lh0 <= lh1); 469 } 470 471 ///ditto 472 Tuple!(T, "chi", T, "psi") 473 generalizedInverseGaussianFixedLambdaEstimate(T) 474 (in T lambda, in GeneralizedInverseGaussinFixedLambdaStatistic!T stat) 475 if(isFloatingPoint!T) 476 in { 477 assert(isNormal(lambda)); 478 } 479 body { 480 import atmosphere.params : GIGEtaOmega; 481 immutable prod = stat.mean * stat.meani; 482 if(!isFinite(prod) || prod <= 1) 483 return typeof(return)(T.nan, T.nan); 484 immutable u = prod / (prod - 1); 485 assert(isFinite(u)); 486 immutable alambda = fabs(lambda); 487 if(alambda >= u) 488 return lambda > 0 ? typeof(return)(0, 2 * alambda / stat.mean) : typeof(return)(2 * alambda / stat.meani, 0); 489 immutable properParams = properGeneralizedInverseGaussianFixedLambdaEstimate!T(lambda, stat); 490 with(GIGEtaOmega!T(properParams.eta, properParams.omega)) return typeof(return)(chi, psi); 491 } 492 493 494 /++ 495 Estimates parameter `omega` of the proper generalized inverse Gaussian distribution for fixed `lambda` and `eta`. 496 497 See_Also: `atmosphere.params` 498 +/ 499 T properGeneralizedInverseGaussianFixedLambdaEtaEstimate(T)(in T lambda, in T eta, in T[] sample) 500 if(isFloatingPoint!T) 501 { 502 return properGeneralizedInverseGaussianFixedLambdaEtaEstimate(lambda, eta, GeneralizedInverseGaussinFixedLambdaStatistic!T(sample)); 503 } 504 505 /// 506 unittest 507 { 508 import std.range; 509 import std.random; 510 import atmosphere.random; 511 import atmosphere.likelihood; 512 auto length = 1000; 513 auto lambda = -2.0, eta = 1.4, omega = 2.3; 514 auto rng = Random(1234); 515 auto sample = ProperGeneralizedInverseGaussianSRNG!double(rng, lambda, eta, omega).take(length).array; 516 auto omega1 = properGeneralizedInverseGaussianFixedLambdaEtaEstimate!double(lambda, eta, sample); 517 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, eta, omega , sample); 518 auto lh1 = properGeneralizedInverseGaussianLikelihood(lambda, eta, omega1, sample); 519 assert(lh0 <= lh1); 520 } 521 522 ///ditto 523 T properGeneralizedInverseGaussianFixedLambdaEtaEstimate(T)(in T lambda, in T eta, in T[] sample, in T[] weights) 524 if(isFloatingPoint!T) 525 { 526 return properGeneralizedInverseGaussianFixedLambdaEtaEstimate(lambda, eta, GeneralizedInverseGaussinFixedLambdaStatistic!T(sample, weights)); 527 } 528 529 /// 530 unittest 531 { 532 import std.range; 533 import std.random; 534 import atmosphere.random; 535 import atmosphere.likelihood; 536 auto length = 1000; 537 auto lambda = -2.0, eta = 1.4, omega = 2.3; 538 auto rng = Random(1234); 539 auto sample = ProperGeneralizedInverseGaussianSRNG!double(rng, lambda, eta, omega).take(length).array; 540 auto weights = iota(1.0, length + 1.0).array; 541 auto omega1 = properGeneralizedInverseGaussianFixedLambdaEtaEstimate!double(lambda, eta, sample, weights); 542 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, eta, omega , sample, weights); 543 auto lh1 = properGeneralizedInverseGaussianLikelihood(lambda, eta, omega1, sample, weights); 544 assert(lh0 <= lh1); 545 } 546 547 548 ///ditto 549 T properGeneralizedInverseGaussianFixedLambdaEtaEstimate(T) 550 (in T lambda, in T eta, in GeneralizedInverseGaussinFixedLambdaStatistic!T stat) 551 if(isFloatingPoint!T) 552 in { 553 assert(isNormal(lambda)); 554 } 555 body { 556 import std.numeric: findRoot; 557 import atmosphere.math; 558 immutable d = stat.mean / eta + stat.meani * eta; 559 return findRoot((T omega) => besselKRS(lambda, omega) - d, double.min_normal, double.max); 560 } 561 562 563 version(none) 564 unittest 565 { 566 import std.range; 567 import std.random; 568 import atmosphere.random; 569 import atmosphere.likelihood; 570 import atmosphere.params; 571 auto length = 1000; 572 auto lambda = -2.0, chi = 1.4, psi = 2.3; 573 auto rng = Random(1234); 574 auto sample = new GeneralizedInverseGaussianRNG!double(rng, lambda, chi, psi).take(length).array; 575 auto chi1 = generalizedInverseGaussianFixedLambdaPsiEstimate!double(lambda, psi, sample); 576 auto p0 = GIGChiPsi!double(chi , psi); 577 auto p1 = GIGChiPsi!double(chi1, psi); 578 auto lh0 = properGeneralizedInverseGaussianLikelihood(lambda, p0.eta, p0.omega , sample); 579 auto lh1 = properGeneralizedInverseGaussianLikelihood(lambda, p1.eta, p1.omega, sample); 580 assert(lh0 <= lh1); 581 }