├── .Rbuildignore ├── .gitignore ├── .travis.yml ├── DESCRIPTION ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── RcppExports.R ├── aaa.R ├── arith.R ├── bind.R ├── broadcast.R ├── clip.R ├── coercion-base.R ├── coercion.R ├── compare.R ├── compat-base.R ├── compat-purrr.R ├── compat-vctrs-arith.R ├── compat-vctrs-math.R ├── compat-vctrs.R ├── container-cast.R ├── container-type.R ├── container-type2.R ├── diagonal.R ├── dim-n.R ├── dim-names-common.R ├── dim-names.R ├── dim.R ├── dot.R ├── duplicate.R ├── expand.R ├── extract-assign.R ├── extract.R ├── extremum.R ├── flatten.R ├── flip.R ├── full-like.R ├── hypot.R ├── inner-cast.R ├── inner-type.R ├── logical.R ├── max-pos.R ├── min-pos.R ├── multiply-add.R ├── pad.R ├── print.R ├── reducers-custom.R ├── reducers.R ├── reshape.R ├── rotate.R ├── rray.R ├── shape.R ├── slice-assign.R ├── slice.R ├── sort.R ├── split.R ├── squeeze.R ├── subset-assign.R ├── subset.R ├── tile.R ├── transpose.R ├── unique.R ├── util.R ├── yank-assign.R └── yank.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── codecov.yml ├── cran-comments.md ├── inst ├── WORDLIST └── include │ ├── api.h │ ├── cast.h │ ├── dispatch.h │ ├── r-api.h │ ├── rray.h │ ├── subset-tools.h │ ├── tools │ ├── errors.h │ ├── template-utils.h │ └── tools.h │ ├── type2.h │ └── utils.h ├── man ├── as_array.Rd ├── as_matrix.Rd ├── as_rray.Rd ├── common-dim-names.Rd ├── dim-names.Rd ├── extremum.Rd ├── figures │ └── logo.png ├── is_rray.Rd ├── new_rray.Rd ├── pad.Rd ├── rray-compare.Rd ├── rray-logical.Rd ├── rray.Rd ├── rray_all_equal.Rd ├── rray_arith.Rd ├── rray_bind.Rd ├── rray_broadcast.Rd ├── rray_clip.Rd ├── rray_diag.Rd ├── rray_dim.Rd ├── rray_dim_n.Rd ├── rray_dot.Rd ├── rray_duplicate.Rd ├── rray_elems.Rd ├── rray_expand.Rd ├── rray_extract.Rd ├── rray_flatten.Rd ├── rray_flip.Rd ├── rray_full_like.Rd ├── rray_hypot.Rd ├── rray_if_else.Rd ├── rray_max.Rd ├── rray_max_pos.Rd ├── rray_mean.Rd ├── rray_min.Rd ├── rray_min_pos.Rd ├── rray_multiply_add.Rd ├── rray_prod.Rd ├── rray_reshape.Rd ├── rray_rotate.Rd ├── rray_slice.Rd ├── rray_sort.Rd ├── rray_split.Rd ├── rray_squeeze.Rd ├── rray_subset.Rd ├── rray_sum.Rd ├── rray_tile.Rd ├── rray_transpose.Rd ├── rray_unique.Rd ├── rray_yank.Rd └── vctrs-compat.Rd ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── rray.Rproj ├── src ├── .gitignore ├── Makevars ├── Makevars.win ├── RcppExports.cpp ├── accumulators.cpp ├── arith.cpp ├── bind.cpp ├── broadcast.cpp ├── builders.cpp ├── cast.cpp ├── clip.cpp ├── compare.cpp ├── dim-names-common.cpp ├── dim-names.cpp ├── dim.cpp ├── extract-assign.cpp ├── extract.cpp ├── extremum.cpp ├── generators.cpp ├── hypot.cpp ├── initialize.cpp ├── logical.cpp ├── manipulation.cpp ├── misc.cpp ├── multiply-add.cpp ├── positions.cpp ├── r-api.cpp ├── reducers-custom.cpp ├── reducers.cpp ├── subset-assign.cpp ├── subset-tools.cpp ├── subset.cpp ├── type2.cpp ├── utils.cpp ├── validation.cpp ├── yank-assign.cpp └── yank.cpp ├── tests ├── testthat.R └── testthat │ ├── out │ ├── test-0-axis-1D.txt │ ├── test-0-axis-2D.txt │ ├── test-0-axis-3D.txt │ ├── test-1D-rray.txt │ ├── test-2D-rray.txt │ ├── test-error-rray-extract-logical-size.txt │ ├── test-error-rray-extract-oob-character.txt │ ├── test-error-rray-extract-oob-negative.txt │ ├── test-error-rray-extract-oob.txt │ ├── test-error-rray-extract-unnamed.txt │ ├── test-error-rray-subset-logical-size.txt │ ├── test-error-rray-subset-oob-character.txt │ ├── test-error-rray-subset-oob-negative.txt │ ├── test-error-rray-subset-oob.txt │ ├── test-error-rray-subset-unnamed.txt │ ├── test-error-rray-yank-oob.txt │ ├── test-error-rray-yank-shaped-logical.txt │ ├── test-str-1.txt │ ├── test-str-2.txt │ ├── test-str-3.txt │ └── test-str-4.txt │ ├── test-arith.R │ ├── test-bind.R │ ├── test-broadcast.R │ ├── test-cast.R │ ├── test-clip.R │ ├── test-coercion.R │ ├── test-compare.R │ ├── test-compat-base.R │ ├── test-compat-vctrs-math.R │ ├── test-compat-vctrs.R │ ├── test-container-cast.R │ ├── test-container-type.R │ ├── test-container-type2.R │ ├── test-creation.R │ ├── test-diagonal.R │ ├── test-diff.R │ ├── test-dim-n.R │ ├── test-dim-names-common.R │ ├── test-dim-names.R │ ├── test-dim.R │ ├── test-dot.R │ ├── test-duplicate.R │ ├── test-expand.R │ ├── test-extract-assign.R │ ├── test-extract.R │ ├── test-extremum.R │ ├── test-flatten.R │ ├── test-flip.R │ ├── test-full-like.R │ ├── test-hypot.R │ ├── test-inner-cast.R │ ├── test-inner-type.R │ ├── test-logical.R │ ├── test-max-pos.R │ ├── test-min-pos.R │ ├── test-multiply-add.R │ ├── test-names.R │ ├── test-pad.R │ ├── test-print.R │ ├── test-reducers-custom.R │ ├── test-reducers.R │ ├── test-reshape.R │ ├── test-rotate.R │ ├── test-slice-assign.R │ ├── test-slice.R │ ├── test-sort.R │ ├── test-split.R │ ├── test-squeeze.R │ ├── test-subset-assign.R │ ├── test-subset.R │ ├── test-tile.R │ ├── test-transpose.R │ ├── test-type2.R │ ├── test-unique.R │ ├── test-yank-assign.R │ └── test-yank.R └── vignettes ├── .gitignore ├── broadcasting.Rmd ├── the-rray.Rmd └── toolkit.Rmd /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^codecov\.yml$ 2 | ^docs$ 3 | ^_pkgdown\.yml$ 4 | ^\.travis\.yml$ 5 | ^README\.Rmd$ 6 | ^LICENSE\.md$ 7 | ^rray\.Rproj$ 8 | ^\.Rproj\.user$ 9 | ^cran-comments\.md$ 10 | ^CRAN-RELEASE$ 11 | ^pkgdown$ 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | inst/doc 2 | .Rhistory 3 | .RData 4 | .Rproj.user 5 | docs/ 6 | .DS_Store 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | sudo: required 5 | cache: packages 6 | 7 | # ------------------------------------------------------------------------------ 8 | # Need to update Travis's really old gcc for use with cpp14 9 | # https://stackoverflow.com/questions/39728709/using-an-alternate-compiler-for-travis-ci-r-project-builds 10 | # 1) Use g++-6 so we definitely have C++14 as the default 11 | # 2) A Makevars is used to build all of the dependencies and my package with 12 | # gcc-6 and g++-6. 13 | # 3) We remove the "request" for CXX14 in src/Makevars and let R just find 14 | # the default, which is now g++-6 (bc of step 2) which uses cpp14 by default. 15 | # Unfortunately this is required. 16 | 17 | # base64 resolves to (yes with a new line for it to work): 18 | # VER=-6 19 | # CC=gcc$(VER) 20 | # CXX=g++$(VER) 21 | # 22 | 23 | addons: 24 | apt: 25 | sources: 26 | - ubuntu-toolchain-r-test 27 | packages: 28 | - g++-6 29 | before_install: 30 | - echo "Updating ~/.R/Makevars to know about g++-6" 31 | - mkdir -p ~/.R 32 | - echo "VkVSPS02CkNDPWdjYyQoVkVSKQpDWFg9ZysrJChWRVIpCg==" | base64 -d > ~/.R/Makevars 33 | - cat ~/.R/Makevars 34 | - echo "Overriding src/Makevars and removing C++14 on Travis only" 35 | - sed -i 's|CXX_STD = CXX14||' src/Makevars 36 | # ------------------------------------------------------------------------------ 37 | 38 | # # To always pull fresh xtensor cpp code 39 | # # Can't rely on Remotes b/c Xtensor.R dynamically pulls in 40 | # # underlying headers 41 | #before_script: 42 | # - Rscript -e 'remotes::install_github("DavisVaughan/Xtensor.R", ref = "dev", force = TRUE)' 43 | 44 | matrix: 45 | include: 46 | - r: devel 47 | - r: release 48 | after_success: 49 | - Rscript -e 'covr::codecov()' 50 | before_cache: 51 | - Rscript -e 'remotes::install_cran("pkgdown")' 52 | deploy: 53 | provider: script 54 | script: Rscript -e 'pkgdown::deploy_site_github(verbose = TRUE)' 55 | skip_cleanup: true 56 | - r: oldrel 57 | - r: 3.2 58 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: rray 2 | Title: Simple Arrays 3 | Version: 0.1.0.9000 4 | Authors@R: 5 | c(person(given = "Davis", 6 | family = "Vaughan", 7 | role = c("aut", "cre"), 8 | email = "davis@rstudio.com"), 9 | person(given = "RStudio", 10 | role = "cph")) 11 | Description: Provides a toolkit for manipulating arrays in a consistent, 12 | powerful, and intuitive manner through the use of broadcasting and a new 13 | array class, the 'rray'. 14 | License: GPL-3 15 | URL: https://github.com/r-lib/rray 16 | BugReports: https://github.com/r-lib/rray/issues 17 | Depends: 18 | R (>= 3.2) 19 | Imports: 20 | glue, 21 | Rcpp (>= 1.0.3), 22 | rlang (>= 0.4.0), 23 | utils, 24 | vctrs (>= 0.2.2) 25 | Suggests: 26 | covr, 27 | knitr, 28 | magrittr, 29 | rmarkdown, 30 | testthat (>= 2.1.0) 31 | LinkingTo: 32 | Rcpp, 33 | xtensor (>= 0.11.1-0) 34 | VignetteBuilder: 35 | knitr 36 | Encoding: UTF-8 37 | LazyData: true 38 | Roxygen: list(markdown = TRUE) 39 | RoxygenNote: 7.0.2 40 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # rray (development version) 2 | 3 | # rray 0.1.0 4 | 5 | * Added a `NEWS.md` file to track changes to the package. 6 | -------------------------------------------------------------------------------- /R/broadcast.R: -------------------------------------------------------------------------------- 1 | #' Broadcast to a new dimension 2 | #' 3 | #' `rray_broadcast()` will _broadcast_ the dimensions of the current 4 | #' object to a new dimension. 5 | #' 6 | #' Broadcasting works by _recycling dimensions_ and _repeating values_ in 7 | #' those dimensions to match the new dimension. 8 | #' 9 | #' Here's an example. Assume you have a 1x3 matrix that you want to broadcast 10 | #' to a dimension of 2x3. Since the 1st dimensions are different, and one of them 11 | #' is 1, the 1 row of the 1x3 matrix is repeated to become a 2x3 matrix. For 12 | #' the second dimension, both are already 3 so nothing is done. 13 | #' 14 | #' ``` 15 | #' (1, 3) 16 | #' (2, 3) 17 | #' ------ 18 | #' (2, 3) 19 | #' ``` 20 | #' 21 | #' As an example that _doesn't_ broadcast, here is an attempt to make a 22 | #' 2x1x4 matrix broadcast to a 2x3x5 matrix (In the R world, 2x3x4 means 23 | #' a 2 row, 3 column, and 4 "deep" array). The first 2 dimensions are fine, 24 | #' but for the third dimension, 4 and 5 are not "recyclable" and are therefore 25 | #' incompatible. 26 | #' 27 | #' ``` 28 | #' (2, 1, 4) 29 | #' (2, 3, 5) 30 | #' --------- 31 | #' (2, 3, X) 32 | #' ``` 33 | #' 34 | #' You can broadcast to higher dimensions too. If you go from a 5x2 to a 35 | #' 5x2x3 array, then the 5x2 matrix implicitly gets a 1 appended as another 36 | #' dimension (i.e. 5x2x1) 37 | #' 38 | #' 39 | #' ``` 40 | #' (5, 2, ) <- implicit 1 is recycled 41 | #' (5, 2, 3) 42 | #' --------- 43 | #' (5, 2, 3) 44 | #' ``` 45 | #' 46 | #' Broadcasting is an important concept in rray, as it is the engine behind 47 | #' the different structure for arithmetic operations. 48 | #' 49 | #' @param x The object to broadcast. 50 | #' @param dim An integer vector. The dimension to broadcast to. 51 | #' 52 | #' @return 53 | #' 54 | #' `x` broadcast to the new dimensions. 55 | #' 56 | #' @examples 57 | #' 58 | #' # From 5x1 ... 59 | #' x <- rray(1:5) 60 | #' 61 | #' # ...to 5x2 62 | #' rray_broadcast(x, c(5, 2)) 63 | #' 64 | #' # Internally, rray() uses broadcasting 65 | #' # for convenience so you could have also 66 | #' # done this with: 67 | #' rray(1:5, dim = c(5, 2)) 68 | #' 69 | #' # Moar dimensions 70 | #' rray_broadcast(x, c(5, 2, 3)) 71 | #' 72 | #' # You cannot broadcast down in dimensions 73 | #' try(rray_broadcast(x, 5)) 74 | #' 75 | #' @export 76 | rray_broadcast <- function(x, dim) { 77 | dim <- vec_cast(dim, integer()) 78 | 79 | res <- rray__broadcast(x, dim) 80 | 81 | vec_cast_container(res, x) 82 | } 83 | -------------------------------------------------------------------------------- /R/clip.R: -------------------------------------------------------------------------------- 1 | #' Bound the values of an array 2 | #' 3 | #' `rray_clip()` sets _inclusive_ lower and upper bounds on the values of `x`. 4 | #' 5 | #' @param x A vector, matrix, array or rray. 6 | #' 7 | #' @param low A single value. The lower bound. `low` is cast to the 8 | #' inner type of `x`. 9 | #' 10 | #' @param high A single value. The upper bound. `high` is cast to the 11 | #' inner type of `x`. 12 | #' 13 | #' @return 14 | #' 15 | #' `x` bounded by `low` and `high`. 16 | #' 17 | #' @examples 18 | #' 19 | #' # bound `x` between 1 and 5 20 | #' x <- matrix(1:10, ncol = 2) 21 | #' rray_clip(x, 1, 5) 22 | #' 23 | #' @export 24 | rray_clip <- function(x, low, high) { 25 | 26 | vec_assert(low, size = 1L, arg = "low") 27 | vec_assert(high, size = 1L, arg = "high") 28 | 29 | inner <- vec_ptype_inner(x) 30 | low <- vec_cast_inner(low, inner) 31 | high <- vec_cast_inner(high, inner) 32 | 33 | if (low > high) { 34 | glubort("`low` must be less than or equal to `high`.") 35 | } 36 | 37 | out <- rray__clip(x, low, high) 38 | 39 | vec_cast_container(out, x) 40 | } 41 | -------------------------------------------------------------------------------- /R/coercion-base.R: -------------------------------------------------------------------------------- 1 | new_array <- function(.data, dim = NULL, dimnames = NULL) { 2 | 3 | dim <- dim %||% length(.data) 4 | dimnames <- dimnames %||% rray_empty_dim_names(length(dim)) 5 | 6 | array(.data, dim = dim, dimnames = dimnames) 7 | } 8 | 9 | new_matrix <- function(.data, dim = NULL, dimnames = NULL) { 10 | 11 | dim <- dim %||% length(.data) 12 | dimnames <- dimnames %||% rray_empty_dim_names(length(dim)) 13 | 14 | dim <- at_least_2D(dim, 1L) 15 | dimnames <- at_least_2D(dimnames, rray_empty_dim_names(1)) 16 | 17 | matrix(.data, nrow = dim[1], ncol = dim[2], dimnames = dimnames) 18 | } 19 | 20 | at_least_2D <- function(x, elem) { 21 | if (vec_size(x) == 1) { 22 | x <- c(x, elem) 23 | } 24 | x 25 | } 26 | 27 | #' @export 28 | as.double.vctrs_rray <- function(x, ...) { 29 | as.vector(vec_cast(x, new_shape(double(), rray_shape(x)))) 30 | } 31 | 32 | #' @export 33 | as.integer.vctrs_rray <- function(x, ...) { 34 | as.vector(vec_cast(x, new_shape(integer(), rray_shape(x)))) 35 | } 36 | 37 | #' @export 38 | as.logical.vctrs_rray <- function(x, ...) { 39 | as.vector(vec_cast(x, new_shape(logical(), rray_shape(x)))) 40 | } 41 | -------------------------------------------------------------------------------- /R/compat-base.R: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | 3 | # xtfrm.vctrs_vctr() calls vec_proxy_compare(), which (as of 2019-06-04) 4 | # converts arrays to data frames, varying the first axis fastest. This makes 5 | # sense for the `vec_order()` functions, but results in bad behavior for 6 | # arrays because we want a global xtfrm, not a rowwise one. Because 7 | # min.vctrs_vctr uses xtfrm, this behavior leaks into these functions as well. 8 | # So, for example, it will return 2 to indicate that the second row is the 9 | # "min" row and then min.vctrs_vctr would just return the first value in the 10 | # second row. This is definitely not the right behavior, as we want the 11 | # global minimum of the array 12 | 13 | # We do borrow from vctrs a bit and ignore the `...` 14 | # but otherwise we fallback to the base R method and then return an rray 15 | 16 | #' @export 17 | min.vctrs_rray <- function(x, ..., na.rm = FALSE) { 18 | vec_summary_base("min", x, na.rm = na.rm) 19 | } 20 | 21 | #' @export 22 | max.vctrs_rray <- function(x, ..., na.rm = FALSE) { 23 | vec_summary_base("max", x, na.rm = na.rm) 24 | } 25 | 26 | #' @export 27 | range.vctrs_rray <- function(x, ..., na.rm = FALSE) { 28 | vec_summary_base("range", x, na.rm = na.rm) 29 | } 30 | 31 | # should keep the inner type and container type 32 | # (but the shape may be different, i.e. the min of a 2D matrix 33 | # is a 1D vector of length 1) 34 | vec_summary_base <- function(.fn, .x, ...) { 35 | value <- vec_math_base(.fn, .x, ...) 36 | value <- vec_cast_inner(value, .x) 37 | vec_cast_container(value, .x) 38 | } 39 | 40 | # ------------------------------------------------------------------------------ 41 | 42 | #' @export 43 | xtfrm.vctrs_rray <- function(x) { 44 | vec_data(x) 45 | } 46 | 47 | #' @export 48 | xtfrm.vctrs_rray_lgl <- function(x) { 49 | vec_cast_inner(vec_data(x), integer()) 50 | } 51 | 52 | # ------------------------------------------------------------------------------ 53 | 54 | #' @export 55 | determinant.vctrs_rray <- function(x, logarithm = TRUE, ...) { 56 | determinant(as.matrix(x), logarithm = logarithm, ...) 57 | } 58 | 59 | # ------------------------------------------------------------------------------ 60 | 61 | #' @export 62 | is.na.vctrs_rray <- function(x) { 63 | res <- is.na(vec_data(x)) 64 | vec_cast_container(res, x) 65 | } 66 | 67 | # Currently, I am choosing to use the vctrs implementation of 68 | # `is.na<-vctrs_vctr`. It assigns entire rows to `NA`, and 69 | # only accepts logicals of either length 1, or as long 70 | # as the number of rows in `x`. 71 | # We test for this in `test-compat-base.R` 72 | 73 | # ------------------------------------------------------------------------------ 74 | 75 | -------------------------------------------------------------------------------- /R/compat-vctrs-math.R: -------------------------------------------------------------------------------- 1 | #' @export 2 | vec_math.vctrs_rray <- function(.fn, .x, ...) { 3 | out <- vec_math_base(.fn, .x, ...) 4 | dim <- rray_dim(out) 5 | 6 | new_rray( 7 | out, 8 | size = dim[1L], 9 | shape = dim[-1L], 10 | dim_names = rray_dim_names(out) 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /R/diagonal.R: -------------------------------------------------------------------------------- 1 | #' Create a matrix with `x` on the diagonal 2 | #' 3 | #' `rray_diag()` creates a matrix filled with `x` on the diagonal. Use `offset` 4 | #' to place `x` along an offset from the diagonal. 5 | #' 6 | #' @details 7 | #' 8 | #' No dimension names will be on the result. 9 | #' 10 | #' @param x A vector, matrix, array or rray. 11 | #' 12 | #' @param offset A single integer specifying the offset from the diagonal to 13 | #' place `x`. This can be positive or negative. 14 | #' 15 | #' @return 16 | #' 17 | #' A matrix, with `x` on the diagonal. 18 | #' 19 | #' @examples 20 | #' # Creates a diagonal matrix 21 | #' rray_diag(1:5) 22 | #' 23 | #' # Offset `1:5` by 1 24 | #' rray_diag(1:5, 1) 25 | #' 26 | #' # You can also go the other way 27 | #' rray_diag(1:5, -1) 28 | #' 29 | #' # Identity matrix 30 | #' rray_diag(rep(1, 5)) 31 | #' 32 | #' # One interesting use case of this is to create 33 | #' # a square empty matrix with dimensions (offset, offset) 34 | #' rray_diag(rray(integer()), 3) 35 | #' rray_diag(logical(), 3) 36 | #' 37 | #' @export 38 | rray_diag <- function(x, offset = 0) { 39 | 40 | if (length(offset) != 1) { 41 | glubort("`offset` must have length 1, not {length(offset)}.") 42 | } 43 | 44 | offset <- vec_cast(offset, integer()) 45 | 46 | res <- rray__diag(x, offset) 47 | 48 | # no dim names on the result 49 | 50 | vec_cast_container(res, x) 51 | } 52 | -------------------------------------------------------------------------------- /R/dim-n.R: -------------------------------------------------------------------------------- 1 | #' Compute the number of dimensions of an object 2 | #' 3 | #' `rray_dim_n()` computes the dimensionality (i.e. the number of dimensions). 4 | #' 5 | #' @param x An object. 6 | #' 7 | #' @details 8 | #' 9 | #' One point worth mentioning is that `rray_dim_n()` is very strict. It does 10 | #' not simply call the generic function `dim()` and then check the length. 11 | #' Rather, it explicitly pulls the attribute for the `"dim"`, and checks 12 | #' the length of that. If an object does not have an attribute, then the 13 | #' dimensionality is 1. 14 | #' 15 | #' This means that data frames have a dimensionality of 1, even though 16 | #' `dim()` defines a method for data frames that would imply a dimensionality 17 | #' of 2. 18 | #' 19 | #' @return 20 | #' 21 | #' An integer vector containing the number of dimensions of `x`. 22 | #' 23 | #' @examples 24 | #' x_1_by_4 <- rray(c(1, 2, 3, 4), c(1, 4)) 25 | #' 26 | #' rray_dim_n(x_1_by_4) 27 | #' 28 | #' # NULL has a dimensionality of 1 29 | #' rray_dim_n(NULL) 30 | #' 31 | #' # The dimensionality of a data frame is 1 32 | #' rray_dim_n(data.frame()) 33 | #' 34 | #' @export 35 | rray_dim_n <- function(x) { 36 | rray__dim_n(x) 37 | } 38 | -------------------------------------------------------------------------------- /R/dot.R: -------------------------------------------------------------------------------- 1 | # %*% is an S4 generic - but dispatches internally. 2 | # Because of this line: 3 | # https://github.com/wch/r-source/blob/1c4cba97b88d233d8a1e41c6f7d1f5e8cfcab359/src/main/array.c#L1231-L1239 4 | # it won't dispatch on an S3 even if we define setOldClass() for it 5 | # unless the other input is S4. This is obviously undesirable. 6 | # There isn't much we can do besides provide a `rray_dot()` function 7 | # and encourage use of that instead 8 | 9 | #' Matrix multiplication 10 | #' 11 | #' `rray_dot()` works exactly like the base R function, `%*%`, but preserves 12 | #' the rray class where applicable. For the exact details of how 1D objects 13 | #' are promoted to 2D objects, see [%*%]. 14 | #' 15 | #' @details 16 | #' 17 | #' Due to some peculiarities with how `%*%` dispatches with S3 objects, calling 18 | #' `%*%` directly with an rray will compute the matrix multiplication correctly, 19 | #' but the class will be lost. `rray_dot()` ensures that the rray class is 20 | #' maintained. 21 | #' 22 | #' @param x,y Arrays or rrays that are either 1D or 2D. 23 | #' 24 | #' @return 25 | #' 26 | #' The result of the matrix multiplication of `x` and `y`. See `%*%` for the 27 | #' exact details. The common type of `x` and `y` will be preserved. 28 | #' 29 | #' @examples 30 | #' rray_dot(1:5, 1:5) 31 | #' 32 | #' rray_dot(rray(1:5), 1:5) 33 | #' 34 | #' @export 35 | rray_dot <- function(x, y) { 36 | 37 | x_dim_n <- rray_dim_n(x) 38 | if (x_dim_n > 2L) { 39 | glubort("`x` must have a dimensionality of 1 or 2, not {x_dim_n}.") 40 | } 41 | 42 | y_dim_n <- rray_dim_n(y) 43 | if (y_dim_n > 2L) { 44 | glubort("`y` must have a dimensionality of 1 or 2, not {y_dim_n}.") 45 | } 46 | 47 | out <- x %*% y 48 | 49 | container <- vec_ptype_container2(x, y) 50 | vec_cast_container(out, container) 51 | } 52 | -------------------------------------------------------------------------------- /R/expand.R: -------------------------------------------------------------------------------- 1 | #' Insert a dimension into an rray 2 | #' 3 | #' `rray_expand()` inserts a new dimension at the `axis` dimension. This 4 | #' expands the number of dimensions of `x` by `1`. 5 | #' 6 | #' @details 7 | #' 8 | #' Dimension names are kept through the insertion of the new dimension. 9 | #' 10 | #' @param x An rray. 11 | #' @param axis An integer of size `1` specifying the location of the new 12 | #' dimension. 13 | #' 14 | #' @return 15 | #' 16 | #' `x` with a new dimension inserted at the `axis`. 17 | #' 18 | #' @examples 19 | #' 20 | #' x <- rray(1:10, c(5, 2)) 21 | #' x <- rray_set_row_names(x, letters[1:5]) 22 | #' x <- rray_set_col_names(x, c("c1", "c2")) 23 | #' 24 | #' # (5, 2) 25 | #' # Add dimension to the front 26 | #' # (1, 5, 2) = 1 row, 5 cols, 2 deep 27 | #' rray_expand(x, 1) 28 | #' 29 | #' # (5, 2) 30 | #' # Add dimension to the middle 31 | #' # (5, 1, 2) = 5 rows, 1 col, 2 deep 32 | #' rray_expand(x, 2) 33 | #' 34 | #' # (5, 2) 35 | #' # Add dimension to the end 36 | #' # (5, 2, 1) = 5 rows, 2 cols, 1 deep 37 | #' rray_expand(x, 3) 38 | #' 39 | #' # In some cases this is different than a simple 40 | #' # rray_reshape() because the dimension names 41 | #' # follow the original dimension position 42 | #' # - 5 row names follow to the new 5 column position 43 | #' # - 2 col names follow to the new 2 deep position 44 | #' # - result has no row names because that is the new axis 45 | #' rray_expand(x, 1) 46 | #' 47 | #' # A reshape, on the other hand, 48 | #' # drops all dimension names 49 | #' rray_reshape(x, c(1, 5, 2)) 50 | #' 51 | #' @export 52 | rray_expand <- function(x, axis) { 53 | 54 | dim_n <- rray_dim_n(x) 55 | 56 | # axis allowed to be max of dim_n + 1 here 57 | axis <- vec_cast(axis, integer()) 58 | validate_axis(axis, x, dim_n = dim_n + 1L) 59 | 60 | res <- rray__expand(x, as_cpp_idx(axis)) 61 | 62 | vec_cast_container(res, x) 63 | } 64 | -------------------------------------------------------------------------------- /R/extract-assign.R: -------------------------------------------------------------------------------- 1 | #' @rdname rray_extract 2 | #' @export 3 | `rray_extract<-` <- function(x, ..., value) { 4 | rray_extract_assign(x, ..., value = value) 5 | } 6 | 7 | #' @rdname rray_extract 8 | #' @export 9 | rray_extract_assign <- function(x, ..., value) { 10 | indexer <- rray_as_index(x, ...) 11 | 12 | vec_assert(value, arg = "value") 13 | value <- vec_cast_inner(value, x) 14 | 15 | # TODO 16 | if (is_any_na_int(indexer)) { 17 | abort("`NA` indices are not yet supported.") 18 | } 19 | 20 | out <- rray__extract_assign(x, indexer, value) 21 | 22 | vec_cast_container(out, x) 23 | } 24 | -------------------------------------------------------------------------------- /R/extract.R: -------------------------------------------------------------------------------- 1 | #' Get or set elements of an array by index 2 | #' 3 | #' `rray_extract()` is the counterpart to [rray_yank()]. It extracts elements 4 | #' from an array _by index_. It _always_ drops dimensions 5 | #' (unlike [rray_subset()]), and a 1D object is always returned. 6 | #' 7 | #' @inheritParams rray_subset 8 | #' 9 | #' @param value The value to assign to the location specified by `...`. 10 | #' Before assignment, `value` is cast to the type and dimension of `x` after 11 | #' extracting elements with `...`. 12 | #' 13 | #' @details 14 | #' 15 | #' Like `[[`, `rray_extract()` will _never_ keep dimension names. 16 | #' 17 | #' `rray_extract()` works with base R objects as well. 18 | #' 19 | #' `rray_extract()` is similar to the traditional behavior of 20 | #' `x[[i, j, ...]]`, but allows each subscript to have length >1. 21 | #' 22 | #' @return 23 | #' 24 | #' A 1D vector of elements extracted from `x`. 25 | #' 26 | #' @examples 27 | #' x <- rray(1:16, c(2, 4, 2), dim_names = list(c("r1", "r2"), NULL, NULL)) 28 | #' 29 | #' # Extract the first row and flatten it 30 | #' rray_extract(x, 1) 31 | #' 32 | #' # Extract the first row and first two columns 33 | #' rray_extract(x, 1, 1:2) 34 | #' 35 | #' # You can assign directly to these elements 36 | #' rray_extract(x, 1, 1:2) <- NA 37 | #' x 38 | #' 39 | #' @family rray subsetters 40 | #' @export 41 | rray_extract <- function(x, ...) { 42 | rray_extract_impl(x, ...) 43 | } 44 | 45 | rray_extract_impl <- function(x, ...) { 46 | indexer <- rray_as_index(x, ...) 47 | 48 | # TODO 49 | if (is_any_na_int(indexer)) { 50 | abort("`NA` indices are not yet supported.") 51 | } 52 | 53 | rray__extract(x, indexer) 54 | } 55 | -------------------------------------------------------------------------------- /R/extremum.R: -------------------------------------------------------------------------------- 1 | #' Maximum and minimum values 2 | #' 3 | #' @description 4 | #' 5 | #' `rray_maximum()` and `rray_minimum()` compute the elementwise max / min 6 | #' between `x` and `y`. 7 | #' 8 | #' @param x,y A vector, matrix, array or rray. 9 | #' 10 | #' @return 11 | #' 12 | #' The elementwise max/min of `x` and `y`, with broadcasting. 13 | #' 14 | #' @examples 15 | #' # Elementwise maximum 16 | #' rray_maximum(c(1, 2, 3), c(3, 2, 1)) 17 | #' 18 | #' # Elementwise minimum 19 | #' rray_minimum(c(1, 2, 3), c(3, 2, 1)) 20 | #' 21 | #' # With broadcasting 22 | #' x <- matrix(1:3) 23 | #' rray_maximum(x, t(x)) 24 | #' 25 | #' @name extremum 26 | #' @export 27 | rray_maximum <- function(x, y) { 28 | out <- rray__maximum(x, y) 29 | container <- vec_ptype_container2(x, y) 30 | vec_cast_container(out, container) 31 | } 32 | 33 | #' @rdname extremum 34 | #' @export 35 | rray_minimum <- function(x, y) { 36 | out <- rray__minimum(x, y) 37 | container <- vec_ptype_container2(x, y) 38 | vec_cast_container(out, container) 39 | } 40 | -------------------------------------------------------------------------------- /R/flatten.R: -------------------------------------------------------------------------------- 1 | #' Flatten an array 2 | #' 3 | #' `rray_flatten()` squashes the dimensionality of `x` so that the result is a 4 | #' 1D object. 5 | #' 6 | #' @details 7 | #' 8 | #' This function is similar to `as.vector()`, but keeps the class of the object 9 | #' and can keep the dimension names if applicable. 10 | #' 11 | #' Dimension names are kept using the same rules that would be applied if you 12 | #' would have called `rray_reshape(x, prod(rray_dim(x)))`. Essentially this 13 | #' means that names in the first dimension are kept if `x` is either already 14 | #' a 1D vector, or a higher dimensional object with 1's in all dimensions 15 | #' except for the first one. 16 | #' 17 | #' @param x A vector, matrix, array or rray. 18 | #' 19 | #' @return 20 | #' 21 | #' A 1D object with the same container type as `x`. 22 | #' 23 | #' @examples 24 | #' library(magrittr) 25 | #' 26 | #' x <- rray(1:10, c(5, 2)) 27 | #' 28 | #' rray_flatten(x) 29 | #' 30 | #' # Dimension names are kept here 31 | #' # (2) -> (2) 32 | #' y <- rray(1:2) %>% rray_set_axis_names(1, letters[1:2]) 33 | #' rray_flatten(y) 34 | #' 35 | #' # And they are kept here 36 | #' # (2, 1) -> (2) 37 | #' y_one_col <- rray_reshape(y, c(2, 1)) 38 | #' rray_flatten(y_one_col) 39 | #' 40 | #' # But not here, since the size of the first dim changes 41 | #' # (1, 2) -> (2) 42 | #' y_one_row <- t(y_one_col) 43 | #' rray_flatten(y_one_row) 44 | #' 45 | #' @export 46 | rray_flatten <- function(x) { 47 | res <- rray__flatten(x) 48 | vec_cast_container(res, x) 49 | } 50 | -------------------------------------------------------------------------------- /R/flip.R: -------------------------------------------------------------------------------- 1 | #' Flip an rray along a dimension 2 | #' 3 | #' `rray_flip()` reverses the elements of an rray along a single dimension. 4 | #' 5 | #' @details 6 | #' 7 | #' Dimension names are flipped as well. 8 | #' 9 | #' @param x An rray. 10 | #' @param axis An integer of size `1` specifying the dimension to flip. 11 | #' 12 | #' @return 13 | #' 14 | #' `x` but with reversed elements along `axis`. 15 | #' 16 | #' @examples 17 | #' 18 | #' x <- rray(1:10, c(5, 2)) 19 | #' x <- rray_set_row_names(x, letters[1:5]) 20 | #' x <- rray_set_col_names(x, c("c1", "c2")) 21 | #' 22 | #' rray_flip(x, 1) 23 | #' 24 | #' rray_flip(x, 2) 25 | #' 26 | #' @export 27 | rray_flip <- function(x, axis) { 28 | 29 | # only integer axes 30 | axis <- vec_cast(axis, integer()) 31 | validate_axis(axis, x) 32 | 33 | res <- rray__flip(x, as_cpp_idx(axis)) 34 | 35 | vec_cast_container(res, x) 36 | } 37 | -------------------------------------------------------------------------------- /R/full-like.R: -------------------------------------------------------------------------------- 1 | #' Create an array like `x` 2 | #' 3 | #' @description 4 | #' 5 | #' - `rray_full_like()` creates an array with the same type and size as `x`, but 6 | #' filled with `value`. 7 | #' 8 | #' - `rray_ones_like()` is `rray_full_like()` with `value = 1`. 9 | #' 10 | #' - `rray_zeros_like()` is `rray_full_like()` with `value = 0`. 11 | #' 12 | #' @details 13 | #' 14 | #' No dimension names will be on the result. 15 | #' 16 | #' @param x A vector, matrix, array or rray. 17 | #' 18 | #' @param value A value coercible to the same _inner_ type as `x` that will be 19 | #' used to fill the result (If `x` is an integer matrix, then `value` will be 20 | #' coerced to an integer). 21 | #' 22 | #' @return 23 | #' 24 | #' An object with the same type as `x`, but filled with `value`. 25 | #' 26 | #' @examples 27 | #' 28 | #' x <- rray(1:10, c(5, 2)) 29 | #' 30 | #' # Same shape and type as x, but filled with 1 31 | #' rray_full_like(x, 1L) 32 | #' 33 | #' # `fill` is coerced to `x` if it can be 34 | #' rray_full_like(x, FALSE) 35 | #' 36 | #' # `value = 1` 37 | #' rray_ones_like(x) 38 | #' 39 | #' # When logicals are used, it is filled with TRUE 40 | #' rray_ones_like(c(FALSE, TRUE)) 41 | #' 42 | #' # `value = 0` 43 | #' rray_zeros_like(x) 44 | #' 45 | #' @export 46 | rray_full_like <- function(x, value) { 47 | 48 | # ensure value is 1D 49 | value <- as.vector(value) 50 | 51 | res <- rray__full_like(x, value) 52 | 53 | vec_cast_container(res, x) 54 | } 55 | 56 | #' @rdname rray_full_like 57 | #' @export 58 | rray_ones_like <- function(x) { 59 | rray_full_like(x, 1L) 60 | } 61 | 62 | #' @rdname rray_full_like 63 | #' @export 64 | rray_zeros_like <- function(x) { 65 | rray_full_like(x, 0L) 66 | } 67 | -------------------------------------------------------------------------------- /R/hypot.R: -------------------------------------------------------------------------------- 1 | #' Compute the square root of the sum of squares 2 | #' 3 | #' `rray_hypot()` computes the elementwise square root of the sum 4 | #' of squares of `x` and `y`. 5 | #' 6 | #' @param x,y A vector, matrix, array or rray. 7 | #' 8 | #' @return 9 | #' 10 | #' An object of the common type of `x` and `y` containing the square root 11 | #' of the sum of squares. 12 | #' 13 | #' @examples 14 | #' x <- matrix(c(2, 4, 6)) 15 | #' 16 | #' # With broadcasting 17 | #' rray_hypot(x, t(x)) 18 | #' 19 | #' @export 20 | rray_hypot <- function(x, y) { 21 | out <- rray__hypot(x, y) 22 | container <- vec_ptype_container2(x, y) 23 | vec_cast_container(out, container) 24 | } 25 | -------------------------------------------------------------------------------- /R/max-pos.R: -------------------------------------------------------------------------------- 1 | #' Locate the position of the maximum value 2 | #' 3 | #' `rray_max_pos()` returns the integer position of the maximum value over an 4 | #' axis. 5 | #' 6 | #' @param x A vector, matrix, array, or rray. 7 | #' @param axis A single integer specifying the axis to compute along. `1` 8 | #' computes along rows, reducing the number of rows to 1. 9 | #' `2` does the same, but along columns, and so on for higher dimensions. 10 | #' The default of `NULL` first flattens `x` to 1-D. 11 | #' 12 | #' @return 13 | #' 14 | #' An integer object of the same type and shape as `x`, except along `axis`, 15 | #' which has been reduced to size 1. 16 | #' 17 | #' @examples 18 | #' 19 | #' x <- rray(c(1:10, 20:11), dim = c(5, 2, 2)) 20 | #' 21 | #' # Find the max position over all of x 22 | #' rray_max_pos(x) 23 | #' 24 | #' # Compute along the rows 25 | #' rray_max_pos(x, 1) 26 | #' 27 | #' # Compute along the columns 28 | #' rray_max_pos(x, 2) 29 | #' 30 | #' @export 31 | rray_max_pos <- function(x, axis = NULL) { 32 | 33 | axis <- vec_cast(axis, integer()) 34 | validate_axis(axis, x) 35 | 36 | res <- rray__max_pos(x, as_cpp_idx(axis)) 37 | 38 | vec_cast_container(res, x) 39 | } 40 | -------------------------------------------------------------------------------- /R/min-pos.R: -------------------------------------------------------------------------------- 1 | #' Locate the position of the minimum value 2 | #' 3 | #' `rray_min_pos()` returns the integer position of the minimum value over an 4 | #' axis. 5 | #' 6 | #' @inheritParams rray_max_pos 7 | #' 8 | #' @return 9 | #' 10 | #' An integer object of the same type and shape as `x`, except along `axis`, 11 | #' which has been reduced to size 1. 12 | #' 13 | #' @examples 14 | #' 15 | #' x <- rray(c(1:10, 20:11), dim = c(5, 2, 2)) 16 | #' 17 | #' # Flatten x, then find the position of the max value 18 | #' rray_min_pos(x) 19 | #' 20 | #' # Compute along the rows 21 | #' rray_min_pos(x, 1) 22 | #' 23 | #' # Compute along the columns 24 | #' rray_min_pos(x, 2) 25 | #' 26 | #' @export 27 | rray_min_pos <- function(x, axis = NULL) { 28 | 29 | axis <- vec_cast(axis, integer()) 30 | validate_axis(axis, x) 31 | 32 | res <- rray__min_pos(x, as_cpp_idx(axis)) 33 | 34 | vec_cast_container(res, x) 35 | } 36 | -------------------------------------------------------------------------------- /R/multiply-add.R: -------------------------------------------------------------------------------- 1 | #' Fused multiply-add 2 | #' 3 | #' `rray_multiply_add()` computes `x * y + z`, with broadcasting. 4 | #' It is more efficient than simply doing those operations in sequence. 5 | #' 6 | #' @param x,y,z A vector, matrix, array or rray. 7 | #' 8 | #' @return 9 | #' 10 | #' An object of the common type of the inputs, containing the result of the 11 | #' multiply-add operation. 12 | #' 13 | #' @examples 14 | #' rray_multiply_add(2, 3, 5) 15 | #' 16 | #' # Using broadcasting 17 | #' rray_multiply_add(matrix(1:5), matrix(1:2, nrow = 1L), 3L) 18 | #' 19 | #' # ^ Equivalent to: 20 | #' x <- matrix(rep(1:5, 2), ncol = 2) 21 | #' y <- matrix(rep(1:2, 5), byrow = TRUE, ncol = 2) 22 | #' z <- matrix(3L, nrow = 5, ncol = 2) 23 | #' x * y + z 24 | #' 25 | #' @export 26 | rray_multiply_add <- function(x, y, z) { 27 | out <- rray__multiply_add(x, y, z) 28 | container <- vec_ptype_container_common(x, y, z) 29 | vec_cast_container(out, container) 30 | } 31 | -------------------------------------------------------------------------------- /R/pad.R: -------------------------------------------------------------------------------- 1 | #' Pad missing dimensions when subsetting 2 | #' 3 | #' `pad()` is used alongside the standard rray subsetting operator `[` (and 4 | #' the underlying `rray_subset()` function) to easily subset into higher 5 | #' dimensions without having to explicitly list the intermediate commas. 6 | #' 7 | #' @return 8 | #' 9 | #' An object that can be used to pad dimensions with when subsetting. 10 | #' 11 | #' @examples 12 | #' x <- rray(1:4, c(1, 1, 2, 2)) 13 | #' 14 | #' # pad() fills in the missing dimensions 15 | #' # essentially it adds commas automatically 16 | #' 17 | #' # second element in the 4th dimension 18 | #' x[pad(), 2] 19 | #' 20 | #' # vs using 21 | #' x[,,,2] 22 | #' 23 | #' # second element in 3rd 24 | #' # first element in 4th 25 | #' x[pad(), 2, 1] 26 | #' 27 | #' # can fill in the missing gaps too 28 | #' # this fills in the 2nd/3rd dimensions 29 | #' x[1, pad(), 1] 30 | #' 31 | #' # if a pad() isn't needed 32 | #' # because the dimensionality is already fully 33 | #' # specified by the indices, its ignored 34 | #' x_flat <- rray_reshape(x, 4) 35 | #' x_flat[pad(), 1] 36 | #' x_flat[1, pad()] 37 | #' 38 | #' # `pad()` can be used with base R 39 | #' # objects as well through `rray_subset()` 40 | #' x_arr <- as.array(x) 41 | #' rray_subset(x_arr, pad(), 1) 42 | #' 43 | #' @export 44 | pad <- function() { 45 | new_pad() 46 | } 47 | 48 | new_pad <- function() { 49 | new_vctr(1L, class = "vctrs_pad", inherit_base_type = FALSE) 50 | } 51 | 52 | #' @export 53 | format.vctrs_pad <- function(x, ...) { 54 | "" 55 | } 56 | 57 | is_pad <- function(x) { 58 | inherits(x, "vctrs_pad") 59 | } 60 | -------------------------------------------------------------------------------- /R/print.R: -------------------------------------------------------------------------------- 1 | # Printing seems to be broken if I try and use the 2 | # format method for array objects (it right aligns characters but not column 3 | # headers). In the long run, we 4 | # probably want our own format method that doesn't use the array 5 | # one. For now, call print(vec_data(x)) in obj_print_data() to have 6 | # the alignment be correct. For an example of bad behavior, print 7 | # as_rray(sh8) from ?solve with the format method 8 | 9 | # format.vctrs_rray <- function(x, ...) { 10 | # format(as_array(x)) 11 | # } 12 | 13 | #' @export 14 | obj_print_data.vctrs_rray <- function(x, ...) { 15 | # vctrs sets names() here which is problematic for 1D arrays 16 | print(vec_data(x)) 17 | invisible(x) 18 | } 19 | 20 | #' @export 21 | vec_ptype_abbr.vctrs_rray <- function(x, ...) { 22 | "rray" 23 | } 24 | 25 | #' @export 26 | vec_ptype_full.vctrs_rray <- function(x, ...) { 27 | paste0("rray<", rray_inner_ptype_abbr(x), ">", vec_ptype_shape(x)) 28 | } 29 | 30 | # from vctrs 31 | vec_ptype_shape <- function(x) { 32 | dim <- rray_dim(x) 33 | if (length(dim) == 1) { 34 | "" 35 | } else { 36 | paste0("[,", paste(dim[-1], collapse = ","), "]") 37 | } 38 | } 39 | 40 | rray_inner_ptype_abbr <- function(x) { 41 | if (is_rray_int(x)) { 42 | "int" 43 | } 44 | else if (is_rray_dbl(x)) { 45 | "dbl" 46 | } 47 | else if (is_rray_lgl(x)) { 48 | "lgl" 49 | } 50 | else { 51 | "unknown" 52 | } 53 | } 54 | 55 | # Because vctrs uses x[1:length] in obj_str_leaf() which 56 | # is not allowed for rray objects. This also has a more informative 57 | # title 58 | 59 | #' @export 60 | obj_str_data.vctrs_rray <- function(x, ...) { 61 | 62 | width <- getOption("width") - 2 63 | out <- vec_data(x) 64 | 65 | # Avoid spending too much time formatting elements that won't see 66 | length <- ceiling(width / 2) 67 | if (vec_size(out) > length) { 68 | out <- vec_slice(out, 1:length) 69 | } else { 70 | out <- out 71 | } 72 | 73 | title <- glue::glue(" {vec_ptype_abbr(x)} {vec_ptype_shape(x)}[{vec_size(x)}] ") 74 | cat_line(inline_list(title, format(out), width = width)) 75 | 76 | invisible(x) 77 | } 78 | 79 | # Print helper stolen from vctrs 80 | cat_line <- function(...) { 81 | cat(paste0(..., "\n", collapse = "")) 82 | } 83 | 84 | # Print helper stolen from vctrs 85 | inline_list <- function(title, x, width = getOption("width"), quote = "") { 86 | label_width <- width - nchar(title) 87 | x <- glue::glue_collapse( 88 | encodeString(x, quote = quote), 89 | sep = ", ", 90 | width = label_width 91 | ) 92 | paste0(title, x) 93 | } 94 | -------------------------------------------------------------------------------- /R/reducers-custom.R: -------------------------------------------------------------------------------- 1 | # #' Reducers 2 | # #' 3 | # #' Apply a generic reducing function to the axes of `.x`. Reducing functions 4 | # #' return a single value by iteratively applying a binary function. For example, 5 | # #' [rray_sum()] is a reducing function that returns the sum along a specified 6 | # #' axis. 7 | # #' 8 | # #' @param .x An array-like object. 9 | # #' @param .f A 2-argument function. The function will be passed the accumulated 10 | # #' value as the first argument and the "next" value as the second argument. It 11 | # #' will be applied in this manner along each of the `axes`. 12 | # #' @param ... Additional arguments passed to `.f`. 13 | # #' @param axes The axes to reduce over. 14 | # #' 15 | # #' @examples 16 | # #' 17 | # #' x <- rray(1:24, c(12, 2)) 18 | # #' 19 | # #' # Equivalent 20 | # #' rray_reduce_int(x, sum) 21 | # #' rray_reduce_int(x, ~.x + .y) 22 | # #' rray_sum(x, axes = 1) 23 | # #' 24 | # #' # Same as above, but reduce the columns 25 | # #' rray_reduce_int(x, sum, axes = 2) 26 | # #' rray_reduce_int(x, ~.x + .y, axes = 2) 27 | # #' rray_sum(x, axes = 2) 28 | # #' 29 | # #' # Running max of each column 30 | # #' x_shuffled <- x[c(1:5, 10:6, 12, 11),] 31 | # #' rray_reduce_int(x_shuffled, max) 32 | # #' 33 | # #' # Passing named arguments through 34 | # #' y <- x 35 | # #' y[1,1] <- NA 36 | # #' rray_reduce_int(y, sum, na.rm = TRUE) 37 | # #' rray_reduce_int(y, ~sum(.x, .y, na.rm = TRUE)) 38 | # #' 39 | # #' @name reducers 40 | # NULL 41 | # 42 | # #' @rdname reducers 43 | # #' @export 44 | # rray_reduce_dbl <- function(.x, .f, ..., axes = 1) { 45 | # reducer_impl(.x, .f, ..., axes = axes, type = "double") 46 | # } 47 | # 48 | # #' @rdname reducers 49 | # #' @export 50 | # rray_reduce_int <- function(.x, .f, ..., axes = 1) { 51 | # reducer_impl(.x, .f, ..., axes = axes, type = "integer") 52 | # } 53 | # 54 | # #' @rdname reducers 55 | # #' @export 56 | # rray_reduce_lgl <- function(.x, .f, ..., axes = 1) { 57 | # reducer_impl(.x, .f, ..., axes = axes, type = "logical") 58 | # } 59 | # 60 | # reducer_impl <- function(.x, .f, ..., axes, type) { 61 | # 62 | # .f <- rlang::as_function(.f) 63 | # 64 | # # Enable passing of ... 65 | # # Stolen from purrr::accumulate 66 | # f <- function(x, y) { 67 | # .f(x, y, ...) 68 | # } 69 | # 70 | # # only integer axes 71 | # axes <- vec_cast(axes, integer()) 72 | # validate_axes(axes, .x) 73 | # 74 | # # perform the reduction 75 | # res <- rray_custom_reducer_cpp(.x, f, as_cpp_idx(axes), type) 76 | # 77 | # # until we get keepdims = True 78 | # new_dim <- rray_dim(.x) 79 | # new_dim[axes] <- 1L 80 | # res <- rray_reshape(res, new_dim) 81 | # 82 | # new_dim_names <- rray_resize_dim_names(rray_dim_names(.x), new_dim) 83 | # res <- rray_set_dim_names(res, new_dim_names) 84 | # 85 | # vec_restore(res, .x) 86 | # } 87 | -------------------------------------------------------------------------------- /R/reshape.R: -------------------------------------------------------------------------------- 1 | #' Reshape an array 2 | #' 3 | #' `rray_reshape()` is similar to `dim()<-`. It reshapes `x` in such a way 4 | #' that the dimensions are different, but the total size of the array is still 5 | #' the same (as measured by [rray_elems()]). 6 | #' 7 | #' @param x A vector, matrix, array or rray. 8 | #' @param dim An integer vector. The dimension to reshape to. 9 | #' 10 | #' @return 11 | #' 12 | #' `x` reshaped to the new dimensions of `dim`. 13 | #' 14 | #' @examples 15 | #' 16 | #' x <- matrix(1:6, ncol = 1) 17 | #' 18 | #' # Reshape with the same dimensionality 19 | #' rray_reshape(x, c(2, 3)) 20 | #' 21 | #' # Change the dimensionality and the dimensions 22 | #' rray_reshape(x, c(3, 2, 1)) 23 | #' 24 | #' # You cannot reshape to a total size that is 25 | #' # different from the current size. 26 | #' try(rray_reshape(x, c(6, 2))) 27 | #' 28 | #' # Note that you can broadcast to these dimensions! 29 | #' rray_broadcast(x, c(6, 2)) 30 | #' 31 | #' @export 32 | rray_reshape <- function(x, dim) { 33 | dim <- vec_cast(dim, integer()) 34 | 35 | res <- rray__reshape(x, dim) 36 | 37 | vec_cast_container(res, x) 38 | } 39 | -------------------------------------------------------------------------------- /R/shape.R: -------------------------------------------------------------------------------- 1 | rray_shape <- function(x) { 2 | # removes vctrs is.object() restriction 3 | rray_dim(x)[-1] 4 | } 5 | 6 | rray_shape2 <- function(x, y) { 7 | rray_dim2(rray_shape(x), rray_shape(y)) 8 | } 9 | -------------------------------------------------------------------------------- /R/slice-assign.R: -------------------------------------------------------------------------------- 1 | #' @rdname rray_slice 2 | #' @export 3 | `rray_slice<-` <- function(x, i, axis, value) { 4 | rray_slice_assign(x, i = i, axis = axis, value = value) 5 | } 6 | 7 | #' @rdname rray_slice 8 | #' @export 9 | rray_slice_assign <- function(x, i, axis, value) { 10 | axis <- vec_cast(axis, integer()) 11 | validate_axis(axis, x) 12 | 13 | indexer <- front_pad(i, axis) 14 | 15 | rray_subset_assign(x, !!!indexer, value = value) 16 | } 17 | -------------------------------------------------------------------------------- /R/slice.R: -------------------------------------------------------------------------------- 1 | #' Get or set a slice of an array 2 | #' 3 | #' `rray_slice()` is a shortcut wrapper around [rray_subset()] that is useful 4 | #' for easily subsetting along a single axis. 5 | #' 6 | #' @param x A vector, matrix, array or rray. 7 | #' 8 | #' @param i Indices to extract along a single axis. 9 | #' - Integer indices extract specific elements of the `axis` dimension. 10 | #' - Logical indices must be length 1, or the length of the `axis` dimension. 11 | #' - Character indices are only allowed if `x` has names for the `axis` dimension. 12 | #' - `NULL` is treated as `0`. 13 | #' 14 | #' @param axis An integer. The axis to subset along. 15 | #' 16 | #' @param value A value to be assigned to the location at 17 | #' `rray_slice(x, i, axis)`. It will be cast to the type and dimension 18 | #' of the slice of `x`. 19 | #' 20 | #' @details 21 | #' 22 | #' `rray_slice()` does exactly the same thing as [rray_subset()], and is 23 | #' mainly helpful for higher dimensional objects, when you need to subset 24 | #' along, for example, only the 4th dimension. 25 | #' 26 | #' @return 27 | #' 28 | #' `x` with the `i` elements extracted from the `axis`. 29 | #' 30 | #' @examples 31 | #' x <- rray(1:16, c(2, 2, 2, 2)) 32 | #' 33 | #' # Selecting the first column 34 | #' rray_slice(x, i = 1, axis = 2) 35 | #' 36 | #' # rray_slice() is particularly useful for 37 | #' # subsetting higher dimensions because you don't 38 | #' # have to worry about the commas 39 | #' rray_slice(x, i = 2, axis = 4) 40 | #' 41 | #' # Compare the above with the equivalent using `[` 42 | #' x[, , , 2] 43 | #' 44 | #' # `i` can be a character vector if `x` has names along `axis` 45 | #' x <- rray_set_axis_names(x, axis = 4, c("foo", "bar")) 46 | #' rray_slice(x, "bar", axis = 4) 47 | #' 48 | #' # The assignment variation can be useful 49 | #' # for assigning to higher dimensional elements 50 | #' rray_slice(x, 1, 3) <- matrix(c(99, 100), nrow = 1) 51 | #' 52 | #' @family rray subsetters 53 | #' @export 54 | rray_slice <- function(x, i, axis) { 55 | axis <- vec_cast(axis, integer()) 56 | validate_axis(axis, x) 57 | 58 | indexer <- front_pad(i, axis) 59 | 60 | rray_subset(x, !!!indexer) 61 | } 62 | 63 | front_pad <- function(i, axis) { 64 | padding <- rep(list(missing_arg()), times = axis - 1L) 65 | c(padding, list(i)) 66 | } 67 | -------------------------------------------------------------------------------- /R/sort.R: -------------------------------------------------------------------------------- 1 | #' Sort an array 2 | #' 3 | #' `rray_sort()` returns an array with the same dimensions as `x`, but sorted 4 | #' along the specified axis. 5 | #' 6 | #' @param x A vector, matrix, array, or rray. 7 | #' 8 | #' @param axis A single integer specifying the axis to compute along. `1` 9 | #' sorts along rows, `2` sorts along columns. The default of `NULL` first 10 | #' flattens `x` to 1-D, sorts, and then reconstructs the original dimensions. 11 | #' 12 | #' @details 13 | #' 14 | #' Dimension names are lost along the axis that you sort along. If 15 | #' `axis = NULL`, then all dimension names are lost. In both cases, meta 16 | #' names are kept. The rationale for this is demonstrated in the examples. 17 | #' There, when you sort `y` along the rows, the rows in the first column change 18 | #' position, but the rows in the second column do not, so there is no rational 19 | #' order that the row names can be placed in. 20 | #' 21 | #' @return 22 | #' 23 | #' An object with the same dimensions as `x`, but sorted along `axis`. The 24 | #' dimension names will be lost along the axis you sort along. 25 | #' 26 | #' @examples 27 | #' x <- rray(c(20:11, 1:10), dim = c(5, 2, 2)) 28 | #' 29 | #' # Flatten, sort, then reconstruct the shape 30 | #' rray_sort(x) 31 | #' 32 | #' # Sort, looking along the rows 33 | #' rray_sort(x, 1) 34 | #' 35 | #' # Sort, looking along the columns 36 | #' rray_sort(x, 2) 37 | #' 38 | #' # Sort, looking along the third dimension 39 | #' # This switches the 20 with the 1, the 40 | #' # 19 with the 2, and so on 41 | #' rray_sort(x, 3) 42 | #' 43 | #' # --------------------------------------------------------------------------- 44 | #' # Dimension names 45 | #' 46 | #' y <- rray( 47 | #' c(2, 1, 1, 2), 48 | #' dim = c(2, 2), 49 | #' dim_names = list( 50 | #' r = c("r1", "r2"), 51 | #' c = c("c1", "c2") 52 | #' ) 53 | #' ) 54 | #' 55 | #' # Dimension names are dropped along the axis you sort along 56 | #' rray_sort(y, 1) 57 | #' rray_sort(y, 2) 58 | #' 59 | #' # All dimension names are dropped if `axis = NULL` 60 | #' rray_sort(y) 61 | #' 62 | #' @export 63 | rray_sort <- function(x, axis = NULL) { 64 | 65 | axis <- vec_cast(axis, integer()) 66 | validate_axis(axis, x) 67 | 68 | res <- rray__sort(x, as_cpp_idx(axis)) 69 | 70 | vec_cast_container(res, x) 71 | } 72 | -------------------------------------------------------------------------------- /R/split.R: -------------------------------------------------------------------------------- 1 | #' Split an array along axes 2 | #' 3 | #' `rray_split()` splits `x` into equal pieces, splitting along the `axes`. 4 | #' 5 | #' @param x A vector, matrix, array, or rray. 6 | #' 7 | #' @param axes An integer vector. The axes to split on. The default splits 8 | #' along all axes. 9 | #' 10 | #' @details 11 | #' 12 | #' `rray_split()` works by splitting along the `axes`. The result is a list 13 | #' of sub arrays, where the `axes` of each sub array have been reduced to 14 | #' length 1. This is consistent with how reducers like [rray_sum()] work. As 15 | #' an example, splitting a `(2, 3, 5)` array along `axes = c(2, 3)` would 16 | #' result in a list of 15 (from `3 * 5`) sub arrays, each with 17 | #' shape `(2, 1, 1)`. 18 | #' 19 | #' @return 20 | #' 21 | #' A list of sub arrays of type `x`. 22 | #' 23 | #' @examples 24 | #' 25 | #' x <- matrix(1:8, ncol = 2) 26 | #' 27 | #' # Split the rows 28 | #' # (4, 2) -> (1, 2) 29 | #' rray_split(x, 1) 30 | #' 31 | #' # Split the columns 32 | #' # (4, 2) -> (4, 1) 33 | #' rray_split(x, 2) 34 | #' 35 | #' # Split along multiple dimensions 36 | #' # (4, 2) -> (1, 1) 37 | #' rray_split(x, c(1, 2)) 38 | #' 39 | #' # The above split is the default behavior 40 | #' rray_split(x) 41 | #' 42 | #' # You can technically split with a size 0 `axes` 43 | #' # argument, which essentially requests no axes 44 | #' # to be split and is the same as `list(x)` 45 | #' rray_split(x, axes = integer(0)) 46 | #' 47 | #' # --------------------------------------------------------------------------- 48 | #' # 4 dimensional example 49 | #' 50 | #' x_4d <- rray( 51 | #' x = 1:16, 52 | #' dim = c(2, 2, 2, 2), 53 | #' dim_names = list( 54 | #' c("r1", "r2"), 55 | #' c("c1", "c2"), 56 | #' c("d1", "d2"), 57 | #' c("e1", "e2") 58 | #' ) 59 | #' ) 60 | #' 61 | #' # Split along the 1st dimension (rows) 62 | #' # (2, 2, 2, 2) -> (1, 2, 2, 2) 63 | #' rray_split(x_4d, 1) 64 | #' 65 | #' # Split along columns 66 | #' # (2, 2, 2, 2) -> (2, 1, 2, 2) 67 | #' rray_split(x_4d, 2) 68 | #' 69 | #' # Probably the most useful thing you might do 70 | #' # is use this to split the 4D array into a set 71 | #' # of 4 2D matrices. 72 | #' rray_split(x_4d, c(3, 4)) 73 | #' 74 | #' @export 75 | rray_split <- function(x, axes = NULL) { 76 | 77 | axes <- vec_cast(axes, integer()) 78 | validate_axes(axes, x) 79 | 80 | if (is_null(axes)) { 81 | axes <- seq_len(rray_dim_n(x)) 82 | } 83 | 84 | res <- rray__split(x, as_cpp_idx(axes)) 85 | 86 | # # Avoid copy by not calling map() 87 | # # map() always copies, even if `vec_cast_container()` 88 | # # does no work 89 | for (i in seq_along(res)) { 90 | res[[i]] <- vec_cast_container(res[[i]], x) 91 | } 92 | 93 | res 94 | } 95 | -------------------------------------------------------------------------------- /R/squeeze.R: -------------------------------------------------------------------------------- 1 | #' Squeeze an rray 2 | #' 3 | #' `rray_squeeze()` is conceptually similar to [base::drop()], but it allows 4 | #' for the specification of specific dimensions to squeeze. 5 | #' 6 | #' @details 7 | #' 8 | #' The dimension name handling of `rray_squeeze()` is essentially identical to 9 | #' `drop()`, but some explanation is always helpful: 10 | #' 11 | #' - Dimension names are removed from the axes that are squeezed. So squeezing 12 | #' a `(2, 1, 2)` object results in a `(2, 2)` object using the dimension names 13 | #' from the original first and third dimensions. 14 | #' 15 | #' - When all dimensions are squeezed, as in the case of `(1, 1, 1)`, then 16 | #' the first dimension names that are found are the ones that are used in the 17 | #' `(1)` result. 18 | #' 19 | #' @param x A vector, matrix, array or rray. 20 | #' 21 | #' @param axes An integer vector specifying the size 1 dimensions to drop. If 22 | #' `NULL`, all size 1 dimensions are dropped. 23 | #' 24 | #' @return 25 | #' 26 | #' `x` with the `axes` dropped, if possible. 27 | #' 28 | #' @examples 29 | #' # (10, 1) -> (10) 30 | #' x <- rray(1:10, c(10, 1)) 31 | #' rray_squeeze(x) 32 | #' 33 | #' # Multiple squeezed dimensions 34 | #' # (10, 1, 1) -> (10) 35 | #' y <- rray_reshape(x, c(10, 1, 1)) 36 | #' rray_squeeze(y) 37 | #' 38 | #' # Use `axes` to specify dimensions to drop 39 | #' # (10, 1, 1) -> drop 2 -> (10, 1) 40 | #' rray_squeeze(y, axes = 2) 41 | #' 42 | #' # Dimension names are kept here 43 | #' # (10, 1) -> (10) 44 | #' x <- rray_set_row_names(x, letters[1:10]) 45 | #' rray_squeeze(x) 46 | #' 47 | #' # And they are kept here 48 | #' # (1, 10) -> (10) 49 | #' rray_squeeze(t(x)) 50 | #' 51 | #' @export 52 | rray_squeeze <- function(x, axes = NULL) { 53 | 54 | if (is.null(axes)) { 55 | dim <- rray_dim(x) 56 | axes <- which(dim == 1L) 57 | 58 | # No axes are length 1 59 | if (length(axes) == 0L) { 60 | return(x) 61 | } 62 | } 63 | 64 | axes <- vec_cast(axes, integer()) 65 | validate_axes(axes, x) 66 | 67 | out <- rray__squeeze(x, as_cpp_idx(axes)) 68 | 69 | vec_cast_container(out, x) 70 | } 71 | -------------------------------------------------------------------------------- /R/subset-assign.R: -------------------------------------------------------------------------------- 1 | #' @rdname rray_subset 2 | #' @export 3 | `rray_subset<-` <- function(x, ..., value) { 4 | rray_subset_assign(x, ..., value = value) 5 | } 6 | 7 | #' @rdname rray_subset 8 | #' @export 9 | `[<-.vctrs_rray` <- function(x, ..., value) { 10 | rray_subset_assign(x, ..., value = value) 11 | } 12 | 13 | # Internally, using `rray_subset_assign()` rather than `rray_subset<-()` results 14 | # in only 1 copy rather than 2 when on R < 3.6.0 due to the way the internal 15 | # R assignment code works 16 | 17 | #' @rdname rray_subset 18 | #' @export 19 | rray_subset_assign <- function(x, ..., value) { 20 | indexer <- rray_as_index(x, ...) 21 | 22 | vec_assert(value, arg = "value") 23 | value <- vec_cast_inner(value, x) 24 | 25 | # TODO 26 | if (is_any_na_int(indexer)) { 27 | abort("`NA` indices are not yet supported.") 28 | } 29 | 30 | out <- rray__subset_assign(x, indexer, value) 31 | 32 | vec_cast_container(out, x) 33 | } 34 | -------------------------------------------------------------------------------- /R/tile.R: -------------------------------------------------------------------------------- 1 | #' Tile an array 2 | #' 3 | #' @param x A vector, matrix, array or rray. 4 | #' 5 | #' @param times An integer vector. The number of times to repeat the 6 | #' array along an axis. 7 | #' 8 | #' @details 9 | #' 10 | #' `rray_tile()` should not be used as a replacement for `rray_broadcast()`, 11 | #' as it is generally less efficient. 12 | #' 13 | #' @return 14 | #' 15 | #' `x` with dimensions repeated as described by `times`. 16 | #' 17 | #' @examples 18 | #' 19 | #' x <- matrix(1:5) 20 | #' 21 | #' # Repeat the rows twice 22 | #' rray_tile(x, 2) 23 | #' 24 | #' # Repeat the rows twice and the columns three times 25 | #' rray_tile(x, c(2, 3)) 26 | #' 27 | #' # Tile into a third dimension 28 | #' rray_tile(x, c(1, 2, 2)) 29 | #' 30 | #' @export 31 | rray_tile <- function(x, times) { 32 | 33 | dim_n <- rray_dim_n(x) 34 | size_times <- vec_size(times) 35 | 36 | if (dim_n < size_times) { 37 | new_dim <- rray_increase_dims(rray_dim(x), size_times) 38 | x <- rray_reshape(x, new_dim) 39 | } 40 | 41 | if (dim_n > size_times) { 42 | times <- rray_increase_dims(times, dim_n) 43 | } 44 | 45 | dim <- rray_dim(x) 46 | 47 | slicer <- map2(times, dim, get_tile_index) 48 | 49 | res <- eval_bare(expr(x[!!!slicer, drop = FALSE])) 50 | 51 | res 52 | } 53 | 54 | # - Generate the repeated index for each dim 55 | # - If `times == 1` for that dim, return a missing arg to return 56 | # that entire dim 57 | # - `single_dim == 0` is handled gracefully and `integer()` 58 | # is returned which is correct 59 | get_tile_index <- function(single_time, single_dim) { 60 | if (single_time == 1L) { 61 | return(missing_arg()) 62 | } 63 | 64 | rep(seq_len(single_dim), times = single_time) 65 | } 66 | -------------------------------------------------------------------------------- /R/util.R: -------------------------------------------------------------------------------- 1 | compact <- function (x) { 2 | is_null <- map_lgl(x, is.null) 3 | x[!is_null] 4 | } 5 | 6 | glubort <- function(..., .sep = "", .envir = parent.frame()) { 7 | abort(glue::glue(..., .sep = .sep, .envir = .envir)) 8 | } 9 | 10 | as_cpp_idx <- function(x) { 11 | 12 | if (is.null(x)) { 13 | return(x) 14 | } 15 | 16 | x - 1L 17 | } 18 | -------------------------------------------------------------------------------- /R/yank-assign.R: -------------------------------------------------------------------------------- 1 | #' @rdname rray_yank 2 | #' @export 3 | `rray_yank<-` <- function(x, i, value) { 4 | rray_yank_assign(x, i = maybe_missing(i), value = value) 5 | } 6 | 7 | #' @rdname rray_yank 8 | #' @export 9 | `[[<-.vctrs_rray` <- function(x, i, ..., value) { 10 | validate_empty_yank_assign_dots(...) 11 | rray_yank_assign(x, i = maybe_missing(i), value = value) 12 | } 13 | 14 | #' @rdname rray_yank 15 | #' @export 16 | rray_yank_assign <- function(x, i, value) { 17 | i <- maybe_missing(i, TRUE) 18 | i <- as_yank_location(i, x) 19 | 20 | vec_assert(value, arg = "value") 21 | value <- vec_cast_inner(value, x) 22 | 23 | # TODO 24 | if (is.integer(i) && is_any_na_int(list(i))) { 25 | abort("`NA` indices are not yet supported.") 26 | } 27 | else if (is.logical(i) && is_any_na_int(list(as.integer(i)))) { 28 | abort("`NA` indices are not yet supported.") 29 | } 30 | 31 | out <- rray__yank_assign(x, i, value) 32 | 33 | vec_cast_container(out, vec_ptype_container(x)) 34 | } 35 | 36 | # ------------------------------------------------------------------------------ 37 | 38 | validate_empty_yank_assign_dots <- function(...) { 39 | 40 | dots <- dots_list(..., .preserve_empty = TRUE, .ignore_empty = "none") 41 | 42 | if (length(dots) > 0L) { 43 | glubort( 44 | "`[[<-` assigns elements by position. ", 45 | "Only `x[[i]] <- value` is supported, but {length(dots) + 1} ", 46 | "indexers were supplied." 47 | ) 48 | } 49 | 50 | invisible() 51 | } 52 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | url: https://rray.r-lib.org 2 | 3 | template: 4 | params: 5 | ganalytics: UA-115082821-1 6 | 7 | development: 8 | mode: auto 9 | 10 | reference: 11 | - title: Coercion 12 | contents: 13 | - as_array 14 | - as_matrix 15 | - as_rray 16 | - is_rray 17 | 18 | - title: Construction 19 | contents: 20 | - new_rray 21 | - rray 22 | - rray_full_like 23 | 24 | - title: Dimension names 25 | contents: 26 | - rray_dim_names_common 27 | - rray_dim_names 28 | 29 | - title: Dimensions 30 | contents: 31 | - rray_dim 32 | - rray_dim_n 33 | - rray_elems 34 | 35 | - title: Subsetting 36 | contents: 37 | - pad 38 | - rray_subset 39 | - rray_extract 40 | - rray_slice 41 | - rray_yank 42 | 43 | - title: Manipulation 44 | contents: 45 | - rray_bind 46 | - rray_broadcast 47 | - rray_reshape 48 | - rray_clip 49 | - rray_diag 50 | - rray_expand 51 | - rray_flatten 52 | - rray_flip 53 | - rray_sort 54 | - rray_split 55 | - rray_squeeze 56 | - rray_tile 57 | - rray_transpose 58 | - rray_maximum 59 | - rray_rotate 60 | 61 | - title: Reducers 62 | contents: 63 | - rray_max 64 | - rray_max_pos 65 | - rray_mean 66 | - rray_min 67 | - rray_min_pos 68 | - rray_prod 69 | - rray_sum 70 | 71 | - title: Duplicate and Unique 72 | contents: 73 | - rray_duplicate_any 74 | - rray_unique 75 | 76 | - title: Arithmetic 77 | contents: 78 | - rray_add 79 | - rray_dot 80 | - rray_multiply_add 81 | - rray_hypot 82 | 83 | - title: Comparison and Logical 84 | contents: 85 | - rray_greater 86 | - rray_all_equal 87 | - rray_logical_and 88 | - rray_if_else 89 | 90 | - title: Compatibility 91 | contents: 92 | - vec_arith.vctrs_rray 93 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | comment: false 2 | 3 | coverage: 4 | status: 5 | project: 6 | default: 7 | target: auto 8 | threshold: 1% 9 | patch: 10 | default: 11 | target: auto 12 | threshold: 1% 13 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Resubmission 2 | This is a resubmission of rray based on the following CRAN comments. 3 | 4 | ``` 5 | Thanks, please do not comment out your examples and use \donttest{} instead: 6 | 7 | \examples{ 8 | examples for users and checks: 9 | executable in < 5 sec 10 | 11 | donttest{ 12 | further examples for users (not used for checks) 13 | } 14 | } 15 | ``` 16 | 17 | I have removed the commented out examples. 18 | 19 | ``` 20 | You have examples for unexported functions which cannot run in this way. 21 | Please either add rray::: to the function calls in the examples, omit 22 | these examples or port these functions. 23 | ``` 24 | 25 | I believe these were related to unexported functions that I still wanted to 26 | document. I no longer generate Rd for these, so this should be fixed. 27 | 28 | ``` 29 | Missing Rd-tags: 30 | as_array.Rd: \value 31 | as_matrix.Rd: \value 32 | as_rray.Rd: \value 33 | .... 34 | 35 | Please add this tag in your Rd-files and explain the function's output. 36 | ``` 37 | 38 | I have added return value descriptions for all functions. 39 | 40 | ## Comments 41 | This is the first release of rray. 42 | 43 | The install size of rray is on the larger end for an R package, but is 44 | generally due to xtensor being a header only library. 45 | 46 | ## Test environments 47 | * local OS X install, R 3.6.0 48 | * ubuntu 14.04 (on travis-ci), R 3.6.0 49 | * win-builder (devel and release) 50 | 51 | ## R CMD check results 52 | 53 | 0 errors | 0 warnings | 1 note 54 | 55 | * This is a new release. 56 | -------------------------------------------------------------------------------- /inst/WORDLIST: -------------------------------------------------------------------------------- 1 | abind 2 | Acknowledgements 3 | ALTREP 4 | broadcasted 5 | Codecov 6 | coercible 7 | Github 8 | ish 9 | Lifecycle 10 | natively 11 | nd 12 | NumPy 13 | programmatically 14 | rray's 15 | subsetters 16 | th 17 | tibble 18 | tidyverse 19 | vctrs 20 | xtensor 21 | -------------------------------------------------------------------------------- /inst/include/api.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_api_h 2 | #define rray_api_h 3 | 4 | #include 5 | 6 | // ----------------------------------------------------------------------------- 7 | // Dimensions / dimensionality 8 | 9 | Rcpp::IntegerVector rray__dim(const Rcpp::RObject& x); 10 | 11 | Rcpp::IntegerVector rray__dim2(Rcpp::IntegerVector x_dim, 12 | Rcpp::IntegerVector y_dim); 13 | 14 | int rray__dim_n(const Rcpp::RObject& x); 15 | 16 | Rcpp::IntegerVector rray__increase_dims(const Rcpp::IntegerVector& dim, 17 | const int& dim_n); 18 | 19 | bool rray__has_dim(const Rcpp::RObject& x); 20 | 21 | // ----------------------------------------------------------------------------- 22 | // Dimension names 23 | 24 | Rcpp::List rray__new_empty_dim_names(int n); 25 | 26 | Rcpp::List rray__dim_names(const Rcpp::RObject& x); 27 | 28 | // ----------------------------------------------------------------------------- 29 | // Common dimension names 30 | 31 | Rcpp::List rray__resize_dim_names(Rcpp::List dim_names, 32 | Rcpp::IntegerVector dim); 33 | 34 | Rcpp::List rray__coalesce_dim_names(Rcpp::List x_dim_names, 35 | Rcpp::List y_dim_names); 36 | 37 | Rcpp::List rray__dim_names2(Rcpp::RObject x, Rcpp::RObject y); 38 | 39 | void rray__resize_and_set_dim_names(Rcpp::RObject res, Rcpp::RObject x); 40 | 41 | void rray__set_dim_names(Rcpp::RObject x, const Rcpp::List& dim_names); 42 | 43 | // ----------------------------------------------------------------------------- 44 | // Miscellaneous 45 | 46 | int rray__prod(Rcpp::IntegerVector x); 47 | 48 | // ----------------------------------------------------------------------------- 49 | // Validation 50 | 51 | void rray__validate_dim(Rcpp::IntegerVector dim); 52 | 53 | void rray__validate_reshape(Rcpp::RObject x, Rcpp::IntegerVector dim); 54 | 55 | void rray__validate_broadcastable_to_dim(Rcpp::IntegerVector x_dim, 56 | Rcpp::IntegerVector dim); 57 | 58 | std::string rray__dim_to_string(Rcpp::IntegerVector dim); 59 | 60 | // ----------------------------------------------------------------------------- 61 | // Re-exposed R API 62 | 63 | #include 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /inst/include/cast.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_cast_h 2 | #define rray_cast_h 3 | 4 | extern SEXP fns_vec_cast_inner; 5 | 6 | SEXP vec__cast_inner(SEXP x, SEXP to); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /inst/include/r-api.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_r_api_h 2 | #define rray_r_api_h 3 | 4 | // Required for SEXP typename and R_MissingArg to work 5 | #include 6 | 7 | bool r_identical(SEXP x, SEXP y); 8 | 9 | bool r_is_null(SEXP x); 10 | 11 | bool r_is_missing(SEXP x); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /inst/include/rray.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_h 2 | #define rray_h 3 | 4 | // for std::vector & std::size_t 5 | #include 6 | 7 | // xtensor-r headers containing R <-> Rcpp <-> xtensor conversion 8 | #include 9 | 10 | // Cross file API 11 | #include "api.h" 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /inst/include/subset-tools.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_subset_tools_h 2 | #define rray_subset_tools_h 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // ----------------------------------------------------------------------------- 9 | // Subsetting helpers that are used across multiple subsetting files 10 | 11 | bool is_stridable(Rcpp::List x); 12 | 13 | xt::xstrided_slice_vector build_strided_slice_vector(Rcpp::List indexer); 14 | 15 | xt::xdynamic_slice_vector build_dynamic_slice_vector(Rcpp::List indexer); 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /inst/include/tools/errors.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_errors_h 2 | #define rray_errors_h 3 | 4 | #include 5 | 6 | [[ noreturn ]] inline void error_unknown_type() { 7 | Rcpp::stop("Incompatible SEXP encountered; only accepts doubles, integers, and logicals."); 8 | } 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /inst/include/tools/tools.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_tools_h 2 | #define rray_tools_h 3 | 4 | // Include all relevant tools 5 | #include 6 | #include 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /inst/include/type2.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_type2_h 2 | #define rray_type2_h 3 | 4 | extern SEXP fns_vec_ptype_inner2; 5 | 6 | SEXP vec__ptype_inner2(SEXP x, SEXP y); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /inst/include/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef rray_utils_h 2 | #define rray_utils_h 3 | 4 | // Required for SEXP typename 5 | #include 6 | 7 | extern SEXP rray_ns_env; 8 | 9 | extern SEXP syms_x; 10 | extern SEXP syms_y; 11 | extern SEXP syms_to; 12 | 13 | extern SEXP rray_shared_empty_lgl; 14 | extern SEXP rray_shared_empty_int; 15 | extern SEXP rray_shared_empty_dbl; 16 | extern SEXP rray_shared_empty_chr; 17 | 18 | extern SEXP fns_vec_cast_inner; 19 | extern SEXP fns_vec_ptype_inner2; 20 | 21 | SEXP r_new_environment(SEXP parent, R_len_t size); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /man/as_array.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/coercion.R 3 | \name{as_array} 4 | \alias{as_array} 5 | \title{Coerce to an array} 6 | \usage{ 7 | as_array(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{An object to coerce to an array.} 11 | 12 | \item{...}{Objects passed on to methods.} 13 | } 14 | \value{ 15 | An array. 16 | } 17 | \description{ 18 | \code{as_array()} coerces \code{x} to an array. \code{x} will keep any existing 19 | dimensions and dimension names. 20 | } 21 | \examples{ 22 | 23 | as_array(1:10) 24 | 25 | } 26 | \seealso{ 27 | \code{\link[=as_matrix]{as_matrix()}} 28 | } 29 | -------------------------------------------------------------------------------- /man/as_matrix.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/coercion.R 3 | \name{as_matrix} 4 | \alias{as_matrix} 5 | \title{Coerce to a matrix} 6 | \usage{ 7 | as_matrix(x, ...) 8 | } 9 | \arguments{ 10 | \item{x}{An object to coerce to a matrix.} 11 | 12 | \item{...}{Objects passed on to methods.} 13 | } 14 | \value{ 15 | A matrix. 16 | } 17 | \description{ 18 | \code{as_matrix()} coerces \code{x} to a matrix. 19 | } 20 | \details{ 21 | 1D arrays are coerced to 1 column matrices. 22 | 23 | For a >2D object to be coercible to a matrix, all of the dimensions 24 | except for the first two must be size 1. Meaning an array with dimensions 25 | \verb{(3, 2, 1)} would be coercible to a \verb{(3, 2)} matrix, but one with \verb{(3, 1, 2)} 26 | would not be. 27 | } 28 | \examples{ 29 | as_matrix(rray(1:10)) 30 | 31 | # >2D structures can be coerced to matrices 32 | # their first and second dimensions are 33 | # the only ones having a size >1 34 | x <- rray(1, c(2, 2, 1)) 35 | as_matrix(x) 36 | 37 | # This cannot be coerced to a matrix 38 | y <- rray_reshape(x, c(2, 1, 2)) 39 | try(as_matrix(y)) 40 | 41 | } 42 | \seealso{ 43 | \code{\link[=as_array]{as_array()}} 44 | } 45 | -------------------------------------------------------------------------------- /man/as_rray.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/coercion.R 3 | \name{as_rray} 4 | \alias{as_rray} 5 | \title{Coerce to an rray} 6 | \usage{ 7 | as_rray(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object to coerce to an rray.} 11 | } 12 | \value{ 13 | An rray. 14 | } 15 | \description{ 16 | Coerce \code{x} to an rray. It will keep its dimensions and dimension names if 17 | it has any. 18 | } 19 | \examples{ 20 | 21 | as_rray(1) 22 | 23 | ex <- matrix(1:10, nrow = 5, dimnames = list(NULL, c("a", "b"))) 24 | as_rray(ex) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /man/common-dim-names.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dim-names-common.R 3 | \name{common-dim-names} 4 | \alias{common-dim-names} 5 | \alias{rray_dim_names_common} 6 | \alias{rray_dim_names2} 7 | \title{Find common dimension names} 8 | \usage{ 9 | rray_dim_names_common(...) 10 | 11 | rray_dim_names2(x, y) 12 | } 13 | \arguments{ 14 | \item{x, y, ...}{Objects to find common dimensions for.} 15 | } 16 | \value{ 17 | A list of the common dimension names of the inputs. 18 | } 19 | \description{ 20 | Obtain a list of common dimension names among a set of objects. For 21 | interactive use, \code{rray_dim_names_common()} is more useful. 22 | } 23 | \details{ 24 | \code{rray_dim_names_common()} is the engine that determines what dim names should 25 | be used in the result of arithmetic operations and other functions that 26 | involve multiple rray objects and return a single result. 27 | 28 | The rules for determining the set of common dim names between objects 29 | \code{x} and \code{y} (in that order) are: 30 | \itemize{ 31 | \item Compute the common \code{dim} between \code{x} and \code{y} using \code{rray_dim_common()}. 32 | \item For each axis along the common \code{dim}: 33 | \itemize{ 34 | \item If \code{x} has names for that axis \emph{and} the size of the names vector 35 | is the same as the size of the axis, use those names for that axis. 36 | \item Else if \code{y} has names for that axis \emph{and} the size of the names vector 37 | is the same as the size of the axis, use those names for that axis. 38 | \item Otherwise, the names for that axis is \code{NULL}. 39 | } 40 | } 41 | } 42 | \examples{ 43 | library(magrittr) 44 | 45 | # 1x2 - Row names but no column names 46 | x <- rray(1, dim = c(1, 2)) \%>\% 47 | rray_set_row_names("r_from_x") 48 | 49 | # 1x1 - Row names and column names 50 | y <- rray(1, dim = c(1, 1)) \%>\% 51 | rray_set_col_names("c_from_y") \%>\% 52 | rray_set_row_names("r_from_y") 53 | 54 | # 1x1 - Row names but no column names 55 | z <- rray(1, c(1, 1)) \%>\% 56 | rray_set_row_names("r_from_z") 57 | 58 | # Combining y and z 59 | # y has names for both dimensions 60 | # so they are used 61 | rray_dim_names_common(y, z) 62 | 63 | # Combining z and y 64 | # - Row names are found first from z 65 | # - But z has no column names 66 | # - So column names are found from y 67 | rray_dim_names_common(z, y) 68 | 69 | # Combining x and y 70 | # - Row names are found first from x 71 | # - x has no column names 72 | # - y has column names but they are 73 | # a different length from the common 74 | # column dimension (common size of 2) 75 | # - So no column names are used 76 | rray_dim_names_common(x, y) 77 | 78 | } 79 | -------------------------------------------------------------------------------- /man/extremum.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extremum.R 3 | \name{extremum} 4 | \alias{extremum} 5 | \alias{rray_maximum} 6 | \alias{rray_minimum} 7 | \title{Maximum and minimum values} 8 | \usage{ 9 | rray_maximum(x, y) 10 | 11 | rray_minimum(x, y) 12 | } 13 | \arguments{ 14 | \item{x, y}{A vector, matrix, array or rray.} 15 | } 16 | \value{ 17 | The elementwise max/min of \code{x} and \code{y}, with broadcasting. 18 | } 19 | \description{ 20 | \code{rray_maximum()} and \code{rray_minimum()} compute the elementwise max / min 21 | between \code{x} and \code{y}. 22 | } 23 | \examples{ 24 | # Elementwise maximum 25 | rray_maximum(c(1, 2, 3), c(3, 2, 1)) 26 | 27 | # Elementwise minimum 28 | rray_minimum(c(1, 2, 3), c(3, 2, 1)) 29 | 30 | # With broadcasting 31 | x <- matrix(1:3) 32 | rray_maximum(x, t(x)) 33 | 34 | } 35 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/man/figures/logo.png -------------------------------------------------------------------------------- /man/is_rray.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rray.R 3 | \name{is_rray} 4 | \alias{is_rray} 5 | \title{Is \code{x} an rray?} 6 | \usage{ 7 | is_rray(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object.} 11 | } 12 | \value{ 13 | A single logical. 14 | } 15 | \description{ 16 | \code{is_rray()} tests if \code{x} is an rray object. 17 | } 18 | \examples{ 19 | 20 | is_rray(rray(1:5)) 21 | 22 | is_rray(1:5) 23 | 24 | } 25 | -------------------------------------------------------------------------------- /man/new_rray.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rray.R 3 | \name{new_rray} 4 | \alias{new_rray} 5 | \title{Create a new rray} 6 | \usage{ 7 | new_rray( 8 | .data = numeric(0), 9 | size = 0L, 10 | shape = integer(0), 11 | dim_names = NULL, 12 | ..., 13 | subclass = character(0) 14 | ) 15 | } 16 | \arguments{ 17 | \item{.data}{A numeric vector with no attributes representing 18 | the data.} 19 | 20 | \item{size}{An integer. The number of \emph{observations} in the object. 21 | This is equivalent to the number of rows.} 22 | 23 | \item{shape}{An integer vector. The shape corresponds to all of the 24 | dimensions in the object except for the first one (the \code{size}).} 25 | 26 | \item{dim_names}{A list. For no names, \code{NULL}, in which case a list of 27 | empty characters will be constructed. Otherwise the list must 28 | be the same length as the total number of dimensions 29 | (i.e \code{length(c(size, shape))}). Each element of the list much be either 30 | a character vector the same size as the corresponding dimension, or 31 | \code{character(0)} for no names for that dimension.} 32 | 33 | \item{...}{Name-value pairs defining attributes.} 34 | 35 | \item{subclass}{The name of the subclass.} 36 | } 37 | \value{ 38 | A new rray. 39 | } 40 | \description{ 41 | Low level constructor for rray objects 42 | } 43 | \examples{ 44 | 45 | rray_ex <- new_rray( 46 | .data = 1:10, 47 | size = 5L, 48 | shape = 2L, 49 | dim_names = list(character(), c("a", "b")) 50 | ) 51 | 52 | rray_ex 53 | 54 | } 55 | -------------------------------------------------------------------------------- /man/pad.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/pad.R 3 | \name{pad} 4 | \alias{pad} 5 | \title{Pad missing dimensions when subsetting} 6 | \usage{ 7 | pad() 8 | } 9 | \value{ 10 | An object that can be used to pad dimensions with when subsetting. 11 | } 12 | \description{ 13 | \code{pad()} is used alongside the standard rray subsetting operator \code{[} (and 14 | the underlying \code{rray_subset()} function) to easily subset into higher 15 | dimensions without having to explicitly list the intermediate commas. 16 | } 17 | \examples{ 18 | x <- rray(1:4, c(1, 1, 2, 2)) 19 | 20 | # pad() fills in the missing dimensions 21 | # essentially it adds commas automatically 22 | 23 | # second element in the 4th dimension 24 | x[pad(), 2] 25 | 26 | # vs using 27 | x[,,,2] 28 | 29 | # second element in 3rd 30 | # first element in 4th 31 | x[pad(), 2, 1] 32 | 33 | # can fill in the missing gaps too 34 | # this fills in the 2nd/3rd dimensions 35 | x[1, pad(), 1] 36 | 37 | # if a pad() isn't needed 38 | # because the dimensionality is already fully 39 | # specified by the indices, its ignored 40 | x_flat <- rray_reshape(x, 4) 41 | x_flat[pad(), 1] 42 | x_flat[1, pad()] 43 | 44 | # `pad()` can be used with base R 45 | # objects as well through `rray_subset()` 46 | x_arr <- as.array(x) 47 | rray_subset(x_arr, pad(), 1) 48 | 49 | } 50 | -------------------------------------------------------------------------------- /man/rray-compare.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/compare.R 3 | \name{rray-compare} 4 | \alias{rray-compare} 5 | \alias{>.vctrs_rray} 6 | \alias{rray_greater} 7 | \alias{>=.vctrs_rray} 8 | \alias{rray_greater_equal} 9 | \alias{<.vctrs_rray} 10 | \alias{rray_lesser} 11 | \alias{<=.vctrs_rray} 12 | \alias{rray_lesser_equal} 13 | \alias{==.vctrs_rray} 14 | \alias{rray_equal} 15 | \alias{!=.vctrs_rray} 16 | \alias{rray_not_equal} 17 | \title{Compare arrays} 18 | \usage{ 19 | \method{>}{vctrs_rray}(e1, e2) 20 | 21 | rray_greater(x, y) 22 | 23 | \method{>=}{vctrs_rray}(e1, e2) 24 | 25 | rray_greater_equal(x, y) 26 | 27 | \method{<}{vctrs_rray}(e1, e2) 28 | 29 | rray_lesser(x, y) 30 | 31 | \method{<=}{vctrs_rray}(e1, e2) 32 | 33 | rray_lesser_equal(x, y) 34 | 35 | \method{==}{vctrs_rray}(e1, e2) 36 | 37 | rray_equal(x, y) 38 | 39 | \method{!=}{vctrs_rray}(e1, e2) 40 | 41 | rray_not_equal(x, y) 42 | } 43 | \arguments{ 44 | \item{e1, e2}{Generally, the same as \code{x} and \code{y}. See Details.} 45 | 46 | \item{x, y}{Two vectors, matrices, arrays, or rrays.} 47 | } 48 | \value{ 49 | The value of the comparison, with dimensions identical to the common 50 | dimensions of the inputs. 51 | } 52 | \description{ 53 | These operators compare multiple arrays together, with broadcasting. The 54 | underlying functions powering the comparison operators are also exported 55 | for use with base R objects. 56 | } 57 | \details{ 58 | The comparison operators themselves rely on R's dispatching rules to 59 | dispatch to the correct rray comparison operator. When comparing rrays with 60 | base R matrices and arrays, this generally works fine. However, if you 61 | compare classed objects like \code{factor("x") > rray(1)} then a fall through 62 | method is used and a warning is thrown. There is nothing we can do about 63 | this. See \code{?groupGeneric} for more information on this. 64 | } 65 | \examples{ 66 | x <- rray(1:12, c(2, 2, 3)) 67 | y <- matrix(1:2) 68 | 69 | # True except in first 2 positions 70 | x > y 71 | 72 | # All true 73 | x >= y 74 | 75 | # False everywhere 76 | x < y 77 | 78 | # False except in the first 2 positions 79 | x <= y 80 | 81 | } 82 | -------------------------------------------------------------------------------- /man/rray.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rray.R 3 | \name{rray} 4 | \alias{rray} 5 | \title{Build a rray object} 6 | \usage{ 7 | rray(x = numeric(0), dim = NULL, dim_names = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A numeric vector, matrix, or array to convert to an rray.} 11 | 12 | \item{dim}{An integer vector describing the dimensions of the rray. If \code{NULL}, 13 | the dimensions are taken from the existing object using \code{\link[=rray_dim]{rray_dim()}}.} 14 | 15 | \item{dim_names}{A list. For no names, \code{NULL}, in which case a list of 16 | empty characters will be constructed. Otherwise the list must 17 | be the same length as the total number of dimensions 18 | (i.e \code{length(c(size, shape))}). Each element of the list much be either 19 | a character vector the same size as the corresponding dimension, or 20 | \code{character(0)} for no names for that dimension.} 21 | } 22 | \value{ 23 | An rray. 24 | } 25 | \description{ 26 | Constructor for building rray objects. Existing vectors, matrices, and 27 | arrays can be used to build the rray, but their dimension names are not 28 | retained. 29 | } 30 | \details{ 31 | The \code{dim} argument is very flexible. 32 | \itemize{ 33 | \item If \code{vec_size(x) == prod(dim)}, then a reshape is performed. 34 | \item Otherwise broadcasting is attempted. 35 | } 36 | 37 | This allows quick construction of a wide variety of structures. See the 38 | example section for more. 39 | 40 | rray objects are never reduced to vectors when subsetting using \code{[} (i.e. 41 | dimensions are never dropped). 42 | } 43 | \examples{ 44 | 45 | # 1D rray. Looks like a vector 46 | # functions similar to a 1 column matrix 47 | rray(c(1,2,3), dim = c(3)) 48 | 49 | # 3 rows, 4 cols 50 | rray(c(1,2,3), dim = c(3, 4)) 51 | 52 | # 3x2x4 array 53 | rray(1, dim = c(3, 2, 4)) 54 | 55 | # from a matrix 56 | mat <- matrix(c(1, 2, 3, 4), ncol = 2) 57 | rray(mat) 58 | 59 | # from a matrix, with broadcasting 60 | rray(mat, dim = c(2, 2, 3)) 61 | 62 | # reshape that matrix during creation 63 | # (different from broadcasting) 64 | rray(mat, dim = c(1, 4)) 65 | 66 | # from an array, with broadcasting 67 | arr <- array(1, c(1, 2, 2)) 68 | rray(arr, c(3, 2, 2)) 69 | 70 | # with row names 71 | rray(c(1, 2, 3), c(3, 2), dim_names = list(c("x", "y", "z"), NULL)) 72 | 73 | } 74 | -------------------------------------------------------------------------------- /man/rray_all_equal.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/compare.R 3 | \name{rray_all_equal} 4 | \alias{rray_all_equal} 5 | \alias{rray_any_not_equal} 6 | \title{Strictly compare arrays} 7 | \usage{ 8 | rray_all_equal(x, y) 9 | 10 | rray_any_not_equal(x, y) 11 | } 12 | \arguments{ 13 | \item{x, y}{Vectors, matrices, arrays, or rrays.} 14 | } 15 | \description{ 16 | Unlike \code{\link[=rray_equal]{rray_equal()}} and \code{\link[=rray_not_equal]{rray_not_equal()}}, these functions perform a 17 | strict comparison of two arrays, and return a single logical value. 18 | Specifically: 19 | \itemize{ 20 | \item Broadcasting is \emph{not} performed here, as the shape is part of the comparison. 21 | \item The underlying type of the values matter, and \code{1} is treated 22 | as different from \code{1L}. 23 | \item Otherwise, attributes are not compared, so dimension names are ignored. 24 | } 25 | } 26 | \examples{ 27 | # This is definitely true! 28 | rray_all_equal(1, 1) 29 | 30 | # Different types! 31 | rray_all_equal(1, 1L) 32 | 33 | # Different types! 34 | rray_all_equal(rray(1), matrix(1)) 35 | 36 | # Different shapes! 37 | rray_all_equal(matrix(1), matrix(1, nrow = 2)) 38 | 39 | # Are any values different? 40 | rray_any_not_equal(c(1, 1), c(1, 2)) 41 | 42 | # Is the shape different? 43 | rray_any_not_equal(1, c(1, 2)) 44 | 45 | # Dimension names don't matter 46 | x <- matrix(1, dimnames = list("foo", "bar")) 47 | rray_all_equal(x, matrix(1)) 48 | 49 | } 50 | -------------------------------------------------------------------------------- /man/rray_arith.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/arith.R 3 | \name{rray_arith} 4 | \alias{rray_arith} 5 | \alias{\%b+\%} 6 | \alias{rray_add} 7 | \alias{\%b-\%} 8 | \alias{rray_subtract} 9 | \alias{\%b*\%} 10 | \alias{rray_multiply} 11 | \alias{\%b/\%} 12 | \alias{rray_divide} 13 | \alias{\%b^\%} 14 | \alias{rray_pow} 15 | \alias{rray_identity} 16 | \alias{rray_opposite} 17 | \title{Arithmetic operations} 18 | \usage{ 19 | x \%b+\% y 20 | 21 | rray_add(x, y) 22 | 23 | x \%b-\% y 24 | 25 | rray_subtract(x, y) 26 | 27 | x \%b*\% y 28 | 29 | rray_multiply(x, y) 30 | 31 | x \%b/\% y 32 | 33 | rray_divide(x, y) 34 | 35 | x \%b^\% y 36 | 37 | rray_pow(x, y) 38 | 39 | rray_identity(x) 40 | 41 | rray_opposite(x) 42 | } 43 | \arguments{ 44 | \item{x, y}{A pair of vectors.} 45 | } 46 | \value{ 47 | The value of the arithmetic operation, with dimensions identical to the 48 | common dimensions of the input. 49 | } 50 | \description{ 51 | These functions provide the implementations for their underlying infix 52 | operators (i.e. \code{rray_add()} powers \code{+}). All operators apply broadcasting 53 | to their input. 54 | } 55 | \details{ 56 | In case you want to apply arithmetic operations with broadcasting to 57 | purely base R objects using infix operators, custom infix functions have 58 | been exported, such as \verb{\%b+\%}, which will perform addition with 59 | broadcasting no matter what type the input is. 60 | } 61 | \examples{ 62 | library(magrittr) 63 | 64 | x <- rray(1:8, c(2, 2, 2)) \%>\% 65 | rray_set_row_names(c("r1", "r2")) \%>\% 66 | rray_set_col_names(c("c1", "c2")) 67 | 68 | y <- matrix(1:2, nrow = 1) 69 | 70 | # All arithmetic functions are applied with broadcasting 71 | rray_add(x, y) 72 | 73 | # And the power `+` when any underlying input 74 | # is an rray 75 | x + y 76 | 77 | # If you happen to only have base R matrices/arrays 78 | # you can use `rray_add()` or `\%b+\%` to get the 79 | # broadcasting behavior 80 | rray_add(y, matrix(1:2)) 81 | 82 | y \%b+\% matrix(1:2) 83 | 84 | } 85 | -------------------------------------------------------------------------------- /man/rray_bind.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/bind.R 3 | \name{rray_bind} 4 | \alias{rray_bind} 5 | \alias{rray_rbind} 6 | \alias{rray_cbind} 7 | \title{Combine many arrays together into one array} 8 | \usage{ 9 | rray_bind(..., .axis) 10 | 11 | rray_rbind(...) 12 | 13 | rray_cbind(...) 14 | } 15 | \arguments{ 16 | \item{...}{Vectors, matrices, arrays, or rrays.} 17 | 18 | \item{.axis}{A single integer. The axis to bind along.} 19 | } 20 | \value{ 21 | An array, or rray, depending on the input. 22 | } 23 | \description{ 24 | These functions bind multiple vectors, matrices, arrays, or rrays together 25 | into one, combining along the \code{.axis}. 26 | } 27 | \details{ 28 | \code{rray_bind()} is extremely flexible. It uses broadcasting to combine 29 | arrays together in a way that the native functions of \code{cbind()} and \code{rbind()} 30 | cannot. See the examples section for more explanation! 31 | } 32 | \examples{ 33 | # --------------------------------------------------------------------------- 34 | a <- matrix(1:4, ncol = 2) 35 | b <- matrix(5:6, ncol = 1) 36 | 37 | # Bind along columns 38 | rray_bind(a, b, .axis = 2) 39 | 40 | # Bind along rows 41 | # Broadcasting is done automatically 42 | rray_bind(a, b, .axis = 1) 43 | 44 | # Notice that this is not possible with rbind()! 45 | try(rbind(a, b)) 46 | 47 | # You can bind "up" to a new dimension 48 | # to stack matrices into an array 49 | rray_bind(a, b, .axis = 3) 50 | 51 | # --------------------------------------------------------------------------- 52 | # Dimension name example 53 | 54 | x <- matrix( 55 | 1:6, 56 | ncol = 3, 57 | dimnames = list(c("a_r1", "a_r2"), c("a_c1", "a_c2", "a_c3")) 58 | ) 59 | 60 | y <- matrix( 61 | 7:8, 62 | ncol = 1, 63 | dimnames = list(NULL, c("b_c1")) 64 | ) 65 | 66 | # Dimension names come along for the ride 67 | # following rray name handling 68 | rray_bind(x, y, .axis = 2) 69 | 70 | # If some inputs are named, and others 71 | # are not, the non-named inputs get `""` 72 | # as names 73 | rray_bind(x, y, .axis = 1) 74 | 75 | # You can add "outer" names to the 76 | # axis you are binding along. 77 | # They are added to existing names with `..` 78 | rray_bind(outer = x, y, .axis = 2) 79 | 80 | # Outer names can be used to give unnamed 81 | # inputs default names 82 | rray_bind(outer = x, outer_y = y, .axis = 1) 83 | 84 | } 85 | -------------------------------------------------------------------------------- /man/rray_broadcast.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/broadcast.R 3 | \name{rray_broadcast} 4 | \alias{rray_broadcast} 5 | \title{Broadcast to a new dimension} 6 | \usage{ 7 | rray_broadcast(x, dim) 8 | } 9 | \arguments{ 10 | \item{x}{The object to broadcast.} 11 | 12 | \item{dim}{An integer vector. The dimension to broadcast to.} 13 | } 14 | \value{ 15 | \code{x} broadcast to the new dimensions. 16 | } 17 | \description{ 18 | \code{rray_broadcast()} will \emph{broadcast} the dimensions of the current 19 | object to a new dimension. 20 | } 21 | \details{ 22 | Broadcasting works by \emph{recycling dimensions} and \emph{repeating values} in 23 | those dimensions to match the new dimension. 24 | 25 | Here's an example. Assume you have a 1x3 matrix that you want to broadcast 26 | to a dimension of 2x3. Since the 1st dimensions are different, and one of them 27 | is 1, the 1 row of the 1x3 matrix is repeated to become a 2x3 matrix. For 28 | the second dimension, both are already 3 so nothing is done.\preformatted{(1, 3) 29 | (2, 3) 30 | ------ 31 | (2, 3) 32 | } 33 | 34 | As an example that \emph{doesn't} broadcast, here is an attempt to make a 35 | 2x1x4 matrix broadcast to a 2x3x5 matrix (In the R world, 2x3x4 means 36 | a 2 row, 3 column, and 4 "deep" array). The first 2 dimensions are fine, 37 | but for the third dimension, 4 and 5 are not "recyclable" and are therefore 38 | incompatible.\preformatted{(2, 1, 4) 39 | (2, 3, 5) 40 | --------- 41 | (2, 3, X) 42 | } 43 | 44 | You can broadcast to higher dimensions too. If you go from a 5x2 to a 45 | 5x2x3 array, then the 5x2 matrix implicitly gets a 1 appended as another 46 | dimension (i.e. 5x2x1)\preformatted{(5, 2, ) <- implicit 1 is recycled 47 | (5, 2, 3) 48 | --------- 49 | (5, 2, 3) 50 | } 51 | 52 | Broadcasting is an important concept in rray, as it is the engine behind 53 | the different structure for arithmetic operations. 54 | } 55 | \examples{ 56 | 57 | # From 5x1 ... 58 | x <- rray(1:5) 59 | 60 | # ...to 5x2 61 | rray_broadcast(x, c(5, 2)) 62 | 63 | # Internally, rray() uses broadcasting 64 | # for convenience so you could have also 65 | # done this with: 66 | rray(1:5, dim = c(5, 2)) 67 | 68 | # Moar dimensions 69 | rray_broadcast(x, c(5, 2, 3)) 70 | 71 | # You cannot broadcast down in dimensions 72 | try(rray_broadcast(x, 5)) 73 | 74 | } 75 | -------------------------------------------------------------------------------- /man/rray_clip.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/clip.R 3 | \name{rray_clip} 4 | \alias{rray_clip} 5 | \title{Bound the values of an array} 6 | \usage{ 7 | rray_clip(x, low, high) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array or rray.} 11 | 12 | \item{low}{A single value. The lower bound. \code{low} is cast to the 13 | inner type of \code{x}.} 14 | 15 | \item{high}{A single value. The upper bound. \code{high} is cast to the 16 | inner type of \code{x}.} 17 | } 18 | \value{ 19 | \code{x} bounded by \code{low} and \code{high}. 20 | } 21 | \description{ 22 | \code{rray_clip()} sets \emph{inclusive} lower and upper bounds on the values of \code{x}. 23 | } 24 | \examples{ 25 | 26 | # bound `x` between 1 and 5 27 | x <- matrix(1:10, ncol = 2) 28 | rray_clip(x, 1, 5) 29 | 30 | } 31 | -------------------------------------------------------------------------------- /man/rray_diag.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/diagonal.R 3 | \name{rray_diag} 4 | \alias{rray_diag} 5 | \title{Create a matrix with \code{x} on the diagonal} 6 | \usage{ 7 | rray_diag(x, offset = 0) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array or rray.} 11 | 12 | \item{offset}{A single integer specifying the offset from the diagonal to 13 | place \code{x}. This can be positive or negative.} 14 | } 15 | \value{ 16 | A matrix, with \code{x} on the diagonal. 17 | } 18 | \description{ 19 | \code{rray_diag()} creates a matrix filled with \code{x} on the diagonal. Use \code{offset} 20 | to place \code{x} along an offset from the diagonal. 21 | } 22 | \details{ 23 | No dimension names will be on the result. 24 | } 25 | \examples{ 26 | # Creates a diagonal matrix 27 | rray_diag(1:5) 28 | 29 | # Offset `1:5` by 1 30 | rray_diag(1:5, 1) 31 | 32 | # You can also go the other way 33 | rray_diag(1:5, -1) 34 | 35 | # Identity matrix 36 | rray_diag(rep(1, 5)) 37 | 38 | # One interesting use case of this is to create 39 | # a square empty matrix with dimensions (offset, offset) 40 | rray_diag(rray(integer()), 3) 41 | rray_diag(logical(), 3) 42 | 43 | } 44 | -------------------------------------------------------------------------------- /man/rray_dim.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dim.R 3 | \name{rray_dim} 4 | \alias{rray_dim} 5 | \alias{rray_dim_common} 6 | \title{Find common dimensions} 7 | \usage{ 8 | rray_dim(x) 9 | 10 | rray_dim_common(...) 11 | } 12 | \arguments{ 13 | \item{x}{An object.} 14 | 15 | \item{...}{Objects to find common dimensions for.} 16 | } 17 | \value{ 18 | An integer vector containing the common dimensions. 19 | } 20 | \description{ 21 | \itemize{ 22 | \item \code{rray_dim()} finds the dimension of a single object. 23 | \item \code{rray_dim_common()} finds the common dimensions of a set of objects. 24 | } 25 | } 26 | \details{ 27 | \code{rray_dim_common()} first finds the common dimensionality, 28 | makes any implicit dimensions explicit, then recycles the size of each 29 | dimension to a common size. 30 | 31 | As an example, the common dimensions of \verb{(4, 5)} and \verb{(4, 1, 2)} are:\preformatted{(4, 5, 1) <- implicit 1 is made to be explicit, then recycled to 2 32 | (4, 1, 2) <- the 1 in the second dimension here is recycled to 5 33 | --------- 34 | (4, 5, 2) <- resulting common dim 35 | } 36 | 37 | The resulting dimensions from \code{rray_dim_common()} are the dimensions that 38 | are used in broadcasted operations. 39 | } 40 | \examples{ 41 | x_1_by_4 <- rray(c(1, 2, 3, 4), c(1, 4)) 42 | x_5_by_1 <- rray(1:5, c(5, 1)) 43 | 44 | rray_dim(x_1_by_4) 45 | 46 | # recycle rows: 1 VS 5 = 5 47 | # recycle cols: 4 VS 1 = 4 48 | rray_dim_common(x_1_by_4, x_5_by_1) 49 | 50 | x_5_by_1_by_3 <- rray(1, c(5, 1, 3)) 51 | 52 | # recycle rows: 5 VS 1 = 5 53 | # recycle cols: 4 VS 1 = 4 54 | # recycle 3rd dim: 1 VS 3 = 3 55 | # (here, 3rd dim of 1 for the matrix is implicit) 56 | rray_dim_common(x_1_by_4, x_5_by_1_by_3) 57 | 58 | # The dimensions of NULL are 0 59 | rray_dim(NULL) 60 | 61 | } 62 | \seealso{ 63 | \code{\link[=rray_dim_n]{rray_dim_n()}} 64 | } 65 | -------------------------------------------------------------------------------- /man/rray_dim_n.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dim-n.R 3 | \name{rray_dim_n} 4 | \alias{rray_dim_n} 5 | \title{Compute the number of dimensions of an object} 6 | \usage{ 7 | rray_dim_n(x) 8 | } 9 | \arguments{ 10 | \item{x}{An object.} 11 | } 12 | \value{ 13 | An integer vector containing the number of dimensions of \code{x}. 14 | } 15 | \description{ 16 | \code{rray_dim_n()} computes the dimensionality (i.e. the number of dimensions). 17 | } 18 | \details{ 19 | One point worth mentioning is that \code{rray_dim_n()} is very strict. It does 20 | not simply call the generic function \code{dim()} and then check the length. 21 | Rather, it explicitly pulls the attribute for the \code{"dim"}, and checks 22 | the length of that. If an object does not have an attribute, then the 23 | dimensionality is 1. 24 | 25 | This means that data frames have a dimensionality of 1, even though 26 | \code{dim()} defines a method for data frames that would imply a dimensionality 27 | of 2. 28 | } 29 | \examples{ 30 | x_1_by_4 <- rray(c(1, 2, 3, 4), c(1, 4)) 31 | 32 | rray_dim_n(x_1_by_4) 33 | 34 | # NULL has a dimensionality of 1 35 | rray_dim_n(NULL) 36 | 37 | # The dimensionality of a data frame is 1 38 | rray_dim_n(data.frame()) 39 | 40 | } 41 | -------------------------------------------------------------------------------- /man/rray_dot.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dot.R 3 | \name{rray_dot} 4 | \alias{rray_dot} 5 | \title{Matrix multiplication} 6 | \usage{ 7 | rray_dot(x, y) 8 | } 9 | \arguments{ 10 | \item{x, y}{Arrays or rrays that are either 1D or 2D.} 11 | } 12 | \value{ 13 | The result of the matrix multiplication of \code{x} and \code{y}. See \code{\%*\%} for the 14 | exact details. The common type of \code{x} and \code{y} will be preserved. 15 | } 16 | \description{ 17 | \code{rray_dot()} works exactly like the base R function, \code{\%*\%}, but preserves 18 | the rray class where applicable. For the exact details of how 1D objects 19 | are promoted to 2D objects, see \link{\%*\%}. 20 | } 21 | \details{ 22 | Due to some peculiarities with how \code{\%*\%} dispatches with S3 objects, calling 23 | \code{\%*\%} directly with an rray will compute the matrix multiplication correctly, 24 | but the class will be lost. \code{rray_dot()} ensures that the rray class is 25 | maintained. 26 | } 27 | \examples{ 28 | rray_dot(1:5, 1:5) 29 | 30 | rray_dot(rray(1:5), 1:5) 31 | 32 | } 33 | -------------------------------------------------------------------------------- /man/rray_duplicate.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/duplicate.R 3 | \name{rray_duplicate} 4 | \alias{rray_duplicate} 5 | \alias{rray_duplicate_any} 6 | \alias{rray_duplicate_detect} 7 | \alias{rray_duplicate_id} 8 | \title{Find duplicated values in an array} 9 | \usage{ 10 | rray_duplicate_any(x, axes = NULL) 11 | 12 | rray_duplicate_detect(x, axes = NULL) 13 | 14 | rray_duplicate_id(x, axes = NULL) 15 | } 16 | \arguments{ 17 | \item{x}{A vector, matrix, array, or rray.} 18 | 19 | \item{axes}{An integer vector. The default of \code{NULL} looks for duplicates 20 | over all axes.} 21 | } 22 | \value{ 23 | See the description for return value details. 24 | } 25 | \description{ 26 | \itemize{ 27 | \item \code{rray_duplicate_any()}: returns a logical with the same shape and type 28 | as \code{x} except over the \code{axes}, which will be reduced to length 1. This 29 | function detects the presence of any duplicated values along the \code{axes}. 30 | \item \code{rray_duplicate_detect()}: returns a logical with the same shape and 31 | type as \code{x} describing if that element of \code{x} is duplicated elsewhere. 32 | \item \code{rray_duplicate_id()}: returns an integer with the same shape and 33 | type as \code{x} giving the location of the first occurrence of the value. 34 | } 35 | } 36 | \examples{ 37 | x <- rray(c(1, 1, 2, 2), c(2, 2)) 38 | x <- rray_set_row_names(x, c("r1", "r2")) 39 | x <- rray_set_col_names(x, c("c1", "c2")) 40 | 41 | # Are there duplicates along the rows? 42 | rray_duplicate_any(x, 1L) 43 | 44 | # Are there duplicates along the columns? 45 | rray_duplicate_any(x, 2L) 46 | 47 | # Create a 3d version of x 48 | # where the columns are not unique 49 | y <- rray_expand(x, 1) 50 | 51 | # Along the rows, all the values are unique... 52 | rray_duplicate_any(y, 1L) 53 | 54 | # ...but along the columns there are duplicates 55 | rray_duplicate_any(y, 2L) 56 | 57 | # --------------------------------------------------------------------------- 58 | 59 | z <- rray(c(1, 1, 2, 3, 1, 4, 5, 6), c(2, 2, 2)) 60 | 61 | # rray_duplicate_detect() looks for any 62 | # duplicates along the axes of interest 63 | # and returns `TRUE` wherever a duplicate is found 64 | # (including the first location) 65 | rray_duplicate_detect(z, 1) 66 | 67 | # Positions 1 and 5 are the same! 68 | rray_duplicate_detect(z, 3) 69 | 70 | # --------------------------------------------------------------------------- 71 | 72 | # rray_duplicate_id() returns the location 73 | # of the first occurance along each axis. 74 | # Compare to rray_duplicate_detect()! 75 | rray_duplicate_detect(z, 1) 76 | rray_duplicate_id(z, 1) 77 | 78 | } 79 | \seealso{ 80 | \code{\link[=rray_unique]{rray_unique()}} for functions that work with the dual of duplicated values: 81 | unique values. 82 | 83 | \code{\link[vctrs:vec_duplicate_any]{vctrs::vec_duplicate_any()}} for functions that detect duplicates among 84 | any type of vector object. 85 | } 86 | -------------------------------------------------------------------------------- /man/rray_elems.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rray.R 3 | \name{rray_elems} 4 | \alias{rray_elems} 5 | \title{Compute the number of elements in an array} 6 | \usage{ 7 | rray_elems(x) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array or rray.} 11 | } 12 | \value{ 13 | A single integer. The number of elements in \code{x}. 14 | } 15 | \description{ 16 | \code{rray_elems()} computes the number of individual elements in an array. It 17 | generally computes the same thing as \code{length()}, but has a more predictable 18 | name. 19 | } 20 | \examples{ 21 | rray_elems(1:5) 22 | 23 | rray_elems(matrix(1, 2, 2)) 24 | 25 | # It is different from `vec_size()`, 26 | # which only returns the number of 27 | # observations 28 | library(vctrs) 29 | vec_size(matrix(1, 2, 2)) 30 | 31 | } 32 | -------------------------------------------------------------------------------- /man/rray_expand.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/expand.R 3 | \name{rray_expand} 4 | \alias{rray_expand} 5 | \title{Insert a dimension into an rray} 6 | \usage{ 7 | rray_expand(x, axis) 8 | } 9 | \arguments{ 10 | \item{x}{An rray.} 11 | 12 | \item{axis}{An integer of size \code{1} specifying the location of the new 13 | dimension.} 14 | } 15 | \value{ 16 | \code{x} with a new dimension inserted at the \code{axis}. 17 | } 18 | \description{ 19 | \code{rray_expand()} inserts a new dimension at the \code{axis} dimension. This 20 | expands the number of dimensions of \code{x} by \code{1}. 21 | } 22 | \details{ 23 | Dimension names are kept through the insertion of the new dimension. 24 | } 25 | \examples{ 26 | 27 | x <- rray(1:10, c(5, 2)) 28 | x <- rray_set_row_names(x, letters[1:5]) 29 | x <- rray_set_col_names(x, c("c1", "c2")) 30 | 31 | # (5, 2) 32 | # Add dimension to the front 33 | # (1, 5, 2) = 1 row, 5 cols, 2 deep 34 | rray_expand(x, 1) 35 | 36 | # (5, 2) 37 | # Add dimension to the middle 38 | # (5, 1, 2) = 5 rows, 1 col, 2 deep 39 | rray_expand(x, 2) 40 | 41 | # (5, 2) 42 | # Add dimension to the end 43 | # (5, 2, 1) = 5 rows, 2 cols, 1 deep 44 | rray_expand(x, 3) 45 | 46 | # In some cases this is different than a simple 47 | # rray_reshape() because the dimension names 48 | # follow the original dimension position 49 | # - 5 row names follow to the new 5 column position 50 | # - 2 col names follow to the new 2 deep position 51 | # - result has no row names because that is the new axis 52 | rray_expand(x, 1) 53 | 54 | # A reshape, on the other hand, 55 | # drops all dimension names 56 | rray_reshape(x, c(1, 5, 2)) 57 | 58 | } 59 | -------------------------------------------------------------------------------- /man/rray_extract.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/extract-assign.R, R/extract.R 3 | \name{rray_extract<-} 4 | \alias{rray_extract<-} 5 | \alias{rray_extract_assign} 6 | \alias{rray_extract} 7 | \title{Get or set elements of an array by index} 8 | \usage{ 9 | rray_extract(x, ...) <- value 10 | 11 | rray_extract_assign(x, ..., value) 12 | 13 | rray_extract(x, ...) 14 | } 15 | \arguments{ 16 | \item{x}{A vector, matrix, array, or rray.} 17 | 18 | \item{...}{A specification of indices to extract. 19 | \itemize{ 20 | \item Integer-ish indices extract specific elements of dimensions. 21 | \item Logical indices must be length 1, or the length of the dimension you are 22 | subsetting over. 23 | \item Character indices are only allowed if \code{x} has names for the corresponding 24 | dimension. 25 | \item \code{NULL} is treated as \code{0}. 26 | }} 27 | 28 | \item{value}{The value to assign to the location specified by \code{...}. 29 | Before assignment, \code{value} is cast to the type and dimension of \code{x} after 30 | extracting elements with \code{...}.} 31 | } 32 | \value{ 33 | A 1D vector of elements extracted from \code{x}. 34 | } 35 | \description{ 36 | \code{rray_extract()} is the counterpart to \code{\link[=rray_yank]{rray_yank()}}. It extracts elements 37 | from an array \emph{by index}. It \emph{always} drops dimensions 38 | (unlike \code{\link[=rray_subset]{rray_subset()}}), and a 1D object is always returned. 39 | } 40 | \details{ 41 | Like \code{[[}, \code{rray_extract()} will \emph{never} keep dimension names. 42 | 43 | \code{rray_extract()} works with base R objects as well. 44 | 45 | \code{rray_extract()} is similar to the traditional behavior of 46 | \code{x[[i, j, ...]]}, but allows each subscript to have length >1. 47 | } 48 | \examples{ 49 | x <- rray(1:16, c(2, 4, 2), dim_names = list(c("r1", "r2"), NULL, NULL)) 50 | 51 | # Extract the first row and flatten it 52 | rray_extract(x, 1) 53 | 54 | # Extract the first row and first two columns 55 | rray_extract(x, 1, 1:2) 56 | 57 | # You can assign directly to these elements 58 | rray_extract(x, 1, 1:2) <- NA 59 | x 60 | 61 | } 62 | \seealso{ 63 | Other rray subsetters: 64 | \code{\link{rray_slice<-}()}, 65 | \code{\link{rray_subset<-}()}, 66 | \code{\link{rray_yank<-}()} 67 | } 68 | \concept{rray subsetters} 69 | -------------------------------------------------------------------------------- /man/rray_flatten.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/flatten.R 3 | \name{rray_flatten} 4 | \alias{rray_flatten} 5 | \title{Flatten an array} 6 | \usage{ 7 | rray_flatten(x) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array or rray.} 11 | } 12 | \value{ 13 | A 1D object with the same container type as \code{x}. 14 | } 15 | \description{ 16 | \code{rray_flatten()} squashes the dimensionality of \code{x} so that the result is a 17 | 1D object. 18 | } 19 | \details{ 20 | This function is similar to \code{as.vector()}, but keeps the class of the object 21 | and can keep the dimension names if applicable. 22 | 23 | Dimension names are kept using the same rules that would be applied if you 24 | would have called \code{rray_reshape(x, prod(rray_dim(x)))}. Essentially this 25 | means that names in the first dimension are kept if \code{x} is either already 26 | a 1D vector, or a higher dimensional object with 1's in all dimensions 27 | except for the first one. 28 | } 29 | \examples{ 30 | library(magrittr) 31 | 32 | x <- rray(1:10, c(5, 2)) 33 | 34 | rray_flatten(x) 35 | 36 | # Dimension names are kept here 37 | # (2) -> (2) 38 | y <- rray(1:2) \%>\% rray_set_axis_names(1, letters[1:2]) 39 | rray_flatten(y) 40 | 41 | # And they are kept here 42 | # (2, 1) -> (2) 43 | y_one_col <- rray_reshape(y, c(2, 1)) 44 | rray_flatten(y_one_col) 45 | 46 | # But not here, since the size of the first dim changes 47 | # (1, 2) -> (2) 48 | y_one_row <- t(y_one_col) 49 | rray_flatten(y_one_row) 50 | 51 | } 52 | -------------------------------------------------------------------------------- /man/rray_flip.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/flip.R 3 | \name{rray_flip} 4 | \alias{rray_flip} 5 | \title{Flip an rray along a dimension} 6 | \usage{ 7 | rray_flip(x, axis) 8 | } 9 | \arguments{ 10 | \item{x}{An rray.} 11 | 12 | \item{axis}{An integer of size \code{1} specifying the dimension to flip.} 13 | } 14 | \value{ 15 | \code{x} but with reversed elements along \code{axis}. 16 | } 17 | \description{ 18 | \code{rray_flip()} reverses the elements of an rray along a single dimension. 19 | } 20 | \details{ 21 | Dimension names are flipped as well. 22 | } 23 | \examples{ 24 | 25 | x <- rray(1:10, c(5, 2)) 26 | x <- rray_set_row_names(x, letters[1:5]) 27 | x <- rray_set_col_names(x, c("c1", "c2")) 28 | 29 | rray_flip(x, 1) 30 | 31 | rray_flip(x, 2) 32 | 33 | } 34 | -------------------------------------------------------------------------------- /man/rray_full_like.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/full-like.R 3 | \name{rray_full_like} 4 | \alias{rray_full_like} 5 | \alias{rray_ones_like} 6 | \alias{rray_zeros_like} 7 | \title{Create an array like \code{x}} 8 | \usage{ 9 | rray_full_like(x, value) 10 | 11 | rray_ones_like(x) 12 | 13 | rray_zeros_like(x) 14 | } 15 | \arguments{ 16 | \item{x}{A vector, matrix, array or rray.} 17 | 18 | \item{value}{A value coercible to the same \emph{inner} type as \code{x} that will be 19 | used to fill the result (If \code{x} is an integer matrix, then \code{value} will be 20 | coerced to an integer).} 21 | } 22 | \value{ 23 | An object with the same type as \code{x}, but filled with \code{value}. 24 | } 25 | \description{ 26 | \itemize{ 27 | \item \code{rray_full_like()} creates an array with the same type and size as \code{x}, but 28 | filled with \code{value}. 29 | \item \code{rray_ones_like()} is \code{rray_full_like()} with \code{value = 1}. 30 | \item \code{rray_zeros_like()} is \code{rray_full_like()} with \code{value = 0}. 31 | } 32 | } 33 | \details{ 34 | No dimension names will be on the result. 35 | } 36 | \examples{ 37 | 38 | x <- rray(1:10, c(5, 2)) 39 | 40 | # Same shape and type as x, but filled with 1 41 | rray_full_like(x, 1L) 42 | 43 | # `fill` is coerced to `x` if it can be 44 | rray_full_like(x, FALSE) 45 | 46 | # `value = 1` 47 | rray_ones_like(x) 48 | 49 | # When logicals are used, it is filled with TRUE 50 | rray_ones_like(c(FALSE, TRUE)) 51 | 52 | # `value = 0` 53 | rray_zeros_like(x) 54 | 55 | } 56 | -------------------------------------------------------------------------------- /man/rray_hypot.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/hypot.R 3 | \name{rray_hypot} 4 | \alias{rray_hypot} 5 | \title{Compute the square root of the sum of squares} 6 | \usage{ 7 | rray_hypot(x, y) 8 | } 9 | \arguments{ 10 | \item{x, y}{A vector, matrix, array or rray.} 11 | } 12 | \value{ 13 | An object of the common type of \code{x} and \code{y} containing the square root 14 | of the sum of squares. 15 | } 16 | \description{ 17 | \code{rray_hypot()} computes the elementwise square root of the sum 18 | of squares of \code{x} and \code{y}. 19 | } 20 | \examples{ 21 | x <- matrix(c(2, 4, 6)) 22 | 23 | # With broadcasting 24 | rray_hypot(x, t(x)) 25 | 26 | } 27 | -------------------------------------------------------------------------------- /man/rray_if_else.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/logical.R 3 | \name{rray_if_else} 4 | \alias{rray_if_else} 5 | \title{Conditional selection} 6 | \usage{ 7 | rray_if_else(condition, true, false) 8 | } 9 | \arguments{ 10 | \item{condition}{A logical vector, matrix, array of rray.} 11 | 12 | \item{true}{A vector, matrix, array, or rray. This is the value in the result 13 | when \code{condition} is \code{TRUE}.} 14 | 15 | \item{false}{A vector, matrix, array, or rray. This is the value in the 16 | result when \code{condition} is \code{FALSE}.} 17 | } 18 | \description{ 19 | \code{rray_if_else()} is like \code{ifelse()}, but works with matrices and arrays, 20 | and fully supports broadcasting between the three inputs. Before the 21 | operation is applied, \code{condition} is cast to a logical, and \code{true} and 22 | \code{false} are cast to their common type. 23 | } 24 | \details{ 25 | The dimension names of the output are taken as the common names of \code{true} 26 | and \code{false}. 27 | } 28 | \examples{ 29 | 30 | cond <- c(TRUE, FALSE) 31 | 32 | true <- array( 33 | 1:2, 34 | dimnames = list(c("r1", "r2")) 35 | ) 36 | 37 | false <- rray( 38 | c(3, 4, 5, 6), 39 | dim = c(2, 2), 40 | dim_names = list(c("rr1", "rr2"), c("c1", "c2")) 41 | ) 42 | 43 | # - All inputs are broadcast to a common 44 | # shape of (2, 2). 45 | # - The first row of the output comes from 46 | # `true`, the second row comes from `false`. 47 | # - The names come from both `true` and `false`. 48 | rray_if_else(cond, true, false) 49 | 50 | } 51 | -------------------------------------------------------------------------------- /man/rray_max.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reducers.R 3 | \name{rray_max} 4 | \alias{rray_max} 5 | \title{Calculate the maximum along an axis} 6 | \usage{ 7 | rray_max(x, axes = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, or array to reduce.} 11 | 12 | \item{axes}{An integer vector specifying the axes to reduce over. \code{1} reduces 13 | the number of rows to 1, performing the reduction along the way. \code{2} does the 14 | same, but with the columns, and so on for higher dimensions. The default 15 | reduces along all axes.} 16 | } 17 | \value{ 18 | The result of the reduction with the same shape as \code{x}, except 19 | along \code{axes}, which have been reduced to size 1. 20 | } 21 | \description{ 22 | \code{rray_max()} computes the maximum along a given axis or axes. The 23 | dimensionality of \code{x} is retained in the result. 24 | } 25 | \examples{ 26 | 27 | x <- rray(1:10, c(5, 2)) 28 | 29 | rray_max(x) 30 | 31 | rray_max(x, 1) 32 | 33 | rray_max(x, 2) 34 | 35 | } 36 | \seealso{ 37 | Other reducers: 38 | \code{\link{rray_mean}()}, 39 | \code{\link{rray_min}()}, 40 | \code{\link{rray_prod}()}, 41 | \code{\link{rray_sum}()} 42 | } 43 | \concept{reducers} 44 | -------------------------------------------------------------------------------- /man/rray_max_pos.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/max-pos.R 3 | \name{rray_max_pos} 4 | \alias{rray_max_pos} 5 | \title{Locate the position of the maximum value} 6 | \usage{ 7 | rray_max_pos(x, axis = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array, or rray.} 11 | 12 | \item{axis}{A single integer specifying the axis to compute along. \code{1} 13 | computes along rows, reducing the number of rows to 1. 14 | \code{2} does the same, but along columns, and so on for higher dimensions. 15 | The default of \code{NULL} first flattens \code{x} to 1-D.} 16 | } 17 | \value{ 18 | An integer object of the same type and shape as \code{x}, except along \code{axis}, 19 | which has been reduced to size 1. 20 | } 21 | \description{ 22 | \code{rray_max_pos()} returns the integer position of the maximum value over an 23 | axis. 24 | } 25 | \examples{ 26 | 27 | x <- rray(c(1:10, 20:11), dim = c(5, 2, 2)) 28 | 29 | # Find the max position over all of x 30 | rray_max_pos(x) 31 | 32 | # Compute along the rows 33 | rray_max_pos(x, 1) 34 | 35 | # Compute along the columns 36 | rray_max_pos(x, 2) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /man/rray_mean.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reducers.R 3 | \name{rray_mean} 4 | \alias{rray_mean} 5 | \title{Calculate the mean along an axis} 6 | \usage{ 7 | rray_mean(x, axes = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, or array to reduce.} 11 | 12 | \item{axes}{An integer vector specifying the axes to reduce over. \code{1} reduces 13 | the number of rows to 1, performing the reduction along the way. \code{2} does the 14 | same, but with the columns, and so on for higher dimensions. The default 15 | reduces along all axes.} 16 | } 17 | \value{ 18 | The result of the reduction as a double with the same shape as \code{x}, except 19 | along \code{axes}, which have been reduced to size 1. 20 | } 21 | \description{ 22 | \code{rray_mean()} computes the mean along a given axis or axes. The 23 | dimensionality of \code{x} is retained in the result. 24 | } 25 | \examples{ 26 | 27 | x <- rray(1:10, c(5, 2)) 28 | 29 | rray_mean(x) 30 | 31 | rray_mean(x, 1) 32 | 33 | rray_mean(x, 2) 34 | 35 | } 36 | \seealso{ 37 | Other reducers: 38 | \code{\link{rray_max}()}, 39 | \code{\link{rray_min}()}, 40 | \code{\link{rray_prod}()}, 41 | \code{\link{rray_sum}()} 42 | } 43 | \concept{reducers} 44 | -------------------------------------------------------------------------------- /man/rray_min.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reducers.R 3 | \name{rray_min} 4 | \alias{rray_min} 5 | \title{Calculate the minimum along an axis} 6 | \usage{ 7 | rray_min(x, axes = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, or array to reduce.} 11 | 12 | \item{axes}{An integer vector specifying the axes to reduce over. \code{1} reduces 13 | the number of rows to 1, performing the reduction along the way. \code{2} does the 14 | same, but with the columns, and so on for higher dimensions. The default 15 | reduces along all axes.} 16 | } 17 | \value{ 18 | The result of the reduction with the same shape as \code{x}, except 19 | along \code{axes}, which have been reduced to size 1. 20 | } 21 | \description{ 22 | \code{rray_min()} computes the minimum along a given axis or axes. The 23 | dimensionality of \code{x} is retained in the result. 24 | } 25 | \examples{ 26 | 27 | x <- rray(1:10, c(5, 2)) 28 | 29 | rray_min(x) 30 | 31 | rray_min(x, 1) 32 | 33 | rray_min(x, 2) 34 | 35 | } 36 | \seealso{ 37 | Other reducers: 38 | \code{\link{rray_max}()}, 39 | \code{\link{rray_mean}()}, 40 | \code{\link{rray_prod}()}, 41 | \code{\link{rray_sum}()} 42 | } 43 | \concept{reducers} 44 | -------------------------------------------------------------------------------- /man/rray_min_pos.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/min-pos.R 3 | \name{rray_min_pos} 4 | \alias{rray_min_pos} 5 | \title{Locate the position of the minimum value} 6 | \usage{ 7 | rray_min_pos(x, axis = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array, or rray.} 11 | 12 | \item{axis}{A single integer specifying the axis to compute along. \code{1} 13 | computes along rows, reducing the number of rows to 1. 14 | \code{2} does the same, but along columns, and so on for higher dimensions. 15 | The default of \code{NULL} first flattens \code{x} to 1-D.} 16 | } 17 | \value{ 18 | An integer object of the same type and shape as \code{x}, except along \code{axis}, 19 | which has been reduced to size 1. 20 | } 21 | \description{ 22 | \code{rray_min_pos()} returns the integer position of the minimum value over an 23 | axis. 24 | } 25 | \examples{ 26 | 27 | x <- rray(c(1:10, 20:11), dim = c(5, 2, 2)) 28 | 29 | # Flatten x, then find the position of the max value 30 | rray_min_pos(x) 31 | 32 | # Compute along the rows 33 | rray_min_pos(x, 1) 34 | 35 | # Compute along the columns 36 | rray_min_pos(x, 2) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /man/rray_multiply_add.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/multiply-add.R 3 | \name{rray_multiply_add} 4 | \alias{rray_multiply_add} 5 | \title{Fused multiply-add} 6 | \usage{ 7 | rray_multiply_add(x, y, z) 8 | } 9 | \arguments{ 10 | \item{x, y, z}{A vector, matrix, array or rray.} 11 | } 12 | \value{ 13 | An object of the common type of the inputs, containing the result of the 14 | multiply-add operation. 15 | } 16 | \description{ 17 | \code{rray_multiply_add()} computes \code{x * y + z}, with broadcasting. 18 | It is more efficient than simply doing those operations in sequence. 19 | } 20 | \examples{ 21 | rray_multiply_add(2, 3, 5) 22 | 23 | # Using broadcasting 24 | rray_multiply_add(matrix(1:5), matrix(1:2, nrow = 1L), 3L) 25 | 26 | # ^ Equivalent to: 27 | x <- matrix(rep(1:5, 2), ncol = 2) 28 | y <- matrix(rep(1:2, 5), byrow = TRUE, ncol = 2) 29 | z <- matrix(3L, nrow = 5, ncol = 2) 30 | x * y + z 31 | 32 | } 33 | -------------------------------------------------------------------------------- /man/rray_prod.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reducers.R 3 | \name{rray_prod} 4 | \alias{rray_prod} 5 | \title{Calculate the product along an axis} 6 | \usage{ 7 | rray_prod(x, axes = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, or array to reduce.} 11 | 12 | \item{axes}{An integer vector specifying the axes to reduce over. \code{1} reduces 13 | the number of rows to 1, performing the reduction along the way. \code{2} does the 14 | same, but with the columns, and so on for higher dimensions. The default 15 | reduces along all axes.} 16 | } 17 | \value{ 18 | The result of the reduction as a double with the same shape as \code{x}, except 19 | along \code{axes}, which have been reduced to size 1. 20 | } 21 | \description{ 22 | \code{rray_prod()} computes the product along a given axis or axes. The 23 | dimensionality of \code{x} is retained in the result. 24 | } 25 | \examples{ 26 | 27 | x <- rray(1:10, c(5, 2)) 28 | 29 | rray_prod(x) 30 | 31 | rray_prod(x, 1) 32 | 33 | rray_prod(x, 2) 34 | 35 | } 36 | \seealso{ 37 | Other reducers: 38 | \code{\link{rray_max}()}, 39 | \code{\link{rray_mean}()}, 40 | \code{\link{rray_min}()}, 41 | \code{\link{rray_sum}()} 42 | } 43 | \concept{reducers} 44 | -------------------------------------------------------------------------------- /man/rray_reshape.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reshape.R 3 | \name{rray_reshape} 4 | \alias{rray_reshape} 5 | \title{Reshape an array} 6 | \usage{ 7 | rray_reshape(x, dim) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array or rray.} 11 | 12 | \item{dim}{An integer vector. The dimension to reshape to.} 13 | } 14 | \value{ 15 | \code{x} reshaped to the new dimensions of \code{dim}. 16 | } 17 | \description{ 18 | \code{rray_reshape()} is similar to \verb{dim()<-}. It reshapes \code{x} in such a way 19 | that the dimensions are different, but the total size of the array is still 20 | the same (as measured by \code{\link[=rray_elems]{rray_elems()}}). 21 | } 22 | \examples{ 23 | 24 | x <- matrix(1:6, ncol = 1) 25 | 26 | # Reshape with the same dimensionality 27 | rray_reshape(x, c(2, 3)) 28 | 29 | # Change the dimensionality and the dimensions 30 | rray_reshape(x, c(3, 2, 1)) 31 | 32 | # You cannot reshape to a total size that is 33 | # different from the current size. 34 | try(rray_reshape(x, c(6, 2))) 35 | 36 | # Note that you can broadcast to these dimensions! 37 | rray_broadcast(x, c(6, 2)) 38 | 39 | } 40 | -------------------------------------------------------------------------------- /man/rray_slice.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/slice-assign.R, R/slice.R 3 | \name{rray_slice<-} 4 | \alias{rray_slice<-} 5 | \alias{rray_slice_assign} 6 | \alias{rray_slice} 7 | \title{Get or set a slice of an array} 8 | \usage{ 9 | rray_slice(x, i, axis) <- value 10 | 11 | rray_slice_assign(x, i, axis, value) 12 | 13 | rray_slice(x, i, axis) 14 | } 15 | \arguments{ 16 | \item{x}{A vector, matrix, array or rray.} 17 | 18 | \item{i}{Indices to extract along a single axis. 19 | \itemize{ 20 | \item Integer indices extract specific elements of the \code{axis} dimension. 21 | \item Logical indices must be length 1, or the length of the \code{axis} dimension. 22 | \item Character indices are only allowed if \code{x} has names for the \code{axis} dimension. 23 | \item \code{NULL} is treated as \code{0}. 24 | }} 25 | 26 | \item{axis}{An integer. The axis to subset along.} 27 | 28 | \item{value}{A value to be assigned to the location at 29 | \code{rray_slice(x, i, axis)}. It will be cast to the type and dimension 30 | of the slice of \code{x}.} 31 | } 32 | \value{ 33 | \code{x} with the \code{i} elements extracted from the \code{axis}. 34 | } 35 | \description{ 36 | \code{rray_slice()} is a shortcut wrapper around \code{\link[=rray_subset]{rray_subset()}} that is useful 37 | for easily subsetting along a single axis. 38 | } 39 | \details{ 40 | \code{rray_slice()} does exactly the same thing as \code{\link[=rray_subset]{rray_subset()}}, and is 41 | mainly helpful for higher dimensional objects, when you need to subset 42 | along, for example, only the 4th dimension. 43 | } 44 | \examples{ 45 | x <- rray(1:16, c(2, 2, 2, 2)) 46 | 47 | # Selecting the first column 48 | rray_slice(x, i = 1, axis = 2) 49 | 50 | # rray_slice() is particularly useful for 51 | # subsetting higher dimensions because you don't 52 | # have to worry about the commas 53 | rray_slice(x, i = 2, axis = 4) 54 | 55 | # Compare the above with the equivalent using `[` 56 | x[, , , 2] 57 | 58 | # `i` can be a character vector if `x` has names along `axis` 59 | x <- rray_set_axis_names(x, axis = 4, c("foo", "bar")) 60 | rray_slice(x, "bar", axis = 4) 61 | 62 | # The assignment variation can be useful 63 | # for assigning to higher dimensional elements 64 | rray_slice(x, 1, 3) <- matrix(c(99, 100), nrow = 1) 65 | 66 | } 67 | \seealso{ 68 | Other rray subsetters: 69 | \code{\link{rray_extract<-}()}, 70 | \code{\link{rray_subset<-}()}, 71 | \code{\link{rray_yank<-}()} 72 | } 73 | \concept{rray subsetters} 74 | -------------------------------------------------------------------------------- /man/rray_sort.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/sort.R 3 | \name{rray_sort} 4 | \alias{rray_sort} 5 | \title{Sort an array} 6 | \usage{ 7 | rray_sort(x, axis = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array, or rray.} 11 | 12 | \item{axis}{A single integer specifying the axis to compute along. \code{1} 13 | sorts along rows, \code{2} sorts along columns. The default of \code{NULL} first 14 | flattens \code{x} to 1-D, sorts, and then reconstructs the original dimensions.} 15 | } 16 | \value{ 17 | An object with the same dimensions as \code{x}, but sorted along \code{axis}. The 18 | dimension names will be lost along the axis you sort along. 19 | } 20 | \description{ 21 | \code{rray_sort()} returns an array with the same dimensions as \code{x}, but sorted 22 | along the specified axis. 23 | } 24 | \details{ 25 | Dimension names are lost along the axis that you sort along. If 26 | \code{axis = NULL}, then all dimension names are lost. In both cases, meta 27 | names are kept. The rationale for this is demonstrated in the examples. 28 | There, when you sort \code{y} along the rows, the rows in the first column change 29 | position, but the rows in the second column do not, so there is no rational 30 | order that the row names can be placed in. 31 | } 32 | \examples{ 33 | x <- rray(c(20:11, 1:10), dim = c(5, 2, 2)) 34 | 35 | # Flatten, sort, then reconstruct the shape 36 | rray_sort(x) 37 | 38 | # Sort, looking along the rows 39 | rray_sort(x, 1) 40 | 41 | # Sort, looking along the columns 42 | rray_sort(x, 2) 43 | 44 | # Sort, looking along the third dimension 45 | # This switches the 20 with the 1, the 46 | # 19 with the 2, and so on 47 | rray_sort(x, 3) 48 | 49 | # --------------------------------------------------------------------------- 50 | # Dimension names 51 | 52 | y <- rray( 53 | c(2, 1, 1, 2), 54 | dim = c(2, 2), 55 | dim_names = list( 56 | r = c("r1", "r2"), 57 | c = c("c1", "c2") 58 | ) 59 | ) 60 | 61 | # Dimension names are dropped along the axis you sort along 62 | rray_sort(y, 1) 63 | rray_sort(y, 2) 64 | 65 | # All dimension names are dropped if `axis = NULL` 66 | rray_sort(y) 67 | 68 | } 69 | -------------------------------------------------------------------------------- /man/rray_split.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/split.R 3 | \name{rray_split} 4 | \alias{rray_split} 5 | \title{Split an array along axes} 6 | \usage{ 7 | rray_split(x, axes = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array, or rray.} 11 | 12 | \item{axes}{An integer vector. The axes to split on. The default splits 13 | along all axes.} 14 | } 15 | \value{ 16 | A list of sub arrays of type \code{x}. 17 | } 18 | \description{ 19 | \code{rray_split()} splits \code{x} into equal pieces, splitting along the \code{axes}. 20 | } 21 | \details{ 22 | \code{rray_split()} works by splitting along the \code{axes}. The result is a list 23 | of sub arrays, where the \code{axes} of each sub array have been reduced to 24 | length 1. This is consistent with how reducers like \code{\link[=rray_sum]{rray_sum()}} work. As 25 | an example, splitting a \verb{(2, 3, 5)} array along \code{axes = c(2, 3)} would 26 | result in a list of 15 (from \code{3 * 5}) sub arrays, each with 27 | shape \verb{(2, 1, 1)}. 28 | } 29 | \examples{ 30 | 31 | x <- matrix(1:8, ncol = 2) 32 | 33 | # Split the rows 34 | # (4, 2) -> (1, 2) 35 | rray_split(x, 1) 36 | 37 | # Split the columns 38 | # (4, 2) -> (4, 1) 39 | rray_split(x, 2) 40 | 41 | # Split along multiple dimensions 42 | # (4, 2) -> (1, 1) 43 | rray_split(x, c(1, 2)) 44 | 45 | # The above split is the default behavior 46 | rray_split(x) 47 | 48 | # You can technically split with a size 0 `axes` 49 | # argument, which essentially requests no axes 50 | # to be split and is the same as `list(x)` 51 | rray_split(x, axes = integer(0)) 52 | 53 | # --------------------------------------------------------------------------- 54 | # 4 dimensional example 55 | 56 | x_4d <- rray( 57 | x = 1:16, 58 | dim = c(2, 2, 2, 2), 59 | dim_names = list( 60 | c("r1", "r2"), 61 | c("c1", "c2"), 62 | c("d1", "d2"), 63 | c("e1", "e2") 64 | ) 65 | ) 66 | 67 | # Split along the 1st dimension (rows) 68 | # (2, 2, 2, 2) -> (1, 2, 2, 2) 69 | rray_split(x_4d, 1) 70 | 71 | # Split along columns 72 | # (2, 2, 2, 2) -> (2, 1, 2, 2) 73 | rray_split(x_4d, 2) 74 | 75 | # Probably the most useful thing you might do 76 | # is use this to split the 4D array into a set 77 | # of 4 2D matrices. 78 | rray_split(x_4d, c(3, 4)) 79 | 80 | } 81 | -------------------------------------------------------------------------------- /man/rray_squeeze.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/squeeze.R 3 | \name{rray_squeeze} 4 | \alias{rray_squeeze} 5 | \title{Squeeze an rray} 6 | \usage{ 7 | rray_squeeze(x, axes = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array or rray.} 11 | 12 | \item{axes}{An integer vector specifying the size 1 dimensions to drop. If 13 | \code{NULL}, all size 1 dimensions are dropped.} 14 | } 15 | \value{ 16 | \code{x} with the \code{axes} dropped, if possible. 17 | } 18 | \description{ 19 | \code{rray_squeeze()} is conceptually similar to \code{\link[base:drop]{base::drop()}}, but it allows 20 | for the specification of specific dimensions to squeeze. 21 | } 22 | \details{ 23 | The dimension name handling of \code{rray_squeeze()} is essentially identical to 24 | \code{drop()}, but some explanation is always helpful: 25 | \itemize{ 26 | \item Dimension names are removed from the axes that are squeezed. So squeezing 27 | a \verb{(2, 1, 2)} object results in a \verb{(2, 2)} object using the dimension names 28 | from the original first and third dimensions. 29 | \item When all dimensions are squeezed, as in the case of \verb{(1, 1, 1)}, then 30 | the first dimension names that are found are the ones that are used in the 31 | \code{(1)} result. 32 | } 33 | } 34 | \examples{ 35 | # (10, 1) -> (10) 36 | x <- rray(1:10, c(10, 1)) 37 | rray_squeeze(x) 38 | 39 | # Multiple squeezed dimensions 40 | # (10, 1, 1) -> (10) 41 | y <- rray_reshape(x, c(10, 1, 1)) 42 | rray_squeeze(y) 43 | 44 | # Use `axes` to specify dimensions to drop 45 | # (10, 1, 1) -> drop 2 -> (10, 1) 46 | rray_squeeze(y, axes = 2) 47 | 48 | # Dimension names are kept here 49 | # (10, 1) -> (10) 50 | x <- rray_set_row_names(x, letters[1:10]) 51 | rray_squeeze(x) 52 | 53 | # And they are kept here 54 | # (1, 10) -> (10) 55 | rray_squeeze(t(x)) 56 | 57 | } 58 | -------------------------------------------------------------------------------- /man/rray_sum.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/reducers.R 3 | \name{rray_sum} 4 | \alias{rray_sum} 5 | \title{Calculate the sum along an axis} 6 | \usage{ 7 | rray_sum(x, axes = NULL) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, or array to reduce.} 11 | 12 | \item{axes}{An integer vector specifying the axes to reduce over. \code{1} reduces 13 | the number of rows to 1, performing the reduction along the way. \code{2} does the 14 | same, but with the columns, and so on for higher dimensions. The default 15 | reduces along all axes.} 16 | } 17 | \value{ 18 | The result of the reduction as a double with the same shape as \code{x}, except 19 | along \code{axes}, which have been reduced to size 1. 20 | } 21 | \description{ 22 | \code{rray_sum()} computes the sum along a given axis or axes. The dimensionality 23 | of \code{x} is retained in the result. 24 | } 25 | \examples{ 26 | 27 | x <- rray(1:10, c(5, 2)) 28 | 29 | # Reduce the number of rows to 1, 30 | # summing along the way 31 | rray_sum(x, 1) 32 | 33 | # Reduce the number of columns to 1, 34 | # summing along the way 35 | rray_sum(x, 2) 36 | 37 | # Reduce along all axes, but keep dimensions 38 | rray_sum(x) 39 | 40 | # Column-wise proportions 41 | x / rray_sum(x, 1) 42 | 43 | # Row-wise proportions 44 | x / rray_sum(x, 2) 45 | 46 | # Reducing over multiple axes 47 | # This reduces over the rows and columns 48 | # of each mini-matrix in the 3rd dimension 49 | y <- rray(1:24, c(2, 3, 4)) 50 | rray_sum(y, c(1, 2)) 51 | 52 | } 53 | \seealso{ 54 | Other reducers: 55 | \code{\link{rray_max}()}, 56 | \code{\link{rray_mean}()}, 57 | \code{\link{rray_min}()}, 58 | \code{\link{rray_prod}()} 59 | } 60 | \concept{reducers} 61 | -------------------------------------------------------------------------------- /man/rray_tile.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/tile.R 3 | \name{rray_tile} 4 | \alias{rray_tile} 5 | \title{Tile an array} 6 | \usage{ 7 | rray_tile(x, times) 8 | } 9 | \arguments{ 10 | \item{x}{A vector, matrix, array or rray.} 11 | 12 | \item{times}{An integer vector. The number of times to repeat the 13 | array along an axis.} 14 | } 15 | \value{ 16 | \code{x} with dimensions repeated as described by \code{times}. 17 | } 18 | \description{ 19 | Tile an array 20 | } 21 | \details{ 22 | \code{rray_tile()} should not be used as a replacement for \code{rray_broadcast()}, 23 | as it is generally less efficient. 24 | } 25 | \examples{ 26 | 27 | x <- matrix(1:5) 28 | 29 | # Repeat the rows twice 30 | rray_tile(x, 2) 31 | 32 | # Repeat the rows twice and the columns three times 33 | rray_tile(x, c(2, 3)) 34 | 35 | # Tile into a third dimension 36 | rray_tile(x, c(1, 2, 2)) 37 | 38 | } 39 | -------------------------------------------------------------------------------- /man/rray_transpose.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/transpose.R 3 | \name{rray_transpose} 4 | \alias{rray_transpose} 5 | \alias{t.vctrs_rray} 6 | \title{Transpose an array} 7 | \usage{ 8 | rray_transpose(x, permutation = NULL) 9 | 10 | \method{t}{vctrs_rray}(x) 11 | } 12 | \arguments{ 13 | \item{x}{A vector, matrix, array, or rray.} 14 | 15 | \item{permutation}{This should be some permutation of \code{1:n} with \code{n} 16 | being the number of dimensions of \code{x}. If \code{NULL}, the reverse of \code{1:n} is 17 | used, which is the normal transpose.} 18 | } 19 | \value{ 20 | \code{x} transposed along the axes defined by the \code{permutation}. 21 | } 22 | \description{ 23 | \code{rray_transpose()} transposes \code{x} along axes defined by \code{permutation}. By 24 | default, a standard transpose is performed, which is equivalent to 25 | permuting along the reversed dimensions of \code{x}. 26 | } 27 | \details{ 28 | Unlike \code{t()}, using \code{rray_transpose()} on a vector does not transpose it, 29 | as it is a 1D object, and the consistent result of transposing a 30 | 1D object is itself. 31 | 32 | \code{t.vctrs_rray()} uses the base R's \code{t()} behavior to be consistent with 33 | user expectations about transposing 1D objects. 34 | 35 | There is an \code{aperm()} method for \code{rray} objects as well. Unlike base R, 36 | it currently does not accept character strings for \code{perm}. 37 | } 38 | \examples{ 39 | 40 | x <- rray( 41 | 1:6, 42 | c(3, 2), 43 | dim_names = list(rows = c("r1", "r2", "r3"), cols = c("c1", "c2")) 44 | ) 45 | 46 | # A standard transpose 47 | rray_transpose(x) 48 | 49 | # Identical to 50 | rray_transpose(x, rev(1:2)) 51 | 52 | x_3d <- rray_broadcast(x, c(3, 2, 2)) 53 | 54 | # transpose here is like setting 55 | # `permutation = c(3, 2, 1)` 56 | # so the result should change _shape_ like: 57 | # (3, 2, 2) -> (2, 2, 3) 58 | rray_transpose(x_3d) 59 | 60 | # This transposes the "inner" matrices 61 | # (flips the first and second dimension) 62 | # and leaves the 3rd dimension alone 63 | rray_transpose(x_3d, c(2, 1, 3)) 64 | 65 | # --------------------------------------------------------------------------- 66 | # Difference from base R 67 | 68 | # Coerces 1:5 into a 2D matrix, then transposes 69 | t(1:5) 70 | 71 | # Leaves it as a 1D array and does nothing 72 | rray_transpose(1:5) 73 | 74 | # t.vctrs_rray() has the same behavior 75 | # as base R 76 | t(rray(1:5)) 77 | 78 | } 79 | -------------------------------------------------------------------------------- /man/vctrs-compat.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/compat-vctrs-arith.R, R/compat-vctrs.R 3 | \name{vec_arith.vctrs_rray} 4 | \alias{vec_arith.vctrs_rray} 5 | \alias{vctrs-compat} 6 | \alias{vec_ptype2.vctrs_rray_dbl} 7 | \alias{vec_ptype2.vctrs_rray_int} 8 | \alias{vec_ptype2.vctrs_rray_lgl} 9 | \alias{vec_cast.vctrs_rray_int} 10 | \alias{vec_cast.vctrs_rray_dbl} 11 | \alias{vec_cast.vctrs_rray_lgl} 12 | \title{vctrs compatibility functions} 13 | \usage{ 14 | \method{vec_arith}{vctrs_rray}(op, x, y) 15 | 16 | \method{vec_ptype2}{vctrs_rray_dbl}(x, y, ...) 17 | 18 | \method{vec_ptype2}{vctrs_rray_int}(x, y, ...) 19 | 20 | \method{vec_ptype2}{vctrs_rray_lgl}(x, y, ...) 21 | 22 | \method{vec_cast}{vctrs_rray_int}(x, to, ...) 23 | 24 | \method{vec_cast}{vctrs_rray_dbl}(x, to, ...) 25 | 26 | \method{vec_cast}{vctrs_rray_lgl}(x, to, ...) 27 | } 28 | \arguments{ 29 | \item{op}{An arithmetic operator as a string.} 30 | 31 | \item{x, y}{Objects.} 32 | 33 | \item{...}{Used to pass along error message information.} 34 | 35 | \item{to}{Type to cast to.} 36 | } 37 | \value{ 38 | See the corresponding vctrs function for the exact return value. 39 | } 40 | \description{ 41 | These functions are the extensions that allow rray objects to 42 | work with vctrs. 43 | } 44 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/r-lib/rray/467ed4bc80d1caeae4024224e511ba886dd7ca31/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /rray.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | *.dll 4 | -------------------------------------------------------------------------------- /src/Makevars: -------------------------------------------------------------------------------- 1 | ## -*- mode: makefile; -*- 2 | 3 | PKG_CXXFLAGS = -I../inst/include -DRCPP_DEFAULT_INCLUDE_CALL=false -DRCPP_NO_MODULES 4 | CXX_STD = CXX14 5 | -------------------------------------------------------------------------------- /src/Makevars.win: -------------------------------------------------------------------------------- 1 | ## -*- mode: makefile; -*- 2 | 3 | PKG_CXXFLAGS = -I../inst/include -DRCPP_DEFAULT_INCLUDE_CALL=false -DRCPP_NO_MODULES 4 | CXX_STD = CXX14 5 | -------------------------------------------------------------------------------- /src/accumulators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Both required for cumsum() / cumprod() 5 | #include 6 | #include 7 | 8 | // ----------------------------------------------------------------------------- 9 | 10 | // BLOCKED until 11 | // https://github.com/QuantStack/xtensor/issues/1334 12 | 13 | // TODO - detect integer overflow, maybe have to write a custom accumulator? 14 | // https://github.com/wch/r-source/blob/5a156a0865362bb8381dcd69ac335f5174a4f60c/src/main/cum.c#L40 15 | // https://github.com/QuantStack/xtensor/blob/94931618b695dbbae9155637dd7a43c8e64121f4/include/xtensor/xmath.hpp#L2042 16 | 17 | // TODO - convert logicals to integers 18 | 19 | // To prevent overflow, return doubles 20 | 21 | // template 22 | // xt::rarray rray__cumsum_impl(const xt::rarray& x, 23 | // Rcpp::RObject axis) { 24 | // 25 | // if (r_is_null(axis)) { 26 | // xt::rarray res = xt::cumsum(x); 27 | // return res; 28 | // } 29 | // 30 | // std::ptrdiff_t xt_axis = Rcpp::as(axis); 31 | // xt::rarray res = xt::cumsum(x, xt_axis); 32 | // 33 | // return res; 34 | // } 35 | // 36 | // // [[Rcpp::export(rng = false)]] 37 | // Rcpp::RObject rray__cumsum(Rcpp::RObject x, Rcpp::RObject axis) { 38 | // DISPATCH_UNARY_ONE(rray__cumsum_impl, x, axis); 39 | // } 40 | 41 | // ----------------------------------------------------------------------------- 42 | 43 | // BLOCKED until 44 | // https://github.com/QuantStack/xtensor/issues/1334 45 | 46 | // template 47 | // xt::rarray rray__cumprod_impl(const xt::rarray& x, 48 | // Rcpp::RObject axis) { 49 | // 50 | // if (r_is_null(axis)) { 51 | // xt::rarray res = xt::cumprod(x); 52 | // return res; 53 | // } 54 | // 55 | // std::ptrdiff_t xt_axis = Rcpp::as(axis); 56 | // xt::rarray res = xt::cumprod(x, xt_axis); 57 | // return res; 58 | // } 59 | // 60 | // // [[Rcpp::export(rng = false)]] 61 | // Rcpp::RObject rray__cumprod(Rcpp::RObject x, Rcpp::RObject axis) { 62 | // DISPATCH_UNARY_ONE(rray__cumprod_impl, x, axis); 63 | // } 64 | 65 | // ----------------------------------------------------------------------------- 66 | -------------------------------------------------------------------------------- /src/broadcast.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | template 5 | Rcpp::RObject rray__broadcast_impl(const xt::rarray& x, 6 | Rcpp::IntegerVector dim) { 7 | 8 | using vec_size_t = typename std::vector; 9 | const vec_size_t& dim_vec = Rcpp::as(dim); 10 | 11 | int dim_n = dim.size(); 12 | 13 | auto x_view = rray__increase_dims_view(x, dim_n); 14 | 15 | xt::rarray out = xt::broadcast(x_view, dim_vec); 16 | 17 | return SEXP(out); 18 | } 19 | 20 | // [[Rcpp::export(rng = false)]] 21 | Rcpp::RObject rray__broadcast(Rcpp::RObject x, Rcpp::IntegerVector dim) { 22 | 23 | if (r_is_null(x)) { 24 | return x; 25 | } 26 | 27 | Rcpp::IntegerVector x_dim = rray__dim(x); 28 | 29 | // Cheap early exit 30 | if (r_identical(x_dim, dim)) { 31 | return x; 32 | } 33 | 34 | rray__validate_broadcastable_to_dim(x_dim, dim); 35 | 36 | Rcpp::RObject out; 37 | DISPATCH_UNARY_ONE(out, rray__broadcast_impl, x, dim); 38 | 39 | rray__resize_and_set_dim_names(out, x); 40 | 41 | return out; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/cast.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | SEXP fns_vec_cast_inner = NULL; 5 | 6 | SEXP vec__cast_inner(SEXP x, SEXP to) { 7 | SEXP env = PROTECT(r_new_environment(rray_ns_env, 2)); 8 | 9 | Rf_defineVar(syms_x, x, env); 10 | Rf_defineVar(syms_to, to, env); 11 | 12 | SEXP call = PROTECT(Rf_lang3(fns_vec_cast_inner, syms_x, syms_to)); 13 | 14 | SEXP res = PROTECT(Rf_eval(call, env)); 15 | 16 | UNPROTECT(3); 17 | return res; 18 | } 19 | 20 | void rray_init_cast(SEXP ns) { 21 | fns_vec_cast_inner = Rf_install("vec_cast_inner"); 22 | } 23 | -------------------------------------------------------------------------------- /src/clip.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Enforced that low/high are the same inner type as `x`, but they are scalar values 7 | 8 | template 9 | xt::rarray rray__clip_impl(const xt::rarray& x, 10 | Rcpp::RObject low, 11 | Rcpp::RObject high) { 12 | 13 | int x_type = TYPEOF(SEXP(x)); 14 | 15 | if (x_type == REALSXP) { 16 | double xt_low = Rcpp::as(low); 17 | double xt_high = Rcpp::as(high); 18 | 19 | return xt::clip(x, xt_low, xt_high); 20 | } 21 | else if (x_type == INTSXP) { 22 | int xt_low = Rcpp::as(low); 23 | int xt_high = Rcpp::as(high); 24 | 25 | return xt::clip(x, xt_low, xt_high); 26 | } 27 | else if (x_type == LGLSXP) { 28 | bool xt_low = Rcpp::as(low); 29 | bool xt_high = Rcpp::as(high); 30 | 31 | return xt::clip(x, xt_low, xt_high); 32 | } 33 | 34 | // Should never get called 35 | error_unknown_type(); 36 | } 37 | 38 | // [[Rcpp::export(rng = false)]] 39 | Rcpp::RObject rray__clip(Rcpp::RObject x, Rcpp::RObject low, Rcpp::RObject high) { 40 | 41 | if (r_is_null(x)) { 42 | return x; 43 | } 44 | 45 | Rcpp::RObject out; 46 | DISPATCH_UNARY_TWO(out, rray__clip_impl, x, low, high); 47 | rray__set_dim_names(out, rray__dim_names(x)); 48 | return out; 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/dim-names.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // ----------------------------------------------------------------------------- 5 | 6 | // [[Rcpp::export(rng = false)]] 7 | Rcpp::List rray__new_empty_dim_names(int n) { 8 | return Rcpp::List(n); 9 | } 10 | 11 | // ----------------------------------------------------------------------------- 12 | 13 | // [[Rcpp::export(rng = false)]] 14 | Rcpp::List rray__dim_names(const Rcpp::RObject& x) { 15 | 16 | Rcpp::RObject x_dim_names; 17 | 18 | if (rray__has_dim(x)) { 19 | x_dim_names = x.attr("dimnames"); 20 | 21 | if (x_dim_names.isNULL()) { 22 | x_dim_names = rray__new_empty_dim_names(rray__dim_n(x)); 23 | } 24 | } 25 | else { 26 | x_dim_names = x.attr("names"); 27 | 28 | if (x_dim_names.isNULL()) { 29 | x_dim_names = rray__new_empty_dim_names(rray__dim_n(x)); 30 | } 31 | else { 32 | // character vector -> list 33 | x_dim_names = Rcpp::List::create(x_dim_names); 34 | } 35 | } 36 | 37 | return Rcpp::as(x_dim_names); 38 | } 39 | 40 | // ----------------------------------------------------------------------------- 41 | -------------------------------------------------------------------------------- /src/extract-assign.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Required for the assignment step 7 | #include 8 | 9 | // Required for xt::flatten() 10 | #include 11 | 12 | // Faster assignment 13 | #include 14 | 15 | template 16 | Rcpp::RObject rray__extract_assign_impl(const xt::rarray& x, 17 | Rcpp::List indexer, 18 | Rcpp::RObject value_) { 19 | 20 | // Copy `x` to get the output container 21 | xt::rarray out = x; 22 | xt::rarray value(value_); 23 | 24 | if (is_stridable(indexer)) { 25 | xt::xstrided_slice_vector sv = build_strided_slice_vector(indexer); 26 | auto xt_out_subset_view = xt::strided_view(out, sv); 27 | auto xt_out_extract_view = xt::flatten(xt_out_subset_view); 28 | rray__validate_broadcastable_to(value, xt_out_extract_view); 29 | xt::noalias(xt_out_extract_view) = value; 30 | } 31 | else { 32 | xt::xdynamic_slice_vector sv = build_dynamic_slice_vector(indexer); 33 | auto xt_out_subset_view = xt::dynamic_view(out, sv); 34 | auto xt_out_extract_view = xt::flatten(xt_out_subset_view); 35 | rray__validate_broadcastable_to(value, xt_out_extract_view); 36 | xt::noalias(xt_out_extract_view) = value; 37 | } 38 | 39 | return Rcpp::as(out); 40 | } 41 | 42 | // [[Rcpp::export(rng = false)]] 43 | Rcpp::RObject rray__extract_assign(Rcpp::RObject x, 44 | Rcpp::List indexer, 45 | Rcpp::RObject value) { 46 | Rcpp::RObject out; 47 | DISPATCH_UNARY_TWO(out, rray__extract_assign_impl, x, indexer, value); 48 | 49 | rray__set_dim_names(out, rray__dim_names(x)); 50 | 51 | return out; 52 | } 53 | -------------------------------------------------------------------------------- /src/extract.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // Used in rray__extract_impl() 5 | #include 6 | 7 | // Required for xt::flatten() which uses an xtensor_adaptor() 8 | #include 9 | 10 | template 11 | Rcpp::RObject rray__extract_impl(const xt::rarray& x, Rcpp::List indexer) { 12 | 13 | xt::rarray out; 14 | 15 | if (is_stridable(indexer)) { 16 | auto x_view = xt::strided_view(x, build_strided_slice_vector(indexer)); 17 | xt::noalias(out) = xt::flatten(x_view); 18 | } 19 | else { 20 | auto x_view = xt::dynamic_view(x, build_dynamic_slice_vector(indexer)); 21 | xt::noalias(out) = xt::flatten(x_view); 22 | } 23 | 24 | return Rcpp::as(out); 25 | } 26 | 27 | // [[Rcpp::export(rng = false)]] 28 | Rcpp::RObject rray__extract(Rcpp::RObject x, Rcpp::List indexer) { 29 | Rcpp::RObject out; 30 | DISPATCH_UNARY_ONE(out, rray__extract_impl, x, indexer); 31 | rray__set_dim_names(out, rray__new_empty_dim_names(1)); 32 | return out; 33 | } 34 | -------------------------------------------------------------------------------- /src/extremum.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // ----------------------------------------------------------------------------- 7 | 8 | template 9 | xt::rarray rray__maximum_impl(const xt::rarray& x, 10 | const xt::rarray& y) { 11 | 12 | auto views = rray__increase_dims_view2(x, y); 13 | auto x_view = std::get<0>(views); 14 | auto y_view = std::get<1>(views); 15 | 16 | return xt::maximum(x_view, y_view); 17 | } 18 | 19 | // [[Rcpp::export(rng = false)]] 20 | Rcpp::RObject rray__maximum(Rcpp::RObject x, Rcpp::RObject y) { 21 | DISPATCH_BINARY_MATH(rray__maximum_impl, x, y); 22 | } 23 | 24 | // ----------------------------------------------------------------------------- 25 | 26 | template 27 | xt::rarray rray__minimum_impl(const xt::rarray& x, 28 | const xt::rarray& y) { 29 | 30 | auto views = rray__increase_dims_view2(x, y); 31 | auto x_view = std::get<0>(views); 32 | auto y_view = std::get<1>(views); 33 | 34 | return xt::minimum(x_view, y_view); 35 | } 36 | 37 | // [[Rcpp::export(rng = false)]] 38 | Rcpp::RObject rray__minimum(Rcpp::RObject x, Rcpp::RObject y) { 39 | DISPATCH_BINARY_MATH(rray__minimum_impl, x, y); 40 | } 41 | -------------------------------------------------------------------------------- /src/generators.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // ----------------------------------------------------------------------------- 5 | 6 | // rray__reshape_dim_names() is essentially rray__resize_dim_names(), but 7 | // it rather than leaving the meta names in place no matter what, it removes 8 | // them if the axis size changes. This is appropriate for a reshape. 9 | 10 | Rcpp::List rray__reshape_dim_names(const Rcpp::List& dim_names, 11 | const Rcpp::IntegerVector& dim, 12 | const Rcpp::IntegerVector& new_dim) { 13 | 14 | Rcpp::List new_dim_names = rray__resize_dim_names(dim_names, new_dim); 15 | 16 | if (r_is_null(new_dim_names.names())) { 17 | return new_dim_names; 18 | } 19 | 20 | const R_xlen_t n = new_dim.size(); 21 | const R_xlen_t n_iter = std::min(n, dim.size()); 22 | Rcpp::CharacterVector new_meta_names(n); 23 | Rcpp::CharacterVector old_meta_names = new_dim_names.names(); 24 | 25 | // Remove meta names if the `dim` changed 26 | for (R_xlen_t i = 0; i < n_iter; ++i) { 27 | if (dim[i] == new_dim[i]) { 28 | new_meta_names[i] = old_meta_names[i]; 29 | } 30 | } 31 | 32 | new_dim_names.names() = new_meta_names; 33 | 34 | return new_dim_names; 35 | } 36 | 37 | template 38 | xt::rarray rray__reshape_impl(const xt::rarray& x, 39 | const Rcpp::IntegerVector& dim) { 40 | 41 | using vec_size_t = typename std::vector; 42 | const vec_size_t& xt_dim = Rcpp::as(dim); 43 | 44 | xt::rarray out = xt::reshape_view(x, xt_dim); 45 | 46 | return out; 47 | } 48 | 49 | // [[Rcpp::export(rng = false)]] 50 | Rcpp::RObject rray__reshape(Rcpp::RObject x, const Rcpp::IntegerVector& dim) { 51 | 52 | if (r_is_null(x)) { 53 | return x; 54 | } 55 | 56 | // Early exit, no reshape needed (no copy made) 57 | const Rcpp::IntegerVector& x_dim = rray__dim(x); 58 | if (r_identical(x_dim, dim)) { 59 | return x; 60 | } 61 | 62 | rray__validate_reshape(x, dim); 63 | 64 | Rcpp::RObject out; 65 | DISPATCH_UNARY_ONE(out, rray__reshape_impl, x, dim); 66 | 67 | // Potentially going down in dimensionality, but this is fine 68 | Rcpp::List new_dim_names = rray__reshape_dim_names(rray__dim_names(x), x_dim, dim); 69 | rray__set_dim_names(out, new_dim_names); 70 | 71 | return out; 72 | } 73 | 74 | // ----------------------------------------------------------------------------- 75 | -------------------------------------------------------------------------------- /src/hypot.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // ----------------------------------------------------------------------------- 7 | 8 | template 9 | xt::rarray rray__hypot_impl(const xt::rarray& x, 10 | const xt::rarray& y) { 11 | 12 | auto views = rray__increase_dims_view2(x, y); 13 | auto x_view = std::get<0>(views); 14 | auto y_view = std::get<1>(views); 15 | 16 | return xt::hypot(x_view, y_view); 17 | } 18 | 19 | // [[Rcpp::export(rng = false)]] 20 | Rcpp::RObject rray__hypot(Rcpp::RObject x, Rcpp::RObject y) { 21 | DISPATCH_BINARY_MATH(rray__hypot_impl, x, y); 22 | } 23 | -------------------------------------------------------------------------------- /src/initialize.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // utils.cpp 4 | void rray_init_utils(SEXP ns); 5 | void rray_init_cast(SEXP ns); 6 | void rray_init_type2(SEXP ns); 7 | 8 | // [[Rcpp::export]] 9 | SEXP rray_init(SEXP ns) { 10 | rray_init_utils(ns); 11 | rray_init_cast(ns); 12 | rray_init_type2(ns); 13 | return R_NilValue; 14 | } 15 | -------------------------------------------------------------------------------- /src/misc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int rray__prod(Rcpp::IntegerVector x) { 4 | int prod = 1; 5 | 6 | for (int i = 0; i < x.size(); ++i) { 7 | prod *= x[i]; 8 | } 9 | 10 | return prod; 11 | } 12 | -------------------------------------------------------------------------------- /src/multiply-add.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // ----------------------------------------------------------------------------- 7 | 8 | // TODO - handle any integer overflow somehow? 9 | 10 | template 11 | xt::rarray rray__multiply_add_impl(const xt::rarray& x, 12 | const xt::rarray& y, 13 | const xt::rarray& z) { 14 | 15 | // Common dim 16 | Rcpp::IntegerVector x_dim = rray__dim(SEXP(x)); 17 | Rcpp::IntegerVector y_dim = rray__dim(SEXP(y)); 18 | Rcpp::IntegerVector z_dim = rray__dim(SEXP(z)); 19 | 20 | Rcpp::IntegerVector dim = rray__dim2(rray__dim2(x_dim, y_dim), z_dim); 21 | 22 | const int& dim_n = dim.size(); 23 | 24 | auto x_view = rray__increase_dims_view(x, dim_n); 25 | auto y_view = rray__increase_dims_view(y, dim_n); 26 | auto z_view = rray__increase_dims_view(z, dim_n); 27 | 28 | return xt::fma(x_view, y_view, z_view); 29 | } 30 | 31 | // [[Rcpp::export(rng = false)]] 32 | Rcpp::RObject rray__multiply_add(Rcpp::RObject x, Rcpp::RObject y, Rcpp::RObject z) { 33 | 34 | Rcpp::IntegerVector x_dim = rray__dim(x); 35 | Rcpp::IntegerVector y_dim = rray__dim(y); 36 | Rcpp::IntegerVector z_dim = rray__dim(z); 37 | 38 | Rcpp::IntegerVector dim = rray__dim2(rray__dim2(x_dim, y_dim), z_dim); 39 | 40 | Rcpp::List resized_x_dim_names = rray__resize_dim_names(rray__dim_names(x), dim); 41 | Rcpp::List resized_y_dim_names = rray__resize_dim_names(rray__dim_names(y), dim); 42 | Rcpp::List resized_z_dim_names = rray__resize_dim_names(rray__dim_names(z), dim); 43 | 44 | Rcpp::List new_dim_names; 45 | 46 | new_dim_names = rray__coalesce_dim_names( 47 | resized_x_dim_names, 48 | resized_y_dim_names 49 | ); 50 | 51 | new_dim_names = rray__coalesce_dim_names( 52 | new_dim_names, 53 | resized_z_dim_names 54 | ); 55 | 56 | Rcpp::RObject tmp_type = vec__ptype_inner2(x, y); 57 | Rcpp::RObject type = vec__ptype_inner2(tmp_type, z); 58 | x = vec__cast_inner(x, type); 59 | y = vec__cast_inner(y, type); 60 | z = vec__cast_inner(z, type); 61 | 62 | Rcpp::RObject out; 63 | DISPATCH_TRINARY_NO_LOGICAL(out, rray__multiply_add_impl, x, y, z); 64 | 65 | rray__set_dim_names(out, new_dim_names); 66 | 67 | return out; 68 | } 69 | -------------------------------------------------------------------------------- /src/r-api.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // (15 is equal to the default settings of identical()) 4 | bool r_identical(SEXP x, SEXP y) { 5 | return R_compute_identical(x, y, 16); 6 | } 7 | 8 | bool r_is_null(SEXP x) { 9 | return Rf_isNull(x); 10 | } 11 | 12 | bool r_is_missing(SEXP x) { 13 | return r_identical(x, R_MissingArg); 14 | } 15 | -------------------------------------------------------------------------------- /src/subset-assign.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // Required for the assignment step 7 | #include 8 | 9 | // For assignment speed 10 | #include 11 | 12 | template 13 | Rcpp::RObject rray__subset_assign_impl(const xt::rarray& x, 14 | Rcpp::List indexer, 15 | Rcpp::RObject value_) { 16 | 17 | xt::rarray value(value_); 18 | 19 | // Reshape `xt_value` to have the dimensionality of `x` 20 | const int& x_dim_n = rray__dim_n(SEXP(x)); 21 | auto value_view = rray__increase_dims_view(value, x_dim_n); 22 | 23 | // Request a copy of `x` that we can assign to 24 | // `x` comes in as a `const&` that we can't modify directly 25 | // (and we don't want to change this. We will have to copy `x` at 26 | // some point for the assignment. It makes sense to do it here.) 27 | xt::rarray out = x; 28 | 29 | if (is_stridable(indexer)) { 30 | xt::xstrided_slice_vector sv = build_strided_slice_vector(indexer); 31 | auto xt_out_subset_view = xt::strided_view(out, sv); 32 | rray__validate_broadcastable_to(value_view, xt_out_subset_view); 33 | xt::noalias(xt_out_subset_view) = value_view; 34 | } 35 | else { 36 | xt::xdynamic_slice_vector sv = build_dynamic_slice_vector(indexer); 37 | auto xt_out_subset_view = xt::dynamic_view(out, sv); 38 | rray__validate_broadcastable_to(value_view, xt_out_subset_view); 39 | xt::noalias(xt_out_subset_view) = value_view; 40 | } 41 | 42 | return Rcpp::as(out); 43 | } 44 | 45 | // [[Rcpp::export(rng = false)]] 46 | Rcpp::RObject rray__subset_assign(Rcpp::RObject x, 47 | Rcpp::List indexer, 48 | Rcpp::RObject value) { 49 | Rcpp::RObject out; 50 | DISPATCH_UNARY_TWO(out, rray__subset_assign_impl, x, indexer, value); 51 | 52 | rray__set_dim_names(out, rray__dim_names(x)); 53 | 54 | return out; 55 | } 56 | -------------------------------------------------------------------------------- /src/subset-tools.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // This check is done after contiguous vectors have been converted to lists of ranges 5 | 6 | bool is_stridable(Rcpp::List x) { 7 | bool stridable = true; 8 | int x_size = x.size(); 9 | 10 | for (int i = 0; i < x_size; ++i) { 11 | 12 | Rcpp::RObject idx = x[i]; 13 | 14 | if (r_is_missing(idx)) { 15 | continue; 16 | } 17 | 18 | // Can't check if its a list with Rf_isList() or .inherits("list") 19 | // as that doesn't really catch it 20 | if (TYPEOF(idx) == VECSXP) { 21 | continue; 22 | } 23 | 24 | stridable = false; 25 | break; 26 | } 27 | 28 | return stridable; 29 | } 30 | 31 | xt::xstrided_slice_vector build_strided_slice_vector(Rcpp::List indexer) { 32 | 33 | xt::xstrided_slice_vector sv({}); 34 | int n = indexer.size(); 35 | 36 | for (int i = 0; i < n; ++i) { 37 | 38 | Rcpp::RObject index = indexer[i]; 39 | 40 | if (r_is_missing(index)) { 41 | sv.emplace_back(xt::all()); 42 | continue; 43 | } 44 | 45 | // It was contiguous, and is now a list of the start/stop positions 46 | int start = *INTEGER(VECTOR_ELT(index, 0)); 47 | int stop = *INTEGER(VECTOR_ELT(index, 1)); 48 | sv.emplace_back(xt::range(start, stop)); 49 | } 50 | 51 | return sv; 52 | } 53 | 54 | xt::xdynamic_slice_vector build_dynamic_slice_vector(Rcpp::List indexer) { 55 | 56 | xt::xdynamic_slice_vector sv({}); 57 | int n = indexer.size(); 58 | 59 | for (int i = 0; i < n; ++i) { 60 | 61 | Rcpp::RObject index = indexer[i]; 62 | 63 | if (r_is_missing(index)) { 64 | sv.emplace_back(xt::all()); 65 | continue; 66 | } 67 | 68 | // It was contiguous, and is now a list of the start/stop positions 69 | if (TYPEOF(index) == VECSXP) { 70 | int start = *INTEGER(VECTOR_ELT(index, 0)); 71 | int stop = *INTEGER(VECTOR_ELT(index, 1)); 72 | sv.emplace_back(xt::range(start, stop)); 73 | continue; 74 | } 75 | 76 | // Else it is a non-contiguous IntegerVector 77 | // Use `int` rather than `size_t` to prevent the indices being copied 78 | std::vector slice = Rcpp::as>(index); 79 | sv.emplace_back(xt::keep(slice)); 80 | } 81 | 82 | return sv; 83 | } 84 | -------------------------------------------------------------------------------- /src/type2.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | SEXP fns_vec_ptype_inner2 = NULL; 5 | 6 | SEXP vec__ptype_inner2(SEXP x, SEXP y) { 7 | SEXP env = PROTECT(r_new_environment(rray_ns_env, 2)); 8 | 9 | Rf_defineVar(syms_x, x, env); 10 | Rf_defineVar(syms_y, y, env); 11 | 12 | SEXP call = PROTECT(Rf_lang3(fns_vec_ptype_inner2, syms_x, syms_y)); 13 | 14 | SEXP res = PROTECT(Rf_eval(call, env)); 15 | 16 | UNPROTECT(3); 17 | return res; 18 | } 19 | 20 | void rray_init_type2(SEXP ns) { 21 | fns_vec_ptype_inner2 = Rf_install("vec_ptype_inner2"); 22 | } 23 | -------------------------------------------------------------------------------- /src/validation.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // [[Rcpp::export(rng = false)]] 4 | void rray__validate_dim(Rcpp::IntegerVector dim) { 5 | bool not_ok = Rcpp::is_true(Rcpp::any(dim < 0)); 6 | 7 | if (not_ok) { 8 | Rcpp::stop("`dim` must be a positive integer vector."); 9 | } 10 | } 11 | 12 | // [[Rcpp::export(rng = false)]] 13 | void rray__validate_reshape(Rcpp::RObject x, Rcpp::IntegerVector dim) { 14 | 15 | rray__validate_dim(dim); 16 | 17 | int x_size = rray__prod(rray__dim(x)); 18 | int new_size = rray__prod(dim); 19 | 20 | if (x_size != new_size) { 21 | Rcpp::stop( 22 | "The size you are reshaping from (%i) must be equal to the size you are reshaping to (%i).", 23 | x_size, new_size 24 | ); 25 | } 26 | 27 | } 28 | 29 | // Convert integer dim to something like '(1, 2, 3)' 30 | std::string rray__dim_to_string(Rcpp::IntegerVector dim) { 31 | 32 | std::vector dim_vec = Rcpp::as>(dim); 33 | 34 | std::ostringstream oss; 35 | 36 | oss << "("; 37 | 38 | if (!dim_vec.empty()) 39 | { 40 | // Convert all but the last element to avoid a trailing "," 41 | std::copy( 42 | dim_vec.begin(), 43 | dim_vec.end() - 1, 44 | std::ostream_iterator(oss, ", ") 45 | ); 46 | 47 | // Now add the last element with no delimiter 48 | oss << dim_vec.back(); 49 | } 50 | 51 | oss << ")"; 52 | 53 | return oss.str(); 54 | } 55 | 56 | // 4 cases where broadcasting works: 57 | // - Dimensions are the same (no change is made) 58 | // - Dimension of x is 1 (broadcast to new dimension) 59 | // - New dimension is 0 (no change is made) 60 | // - Dimensions of x are shorter than `dim` (i.e. x is 3D but dim is 4D) 61 | // in that case, we check the 3 first dimensions and assume the 4th will 62 | // be reshape-viewed to work 63 | 64 | // [[Rcpp::export(rng = false)]] 65 | void rray__validate_broadcastable_to_dim(Rcpp::IntegerVector x_dim, 66 | Rcpp::IntegerVector dim) { 67 | 68 | int n_x = x_dim.size(); 69 | int n_to = dim.size(); 70 | 71 | if (n_x > n_to) { 72 | Rcpp::stop( 73 | "Cannot decrease dimensionality from %i to %i.", 74 | n_x, n_to 75 | ); 76 | } 77 | 78 | for (int i = 0; i < n_x; ++i) { 79 | int x_dim_i = x_dim[i]; 80 | int dim_i = dim[i]; 81 | 82 | bool ok = (x_dim_i == dim_i || x_dim_i == 1); 83 | 84 | if (!ok) { 85 | Rcpp::stop( 86 | "Cannot broadcast from %s to %s due to dimension %i.", 87 | rray__dim_to_string(x_dim), 88 | rray__dim_to_string(dim), 89 | i + 1 90 | ); 91 | } 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /src/yank-assign.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // For `filter()` and `index_view()` 7 | #include 8 | 9 | // For `i` 10 | #include 11 | 12 | // For `unravel_indices()` 13 | #include 14 | 15 | #include 16 | 17 | // ----------------------------------------------------------------------------- 18 | 19 | // For the assignment step to work, `x` cannot be a const reference 20 | 21 | // filter() view happens when there is a logical i and `rray_dim_n(i) == rray_dim_n(x)` 22 | 23 | template 24 | auto rray__yank_non_const_filter_impl(xt::rarray& x, const Rcpp::RObject& i) { 25 | xt::rarray xt_i = Rcpp::as>(i); 26 | return xt::filter(x, xt_i); 27 | } 28 | 29 | template 30 | auto rray__yank_non_const_index_impl(xt::rarray& x, const Rcpp::RObject& i) { 31 | 32 | const xt::rtensor xt_i = Rcpp::as>(i); 33 | 34 | // Ideally wouldn't have to do this, but `x.shape()` isn't recognized by `unravel_indices()` 35 | const std::vector shape(x.shape().begin(), x.shape().end()); 36 | 37 | // Convert flat indices -> array indices 38 | auto array_indices = xt::unravel_indices(xt_i, shape, xt::layout_type::column_major); 39 | 40 | return xt::index_view(x, array_indices); 41 | } 42 | 43 | 44 | template 45 | Rcpp::RObject rray__yank_assign_impl(const xt::rarray& x, Rcpp::RObject i, Rcpp::RObject value_) { 46 | 47 | // Copy `x` 48 | xt::rarray out = x; 49 | 50 | xt::rarray value(value_); 51 | 52 | if (TYPEOF(i) == LGLSXP) { 53 | auto out_view = rray__yank_non_const_filter_impl(out, i); 54 | rray__validate_broadcastable_to(value, out_view); 55 | out_view = value; 56 | } 57 | else if (TYPEOF(i) == INTSXP) { 58 | auto out_view = rray__yank_non_const_index_impl(out, i); 59 | rray__validate_broadcastable_to(value, out_view); 60 | out_view = value; 61 | } 62 | else { 63 | Rcpp::stop("Internal error: `i` is somehow not a logical or integer."); 64 | } 65 | 66 | return Rcpp::as(out); 67 | } 68 | 69 | // [[Rcpp::export(rng = false)]] 70 | Rcpp::RObject rray__yank_assign(Rcpp::RObject x, Rcpp::RObject i, Rcpp::RObject value) { 71 | Rcpp::RObject out; 72 | DISPATCH_UNARY_TWO(out, rray__yank_assign_impl, x, i, value); 73 | 74 | rray__set_dim_names(out, rray__dim_names(x)); 75 | 76 | return out; 77 | } 78 | -------------------------------------------------------------------------------- /src/yank.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | // For `filter()` and `index_view()` 7 | #include 8 | 9 | // For `i` 10 | #include 11 | 12 | // For `unravel_indices()` 13 | #include 14 | 15 | // ----------------------------------------------------------------------------- 16 | 17 | // filter() view. `rray_dim_n(i) == rray_dim_n(x)` 18 | 19 | template 20 | auto rray__yank_filter_impl(const xt::rarray& x, const Rcpp::RObject& i) { 21 | xt::rarray xt_i = Rcpp::as>(i); 22 | return xt::filter(x, xt_i); 23 | } 24 | 25 | template 26 | auto rray__yank_index_impl(const xt::rarray& x, const Rcpp::RObject& i) { 27 | 28 | const xt::rtensor xt_i = Rcpp::as>(i); 29 | 30 | // Ideally wouldn't have to do this, but `x.shape()` isn't recognized by `unravel_indices()` 31 | const std::vector shape(x.shape().begin(), x.shape().end()); 32 | 33 | // Convert flat indices -> array indices 34 | auto array_indices = xt::unravel_indices(xt_i, shape, xt::layout_type::column_major); 35 | 36 | return xt::index_view(x, array_indices); 37 | } 38 | 39 | 40 | template 41 | Rcpp::RObject rray__yank_impl(const xt::rarray& x, Rcpp::RObject i) { 42 | 43 | xt::rarray out; 44 | 45 | if (TYPEOF(i) == LGLSXP) { 46 | out = rray__yank_filter_impl(x, i); 47 | } 48 | else if (TYPEOF(i) == INTSXP) { 49 | out = rray__yank_index_impl(x, i); 50 | } 51 | else { 52 | Rcpp::stop("Internal error: `i` is somehow not a logical or integer."); 53 | } 54 | 55 | return Rcpp::as(out); 56 | } 57 | 58 | // [[Rcpp::export(rng = false)]] 59 | Rcpp::RObject rray__yank(Rcpp::RObject x, Rcpp::RObject i) { 60 | Rcpp::RObject out; 61 | DISPATCH_UNARY_ONE(out, rray__yank_impl, x, i); 62 | 63 | out.attr("dimnames") = rray__new_empty_dim_names(1); 64 | 65 | return out; 66 | } 67 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(rray) 3 | 4 | test_check("rray") 5 | -------------------------------------------------------------------------------- /tests/testthat/out/test-0-axis-1D.txt: -------------------------------------------------------------------------------- 1 | [0]> 2 | numeric(0) 3 | -------------------------------------------------------------------------------- /tests/testthat/out/test-0-axis-2D.txt: -------------------------------------------------------------------------------- 1 | [,1][0]> 2 | [,1] 3 | -------------------------------------------------------------------------------- /tests/testthat/out/test-0-axis-3D.txt: -------------------------------------------------------------------------------- 1 | [,1,0][0]> 2 | <0 x 1 x 0 array of double> 3 | [,1] 4 | 5 | -------------------------------------------------------------------------------- /tests/testthat/out/test-1D-rray.txt: -------------------------------------------------------------------------------- 1 | [1]> 2 | [1] 1 3 | -------------------------------------------------------------------------------- /tests/testthat/out/test-2D-rray.txt: -------------------------------------------------------------------------------- 1 | [,1][1]> 2 | [,1] 3 | [1,] 1 4 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-extract-logical-size.txt: -------------------------------------------------------------------------------- 1 | > rray_extract(x, c(TRUE, TRUE, TRUE)) 2 | Error: Must subset elements with a valid subscript vector. 3 | i Logical subscripts must match the size of the indexed input. 4 | x The input has size 2 but the subscript has size 3. 5 | 6 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-extract-oob-character.txt: -------------------------------------------------------------------------------- 1 | > rray_extract(x, "r3") 2 | Error: Can't subset elements that don't exist. 3 | x The element `r3` doesn't exist. 4 | 5 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-extract-oob-negative.txt: -------------------------------------------------------------------------------- 1 | > rray_extract(x, -3) 2 | Error: Can't negate elements that don't exist. 3 | x The location 3 doesn't exist. 4 | i There are only 2 elements. 5 | 6 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-extract-oob.txt: -------------------------------------------------------------------------------- 1 | > rray_extract(x, 3) 2 | Error: Can't subset elements that don't exist. 3 | x The location 3 doesn't exist. 4 | i There are only 2 elements. 5 | 6 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-extract-unnamed.txt: -------------------------------------------------------------------------------- 1 | > rray_extract(1, "x") 2 | Error: Can't use character names to index an unnamed vector. 3 | 4 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-subset-logical-size.txt: -------------------------------------------------------------------------------- 1 | > rray_subset(x, c(TRUE, TRUE, TRUE)) 2 | Error: Must subset elements with a valid subscript vector. 3 | i Logical subscripts must match the size of the indexed input. 4 | x The input has size 2 but the subscript has size 3. 5 | 6 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-subset-oob-character.txt: -------------------------------------------------------------------------------- 1 | > rray_subset(x, "r3") 2 | Error: Can't subset elements that don't exist. 3 | x The element `r3` doesn't exist. 4 | 5 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-subset-oob-negative.txt: -------------------------------------------------------------------------------- 1 | > x[-3] 2 | Error: Can't negate elements that don't exist. 3 | x The location 3 doesn't exist. 4 | i There are only 2 elements. 5 | 6 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-subset-oob.txt: -------------------------------------------------------------------------------- 1 | > rray_subset(x, 3) 2 | Error: Can't subset elements that don't exist. 3 | x The location 3 doesn't exist. 4 | i There are only 2 elements. 5 | 6 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-subset-unnamed.txt: -------------------------------------------------------------------------------- 1 | > rray_subset(1, "x") 2 | Error: Can't use character names to index an unnamed vector. 3 | 4 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-yank-oob.txt: -------------------------------------------------------------------------------- 1 | > rray_yank(x, 9) 2 | Error: Can't subset elements that don't exist. 3 | x The location 9 doesn't exist. 4 | i There are only 8 elements. 5 | 6 | -------------------------------------------------------------------------------- /tests/testthat/out/test-error-rray-yank-shaped-logical.txt: -------------------------------------------------------------------------------- 1 | > rray_yank(x, idx) 2 | Error: `i` must have one dimension, not 2. 3 | 4 | -------------------------------------------------------------------------------- /tests/testthat/out/test-str-1.txt: -------------------------------------------------------------------------------- 1 | rray [5] 1, 2, 3, 4, 5 2 | @ dim : int 5 3 | @ dimnames:List of 1 4 | ..$ : NULL 5 | -------------------------------------------------------------------------------- /tests/testthat/out/test-str-2.txt: -------------------------------------------------------------------------------- 1 | rray [50] 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, ... 2 | @ dim : int 50 3 | @ dimnames:List of 1 4 | ..$ : NULL 5 | -------------------------------------------------------------------------------- /tests/testthat/out/test-str-3.txt: -------------------------------------------------------------------------------- 1 | rray [,1][1] 1 2 | @ dim : int [1:2] 1 1 3 | @ dimnames:List of 2 4 | ..$ : NULL 5 | ..$ : NULL 6 | -------------------------------------------------------------------------------- /tests/testthat/out/test-str-4.txt: -------------------------------------------------------------------------------- 1 | rray [,1,50][1] 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15... 2 | @ dim : int [1:3] 1 1 50 3 | @ dimnames:List of 3 4 | ..$ : NULL 5 | ..$ : NULL 6 | ..$ : NULL 7 | -------------------------------------------------------------------------------- /tests/testthat/test-clip.R: -------------------------------------------------------------------------------- 1 | test_that("basics", { 2 | expect_identical(rray_clip(1:3, 1, 2), new_array(c(1L, 2L, 2L))) 3 | expect_identical( 4 | rray_clip(rray(1:6, c(2, 3, 1)), 1, 3), 5 | rray(c(1L, 2L, rep(3L, 4)), c(2, 3, 1)) 6 | ) 7 | }) 8 | 9 | test_that("dimension names are kept", { 10 | x <- rray(c(0, 0), c(2, 1), list(c("r1", "r2"), "c1")) 11 | expect_equal( 12 | rray_clip(x, 1, 2), 13 | rray(1, c(2, 1), list(c("r1", "r2"), "c1")) 14 | ) 15 | }) 16 | 17 | test_that("cannot clip if `low` is greater than `high`", { 18 | expect_error(rray_clip(1, 2, 1), "less than or equal to") 19 | }) 20 | 21 | test_that("`low` and `high` must be size 1", { 22 | expect_error(rray_clip(1, c(1, 1), 1), "1, not size 2", class = "vctrs_error_assert_size") 23 | expect_error(rray_clip(1, 1, c(1, 1)), "1, not size 2", class = "vctrs_error_assert_size") 24 | }) 25 | 26 | test_that("cannot clip with NULL bounds", { 27 | expect_error(rray_clip(1, NULL, 1), "not NULL", class = "vctrs_error_scalar_type") 28 | expect_error(rray_clip(1, 1, NULL), "not NULL", class = "vctrs_error_scalar_type") 29 | }) 30 | 31 | test_that("clip NULL", { 32 | expect_equal(rray_clip(NULL, 1, 1), NULL) 33 | }) 34 | 35 | test_that("clip with length 0 x", { 36 | expect_equal(rray_clip(logical(), 1, 1), new_array(logical())) 37 | expect_equal(rray_clip(numeric(), 1, 1), new_array(numeric())) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-compat-vctrs.R: -------------------------------------------------------------------------------- 1 | library(vctrs) 2 | 3 | # ------------------------------------------------------------------------------ 4 | context("test-vec-order-compat") 5 | 6 | # (flattens to 2D using as.data.frame(), then checks order rowwise) 7 | 8 | test_that("can vec_order() with rrays", { 9 | x <- rray(1:8, c(2, 2, 2)) 10 | x_df <- as.data.frame(x) 11 | expect_equal(vec_order(x), vec_order(x_df)) 12 | expect_equal(vec_order(x, direction = "desc"), vec_order(x_df, direction = "desc")) 13 | }) 14 | 15 | # ------------------------------------------------------------------------------ 16 | context("test-vec-sort-compat") 17 | 18 | # (sorts entire rows together, even across dimensions. 19 | # different from rray_sort()!) 20 | 21 | test_that("can vec_sort() with rrays", { 22 | x <- rray(8:1, c(2, 2, 2)) 23 | expect_equal(vec_sort(x), x[c(2, 1)]) 24 | expect_equal(vec_sort(x, direction = "desc"), x) 25 | }) 26 | 27 | # ------------------------------------------------------------------------------ 28 | context("test-vec-count-compat") 29 | 30 | # vec_count(sort = "key") uses vec_order(), so we want to be sure it works 31 | 32 | test_that("can vec_count() with rrays", { 33 | x_core <- rray(8:1, c(2, 2, 2)) 34 | x <- rray_rbind(x_core, x_core[2]) 35 | 36 | x_loc <- new_data_frame(n = 2L) 37 | x_loc$key <- x_core 38 | x_loc$count <- c(1L, 2L) 39 | 40 | x_count <- new_data_frame(n = 2L) 41 | x_count$key <- x_core[c(2, 1)] 42 | x_count$count <- c(2L, 1L) 43 | 44 | x_key <- new_data_frame(n = 2L) 45 | x_key$key <- x_core[c(2, 1)] 46 | x_key$count <- c(2L, 1L) 47 | 48 | expect_equal(vec_count(x, sort = "location"), x_loc) 49 | expect_equal(vec_count(x, sort = "count"), x_count) 50 | expect_equal(vec_count(x, sort = "key"), x_key) 51 | }) 52 | 53 | -------------------------------------------------------------------------------- /tests/testthat/test-container-type.R: -------------------------------------------------------------------------------- 1 | context("test-container-type") 2 | 3 | xs <- list(logical(), integer(), double(), character()) 4 | 5 | # ------------------------------------------------------------------------------ 6 | # Base R atomic container types 7 | 8 | for (x in xs) { 9 | test_that(glue::glue("container type for {typeof(x)}."), { 10 | expect_equal(vec_ptype_container(x), logical()) 11 | }) 12 | } 13 | 14 | # ------------------------------------------------------------------------------ 15 | # Bad `x` 16 | 17 | bad_x <- new_vctr(1, class = "unknown", inherit_base_type = FALSE) 18 | 19 | test_that("unknown container types are caught", { 20 | expect_error(vec_ptype_container(bad_x)) 21 | }) 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Unspecified 25 | 26 | test_that("unspecified container type is logical()", { 27 | expect_equal(vec_ptype_container(vctrs::unspecified()), logical()) 28 | }) 29 | 30 | # ------------------------------------------------------------------------------ 31 | # NULL 32 | 33 | test_that("container type allows NULL `x`", { 34 | expect_equal(vec_ptype_container(NULL), NULL) 35 | }) 36 | 37 | # ------------------------------------------------------------------------------ 38 | # rray container type 39 | 40 | test_that("rray container types are rray(logical())", { 41 | expect_equal(vec_ptype_container(rray(1)), rray(logical())) 42 | expect_equal(vec_ptype_container(rray(TRUE)), rray(logical())) 43 | expect_equal(vec_ptype_container(rray(1L)), rray(logical())) 44 | }) 45 | 46 | # ------------------------------------------------------------------------------ 47 | # common container type 48 | 49 | test_that("common container type can be found", { 50 | expect_equal(vec_ptype_container_common(1, 1L), logical()) 51 | }) 52 | 53 | test_that("common container type with 1 input", { 54 | expect_equal(vec_ptype_container_common(1), logical()) 55 | }) 56 | 57 | test_that("common container type with no input", { 58 | expect_equal(vec_ptype_container_common(), NULL) 59 | }) 60 | 61 | test_that("can specify ptype", { 62 | expect_equal(vec_ptype_container_common(.ptype = 1), logical()) 63 | expect_equal(vec_ptype_container_common(.ptype = rray(1)), rray(logical())) 64 | }) 65 | 66 | test_that("can find a common container type with characters", { 67 | expect_equal(vec_ptype_container_common(1, character()), logical()) 68 | }) 69 | -------------------------------------------------------------------------------- /tests/testthat/test-diagonal.R: -------------------------------------------------------------------------------- 1 | context("test-diag") 2 | 3 | test_that("can create a diagonal matrix", { 4 | x <- rray_diag(1L) 5 | expect_equal(rray_dim(x), c(1, 1)) 6 | expect_equal(storage.mode(x), "integer") 7 | 8 | x <- rray_diag(TRUE) 9 | expect_equal(storage.mode(x), "logical") 10 | 11 | x <- rray_diag(c(1, 2, 3)) 12 | expect_equal(x, diag(c(1, 2, 3))) 13 | }) 14 | 15 | test_that("rray class is kept", { 16 | expect_is(rray_diag(rray(1:5), 1), "vctrs_rray_int") 17 | }) 18 | 19 | test_that("can offset the diagonal", { 20 | expect_equal(rray_diag(1, 1), array(c(0, 0, 1, 0), c(2, 2))) 21 | expect_equal(rray_diag(1, -1), array(c(0, 1, 0, 0), c(2, 2))) 22 | }) 23 | 24 | test_that("can create empty matrices with 0 length input", { 25 | expect_equal(rray_diag(logical()), matrix(logical(), 0, 0)) 26 | expect_equal(rray_diag(logical(), offset = 1), matrix(FALSE)) 27 | expect_equal(rray_diag(integer(), offset = 3), matrix(0, 3, 3)) 28 | }) 29 | 30 | test_that("`NULL` passes through", { 31 | expect_equal(rray_diag(NULL), NULL) 32 | }) 33 | 34 | test_that("fails if `x` is not an allowed type", { 35 | expect_error(rray_diag("hi"), "Incompatible") 36 | }) 37 | 38 | test_that("fails if `x` is not 1D", { 39 | expect_error(rray_diag(matrix(1)), "`x` must be 1D, not 2D") 40 | }) 41 | 42 | test_that("fails with bad `offset`", { 43 | expect_error(rray_diag(1, offset = c(1, 1)), "1, not 2") 44 | }) 45 | -------------------------------------------------------------------------------- /tests/testthat/test-diff.R: -------------------------------------------------------------------------------- 1 | context("test-diff") 2 | 3 | # Using `vctrs:::diff.vctrs_vctr` rather than implementing our own method as 4 | # it works just fine! 5 | 6 | test_that("can compute a diff on 1D", { 7 | x <- rray(c(1, 3, 4, 5)) 8 | expect_equal(diff(x), rray(c(2, 1, 1))) 9 | expect_equal(diff(x, lag = 2), rray(c(3, 2))) 10 | expect_equal(diff(x, differences = 2), rray(c(-1, 0))) 11 | }) 12 | 13 | test_that("can compute a diff on 2D", { 14 | x <- rray(c(1, 3, 4, 5, 6, 8), c(3, 2)) 15 | expect_equal(diff(x), rray(c(2, 1, 1, 2), c(2, 2))) 16 | }) 17 | 18 | test_that("can compute a diff on 3D", { 19 | x <- rray(c(1, 3, 4, 5, 6, 8, 9, 1), c(2, 2, 2)) 20 | expect_equal(diff(x), rray(c(2, 1, 2, -8), c(1, 2, 2))) 21 | }) 22 | 23 | test_that("diff on logical returns integers", { 24 | expect_equal(diff(rray(c(TRUE, FALSE))), rray(-1L)) 25 | }) 26 | 27 | test_that("diff with too many lags/differences keeps shape", { 28 | x <- rray(1:6, c(3, 2)) 29 | expect_equal(diff(x, lag = 3), vec_slice(x, 0L)) 30 | expect_equal(diff(x, differences = 3), vec_slice(x, 0L)) 31 | }) 32 | 33 | test_that("diff keeps names", { 34 | x <- rray(1:6, c(3, 2), dim_names = list(letters[1:3], letters[4:5])) 35 | expect_equal(rray_dim_names(diff(x)), list(letters[2:3], letters[4:5])) 36 | expect_equal(rray_dim_names(diff(x, lag = 2)), list(letters[3], letters[4:5])) 37 | expect_equal(rray_dim_names(diff(x, differences = 2)), list(letters[3], letters[4:5])) 38 | }) 39 | -------------------------------------------------------------------------------- /tests/testthat/test-dim-n.R: -------------------------------------------------------------------------------- 1 | context("test-dim-n") 2 | 3 | x_5 <- rep(1, times = 5) 4 | x_2x3 <- matrix(1, nrow = 2, ncol = 3) 5 | x_6x1x3 <- array(1, c(6, 1, 3)) 6 | 7 | test_that("can compute the number of dimensions", { 8 | expect_equal(rray_dim_n(x_5), 1) 9 | expect_equal(rray_dim_n(x_2x3), 2) 10 | expect_equal(rray_dim_n(x_6x1x3), 3) 11 | }) 12 | 13 | test_that("dimensionality of NULL is 1", { 14 | expect_equal(rray_dim_n(NULL), 1) 15 | }) 16 | 17 | test_that("dimensionality of data frames is 1", { 18 | expect_equal(rray_dim_n(mtcars), 1) 19 | }) 20 | -------------------------------------------------------------------------------- /tests/testthat/test-dim-names-common.R: -------------------------------------------------------------------------------- 1 | test_that("first input names are used", { 2 | x <- array(1, c(1, 1), dimnames = list("r1", "c1")) 3 | y <- array(1, c(1, 1), dimnames = list(NULL, NULL)) 4 | 5 | expect_equal( 6 | rray_dim_names_common(x, y), 7 | rray_dim_names(x) 8 | ) 9 | }) 10 | 11 | test_that("first input names have priorities", { 12 | x <- array(1, c(1, 1), dimnames = list("r1", "c1")) 13 | y <- array(1, c(1, 1), dimnames = list("r2", "c2")) 14 | 15 | expect_equal( 16 | rray_dim_names_common(x, y), 17 | rray_dim_names(x) 18 | ) 19 | }) 20 | 21 | test_that("dim names can come from both inputs", { 22 | x <- array(1, c(1, 1), dimnames = list("r1", NULL)) 23 | y <- array(1, c(1, 1), dimnames = list("r2", "c2")) 24 | 25 | expect_equal( 26 | rray_dim_names_common(x, y), 27 | list("r1", "c2") 28 | ) 29 | }) 30 | 31 | test_that("dim names have to match the common dim to be used", { 32 | x <- array(1, c(2, 1), dimnames = list(NULL, "c1")) 33 | y <- array(1, c(1, 2), dimnames = list("r2", NULL)) 34 | 35 | expect_equal( 36 | rray_dim_names_common(x, y), 37 | list(NULL, NULL) 38 | ) 39 | }) 40 | 41 | test_that("meta dim names are used even if names aren't", { 42 | x <- array(1, c(2, 1), dimnames = list(x = NULL, "c1")) 43 | y <- array(1, c(1, 2), dimnames = list("r2", NULL)) 44 | 45 | expect_equal( 46 | rray_dim_names_common(x, y), 47 | list(x = NULL, NULL) 48 | ) 49 | }) 50 | 51 | test_that("meta dim names are used from first input", { 52 | x <- array(1, dimnames = list(x = NULL)) 53 | y <- array(1, dimnames = list(y = NULL)) 54 | 55 | expect_equal( 56 | rray_dim_names_common(x, y), 57 | list(x = NULL) 58 | ) 59 | }) 60 | 61 | test_that("meta dim names can be constructed from both inputs", { 62 | x <- array(1, c(2, 1), dimnames = list(x = NULL, NULL)) 63 | y <- array(1, c(1, 2), dimnames = list(NULL, y = NULL)) 64 | 65 | expect_equal( 66 | rray_dim_names_common(x, y), 67 | list(x = NULL, y = NULL) 68 | ) 69 | }) 70 | 71 | -------------------------------------------------------------------------------- /tests/testthat/test-dim.R: -------------------------------------------------------------------------------- 1 | context("test-dim") 2 | 3 | x_2x3 <- matrix(1, nrow = 2, ncol = 3) 4 | x_1x5 <- matrix(1, nrow = 1, ncol = 5) 5 | x_5 <- rep(1, times = 5) 6 | x_6x1x3 <- array(1, c(6, 1, 3)) 7 | 8 | test_that("common dim", { 9 | expect_error(rray_dim2(rray_dim(x_2x3), rray_dim(x_1x5))) 10 | 11 | expect_equal(rray_dim2(rray_dim(x_5), rray_dim(x_1x5)), c(5, 5)) 12 | expect_equal(rray_dim2(rray_dim(x_1x5), rray_dim(x_6x1x3)), c(6, 5, 3)) 13 | }) 14 | 15 | test_that("`dim<-` can expand a 0 dimension if another dimension is 0", { 16 | x <- rray(numeric(), c(0, 1, 0)) 17 | dim(x) <- c(2, 1, 0) 18 | expect_equal(rray_dim(x), c(2, 1, 0)) 19 | }) 20 | 21 | test_that("0 size dim handling", { 22 | x <- c(0, 2) 23 | 24 | # 1 is broadcast down to 0 25 | expect_equal(rray_dim2(x, c(1, 2)), c(0, 2)) 26 | 27 | # 0 is same as 0 28 | expect_equal(rray_dim2(x, c(0, 2)), c(0, 2)) 29 | 30 | # 2 is not equal to 0, and is not 1, so error 31 | expect_error(rray_dim2(x, c(2, 2)), "\\(0, 2\\) and \\(2, 2\\)") 32 | }) 33 | 34 | test_that("corner cases for rray_dim_common()", { 35 | expect_equal(rray_dim_common(), NULL) 36 | expect_equal(rray_dim_common(integer()), 0) 37 | expect_equal(rray_dim_common(matrix(logical(), 0, 1)), c(0, 1)) 38 | expect_equal(rray_dim_common(matrix(logical(), 0, 0)), c(0, 0)) 39 | expect_equal(rray_dim_common(integer(), NULL), 0) 40 | expect_equal(rray_dim_common(NULL), 0) 41 | expect_equal(rray_dim_common(NULL, matrix()), c(0, 1)) 42 | }) 43 | -------------------------------------------------------------------------------- /tests/testthat/test-dot.R: -------------------------------------------------------------------------------- 1 | test_that("matrix multiplication works but the class is lost", { 2 | x <- rray(1:2) 3 | expect_equal(x %*% x, matrix(5)) 4 | }) 5 | 6 | test_that("The class is preserved", { 7 | x <- rray(1:2) 8 | expect_equal(rray_dot(x, x), rray(5, c(1, 1))) 9 | }) 10 | 11 | test_that("Error if input is >2D", { 12 | x <- array(1, c(1, 1, 1)) 13 | expect_error(rray_dot(x, 1), "1 or 2, not 3") 14 | expect_error(rray_dot(1, x), "1 or 2, not 3") 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-expand.R: -------------------------------------------------------------------------------- 1 | context("test-expand") 2 | 3 | test_that("various dimension expanding variations work", { 4 | 5 | x <- rray(1:10, c(5, 2)) 6 | 7 | expect_equal( 8 | rray_dim(rray_expand(x, 1)), 9 | c(1, 5, 2) 10 | ) 11 | 12 | expect_equal( 13 | rray_dim(rray_expand(x, 2)), 14 | c(5, 1, 2) 15 | ) 16 | 17 | expect_equal( 18 | rray_dim(rray_expand(x, 3)), 19 | c(5, 2, 1) 20 | ) 21 | 22 | }) 23 | 24 | test_that("error on bad expansion", { 25 | 26 | x <- rray(1:10, c(5, 2)) 27 | 28 | expect_error( 29 | rray_expand(x, 4), 30 | "The maximum value for `axis` is 3." 31 | ) 32 | 33 | }) 34 | 35 | test_that("dimension names kept on expansion", { 36 | 37 | x <- rray(1:10, c(5, 2)) 38 | x <- rray_set_row_names(x, letters[1:5]) 39 | x <- rray_set_col_names(x, c("c1", "c2")) 40 | 41 | expect_equal( 42 | rray_dim_names(rray_expand(x, 1)), 43 | c(list(NULL), rray_dim_names(x)) 44 | ) 45 | 46 | expect_equal( 47 | rray_dim_names(rray_expand(x, 2)), 48 | c(rray_dim_names(x)[1], list(NULL), rray_dim_names(x)[2]) 49 | ) 50 | 51 | expect_equal( 52 | rray_dim_names(rray_expand(x, 3)), 53 | c(rray_dim_names(x), list(NULL)) 54 | ) 55 | 56 | }) 57 | 58 | test_that("can expand on `NULL` input", { 59 | expect_equal(rray_expand(NULL, 2), NULL) 60 | }) 61 | -------------------------------------------------------------------------------- /tests/testthat/test-extract-assign.R: -------------------------------------------------------------------------------- 1 | test_that("can use a extract assign", { 2 | x <- rray(1:8, dim = c(2, 2, 2)) 3 | rray_extract(x, 1, 1, 1) <- NA 4 | expect_is(x, "vctrs_rray") 5 | expect_equal(as.vector(x), c(NA, 2:8)) 6 | }) 7 | 8 | test_that("value is broadcast in integer extract assign", { 9 | x <- rray(1:8, dim = c(2, 2, 2)) 10 | rray_extract(x, 1) <- NA 11 | expect_equal(as.vector(x), c(NA, 2, NA, 4, NA, 6, NA, 8)) 12 | }) 13 | 14 | test_that("assigning to 0 does nothing", { 15 | x <- rray(1:8, dim = c(2, 2, 2)) 16 | rray_extract(x, 0) <- 1 17 | expect_equal(x, rray(1:8, dim = c(2, 2, 2))) 18 | 19 | rray_extract(x, 0, 0) <- 1 20 | expect_equal(x, rray(1:8, dim = c(2, 2, 2))) 21 | }) 22 | 23 | test_that("assigning to NULL does nothing", { 24 | x <- rray(1:8, dim = c(2, 2, 2)) 25 | rray_extract(x, NULL) <- 1 26 | expect_equal(x, rray(1:8, dim = c(2, 2, 2))) 27 | }) 28 | 29 | test_that("broadcast can fail gracefully in extract assign", { 30 | x <- rray(1:8, dim = c(2, 2, 2)) 31 | expect_error(rray_extract(x, 1) <- c(1, 2), "due to dimension 1") 32 | }) 33 | 34 | test_that("can extract assign with base R objects", { 35 | x <- matrix(1:8, nrow = 2) 36 | rray_extract(x, 1) <- 4:1 37 | expect_equal(as.vector(rray_subset(x, 1)), 4:1) 38 | }) 39 | 40 | test_that("extract assigning a non-vector is an error", { 41 | x <- array(1:5) 42 | expect_error(rray_extract(x, 1) <- NULL, class = "vctrs_error_scalar_type") 43 | expect_error(rray_yank(x, 1) <- environment(), class = "vctrs_error_scalar_type") 44 | }) 45 | 46 | -------------------------------------------------------------------------------- /tests/testthat/test-extremum.R: -------------------------------------------------------------------------------- 1 | # ------------------------------------------------------------------------------ 2 | context("test-maximum") 3 | 4 | test_that("basics", { 5 | expect_identical(rray_maximum(1, 2), new_array(2)) 6 | expect_identical(rray_maximum(1L, 2L), new_array(2L)) 7 | }) 8 | 9 | test_that("broadcasting works", { 10 | x <- matrix(1:2) 11 | expect_equal(rray_maximum(x, t(x)), new_matrix(c(1, 2, 2, 2), c(2, 2))) 12 | }) 13 | 14 | test_that("works with 3D", { 15 | x <- array(1:2, c(2, 1, 2)) 16 | y <- matrix(2:1) 17 | expect_equal(rray_maximum(x, y), new_array(2, c(2, 1, 2))) 18 | }) 19 | 20 | test_that("dimension names are kept", { 21 | x <- rray(c(0, 0), c(2, 1), list(c("r1", "r2"), "c1")) 22 | expect_equal( 23 | rray_maximum(x, 1), 24 | rray(c(1, 1), c(2, 1), list(c("r1", "r2"), "c1")) 25 | ) 26 | }) 27 | 28 | # ------------------------------------------------------------------------------ 29 | context("test-minimum") 30 | 31 | test_that("basics", { 32 | expect_identical(rray_minimum(1, 2), new_array(1)) 33 | expect_identical(rray_minimum(1L, 2L), new_array(1L)) 34 | }) 35 | 36 | test_that("broadcasting works", { 37 | x <- matrix(1:2) 38 | expect_equal(rray_minimum(x, t(x)), new_matrix(c(1, 1, 1, 2), c(2, 2))) 39 | }) 40 | 41 | test_that("works with 3D", { 42 | x <- array(1:2, c(2, 1, 2)) 43 | y <- matrix(2:1) 44 | expect_equal(rray_minimum(x, y), new_array(1, c(2, 1, 2))) 45 | }) 46 | 47 | test_that("dimension names are kept", { 48 | x <- rray(c(0, 0), c(2, 1), list(c("r1", "r2"), "c1")) 49 | expect_equal( 50 | rray_minimum(x, 1), 51 | rray(c(0, 0), c(2, 1), list(c("r1", "r2"), "c1")) 52 | ) 53 | }) 54 | -------------------------------------------------------------------------------- /tests/testthat/test-flatten.R: -------------------------------------------------------------------------------- 1 | 2 | test_that("can flatten input", { 3 | expect_equal(rray_flatten(1:5), new_array(1:5)) 4 | 5 | x <- matrix(1:6, 2) 6 | expect_equal(rray_flatten(x), new_array(as.vector(x))) 7 | 8 | x <- array(1:8, c(2, 2, 2)) 9 | expect_equal(rray_flatten(as.vector(x)), new_array(as.vector(x))) 10 | }) 11 | 12 | test_that("rray class is kept", { 13 | expect_equal(rray_flatten(rray(1)), rray(1)) 14 | }) 15 | 16 | test_that("can keep names with 1D objects", { 17 | x <- rray(1, dim_names = list("foo")) 18 | expect_equal(rray_dim_names(rray_flatten(x)), rray_dim_names(x)) 19 | }) 20 | 21 | test_that("can keep names with higher dim objects", { 22 | x <- rray(1:2, c(2, 1), dim_names = list(c("foo", "foofy"), "bar")) 23 | expect_equal(rray_dim_names(rray_flatten(x)), list(c("foo", "foofy"))) 24 | 25 | # no names 26 | x_t <- t(x) 27 | expect_equal(rray_dim_names(rray_flatten(x_t)), list(NULL)) 28 | }) 29 | 30 | test_that("can flatten NULL", { 31 | expect_equal(rray_flatten(NULL), NULL) 32 | }) 33 | 34 | test_that("can flatten 0 length input", { 35 | expect_equal(rray_flatten(numeric()), new_array(numeric())) 36 | }) 37 | -------------------------------------------------------------------------------- /tests/testthat/test-flip.R: -------------------------------------------------------------------------------- 1 | context("test-flip") 2 | 3 | test_that("flipping works", { 4 | 5 | x <- rray(as.double(1:6), c(3, 2)) 6 | 7 | expect_equal( 8 | rray_flip(x, 1), 9 | rray(c(3,2,1,6,5,4), c(3,2)) 10 | ) 11 | 12 | expect_equal( 13 | rray_flip(x, 2), 14 | rray(c(4,5,6,1,2,3), c(3,2)) 15 | ) 16 | 17 | }) 18 | 19 | test_that("flipping flips dimension names", { 20 | 21 | x <- rray(1:10, c(5, 2)) 22 | x <- rray_set_row_names(x, letters[1:5]) 23 | x <- rray_set_col_names(x, c("c1", "c2")) 24 | 25 | expect_equal( 26 | rray_row_names(rray_flip(x, 1)), 27 | rev(letters[1:5]) 28 | ) 29 | 30 | expect_equal( 31 | rray_col_names(rray_flip(x, 2)), 32 | c("c2", "c1") 33 | ) 34 | 35 | }) 36 | 37 | test_that("can flip base types", { 38 | 39 | x <- matrix(1:10, ncol = 2) 40 | x <- rray_set_row_names(x, letters[1:5]) 41 | x <- rray_set_col_names(x, c("c1", "c2")) 42 | 43 | y <- array(1:12, c(2, 2, 3)) 44 | y <- rray_set_axis_names(y, 3, c("d1", "d2", "d3")) 45 | 46 | expect_is(rray_flip(x, 1), "matrix") 47 | 48 | expect_equal( 49 | rray_row_names(rray_flip(x, 1)), 50 | rev(rray_row_names(x)) 51 | ) 52 | 53 | expect_equal( 54 | as.vector(rray_flip(x, 1)), 55 | c(5:1, 10:6) 56 | ) 57 | 58 | expect_equal( 59 | as.vector(rray_flip(x, 2)), 60 | c(6:10, 1:5) 61 | ) 62 | 63 | expect_equal( 64 | rray_dim_names(rray_flip(y, 3))[[3]], 65 | rev(rray_dim_names(y)[[3]]) 66 | ) 67 | 68 | expect_equal( 69 | as.vector(rray_flip(y, 3)), 70 | c(9:12, 5:8, 1:4) 71 | ) 72 | 73 | }) 74 | 75 | test_that("can flip with NULL", { 76 | expect_equal(rray_flip(NULL, 1), NULL) 77 | }) 78 | -------------------------------------------------------------------------------- /tests/testthat/test-full-like.R: -------------------------------------------------------------------------------- 1 | context("test-full-like") 2 | 3 | test_that("can perform a basic fill", { 4 | x <- array(1:10) 5 | expect_equal( 6 | rray_full_like(x, 1L), 7 | array(rep(1L, 10)) 8 | ) 9 | }) 10 | 11 | test_that("rray class is retained", { 12 | x <- rray(1:10, c(5, 2)) 13 | expect_equal( 14 | rray_full_like(x, 0), 15 | rray(0L, c(5, 2)) 16 | ) 17 | }) 18 | 19 | test_that("can catch `value` with length >1", { 20 | expect_error(rray_full_like(1, c(1, 2)), "1, not 2") 21 | }) 22 | 23 | test_that("can coerce `value` as needed", { 24 | expect_is( 25 | rray_full_like(rray(1), 1L), 26 | "vctrs_rray_dbl" 27 | ) 28 | 29 | expect_is( 30 | rray_full_like(rray(1), TRUE), 31 | "vctrs_rray_dbl" 32 | ) 33 | 34 | expect_error(rray_full_like(rray(1), "foo"), class = "vctrs_error_cast_lossy") 35 | }) 36 | 37 | test_that("character `value` is supported", { 38 | expect_equal(rray_full_like(rray(1), "2"), rray(2)) 39 | }) 40 | 41 | test_that("arrays of >1 dimensionality are supported", { 42 | expect_equal( 43 | rray_full_like(rray(c(TRUE, FALSE)), array(1, c(1, 1))), 44 | rray(c(TRUE, TRUE)) 45 | ) 46 | 47 | expect_equal( 48 | rray_full_like(rray(c(TRUE, FALSE)), array(1, c(1, 1, 1))), 49 | rray(c(TRUE, TRUE)) 50 | ) 51 | }) 52 | 53 | test_that("can fill 3D", { 54 | expect_equal( 55 | rray_full_like(rray(1:12, c(2, 3, 2)), 0), 56 | rray(0L, c(2, 3, 2)) 57 | ) 58 | }) 59 | 60 | test_that("`NULL` input returns `NULL`", { 61 | expect_equal(rray_full_like(NULL, 1), NULL) 62 | }) 63 | 64 | test_that("0-length input is supported", { 65 | expect_equal(rray_full_like(numeric(), 1), array(numeric())) 66 | }) 67 | 68 | test_that("ones of different types are generated", { 69 | expect_identical(rray_ones_like(rray(2L)), rray(1L)) 70 | expect_identical(rray_ones_like(rray(2)), rray(1)) 71 | expect_identical(rray_ones_like(rray(FALSE)), rray(TRUE)) 72 | }) 73 | 74 | test_that("zeroes of different types are generated", { 75 | expect_identical(rray_zeros_like(rray(2L)), rray(0L)) 76 | expect_identical(rray_zeros_like(rray(2)), rray(0)) 77 | expect_identical(rray_zeros_like(rray(FALSE)), rray(FALSE)) 78 | }) 79 | -------------------------------------------------------------------------------- /tests/testthat/test-hypot.R: -------------------------------------------------------------------------------- 1 | test_that("basic", { 2 | expect_equal(rray_hypot(2, 3), new_array(sqrt(2^2 + 3^2))) 3 | expect_equal(rray_hypot(TRUE, TRUE), new_array(sqrt(1^2 + 1^2))) 4 | }) 5 | 6 | test_that("broadcasting is performed", { 7 | expect_equal( 8 | rray_hypot(matrix(1:2), matrix(1:2, 1)), 9 | 10 | new_matrix( 11 | c( 12 | sqrt(1 ^ 2 + 1 ^ 2), 13 | sqrt(1 ^ 2 + 2 ^ 2), 14 | sqrt(2 ^ 2 + 1 ^ 2), 15 | sqrt(2 ^ 2 + 2 ^ 2) 16 | ), 17 | c(2, 2) 18 | ) 19 | ) 20 | }) 21 | 22 | test_that("dimension names are kept", { 23 | x <- rray(1, dim = c(1, 1), dim_names = list("r1", NULL)) 24 | y <- rray(2, dim = c(1, 1), dim_names = list("rr1", "cc1")) 25 | expect_equal(rray_dim_names(rray_hypot(x, y)), list("r1", "cc1")) 26 | expect_equal(rray_dim_names(rray_hypot(y, x)), rray_dim_names(y)) 27 | }) 28 | 29 | test_that("corner cases", { 30 | expect_equal(rray_hypot(Inf, 1), new_array(Inf)) 31 | expect_equal(rray_hypot(-Inf, 1), new_array(Inf)) 32 | 33 | expect_equal(rray_hypot(0, 0), new_array(0)) 34 | 35 | expect_equal(rray_hypot(NaN, NaN), new_array(NaN)) 36 | }) 37 | -------------------------------------------------------------------------------- /tests/testthat/test-inner-type.R: -------------------------------------------------------------------------------- 1 | context("test-inner-type") 2 | 3 | xs <- list(logical(), integer(), double(), character()) 4 | 5 | # ------------------------------------------------------------------------------ 6 | # Base R atomic inner types 7 | 8 | for (x in xs) { 9 | test_that(glue::glue("inner type for {typeof(x)}."), { 10 | expect_equal(vec_ptype_inner(x), x) 11 | }) 12 | } 13 | 14 | # ------------------------------------------------------------------------------ 15 | # Bad `x` 16 | 17 | bad_x <- new_vctr(1, class = "unknown", inherit_base_type = FALSE) 18 | 19 | test_that("unknown inner types are caught", { 20 | expect_error(vec_ptype_inner(bad_x)) 21 | }) 22 | 23 | # ------------------------------------------------------------------------------ 24 | # Unspecified 25 | 26 | test_that("unspecified inner type is logical()", { 27 | expect_equal(vec_ptype_inner(vctrs::unspecified()), logical()) 28 | }) 29 | 30 | # ------------------------------------------------------------------------------ 31 | # NULL 32 | 33 | test_that("inner type allows NULL `x`", { 34 | expect_equal(vec_ptype_inner(NULL), NULL) 35 | }) 36 | 37 | # ------------------------------------------------------------------------------ 38 | # rray inner type 39 | 40 | test_that("rray inner types are base R constructor objects", { 41 | expect_equal(vec_ptype_inner(rray(1)), numeric()) 42 | expect_equal(vec_ptype_inner(rray(TRUE)), logical()) 43 | expect_equal(vec_ptype_inner(rray(1L)), integer()) 44 | }) 45 | 46 | # ------------------------------------------------------------------------------ 47 | # common inner type 48 | 49 | test_that("common inner type can be found", { 50 | expect_equal(vec_ptype_inner_common(1, 1L), numeric()) 51 | expect_equal(vec_ptype_inner_common(matrix(1), matrix(1L)), numeric()) 52 | expect_equal(vec_ptype_inner_common(rray(TRUE), matrix(1L)), integer()) 53 | }) 54 | 55 | test_that("common inner type with 1 input", { 56 | expect_equal(vec_ptype_inner_common(1), numeric()) 57 | }) 58 | 59 | test_that("common inner type with no input", { 60 | expect_equal(vec_ptype_inner_common(), NULL) 61 | }) 62 | 63 | test_that("can specify ptype", { 64 | expect_equal(vec_ptype_inner_common(.ptype = 1), numeric()) 65 | expect_equal(vec_ptype_inner_common(.ptype = rray(1)), numeric()) 66 | }) 67 | 68 | test_that("common inner type errors with characters", { 69 | expect_error(vec_ptype_inner_common(1, character()), class = "vctrs_error_incompatible_type") 70 | expect_error(vec_ptype_inner_common(TRUE, character()), class = "vctrs_error_incompatible_type") 71 | expect_error(vec_ptype_inner_common(1L, character()), class = "vctrs_error_incompatible_type") 72 | }) 73 | -------------------------------------------------------------------------------- /tests/testthat/test-max-pos.R: -------------------------------------------------------------------------------- 1 | context("test-max-pos") 2 | 3 | test_that("can compute max positions", { 4 | 5 | x <- rray(1:5) 6 | 7 | expect_equal( 8 | rray_max_pos(x), 9 | rray(5L) 10 | ) 11 | 12 | xx <- rray_reshape(x, c(5, 1)) 13 | 14 | expect_equal( 15 | rray_max_pos(xx, NULL), 16 | rray(5L, c(1, 1)) 17 | ) 18 | 19 | # https://github.com/QuantStack/xtensor/issues/1487 20 | expect_equal( 21 | rray_max_pos(xx, 1), 22 | rray(5L, c(1, 1)) 23 | ) 24 | 25 | expect_equal( 26 | rray_max_pos(xx, 2), 27 | rray(rep(1L, times = 5), c(5, 1)) 28 | ) 29 | 30 | }) 31 | 32 | test_that("dimension names are kept", { 33 | 34 | x <- rray(1:5, c(5, 1)) 35 | x <- rray_set_col_names(x, "c1") 36 | x <- rray_set_row_names(x, letters[1:5]) 37 | 38 | expect_equal( 39 | rray_dim_names(rray_max_pos(x, 1)), 40 | c(rray_empty_dim_names(1), rray_col_names(x)) 41 | ) 42 | 43 | expect_equal( 44 | rray_dim_names(rray_max_pos(x, 2)), 45 | rray_dim_names(x) 46 | ) 47 | 48 | xx <- rray_broadcast(x, c(5, 2)) 49 | xx <- rray_set_col_names(xx, c("c1", "c2")) 50 | 51 | expect_equal( 52 | rray_dim_names(rray_max_pos(xx, 2)), 53 | c(list(rray_row_names(xx)), rray_empty_dim_names(1)) 54 | ) 55 | }) 56 | 57 | # Confirming that the row major + column major iteration 58 | # combination results in correct behavior 59 | test_that("3D objects are iterated over correctly", { 60 | 61 | x <- rray(c(1, 5, 3, 6, 10, 2, 5, 12, 8, 21, 1, 4, 20, 5, 7, 18, 3, 9), c(3, 3, 2)) 62 | 63 | # fully column major iteration over all axes 64 | expect_equal(rray_max_pos(x), rray(10L, c(1, 1, 1))) 65 | 66 | # argmax() is row major iteration, then the 67 | # keep dims reshape is column major 68 | expect_equal( 69 | rray_max_pos(x, 1), 70 | rray(c(2L, 2L, 2L, 1L, 1L, 1L), c(1, 3, 2)) 71 | ) 72 | 73 | expect_equal( 74 | rray_max_pos(x, 2), 75 | rray(c(2L, 3L, 3L, 1L, 2L, 3L), c(3, 1, 2)) 76 | ) 77 | 78 | }) 79 | -------------------------------------------------------------------------------- /tests/testthat/test-min-pos.R: -------------------------------------------------------------------------------- 1 | context("test-min-pos") 2 | 3 | test_that("can compute min positions", { 4 | 5 | x <- rray(1:5) 6 | 7 | expect_equal( 8 | rray_min_pos(x), 9 | rray(1L) 10 | ) 11 | 12 | xx <- rray_reshape(x, c(5, 1)) 13 | 14 | expect_equal( 15 | rray_min_pos(xx, NULL), 16 | rray(1L, c(1, 1)) 17 | ) 18 | 19 | expect_equal( 20 | rray_min_pos(xx, 1), 21 | rray(1L, c(1, 1)) 22 | ) 23 | 24 | xxx <- rray(cbind(xx * 2, xx)) 25 | 26 | expect_equal( 27 | rray_min_pos(xxx, 2), 28 | rray(rep(2L, times = 5), c(5, 1)) 29 | ) 30 | 31 | y <- rray_flip(xx, 1) 32 | 33 | # TODO - https://github.com/QuantStack/xtensor/issues/1487 34 | expect_equal( 35 | rray_min_pos(y, 1), 36 | rray(5L, c(1, 1)) 37 | ) 38 | 39 | }) 40 | 41 | test_that("dimension names are kept", { 42 | 43 | x <- rray(1:5, c(5, 1)) 44 | x <- rray_set_col_names(x, "c1") 45 | x <- rray_set_row_names(x, letters[1:5]) 46 | 47 | expect_equal( 48 | rray_dim_names(rray_min_pos(x, 1)), 49 | c(rray_empty_dim_names(1), rray_col_names(x)) 50 | ) 51 | 52 | expect_equal( 53 | rray_dim_names(rray_min_pos(x, 2)), 54 | rray_dim_names(x) 55 | ) 56 | 57 | xx <- rray_broadcast(x, c(5, 2)) 58 | xx <- rray_set_col_names(xx, c("c1", "c2")) 59 | 60 | expect_equal( 61 | rray_dim_names(rray_min_pos(xx, 2)), 62 | c(list(rray_row_names(xx)), rray_empty_dim_names(1)) 63 | ) 64 | }) 65 | 66 | # Confirming that the row major + column major iteration 67 | # combination results in correct behavior 68 | test_that("3D objects are iterated over correctly", { 69 | 70 | x <- rray(c(1, 5, 3, 6, 10, 2, 5, 12, 8, 21, 1, 4, 20, 5, 7, 18, 3, 9), c(3, 3, 2)) 71 | 72 | # fully column major iteration over all axes 73 | expect_equal(rray_min_pos(x), rray(1L, c(1, 1, 1))) 74 | 75 | # argmax() is row major iteration, then the 76 | # keep dims reshape is column major 77 | expect_equal( 78 | rray_min_pos(x, 1), 79 | rray(c(1L, 3L, 1L, 2L, 2L, 2L), c(1, 3, 2)) 80 | ) 81 | 82 | expect_equal( 83 | rray_min_pos(x, 2), 84 | rray(c(1L, 1L, 2L, 3L, 1L, 1L), c(3, 1, 2)) 85 | ) 86 | 87 | }) 88 | -------------------------------------------------------------------------------- /tests/testthat/test-multiply-add.R: -------------------------------------------------------------------------------- 1 | test_that("rray_multiply_add() basics", { 2 | 3 | expect_equal(rray_multiply_add(1, 2, 1), new_array(3)) 4 | expect_equal(rray_multiply_add(1L, 2L, 1L), new_array(3L)) 5 | 6 | # broadcasting 7 | x <- matrix(1:5) 8 | expect_equal(rray_dim(rray_multiply_add(x, t(x), x)), c(5, 5)) 9 | 10 | # with names 11 | x <- rray(c(0, 0), c(2, 1), list(c("r1", "r2"), "c1")) 12 | expect_equal( 13 | rray_multiply_add(x, 1, 1), 14 | rray(c(1, 1), c(2, 1), list(c("r1", "r2"), "c1")) 15 | ) 16 | 17 | }) 18 | 19 | test_that("rray_multiply_add() corner cases", { 20 | 21 | # Logicals 22 | expect_equal(rray_multiply_add(TRUE, TRUE, TRUE), new_array(2L)) 23 | expect_equal(rray_multiply_add(FALSE, FALSE, FALSE), new_array(0L)) 24 | 25 | # NaN 26 | expect_equal(rray_multiply_add(NaN, NaN, NaN), as_array(NaN)) 27 | 28 | # Inf 29 | expect_equal(rray_multiply_add(-Inf, -1, 1), as_array(Inf)) 30 | }) 31 | -------------------------------------------------------------------------------- /tests/testthat/test-names.R: -------------------------------------------------------------------------------- 1 | context("test-names") 2 | 3 | test_that("can assign names() on 1D rrays", { 4 | 5 | x <- rray(1:5) 6 | 7 | names(x) <- letters[1:5] 8 | 9 | expect_equal( 10 | rray_dim_names(x), 11 | list(letters[1:5]) 12 | ) 13 | 14 | expect_is(x, "vctrs_rray") 15 | 16 | x_unnamed <- unname(x) 17 | expect_equal(attr(x_unnamed, "dimnames"), rray_empty_dim_names(1)) 18 | 19 | }) 20 | 21 | test_that("cannot assign names() on a 2D+ rray", { 22 | x <- rray(1:5, dim = c(5, 1)) 23 | expect_error(names(x) <- letters[1:5], "Cannot set `names`") 24 | }) 25 | -------------------------------------------------------------------------------- /tests/testthat/test-pad.R: -------------------------------------------------------------------------------- 1 | context("test-pad") 2 | 3 | test_that("pad structure", { 4 | expect_is(pad(), "vctrs_pad") 5 | }) 6 | 7 | test_that("can pad the front side", { 8 | x <- rray(1:4, c(1, 1, 2, 2)) 9 | expect_equal(x[pad(), 1], x[, , , 1]) 10 | expect_equal(x[pad(), 1, 1], x[, , 1, 1]) 11 | expect_equal(x[pad(), 1, 1], x[, , 1, 1]) 12 | }) 13 | 14 | test_that("can pad the middle", { 15 | x <- rray(1:8, c(2, 1, 2, 2)) 16 | expect_equal(x[1, pad(), 1], x[1, , , 1]) 17 | expect_equal(x[1, pad(), 1, 1], x[1, , 1, 1]) 18 | }) 19 | 20 | test_that("pad() is the same as asking for the entire array", { 21 | x <- rray(1:8, c(2, 1, 2, 2)) 22 | expect_equal(x[pad()], x[]) 23 | expect_equal(x[pad()], x) 24 | }) 25 | 26 | test_that("padding is ignored if not required", { 27 | x <- rray(1:8, c(2, 1, 2, 2)) 28 | expect_equal(x[pad(), 1, 1, 1, 1], x[1, 1, 1, 1]) 29 | expect_equal(x[1, pad(), 1, 1, 1], x[1, 1, 1, 1]) 30 | expect_equal(x[1, 1, 1, 1, pad()], x[1, 1, 1, 1]) 31 | }) 32 | 33 | test_that("pad() allows dimensionality errors through correctly", { 34 | x <- rray(1:8, c(2, 1, 2, 2)) 35 | expect_error(x[pad(), 1, 1, 1, 1, 1], "into dimension 5") 36 | expect_error(x[1, pad(), 1, 1, 1, 1], "into dimension 5") 37 | expect_error(x[1, 1, 1, 1, 1, 1, pad()], "into dimension 6") 38 | }) 39 | 40 | test_that("can pad() base R", { 41 | x <- new_array(1:8, c(2, 1, 2, 2)) 42 | expect_equal(rray_subset(x, pad(), 1), x[, , , 1, drop = FALSE]) 43 | }) 44 | 45 | test_that("cannot have more than 1 pad()", { 46 | x <- rray(1:8, c(2, 1, 2, 2)) 47 | expect_error(x[pad(), pad()], "Only one") 48 | expect_error(x[pad(), 1, pad()], "Only one") 49 | expect_error(x[1, 1, pad(), pad()], "Only one") 50 | }) 51 | 52 | test_that("pad format", { 53 | expect_equal(format(pad()), "") 54 | }) 55 | -------------------------------------------------------------------------------- /tests/testthat/test-print.R: -------------------------------------------------------------------------------- 1 | test_that("printing works as expected", { 2 | expect_known_output(print(rray(1)), test_path("out/test-1D-rray.txt")) 3 | expect_known_output(print(rray(1, c(1, 1))), test_path("out/test-2D-rray.txt")) 4 | }) 5 | 6 | test_that("printing works when one axis is 0", { 7 | expect_known_output(print(rray(numeric())), test_path("out/test-0-axis-1D.txt")) 8 | expect_known_output(print(rray(numeric(), c(0, 1))), test_path("out/test-0-axis-2D.txt")) 9 | expect_known_output(print(rray(numeric(), c(0, 1, 0))), test_path("out/test-0-axis-3D.txt")) 10 | }) 11 | 12 | test_that("str() prints correct", { 13 | x <- rray(1:5) 14 | expect_known_output(str(x), test_path("out/test-str-1.txt")) 15 | 16 | # test long vector 17 | y <- rray(1:50) 18 | expect_known_output(str(y), test_path("out/test-str-2.txt")) 19 | }) 20 | 21 | test_that("str() prints 2D+ correctly", { 22 | x <- rray(1, c(1, 1)) 23 | expect_known_output(str(x), test_path("out/test-str-3.txt")) 24 | 25 | y <- rray(1:50, c(1, 1, 50)) 26 | expect_known_output(str(y), test_path("out/test-str-4.txt")) 27 | }) 28 | 29 | test_that("abbreviation is correct", { 30 | expect_equal(vec_ptype_abbr(rray()), "rray") 31 | }) 32 | 33 | test_that("full ptype is correct", { 34 | expect_equal(vec_ptype_full(rray(1)), "rray") 35 | expect_equal(vec_ptype_full(rray(1L)), "rray") 36 | expect_equal(vec_ptype_full(rray(TRUE)), "rray") 37 | 38 | expect_equal(vec_ptype_full(rray(1, c(1, 1))), "rray[,1]") 39 | expect_equal(vec_ptype_full(rray(1, c(1, 1, 1))), "rray[,1,1]") 40 | expect_equal(vec_ptype_full(rray(numeric(), c(0, 1, 1))), "rray[,1,1]") 41 | }) 42 | -------------------------------------------------------------------------------- /tests/testthat/test-reducers-custom.R: -------------------------------------------------------------------------------- 1 | # context("test-reducers-custom") 2 | # 3 | # x <- rray(1:4) 4 | # y <- rray_reshape(x, c(2, 2)) 5 | # 6 | # test_that("Results are equivalent to rray_sum()", { 7 | # # sum converts integers to doubles 8 | # expect_equal(rray_sum(y, axes = 1), rray_reduce_dbl(y, sum)) 9 | # expect_equal(rray_sum(y, axes = 2), rray_reduce_dbl(y, sum, axes = 2)) 10 | # }) 11 | # 12 | # test_that("Lambda functions are allowed", { 13 | # expect_equal( 14 | # vec_data(rray_reduce_dbl(y, ~.x / .y)), 15 | # c(.5, .75) 16 | # ) 17 | # }) 18 | # 19 | # test_that("Dimension names are kept", { 20 | # 21 | # yy <- rray_set_col_names(y, c("c1", "c2")) 22 | # yy <- rray_set_row_names(yy, letters[1:2]) 23 | # 24 | # expect_equal( 25 | # rray_col_names(rray_reduce_int(yy, ~.x + .y)), 26 | # c("c1", "c2") 27 | # ) 28 | # 29 | # expect_equal( 30 | # rray_row_names(rray_reduce_int(yy, ~.x + .y, axes = 2)), 31 | # letters[1:2] 32 | # ) 33 | # 34 | # }) 35 | # 36 | # test_that("Can reduce over multiple axes", { 37 | # out <- rray_reduce_dbl(rray(1, c(2, 3, 4)), ~ .x + .y, axes = c(1, 2)) 38 | # expect_equal(vec_data(out), rep(6, times = 4)) 39 | # expect_equal(rray_dim(out), c(1, 1, 4)) 40 | # }) 41 | # 42 | # test_that("Can reduce base R objects", { 43 | # y_mat <- as.matrix(y) 44 | # expect_equal( 45 | # rray_reduce_int(y_mat, ~.x + .y), 46 | # matrix(c(3L, 7L), ncol = 2, dimnames = list(NULL, NULL)) 47 | # ) 48 | # }) 49 | # 50 | # test_that("Reducing where x is initially int then becomes dbl works", { 51 | # x <- rray(1:5, c(5, 1)) 52 | # 53 | # # informative to see what is happening 54 | # # if its working, we get 1, 1.5, 2, 2.5 55 | # # if not working, get 1 1 1 1 56 | # # rray_reduce_dbl(x, ~{print(.x); .x + .5}) 57 | # 58 | # # If this doesn't work, the result is 1.5 because .x is coerced 59 | # # down to int each time. Bad! 60 | # expect_equal( 61 | # vec_data(rray_reduce_dbl(x, ~.x + .5)), 62 | # 3 63 | # ) 64 | # }) 65 | # 66 | # test_that("Reducing to 0D works", { 67 | # 68 | # x_mat <- as.matrix(x) 69 | # 70 | # sum_1D <- rray_reduce_dbl(x, `+`, axes = 1L) 71 | # sum_2D <- rray_reduce_dbl(x_mat, `+`, axes = c(1, 2)) 72 | # 73 | # expect_equal(rray_dim(sum_1D), 1L) 74 | # expect_equal(rray_dim(sum_2D), c(1L, 1L)) 75 | # 76 | # expect_equal(vec_data(sum_1D), 10) 77 | # expect_equal(vec_data(sum_2D), 10) 78 | # }) 79 | -------------------------------------------------------------------------------- /tests/testthat/test-slice-assign.R: -------------------------------------------------------------------------------- 1 | test_that("can get identical results with slice assign and subset assign", { 2 | x <- array(1:8, c(2, 2, 2)) 3 | expect <- x 4 | 5 | rray_slice(x, 1, 2) <- 1 6 | rray_subset(expect, , 1) <- 1 7 | 8 | expect_equal(x, expect) 9 | 10 | rray_slice(x, 2, 3) <- matrix(1:2, nrow = 1) 11 | rray_subset(expect, , , 2) <- matrix(1:2, nrow = 1) 12 | 13 | expect_equal(x, expect) 14 | }) 15 | -------------------------------------------------------------------------------- /tests/testthat/test-slice.R: -------------------------------------------------------------------------------- 1 | test_that("can get identical results with slice and subset", { 2 | x <- array(1:8, c(2, 2, 2)) 3 | 4 | expect_equal(rray_slice(x, 1, 2), rray_subset(x, , 1)) 5 | expect_equal(rray_slice(x, 1, 1), rray_subset(x, 1)) 6 | expect_equal(rray_slice(x, 2, 3), rray_subset(x, , , 2)) 7 | }) 8 | 9 | test_that("slice can use logical and character indices", { 10 | x <- array(1:8, c(2, 2, 2), dimnames = list(c("r1", "r2"))) 11 | 12 | expect_equal(rray_slice(x, TRUE, 1), rray_subset(x, TRUE)) 13 | expect_equal(rray_slice(x, c(TRUE, FALSE), 3), rray_subset(x, , , c(TRUE, FALSE))) 14 | expect_equal(rray_slice(x, "r1", 1), rray_subset(x, "r1")) 15 | }) 16 | -------------------------------------------------------------------------------- /tests/testthat/test-sort.R: -------------------------------------------------------------------------------- 1 | context("test-sort") 2 | 3 | test_that("can sort vectors", { 4 | x <- rray(10:1) 5 | expect_equal(rray_sort(x), rray(1:10)) 6 | expect_equal(rray_sort(x), rray_sort(x, axis = 1)) 7 | }) 8 | 9 | test_that("can sort matrices", { 10 | x <- rray(c(5:1, 6:10), c(5, 2)) 11 | 12 | # global sort 13 | expect_equal(rray_sort(x), rray(1:10, c(5, 2))) 14 | 15 | # along rows 16 | expect_equal(rray_sort(x, axis = 1), rray(1:10, c(5, 2))) 17 | 18 | # along cols 19 | x[[1]] <- 7 20 | expect_equal(rray_sort(x, axis = 2), rray(c(6L, 4:1, 7L, 7:10), c(5, 2))) 21 | }) 22 | 23 | test_that("can sort 3D arrays", { 24 | x <- rray(12:1, c(2, 3, 2)) 25 | 26 | expect_equal(rray_sort(x), rray(1:12, c(2, 3, 2))) 27 | 28 | expect_equal(rray_sort(x, axis = 1), rray(c(11:12, 9:10, 7:8, 5:6, 3:4, 1:2), c(2, 3, 2))) 29 | 30 | expect_equal(rray_sort(x, axis = 2), rray(c(8:7, 10:9, 12:11, 2:1, 4:3, 6:5), c(2, 3, 2))) 31 | 32 | expect_equal(rray_sort(x, axis = 3), rray_bind(x[,,2], x[,,1], .axis = 3)) 33 | }) 34 | 35 | test_that("error is thrown when trying to sort on unknown axis", { 36 | x <- 1:10 37 | expect_error(rray_sort(x, 2)) 38 | }) 39 | 40 | test_that("sorting drops the names along the axis", { 41 | 42 | x <- rray( 43 | c(2, 1, 1, 2), 44 | dim = c(2, 2), 45 | dim_names = list( 46 | r = c("r1", "r2"), 47 | c = c("c1", "c2") 48 | ) 49 | ) 50 | 51 | expect_equal( 52 | rray_dim_names(rray_sort(x, axis = 1L)), 53 | list(r = NULL, c = c("c1", "c2")) 54 | ) 55 | 56 | expect_equal( 57 | rray_dim_names(rray_sort(x, axis = 2L)), 58 | list(r = c("r1", "r2"), c = NULL) 59 | ) 60 | 61 | # dropped along all axes 62 | expect_equal( 63 | rray_dim_names(rray_sort(x)), 64 | list(r = NULL, c = NULL) 65 | ) 66 | }) 67 | -------------------------------------------------------------------------------- /tests/testthat/test-subset-assign.R: -------------------------------------------------------------------------------- 1 | test_that("can use a subset assign", { 2 | x <- rray(1:8, dim = c(2, 2, 2)) 3 | rray_subset(x, 1, 1, 1) <- NA 4 | expect_is(x, "vctrs_rray") 5 | expect_equal(storage.mode(x), "integer") 6 | expect_equal(as.vector(x), c(NA, 2:8)) 7 | }) 8 | 9 | test_that("value is broadcast in subset assign", { 10 | x <- rray(1:8, dim = c(2, 2, 2)) 11 | rray_subset(x, 1:2, 1) <- NA 12 | expect_equal(as.vector(x), c(NA, NA, 3, 4, NA, NA, 7, 8)) 13 | }) 14 | 15 | test_that("assigning to 0 does nothing", { 16 | x <- rray(1:8, dim = c(2, 2, 2)) 17 | rray_subset(x, 0) <- 1 18 | expect_equal(x, rray(1:8, dim = c(2, 2, 2))) 19 | 20 | x <- rray(1:8, dim = c(2, 2, 2)) 21 | rray_subset(x, 0, 1) <- 1 22 | expect_equal(x, rray(1:8, dim = c(2, 2, 2))) 23 | }) 24 | 25 | test_that("assigning to NULL does nothing", { 26 | x <- rray(1:8, dim = c(2, 2, 2)) 27 | rray_subset(x, NULL) <- 1 28 | expect_equal(x, rray(1:8, dim = c(2, 2, 2))) 29 | }) 30 | 31 | test_that("broadcast can fail gracefully in subset assign", { 32 | x <- rray(1:8, dim = c(2, 2, 2)) 33 | expect_error(rray_subset(x, 1, 1) <- c(1, 2), "due to dimension 1") 34 | }) 35 | 36 | test_that("cannot assign down in dimensionality", { 37 | x <- 1 38 | expect_error(rray_subset(x, 1) <- matrix(1), "from 2 to 1") 39 | }) 40 | 41 | test_that("can subset assign with shaped input", { 42 | x <- rray(1:8, dim = c(2, 2, 2)) 43 | expect_error(rray_subset(x, , 1) <- matrix(1:2), NA) 44 | expect_equal( 45 | as.vector(x), 46 | c(1:4, 1:2, 7:8) 47 | ) 48 | }) 49 | 50 | test_that("can subset assign with base R objects", { 51 | x <- matrix(1:8, nrow = 2) 52 | rray_subset(x, 1) <- matrix(4:1, nrow = 1) 53 | expect_equal(as.vector(x), c(4, 2, 3, 4, 2, 6, 1, 8)) 54 | }) 55 | 56 | test_that("subset assign keeps names", { 57 | nms <- list(r = "r1", c = "c1") 58 | x <- array(1, c(1, 1), dimnames = nms) 59 | rray_subset(x, 1) <- 2 60 | expect_equal(rray_dim_names(x), nms) 61 | }) 62 | 63 | test_that("subset assigning a non-vector is an error", { 64 | x <- array(1:5) 65 | expect_error(rray_subset(x, 1) <- NULL, class = "vctrs_error_scalar_type") 66 | expect_error(rray_subset(x, 1) <- environment(), class = "vctrs_error_scalar_type") 67 | }) 68 | -------------------------------------------------------------------------------- /tests/testthat/test-tile.R: -------------------------------------------------------------------------------- 1 | context("test-tile") 2 | 3 | test_that("can tile a vector", { 4 | 5 | x <- new_array(1:5) 6 | 7 | expect_equal( 8 | rray_tile(x, 2), 9 | as_array(c(x, x)) 10 | ) 11 | 12 | expect_equal( 13 | rray_tile(x, c(1, 1)), 14 | new_matrix(x) 15 | ) 16 | }) 17 | 18 | test_that("can tile a matrix", { 19 | 20 | x <- new_matrix(1:5) 21 | 22 | expect_equal( 23 | rray_tile(x, 2), 24 | new_matrix(c(x, x)) 25 | ) 26 | }) 27 | 28 | test_that("can tile a 3D array", { 29 | 30 | x <- new_array(1:8, c(2, 2, 2)) 31 | 32 | expect_equal( 33 | rray_tile(x, 2), 34 | new_array(c(1:2, 1:2, 3:4, 3:4, 5:6, 5:6, 7:8, 7:8), c(4, 2, 2)) 35 | ) 36 | 37 | expect_equal( 38 | rray_tile(x, c(1, 1, 1, 1)), 39 | rray_expand(x, 4) 40 | ) 41 | 42 | }) 43 | 44 | test_that("names are carried along when tiling", { 45 | 46 | x <- new_array(1:5, c(5, 1), list(letters[1:5], "c1")) 47 | 48 | expect_equal( 49 | rray_row_names(rray_tile(x, 2)), 50 | rep(rray_row_names(x), 2) 51 | ) 52 | 53 | expect_equal( 54 | rray_col_names(rray_tile(x, 2)), 55 | rray_col_names(x) 56 | ) 57 | 58 | }) 59 | 60 | test_that("can tile length 0 input", { 61 | 62 | x <- new_array(numeric()) 63 | 64 | expect_equal( 65 | rray_tile(x, 1), 66 | x 67 | ) 68 | 69 | expect_equal( 70 | rray_tile(x, c(1, 2)), 71 | new_array(numeric(), c(0, 2)) 72 | ) 73 | 74 | expect_equal( 75 | rray_tile(x, c(1, 2)), 76 | rray_tile(x, c(2, 2)) 77 | ) 78 | 79 | expect_equal( 80 | rray_tile(x, c(1, 2, 1)), 81 | new_array(numeric(), c(0, 2, 1)) 82 | ) 83 | }) 84 | 85 | test_that("can tile 0 column input", { 86 | 87 | x <- new_matrix(numeric(), c(1, 0)) 88 | 89 | expect_equal( 90 | rray_tile(x, 1), 91 | x 92 | ) 93 | 94 | expect_equal( 95 | rray_tile(x, 2), 96 | rbind(x, x) 97 | ) 98 | 99 | expect_equal( 100 | rray_tile(x, c(1, 2)), 101 | x 102 | ) 103 | }) 104 | 105 | test_that("`NULL` input", { 106 | expect_equal(rray_tile(NULL, c(1, 2)), NULL) 107 | }) 108 | -------------------------------------------------------------------------------- /tests/testthat/test-transpose.R: -------------------------------------------------------------------------------- 1 | context("test-transpose") 2 | 3 | test_that("can transpose a base R matrix with names", { 4 | 5 | x <- matrix(1:6, c(3, 2), dimnames = list(letters[1:3], letters[4:5])) 6 | 7 | expect_equal( 8 | rray_transpose(x), 9 | t(x) 10 | ) 11 | }) 12 | 13 | test_that("can transpose a 3D array with names", { 14 | 15 | x <- new_array(1:2, c(2, 1, 2), dimnames = list(letters[1:2], letters[3], letters[4:5])) 16 | 17 | expect_equal( 18 | rray_transpose(x), 19 | aperm(x) 20 | ) 21 | 22 | }) 23 | 24 | test_that("transposing a 1D array does nothing", { 25 | expect_equal( 26 | rray_transpose(1:5), 27 | new_array(1:5) 28 | ) 29 | }) 30 | 31 | test_that("t() method for rray objects follows base behavior", { 32 | 33 | x <- rray(1:5) 34 | 35 | expect_equal( 36 | rray(1:5, c(1, 5)), 37 | t(x) 38 | ) 39 | 40 | }) 41 | 42 | test_that("t() errors on >2D", { 43 | xx <- rray(1:6, c(3, 2, 1)) 44 | expect_error(t(xx), "do you need `rray_transpose()`?") 45 | }) 46 | 47 | test_that("aperm() method for rray objects", { 48 | 49 | x <- rray(1:5) 50 | 51 | expect_equal( 52 | rray_transpose(x), 53 | aperm(x) 54 | ) 55 | 56 | xx <- rray(1:6, c(3, 2, 1)) 57 | 58 | expect_equal( 59 | rray_transpose(xx), 60 | aperm(xx) 61 | ) 62 | 63 | expect_equal( 64 | rray_transpose(xx, c(2, 1, 3)), 65 | aperm(xx, c(2, 1, 3)) 66 | ) 67 | }) 68 | 69 | test_that("validate permutation", { 70 | expect_error(rray_transpose(1, "hi")) 71 | expect_error(rray_transpose(1, 2), "maximum value for `permutation` is 1") 72 | expect_error(rray_transpose(1, c(1, 2)), "must have size 1 to permute `x`") 73 | expect_error(rray_transpose(matrix(1), c(1, 1)), "more than once: 1") 74 | }) 75 | -------------------------------------------------------------------------------- /tests/testthat/test-type2.R: -------------------------------------------------------------------------------- 1 | context("test-rray-type2") 2 | 3 | test_that("vec_ptype2 with same dimensions", { 4 | x <- as_rray(array(1, dim = c(2, 2, 2))) 5 | 6 | expect_equal(dim(vec_ptype2(x, x)), c(0, 2, 2)) 7 | expect_equal(vec_ptype2(x, x), vec_ptype(x)) 8 | 9 | expect_equal(dim(vec_ptype(x[0,0])), c(0, 0, 2)) 10 | 11 | expect_equal(vec_ptype_common(x, x), vec_ptype2(x, x)) 12 | }) 13 | 14 | 15 | test_that("Common dim is found", { 16 | 17 | x <- as_rray(array(1, dim = c(2, 2, 2))) 18 | y <- as_rray(array(1, dim = c(2, 2))) 19 | 20 | # common dim 21 | expect_equal(dim(vec_ptype2(x, y)), c(0, 2, 2)) 22 | expect_equal(dim(vec_ptype2(y, x)), c(0, 2, 2)) 23 | 24 | expect_equal(vec_ptype_common(x, y), vec_ptype2(x, y)) 25 | }) 26 | 27 | test_that("Common inner type is found", { 28 | 29 | x <- rray(1) 30 | y <- rray(1L) 31 | z <- 1L 32 | 33 | # numeric + integer 34 | expect_equal(vec_ptype2(x, y), new_rray(numeric())) 35 | 36 | # numeric + integer 37 | expect_equal(vec_ptype2(x, z), new_rray(numeric())) 38 | 39 | # integer + integer 40 | expect_equal(vec_ptype2(y, z), new_rray(integer())) 41 | }) 42 | -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | --------------------------------------------------------------------------------