## ----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) ## ----------------------------------------------------------------------------- hseq <- 10^seq(-9, -3, length.out = 101) hopt <- (1.5 * .Machine$double.eps)^(1/3) e <- function(h) h^2/6 + 0.5*.Machine$double.eps / h plot(hseq, e(hseq), log = "xy", xlab = "Step size", ylab = "Total error", asp = 1, bty = "n", type = "l", main = "Inaccuracy of CD-based derivatives (logarithmic)") abline(v = hopt, lty = 2) hseq2 <- seq(hopt - 5e-6, hopt + 5e-6, length.out = 101) plot(hseq2, e(hseq2), xlab = "Step size", ylab = "Total error", bty = "n", type = "l", main = "Inaccuracy of CD-based derivatives (linear)") abline(v = hopt, lty = 2) ## ----------------------------------------------------------------------------- fdCoef(deriv.order = 2, acc.order = 2) # Same as fdCoef(2) ## ----------------------------------------------------------------------------- w3 <- fdCoef(3) w4 <- fdCoef(4) print(w3) print(w4) ## ----------------------------------------------------------------------------- denom <- factorial(0:6) names(denom) <- paste0("f'", 0:6) num.0 <- c(1, rep(0, 6)) # f(x) = f(x) + 0*f'(x) + 0*f''(x) + ... num.h <- rep(1, 7) num.2h <- 2^(0:6) # f(x-ch) = f - ch f' + (ch)^2/2 f'' - (ch)^3/6 f''' ... num.mh <- suppressWarnings(num.h * c(1, -1)) # Relying on recycling num.m2h <- suppressWarnings(num.2h * c(1, -1)) num <- colSums(rbind(num.m2h, num.mh, num.0, num.h, num.2h) * w4$weights) print(round(num / denom, 5)) ## ----------------------------------------------------------------------------- sum(abs(w4$weights[c(1, 2, 4, 5)] * c(num.m2h[7], num.mh[7], num.h[7], num.2h[7]))) / denom[7] ## ----------------------------------------------------------------------------- sum(abs(w4$weights)) ## ----------------------------------------------------------------------------- w <- fdCoef(acc.order = 4) h2 <- 2^(0:5) h <- rep(1, 6) hm <- h * c(1, -1) h2m <- h2 * c(1, -1) coef.tab <- rbind(h2m, hm, h, h2) # Here, using rbind is more convenient rownames(coef.tab) <- names(w$weights) colnames(coef.tab) <- paste0("f'", seq_len(ncol(coef.tab)) - 1) print(coef.tab * w$weights) print(colSums(coef.tab * w$weights)) ## ----------------------------------------------------------------------------- 0.5*sum(abs(w$weights)) ## ----------------------------------------------------------------------------- m <- 7 # Example order w <- fdCoef(m) k <- sum(w$stencil > 0) # ±h, ±2h, ..., ±kh num.pos <- sapply(1:k, function(i) i^(0:(m+2))) num.neg <- apply(num.pos, 2, function(x) x * c(1, -1)) num.neg <- num.neg[, rev(seq_len(ncol(num.neg)))] nz <- abs(w$stencil) > 1e-12 # Non-zero function weights coef.tab <- sweep(cbind(num.neg, num.pos), 2, w$weights[nz], "*") rownames(coef.tab) <- paste0("f'", seq_len(nrow(coef.tab))-1) colnames(coef.tab) <- names(w$weights[nz]) print(coef.tab) ## ----------------------------------------------------------------------------- rs <- rowSums(coef.tab) print(round(rs, 4)) ## ----------------------------------------------------------------------------- print(c1 <- sum(abs(coef.tab[nrow(coef.tab), ])) / factorial(m+2)) ## ----------------------------------------------------------------------------- print(c2 <- 0.5*sum(abs(w$weights))) ## ----------------------------------------------------------------------------- getCoefs <- function(x, ord) do.call(expand.grid, replicate(ord, x, simplify = FALSE)) rowProd <- function(x) apply(x, 1, prod) getMults <- function(ord) { steps <- list(c(1, 1), c(-1, 1), c(1, -1), c(-1, -1)) coefs <- lapply(steps, getCoefs, ord = ord) signs <- lapply(coefs, rowProd) mults <- signs[[1]] - signs[[2]] - signs[[3]] + signs[[4]] ntab <- expand.grid(replicate(ord, c("i", "j"), simplify = FALSE)) names(mults) <- apply(ntab, 1, paste0, collapse = "") return(mults) } print(getMults(2)) print(getMults(3)) ## ----------------------------------------------------------------------------- mults4 <- getMults(4) print(mults4[mults4 != 0]) ## ----------------------------------------------------------------------------- x <- -0.2456605107847454 # 16 sig. digs t <- 1/59 print(res1 <- (x-t)^4 * (t^-4 / 4), 17) print(res2 <- (x-t)^4 / (t^4 * 4), 17) print(res1 - res2) ## ----------------------------------------------------------------------------- f1 <- function(x) expm1(x)^2 + (1/sqrt(1+x^2) - 1)^2 df1 <- function(x) 2 * exp(x) * expm1(x) - 2*x * (1/sqrt(1+x^2) - 1) / (1 + x^2) / sqrt(1 + x^2) ddf1 <- function(x) (6 * (1/sqrt(1 + x^2) - 1) * x^2)/(1 + x^2)^(5/2) + (2 * x^2)/(1 + x^2)^3 - (2 * (1/sqrt(1 + x^2) - 1))/(1 + x^2)^(3/2) + 2 * exp(2*x) + 2 * exp(x) * expm1(x) dddf1 <- function(x) (18 * (1/sqrt(1 + x^2) - 1) * x)/(1 + x^2)^(5/2) + (6 * x)/(1 + x^2)^3 - (30 * (1/sqrt(1 + x^2) - 1) * x^3)/(1 + x^2)^(7/2) - (18 * x^3)/(1 + x^2)^4 + 6 * exp(2*x) + 2 * exp(x) * expm1(1) squish <- function(x, pow = 1/2, shift = 1) ((abs(x) + shift)^pow - shift^pow) * sign(x) unsquish <- function(y, pow = 1/2, shift = 1) ((abs(y) + shift^pow)^(1/pow) - shift) * sign(y) xgrid <- seq(-0.2, 1.5, 0.01) par(mar = c(2, 2, 0, 0) + .1) plot(xgrid, squish(f1(xgrid)), type = "l", ylim = squish(c(-1, 20)), bty = "n", lwd = 2, xlab = "", ylab = "", yaxt = "n") lines(xgrid, squish(df1(xgrid)), col = 2) lines(xgrid, squish(ddf1(xgrid)), col = 3) lines(xgrid, squish(dddf1(xgrid)), col = 4) axis(2, squish(ats <- c(-1, 0, 1, 2, 5, 10, 20)), labels = ats, las = 1) ## ----eval=FALSE, include=FALSE------------------------------------------------ # f1 <- function(x) x^4 # try1.good <- step.SW(x = 1, f1) # Starts at h0 = 1e-5 # try1.small <- step.SW(x = 1, f1, h0 = 1e-9) # try1.large <- step.SW(x = 1, f1, h0 = 10) # try1.huge <- step.SW(x = 1, f1, h0 = 1000) # try1 <- list(try1.good, try1.small, try1.large, try1.huge) # # hvals1 <- sapply(try1, function(x) x$iterations$h[1]) # for (i in 1:4) { # cat("\n\nDiagnostics for the SW79 algorithm, f(x) = x^4, x = 1, h0 =", hvals1[i], "\n") # cairo_pdf(paste0("power-", i, ".pdf"), 6.2, 4) # tryCatch(par(family = "Fira Sans"), error = \(e) NULL, warning = \(w) NULL) # printDiag(try1[[i]], true.val = 4, main = paste0("f(x) = x^4 with initial h = ", hvals1[i])) # dev.off() # } # # f2 <- sin # try2.good <- step.SW(x = pi/4, f2) # Starts at h0 = 1e-5 # try2.small <- step.SW(x = pi/4, f2, h0 = 1e-9) # try2.large <- step.SW(x = pi/4, f2, h0 = 10) # try2.huge <- step.SW(x = pi/4, f2, h0 = 1000) # Observe the custom warning # try2 <- list(try2.good, try2.small, try2.large, try2.huge) # # hvals2 <- sapply(try1, function(x) x$iterations$h[1]) # for (i in 1:4) { # cat("\n\nDiagnostics for the SW79 algorithm, f(x) = sin(x), x = pi/4, h0 =", hvals1[i], "\n") # cairo_pdf(paste0("sine-", i, ".pdf"), 6.2, 4) # tryCatch(par(family = "Fira Sans"), error = \(e) NULL, warning = \(w) NULL) # printDiag(try2[[i]], true.val = sqrt(2)/2, main = paste0("f(x) = sin(x) with initial h = ", hvals2[i])) # dev.off() # }