2
## This R package is free software; you can redistribute it and/or
3
## modify it under the terms of the GNU Library General Public
4
## License as published by the Free Software Foundation; either
5
## version 2 of the License, or (at your option) any later version.
7
## This R package is distributed in the hope that it will be useful,
8
## but WITHOUT ANY WARRANTY; without even the implied warranty of
9
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
## GNU Library General Public License for more details.
12
## You should have received a copy of the GNU Library General
13
## Public License along with this library; if not, write to the
14
## Free Foundation, Inc., 59 Temple Place, Suite 330, Boston,
18
################################################################################
19
## FUNCTIONS: DESCRIPTION:
20
## dstable Returns density for stable DF
21
## pstable Returns probabilities for stable DF
22
## qstable Returns quantiles for stable DF
23
## rstable Returns random variates for stable DF
24
## UTILITY FUNCTION DESCRIPTION:
25
## .integrate2 Integrates internal functions for *stable
26
################################################################################
29
##==============================================================================
33
## 0) All d, p, q, q -- have identical parts
34
## a) 'parametrization' (pm) check
35
## b) checking, alpha, beta,
36
## c) subdivisions etc {all but rstable}
37
## --- to do: "Fix" these in dstable(), then copy/paste to others
39
##==============================================================================
41
##' @title omega() according to Lambert & Lindsey (1999), p.412
45
.om <- function(gamma,alpha)
46
if(alpha == 1) (2/pi)*log(gamma) else tan(pi*alpha/2)
48
dstable <- function(x, alpha, beta,
49
gamma = 1, delta = 0, pm = 0, log = FALSE,
50
tol = 16*.Machine$double.eps, subdivisions = 1000)
52
## Original implemented by Diethelm Wuertz;
53
## Changes for efficiency and accuracy by Martin Maechler
56
## Returns density for stable DF
59
## The function uses the approach of J.P. Nolan for general
60
## stable distributions. Nolan derived expressions in form
61
## of integrals based on the charcteristic function for
62
## standardized stable random variables. These integrals
63
## can be numerically evaluated.
66
## alpha = index of stability, in the range (0,2]
67
## beta = skewness, in the range [-1, 1]
68
## gamma = scale, in the range (0, infinity)
69
## delta = location, in the range (-infinity, +infinity)
70
## param = type of parmeterization
72
## Note: S+ compatibility no longer considered (explicitly)
75
## NB: (gamma, delta) can be *vector*s (vectorized along x)
76
stopifnot( 0 < alpha, alpha <= 2, length(alpha) == 1,
77
-1 <= beta, beta <= 1, length(beta) == 1,
78
0 <= gamma, length(pm) == 1, pm %in% 0:2,
79
tol > 0, subdivisions > 0)
83
delta <- delta + beta*gamma * .om(gamma,alpha)
85
delta <- delta - alpha^(-1/alpha)*gamma*stableMode(alpha, beta)
86
gamma <- alpha^(-1/alpha) * gamma
90
x <- (x - delta) / gamma
94
dnorm(x, mean = 0, sd = sqrt(2))
95
} else if (alpha == 1 && beta == 0) {
100
if (alpha != 1) { ## 0 < alpha < 2 & |beta| <= 1 from above
101
tanpa2 <- tan(pi*alpha/2)
102
zeta <- -beta * tanpa2
103
theta0 <- atan(beta * tanpa2) / alpha
104
## Loop over all x values:
105
unlist(lapply(x, function(z)
106
.fct1(z, zeta, alpha=alpha, theta0 = theta0,
107
tol=tol, subdivisions=subdivisions)))
109
## Special Case alpha == 1 and -1 <= beta <= 1 (but not = 0) :
110
else { ## (alpha == 1) and 0 < |beta| <= 1 from above
111
## Loop over all x values:
112
unlist(lapply(x, function(z) {
114
.fct2( z , beta, tol=tol, subdivisions=subdivisions)
116
.fct2(-z, -beta, tol=tol, subdivisions=subdivisions)
124
if (log) log(ans) else ans
127
## ------------------------------------------------------------------------------
129
.fct1 <- function(x, zeta, alpha, theta0, tol, subdivisions,
130
verbose = getOption("dstable.debug", default=FALSE))
132
## -- Integrand for dstable() --
134
x.m.zet <- abs(x - zeta)
136
gamma(1+1/alpha)*cos(theta0) / (pi*(1+zeta^2)^(1/(2*alpha)))
138
## Modified: originally was if (z == zeta),
139
## then (D.W.) if (x.m.zet < 2 * .Machine$double.eps)
140
## then (M.M.) if (x.m.zet <= 1e-5 * abs(x))
143
## the real check should be about the feasibility of g() below, or its integration
145
if(x < zeta) theta0 <- -theta0
147
## constants ( independent of integrand g1(th) = g*exp(-g) ):
148
## zeta <- -beta * tan(pi*alpha/2)
149
## theta0 <- (1/alpha) * atan( beta * tan(pi*alpha/2))
150
## x.m.zet <- abs(x - zeta)
152
cat0 <- cos(at0 <- alpha*theta0)
154
g <- function(th) (cat0 * cos(th) * (x.m.zet/sin(at0+alpha*th))^alpha)^(1/a_1) * cos(at0+ a_1*th)
156
## Function to Integrate:
157
g1 <- function(th) ## and (xarg, alpha, beta) => (zeta,at0,g0,.....)
159
## g1 = g(.) exp(-g(.))
161
## making sure that we don't get Inf * 0 => NaN
163
if(any(L <- v > 1000)) ## actually, v > -(.Machine$double.min.exp * log(2)) == 708.396...
168
c2 <- ( alpha / (pi*abs(a_1)*x.m.zet) )
169
## Result = c2 * \int_{-t0}^{pi/2} g1(u) du
170
## where however, g1(.) may look to be (almost) zero almost everywhere and just have a small peak
171
## ==> Split the integral into two parts of two intervals (t0, t_max) + (t_max, pi/2)
173
## However, this may still be bad, e.g., for dstable(71.61531, alpha=1.001, beta=0.6),
174
## or dstable(1.205, 0.75, -0.5)
175
## the 2nd integral is "completely wrong" (basically zero, instead of ..e-5)
176
## FIXME --- Lindsey uses "Romberg" integration -- maybe we must split even more
179
g. <- if(alpha >= 1) g(-theta0+ 1e-6*abs(theta0)) else g(pi/2 -1e-6*(pi/2))
180
if(is.na(g.) || identical(g., 0))# g() is not usable
183
## We know that the maximum of g1(.) is = exp(-1) = 0.3679 "at" g(.) == 1
184
## find that by uniroot :
185
ur <- uniroot(function(th) g(th) - 1, lower = -theta0, upper = pi/2, tol = tol)
188
## now, because the peak may be extreme, we find two more intermediate values
189
## NB: Max = 0.3679 ==> 1e-4 is a very small fraction of that
191
th1 <- uniroot(function(th) g1(th) - 1e-4, lower = -theta0, upper = theta2,
193
if((do4 <- g1(pi/2) < 1e-4))
195
th3 <- uniroot(function(th) g1(th) - 1e-4, lower = theta2, upper = pi/2,
199
.integrate2(g1, lower = a, upper = b,
200
subdivisions=subdivisions, rel.tol= tol, abs.tol= tol)
202
r1 <- Int(-theta0, th1)
203
r2 <- Int( th1, theta2)
205
r3 <- Int( theta2, th3)
206
r4 <- Int( th3, pi/2)
208
r3 <- Int( theta2, pi/2)
212
cat(sprintf(".fct1(%11g,%10g,..): c2*sum(r[1..4])= %11g*(%9.4g + %9.4g + %9.4g + %9.4g)= %g\n",
213
x,zeta, c2, r1,r2,r3,r4, c2*(r1+r2+r3+r4)))
218
## ------------------------------------------------------------------------------
220
##' is only used when alpha == 1 (!)
221
.fct2 <- function(xarg, beta, tol, subdivisions)
226
p2b <- pi*i2b # = pi/(2 beta)
230
## Function to Integrate; x is a non-sorted vector!
231
g2 <- function(x) { ## and (xarg, beta)
232
g <- p2b+ x # == g'/beta where g' := pi/2 + beta*x
233
v <- g / (p2b*cos(x)) * exp(g*tan(x))
236
if(any(ina <- is.na(gval))) gval[ina] <- 0 ## replace NA at pi/2
240
theta2 <- optimize(g2, lower = -pi2, upper = pi2,
241
maximum = TRUE, tol = tol)$maximum
242
r1 <- .integrate2(g2, lower = -pi2, upper = theta2,
243
subdivisions = subdivisions,
244
rel.tol = tol, abs.tol = tol)
245
r2 <- .integrate2(g2, lower = theta2, upper = pi2,
246
subdivisions = subdivisions,
247
rel.tol = tol, abs.tol = tol)
251
### ------------------------------------------------------------------------------
254
pstable <- function(q, alpha, beta, gamma = 1, delta = 0, pm = 0,
255
tol = 16*.Machine$double.eps, subdivisions = 1000)
257
## A function implemented by Diethelm Wuertz
260
## Returns probability for stable DF
264
## NB: (gamma, delta) can be *vector*s (vectorized along x)
265
stopifnot( 0 < alpha, alpha <= 2, length(alpha) == 1,
266
-1 <= beta, beta <= 1, length(beta) == 1,
267
0 <= gamma, length(pm) == 1, pm %in% 0:2,
268
tol > 0, subdivisions > 0)
270
## Parameterizations:
272
delta <- delta + beta*gamma * .om(gamma,alpha)
273
} else if (pm == 2) {
274
delta <- delta - alpha^(-1/alpha)*gamma*stableMode(alpha, beta)
275
gamma <- alpha^(-1/alpha) * gamma
279
x <- (x - delta) / gamma
282
## ------ first, special cases:
284
pnorm(x, mean = 0, sd = sqrt(2))
285
} else if (alpha == 1 && beta == 0) {
290
if (alpha != 1) { ## 0 < alpha < 2 & |beta| <= 1 from above
291
tanpa2 <- tan(pi*alpha/2)
292
zeta <- -beta * tanpa2
293
theta0 <- atan(beta * tanpa2) / alpha
295
## Loop over all x values:
296
unlist(lapply(x, function(z) {
297
z.m.zet <- abs(z - zeta)
299
if (z.m.zet < 2 * .Machine$double.eps)
300
## FIXME? same problem as dstable
303
.FCT1(z.m.zet, alpha=alpha, theta0= theta0,
304
tol = tol, subdivisions = subdivisions)
306
1 - .FCT1(z.m.zet, alpha=alpha, theta0= -theta0,
307
tol = tol, subdivisions = subdivisions)
310
## Special Case alpha == 1 and -1 <= beta <= 1 (but not = 0) :
311
else { ## (alpha == 1) and 0 < |beta| <= 1 from above
312
## Loop over all x values:
313
unlist(lapply(x, function(z) {
315
.FCT2(xarg = z, beta = beta,
316
tol = tol, subdivisions = subdivisions)
318
1 - .FCT2(xarg = -z, beta = -beta,
319
tol = tol, subdivisions = subdivisions)
326
## ------------------------------------------------------------------------------
328
.FCT1 <- function(x.m.zeta, alpha, theta0, tol, subdivisions)
332
cat0 <- cos(at0 <- alpha*theta0)
335
## Function to integrate:
336
G1 <- function(x) { ## (xarg, alpha, beta)
337
v <- (cat0*cos(x))^(1/a_1) * sin(at0+ alpha*x)^-aa1 * cos(at0+a_1*x)
341
theta2 <- optimize(G1, lower = -theta0, upper = pi/2,
342
maximum = TRUE, tol = tol)$maximum
343
c1 <- if(alpha < 1) 1/2 - theta0/pi else 1
344
c3 <- sign(1-alpha)/pi
345
r1 <- .integrate2(G1, lower = -theta0,
346
upper = theta2, subdivisions = subdivisions,
347
rel.tol = tol, abs.tol = tol)
348
r2 <- .integrate2(G1, lower = theta2,
349
upper = pi/2, subdivisions = subdivisions,
350
rel.tol = tol, abs.tol = tol)
354
## ------------------------------------------------------------------------------
356
.FCT2 <- function(xarg, beta, tol, subdivisions)
359
p2b <- pi*i2b # = pi/(2 beta)
363
## Function to Integrate; x is a non-sorted vector!
364
G2 <- function(x) { ## and (xarg, beta)
365
g <- p2b+ x # == g'/beta where g' := pi/2 + beta*x
366
v <- g / (p2b*cos(x)) * exp(g*tan(x))
369
if(any(ina <- is.na(gval))) gval[ina] <- 0 ## replace NA at pi/2
374
theta2 <- optimize(G2, lower = -pi2, upper = pi2,
375
maximum = TRUE, tol = tol)$maximum
376
r1 <- .integrate2(G2, lower = -pi2,
377
upper = theta2, subdivisions = subdivisions,
378
rel.tol = tol, abs.tol = tol)
379
r2 <- .integrate2(G2, lower = theta2,
380
upper = pi2, subdivisions = subdivisions,
381
rel.tol = tol, abs.tol = tol)
385
### ------------------------------------------------------------------------------
388
qstable <- function(p, alpha, beta, gamma = 1, delta = 0, pm = 0,
389
tol = .Machine$double.eps^0.25, maxiter = 1000,
390
integ.tol = 1e-7, subdivisions = 200)
392
## A function implemented by Diethelm Wuertz
395
## Returns quantiles for stable DF
398
## NB: (gamma, delta) can be *vector*s (vectorized along x)
399
stopifnot( 0 < alpha, alpha <= 2, length(alpha) == 1,
400
-1 <= beta, beta <= 1, length(beta) == 1,
401
0 <= gamma, length(pm) == 1, pm %in% 0:2,
402
tol > 0, subdivisions > 0)
404
## Parameterizations:
406
delta <- delta + beta*gamma * .om(gamma,alpha)
407
} else if (pm == 2) {
408
delta <- delta - alpha^(-1/alpha)*gamma*stableMode(alpha, beta)
409
gamma <- alpha^(-1/alpha) * gamma
415
qnorm(p, mean = 0, sd = sqrt(2))
416
else if (alpha == 1 && beta == 0)
418
else if (abs(alpha-1) < 1) { ## -------------- 0 < alpha < 2 ---------------
419
.froot <- function(x, p) {
420
pstable(q = x, alpha=alpha, beta=beta, pm = 0,
421
tol=integ.tol, subdivisions=subdivisions) - p
424
unlist(lapply(p, function(pp) {
429
xmax <- qnorm(pp, mean = 0, sd = sqrt(2))
439
xmin <- qnorm(pp, mean = 0, sd = sqrt(2))
448
xmin <- qnorm(pp, mean = 0, sd = sqrt(2))
452
xmax <- qnorm(pp, mean = 0, sd = sqrt(2))
459
while (is.na(root)) {
460
root <- .unirootNA(.froot, interval = c(xmin, xmax), p = pp,
461
tol=tol, maxiter=maxiter)
462
counter <- counter + 1
463
xmin <- xmin-2^counter
464
xmax <- xmax+2^counter
471
result * gamma + delta
474
## ------------------------------------------------------------------------------
477
rstable <- function(n, alpha, beta, gamma = 1, delta = 0, pm = 0)
480
## Returns random variates for stable DF
482
## slightly amended along nacopula::rstable1
485
## NB: (gamma, delta) can be *vector*s (vectorized along x)
486
stopifnot( 0 < alpha, alpha <= 2, length(alpha) == 1,
487
-1 <= beta, beta <= 1, length(beta) == 1,
488
0 <= gamma, length(pm) == 1, pm %in% 0:2)
490
## Parameterizations:
492
delta <- delta + beta*gamma * .om(gamma,alpha)
493
} else if (pm == 2) {
494
delta <- delta - alpha^(-1/alpha)*gamma*stableMode(alpha, beta)
495
gamma <- alpha^(-1/alpha) * gamma
498
## Calculate uniform and exponential distributed random numbers:
499
theta <- pi * (runif(n)-1/2)
503
## If alpha is equal 1 then:
504
if (alpha == 1 & beta == 0) {
506
## Otherwise, if alpha is different from 1:
508
## FIXME: learn from nacopula::rstable1R()
509
b.tan.pa <- beta*tan(pi*alpha/2)
510
theta0 <- atan(b.tan.pa) / alpha ## == \theta_0
511
c <- (1+b.tan.pa^2)^(1/(2*alpha))
512
a.tht <- alpha*(theta+theta0)
514
(cos(theta))^(1/alpha) ) *
515
(cos(theta-a.tht)/w)^((1-alpha)/alpha)
516
## Use Parametrization 0:
521
result * gamma + delta
525
## ------------------------------------------------------------------------------
528
##' Numerically Integrate -- basically the same as R's integrate()
529
##' --------------------- main difference: no errors, but warnings
530
.integrate2 <- function(f, lower, upper, subdivisions, rel.tol, abs.tol, ...)
532
## Originally implemented by Diethelm Wuertz -- without *any* warnings
534
if (class(version) != "Sversion") {
537
ff <- function(x) f(x, ...)
538
wk <- .External("call_dqags", ff,
539
rho = environment(), as.double(lower),
540
as.double(upper), as.double(abs.tol),
541
as.double(rel.tol), limit = as.integer(subdivisions),
542
PACKAGE = "base")[c("value","ierr")]
544
if(iErr == 6) stop("the input is invalid")
546
## NB: "roundoff error ..." happens many times
547
warning(switch(iErr + 1, "OK",
548
"maximum number of subdivisions reached",
549
"roundoff error was detected",
550
"extremely bad integrand behaviour",
551
"roundoff error is detected in the extrapolation table",
552
"the integral is probably divergent"))
557
integrate(f, lower, upper, subdivisions, rel.tol, abs.tol, ...)[[1]]
562
################################################################################