R Under development (unstable) (2024-09-02 r87090 ucrt) -- "Unsuffered Consequences" Copyright (C) 2024 The R Foundation for Statistical Computing Platform: x86_64-w64-mingw32/x64 R is free software and comes with ABSOLUTELY NO WARRANTY. You are welcome to redistribute it under certain conditions. Type 'license()' or 'licence()' for distribution details. R is a collaborative project with many contributors. Type 'contributors()' for more information and 'citation()' on how to cite R or R packages in publications. Type 'demo()' for some demos, 'help()' for on-line help, or 'help.start()' for an HTML browser interface to help. Type 'q()' to quit R. > library("matrixStats") > > rowSums2_R <- function(x, na.rm = FALSE, ..., useNames = NA) { + ## FIXME: sum() may overflow for integers, whereas + ## base::rowSums() doesn't. What should rowSums2() do? + ## apply(x, MARGIN = 1L, FUN = sum, na.rm = na.rm) + res <- rowSums(x, na.rm = na.rm) + if (is.na(useNames) || !useNames) names(res) <- NULL + res + } > > colSums2_R <- function(x, na.rm = FALSE, ..., useNames = NA) { + ## FIXME: sum() may overflow for integers, whereas + ## base::colSums() doesn't. What should colSums2() do? + ## apply(x, MARGIN = 2L, FUN = sum, na.rm = na.rm) + res <- colSums(x, na.rm = na.rm) + if (is.na(useNames) || !useNames) names(res) <- NULL + res + } > > for (mode in c("integer", "logical", "double")) { + x <- matrix(-4:4, nrow = 3, ncol = 3) + storage.mode(x) <- mode + if (mode == "double") x <- x + 0.1 + + # To check names attribute + dimnames <- list(letters[1:3], LETTERS[1:3]) + + # Test with and without dimnames on x + for (setDimnames in c(TRUE, FALSE)) { + if (setDimnames) dimnames(x) <- dimnames + else dimnames(x) <- NULL + # Check names attribute + for (useNames in c(if (!matrixStats:::isUseNamesNADefunct()) NA, TRUE, FALSE)) { + y0 <- rowSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- rowSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- colSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + } + } + } > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: Single-element matrix > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: Single-element matrix:\n") Special case: Single-element matrix: > for (mode in c("integer", "logical", "double")) { + x <- matrix(1, nrow = 1, ncol = 1) + storage.mode(x) <- mode + + # To check names attribute + dimnames <- list("a", "A") + + # Test with and without dimnames on x + for (setDimnames in c(TRUE, FALSE)) { + if (setDimnames) dimnames(x) <- dimnames + else dimnames(x) <- NULL + # Check names attribute + for (useNames in c(if (!matrixStats:::isUseNamesNADefunct()) NA, TRUE, FALSE)) { + y0 <- rowSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- rowSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- colSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + } + } + } > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: Empty matrix > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: Empty matrix:\n") Special case: Empty matrix: > for (mode in c("integer", "logical", "double")) { + x <- matrix(integer(0), nrow = 0, ncol = 0) + storage.mode(x) <- mode + + y0 <- rowSums2_R(x, na.rm = FALSE) + y1 <- rowSums2(x, na.rm = FALSE) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = FALSE) + y1 <- colSums2(x, na.rm = FALSE) + stopifnot(all.equal(y1, y0)) + } > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: All NAs > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: All NAs:\n") Special case: All NAs: > for (mode in c("integer", "logical", "double")) { + x <- matrix(NA_integer_, nrow = 3, ncol = 3) + storage.mode(x) <- mode + + # To check names attribute + dimnames <- list(letters[1:3], LETTERS[1:3]) + + # Test with and without dimnames on x + for (setDimnames in c(TRUE, FALSE)) { + if (setDimnames) dimnames(x) <- dimnames + else dimnames(x) <- NULL + # Check names attribute + for (useNames in c(if (!matrixStats:::isUseNamesNADefunct()) NA, TRUE, FALSE)) { + y0 <- rowSums2_R(x, na.rm = TRUE, useNames = useNames) + y1 <- rowSums2(x, na.rm = TRUE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = TRUE, useNames = useNames) + y1 <- colSums2(x, na.rm = TRUE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + } + } + } > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: All NaNs > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: All NaNs:\n") Special case: All NaNs: > x <- matrix(NA_real_, nrow = 3, ncol = 3) > > # Test with and without dimnames on x > for (setDimnames in c(TRUE, FALSE)) { + if (setDimnames) dimnames(x) <- dimnames + else dimnames(x) <- NULL + # Check names attribute + for (useNames in c(if (!matrixStats:::isUseNamesNADefunct()) NA, TRUE, FALSE)) { + y0 <- rowSums2_R(x, na.rm = TRUE, useNames = useNames) + y1 <- rowSums2(x, na.rm = TRUE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = TRUE, useNames = useNames) + y1 <- colSums2(x, na.rm = TRUE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + } + } > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: All Infs > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: All Infs:\n") Special case: All Infs: > x <- matrix(Inf, nrow = 3, ncol = 3) > > # Test with and without dimnames on x > for (setDimnames in c(TRUE, FALSE)) { + if (setDimnames) dimnames(x) <- dimnames + else dimnames(x) <- NULL + # Check names attribute + for (useNames in c(if (!matrixStats:::isUseNamesNADefunct()) NA, TRUE, FALSE)) { + y0 <- rowSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- rowSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- colSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + } + } > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: All -Infs > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: All -Infs:\n") Special case: All -Infs: > x <- matrix(-Inf, nrow = 3, ncol = 3) > > # Test with and without dimnames on x > for (setDimnames in c(TRUE, FALSE)) { + if (setDimnames) dimnames(x) <- dimnames + else dimnames(x) <- NULL + # Check names attribute + for (useNames in c(if (!matrixStats:::isUseNamesNADefunct()) NA, TRUE, FALSE)) { + y0 <- rowSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- rowSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- colSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + } + } > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: Infs and -Infs > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: Infs and -Infs:\n") Special case: Infs and -Infs: > x <- matrix(c(-Inf, +Inf), nrow = 4, ncol = 4) > > # To check names attribute > dimnames <- list(letters[1:4], LETTERS[1:4]) > > # Test with and without dimnames on x > for (setDimnames in c(TRUE, FALSE)) { + if (setDimnames) dimnames(x) <- dimnames + else dimnames(x) <- NULL + # Check names attribute + for (useNames in c(if (!matrixStats:::isUseNamesNADefunct()) NA, TRUE, FALSE)) { + y0 <- rowSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- rowSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- colSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + } + } > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: NaNs and NAs > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: Infs and -Infs:\n") Special case: Infs and -Infs: > x <- matrix(c(NaN, NA_real_), nrow = 4, ncol = 4) > > y0 <- rowSums(x, na.rm = FALSE) > str(y0) num [1:4] NaN NA NaN NA > stopifnot(all(is.na(y0)), length(unique(y0)) >= 1L) > y1 <- rowSums2(x, na.rm = FALSE) > str(y0) num [1:4] NaN NA NaN NA > stopifnot(all(is.na(y1)), length(unique(y1)) >= 1L) > stopifnot(all.equal(y1, y0)) > > y0 <- colSums(x, na.rm = FALSE) > stopifnot(all(is.na(y0)), length(unique(y0)) == 1L) > y1 <- colSums2(x, na.rm = FALSE) > stopifnot(all(is.na(y1)), length(unique(y1)) == 1L) > ## NOTE, due to compiler optimization, it is not guaranteed that NA is > ## returned here (as one would expect). NaN might very well be returned, > ## when both NA and NaN are involved. This is an accepted feature in R, > ## which is documented in help("is.nan"). See also > ## https://stat.ethz.ch/pipermail/r-devel/2017-April/074009.html. > ## Thus, we cannot guarantee that y1 is identical to y0. > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Special case: Integer overflow with ties > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > cat("Special case: Integer overflow with ties:\n") Special case: Integer overflow with ties: > x <- matrix(.Machine$integer.max, nrow = 4, ncol = 4) > > # Test with and without dimnames on x > for (setDimnames in c(TRUE, FALSE)) { + if (setDimnames) dimnames(x) <- dimnames + else dimnames(x) <- NULL + # Check names attribute + for (useNames in c(if (!matrixStats:::isUseNamesNADefunct()) NA, TRUE, FALSE)) { + y0 <- rowSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- rowSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + + y0 <- colSums2_R(x, na.rm = FALSE, useNames = useNames) + y1 <- colSums2(x, na.rm = FALSE, useNames = useNames) + stopifnot(all.equal(y1, y0)) + } + } > > > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > # Consistency checks > # - - - - - - - - - - - - - - - - - - - - - - - - - - - - > set.seed(1) > > cat("Consistency checks:\n") Consistency checks: > n_sims <- if (Sys.getenv("_R_CHECK_USE_VALGRIND_") != "") 4L else 20L > for (kk in seq_len(n_sims)) { + cat("Random test #", kk, "\n", sep = "") + + # Simulate data in a matrix of any shape + dim <- sample(50:200, size = 2) + n <- prod(dim) + x <- rnorm(n, sd = 100) + dim(x) <- dim + + # Add NAs? + if ((kk %% 4) %in% c(3, 0)) { + cat("Adding NAs\n") + nna <- sample(n, size = 1) + na_values <- c(NA_real_, NaN) + t <- sample(na_values, size = nna, replace = TRUE) + x[sample(length(x), size = nna)] <- t + } + + # Mode? + modes <- "double" + if ((kk %% 4) %in% c(2, 0)) { + modes <- c("integer", "logical") + } + + for (mode in modes) { + if (mode != "double") { + cat(sprintf("Coercing from %s to %s\n", storage.mode(x), mode)) + storage.mode(x) <- mode + } + + na.rm <- sample(c(TRUE, FALSE), size = 1) + + # rowSums2(): + y0 <- rowSums2_R(x, na.rm = na.rm) + y1 <- rowSums2(x, na.rm = na.rm) + stopifnot(all.equal(y1, y0)) + y2 <- colSums2(t(x), na.rm = na.rm) + stopifnot(all.equal(y2, y0)) + + # colSums2(): + y0 <- colSums2_R(x, na.rm = na.rm) + y1 <- colSums2(x, na.rm = na.rm) + stopifnot(all.equal(y1, y0)) + y2 <- rowSums2(t(x), na.rm = na.rm) + stopifnot(all.equal(y2, y0)) + } + } # for (kk ...) Random test #1 Random test #2 Coercing from double to integer Coercing from integer to logical Random test #3 Adding NAs Random test #4 Adding NAs Coercing from double to integer Coercing from integer to logical Random test #5 Random test #6 Coercing from double to integer Coercing from integer to logical Random test #7 Adding NAs Random test #8 Adding NAs Coercing from double to integer Coercing from integer to logical Random test #9 Random test #10 Coercing from double to integer Coercing from integer to logical Random test #11 Adding NAs Random test #12 Adding NAs Coercing from double to integer Coercing from integer to logical Random test #13 Random test #14 Coercing from double to integer Coercing from integer to logical Random test #15 Adding NAs Random test #16 Adding NAs Coercing from double to integer Coercing from integer to logical Random test #17 Random test #18 Coercing from double to integer Coercing from integer to logical Random test #19 Adding NAs Random test #20 Adding NAs Coercing from double to integer Coercing from integer to logical > > proc.time() user system elapsed 0.43 0.10 0.48