Rev 4483 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
#### All Methods in relation with the sparseVector (sub)classes# atomicVector : classUnion (logical,integer,double,....)setAs("atomicVector", "sparseVector",function(from) {n <- length(from)r <- new(paste(.V.kind(from), "sparseVector", sep=''), length = n)ii <- from != 0r@x <- from[ii]r@i <- seq_len(n)[ii]r})for(T in c("d","i","l","z")) {setAs("xsparseVector", paste(T, "sparseVector", sep=''),function(from) {from@x <- as(from@x, .type.kind[T])## and now "the hack":class(from) <- paste(T, "sparseVector", sep='')from})}setAs("sparseVector", "nsparseVector",function(from) {if(any(is.na(from@x)))stop("cannot coerce 'NA's to \"nsparseVector\"")new("nsparseVector", i = from@i, length = from@length)})sp2vec <- function(x, mode = .type.kind[substr(cl, 1,1)]) {cl <- class(x)r <- vector(mode, x@length)r[x@i] <-if(cl != "nsparseVector") { # cheap test for 'has x slot'if(is(x@x, mode)) x@x else as(x@x, mode)} else TRUEr}setAs("sparseVector", "vector", function(from) sp2vec(from))setMethod("as.vector", signature(x = "sparseVector", mode = "missing"),sp2vec)setMethod("as.vector", signature(x = "sparseVector", mode = "character"),sp2vec)setMethod("as.numeric", "sparseVector", function(x) sp2vec(x, mode = "double"))## the "catch all remaining" method:setAs("ANY", "sparseVector",function(from) as(as.vector(from), "sparseVector"))setAs("diagonalMatrix", "sparseVector",function(from) {kind <- .M.kind(from) ## currently only "l" and "d" --> have 'x'n <- nrow(from)new(paste(kind, "sparseVector", sep=''),length = n, # 1-based indexingi = as.integer(seq(1L, by = n+1, length.out = n)),x = if(from@diag != "U") from@x elseswitch(kind, "d" = 1, "l" = TRUE, "i" = 1L, "z" = 1+0i))})setAs("sparseMatrix", "sparseVector",function(from) as(as(from, "TsparseMatrix"), "sparseVector"))setAs("TsparseMatrix", "sparseVector",function(from) {d <- dim(from)n <- d[1] * d[2] # length of vectorkind <- .M.kind(from)if(is_duplicatedT(from, nr = d[1]))from <- uniqTsparse(from)r <- new(paste(kind, "sparseVector", sep=''), length = n)r@i <- 1L + from@i + d[1] * from@jif(kind != "n") ## have 'x' slotr@x <- from@xr})## TODO -- also want (sparseVector, dim) |---> sparseMatrix## because of (nrow,ncol) specification can not (?) use as(.).## Hence use Matrix(.) ? or my spMatrix(.) ?## For now, define this utility function:spV2M <- function (x, nrow, ncol, byrow = FALSE){## Purpose: sparseVector --> sparseMatrix constructor## ----------------------------------------------------------------------## Arguments: x: "sparseVector" object## nrow, ncol, byrow: as for matrix() or Matrix()## ----------------------------------------------------------------------## Author: Martin Maechler, Date: 11 May 2007cx <- class(x)stopifnot(extends(cx, "sparseVector"))if(!missing(ncol)) { ncol <- as.integer(ncol)if(ncol <= 0) stop("'ncol' must be >= 1") }if(!missing(nrow)) { nrow <- as.integer(nrow)if(nrow <= 0) stop("'nrow' must be >= 1") }n <- length(x)if(missing(nrow)) {if(missing(ncol)) { ## both missing: --> (n x 1)ncol <- 1Lnrow <- n} else {if(n %% ncol != 0) warning("'ncol' is not a factor of length(x)")nrow <- as.integer(ceiling(n / ncol))}} else {if(missing(ncol)) {if(n %% nrow != 0) warning("'nrow' is not a factor of length(x)")ncol <- as.integer(ceiling(n / nrow))} else { ## both nrow and ncol specifiedif(ncol * nrow < n) stop("nrow * ncol < length(x)")if(ncol * nrow != n) warning("nrow * ncol != length(x)")}}## now nrow * ncol >= n## ~~~~~~~~~~~~~~~~cld <- getClassDef(cx)kind <- .M.kindC(cld) # "d", "n", "l", "z", ...has.x <- kind != "n"r <- new(paste(kind,"gTMatrix", sep=''), Dim = c(nrow, ncol))## now "compute" the (i,j,x) slots given x@(i,x)i0 <- x@i - 1Lif(byrow) {r@j <- i0 %% ncolr@i <- i0 %/% ncol} else { # default{byrow = FALSE}r@i <- i0 %% nrowr@j <- i0 %/% nrow}if(has.x) r@x <- x@xr}setMethod("length", "sparseVector", function(x) x@length)setMethod("show", signature(object = "sparseVector"),function(object) {n <- object@lengthcl <- class(object)cat(sprintf('sparse vector (nnz/length = %d/%d) of class "%s"\n',length(object@i), n, cl))maxp <- max(1, getOption("max.print"))if(n <= maxp) {prSpVector(object, maxp = maxp)} else { # n > maxp : will cut length of what we'll display :## cannot easily show head(.) & tail(.) because of "[1] .." printing of tailprSpVector(object[seq_len(maxp)], maxp = maxp)cat(" ............................","\n ........suppressing ", n - maxp," entries in show(); maybe adjust 'options(max.print= *)'","\n ............................\n\n", sep='')}invisible(object)})prSpVector <- function(x, digits = getOption("digits"),maxp = getOption("max.print"), zero.print = "."){cld <- getClassDef(cl <- class(x))stopifnot(extends(cld, "sparseVector"), maxp >= 1)if(is.logical(zero.print))zero.print <- if(zero.print) "0" else " "## kind <- .M.kindC(cld)## has.x <- kind != "n"n <- x@lengthif(n > maxp) {# n > maxp =: nn : will cut length of what we'll display :x <- x[seq_len(maxp)] # need "[" to work ...n <- as.integer(maxp)}xi <- x@ilogi <- extends(cld, "lsparseVector") || extends(cld, "nsparseVector")cx <- if(logi) rep.int("N", n) else character(n)cx[ -xi ] <- zero.printcx[ xi ] <- {if(logi) "|" else## numeric (or --not yet-- complex): 'has.x' in any casesformat(x@x, digits = digits)}## right = TRUE : cheap attempt to get better "." alignmentprint(cx, quote = FALSE, right = TRUE, max = maxp)invisible(x) # TODO? in case of n > maxp, "should" return original x}## This is a simplified intI() {-> ./Tsparse.R } -- for sparseVector indexing:intIv <- function(i, n){## Purpose: translate numeric | logical index into 1-based integer## --------------------------------------------------------------------## Arguments: i: index vector (numeric | logical)## n: array extent { == length(.) }if(missing(i))seq_len(n)else if(is(i, "numeric")) {storage.mode(i) <- "integer"if(any(i < 0L)) {if(any(i > 0L))stop("you cannot mix negative and positive indices")seq_len(n)[i]} else {if(length(i) && max(i) > n)stop("indexing out of range 0:",n)if(any(z <- i == 0))i <- i[!z]i}}else if (is(i, "logical")) {seq_len(n)[i]} else stop("index must be numeric or logical for 'sparseVector' indexing")}setMethod("[", signature(x = "sparseVector", i = "index"),function (x, i, j, drop) {cld <- getClassDef(class(x))has.x <- !extends(cld, "nsparseVector")n <- x@lengthii <- intIv(i, n)anyDup <- any(iDup <- duplicated(ii))m <- match(x@i, ii, nomatch = 0)sel <- m > 0Lx@length <- length(ii)x@i <- m[sel]if(anyDup) {i.i <- match(ii[iDup], ii)jm <- lapply(i.i, function(.) which(. == m))sel <- c(which(sel), unlist(jm))x@i <- c(x@i, rep.int(which(iDup), sapply(jm, length)))}if (has.x)x@x <- x@x[sel]x})## This is much analogous to replTmat in ./Tsparse.R:replSPvec <- function (x, i, value){n <- x@lengthii <- intIv(i, n)lenRepl <- length(ii)lenV <- length(value)if(lenV == 0) {if(lenRepl != 0)stop("nothing to replace with")else return(x)}## else: lenV := length(value) > 0if(lenRepl %% lenV != 0)stop("number of items to replace is not a multiple of replacement length")anyDup <- any(duplicated(ii))if(anyDup) { ## multiple *replacement* indices: last one wins## TODO: in R 2.6.0 use duplicate(*, fromLast=TRUE)ir <- lenRepl:1keep <- match(ii, ii[ir]) == irii <- ii[keep]lenV <- length(value <- rep(value, length = lenRepl)[keep])lenRepl <- length(ii)}cld <- getClassDef(class(x))has.x <- !extends(cld, "nsparseVector")m <- match(x@i, ii, nomatch = 0)sel <- m > 0L## the simplest caseif(all0(value)) { ## just drop the non-zero entriesif(any(sel)) { ## non-zero therex@i <- x@i[!sel]if(has.x)x@x <- x@x[!sel]}return(x)}## else -- some( value != 0 ) --if(lenV > lenRepl)stop("too many replacement values")else if(lenV < lenRepl)value <- rep(value, length = lenRepl)## now: length(value) == lenReplv0 <- is0(value)## value[1:lenRepl]: which are structural 0 now, which not?if(any(sel)) {## indices of non-zero entries -- WRT to subvectoriN0 <- m[sel] ## == match(x@i[sel], ii)## 1a) replace those that are already non-zero with new val.vN0 <- !v0[iN0]if(any(vN0) && has.x)x@x[sel][vN0] <- value[iN0[vN0]]## 1b) replace non-zeros with 0 --> drop entriesif(any(!vN0)) {i <- which(sel)[!vN0]if(has.x)x@x <- x@x[-i]x@i <- x@i[-i]}iI0 <- if(length(iN0) < lenRepl)seq_len(lenRepl)[-iN0]} else iI0 <- seq_len(lenRepl)if(length(iI0) && any(vN0 <- !v0[iI0])) {## 2) add those that were structural 0 (where value != 0)ij0 <- iI0[vN0]x@i <- c(x@i, ii[ij0])if(has.x)x@x <- c(x@x, value[ij0])}x}setReplaceMethod("[", signature(x = "sparseVector", i = "index", j = "missing",value = "replValue"),replSPvec)## a "method" for c(<(sparse)Vector>, <(sparse)Vector>):c2v <- function(x, y) {## these as(., "sp..V..") check input implicitly:cx <- class(x <- as(x, "sparseVector"))cy <- class(y <- as(y, "sparseVector"))if(cx != cy) { ## find "common" class; result does have 'x' slotcxy <- c(cx,cy)commType <- {if(all(cxy %in% c("nsparseVector", "lsparseVector")))"lsparseVector"else { # ==> "numeric" ("integer") or "complex"xslot1 <- function(u, cl.u)if(cl.u != "nsparseVector") u@x[1] else TRUEswitch(typeof(xslot1(x, cx) + xslot1(y, cy)),## "integer", "double", or "complex""integer" = "isparseVector","double" = "dsparseVector","complex" = "zsparseVector")}}if(cx != commType) x <- as(x, commType)if(cy != commType) y <- as(y, commType)cx <- commType}## now *have* common type -- transform 'x' into result:nx <- x@lengthx@length <- nx + y@lengthx@i <- c(x@i, nx + y@i)if(cx != "nsparseVector")x@x <- c(x@x, y@x)x}### Group Methods (!)## o "Ops" , "Arith", "Compare" : ---> in ./Ops.R