From fcc24ab2d5dc64409bc131f72d0ccef6cc5e76c4 Mon Sep 17 00:00:00 2001 From: Uchida Mizuki Date: Sun, 16 Jun 2024 11:19:29 +0900 Subject: [PATCH 1/2] keep class (#12) --- R/apply.R | 4 +++- R/broadcast.R | 12 +++++++++--- R/ddf_col.R | 5 +++-- R/dibble-package.R | 5 +++++ R/dibble.R | 14 ++++++++++---- R/extremes.R | 8 ++++++-- R/ifelse.R | 4 +++- R/matrix.R | 21 +++++++++++++++------ R/methods.R | 4 +++- R/rows.R | 7 +++++-- R/tbl_ddf.R | 15 ++++++++++----- R/utils.R | 3 ++- man/dibble-package.Rd | 23 +++++++++++++++++++++++ 13 files changed, 97 insertions(+), 28 deletions(-) create mode 100644 man/dibble-package.Rd diff --git a/R/apply.R b/R/apply.R index cca46eb..a806cc8 100644 --- a/R/apply.R +++ b/R/apply.R @@ -59,6 +59,8 @@ apply.ddf_col <- function(X, MARGIN, FUN, ...) { MARGIN <- vec_match(MARGIN, names(dim_names)) } + class <- class(X) X <- apply(as.array(X), MARGIN, FUN, ...) - new_ddf_col(X, dim_names[MARGIN]) + new_ddf_col(X, dim_names[MARGIN], + class = class) } diff --git a/R/broadcast.R b/R/broadcast.R index 7affd69..4bbb493 100644 --- a/R/broadcast.R +++ b/R/broadcast.R @@ -37,11 +37,13 @@ broadcast.default <- function(x, is_dim_names(dim_names) ) + class <- class(x) dim <- list_sizes_unnamed(dim_names) x <- array(vec_recycle(x, prod(dim)), dim = dim) - new_ddf_col(x, dim_names) + new_ddf_col(x, dim_names, + class = class) } else { broadcast(as_dibble(x), dim_names) } @@ -50,19 +52,23 @@ broadcast.default <- function(x, #' @rdname broadcast #' @export broadcast.ddf_col <- function(x, dim_names, ...) { + class <- class(x) brdcst_dim_names <- broadcast_dim_names(x, dim_names) x <- broadcast_dibble(x, brdcst_dim_names$broadcast) - new_ddf_col(x, brdcst_dim_names$new_dim_names) + new_ddf_col(x, brdcst_dim_names$new_dim_names, + class = class) } #' @rdname broadcast #' @export broadcast.tbl_ddf <- function(x, dim_names, ...) { + class <- class(x) brdcst_dim_names <- broadcast_dim_names(x, dim_names) x <- broadcast_dibble(x, brdcst_dim_names$broadcast) - new_tbl_ddf(x, brdcst_dim_names$new_dim_names) + new_tbl_ddf(x, brdcst_dim_names$new_dim_names, + class = class) } broadcast_dibble <- function(x, brdcst) { diff --git a/R/ddf_col.R b/R/ddf_col.R index 6acaadb..9ab6ad0 100644 --- a/R/ddf_col.R +++ b/R/ddf_col.R @@ -1,7 +1,8 @@ -new_ddf_col <- function(x, dim_names) { +new_ddf_col <- function(x, dim_names, + class = character()) { structure(x, dim_names = dim_names, - class = "ddf_col") + class = c(setdiff(class, "ddf_col"), "ddf_col")) } as_ddf_col <- function(x, ...) { diff --git a/R/dibble-package.R b/R/dibble-package.R index ff933ff..b4e8fe1 100644 --- a/R/dibble-package.R +++ b/R/dibble-package.R @@ -1,3 +1,8 @@ +#' @keywords internal +"_PACKAGE" + +## usethis namespace: start #' @import rlang #' @import vctrs +## usethis namespace: end NULL diff --git a/R/dibble.R b/R/dibble.R index bfdf73d..895fcc8 100644 --- a/R/dibble.R +++ b/R/dibble.R @@ -236,15 +236,18 @@ aperm_dibble <- function(a, perm, ...) { } } + class <- class(a) if (is_ddf_col(a)) { a <- aperm(as.array(a), perm, ...) - new_ddf_col(a, new_dim_names) + new_ddf_col(a, new_dim_names, + class = class) } else { a <- purrr::modify(undibble(a), function(x) { aperm(x, perm, ...) }) - new_tbl_ddf(a, new_dim_names) + new_tbl_ddf(a, new_dim_names, + class = class) } } @@ -280,17 +283,20 @@ slice_dibble <- function(.data, ...) { }) names(dim_names) <- axes + class <- class(.data) if (is_ddf_col(.data)) { new_ddf_col(exec(`[`, .data, !!!locs, drop = FALSE), - dim_names = dim_names) + dim_names = dim_names, + class = class) } else if (is_tbl_ddf(.data)) { new_tbl_ddf(purrr::modify(undibble(.data), function(x) { exec(`[`, x, !!!locs, drop = FALSE) }), - dim_names = dim_names) + dim_names = dim_names, + class = class) } } diff --git a/R/extremes.R b/R/extremes.R index 58dd02b..5426e7b 100644 --- a/R/extremes.R +++ b/R/extremes.R @@ -49,6 +49,7 @@ pmax.tbl_ddf <- function(..., pmax_dibble <- function(..., na.rm) { args <- list2(...) + class <- class(args[[1]]) dim_names <- union_dim_names(purrr::map(args, dimnames)) args <- purrr::modify(args, function(x) { @@ -56,7 +57,8 @@ pmax_dibble <- function(..., na.rm) { }) new_ddf_col(exec(base::pmax, !!!args), - dim_names) + dim_names, + class = class) } #' @rdname extremes @@ -92,6 +94,7 @@ pmin.tbl_ddf <- function(..., pmin_dibble <- function(..., na.rm) { args <- list2(...) + class <- class(args[[1]]) dim_names <- union_dim_names(purrr::map(args, dimnames)) args <- purrr::modify(args, function(x) { @@ -99,5 +102,6 @@ pmin_dibble <- function(..., na.rm) { }) new_ddf_col(exec(base::pmin, !!!args), - dim_names) + dim_names, + class = class) } diff --git a/R/ifelse.R b/R/ifelse.R index 9556f6f..626e004 100644 --- a/R/ifelse.R +++ b/R/ifelse.R @@ -36,11 +36,13 @@ ifelse.tbl_ddf <- function(test, yes, no, ...) { #' @rdname ifelse #' @export ifelse.ddf_col <- function(test, yes, no, ...) { + class <- class(test) dim_names <- union_dim_names(list(dimnames(test), dimnames(yes), dimnames(no))) test <- as.array(broadcast(test, dim_names)) yes <- as.array(broadcast(yes, dim_names)) no <- as.array(broadcast(no, dim_names)) new_ddf_col(ifelse(test, yes, no), - dim_names) + dim_names, + class = class) } diff --git a/R/matrix.R b/R/matrix.R index deda962..8e107ec 100644 --- a/R/matrix.R +++ b/R/matrix.R @@ -38,6 +38,7 @@ matmult_dibble <- function(x, y) { x <- as_ddf_col(x) y <- as_ddf_col(y) + class <- class(x) dim_names_x <- dimnames(x) dim_names_y <- dimnames(y) @@ -65,20 +66,23 @@ matmult_dibble <- function(x, y) { as.vector(out) } else { dim(out) <- list_sizes_unnamed(new_dim_names) - new_ddf_col(out, new_dim_names) + new_ddf_col(out, new_dim_names, + class = class) } } #' @export t.tbl_ddf <- function(x) { new_tbl_ddf(purrr::modify(undibble(x), t), - rev(dimnames(x))) + rev(dimnames(x)), + class = class(x)) } #' @export t.ddf_col <- function(x) { new_ddf_col(t(undibble(x)), - rev(dimnames(x))) + rev(dimnames(x)), + class = class(x)) } #' @export @@ -94,8 +98,10 @@ solve.tbl_ddf <- function(a, b, ...) { solve.ddf_col <- function(a, b, ...) { if (is_missing(b)) { dim_names <- dimnames(a) + class <- class(a) a <- undibble(a) - new_ddf_col(unname(solve(a)), rev(dim_names)) + new_ddf_col(unname(solve(a)), rev(dim_names), + class = class) } else { NextMethod() } @@ -185,7 +191,8 @@ diag.ddf_col <- function(x, axes, ...) { names(new_dim_names) <- axes } new_ddf_col(diag(as.array(x), ...), - new_dim_names) + new_dim_names, + class = class(x)) } #' @rdname diag @@ -220,9 +227,11 @@ diag.ddf_col <- function(x, axes, ...) { is.null(dim_names_value) || is_scalar_list(dim_names_value) ) + class <- class(x) x <- as.array(x) diag(x) <- as.vector(broadcast(value, dim_names[1L])) - new_ddf_col(x, dim_names) + new_ddf_col(x, dim_names, + class = class) } #' Basic matrices and arrays diff --git a/R/methods.R b/R/methods.R index fbc079f..714baae 100644 --- a/R/methods.R +++ b/R/methods.R @@ -6,6 +6,7 @@ Ops_dibble <- function(e1, e2) { is_ddf_col_e1 <- is_ddf_col(e1) } + class <- class(e1) if (is_missing(e2)) { new_dim_names <- dimnames(e1) } else { @@ -35,7 +36,8 @@ Ops_dibble <- function(e1, e2) { } } - new_ddf_col(NextMethod(), new_dim_names) + new_ddf_col(NextMethod(), new_dim_names, + class = class) } methods_dibble <- function(x, ...) { diff --git a/R/rows.R b/R/rows.R index a8593f8..35e69c5 100644 --- a/R/rows.R +++ b/R/rows.R @@ -36,6 +36,7 @@ rows_upsert_dibble <- function(type = c("insert", "update", "patch", "upsert"), ) is_ddf_col_new <- FALSE } + class <- class(x) # locations of x to new brdcst_x <- broadcast_dim_names_warn(dim_names_x, new_dim_names) @@ -107,9 +108,11 @@ rows_upsert_dibble <- function(type = c("insert", "update", "patch", "upsert"), } if (is_ddf_col_new) { - new_ddf_col(new, new_dim_names) + new_ddf_col(new, new_dim_names, + class = class) } else { - new_tbl_ddf(new, new_dim_names) + new_tbl_ddf(new, new_dim_names, + class = class) } } diff --git a/R/tbl_ddf.R b/R/tbl_ddf.R index 645886e..d0a612a 100644 --- a/R/tbl_ddf.R +++ b/R/tbl_ddf.R @@ -1,7 +1,8 @@ -new_tbl_ddf <- function(x, dim_names) { +new_tbl_ddf <- function(x, dim_names, + class = character()) { structure(x, dim_names = dim_names, - class = "tbl_ddf") + class = c(setdiff(class, "tbl_ddf"), "tbl_ddf")) } is_tbl_ddf <- function(x) { @@ -11,9 +12,11 @@ is_tbl_ddf <- function(x) { #' @export as.list.tbl_ddf <- function(x, ...) { dim_names <- dimnames(x) + class <- class(x) purrr::modify(undibble(x), function(x) { - new_ddf_col(x, dim_names) + new_ddf_col(x, dim_names, + class = setdiff(class, "tbl_ddf")) }) } @@ -97,7 +100,8 @@ is.nan.tbl_ddf <- function(x) { #' @export `[.tbl_ddf` <- function(x, i) { - new_tbl_ddf(NextMethod(), dimnames(x)) + new_tbl_ddf(NextMethod(), dimnames(x), + class = class(x)) } #' @export @@ -145,7 +149,8 @@ mutate.tbl_ddf <- function(.data, ...) { data[[nm]] <- data_nm .data[[nm]] <- undibble(data_nm) } - new_tbl_ddf(.data, dim_names) + new_tbl_ddf(.data, dim_names, + class = class(.data)) } #' @importFrom dplyr select diff --git a/R/utils.R b/R/utils.R index 0ca45a9..2295940 100644 --- a/R/utils.R +++ b/R/utils.R @@ -25,7 +25,8 @@ wrap_ddf_col <- function(f, matrix = FALSE) { function(x, ...) { new_ddf_col(f(as(x), ...), - dim_names = dimnames(x)) + dim_names = dimnames(x), + class = class(x)) } } diff --git a/man/dibble-package.Rd b/man/dibble-package.Rd new file mode 100644 index 0000000..19b0f62 --- /dev/null +++ b/man/dibble-package.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/dibble-package.R +\docType{package} +\name{dibble-package} +\alias{dibble-package} +\title{dibble: Dimensional Data Frames} +\description{ +Provides a 'dibble' that implements data cubes (derived from 'dimensional tibble'), and allows broadcasting by dimensional names. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/UchidaMizuki/dibble} + \item \url{https://uchidamizuki.github.io/dibble/} + \item Report bugs at \url{https://github.com/UchidaMizuki/dibble/issues} +} + +} +\author{ +\strong{Maintainer}: Mizuki Uchida \email{uchidamizuki@vivaldi.net} + +} +\keyword{internal} From 361b970e064fafca6b4203f27169f550088e5b8f Mon Sep 17 00:00:00 2001 From: Uchida Mizuki Date: Sun, 16 Jun 2024 15:37:50 +0900 Subject: [PATCH 2/2] Add tests, fix bugs and implement matrixOps --- DESCRIPTION | 2 +- NAMESPACE | 4 - R/broadcast.R | 4 +- R/dibble.R | 9 +- R/dim_names.R | 4 +- R/extremes.R | 8 +- R/matrix.R | 73 -------------- R/methods.R | 37 +++++++ R/tbl_ddf.R | 3 +- R/zzz.R | 7 +- man/grapes-times-grapes.Rd | 28 ----- tests/testthat/test-apply.R | 9 +- tests/testthat/test-broadcast.R | 27 +++-- tests/testthat/test-ddf_col.R | 174 ++++++++++++++++++++++++++++++++ tests/testthat/test-dibble.R | 16 +-- tests/testthat/test-extremes.R | 35 +++++++ tests/testthat/test-ifelse.R | 9 +- tests/testthat/test-matrix.R | 41 +++++++- tests/testthat/test-rows.R | 102 +++++++++---------- tests/testthat/test-tbl_ddf.R | 9 ++ 20 files changed, 406 insertions(+), 195 deletions(-) delete mode 100644 man/grapes-times-grapes.Rd create mode 100644 tests/testthat/test-ddf_col.R create mode 100644 tests/testthat/test-extremes.R create mode 100644 tests/testthat/test-tbl_ddf.R diff --git a/DESCRIPTION b/DESCRIPTION index eb29861..89bad4b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -31,7 +31,7 @@ Suggests: testthat (>= 3.0.0) Config/testthat/edition: 3 Depends: - R (>= 2.10) + R (>= 4.4) URL: https://github.com/UchidaMizuki/dibble, https://uchidamizuki.github.io/dibble/ BugReports: https://github.com/UchidaMizuki/dibble/issues diff --git a/NAMESPACE b/NAMESPACE index cfd0b15..341fc16 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,9 +3,6 @@ S3method("!",ddf_col) S3method("!",tbl_ddf) S3method("$",tbl_ddf) -S3method("%*%",ddf_col) -S3method("%*%",default) -S3method("%*%",tbl_ddf) S3method("[",tbl_ddf) S3method("[[",tbl_ddf) S3method("diag<-",ddf_col) @@ -115,7 +112,6 @@ S3method(zeros,array) S3method(zeros,ddf_col) S3method(zeros,default) S3method(zeros,tbl_ddf) -export("%*%") export("diag<-") export(apply) export(as_dibble) diff --git a/R/broadcast.R b/R/broadcast.R index 4bbb493..7b71dc8 100644 --- a/R/broadcast.R +++ b/R/broadcast.R @@ -37,13 +37,11 @@ broadcast.default <- function(x, is_dim_names(dim_names) ) - class <- class(x) dim <- list_sizes_unnamed(dim_names) x <- array(vec_recycle(x, prod(dim)), dim = dim) - new_ddf_col(x, dim_names, - class = class) + new_ddf_col(x, dim_names) } else { broadcast(as_dibble(x), dim_names) } diff --git a/R/dibble.R b/R/dibble.R index 895fcc8..f8aff88 100644 --- a/R/dibble.R +++ b/R/dibble.R @@ -52,7 +52,7 @@ dibble <- function(..., x } }) - args <- vec_c(!!!args) + args <- list_unchop(args) if (!is_named(args)) { stopifnot( @@ -399,9 +399,10 @@ find_index <- function(x, names) { } else { stopifnot(is_call(x)) - out <- purrr::map(x[-1L], find_index, - names = names) - vec_c(!!!out) + out <- purrr::map(as.list(x[-1L]), + \(x) find_index(x, + names = names)) + list_unchop(out) } } diff --git a/R/dim_names.R b/R/dim_names.R index 3851b60..b11ceef 100644 --- a/R/dim_names.R +++ b/R/dim_names.R @@ -57,12 +57,12 @@ is_dim_names <- function(x) { } union_dim_names <- function(x) { - x <- vec_c(!!!x) + x <- list_unchop(x) nms <- names(x) nms_unique <- unique(nms) out <- purrr::map(nms_unique, function(nm_unique) { - unique(vec_c(!!!unname(x[nms == nm_unique]))) + unique(list_unchop(unname(x[nms == nm_unique]))) }) names(out) <- nms_unique out diff --git a/R/extremes.R b/R/extremes.R index 5426e7b..0ff8ed2 100644 --- a/R/extremes.R +++ b/R/extremes.R @@ -56,9 +56,9 @@ pmax_dibble <- function(..., na.rm) { as.array(broadcast(x, dim_names)) }) - new_ddf_col(exec(base::pmax, !!!args), + new_ddf_col(exec(base::pmax, !!!args, na.rm = na.rm), dim_names, - class = class) + class = setdiff(class, "tbl_ddf")) } #' @rdname extremes @@ -101,7 +101,7 @@ pmin_dibble <- function(..., na.rm) { as.array(broadcast(x, dim_names)) }) - new_ddf_col(exec(base::pmin, !!!args), + new_ddf_col(exec(base::pmin, !!!args, na.rm = na.rm), dim_names, - class = class) + class = setdiff(class, "tbl_ddf")) } diff --git a/R/matrix.R b/R/matrix.R index 8e107ec..1cc9e05 100644 --- a/R/matrix.R +++ b/R/matrix.R @@ -1,76 +1,3 @@ -#' Matrix Multiplication -#' -#' Multiplies two matrices, if they are conformable. -#' -#' `%*%` overrides [`base::%*%`] to make it generic. The default method -#' calls the base version. -#' -#' @param x Numeric or complex dibble, matrices or vectors. -#' @param y Numeric or complex dibble, matrices or vectors. -#' -#' @return A dibble if x or y is a dibble of a matrix. A scalar numeric if both -#' x and y are dibbles of vectors. See [`base::%*%`] for the return value of the -#' default method. -#' -#' @seealso [`base::%*%`] -#' -#' @export -`%*%` <- function(x, y) { - UseMethod("%*%") -} - -#' @export -`%*%.default` <- function(x, y) { - base::`%*%`(x, y) -} - -#' @export -`%*%.tbl_ddf` <- function(x, y) { - matmult_dibble(x, y) -} - -#' @export -`%*%.ddf_col` <- function(x, y) { - matmult_dibble(x, y) -} - -matmult_dibble <- function(x, y) { - x <- as_ddf_col(x) - y <- as_ddf_col(y) - - class <- class(x) - dim_names_x <- dimnames(x) - dim_names_y <- dimnames(y) - - if (vec_size(dim_names_x) == 1L) { - x <- as.vector(x) - dim_names_x <- NULL - } else { - x <- as.matrix(x) - dim_names_x <- dim_names_x[1L] - } - - if (vec_size(dim_names_y) == 1L) { - y <- as.vector(y) - dim_names_y <- NULL - } else { - y <- as.matrix(y) - dim_names_y <- dim_names_y[2L] - } - - new_dim_names <- purrr::compact(c(dim_names_x, dim_names_y)) - - out <- x %*% y - - if (vec_is_empty(new_dim_names)) { - as.vector(out) - } else { - dim(out) <- list_sizes_unnamed(new_dim_names) - new_ddf_col(out, new_dim_names, - class = class) - } -} - #' @export t.tbl_ddf <- function(x) { new_tbl_ddf(purrr::modify(undibble(x), t), diff --git a/R/methods.R b/R/methods.R index 714baae..ea6d7b5 100644 --- a/R/methods.R +++ b/R/methods.R @@ -40,6 +40,43 @@ Ops_dibble <- function(e1, e2) { class = class) } +matrixOps_dibble <- function(e1, e2) { + e1 <- as_ddf_col(e1) + e2 <- as_ddf_col(e2) + + class <- class(e1) + dim_names_x <- dimnames(e1) + dim_names_y <- dimnames(e2) + + if (vec_size(dim_names_x) == 1L) { + e1 <- as.vector(e1) + dim_names_x <- NULL + } else { + e1 <- as.matrix(e1) + dim_names_x <- dim_names_x[1L] + } + + if (vec_size(dim_names_y) == 1L) { + e2 <- as.vector(e2) + dim_names_y <- NULL + } else { + e2 <- as.matrix(e2) + dim_names_y <- dim_names_y[2L] + } + + new_dim_names <- purrr::compact(c(dim_names_x, dim_names_y)) + + out <- NextMethod() + + if (vec_is_empty(new_dim_names)) { + as.vector(out) + } else { + dim(out) <- list_sizes_unnamed(new_dim_names) + new_ddf_col(out, new_dim_names, + class = class) + } +} + methods_dibble <- function(x, ...) { x <- as_ddf_col(x) NextMethod() diff --git a/R/tbl_ddf.R b/R/tbl_ddf.R index d0a612a..02f9502 100644 --- a/R/tbl_ddf.R +++ b/R/tbl_ddf.R @@ -134,6 +134,7 @@ mutate.tbl_ddf <- function(.data, ...) { nms <- names(dots) dim_names <- dimnames(.data) + class <- class(.data) data <- as.list(.data) .data <- undibble(.data) @@ -150,7 +151,7 @@ mutate.tbl_ddf <- function(.data, ...) { .data[[nm]] <- undibble(data_nm) } new_tbl_ddf(.data, dim_names, - class = class(.data)) + class = class) } #' @importFrom dplyr select diff --git a/R/zzz.R b/R/zzz.R index 3b73a10..23efa2c 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,4 +1,4 @@ -.onLoad <- function(...) { +.onLoad <- function(...) { # nocov start as_dim_names <<- memoise::memoise(as_dim_names) union_dim_names <<- memoise::memoise(union_dim_names) broadcast_dim_names_impl <<- memoise::memoise(broadcast_dim_names_impl) @@ -9,7 +9,10 @@ registerS3method("Ops", "ddf_col", Ops_dibble) registerS3method("Ops", "tbl_ddf", Ops_dibble) + registerS3method("matrixOps", "ddf_col", matrixOps_dibble) + registerS3method("matrixOps", "tbl_ddf", matrixOps_dibble) + registerS3method("Math", "tbl_ddf", methods_dibble) registerS3method("Summary", "tbl_ddf", methods_dibble) -} +} # nocov end diff --git a/man/grapes-times-grapes.Rd b/man/grapes-times-grapes.Rd deleted file mode 100644 index 1475b23..0000000 --- a/man/grapes-times-grapes.Rd +++ /dev/null @@ -1,28 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/matrix.R -\name{\%*\%} -\alias{\%*\%} -\title{Matrix Multiplication} -\usage{ -x \%*\% y -} -\arguments{ -\item{x}{Numeric or complex dibble, matrices or vectors.} - -\item{y}{Numeric or complex dibble, matrices or vectors.} -} -\value{ -A dibble if x or y is a dibble of a matrix. A scalar numeric if both -x and y are dibbles of vectors. See \code{\link[base:matmult]{base::\%*\%}} for the return value of the -default method. -} -\description{ -Multiplies two matrices, if they are conformable. -} -\details{ -\code{\%*\%} overrides \code{\link[base:matmult]{base::\%*\%}} to make it generic. The default method -calls the base version. -} -\seealso{ -\code{\link[base:matmult]{base::\%*\%}} -} diff --git a/tests/testthat/test-apply.R b/tests/testthat/test-apply.R index f7cac0a..ac64310 100644 --- a/tests/testthat/test-apply.R +++ b/tests/testthat/test-apply.R @@ -1,4 +1,4 @@ -test_that("apply", { +test_that("apply() works", { arr <- array(1:24, 2:4, list(axis1 = 1:2, axis2 = 1:3, @@ -18,4 +18,11 @@ test_that("apply", { test_apply(ddf_col) test_apply(tbl_ddf) + + # Test that the class is preserved + class(ddf_col) <- c("my_class", class(ddf_col)) + expect_s3_class(apply(ddf_col, 2, sum), c("my_class", "ddf_col")) + + class(tbl_ddf) <- c("my_class", class(tbl_ddf)) + expect_s3_class(apply(tbl_ddf, 2, sum), c("my_class", "ddf_col")) }) diff --git a/tests/testthat/test-broadcast.R b/tests/testthat/test-broadcast.R index ea77a4c..354af25 100644 --- a/tests/testthat/test-broadcast.R +++ b/tests/testthat/test-broadcast.R @@ -1,4 +1,4 @@ -test_that("broadcast", { +test_that("broadcast() works", { x <- broadcast(1:2, list(axis1 = letters[1:2])) expect_equal(as.array(x), @@ -9,22 +9,37 @@ test_that("broadcast", { expect_equal(as.array(y), array(1:3, 3)) - expect_silent(broadcast(x * y, c("axis1", "axis2"))) + z <- broadcast(1:4, + list(axis3 = letters[1:4])) + expect_equal(as.array(z), + array(1:4, 4)) + + xy <- expect_silent(broadcast(x * y, c("axis1", "axis2"))) + expect_equal(as.array(xy), outer(as.array(x), as.array(y))) + + xyz <- expect_silent(broadcast(x * y * z, c("axis1", "axis2", "axis3"))) + expect_equal(as.array(xyz), outer(outer(as.array(x), as.array(y)), as.array(z))) + + # Test that the class is preserved + class(x) <- c("my_class", class(x)) + xy <- broadcast(x * y, c("axis1", "axis2")) + expect_s3_class(xy, class(x)) }) -test_that("broadcast-warn", { +test_that("broadcast() warns", { x <- broadcast(1:4, list(axis1 = 1:2, axis2 = 1:2)) y <- x - expect_silent(x * y) + xy1 <- expect_silent(x * y) y <- t(x) expect_warning(x * y) - expect_silent(broadcast(x * y, - c("axis1", "axis2"))) + xy2 <- expect_silent(broadcast(x * y, + c("axis1", "axis2"))) + expect_equal(xy1, xy2) y <- broadcast(1:6, list(axis1 = 1:2, diff --git a/tests/testthat/test-ddf_col.R b/tests/testthat/test-ddf_col.R new file mode 100644 index 0000000..05e4f8b --- /dev/null +++ b/tests/testthat/test-ddf_col.R @@ -0,0 +1,174 @@ +test_that("as.matrix.ddf_col() works", { + x <- broadcast(1:2, + dim_names = list(axis1 = 1:2)) + expect_equal(as.matrix(x), matrix(1:2)) + + x <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + expect_equal(as.matrix(x), matrix(1:6, 2, 3)) + + x <- broadcast(1:24, + dim_names = list(axis1 = 1:2, + axis2 = 1:3, + axis3 = 1:4)) + expect_error(as.matrix(x)) +}) + +test_that("as.table.ddf_col() works", { + dim_names <- list(axis1 = letters[1:2]) + x <- broadcast(1:2, + dim_names = dim_names) + expect_s3_class(as.table(x), "table") + expect_equal(dimnames(as.table(x)), dim_names) + + dim_names <- list(axis1 = letters[1:2], + axis2 = letters[1:3]) + x <- broadcast(1:6, + dim_names = dim_names) + expect_s3_class(as.table(x), "table") + expect_equal(dimnames(as.table(x)), dim_names) +}) + +test_that("`dimnames<-.ddf_col`() works", { + dim_names <- list(axis1 = letters[1:2], + axis2 = letters[1:3]) + x <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + dimnames(x) <- dim_names + expect_equal(dimnames(x), dim_names) +}) + +test_that("as.data.frame.ddf_col() works", { + x <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + y <- expect_s3_class(as.data.frame(x), "data.frame") + + y <- y %>% + dibble_by("axis1", "axis2") + y <- y[[1]] + expect_equal(y, x) +}) + +test_that("aperm.ddf_col() works", { + x <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + y <- aperm(x, c(2, 1)) + expect_equal(y, t(x)) + + x <- broadcast(1:24, + dim_names = list(axis1 = 1:2, + axis2 = 1:3, + axis3 = 1:4)) + y <- array(1:24, c(2, 3, 4)) + expect_equal(as.array(aperm(x, c(3, 1, 2))), aperm(y, c(3, 1, 2))) + + # Test that the class is preserved + class(x) <- c("my_class", class(x)) + y <- aperm(x, c(3, 1, 2)) + expect_s3_class(y, class(x)) +}) + +test_that("`wrap_ddf_col() works", { + set.seed(1234) + + # `!.ddf_col`() + x <- sample(c(FALSE, TRUE), 6, + replace = TRUE) + ddf_col <- broadcast(x, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + arr <- array(x, c(2, 3)) + + expect_equal(!(!ddf_col), ddf_col) + expect_equal(as.array(!ddf_col), !arr) + + # is.finite.ddf_col(), is.infinite.ddf_col(), is.nan.ddf_col(), is.na.ddf_col() + x <- c(1, 2, NA, Inf, -Inf, NaN) + ddf_col <- broadcast(x, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + arr <- array(x, c(2, 3)) + + expect_equal(as.array(is.finite(ddf_col)), is.finite(arr)) + expect_equal(as.array(is.infinite(ddf_col)), is.infinite(arr)) + expect_equal(as.array(is.nan(ddf_col)), is.nan(arr)) + expect_equal(as.array(is.na(ddf_col)), is.na(arr)) + + # Test that the class is preserved + class(ddf_col) <- c("my_class", class(ddf_col)) + expect_s3_class(!ddf_col, class(ddf_col)) +}) + +test_that("slice.ddf_col() works", { + ddf_col <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + arr <- array(1:6, c(2, 3)) + + expect_equal(as.array(slice(ddf_col, 1:2, 2:3)), arr[1:2, 2:3]) + expect_equal(as.vector(slice(ddf_col, 1, 2:3)), arr[1, 2:3]) + + # Test that the class is preserved + class(ddf_col) <- c("my_class", class(ddf_col)) + expect_s3_class(slice(ddf_col, 1:2, 2:3), class(ddf_col)) +}) + +test_that("select.ddf_col() and relocate.ddf_col() work", { + ddf_col <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + ddf_col_selected <- ddf_col %>% + select("axis2") + ddf_col_relocated <- ddf_col %>% + relocate("axis2") + + expect_equal(names(dimnames(ddf_col_selected)), c("axis2", "axis1")) + expect_equal(ddf_col_selected, aperm(ddf_col, c("axis2", "axis1"))) + + expect_equal(names(dimnames(ddf_col_relocated)), c("axis2", "axis1")) + expect_equal(ddf_col_relocated, aperm(ddf_col, c("axis2", "axis1"))) + + # Test that the class is preserved + class(ddf_col) <- c("my_class", class(ddf_col)) + expect_s3_class(select(ddf_col, "axis2"), class(ddf_col)) +}) + +test_that("rename.ddf_col() works", { + ddf_col <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + ddf_col_renamed <- ddf_col %>% + rename("axis1_2" = "axis1", + "axis2_2" = "axis2") + expect_equal(names(dimnames(ddf_col_renamed)), c("axis1_2", "axis2_2")) + + # Test that the class is preserved + class(ddf_col) <- c("my_class", class(ddf_col)) + expect_s3_class(rename(ddf_col, "axis1_2" = "axis1"), class(ddf_col)) +}) + +test_that("filter.ddf_col() works", { + ddf_col <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + arr <- array(1:6, c(2, 3)) + + ddf_col_filtered <- ddf_col %>% + filter(axis1 == 2) + expect_equal(as.vector(ddf_col_filtered), arr[2, ]) + + # Test that the class is preserved + class(ddf_col) <- c("my_class", class(ddf_col)) + expect_s3_class(filter(ddf_col, axis1 == 2), class(ddf_col)) +}) + +test_that("print.ddf_col() works", { + ddf_col <- broadcast(1:6, + dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + expect_output(print(ddf_col)) +}) diff --git a/tests/testthat/test-dibble.R b/tests/testthat/test-dibble.R index 0d309f8..aaf43ce 100644 --- a/tests/testthat/test-dibble.R +++ b/tests/testthat/test-dibble.R @@ -1,4 +1,4 @@ -test_that("dibble", { +test_that("dibble() works", { arr1 <- array(1:6, 2:3, list(axis1 = letters[1:2], axis2 = letters[1:3])) @@ -14,15 +14,15 @@ test_that("dibble", { .dim_names = c("axis1", "axis2", "axis3")) expect_s3_class(tbl_ddf, "tbl_ddf") -}) -test_that("dibble_by", { - library(dplyr) - library(tidyr) + tbl_ddf2 <- dibble(tbl_ddf) + expect_equal(tbl_ddf2, tbl_ddf) +}) - df <- expand_grid(axis1 = letters[1:3], - axis2 = letters[1:3]) %>% - mutate(value = row_number()) +test_that("dibble_by() works", { + df <- tidyr::expand_grid(axis1 = letters[1:3], + axis2 = letters[1:3]) %>% + dplyr::mutate(value = dplyr::row_number()) expect_equal(df, df %>% diff --git a/tests/testthat/test-extremes.R b/tests/testthat/test-extremes.R new file mode 100644 index 0000000..92cc521 --- /dev/null +++ b/tests/testthat/test-extremes.R @@ -0,0 +1,35 @@ +test_that("pmax() and pmin() work", { + x <- c(1, 2, 3, NA, 5, 6) + y <- c(3, 2, 1, 5, NA, 6) + + x_tbl_ddf <- dibble(x = x, + .dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + y_tbl_ddf <- dibble(y = y, + .dim_names = list(axis1 = 1:2, + axis2 = 1:3)) + x_ddf_col <- x_tbl_ddf$x + y_ddf_col <- y_tbl_ddf$y + + x_arr <- array(x, dim = c(2, 3)) + y_arr <- array(y, dim = c(2, 3)) + + expect_equal(as.array(pmax(x_tbl_ddf, y_tbl_ddf)), pmax(x_arr, y_arr)) + expect_equal(as.array(pmax(x_ddf_col, y_ddf_col)), pmax(x_arr, y_arr)) + expect_equal(as.array(pmax(x_ddf_col, y_ddf_col, na.rm = TRUE)), + pmax(x_arr, y_arr, na.rm = TRUE)) + + expect_equal(as.array(pmin(x_tbl_ddf, y_tbl_ddf)), pmin(x_arr, y_arr)) + expect_equal(as.array(pmin(x_ddf_col, y_ddf_col)), pmin(x_arr, y_arr)) + expect_equal(as.array(pmin(x_ddf_col, y_ddf_col, na.rm = TRUE)), + pmin(x_arr, y_arr, na.rm = TRUE)) + + # Test that the class is preserved + class(x_tbl_ddf) <- c("my_class", class(x_tbl_ddf)) + expect_s3_class(pmax(x_tbl_ddf, y_tbl_ddf), c("my_class", "tbl_ddf")) + expect_s3_class(pmin(x_tbl_ddf, y_tbl_ddf), c("my_class", "ddf_col")) + + class(x_ddf_col) <- c("my_class", class(x_ddf_col)) + expect_s3_class(pmax(x_ddf_col, y_ddf_col), c("my_class", "ddf_col")) + expect_s3_class(pmin(x_ddf_col, y_ddf_col), c("my_class", "ddf_col")) +}) diff --git a/tests/testthat/test-ifelse.R b/tests/testthat/test-ifelse.R index 9867735..33b13b2 100644 --- a/tests/testthat/test-ifelse.R +++ b/tests/testthat/test-ifelse.R @@ -1,9 +1,12 @@ -test_that("ifelse", { +test_that("ifelse() works", { expect_equal(ifelse(1:3 == 2, 4, 5), base::ifelse(1:3 == 2, 4, 5)) - ddf_col <- broadcast(1:3, - list(axis = 1:3)) + tbl_ddf <- dibble(x = 1:3, + .dim_names = list(axis = 1:3)) + ddf_col <- tbl_ddf$x + expect_equal(as.vector(ifelse(tbl_ddf$x == 2, 4, 5)), + base::ifelse(1:3 == 2, 4, 5)) expect_equal(as.vector(ifelse(ddf_col == 2, 4, 5)), base::ifelse(1:3 == 2, 4, 5)) }) diff --git a/tests/testthat/test-matrix.R b/tests/testthat/test-matrix.R index c70b516..3a81d1b 100644 --- a/tests/testthat/test-matrix.R +++ b/tests/testthat/test-matrix.R @@ -1,4 +1,4 @@ -test_that("%*%", { +test_that("`%*%`() works", { # mat %*% mat mat_x <- matrix(1:9, 3, dimnames = list(axis1 = 1:3, @@ -10,6 +10,10 @@ test_that("%*%", { ddf_y <- as_dibble(mat_y) expect_equal(as.matrix(ddf_x %*% ddf_y), unname(mat_x %*% mat_y)) + ddf_x <- dibble(x = ddf_x) + ddf_y <- dibble(x = ddf_y) + expect_equal(as.matrix(ddf_x %*% ddf_y), unname(mat_x %*% mat_y)) + # vec %*% mat vec_x <- array(1:3, 3, dimnames = list(axis2 = 1:3)) @@ -40,13 +44,16 @@ test_that("%*%", { expect_equal(ddf_x %*% ddf_y, as.vector(vec_x %*% vec_y)) }) -test_that("t", { +test_that("t() works", { # vec vec <- array(1:3, 3, dimnames = list(axis = 1:3)) ddf <- as_dibble(vec) expect_equal(as.array(t(ddf)), unname(t(vec))) + ddf <- dibble(x = ddf) + expect_equal(as.array(t(ddf)), unname(t(vec))) + # mat mat <- matrix(1:9, 3, dimnames = list(axis1 = 1:3, @@ -55,7 +62,21 @@ test_that("t", { expect_equal(as.array(t(ddf)), unname(t(mat))) }) -test_that("diag", { +test_that("solve() works", { + set.seed(1234) + + # mat + mat <- matrix(runif(9), 3, + dimnames = list(axis1 = 1:3, + axis2 = 1:3)) + ddf <- as_dibble(mat) + expect_equal(as.matrix(solve(ddf)), unname(solve(mat))) + + ddf <- dibble(x = ddf) + expect_equal(as.matrix(solve(ddf)), unname(solve(mat))) +}) + +test_that("diag() works", { arr <- matrix(1:9, 3) ddf_col <- broadcast(1:9, list(axis1 = letters[1:3], @@ -68,3 +89,17 @@ test_that("diag", { expect_equal(as.array(ddf_col), arr) }) + +test_that("eye(), ones() and zeros() work", { + ddf <- broadcast(1:9, + list(axis1 = letters[1:3], + axis2 = letters[1:3])) + expect_equal(as.matrix(eye(ddf)), diag(3)) + expect_equal(as.matrix(ones(ddf)), matrix(1, 3, 3)) + expect_equal(as.matrix(zeros(ddf)), matrix(0, 3, 3)) + + ddf <- dibble(x = ddf) + expect_equal(as.matrix(eye(ddf)), diag(3)) + expect_equal(as.matrix(ones(ddf)), matrix(1, 3, 3)) + expect_equal(as.matrix(zeros(ddf)), matrix(0, 3, 3)) +}) diff --git a/tests/testthat/test-rows.R b/tests/testthat/test-rows.R index a904b8c..492cfa6 100644 --- a/tests/testthat/test-rows.R +++ b/tests/testthat/test-rows.R @@ -1,30 +1,28 @@ test_that("rows", { - library(dplyr) - check_rows <- function(x, y, axes) { # check insert expect_error(x %>% - rows_insert(y)) + dplyr::rows_insert(y)) check_insert <- function(x) { x_insert1 <- x %>% - rows_insert(y, - conflict = "ignore") %>% + dplyr::rows_insert(y, + conflict = "ignore") %>% broadcast(axes) %>% - as_tibble(n = "x") + tibble::as_tibble(n = "x") x_insert2 <- x %>% - as_tibble(n = "x") %>% - rows_insert(y %>% - as_tibble(n = "x"), - by = axes, - conflict = "ignore") + tibble::as_tibble(n = "x") %>% + dplyr::rows_insert(y %>% + tibble::as_tibble(n = "x"), + by = axes, + conflict = "ignore") x_insert <- x_insert1 %>% - rename(x1 = x) %>% - left_join(x_insert2 %>% - rename(x2 = x), - by = axes) + dplyr::rename(x1 = x) %>% + dplyr::left_join(x_insert2 %>% + dplyr::rename(x2 = x), + by = axes) expect_equal(x_insert$x1, x_insert$x2) } @@ -33,27 +31,27 @@ test_that("rows", { # check update expect_error(x %>% - rows_update(y)) + dplyr::rows_update(y)) check_update <- function(x) { x_update1 <- x %>% - rows_update(y, - unmatched = "ignore") %>% + dplyr::rows_update(y, + unmatched = "ignore") %>% broadcast(axes) %>% - as_tibble(n = "x") + tibble::as_tibble(n = "x") x_update2 <- x %>% - as_tibble(n = "x") %>% - rows_update(y %>% - as_tibble(n = "x"), - by = axes, - unmatched = "ignore") + tibble::as_tibble(n = "x") %>% + dplyr::rows_update(y %>% + tibble::as_tibble(n = "x"), + by = axes, + unmatched = "ignore") x_update <- x_update1 %>% - rename(x1 = x) %>% - left_join(x_update2 %>% - rename(x2 = x), - by = axes) + dplyr::rename(x1 = x) %>% + dplyr::left_join(x_update2 %>% + dplyr::rename(x2 = x), + by = axes) expect_equal(x_update$x1, x_update$x2) } @@ -62,27 +60,27 @@ test_that("rows", { # check patch expect_error(x %>% - rows_patch(y)) + dplyr::rows_patch(y)) check_patch <- function(x) { x_patch1 <- x %>% - rows_patch(y, - unmatched = "ignore") %>% + dplyr::rows_patch(y, + unmatched = "ignore") %>% broadcast(axes) %>% - as_tibble(n = "x") + tibble::as_tibble(n = "x") x_patch2 <- x %>% - as_tibble(n = "x") %>% - rows_patch(y %>% - as_tibble(n = "x"), - by = axes, - unmatched = "ignore") + tibble::as_tibble(n = "x") %>% + dplyr::rows_patch(y %>% + tibble::as_tibble(n = "x"), + by = axes, + unmatched = "ignore") x_patch <- x_patch1 %>% - rename(x1 = x) %>% - left_join(x_patch2 %>% - rename(x2 = x), - by = axes) + dplyr::rename(x1 = x) %>% + dplyr::left_join(x_patch2 %>% + dplyr::rename(x2 = x), + by = axes) expect_equal(x_patch$x1, x_patch$x2) } @@ -91,26 +89,26 @@ test_that("rows", { # check upsert expect_silent(x %>% - rows_upsert(y) %>% + dplyr::rows_upsert(y) %>% broadcast(axes)) check_upsert <- function(x) { x_upsert1 <- x %>% - rows_upsert(y) %>% + dplyr::rows_upsert(y) %>% broadcast(axes) %>% - as_tibble(n = "x") + tibble::as_tibble(n = "x") x_upsert2 <- x %>% - as_tibble(n = "x") %>% - rows_upsert(y %>% - as_tibble(n = "x"), - by = axes) + tibble::as_tibble(n = "x") %>% + dplyr::rows_upsert(y %>% + tibble::as_tibble(n = "x"), + by = axes) x_upsert <- x_upsert1 %>% - rename(x1 = x) %>% - left_join(x_upsert2 %>% - rename(x2 = x), - by = axes) + dplyr::rename(x1 = x) %>% + dplyr::left_join(x_upsert2 %>% + dplyr::rename(x2 = x), + by = axes) expect_equal(x_upsert$x1, x_upsert$x2) } diff --git a/tests/testthat/test-tbl_ddf.R b/tests/testthat/test-tbl_ddf.R new file mode 100644 index 0000000..bf05ea0 --- /dev/null +++ b/tests/testthat/test-tbl_ddf.R @@ -0,0 +1,9 @@ +test_that("mutate.tbl_ddf() works", { + tbl_ddf <- dibble(x = 1:12, + y = 13:24, + .dim_names = list(axis1 = 1:4, + axis2 = 1:3)) %>% + mutate(z = x + y) + + expect_equal(tbl_ddf$z, tbl_ddf$x + tbl_ddf$y) +})