The R Project SVN R-packages

Rev

Rev 4501 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
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