Skip to content

Commit

Permalink
Plumb through iterated coordinate strider
Browse files Browse the repository at this point in the history
  • Loading branch information
mojaveazure committed Feb 19, 2024
1 parent 5108138 commit d07fadd
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 14 deletions.
1 change: 1 addition & 0 deletions apis/r/NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ S3method(write_soma,character)
S3method(write_soma,data.frame)
S3method(write_soma,matrix)
export(ConfigList)
export(CoordsStrider)
export(EphemeralCollection)
export(EphemeralCollectionBase)
export(EphemeralExperiment)
Expand Down
67 changes: 66 additions & 1 deletion apis/r/R/CoordsStrider.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,34 @@
#' The Coordinate Strider
#'
#' @description The \code{CoordsStrider} allows creating coordinate slices
#' in an interated manner. Alternatively, it can chunk an existing vector of
#' coordinates
#'
#' @keywords internal
#'
#' @export
#'
#' @examples
#' strider <- CoordsStrider$new(start = 1L, end = 200L, stride = 15L)
#' while (strider$hasNext()) {
#' strider$nextElem()
#' }
#'
CoordsStrider <- R6::R6Class(
classname = "CoordsStrider",
cloneable = FALSE,
public = list(
#' @description Create a coordinate strider
#'
#' @param coords An integer vector of coordinates
#' @param ... Ignored
#' @param stride The stride of how many coordinates to yield per iteration;
#' by default, will try to yield all coordinates per iteration
#' @param start If \code{coords} is missing, the starting coordinate
#' to generate
#' @param end If \code{coords} is missing, the ending coordinate
#' to generate
#'
initialize = function(coords, ..., stride = NULL, start = NULL, end = NULL) {
if (missing(coords)) {
stopifnot(
Expand All @@ -25,6 +52,8 @@ CoordsStrider <- R6::R6Class(
stopifnot(rlang::is_integerish(stride, 1L, TRUE) && stride > 0L)
private$.stride <- stride
},
#' @description Print the coordinate strider to the screen
#'
print = function() {
cat("<", class(self)[1L], ">\n", sep = "")
if (is.null(self$coords)) {
Expand All @@ -36,12 +65,22 @@ CoordsStrider <- R6::R6Class(
cat(" stride:", self$stride, "\n")
return(invisible(self))

Check warning on line 66 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L65-L66

Added lines #L65 - L66 were not covered by tests
},
#' @description Determine if there are more coordinates to yield
#'
#' @return \code{TRUE} if there are more coordinates to yield or
#' \code{FALSE} if otherwise
#'
hasNext = function() {
if (is.null(self$coords)) {
return(private$.index <= abs(self$end - self$start))

Check warning on line 75 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L74-L75

Added lines #L74 - L75 were not covered by tests
}
return(private$.index <= length(self$coords))

Check warning on line 77 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L77

Added line #L77 was not covered by tests
},
#' @description Generate the next set of coordinates to yield. If there are
#' no more coordiantes to yield, raises a \code{stopIteration} error
#'
#' @return An integer vector of the next set of coordinates
#'
nextElem = function() {
if (!self$hasNext()) {
private$.stopIteration()

Check warning on line 86 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L85-L86

Added lines #L85 - L86 were not covered by tests
Expand All @@ -63,10 +102,36 @@ CoordsStrider <- R6::R6Class(
}
),
active = list(
#' @field coords If set, the coordinates to iterate over
#'
coords = function() private$.coords,

Check warning on line 107 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L107

Added line #L107 was not covered by tests
#' @field start If set, the starting point of the iterated coordinates;
#' otherwise the minimum value of \code{self$coords}
#'
start = function() ifelse(is.null(self$coords), private$.start, min(self$coords)),

Check warning on line 111 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L111

Added line #L111 was not covered by tests
#' @field end If set, the end point of the iterated coordinates;
#' otherwise the maximum value of \code{self$coords}
#'
end = function() ifelse(is.null(self$coords), private$.end, max(self$coords)),

Check warning on line 115 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L115

Added line #L115 was not covered by tests
stride = function() private$.stride
#' @field stride The stride, or how many coordiantes to generate per
#' iteration; note: this field is settable, which will reset the iterator
#'
stride = function(value) {
if (missing(value)) {
return(private$.stride)

Check warning on line 121 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L120-L121

Added lines #L120 - L121 were not covered by tests
}
stopifnot(rlang::is_integerish(value, n = 1L, finite = TRUE) && value > 0L)
private$.stride <- value
index <- ifelse(is.null(self$coords), yes = 0L, no = 1L)
if (private$.index != index) {
warning(warningCondition(
"The stride has changed, coordinates have been put back at the beginning",
class = "coordsStrideChangedWarning"

Check warning on line 129 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L123-L129

Added lines #L123 - L129 were not covered by tests
))
}
private$.index <- index
return(invisible(NULL))

Check warning on line 133 in apis/r/R/CoordsStrider.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/CoordsStrider.R#L132-L133

Added lines #L132 - L133 were not covered by tests
}
),
private = list(
.coords = NULL,
Expand Down
27 changes: 15 additions & 12 deletions apis/r/R/SOMASparseNDArrayRead.R
Original file line number Diff line number Diff line change
Expand Up @@ -22,30 +22,29 @@ SOMASparseNDArrayReadBase <- R6::R6Class(
"'array' must be a SOMASparseNDArray" = inherits(array, "SOMASparseNDArray")
)
if (is.null(coords)) {
private$.striders <- vector(mode = "list", length = array$ndim())
private$.coords <- vector(mode = "list", length = array$ndim())
shape <- array$shape()
for (i in seq_along(private$.striders)) {
private$.striders[[i]] <- CoordsStrider$new(
for (i in seq_along(private$.coords)) {
private$.coords[[i]] <- CoordsStrider$new(
start = 0L,
end = shape[i],
stride = .Machine$integer.max
)
}
names(private$.striders) <- array$dimnames()
# shape <- array$shape()
# coords <- vector(mode = "list", length = array$ndim())
# for (i in seq_along(coords)) {
# coords[[i]] <- bit64::seq.integer64(0L, shape[i] - 1L)
# }
# names(coords) <- array$dimnames()
names(private$.coords) <- array$dimnames()
} else {
stopifnot(
"'coords' must be a list of integer64 values" = is.list(coords) &&
all(vapply_lgl(coords, inherits, what = c('integer64', 'numeric'))),
"'coords' must be named with the dimnames of 'array'" = is_named(coords, FALSE) &&
all(names(coords) %in% array$dimnames())
)
private$.coords <- coords
private$.coords_vec <- coords
private$.coords <- vector(mode = "list", length = length(coords))
names(private$.coords) <- names(coords)
for (i in names(coords)) {
private$.coords[[i]] <- CoordsStrider$new(coords[[i]], stride = .Machine$integer.max)
}
}
private$.sr <- sr
private$.array <- array
Expand All @@ -57,15 +56,19 @@ SOMASparseNDArrayReadBase <- R6::R6Class(
sr = function() return(private$.sr),
#' @field array The underlying \code{\link{SOMASparseNDArray}}
array = function() return(private$.array),
#' @field coords The coordinates for the read
#' @field coords The iterated coordinates for the read
coords = function() return(private$.coords),

Check warning on line 60 in apis/r/R/SOMASparseNDArrayRead.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/SOMASparseNDArrayRead.R#L60

Added line #L60 was not covered by tests
#' @field coords_vec If \code{coords} is passed, then the coordinate vector
#'
coords_vec = function() return(private$.coords_vec),

Check warning on line 63 in apis/r/R/SOMASparseNDArrayRead.R

View check run for this annotation

Codecov / codecov/patch

apis/r/R/SOMASparseNDArrayRead.R#L63

Added line #L63 was not covered by tests
#' @field shape The shape of the underlying array
shape = function() return(self$array$shape())
),
private = list(
.sr = NULL,
.array = NULL,
.coords = NULL,
.coords_vec = NULL,
.striders = NULL
)
)
Expand Down
110 changes: 110 additions & 0 deletions apis/r/man/CoordsStrider.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apis/r/man/reexports.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit d07fadd

Please sign in to comment.