Skip to content

Commit 510e7d3

Browse files
committed
drop coercion and boolean warnings, add support for probabilistic comparisons
1 parent 4805a3f commit 510e7d3

5 files changed

Lines changed: 61 additions & 46 deletions

File tree

R/init.R

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
11
.onLoad <- function(libname, pkgname) {
2-
types <- c("bool", "coercion", "matmult")
3-
types <- paste0("errors.warn.", types)
4-
options(as.list(setNames(rep.int(TRUE, length(types)), types)))
52
register_all_s3_methods()
63
}

R/ops.R

Lines changed: 39 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,75 @@
11
#' @rdname groupGeneric.errors
22
#'
33
#' @details \subsection{\code{Ops}}{
4-
#' Boolean operators drop the uncertainty (showing a warning once) and operate on the
5-
#' numeric values. The rest of the operators propagate the uncertainty as expected from
4+
#' Boolean operators drop the uncertainty and operate on the numeric values
5+
#' unless the option \code{errors.compare.probabilistic} is set to \code{TRUE}.
6+
#' In such case the comparison operators return a numeric value between 0 and 1,
7+
#' representing the probability that the comparison is true, assuming normal
8+
#' distribution of the errors.
9+
#' The rest of the operators propagate the uncertainty as expected from
610
#' the first-order Taylor series method. Any numeric operand is automatically
7-
#' coerced to \code{errors} (showing a warning once) with no uncertainty.}
11+
#' coerced to \code{errors} with no uncertainty.}
812
#'
913
#' @examples
10-
#' y <- set_errors(4:6, 0.2)
14+
#' y <- set_errors(1:3 + 0.1, c(0, 0.1, 0.2))
1115
#' x / sqrt(y) + y * sin(x)
1216
#'
1317
#' # numeric values are automatically coerced to errors
1418
#' x^2
1519
#'
1620
#' # boolean operators drop uncertainty
1721
#' y > x
22+
#' # unless probabilistic comparisons are enabled
23+
#' options(errors.compare.probabilistic = TRUE)
24+
#' y > x
25+
#' options(errors.compare.probabilistic = NULL)
1826
#'
1927
#' @export
2028
Ops.errors <- function(e1, e2) {
21-
if (.Generic %in% c("&", "|", "!", "==", "!=", "<", ">", "<=", ">=")) {
22-
warn_once_bool(.Generic)
29+
cmp <- .Generic %in% c("==", "!=", "<", ">", "<=", ">=") # comparison-type
30+
pm <- .Generic %in% c("+", "-") # addition-type
31+
prd <- .Generic %in% c("*", "/", "%/%", "%%") # product-type
32+
pw <- .Generic %in% c("**", "^") # power-type
33+
34+
if (!any(cmp, pm, prd, pw))
35+
stop(paste("operation", .Generic, "not allowed"))
36+
37+
if (cmp && !getOption("errors.compare.probabilistic", default=FALSE))
2338
return(NextMethod())
24-
}
2539

2640
if (!missing(e2)) {
27-
coercion <- cond2int(!inherits(e1, "errors"), !inherits(e2, "errors"))
28-
if (coercion) {
29-
warn_once_coercion("Ops")
30-
switch(coercion, e1<-set_errors(e1), e2<-set_errors(e2))
31-
}
41+
if (!inherits(e1, "errors")) e1 <- set_errors(e1)
42+
if (!inherits(e2, "errors")) e2 <- set_errors(e2)
3243
}
3344

3445
deriv <- switch(
3546
.Generic,
47+
48+
# comparison-type
49+
"==" = return(NextMethod() & ((!.e(e1) & !.e(e2)) | .c(e1, e2) == 1)),
50+
"!=" = return(NextMethod() | (( .e(e1) | .e(e2)) & .c(e1, e2) != 1)),
51+
"<" = , "<=" = return(zstd(e2 - e1, .Generic)),
52+
">" = , ">=" = return(zstd(e1 - e2, .Generic)),
53+
54+
# addition-type
3655
"+" = , "-" =
3756
if (missing(e2)) {
3857
e2 <- NA
3958
list(do.call(.Generic, list(1)), NA)
4059
}
4160
else list(1, do.call(.Generic, list(1))),
61+
62+
# product-type
4263
"*" = list(.v(e2), .v(e1)),
4364
"/" = list(1 / .v(e2), -.v(e1) / .v(e2)^2),
4465
"%/%" = return(round(e1 / e2)),
4566
"%%" = return(e1 - round(e1 / e2) * e2),
46-
"^" = list(.v(e1)^(.v(e2)-1) * .v(e2), .v(e1)^.v(e2) * log(abs(.v(e1))))
67+
68+
# power-type
69+
"**" = , "^" =
70+
list(.v(e1)^(.v(e2)-1) * .v(e2), .v(e1)^.v(e2) * log(abs(.v(e1))))
4771
)
72+
4873
propagate(unclass(NextMethod()), e1, e2, deriv[[1]], deriv[[2]])
4974
}
5075

@@ -61,10 +86,6 @@ Ops.errors <- function(e1, e2) {
6186
#'
6287
#' #' @export
6388
#' `%*%.errors` = function(x, y) {
64-
#' warn_once(
65-
#' "matrix multiplication not supported for 'errors' objects, uncertainty dropped",
66-
#' fun = .Generic,
67-
#' type = "matmult"
68-
#' )
89+
#' warning("matrix multiplication not supported for 'errors' objects, uncertainty dropped")
6990
#' base::`%*%`(unclass(x), unclass(y))
7091
#' }

R/tidyverse.R

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ vec_restore.errors <- function(x, ...) {
3838
}
3939

4040
vec_proxy_equal.errors <- function(x, ...) {
41-
warn_once_bool("vctrs::vec_proxy_equal")
4241
x
4342
}
4443
# Currently necessary because of r-lib/vctrs/issues/1140

R/utils.R

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,18 @@
11
.pm <- enc2native(intToUtf8(177))
22

3-
warn_once <- function(message, fun, type) {
4-
type <- paste0("errors.warn.", type)
5-
if (getOption(type)) {
6-
options(as.list(setNames(FALSE, type)))
7-
warning("In '", fun, "' : ", message, call. = FALSE)
8-
}
9-
}
10-
11-
warn_once_bool <- function(fun) warn_once(
12-
"boolean operators not defined for 'errors' objects, uncertainty dropped",
13-
fun = fun,
14-
type = "bool"
15-
)
16-
17-
warn_once_coercion <- function(fun) warn_once(
18-
"non-'errors' operand automatically coerced to an 'errors' object with no uncertainty",
19-
fun = "Ops",
20-
type = "coercion"
21-
)
22-
233
# ensure it's numeric
244
.v <- function(x) as.numeric(x)
255
.e <- function(x) as.numeric(errors(x))
6+
.c <- function(x, y) {
7+
if (is.null(cor <- correl(x, y)))
8+
cor <- rep(0, length(x))
9+
cor
10+
}
11+
12+
zstd <- function(x, op) {
13+
p <- pnorm(.v(x) / .e(x))
14+
replace(p, is.nan(p), if (nchar(op) == 1L) 0 else 1)
15+
}
2616

2717
get_exponent <- function(x) ifelse(.v(x), floor(log10(abs(.v(x)))), 0)
2818

man/groupGeneric.errors.Rd

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

0 commit comments

Comments
 (0)