| 4354 |
maechler |
1 |
#### All Methods in relation with the sparseVector (sub)classes
|
|
|
2 |
|
|
|
3 |
|
|
|
4 |
# atomicVector : classUnion (logical,integer,double,....)
|
|
|
5 |
setAs("atomicVector", "sparseVector",
|
|
|
6 |
function(from) {
|
|
|
7 |
n <- length(from)
|
| 4501 |
maechler |
8 |
r <- new(paste(.V.kind(from), "sparseVector", sep=''), length = n)
|
| 4354 |
maechler |
9 |
ii <- from != 0
|
|
|
10 |
r@x <- from[ii]
|
|
|
11 |
r@i <- seq_len(n)[ii]
|
|
|
12 |
r
|
|
|
13 |
})
|
|
|
14 |
|
| 4501 |
maechler |
15 |
|
|
|
16 |
for(T in c("d","i","l","z")) {
|
|
|
17 |
setAs("xsparseVector", paste(T, "sparseVector", sep=''),
|
|
|
18 |
function(from) {
|
|
|
19 |
from@x <- as(from@x, .type.kind[T])
|
|
|
20 |
## and now "the hack":
|
|
|
21 |
class(from) <- paste(T, "sparseVector", sep='')
|
|
|
22 |
from
|
|
|
23 |
})
|
|
|
24 |
}
|
|
|
25 |
|
|
|
26 |
setAs("sparseVector", "nsparseVector",
|
|
|
27 |
function(from) {
|
|
|
28 |
if(any(is.na(from@x)))
|
|
|
29 |
stop("cannot coerce 'NA's to \"nsparseVector\"")
|
|
|
30 |
new("nsparseVector", i = from@i, length = from@length)
|
|
|
31 |
})
|
|
|
32 |
|
| 4354 |
maechler |
33 |
sp2vec <- function(x, mode = .type.kind[substr(cl, 1,1)]) {
|
|
|
34 |
cl <- class(x)
|
|
|
35 |
r <- vector(mode, x@length)
|
|
|
36 |
r[x@i] <-
|
|
|
37 |
if(cl != "nsparseVector") { # cheap test for 'has x slot'
|
|
|
38 |
if(is(x@x, mode)) x@x else as(x@x, mode)
|
|
|
39 |
} else TRUE
|
|
|
40 |
r
|
|
|
41 |
}
|
|
|
42 |
|
|
|
43 |
setAs("sparseVector", "vector", function(from) sp2vec(from))
|
|
|
44 |
|
|
|
45 |
setMethod("as.vector", signature(x = "sparseVector", mode = "missing"),
|
|
|
46 |
sp2vec)
|
|
|
47 |
setMethod("as.vector", signature(x = "sparseVector", mode = "character"),
|
|
|
48 |
sp2vec)
|
|
|
49 |
|
|
|
50 |
setMethod("as.numeric", "sparseVector", function(x) sp2vec(x, mode = "double"))
|
|
|
51 |
|
|
|
52 |
## the "catch all remaining" method:
|
|
|
53 |
setAs("ANY", "sparseVector",
|
|
|
54 |
function(from) as(as.vector(from), "sparseVector"))
|
|
|
55 |
|
|
|
56 |
setAs("diagonalMatrix", "sparseVector",
|
|
|
57 |
function(from) {
|
|
|
58 |
kind <- .M.kind(from) ## currently only "l" and "d" --> have 'x'
|
|
|
59 |
n <- nrow(from)
|
|
|
60 |
new(paste(kind, "sparseVector", sep=''),
|
|
|
61 |
length = n, # 1-based indexing
|
|
|
62 |
i = as.integer(seq(1L, by = n+1, length.out = n)),
|
|
|
63 |
x = if(from@diag != "U") from@x else
|
|
|
64 |
switch(kind, "d" = 1, "l" = TRUE, "i" = 1L, "z" = 1+0i))
|
|
|
65 |
})
|
|
|
66 |
|
|
|
67 |
setAs("sparseMatrix", "sparseVector",
|
|
|
68 |
function(from) as(as(from, "TsparseMatrix"), "sparseVector"))
|
|
|
69 |
|
|
|
70 |
setAs("TsparseMatrix", "sparseVector",
|
|
|
71 |
function(from) {
|
|
|
72 |
d <- dim(from)
|
|
|
73 |
n <- d[1] * d[2] # length of vector
|
|
|
74 |
kind <- .M.kind(from)
|
|
|
75 |
if(is_duplicatedT(from, nr = d[1]))
|
|
|
76 |
from <- uniqTsparse(from)
|
|
|
77 |
r <- new(paste(kind, "sparseVector", sep=''), length = n)
|
|
|
78 |
r@i <- 1L + from@i + d[1] * from@j
|
|
|
79 |
if(kind != "n") ## have 'x' slot
|
|
|
80 |
r@x <- from@x
|
|
|
81 |
r
|
|
|
82 |
})
|
|
|
83 |
|
|
|
84 |
|
|
|
85 |
|
|
|
86 |
## TODO -- also want (sparseVector, dim) |---> sparseMatrix
|
|
|
87 |
## because of (nrow,ncol) specification can not (?) use as(.).
|
|
|
88 |
## Hence use Matrix(.) ? or my spMatrix(.) ?
|
|
|
89 |
|
|
|
90 |
## For now, define this utility function:
|
|
|
91 |
spV2M <- function (x, nrow, ncol, byrow = FALSE)
|
|
|
92 |
{
|
|
|
93 |
## Purpose: sparseVector --> sparseMatrix constructor
|
|
|
94 |
## ----------------------------------------------------------------------
|
|
|
95 |
## Arguments: x: "sparseVector" object
|
|
|
96 |
## nrow, ncol, byrow: as for matrix() or Matrix()
|
|
|
97 |
## ----------------------------------------------------------------------
|
|
|
98 |
## Author: Martin Maechler, Date: 11 May 2007
|
|
|
99 |
|
|
|
100 |
cx <- class(x)
|
|
|
101 |
stopifnot(extends(cx, "sparseVector"))
|
|
|
102 |
if(!missing(ncol)) { ncol <- as.integer(ncol)
|
|
|
103 |
if(ncol <= 0) stop("'ncol' must be >= 1") }
|
|
|
104 |
if(!missing(nrow)) { nrow <- as.integer(nrow)
|
|
|
105 |
if(nrow <= 0) stop("'nrow' must be >= 1") }
|
|
|
106 |
n <- length(x)
|
|
|
107 |
if(missing(nrow)) {
|
|
|
108 |
if(missing(ncol)) { ## both missing: --> (n x 1)
|
|
|
109 |
ncol <- 1L
|
|
|
110 |
nrow <- n
|
|
|
111 |
} else {
|
|
|
112 |
if(n %% ncol != 0) warning("'ncol' is not a factor of length(x)")
|
|
|
113 |
nrow <- as.integer(ceiling(n / ncol))
|
|
|
114 |
}
|
|
|
115 |
} else {
|
|
|
116 |
if(missing(ncol)) {
|
|
|
117 |
if(n %% nrow != 0) warning("'nrow' is not a factor of length(x)")
|
|
|
118 |
ncol <- as.integer(ceiling(n / nrow))
|
|
|
119 |
} else { ## both nrow and ncol specified
|
|
|
120 |
if(ncol * nrow < n) stop("nrow * ncol < length(x)")
|
|
|
121 |
if(ncol * nrow != n) warning("nrow * ncol != length(x)")
|
|
|
122 |
}
|
|
|
123 |
}
|
|
|
124 |
## now nrow * ncol >= n
|
|
|
125 |
## ~~~~~~~~~~~~~~~~
|
|
|
126 |
cld <- getClassDef(cx)
|
|
|
127 |
kind <- .M.kindC(cld) # "d", "n", "l", "z", ...
|
|
|
128 |
has.x <- kind != "n"
|
|
|
129 |
r <- new(paste(kind,"gTMatrix", sep=''), Dim = c(nrow, ncol))
|
|
|
130 |
## now "compute" the (i,j,x) slots given x@(i,x)
|
|
|
131 |
i0 <- x@i - 1L
|
|
|
132 |
if(byrow) {
|
|
|
133 |
r@j <- i0 %% ncol
|
|
|
134 |
r@i <- i0 %/% ncol
|
|
|
135 |
} else { # default{byrow = FALSE}
|
|
|
136 |
r@i <- i0 %% nrow
|
|
|
137 |
r@j <- i0 %/% nrow
|
|
|
138 |
}
|
|
|
139 |
if(has.x) r@x <- x@x
|
|
|
140 |
r
|
|
|
141 |
}
|
|
|
142 |
|
|
|
143 |
setMethod("length", "sparseVector", function(x) x@length)
|
|
|
144 |
|
|
|
145 |
setMethod("show", signature(object = "sparseVector"),
|
|
|
146 |
function(object) {
|
|
|
147 |
n <- object@length
|
|
|
148 |
cl <- class(object)
|
|
|
149 |
cat(sprintf('sparse vector (nnz/length = %d/%d) of class "%s"\n',
|
|
|
150 |
length(object@i), n, cl))
|
|
|
151 |
maxp <- max(1, getOption("max.print"))
|
|
|
152 |
if(n <= maxp) {
|
|
|
153 |
prSpVector(object, maxp = maxp)
|
|
|
154 |
} else { # n > maxp : will cut length of what we'll display :
|
|
|
155 |
## cannot easily show head(.) & tail(.) because of "[1] .." printing of tail
|
|
|
156 |
prSpVector(object[seq_len(maxp)], maxp = maxp)
|
|
|
157 |
cat(" ............................",
|
|
|
158 |
"\n ........suppressing ", n - maxp,
|
|
|
159 |
" entries in show(); maybe adjust 'options(max.print= *)'",
|
|
|
160 |
"\n ............................\n\n", sep='')
|
|
|
161 |
}
|
|
|
162 |
invisible(object)
|
|
|
163 |
})
|
|
|
164 |
|
|
|
165 |
prSpVector <- function(x, digits = getOption("digits"),
|
|
|
166 |
maxp = getOption("max.print"), zero.print = ".")
|
|
|
167 |
{
|
|
|
168 |
cld <- getClassDef(cl <- class(x))
|
|
|
169 |
stopifnot(extends(cld, "sparseVector"), maxp >= 1)
|
|
|
170 |
if(is.logical(zero.print))
|
|
|
171 |
zero.print <- if(zero.print) "0" else " "
|
|
|
172 |
## kind <- .M.kindC(cld)
|
|
|
173 |
## has.x <- kind != "n"
|
|
|
174 |
n <- x@length
|
|
|
175 |
if(n > maxp) {# n > maxp =: nn : will cut length of what we'll display :
|
|
|
176 |
x <- x[seq_len(maxp)] # need "[" to work ...
|
|
|
177 |
n <- as.integer(maxp)
|
|
|
178 |
}
|
|
|
179 |
xi <- x@i
|
|
|
180 |
logi <- extends(cld, "lsparseVector") || extends(cld, "nsparseVector")
|
|
|
181 |
cx <- if(logi) rep.int("N", n) else character(n)
|
|
|
182 |
cx[ -xi ] <- zero.print
|
|
|
183 |
cx[ xi ] <- {
|
|
|
184 |
if(logi) "|" else
|
|
|
185 |
## numeric (or --not yet-- complex): 'has.x' in any cases
|
|
|
186 |
format(x@x, digits = digits)
|
|
|
187 |
}
|
|
|
188 |
## right = TRUE : cheap attempt to get better "." alignment
|
|
|
189 |
print(cx, quote = FALSE, right = TRUE, max = maxp)
|
|
|
190 |
invisible(x) # TODO? in case of n > maxp, "should" return original x
|
|
|
191 |
}
|
|
|
192 |
|
|
|
193 |
## This is a simplified intI() {-> ./Tsparse.R } -- for sparseVector indexing:
|
|
|
194 |
intIv <- function(i, n)
|
|
|
195 |
{
|
|
|
196 |
## Purpose: translate numeric | logical index into 1-based integer
|
|
|
197 |
## --------------------------------------------------------------------
|
|
|
198 |
## Arguments: i: index vector (numeric | logical)
|
|
|
199 |
## n: array extent { == length(.) }
|
| 4371 |
maechler |
200 |
if(missing(i))
|
|
|
201 |
seq_len(n)
|
|
|
202 |
else if(is(i, "numeric")) {
|
| 4354 |
maechler |
203 |
storage.mode(i) <- "integer"
|
|
|
204 |
if(any(i < 0L)) {
|
|
|
205 |
if(any(i > 0L))
|
|
|
206 |
stop("you cannot mix negative and positive indices")
|
|
|
207 |
seq_len(n)[i]
|
|
|
208 |
} else {
|
|
|
209 |
if(length(i) && max(i) > n)
|
|
|
210 |
stop("indexing out of range 0:",n)
|
|
|
211 |
if(any(z <- i == 0))
|
|
|
212 |
i <- i[!z]
|
|
|
213 |
i
|
|
|
214 |
}
|
|
|
215 |
}
|
|
|
216 |
else if (is(i, "logical")) {
|
|
|
217 |
seq_len(n)[i]
|
|
|
218 |
} else stop("index must be numeric or logical for 'sparseVector' indexing")
|
|
|
219 |
}
|
|
|
220 |
|
|
|
221 |
|
|
|
222 |
setMethod("[", signature(x = "sparseVector", i = "index"),
|
| 4743 |
maechler |
223 |
function (x, i, j, ..., drop) {
|
| 4354 |
maechler |
224 |
cld <- getClassDef(class(x))
|
|
|
225 |
has.x <- !extends(cld, "nsparseVector")
|
|
|
226 |
n <- x@length
|
|
|
227 |
ii <- intIv(i, n)
|
|
|
228 |
anyDup <- any(iDup <- duplicated(ii))
|
|
|
229 |
m <- match(x@i, ii, nomatch = 0)
|
|
|
230 |
sel <- m > 0L
|
|
|
231 |
x@length <- length(ii)
|
|
|
232 |
x@i <- m[sel]
|
|
|
233 |
if(anyDup) {
|
|
|
234 |
i.i <- match(ii[iDup], ii)
|
|
|
235 |
jm <- lapply(i.i, function(.) which(. == m))
|
|
|
236 |
sel <- c(which(sel), unlist(jm))
|
|
|
237 |
x@i <- c(x@i, rep.int(which(iDup), sapply(jm, length)))
|
|
|
238 |
}
|
|
|
239 |
if (has.x)
|
|
|
240 |
x@x <- x@x[sel]
|
|
|
241 |
x
|
|
|
242 |
})
|
|
|
243 |
|
| 4371 |
maechler |
244 |
## This is much analogous to replTmat in ./Tsparse.R:
|
|
|
245 |
replSPvec <- function (x, i, value)
|
|
|
246 |
{
|
|
|
247 |
n <- x@length
|
|
|
248 |
ii <- intIv(i, n)
|
|
|
249 |
lenRepl <- length(ii)
|
|
|
250 |
lenV <- length(value)
|
|
|
251 |
if(lenV == 0) {
|
|
|
252 |
if(lenRepl != 0)
|
|
|
253 |
stop("nothing to replace with")
|
|
|
254 |
else return(x)
|
|
|
255 |
}
|
|
|
256 |
## else: lenV := length(value) > 0
|
|
|
257 |
if(lenRepl %% lenV != 0)
|
|
|
258 |
stop("number of items to replace is not a multiple of replacement length")
|
|
|
259 |
anyDup <- any(duplicated(ii))
|
|
|
260 |
if(anyDup) { ## multiple *replacement* indices: last one wins
|
|
|
261 |
## TODO: in R 2.6.0 use duplicate(*, fromLast=TRUE)
|
|
|
262 |
ir <- lenRepl:1
|
|
|
263 |
keep <- match(ii, ii[ir]) == ir
|
|
|
264 |
ii <- ii[keep]
|
|
|
265 |
lenV <- length(value <- rep(value, length = lenRepl)[keep])
|
|
|
266 |
lenRepl <- length(ii)
|
|
|
267 |
}
|
|
|
268 |
|
|
|
269 |
cld <- getClassDef(class(x))
|
|
|
270 |
has.x <- !extends(cld, "nsparseVector")
|
|
|
271 |
m <- match(x@i, ii, nomatch = 0)
|
|
|
272 |
sel <- m > 0L
|
|
|
273 |
|
|
|
274 |
## the simplest case
|
|
|
275 |
if(all0(value)) { ## just drop the non-zero entries
|
|
|
276 |
if(any(sel)) { ## non-zero there
|
|
|
277 |
x@i <- x@i[!sel]
|
|
|
278 |
if(has.x)
|
|
|
279 |
x@x <- x@x[!sel]
|
|
|
280 |
}
|
|
|
281 |
return(x)
|
|
|
282 |
|
|
|
283 |
}
|
|
|
284 |
## else -- some( value != 0 ) --
|
|
|
285 |
if(lenV > lenRepl)
|
|
|
286 |
stop("too many replacement values")
|
|
|
287 |
else if(lenV < lenRepl)
|
|
|
288 |
value <- rep(value, length = lenRepl)
|
|
|
289 |
## now: length(value) == lenRepl
|
|
|
290 |
|
|
|
291 |
v0 <- is0(value)
|
|
|
292 |
## value[1:lenRepl]: which are structural 0 now, which not?
|
|
|
293 |
|
|
|
294 |
if(any(sel)) {
|
|
|
295 |
## indices of non-zero entries -- WRT to subvector
|
|
|
296 |
iN0 <- m[sel] ## == match(x@i[sel], ii)
|
|
|
297 |
|
|
|
298 |
## 1a) replace those that are already non-zero with new val.
|
|
|
299 |
vN0 <- !v0[iN0]
|
|
|
300 |
if(any(vN0) && has.x)
|
|
|
301 |
x@x[sel][vN0] <- value[iN0[vN0]]
|
|
|
302 |
|
|
|
303 |
## 1b) replace non-zeros with 0 --> drop entries
|
|
|
304 |
if(any(!vN0)) {
|
|
|
305 |
i <- which(sel)[!vN0]
|
|
|
306 |
if(has.x)
|
|
|
307 |
x@x <- x@x[-i]
|
|
|
308 |
x@i <- x@i[-i]
|
|
|
309 |
}
|
|
|
310 |
iI0 <- if(length(iN0) < lenRepl)
|
|
|
311 |
seq_len(lenRepl)[-iN0]
|
|
|
312 |
} else iI0 <- seq_len(lenRepl)
|
|
|
313 |
|
|
|
314 |
if(length(iI0) && any(vN0 <- !v0[iI0])) {
|
|
|
315 |
## 2) add those that were structural 0 (where value != 0)
|
|
|
316 |
ij0 <- iI0[vN0]
|
|
|
317 |
x@i <- c(x@i, ii[ij0])
|
|
|
318 |
if(has.x)
|
|
|
319 |
x@x <- c(x@x, value[ij0])
|
|
|
320 |
}
|
|
|
321 |
x
|
|
|
322 |
|
|
|
323 |
}
|
|
|
324 |
|
| 4440 |
maechler |
325 |
setReplaceMethod("[", signature(x = "sparseVector", i = "index", j = "missing",
|
| 4371 |
maechler |
326 |
value = "replValue"),
|
|
|
327 |
replSPvec)
|
|
|
328 |
|
|
|
329 |
|
|
|
330 |
|
| 4483 |
maechler |
331 |
## a "method" for c(<(sparse)Vector>, <(sparse)Vector>):
|
| 4743 |
maechler |
332 |
## FIXME: This is not exported, nor used (nor documented)
|
| 4354 |
maechler |
333 |
c2v <- function(x, y) {
|
| 4483 |
maechler |
334 |
## these as(., "sp..V..") check input implicitly:
|
|
|
335 |
cx <- class(x <- as(x, "sparseVector"))
|
|
|
336 |
cy <- class(y <- as(y, "sparseVector"))
|
| 4354 |
maechler |
337 |
if(cx != cy) { ## find "common" class; result does have 'x' slot
|
|
|
338 |
cxy <- c(cx,cy)
|
|
|
339 |
commType <- {
|
|
|
340 |
if(all(cxy %in% c("nsparseVector", "lsparseVector")))
|
|
|
341 |
"lsparseVector"
|
|
|
342 |
else { # ==> "numeric" ("integer") or "complex"
|
|
|
343 |
xslot1 <- function(u, cl.u)
|
|
|
344 |
if(cl.u != "nsparseVector") u@x[1] else TRUE
|
|
|
345 |
switch(typeof(xslot1(x, cx) + xslot1(y, cy)),
|
|
|
346 |
## "integer", "double", or "complex"
|
|
|
347 |
"integer" = "isparseVector",
|
|
|
348 |
"double" = "dsparseVector",
|
|
|
349 |
"complex" = "zsparseVector")
|
|
|
350 |
}
|
|
|
351 |
}
|
|
|
352 |
if(cx != commType) x <- as(x, commType)
|
|
|
353 |
if(cy != commType) y <- as(y, commType)
|
|
|
354 |
cx <- commType
|
|
|
355 |
}
|
|
|
356 |
## now *have* common type -- transform 'x' into result:
|
|
|
357 |
nx <- x@length
|
|
|
358 |
x@length <- nx + y@length
|
|
|
359 |
x@i <- c(x@i, nx + y@i)
|
|
|
360 |
if(cx != "nsparseVector")
|
|
|
361 |
x@x <- c(x@x, y@x)
|
|
|
362 |
x
|
|
|
363 |
}
|
|
|
364 |
|
|
|
365 |
|
|
|
366 |
### Group Methods (!)
|
|
|
367 |
|
| 4371 |
maechler |
368 |
## o "Ops" , "Arith", "Compare" : ---> in ./Ops.R
|
| 4354 |
maechler |
369 |
|