Nothing
## ----include = FALSE----------------------------------------------------------
knitr::knit_hooks$set(pngquant = knitr::hook_pngquant)
knitr::opts_chunk$set(
dev = "png",
dev.args = list(type = if (Sys.info()["sysname"] == "Darwin") "quartz" else "cairo-png"),
fig.width = 512 / 72,
fig.height = 320 / 72,
out.width="10cm",
dpi = 72,
fig.retina = 1,
collapse = TRUE,
comment = "#>"
)
if (.Platform$OS.type == "unix") knitr::opts_chunk$set(pngquant = "--speed=1 --quality=50-60")
## ----setup--------------------------------------------------------------------
library(pnd)
## -----------------------------------------------------------------------------
h0 <- 1e-4
x0 <- 1
fun <- function(x) sin(x)
getRatio <- function(FUN, x, h) {
f <- FUN(x)
fplus <- FUN(x + h)
fminus <- FUN(x - h)
fd <- (fplus - f) / h
bd <- (f - fminus) / h
cd <- (fplus - fminus) / h / 2
et <- abs(cd - fd)
er <- 0.5 * abs(f) * .Machine$double.eps / h
ret <- et / er
attr(ret, "vals") <- c(`h` = h,
bd = bd, cd = cd, fd = fd,
e_trunc = et, e_round = er)
return(ret)
}
print(u0 <- getRatio(FUN = fun, x = x0, h = h0)) # 45035996, too high
## -----------------------------------------------------------------------------
h1 <- h0 * sqrt(100 / max(u0, 1))
print(u1 <- getRatio(FUN = fun, x = x0, h = h1))
## -----------------------------------------------------------------------------
uopt <- getRatio(FUN = fun, x = x0, h = (1.5 * tan(1) * .Machine$double.eps)^(1/3))
nd <- c(step0 = attr(u0, "vals")["cd"], step1 = attr(u1, "vals")["cd"],
optimal = attr(uopt, "vals")["cd"])
print(total.err <- cos(x0) - nd)
## -----------------------------------------------------------------------------
h0 <- 1e-5
x0 <- 0.1
fun <- function(x) pi*x + exp(1)
print(u0 <- getRatio(FUN = fun, x = x0, h = h0))
h1 <- h0 * sqrt(100 / max(u0, 1))
print(u1 <- getRatio(FUN = fun, x = x0, h = h1))
h2 <- h1 * sqrt(100 / max(u0, 1))
print(u2 <- getRatio(FUN = fun, x = x0, h = h2))
## -----------------------------------------------------------------------------
h0 <- 2^-16
x0 <- sqrt(2)
fun <- function(x) x^6 - 2*x^4 - 4*x^2
fun1 <- function(x) 6*x^5 - 8*x^3 - 8*x # f'
fun3 <- function(x) 120*x^3 - 48*x # f'''
print(u0 <- getRatio(FUN = fun, x = x0, h = h0))
h1 <- h0 * sqrt(100 / max(u0, 1))
print(u1 <- getRatio(FUN = fun, x = x0, h = h1))
hopt <- abs(1.5 * fun(x0) / fun3(x0) * .Machine$double.eps)^(1/3)
uopt <- getRatio(FUN = fun, x = x0, h = hopt)
fp.est <- c(step0 = attr(u0, "vals")["cd"], step1 = attr(u1, "vals")["cd"],
optimal = attr(uopt, "vals")["cd"])
print(total.err <- fun1(x0) - fp.est)
## -----------------------------------------------------------------------------
dsin <- function(x, h) (sin(x+h) - sin(x-h)) / h / 2
totErr <- function(x, h, t = 0.5) (dsin(x, t*h) - dsin(x, h)) / (1 - t^2)
hgrid <- 2^seq(-52, 12, 0.5)
suppressWarnings(plot(hgrid, totErr(x = pi/4, hgrid), log = "xy",
main = "Truncation + round-off error of d/dx sin(x) at x = pi/4",
bty = "n", xlab = "Step size", ylab = "Sum of errors"))
## -----------------------------------------------------------------------------
h <- c(2^-8, 2^-9)
te <- totErr(x = pi/4, h = h)
print(diff(log(te)) / diff(log(h)))
## -----------------------------------------------------------------------------
h <- c(1e-4, 1.490116e-07)
b <- c(-h, 0, rev(h)) / min(h)
fc <- fdCoef(deriv.order = 1, stencil = b)
print(fc, 3)
## -----------------------------------------------------------------------------
cos(1) - sum(sin(1 + fc$stencil * h[2]) * fc$weights) / h[2]
## -----------------------------------------------------------------------------
hOpt <- function(x) (1.5 * abs(tan(x)) * .Machine$double.eps)^(1/3)
set.seed(1)
xgrid <- sort(runif(10000, max = 2*pi))
hgrid <- hOpt(xgrid)
df1 <- (sin(xgrid + hgrid) - sin(xgrid - hgrid)) / hgrid / 2
df2 <- (sin(xgrid + 7e-6) - sin(xgrid - 7e-6)) / 7e-6 / 2
fc <- fdCoef(deriv.order = 1, stencil = c(-500, -1, 1, 500))
h4grid <- outer(hgrid, c(-500, -1, 1, 500))
df4 <- rowSums(sweep(sin(xgrid + h4grid), 2, fc$weights, "*")) / hgrid
df.true <- cos(xgrid)
err <- df.true - data.frame(df1, df2, df4)
abserr <- abs(err)
print(summary(err))
print(summary(abserr))
squish <- function(x, pow = 1/6, shift = 1e-12) ((abs(x) + shift)^pow - shift^pow) * sign(x)
xnice <- seq(0, 2*pi, length.out = 401)
plot(xnice, hOpt(xnice), type = "l", log = "y", main = "Optimal step size for sin(x)", bty = "n")
par(mar = c(2, 4, 0, 0) + .1)
matplot(xgrid, squish(abserr[, 2:3] - abserr[, 1]), type = "p", bty = "n",
xlab = "", ylab = "", ylim = squish(c(-5e-10, 5e-11)), yaxt = "n",
col = c("#0000AA88", "#AA000088"), pch = 16, cex = 0.3)
abline(h = 0, lwd = 3, col = "white")
abline(h = 0, lty = 2)
legend("bottomleft", c("Fixed vs. optimal", "4th-order vs. optimal"), bty = "n", pch = 16, col = c("#00008888", "#88000088"))
yax.vals <- c(-3e-10, -1e-10, -3e-11, -1e-11, -1e-12, 0, 1e-12, 1e-11, 3e-11)
axis(2, squish(yax.vals), yax.vals, las = 1)
## -----------------------------------------------------------------------------
S <- function(r) {
if (is.unsorted(r)) r <- sort(r)
n_2 <- length(r)
n <- length(r) * 2
s <- numeric(n_2)
for (k in 1:n_2) {
j <- setdiff(1:n_2, k)
s[k] <- prod(abs(r[j]^2 / (r[k]^2 - r[j]^2))) / r[k]
}
prod(r)^(1/n_2) * sum(s)
}
## -----------------------------------------------------------------------------
S(c(1, 2))
S(c(1, 3)) # Better
S(c(1, 2.6)) # Even better
## -----------------------------------------------------------------------------
ff <- Vectorize(function(x) S(c(1, x)))
oldpar <- par(mar = c(4, 4, 0, 0) + .1)
curve(ff, 1.2, 5, bty = "n", xlab = expression(c[1]), ylab = "S")
## -----------------------------------------------------------------------------
optim(par = 2, fn = ff, method = "BFGS")$par
# THE optimal length-4 grid is x0 + (-2.62, -1, 1, 2.62)h
# Finding the optimum for multiple lengths
nn <- 9
res <- vector("list", nn)
for (i in seq_along(res)) {
set.seed(i)
n <- 2 + 2*i
# init.val <- (1:i)*2
ff <- function(x) S(c(1, x))
lower <- 1:i
upper <- (1+(1:i)*3)^0.9
init.pop <- sapply(1:i, function(j) runif(n*20, lower[j], upper[j]))
init.pop <- apply(init.pop, 1, sort)
if (NCOL(init.pop) == 1) init.pop <- matrix(init.pop) else
if (ncol(init.pop) > nrow(init.pop)) init.pop <- t(init.pop)
ff0 <- apply(init.pop, 1, ff)
x0 <- init.pop[which.min(ff0), ]
res[[i]] <- sort(optim(par = x0, fn = ff, method = "BFGS",
control = list(reltol = 1e-8, maxit = 100))$par)
}
# Table 2b from Oliver & Ruffhead (1975)
tab <- matrix(nrow = length(res), ncol = nn)
for (i in 1:nn) tab[i, 1:i] <- res[[i]]
## -----------------------------------------------------------------------------
bmean <- round(colMeans(tab, na.rm = TRUE), 2)
print(bmean)
ff(bmean) # Close to 10
ff(bmean[1]) # Close to 2
## -----------------------------------------------------------------------------
par(mar = c(4, 4, 0, 0) + .1)
plot(NULL, NULL, xlim = c(0, max(res[[i]]) + .5), ylim = c(0, nn+1),
xlab = "Evaluation points", ylab = expression(n/2-1), bty = "n")
for (i in 1:9) points(c(1, res[[i]]), rep(i, length(res[[i]])+1), pch = 16, type = "b")
for (i in 1:9) points(sapply(res, "[", i), rep(1:nn), pch = 16, type = "b")
abline(v = 0, lty = 2)
abline(v = seq(1, max(bmean)+1), lty = 3, col = "#00000044")
## -----------------------------------------------------------------------------
b <- c(1, bmean) # Nodes
x <- 1:10
plot(x, b, bty = "n", xlab = expression(n/2-1), ylim = c(0, max(bmean)+1),
ylab = expression("Approximate"~c[i]))
ft <- nls(b ~ d + c*x^a, start = c(d = 0, c = 2.5, a = 0.75), weights = 1:10)
lines(x, -4.37 + 5.03 * x^0.55)
lines(x, predict(ft), col = 2)
par(oldpar)
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.