Skip to content

Commit 0e29e5c

Browse files
committed
Made zero tolerance adaptive for higher orders of diff. and accuracy
1 parent 28f0239 commit 0e29e5c

9 files changed

Lines changed: 42 additions & 36 deletions

File tree

R/gradient.R

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
checkDimensions <- function(FUN, x, f0 = NULL, func = NULL,
3737
elementwise = NA, vectorised = NA, multivalued = NA,
3838
deriv.order = 1, acc.order = 2, side = 0, h = NULL,
39-
zero.tol = sqrt(.Machine$double.eps), cores = 1, preschedule = TRUE, cl = NULL, ...) {
39+
zero.tol = NULL, cores = 1, preschedule = TRUE, cl = NULL, ...) {
4040
if (missing(FUN)) {
4141
if (is.function(func)) {
4242
FUN <- func
@@ -273,8 +273,8 @@ generateGrid <- function(x, h, stencils, elementwise, vectorised) {
273273
#' \code{"DV"}, or \code{"SW"} to be used in [gradstep()]). The default value is
274274
#' described in \code{?GenD}.
275275
#' @param zero.tol Small positive integer: if \code{abs(x) >= zero.tol}, then, the automatically
276-
#' guessed step size is relative (\code{x} multiplied by the step), unless an auto-selection
277-
#' procedure is requested; otherwise, it is absolute.
276+
#' guessed step size is relative or near-relative (\code{x} multiplied by the step),
277+
#' unless an auto-selection procedure is requested; otherwise, it is absolute.
278278
#' @param f0 Optional numeric: if provided, used to determine the vectorisation type
279279
#' to save time. If FUN(x) must be evaluated (e.g. second derivatives), saves one evaluation.
280280
#' @param h0 Numeric scalar of vector: initial step size for automatic search with
@@ -368,7 +368,7 @@ generateGrid <- function(x, h, stencils, elementwise, vectorised) {
368368
#' system.time(GenD(fslow, x, side = 1, acc.order = 2))
369369
GenD <- function(FUN, x, elementwise = NA, vectorised = NA, multivalued = NA,
370370
deriv.order = 1L, side = 0, acc.order = 2L, stencil = NULL,
371-
h = NULL, zero.tol = sqrt(.Machine$double.eps), h0 = NULL, control = list(),
371+
h = NULL, zero.tol = NULL, h0 = NULL, control = list(),
372372
f0 = NULL, cores = 1, preschedule = TRUE, cl = NULL,
373373
func = NULL, method = NULL, method.args = list(), ...) {
374374
if (is.function(x) && !is.function(FUN)) {
@@ -629,7 +629,7 @@ GenD <- function(FUN, x, elementwise = NA, vectorised = NA, multivalued = NA,
629629
#' Grad(LReLU, seq(-1, 1, 0.1))
630630
Grad <- function(FUN, x, elementwise = NA, vectorised = NA, multivalued = NA,
631631
deriv.order = 1L, side = 0, acc.order = 2, stencil = NULL,
632-
h = NULL, zero.tol = sqrt(.Machine$double.eps), h0 = NULL, control = list(),
632+
h = NULL, zero.tol = NULL, h0 = NULL, control = list(),
633633
f0 = NULL, cores = 1, preschedule = TRUE, cl = NULL,
634634
func = NULL, method = NULL, method.args = list(), ...) {
635635
if (is.function(x) && !is.function(FUN)) {
@@ -714,7 +714,7 @@ Grad <- function(FUN, x, elementwise = NA, vectorised = NA, multivalued = NA,
714714
#' @export
715715
Jacobian <- function(FUN, x, elementwise = NA, vectorised = NA, multivalued = NA,
716716
deriv.order = 1L, side = 0, acc.order = 2, stencil = NULL,
717-
h = NULL, zero.tol = sqrt(.Machine$double.eps), h0 = NULL,
717+
h = NULL, zero.tol = NULL, h0 = NULL,
718718
control = list(), f0 = NULL,
719719
cores = 1, preschedule = TRUE, cl = NULL,
720720
func = NULL, method = NULL, method.args = list(), ...) {

R/step-select.R

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,32 @@
1414
#' # The step-selection function is piecewise linear in log-coordinates
1515
#' plot(-12:4, stepx(10^(-12:4)), log = "y", type = "l")
1616
#' stepx(10^(-10:2), deriv.order = 2, acc.order = 4)
17-
stepx <- function(x, deriv.order = 1, acc.order = 2, zero.tol = sqrt(.Machine$double.eps)) {
17+
stepx <- function(x, deriv.order = 1, acc.order = 2, zero.tol = NULL) {
1818
x <- abs(x)
1919
n <- length(x)
20-
i1 <- x < zero.tol
21-
i3 <- x > 1
22-
i2 <- (!i1) & (!i3)
23-
ret <- rep(zero.tol, length(x))
2420

2521
if (length(deriv.order) == 1) deriv.order <- rep(deriv.order, n)
2622
if (length(acc.order) == 1) acc.order <- rep(acc.order, n)
2723
if (length(deriv.order) != n) stop("The argument 'deriv.order' must have length 1 or length(x).")
2824
if (length(acc.order) != n) stop("The argument 'acc.order' must have length 1 or length(x).")
29-
3025
ad <- deriv.order + acc.order
26+
27+
if (is.null(zero.tol)) zero.tol <- .Machine$double.eps^(1/(ad-0.5))
28+
if (length(zero.tol) == 1) zero.tol <- rep(zero.tol, n) # When it is passed from outside
29+
i1 <- x < zero.tol
30+
i3 <- x > 1
31+
i2 <- (!i1) & (!i3)
32+
ret <- zero.tol # Initialised with i1 case everywhere
33+
3134
if (any(i3)) ret[i3] <- x[i3] * .Machine$double.eps^(1/ad[i3])
3235
if (any(i2)) { # Exponential interpolation via log(y) ~ a + b*log(x)
33-
# f(sqrt(macheps)) = macheps^0.5, f(1) = macheps^(1/(a+d))
34-
leps <- log(.Machine$double.eps)
35-
a <- leps / ad[i2]
36-
b <- 1 - a / leps * 2
37-
ret[i2] <- exp(a + b * log(x[i2]))
36+
# f(zero.tol) = macheps^(1/(a+d-0.5)), f(1) = macheps^(1/(a+d))
37+
leps <- log(.Machine$double.eps)
38+
b0 <- leps / ad[i2] # Passes through (x=1, y = eps^(1/ad))
39+
lz <- log(zero.tol[i2])
40+
y0log <- leps / (ad[i2] - 0.5) # log y at x = zero.tol
41+
b1 <- (y0log - b0) / lz # Slope in log-log space
42+
ret[i2] <- exp(b0 + b1 * log(x[i2]))
3843
}
3944
return(ret)
4045
}

man/GenD.Rd

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/Grad.Rd

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/Jacobian.Rd

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/checkDimensions.Rd

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/stepx.Rd

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tests/testthat/test-Jacobian.R

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ test_that("Jacobian works for scalar functions", {
2727
}
2828
p0 <- structure(c(0.1, 0.2, 0.3), names = c("A", "B", "C"))
2929
h1.jac <- Jacobian(h1, p0)
30-
h2.jac <- pnd::Jacobian(h2, p0)
30+
h2.jac <- Jacobian(h2, p0)
3131
expect_true(inherits(h1.jac, "GenD"))
3232
expect_true(inherits(h2.jac, "GenD"))
3333
expect_identical(dim(h1.jac), c(1L, 3L))

tests/testthat/test-helpers.R

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ test_that("step size is valid for various values of x", {
2020
h0 <- stepx(10^(-16:3))
2121
h <- attr(GenD(sin, x = 10^(-16:3)), "step.size")
2222
expect_identical(h0, h)
23-
expect_true(all(diff(h) >= 0))
24-
expect_identical(h[1], h[2]) # Constant step for small x
25-
expect_identical(h[length(h)], 1000*.Machine$double.eps^(1/3))
23+
expect_true(all(diff(h0) >= 0))
24+
expect_identical(h0[1], h0[2]) # Constant step for small x
25+
# The following depends on the defaults in stepx!
26+
expect_identical(h0[length(h0)], 1000*.Machine$double.eps^(1/3))
2627

2728
expect_true(all(diff(stepx(10^(-16:3), deriv.order = 2, acc.order = 4)) >= 0))
2829
})

0 commit comments

Comments
 (0)